mirror of
https://github.com/notion-enhancer/notion-enhancer.git
synced 2025-04-06 21:49:03 +00:00
sync menu & notion themes, mod page routing, better component gen
This commit is contained in:
parent
d2292137da
commit
93e764fb0a
@ -13,7 +13,8 @@ export const ERROR = Symbol();
|
||||
export const env = {};
|
||||
env.name = 'browser';
|
||||
|
||||
env.openEnhancerMenu = () => chrome.runtime.sendMessage({ type: 'enhancerMenu.open' });
|
||||
env.openEnhancerMenu = ({ theme } = {}) =>
|
||||
chrome.runtime.sendMessage({ type: 'enhancerMenu.open', data: { theme } });
|
||||
|
||||
export const web = {};
|
||||
|
||||
@ -50,7 +51,7 @@ web.createElement = (html) => {
|
||||
: html
|
||||
.split(/\n/)
|
||||
.map((line) => line.trim())
|
||||
.join('');
|
||||
.join(' ');
|
||||
return template.content.firstElementChild;
|
||||
};
|
||||
web.htmlEscape = (str) =>
|
||||
|
@ -16,6 +16,5 @@ import(chrome.runtime.getURL('helpers.js')).then(({ web, registry }) => {
|
||||
import(chrome.runtime.getURL(`repo/${mod._dir}/${script}`));
|
||||
}
|
||||
}
|
||||
console.log(await registry.errors());
|
||||
});
|
||||
});
|
||||
|
@ -27,5 +27,6 @@
|
||||
"js": ["launcher.js"]
|
||||
}
|
||||
],
|
||||
"permissions": ["storage"],
|
||||
"host_permissions": ["https://*.notion.so/*"]
|
||||
}
|
||||
|
@ -15,7 +15,19 @@ web.whenReady([sidebarSelector], async () => {
|
||||
enhancerSidebarElement = web.createElement(
|
||||
`<div class="enhancer--sidebarMenuTrigger" role="button" tabindex="0"><div><div>${enhancerIcon}</div><div><div>notion-enhancer</div></div></div></div>`
|
||||
);
|
||||
enhancerSidebarElement.addEventListener('click', env.openEnhancerMenu);
|
||||
const setTheme = () =>
|
||||
new Promise((res, rej) =>
|
||||
chrome.storage.local.set(
|
||||
{ 'notion.theme': document.querySelector('.notion-dark-theme') ? 'dark' : 'light' },
|
||||
res
|
||||
)
|
||||
);
|
||||
enhancerSidebarElement.addEventListener('click', () =>
|
||||
setTheme().then(env.openEnhancerMenu)
|
||||
);
|
||||
window.addEventListener('focus', setTheme);
|
||||
window.addEventListener('blur', setTheme);
|
||||
setTheme();
|
||||
document.querySelector(sidebarSelector).appendChild(enhancerSidebarElement);
|
||||
});
|
||||
web.hotkeyListener(['Ctrl', 'Alt', 'E'], env.openEnhancerMenu);
|
||||
|
@ -12,6 +12,13 @@
|
||||
color: var(--theme--text);
|
||||
}
|
||||
|
||||
html {
|
||||
transition: opacity 50ms ease-out;
|
||||
}
|
||||
html[class] {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 1.5rem;
|
||||
background: var(--theme--sidebar);
|
||||
@ -37,12 +44,14 @@ main section[data-container] {
|
||||
display: grid;
|
||||
grid-gap: 1.25em;
|
||||
grid-template-columns: 1fr;
|
||||
opacity: 1;
|
||||
transition: opacity 200ms ease-out;
|
||||
}
|
||||
@media (min-width: 550px) {
|
||||
main section[data-container] {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
main section[data-container='page'] > .documentation--buttons {
|
||||
main section[data-container='mod'] > .documentation--buttons {
|
||||
grid-column: span 2;
|
||||
}
|
||||
}
|
||||
@ -50,10 +59,10 @@ main section[data-container] {
|
||||
main section[data-container] {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
main section[data-container='page'] > .documentation--buttons {
|
||||
main section[data-container='mod'] > .documentation--buttons {
|
||||
grid-column: span 3;
|
||||
}
|
||||
main section[data-container='page'] > .documentation--body {
|
||||
main section[data-container='mod'] > .documentation--body {
|
||||
grid-column: span 2;
|
||||
}
|
||||
}
|
||||
@ -61,10 +70,10 @@ main section[data-container] {
|
||||
main section[data-container] {
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
main section[data-container='page'] > .documentation--buttons {
|
||||
main section[data-container='mod'] > .documentation--buttons {
|
||||
grid-column: span 4;
|
||||
}
|
||||
main section[data-container='page'] > .documentation--body {
|
||||
main section[data-container='mod'] > .documentation--body {
|
||||
grid-column: span 3;
|
||||
}
|
||||
}
|
||||
@ -72,10 +81,10 @@ main section[data-container] {
|
||||
main section[data-container] {
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||
}
|
||||
main section[data-container='page'] > .documentation--buttons {
|
||||
main section[data-container='mod'] > .documentation--buttons {
|
||||
grid-column: span 5;
|
||||
}
|
||||
main section[data-container='page'] > .documentation--body {
|
||||
main section[data-container='mod'] > .documentation--body {
|
||||
grid-column: span 4;
|
||||
}
|
||||
}
|
||||
@ -122,10 +131,8 @@ main section[data-container] article > div {
|
||||
padding-top: 2px;
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
.documentation--buttons svg polygon,
|
||||
.documentation--buttons svg path,
|
||||
.library--expand svg polygon,
|
||||
.library--expand svg path {
|
||||
.documentation--buttons svg *,
|
||||
.library--expand svg * {
|
||||
fill: var(--theme--text_property);
|
||||
}
|
||||
|
||||
@ -222,7 +229,7 @@ main section[data-container] article > div {
|
||||
}
|
||||
.library--toggle_label > :not(input) .library--toggle::after {
|
||||
content: '';
|
||||
transition: transform 200ms ease-out 0s, background 200ms ease-out 0s;
|
||||
transition: transform 200ms ease-out, background 200ms ease-out;
|
||||
height: 0.8rem;
|
||||
width: 0.8rem;
|
||||
left: 0.325rem;
|
||||
@ -268,13 +275,12 @@ main section[data-container] article > div {
|
||||
border-radius: 3px;
|
||||
border: none;
|
||||
box-shadow: var(--theme--input-border) 0px 0px 0px 1px inset;
|
||||
--theme--input_icon: var(--theme_dark--input_icon);
|
||||
}
|
||||
.library--select_label .library--select select {
|
||||
outline: none;
|
||||
}
|
||||
.library--select_label .library--select select option {
|
||||
background: var(--theme_dark--tag_select);
|
||||
background: var(--theme--tag_select);
|
||||
}
|
||||
.library--select_label .library--select,
|
||||
.library--file_label .library--file {
|
||||
@ -292,6 +298,10 @@ main section[data-container] article > div {
|
||||
width: 0.9em;
|
||||
margin: auto 0;
|
||||
}
|
||||
.library--select_label .library--select > :first-child svg *,
|
||||
.library--file_label .library--file > :first-child svg * {
|
||||
color: var(--theme--input_icon);
|
||||
}
|
||||
.library--select_label .library--select > :last-child,
|
||||
.library--file_label .library--file > :last-child {
|
||||
margin: auto 0;
|
||||
@ -312,7 +322,7 @@ main section[data-container] article > div {
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.library--full_card,
|
||||
main section[data-container='mod'] .library--card,
|
||||
.documentation--body {
|
||||
max-height: calc(100vh - 10rem);
|
||||
overflow: auto;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="notion-dark-theme">
|
||||
<html lang="en" style="opacity: 0">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
@ -9,13 +9,13 @@
|
||||
<body>
|
||||
<header>
|
||||
<p><img width="24" src="../../icons/colour.svg" /></p>
|
||||
<h1><a href="?" data-target="library" data-active>library</a></h1>
|
||||
<h1><a href="?" data-target="alerts">alerts</a></h1>
|
||||
<h1><a href="?view=library" data-target="library">library</a></h1>
|
||||
<h1><a href="?view=alerts" data-target="alerts">alerts</a></h1>
|
||||
<h1><a href="https://github.com/notion-enhancer/extension">github</a></h1>
|
||||
<h1><a href="https://discord.gg/sFWPXtA">discord</a></h1>
|
||||
</header>
|
||||
<main>
|
||||
<section data-container="library" data-active></section>
|
||||
<section data-container></section>
|
||||
</main>
|
||||
<script src="./menu.js" type="module"></script>
|
||||
</body>
|
||||
|
@ -15,285 +15,279 @@ for (let mod of await registry.get()) {
|
||||
}
|
||||
|
||||
// why a tagged template? because it syntax highlights
|
||||
// https://marketplace.visualstudio.com/items?itemName=bierner.lit-html
|
||||
const html = (html, ...templates) =>
|
||||
html.map((str) => str + (templates.shift() || '')).join('');
|
||||
|
||||
const views = {};
|
||||
views.components = {
|
||||
card: {
|
||||
preview: ({ preview = '' }) =>
|
||||
web.createElement(
|
||||
html`<img
|
||||
alt=""
|
||||
class="library--preview"
|
||||
src="${web.htmlEscape(preview)}"
|
||||
onerror="this.remove()"
|
||||
/>`
|
||||
),
|
||||
name: ({ name, id, version }) =>
|
||||
web.createElement(
|
||||
html`<label
|
||||
for="enable--${web.htmlEscape(id)}"
|
||||
class="library--title library--toggle_label"
|
||||
>
|
||||
<input type="checkbox" id="enable--${web.htmlEscape(id)}" />
|
||||
<h2>
|
||||
<span>
|
||||
${web.htmlEscape(name)}
|
||||
<span class="library--version">v${web.htmlEscape(version)}</span>
|
||||
</span>
|
||||
<span class="library--toggle"></span>
|
||||
</h2>
|
||||
</label>`
|
||||
),
|
||||
tags: ({ tags = [] }) =>
|
||||
web.createElement(
|
||||
html`<ul class="library--tags">
|
||||
${tags.map((tag) => html`<li>#${tag}</li>`).join('')}
|
||||
</ul>`
|
||||
),
|
||||
description: ({ description }) =>
|
||||
html`<p class="library--description">${markdown.renderInline(description)}</p>`,
|
||||
authors: ({ authors }) =>
|
||||
html`<ul class="library--authors">
|
||||
${authors
|
||||
.map(
|
||||
(author) =>
|
||||
html`<li>
|
||||
<a href="${author.url}"
|
||||
><img src="${author.icon}" /> <span>${author.name}</span></a
|
||||
>
|
||||
</li>`
|
||||
)
|
||||
.join('')}
|
||||
</ul>`,
|
||||
async expand({ id }) {
|
||||
const element = web.createElement(
|
||||
`<p class="library--expand"><a href="?mod=${id}">${await fs.getText(
|
||||
'icons/fontawesome/long-arrow-alt-right.svg'
|
||||
)}</span> <span>settings & documentation</span></a></p>`
|
||||
);
|
||||
return element;
|
||||
},
|
||||
},
|
||||
options: {
|
||||
toggle(id, { key, label, value }) {
|
||||
const element = web.createElement(`<label for="toggle--${id}.${key}" class="library--toggle_label">
|
||||
<input type="checkbox" id="toggle--${id}.${key}" />
|
||||
<p><span>${label}</span><span class="library--toggle"></span></p></label>`);
|
||||
return element;
|
||||
},
|
||||
async select(id, { key, label, values }) {
|
||||
const element = web.createElement(`<label for="select--${id}.${key}" class="library--select_label">
|
||||
<p>${label}</p><p class="library--select"><span>
|
||||
${await fs.getText('icons/fontawesome/caret-down.svg')}</span>
|
||||
<select id="select--${id}.${key}">${values.map(
|
||||
(value) => `<option value="${value}">${value}</option>`
|
||||
)}</select></p></label>`);
|
||||
return element;
|
||||
},
|
||||
text(id, { key, label, value }) {
|
||||
const element = web.createElement(`<label for="text--${id}.${key}" class="library--text_label">
|
||||
<p>${label}</p><textarea id="text--${id}.${key}" rows="1"></textarea></label>`);
|
||||
element.querySelector('textarea').addEventListener('input', (ev) => {
|
||||
ev.target.style.removeProperty('--txt--scroll-height');
|
||||
ev.target.style.setProperty('--txt--scroll-height', ev.target.scrollHeight + 'px');
|
||||
});
|
||||
return element;
|
||||
},
|
||||
number(id, { key, label, value }) {
|
||||
const element = web.createElement(`<label for="number--${id}.${key}" class="library--number_label">
|
||||
<p>${label}</p><input id="number--${id}.${key}" type="number"></inpu></label>`);
|
||||
return element;
|
||||
},
|
||||
const components = {};
|
||||
components.card = {
|
||||
preview: ({ preview = '' }) =>
|
||||
web.createElement(html`<img
|
||||
alt=""
|
||||
class="library--preview"
|
||||
src="${web.htmlEscape(preview)}"
|
||||
/>`),
|
||||
name: ({ name, id, version }) =>
|
||||
web.createElement(html`<label
|
||||
for="enable--${web.htmlEscape(id)}"
|
||||
class="library--title library--toggle_label"
|
||||
>
|
||||
<input type="checkbox" id="enable--${web.htmlEscape(id)}" />
|
||||
<h2>
|
||||
<span>
|
||||
${web.htmlEscape(name)}
|
||||
<span class="library--version">v${web.htmlEscape(version)}</span>
|
||||
</span>
|
||||
<span class="library--toggle"></span>
|
||||
</h2>
|
||||
</label>`),
|
||||
tags: ({ tags = [] }) =>
|
||||
web.createElement(html`<ul class="library--tags">
|
||||
${tags.map((tag) => html`<li>#${web.htmlEscape(tag)}</li>`).join('')}
|
||||
</ul>`),
|
||||
description: ({ description }) =>
|
||||
web.createElement(
|
||||
html`<p class="library--description">${markdown.renderInline(description)}</p>`
|
||||
),
|
||||
authors: ({ authors }) =>
|
||||
web.createElement(html`<ul class="library--authors">
|
||||
${authors
|
||||
.map(
|
||||
(author) =>
|
||||
html`<li>
|
||||
<a href="${web.htmlEscape(author.url)}">
|
||||
<img src="${web.htmlEscape(author.icon)}" />
|
||||
<span>${web.htmlEscape(author.name)}</span>
|
||||
</a>
|
||||
</li>`
|
||||
)
|
||||
.join('')}
|
||||
</ul>`),
|
||||
expand: async ({ id }) =>
|
||||
web.createElement(
|
||||
html`<p class="library--expand">
|
||||
<a href="?view=mod&id=${web.htmlEscape(id)}">
|
||||
<span>${await fs.getText('icons/fontawesome/long-arrow-alt-right.svg')}</span>
|
||||
<span>settings & documentation</span>
|
||||
</a>
|
||||
</p>`
|
||||
),
|
||||
async _generate(mod) {
|
||||
const card = web.createElement(html`<article class="library--card"></article>`),
|
||||
body = web.createElement(html`<div></div>`);
|
||||
card.append(this.preview(mod));
|
||||
body.append(this.name(mod));
|
||||
body.append(this.tags(mod));
|
||||
body.append(this.description(mod));
|
||||
body.append(this.authors(mod));
|
||||
body.append(await this.expand(mod));
|
||||
card.append(body);
|
||||
return card;
|
||||
},
|
||||
};
|
||||
|
||||
const components = {
|
||||
preview: ({ preview = '' }) =>
|
||||
web.createElement(
|
||||
html`<img alt="" class="library--preview" src="${preview}" onerror="this.remove()" />`
|
||||
),
|
||||
name: ({ name, id, version }) =>
|
||||
web.createElement(`<label for="enable--${id}" class="library--title library--toggle_label">
|
||||
<input type="checkbox" id="enable--${id}" /><h2><span>${name} <span class="library--version">v${version}</span></span>
|
||||
<span class="library--toggle"></span></h2></label>`),
|
||||
tags({ tags }) {
|
||||
if (!tags || !tags.length) return '';
|
||||
const element = web.createElement(
|
||||
`<ul class="library--tags">${tags.map((tag) => `<li>#${tag}</li>`).join('')}</ul>`
|
||||
);
|
||||
return element;
|
||||
},
|
||||
description({ description }) {
|
||||
const element = web.createElement(
|
||||
`<p class="library--description">${markdown.renderInline(description)}</p>`
|
||||
);
|
||||
return element;
|
||||
},
|
||||
authors: ({ authors }) =>
|
||||
html`<ul class="library--authors">
|
||||
${authors
|
||||
.map(
|
||||
(author) =>
|
||||
html`<li>
|
||||
<a href="${author.url}"
|
||||
><img src="${author.icon}" /> <span>${author.name}</span></a
|
||||
>
|
||||
</li>`
|
||||
)
|
||||
.join('')}
|
||||
</ul>`,
|
||||
async expand({ id }) {
|
||||
const element = web.createElement(
|
||||
`<p class="library--expand"><a href="?mod=${id}">${await fs.getText(
|
||||
'icons/fontawesome/long-arrow-alt-right.svg'
|
||||
)}</span> <span>settings & documentation</span></a></p>`
|
||||
);
|
||||
return element;
|
||||
},
|
||||
toggle(id, { key, label, value }) {
|
||||
const element = web.createElement(`<label for="toggle--${id}.${key}" class="library--toggle_label">
|
||||
<input type="checkbox" id="toggle--${id}.${key}" />
|
||||
<p><span>${label}</span><span class="library--toggle"></span></p></label>`);
|
||||
return element;
|
||||
},
|
||||
async select(id, { key, label, values }) {
|
||||
const element = web.createElement(`<label for="select--${id}.${key}" class="library--select_label">
|
||||
<p>${label}</p><p class="library--select"><span>
|
||||
${await fs.getText('icons/fontawesome/caret-down.svg')}</span>
|
||||
<select id="select--${id}.${key}">${values.map(
|
||||
(value) => `<option value="${value}">${value}</option>`
|
||||
)}</select></p></label>`);
|
||||
return element;
|
||||
},
|
||||
text(id, { key, label, value }) {
|
||||
const element = web.createElement(`<label for="text--${id}.${key}" class="library--text_label">
|
||||
<p>${label}</p><textarea id="text--${id}.${key}" rows="1"></textarea></label>`);
|
||||
element.querySelector('textarea').addEventListener('input', (ev) => {
|
||||
ev.target.style.removeProperty('--txt--scroll-height');
|
||||
ev.target.style.setProperty('--txt--scroll-height', ev.target.scrollHeight + 'px');
|
||||
});
|
||||
return element;
|
||||
},
|
||||
number(id, { key, label, value }) {
|
||||
const element = web.createElement(`<label for="number--${id}.${key}" class="library--number_label">
|
||||
<p>${label}</p><input id="number--${id}.${key}" type="number"></inpu></label>`);
|
||||
return element;
|
||||
},
|
||||
async file(id, { key, label, extensions }) {
|
||||
const accept =
|
||||
extensions && extensions.length ? ` accept="${extensions.join(',')}"` : '';
|
||||
const element = web.createElement(`<label for="file--${id}.${key}" class="library--file_label">
|
||||
<input type="file" id="file--${id}.${key}"${accept}/><p>${label}</p>
|
||||
<p class="library--file"><span>${await fs.getText(
|
||||
'icons/fontawesome/file.svg'
|
||||
)}</span><span class="library--file_path">choose file...</span></p></label>`);
|
||||
element.querySelector('input[type="file"]').addEventListener('change', (ev) => {
|
||||
element.querySelector('.library--file_path').innerText = ev.target.files[0].name;
|
||||
});
|
||||
return element;
|
||||
},
|
||||
async documentation_buttons({ _dir }) {
|
||||
const element = web.createElement(`<p class="documentation--buttons">
|
||||
<a href="?">
|
||||
<span>
|
||||
${await fs.getText(
|
||||
'icons/fontawesome/long-arrow-alt-left.svg'
|
||||
)}</span> <span>back to library</span></a>
|
||||
<a href="https://github.com/notion-enhancer/extension/tree/main/repo/${encodeURIComponent(
|
||||
_dir
|
||||
)}">
|
||||
<span>
|
||||
${await fs.getText(
|
||||
'icons/fontawesome/code.svg'
|
||||
)}</span> <span>view source code</span></a>
|
||||
</p>`);
|
||||
return element;
|
||||
},
|
||||
components.options = {
|
||||
toggle: (id, { key, label, value }) =>
|
||||
web.createElement(html`<label
|
||||
for="toggle--${web.htmlEscape(`${id}.${key}`)}"
|
||||
class="library--toggle_label"
|
||||
>
|
||||
<input type="checkbox" id="toggle--${web.htmlEscape(`${id}.${key}`)}" />
|
||||
<p><span>${label}</span><span class="library--toggle"></span></p
|
||||
></label>`),
|
||||
select: async (id, { key, label, values }) =>
|
||||
web.createElement(html`<label
|
||||
for="select--${web.htmlEscape(`${id}.${key}`)}"
|
||||
class="library--select_label"
|
||||
>
|
||||
<p>${label}</p>
|
||||
<p class="library--select">
|
||||
<span> ${await fs.getText('icons/fontawesome/caret-down.svg')}</span>
|
||||
<select id="select--${web.htmlEscape(`${id}.${key}`)}">
|
||||
${values.map(
|
||||
(value) =>
|
||||
html`<option value="${web.htmlEscape(value)}">${web.htmlEscape(value)}</option>`
|
||||
)}
|
||||
</select>
|
||||
</p>
|
||||
</label>`),
|
||||
text(id, { key, label, value }) {
|
||||
const opt = web.createElement(html`<label
|
||||
for="text--${web.htmlEscape(`${id}.${key}`)}"
|
||||
class="library--text_label"
|
||||
>
|
||||
<p>${label}</p>
|
||||
<textarea id="text--${web.htmlEscape(`${id}.${key}`)}" rows="1"></textarea>
|
||||
</label>`);
|
||||
opt.querySelector('textarea').addEventListener('input', (ev) => {
|
||||
ev.target.style.removeProperty('--txt--scroll-height');
|
||||
ev.target.style.setProperty('--txt--scroll-height', ev.target.scrollHeight + 'px');
|
||||
});
|
||||
return opt;
|
||||
},
|
||||
generators = {
|
||||
async summary_card(mod) {
|
||||
const article = web.createElement('<article class="library--summary_card"></article>'),
|
||||
body = web.createElement('<div></div>');
|
||||
article.append(await components.preview(mod));
|
||||
body.append(await components.name(mod));
|
||||
body.append(await components.tags(mod));
|
||||
body.append(await components.description(mod));
|
||||
body.append(await components.authors(mod));
|
||||
body.append(await components.expand(mod));
|
||||
article.append(body);
|
||||
return article;
|
||||
},
|
||||
async full_card(mod) {
|
||||
const article = web.createElement('<article class="library--full_card"></article>'),
|
||||
body = web.createElement('<div></div>');
|
||||
article.append(await components.preview(mod));
|
||||
body.append(await components.name(mod));
|
||||
body.append(await components.tags(mod));
|
||||
body.append(await components.description(mod));
|
||||
body.append(await components.authors(mod));
|
||||
article.append(body);
|
||||
if (mod.options && mod.options.length) {
|
||||
const options = web.createElement(`<div class="library--options"></div>`);
|
||||
(
|
||||
await Promise.all(mod.options.map((opt) => components[opt.type](mod.id, opt)))
|
||||
).map((opt) => options.append(opt));
|
||||
article.append(options);
|
||||
}
|
||||
return article;
|
||||
},
|
||||
async documentation(mod) {
|
||||
const content = (await fs.isFile(`repo/${mod._dir}/README.md`))
|
||||
? markdown.render(await fs.getText(`repo/${mod._dir}/README.md`))
|
||||
: '',
|
||||
article = web.createElement(
|
||||
`<article class="documentation--body">${content}</article>`
|
||||
);
|
||||
return article;
|
||||
},
|
||||
},
|
||||
tabs = {
|
||||
library: {
|
||||
title: document.querySelector('header [data-target="library"]'),
|
||||
async container() {
|
||||
document.querySelector('[data-target][data-active]').removeAttribute('data-active');
|
||||
this.title.dataset.active = true;
|
||||
const $container = document.querySelector('[data-container]');
|
||||
$container.dataset.container = 'library';
|
||||
$container.innerHTML = '';
|
||||
for (let mod of await registry.get())
|
||||
$container.append(await generators.summary_card(mod));
|
||||
},
|
||||
},
|
||||
mod: {
|
||||
title: document.querySelector('header [data-target="library"]'),
|
||||
async container(mod) {
|
||||
document.querySelector('[data-target][data-active]').removeAttribute('data-active');
|
||||
this.title.dataset.active = true;
|
||||
const $container = document.querySelector('[data-container]');
|
||||
$container.dataset.container = 'page';
|
||||
$container.innerHTML = '';
|
||||
$container.append(await components.documentation_buttons(mod));
|
||||
$container.append(await generators.full_card(mod));
|
||||
$container.append(await generators.documentation(mod));
|
||||
},
|
||||
},
|
||||
};
|
||||
tabs.library.title.addEventListener('click', (ev) => tabs.library.container());
|
||||
number: (id, { key, label, value }) =>
|
||||
web.createElement(html`<label
|
||||
for="number--${web.htmlEscape(`${id}.${key}`)}"
|
||||
class="library--number_label"
|
||||
>
|
||||
<p>${web.htmlEscape(label)}</p>
|
||||
<input id="number--${web.htmlEscape(`${id}.${key}`)}" type="number" />
|
||||
</label>`),
|
||||
|
||||
(async () => {
|
||||
const search = new Map(
|
||||
async file(id, { key, label, extensions }) {
|
||||
const opt = web.createElement(html`<label
|
||||
for="file--${web.htmlEscape(`${id}.${key}`)}"
|
||||
class="library--file_label"
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
id="file--${web.htmlEscape(`${id}.${key}`)}"
|
||||
${web.htmlEscape(
|
||||
extensions && extensions.length
|
||||
? ` accept="${web.htmlEscape(extensions.join(','))}"`
|
||||
: ''
|
||||
)}
|
||||
/>
|
||||
<p>${web.htmlEscape(label)}</p>
|
||||
<p class="library--file">
|
||||
<span>${await fs.getText('icons/fontawesome/file.svg')}</span>
|
||||
<span class="library--file_path">choose file...</span>
|
||||
</p>
|
||||
</label>`);
|
||||
opt.querySelector('input').addEventListener('change', (ev) => {
|
||||
opt.querySelector('.library--file_path').innerText = ev.target.files[0].name;
|
||||
});
|
||||
return opt;
|
||||
},
|
||||
async _generate(mod) {
|
||||
const card = await components.card._generate(mod);
|
||||
card.querySelector('.library--expand').remove();
|
||||
if (mod.options && mod.options.length) {
|
||||
const options = web.createElement(html`<div class="library--options"></div>`),
|
||||
inputs = await Promise.all(mod.options.map((opt) => this[opt.type](mod.id, opt)));
|
||||
inputs.forEach((opt) => options.append(opt));
|
||||
card.append(options);
|
||||
}
|
||||
return card;
|
||||
},
|
||||
};
|
||||
components.documentation = {
|
||||
buttons: async ({ _dir }) =>
|
||||
web.createElement(html`<p class="documentation--buttons">
|
||||
<a href="?view=library">
|
||||
<span>${await fs.getText('icons/fontawesome/long-arrow-alt-left.svg')}</span>
|
||||
<span>back to library</span>
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/notion-enhancer/extension/tree/main/repo/${encodeURIComponent(
|
||||
_dir
|
||||
)}"
|
||||
>
|
||||
<span>${await fs.getText('icons/fontawesome/code.svg')}</span>
|
||||
<span>view source code</span>
|
||||
</a>
|
||||
</p>`),
|
||||
readme: async (mod) =>
|
||||
web.createElement(html`<article class="documentation--body">
|
||||
${(await fs.isFile(`repo/${mod._dir}/README.md`))
|
||||
? markdown.render(await fs.getText(`repo/${mod._dir}/README.md`))
|
||||
: ''}
|
||||
</article>`),
|
||||
};
|
||||
const views = {
|
||||
$container: document.querySelector('[data-container]'),
|
||||
_router(event) {
|
||||
event.preventDefault();
|
||||
let anchor,
|
||||
i = 0;
|
||||
do {
|
||||
anchor = event.path[i];
|
||||
i++;
|
||||
} while (anchor.nodeName !== 'A');
|
||||
if (location.search !== anchor.getAttribute('href')) {
|
||||
window.history.pushState({}, '', anchor.href);
|
||||
this._load();
|
||||
}
|
||||
},
|
||||
_reset() {
|
||||
document
|
||||
.querySelectorAll('a[href^="?"]')
|
||||
.forEach((a) => a.removeEventListener('click', this._router));
|
||||
this.$container.style.opacity = 0;
|
||||
return new Promise((res, rej) => {
|
||||
setTimeout(() => {
|
||||
this.$container.innerHTML = '';
|
||||
this.$container.style.opacity = '';
|
||||
this.$container.dataset.container = '';
|
||||
document.querySelector('[data-target][data-active]')?.removeAttribute('data-active');
|
||||
res();
|
||||
}, 200);
|
||||
});
|
||||
},
|
||||
async _load() {
|
||||
await this._reset();
|
||||
|
||||
const search = new Map(
|
||||
location.search
|
||||
.slice(1)
|
||||
.split('&')
|
||||
.map((query) => query.split('='))
|
||||
),
|
||||
mod = (await registry.get()).find((mod) => mod.id === search.get('mod'));
|
||||
if (mod) {
|
||||
tabs.mod.container(mod);
|
||||
} else tabs.library.container();
|
||||
})();
|
||||
);
|
||||
switch (search.get('view')) {
|
||||
case 'alerts':
|
||||
await this.alerts();
|
||||
break;
|
||||
case 'mod':
|
||||
const mod = (await registry.get()).find((mod) => mod.id === search.get('id'));
|
||||
if (mod) {
|
||||
await this.mod(mod);
|
||||
break;
|
||||
}
|
||||
case 'library':
|
||||
await this.library();
|
||||
break;
|
||||
default:
|
||||
window.history.replaceState({}, '', '?view=library');
|
||||
return this._load();
|
||||
}
|
||||
|
||||
document
|
||||
.querySelectorAll('img')
|
||||
.forEach((img) => (img.onerror = (ev) => ev.target.remove()));
|
||||
document
|
||||
.querySelectorAll('a[href^="?"]')
|
||||
.forEach((a) => a.addEventListener('click', this._router));
|
||||
},
|
||||
async alerts() {
|
||||
this.$container.dataset.container = 'alerts';
|
||||
document.querySelector('header [data-target="alerts"]').dataset.active = true;
|
||||
for (let mod of await registry.get())
|
||||
this.$container.append(await components.card._generate(mod));
|
||||
},
|
||||
async mod(mod) {
|
||||
this.$container.dataset.container = 'mod';
|
||||
document.querySelector('header [data-target="library"]').dataset.active = true;
|
||||
this.$container.append(await components.documentation.buttons(mod));
|
||||
this.$container.append(await components.options._generate(mod));
|
||||
this.$container.append(await components.documentation.readme(mod));
|
||||
},
|
||||
async library() {
|
||||
this.$container.dataset.container = 'library';
|
||||
document.querySelector('header [data-target="library"]').dataset.active = true;
|
||||
for (let mod of await registry.get())
|
||||
this.$container.append(await components.card._generate(mod));
|
||||
},
|
||||
};
|
||||
views._router = views._router.bind(views);
|
||||
views._load();
|
||||
window.addEventListener('popstate', (ev) => views._load());
|
||||
|
||||
function theme() {
|
||||
chrome.storage.local.get(['notion.theme'], (result) => {
|
||||
document.documentElement.className = `notion-${result['notion.theme'] || 'dark'}-theme`;
|
||||
});
|
||||
}
|
||||
window.addEventListener('focus', theme);
|
||||
theme();
|
||||
|
||||
// registry.errors().then((err) => {
|
||||
// document.querySelector('[data-section="alerts"]').innerHTML = JSON.stringify(err);
|
||||
|
Loading…
Reference in New Issue
Block a user