From 8f1612e43cd6d4eb5603c62d1033cb137cb4a923 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Wed, 30 Sep 2020 14:25:59 +1000 Subject: [PATCH 01/50] #126 board view shadow, remove messenger emoji set, bugfix EACCES response --- CHANGELOG.md | 7 +++++++ mods/core/css/theme.css | 11 ++++++++--- mods/emoji-sets/mod.js | 21 ++++++++++----------- mods/emoji-sets/styles.css | 5 ----- pkg/apply.js | 10 +++++++--- pkg/remove.js | 10 +++++++--- 6 files changed, 39 insertions(+), 25 deletions(-) delete mode 100644 mods/emoji-sets/styles.css diff --git a/CHANGELOG.md b/CHANGELOG.md index 49a8d6d..d59057e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ - [advanced math editor](https://github.com/Manueloccorso/NotionMathEditor_BrowserExtension) - re-orderable extensions +### v0.?.? (wip) + +- bugfix: removed messenger emoji set as the provider no longer supports it. +- bugfix: remove shadow around light mode board headers + \+ minor text colour fixes for night shift theming. +- bugfix: properly detect/respond to `EACCES` errors. + ### v0.9.1 (2020-09-26) - bugfix: font chooser will continue iterating through fonts after encountering a blank option. diff --git a/mods/core/css/theme.css b/mods/core/css/theme.css index 052c6c0..4cfc448 100644 --- a/mods/core/css/theme.css +++ b/mods/core/css/theme.css @@ -203,7 +203,9 @@ .notion-body.dark [style*='box-shadow: rgba(15, 15, 15, 0.2) 0px 0px 0px 1px, rgba(15, 15, 15, 0.2) 0px 2px 4px'], -.notion-body:not(.dark) [style*='box-shadow: white -3px 0px 0px'] { +.notion-body:not(.dark) + .notion-dark-theme + [style*='box-shadow: white -3px 0px 0px'] { box-shadow: rgba(15, 15, 15, 0.1) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 2px 4px !important; } @@ -425,8 +427,11 @@ .notion-page-content [style*='color: inherit;'], .notion-frame .notion-page-block, .notion-body.dark [style*=' color: rgba(255, 255, 255, 0.9)'], -.notion-body.dark [style*='color: rgba(255, 255, 255, 0.7)'], -.notion-body:not(.dark) [style*=' color: rgb(55, 53, 47);'] { +.notion-body.dark [style^='color: rgba(255, 255, 255, 0.9)'], +.notion-body.dark [style*=' color: rgba(255, 255, 255, 0.7)'], +.notion-body.dark [style^='color: rgba(255, 255, 255, 0.7)'], +.notion-body:not(.dark) [style*=' color: rgb(55, 53, 47);'], +.notion-body:not(.dark) [style^='color: rgb(55, 53, 47);'] { color: var(--theme--text) !important; } .notion-body.dark [style*='color: rgba(255, 255, 255, 0.6)'], diff --git a/mods/emoji-sets/mod.js b/mods/emoji-sets/mod.js index 289da8b..8ceb5b5 100644 --- a/mods/emoji-sets/mod.js +++ b/mods/emoji-sets/mod.js @@ -29,7 +29,6 @@ module.exports = { 'joypixels', 'openmoji', 'emojidex', - 'messenger', 'lg', 'htc', 'mozilla', @@ -109,6 +108,15 @@ module.exports = { el.style.display = 'none'; if (el.parentElement.getAttribute('contenteditable')) el.remove(); + } else if ( + el.previousElementSibling.matches( + 'span[role="image"][aria-label]' + ) + ) { + el.previousElementSibling.innerText = el.getAttribute( + 'alt' + ); + el.setAttribute('aria-label', el.getAttribute('alt')); } }); } else { @@ -116,11 +124,11 @@ module.exports = { el.parentElement .querySelectorAll('span[role="image"][aria-label]') .forEach((text) => text.remove()); + el.style.display = 'inline-block'; if (!el.style.background.includes(store().style)) { el.style.background = `url(https://emojicdn.elk.sh/${el.getAttribute( 'aria-label' )}?style=${store().style})`; - el.style.display = 'inline-block'; el.style.backgroundSize = 'contain'; el.style.backgroundRepeat = 'no-repeat'; el.style.opacity = 1; @@ -135,12 +143,3 @@ module.exports = { }, }, }; -// span[role="image"][aria-label] -/* */ - -//
-// 😀 -// 😀 -//
- -// ✝ diff --git a/mods/emoji-sets/styles.css b/mods/emoji-sets/styles.css deleted file mode 100644 index 600e758..0000000 --- a/mods/emoji-sets/styles.css +++ /dev/null @@ -1,5 +0,0 @@ -.notion-emoji::after { - content: attr(aria-label, ''); - width: 1em; - height: 1em; -} diff --git a/pkg/apply.js b/pkg/apply.js index 36f95ab..c49771f 100644 --- a/pkg/apply.js +++ b/pkg/apply.js @@ -112,11 +112,15 @@ module.exports = async function ({ overwrite_version, friendly_errors } = {}) { return true; } catch (err) { console.error('### ERROR ###'); - if (err.toString().includes('EACCESS') && friendly_errors) { + if (err.code === 'EACCES' && friendly_errors) { console.error( - 'file access forbidden: try again with sudo or in an elevated/admin prompt.' + `file access forbidden - ${ + process.platform === 'win32' + ? 'make sure your user has elevated permissions.' + : `try running "chown -R ${err.path}"` + }` ); - } else if (err.toString().includes('EIO') && friendly_errors) { + } else if (err.code === 'EIO' && friendly_errors) { console.error('file access failed: is notion running?'); } else console.error(err); return false; diff --git a/pkg/remove.js b/pkg/remove.js index bf28f00..16b32d1 100644 --- a/pkg/remove.js +++ b/pkg/remove.js @@ -114,11 +114,15 @@ module.exports = async function ({ return true; } catch (err) { console.error('### ERROR ###'); - if (err.toString().includes('EACCESS') && friendly_errors) { + if (err.code === 'EACCES' && friendly_errors) { console.error( - 'file access forbidden: try again with sudo or in an elevated/admin prompt.' + `file access forbidden - ${ + process.platform === 'win32' + ? 'make sure your user has elevated permissions.' + : `try running "chown -R ${err.path}"` + }` ); - } else if (err.toString().includes('EIO') && friendly_errors) { + } else if (err.code === 'EIO' && friendly_errors) { console.error('file access failed: is notion running?'); } else console.error(err); return false; From a3e8758280908bd1db430e397dcd74488692ad6b Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Wed, 30 Sep 2020 14:43:23 +1000 Subject: [PATCH 02/50] night shift checks every interaction to respond to system changes --- CHANGELOG.md | 2 ++ README.md | 2 +- mods/night-shift/mod.js | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d59057e..c11166c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ - bugfix: remove shadow around light mode board headers \+ minor text colour fixes for night shift theming. - bugfix: properly detect/respond to `EACCES` errors. +- bugfix: night shift checks every interaction, + will respond to system changes without any manual changes. ### v0.9.1 (2020-09-26) diff --git a/README.md b/README.md index 8a749d2..fdac56c 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ execute the following lines in the terminal: ``` bash curl -sL https://deb.nodesource.com setup_current.x | sudo -E bash - sudo apt-get install -y nodejs -sudo npm i -g notion-enhancer +npm i -g notion-enhancer ``` **arch linux, manjaro** diff --git a/mods/night-shift/mod.js b/mods/night-shift/mod.js index 51d5702..8014918 100644 --- a/mods/night-shift/mod.js +++ b/mods/night-shift/mod.js @@ -27,6 +27,7 @@ module.exports = { const observer = new MutationObserver(process); observer.observe(notion_elem, { attributes: true, + subtree: true, }); function process(list, observer) { const mode = `notion-app-inner notion-${ @@ -34,8 +35,7 @@ module.exports = { ? 'dark' : 'light' }-theme`; - if (list[0].target.className !== mode) - list[0].target.className = mode; + if (notion_elem.className !== mode) notion_elem.className = mode; } } }); From 4c480c5b5da03444b8619bb79b2dd08d37c88d72 Mon Sep 17 00:00:00 2001 From: blacksuan19 Date: Thu, 24 Sep 2020 13:46:27 +0800 Subject: [PATCH 03/50] mods: add material ocean theme Signed-off-by: blacksuan19 --- mods/material-ocean/mod.js | 16 +++++ mods/material-ocean/styles.css | 121 +++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 mods/material-ocean/mod.js create mode 100644 mods/material-ocean/styles.css diff --git a/mods/material-ocean/mod.js b/mods/material-ocean/mod.js new file mode 100644 index 0000000..e4a8b42 --- /dev/null +++ b/mods/material-ocean/mod.js @@ -0,0 +1,16 @@ +/* + * Material Ocean + * (c) 2020 Abubakar Yagoub (https://blacksuan19.tk) + * under GNU's GPL3 license + */ + +"use strict"; + +module.exports = { + id: "69e7ccb2-4aef-484c-876d-3de1b433d2b9", + tags: ["theme", "dark"], + name: "Material Ocean", + desc: "a Material theme with oceanic colors", + version: "0.1", + author: "blacksuan19", +}; diff --git a/mods/material-ocean/styles.css b/mods/material-ocean/styles.css new file mode 100644 index 0000000..02bc6f0 --- /dev/null +++ b/mods/material-ocean/styles.css @@ -0,0 +1,121 @@ +/* Copyright © Blacksuan19 @ 2020 */ +/* part of Material Ocean Color Scheme */ + +:root { + /* material ocean colors */ + --ocean-main: #0f111a; + --ocean-sec: #00010a; + --ocean-accent: #ff4151; + --ocean-gray: #e0e0e0; + --ocean-brown: #d8b6a6; + --ocean-orange: #fde3c0; + --ocean-yellow: #ebcb8b; + --ocean-green: #a3be8c; + --ocean-blue: #81a1c1; + --ocean-purple: #b48ead; + --ocean-pink: #ffc0cb; + --ocean-red: #bf616a; + + --theme_dark--main: var(--ocean-main); + --theme_dark--sidebar: var(--ocean-sec); + --theme_dark--overlay: var(--ocean-sec); + --theme_dark--dragarea: var(--ocean-sec); + + --theme_dark--scrollbar: var(--ocean-sec); + --theme_dark--scrollbar_hover: var(--ocean-accent); + + --theme_dark--card: var(--ocean-sec); + --theme_dark--gallery: var(--ocean-sec); + --theme_dark--table-border: rgba(255, 255, 255, 0.1); + --theme_dark--interactive_hover: var(--ocean-main); + --theme_dark--button_close: var(--ocean-accent); + + --theme_dark--selected: rgba(255, 65, 81, 0.2); + --theme_dark--primary: var(--ocean-accent); + --theme_dark--primary_hover: var(--ocean-accent); + --theme_dark--primary_click: var(--ocean-sec); + --theme_dark--primary_indicator: var(--ocean-accent); + + --theme_dark--option_active-background: var(--theme_dark--primary); + --theme_dark--option_hover-background: var(--theme_dark--primary_hover); + + --theme_dark--danger_text: #eb5757; + --theme_dark--danger_border: rgba(235, 87, 87, 0.5); + + --theme_dark--text: #ffffff; + --theme_dark--text_ui: var(--ocean-gray); + --theme_dark--text_ui_info: var(--ocean-gray); + + --theme_dark--text_gray: var(--ocean-gray); + --theme_dark--text_brown: var(--ocean-brown); + --theme_dark--text_orange: var(--ocean-orange); + --theme_dark--text_yellow: var(--ocean-yellow); + --theme_dark--text_green: var(--ocean-green); + --theme_dark--text_blue: var(--ocean-blue); + --theme_dark--text_purple: var(--ocean-purple); + --theme_dark--text_pink: var(--ocean-pink); + --theme_dark--text_red: var(--ocean-red); + + --theme_dark--select-text: var(--ocean-main); + --theme_dark--select_gray: var(--ocean-gray); + --theme_dark--select_brown: var(--ocean-brown); + --theme_dark--select_orange: var(--ocean-orange); + --theme_dark--select_yellow: var(--ocean-yellow); + --theme_dark--select_green: var(--ocean-green); + --theme_dark--select_blue: var(--ocean-blue); + --theme_dark--select_purple: var(--ocean-purple); + --theme_dark--select_pink: var(--ocean-pink); + --theme_dark--select_red: var(--ocean-red); + + --theme_dark--line-text: var(--ocean-main); + --theme_dark--line_gray: #e0e0e089; + --theme_dark--line_brown: #d8b6a692; + --theme_dark--line_orange: #fde3c09f; + --theme_dark--line_yellow: #ffe6a6ad; + --theme_dark--line_green: #a3be8ca3; + --theme_dark--line_blue: #81a1c1a3; + --theme_dark--line_purple: #b48eada8; + --theme_dark--line_pink: #ffc0cbb1; + --theme_dark--line_red: #bf616a9e; + + --theme_dark--bg-text: var(--theme_dark--select-text); + --theme_dark--bg_gray: var(--theme_dark--select_gray); + --theme_dark--bg_brown: var(--theme_dark--select_brown); + --theme_dark--bg_orange: var(--theme_dark--select_orange); + --theme_dark--bg_yellow: var(--theme_dark--select_yellow); + --theme_dark--bg_green: var(--theme_dark--select_green); + --theme_dark--bg_blue: var(--theme_dark--select_blue); + --theme_dark--bg_purple: var(--theme_dark--select_purple); + --theme_dark--bg_pink: var(--theme_dark--select_pink); + --theme_dark--bg_red: var(--theme_dark--select_red); + + --theme_dark--callout-text: var(--theme_dark--line-text); + --theme_dark--callout_gray: var(--theme_dark--line_gray); + --theme_dark--callout_brown: var(--theme_dark--line_brown); + --theme_dark--callout_orange: var(--theme_dark--line_orange); + --theme_dark--callout_yellow: var(--theme_dark--line_yellow); + --theme_dark--callout_green: var(--theme_dark--line_green); + --theme_dark--callout_blue: var(--theme_dark--line_blue); + --theme_dark--callout_purple: var(--theme_dark--line_purple); + --theme_dark--callout_pink: var(--theme_dark--line_pink); + --theme_dark--callout_red: var(--theme_dark--line_red); + + --theme_dark--code_inline-text: #b3f5c8; + --theme_dark--code_inline-background: var(--ocean-sec); + --theme_dark--code-text: var(--theme_dark--text); + --theme_dark--code-background: var(--ocean-sec); + --theme_dark--code_function: var(--theme_dark--text_blue); + --theme_dark--code_keyword: var(--theme_dark--text_pink); + --theme_dark--code_tag: var(--theme_dark--text_pink); + --theme_dark--code_operator: var(--theme_dark--text_yellow); + --theme_dark--code_important: var(--theme_dark--text_yellow); + --theme_dark--code_property: var(--theme_dark--text_pink); + --theme_dark--code_builtin: var(--theme_dark--text_yellow); + --theme_dark--code_attr-name: var(--theme_dark--text_yellow); + --theme_dark--code_comment: var(--theme_dark--text_gray); + --theme_dark--code_punctuation: var(--theme_dark--text_gray); + --theme_dark--code_doctype: var(--theme_dark--text_gray); + --theme_dark--code_number: var(--theme_dark--text_purple); + --theme_dark--code_string: var(--theme_dark--text_orange); + --theme_dark--code_attr-value: var(--theme_dark--text_orange); +} From 74a03a176c5bab2c9234a2ddf3963cab5e7f7ece Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Thu, 1 Oct 2020 13:32:50 +1000 Subject: [PATCH 04/50] re-orderable mods: menu elements can be dragged --- mods/core/client.js | 1 + mods/core/css/menu.css | 64 +++++++++++++++ mods/core/menu.html | 4 + mods/core/menu.js | 171 ++++++++++++++++++++++++++++++----------- pkg/helpers.js | 7 ++ 5 files changed, 201 insertions(+), 46 deletions(-) diff --git a/mods/core/client.js b/mods/core/client.js index 0aca69c..396c8bd 100644 --- a/mods/core/client.js +++ b/mods/core/client.js @@ -115,6 +115,7 @@ module.exports = (store, __exports) => { '--theme--interactive_hover-border', '--theme--button_close', '--theme--button_close-fill', + '--theme--selected', '--theme--primary', '--theme--primary_click', '--theme--option-color', diff --git a/mods/core/css/menu.css b/mods/core/css/menu.css index 9bb5c5d..43a26fd 100644 --- a/mods/core/css/menu.css +++ b/mods/core/css/menu.css @@ -254,6 +254,9 @@ s { /* module meta */ +#modules { + position: relative; +} #modules section { background: var(--theme--sidebar); border: 1px solid var(--theme--table-border); @@ -589,3 +592,64 @@ s { height: 132.5px; } } + +/* draggable re-ordering of mods */ + +#draggable-toggle { + background: none; + border: none; + margin-top: 0.8em; + padding-left: 0; + cursor: pointer; + color: var(--theme--text_ui); +} + +[data-bolded] { + display: inline-flex; + flex-direction: column; +} +[data-bolded]::after { + content: attr(data-bolded); + height: 0; + visibility: hidden; + overflow: hidden; + user-select: none; + pointer-events: none; + font-weight: bold; +} + +#modules.reorder section { + margin-bottom: 0.4em; +} +#modules.reorder [draggable] { + margin-bottom: 1.15em; +} +#modules.reorder [draggable]::after { + content: ''; + height: 0.3em; + width: 99%; + position: absolute; + margin: 0.5em 0; + opacity: 0.7; + background: var(--theme--table-border); +} +#modules.reorder [draggable].dragged-over::after { + background: var(--theme--selected); +} + +#modules.reorder .switch, +#modules.reorder .tags, +#modules.reorder .desc, +#modules.reorder .options, +#modules.reorder .author, +#modules.reorder .version { + display: none; +} +#modules.reorder label { + cursor: pointer; +} +#modules.reorder label::before { + content: '::'; + margin-right: 0.4em; + color: var(--theme--text_ui); +} diff --git a/mods/core/menu.html b/mods/core/menu.html index 83e6d60..3b3f91a 100644 --- a/mods/core/menu.html +++ b/mods/core/menu.html @@ -20,6 +20,10 @@
+
diff --git a/mods/core/menu.js b/mods/core/menu.js index d839720..22e79c6 100644 --- a/mods/core/menu.js +++ b/mods/core/menu.js @@ -184,12 +184,12 @@ window['__start'] = async () => { }; function innerText(elem) { let text = ''; - for (let node of elem.childNodes) { - if (node.nodeType === 3) text += node.textContent; - if (node.nodeType === 1) - text += ['text', 'number'].includes(node.type) - ? node.value - : innerText(node); + for (let $node of elem.childNodes) { + if ($node.nodeType === 3) text += $node.textContent; + if ($node.nodeType === 1) + text += ['text', 'number'].includes($node.type) + ? $node.value + : innerText($node); } return text; } @@ -284,20 +284,20 @@ window['__start'] = async () => { return parsed; } - let modified_notice; + let $modified_notice; function modified() { - if (modified_notice) return; - modified_notice = createAlert( + if ($modified_notice) return; + $modified_notice = createAlert( 'info', `changes may not fully apply until app relaunch.` ); - modified_notice.el + $modified_notice.el .querySelector('[data-relaunch]') .addEventListener('click', (event) => { electron.remote.app.relaunch(); electron.remote.app.quit(); }); - modified_notice.append(); + $modified_notice.append(); } const file_icon = await fs.readFile( @@ -389,15 +389,8 @@ window['__start'] = async () => { } const $modules = document.querySelector('#modules'); - for (let mod of modules.loaded.sort((a, b) => - a.tags.includes('core') || - store('mods', { [a.id]: { pinned: false } }).pinned - ? -1 - : b.tags.includes('core') || - store('mods', { [b.id]: { pinned: false } }).pinned - ? 1 - : a.name.localeCompare(b.name) - )) { + + for (let mod of modules.loaded) { for (let fonts of mod.fonts || []) { document .querySelector('head') @@ -417,37 +410,39 @@ window['__start'] = async () => { avatar: `https://github.com/${mod.author}.png`, }; mod.elem = helpers.createElement(` -
+
-

${mod.name}` - : `class="toggle"> - ${mod.name}` + : `class="toggle"> + ` - }

-

${mod.tags - .map((tag) => (tag.startsWith('#') ? tag : `#${tag}`)) - .join(' ')}

-
${markdown(mod.desc)}
-

- + ` + } +

${mod.tags + .map((tag) => (tag.startsWith('#') ? tag : `#${tag}`)) + .join(' ')}

+
${markdown(mod.desc)}
+

+ ${author.name} - + v${mod.version} -

-
- ${ - mod.options && mod.options.length ? '
' : '' - } -
+

+ + ${ + mod.options && mod.options.length + ? '
' + : '' + } +
`); const $enable = mod.elem.querySelector(`#enable_${mod.id}`); if ($enable) @@ -500,12 +495,96 @@ window['__start'] = async () => { } $options.appendChild($opt); } - $modules.append(mod.elem); + if (mod.tags.includes('core')) $modules.append(mod.elem); } - document .querySelectorAll('input[type="checkbox"]') .forEach((checkbox) => checkbox.addEventListener('click', (event) => event.target.blur()) ); + + // draggable re-ordering + const draggable = { + state: 0, + tags: ['b', 'span'], + $toggle: document.querySelector('#draggable-toggle'), + list: modules.loaded + .filter((m) => !m.tags.includes('core')) + .map((m) => m.elem), + target: null, + render() { + draggable.target = null; + for (let $node of draggable.list) { + $node.draggable = false; + $modules.append($node); + } + }, + mouseover(event) { + if (!draggable.target && event.target.innerText) { + for (let $node of draggable.list) $node.draggable = false; + const $node = draggable.list.find( + (node) => node.innerText === event.target.innerText + ); + if ($node) $node.draggable = draggable.state; + } + }, + }; + document.addEventListener('dragstart', (event) => { + draggable.target = event.target; + event.target.style.opacity = 0.5; + }); + document.addEventListener('dragend', (event) => { + event.target.style.opacity = ''; + }); + document.addEventListener('dragover', (event) => { + event.preventDefault(); + document + .querySelectorAll('.dragged-over') + .forEach((el) => el.classList.remove('dragged-over')); + const $node = draggable.list.find( + (node) => node.innerText === event.target.innerText + ); + if ($node) $node.classList.add('dragged-over'); + }); + document.addEventListener('drop', (event) => { + event.preventDefault(); + document + .querySelectorAll('.dragged-over') + .forEach((el) => el.classList.remove('dragged-over')); + if ( + draggable.target && + draggable.target.innerText !== event.target.innerText + ) { + const from = draggable.list.findIndex( + (node) => node.innerText === draggable.target.innerText + ), + to = draggable.list.findIndex( + (node) => node.innerText === event.target.innerText + ); + // [draggable.list[from], draggable.list[to]] = [ + // draggable.list[to], + // draggable.list[from], + // ]; -- swap + if (to >= draggable.list.length) { + let k = to - draggable.list.length; + while (k--) draggable.list.push(undefined); + } + draggable.list.splice(to, 0, draggable.list.splice(from, 1)[0]); + } + draggable.render(); + }); + document.addEventListener('mouseover', draggable.mouseover); + draggable.render(); + draggable.$toggle.addEventListener('click', (event) => { + draggable.state = !draggable.state; + draggable.tags = draggable.tags.reverse(); + draggable.$toggle.innerHTML = ` + <${draggable.tags[0]} data-bolded="configure">configure | + <${draggable.tags[1]} data-bolded="reorder">reorder + `; + $modules.classList[draggable.state ? 'add' : 'remove']('reorder'); + $modules + .querySelectorAll('input') + .forEach((input) => (input.disabled = draggable.state)); + }); }; diff --git a/pkg/helpers.js b/pkg/helpers.js index c905331..7ff97e9 100644 --- a/pkg/helpers.js +++ b/pkg/helpers.js @@ -140,6 +140,13 @@ function getEnhancements() { modules.invalid.push(dir); } } + modules.loaded = modules.loaded.sort((a, b) => + a.tags.includes('core') + ? -1 + : b.tags.includes('core') + ? 1 + : a.name.localeCompare(b.name) + ); return modules; } From 80fca9d18782535c19041295ded3166431145556 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Thu, 1 Oct 2020 23:11:31 +1000 Subject: [PATCH 05/50] re-orderable mods: order is saved + mods are loaded according to priority --- CHANGELOG.md | 6 ++- README.md | 3 +- mods/core/css/menu.css | 39 ++++++++--------- mods/core/menu.js | 76 ++++++++++++++++++---------------- mods/custom-inserts/mod.js | 5 ++- mods/material-ocean/mod.js | 18 ++++---- mods/material-ocean/styles.css | 8 ++-- mods/night-shift/mod.js | 2 +- pkg/apply.js | 2 +- pkg/helpers.js | 18 ++++---- pkg/loader.js | 5 ++- pkg/remove.js | 2 +- 12 files changed, 102 insertions(+), 82 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c11166c..702cf1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,16 +6,20 @@ - [improved responsiveness](https://chrome.google.com/webstore/detail/notion%20%20-responsiveness-f/leadcilhbmibbkgbnjgmmnfgnnhmeddk) - [highlight/mark viewer](https://chrome.google.com/webstore/detail/notion%2B-mark-manager/hipgmnlpnimedfepbfbfiaobohhffcfc) - [advanced math editor](https://github.com/Manueloccorso/NotionMathEditor_BrowserExtension) -- re-orderable extensions ### v0.?.? (wip) +- 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 core, which though pinned to the top of the list is always loaded first so theming + variables can be modified.) - bugfix: removed messenger emoji set as the provider no longer supports it. - bugfix: remove shadow around light mode board headers \+ minor text colour fixes for night shift theming. - bugfix: properly detect/respond to `EACCES` errors. - bugfix: night shift checks every interaction, will respond to system changes without any manual changes. +- extension: "material ocean" = an oceanic colour palette. ### v0.9.1 (2020-09-26) diff --git a/README.md b/README.md index fdac56c..080124b 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,8 @@ on top of other windows even if it's not focused. **tags:** #extension -**description:** link files for small client-side tweaks. +**description:** link files for small client-side tweaks. (not sure how to do something? check out the +[tweaks](https://github.com/dragonwocky/notion-enhancer/blob/master/TWEAKS.md) collection.) **author**: [dragonwocky](https://github.com/dragonwocky/) diff --git a/mods/core/css/menu.css b/mods/core/css/menu.css index 43a26fd..17992b8 100644 --- a/mods/core/css/menu.css +++ b/mods/core/css/menu.css @@ -231,7 +231,7 @@ s { background: var(--theme--option-background); color: var(--theme--option-color); border-radius: 2px; - transition: color 200ms, background 200ms; + transition: color 200ms, background 200ms, opacity 200ms; user-select: none; } #search #tags > span:not(:last-child) { @@ -618,37 +618,38 @@ s { font-weight: bold; } -#modules.reorder section { - margin-bottom: 0.4em; +.reorder #search #tags > span, +.reorder #search #tags > span:hover { + opacity: 0.7; + background: var(--theme--option-background); } -#modules.reorder [draggable] { - margin-bottom: 1.15em; +.reorder #search #tags > .selected, +.reorder #search #tags > .selected:hover { + background: var(--tag_color, var(--theme--option_active-background)); } -#modules.reorder [draggable]::after { + +.reorder #modules .dragged-over::after { content: ''; - height: 0.3em; + height: 0.25em; width: 99%; position: absolute; - margin: 0.5em 0; + margin: 0.3em 0; opacity: 0.7; - background: var(--theme--table-border); -} -#modules.reorder [draggable].dragged-over::after { background: var(--theme--selected); } -#modules.reorder .switch, -#modules.reorder .tags, -#modules.reorder .desc, -#modules.reorder .options, -#modules.reorder .author, -#modules.reorder .version { +.reorder #modules .switch, +.reorder #modules .tags, +.reorder #modules .desc, +.reorder #modules .options, +.reorder #modules .author, +.reorder #modules .version { display: none; } -#modules.reorder label { +.reorder #modules label { cursor: pointer; } -#modules.reorder label::before { +.reorder #modules label::before { content: '::'; margin-right: 0.4em; color: var(--theme--text_ui); diff --git a/mods/core/menu.js b/mods/core/menu.js index 22e79c6..533f009 100644 --- a/mods/core/menu.js +++ b/mods/core/menu.js @@ -7,12 +7,10 @@ 'use strict'; const store = require('../../pkg/store.js'), - { id } = require('./mod.js'), helpers = require('../../pkg/helpers.js'), fs = require('fs-extra'), path = require('path'), - electron = require('electron'), - browser = electron.remote.getCurrentWindow(); + electron = require('electron'); window['__start'] = async () => { const buttons = require('./buttons.js')(() => ({ @@ -197,13 +195,15 @@ window['__start'] = async () => { modules.loaded.forEach((mod) => { const $search_input = document.querySelector('#search > input'); if ( - (mod.elem.classList.contains('enabled') && !search_filters.enabled) || - (mod.elem.classList.contains('disabled') && !search_filters.disabled) || - !mod.tags.some((tag) => search_filters.tags.has(tag)) || - ($search_input.value && - !innerText(mod.elem) - .toLowerCase() - .includes($search_input.value.toLowerCase().trim())) + !document.body.classList.contains('reorder') && + ((mod.elem.classList.contains('enabled') && !search_filters.enabled) || + (mod.elem.classList.contains('disabled') && + !search_filters.disabled) || + !mod.tags.some((tag) => search_filters.tags.has(tag)) || + ($search_input.value && + !innerText(mod.elem) + .toLowerCase() + .includes($search_input.value.toLowerCase().trim()))) ) return (mod.elem.style.display = 'none'); mod.elem.style.display = 'block'; @@ -223,21 +223,20 @@ window['__start'] = async () => { ); document.querySelector('#tags').append(el); el.addEventListener('click', (event) => { - el.className = el.className === 'selected' ? '' : 'selected'; - onclick(el.className === 'selected'); + if (!document.body.classList.contains('reorder')) { + el.className = el.className === 'selected' ? '' : 'selected'; + onclick(el.className === 'selected'); + } }); return el; } - createTag( - 'enabled', - (state) => [(search_filters.enabled = state), search()] - // 'var(--theme--bg_green)' - ); - createTag( - 'disabled', - (state) => [(search_filters.disabled = state), search()] - // 'var(--theme--bg_red)' - ); + createTag('enabled', (state) => [ + ((search_filters.enabled = state), search()), + ]); + createTag('disabled', (state) => [ + (search_filters.disabled = state), + search(), + ]); for (let tag of search_filters.tags) createTag(`#${tag}`, (state) => [ state ? search_filters.tags.add(tag) : search_filters.tags.delete(tag), @@ -541,9 +540,10 @@ window['__start'] = async () => { document .querySelectorAll('.dragged-over') .forEach((el) => el.classList.remove('dragged-over')); - const $node = draggable.list.find( - (node) => node.innerText === event.target.innerText - ); + const $node = [ + draggable.list[0].previousElementSibling, + ...draggable.list, + ].find((node) => node.innerText === event.target.innerText); if ($node) $node.classList.add('dragged-over'); }); document.addEventListener('drop', (event) => { @@ -558,18 +558,21 @@ window['__start'] = async () => { const from = draggable.list.findIndex( (node) => node.innerText === draggable.target.innerText ), - to = draggable.list.findIndex( - (node) => node.innerText === event.target.innerText + to = + event.target.innerText === + draggable.list[0].previousElementSibling.innerText + ? 0 + : draggable.list.findIndex( + (node) => node.innerText === event.target.innerText + ) + 1; + if (to >= 0) { + draggable.list.splice( + to > from ? to - 1 : to, + 0, + draggable.list.splice(from, 1)[0] ); - // [draggable.list[from], draggable.list[to]] = [ - // draggable.list[to], - // draggable.list[from], - // ]; -- swap - if (to >= draggable.list.length) { - let k = to - draggable.list.length; - while (k--) draggable.list.push(undefined); + store('mods').priority = draggable.list.map((m) => m.id); } - draggable.list.splice(to, 0, draggable.list.splice(from, 1)[0]); } draggable.render(); }); @@ -582,9 +585,10 @@ window['__start'] = async () => { <${draggable.tags[0]} data-bolded="configure">configure | <${draggable.tags[1]} data-bolded="reorder">reorder `; - $modules.classList[draggable.state ? 'add' : 'remove']('reorder'); + document.body.classList[draggable.state ? 'add' : 'remove']('reorder'); $modules .querySelectorAll('input') .forEach((input) => (input.disabled = draggable.state)); + search(); }); }; diff --git a/mods/custom-inserts/mod.js b/mods/custom-inserts/mod.js index 59c0ba0..8ae3aa4 100644 --- a/mods/custom-inserts/mod.js +++ b/mods/custom-inserts/mod.js @@ -12,8 +12,9 @@ module.exports = { id: 'b4b0aced-2059-43bf-8d1d-ccd757ee5ebb', tags: ['extension'], name: 'custom inserts', - desc: 'link files for small client-side tweaks.', - version: '0.1.2', + desc: `link files for small client-side tweaks. (not sure how to do something? check out the + [tweaks](https://github.com/dragonwocky/notion-enhancer/blob/master/TWEAKS.md) collection.)`, + version: '0.1.3', author: 'dragonwocky', options: [ { diff --git a/mods/material-ocean/mod.js b/mods/material-ocean/mod.js index e4a8b42..19b6752 100644 --- a/mods/material-ocean/mod.js +++ b/mods/material-ocean/mod.js @@ -1,16 +1,16 @@ /* - * Material Ocean + * material ocean * (c) 2020 Abubakar Yagoub (https://blacksuan19.tk) - * under GNU's GPL3 license + * under the MIT license */ -"use strict"; +'use strict'; module.exports = { - id: "69e7ccb2-4aef-484c-876d-3de1b433d2b9", - tags: ["theme", "dark"], - name: "Material Ocean", - desc: "a Material theme with oceanic colors", - version: "0.1", - author: "blacksuan19", + id: '69e7ccb2-4aef-484c-876d-3de1b433d2b9', + tags: ['theme', 'dark'], + name: 'material ocean', + desc: 'an oceanic colour palette.', + version: '0.1', + author: 'blacksuan19', }; diff --git a/mods/material-ocean/styles.css b/mods/material-ocean/styles.css index 02bc6f0..cb6bc4f 100644 --- a/mods/material-ocean/styles.css +++ b/mods/material-ocean/styles.css @@ -1,8 +1,10 @@ -/* Copyright © Blacksuan19 @ 2020 */ -/* part of Material Ocean Color Scheme */ +/* + * material ocean + * (c) 2020 Abubakar Yagoub (https://blacksuan19.tk) + * under the MIT license + */ :root { - /* material ocean colors */ --ocean-main: #0f111a; --ocean-sec: #00010a; --ocean-accent: #ff4151; diff --git a/mods/night-shift/mod.js b/mods/night-shift/mod.js index 8014918..0c29d7c 100644 --- a/mods/night-shift/mod.js +++ b/mods/night-shift/mod.js @@ -12,7 +12,7 @@ module.exports = { name: 'night shift', desc: 'sync dark/light theme with the system (overrides normal theme setting).', - version: '0.1.0', + version: '0.1.1', author: 'dragonwocky', hacks: { 'renderer/preload.js'(store, __exports) { diff --git a/pkg/apply.js b/pkg/apply.js index c49771f..79308dc 100644 --- a/pkg/apply.js +++ b/pkg/apply.js @@ -117,7 +117,7 @@ module.exports = async function ({ overwrite_version, friendly_errors } = {}) { `file access forbidden - ${ process.platform === 'win32' ? 'make sure your user has elevated permissions.' - : `try running "chown -R ${err.path}"` + : `try running "chown -R $USER ${err.path}"` }` ); } else if (err.code === 'EIO' && friendly_errors) { diff --git a/pkg/helpers.js b/pkg/helpers.js index 7ff97e9..325433f 100644 --- a/pkg/helpers.js +++ b/pkg/helpers.js @@ -140,13 +140,17 @@ function getEnhancements() { modules.invalid.push(dir); } } - modules.loaded = modules.loaded.sort((a, b) => - a.tags.includes('core') - ? -1 - : b.tags.includes('core') - ? 1 - : a.name.localeCompare(b.name) - ); + modules.loaded = modules.loaded.sort((a, b) => a.name.localeCompare(b.name)); + const priority = require('./store.js')('mods', { priority: [] }).priority; + modules.loaded = [ + ...modules.loaded.filter((m) => m.tags.includes('core')), + ...modules.loaded.filter( + (m) => !m.tags.includes('core') && !priority.includes(m.id) + ), + ...priority + .map((id) => modules.loaded.find((m) => m.id === id)) + .filter((m) => m), + ]; return modules; } diff --git a/pkg/loader.js b/pkg/loader.js index 9466004..9607c39 100644 --- a/pkg/loader.js +++ b/pkg/loader.js @@ -55,7 +55,10 @@ module.exports = function (__file, __exports) { } const modules = helpers.getEnhancements(); - for (let mod of modules.loaded) { + for (let mod of [ + ...modules.loaded.filter((m) => m.tags.includes('core')), + ...modules.loaded.filter((m) => !m.tags.includes('core')).reverse(), + ]) { if ( (mod.tags || []).includes('core') || store('mods', { [mod.id]: { enabled: false } })[mod.id].enabled diff --git a/pkg/remove.js b/pkg/remove.js index 16b32d1..865ef36 100644 --- a/pkg/remove.js +++ b/pkg/remove.js @@ -119,7 +119,7 @@ module.exports = async function ({ `file access forbidden - ${ process.platform === 'win32' ? 'make sure your user has elevated permissions.' - : `try running "chown -R ${err.path}"` + : `try running "chown -R $USER ${err.path}"` }` ); } else if (err.code === 'EIO' && friendly_errors) { From 4cc002c7c2671334aad6f05d1e40b56acde79b29 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Fri, 2 Oct 2020 10:43:47 +1000 Subject: [PATCH 06/50] bugfix: toc blocks can have text colours --- CHANGELOG.md | 5 ++++- mods/core/css/theme.css | 1 - mods/core/menu.js | 1 + mods/material-ocean/mod.js | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 702cf1b..93b1947 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ - [highlight/mark viewer](https://chrome.google.com/webstore/detail/notion%2B-mark-manager/hipgmnlpnimedfepbfbfiaobohhffcfc) - [advanced math editor](https://github.com/Manueloccorso/NotionMathEditor_BrowserExtension) -### v0.?.? (wip) +### v0.10.0 (wip) + +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. @@ -19,6 +21,7 @@ - bugfix: properly detect/respond to `EACCES` errors. - bugfix: night shift checks every interaction, will respond to system changes without any manual changes. +- bugfix: toc blocks can have text colours. - extension: "material ocean" = an oceanic colour palette. ### v0.9.1 (2020-09-26) diff --git a/mods/core/css/theme.css b/mods/core/css/theme.css index 4cfc448..0608b2f 100644 --- a/mods/core/css/theme.css +++ b/mods/core/css/theme.css @@ -424,7 +424,6 @@ /** content colours **/ .notion-body, -.notion-page-content [style*='color: inherit;'], .notion-frame .notion-page-block, .notion-body.dark [style*=' color: rgba(255, 255, 255, 0.9)'], .notion-body.dark [style^='color: rgba(255, 255, 255, 0.9)'], diff --git a/mods/core/menu.js b/mods/core/menu.js index 533f009..d5e72b4 100644 --- a/mods/core/menu.js +++ b/mods/core/menu.js @@ -575,6 +575,7 @@ window['__start'] = async () => { } } draggable.render(); + modified(); }); document.addEventListener('mouseover', draggable.mouseover); draggable.render(); diff --git a/mods/material-ocean/mod.js b/mods/material-ocean/mod.js index 19b6752..dd3eab5 100644 --- a/mods/material-ocean/mod.js +++ b/mods/material-ocean/mod.js @@ -11,6 +11,6 @@ module.exports = { tags: ['theme', 'dark'], name: 'material ocean', desc: 'an oceanic colour palette.', - version: '0.1', + version: '0.1.0', author: 'blacksuan19', }; From 9429426ded208ca0265c57f4858c298955423c0b Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Fri, 2 Oct 2020 11:22:07 +1000 Subject: [PATCH 07/50] #124 tweak: sticky table/list rows. --- CHANGELOG.md | 1 + TWEAKS.md | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93b1947..7c7eab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ a flexibility update. - bugfix: night shift checks every interaction, will respond to system changes without any manual changes. - bugfix: toc blocks can have text colours. +- tweak: sticky table/list rows. - extension: "material ocean" = an oceanic colour palette. ### v0.9.1 (2020-09-26) diff --git a/TWEAKS.md b/TWEAKS.md index a15d9ed..aba6147 100644 --- a/TWEAKS.md +++ b/TWEAKS.md @@ -70,10 +70,34 @@ then use the 3 dots up in the top-right corner to remove them. +### sticky table/list row + +note: this will make the first row stick to the top of the screen when scrolling down. +to stick a specific row replace `:nth-child(2)` with `[data-block-id="ROW_BLOCK_ID_HERE"]`. + +does not apply to inline databases. + +```css +.notion-collection_view_page-block + .notion-page-block.notion-collection-item:nth-child(2) { + background: var(--theme--main); + z-index: 10; + position: sticky; + top: 0; +} +.notion-table-view + .notion-collection_view_page-block + .notion-page-block.notion-collection-item:nth-child(2) { + top: 32px; +} +``` + +![image](https://user-images.githubusercontent.com/16874139/94878420-a1c12400-04a0-11eb-8e74-2f01e2e696cd.png) + ### table columns below 100px **not recommended!** this may cause buggy viewing. -as it is a per-table-column style, unlike all others here, it must be prepended with the block ID and repeated for each column. +as it is a per-table-column style, unlike most others here, it must be prepended with the block ID and repeated for each column. to see how to do this, watch [this video](https://www.youtube.com/watch?v=6V7eqShm_4w). From e82fb38ce8f669c8bd4b626f10e47d9988df5725 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Fri, 2 Oct 2020 13:44:16 +1000 Subject: [PATCH 08/50] improved responsiveness + snappier transitions mode --- CHANGELOG.md | 4 +++- mods/core/client.js | 4 +++- mods/core/css/responsive.css | 26 ++++++++++++++++++++++++++ mods/core/css/theme.css | 6 ++++++ mods/core/css/variables.css | 16 ++++++++++------ mods/core/mod.js | 6 ++++++ mods/core/styles.css | 1 + 7 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 mods/core/css/responsive.css diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c7eab4..09ce472 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,6 @@ **potential future features (not confirmed)** - [groupy-like tabbing](https://www.npmjs.com/package/electron-tabs) -- [improved responsiveness](https://chrome.google.com/webstore/detail/notion%20%20-responsiveness-f/leadcilhbmibbkgbnjgmmnfgnnhmeddk) - [highlight/mark viewer](https://chrome.google.com/webstore/detail/notion%2B-mark-manager/hipgmnlpnimedfepbfbfiaobohhffcfc) - [advanced math editor](https://github.com/Manueloccorso/NotionMathEditor_BrowserExtension) @@ -15,6 +14,9 @@ a flexibility update. higher up on the list = higher priority of application = loaded last in order to override others. (excluding core, which though pinned to the top of the list is always loaded first so theming variables can be modified.) +- new: in-page columns disabled/wrapped and wider pages when the window is narrower than 600px + for improved responsiveness. +- improved: a core mod option to make transitions snappy/0s. - bugfix: removed messenger emoji set as the provider no longer supports it. - bugfix: remove shadow around light mode board headers \+ minor text colour fixes for night shift theming. diff --git a/mods/core/client.js b/mods/core/client.js index 396c8bd..592a2ce 100644 --- a/mods/core/client.js +++ b/mods/core/client.js @@ -29,9 +29,11 @@ module.exports = (store, __exports) => { return; clearInterval(attempt_interval); - // scrollbars + // toggleable styles if (store().smooth_scrollbars) document.body.classList.add('smooth-scrollbars'); + if (store().snappy_transitions) + document.body.classList.add('snappy-transitions'); // frameless if (store().frameless && !store().tiling_mode) { diff --git a/mods/core/css/responsive.css b/mods/core/css/responsive.css new file mode 100644 index 0000000..0b92c03 --- /dev/null +++ b/mods/core/css/responsive.css @@ -0,0 +1,26 @@ +/* + * notion-enhancer + * (c) 2020 dragonwocky (https://dragonwocky.me/) + * under the MIT license + */ + +@media (max-width: 600px) { + .notion-column_list-block [style='display: flex;'] > div { + width: 100% !important; + } + .notion-column_list-block [style='display: flex;'] { + flex-direction: column !important; + } + + .notion-app-inner { + --theme_dark--page_normal-width: 100%; + --theme_dark--page-padding: calc(48px + env(safe-area-inset-left)); + --theme_light--page_normal-width: 100%; + --theme_light--page-padding: calc(48px + env(safe-area-inset-left)); + } +} + +.snappy-transitions * { + animation-duration: 0s !important; + transition-duration: 0s !important; +} diff --git a/mods/core/css/theme.css b/mods/core/css/theme.css index 0608b2f..7778954 100644 --- a/mods/core/css/theme.css +++ b/mods/core/css/theme.css @@ -40,6 +40,12 @@ width: var(--theme--page_normal-width) !important; } +.notion-frame + [style*='padding-left: calc(96px + env(safe-area-inset-left)); padding-right: calc(96px + env(safe-area-inset-right));'] { + padding-left: var(--theme--page-padding) !important; + padding-right: var(--theme--page-padding) !important; +} + .notion-page-content [data-block-id][style*='max-width'] { max-width: 100% !important; } diff --git a/mods/core/css/variables.css b/mods/core/css/variables.css index 225fdd3..76e4bbd 100644 --- a/mods/core/css/variables.css +++ b/mods/core/css/variables.css @@ -16,10 +16,11 @@ --theme_dark--dragarea: #272d2f; --theme_dark--page_normal-width: 900px; --theme_dark--page_full-width: 100%; + --theme_dark--page-padding: calc(96px + env(safe-area-inset-left)); + --theme_dark--page_banner-height: 30vh; --theme_dark--preview-width: 977px; --theme_dark--preview-padding: 8rem; --theme_dark--preview_banner-height: 20vh; - --theme_dark--page_banner-height: 30vh; --theme_dark--font_sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, 'Apple Color Emoji', Arial, sans-serif, 'Segoe UI Emoji', @@ -190,10 +191,11 @@ --theme_light--dragarea: rgba(55, 53, 47, 0.04); --theme_light--page_normal-width: 900px; --theme_light--page_full-width: 100%; + --theme_light--page-padding: calc(96px + env(safe-area-inset-left)); + --theme_light--page_banner-height: 30vh; --theme_light--preview-width: 977px; --theme_light--preview-padding: 8rem; --theme_light--preview_banner-height: 20vh; - --theme_light--page_banner-height: 30vh; --theme_light--font_sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, 'Apple Color Emoji', Arial, sans-serif, 'Segoe UI Emoji', @@ -364,10 +366,11 @@ --theme--dragarea: var(--theme_dark--dragarea); --theme--page_normal-width: var(--theme_dark--page_normal-width); --theme--page_full-width: var(--theme_dark--page_full-width); + --theme--page-padding: var(--theme_dark--page-padding); + --theme--page_banner-height: var(--theme_dark--page_banner-height); --theme--preview-width: var(--theme_dark--preview-width); --theme--preview-padding: var(--theme_dark--preview-padding); --theme--preview_banner-height: var(--theme_dark--preview_banner-height); - --theme--page_banner-height: var(--theme_dark--page_banner-height); --theme--font_sans: var(--theme_dark--font_sans); --theme--font_serif: var(--theme_dark--font_serif); --theme--font_mono: var(--theme_dark--font_mono); @@ -521,12 +524,13 @@ --theme--sidebar: var(--theme_light--sidebar); --theme--overlay: var(--theme_light--overlay); --theme--dragarea: var(--theme_light--dragarea); - --theme--page_normal-width: var(--theme_dark--page_normal-width); - --theme--page_full-width: var(--theme_dark--page_full-width); + --theme--page_normal-width: var(--theme_light--page_normal-width); + --theme--page_full-width: var(--theme_light--page_full-width); + --theme--page-padding: var(--theme_light--page-padding); + --theme--page_banner-height: var(--theme_light--page_banner-height); --theme--preview-width: var(--theme_light--preview-width); --theme--preview-padding: var(--theme_light--preview-padding); --theme--preview_banner-height: var(--theme_light--preview_banner-height); - --theme--page_banner-height: var(--theme_light--page_banner-height); --theme--font_sans: var(--theme_light--font_sans); --theme--font_serif: var(--theme_light--font_serif); --theme--font_mono: var(--theme_light--font_mono); diff --git a/mods/core/mod.js b/mods/core/mod.js index 2294d0a..70bbd29 100644 --- a/mods/core/mod.js +++ b/mods/core/mod.js @@ -56,6 +56,12 @@ module.exports = { type: 'toggle', value: true, }, + { + key: 'snappy_transitions', + label: 'snappy transitions', + type: 'toggle', + value: false, + }, { key: 'hotkey', label: 'window display hotkey:', diff --git a/mods/core/styles.css b/mods/core/styles.css index da69ff5..fbfe5be 100644 --- a/mods/core/styles.css +++ b/mods/core/styles.css @@ -8,3 +8,4 @@ @import './css/variables.css'; @import './css/scrollbars.css'; @import './css/titlebar.css'; +@import './css/responsive.css'; From bc646ab8aeb6219a5e13217978c21ca8151eb595 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Fri, 2 Oct 2020 15:46:11 +1000 Subject: [PATCH 09/50] #134 bypass preview operates more reliably when keyboard shortcuts are used --- CHANGELOG.md | 1 + mods/bypass-preview/mod.js | 76 ++++++++++++++-------------------- mods/bypass-preview/styles.css | 2 +- mods/core/css/titlebar.css | 10 +++-- mods/word-counter/mod.js | 4 +- package.json | 2 +- 6 files changed, 43 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09ce472..dd5768c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ a flexibility update. - 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. - tweak: sticky table/list rows. - extension: "material ocean" = an oceanic colour palette. diff --git a/mods/bypass-preview/mod.js b/mods/bypass-preview/mod.js index 0a12995..2fe9f02 100644 --- a/mods/bypass-preview/mod.js +++ b/mods/bypass-preview/mod.js @@ -11,57 +11,43 @@ module.exports = { tags: ['extension'], name: 'bypass preview', desc: 'go straight to the normal full view when opening a page.', - version: '0.1.0', + version: '0.1.2', author: 'dragonwocky', hacks: { 'renderer/preload.js'(store, __exports) { document.addEventListener('readystatechange', (event) => { if (document.readyState !== 'complete') return false; - const attempt_interval = setInterval(enhance, 500); - function enhance() { - const notion_elem = document.querySelector('.notion-app-inner'); - if (!notion_elem) return; - clearInterval(attempt_interval); - const observer = new MutationObserver(handle); - observer.observe(notion_elem, { - childList: true, - subtree: true, - }); + let queue = []; + const observer = new MutationObserver((list, observer) => { + if (!queue.length) requestIdleCallback(() => handle(queue)); + queue.push(...list); + }); + observer.observe(document.body, { + childList: true, + subtree: true, + attributes: true, + }); - let pageHistory = []; - handle(); - function handle(list, observer) { - const pageID = (location.search - .slice(1) - .split('&') - .map((opt) => opt.split('=')) - .find((opt) => opt[0] === 'p') || [ - '', - ...location.pathname.split(/(-|\/)/g).reverse(), - ])[1], - preview = document.querySelector( - '.notion-peek-renderer [style*="height: 45px;"] a' - ); - if ( - pageID && - (!pageHistory[0] || - pageHistory[0][0] !== pageID || - pageHistory[0][1] !== !!preview) - ) { - if (preview) { - if ( - pageHistory[1] && - pageHistory[0][0] === pageID && - pageHistory[1][0] === pageID && - pageHistory[1][1] - ) { - document.querySelector('.notion-history-back-button').click(); - } else preview.click(); - } - // most recent is at start for easier access - pageHistory.unshift([pageID, !!preview]); - } - } + let lastPageID; + function handle(list) { + queue = []; + const pageID = (location.search + .slice(1) + .split('&') + .map((opt) => opt.split('=')) + .find((opt) => opt[0] === 'p') || [ + '', + ...location.pathname.split(/(-|\/)/g).reverse(), + ])[1], + preview = document.querySelector( + '.notion-peek-renderer [style*="height: 45px;"] a' + ); + if (!pageID) return; + if (preview) { + if (pageID === lastPageID) { + history.back(); + } else preview.click(); + } else lastPageID = pageID; } }); }, diff --git a/mods/bypass-preview/styles.css b/mods/bypass-preview/styles.css index 95f2308..176a1b9 100644 --- a/mods/bypass-preview/styles.css +++ b/mods/bypass-preview/styles.css @@ -5,5 +5,5 @@ */ .notion-peek-renderer { - opacity: 0; + display: none; } diff --git a/mods/core/css/titlebar.css b/mods/core/css/titlebar.css index 0fd160f..9ab225c 100644 --- a/mods/core/css/titlebar.css +++ b/mods/core/css/titlebar.css @@ -8,19 +8,23 @@ @import './buttons.css'; .frameless .notion-topbar { - height: calc(var(--configured--dragarea_height, 10px) + 45px) !important; + height: calc(var(--configured--dragarea_height, 15px) + 45px) !important; } .frameless .window-dragarea { - height: var(--configured--dragarea_height, 10px); + height: var(--configured--dragarea_height, 15px); width: 100%; } .frameless .window-dragarea { background: var(--theme--dragarea); } +.frameless [style*='top: 10.4972px'] { + top: calc(10.4972px + var(--configured--dragarea_height, 15px)) !important; +} + @media (max-width: 760px) { .frameless .notion-topbar { - height: calc(var(--configured--dragarea_height, 10px) + 80px) !important; + height: calc(var(--configured--dragarea_height, 15px) + 80px) !important; } .frameless .notion-topbar > :nth-child(2) { height: 80px !important; diff --git a/mods/word-counter/mod.js b/mods/word-counter/mod.js index 19edd55..ea183c1 100644 --- a/mods/word-counter/mod.js +++ b/mods/word-counter/mod.js @@ -54,7 +54,7 @@ module.exports = { let queue = [], $page = document.getElementsByClassName('notion-page-content')[0]; const DOCUMENT_OBSERVER = new MutationObserver((list, observer) => { - if (!queue.length) requestIdleCallback(() => process(queue)); + if (!queue.length) requestIdleCallback(() => handle(queue)); queue.push(...list); }), PAGE_OBSERVER = new MutationObserver(showPageWordDetails); @@ -62,7 +62,7 @@ module.exports = { childList: true, subtree: true, }); - function process(list) { + function handle(list) { queue = []; for (let { addedNodes } of list) { if ( diff --git a/package.json b/package.json index d0cc94f..aaa8e97 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "notion-enhancer", - "version": "0.9.1", + "version": "0.10.0-wip", "description": "an enhancer/customiser for the all-in-one productivity workspace notion.so", "main": "index.js", "bin": { From 4f053dc23f82605e1880ac3101ac6384d929c38e Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Fri, 2 Oct 2020 23:06:44 +1000 Subject: [PATCH 10/50] tabs proof-of-concept (unusable) --- mods/core/create.js | 1 + mods/core/render.js | 550 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 529 insertions(+), 22 deletions(-) diff --git a/mods/core/create.js b/mods/core/create.js index 47165d0..fb37b5a 100644 --- a/mods/core/create.js +++ b/mods/core/create.js @@ -79,6 +79,7 @@ module.exports = (store, __exports) => { }); electron.app.on('before-quit', () => (intended_quit = true)); window.loadURL(__exports.getIndexUrl(relativeUrl)); + window.webContents.openDevTools(); return window; }; return __exports.createWindow; diff --git a/mods/core/render.js b/mods/core/render.js index 9b17f03..dc94206 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -6,30 +6,536 @@ 'use strict'; +const url = require('url'), + path = require('path'), + { __notion } = require('../../pkg/helpers.js'), + config = require(`${__notion}/app/config.js`), + constants = require(`${__notion}/app/shared/constants.js`), + notion_intl = require(`${__notion}/app/shared/notion-intl/index.js`), + notionIpc = require(`${__notion}/app/helpers/notionIpc.js`), + localizationHelper = require(`${__notion}/app/helpers/localizationHelper.js`), + koMessages = require(`${__notion}/app/i18n/ko_KR/messages.json`), + schemeHelpers = require(`${__notion}/app/shared/schemeHelpers.js`), + React = require(`${__notion}/app/node_modules/react/index.js`), + ReactDOM = require(`${__notion}/app/node_modules/react-dom/index.js`); + module.exports = (store, __exports) => { - const __start = window['__start']; + if (store().tabs) { + class Index extends React.PureComponent { + constructor() { + super(...arguments); + this.state = { + error: false, + searching: false, + searchingPeekView: false, + zoomFactor: 1, + tabs: 2, + }; + this.notionElm = []; + this.loadedElms = []; + this.reactTabs = []; + this.handleNotionRef = (notionElm) => { + this.notionElm.push(notionElm); + }; + this.searchElm = null; + this.handleSearchRef = (searchElm) => { + this.searchElm = searchElm; + }; + this.handleReload = () => { + this.setState({ error: false }); + setTimeout(() => { + if (this.notionElm.length) { + this.notionElm.forEach(($notion) => { + if ($notion.isWaitingForResponse()) $notion.reload(); + }); + } + }, 50); + }; + window['newtab'] = () => { + this.setState({ tabs: this.state.tabs + 1 }); + setTimeout(() => this.addListeners(), 100); + }; + } + componentDidMount() { + this.addListeners(); + } + addListeners() { + const searchElm = this.searchElm; + const notionElm = this.notionElm; + if (!searchElm || !notionElm.length) { + return; + } - window['__start'] = function () { - __start(); - const dragarea = document.querySelector( - '#root [style*="-webkit-app-region: drag"]' - ), - default_styles = dragarea.getAttribute('style'); - - if (store().tiling_mode) { - dragarea.style.display = 'none'; - } else { - document - .getElementById('notion') - .addEventListener('ipc-message', (event) => { - if (event.channel !== 'enhancer:sidebar-width') return; - dragarea.setAttribute( - 'style', - `${default_styles} top: 2px; height: ${ - store().dragarea_height - }px; left: ${event.args[0]};` + notionElm + .filter(($notion) => !this.loadedElms.includes($notion)) + .forEach(($notion) => { + this.loadedElms.push($notion); + $notion.addEventListener('did-fail-load', (error) => { + // logger.info('Failed to load:', error); + if (error.errorCode === -3) { + return; + } + if ( + !error.validatedURL.startsWith( + schemeHelpers.getSchemeUrl({ + httpUrl: config.default.baseURL, + protocol: config.default.protocol, + }) + ) + ) { + return; + } + this.setState({ error: true }); + }); + notionIpc.receiveIndexFromNotion.addListener( + $notion, + 'search:start', + (isPeekView) => { + this.setState({ + searching: true, + searchingPeekView: isPeekView, + }); + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + searchElm.focus(); + notionIpc.sendIndexToSearch(searchElm, 'search:start'); + notionIpc.sendIndexToNotion(searchElm, 'search:started'); + } + ); + notionIpc.receiveIndexFromNotion.addListener( + $notion, + 'search:stop', + () => { + notionIpc.sendIndexToSearch(searchElm, 'search:reset'); + this.setState({ + searching: false, + }); + this.lastSearchQuery = undefined; + $notion.getWebContents().stopFindInPage('clearSelection'); + notionIpc.sendIndexToNotion($notion, 'search:stopped'); + } + ); + notionIpc.receiveIndexFromSearch.addListener( + searchElm, + 'search:next', + (query) => { + $notion.getWebContents().findInPage(query, { + forward: true, + findNext: query === this.lastSearchQuery, + }); + this.lastSearchQuery = query; + } + ); + notionIpc.receiveIndexFromSearch.addListener( + searchElm, + 'search:prev', + (query) => { + $notion.getWebContents().findInPage(query, { + forward: false, + findNext: query === this.lastSearchQuery, + }); + this.lastSearchQuery = query; + } + ); + notionIpc.receiveIndexFromSearch.addListener( + searchElm, + 'search:clear', + () => { + this.lastSearchQuery = undefined; + $notion.getWebContents().stopFindInPage('clearSelection'); + } + ); + notionIpc.receiveIndexFromSearch.addListener( + searchElm, + 'search:stop', + () => { + this.lastSearchQuery = undefined; + $notion.getWebContents().stopFindInPage('clearSelection'); + this.setState({ searching: false }); + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + $notion.focus(); + notionIpc.sendIndexToNotion($notion, 'search:stopped'); + } + ); + $notion.addEventListener('dom-ready', () => { + $notion + .getWebContents() + .addListener('found-in-page', (event, result) => { + const matches = result + ? { + count: result.matches, + index: result.activeMatchOrdinal, + } + : { count: 0, index: 0 }; + notionIpc.sendIndexToSearch( + searchElm, + 'search:result', + matches + ); + }); + notionIpc.proxyAllMainToNotion($notion); + }); + notionIpc.receiveIndexFromNotion.addListener( + $notion, + 'search:set-theme', + (theme) => { + notionIpc.sendIndexToSearch( + searchElm, + 'search:set-theme', + theme + ); + } + ); + notionIpc.receiveIndexFromNotion.addListener( + $notion, + 'zoom', + (zoomFactor) => { + $notion.getWebContents().setZoomFactor(zoomFactor); + searchElm.getWebContents().setZoomFactor(zoomFactor); + this.setState({ zoomFactor }); + } + ); + let electronWindow; + try { + electronWindow = electron.remote.getCurrentWindow(); + } catch (error) { + notionIpc.sendToMain('notion:log-error', { + level: 'error', + from: 'index', + type: 'GetCurrentWindowError', + error: error.message, + }); + } + if (!electronWindow) { + this.setState({ error: true }); + this.handleReload(); + return; + } + electronWindow.on('focus', (e) => { + $notion.focus(); + }); + $notion.addEventListener('dom-ready', function () { + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + $notion.blur(); + $notion.focus(); + }); + electronWindow.addListener('app-command', (e, cmd) => { + const webContents = $notion.getWebContents(); + if (cmd === 'browser-backward' && webContents.canGoBack()) { + webContents.goBack(); + } else if ( + cmd === 'browser-forward' && + webContents.canGoForward() + ) { + webContents.goForward(); + } + }); + electronWindow.addListener('swipe', (e, dir) => { + const webContents = $notion.getWebContents(); + if (dir === 'left' && webContents.canGoBack()) { + webContents.goBack(); + } else if (dir === 'right' && webContents.canGoForward()) { + webContents.goForward(); + } + }); + const sendFullScreenChangeEvent = () => { + notionIpc.sendIndexToNotion( + $notion, + 'notion:full-screen-changed' + ); + }; + electronWindow.addListener( + 'enter-full-screen', + sendFullScreenChangeEvent + ); + electronWindow.addListener( + 'leave-full-screen', + sendFullScreenChangeEvent + ); + electronWindow.addListener( + 'enter-html-full-screen', + sendFullScreenChangeEvent + ); + electronWindow.addListener( + 'leave-html-full-screen', + sendFullScreenChangeEvent + ); + }); + } + renderSearchContainer() { + return React.createElement( + 'div', + { style: this.getSearchContainerStyle() }, + React.createElement('webview', { + id: 'search', + style: this.getSearchWebviewStyle(), + ref: this.handleSearchRef, + partition: constants.electronSessionPartition, + preload: `file://${path.resolve( + `${__notion}/app/renderer/search.js` + )}`, + src: `file://${path.resolve( + `${__notion}/app/renderer/search.html` + )}`, + }) + ); + } + renderNotionContainer() { + this.reactTabs = [ + ...this.reactTabs, + ...new Array(this.state.tabs - this.reactTabs.length) + .fill(0) + .map((i) => + React.createElement('webview', { + className: 'notion', + style: Index.notionWebviewStyle, + ref: this.handleNotionRef, + partition: constants.electronSessionPartition, + preload: path.resolve(`${__notion}/app/renderer/preload.js`), + src: this.props.notionUrl, + }) + ), + ]; + return React.createElement( + 'div', + { style: this.getNotionContainerStyle() }, + ...this.reactTabs + ); + } + renderErrorContainer() { + return React.createElement( + 'div', + { style: this.getErrorContainerStyle() }, + React.createElement('img', { + style: Index.frontImageStyle, + src: './onboarding-offline.png', + }), + React.createElement( + 'div', + { style: Index.frontMessageStyle }, + React.createElement( + 'div', + null, + React.createElement(notion_intl.FormattedMessage, { + id: 'desktopLogin.offline.title', + defaultMessage: 'Welcome to Notion!', + values: { + strong: (...chunks) => + React.createElement('strong', null, chunks), + }, + }) + ), + React.createElement( + 'div', + null, + React.createElement(notion_intl.FormattedMessage, { + id: 'desktopLogin.offline.message', + defaultMessage: 'Connect to the internet to get started.', + }) + ) + ), + React.createElement( + 'div', + null, + React.createElement( + 'button', + { style: Index.reloadButtonStyle, onClick: this.handleReload }, + React.createElement(notion_intl.FormattedMessage, { + id: + 'desktopLogin.offline.retryConnectingToInternetButton.label', + defaultMessage: 'Try again', + }) + ) + ) + ); + } + renderDragRegion() { + return React.createElement('div', { style: Index.dragRegionStyle }); + } + render() { + const notionLocale = localizationHelper.getNotionLocaleFromElectronLocale( + window.navigator.language + ), + result = React.createElement( + notion_intl.IntlProvider, + { + locale: notionLocale, + messages: notionLocale === 'ko-KR' ? koMessages : {}, + }, + this.renderDragRegion(), + this.renderNotionContainer(), + this.renderSearchContainer(), + this.renderErrorContainer() ); - }); + this.addListeners(); + return result; + } + getNotionContainerStyle() { + const style = { + position: 'fixed', + top: 0, + left: 0, + right: 0, + bottom: 0, + display: this.state.error ? 'none' : 'flex', + }; + return style; + } + getErrorContainerStyle() { + const style = { + position: 'fixed', + top: 0, + left: 0, + right: 0, + bottom: 0, + display: this.state.error ? 'flex' : 'none', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + padding: 24, + paddingBottom: '8vh', + }; + return style; + } + getSearchWebviewStyle() { + const style = { + width: '100%', + height: '100%', + transition: 'transform 70ms ease-in', + transform: 'translateY(-100%)', + pointerEvents: 'none', + }; + if (this.state.searching) { + style.transition = 'transform 70ms ease-out'; + style.transform = 'translateY(0%)'; + style.pointerEvents = 'auto'; + } + return style; + } + getSearchContainerStyle() { + const style = { + position: 'fixed', + overflow: 'hidden', + pointerEvents: 'none', + padding: '0 20px', + top: + (this.state.searchingPeekView + ? 0 + : process.platform === 'darwin' + ? 37 + : 45) * this.state.zoomFactor, + right: (48 - 24) * this.state.zoomFactor, + width: 440 * this.state.zoomFactor, + height: 72 * this.state.zoomFactor, + }; + return style; + } } - }; + Index.frontMessageStyle = { + paddingTop: 16, + paddingBottom: 16, + textAlign: 'center', + lineHeight: 1.4, + fontSize: 17, + letterSpacing: '-0.01em', + color: '#424241', + fontWeight: 500, + }; + Index.reloadButtonStyle = { + background: '#fefaf8', + border: '1px solid #f1cbca', + boxSizing: 'border-box', + boxShadow: '0px 1px 2px rgba(0, 0, 0, 0.1)', + borderRadius: 3, + lineHeight: 'normal', + fontSize: 14, + fontWeight: 600, + letterSpacing: '-0.03em', + color: '#d8615c', + paddingLeft: 12, + paddingRight: 12, + height: 36, + }; + Index.frontImageStyle = { + width: 300, + maxWidth: '100%', + }; + Index.notionWebviewStyle = { + width: '100%', + height: '100%', + }; + Index.dragRegionStyle = { + position: 'absolute', + zIndex: 9999, + top: 0, + left: 0, + right: 0, + height: 2, + pointerEvents: 'none', + WebkitAppRegion: 'drag', + }; + + window['__start'] = () => { + const parsed = url.parse(window.location.href, true), + notionUrl = + parsed.query.path || + schemeHelpers.getSchemeUrl({ + httpUrl: config.default.baseURL, + protocol: config.default.protocol, + }); + delete parsed.search; + delete parsed.query; + const plainUrl = url.format(parsed); + window.history.replaceState(undefined, undefined, plainUrl); + document.title = localizationHelper + .createIntlShape( + localizationHelper.getNotionLocaleFromElectronLocale( + window.navigator.language + ) + ) + .formatMessage( + notion_intl.defineMessages({ + documentTitle: { + id: 'desktop.documentTitle', + defaultMessage: 'Notion Desktop', + }, + }).documentTitle + ); + const rootElm = document.getElementById('root'); + ReactDOM.render( + React.createElement(Index, { notionUrl: notionUrl }), + rootElm + ); + }; + } else { + const __start = window['__start']; + + window['__start'] = () => { + __start(); + const dragarea = document.querySelector( + '#root [style*="-webkit-app-region: drag"]' + ), + default_styles = dragarea.getAttribute('style'); + if (store().tiling_mode) { + dragarea.style.display = 'none'; + } else { + document + .getElementById('notion') + .addEventListener('ipc-message', (event) => { + if (event.channel !== 'enhancer:sidebar-width') return; + dragarea.setAttribute( + 'style', + `${default_styles} top: 2px; height: ${ + store().dragarea_height + }px; left: ${event.args[0]};` + ); + }); + } + }; + } }; From 85636647bd1911273827854130b40a40fdda1ed1 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Tue, 6 Oct 2020 10:15:30 +1100 Subject: [PATCH 11/50] catch EBUSY, potential csp fix for #66 --- CHANGELOG.md | 2 +- mods/core/create.js | 14 +++++++++++ mods/core/render.js | 61 +++++++++++++++++++++++++++------------------ pkg/apply.js | 4 +-- pkg/remove.js | 2 +- 5 files changed, 55 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd5768c..a84c6a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ a flexibility update. - bugfix: removed messenger emoji set as the provider no longer supports it. - bugfix: remove shadow around light mode board headers \+ minor text colour fixes for night shift theming. -- bugfix: properly detect/respond to `EACCES` errors. +- 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. diff --git a/mods/core/create.js b/mods/core/create.js index fb37b5a..9daff2c 100644 --- a/mods/core/create.js +++ b/mods/core/create.js @@ -52,6 +52,20 @@ module.exports = (store, __exports) => { }, ...rect, }); + electron.session + .fromPartition('persist:notion') + .webRequest.onHeadersReceived((details, callback) => { + callback({ + responseHeaders: Object.assign( + { + 'Content-Security-Policy': [ + "script-src 'self' 'unsafe-inline' 'unsafe-eval' enhancement: https://gist.github.com https://apis.google.com https://api.amplitude.com https://widget.intercom.io https://js.intercomcdn.com https://logs-01.loggly.com https://cdn.segment.com https://analytics.pgncs.notion.so https://checkout.stripe.com https://embed.typeform.com https://admin.typeform.com https://platform.twitter.com https://cdn.syndication.twimg.com; connect-src 'self' https://msgstore.www.notion.so wss://msgstore.www.notion.so https://notion-emojis.s3-us-west-2.amazonaws.com https://s3-us-west-2.amazonaws.com https://s3.us-west-2.amazonaws.com https://notion-production-snapshots-2.s3.us-west-2.amazonaws.com https: http: https://api.amplitude.com https://api.embed.ly https://js.intercomcdn.com https://api-iam.intercom.io wss://nexus-websocket-a.intercom.io https://logs-01.loggly.com https://api.segment.io https://api.pgncs.notion.so https://checkout.stripe.com https://cdn.contentful.com https://preview.contentful.com https://images.ctfassets.net https://api.unsplash.com https://boards-api.greenhouse.io; font-src 'self' data: https://cdnjs.cloudflare.com https://js.intercomcdn.com; img-src 'self' data: blob: https: https://platform.twitter.com https://syndication.twitter.com https://pbs.twimg.com https://ton.twimg.com; style-src 'self' 'unsafe-inline' enhancement: https://cdnjs.cloudflare.com https://github.githubassets.com https://platform.twitter.com https://ton.twimg.com; frame-src https: http:; media-src https: http:", + ], + }, + details.responseHeaders + ), + }); + }); window.once('ready-to-show', function () { if ( !store().openhidden || diff --git a/mods/core/render.js b/mods/core/render.js index dc94206..3b0b494 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -21,6 +21,7 @@ const url = require('url'), module.exports = (store, __exports) => { if (store().tabs) { + let $currentTab; class Index extends React.PureComponent { constructor() { super(...arguments); @@ -29,11 +30,11 @@ module.exports = (store, __exports) => { searching: false, searchingPeekView: false, zoomFactor: 1, - tabs: 2, + tabs: [], }; this.notionElm = []; this.loadedElms = []; - this.reactTabs = []; + this.reactTabs = {}; this.handleNotionRef = (notionElm) => { this.notionElm.push(notionElm); }; @@ -51,13 +52,26 @@ module.exports = (store, __exports) => { } }, 50); }; - window['newtab'] = () => { - this.setState({ tabs: this.state.tabs + 1 }); - setTimeout(() => this.addListeners(), 100); + window['tab'] = (id) => { + if (!id) return; + this.setState({ tabs: [...new Set([...this.state.tabs, id])] }); + setTimeout(() => { + this.addListeners(); + if (document.querySelector(`#tab-${id}`)) { + $currentTab = document.querySelector(`#tab-${id}`); + $currentTab.focus(); + } + }, 100); }; } componentDidMount() { this.addListeners(); + + try { + electron.remote.getCurrentWindow().on('focus', (e) => { + $notion.focus(); + }); + } catch {} } addListeners() { const searchElm = this.searchElm; @@ -214,10 +228,8 @@ module.exports = (store, __exports) => { this.handleReload(); return; } - electronWindow.on('focus', (e) => { - $notion.focus(); - }); $notion.addEventListener('dom-ready', function () { + if ($notion !== $currentTab) return; if (document.activeElement instanceof HTMLElement) { document.activeElement.blur(); } @@ -286,25 +298,26 @@ module.exports = (store, __exports) => { ); } renderNotionContainer() { - this.reactTabs = [ - ...this.reactTabs, - ...new Array(this.state.tabs - this.reactTabs.length) - .fill(0) - .map((i) => - React.createElement('webview', { - className: 'notion', - style: Index.notionWebviewStyle, - ref: this.handleNotionRef, - partition: constants.electronSessionPartition, - preload: path.resolve(`${__notion}/app/renderer/preload.js`), - src: this.props.notionUrl, - }) - ), - ]; + this.reactTabs = Object.fromEntries( + this.state.tabs.map((id) => { + return [ + id, + this.reactTabs[id] || + React.createElement('webview', { + className: 'notion', + style: Index.notionWebviewStyle, + ref: this.handleNotionRef, + partition: constants.electronSessionPartition, + preload: path.resolve(`${__notion}/app/renderer/preload.js`), + src: this.props.notionUrl, + }), + ]; + }) + ); return React.createElement( 'div', { style: this.getNotionContainerStyle() }, - ...this.reactTabs + ...Object.values(this.reactTabs) ); } renderErrorContainer() { diff --git a/pkg/apply.js b/pkg/apply.js index 79308dc..fae2201 100644 --- a/pkg/apply.js +++ b/pkg/apply.js @@ -55,7 +55,7 @@ module.exports = async function ({ overwrite_version, friendly_errors } = {}) { console.info(' ...unpacking app.asar.'); const asar_app = path.resolve(`${helpers.__notion}/app.asar`); extractAll(asar_app, `${path.resolve(`${helpers.__notion}/app`)}`); - fs.move(asar_app, path.resolve(`${helpers.__notion}/app.asar.bak`)); + await fs.move(asar_app, path.resolve(`${helpers.__notion}/app.asar.bak`)); // patching launch script target of custom wrappers if ( @@ -120,7 +120,7 @@ module.exports = async function ({ overwrite_version, friendly_errors } = {}) { : `try running "chown -R $USER ${err.path}"` }` ); - } else if (err.code === 'EIO' && friendly_errors) { + } else if (['EIO', 'EBUSY'].includes(err.code) && friendly_errors) { console.error('file access failed: is notion running?'); } else console.error(err); return false; diff --git a/pkg/remove.js b/pkg/remove.js index 865ef36..f003957 100644 --- a/pkg/remove.js +++ b/pkg/remove.js @@ -122,7 +122,7 @@ module.exports = async function ({ : `try running "chown -R $USER ${err.path}"` }` ); - } else if (err.code === 'EIO' && friendly_errors) { + } else if (['EIO', 'EBUSY'].includes(err.code) && friendly_errors) { console.error('file access failed: is notion running?'); } else console.error(err); return false; From 5bec4e31b680f7465bc5e30b65d714bb6a16249a Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Tue, 6 Oct 2020 11:47:33 +1100 Subject: [PATCH 12/50] attempt 3 at #66 --- CHANGELOG.md | 1 + mods/core/create.js | 15 +++++++-------- mods/core/render.js | 29 ++++++++++++++++++++--------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a84c6a3..c20b2d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ a flexibility update. 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. - tweak: sticky table/list rows. - extension: "material ocean" = an oceanic colour palette. diff --git a/mods/core/create.js b/mods/core/create.js index 9daff2c..f428013 100644 --- a/mods/core/create.js +++ b/mods/core/create.js @@ -55,15 +55,14 @@ module.exports = (store, __exports) => { electron.session .fromPartition('persist:notion') .webRequest.onHeadersReceived((details, callback) => { + alert(1); callback({ - responseHeaders: Object.assign( - { - 'Content-Security-Policy': [ - "script-src 'self' 'unsafe-inline' 'unsafe-eval' enhancement: https://gist.github.com https://apis.google.com https://api.amplitude.com https://widget.intercom.io https://js.intercomcdn.com https://logs-01.loggly.com https://cdn.segment.com https://analytics.pgncs.notion.so https://checkout.stripe.com https://embed.typeform.com https://admin.typeform.com https://platform.twitter.com https://cdn.syndication.twimg.com; connect-src 'self' https://msgstore.www.notion.so wss://msgstore.www.notion.so https://notion-emojis.s3-us-west-2.amazonaws.com https://s3-us-west-2.amazonaws.com https://s3.us-west-2.amazonaws.com https://notion-production-snapshots-2.s3.us-west-2.amazonaws.com https: http: https://api.amplitude.com https://api.embed.ly https://js.intercomcdn.com https://api-iam.intercom.io wss://nexus-websocket-a.intercom.io https://logs-01.loggly.com https://api.segment.io https://api.pgncs.notion.so https://checkout.stripe.com https://cdn.contentful.com https://preview.contentful.com https://images.ctfassets.net https://api.unsplash.com https://boards-api.greenhouse.io; font-src 'self' data: https://cdnjs.cloudflare.com https://js.intercomcdn.com; img-src 'self' data: blob: https: https://platform.twitter.com https://syndication.twitter.com https://pbs.twimg.com https://ton.twimg.com; style-src 'self' 'unsafe-inline' enhancement: https://cdnjs.cloudflare.com https://github.githubassets.com https://platform.twitter.com https://ton.twimg.com; frame-src https: http:; media-src https: http:", - ], - }, - details.responseHeaders - ), + responseHeaders: { + ...details.responseHeaders, + 'Content-Security-Policy': [ + "script-src 'self' 'unsafe-inline' 'unsafe-eval' enhancement: https://gist.github.com https://apis.google.com https://api.amplitude.com https://widget.intercom.io https://js.intercomcdn.com https://logs-01.loggly.com https://cdn.segment.com https://analytics.pgncs.notion.so https://checkout.stripe.com https://embed.typeform.com https://admin.typeform.com https://platform.twitter.com https://cdn.syndication.twimg.com; connect-src 'self' https://msgstore.www.notion.so wss://msgstore.www.notion.so https://notion-emojis.s3-us-west-2.amazonaws.com https://s3-us-west-2.amazonaws.com https://s3.us-west-2.amazonaws.com https://notion-production-snapshots-2.s3.us-west-2.amazonaws.com https: http: https://api.amplitude.com https://api.embed.ly https://js.intercomcdn.com https://api-iam.intercom.io wss://nexus-websocket-a.intercom.io https://logs-01.loggly.com https://api.segment.io https://api.pgncs.notion.so https://checkout.stripe.com https://cdn.contentful.com https://preview.contentful.com https://images.ctfassets.net https://api.unsplash.com https://boards-api.greenhouse.io; font-src 'self' data: https://cdnjs.cloudflare.com https://js.intercomcdn.com; img-src 'self' data: blob: https: https://platform.twitter.com https://syndication.twitter.com https://pbs.twimg.com https://ton.twimg.com; style-src 'self' 'unsafe-inline' enhancement: https://cdnjs.cloudflare.com https://github.githubassets.com https://platform.twitter.com https://ton.twimg.com; frame-src https: http:; media-src https: http:", + ], + }, }); }); window.once('ready-to-show', function () { diff --git a/mods/core/render.js b/mods/core/render.js index 3b0b494..8b26f1a 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -19,6 +19,13 @@ const url = require('url'), React = require(`${__notion}/app/node_modules/react/index.js`), ReactDOM = require(`${__notion}/app/node_modules/react-dom/index.js`); +const insertCSP = ` + const csp = document.createElement('meta'); + csp.httpEquiv = 'Content-Security-Policy'; + csp.content = "script-src 'self' 'unsafe-inline' 'unsafe-eval' enhancement: https://gist.github.com https://apis.google.com https://api.amplitude.com https://widget.intercom.io https://js.intercomcdn.com https://logs-01.loggly.com https://cdn.segment.com https://analytics.pgncs.notion.so https://checkout.stripe.com https://embed.typeform.com https://admin.typeform.com https://platform.twitter.com https://cdn.syndication.twimg.com; connect-src 'self' https://msgstore.www.notion.so wss://msgstore.www.notion.so https://notion-emojis.s3-us-west-2.amazonaws.com https://s3-us-west-2.amazonaws.com https://s3.us-west-2.amazonaws.com https://notion-production-snapshots-2.s3.us-west-2.amazonaws.com https: http: https://api.amplitude.com https://api.embed.ly https://js.intercomcdn.com https://api-iam.intercom.io wss://nexus-websocket-a.intercom.io https://logs-01.loggly.com https://api.segment.io https://api.pgncs.notion.so https://checkout.stripe.com https://cdn.contentful.com https://preview.contentful.com https://images.ctfassets.net https://api.unsplash.com https://boards-api.greenhouse.io; font-src 'self' data: https://cdnjs.cloudflare.com https://js.intercomcdn.com; img-src 'self' data: blob: https: https://platform.twitter.com https://syndication.twitter.com https://pbs.twimg.com https://ton.twimg.com; style-src 'self' 'unsafe-inline' enhancement: https://cdnjs.cloudflare.com https://github.githubassets.com https://platform.twitter.com https://ton.twimg.com; frame-src https: http:; media-src https: http:"; + document.head.appendChild(csp); +`; + module.exports = (store, __exports) => { if (store().tabs) { let $currentTab; @@ -53,7 +60,7 @@ module.exports = (store, __exports) => { }, 50); }; window['tab'] = (id) => { - if (!id) return; + if (!id && id !== 0) return; this.setState({ tabs: [...new Set([...this.state.tabs, id])] }); setTimeout(() => { this.addListeners(); @@ -175,6 +182,7 @@ module.exports = (store, __exports) => { } ); $notion.addEventListener('dom-ready', () => { + $notion.executeJavaScript(insertCSP); $notion .getWebContents() .addListener('found-in-page', (event, result) => { @@ -191,6 +199,12 @@ module.exports = (store, __exports) => { ); }); notionIpc.proxyAllMainToNotion($notion); + if ($notion !== $currentTab) return; + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + $notion.blur(); + $notion.focus(); }); notionIpc.receiveIndexFromNotion.addListener( $notion, @@ -228,14 +242,6 @@ module.exports = (store, __exports) => { this.handleReload(); return; } - $notion.addEventListener('dom-ready', function () { - if ($notion !== $currentTab) return; - if (document.activeElement instanceof HTMLElement) { - document.activeElement.blur(); - } - $notion.blur(); - $notion.focus(); - }); electronWindow.addListener('app-command', (e, cmd) => { const webContents = $notion.getWebContents(); if (cmd === 'browser-backward' && webContents.canGoBack()) { @@ -524,6 +530,7 @@ module.exports = (store, __exports) => { React.createElement(Index, { notionUrl: notionUrl }), rootElm ); + tab(0); }; } else { const __start = window['__start']; @@ -548,6 +555,10 @@ module.exports = (store, __exports) => { }px; left: ${event.args[0]};` ); }); + + document.getElementById('notion').addEventListener('dom-ready', () => { + document.getElementById('notion').executeJavaScript(insertCSP); + }); } }; } From 157d44025421459d233a4bd4d27cee1287479500 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Tue, 6 Oct 2020 22:12:25 +1100 Subject: [PATCH 13/50] separate search working for tabs --- mods/core/create.js | 1 - mods/core/render.js | 277 ++++++++++++++++++++++++++------------------ pkg/apply.js | 2 +- pkg/remove.js | 2 +- 4 files changed, 164 insertions(+), 118 deletions(-) diff --git a/mods/core/create.js b/mods/core/create.js index f428013..58437c8 100644 --- a/mods/core/create.js +++ b/mods/core/create.js @@ -55,7 +55,6 @@ module.exports = (store, __exports) => { electron.session .fromPartition('persist:notion') .webRequest.onHeadersReceived((details, callback) => { - alert(1); callback({ responseHeaders: { ...details.responseHeaders, diff --git a/mods/core/render.js b/mods/core/render.js index 8b26f1a..1e3f4a1 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -27,8 +27,7 @@ const insertCSP = ` `; module.exports = (store, __exports) => { - if (store().tabs) { - let $currentTab; + if (!store().tabs) { class Index extends React.PureComponent { constructor() { super(...arguments); @@ -39,64 +38,186 @@ module.exports = (store, __exports) => { zoomFactor: 1, tabs: [], }; + this.$currentTab; + this.tabCache = { + react: {}, + active: [], + loading: [], + }; this.notionElm = []; this.loadedElms = []; this.reactTabs = {}; - this.handleNotionRef = (notionElm) => { - this.notionElm.push(notionElm); + this.handleNotionRef = ($notion) => { + this.tabCache.loading.push($notion); }; - this.searchElm = null; + this.$search = null; this.handleSearchRef = (searchElm) => { - this.searchElm = searchElm; + this.$search = searchElm; }; this.handleReload = () => { this.setState({ error: false }); setTimeout(() => { - if (this.notionElm.length) { - this.notionElm.forEach(($notion) => { - if ($notion.isWaitingForResponse()) $notion.reload(); - }); - } + this.tabCache.loading.forEach(($notion) => { + if ($notion.isWaitingForResponse()) $notion.reload(); + }); }, 50); }; + this.startSearch = this.startSearch.bind(this); + this.stopSearch = this.stopSearch.bind(this); + this.nextSearch = this.nextSearch.bind(this); + this.prevSearch = this.prevSearch.bind(this); + this.clearSearch = this.clearSearch.bind(this); + this.doneSearch = this.doneSearch.bind(this); window['tab'] = (id) => { if (!id && id !== 0) return; this.setState({ tabs: [...new Set([...this.state.tabs, id])] }); setTimeout(() => { - this.addListeners(); + this.loadListeners(); + this.blurListeners(); if (document.querySelector(`#tab-${id}`)) { - $currentTab = document.querySelector(`#tab-${id}`); - $currentTab.focus(); + this.tabCache.active.forEach(($notion) => { + $notion.style.display = 'none'; + }); + this.$currentTab = document.querySelector(`#tab-${id}`); + this.$currentTab.style.display = 'flex'; + this.focusListeners(); } - }, 100); + }, 1000); }; } componentDidMount() { - this.addListeners(); + this.loadListeners(); try { electron.remote.getCurrentWindow().on('focus', (e) => { - $notion.focus(); + this.$currentTab.focus(); }); } catch {} } - addListeners() { - const searchElm = this.searchElm; - const notionElm = this.notionElm; - if (!searchElm || !notionElm.length) { - return; + startSearch(isPeekView) { + this.setState({ + searching: true, + searchingPeekView: isPeekView, + }); + if (document.activeElement instanceof HTMLElement) + document.activeElement.blur(); + this.$search.focus(); + notionIpc.sendIndexToSearch(this.$search, 'search:start'); + notionIpc.sendIndexToNotion(this.$search, 'search:started'); + } + stopSearch() { + notionIpc.sendIndexToSearch(this.$search, 'search:reset'); + this.setState({ + searching: false, + }); + this.lastSearchQuery = undefined; + this.$currentTab.getWebContents().stopFindInPage('clearSelection'); + notionIpc.sendIndexToNotion(this.$currentTab, 'search:stopped'); + } + nextSearch(query) { + this.$currentTab.getWebContents().findInPage(query, { + forward: true, + findNext: query === this.lastSearchQuery, + }); + this.lastSearchQuery = query; + } + prevSearch(query) { + this.$currentTab.getWebContents().findInPage(query, { + forward: false, + findNext: query === this.lastSearchQuery, + }); + this.lastSearchQuery = query; + } + clearSearch() { + this.lastSearchQuery = undefined; + this.$currentTab.getWebContents().stopFindInPage('clearSelection'); + } + doneSearch() { + this.lastSearchQuery = undefined; + this.$currentTab.getWebContents().stopFindInPage('clearSelection'); + this.setState({ searching: false }); + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); } - - notionElm - .filter(($notion) => !this.loadedElms.includes($notion)) + this.$currentTab.focus(); + notionIpc.sendIndexToNotion(this.$currentTab, 'search:stopped'); + } + blurListeners() { + if (!this.$currentTab) return; + if (this.state.searching) this.stopSearch(); + notionIpc.receiveIndexFromNotion.removeListener( + this.$currentTab, + 'search:start', + this.startSearch + ); + notionIpc.receiveIndexFromNotion.removeListener( + this.$currentTab, + 'search:stop', + this.stopSearch + ); + notionIpc.receiveIndexFromSearch.removeListener( + this.$search, + 'search:next', + this.nextSearch + ); + notionIpc.receiveIndexFromSearch.removeListener( + this.$search, + 'search:prev', + this.prevSearch + ); + notionIpc.receiveIndexFromSearch.removeListener( + this.$search, + 'search:clear', + this.clearSearch + ); + notionIpc.receiveIndexFromSearch.removeListener( + this.$search, + 'search:stop', + this.doneSearch + ); + } + focusListeners() { + notionIpc.receiveIndexFromNotion.addListener( + this.$currentTab, + 'search:start', + this.startSearch + ); + notionIpc.receiveIndexFromNotion.addListener( + this.$currentTab, + 'search:stop', + this.stopSearch + ); + notionIpc.receiveIndexFromSearch.addListener( + this.$search, + 'search:next', + this.nextSearch + ); + notionIpc.receiveIndexFromSearch.addListener( + this.$search, + 'search:prev', + this.prevSearch + ); + notionIpc.receiveIndexFromSearch.addListener( + this.$search, + 'search:clear', + this.clearSearch + ); + notionIpc.receiveIndexFromSearch.addListener( + this.$search, + 'search:stop', + this.doneSearch + ); + } + loadListeners() { + if (!this.$search) return; + this.tabCache.loading + .filter(($notion) => !this.tabCache.active.includes($notion)) .forEach(($notion) => { - this.loadedElms.push($notion); + this.tabCache.active.push($notion); $notion.addEventListener('did-fail-load', (error) => { // logger.info('Failed to load:', error); - if (error.errorCode === -3) { - return; - } if ( + error.errorCode === -3 || !error.validatedURL.startsWith( schemeHelpers.getSchemeUrl({ httpUrl: config.default.baseURL, @@ -108,81 +229,8 @@ module.exports = (store, __exports) => { } this.setState({ error: true }); }); - notionIpc.receiveIndexFromNotion.addListener( - $notion, - 'search:start', - (isPeekView) => { - this.setState({ - searching: true, - searchingPeekView: isPeekView, - }); - if (document.activeElement instanceof HTMLElement) { - document.activeElement.blur(); - } - searchElm.focus(); - notionIpc.sendIndexToSearch(searchElm, 'search:start'); - notionIpc.sendIndexToNotion(searchElm, 'search:started'); - } - ); - notionIpc.receiveIndexFromNotion.addListener( - $notion, - 'search:stop', - () => { - notionIpc.sendIndexToSearch(searchElm, 'search:reset'); - this.setState({ - searching: false, - }); - this.lastSearchQuery = undefined; - $notion.getWebContents().stopFindInPage('clearSelection'); - notionIpc.sendIndexToNotion($notion, 'search:stopped'); - } - ); - notionIpc.receiveIndexFromSearch.addListener( - searchElm, - 'search:next', - (query) => { - $notion.getWebContents().findInPage(query, { - forward: true, - findNext: query === this.lastSearchQuery, - }); - this.lastSearchQuery = query; - } - ); - notionIpc.receiveIndexFromSearch.addListener( - searchElm, - 'search:prev', - (query) => { - $notion.getWebContents().findInPage(query, { - forward: false, - findNext: query === this.lastSearchQuery, - }); - this.lastSearchQuery = query; - } - ); - notionIpc.receiveIndexFromSearch.addListener( - searchElm, - 'search:clear', - () => { - this.lastSearchQuery = undefined; - $notion.getWebContents().stopFindInPage('clearSelection'); - } - ); - notionIpc.receiveIndexFromSearch.addListener( - searchElm, - 'search:stop', - () => { - this.lastSearchQuery = undefined; - $notion.getWebContents().stopFindInPage('clearSelection'); - this.setState({ searching: false }); - if (document.activeElement instanceof HTMLElement) { - document.activeElement.blur(); - } - $notion.focus(); - notionIpc.sendIndexToNotion($notion, 'search:stopped'); - } - ); $notion.addEventListener('dom-ready', () => { - $notion.executeJavaScript(insertCSP); + $notion.getWebContents().executeJavaScript(insertCSP); $notion .getWebContents() .addListener('found-in-page', (event, result) => { @@ -193,25 +241,19 @@ module.exports = (store, __exports) => { } : { count: 0, index: 0 }; notionIpc.sendIndexToSearch( - searchElm, + this.$search, 'search:result', matches ); }); notionIpc.proxyAllMainToNotion($notion); - if ($notion !== $currentTab) return; - if (document.activeElement instanceof HTMLElement) { - document.activeElement.blur(); - } - $notion.blur(); - $notion.focus(); }); notionIpc.receiveIndexFromNotion.addListener( $notion, 'search:set-theme', (theme) => { notionIpc.sendIndexToSearch( - searchElm, + this.$search, 'search:set-theme', theme ); @@ -222,7 +264,7 @@ module.exports = (store, __exports) => { 'zoom', (zoomFactor) => { $notion.getWebContents().setZoomFactor(zoomFactor); - searchElm.getWebContents().setZoomFactor(zoomFactor); + this.$search.getWebContents().setZoomFactor(zoomFactor); this.setState({ zoomFactor }); } ); @@ -284,6 +326,7 @@ module.exports = (store, __exports) => { sendFullScreenChangeEvent ); }); + this.tabCache.loading = []; } renderSearchContainer() { return React.createElement( @@ -311,6 +354,7 @@ module.exports = (store, __exports) => { this.reactTabs[id] || React.createElement('webview', { className: 'notion', + id: `tab-${id}`, style: Index.notionWebviewStyle, ref: this.handleNotionRef, partition: constants.electronSessionPartition, @@ -391,7 +435,7 @@ module.exports = (store, __exports) => { this.renderSearchContainer(), this.renderErrorContainer() ); - this.addListeners(); + this.loadListeners(); return result; } getNotionContainerStyle() { @@ -487,6 +531,7 @@ module.exports = (store, __exports) => { Index.notionWebviewStyle = { width: '100%', height: '100%', + display: 'none', }; Index.dragRegionStyle = { position: 'absolute', @@ -534,7 +579,6 @@ module.exports = (store, __exports) => { }; } else { const __start = window['__start']; - window['__start'] = () => { __start(); const dragarea = document.querySelector( @@ -557,7 +601,10 @@ module.exports = (store, __exports) => { }); document.getElementById('notion').addEventListener('dom-ready', () => { - document.getElementById('notion').executeJavaScript(insertCSP); + document + .getElementById('notion') + .getWebContents() + .executeJavaScript(insertCSP); }); } }; diff --git a/pkg/apply.js b/pkg/apply.js index fae2201..96f3746 100644 --- a/pkg/apply.js +++ b/pkg/apply.js @@ -117,7 +117,7 @@ module.exports = async function ({ overwrite_version, friendly_errors } = {}) { `file access forbidden - ${ process.platform === 'win32' ? 'make sure your user has elevated permissions.' - : `try running "chown -R $USER ${err.path}"` + : `try running "sudo chmod a+wr -R ${err.path}"` }` ); } else if (['EIO', 'EBUSY'].includes(err.code) && friendly_errors) { diff --git a/pkg/remove.js b/pkg/remove.js index f003957..4f54abb 100644 --- a/pkg/remove.js +++ b/pkg/remove.js @@ -119,7 +119,7 @@ module.exports = async function ({ `file access forbidden - ${ process.platform === 'win32' ? 'make sure your user has elevated permissions.' - : `try running "chown -R $USER ${err.path}"` + : `try running "sudo chmod a+wr -R ${err.path}"` }` ); } else if (['EIO', 'EBUSY'].includes(err.code) && friendly_errors) { From 6e43097a3fb2b3a5918d85affd23f4846516d599 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Wed, 7 Oct 2020 23:58:22 +1100 Subject: [PATCH 14/50] replace dragarea with titlebar in tabbable mode --- mods/core/buttons.js | 2 +- mods/core/client.js | 65 +++-- mods/core/css/menu.css | 24 +- mods/core/css/tabs.css | 80 ++++++ mods/core/icons/alwaysontop_off.svg | 2 +- mods/core/icons/alwaysontop_on.svg | 2 +- mods/core/icons/maximize_off.svg | 2 +- mods/core/icons/maximize_on.svg | 2 +- mods/core/icons/minimize.svg | 2 +- mods/core/menu.html | 2 +- mods/core/menu.js | 6 +- mods/core/mod.js | 6 + mods/core/render.js | 399 ++++++++++++++-------------- mods/core/tray.js | 8 +- pkg/loader.js | 2 +- 15 files changed, 352 insertions(+), 252 deletions(-) create mode 100644 mods/core/css/tabs.css diff --git a/mods/core/buttons.js b/mods/core/buttons.js index e93dddd..e50de06 100644 --- a/mods/core/buttons.js +++ b/mods/core/buttons.js @@ -88,7 +88,7 @@ module.exports = (store) => { ]()}`; } for (let btn of buttons.insert) { - document.querySelector(`.window-button#btn-${btn}`).onclick = + buttons.element.querySelector(`.window-button#btn-${btn}`).onclick = buttons.actions[btn]; } if (store().frameless && !store().tiling_mode && !is_mac) { diff --git a/mods/core/client.js b/mods/core/client.js index 592a2ce..aa1f1bf 100644 --- a/mods/core/client.js +++ b/mods/core/client.js @@ -36,7 +36,7 @@ module.exports = (store, __exports) => { document.body.classList.add('snappy-transitions'); // frameless - if (store().frameless && !store().tiling_mode) { + if (store().frameless && !store().tiling_mode && !store().tabs) { document.body.classList.add('frameless'); // draggable area const dragarea = helpers.createElement( @@ -50,10 +50,12 @@ module.exports = (store, __exports) => { } // window buttons - const buttons = require('./buttons.js')(store); - document - .querySelector('.notion-topbar > div[style*="display: flex"]') - .appendChild(buttons.element); + if (!store().tabs) { + const buttons = require('./buttons.js')(store); + document + .querySelector('.notion-topbar > div[style*="display: flex"]') + .appendChild(buttons.element); + } document .querySelector('.notion-history-back-button') .parentElement.nextElementSibling.classList.add( @@ -100,7 +102,7 @@ module.exports = (store, __exports) => { // enhancer menu function setThemeVars() { electron.ipcRenderer.send( - 'enhancer:set-theme-vars', + 'enhancer:set-menu-theme', [ '--theme--main', '--theme--sidebar', @@ -142,31 +144,46 @@ module.exports = (store, __exports) => { '--theme--code_inline-background', ].map((rule) => [rule, getStyle(rule)]) ); + electron.ipcRenderer.sendToHost( + 'enhancer:set-tab-theme', + [ + '--theme--dragarea', + '--theme--font_sans', + '--theme--table-border', + '--theme--interactive_hover', + '--theme--interactive_hover-border', + '--theme--button_close', + '--theme--button_close-fill', + '--theme--text', + ].map((rule) => [rule, getStyle(rule)]) + ); } setThemeVars(); const theme_observer = new MutationObserver(setThemeVars); theme_observer.observe(document.querySelector('.notion-app-inner'), { attributes: true, }); - electron.ipcRenderer.on('enhancer:get-theme-vars', setThemeVars); + electron.ipcRenderer.on('enhancer:get-menu-theme', setThemeVars); - const sidebar_observer = new MutationObserver(setSidebarWidth); - sidebar_observer.observe(document.querySelector('.notion-sidebar'), { - attributes: true, - }); - let sidebar_width; - function setSidebarWidth(list) { - if (!store().frameless && store().tiling_mode) return; - const new_sidebar_width = - list[0].target.style.height === 'auto' - ? '0px' - : list[0].target.style.width; - if (new_sidebar_width !== sidebar_width) { - sidebar_width = new_sidebar_width; - electron.ipcRenderer.sendToHost( - 'enhancer:sidebar-width', - sidebar_width - ); + if (!store().tabs) { + const sidebar_observer = new MutationObserver(setSidebarWidth); + sidebar_observer.observe(document.querySelector('.notion-sidebar'), { + attributes: true, + }); + let sidebar_width; + function setSidebarWidth(list) { + if (!store().frameless && store().tiling_mode) return; + const new_sidebar_width = + list[0].target.style.height === 'auto' + ? '0px' + : list[0].target.style.width; + if (new_sidebar_width !== sidebar_width) { + sidebar_width = new_sidebar_width; + electron.ipcRenderer.sendToHost( + 'enhancer:sidebar-width', + sidebar_width + ); + } } } setSidebarWidth([{ target: document.querySelector('.notion-sidebar') }]); diff --git a/mods/core/css/menu.css b/mods/core/css/menu.css index 17992b8..2c393c8 100644 --- a/mods/core/css/menu.css +++ b/mods/core/css/menu.css @@ -50,10 +50,10 @@ body:not([style]) > * { body:not([style])::after { content: ''; position: absolute; - left: 44vw; - top: calc(50% - 7.5vw); - width: 10vw; - height: 10vw; + left: calc(50vw - 15px); + top: calc(50vh - 15px); + width: 30px; + height: 30px; border: 4px solid rgb(34, 34, 34); border-top-color: transparent; border-radius: 50%; @@ -93,7 +93,7 @@ s { /* titlebar */ -#menu-titlebar::before { +#titlebar::before { content: ''; position: absolute; width: 100%; @@ -103,20 +103,18 @@ s { height: 2px; } -#menu-titlebar { +#titlebar { display: flex; -webkit-app-region: drag; -} -#menu-titlebar button { - -webkit-app-region: no-drag; -} -#menu-titlebar { background: var(--theme--dragarea); } -#menu-titlebar > .window-buttons-area { +#titlebar button { + -webkit-app-region: no-drag; +} +#titlebar .window-buttons-area { margin: 0.4em 0.4em 0.4em auto; } -#menu-titlebar > .window-buttons-area:empty { +#titlebar .window-buttons-area:empty { display: none; } diff --git a/mods/core/css/tabs.css b/mods/core/css/tabs.css new file mode 100644 index 0000000..2e30eb1 --- /dev/null +++ b/mods/core/css/tabs.css @@ -0,0 +1,80 @@ +/* + * notion-enhancer + * (c) 2020 dragonwocky (https://dragonwocky.me/) + * under the MIT license + */ + +@import './buttons.css'; + +* { + box-sizing: border-box; + word-break: break-word; + text-decoration: none; + text-size-adjust: 100%; + font-family: var(--theme--font_sans); + outline-color: var(--theme--table-border); +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +body:not([style*='--theme']) > * { + opacity: 0; +} +body:not([style*='--theme'])::after { + content: ''; + position: absolute; + left: calc(50vw - 25px); + top: calc(50vh - 25px); + width: 50px; + height: 50px; + border: 4px solid rgb(34, 34, 34); + border-top-color: transparent; + border-radius: 50%; + animation: spin 0.8s linear infinite; +} + +html, +body, +#root { + height: 100%; + margin: 0; +} +#root { + display: flex; + flex-direction: column; +} + +#titlebar::before { + content: ''; + position: absolute; + width: 100%; + -webkit-app-region: no-drag; + top: 0; + left: 0; + height: 2px; +} +#titlebar { + display: flex; + flex-shrink: 1; + padding: 0.5em 0.15em; + user-select: none; + -webkit-app-region: drag; + background: var(--theme--dragarea); +} +#titlebar button { + color: var(--theme--text); + -webkit-app-region: no-drag; +} +#titlebar .window-buttons-area { + margin: auto 0.4em auto auto; +} +#titlebar .window-buttons-area:empty { + display: none; +} diff --git a/mods/core/icons/alwaysontop_off.svg b/mods/core/icons/alwaysontop_off.svg index 9fa0fb5..96afcf0 100644 --- a/mods/core/icons/alwaysontop_off.svg +++ b/mods/core/icons/alwaysontop_off.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/mods/core/icons/alwaysontop_on.svg b/mods/core/icons/alwaysontop_on.svg index 1c344f8..3fec5d5 100644 --- a/mods/core/icons/alwaysontop_on.svg +++ b/mods/core/icons/alwaysontop_on.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/mods/core/icons/maximize_off.svg b/mods/core/icons/maximize_off.svg index 7241f63..0bf56b0 100644 --- a/mods/core/icons/maximize_off.svg +++ b/mods/core/icons/maximize_off.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/mods/core/icons/maximize_on.svg b/mods/core/icons/maximize_on.svg index 681fdc9..af77a3e 100644 --- a/mods/core/icons/maximize_on.svg +++ b/mods/core/icons/maximize_on.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/mods/core/icons/minimize.svg b/mods/core/icons/minimize.svg index abcebb7..d179e14 100644 --- a/mods/core/icons/minimize.svg +++ b/mods/core/icons/minimize.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/mods/core/menu.html b/mods/core/menu.html index 3b3f91a..56da84e 100644 --- a/mods/core/menu.html +++ b/mods/core/menu.html @@ -9,7 +9,7 @@ - +