sync menu & notion themes, mod page routing, better component gen

This commit is contained in:
dragonwocky 2021-04-21 00:07:49 +10:00
parent d2292137da
commit 93e764fb0a
7 changed files with 308 additions and 291 deletions

View File

@ -13,7 +13,8 @@ export const ERROR = Symbol();
export const env = {}; export const env = {};
env.name = 'browser'; 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 = {}; export const web = {};
@ -50,7 +51,7 @@ web.createElement = (html) => {
: html : html
.split(/\n/) .split(/\n/)
.map((line) => line.trim()) .map((line) => line.trim())
.join(''); .join(' ');
return template.content.firstElementChild; return template.content.firstElementChild;
}; };
web.htmlEscape = (str) => web.htmlEscape = (str) =>

View File

@ -16,6 +16,5 @@ import(chrome.runtime.getURL('helpers.js')).then(({ web, registry }) => {
import(chrome.runtime.getURL(`repo/${mod._dir}/${script}`)); import(chrome.runtime.getURL(`repo/${mod._dir}/${script}`));
} }
} }
console.log(await registry.errors());
}); });
}); });

View File

@ -27,5 +27,6 @@
"js": ["launcher.js"] "js": ["launcher.js"]
} }
], ],
"permissions": ["storage"],
"host_permissions": ["https://*.notion.so/*"] "host_permissions": ["https://*.notion.so/*"]
} }

View File

