From bc38f5d972a26abdfb917dee5c8eecc53e9228a3 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Sun, 3 Oct 2021 00:13:50 +1000 Subject: [PATCH] side panel component: working except switcher --- extension/api/_.mjs | 2 +- extension/api/components/_.mjs | 12 +- extension/api/components/feather.mjs | 36 +++++ extension/api/components/panel.css | 151 ++++++++++++++++++ extension/api/components/panel.mjs | 141 ++++++++++++++++ extension/api/components/sidebar.css | 6 - extension/api/components/sidebar.mjs | 24 --- extension/api/components/tooltip.mjs | 4 +- extension/api/fmt.mjs | 4 +- extension/api/web.mjs | 119 ++++++-------- .../client.mjs | 6 +- .../mod.json | 8 +- .../blocks.mjs | 26 +-- .../menu.mjs | 26 +-- .../notifications.mjs | 10 +- .../styles.mjs | 5 +- 16 files changed, 434 insertions(+), 146 deletions(-) create mode 100644 extension/api/components/feather.mjs create mode 100644 extension/api/components/panel.css create mode 100644 extension/api/components/panel.mjs delete mode 100644 extension/api/components/sidebar.css delete mode 100644 extension/api/components/sidebar.mjs diff --git a/extension/api/_.mjs b/extension/api/_.mjs index c1a108d..334d08c 100644 --- a/extension/api/_.mjs +++ b/extension/api/_.mjs @@ -21,5 +21,5 @@ export * as fmt from './fmt.mjs'; export * as registry from './registry.mjs'; /** helpers for manipulation of a webpage */ export * as web from './web.mjs'; -/** notion-style elements inc. the sidebar */ +/** shared notion-style elements */ export * as components from './components/_.mjs'; diff --git a/extension/api/components/_.mjs b/extension/api/components/_.mjs index 63e8daa..14544e3 100644 --- a/extension/api/components/_.mjs +++ b/extension/api/components/_.mjs @@ -7,7 +7,7 @@ 'use strict'; /** - * notion-style elements inc. the sidebar + * shared notion-style elements * @module notion-enhancer/api/components */ @@ -18,4 +18,12 @@ */ export { tooltip } from './tooltip.mjs'; -export { side } from './tooltip.mjs'; +/** + * generate an icon from the feather icons set + * @param {string} name - the name/id of the icon + * @param {object} attrs - an object of attributes to apply to the icon e.g. classes + * @returns {string} an svg string + */ +export { feather } from './feather.mjs'; + +export { panel } from './panel.mjs'; diff --git a/extension/api/components/feather.mjs b/extension/api/components/feather.mjs new file mode 100644 index 0000000..3734bda --- /dev/null +++ b/extension/api/components/feather.mjs @@ -0,0 +1,36 @@ +/* + * notion-enhancer: api + * (c) 2021 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +'use strict'; + +/** + * shared notion-style elements + * @module notion-enhancer/api/components/feather + */ + +import { fs, web } from '../_.mjs'; + +let _$iconSheet; + +/** + * generate an icon from the feather icons set + * @param {string} name - the name/id of the icon + * @param {object} attrs - an object of attributes to apply to the icon e.g. classes + * @returns {string} an svg string + */ +export const feather = async (name, attrs = {}) => { + if (!_$iconSheet) { + _$iconSheet = web.html`${await fs.getText('dep/feather-sprite.svg')}`; + } + attrs.style = ( + (attrs.style ? attrs.style + ';' : '') + + 'stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;fill:none;' + ).trim(); + attrs.viewBox = '0 0 24 24'; + return ` `${web.escape(key)}="${web.escape(val)}"`) + .join(' ')}>${_$iconSheet.getElementById(name)?.innerHTML}`; +}; diff --git a/extension/api/components/panel.css b/extension/api/components/panel.css new file mode 100644 index 0000000..7458bc5 --- /dev/null +++ b/extension/api/components/panel.css @@ -0,0 +1,151 @@ +/* + * notion-enhancer core: components + * (c) 2021 dragonwocky (https://dragonwocky.me/) + * (c) 2021 CloudHill (https://github.com/CloudHill) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +:root { + --component--panel-width: 260px; +} + +#enhancer--panel-hover-trigger { + height: 100vh; + width: 2.5rem; + max-height: 100%; + z-index: 999; + position: absolute; + top: 0; + right: 0; + flex-grow: 0; + flex-shrink: 0; + transition: width 300ms ease-in-out; +} +#enhancer--panel-hover-trigger[data-enhancer-panel-pinned] { + /* taking up the physical space of the panel to move topbar buttons */ + position: relative; + width: var(--component--panel-width); +} + +.notion-cursor-listener > div[style*='flex-end'] { + transition: margin-right 300ms ease-in-out; +} +.notion-cursor-listener > div[style*='flex-end'][data-enhancer-panel-pinned] { + margin-right: var(--component--panel-width); +} +.notion-frame { + transition: padding-right 300ms ease-in-out; +} +.notion-frame[data-enhancer-panel-pinned] { + padding-right: var(--component--panel-width); +} + +#enhancer--panel { + z-index: 999; + position: absolute; + background: var(--theme--bg_secondary); + width: var(--component--panel-width); + right: calc(-1 * var(--component--panel-width)); + opacity: 0; + height: 100vh; + flex-grow: 0; + flex-shrink: 0; + display: flex; + flex-direction: column; + transition: 300ms ease-in; + + margin-top: 5rem; + max-height: calc(100vh - 10rem); +} +#enhancer--panel-hover-trigger:hover + #enhancer--panel:not([data-enhancer-panel-pinned]), +#enhancer--panel:not([data-enhancer-panel-pinned]):hover { + opacity: 1; + transform: translateX(calc(-1 * var(--component--panel-width))); + box-shadow: var(--theme--ui_shadow, rgba(15, 15, 15, 0.05)) 0px 0px 0px 1px, + var(--theme--ui_shadow, rgba(15, 15, 15, 0.1)) 0px 3px 6px, + var(--theme--ui_shadow, rgba(15, 15, 15, 0.2)) 0px 9px 24px !important; +} +#enhancer--panel[data-enhancer-panel-pinned] { + opacity: 1; + max-height: 100%; + margin-top: 0; + transform: translateX(calc(-1 * var(--component--panel-width))); +} + +#enhancer--panel-header { + font-size: 1.35rem; + font-weight: bold; + display: flex; + padding: 0.75rem 1rem; + align-items: center; +} +#enhancer--panel-content { + font-size: 1rem; + padding: 0.75rem 1rem; +} +#enhancer--panel-header-title { + padding-left: 0.5em; + padding-bottom: 0.1em; +} +#enhancer--panel-header-title > p { + margin: 0; + height: 1em; + display: flex; + align-items: center; +} +#enhancer--panel-header-title > p svg, +#enhancer--panel-header-title > p img { + height: 1em; + width: 1em; +} +#enhancer--panel-header-title > p span { + font-size: 0.9em; + margin-left: 0.5em; +} +#enhancer--panel-header-toggle { + margin-left: auto; +} +#enhancer--panel-header-toggle, +#enhancer--panel-header-switcher { + height: 1em; + width: 1em; + cursor: pointer; + opacity: 0; + transition: 300ms ease-in-out; + display: flex; + flex-direction: column; +} +#enhancer--panel-header-switcher svg { + width: 0.5em; + height: 0.5em; + display: block; + margin: auto; +} + +#enhancer--panel:not([data-enhancer-panel-pinned]) #enhancer--panel-header-toggle { + transform: rotateZ(-180deg); +} +#enhancer--panel:hover #enhancer--panel-header-toggle, +#enhancer--panel:hover #enhancer--panel-header-switcher { + opacity: 1; +} + +#enhancer--panel-resize { + position: absolute; + left: -5px; + height: 100%; + width: 10px; +} +#enhancer--panel[data-enhancer-panel-pinned] #enhancer--panel-resize { + cursor: col-resize; +} +#enhancer--panel-resize div { + transition: background 150ms ease-in-out; + background: transparent; + width: 2px; + margin-left: 4px; + height: 100%; +} +#enhancer--panel[data-enhancer-panel-pinned] #enhancer--panel-resize:hover div { + background: var(--theme--ui_divider); +} diff --git a/extension/api/components/panel.mjs b/extension/api/components/panel.mjs new file mode 100644 index 0000000..b9f44e1 --- /dev/null +++ b/extension/api/components/panel.mjs @@ -0,0 +1,141 @@ +/* + * notion-enhancer: api + * (c) 2021 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +'use strict'; + +/** + * shared notion-style elements + * @module notion-enhancer/api/components/side-panel + */ + +import { web, components, registry } from '../_.mjs'; +const db = await registry.db('36a2ffc9-27ff-480e-84a7-c7700a7d232d'); + +let $panel, + _views = []; + +export const panel = async (icon, title, generator = () => {}) => { + _views.push({ + icon: web.html`${icon}`, + title: web.html`${web.escape(title)}`, + $elem: generator(), + }); + + if (!$panel) { + $panel = web.html`
`; + + const notionRightSidebarSelector = '.notion-cursor-listener > div[style*="flex-end"]'; + await web.whenReady([notionRightSidebarSelector]); + web.loadStylesheet('api/components/panel.css'); + + const $title = web.html`
`, + $header = web.render(web.html`
`, $title), + $content = web.html`
`; + + // opening/closing + const $notionFrame = document.querySelector('.notion-frame'), + $notionRightSidebar = document.querySelector(notionRightSidebarSelector), + $pinnedToggle = web.html`
+ ${await components.feather('chevrons-right')} +
`, + $hoverTrigger = web.html`
`, + panelPinnedAttr = 'data-enhancer-panel-pinned', + isPinned = () => $panel.hasAttribute(panelPinnedAttr), + isRightSidebarOpen = () => + $notionRightSidebar.matches('[style*="border-left: 1px solid rgba(0, 0, 0, 0)"]'), + togglePanel = () => { + const $elems = [$notionRightSidebar, $hoverTrigger, $panel]; + if (isPinned()) { + if (isRightSidebarOpen()) $elems.push($notionFrame); + for (const $elem of $elems) $elem.removeAttribute(panelPinnedAttr); + } else { + $elems.push($notionFrame); + for (const $elem of $elems) $elem.setAttribute(panelPinnedAttr, 'true'); + } + db.set(['panel.pinned'], isPinned()); + }; + web.addDocumentObserver(() => { + if (isPinned()) { + if (isRightSidebarOpen()) { + $notionFrame.removeAttribute(panelPinnedAttr); + } else { + $notionFrame.setAttribute(panelPinnedAttr, 'true'); + } + } + }, [notionRightSidebarSelector]); + if (await db.get(['panel.pinned'])) togglePanel(); + web.addHotkeyListener(await db.get(['panel.hotkey']), togglePanel); + $pinnedToggle.addEventListener('click', togglePanel); + + // resizing + let dragStartX, + dragStartWidth, + dragEventsFired, + panelWidth = await db.get(['panel.width'], 240); + const $resizeHandle = web.html`
`, + updateWidth = async () => { + document.documentElement.style.setProperty( + '--component--panel-width', + panelWidth + 'px' + ); + db.set(['panel.width'], panelWidth); + }, + resizeDrag = (event) => { + event.preventDefault(); + dragEventsFired = true; + panelWidth = dragStartWidth + (dragStartX - event.clientX); + if (panelWidth < 190) panelWidth = 190; + if (panelWidth > 480) panelWidth = 480; + $panel.style.width = panelWidth + 'px'; + $hoverTrigger.style.width = panelWidth + 'px'; + $notionFrame.style.paddingRight = panelWidth + 'px'; + $notionRightSidebar.style.right = panelWidth + 'px'; + }, + resizeEnd = (event) => { + $panel.style.width = ''; + $hoverTrigger.style.width = ''; + $notionFrame.style.paddingRight = ''; + $notionRightSidebar.style.right = ''; + updateWidth(); + $resizeHandle.style.cursor = ''; + document.body.removeEventListener('mousemove', resizeDrag); + document.body.removeEventListener('mouseup', resizeEnd); + }, + resizeStart = (event) => { + dragStartX = event.clientX; + dragStartWidth = panelWidth; + $resizeHandle.style.cursor = 'auto'; + document.body.addEventListener('mousemove', resizeDrag); + document.body.addEventListener('mouseup', resizeEnd); + }; + updateWidth(); + $resizeHandle.addEventListener('mousedown', resizeStart); + $resizeHandle.addEventListener('click', () => { + if (dragEventsFired) { + dragEventsFired = false; + } else togglePanel(); + }); + + // view selection + const $switcherTrigger = web.html`
+ ${await components.feather('chevron-up')} + ${await components.feather('chevron-down')} +
`, + renderView = (view) => { + web.render(web.empty($title), web.render(web.html`

