This commit is contained in:
dragonwocky 2021-12-31 20:47:46 +11:00
commit 5b8f37f226
65 changed files with 107 additions and 6827 deletions

View File

@ -0,0 +1,20 @@
name: 'update submodules'
on:
workflow_dispatch:
jobs:
sync:
name: 'update submodules'
runs-on: ubuntu-latest
steps:
- name: checkout repo
uses: actions/checkout@v2
with:
submodules: true
- name: pull updates
run: |
git pull --recurse-submodules
git submodule update --remote --recursive
- name: commit changes
uses: stefanzweifel/git-auto-commit-action@v4

13
extension/.gitmodules vendored
View File

@ -1,3 +1,16 @@
[submodule "api"]
path = api
url = git@github.com:notion-enhancer/api.git
branch = dev
[submodule "repo"]
path = repo
url = git@github.com:notion-enhancer/repo.git
branch = dev
[submodule "media"]
path = media
url = git@github.com:notion-enhancer/media.git
branch = main
[submodule "dep"]
path = dep
url = git@github.com:notion-enhancer/dep.git
branch = main

View File

@ -1,361 +0,0 @@
# changelog
### v0.11.0 (dev)
a complete rework of the enhancer including a port to the browser as a chrome extension.
- new: cross-environment and properly documented api to replace helpers.
- new: cross-environment mod loader structure.
- new: notifications sourced from an online endpoint for sending global user alerts.
- new: simplify user installs by depending on the chrome web store and [notion-repackaged](https://github.com/notion-enhancer/notion-repackaged).
- new: separate menu profiles for mod configurations.
- new: a hotkey option type that allows typing in/pressing a hotkey to enter it, instead of typing.
- improved: split the core mod into separate mods for specific features.
- improved: theming variables that are more specific, less laggy, and less complicated.
- improved: merged bracketed-links into tweaks.
- improved: a redesigned menu with nicer ui, separate categories for mods and a sidebar for configuration.
- removed: integrated scrollbar tweak (notion now includes by default).
- removed: js insert. css insert moved to tweaks mod.
- removed: majority of layout and font size variables - better to leave former to notion and use `ctrl +` for latter.
- bugfix: bypass csp restrictions.
**below this point the enhancer was desktop-only. in v0.11.0 it was been ported to also**
**run as a chrome extension. changes made to both are indicated above.**
### v0.10.2 (2020-12-05)
again, an emergency release for bugfixes.
not properly documented and new features have not yet been fully reviewed/edited.
- new: side panel - adds an extra sidebar on the right for use by other mods,
toggleable with `ctrl+shift+backslash`.
- improved: notion icons uses spritesheets for faster loading of icons.
- improved: icon sets can be hidden/toggled.
- improved: toggles in the enhancer menu follow the same style as notion's toggles.
- improved: separate quote font variable & option in the font chooser mod (`--theme_[dark|light]--font_quote`).
- improved: option to hide the "page details" text for the word counter extension.
- bugfix: notion icons tab is now visible in fullpage databases.
- bugfix: code line numbers handles wrapped code blocks.
- bugfix: file explorer no longer opens when enhancer menu is opened.
- bugfix: enable the remote module in webviews (windows/tabs) for compatibility with the
updated version of electron used by new notion builds (>= 2.0.10).
- bugfix: add support for enhancing an `app` folder if there is no `app.asar` file present.
- extension: "outliner" = table of contents in right sidebar.
- extension: "panel sites" = embed sites on the site panel.
- extension: "indentation lines" = adds vertical relationship lines to make list trees easier to follow.
- extension: "truncated table titles" = see the full text of the truncated table titles on hover over.
> 📥 `npm i -g notion-enhancer@0.10.2`
### v0.10.1 (2020-11-18)
essentially a prerelease for v0.11.0: pushed out for urgent bugfixes during
exam/study weeks when there's no time to code a full release.
note that this means new features have not yet been fully documented and
may not be fully ready for ideal use yet. however, things overall will
work more reliably than v0.10.0.
- new: different css entrypoints for different components (tabs, menu, app).
- improved: use an svg for the scroll-to-top button.
- improved: use a better-matching icon and add transitions to the property layout toggle.
- improved: themes are directly applied to tabs and menu rather than sync-ed between (infinite loading).
- improved: error message "is notion running?" --> clearer "make sure notion isn't running!"
- improved: auto-shrink system for tabs (max of 15 open in a window).
- bugfix: disable fadein of selected block halo with snappy transitions.
- bugfix: increase contrast of `--theme_dark--interactive_hover` in dark+ and dracula.
- bugfix: tabs are focused properly for input.
- bugfix: keyboard shortcut listeners are stricter so they don't conflict.
- bugfix: dots indicating draggability are no longer next to the tabs mod in the menu.
- bugfix: prevent empty hotkeys from triggering every keypress.
- bugfix: don't try loading an empty default page url (infinite loading).
- bugfix: remove `* { z-index: 1}` rule so format dropdowns in table view can be opened.
- extension: "topbar icons" = replaces the topbar buttons with icons.
- extension: "code line numbers" = adds line numbers to code blocks.
- extension: "notion icons" = use custom icon sets directly in notion.
- tweak: vertical indentation/relationship lines for lists.
- tweak: scroll database toolbars horizontally if partially hidden.
- tweak: condense bullet points (decrease line spacing).
> 📥 `npm i -g notion-enhancer@0.10.1`
### v0.10.0 (2020-11-02)
a flexibility update.
- new: mods can be reordered in the menu to control what order styling/scripts are added/executed in.
higher up on the list = higher priority of application = loaded last in order to override others.
(excluding the core, which though pinned to the top of the list is always loaded first so theming
variables can be modified.)
- new: relaunch button in tray menu.
- new: a core mod option for a default page id/url (all new windows will load it instead of the
normal "most recent" page).
- new: css variables for increasing line spacing/paragraph margins.
- new: patch the notion:// url scheme/protocol to work on linux.
- new: menu shows theme conflicts + a core mod option to auto-resolve theme conflicts.
- new: a `-n` cli option.
- improved: menu will now respect integrated titlebar setting.
- improved: use keyup listeners instead of a globalShortcut for the enhancements menu toggle.
- improved: overwrite `app.asar.bak` if already exists (e.g. for app updates).
- improved: additional menu option descriptions on hover.
- improved: listen to prefers-color-scheme to better change theme in night shift.
- improved: platform-specific option overrides for features not required on macOS.
- improved: made extra padding at the bottom with the "focus mode" extension toggleable.
- bugfix: removed messenger emoji set as the provider no longer supports it.
- bugfix: remove shadow around light mode board headers.
- bugfix: properly detect/respond to `EACCES`/`EBUSY` errors.
- bugfix: night shift checks every interaction,
will respond to system changes without any manual changes.
- bugfix: toc blocks can have text colours.
- bugfix: bypass preview extension works with the back/forward keyboard shortcuts.
- bugfix: (maybe) fix csp issues under proxy.
- bugfix: remove focus mode footer from neutral theme + better contrast in calendar views.
- bugfix: improvements to the colour theming, particularly to make real- and fake-light/dark
modes (as applied by the night shift extension) look consistent.
relevant variables (assuming all are prefixed by `--theme_[dark|light]--`):
`box-shadow`, `box-shadow_strong`, `select_input`, and `ui-border`
- bugfix: font sizing applied to overlays/previews.
- bugfix: removed typo in variable name for brown text.
- bugfix: primary-colour text (mainly in "add a \_" popups) is now properly themed.
- bugfix: right-to-left extension applies to text in columns.
- bugfix: block text colour applies to text with backgrounds.
- bugfix: font applied to wrong mode with littlepig dark.
- bugfix: keep "empty" top bar visible in the menu.
- bugfix: set NSRequiresAquaSystemAppearance to false in /Applications/Notion.app/Contents/Info.plist
so system dark/light mode can be properly detected.
- bugfix: make ctrl+f popover shadow less extreme.
- bugfix: "weekly" calendar view name made case insensitive.
- bugfix: re-show hidden windows when clicking on the dock.
- tweak: sticky table/list rows.
- theme: "material ocean" = an oceanic colour palette.
- theme: "cherry cola" = a delightfully plummy, cherry cola flavored theme.
- theme: "dracula" = a theme based on the popular dracula color palette
originally by zeno rocha and friends.
- extension: "tabs" = have multiple notion pages open in a single window. tabs can be controlled
with keyboard shortcuts and dragged/reordered within/between windows.
- extension: "scroll to top" = add an arrow above the help button to scroll back to the top of a page.
- extension: "tweaks" = common style/layout changes. includes:
- new: make transitions snappy/0s.
- new: in-page columns are disabled/wrapped and pages are wider when
the window is narrower than 600px for improved responsiveness.
- new: thicker bold text for better visibility.
- new: more readable line spacing.
- moved: smooth scrollbars.
- moved: change dragarea height.
- moved: hide help.
a fork of notion-deb-builder that does generate an app.asar has been created and is once again supported.
> 📥 `npm i -g notion-enhancer@0.10.0`
### v0.9.1 (2020-09-26)
- bugfix: font chooser will continue iterating through fonts after encountering a blank option.
- bugfix: block indents are no longer overriden.
- bugfix: neutral does not force full width pages.
- bugfix: bypass preview extension works with the back/forward arrows.
- bugfix: check all views on a page for a weekly calendar.
- bugfix: emoji sets no longer modifies the user agent = doesn't break hotkeys.
> 📥 `npm i -g notion-enhancer@0.9.1`
### v0.9.0 (2020-09-20)
a feature and cleanup update.
- improved: halved the number of css rules used -> much better performance.
- improved: font imports must be define in the `mod.js` so that they can also be used in
the enhancements menu.
- improved: tiling window-manager support (can hide titlebars entirely without dragarea/buttons).
- improved: extensions menu search is now case insensitive and includes options, inputs and versions.
the search box can also for focused with `CMD/CTRL+F`.
- improved: extensions menu filters shown either a ✓ or × to help understand the current state.
- improved: added individual text-colour rules for different background colours.
- improved: added variables for callout colouring.
- improved: replaced with `helpers.getNotion()` with the constant `helpers.__notion` to reduce
repeated function calls.
- improved: added variables for page width.
- improved/bugfix: emoji sets extension should now work on macOS and will change user agent to use
real emojis instead of downloading images when system default is selected.
- bugfix: enhancer settings should no longer reset on update (though this will not have
effect until the release after this one).
- bugfix: blue select tags are no longer purple.
- bugfix: page titles now respond to small-text mode.
- bugfix: weekly calendar view height is now sized correctly according to its contents.
- bugfix: made the open enhancements menu hotkey configurable and changed the default to `ALT+E`.
to remove conflict with the inline code highlight shortcut.
- bugfix: update property-layout to match notion changes again.
- bugfix: updated some of the tweak styling to match notion changes.
- bugfix: block-level text colours are now changed properly.
- bugfix: do not require data folder during installation, to prevent `sudo` attempting to
create it in `/var/root/`.
- bugfix: bullet points/checkboxes will now align properly in the right-to-left extension.
- themes: "littlepig" (light + dark) = monospaced themes using emojis and colourful text.
- extension: "font chooser" = customize fonts. for each option, type in the name of the font you would like to use,
or leave it blank to not change anything.
- extension: "always on top" = add an arrow/button to show the notion window on top of other windows
even if it's not focused.
- extension: "calendar scroll" = add a button to scroll down to the current week in fullpage/infinite-scroll calendars.
- extension: "hide help button" = hide the help button if you don't need it.
- extension: "bypass preview" = go straight to the normal full view when opening a page.
- extension: "word counter" = add page details: word/character/sentence/block count & speaking/reading times.
notion-deb-builder has been discovered to not generate an app.asar and so is no longer supported.
> 📥 `npm i -g notion-enhancer@0.9.0`
### v0.8.5 (2020-08-29)
- bugfix: separate text highlight and select tag variables.
- bugfix: bypass CSP for the `enhancement://` protocol - was failing on some platforms?
> 📥 `npm i -g notion-enhancer@0.8.5`
### v0.8.4 (2020-08-29)
- bugfix: property-layout now works consistently with or without a banner.
> 📥 `npm i -g notion-enhancer@0.8.4`
### v0.8.3 (2020-08-29)
previous release was a mistake: it did as intended on linux, but broke windows.
this should achieve the same thing in a more compatible way.
> 📥 `npm i -g notion-enhancer@0.8.3`
### v0.8.2 (2020-08-28)
some things you just can't test until production... fixed the auto-installer
to use `./bin.js` instead of `notion-enhancer`
> 📥 `npm i -g notion-enhancer@0.8.2`
### v0.8.1 (2020-08-28)
a clarity and stability update.
- improved: more informative cli error messages (original ones can be accessed with the `-d/--dev` flag).
- bugfix: gallery variable didn't apply on fullpage.
- bugfix: date picker hid current date number.
- bugfix: small-text pages should now work as expected.
- bugfix: padding issues in page previews.
- bugfix: property-layout extension had been broken by internal notion changes.
- bugfix: linux installer path typo.
- bugfix: caret-color was being mistaken for color and block-level text colouring was broken.
- improved: auto-application on install.
> 📥 `npm i -g notion-enhancer@0.8.1`
### v0.8.0 (2020-08-27)
complete rewrite with node.js.
- new: simpler cli installation system (inc. commands: `apply`, `remove`, and `check`).
- new: mod loading system (easier to create new mods, adds to notion rather than overwriting).
- new: mod configuration menu.
- improved: more theming variable coverage - inc. light theme and sizing/spacing.
- bugfix: non-reproducable errors with python.
- bugfix: better launcher patching on linux.
- bugfix: fix frameless window issue introduced by notion desktop 2.0.9.
- extension: "custom inserts" = link files for small client-side tweaks.
- extension: "bracketed links" = render links surrounded with \[\[brackets]] instead of underlined.
- extension: "focus mode" = hide the titlebar/menubar if the sidebar is closed (will be shown on hover).
- theme: "dark+" = a vivid-colour near-black theme.
- theme: "neutral" = smoother colours and fonts, designed to be more pleasing to the eye.
- theme: "gameish" = a purple, "gamer-styled" theme with a blocky-font.
- theme: "pastel dark" = a smooth-transition true dark theme with a hint of pastel.
- extension: "emoji sets" = pick from a variety of emoji styles to use.
- extension: "night shift" = sync dark/light theme with the system (overrides normal theme setting).
- extension: "right-to-left" = enables auto rtl/ltr text direction detection. (ported from [github.com/obahareth/notion-rtl](https://github.com/obahareth/notion-rtl).)
- extension: "weekly view" = calendar views named "weekly" will show only the 7 days of this week. (ported from [github.com/adihd/notionweeklyview](https://github.com/adihd/notionweeklyview).)]
- extension: "property layout" = auto-collapse page properties that usually push down page content. (ported from [github.com/alexander-kazakov/notion-layout-extension](https://github.com/alexander-kazakov/notion-layout-extension).)
> 📥 `npm i -g notion-enhancer@0.8.0`
### v0.7.0 (2020-07-09)
- new: tray option to use system default emojis (instead of twitter's emojiset).
- new: mac support (identical functionality to other platforms with the
exception of the native minimise/maximise/close buttons being kept, as they integrate
better with the OS while not being out-of-place in notion).
- new: notion-deb-builder support for linux.
- new: an alert will be shown if there is an update available for the enhancer.
- improved: replaced button symbols with svgs for multi-platform support.
- improved: window close button is now red on hover (thanks to [@torchatlas](https://github.com/torchatlas)).
- bugfix: `cleaner.py` patched for linux.
- bugfix: tray now operates as expected on linux.
- bugfix: odd mix of `\\` and `/` being used for windows filepaths.
- bugfix: app no longer crashes when sidebar is toggled.
> 📥 [notion-enhancer.v0.7.0.zip](https://github.com/notion-enhancer/notion-enhancer/archive/v0.7.0.zip)
### v0.6.0 (2020-06-30)
- style: custom fonts.
- style: font resizing.
- style: hide discussions (thanks to [u/Roosmaryn](https://www.reddit.com/user/Roosmaryn/)).
- new: custom colour theming, demonstrated via the dark+ theme.
- new: linux support (thanks to [@Blacksuan19](https://github.com/Blacksuan19)).
- improved: if hotkey is pressed while notion is unfocused, it will bring it to the front rather than hiding it.
- improved: stop window buttons breaking at smaller widths.
- improved: more obviously visible drag area.
- bugfix: specify UTF-8 encoding to prevent multibyte/gbk codec errors (thanks to [@etnperlong](https://github.com/etnperlong)).
> 📥 [notion-enhancer.v0.6.0.zip](https://github.com/notion-enhancer/notion-enhancer/archive/v0.6.0.zip)
### v0.5.0 (2020-05-23)
- new: running from the wsl.
- new: reload window with f5.
- improved: code has been refactored and cleaned up,
inc. file renaming and a `customiser.py` that doesn't require
a run of `cleaner.py` to build modifications.
improved: scrollbar colours that fit better with notion's theming.
- bugfix: un-break having multiple notion windows open.
> 📥 [notion-enhancer.v0.5.0.zip](https://github.com/notion-enhancer/notion-enhancer/archive/v0.5.0.zip)
**development here taken over by [@dragonwocky](https://github.com/dragonwocky).**
**the ~~crossed out~~ features below are no longer features included by default,**
**but can still easily be added as [custom tweaks](https://github.com/notion-enhancer/tweaks).**
### v0.4.1 (2020-02-13)
- bugfix: wider table & the "+" button not working in database pages.
> 📥 [notion-enhancer.v4.1.zip](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d239a3cf-d553-4ef3-ab04-8b47892d9f9a/Notion_Customization_v4.1.zip)
### v0.4.0
- new: tray icon.
- new: app startup options (+ saving).
- new: `Reset.py`
- improved: better output from `Customization Patcher.py`.
- bugfix: wider tables in "short page" mode.
- bugfix: unclickable buttons/draggable area (of titlebar).
### v0.3.0
- new: show/hide window hotkey.
- new: app startup options.
- ~~style: smaller table icons.~~
> 📥 [notion-enhancer.v3.zip](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b01aa446-5727-476a-a25e-395472bfb1be/NotionScriptsV3.zip)
### v0.2.0
- new: light/dark theme support for window control buttons + scrollbars.
- new: custom styles directly linked to the enhancer resources + compatible with web version.
- ~~improved: making table column width go below 100px.~~
### v0.1.0
- new: custom window control buttons.
- removed: default titlebar/menubar.
- ~~removed: huge padding of board view.~~
- ~~removed: huge padding of table view.~~
- ~~optional: making table column width go below 100px.~~
- ~~style: thinner cover image + higher content block.~~
- style: scrollbars.

View File

@ -1,13 +1,5 @@
# extension
# notion-enhancer/extension
bringing all your favourite notion-enhancer features to the browser (wip)
an enhancer/customiser for the all-in-one productivity workspace notion.so (browser)
> considering that using notion in the browser is more lightweight & probably preferred for some people since it means they have less apps open, i've always planned to eventually port the enhancer to be a chrome extension.
>
> since the enhancer focuses on being able to manipulate notion's app files, it's not going to be a very friendly transfer to web - a few features will have to be lost (e.g. frameless mode & tabs, of course) and the extensions system will need to be completely rebuilt.
>
> to make this work better, i'm splitting things up: an mod repository, a chrome extension, and an app loader.
>
> i'll be building the enhancer chrome-first from now on, since it'll be more limited there (and it's easier to add extra features when porting than to take features out), and then releasing the app loader a little afterwards. both the app loader and the chrome extension will source the same themes & extensions from the mod repository, and updates & releases of individual mods won't require waiting for the enhancer version anymore.
-- from the #announcements channel of the [notion-enhancer discord](https://discord.gg/sFWPXtA)
[read the docs online](https://notion-enhancer.github.io/)

@ -1 +1 @@
Subproject commit 5030fe2b0fd71b397796b055934ec50f7e909a5c
Subproject commit 9815d73b9277e96864654a8d8dd48762039c9845

1
extension/dep Submodule

@ -0,0 +1 @@
Subproject commit 1a4762550fe185706be26678f734b0475066c3e4

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 59 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,58 +0,0 @@
/**
* style-vendorizer v2.0.0
* @license MIT
* @source https://unpkg.com/style-vendorizer@^2.0.0?module
*/
var i = new Map([
['align-self', '-ms-grid-row-align'],
['color-adjust', '-webkit-print-color-adjust'],
['column-gap', 'grid-column-gap'],
['gap', 'grid-gap'],
['grid-template-columns', '-ms-grid-columns'],
['grid-template-rows', '-ms-grid-rows'],
['justify-self', '-ms-grid-column-align'],
['margin-inline-end', '-webkit-margin-end'],
['margin-inline-start', '-webkit-margin-start'],
['overflow-wrap', 'word-wrap'],
['padding-inline-end', '-webkit-padding-end'],
['padding-inline-start', '-webkit-padding-start'],
['row-gap', 'grid-row-gap'],
['scroll-margin-bottom', 'scroll-snap-margin-bottom'],
['scroll-margin-left', 'scroll-snap-margin-left'],
['scroll-margin-right', 'scroll-snap-margin-right'],
['scroll-margin-top', 'scroll-snap-margin-top'],
['scroll-margin', 'scroll-snap-margin'],
['text-combine-upright', '-ms-text-combine-horizontal'],
]);
function r(r) {
return i.get(r);
}
function n(i) {
var r =
/^(?:(text-(?:decoration$|e|or|si)|back(?:ground-cl|d|f)|box-d|(?:mask(?:$|-[ispro]|-cl)))|(tab-|column(?!-s)|text-align-l)|(ap)|(u|hy))/i.exec(
i
);
return r ? (r[1] ? 1 : r[2] ? 2 : r[3] ? 3 : 5) : 0;
}
function t(i, r) {
var n = /^(?:(pos)|(background-i)|((?:max-|min-)?(?:block-s|inl|he|widt))|(dis))/i.exec(i);
return n
? n[1]
? /^sti/i.test(r)
? 1
: 0
: n[2]
? /^image-/i.test(r)
? 1
: 0
: n[3]
? '-' === r[3]
? 2
: 0
: /^(inline-)?grid$/i.test(r)
? 4
: 0
: 0;
}
export { r as cssPropertyAlias, n as cssPropertyPrefixFlags, t as cssValuePrefixFlags };

View File

@ -1,43 +0,0 @@
/**
* Twind v0.16.16
* @license MIT
* @source https://unpkg.com/@twind/content@0.1.0/content.js?module
*/
import { directive as o } from './twind.mjs';
var c = new Set([
'open-quote',
'close-quote',
'no-open-quote',
'no-close-quote',
'normal',
'none',
'inherit',
'initial',
'unset',
]),
n = (t) => t.join('-'),
s = (t) => {
switch (t[0]) {
case 'data':
return `attr(${n(t)})`;
case 'attr':
case 'counter':
return `${t[0]}(${n(t.slice(1))})`;
case 'var':
return `var(--${n(t)})`;
case void 0:
return 'attr(data-content)';
default:
return JSON.stringify(n(t));
}
},
i = (t, { theme: r }) => {
let e = Array.isArray(t) ? n(t) : t;
return {
content:
(e && r('content', [e], '')) || (c.has(e) && e) || (Array.isArray(t) ? s(t) : e),
};
},
u = (t, r) => (Array.isArray(t) ? i(t, r) : o(i, t));
export { u as content };

View File

@ -1,134 +0,0 @@
/**
* Twind v0.16.16
* @license MIT
* @source https://unpkg.com/twind@0.16.16/css/css.js?module
*/
// src/css/index.ts
import { apply, hash, directive } from "./twind.mjs";
// src/internal/util.ts
var includes = (value, search) => !!~value.indexOf(search);
var join = (parts, separator = "-") => parts.join(separator);
var hyphenate = value => value.replace(/[A-Z]/g, "-$&").toLowerCase();
var evalThunk = (value, context) => {
while (typeof value == "function") {
value = value(context);
}
return value;
};
var isCSSProperty = (key, value) => !includes("@:&", key[0]) && (includes("rg", (typeof value)[5]) || Array.isArray(value));
var merge = (target, source, context) => source ? Object.keys(source).reduce((target2, key) => {
const value = evalThunk(source[key], context);
if (isCSSProperty(key, value)) {
target2[hyphenate(key)] = value;
} else {
target2[key] = key[0] == "@" && includes("figa", key[1]) ? (target2[key] || []).concat(value) : merge(target2[key] || {}, value, context);
}
return target2;
}, target) : target;
var escape = typeof CSS !== "undefined" && CSS.escape || (className => className.replace(/[!"'`*+.,;:\\/<=>?@#$%&^|~()[\]{}]/g, "\\$&").replace(/^\d/, "\\3$& "));
var buildMediaQuery = screen2 => {
if (!Array.isArray(screen2)) {
screen2 = [screen2];
}
return "@media " + join(screen2.map(screen3 => {
if (typeof screen3 == "string") {
screen3 = { min: screen3 };
}
return screen3.raw || join(Object.keys(screen3).map(feature => `(${feature}-width:${screen3[feature]})`), " and ");
}), ",");
};
// src/css/index.ts
var translate = (tokens, context) => {
const collect = (target, token) => Array.isArray(token) ? token.reduce(collect, target) : merge(target, evalThunk(token, context), context);
return tokens.reduce(collect, {});
};
var newRule = /\s*(?:([\w-%@]+)\s*:?\s*([^{;]+?)\s*(?:;|$|})|([^;}{]*?)\s*{)|(})/gi;
var ruleClean = /\/\*[\s\S]*?\*\/|\s+|\n/gm;
var decorate = (selectors, currentBlock) => selectors.reduceRight((rules, selector) => ({ [selector]: rules }), currentBlock);
var saveBlock = (rules, selectors, currentBlock) => {
if (currentBlock) {
rules.push(decorate(selectors, currentBlock));
}
};
var interleave = (strings, interpolations, context) => {
let buffer = strings[0];
const result = [];
for (let index = 0; index < interpolations.length;) {
const interpolation = evalThunk(interpolations[index], context);
if (interpolation && typeof interpolation == "object") {
result.push(buffer, interpolation);
buffer = strings[++index];
} else {
buffer += (interpolation || "") + strings[++index];
}
}
result.push(buffer);
return result;
};
var astish = (values, context) => {
const selectors = [];
const rules = [];
let currentBlock;
let match;
for (let index = 0; index < values.length; index++) {
const value = values[index];
if (typeof value == "string") {
while (match = newRule.exec(value.replace(ruleClean, " "))) {
if (!match[0])
continue;
if (match[4]) {
currentBlock = saveBlock(rules, selectors, currentBlock);
selectors.pop();
}
if (match[3]) {
currentBlock = saveBlock(rules, selectors, currentBlock);
selectors.push(match[3]);
} else if (!match[4]) {
if (!currentBlock)
currentBlock = {};
const value2 = match[2] && /\S/.test(match[2]) ? match[2] : values[++index];
if (value2) {
if (match[1] == "@apply") {
merge(currentBlock, evalThunk(apply(value2), context), context);
} else {
currentBlock[match[1]] = value2;
}
}
}
}
} else {
currentBlock = saveBlock(rules, selectors, currentBlock);
rules.push(decorate(selectors, value));
}
}
saveBlock(rules, selectors, currentBlock);
return rules;
};
var cssFactory = (tokens, context) => translate(Array.isArray(tokens[0]) && Array.isArray(tokens[0].raw) ? astish(interleave(tokens[0], tokens.slice(1), context), context) : tokens, context);
var css = (...tokens) => directive(cssFactory, tokens);
var keyframesFactory = (tokens, context) => {
const waypoints = cssFactory(tokens, context);
const id = hash(JSON.stringify(waypoints));
context.tw(() => ({ [`@keyframes ${id}`]: waypoints }));
return id;
};
var keyframes = (...tokens) => directive(keyframesFactory, tokens);
var animation = (value, waypoints) => waypoints === void 0 ? (...args) => animation(value, keyframes(...args)) : css({
...(value && typeof value == "object" ? value : { animation: value }),
animationName: typeof waypoints == "function" ? waypoints : keyframes(waypoints) });
var screenFactory = ({ size, rules }, context) => {
const media = buildMediaQuery(context.theme("screens", size));
return rules === void 0 ? media : {
[media]: typeof rules == "function" ? evalThunk(rules, context) : cssFactory([rules], context) };
};
var screen = (size, rules) => directive(screenFactory, { size, rules });
export {
animation,
css,
keyframes,
screen };

File diff suppressed because it is too large Load Diff

View File

@ -6,10 +6,7 @@
'use strict';
/**
* environment-specific methods and constants
* @module notion-enhancer/api/env
*/
/** environment-specific methods and constants */
/**
* the environment/platform name code is currently being executed in

View File

@ -6,10 +6,7 @@
'use strict';
/**
* environment-specific filesystem reading
* @module notion-enhancer/api/fs
*/
/** environment-specific file reading */
/**
* transform a path relative to the enhancer root directory into an absolute path
@ -21,7 +18,7 @@ export const localPath = chrome.runtime.getURL;
/**
* 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
* @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 = {}) =>
@ -30,7 +27,7 @@ export const getJSON = (path, opts = {}) =>
/**
* 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
* @param {object=} opts - the second argument of a fetch() request
* @returns {string} the text content of the requested file
*/
export const getText = (path, opts = {}) =>

View File

@ -6,18 +6,15 @@
'use strict';
/**
* environment-specific data persistence
* @module notion-enhancer/api/storage
*/
/** environment-specific data persistence */
const _queue = [],
_onChangeListeners = [];
/**
* get persisted data
* @param {array<string>} path - the path of keys to the value being fetched
* @param {*} [fallback] - a default value if the path is not matched
* @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) => {
@ -39,8 +36,8 @@ export const get = (path, fallback = undefined) => {
/**
* persist data
* @param {array<string>} path - the path of keys to the value being set
* @param {*} value - the data to save
* @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) => {
@ -68,7 +65,7 @@ export const set = (path, value) => {
}
chrome.storage.local.set({ [namespace]: values[namespace] }, () => {
_onChangeListeners.forEach((listener) =>
listener({ type: 'set', path: pathClone, new: value, old })
listener({ path: pathClone, new: value, old })
);
res(value);
});
@ -80,12 +77,13 @@ export const set = (path, value) => {
/**
* create a wrapper for accessing a partition of the storage
* @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
* @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),
@ -112,9 +110,7 @@ export const removeChangeListener = (callback) => {
/**
* @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
* @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
*/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

35
extension/init.js Normal file
View File

@ -0,0 +1,35 @@
/*
* notion-enhancer
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
(async () => {
const site = location.host.endsWith('.notion.site'),
page = location.pathname.split(/[/-]/g).reverse()[0].length === 32,
whitelisted = ['/', '/onboarding'].includes(location.pathname),
signedIn = localStorage['LRU:KeyValueStore2:current-user-id'];
if (site || page || (whitelisted && signedIn)) {
const api = await import(chrome.runtime.getURL('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?.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) {
console.log('[notion-enhancer] registry errors:');
console.table(errors);
}
}
})();

View File

@ -1,34 +0,0 @@
/*
* notion-enhancer
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
(async () => {
if (location.pathname === '/') await new Promise((res, rej) => setTimeout(res, 500));
const site = location.host.endsWith('.notion.site'),
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;
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(fs.localPath(`repo/${mod._dir}/${script}`));
script.default(api, await registry.db(mod.id));
}
}
const errors = await registry.errors();
if (errors.length) {
console.log('[notion-enhancer] registry errors:');
console.table(errors);
}
});
}
})();

View File

@ -6,32 +6,25 @@
"description": "an enhancer/customiser for the all-in-one productivity workspace notion.so",
"homepage_url": "https://notion-enhancer.github.io",
"icons": {
"16": "icon/colour-x16.png",
"32": "icon/colour-x32.png",
"48": "icon/colour-x48.png",
"128": "icon/colour-x128.png",
"256": "icon/colour-x256.png",
"512": "icon/colour-x512.png"
"16": "media/colour-x16.png",
"32": "media/colour-x32.png",
"48": "media/colour-x48.png",
"128": "media/colour-x128.png",
"256": "media/colour-x256.png",
"512": "media/colour-x512.png"
},
"browser_action": {},
"background": { "scripts": ["worker.js"] },
"options_ui": {
"page": "repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.html",
"page": "repo/menu/menu.html",
"open_in_tab": true
},
"web_accessible_resources": ["env/*", "api/*", "dep/*", "icon/*", "repo/*"],
"web_accessible_resources": ["env/*", "api/*", "dep/*", "media/*", "repo/*"],
"content_scripts": [
{
"matches": ["https://*.notion.so/*", "https://*.notion.site/*"],
"js": ["launcher.js"]
"js": ["init.js"]
}
],
"permissions": [
"tabs",
"storage",
"unlimitedStorage",
"https://*.notion.so/*",
"https://*.notion.site/*",
"<all_urls>"
]
"permissions": ["tabs", "storage", "clipboardRead", "clipboardWrite", "unlimitedStorage"]
}

1
extension/media Submodule

@ -0,0 +1 @@
Subproject commit 2a0a17998385f1d86148b9213451b3a5deff6bae

1
extension/repo Submodule

@ -0,0 +1 @@
Subproject commit 76e36ab47ca2ffd354280b5c907f9ebb827c30c4

View File

@ -1,9 +0,0 @@
/*
* notion-enhancer: bypass-preview
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
.notion-peek-renderer {
display: none;
}

View File

@ -1,33 +0,0 @@
/*
* notion-enhancer: bypass-preview
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
export default async function (api, db) {
const { web, components } = api;
await web.whenReady();
let _lastPage = {};
function getCurrentPage() {
if (web.queryParams().get('p')) return { type: 'preview', id: web.queryParams().get('p') };
return { type: 'page', id: location.pathname.split(/(-|\/)/g).reverse()[0] };
}
web.addDocumentObserver((event) => {
const currentPage = getCurrentPage();
if (currentPage.id !== _lastPage.id || currentPage.type !== _lastPage.type) {
const openAsPage = document.querySelector(
'.notion-peek-renderer [style*="height: 45px;"] a'
);
if (openAsPage) {
if (currentPage.id === _lastPage.id && currentPage.type === 'preview') {
history.back();
} else openAsPage.click();
}
_lastPage = getCurrentPage();
}
});
}

View File

@ -1,22 +0,0 @@
{
"name": "bypass-preview",
"id": "cb6fd684-f113-4a7a-9423-8f0f0cff069f",
"version": "0.2.0",
"description": "go straight to the normal full view when opening a page.",
"tags": ["extension", "automation"],
"authors": [
{
"name": "dragonwocky",
"email": "thedragonring.bod@gmail.com",
"homepage": "https://dragonwocky.me/",
"avatar": "https://dragonwocky.me/avatar.jpg"
}
],
"js": {
"client": ["client.mjs"]
},
"css": {
"client": ["client.css"]
},
"options": []
}

View File

@ -1,21 +0,0 @@
/*
* notion-enhancer: calendar-scroll
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
#calendar-scroll-to-week {
background: var(--theme--button_hover);
border: 1px solid transparent;
font-size: var(--theme--font_label-size);
color: var(--theme--text);
height: 24px;
border-radius: 3px;
line-height: 1.2;
padding: 0 0.5em;
margin-right: 5px;
}
#calendar-scroll-to-week:hover {
background: transparent;
border: 1px solid var(--theme--button_hover);
}

View File

@ -1,64 +0,0 @@
/*
* notion-enhancer core: bypass-preview
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
import { web } from '../../api/_.mjs';
const $button = web.createElement(
web.html`<button id="calendar-scroll-to-week">Scroll</button>`
);
$button.addEventListener('click', async (event) => {
let $day = document.querySelector('.notion-calendar-view-day[style*="background:"]');
while (!$day) {
const $toolbar = document.querySelector(
'.notion-calendar-view > :first-child > :first-child > :first-child'
),
year = +$toolbar.children[0].innerText.split(' ')[1],
month = {
'January': 0,
'February': 1,
'March': 2,
'April': 3,
'May': 4,
'June': 5,
'July': 6,
'August': 7,
'September': 8,
'October': 9,
'November': 10,
'December': 11,
}[$toolbar.children[0].innerText.split(' ')[0]],
now = new Date();
switch (true) {
case now.getFullYear() < year:
case now.getFullYear() === year && now.getMonth() < month:
$toolbar.children[3].click();
break;
case now.getFullYear() > year:
case now.getFullYear() === year && now.getMonth() > month:
$toolbar.children[5].click();
break;
default:
await new Promise((res, rej) => requestAnimationFrame(res));
$day = document.querySelector('.notion-calendar-view-day[style*="background:"]');
}
await new Promise((res, rej) => requestAnimationFrame(res));
}
const $scroller = document.querySelector('.notion-frame .notion-scroller');
$scroller.scroll({
top: $day.offsetParent.offsetParent.offsetTop + 70,
behavior: 'auto',
});
});
web.addDocumentObserver((event) => {
if (document.contains($button)) return;
const toolbar = document.querySelector(
'.notion-calendar-view > :first-child > :first-child > :first-child'
);
if (toolbar) toolbar.insertBefore($button, toolbar.children[2]);
});

View File

@ -1,22 +0,0 @@
{
"name": "calendar-scroll",
"id": "b1c7db33-dfee-489a-a76c-0dd66f7ed29a",
"version": "0.2.0",
"description": "add a button to jump down to the current week in fullpage/infinite-scroll calendars.",
"tags": ["extension", "shortcut"],
"authors": [
{
"name": "dragonwocky",
"email": "thedragonring.bod@gmail.com",
"homepage": "https://dragonwocky.me/",
"avatar": "https://dragonwocky.me/avatar.jpg"
}
],
"js": {
"client": ["client.mjs"]
},
"css": {
"client": ["client.css"]
},
"options": []
}

View File

@ -1,33 +0,0 @@
{
"__comment": "pseudo-mod to allow configuration of API-provided components",
"name": "components",
"id": "36a2ffc9-27ff-480e-84a7-c7700a7d232d",
"version": "0.2.0",
"description": "shared notion-style elements.",
"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": {},
"css": {},
"options": [
{
"type": "hotkey",
"key": "panel.hotkey",
"label": "toggle panel hotkey",
"value": "Ctrl+Alt+\\",
"tooltip": "opens/closes the side panel in notion - will only work if a mod is making use of it."
}
]
}

View File

@ -1,237 +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 { fmt, web, registry, components } from '../../api/_.mjs';
import { notifications } from './notifications.mjs';
const profileDB = await registry.profileDB();
export const blocks = {
preview: (url) => web.html`<img
class="mod-preview"
src="${web.escape(url)}"
alt=""
>`,
title: (title) => web.html`<h4 class="mod-title"><span>${web.escape(title)}</span></h4>`,
version: (version) => web.html`<span class="mod-version">v${web.escape(version)}</span>`,
tags: (tags) => {
if (!tags.length) return '';
return web.render(
web.html`<p class="mod-tags"></p>`,
tags.map((tag) => `#${web.escape(tag)}`).join(' ')
);
},
description: (description) => web.html`<p class="mod-description markdown-inline">
${fmt.md.renderInline(description)}
</p>`,
authors: (authors) => {
const author = (author) => web.html`<a
class="mod-author"
href="${web.escape(author.homepage)}"
target="_blank"
>
<img class="mod-author-avatar"
src="${web.escape(author.avatar)}" alt="${web.escape(author.name)}'s avatar"
> <span>${web.escape(author.name)}</span>
</a>`;
return web.render(web.html`<p class="mod-authors-container"></p>`, ...authors.map(author));
},
toggle: (label, checked) => {
const $label = web.html`<label tabindex="0" class="toggle-label">
<span>${web.escape(label)}</span>
</label>`,
$input = web.html`<input tabindex="-1" type="checkbox" class="toggle-check"
${checked ? 'checked' : ''}>`,
$feature = web.html`<span class="toggle-box toggle-feature"></span>`;
$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 checked = await profileDB.get([mod.id, opt.key], opt.value),
$toggle = blocks.toggle(opt.label, checked),
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
$label = $toggle.children[0],
$input = $toggle.children[1];
if (opt.tooltip) {
$label.prepend($tooltip);
components.tooltip($tooltip, opt.tooltip);
}
$input.addEventListener('change', async (event) => {
await profileDB.set([mod.id, opt.key], $input.checked);
notifications.onChange();
});
return $toggle;
},
select: async (mod, opt) => {
const value = await profileDB.get([mod.id, opt.key], opt.values[0]),
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
$label = web.render(
web.html`<label class="input-label"></label>`,
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
),
$options = opt.values.map(
(option) => web.raw`<option
class="select-option"
value="${web.escape(option)}"
${option === value ? 'selected' : ''}
>${web.escape(option)}</option>`
),
$select = web.html`<select class="input">
${$options.join('')}
</select>`,
$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);
notifications.onChange();
});
return web.render($label, $select, $icon);
},
text: async (mod, opt) => {
const value = await profileDB.get([mod.id, opt.key], opt.value),
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
$label = web.render(
web.html`<label class="input-label"></label>`,
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
),
$input = web.html`<input type="text" class="input" value="${web.escape(value)}">`,
$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);
notifications.onChange();
});
return web.render($label, $input, $icon);
},
number: async (mod, opt) => {
const value = await profileDB.get([mod.id, opt.key], opt.value),
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
$label = web.render(
web.html`<label class="input-label"></label>`,
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
),
$input = web.html`<input type="number" class="input" value="${value}">`,
$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);
notifications.onChange();
});
return web.render($label, $input, $icon);
},
color: async (mod, opt) => {
const value = await profileDB.get([mod.id, opt.key], opt.value),
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
$label = web.render(
web.html`<label class="input-label"></label>`,
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
),
$input = web.html`<input type="text" class="input">`,
$icon = web.html`${await components.feather('droplet', { class: 'input-icon' })}`,
paint = () => {
$input.style.background = $picker.toBackground();
$input.style.color = $picker.isLight() ? '#000' : '#fff';
$input.style.padding = '';
},
$picker = new web.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.tooltip($tooltip, opt.tooltip);
$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 { filename } = (await profileDB.get([mod.id, opt.key], {})) || {},
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
$label = web.render(
web.html`<label class="input-label"></label>`,
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
),
$pseudo = web.html`<span class="input"><span class="input-placeholder">Upload file...</span></span>`,
$input = web.html`<input type="file" class="hidden" accept=${web.escape(
opt.extensions.join(',')
)}>`,
$icon = web.html`${await components.feather('file', { class: 'input-icon' })}`,
$filename = web.html`<span>${web.escape(filename || 'none')}</span>`,
$latest = web.render(web.html`<button class="file-latest">Latest: </button>`, $filename);
if (opt.tooltip) components.tooltip($tooltip, opt.tooltip);
$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`<div></div>`,
web.render($label, $input, $pseudo, $icon),
$latest
);
},
hotkey: async (mod, opt) => {
const value = await profileDB.get([mod.id, opt.key], opt.value),
$tooltip = web.html`${await components.feather('info', { class: 'input-tooltip' })}`,
$label = web.render(
web.html`<label class="input-label"></label>`,
web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
),
$input = web.html`<input type="text" class="input" value="${web.escape(value)}">`,
$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();
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.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);
},
};

View File

@ -1,69 +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
*/
.enhancer--sidebarMenuLink {
user-select: none;
-webkit-user-select: none;
transition: background 20ms ease-in 0s;
cursor: pointer;
color: var(--theme--text_secondary);
}
.enhancer--sidebarMenuLink:hover {
background: var(--theme--ui_interactive-hover);
}
.enhancer--sidebarMenuLink svg {
width: 16px;
height: 16px;
margin-left: 2px;
}
.enhancer--sidebarMenuLink > div {
display: flex;
align-items: center;
min-height: 27px;
font-size: 14px;
padding: 2px 14px;
width: 100%;
}
.enhancer--sidebarMenuLink > div > :first-child {
flex-shrink: 0;
flex-grow: 0;
border-radius: 3px;
width: 22px;
height: 22px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 8px;
}
.enhancer--sidebarMenuLink > div > :nth-child(2) {
flex: 1 1 auto;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.enhancer--sidebarMenuLink[data-has-notifications] {
color: var(--theme--text);
}
.enhancer--sidebarMenuLink > div > .enhancer--notificationBubble {
display: flex;
}
.enhancer--sidebarMenuLink > div > .enhancer--notificationBubble > div {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
font-size: 10px;
font-weight: 600;
border-radius: 3px;
color: var(--theme--accent_red-text);
background: var(--theme--accent_red);
}
.enhancer--sidebarMenuLink > div > .enhancer--notificationBubble > div > span {
margin-bottom: 1px;
margin-left: -0.5px;
}

View File

@ -1,59 +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';
export default async function (api, db) {
const { env, fs, storage, registry, web } = api;
web.addHotkeyListener(await db.get(['hotkey']), env.focusMenu);
const updateTheme = () =>
storage.set(['theme'], document.querySelector('.notion-dark-theme') ? 'dark' : 'light');
web.addDocumentObserver((mutation) => {
if (mutation.target === document.body && document.hasFocus()) updateTheme();
});
if (document.hasFocus()) updateTheme();
document.addEventListener('visibilitychange', updateTheme);
const sidebarSelector = '.notion-sidebar-container .notion-sidebar > div:nth-child(4)';
await web.whenReady([sidebarSelector]);
const $sidebarLink = web.html`<div class="enhancer--sidebarMenuLink" role="button" tabindex="0">
<div>
<div>${await fs.getText('icon/colour.svg')}</div>
<div><div>notion-enhancer</div></div>
</div>
</div>`;
$sidebarLink.addEventListener('click', env.focusMenu);
const notifications = {
cache: await storage.get(['notifications'], []),
provider: [
registry.welcomeNotification,
...(await fs.getJSON('https://notion-enhancer.github.io/notifications.json')),
],
count: (await registry.errors()).length,
};
for (const notification of notifications.provider) {
if (
!notifications.cache.includes(notification.id) &&
notification.version === env.version &&
(!notification.environments || notification.environments.includes(env.name))
) {
notifications.count++;
}
}
if (notifications.count) {
$sidebarLink.dataset.hasNotifications = true;
web.render(
$sidebarLink.children[0],
web.html`<div class="enhancer--notificationBubble"><div><span>${notifications.count}</span></div></div>`
);
}
web.render(document.querySelector(sidebarSelector), $sidebarLink);
}

View File

@ -1,165 +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
*/
.markdown table {
border-spacing: 0;
border: 1px solid var(--theme--ui_divider);
}
.markdown table th {
text-align: left;
}
.markdown table th,
.markdown table td {
padding: 5px 8px 6px;
border: 1px solid var(--theme--ui_divider);
}
.markdown h1 {
font-size: 1.875rem;
margin: 1rem 0 0.5rem 0;
}
.markdown h2 {
font-size: 1.5rem;
margin: 1rem 0 0.5rem 0;
}
.markdown h3 {
font-size: 1.25rem;
margin: 1rem 0 0.5rem 0;
}
.markdown ul,
.markdown ol {
padding-left: 1.25rem;
}
.markdown li {
margin: 0.4rem 0;
}
.markdown ol li {
padding-left: 0.25rem;
}
.markdown blockquote {
border-left: 2px solid currentColor;
padding-left: 0.75rem;
margin: 0.5rem 0;
}
.markdown hr {
border: 0.5px solid var(--theme--ui_divider);
}
.markdown.markdown-inline a {
opacity: 0.7;
text-decoration: none;
border-bottom: 0.05em solid var(--theme--text_secondary);
}
.markdown.markdown-inline a:hover {
opacity: 0.9;
}
.markdown :not(pre) > code,
.markdown-inline code {
padding: 0.2em 0.4em;
border-radius: 3px;
background: var(--theme--code_inline);
color: var(--theme--code_inline-text);
}
.markdown pre {
padding: 2em 1.25em;
border-radius: 3px;
tab-size: 2;
white-space: pre;
overflow-x: auto;
background: var(--theme--code);
color: var(--theme--code_plain);
}
.markdown pre,
.markdown.markdown-inline code {
font-family: var(--theme--font_code);
font-size: 0.796875rem;
text-align: left;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
hyphens: none;
line-height: 1.5;
}
/*
* https://prismjs.com/plugins/inline-color/
*/
.markdown .inline-color-wrapper {
/*
* base64 svg (https://stackoverflow.com/a/21626701/7595472 - prevents visual glitches)
* <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2">
* <path fill="gray" d="M0 0h2v2H0z"/>
* <path fill="white" d="M0 0h1v1H0zM1 1h1v1H1z"/>
* </svg>
*/
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyIDIiPjxwYXRoIGZpbGw9ImdyYXkiIGQ9Ik0wIDBoMnYySDB6Ii8+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0wIDBoMXYxSDB6TTEgMWgxdjFIMXoiLz48L3N2Zz4=');
background-position: center;
background-size: 110%;
display: inline-block;
height: 1.333ch;
width: 1.333ch;
margin: 0 0.333ch;
box-sizing: border-box;
border: 0.5px solid var(--theme--code_plain);
overflow: hidden;
}
.markdown .inline-color {
display: block;
height: 120%;
width: 120%;
}
/*
* https://prismjs.com/plugins/match-braces/
*/
.markdown .token.punctuation.brace-hover,
.markdown .token.punctuation.brace-selected {
outline: solid 1px;
}
/*
* https://prismjs.com/plugins/show-language/
* https://prismjs.com/plugins/copy-to-clipboard/
*/
.markdown .code-toolbar {
position: relative;
}
.markdown .code-toolbar .toolbar-item {
position: absolute;
top: 0.35rem;
display: inline-block;
transition: opacity 200ms ease-in-out;
opacity: 0;
}
.markdown .code-toolbar .toolbar-item:first-child {
left: 0.8rem;
}
.markdown .code-toolbar .toolbar-item:last-child {
right: 0.8rem;
}
.markdown .code-toolbar:hover .toolbar-item,
.markdown .code-toolbar:focus-within .toolbar-item {
opacity: 1;
}
.markdown .code-toolbar .toolbar-item > * {
padding: 0.25rem 0.35rem;
color: var(--theme--text_secondary);
font-size: 11px;
font-family: inherit;
}
.markdown .code-toolbar .toolbar-item .copy-to-clipboard-button {
border: none;
background: none;
cursor: pointer;
border-radius: 3px;
transition: background 100ms ease-in-out;
}
.markdown .code-toolbar .toolbar-item .copy-to-clipboard-button:hover {
background: var(--theme--button-hover);
}
.markdown .code-toolbar .toolbar-item .copy-to-clipboard-button svg {
width: 1em;
margin-right: 0.5em;
}

View File

@ -1,25 +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
*/
::selection {
background: var(--theme--accent_blue-selection);
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
background: transparent;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-corner {
background: var(--theme--scrollbar_track) !important;
}
::-webkit-scrollbar-thumb {
background: var(--theme--scrollbar_thumb) !important;
}
::-webkit-scrollbar-thumb:hover {
background: var(--theme--scrollbar_thumb-hover) !important;
}

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>notion-enhancer menu</title>
</head>
<body>
<script src="./menu.mjs" type="module"></script>
</body>
</html>

View File

@ -1,370 +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 { env, fs, storage, registry, web, components } from '../../api/_.mjs';
import { notifications } from './notifications.mjs';
import { blocks, options } from './blocks.mjs';
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);
const loadTheme = async () => {
document.documentElement.className =
(await storage.get(['theme'], 'light')) === 'dark' ? 'dark' : '';
};
document.addEventListener('visibilitychange', loadTheme);
loadTheme();
window.addEventListener('beforeunload', (event) => {
// trigger input save
document.activeElement.blur();
});
const $main = web.html`<main class="main"></main>`,
$sidebar = web.html`<article class="sidebar"></article>`,
$options = web.html`<div class="options-container">
<p class="options-placeholder">Select a mod to view and configure its options.</p>
</div>`,
$profile = web.html`<button class="profile-trigger">
Profile: ${web.escape(profileName)}
</button>`;
let _$profileConfig;
$profile.addEventListener('click', async (event) => {
for (const $selected of document.querySelectorAll('.mod-selected')) {
$selected.className = 'mod';
}
if (!_$profileConfig) {
const profileNames = [
...new Set([
...Object.keys(await storage.get(['profiles'], { default: {} })),
profileName,
]),
],
$options = profileNames.map(
(profile) => web.raw`<option
class="select-option"
value="${web.escape(profile)}"
${profile === profileName ? 'selected' : ''}
>${web.escape(profile)}</option>`
),
$select = web.html`<select class="input">
<option class="select-option" value="--">-- new --</option>
${$options.join('')}
</select>`,
$edit = web.html`<input
type="text"
class="input"
value="${web.escape(profileName)}"
pattern="/^[A-Za-z0-9_-]+$/"
>`,
$export = web.html`<button class="profile-export">
${await components.feather('download', { class: 'profile-icon-action' })}
</button>`,
$import = web.html`<label class="profile-import">
<input type="file" class="hidden" accept="application/json">
${await components.feather('upload', { class: 'profile-icon-action' })}
</label>`,
$save = web.html`<button class="profile-save">
${await components.feather('save', { class: 'profile-icon-text' })} Save
</button>`,
$delete = web.html`<button class="profile-delete">
${await components.feather('trash-2', { class: 'profile-icon-text' })} Delete
</button>`,
$error = web.html`<p class="profile-error"></p>`;
$export.addEventListener('click', async (event) => {
const now = new Date(),
$a = web.html`<a
class="hidden"
download="notion-enhancer_${web.escape($select.value)}_${now.getFullYear()}-${
now.getMonth() + 1
}-${now.getDate()}.json"
href="data:text/plain;charset=utf-8,${encodeURIComponent(
JSON.stringify(await storage.get(['profiles', $select.value], {}), null, 2)
)}"
></a>`;
web.render(document.body, $a);
$a.click();
$a.remove();
});
$import.addEventListener('change', (event) => {
const file = event.target.files[0],
reader = new FileReader();
reader.onload = async (progress) => {
try {
const profileUpload = JSON.parse(progress.currentTarget.result);
if (!profileUpload) throw Error;
await storage.set(['profiles', $select.value], profileUpload);
env.reload();
} catch {
web.render(web.empty($error), 'Invalid JSON uploaded.');
}
};
reader.readAsText(file);
});
$select.addEventListener('change', async (event) => {
if ($select.value === '--') {
$edit.value = '';
} else $edit.value = $select.value;
});
$save.addEventListener('click', async (event) => {
if (profileNames.includes($edit.value) && $select.value !== $edit.value) {
web.render(
web.empty($error),
`The profile "${web.escape($edit.value)}" already exists.`
);
return false;
}
if (!$edit.value) {
web.render(web.empty($error), 'Profile names cannot be empty.');
return false;
}
if (!$edit.value.match(/^[A-Za-z0-9_-]+$/)) {
web.render(
web.empty($error),
'Profile names can only contain letters, numbers, dashes and underscores.'
);
return false;
}
await storage.set(['currentprofile'], $edit.value);
if ($select.value === '--') {
await storage.set(['profiles', $edit.value], {});
} else if ($select.value !== $edit.value) {
await storage.set(
['profiles', $edit.value],
await storage.get(['profiles', $select.value], {})
);
await storage.set(['profiles', $select.value], undefined);
}
env.reload();
});
$delete.addEventListener('click', async (event) => {
await storage.set(['profiles', $select.value], undefined);
await storage.set(
['currentprofile'],
profileNames.find((profile) => profile !== $select.value) || 'default'
);
env.reload();
});
_$profileConfig = web.render(
web.html`<div></div>`,
web.html`<p class="options-placeholder">
Profiles are used to switch entire configurations.
Here they can be selected, renamed or deleted.
Profile names can only contain letters, numbers,
dashes and underscores. <br>
Be careful - deleting a profile deletes all configuration
related to it.
</p>`,
web.render(
web.html`<label class="input-label"></label>`,
$select,
web.html`${await components.feather('chevron-down', { class: 'input-icon' })}`
),
web.render(
web.html`<label class="input-label"></label>`,
$edit,
web.html`${await components.feather('type', { class: 'input-icon' })}`
),
web.render(web.html`<p class="profile-actions"></p>`, $export, $import, $save, $delete),
$error
);
}
web.render(web.empty($options), _$profileConfig);
});
const _$modListCache = {},
generators = {
options: async (mod) => {
const $fragment = document.createDocumentFragment();
for (const opt of mod.options) {
web.render($fragment, await options[opt.type](mod, opt));
}
if (!mod.options.length) {
web.render($fragment, web.html`<p class="options-placeholder">No options.</p>`);
}
return $fragment;
},
mod: async (mod) => {
const $mod = web.html`<div class="mod" data-id="${web.escape(mod.id)}"></div>`,
$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',
id = mod.id,
mods = await registry.list(
(mod) =>
mod.environments.includes(env.name) &&
mod.tags.includes('theme') &&
mod.tags.includes(mode) &&
mod.id !== id
);
for (const mod of mods) {
profileDB.set(['_mods', mod.id], false);
document.querySelector(
`[data-id="${web.escape(mod.id)}"] .toggle-check`
).checked = false;
}
}
profileDB.set(['_mods', mod.id], event.target.checked);
notifications.onChange();
});
$mod.addEventListener('click', async (event) => {
if ($mod.className === 'mod-selected') return;
for (const $selected of document.querySelectorAll('.mod-selected')) {
$selected.className = 'mod';
}
$mod.className = 'mod-selected';
const fragment = [
web.render(blocks.title(mod.name), blocks.version(mod.version)),
blocks.tags(mod.tags),
await generators.options(mod),
];
web.render(web.empty($options), ...fragment);
});
return web.render(
web.html`<article class="mod-container"></article>`,
web.render(
$mod,
mod.preview
? blocks.preview(
mod.preview.startsWith('http')
? mod.preview
: fs.localPath(`repo/${mod._dir}/${mod.preview}`)
)
: '',
web.render(
web.html`<div class="mod-body"></div>`,
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
: ''
)
)
);
},
modList: async (category, message = '') => {
if (!_$modListCache[category]) {
const $search = web.html`<input type="search" class="search"
placeholder="Search ('/' to focus)">`,
$list = web.html`<div class="mods-list"></div>`,
mods = await registry.list(
(mod) => mod.environments.includes(env.name) && mod.tags.includes(category)
);
web.addHotkeyListener(['/'], () => $search.focus());
$search.addEventListener('input', (event) => {
const query = $search.value.toLowerCase();
for (const $mod of $list.children) {
const matches = !query || $mod.innerText.toLowerCase().includes(query);
$mod.classList[matches ? 'remove' : 'add']('hidden');
}
});
for (const mod of mods) {
mod.tags = mod.tags.filter((tag) => tag !== category);
web.render($list, await generators.mod(mod));
mod.tags.unshift(category);
}
_$modListCache[category] = web.render(
web.html`<div></div>`,
web.render(
web.html`<label class="search-container"></label>`,
$search,
web.html`${await components.feather('search', { class: 'input-icon' })}`
),
message ? web.html`<p class="main-message">${web.escape(message)}</p>` : '',
$list
);
}
return _$modListCache[category];
},
};
const $notionNavItem = web.html`<h1 class="nav-notion">
${(await fs.getText('icon/colour.svg')).replace(
/width="\d+" height="\d+"/,
`class="nav-notion-icon"`
)}
<span>notion-enhancer</span>
</h1>`;
$notionNavItem.addEventListener('click', env.focusNotion);
const $coreNavItem = web.html`<a href="?view=core" class="nav-item">core</a>`,
$extensionsNavItem = web.html`<a href="?view=extensions" class="nav-item">extensions</a>`,
$themesNavItem = web.html`<a href="?view=themes" class="nav-item">themes</a>`;
web.render(
document.body,
web.render(
web.html`<div class="body-container"></div>`,
web.render(
web.html`<div class="content-container"></div>`,
web.render(
web.html`<nav class="nav"></nav>`,
$notionNavItem,
$coreNavItem,
$extensionsNavItem,
$themesNavItem,
web.html`<a href="https://notion-enhancer.github.io" class="nav-item">docs</a>`,
web.html`<a href="https://discord.gg/sFWPXtA" class="nav-item">community</a>`
),
$main
),
web.render($sidebar, $profile, $options)
)
);
function selectNavItem($item) {
for (const $selected of document.querySelectorAll('.nav-item-selected')) {
$selected.className = 'nav-item';
}
$item.className = 'nav-item-selected';
}
import * as router from './router.mjs';
router.addView('core', async () => {
web.empty($main);
selectNavItem($coreNavItem);
return web.render($main, await generators.modList('core'));
});
router.addView('extensions', async () => {
web.empty($main);
selectNavItem($extensionsNavItem);
return web.render($main, await generators.modList('extension'));
});
router.addView('themes', async () => {
web.empty($main);
selectNavItem($themesNavItem);
return web.render(
$main,
await generators.modList(
'theme',
`Dark themes will only work when Notion is in dark mode,
and light themes will only work when Notion is in light mode.
Only one theme of each mode can be enabled at a time.`
)
);
});
router.loadView('extensions', $main);

View File

@ -1,31 +0,0 @@
{
"name": "menu",
"id": "a6621988-551d-495a-97d8-3c568bca2e9e",
"version": "0.11.0",
"description": "the enhancer's graphical menu, related buttons and shortcuts.",
"tags": ["core"],
"authors": [
{
"name": "dragonwocky",
"email": "thedragonring.bod@gmail.com",
"homepage": "https://dragonwocky.me/",
"avatar": "https://dragonwocky.me/avatar.jpg"
}
],
"css": {
"client": ["client.css"],
"menu": ["menu.css", "markdown.css"]
},
"js": {
"client": ["client.mjs"]
},
"options": [
{
"type": "hotkey",
"key": "hotkey",
"label": "toggle focus hotkey",
"value": "Ctrl+Alt+E",
"tooltip": "switches between notion & the enhancer menu"
}
]
}

View File

@ -1,86 +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 { env, fs, storage, fmt, registry, web, components } from '../../api/_.mjs';
import { tw } from './styles.mjs';
export const notifications = {
$container: web.html`<div class="notifications-container"></div>`,
cache: await storage.get(['notifications'], []),
provider: [
registry.welcomeNotification,
...(await fs.getJSON('https://notion-enhancer.github.io/notifications.json')),
],
async add({ icon, message, id = undefined, color = undefined, link = undefined }) {
const $notification = link
? web.html`<a
href="${web.escape(link)}"
class="${tw`notification-${color || 'default'}`}"
role="alert"
target="_blank"
></a>`
: web.html`<p
class="${tw`notification-${color || 'default'}`}"
role="alert"
tabindex="0"
></p>`,
resolve = async () => {
if (id !== undefined) {
notifications.cache.push(id);
await storage.set(['notifications'], notifications.cache);
}
$notification.remove();
};
$notification.addEventListener('click', resolve);
$notification.addEventListener('keyup', (event) => {
if (['Enter', ' '].includes(event.key)) resolve();
});
web.render(
notifications.$container,
web.render(
$notification,
web.html`<span class="notification-text markdown-inline">
${fmt.md.renderInline(message)}
</span>`,
web.html`${await components.feather(icon, { class: 'notification-icon' })}`
)
);
return $notification;
},
_onChange: false,
async onChange() {
if (this._onChange) return;
this._onChange = true;
const $notification = await this.add({
icon: 'refresh-cw',
message: 'Reload to apply changes.',
});
$notification.addEventListener('click', env.reload);
},
};
web.render(document.body, notifications.$container);
for (const notification of notifications.provider) {
if (
!notifications.cache.includes(notification.id) &&
notification.version === env.version &&
(!notification.environments || notification.environments.includes(env.name))
) {
notifications.add(notification);
}
}
const errors = await registry.errors();
if (errors.length) {
console.log('[notion-enhancer] registry errors:');
console.table(errors);
notifications.add({
icon: 'alert-circle',
message: 'Failed to load mods (check console).',
color: 'red',
});
}

View File

@ -1,72 +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 { web } from '../../api/_.mjs';
let _defaultView = '';
const _views = new Map();
export function addView(name, loadFunc) {
_views.set(name, loadFunc);
}
export function removeView(name) {
_views.delete(name);
}
function router(event) {
event.preventDefault();
const anchor = event.path
? event.path.find((anchor) => anchor.nodeName === 'A')
: event.target;
if (location.search !== anchor.getAttribute('href')) {
window.history.pushState(null, null, anchor.href);
loadView();
}
}
function navigator(event) {
event.preventDefault();
const anchor = event.path
? event.path.find((anchor) => anchor.nodeName === 'A')
: event.target,
hash = anchor.getAttribute('href').slice(1);
document.getElementById(hash).scrollIntoView(true);
document.documentElement.scrollTop = 0;
history.replaceState({ search: location.search, hash }, null, `#${hash}`);
}
export async function loadView(defaultView = null) {
if (defaultView) _defaultView = defaultView;
if (!_defaultView) throw new Error('no view root set.');
const query = web.queryParams(),
fallbackView = () => {
window.history.replaceState(null, null, `?view=${_defaultView}`);
return loadView();
};
if (!query.get('view') || document.body.dataset.view !== query.get('view')) {
if (_views.get(query.get('view'))) {
await _views.get(query.get('view'))();
} else return fallbackView();
} else return fallbackView();
}
window.addEventListener('popstate', (event) => {
if (event.state) loadView();
document.getElementById(location.hash.slice(1))?.scrollIntoView(true);
document.documentElement.scrollTop = 0;
});
web.addDocumentObserver((mutation) => {
mutation.target.querySelectorAll('a[href^="?"]').forEach((a) => {
a.removeEventListener('click', router);
a.addEventListener('click', router);
});
mutation.target.querySelectorAll('a[href^="#"]').forEach((a) => {
a.removeEventListener('click', navigator);
a.addEventListener('click', navigator);
});
});

View File

@ -1,157 +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';
// css-in-js for better component generation
import { tw, apply, setup } from '../../dep/twind.mjs';
import { content } from '../../dep/twind-content.mjs';
const pseudoContent = content('""');
const mapColorVariables = (color) => ({
'text': `var(--theme--text_${color})`,
'highlight': `var(--theme--highlight_${color})`,
'highlight-text': `var(--theme--highlight_${color}-text)`,
'block': `var(--theme--block_${color})`,
'block-text': `var(--theme--block_${color}-text)`,
'tag': `var(--theme--tag_${color})`,
'tag-text': `var(--theme--tag_${color}-text)`,
'callout': `var(--theme--callout_${color})`,
'callout-text': `var(--theme--callout_${color}-text)`,
});
const customClasses = {
'notifications-container': apply`absolute bottom-0 right-0 px-4 py-3 max-w-full w-96`,
'notification': ([color = 'default']) =>
apply`p-2 ${
color === 'default'
? 'bg-tag text-tag-text hover:bg-interactive-hover border border-divider'
: `bg-${color}-tag text-${color}-tag-text border border-${color}-text hover:bg-${color}-text`
} flex items-center rounded-full mt-3 shadow-md cursor-pointer`,
'notification-text': apply`font-semibold text-xs mx-2 flex-auto`,
'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-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-active`,
'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-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`,
'mod': apply`relative h-full w-full flex flex-col overflow-hidden rounded-lg shadow-lg
bg-notion-secondary border border-divider cursor-pointer`,
'mod-selected': apply`mod ring ring-accent-blue-focus`,
'mod-body': apply`px-4 py-3 flex flex-col flex-auto children:cursor-pointer`,
'mod-preview': apply`object-cover w-full h-32`,
'mod-title': apply`mb-2 text-xl font-semibold tracking-tight flex items-center`,
'mod-version': apply`mt-px ml-3 p-1 font-normal text-xs leading-none bg-tag text-tag-text rounded`,
'mod-tags': apply`text-foreground-secondary mb-2 text-xs`,
'mod-description': apply`mb-2 text-sm`,
'mod-authors-container': apply`text-sm font-medium`,
'mod-author': apply`flex items-center mb-2`,
'mod-author-avatar': apply`inline object-cover w-5 h-5 rounded-full mr-2`,
'sidebar': apply`h-full w-96 px-4 pt-3 pb-32 flex flex-col bg-notion-secondary border-l border-divider`,
'profile-trigger': apply`block px-4 py-3 mb-2 rounded-md text-sm text-left font-semibold shadow-inner
bg-accent-red-hover border border-accent-red text-accent-red focus:(outline-none ring ring-inset ring-accent-red)`,
'profile-actions': apply`flex`,
'profile-save': apply`text-sm px-3 py-2 font-medium mt-2 bg-accent-blue text-accent-blue-text rounded-md flex-grow
hover:bg-accent-blue-hover focus:(bg-accent-blue-focus outline-none) text-center`,
'profile-delete': apply`text-sm px-3 py-2 font-medium ml-3 mt-2 bg-red-tag text-red-tag-text rounded-md flex-grow
border border-red-text hover:bg-red-text focus:(outline-none bg-red-text) text-center`,
'profile-export': apply`profile-save mr-2`,
'profile-import': apply`profile-save mr-2`,
'profile-error': apply`text-xs mt-2 text-red-text`,
'profile-icon-action': apply`w-4 h-4 -mt-1 inline-block`,
'profile-icon-text': apply`w-4 h-4 -mt-1 inline-block mr-1`,
'options-container': apply`px-4 py-3 shadow-inner rounded-lg bg-notion border border-divider space-y-3`,
'options-placeholder': apply`text-sm text-foreground-secondary`,
'toggle-box': apply`w-9 h-5 p-0.5 flex items-center bg-toggle-off rounded-full duration-300 ease-in-out cursor-pointer`,
'toggle-label': apply`relative text-sm flex w-full mt-auto`,
'toggle-check': apply`appearance-none ml-auto checked:sibling:(bg-toggle-on after::translate-x-4)`,
'toggle-feature': apply`after::(${pseudoContent} w-4 h-4 bg-toggle-feature rounded-full duration-300) cursor-pointer`,
'input-label': apply`block text-sm mt-2 relative`,
'input': apply`transition block w-full mt-2 pl-3 pr-14 py-2 text-sm rounded-md flex bg-input text-foreground
appearance-none placeholder-foreground-secondary ring-1 ring-divider focus:(outline-none ring ring-accent-blue-focus)`,
'input-tooltip': apply`h-4 w-4 -mt-1 inline-block mr-2`,
'input-icon': apply`absolute w-11 h-9 right-0 bottom-0 py-2 px-3 bg-notion-secondary rounded-r-md text-icon`,
'input-placeholder': apply`text-foreground-secondary`,
'select-option': apply`bg-notion-secondary`,
'file-latest': apply`block w-full text-left text-foreground-secondary text-xs mt-2 hover:line-through cursor-pointer`,
'search-container': apply`block mx-2.5 my-2.5 relative`,
'search': apply`input pr-12`,
};
setup({
preflight: {
html: apply`w-full h-full`,
body: apply`w-full h-full bg-notion font-sans text-foreground`,
},
theme: {
fontFamily: {
sans: ['var(--theme--font_sans)'],
mono: ['var(--theme--font_mono)'],
},
colors: {
'notion': 'var(--theme--bg)',
'notion-secondary': 'var(--theme--bg_secondary)',
'notion-popup': 'var(--theme--bg_popup)',
'divider': 'var(--theme--ui_divider)',
'input': 'var(--theme--ui_input)',
'icon': 'var(--theme--icon)',
'icon-secondary': 'var(--theme--icon_secondary)',
'foreground': 'var(--theme--text)',
'foreground-secondary': 'var(--theme--text_secondary)',
'interactive-hover': 'var(--theme--ui_interactive-hover)',
'interactive-active': 'var(--theme--ui_interactive-active)',
'tag': 'var(--theme--tag_default)',
'tag-text': 'var(--theme--tag_default-text)',
'toggle': {
'on': 'var(--theme--ui_toggle-on)',
'off': 'var(--theme--ui_toggle-off)',
'feature': 'var(--theme--ui_toggle-feature)',
},
'accent': {
'blue': 'var(--theme--accent_blue)',
'blue-hover': 'var(--theme--accent_blue-hover)',
'blue-focus': 'var(--theme--accent_blue-focus)',
'blue-text': 'var(--theme--accent_blue-text)',
'red': 'var(--theme--accent_red)',
'red-hover': 'var(--theme--accent_red-hover)',
'red-text': 'var(--theme--accent_red-text)',
},
'grey': mapColorVariables('grey'),
'brown': mapColorVariables('brown'),
'orange': mapColorVariables('orange'),
'yellow': mapColorVariables('yellow'),
'green': mapColorVariables('green'),
'blue': mapColorVariables('blue'),
'purple': mapColorVariables('purple'),
'pink': mapColorVariables('pink'),
'red': mapColorVariables('red'),
},
extend: {
width: {
'full-96': 'calc(100% - 24rem)',
},
maxHeight: {
'full-16': 'calc(100% - 4rem)',
'full-32': 'calc(100% - 8rem)',
'full-48': 'calc(100% - 12rem)',
'full-64': 'calc(100% - 16rem)',
},
},
},
plugins: customClasses,
});
tw`hidden ${Object.keys(customClasses).join(' ')}`;
export { tw };

View File

@ -1,8 +0,0 @@
[
"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"
]

View File

@ -1,20 +0,0 @@
/*
* notion-enhancer core: theming
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
export default function (api, db) {
const { web } = api;
const updateTheme = () =>
document.documentElement.classList[
document.body.classList.contains('dark') ? 'add' : 'remove'
]('dark');
updateTheme();
web.addDocumentObserver((mutation) => {
if (mutation.target === document.body) updateTheme();
});
}

View File

@ -1,24 +0,0 @@
{
"name": "theming",
"id": "0f0bf8b6-eae6-4273-b307-8fc43f2ee082",
"version": "0.11.0",
"description": "the default theme variables, required by other themes & extensions.",
"tags": ["core"],
"authors": [
{
"name": "dragonwocky",
"email": "thedragonring.bod@gmail.com",
"homepage": "https://dragonwocky.me/",
"avatar": "https://dragonwocky.me/avatar.jpg"
}
],
"css": {
"frame": ["variables.css"],
"client": ["variables.css", "prism.css", "theme.css"],
"menu": ["variables.css", "prism.css"]
},
"js": {
"client": ["client.mjs"]
},
"options": []
}

View File

@ -1,156 +0,0 @@
/*
* notion-enhancer core: theming
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
.token.property {
color: var(--theme--code_property) !important;
}
.token.tag {
color: var(--theme--code_tag) !important;
}
.token.boolean {
color: var(--theme--code_boolean) !important;
}
.token.number {
color: var(--theme--code_number) !important;
}
.token.constant {
color: var(--theme--code_constant) !important;
}
.token.symbol {
color: var(--theme--code_symbol) !important;
}
.token.deleted {
color: var(--theme--code_deleted) !important;
}
.token.selector {
color: var(--theme--code_selector) !important;
}
.token.attr-name {
color: var(--theme--code_attr-name) !important;
}
.token.string {
color: var(--theme--code_string) !important;
}
.token.char {
color: var(--theme--code_char) !important;
}
.token.builtin {
color: var(--theme--code_builtin) !important;
}
.token.inserted {
color: var(--theme--code_inserted) !important;
}
.token.operator {
color: var(--theme--code_operator) !important;
}
.token.entity {
color: var(--theme--code_entity) !important;
}
.token.url {
color: var(--theme--code_url) !important;
}
.token.variable {
color: var(--theme--code_variable) !important;
}
.token.comment {
color: var(--theme--code_comment) !important;
}
.token.cdata {
color: var(--theme--code_cdata) !important;
}
.token.prolog {
color: var(--theme--code_prolog) !important;
}
.token.doctype {
color: var(--theme--code_doctype) !important;
}
.token.atrule {
color: var(--theme--code_atrule) !important;
}
.token.attr-value {
color: var(--theme--code_attr-value) !important;
}
.token.keyword {
color: var(--theme--code_keyword) !important;
}
.token.regex {
color: var(--theme--code_regex) !important;
}
.token.important {
color: var(--theme--code_important) !important;
}
.token.function {
color: var(--theme--code_function) !important;
}
.token.class-name {
color: var(--theme--code_class-name) !important;
}
.token.parameter {
color: var(--theme--code_parameter) !important;
}
.token.decorator {
color: var(--theme--code_decorator) !important;
}
.token.id {
color: var(--theme--code_id) !important;
}
.token.class {
color: var(--theme--code_class) !important;
}
.token.pseudo-element {
color: var(--theme--code_pseudo-element) !important;
}
.token.pseudo-class {
color: var(--theme--code_pseudo-class) !important;
}
.token.attribute {
color: var(--theme--code_attribute) !important;
}
.token.value {
color: var(--theme--code_value) !important;
}
.token.unit {
color: var(--theme--code_unit) !important;
}
.token.punctuation {
color: var(--theme--code_punctuation) !important;
opacity: 0.7 !important;
}
.token.annotation {
color: var(--theme--code_annotation) !important;
}
.token.operator {
background: transparent !important;
}
.token.namespace {
opacity: 0.7 !important;
}
.token.important,
.token.bold {
font-weight: bold !important;
}
.token.italic {
font-style: italic !important;
}
.token.entity {
cursor: help !important;
}
.token a {
color: inherit !important;
}
.token.punctuation.brace-hover,
.token.punctuation.brace-selected {
outline: solid 1px !important;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
background: none !important;
}

View File

@ -1,364 +0,0 @@
/*
* notion-enhancer core: theming
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*
* (rgb|hsl|#)[^;]+;
*/
:root {
--theme--page-padding: calc(96px + env(safe-area-inset-left));
--theme--page-width: 900px;
--theme--page-width_full: 100%;
--theme--page_banner-height: 30vh;
--theme--page_preview-padding: 8rem;
--theme--page_preview-width: 977px;
--theme--page_preview_banner-height: 20vh;
--theme--font_sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica,
'Apple Color Emoji', Arial, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol';
--theme--font_serif: Lyon-Text, Georgia, YuMincho, 'Yu Mincho', 'Hiragino Mincho ProN',
'Hiragino Mincho Pro', 'Songti TC', 'Songti SC', SimSun, 'Nanum Myeongjo', NanumMyeongjo,
Batang, serif;
--theme--font_mono: iawriter-mono, Nitti, Menlo, Courier, monospace;
--theme--font_code: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace;
--theme--font_quote: var(--theme--font_sans);
--theme--font_headings: var(--theme--font_sans);
--theme--accent_blue: rgb(46, 170, 220);
--theme--accent_blue-selection: rgb(46, 170, 220, 0.25);
--theme--accent_blue-hover: rgb(6, 156, 205);
--theme--accent_blue-focus: rgb(0, 141, 190);
--theme--accent_blue-text: #fff;
--theme--accent_red: #eb5757;
--theme--accent_red-hover: rgba(235, 87, 87, 0.1);
--theme--accent_red-text: #fff;
}
:root {
--theme--bg: #fff;
--theme--bg_secondary: rgb(247, 246, 243);
--theme--bg_popup: #fff;
--theme--scrollbar_track: #edece9;
--theme--scrollbar_thumb: #d3d1cb;
--theme--scrollbar_thumb-hover: #aeaca6;
--theme--ui_shadow: rgba(15, 15, 15, 0.15);
--theme--ui_divider: rgb(237, 237, 236);
--theme--ui_interactive-hover: rgba(55, 53, 47, 0.08);
--theme--ui_interactive-active: rgba(55, 53, 47, 0.16);
--theme--ui_toggle-on: var(--theme--accent_blue);
--theme--ui_toggle-off: rgba(135, 131, 120, 0.3);
--theme--ui_toggle-feature: #fff;
--theme--ui_input: rgba(242, 241, 238, 0.6);
--theme--ui_tooltip: rgb(15, 15, 15);
--theme--ui_tooltip-title: rgba(255, 255, 255, 0.9);
--theme--ui_tooltip-description: rgba(206, 205, 202, 0.6);
--theme--icon: rgba(55, 53, 47, 0.8);
--theme--icon_secondary: rgba(55, 53, 47, 0.4);
--theme--text: rgb(55, 43, 47);
--theme--text_secondary: rgba(55, 43, 47, 0.6);
--theme--text_grey: rgb(155, 154, 151);
--theme--text_brown: rgb(100, 71, 58);
--theme--text_orange: rgb(217, 115, 13);
--theme--text_yellow: rgb(223, 171, 1);
--theme--text_green: rgb(15, 123, 108);
--theme--text_blue: rgb(11, 110, 153);
--theme--text_purple: rgb(105, 64, 165);
--theme--text_pink: rgb(173, 26, 114);
--theme--text_red: rgb(224, 62, 62);
--theme--highlight-text: var(--theme--text);
--theme--highlight_grey: rgb(235, 236, 237);
--theme--highlight_grey-text: var(--theme--highlight-text);
--theme--highlight_brown: rgb(233, 229, 227);
--theme--highlight_brown-text: var(--theme--highlight-text);
--theme--highlight_orange: rgb(250, 235, 221);
--theme--highlight_orange-text: var(--theme--highlight-text);
--theme--highlight_yellow: rgb(251, 243, 219);
--theme--highlight_yellow-text: var(--theme--highlight-text);
--theme--highlight_green: rgb(221, 237, 234);
--theme--highlight_green-text: var(--theme--highlight-text);
--theme--highlight_blue: rgb(221, 235, 241);
--theme--highlight_blue-text: var(--theme--highlight-text);
--theme--highlight_purple: rgb(234, 228, 242);
--theme--highlight_purple-text: var(--theme--highlight-text);
--theme--highlight_pink: rgb(244, 223, 235);
--theme--highlight_pink-text: var(--theme--highlight-text);
--theme--highlight_red: rgb(251, 228, 228);
--theme--highlight_red-text: var(--theme--highlight-text);
--theme--block-text: var(--theme--text);
--theme--block_grey: rgb(235, 236, 237);
--theme--block_grey-text: var(--theme--block-text);
--theme--block_brown: rgb(233, 229, 227);
--theme--block_brown-text: var(--theme--block-text);
--theme--block_orange: rgb(250, 235, 221);
--theme--block_orange-text: var(--theme--block-text);
--theme--block_yellow: rgb(251, 243, 219);
--theme--block_yellow-text: var(--theme--block-text);
--theme--block_green: rgb(221, 237, 234);
--theme--block_green-text: var(--theme--block-text);
--theme--block_blue: rgb(221, 235, 241);
--theme--block_blue-text: var(--theme--block-text);
--theme--block_purple: rgb(234, 228, 242);
--theme--block_purple-text: var(--theme--block-text);
--theme--block_pink: rgb(244, 223, 235);
--theme--block_pink-text: var(--theme--block-text);
--theme--block_red: rgb(251, 228, 228);
--theme--block_red-text: var(--theme--block-text);
--theme--tag-text: var(--theme--text);
--theme--tag_default: rgba(206, 205, 202, 0.5);
--theme--tag_default-text: var(--theme--tag-text);
--theme--tag_grey: rgba(140, 46, 0, 0.2);
--theme--tag_grey-text: var(--theme--tag-text);
--theme--tag_brown: rgba(140, 46, 0, 0.2);
--theme--tag_brown-text: var(--theme--tag-text);
--theme--tag_orange: rgba(245, 93, 0, 0.2);
--theme--tag_orange-text: var(--theme--tag-text);
--theme--tag_yellow: rgba(233, 168, 0, 0.2);
--theme--tag_yellow-text: var(--theme--tag-text);
--theme--tag_green: rgba(0, 135, 107, 0.2);
--theme--tag_green-text: var(--theme--tag-text);
--theme--tag_blue: rgba(0, 120, 223, 0.2);
--theme--tag_blue-text: var(--theme--tag-text);
--theme--tag_purple: rgba(103, 36, 222, 0.2);
--theme--tag_purple-text: var(--theme--tag-text);
--theme--tag_pink: rgba(221, 0, 129, 0.2);
--theme--tag_pink-text: var(--theme--tag-text);
--theme--tag_red: rgba(255, 0, 26, 0.2);
--theme--tag_red-text: var(--theme--tag-text);
--theme--callout-text: var(--theme--text);
--theme--callout_grey: rgba(235, 236, 237, 0.3);
--theme--callout_grey-text: var(--theme--callout-text);
--theme--callout_brown: rgba(233, 229, 227, 0.3);
--theme--callout_brown-text: var(--theme--callout-text);
--theme--callout_orange: rgba(250, 235, 221, 0.3);
--theme--callout_orange-text: var(--theme--callout-text);
--theme--callout_yellow: rgba(251, 243, 219, 0.3);
--theme--callout_yellow-text: var(--theme--callout-text);
--theme--callout_green: rgba(221, 237, 234, 0.3);
--theme--callout_green-text: var(--theme--callout-text);
--theme--callout_blue: rgba(221, 235, 241, 0.3);
--theme--callout_blue-text: var(--theme--callout-text);
--theme--callout_purple: rgba(234, 228, 242, 0.3);
--theme--callout_purple-text: var(--theme--callout-text);
--theme--callout_pink: rgba(244, 223, 235, 0.3);
--theme--callout_pink-text: var(--theme--callout-text);
--theme--callout_red: rgba(251, 228, 228, 0.3);
--theme--callout_red-text: var(--theme--callout-text);
--theme--code_inline: rgba(135, 131, 120, 0.15);
--theme--code_inline-text: #eb5757;
--theme--code: #f7f6f3;
--theme--code_plain: var(--theme--text);
--theme--code_property: #905;
--theme--code_tag: var(--theme--code_property);
--theme--code_boolean: var(--theme--code_property);
--theme--code_number: var(--theme--code_property);
--theme--code_constant: var(--theme--code_property);
--theme--code_symbol: var(--theme--code_property);
--theme--code_deleted: var(--theme--code_property);
--theme--code_selector: #690;
--theme--code_attr-name: var(--theme--code_selector);
--theme--code_string: var(--theme--code_selector);
--theme--code_char: var(--theme--code_selector);
--theme--code_builtin: var(--theme--code_selector);
--theme--code_inserted: var(--theme--code_selector);
--theme--code_operator: #9a6e3a;
--theme--code_entity: var(--theme--code_operator);
--theme--code_url: var(--theme--code_operator);
--theme--code_variable: var(--theme--code_regex);
--theme--code_comment: slategrey;
--theme--code_cdata: var(--theme--code_comment);
--theme--code_prolog: var(--theme--code_comment);
--theme--code_doctype: var(--theme--code_comment);
--theme--code_atrule: #07a;
--theme--code_attr-value: var(--theme--code_atrule);
--theme--code_keyword: var(--theme--code_atrule);
--theme--code_regex: #e90;
--theme--code_important: var(--theme--code_regex);
--theme--code_function: #dd4a68;
--theme--code_class-name: var(--theme--code_function);
--theme--code_parameter: var(--theme--code_plain);
--theme--code_decorator: var(--theme--code_plain);
--theme--code_id: var(--theme--code_plain);
--theme--code_class: var(--theme--code_plain);
--theme--code_pseudo-element: var(--theme--code_plain);
--theme--code_pseudo-class: var(--theme--code_plain);
--theme--code_attribute: var(--theme--code_plain);
--theme--code_value: var(--theme--code_plain);
--theme--code_unit: var(--theme--code_plain);
--theme--code_punctuation: #999;
--theme--code_annotation: var(--theme--code_plain);
}
:root.dark {
--theme--bg: rgb(47, 52, 55);
--theme--bg_secondary: rgb(55, 60, 63);
--theme--bg_popup: rgb(63, 68, 71);
--theme--scrollbar_track: rgba(202, 204, 206, 0.04);
--theme--scrollbar_thumb: #474c50;
--theme--scrollbar_thumb-hover: rgba(202, 204, 206, 0.3);
--theme--ui_shadow: rgba(15, 15, 15, 0.15);
--theme--ui_divider: rgb(255, 255, 255, 0.07);
--theme--ui_interactive-hover: rgb(71, 76, 80);
--theme--ui_interactive-active: rgb(63, 68, 71);
--theme--ui_toggle-on: var(--theme--accent_blue);
--theme--ui_toggle-off: rgba(202, 204, 206, 0.3);
--theme--ui_toggle-feature: #fff;
--theme--ui_input: rgba(15, 15, 15, 0.3);
--theme--ui_tooltip: rgb(202, 204, 206);
--theme--ui_tooltip-title: rgb(15, 15, 15);
--theme--ui_tooltip-description: rgba(47, 52, 55, 0.6);
--theme--icon: rgba(202, 204, 206);
--theme--icon_secondary: rgb(202, 204, 206, 0.6);
--theme--text: rgba(255, 255, 255, 0.9);
--theme--text_secondary: rgba(255, 255, 255, 0.6);
--theme--text_grey: rgba(151, 154, 155, 0.95);
--theme--text_brown: rgb(147, 114, 100);
--theme--text_orange: rgb(255, 163, 68);
--theme--text_yellow: rgb(255, 220, 73);
--theme--text_green: rgb(77, 171, 154);
--theme--text_blue: rgb(82, 156, 202);
--theme--text_purple: rgb(154, 109, 215);
--theme--text_pink: rgb(226, 85, 161);
--theme--text_red: rgb(255, 115, 105);
--theme--highlight-text: var(--theme--text);
--theme--highlight_grey: rgb(69, 75, 78);
--theme--highlight_grey-text: var(--theme--highlight-text);
--theme--highlight_brown: rgb(67, 64, 64);
--theme--highlight_brown-text: var(--theme--highlight-text);
--theme--highlight_orange: rgb(89, 74, 58);
--theme--highlight_orange-text: var(--theme--highlight-text);
--theme--highlight_yellow: rgb(89, 86, 59);
--theme--highlight_yellow-text: var(--theme--highlight-text);
--theme--highlight_green: rgb(53, 76, 75);
--theme--highlight_green-text: var(--theme--highlight-text);
--theme--highlight_blue: rgb(54, 73, 84);
--theme--highlight_blue-text: var(--theme--highlight-text);
--theme--highlight_purple: rgb(68, 63, 87);
--theme--highlight_purple-text: var(--theme--highlight-text);
--theme--highlight_pink: rgb(83, 59, 76);
--theme--highlight_pink-text: var(--theme--highlight-text);
--theme--highlight_red: rgb(89, 65, 65);
--theme--highlight_red-text: var(--theme--highlight-text);
--theme--block-text: var(--theme--text);
--theme--block_grey: rgb(69, 75, 78);
--theme--block_grey-text: var(--theme--block-text);
--theme--block_brown: rgb(67, 64, 64);
--theme--block_brown-text: var(--theme--block-text);
--theme--block_orange: rgb(89, 74, 58);
--theme--block_orange-text: var(--theme--block-text);
--theme--block_yellow: rgb(89, 86, 59);
--theme--block_yellow-text: var(--theme--block-text);
--theme--block_green: rgb(53, 76, 75);
--theme--block_green-text: var(--theme--block-text);
--theme--block_blue: rgb(54, 73, 84);
--theme--block_blue-text: var(--theme--block-text);
--theme--block_purple: rgb(68, 63, 87);
--theme--block_purple-text: var(--theme--block-text);
--theme--block_pink: rgb(83, 59, 76);
--theme--block_pink-text: var(--theme--block-text);
--theme--block_red: rgb(89, 65, 65);
--theme--block_red-text: var(--theme--block-text);
--theme--tag-text: var(--theme--text);
--theme--tag_default: rgb(80, 85, 88);
--theme--tag_default-text: var(--theme--tag-text);
--theme--tag_grey: rgba(151, 154, 155, 0.5);
--theme--tag_grey-text: var(--theme--tag-text);
--theme--tag_brown: rgba(147, 114, 100, 0.5);
--theme--tag_brown-text: var(--theme--tag-text);
--theme--tag_orange: rgba(255, 163, 68, 0.5);
--theme--tag_orange-text: var(--theme--tag-text);
--theme--tag_yellow: rgba(255, 220, 73, 0.5);
--theme--tag_yellow-text: var(--theme--tag-text);
--theme--tag_green: rgba(77, 171, 154, 0.5);
--theme--tag_green-text: var(--theme--tag-text);
--theme--tag_blue: rgba(82, 156, 202, 0.5);
--theme--tag_blue-text: var(--theme--tag-text);
--theme--tag_purple: rgba(154, 109, 215, 0.5);
--theme--tag_purple-text: var(--theme--tag-text);
--theme--tag_pink: rgba(226, 85, 161, 0.5);
--theme--tag_pink-text: var(--theme--tag-text);
--theme--tag_red: rgba(255, 115, 105, 0.5);
--theme--tag_red-text: var(--theme--tag-text);
--theme--callout-text: var(--theme--text);
--theme--callout_grey: rgba(69, 75, 78, 0.3);
--theme--callout_grey-text: var(--theme--callout-text);
--theme--callout_brown: rgba(67, 64, 64, 0.3);
--theme--callout_brown-text: var(--theme--callout-text);
--theme--callout_orange: rgba(89, 74, 58, 0.3);
--theme--callout_orange-text: var(--theme--callout-text);
--theme--callout_yellow: rgba(89, 86, 59, 0.3);
--theme--callout_yellow-text: var(--theme--callout-text);
--theme--callout_green: rgba(53, 76, 75, 0.3);
--theme--callout_green-text: var(--theme--callout-text);
--theme--callout_blue: rgba(54, 73, 84, 0.3);
--theme--callout_blue-text: var(--theme--callout-text);
--theme--callout_purple: rgba(68, 63, 87, 0.3);
--theme--callout_purple-text: var(--theme--callout-text);
--theme--callout_pink: rgba(83, 59, 76, 0.3);
--theme--callout_pink-text: var(--theme--callout-text);
--theme--callout_red: rgba(89, 65, 65, 0.3);
--theme--callout_red-text: var(--theme--callout-text);
--theme--code_inline: rgba(135, 131, 120, 0.15);
--theme--code_inline-text: #eb5757;
--theme--code: rgb(63, 68, 71);
--theme--code_plain: var(--theme--text);
--theme--code_property: hsl(350, 40%, 70%);
--theme--code_tag: var(--theme--code_property);
--theme--code_boolean: var(--theme--code_property);
--theme--code_number: var(--theme--code_property);
--theme--code_constant: var(--theme--code_property);
--theme--code_symbol: var(--theme--code_property);
--theme--code_deleted: #f00;
--theme--code_selector: hsl(75, 70%, 60%);
--theme--code_attr-name: var(--theme--code_selector);
--theme--code_string: var(--theme--code_selector);
--theme--code_char: var(--theme--code_selector);
--theme--code_builtin: var(--theme--code_selector);
--theme--code_inserted: var(--theme--code_selector);
--theme--code_operator: hsl(40, 90%, 60%);
--theme--code_entity: var(--theme--code_operator);
--theme--code_url: var(--theme--code_operator);
--theme--code_variable: var(--theme--code_operator);
--theme--code_comment: hsl(30, 20%, 50%);
--theme--code_cdata: var(--theme--code_comment);
--theme--code_prolog: var(--theme--code_comment);
--theme--code_doctype: var(--theme--code_comment);
--theme--code_atrule: hsl(350, 40%, 70%);
--theme--code_attr-value: var(--theme--code_atrule);
--theme--code_keyword: var(--theme--code_atrule);
--theme--code_regex: #e90;
--theme--code_important: var(--theme--code_regex);
--theme--code_function: var(--theme--code_plain);
--theme--code_class-name: var(--theme--code_function);
--theme--code_parameter: var(--theme--code_plain);
--theme--code_decorator: var(--theme--code_plain);
--theme--code_id: var(--theme--code_plain);
--theme--code_class: var(--theme--code_plain);
--theme--code_pseudo-element: var(--theme--code_plain);
--theme--code_pseudo-class: var(--theme--code_plain);
--theme--code_attribute: var(--theme--code_plain);
--theme--code_value: var(--theme--code_plain);
--theme--code_unit: var(--theme--code_plain);
--theme--code_punctuation: var(--theme--code_plain);
--theme--code_annotation: var(--theme--code_plain);
}

View File

@ -1,61 +0,0 @@
/*
* notion-enhancer: tweaks
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (c) 2020 arecsu
* (https://notion-enhancer.github.io/) under the MIT license
*/
.tweak--snappy_transitions * {
animation-duration: 0s !important;
transition-duration: 0s !important;
}
.tweak--snappy_transitions .notion-selectable-halo {
opacity: 1 !important;
}
.tweak--hide_help .notion-help-button {
display: none !important;
}
.tweak--thicker_bold .notion-page-content span[style*='font-weight:600'] {
font-weight: 700 !important;
}
.tweak--spaced_lines .notion-page-content .notion-selectable.notion-text-block {
line-height: 1.65 !important;
margin-top: 0.75em !important;
}
.tweak--condensed_bullets .notion-selectable.notion-bulleted_list-block {
margin-top: -1.5px !important;
margin-bottom: -1.5px !important;
}
.tweak--responsive_breakpoint .notion-column_list-block [style='display: flex;'] > div {
width: 100% !important;
}
.tweak--responsive_breakpoint .notion-column_list-block [style='display: flex;'] {
flex-direction: column !important;
}
.tweak--responsive_breakpoint .notion-app-inner {
--theme--page-width: 100%;
--theme--page-padding: calc(48px + env(safe-area-inset-left));
}
.tweak--bracketed_links .notion-link-token span {
border-bottom: none !important;
}
.tweak--bracketed_links .notion-link-token:before {
content: '[[';
opacity: 0.7;
transition: opacity 100ms ease-in;
}
.tweak--bracketed_links .notion-link-token:after {
content: ']]';
opacity: 0.7;
transition: opacity 100ms ease-in;
}
.tweak--bracketed_links .notion-link-token:hover::before,
.tweak--bracketed_links .notion-link-token:hover::after {
opacity: 1;
}

View File

@ -1,49 +0,0 @@
/*
* notion-enhancer: tweaks
* (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
* (https://notion-enhancer.github.io/) under the MIT license
*/
'use strict';
const _id = '5174a483-c88d-4bf8-a95f-35cd330b76e2';
import { env, storage, web } from '../../api/_.mjs';
web.whenReady().then(async () => {
const cssInsert = await storage.get(_id, '_file.insert.css');
if (cssInsert) {
document.body.append(
web.createElement(
web.html`
<style id="${await storage.get(_id, 'insert.css')}@${_id}">${cssInsert}</style>`
)
);
}
if (['linux', 'win32'].includes(env.name)) {
// dragarea_height
}
for (const tweak of [
'snappy_transitions',
'thicker_bold',
'spaced_lines',
'hide_help',
'condensed_bullets',
'bracketed_links',
]) {
if (await storage.get(_id, `tweak.${tweak}`)) {
document.body.classList.add(`tweak--${tweak}`);
}
}
const responsiveBreakpoint = await storage.get(_id, 'tweak.responsive_breakpoint'),
addResponsiveBreakpoint = () => {
document.body.classList.remove('tweak--responsive_breakpoint');
if (window.innerWidth <= responsiveBreakpoint) {
document.body.classList.add('tweak--responsive_breakpoint');
}
};
window.addEventListener('resize', addResponsiveBreakpoint);
addResponsiveBreakpoint();
});

View File

@ -1,84 +0,0 @@
{
"name": "tweaks",
"id": "5174a483-c88d-4bf8-a95f-35cd330b76e2",
"version": "0.2.0",
"description": "common style/layout changes and custom CSS insertion.",
"tags": ["extension", "customisation"],
"authors": [
{
"name": "dragonwocky",
"email": "thedragonring.bod@gmail.com",
"homepage": "https://dragonwocky.me/",
"avatar": "https://dragonwocky.me/avatar.jpg"
}
],
"css": {
"client": ["client.css"]
},
"js": {
"client": ["client.mjs"]
},
"options": [
{
"type": "file",
"key": "insert.css",
"label": "css insert",
"extensions": [".css"]
},
{
"key": "tweak.dragarea_height",
"label": "height of frameless dragarea:",
"tooltip": "the rectangle added at the top of a window in 'integrated titlebar' mode, used to drag/move the window.",
"type": "number",
"value": 15,
"environments": ["linux", "win32"]
},
{
"key": "tweak.responsive_breakpoint",
"label": "responsive columns breakpoint (px)",
"tooltip": "the width in pixels below which in-page columns are resized to appear full-width so content isn't squished.",
"type": "number",
"value": 600
},
{
"key": "tweak.snappy_transitions",
"label": "snappy transitions",
"tooltip": "set animation time for all css-driven animations to 0s. may not affect element motion e.g. the sidebar popping out.",
"type": "toggle",
"value": false
},
{
"key": "tweak.hide_help",
"label": "hide help button",
"type": "toggle",
"value": false
},
{
"key": "tweak.thicker_bold",
"label": "thicker bold text",
"type": "toggle",
"value": true
},
{
"key": "tweak.spaced_lines",
"label": "readable line spacing",
"tooltip": "greater line spacing between text blocks.",
"type": "toggle",
"value": false
},
{
"key": "tweak.condensed_bullets",
"label": "condense bullet points",
"tooltip": "tighter line spacing between bullet point blocks.",
"type": "toggle",
"value": false
},
{
"key": "tweak.bracketed_links",
"label": "bracketed links",
"tooltip": "render links surrounded with [[brackets]] instead of __underlined__.",
"type": "toggle",
"value": false
}
]
}

View File

@ -6,11 +6,9 @@
'use strict';
async function focusMenu() {
function focusMenu() {
chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT }, (tabs) => {
const url = chrome.runtime.getURL(
'repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.html'
),
const url = chrome.runtime.getURL('repo/menu/menu.html'),
menu = tabs.find((tab) => tab.url.startsWith(url));
if (menu) {
chrome.tabs.highlight({ 'tabs': menu.index });
@ -19,7 +17,7 @@ async function focusMenu() {
}
chrome.browserAction.onClicked.addListener(focusMenu);
async function focusNotion() {
function focusNotion() {
chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT }, (tabs) => {
const notion = tabs.find((tab) => {
const url = new URL(tab.url),
@ -32,11 +30,9 @@ async function focusNotion() {
});
}
async function reload() {
function reload() {
chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT }, (tabs) => {
const menu = chrome.runtime.getURL(
'repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.html'
);
const menu = chrome.runtime.getURL('repo/menu/menu.html');
tabs.forEach((tab) => {
const url = new URL(tab.url),
matches =