@ -15,7 +15,19 @@ web.whenReady([sidebarSelector], async () => {
enhancerSidebarElement = web.createElement( enhancerSidebarElement = web.createElement(
`<div class="enhancer--sidebarMenuTrigger" role="button" tabindex="0"><div><div>${enhancerIcon}</div><div><div>notion-enhancer</div></div></div></div>` `<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); document.querySelector(sidebarSelector).appendChild(enhancerSidebarElement);
}); });
web.hotkeyListener(['Ctrl', 'Alt', 'E'], env.openEnhancerMenu); web.hotkeyListener(['Ctrl', 'Alt', 'E'], env.openEnhancerMenu);

View File

@ -12,6 +12,13 @@
color: var(--theme--text); color: var(--theme--text);
} }
html {
transition: opacity 50ms ease-out;
}
html[class] {
opacity: 1 !important;
}
body { body {
padding: 1.5rem; padding: 1.5rem;
background: var(--theme--sidebar); background: var(--theme--sidebar);
@ -37,12 +44,14 @@ main section[data-container] {
display: grid; display: grid;
grid-gap: 1.25em; grid-gap: 1.25em;
grid-template-columns: 1fr; grid-template-columns: 1fr;
opacity: 1;
transition: opacity 200ms ease-out;
} }
@media (min-width: 550px) { @media (min-width: 550px) {
main section[data-container] { main section[data-container] {
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
} }
main section[data-container='page'] > .documentation--buttons { main section[data-container='mod'] > .documentation--buttons {
grid-column: span 2; grid-column: span 2;
} }
} }
@ -50,10 +59,10 @@ main section[data-container] {
main section[data-container] { main section[data-container] {
grid-template-columns: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr;
} }
main section[data-container='page'] > .documentation--buttons { main section[data-container='mod'] > .documentation--buttons {
grid-column: span 3; grid-column: span 3;
} }
main section[data-container='page'] > .documentation--body { main section[data-container='mod'] > .documentation--body {
grid-column: span 2; grid-column: span 2;
} }
} }
@ -61,10 +70,10 @@ main section[data-container] {
main section[data-container] { main section[data-container] {
grid-template-columns: 1fr 1fr 1fr 1fr; 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; grid-column: span 4;
} }
main section[data-container='page'] > .documentation--body { main section[data-container='mod'] > .documentation--body {
grid-column: span 3; grid-column: span 3;
} }
} }
@ -72,10 +81,10 @@ main section[data-container] {
main section[data-container] { main section[data-container] {
grid-template-columns: 1fr 1fr 1fr 1fr 1fr; 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; grid-column: span 5;
} }
main section[data-container='page'] > .documentation--body { main section[data-container='mod'] > .documentation--body {
grid-column: span 4; grid-column: span 4;
} }
} }
@ -122,10 +131,8 @@ main section[data-container] article > div {
padding-top: 2px; padding-top: 2px;
margin-right: 0.3rem; margin-right: 0.3rem;
} }
.documentation--buttons svg polygon, .documentation--buttons svg *,
.documentation--buttons svg path, .library--expand svg * {
.library--expand svg polygon,
.library--expand svg path {
fill: var(--theme--text_property); fill: var(--theme--text_property);
} }
@ -222,7 +229,7 @@ main section[data-container] article > div {
} }
.library--toggle_label > :not(input) .library--toggle::after { .library--toggle_label > :not(input) .library--toggle::after {
content: ''; content: '';
transition: transform 200ms ease-out 0s, background 200ms ease-out 0s; transition: transform 200ms ease-out, background 200ms ease-out;
height: 0.8rem; height: 0.8rem;
width: 0.8rem; width: 0.8rem;
left: 0.325rem; left: 0.325rem;
@ -268,13 +275,12 @@ main section[data-container] article > div {
border-radius: 3px; border-radius: 3px;
border: none; border: none;
box-shadow: var(--theme--input-border) 0px 0px 0px 1px inset; 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 { .library--select_label .library--select select {
outline: none; outline: none;
} }
.library--select_label .library--select select option { .library--select_label .library--select select option {
background: var(--theme_dark--tag_select); background: var(--theme--tag_select);
} }
.library--select_label .library--select, .library--select_label .library--select,
.library--file_label .library--file { .library--file_label .library--file {
@ -292,6 +298,10 @@ main section[data-container] article > div {
width: 0.9em; width: 0.9em;
margin: auto 0; 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--select_label .library--select > :last-child,
.library--file_label .library--file > :last-child { .library--file_label .library--file > :last-child {
margin: auto 0; margin: auto 0;
@ -312,7 +322,7 @@ main section[data-container] article > div {
padding-bottom: 0.25rem; padding-bottom: 0.25rem;
} }
.library--full_card, main section[data-container='mod'] .library--card,
.documentation--body { .documentation--body {
max-height: calc(100vh - 10rem); max-height: calc(100vh - 10rem);
overflow: auto; overflow: auto;

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" class="notion-dark-theme"> <html lang="en" style="opacity: 0">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
@ -9,13 +9,13 @@
<body> <body>
<header> <header>
<p><img width="24" src="../../icons/colour.svg" /></p> <p><img width="24" src="../../icons/colour.svg" /></p>
<h1><a href="?" data-target="library" data-active>library</a></h1> <h1><a href="?view=library" data-target="library">library</a></h1>
<h1><a href="?" data-target="alerts">alerts</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://github.com/notion-enhancer/extension">github</a></h1>
<h1><a href="https://discord.gg/sFWPXtA">discord</a></h1> <h1><a href="https://discord.gg/sFWPXtA">discord</a></h1>
</header> </header>
<main> <main>
<section data-container="library" data-active></section> <section data-container></section>
</main> </main>
<script src="./menu.js" type="module"></script> <script src="./menu.js" type="module"></script>
</body> </body>

View File

@ -15,24 +15,20 @@ for (let mod of await registry.get()) {
} }
// why a tagged template? because it syntax highlights // why a tagged template? because it syntax highlights
// https://marketplace.visualstudio.com/items?itemName=bierner.lit-html
const html = (html, ...templates) => const html = (html, ...templates) =>
html.map((str) => str + (templates.shift() || '')).join(''); html.map((str) => str + (templates.shift() || '')).join('');
const views = {}; const components = {};
views.components = { components.card = {
card: {
preview: ({ preview = '' }) => preview: ({ preview = '' }) =>
web.createElement( web.createElement(html`<img
html`<img
alt="" alt=""
class="library--preview" class="library--preview"
src="${web.htmlEscape(preview)}" src="${web.htmlEscape(preview)}"
onerror="this.remove()" />`),
/>`
),
name: ({ name, id, version }) => name: ({ name, id, version }) =>
web.createElement( web.createElement(html`<label
html`<label
for="enable--${web.htmlEscape(id)}" for="enable--${web.htmlEscape(id)}"
class="library--title library--toggle_label" class="library--title library--toggle_label"
> >
@ -44,256 +40,254 @@ views.components = {
</span> </span>
<span class="library--toggle"></span> <span class="library--toggle"></span>
</h2> </h2>
</label>` </label>`),
),
tags: ({ tags = [] }) => tags: ({ tags = [] }) =>
web.createElement( web.createElement(html`<ul class="library--tags">
html`<ul class="library--tags"> ${tags.map((tag) => html`<li>#${web.htmlEscape(tag)}</li>`).join('')}
${tags.map((tag) => html`<li>#${tag}</li>`).join('')} </ul>`),
</ul>`
),
description: ({ description }) => description: ({ description }) =>
html`<p class="library--description">${markdown.renderInline(description)}</p>`, web.createElement(
html`<p class="library--description">${markdown.renderInline(description)}</p>`
),
authors: ({ authors }) => authors: ({ authors }) =>
html`<ul class="library--authors"> web.createElement(html`<ul class="library--authors">
${authors ${authors
.map( .map(
(author) => (author) =>
html`<li> html`<li>
<a href="${author.url}" <a href="${web.htmlEscape(author.url)}">
><img src="${author.icon}" /> <span>${author.name}</span></a <img src="${web.htmlEscape(author.icon)}" />
> <span>${web.htmlEscape(author.name)}</span>
</a>
</li>` </li>`
) )
.join('')} .join('')}
</ul>`, </ul>`),
async expand({ id }) { expand: async ({ id }) =>
const element = web.createElement( web.createElement(
`<p class="library--expand"><a href="?mod=${id}">${await fs.getText( html`<p class="library--expand">
'icons/fontawesome/long-arrow-alt-right.svg' <a href="?view=mod&id=${web.htmlEscape(id)}">
)}</span> <span>settings & documentation</span></a></p>` <span>${await fs.getText('icons/fontawesome/long-arrow-alt-right.svg')}</span>
); <span>settings & documentation</span>
return element; </a>
}, </p>`
}, ),
options: { async _generate(mod) {
toggle(id, { key, label, value }) { const card = web.createElement(html`<article class="library--card"></article>`),
const element = web.createElement(`<label for="toggle--${id}.${key}" class="library--toggle_label"> body = web.createElement(html`<div></div>`);
<input type="checkbox" id="toggle--${id}.${key}" /> card.append(this.preview(mod));
<p><span>${label}</span><span class="library--toggle"></span></p></label>`); body.append(this.name(mod));
return element; body.append(this.tags(mod));
}, body.append(this.description(mod));
async select(id, { key, label, values }) { body.append(this.authors(mod));
const element = web.createElement(`<label for="select--${id}.${key}" class="library--select_label"> body.append(await this.expand(mod));
<p>${label}</p><p class="library--select"><span> card.append(body);
${await fs.getText('icons/fontawesome/caret-down.svg')}</span> return card;
<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;
},
}, },
}; };
components.options = {
const components = { toggle: (id, { key, label, value }) =>
preview: ({ preview = '' }) => web.createElement(html`<label
web.createElement( for="toggle--${web.htmlEscape(`${id}.${key}`)}"
html`<img alt="" class="library--preview" src="${preview}" onerror="this.remove()" />` class="library--toggle_label"
),
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>` <input type="checkbox" id="toggle--${web.htmlEscape(`${id}.${key}`)}" />
) <p><span>${label}</span><span class="library--toggle"></span></p
.join('')} ></label>`),
</ul>`, select: async (id, { key, label, values }) =>
async expand({ id }) { web.createElement(html`<label
const element = web.createElement( for="select--${web.htmlEscape(`${id}.${key}`)}"
`<p class="library--expand"><a href="?mod=${id}">${await fs.getText( class="library--select_label"
'icons/fontawesome/long-arrow-alt-right.svg' >
)}</span> <span>settings & documentation</span></a></p>` <p>${label}</p>
); <p class="library--select">
return element; <span> ${await fs.getText('icons/fontawesome/caret-down.svg')}</span>
}, <select id="select--${web.htmlEscape(`${id}.${key}`)}">
toggle(id, { key, label, value }) { ${values.map(
const element = web.createElement(`<label for="toggle--${id}.${key}" class="library--toggle_label"> (value) =>
<input type="checkbox" id="toggle--${id}.${key}" /> html`<option value="${web.htmlEscape(value)}">${web.htmlEscape(value)}</option>`
<p><span>${label}</span><span class="library--toggle"></span></p></label>`); )}
return element; </select>
}, </p>
async select(id, { key, label, values }) { </label>`),
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 }) { text(id, { key, label, value }) {
const element = web.createElement(`<label for="text--${id}.${key}" class="library--text_label"> const opt = web.createElement(html`<label
<p>${label}</p><textarea id="text--${id}.${key}" rows="1"></textarea></label>`); for="text--${web.htmlEscape(`${id}.${key}`)}"
element.querySelector('textarea').addEventListener('input', (ev) => { 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.removeProperty('--txt--scroll-height');
ev.target.style.setProperty('--txt--scroll-height', ev.target.scrollHeight + 'px'); ev.target.style.setProperty('--txt--scroll-height', ev.target.scrollHeight + 'px');
}); });
return element; return opt;
}, },
number(id, { key, label, value }) { number: (id, { key, label, value }) =>
const element = web.createElement(`<label for="number--${id}.${key}" class="library--number_label"> web.createElement(html`<label
<p>${label}</p><input id="number--${id}.${key}" type="number"></inpu></label>`); for="number--${web.htmlEscape(`${id}.${key}`)}"
return element; class="library--number_label"
}, >
async file(id, { key, label, extensions }) { <p>${web.htmlEscape(label)}</p>
const accept = <input id="number--${web.htmlEscape(`${id}.${key}`)}" type="number" />
extensions && extensions.length ? ` accept="${extensions.join(',')}"` : ''; </label>`),
const element = web.createElement(`<label for="file--${id}.${key}" class="library--file_label">
<input type="file" id="file--${id}.${key}"${accept}/><p>${label}</p> async file(id, { key, label, extensions }) {
<p class="library--file"><span>${await fs.getText( const opt = web.createElement(html`<label
'icons/fontawesome/file.svg' for="file--${web.htmlEscape(`${id}.${key}`)}"
)}</span><span class="library--file_path">choose file...</span></p></label>`); class="library--file_label"
element.querySelector('input[type="file"]').addEventListener('change', (ev) => { >
element.querySelector('.library--file_path').innerText = ev.target.files[0].name; <input
}); type="file"
return element; id="file--${web.htmlEscape(`${id}.${key}`)}"
}, ${web.htmlEscape(
async documentation_buttons({ _dir }) { extensions && extensions.length
const element = web.createElement(`<p class="documentation--buttons"> ? ` accept="${web.htmlEscape(extensions.join(','))}"`
<a href="?"> : ''
<span> )}
${await fs.getText( />
'icons/fontawesome/long-arrow-alt-left.svg' <p>${web.htmlEscape(label)}</p>
)}</span> <span>back to library</span></a> <p class="library--file">
<a href="https://github.com/notion-enhancer/extension/tree/main/repo/${encodeURIComponent( <span>${await fs.getText('icons/fontawesome/file.svg')}</span>
_dir <span class="library--file_path">choose file...</span>
)}"> </p>
<span> </label>`);
${await fs.getText( opt.querySelector('input').addEventListener('change', (ev) => {
'icons/fontawesome/code.svg' opt.querySelector('.library--file_path').innerText = ev.target.files[0].name;
)}</span> <span>view source code</span></a> });
</p>`); return opt;
return element; },
}, async _generate(mod) {
}, const card = await components.card._generate(mod);
generators = { card.querySelector('.library--expand').remove();
async summary_card(mod) { if (mod.options && mod.options.length) {
const article = web.createElement('<article class="library--summary_card"></article>'), const options = web.createElement(html`<div class="library--options"></div>`),
body = web.createElement('<div></div>'); inputs = await Promise.all(mod.options.map((opt) => this[opt.type](mod.id, opt)));
article.append(await components.preview(mod)); inputs.forEach((opt) => options.append(opt));
body.append(await components.name(mod)); card.append(options);
body.append(await components.tags(mod)); }
body.append(await components.description(mod)); return card;
body.append(await components.authors(mod)); },
body.append(await components.expand(mod)); };
article.append(body); components.documentation = {
return article; buttons: async ({ _dir }) =>
}, web.createElement(html`<p class="documentation--buttons">
async full_card(mod) { <a href="?view=library">
const article = web.createElement('<article class="library--full_card"></article>'), <span>${await fs.getText('icons/fontawesome/long-arrow-alt-left.svg')}</span>
body = web.createElement('<div></div>'); <span>back to library</span>
article.append(await components.preview(mod)); </a>
body.append(await components.name(mod)); <a
body.append(await components.tags(mod)); href="https://github.com/notion-enhancer/extension/tree/main/repo/${encodeURIComponent(
body.append(await components.description(mod)); _dir
body.append(await components.authors(mod)); )}"
article.append(body); >
if (mod.options && mod.options.length) { <span>${await fs.getText('icons/fontawesome/code.svg')}</span>
const options = web.createElement(`<div class="library--options"></div>`); <span>view source code</span>
( </a>
await Promise.all(mod.options.map((opt) => components[opt.type](mod.id, opt))) </p>`),
).map((opt) => options.append(opt)); readme: async (mod) =>
article.append(options); web.createElement(html`<article class="documentation--body">
} ${(await fs.isFile(`repo/${mod._dir}/README.md`))
return article; ? markdown.render(await fs.getText(`repo/${mod._dir}/README.md`))
}, : ''}
async documentation(mod) { </article>`),
const content = (await fs.isFile(`repo/${mod._dir}/README.md`)) };
? markdown.render(await fs.getText(`repo/${mod._dir}/README.md`)) const views = {
: '', $container: document.querySelector('[data-container]'),
article = web.createElement( _router(event) {
`<article class="documentation--body">${content}</article>` event.preventDefault();
); let anchor,
return article; i = 0;
}, do {
}, anchor = event.path[i];
tabs = { i++;
library: { } while (anchor.nodeName !== 'A');
title: document.querySelector('header [data-target="library"]'), if (location.search !== anchor.getAttribute('href')) {
async container() { window.history.pushState({}, '', anchor.href);
document.querySelector('[data-target][data-active]').removeAttribute('data-active'); this._load();
this.title.dataset.active = true; }
const $container = document.querySelector('[data-container]'); },
$container.dataset.container = 'library'; _reset() {
$container.innerHTML = ''; document
for (let mod of await registry.get()) .querySelectorAll('a[href^="?"]')
$container.append(await generators.summary_card(mod)); .forEach((a) => a.removeEventListener('click', this._router));
}, this.$container.style.opacity = 0;
}, return new Promise((res, rej) => {
mod: { setTimeout(() => {
title: document.querySelector('header [data-target="library"]'), this.$container.innerHTML = '';
async container(mod) { this.$container.style.opacity = '';
document.querySelector('[data-target][data-active]').removeAttribute('data-active'); this.$container.dataset.container = '';
this.title.dataset.active = true; document.querySelector('[data-target][data-active]')?.removeAttribute('data-active');
const $container = document.querySelector('[data-container]'); res();
$container.dataset.container = 'page'; }, 200);
$container.innerHTML = ''; });
$container.append(await components.documentation_buttons(mod)); },
$container.append(await generators.full_card(mod)); async _load() {
$container.append(await generators.documentation(mod)); await this._reset();
},
},
};
tabs.library.title.addEventListener('click', (ev) => tabs.library.container());
(async () => {
const search = new Map( const search = new Map(
location.search location.search
.slice(1) .slice(1)
.split('&') .split('&')
.map((query) => query.split('=')) .map((query) => query.split('='))
), );
mod = (await registry.get()).find((mod) => mod.id === search.get('mod')); 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) { if (mod) {
tabs.mod.container(mod); await this.mod(mod);
} else tabs.library.container(); 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) => { // registry.errors().then((err) => {
// document.querySelector('[data-section="alerts"]').innerHTML = JSON.stringify(err); // document.querySelector('[data-section="alerts"]').innerHTML = JSON.stringify(err);