replace hook with pseudo-mod, env folder = simpler documentation

This commit is contained in:
dragonwocky 2021-10-02 12:31:07 +10:00
parent a7549cd9db
commit 33e8907d4f
23 changed files with 284 additions and 162 deletions

View File

@ -9,18 +9,17 @@
/** @module notion-enhancer/api */
/** environment-specific methods and constants */
import * as env from './env.mjs';
export * as env from './env.mjs';
/** environment-specific filesystem reading */
const fs = env.name === 'extension' ? await import('./extension-fs.mjs') : {};
export * as fs from './fs.mjs';
/** environment-specific data persistence */
const storage = env.name === 'extension' ? await import('./extension-storage.mjs') : {};
export * as storage from './storage.mjs';
/** helpers for formatting, validating and parsing values */
import * as fmt from './fmt.mjs';
export * as fmt from './fmt.mjs';
/** interactions with the enhancer's repository of mods */
import * as registry from './registry.mjs';
export * as registry from './registry.mjs';
/** helpers for manipulation of a webpage */
import * as web from './web.mjs';
export { env, fs, storage, fmt, registry, web };
export * as web from './web.mjs';
/** notion-style elements inc. the sidebar */
export * as components from './components/_.mjs';

View File

@ -0,0 +1,21 @@
/*
* notion-enhancer: api
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (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
*/
/**
* 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 { tooltip } from './tooltip.mjs';
export { side } from './tooltip.mjs';

View File

@ -0,0 +1,24 @@
/*
* notion-enhancer: api
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (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`<div id="enhancer--sidebar"></div>`;
web.render(document.body, _$sidebar);
}
};

View File

@ -0,0 +1,41 @@
/*
* notion-enhancer: api
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (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/tooltip
*/
import { fmt, web } from '../_.mjs';
let _$tooltip;
/**
* 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) {
web.loadStylesheet('api/components/tooltip.css');
_$tooltip = web.html`<div id="enhancer--tooltip"></div>`;
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 = '';
});
};

View File

@ -11,7 +11,7 @@
* @module notion-enhancer/api/env
*/
import env from '../env.mjs';
import * as env from '../env/env.mjs';
/**
* the environment/platform name code is currently being executed in

46
extension/api/fs.mjs Normal file
View File

@ -0,0 +1,46 @@
/*
* notion-enhancer: api
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
/**
* environment-specific filesystem reading
* @module notion-enhancer/api/fs
*/
import * as fs from '../env/fs.mjs';
/**
* transform a path relative to the enhancer root directory into an absolute path
* @type {function}
* @param {string} path - a url or within-the-enhancer filepath
* @returns {string} an absolute filepath
*/
export const localPath = fs.localPath;
/**
* fetch and parse a json file's contents
* @type {function}
* @param {string} path - a url or within-the-enhancer filepath
* @returns {object} the json value of the requested file as a js object
*/
export const getJSON = fs.getJSON;
/**
* fetch a text file's contents
* @type {function}
* @param {string} path - a url or within-the-enhancer filepath
* @returns {string} the text content of the requested file
*/
export const getText = fs.getText;
/**
* check if a file exists
* @type {function}
* @param {string} path - a url or within-the-enhancer filepath
* @returns {boolean} whether or not the file exists
*/
export const isFile = fs.isFile;

View File

@ -148,22 +148,6 @@ 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;
});
},

67
extension/api/storage.mjs Normal file
View File

@ -0,0 +1,67 @@
/*
* notion-enhancer: api
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
/**
* environment-specific data persistence
* @module notion-enhancer/api/storage
*/
import * as storage from '../env/storage.mjs';
/**
* get persisted data
* @type {function}
* @param {array<string>} path - the path of keys to the value being fetched
* @param {*} [fallback] - a default value if the path is not matched
* @returns {Promise} value ?? fallback
*/
export const get = storage.get;
/**
* persist data
* @type {function}
* @param {array<string>} path - the path of keys to the value being set
* @param {*} value - the data to save
* @returns {Promise} resolves when data has been saved
*/
export const set = storage.set;
/**
* create a wrapper for accessing a partition of the storage
* @type {function}
* @param {array<string>} namespace - the path of keys to prefix all storage requests with
* @param {function} [get] - the storage get function to be wrapped
* @param {function} [set] - the storage set function to be wrapped
* @returns {object} an object with the wrapped get/set functions
*/
export const db = storage.db;
/**
* add an event listener for changes in storage
* @type {function}
* @param {onStorageChangeCallback} callback - called whenever a change in
* storage is initiated from the current process
*/
export const addChangeListener = storage.addChangeListener;
/**
* remove a listener added with storage.addChangeListener
* @type {function}
* @param {onStorageChangeCallback} callback
*/
export const removeChangeListener = storage.removeChangeListener;
/**
* @callback onStorageChangeCallback
* @param {object} event
* @param {string} event.type - 'set' or 'reset'
* @param {string} event.namespace- the name of the store, e.g. a mod id
* @param {string} [event.key] - the key associated with the changed value
* @param {string} [event.new] - the new value being persisted to the store
* @param {string} [event.old] - the previous value associated with the key
*/

View File

