diff --git a/extension/api/registry-validation.mjs b/extension/api/registry-validation.mjs
index afe7819..48add10 100644
--- a/extension/api/registry-validation.mjs
+++ b/extension/api/registry-validation.mjs
@@ -148,6 +148,22 @@ const check = async (
});
tests.push(test);
}
+ if (mod.js.hook) {
+ if (mod.tags.includes('core')) {
+ const test = check(mod, 'js.hook', mod.js.hook, 'file', {
+ extension: '.mjs',
+ });
+ tests.push(test);
+ } else {
+ registry._errors.push({
+ source: mod._dir,
+ message: `js.hook (only core mods can register hooks): ${JSON.stringify(
+ mod.tags
+ )}`,
+ });
+ tests.push(false);
+ }
+ }
return tests;
});
},
diff --git a/extension/api/registry.mjs b/extension/api/registry.mjs
index d55e0dd..54ee095 100644
--- a/extension/api/registry.mjs
+++ b/extension/api/registry.mjs
@@ -25,6 +25,7 @@ export const _cache = [],
export const core = [
'a6621988-551d-495a-97d8-3c568bca2e9e',
'0f0bf8b6-eae6-4273-b307-8fc43f2ee082',
+ '36a2ffc9-27ff-480e-84a7-c7700a7d232d',
];
/**
diff --git a/extension/api/web.mjs b/extension/api/web.mjs
index ad8d32e..e116b44 100644
--- a/extension/api/web.mjs
+++ b/extension/api/web.mjs
@@ -17,7 +17,7 @@ const _hotkeyEventListeners = [],
_documentObserverListeners = [],
_documentObserverEvents = [];
-let _$tooltip, _$tooltipStylesheet, _hotkeyEvent, _documentObserver;
+let _hotkeyEvent, _documentObserver;
import '../dep/jscolor.min.js';
/** color picker with alpha channel using https://jscolor.com/ */
@@ -160,52 +160,6 @@ export const icon = (name, attrs = {}) => {
.join(' ')}>`;
};
-/**
- * add a tooltip to show extra information on hover
- * @param {HTMLElement} $ref - the element that will trigger the tooltip when hovered
- * @param {string} text - the markdown content of the tooltip
- */
-export const tooltip = ($ref, text) => {
- if (!_$tooltip) {
- _$tooltip = html`
`;
- _$tooltipStylesheet = html``;
- render(document.head, _$tooltipStylesheet);
- render(document.body, _$tooltip);
- }
- text = fmt.md.render(text);
- $ref.addEventListener('mouseover', (event) => {
- _$tooltip.innerHTML = text;
- _$tooltip.style.display = 'block';
- });
- $ref.addEventListener('mousemove', (event) => {
- _$tooltip.style.top = event.clientY - _$tooltip.clientHeight + 'px';
- _$tooltip.style.left = event.clientX - _$tooltip.clientWidth + 'px';
- });
- $ref.addEventListener('mouseout', (event) => {
- _$tooltip.style.display = '';
- });
-};
-
/**
* register a hotkey listener to the page
* @param {array} keys - the combination of keys that will trigger the hotkey.
diff --git a/extension/launcher.js b/extension/launcher.js
index 5319194..cf7173c 100644
--- a/extension/launcher.js
+++ b/extension/launcher.js
@@ -13,16 +13,28 @@
page = location.pathname.split(/[/-]/g).reverse()[0].length === 32;
if (site || page) {
- import(chrome.runtime.getURL('api/_.mjs')).then(async (api) => {
- const { registry, web } = api;
+ import(chrome.runtime.getURL('api/_.mjs')).then(async ({ ...api }) => {
+ const { fs, registry, web } = api,
+ insert = async (mod) => {
+ for (const sheet of mod.css?.client || []) {
+ web.loadStylesheet(`repo/${mod._dir}/${sheet}`);
+ }
+ for (let script of mod.js?.client || []) {
+ script = await import(fs.localPath(`repo/${mod._dir}/${script}`));
+ script.default(api, await registry.db(mod.id));
+ }
+ return true;
+ };
+ for (const mod of await registry.list((mod) => registry.core.includes(mod.id))) {
+ if (mod.js?.hook) {
+ let script = mod.js.hook;
+ script = await import(fs.localPath(`repo/${mod._dir}/${script}`));
+ api[mod.name] = await script.default(api, await registry.db(mod.id));
+ }
+ await insert(mod);
+ }
for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
- for (const sheet of mod.css?.client || []) {
- web.loadStylesheet(`repo/${mod._dir}/${sheet}`);
- }
- for (let script of mod.js?.client || []) {
- script = await import(chrome.runtime.getURL(`repo/${mod._dir}/${script}`));
- script.default(api, await registry.db(mod.id));
- }
+ if (!registry.core.includes(mod.id)) await insert(mod);
}
const errors = await registry.errors();
if (errors.length) {
diff --git a/extension/manifest.json b/extension/manifest.json
index 9a687df..cb74f57 100644
--- a/extension/manifest.json
+++ b/extension/manifest.json
@@ -19,7 +19,7 @@
"page": "repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.html",
"open_in_tab": true
},
- "web_accessible_resources": ["api/*", "dep/*", "icon/*", "repo/*"],
+ "web_accessible_resources": ["env.mjs", "api/*", "dep/*", "icon/*", "repo/*"],
"content_scripts": [
{
"matches": ["https://*.notion.so/*", "https://*.notion.site/*"],
diff --git a/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/hook.mjs b/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/hook.mjs
new file mode 100644
index 0000000..ee8c4b8
--- /dev/null
+++ b/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/hook.mjs
@@ -0,0 +1,38 @@
+/*
+ * 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
+ */
+
+let _$tooltip;
+
+export default function (api, db) {
+ const { web, fmt } = api;
+
+ return {
+ /**
+ * add a tooltip to show extra information on hover
+ * @param {HTMLElement} $ref - the element that will trigger the tooltip when hovered
+ * @param {string} text - the markdown content of the tooltip
+ */
+ tooltip: ($ref, text) => {
+ if (!_$tooltip) {
+ _$tooltip = web.html``;
+ web.render(document.body, _$tooltip);
+ }
+ text = fmt.md.render(text);
+ $ref.addEventListener('mouseover', (event) => {
+ _$tooltip.innerHTML = text;
+ _$tooltip.style.display = 'block';
+ });
+ $ref.addEventListener('mousemove', (event) => {
+ _$tooltip.style.top = event.clientY - _$tooltip.clientHeight + 'px';
+ _$tooltip.style.left = event.clientX - _$tooltip.clientWidth + 'px';
+ });
+ $ref.addEventListener('mouseout', (event) => {
+ _$tooltip.style.display = '';
+ });
+ },
+ };
+}
diff --git a/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/mod.json b/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/mod.json
new file mode 100644
index 0000000..343efc2
--- /dev/null
+++ b/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/mod.json
@@ -0,0 +1,38 @@
+{
+ "name": "components",
+ "id": "36a2ffc9-27ff-480e-84a7-c7700a7d232d",
+ "version": "0.2.0",
+ "description": "notion-style elements reuseable by other mods, inc. tooltips and the side panel.",
+ "tags": ["core"],
+ "authors": [
+ {
+ "name": "dragonwocky",
+ "email": "thedragonring.bod@gmail.com",
+ "homepage": "https://dragonwocky.me/",
+ "avatar": "https://dragonwocky.me/avatar.jpg"
+ },
+ {
+ "name": "CloudHill",
+ "email": "rh.cloudhill@gmail.com",
+ "homepage": "https://github.com/CloudHill",
+ "avatar": "https://avatars.githubusercontent.com/u/54142180"
+ }
+ ],
+ "js": {
+ "hook": "hook.mjs"
+ },
+ "css": {
+ "client": ["tooltip.css", "sidebar.css"],
+ "menu": ["tooltip.css"],
+ "frame": ["tooltip.css"]
+ },
+ "options": [
+ {
+ "type": "hotkey",
+ "key": "side-panel-hotkey",
+ "label": "toggle side panel hotkey",
+ "value": "Ctrl+Alt+\\",
+ "tooltip": "opens the side panel in notion - will only work if a mod is making use of it."
+ }
+ ]
+}
diff --git a/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/sidebar.css b/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/sidebar.css
new file mode 100644
index 0000000..b52afd8
--- /dev/null
+++ b/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/sidebar.css
@@ -0,0 +1,6 @@
+/*
+ * 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/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/tooltip.css b/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/tooltip.css
new file mode 100644
index 0000000..b919963
--- /dev/null
+++ b/extension/repo/components@36a2ffc9-27ff-480e-84a7-c7700a7d232d/tooltip.css
@@ -0,0 +1,25 @@
+/*
+ * notion-enhancer core: components
+ * (c) 2021 dragonwocky (https://dragonwocky.me/)
+ * (https://notion-enhancer.github.io/) under the MIT license
+ */
+
+#enhancer--tooltip {
+ position: absolute;
+ background: var(--theme--ui_tooltip);
+ font-size: 11.5px;
+ padding: 0.15rem 0.4rem;
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
+ border-radius: 3px;
+ max-width: 20rem;
+ display: none;
+}
+#enhancer--tooltip p {
+ margin: 0.25rem 0;
+}
+#enhancer--tooltip p:first-child {
+ color: var(--theme--ui_tooltip-title);
+}
+#enhancer--tooltip p:not(:first-child) {
+ color: var(--theme--ui_tooltip-description);
+}
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/components.mjs b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/blocks.mjs
similarity index 93%
rename from extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/components.mjs
rename to extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/blocks.mjs
index af203fd..472f850 100644
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/components.mjs
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/blocks.mjs
@@ -6,11 +6,11 @@
'use strict';
-import { fmt, web } from '../../api/_.mjs';
+import { api, profileDB } from './loader.mjs';
import { notifications } from './notifications.mjs';
-import { profileDB } from './menu.mjs';
+const { fmt, web, components } = api;
-export const components = {
+export const blocks = {
preview: (url) => web.html`
{
const checked = await profileDB.get([mod.id, opt.key], opt.value),
- $toggle = components.toggle(opt.label, checked),
+ $toggle = blocks.toggle(opt.label, checked),
$tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
$label = $toggle.children[0],
$input = $toggle.children[1];
if (opt.tooltip) {
$label.prepend($tooltip);
- web.tooltip($tooltip, opt.tooltip);
+ components.tooltip($tooltip, opt.tooltip);
}
$input.addEventListener('change', async (event) => {
await profileDB.set([mod.id, opt.key], $input.checked);
@@ -89,7 +89,7 @@ export const options = {
${$options.join('')}
`,
$icon = web.html`${web.icon('chevron-down', { class: 'input-icon' })}`;
- if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+ if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
$select.addEventListener('change', async (event) => {
await profileDB.set([mod.id, opt.key], $select.value);
notifications.onChange();
@@ -105,7 +105,7 @@ export const options = {
),
$input = web.html``,
$icon = web.html`${web.icon('type', { class: 'input-icon' })}`;
- if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+ if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
$input.addEventListener('change', async (event) => {
await profileDB.set([mod.id, opt.key], $input.value);
notifications.onChange();
@@ -121,7 +121,7 @@ export const options = {
),
$input = web.html``,
$icon = web.html`${web.icon('hash', { class: 'input-icon' })}`;
- if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+ if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
$input.addEventListener('change', async (event) => {
await profileDB.set([mod.id, opt.key], $input.value);
notifications.onChange();
@@ -153,7 +153,7 @@ export const options = {
onInput: paint,
onChange: paint,
});
- if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+ if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
$input.addEventListener('change', async (event) => {
await profileDB.set([mod.id, opt.key], $input.value);
notifications.onChange();
@@ -175,7 +175,7 @@ export const options = {
$icon = web.html`${web.icon('file', { class: 'input-icon' })}`,
$filename = web.html`${web.escape(filename || 'none')}`,
$latest = web.render(web.html``, $filename);
- if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+ if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
$input.addEventListener('change', (event) => {
const file = event.target.files[0],
reader = new FileReader();
@@ -208,7 +208,7 @@ export const options = {
),
$input = web.html``,
$icon = web.html`${web.icon('command', { class: 'input-icon' })}`;
- if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+ if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
$input.addEventListener('keydown', async (event) => {
event.preventDefault();
const pressed = [],
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/loader.mjs b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/loader.mjs
new file mode 100644
index 0000000..3db3711
--- /dev/null
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/loader.mjs
@@ -0,0 +1,32 @@
+/*
+ * notion-enhancer core: menu
+ * (c) 2021 dragonwocky (https://dragonwocky.me/)
+ * (https://notion-enhancer.github.io/) under the MIT license
+ */
+
+'use strict';
+
+import * as _api from '../../api/_.mjs';
+export const api = { ..._api },
+ { fs, registry, web } = api;
+
+export const db = await registry.db('a6621988-551d-495a-97d8-3c568bca2e9e'),
+ profileName = await registry.profileName(),
+ profileDB = await registry.profileDB();
+
+const insert = (mod) => {
+ for (const sheet of mod.css?.menu || []) {
+ web.loadStylesheet(`repo/${mod._dir}/${sheet}`);
+ }
+};
+for (const mod of await registry.list((mod) => registry.core.includes(mod.id))) {
+ if (mod.js?.hook) {
+ let script = mod.js.hook;
+ script = await import(fs.localPath(`repo/${mod._dir}/${script}`));
+ api[mod.name] = await script.default(api, await registry.db(mod.id));
+ }
+ await insert(mod);
+}
+for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
+ if (!registry.core.includes(mod.id)) await insert(mod);
+}
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 1208f52..819720b 100644
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.mjs
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.mjs
@@ -6,24 +6,14 @@
'use strict';
-import { env, fs, storage, registry, web } from '../../api/_.mjs';
-
-export const db = await registry.db('a6621988-551d-495a-97d8-3c568bca2e9e'),
- profileName = await registry.profileName(),
- profileDB = await registry.profileDB();
-
+import { api, db, profileName, profileDB } from './loader.mjs';
import './styles.mjs';
import { notifications } from './notifications.mjs';
-import { components, options } from './components.mjs';
+import { blocks, options } from './blocks.mjs';
+const { env, fs, storage, registry, web } = api;
web.addHotkeyListener(await db.get(['hotkey']), env.focusNotion);
-for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
- for (const sheet of mod.css?.menu || []) {
- web.loadStylesheet(`repo/${mod._dir}/${sheet}`);
- }
-}
-
const loadTheme = async () => {
document.documentElement.className =
(await db.get(['theme'], 'light')) === 'dark' ? 'dark' : '';
@@ -204,7 +194,7 @@ const _$modListCache = {},
},
mod: async (mod) => {
const $mod = web.html``,
- $toggle = components.toggle('', await registry.enabled(mod.id));
+ $toggle = blocks.toggle('', await registry.enabled(mod.id));
$toggle.addEventListener('change', async (event) => {
if (event.target.checked && mod.tags.includes('theme')) {
const mode = mod.tags.includes('light') ? 'light' : 'dark',
@@ -233,8 +223,8 @@ const _$modListCache = {},
}
$mod.className = 'mod-selected';
const fragment = [
- web.render(components.title(mod.name), components.version(mod.version)),
- components.tags(mod.tags),
+ web.render(blocks.title(mod.name), blocks.version(mod.version)),
+ blocks.tags(mod.tags),
await generators.options(mod),
];
web.render(web.empty($options), ...fragment);
@@ -244,7 +234,7 @@ const _$modListCache = {},
web.render(
$mod,
mod.preview
- ? components.preview(
+ ? blocks.preview(
mod.preview.startsWith('http')
? mod.preview
: fs.localPath(`repo/${mod._dir}/${mod.preview}`)
@@ -252,10 +242,10 @@ const _$modListCache = {},
: '',
web.render(
web.html``,
- web.render(components.title(mod.name), components.version(mod.version)),
- components.tags(mod.tags),
- components.description(mod.description),
- components.authors(mod.authors),
+ web.render(blocks.title(mod.name), blocks.version(mod.version)),
+ blocks.tags(mod.tags),
+ blocks.description(mod.description),
+ blocks.authors(mod.authors),
mod.environments.includes(env.name) && !registry.core.includes(mod.id)
? $toggle
: ''
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 5ca52fc..305dae6 100644
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/notifications.mjs
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/notifications.mjs
@@ -6,10 +6,9 @@
'use strict';
-import { env, fs, storage, fmt, registry, web } from '../../api/_.mjs';
-const db = await registry.db('a6621988-551d-495a-97d8-3c568bca2e9e');
-
+import { api } from './loader.mjs';
import { tw } from './styles.mjs';
+const { env, fs, storage, fmt, registry, web } = api;
export const notifications = {
$container: web.html``,
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/router.mjs b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/router.mjs
index 8a5e70e..6ea1353 100644
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/router.mjs
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/router.mjs
@@ -6,7 +6,8 @@
'use strict';
-import { web } from '../../api/_.mjs';
+import { api } from './loader.mjs';
+const { web } = api;
let _defaultView = '';
const _views = new Map();
diff --git a/extension/repo/registry.json b/extension/repo/registry.json
index 4aaac80..7977fb3 100644
--- a/extension/repo/registry.json
+++ b/extension/repo/registry.json
@@ -1,6 +1,7 @@
[
"menu@a6621988-551d-495a-97d8-3c568bca2e9e",
"theming@0f0bf8b6-eae6-4273-b307-8fc43f2ee082",
+ "components@36a2ffc9-27ff-480e-84a7-c7700a7d232d",
"tweaks@5174a483-c88d-4bf8-a95f-35cd330b76e2",
"bypass-preview@cb6fd684-f113-4a7a-9423-8f0f0cff069f",
"calendar-scroll@b1c7db33-dfee-489a-a76c-0dd66f7ed29a"