`, view.icon, view.title)); + web.render(web.empty($content), view.$elem); + }; + renderView(_views[0]); + + web.render( + $panel, + web.render($header, $switcherTrigger, $title, $pinnedToggle), + $content, + $resizeHandle + ); + $notionRightSidebar.after($hoverTrigger, $panel); + } +}; diff --git a/extension/api/components/sidebar.css b/extension/api/components/sidebar.css deleted file mode 100644 index b52afd8..0000000 --- a/extension/api/components/sidebar.css +++ /dev/null @@ -1,6 +0,0 @@ -/* - * notion-enhancer core: components - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (c) 2021 CloudHill (https://github.com/CloudHill) - * (https://notion-enhancer.github.io/) under the MIT license - */ diff --git a/extension/api/components/sidebar.mjs b/extension/api/components/sidebar.mjs deleted file mode 100644 index 7593a46..0000000 --- a/extension/api/components/sidebar.mjs +++ /dev/null @@ -1,24 +0,0 @@ -/* - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** - * notion-style elements inc. the sidebar - * @module notion-enhancer/api/components/side-panel - */ - -import { web } from '../_.mjs'; - -let _$sidebar; - -export const sidebar = (icon, name, loader = ($panel) => {}) => { - if (!_$sidebar) { - web.loadStylesheet('api/components/sidebar.css'); - _$sidebar = web.html`
`; - web.render(document.body, _$sidebar); - } -}; diff --git a/extension/api/components/tooltip.mjs b/extension/api/components/tooltip.mjs index 5d03bb8..4487ed7 100644 --- a/extension/api/components/tooltip.mjs +++ b/extension/api/components/tooltip.mjs @@ -7,7 +7,7 @@ 'use strict'; /** - * notion-style elements inc. the sidebar + * shared notion-style elements * @module notion-enhancer/api/components/tooltip */ @@ -22,8 +22,8 @@ let _$tooltip; */ export const tooltip = ($ref, text) => { if (!_$tooltip) { - web.loadStylesheet('api/components/tooltip.css'); _$tooltip = web.html`
`; + web.loadStylesheet('api/components/tooltip.css'); web.render(document.body, _$tooltip); } text = fmt.md.render(text); diff --git a/extension/api/fmt.mjs b/extension/api/fmt.mjs index 0c75932..f905c01 100644 --- a/extension/api/fmt.mjs +++ b/extension/api/fmt.mjs @@ -11,7 +11,7 @@ * @module notion-enhancer/api/fmt */ -import { web, fs } from './_.mjs'; +import { web, fs, components } from './_.mjs'; import '../dep/prism.min.js'; /** syntax highlighting using https://prismjs.com/ */ @@ -21,7 +21,7 @@ Prism.hooks.add('complete', async (event) => { event.element.parentElement.removeAttribute('tabindex'); event.element.parentElement.parentElement .querySelector('.copy-to-clipboard-button') - .prepend(web.html`${await web.icon('clipboard')}`); + .prepend(web.html`${await components.feather('clipboard')}`); }); import '../dep/markdown-it.min.js'; diff --git a/extension/api/web.mjs b/extension/api/web.mjs index e116b44..d215c49 100644 --- a/extension/api/web.mjs +++ b/extension/api/web.mjs @@ -13,12 +13,6 @@ import { fs, fmt } from './_.mjs'; -const _hotkeyEventListeners = [], - _documentObserverListeners = [], - _documentObserverEvents = []; - -let _hotkeyEvent, _documentObserver; - import '../dep/jscolor.min.js'; /** color picker with alpha channel using https://jscolor.com/ */ export const jscolor = JSColor; @@ -144,21 +138,27 @@ export const loadStylesheet = (path) => { return true; }; -/** - * generate an icon from the feather icons set - * @param {string} name - the name/id of the icon - * @param {object} attrs - an object of attributes to apply to the icon e.g. classes - * @returns {string} an svg string - */ -export const icon = (name, attrs = {}) => { - attrs.style = ( - (attrs.style || '') + - ';stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;fill:none;' - ).trim(); - return ` `${escape(key)}="${escape(val)}"`) - .join(' ')}>`; -}; +const _hotkeyEvent = document.addEventListener('keyup', (event) => { + if (document.activeElement.nodeName === 'INPUT') return; + for (const hotkey of _hotkeyEventListeners) { + const pressed = hotkey.keys.every((key) => { + key = key.toLowerCase(); + const modifiers = { + metaKey: ['meta', 'os', 'win', 'cmd', 'command'], + ctrlKey: ['ctrl', 'control'], + shiftKey: ['shift'], + altKey: ['alt'], + }; + for (const modifier in modifiers) { + const pressed = modifiers[modifier].includes(key) && event[modifier]; + if (pressed) return true; + } + if (key === event.key.toLowerCase()) return true; + }); + if (pressed) hotkey.callback(); + } + }), + _hotkeyEventListeners = []; /** * register a hotkey listener to the page @@ -169,28 +169,6 @@ export const icon = (name, attrs = {}) => { */ export const addHotkeyListener = (keys, callback) => { if (typeof keys === 'string') keys = keys.split('+'); - if (!_hotkeyEvent) { - _hotkeyEvent = document.addEventListener('keyup', (event) => { - if (document.activeElement.nodeName === 'INPUT') return; - for (const hotkey of _hotkeyEventListeners) { - const pressed = hotkey.keys.every((key) => { - key = key.toLowerCase(); - const modifiers = { - metaKey: ['meta', 'os', 'win', 'cmd', 'command'], - ctrlKey: ['ctrl', 'control'], - shiftKey: ['shift'], - altKey: ['alt'], - }; - for (const modifier in modifiers) { - const pressed = modifiers[modifier].includes(key) && event[modifier]; - if (pressed) return true; - } - if (key === event.key.toLowerCase()) return true; - }); - if (pressed) hotkey.callback(); - } - }); - } _hotkeyEventListeners.push({ keys, callback }); }; /** @@ -203,40 +181,39 @@ export const removeHotkeyListener = (callback) => { ); }; +const _documentObserver = new MutationObserver((list, observer) => { + if (!_documentObserverEvents.length) + requestIdleCallback(() => (queue) => { + while (queue.length) { + const event = queue.shift(); + for (const listener of _documentObserverListeners) { + if ( + !listener.selectors.length || + listener.selectors.some( + (selector) => + event.target.matches(selector) || event.target.matches(`${selector} *`) + ) + ) { + listener.callback(event); + } + } + } + }); + _documentObserverEvents.push(...list); + }), + _documentObserverListeners = [], + _documentObserverEvents = []; +_documentObserver.observe(document.body, { + childList: true, + subtree: true, + attributes: true, +}); /** * add a listener to watch for changes to the dom * @param {onDocumentObservedCallback} callback * @param {array} [selectors] */ export const addDocumentObserver = (callback, selectors = []) => { - if (!_documentObserver) { - const handle = (queue) => { - while (queue.length) { - const event = queue.shift(); - for (const listener of _documentObserverListeners) { - if ( - !listener.selectors.length || - listener.selectors.some( - (selector) => - event.target.matches(selector) || event.target.matches(`${selector} *`) - ) - ) { - listener.callback(event); - } - } - } - }; - _documentObserver = new MutationObserver((list, observer) => { - if (!_documentObserverEvents.length) - requestIdleCallback(() => handle(_documentObserverEvents)); - _documentObserverEvents.push(...list); - }); - _documentObserver.observe(document.body, { - childList: true, - subtree: true, - attributes: true, - }); - } _documentObserverListeners.push({ callback, selectors }); }; diff --git a/extension/repo/bypass-preview@cb6fd684-f113-4a7a-9423-8f0f0cff069f/client.mjs b/extension/repo/bypass-preview@cb6fd684-f113-4a7a-9423-8f0f0cff069f/client.mjs index 4c640f6..1a0d46c 100644 --- a/extension/repo/bypass-preview@cb6fd684-f113-4a7a-9423-8f0f0cff069f/client.mjs +++ b/extension/repo/bypass-preview@cb6fd684-f113-4a7a-9423-8f0f0cff069f/client.mjs @@ -7,7 +7,7 @@ 'use strict'; export default async function (api, db) { - const { web } = api; + const { web, components } = api; await web.whenReady(); let _lastPage = {}; @@ -30,4 +30,8 @@ export default async function (api, db) { _lastPage = getCurrentPage(); } }); + + components.panel(await components.feather('sidebar'), 'Test Panel', ($panel) => { + return web.html`