@ -1,24 +0,0 @@
/*
* notion-enhancer: api
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
/**
* environment-specific methods and constants
* @module notion-enhancer/api/env
*/
const focusMenu = () => chrome.runtime.sendMessage({ action: 'focusMenu' }),
focusNotion = () => chrome.runtime.sendMessage({ action: 'focusNotion' }),
reload = () => chrome.runtime.sendMessage({ action: 'reload' });
export default {
name: 'extension',
version: chrome.runtime.getManifest().version,
focusMenu,
focusNotion,
reload,
};

44
extension/env/env.mjs vendored Normal file
View File

@ -0,0 +1,44 @@
/*
* notion-enhancer: api
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
/**
* environment-specific methods and constants
* @module notion-enhancer/api/env
*/
/**
* the environment/platform name code is currently being executed in
* @constant
* @type {string}
*/
export const name = 'extension';
/**
* the current version of the enhancer
* @constant
* @type {string}
*/
export const version = chrome.runtime.getManifest().version;
/**
* open the enhancer's menu
* @type {function}
*/
export const focusMenu = () => chrome.runtime.sendMessage({ action: 'focusMenu' });
/**
* focus an active notion tab
* @type {function}
*/
export const focusNotion = () => chrome.runtime.sendMessage({ action: 'focusNotion' });
/**
* reload all notion and enhancer menu tabs to apply changes
* @type {function}
*/
export const reload = () => chrome.runtime.sendMessage({ action: 'reload' });

View File

@ -13,28 +13,16 @@
page = location.pathname.split(/[/-]/g).reverse()[0].length === 32;
if (site || page) {
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);
}
import(chrome.runtime.getURL('api/_.mjs')).then(async (api) => {
const { fs, registry, web } = api;
for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
if (!registry.core.includes(mod.id)) await insert(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));
}
}
const errors = await registry.errors();
if (errors.length) {

View File

@ -19,7 +19,7 @@
"page": "repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.html",
"open_in_tab": true
},
"web_accessible_resources": ["env.mjs", "api/*", "dep/*", "icon/*", "repo/*"],
"web_accessible_resources": ["env/*", "api/*", "dep/*", "icon/*", "repo/*"],
"content_scripts": [
{
"matches": ["https://*.notion.so/*", "https://*.notion.site/*"],

View File

@ -1,38 +0,0 @@
/*
* notion-enhancer core: components
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (c) 2021 CloudHill <rl.cloudhill@gmail.com> (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`<div id="enhancer--tooltip"></div>`;
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 = '';
});
},
};
}

View File

@ -1,8 +1,9 @@
{
"__comment": "pseudo-mod to allow configuration of API-provided components",
"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.",
"description": "notion-style elements reused by other mods, inc. the sidebar.",
"tags": ["core"],
"authors": [
{
@ -18,21 +19,15 @@
"avatar": "https://avatars.githubusercontent.com/u/54142180"
}
],
"js": {
"hook": "hook.mjs"
},
"css": {
"client": ["tooltip.css", "sidebar.css"],
"menu": ["tooltip.css"],
"frame": ["tooltip.css"]
},
"js": {},
"css": {},
"options": [
{
"type": "hotkey",
"key": "side-panel-hotkey",
"label": "toggle side panel hotkey",
"label": "toggle enhancer sidebar hotkey",
"value": "Ctrl+Alt+\\",
"tooltip": "opens the side panel in notion - will only work if a mod is making use of it."
"tooltip": "opens/closes the extra sidebar in notion - will only work if a mod is making use of it."
}
]
}

View File

@ -6,9 +6,9 @@
'use strict';
import { api, profileDB } from './loader.mjs';
import { fmt, web, registry, components } from '../../api/_.mjs';
import { notifications } from './notifications.mjs';
const { fmt, web, components } = api;
const profileDB = await registry.profileDB();
export const blocks = {
preview: (url) => web.html`<img

View File

@ -1,32 +0,0 @@
/*
* notion-enhancer core: menu
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (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);
}

View File

@ -6,11 +6,20 @@
'use strict';
import { api, db, profileName, profileDB } from './loader.mjs';
import './styles.mjs';
import { env, fs, storage, registry, web } from '../../api/_.mjs';
import { notifications } from './notifications.mjs';
import { blocks, options } from './blocks.mjs';
const { env, fs, storage, registry, web } = api;
import './styles.mjs';
const db = await registry.db('a6621988-551d-495a-97d8-3c568bca2e9e'),
profileName = await registry.profileName(),
profileDB = await registry.profileDB();
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}`);
}
}
web.addHotkeyListener(await db.get(['hotkey']), env.focusNotion);

View File

@ -6,9 +6,8 @@
'use strict';
import { api } from './loader.mjs';
import { env, fs, storage, fmt, registry, web } from '../../api/_.mjs';
import { tw } from './styles.mjs';
const { env, fs, storage, fmt, registry, web } = api;
export const notifications = {
$container: web.html`<div class="notifications-container"></div>`,

View File

@ -6,8 +6,7 @@
'use strict';
import { api } from './loader.mjs';
const { web } = api;
import { web } from '../../api/_.mjs';
let _defaultView = '';
const _views = new Map();