From 93e764fb0a7f84681f75b14687e7eec6b02a3080 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Wed, 21 Apr 2021 00:07:49 +1000 Subject: [PATCH] sync menu & notion themes, mod page routing, better component gen --- extension/helpers.js | 5 +- extension/launcher.js | 1 - extension/manifest.json | 1 + .../client.js | 14 +- .../menu.css | 40 +- .../menu.html | 8 +- .../menu.js | 530 +++++++++--------- 7 files changed, 308 insertions(+), 291 deletions(-) diff --git a/extension/helpers.js b/extension/helpers.js index 81ad92b..7b727ec 100644 --- a/extension/helpers.js +++ b/extension/helpers.js @@ -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) => diff --git a/extension/launcher.js b/extension/launcher.js index 78fdbc6..5a716c4 100644 --- a/extension/launcher.js +++ b/extension/launcher.js @@ -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()); }); }); diff --git a/extension/manifest.json b/extension/manifest.json index 5b8ba40..3cdac82 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -27,5 +27,6 @@ "js": ["launcher.js"] } ], + "permissions": ["storage"], "host_permissions": ["https://*.notion.so/*"] } diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.js b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.js index 308c806..8e05302 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.js +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.js @@ -15,7 +15,19 @@ web.whenReady([sidebarSelector], async () => { enhancerSidebarElement = web.createElement( `
${enhancerIcon}
notion-enhancer
` ); - 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); diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css index 7b2e43f..2eb32ee 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.css @@ -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; diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.html b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.html index abc689c..d2efe60 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.html +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.html @@ -1,5 +1,5 @@ - + @@ -9,13 +9,13 @@

-

library

-

alerts

+

library

+

alerts

github

discord

-
+
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js index e555aa8..e3348df 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.js @@ -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`` - ), - name: ({ name, id, version }) => - web.createElement( - html`` - ), - tags: ({ tags = [] }) => - web.createElement( - html`` - ), - description: ({ description }) => - html`

${markdown.renderInline(description)}

`, - authors: ({ authors }) => - html``, - async expand({ id }) { - const element = web.createElement( - `

${await fs.getText( - 'icons/fontawesome/long-arrow-alt-right.svg' - )} settings & documentation

` - ); - return element; - }, - }, - options: { - toggle(id, { key, label, value }) { - const element = web.createElement(``); - return element; - }, - async select(id, { key, label, values }) { - const element = web.createElement(``); - return element; - }, - text(id, { key, label, value }) { - const element = web.createElement(``); - 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(``); - return element; - }, +const components = {}; +components.card = { + preview: ({ preview = '' }) => + web.createElement(html``), + name: ({ name, id, version }) => + web.createElement(html``), + tags: ({ tags = [] }) => + web.createElement(html``), + description: ({ description }) => + web.createElement( + html`

${markdown.renderInline(description)}

` + ), + authors: ({ authors }) => + web.createElement(html``), + expand: async ({ id }) => + web.createElement( + html`

+ + ${await fs.getText('icons/fontawesome/long-arrow-alt-right.svg')} + settings & documentation + +

` + ), + async _generate(mod) { + const card = web.createElement(html`
`), + body = web.createElement(html`
`); + 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`` - ), - name: ({ name, id, version }) => - web.createElement(``), - tags({ tags }) { - if (!tags || !tags.length) return ''; - const element = web.createElement( - `` - ); - return element; - }, - description({ description }) { - const element = web.createElement( - `

${markdown.renderInline(description)}

` - ); - return element; - }, - authors: ({ authors }) => - html``, - async expand({ id }) { - const element = web.createElement( - `

${await fs.getText( - 'icons/fontawesome/long-arrow-alt-right.svg' - )} settings & documentation

` - ); - return element; - }, - toggle(id, { key, label, value }) { - const element = web.createElement(``); - return element; - }, - async select(id, { key, label, values }) { - const element = web.createElement(``); - return element; - }, - text(id, { key, label, value }) { - const element = web.createElement(``); - 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(``); - return element; - }, - async file(id, { key, label, extensions }) { - const accept = - extensions && extensions.length ? ` accept="${extensions.join(',')}"` : ''; - const element = web.createElement(``); - 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(`

- - - ${await fs.getText( - 'icons/fontawesome/long-arrow-alt-left.svg' - )} back to library - - - ${await fs.getText( - 'icons/fontawesome/code.svg' - )} view source code -

`); - return element; - }, +components.options = { + toggle: (id, { key, label, value }) => + web.createElement(html``), + select: async (id, { key, label, values }) => + web.createElement(html``), + text(id, { key, label, value }) { + const opt = web.createElement(html``); + 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('
'), - body = web.createElement('
'); - 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('
'), - body = web.createElement('
'); - 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(`
`); - ( - 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( - `
${content}
` - ); - 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``), -(async () => { - const search = new Map( + async file(id, { key, label, extensions }) { + const opt = web.createElement(html``); + 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`
`), + 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`

+ + ${await fs.getText('icons/fontawesome/long-arrow-alt-left.svg')} + back to library + + + ${await fs.getText('icons/fontawesome/code.svg')} + view source code + +

`), + readme: async (mod) => + web.createElement(html`
+ ${(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]'), + _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);