test

`; + }); } diff --git a/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/mod.json b/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/mod.json index 5b43a62..bb0cc36 100644 --- a/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/mod.json +++ b/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/mod.json @@ -3,7 +3,7 @@ "name": "components", "id": "36a2ffc9-27ff-480e-84a7-c7700a7d232d", "version": "0.2.0", - "description": "notion-style elements reused by other mods, inc. the sidebar.", + "description": "shared notion-style elements.", "tags": ["core"], "authors": [ { @@ -24,10 +24,10 @@ "options": [ { "type": "hotkey", - "key": "side-panel-hotkey", - "label": "toggle enhancer sidebar hotkey", + "key": "panel.hotkey", + "label": "toggle panel hotkey", "value": "Ctrl+Alt+\\", - "tooltip": "opens/closes the extra sidebar in notion - will only work if a mod is making use of it." + "tooltip": "opens/closes the side panel in notion - will only work if a mod is making use of it." } ] } diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/blocks.mjs b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/blocks.mjs index 41cf1cb..4f1a7e0 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/blocks.mjs +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/blocks.mjs @@ -58,7 +58,7 @@ export const options = { toggle: async (mod, opt) => { const checked = await profileDB.get([mod.id, opt.key], opt.value), $toggle = blocks.toggle(opt.label, checked), - $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`, + $tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = $toggle.children[0], $input = $toggle.children[1]; if (opt.tooltip) { @@ -73,7 +73,7 @@ export const options = { }, select: async (mod, opt) => { const value = await profileDB.get([mod.id, opt.key], opt.values[0]), - $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`, + $tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltip : '', opt.label) @@ -88,7 +88,7 @@ export const options = { $select = web.html``, - $icon = web.html`${web.icon('chevron-down', { class: 'input-icon' })}`; + $icon = web.html`${await components.feather('chevron-down', { class: 'input-icon' })}`; if (opt.tooltip) components.tooltip($tooltip, opt.tooltip); $select.addEventListener('change', async (event) => { await profileDB.set([mod.id, opt.key], $select.value); @@ -98,13 +98,13 @@ export const options = { }, text: async (mod, opt) => { const value = await profileDB.get([mod.id, opt.key], opt.value), - $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`, + $tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltip : '', opt.label) ), $input = web.html``, - $icon = web.html`${web.icon('type', { class: 'input-icon' })}`; + $icon = web.html`${await components.feather('type', { class: 'input-icon' })}`; if (opt.tooltip) components.tooltip($tooltip, opt.tooltip); $input.addEventListener('change', async (event) => { await profileDB.set([mod.id, opt.key], $input.value); @@ -114,13 +114,13 @@ export const options = { }, number: async (mod, opt) => { const value = await profileDB.get([mod.id, opt.key], opt.value), - $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`, + $tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltip : '', opt.label) ), $input = web.html``, - $icon = web.html`${web.icon('hash', { class: 'input-icon' })}`; + $icon = web.html`${await components.feather('hash', { class: 'input-icon' })}`; if (opt.tooltip) components.tooltip($tooltip, opt.tooltip); $input.addEventListener('change', async (event) => { await profileDB.set([mod.id, opt.key], $input.value); @@ -130,13 +130,13 @@ export const options = { }, color: async (mod, opt) => { const value = await profileDB.get([mod.id, opt.key], opt.value), - $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`, + $tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltip : '', opt.label) ), $input = web.html``, - $icon = web.html`${web.icon('droplet', { class: 'input-icon' })}`, + $icon = web.html`${await components.feather('droplet', { class: 'input-icon' })}`, paint = () => { $input.style.background = $picker.toBackground(); $input.style.color = $picker.isLight() ? '#000' : '#fff'; @@ -163,7 +163,7 @@ export const options = { }, file: async (mod, opt) => { const { filename } = (await profileDB.get([mod.id, opt.key], {})) || {}, - $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`, + $tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltip : '', opt.label) @@ -172,7 +172,7 @@ export const options = { $input = web.html``, - $icon = web.html`${web.icon('file', { class: 'input-icon' })}`, + $icon = web.html`${await components.feather('file', { class: 'input-icon' })}`, $filename = web.html`${web.escape(filename || 'none')}`, $latest = web.render(web.html``, $filename); if (opt.tooltip) components.tooltip($tooltip, opt.tooltip); @@ -201,13 +201,13 @@ export const options = { }, hotkey: async (mod, opt) => { const value = await profileDB.get([mod.id, opt.key], opt.value), - $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`, + $tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltip : '', opt.label) ), $input = web.html``, - $icon = web.html`${web.icon('command', { class: 'input-icon' })}`; + $icon = web.html`${await components.feather('command', { class: 'input-icon' })}`; if (opt.tooltip) components.tooltip($tooltip, opt.tooltip); $input.addEventListener('keydown', async (event) => { event.preventDefault(); diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.mjs b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.mjs index 49c2611..6679759 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.mjs +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.mjs @@ -6,7 +6,7 @@ 'use strict'; -import { env, fs, storage, registry, web } from '../../api/_.mjs'; +import { env, fs, storage, registry, web, components } from '../../api/_.mjs'; import { notifications } from './notifications.mjs'; import { blocks, options } from './blocks.mjs'; import './styles.mjs'; @@ -74,17 +74,17 @@ $profile.addEventListener('click', async (event) => { pattern="/^[A-Za-z0-9_-]+$/" >`, $export = web.html``, $import = web.html``, $save = web.html``, $delete = web.html``, $error = web.html`

`; $export.addEventListener('click', async (event) => { @@ -175,12 +175,12 @@ $profile.addEventListener('click', async (event) => { web.render( web.html``, $select, - web.html`${web.icon('chevron-down', { class: 'input-icon' })}` + web.html`${await components.feather('chevron-down', { class: 'input-icon' })}` ), web.render( web.html``, $edit, - web.html`${web.icon('type', { class: 'input-icon' })}` + web.html`${await components.feather('type', { class: 'input-icon' })}` ), web.render(web.html`

`, $export, $import, $save, $delete), $error @@ -288,7 +288,7 @@ const _$modListCache = {}, web.render( web.html``, $search, - web.html`${web.icon('search', { class: 'input-icon' })}` + web.html`${await components.feather('search', { class: 'input-icon' })}` ), message ? web.html`

${web.escape(message)}

` : '', $list @@ -303,14 +303,13 @@ const $notionNavItem = web.html`

/width="\d+" height="\d+"/, `class="nav-notion-icon"` )} - notion-enhancer + notion-enhancer

`; -$notionNavItem.children[0].addEventListener('click', env.focusNotion); +$notionNavItem.addEventListener('click', env.focusNotion); const $coreNavItem = web.html`core`, $extensionsNavItem = web.html`extensions`, - $themesNavItem = web.html`themes`, - $communityNavItem = web.html`community`; + $themesNavItem = web.html`themes`; web.render( document.body, @@ -324,7 +323,8 @@ web.render( $coreNavItem, $extensionsNavItem, $themesNavItem, - $communityNavItem + web.html`docs`, + web.html`community` ), $main ), diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/notifications.mjs b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/notifications.mjs index 64fcf64..97e0f93 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/notifications.mjs +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/notifications.mjs @@ -6,7 +6,7 @@ 'use strict'; -import { env, fs, storage, fmt, registry, web } from '../../api/_.mjs'; +import { env, fs, storage, fmt, registry, web, components } from '../../api/_.mjs'; import { tw } from './styles.mjs'; export const notifications = { @@ -16,7 +16,7 @@ export const notifications = { registry.welcomeNotification, ...(await fs.getJSON('https://notion-enhancer.github.io/notifications.json')), ], - add({ icon, message, id = undefined, color = undefined, link = undefined }) { + async add({ icon, message, id = undefined, color = undefined, link = undefined }) { const $notification = link ? web.html` ${fmt.md.renderInline(message)} `, - web.html`${web.icon(icon, { class: 'notification-icon' })}` + web.html`${await components.feather(icon, { class: 'notification-icon' })}` ) ); return $notification; }, _onChange: false, - onChange() { + async onChange() { if (this._onChange) return; this._onChange = true; - const $notification = this.add({ + const $notification = await this.add({ icon: 'refresh-cw', message: 'Reload to apply changes.', }); diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/styles.mjs b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/styles.mjs index de8337f..f9e15c1 100644 --- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/styles.mjs +++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/styles.mjs @@ -36,13 +36,13 @@ const customClasses = { 'notification-icon': apply`fill-current opacity-75 h-4 w-4 mx-2`, 'body-container': apply`flex w-full h-full overflow-hidden`, 'content-container': apply`h-full w-full-96`, - 'nav': apply`px-4 py-3 flex flex-wrap items-center border-b border-divider h-48 sm:h-32 lg:h-16`, + 'nav': apply`px-4 py-3 flex flex-wrap items-center border-b border-divider h-64 sm:h-48 md:h-32 lg:h-16`, 'nav-notion': apply`flex items-center font-semibold text-xl cursor-pointer select-none mr-4 ml-4 sm:mb-4 md:w-full lg:(w-auto ml-0 mb-0)`, 'nav-notion-icon': apply`h-12 w-12 mr-5 sm:(h-6 w-6 mr-3)`, 'nav-item': apply`ml-4 px-3 py-2 rounded-md text-sm font-medium hover:bg-interactive-hover focus:bg-interactive-focus`, 'nav-item-selected': apply`ml-4 px-3 py-2 rounded-md text-sm font-medium ring-1 ring-divider bg-notion-secondary`, - 'main': apply`transition px-4 py-3 overflow-y-auto max-h-full-48 sm:max-h-full-32 lg:max-h-full-16`, + 'main': apply`transition px-4 py-3 overflow-y-auto max-h-full-64 sm:max-h-full-48 md:max-h-full-32 lg:max-h-full-16`, 'main-message': apply`mx-2.5 my-2.5 px-px text-sm text-foreground-secondary text-justify`, 'mods-list': apply`flex flex-wrap`, 'mod-container': apply`w-full md:w-1/2 lg:w-1/3 xl:w-1/4 2xl:w-1/5 px-2.5 py-2.5 box-border`, @@ -145,6 +145,7 @@ setup({ 'full-16': 'calc(100% - 4rem)', 'full-32': 'calc(100% - 8rem)', 'full-48': 'calc(100% - 12rem)', + 'full-64': 'calc(100% - 16rem)', }, }, },