/** * notion-enhancer: menu * (c) 2021 dragonwocky (https://dragonwocky.me/) * (https://notion-enhancer.github.io/) under the MIT license */ 'use strict'; import { fmt, web, registry, components } from '../../api/index.mjs'; import { notifications } from './notifications.mjs'; import '../../dep/jscolor.min.js'; import '../../dep/markdown-it.min.js'; const md = markdownit({ linkify: true }); export const modComponents = { preview: (url) => web.html``, title: (title) => web.html`

${web.escape(title)}

`, version: (version) => web.html`v${web.escape(version)}`, tags: (tags) => { if (!tags.length) return ''; return web.render( web.html`

`, tags.map((tag) => `#${web.escape(tag)}`).join(' ') ); }, description: (description) => { const $description = web.html`

${md.renderInline(description)}

`; $description.querySelectorAll('a').forEach((a) => { a.target = '_blank'; }); return $description; }, authors: (authors) => { const author = (author) => web.html` ${web.escape(author.name)}'s avatar ${web.escape(author.name)} `; return web.render(web.html`

`, ...authors.map(author)); }, toggle: (label, checked) => { const $label = web.html``, $input = web.html``, $feature = web.html``; $label.addEventListener('keyup', (event) => { if (['Enter', ' '].includes(event.key)) $input.checked = !$input.checked; }); return web.render($label, $input, $feature); }, }; export const options = { toggle: async (mod, opt) => { const profileDB = await registry.profileDB(), checked = await profileDB.get([mod.id, opt.key], opt.value), $toggle = modComponents.toggle(opt.label, checked), $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = $toggle.children[0], $input = $toggle.children[1]; if (opt.tooltip) { $label.prepend($tooltipIcon); components.addTooltip($tooltipIcon, opt.tooltip, { offsetDirection: 'left', maxLines: 3, }); } $input.addEventListener('change', async (_event) => { await profileDB.set([mod.id, opt.key], $input.checked); notifications.onChange(); }); return $toggle; }, select: async (mod, opt) => { const profileDB = await registry.profileDB(), value = await profileDB.get([mod.id, opt.key], opt.values[0]), $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltipIcon : '', opt.label) ), $options = opt.values.map( (option) => web.raw`` ), $select = web.html``, $icon = web.html`${await components.feather('chevron-down', { class: 'input-icon' })}`; if (opt.tooltip) components.addTooltip($tooltipIcon, opt.tooltip, { offsetDirection: 'left', maxLines: 3, }); $select.addEventListener('change', async (_event) => { await profileDB.set([mod.id, opt.key], $select.value); notifications.onChange(); }); return web.render($label, $select, $icon); }, text: async (mod, opt) => { const profileDB = await registry.profileDB(), value = await profileDB.get([mod.id, opt.key], opt.value), $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltipIcon : '', opt.label) ), $input = web.html``, $icon = web.html`${await components.feather('type', { class: 'input-icon' })}`; if (opt.tooltip) components.addTooltip($tooltipIcon, opt.tooltip, { offsetDirection: 'left', maxLines: 3, }); $input.addEventListener('change', async (_event) => { await profileDB.set([mod.id, opt.key], $input.value); notifications.onChange(); }); return web.render($label, $input, $icon); }, number: async (mod, opt) => { const profileDB = await registry.profileDB(), value = await profileDB.get([mod.id, opt.key], opt.value), $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltipIcon : '', opt.label) ), $input = web.html``, $icon = web.html`${await components.feather('hash', { class: 'input-icon' })}`; if (opt.tooltip) components.addTooltip($tooltipIcon, opt.tooltip, { offsetDirection: 'left', maxLines: 3, }); $input.addEventListener('change', async (_event) => { await profileDB.set([mod.id, opt.key], $input.value); notifications.onChange(); }); return web.render($label, $input, $icon); }, color: async (mod, opt) => { const profileDB = await registry.profileDB(), value = await profileDB.get([mod.id, opt.key], opt.value), $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltipIcon : '', opt.label) ), $input = web.html``, $icon = web.html`${await components.feather('droplet', { class: 'input-icon' })}`, paint = () => { $input.style.background = $picker.toBackground(); const [r, g, b] = $picker .toRGBAString() .slice(5, -1) .split(',') .map((i) => parseInt(i)); $input.style.color = fmt.rgbContrast(r, g, b); $input.style.padding = ''; }, $picker = new JSColor($input, { value, format: 'rgba', previewSize: 0, borderRadius: 3, borderColor: 'var(--theme--ui_divider)', controlBorderColor: 'var(--theme--ui_divider)', backgroundColor: 'var(--theme--bg)', onInput: paint, onChange: paint, }); if (opt.tooltip) components.addTooltip($tooltipIcon, opt.tooltip, { offsetDirection: 'left', maxLines: 3, }); $input.addEventListener('change', async (_event) => { await profileDB.set([mod.id, opt.key], $input.value); notifications.onChange(); }); paint(); return web.render($label, $input, $icon); }, file: async (mod, opt) => { const profileDB = await registry.profileDB(), { filename } = (await profileDB.get([mod.id, opt.key], {})) || {}, $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltipIcon : '', opt.label) ), $pseudo = web.html`Upload file...`, $input = web.html``, $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.addTooltip($tooltipIcon, opt.tooltip, { offsetDirection: 'left', maxLines: 3, }); $input.addEventListener('change', (event) => { const file = event.target.files[0], reader = new FileReader(); reader.onload = async (progress) => { $filename.innerText = file.name; await profileDB.set([mod.id, opt.key], { filename: file.name, content: progress.currentTarget.result, }); notifications.onChange(); }; reader.readAsText(file); }); $latest.addEventListener('click', (_event) => { $filename.innerText = 'none'; profileDB.set([mod.id, opt.key], {}); }); return web.render( web.html`
`, web.render($label, $input, $pseudo, $icon), $latest ); }, hotkey: async (mod, opt) => { const profileDB = await registry.profileDB(), value = await profileDB.get([mod.id, opt.key], opt.value), $tooltipIcon = web.html`${await components.feather('info', { class: 'input-tooltip' })}`, $label = web.render( web.html``, web.render(web.html`

`, opt.tooltip ? $tooltipIcon : '', opt.label) ), $input = web.html``, $icon = web.html`${await components.feather('command', { class: 'input-icon' })}`; if (opt.tooltip) components.addTooltip($tooltipIcon, opt.tooltip, { offsetDirection: 'left', maxLines: 3, }); $input.addEventListener('keydown', async (event) => { event.preventDefault(); const pressed = [], modifiers = { metaKey: 'Meta', ctrlKey: 'Control', altKey: 'Alt', shiftKey: 'Shift', }; for (const modifier in modifiers) { if (event[modifier]) pressed.push(modifiers[modifier]); } const empty = ['Backspace', 'Delete'].includes(event.key) && !pressed.length; if (!empty && !pressed.includes(event.key)) { let key = event.key; if (key === ' ') key = 'Space'; if (key === '+') key = 'Plus'; if (key.length === 1) key = event.key.toUpperCase(); pressed.push(key); } $input.value = pressed.join('+'); await profileDB.set([mod.id, opt.key], $input.value); notifications.onChange(); }); return web.render($label, $input, $icon); }, };