diff --git a/bin.mjs b/bin.mjs index 0bfbdfd..ad32701 100755 --- a/bin.mjs +++ b/bin.mjs @@ -13,14 +13,14 @@ import { createRequire } from "node:module"; import { getAppPath, getBackupPath, - getCachePath, + getConfigPath, checkEnhancementVersion, setNotionPath, unpackApp, applyEnhancements, takeBackup, restoreBackup, - removeCache, + removeConfig, } from "./scripts/enhance-desktop-app.mjs"; import { existsSync } from "node:fs"; const nodeRequire = createRequire(import.meta.url), @@ -201,7 +201,7 @@ try { const appPath = getAppPath(), backupPath = getBackupPath(), - cachePath = getCachePath(), + configPath = getConfigPath(), insertVersion = checkEnhancementVersion(); const messages = { @@ -223,9 +223,9 @@ try { then install a vanilla version of the app from https://www.notion.so/desktop (mac, windows) or ${manifest.homepage}/getting-started/installation (linux)`, - "cache-found": `cache found`, - "cache-not-found": `cache not found: nothing to remove`, - "prompt-cache-removal": `remove?`, + "config-found": `config found`, + "config-not-found": `config not found: nothing to remove`, + "prompt-config-removal": `remove?`, }; const SUCCESS = chalk`{bold.whiteBright SUCCESS} {green ✔}`, FAILURE = chalk`{bold.whiteBright FAILURE} {red ✘}`, @@ -309,17 +309,16 @@ try { print` {grey * ${messages["notion-found"]}: ${messages["not-applied"]}}\n`; return SUCCESS; }, - promptCacheRemoval = async () => { - // optionally remove ~/.notion-enhancer - if (existsSync(cachePath)) { - print` {grey * ${messages["cache-found"]}: ${cachePath}}\n`; - if (["Y", "y"].includes(await promptConfirmation(messages["prompt-cache-removal"]))) { + promptConfigRemoval = async () => { + if (existsSync(configPath)) { + print` {grey * ${messages["config-found"]}: ${configPath}}\n`; + if (["Y", "y"].includes(await promptConfirmation(messages["prompt-config-removal"]))) { print` `; startSpinner(); - await removeCache(); + await removeConfig(); stopSpinner(); } else print`\n`; - } else print` {grey * ${messages["cache-not-found"]}}\n`; + } else print` {grey * ${messages["config-not-found"]}}\n`; }; switch (args["_"][0]) { @@ -333,7 +332,7 @@ try { case "remove": { print`{bold.whiteBright [NOTION-ENHANCER] REMOVE}\n`; const res = await interactiveRemoveEnhancements(); - await promptCacheRemoval(); + await promptConfigRemoval(); print`${res}\n`; break; } @@ -342,8 +341,8 @@ try { printObject({ appPath, backupPath, - cachePath, - cacheExists: existsSync(cachePath), + configPath, + configExists: existsSync(configPath), insertVersion, currentVersion: manifest.version, }); diff --git a/scripts/enhance-desktop-app.mjs b/scripts/enhance-desktop-app.mjs index c962126..6833abb 100755 --- a/scripts/enhance-desktop-app.mjs +++ b/scripts/enhance-desktop-app.mjs @@ -15,7 +15,7 @@ import { createRequire } from "node:module"; import patch from "./patch-desktop-app.mjs"; -let __notionResources, __enhancerCache; +let __notionResources, __enhancerConfig; const nodeRequire = createRequire(import.meta.url), manifest = nodeRequire("../package.json"), platform = @@ -89,11 +89,11 @@ const setNotionPath = (path) => { // prefer unpacked if both exist getAppPath = () => ["app", "app.asar"].map(getResourcePath).find(existsSync), getBackupPath = () => ["app.bak", "app.asar.bak"].map(getResourcePath).find(existsSync), - getCachePath = () => { - if (__enhancerCache) return __enhancerCache; + getConfigPath = () => { + if (__enhancerConfig) return __enhancerConfig; const home = platform === "wsl" ? polyfillWslEnv("HOMEPATH") : os.homedir(); - __enhancerCache = resolve(`${home}/.notion-enhancer`); - return __enhancerCache; + __enhancerConfig = resolve(`${home}/.notion-enhancer.db`); + return __enhancerConfig; }, checkEnhancementVersion = () => { const manifestPath = getResourcePath("app/node_modules/notion-enhancer/package.json"); @@ -172,9 +172,9 @@ const unpackApp = async () => { if (destPath !== appPath) await fsp.rm(appPath, { recursive: true }); return true; }, - removeCache = async () => { - if (!existsSync(getCachePath())) return; - await fsp.rm(getCachePath()); + removeConfig = async () => { + if (!existsSync(getConfigPath())) return; + await fsp.rm(getConfigPath()); return true; }; @@ -182,12 +182,12 @@ export { getResourcePath, getAppPath, getBackupPath, - getCachePath, + getConfigPath, checkEnhancementVersion, setNotionPath, unpackApp, applyEnhancements, takeBackup, restoreBackup, - removeCache, + removeConfig, }; diff --git a/src/electron/electronApi.cjs b/src/electron/electronApi.cjs deleted file mode 100644 index 0f3a69a..0000000 --- a/src/electron/electronApi.cjs +++ /dev/null @@ -1,169 +0,0 @@ -/** - * notion-enhancer - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -const os = require('os'), - path = require('path'), - fs = require('fs'), - _cacheFile = path.resolve(`${os.homedir()}/.notion-enhancer`), - _fsQueue = new Set(), - _onDbChangeListeners = []; - -// handle leftover cache from prev versions -if (fs.existsSync(_cacheFile) && fs.lstatSync(_cacheFile).isDirectory()) { - fs.rmdirSync(_cacheFile); -} - -const isRenderer = process && process.type === 'renderer'; - -// things are a little weird here: -// multiple processes performing file ops at once -// (e.g. when too many windows/tabs are open) -// = an empty string is returned the cache contents -// and the db is reset. this loop roughly addresses that. - -// a "real" db might be better, but sql or query-based -// would be incompatible with the chrome ext. -// -- lowdb might have been a nice flat/json db, -// but unfortunately it is esm only - -const getData = async () => { - if (!fs.existsSync(_cacheFile)) { - fs.writeFileSync(_cacheFile, '{}', 'utf8'); - return {}; - } - - let cacheBuffer = '', - jsonData = {}, - attemptsRemaining = 3; - while (attemptsRemaining) { - cacheBuffer = fs.readFileSync(_cacheFile); - if (cacheBuffer) { - try { - jsonData = JSON.parse(cacheBuffer); - break; - } catch { - jsonData = {}; - } - } - --attemptsRemaining || (await new Promise((res, rej) => setTimeout(res, 50))); - } - return jsonData; - }, - saveData = (data) => fs.writeFileSync(_cacheFile, JSON.stringify(data)), - performFsOperation = async (callback) => { - while (_fsQueue.size) await new Promise(requestIdleCallback); - const op = Symbol(); - _fsQueue.add(op); - const res = await callback(); - _fsQueue.delete(op); - return res; - }; - -const db = { - get: async (path, fallback = undefined) => { - if (!path.length) return fallback; - while (_fsQueue.size) await new Promise(requestIdleCallback); - const values = await getData(); - let value = values; - while (path.length) { - if (value === undefined) { - value = fallback; - break; - } - value = value[path.shift()]; - } - return value ?? fallback; - }, - set: async (path, value) => { - if (!path.length) return undefined; - return await performFsOperation(async () => { - const pathClone = [...path], - values = await getData(); - let pointer = values, - old; - while (path.length) { - const key = path.shift(); - if (!path.length) { - old = pointer[key]; - pointer[key] = value; - break; - } - pointer[key] = pointer[key] ?? {}; - pointer = pointer[key]; - } - saveData(values); - _onDbChangeListeners.forEach((listener) => - listener({ path: pathClone, new: value, old }) - ); - return value; - }); - }, - addChangeListener: (callback) => { - _onDbChangeListeners.push(callback); - }, - removeChangeListener: (callback) => { - _onDbChangeListeners = _onDbChangeListeners.filter((listener) => listener !== callback); - }, -}; - -const ipcRenderer = { - sendMessage: (channel, data = undefined, namespace = 'notion-enhancer') => { - const { ipcRenderer } = require('electron'); - channel = namespace ? `${namespace}:${channel}` : channel; - ipcRenderer.send(channel, data); - }, - sendMessageToHost: (channel, data = undefined, namespace = 'notion-enhancer') => { - const { ipcRenderer } = require('electron'); - channel = namespace ? `${namespace}:${channel}` : channel; - ipcRenderer.sendToHost(channel, data); - }, - onMessage: (channel, callback, namespace = 'notion-enhancer') => { - const { ipcRenderer } = require('electron'); - channel = namespace ? `${namespace}:${channel}` : channel; - ipcRenderer.on(channel, callback); - }, -}; - -globalThis.__enhancerElectronApi = { - platform: process.platform, - version: require('notion-enhancer/package.json').version, - db, - - browser: isRenderer ? require('electron').remote.getCurrentWindow() : {}, - webFrame: isRenderer ? require('electron').webFrame : {}, - notionRequire: (path) => require(`../../${path}`), - notionPath: (path) => require('path').resolve(`${__dirname}/../../${path}`), - nodeRequire: (path) => require(path), - - focusMenu: () => { - if (isRenderer) return ipcRenderer.sendMessage('focusMenu'); - const { focusMenu } = require('notion-enhancer/worker.cjs'); - return focusMenu(); - }, - focusNotion: () => { - if (isRenderer) return ipcRenderer.sendMessage('focusNotion'); - const { focusNotion } = require('notion-enhancer/worker.cjs'); - return focusNotion(); - }, - reload: () => { - if (isRenderer) return ipcRenderer.sendMessage('reload'); - const { reload } = require('notion-enhancer/worker.cjs'); - return reload(); - }, - - getNotionWindows: () => { - const { getNotionWindows } = require('notion-enhancer/worker.cjs'); - return getNotionWindows(); - }, - getFocusedNotionWindow: () => { - const { getFocusedNotionWindow } = require('notion-enhancer/worker.cjs'); - return getFocusedNotionWindow(); - }, - - ipcRenderer, -}; diff --git a/src/electron/env/env.mjs b/src/electron/env/env.mjs deleted file mode 100644 index 31f13bd..0000000 --- a/src/electron/env/env.mjs +++ /dev/null @@ -1,41 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** environment-specific methods and constants */ - -/** - * the environment/platform name code is currently being executed in - * @constant - * @type {string} - */ -export const name = globalThis.__enhancerElectronApi.platform; - -/** - * the current version of the enhancer - * @constant - * @type {string} - */ -export const version = globalThis.__enhancerElectronApi.version; - -/** - * open the enhancer's menu - * @type {function} - */ -export const focusMenu = globalThis.__enhancerElectronApi.focusMenu; - -/** - * focus an active notion tab - * @type {function} - */ -export const focusNotion = globalThis.__enhancerElectronApi.focusNotion; - -/** - * reload all notion and enhancer menu tabs to apply changes - * @type {function} - */ -export const reload = globalThis.__enhancerElectronApi.reload; diff --git a/src/electron/env/fs.mjs b/src/electron/env/fs.mjs deleted file mode 100644 index 35feb82..0000000 --- a/src/electron/env/fs.mjs +++ /dev/null @@ -1,81 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** environment-specific file reading */ - -/** - * get an absolute path to files within notion - * @param {string} path - relative to the root notion/resources/app/ e.g. renderer/search.js - * @process electron - */ -export const notionPath = globalThis.__enhancerElectronApi.notionPath; - -/** - * transform a path relative to the enhancer root directory into an absolute path - * @param {string} path - a url or within-the-enhancer filepath - * @returns {string} an absolute filepath - */ -export const localPath = (path) => `notion://www.notion.so/__notion-enhancer/${path}`; - -/** - * fetch and parse a json file's contents - * @param {string} path - a url or within-the-enhancer filepath - * @param {object=} opts - the second argument of a fetch() request - * @returns {object} the json value of the requested file as a js object - */ -export const getJSON = (path, opts = {}) => { - path = path.replace(/^https:\/\/www\.notion\.so\//, 'notion://www.notion.so/'); - const networkPath = path.startsWith('http') || path.startsWith('notion://'); - if (networkPath) return fetch(path, opts).then((res) => res.json()); - try { - return globalThis.__enhancerElectronApi.nodeRequire(`notion-enhancer/${path}`); - } catch { - return fetch(localPath(path), opts).then((res) => res.json()); - } -}; - -/** - * fetch a text file's contents - * @param {string} path - a url or within-the-enhancer filepath - * @param {object=} opts - the second argument of a fetch() request - * @returns {string} the text content of the requested file - */ -export const getText = (path, opts = {}) => { - path = path.replace(/^https:\/\/www\.notion\.so\//, 'notion://www.notion.so/'); - const networkPath = path.startsWith('http') || path.startsWith('notion://'); - if (networkPath) return fetch(path, opts).then((res) => res.text()); - try { - const fs = globalThis.__enhancerElectronApi.nodeRequire('fs'); - return fs.readFileSync(notionPath(`notion-enhancer/${path}`)); - } catch { - return fetch(localPath(path), opts).then((res) => res.text()); - } -}; - -/** - * check if a file exists - * @param {string} path - a url or within-the-enhancer filepath - * @returns {boolean} whether or not the file exists - */ -export const isFile = async (path) => { - try { - const fs = globalThis.__enhancerElectronApi.nodeRequire('fs'); - if (path.startsWith('http')) { - await fetch(path); - } else { - try { - fs.existsSync(notionPath(`notion-enhancer/${path}`)); - } catch { - await fetch(localPath(path)); - } - } - return true; - } catch { - return false; - } -}; diff --git a/src/electron/env/storage.mjs b/src/electron/env/storage.mjs deleted file mode 100644 index 5cca13a..0000000 --- a/src/electron/env/storage.mjs +++ /dev/null @@ -1,69 +0,0 @@ -/** - * notion-enhancer: api - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -/** environment-specific data persistence */ - -/** - * get persisted data - * @param {string[]} path - the path of keys to the value being fetched - * @param {unknown=} fallback - a default value if the path is not matched - * @returns {Promise} value ?? fallback - */ -export const get = (path, fallback = undefined) => { - return globalThis.__enhancerElectronApi.db.get(path, fallback); -}; - -/** - * persist data - * @param {string[]} path - the path of keys to the value being set - * @param {unknown} value - the data to save - * @returns {Promise} resolves when data has been saved - */ -export const set = (path, value) => { - return globalThis.__enhancerElectronApi.db.set(path, value); -}; - -/** - * create a wrapper for accessing a partition of the storage - * @param {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 = (namespace, getFunc = get, setFunc = set) => { - if (typeof namespace === 'string') namespace = [namespace]; - return { - get: (path = [], fallback = undefined) => getFunc([...namespace, ...path], fallback), - set: (path, value) => setFunc([...namespace, ...path], value), - }; -}; - -/** - * add an event listener for changes in storage - * @param {onStorageChangeCallback} callback - called whenever a change in - * storage is initiated from the current process - */ -export const addChangeListener = (callback) => { - return globalThis.__enhancerElectronApi.db.addChangeListener(callback); -}; - -/** - * remove a listener added with storage.addChangeListener - * @param {onStorageChangeCallback} callback - */ -export const removeChangeListener = (callback) => { - return globalThis.__enhancerElectronApi.db.removeChangeListener(callback); -}; - -/** - * @callback onStorageChangeCallback - * @param {object} event - * @param {string} event.path- the path of keys to 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 - */ diff --git a/src/electron/frame.mjs b/src/electron/frame.mjs deleted file mode 100644 index 5fd42a3..0000000 --- a/src/electron/frame.mjs +++ /dev/null @@ -1,28 +0,0 @@ -/** - * notion-enhancer - * (c) 2021 dragonwocky (https://dragonwocky.me/) - * (https://notion-enhancer.github.io/) under the MIT license - */ - -'use strict'; - -(async () => { - const api = await import('./api/index.mjs'), - { fs, registry, web } = api; - - for (const mod of await registry.list((mod) => registry.enabled(mod.id))) { - for (const sheet of mod.css?.frame || []) { - web.loadStylesheet(`repo/${mod._dir}/${sheet}`); - } - for (let script of mod.js?.frame || []) { - 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) { - console.error('[notion-enhancer] registry errors:'); - console.table(errors); - } - } -})(); diff --git a/src/electron/init.cjs b/src/electron/init.cjs index 3bb2c44..5f60c8e 100644 --- a/src/electron/init.cjs +++ b/src/electron/init.cjs @@ -1,46 +1,50 @@ /** * notion-enhancer - * (c) 2021 dragonwocky (https://dragonwocky.me/) + * (c) 2022 dragonwocky (https://dragonwocky.me/) * (https://notion-enhancer.github.io/) under the MIT license */ "use strict"; -module.exports = async function (target, __exports, __eval) { - require("notion-enhancer/electronApi.cjs"); - const api = require("notion-enhancer/api/index.cjs"), - { registry } = api; +module.exports = async (target, __exports, __eval) => { + // if (target === "renderer/preload") { + const { initDatabase } = require("./node.cjs"); - if (target === "renderer/index") { - document.addEventListener("readystatechange", (event) => { - if (document.readyState !== "complete") return false; - const script = document.createElement("script"); - script.type = "module"; - script.src = api.fs.localPath("frame.mjs"); - document.head.appendChild(script); - }); - } + // require("notion-enhancer/electronApi.cjs"); + // const api = require("notion-enhancer/api/index.cjs"), + // { registry } = api; - if (target === "renderer/preload") { - document.addEventListener("readystatechange", (event) => { - if (document.readyState !== "complete") return false; - const script = document.createElement("script"); - script.type = "module"; - script.src = api.fs.localPath("client.mjs"); - document.head.appendChild(script); - }); - } + // if (target === "renderer/index") { + // document.addEventListener("readystatechange", (event) => { + // if (document.readyState !== "complete") return false; + // const script = document.createElement("script"); + // script.type = "module"; + // script.src = api.fs.localPath("frame.mjs"); + // document.head.appendChild(script); + // }); + // } - if (target === "main/main") { - const { app } = require("electron"); - app.whenReady().then(require("notion-enhancer/worker.cjs").listen); - } + // if (target === "renderer/preload") { + const db = initDatabase("config"); + // document.addEventListener("readystatechange", (event) => { + // if (document.readyState !== "complete") return false; + // const script = document.createElement("script"); + // script.type = "module"; + // script.src = api.fs.localPath("client.mjs"); + // document.head.appendChild(script); + // }); + // } - for (const mod of await registry.list((mod) => registry.enabled(mod.id))) { - for (const { source, target: scriptTarget } of (mod.js ? mod.js.electron : []) || []) { - if (`${target}.js` !== scriptTarget) continue; - const script = require(`notion-enhancer/repo/${mod._dir}/${source}`); - script(api, await registry.db(mod.id), __exports, __eval); - } - } + // if (target === "main/main") { + // const { app } = require("electron"); + // app.whenReady().then(require("notion-enhancer/worker.cjs").listen); + // } + + // for (const mod of await registry.list((mod) => registry.enabled(mod.id))) { + // for (const { source, target: scriptTarget } of (mod.js ? mod.js.electron : []) || []) { + // if (`${target}.js` !== scriptTarget) continue; + // const script = require(`notion-enhancer/repo/${mod._dir}/${source}`); + // script(api, await registry.db(mod.id), __exports, __eval); + // } + // } }; diff --git a/src/electron/node.cjs b/src/electron/node.cjs new file mode 100644 index 0000000..aba7323 --- /dev/null +++ b/src/electron/node.cjs @@ -0,0 +1,67 @@ +/** + * notion-enhancer + * (c) 2022 dragonwocky (https://dragonwocky.me/) + * (https://notion-enhancer.github.io/) under the MIT license + */ + +"use strict"; + +const os = require("os"), + path = require("path"), + electron = require("electron"), + sqlite = require("better-sqlite3"); + +const notionRequire = (target) => require(`../../../${target}`), + notionPath = (target) => path.resolve(`${__dirname}/../../../${target}`), + notionPlatform = process.platform; + +const enhancerRequire = (target) => require(`../${target}`), + enhancerPath = (target) => path.resolve(`${__dirname}/../${target}`), + enhancerUrl = (target) => `notion://www.notion.so/__notion-enhancer/${target}`, + enhancerVersion = enhancerRequire("package.json").version, + enhancerConfig = path.resolve(`${os.homedir()}/.notion-enhancer.db`); + +const reloadApp = () => { + const args = process.argv.slice(1).filter((arg) => arg !== "--startup"); + electron.app.relaunch({ args }); + electron.app.exit(); +}; + +let __db; +const initDatabase = (table) => { + const db = __db ?? sqlite(enhancerConfig), + init = db.prepare(`CREATE TABLE IF NOT EXISTS ${table} ( + key TEXT PRIMARY KEY, + value TEXT, + mtime INTEGER + )`); + init.run(); + __db = db; + + const insert = db.prepare(`INSERT INTO ${table} (key, value, mtime) VALUES (?, ?, ?)`), + update = db.prepare(`UPDATE ${table} SET value = ?, mtime = ? WHERE key = ?`), + select = db.prepare(`SELECT * FROM ${table} WHERE key = ? LIMIT 1`), + dump = db.prepare(`SELECT * FROM ${table}`); + + return { + get: (key) => select.get(key)?.value, + set: (key, value) => { + if (select.get(key)) return update.run(value, key, Date.now()); + else return insert.run(key, value, Date.now()); + }, + dump: () => dump.all(), + }; +}; + +module.exports = { + notionRequire, + notionPath, + notionPlatform, + enhancerRequire, + enhancerPath, + enhancerUrl, + enhancerVersion, + enhancerConfig, + reloadApp, + initDatabase, +}; diff --git a/src/mods/.github/workflows/update-parents.yml b/src/mods/.github/workflows/update-parents.yml deleted file mode 100644 index ac428e4..0000000 --- a/src/mods/.github/workflows/update-parents.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: 'update parent repositories' - -on: - push: - branches: - - dev - -jobs: - sync: - name: update parent - runs-on: ubuntu-latest - strategy: - matrix: - repo: ['notion-enhancer/extension', 'notion-enhancer/desktop'] - steps: - - name: checkout repo - uses: actions/checkout@v2 - with: - token: ${{ secrets.CI_TOKEN }} - submodules: true - repository: ${{ matrix.repo }} - - name: pull updates - run: | - git pull --recurse-submodules - git submodule update --remote --recursive - - name: commit changes - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: '[${{ github.event.repository.name }}] ${{ github.event.head_commit.message }}' diff --git a/src/mods/LICENSE b/src/mods/LICENSE deleted file mode 100644 index b503961..0000000 --- a/src/mods/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 dragonwocky (https://dragonwocky.me/) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/src/mods/README.md b/src/mods/README.md deleted file mode 100644 index 0885816..0000000 --- a/src/mods/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# notion-enhancer/repo - -the collection of mods run by the notion-enhancer - -[read the docs online](https://notion-enhancer.github.io/getting-started/features)