From e826b9ff73d98d1f9e2e440f5626badc6648a9f2 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Thu, 15 Oct 2020 12:19:21 +1100 Subject: [PATCH 1/7] #160 patch opening by notion://url on linux + tab bugfixes --- CHANGELOG.md | 5 ++-- README.md | 12 ++++++-- mods/core/client.js | 3 +- mods/core/{menu.js => enhancerMenu.js} | 7 +++-- mods/core/render.js | 18 ++++++++---- mods/core/systemMenu.js | 0 mods/core/tray.js | 11 ++++---- pkg/apply.js | 38 ++++++++++++++++++++------ 8 files changed, 66 insertions(+), 28 deletions(-) rename mods/core/{menu.js => enhancerMenu.js} (98%) create mode 100644 mods/core/systemMenu.js diff --git a/CHANGELOG.md b/CHANGELOG.md index daf7cc9..aea659c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,13 +13,14 @@ a flexibility update. higher up on the list = higher priority of application = loaded last in order to override others. (excluding the core, which though pinned to the top of the list is always loaded first so theming variables can be modified.) -- new: in-page columns disabled/wrapped and wider pages when the window is narrower than 600px - for improved responsiveness. +- new: in-page columns are disabled/wrapped and pages are wider when + the window is narrower than 600px for improved responsiveness. - new: relaunch button in tray menu. - new: a core mod option to make transitions snappy/0s. - new: a core mod option for a default page id/url (all new windows will load it instead of the normal "most recent" page). - new: css variables for increasing line spacing/paragraph margins. +- new: patch the notion:// url scheme/protocol to work on linux. - improved: menu will now respect integrated titlebar setting. - improved: use keyup listeners instead of a globalShortcut for the enhancements menu toggle. - bugfix: removed messenger emoji set as the provider no longer supports it. diff --git a/README.md b/README.md index a80ca9c..ef7ed44 100644 --- a/README.md +++ b/README.md @@ -114,8 +114,16 @@ team to take to heart for future improvements." ## features -once applied, modules can be configured via the graphical menu, which is opened from -the tray/menubar icon or with `OPTION/ALT+E`. +most of the enhancer's functionality is split into configurable enhancement modules, +but some basic improvements are built in by default: + +- the notion:// url scheme/protocol is patched to work on linux. +- in-page columns are disabled/wrapped and pages are wider when + the window is narrower than 600px for improved responsiveness. +- a tray/menubar icon: links relevant to the enhancer + buttons to manage notion windows. + +once applied, modules can be configured via the graphical menu, +which is opened from the tray/menubar ic,on or with `OPTION/ALT+E`. ![](https://user-images.githubusercontent.com/16874139/93692603-954fd980-fb38-11ea-9d52-82ac53449d33.png) diff --git a/mods/core/client.js b/mods/core/client.js index 7edcc75..f1cabbb 100644 --- a/mods/core/client.js +++ b/mods/core/client.js @@ -18,7 +18,7 @@ module.exports = (store, __exports) => { document.defaultView.addEventListener('keyup', (event) => { // additional hotkeys - if (event.code === 'F5') location.reload(); + if (event.key === 'F5') location.reload(); // open menu on hotkey toggle const hotkey = toKeyEvent(store().menu_toggle); let triggered = true; @@ -49,7 +49,6 @@ module.exports = (store, __exports) => { triggered = true; for (let prop in close_tab_keybinding) if (close_tab_keybinding[prop] !== event[prop]) triggered = false; - console.log(triggered, event); if (triggered) electron.ipcRenderer.sendToHost('enhancer:close-tab'); } }); diff --git a/mods/core/menu.js b/mods/core/enhancerMenu.js similarity index 98% rename from mods/core/menu.js rename to mods/core/enhancerMenu.js index 60a0d20..7a4829d 100644 --- a/mods/core/menu.js +++ b/mods/core/enhancerMenu.js @@ -118,7 +118,7 @@ window['__start'] = async () => { const $popup = document.querySelector('#popup'); document.addEventListener('keyup', (event) => { - if (event.code === 'F5') location.reload(); + if (event.key === 'F5') location.reload(); // further-configuration popup if ( $popup.classList.contains('visible') && @@ -126,12 +126,13 @@ window['__start'] = async () => { ) $popup.classList.remove('visible'); // close window on hotkey toggle - console.log(); const hotkey = toKeyEvent(coreStore().menu_toggle); let triggered = true; for (let prop in hotkey) if (hotkey[prop] !== event[prop]) triggered = false; - if (triggered) electron.remote.getCurrentWindow().close(); + if (triggered || ((event.ctrlKey || event.metaKey) && event.key === 'w')) + electron.remote.getCurrentWindow().close(); + console.log(event.ctrlKey, event.key); // focus search const meta = !(event.ctrlKey || event.metaKey) && !event.altKey && !event.shiftKey; diff --git a/mods/core/render.js b/mods/core/render.js index 085ecc3..d21d8df 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -108,14 +108,20 @@ module.exports = (store, __exports) => { document .querySelectorAll('.dragged-over') .forEach((el) => el.classList.remove('dragged-over')); + document + .querySelectorAll('.slideIn') + .forEach((el) => el.classList.remove('slideIn')); const from = getTab(this.views.tabs[+this.$dragging]), to = getTab(event.target); if (!from[1].classList.contains('new') && from[0] !== to[0]) to[1].parentElement.insertBefore(from[1], to[1]); - from[1].classList.remove('slideIn'); this.$dragging = null; + document + .querySelector('#tabs') + .appendChild(document.querySelector('.tab.new')); }); document.addEventListener('keyup', (event) => { + if (!electron.remote.getCurrentWindow().isFocused()) return; // switch between tabs via key modifier const select_tab_modifier = toKeyEvent( store('e1692c29-475e-437b-b7ff-3eee872e1a42').select_modifier @@ -139,8 +145,8 @@ module.exports = (store, __exports) => { triggered = true; for (let prop in close_tab_keybinding) if (close_tab_keybinding[prop] !== event[prop]) triggered = false; - console.log(triggered, event); - if (triggered) this.closeTab(this.views.current.id); + if (triggered && document.querySelector('.tab.current .close')) + document.querySelector('.tab.current .close').click(); }); } @@ -219,7 +225,7 @@ module.exports = (store, __exports) => { ? idToNotionURL(store().default_page) : this.views.current.$el().src ); - this.views.html[id].getWebContents().openDevTools(); + // this.views.html[id].getWebContents().openDevTools(); } }); } @@ -297,8 +303,8 @@ module.exports = (store, __exports) => { this.newTab(); break; case 'enhancer:close-tab': - if (event.target.id == this.views.current.id) - this.closeTab(+event.target.id); + if (document.querySelector('.tab.current .close')) + document.querySelector('.tab.current .close').click(); break; } } diff --git a/mods/core/systemMenu.js b/mods/core/systemMenu.js new file mode 100644 index 0000000..e69de29 diff --git a/mods/core/tray.js b/mods/core/tray.js index 0fd4c04..cbd62d4 100644 --- a/mods/core/tray.js +++ b/mods/core/tray.js @@ -33,7 +33,7 @@ module.exports = (store, __exports) => { // menu electron.ipcMain.on('enhancer:open-menu', (event, arg) => { - openExtensionMenu(); + openEnhancerMenu(); }); electron.ipcMain.on('enhancer:set-menu-theme', (event, arg) => { if (!enhancer_menu) return; @@ -81,13 +81,13 @@ module.exports = (store, __exports) => { }; } - function openExtensionMenu() { + function openEnhancerMenu() { if (enhancer_menu) return enhancer_menu.show(); const window_state = require(`${helpers.__notion.replace( /\\/g, '/' )}/app/node_modules/electron-window-state/index.js`)({ - file: 'menu-windowstate.json', + file: 'enhancerMenu.windowState.json', path: helpers.__data, defaultWidth: 275, defaultHeight: 600, @@ -106,7 +106,7 @@ module.exports = (store, __exports) => { width: window_state.width, height: window_state.height, webPreferences: { - preload: path.resolve(`${__dirname}/menu.js`), + preload: path.resolve(`${__dirname}/enhancerMenu.js`), nodeIntegration: true, session: electron.session.fromPartition('persist:notion'), }, @@ -116,6 +116,7 @@ module.exports = (store, __exports) => { window_state.saveState(enhancer_menu); enhancer_menu = null; }); + // enhancer_menu.webContents.openDevTools(); } // tray @@ -165,7 +166,7 @@ module.exports = (store, __exports) => { type: 'normal', label: 'Enhancements', accelerator: store().menu_toggle, - click: openExtensionMenu, + click: openEnhancerMenu, }, { type: 'normal', diff --git a/pkg/apply.js b/pkg/apply.js index d773356..3518e1c 100644 --- a/pkg/apply.js +++ b/pkg/apply.js @@ -90,18 +90,40 @@ module.exports = async function ({ overwrite_version, friendly_errors } = {}) { filter: (stats) => stats.isFile() && stats.path.endsWith('.js'), } )) { - insertion_target = path.resolve( + const insertion_file = path.resolve( `${helpers.__notion}/app/${insertion_target}` ); - fs.appendFile( - insertion_target, - `\n\n//notion-enhancer\nrequire('${helpers.realpath( - __dirname - )}/loader.js')(__filename, exports);` - ); + if (insertion_target === 'main/main.js') { + // https://github.com/dragonwocky/notion-enhancer/issues/160 + // patch the notion:// url scheme/protocol to work on linux + fs.readFile(insertion_file, 'utf8', (err, data) => { + if (err) throw err; + fs.writeFile( + insertion_file, + `${data.replace( + /process.platform === "win32"/g, + 'process.platform === "win32" || process.platform === "linux"' + )}\n\n//notion-enhancer\nrequire('${helpers.realpath( + __dirname + )}/loader.js')(__filename, exports);`, + 'utf8', + (err) => { + if (err) throw err; + } + ); + }); + } else { + fs.appendFile( + insertion_file, + `\n\n//notion-enhancer\nrequire('${helpers.realpath( + __dirname + )}/loader.js')(__filename, exports);` + ); + } } - // not resolved, nothing depends on it so it's just a "let it do its thing" + // not resolved, nothing else in application depends on it + // so it's just a "let it do its thing" console.info(' ...recording enhancement version.'); fs.outputFile( path.resolve(`${helpers.__notion}/app/ENHANCER_VERSION.txt`), From 0910e56d5356f2161796a0baf126815410a80452 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Thu, 15 Oct 2020 12:37:51 +1100 Subject: [PATCH 2/7] #161 removed typo in variable name for brown text. --- CHANGELOG.md | 1 + mods/core/css/theme.css | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aea659c..30f9bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ a flexibility update. - bugfix: improvements to the colour theming, particularly to make real- and fake-light/dark modes (as applied by the night shift extension) look consistent. - bugfix: font sizing applied to overlays/previews. +- bugfix: removed typo in variable name for brown text. - tweak: sticky table/list rows. - theme: "material ocean" = an oceanic colour palette. - theme: "dracula" = a theme based on the popular dracula color palette diff --git a/mods/core/css/theme.css b/mods/core/css/theme.css index a8e99ad..f5b270d 100644 --- a/mods/core/css/theme.css +++ b/mods/core/css/theme.css @@ -153,7 +153,7 @@ font-family: var(--theme--font_code) !important; } .notion-frame .notion-page-block div[placeholder='Untitled'], -.notion-overlay-container .notion-page-block div[placeholder='Untitled']{ +.notion-overlay-container .notion-page-block div[placeholder='Untitled'] { font-size: calc( var(--theme--font_body-size) * (var(--theme--font_heading1-size) / 1em) ) !important; @@ -174,15 +174,19 @@ ) !important; } .notion-frame .notion-scroller.vertical.horizontal [style*='font-size: 14px'], -.notion-overlay-container .notion-scroller.vertical [style*='font-size: 14px']{ +.notion-overlay-container .notion-scroller.vertical [style*='font-size: 14px'] { font-size: var(--theme--font_label-size) !important; } .notion-frame .notion-scroller.vertical.horizontal .notion-page-content, .notion-overlay-container .notion-scroller.vertical .notion-page-content { font-size: var(--theme--font_body-size) !important; } -.notion-frame .notion-scroller.vertical.horizontal .notion-page-content[style*='font-size: 14px'], -.notion-overlay-container .notion-scroller.vertical .notion-page-content[style*='font-size: 14px'] { +.notion-frame + .notion-scroller.vertical.horizontal + .notion-page-content[style*='font-size: 14px'], +.notion-overlay-container + .notion-scroller.vertical + .notion-page-content[style*='font-size: 14px'] { font-size: var(--theme--font_body-size_small) !important; } .notion-code-block [placeholder=' '] { @@ -557,7 +561,7 @@ .notion-body:not(.dark) [style*='color: rgb(100, 71, 58); fill: rgb(100, 71, 58);'] { fill: var(--theme--text_brown) !important; - color: var(--theme--text_brown-text) !important; + color: var(--theme--text_brown) !important; } .notion-body.dark [style*='background: rgba(147, 114, 100, 0.5)'], .notion-body:not(.dark) [style*='background: rgba(140, 46, 0, 0.2)'] { From dcbe96f447a377e744f5c3738c68cb3d6a44221d Mon Sep 17 00:00:00 2001 From: Alexa B Date: Thu, 15 Oct 2020 02:57:16 -0400 Subject: [PATCH 3/7] theme: cherry cola (#161) --- mods/cherrycola/mod.js | 16 +++++ mods/cherrycola/styles.css | 131 +++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 mods/cherrycola/mod.js create mode 100644 mods/cherrycola/styles.css diff --git a/mods/cherrycola/mod.js b/mods/cherrycola/mod.js new file mode 100644 index 0000000..33e4c34 --- /dev/null +++ b/mods/cherrycola/mod.js @@ -0,0 +1,16 @@ +/* + * cherry cola + * (c) 2020 Alexa Baldon (https://github.com/runargs) + * under the MIT license + */ + +'use strict'; + +module.exports = { + id: 'ec5c4640-68d4-4d25-aefd-62c7e9737cfb', + tags: ['theme', 'dark'], + name: 'cherry cola', + desc: 'a delightfully plummy, cherry cola flavored theme.', + version: '0.1.0', + author: 'runargs', +}; diff --git a/mods/cherrycola/styles.css b/mods/cherrycola/styles.css new file mode 100644 index 0000000..cabd481 --- /dev/null +++ b/mods/cherrycola/styles.css @@ -0,0 +1,131 @@ +/* + * cherry cola + * (c) 2020 Alexa Baldon (https://github.com/runargs) + * under the MIT license + */ + + :root { + + --cola-main: #180915; + --cola-sec: #1d0919; + --cola-accent: #bf799b; + --cola-gray: #696460; + --cola-brown: #755241; + --cola-orange: #e6846b; + --cola-yellow: #d7b56e; + --cola-green: #8f9b4f; + --cola-blue: #6ebdb7; + --cola-purple: #813d63; + --cola-pink: #d86f71; + --cola-red: #a33232; + + --theme_dark--main: var(--cola-main); + --theme_dark--sidebar: var(--cola-sec); + --theme_dark--overlay: var(--cola-sec); + --theme_dark--dragarea: var(--cola-sec); + + --theme_dark--scrollbar: var(--cola-sec); + --theme_dark--scrollbar_hover: var(--cola-accent); + + --theme_dark--card: var(--cola-sec); + --theme_dark--gallery: var(--cola-sec); + --theme_dark--table-border: var(--cola-sec); + --theme_dark--interactive_hover: var(--cola-main); + --theme_dark--button_close: var(--cola-accent); + + --theme_dark--selected: var(--cola-sec); + --theme_dark--primary: var(--cola-accent); + --theme_dark--primary_hover: var(--cola-accent); + --theme_dark--primary_click: var(--cola-sec); + --theme_dark--primary_indicator: var(--cola-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(--cola-gray); + --theme_dark--text_ui_info: var(--cola-gray); + + --theme_dark--text_gray: var(--cola-gray); + --theme_dark--text_brown: var(--cola-brown); + --theme_dark--text_orange: var(--cola-orange); + --theme_dark--text_yellow: var(--cola-yellow); + --theme_dark--text_green: var(--cola-green); + --theme_dark--text_blue: var(--cola-blue); + --theme_dark--text_purple: var(--cola-purple); + --theme_dark--text_pink: var(--cola-pink); + --theme_dark--text_red: var(--cola-red); + + --theme_dark--select-text: var(--cola-main); + --theme_dark--select_gray: var(--cola-gray); + --theme_dark--select_brown: var(--cola-brown); + --theme_dark--select_orange: var(--cola-orange); + --theme_dark--select_yellow: var(--cola-yellow); + --theme_dark--select_green: var(--cola-green); + --theme_dark--select_blue: var(--cola-blue); + --theme_dark--select_purple: var(--cola-purple); + --theme_dark--select_pink: var(--cola-pink); + --theme_dark--select_red: var(--cola-red); + + --theme_dark--line-text: var(--cola-main); + --theme_dark--line_gray: var(--cola-gray); + --theme_dark--line_brown: var(--cola-brown); + --theme_dark--line_orange: var(--cola-orange); + --theme_dark--line_yellow: var(--cola-yellow); + --theme_dark--line_green: var(--cola-green); + --theme_dark--line_blue: var(--cola-blue); + --theme_dark--line_purple: var(--cola-purple); + --theme_dark--line_pink: var(--cola-pink); + --theme_dark--line_red: var(--cola-red); + + --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: var(--cola-accent); + --theme_dark--code_inline-background: var(--cola-main); + --theme_dark--code-text: var(--theme_dark--text); + --theme_dark--code-background: var(--cola-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); + +} + +.notion-dark-theme + .notion-quote-block{ + font-family: Georgia, 'Times New Roman', Times, serif; + background-color: var(--cola-sec); +} \ No newline at end of file From b23b9282899d62f473ff1f2e9ab206ea1d756ec4 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Thu, 15 Oct 2020 22:01:28 +1100 Subject: [PATCH 4/7] + left/right tab switching, + remove cmd/ctrl+w from menu, - break tab opening/closing/titles --- CHANGELOG.md | 3 + README.md | 2 +- mods/core/client.js | 39 +- mods/core/{create.js => createWindow.js} | 0 mods/core/mod.js | 3 +- mods/core/render.js | 239 +++++++----- mods/core/systemMenu.js | 476 +++++++++++++++++++++++ mods/core/tray.js | 4 +- mods/tabs/mod.js | 14 +- 9 files changed, 658 insertions(+), 122 deletions(-) rename mods/core/{create.js => createWindow.js} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30f9bf6..9433cb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,8 @@ a flexibility update. - bugfix: remove focus mode footer from neutral theme. - bugfix: improvements to the colour theming, particularly to make real- and fake-light/dark modes (as applied by the night shift extension) look consistent. + relevant variables (assuming all are prefixed by `--theme_[dark|light]--`): + `box-shadow`, `box-shadow_strong`, `select_input`, and `ui-border` - bugfix: font sizing applied to overlays/previews. - bugfix: removed typo in variable name for brown text. - tweak: sticky table/list rows. @@ -52,6 +54,7 @@ a fork of notion-deb-builder that does generate an app.asar has been created and - bugfix: night shift working on macOS. - bugfix: windows are properly hidden/shown on macOS. - extension: "tweaks" = common layout changes. +- update themes to new variables. ### v0.9.1 (2020-09-26) diff --git a/README.md b/README.md index ef7ed44..91c4019 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ but some basic improvements are built in by default: - a tray/menubar icon: links relevant to the enhancer + buttons to manage notion windows. once applied, modules can be configured via the graphical menu, -which is opened from the tray/menubar ic,on or with `OPTION/ALT+E`. +which is opened from the tray/menubar icon or with `OPTION/ALT+E`. ![](https://user-images.githubusercontent.com/16874139/93692603-954fd980-fb38-11ea-9d52-82ac53449d33.png) diff --git a/mods/core/client.js b/mods/core/client.js index f1cabbb..29f6b6b 100644 --- a/mods/core/client.js +++ b/mods/core/client.js @@ -14,7 +14,9 @@ module.exports = (store, __exports) => { /\\/g, '/' )}/app/helpers/notionIpc.js`), - { toKeyEvent } = require('keyboardevent-from-electron-accelerator'); + { toKeyEvent } = require('keyboardevent-from-electron-accelerator'), + tabsEnabled = (store('mods')['e1692c29-475e-437b-b7ff-3eee872e1a42'] || {}) + .enabled; document.defaultView.addEventListener('keyup', (event) => { // additional hotkeys @@ -25,7 +27,7 @@ module.exports = (store, __exports) => { for (let prop in hotkey) if (hotkey[prop] !== event[prop]) triggered = false; if (triggered) electron.ipcRenderer.send('enhancer:open-menu'); - if ((store('mods')['e1692c29-475e-437b-b7ff-3eee872e1a42'] || {}).enabled) { + if (tabsEnabled) { // switch between tabs via key modifier const select_tab_modifier = toKeyEvent( store('e1692c29-475e-437b-b7ff-3eee872e1a42').select_modifier @@ -33,7 +35,22 @@ module.exports = (store, __exports) => { let triggered = true; for (let prop in select_tab_modifier) if (select_tab_modifier[prop] !== event[prop]) triggered = false; - if (triggered && [1, 2, 3, 4, 5, 6, 7, 8, 9].includes(+event.key)) + if ( + triggered && + [ + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'ArrowRight', + 'ArrowLeft', + ].includes(event.key) + ) electron.ipcRenderer.sendToHost('enhancer:select-tab', event.key); // create/close tab keybindings const new_tab_keybinding = toKeyEvent( @@ -69,11 +86,7 @@ module.exports = (store, __exports) => { document.body.classList.add('snappy-transitions'); // frameless - if ( - store().frameless && - !store().tiling_mode && - !(store('mods')['e1692c29-475e-437b-b7ff-3eee872e1a42'] || {}).enabled - ) { + if (store().frameless && !store().tiling_mode && !tabsEnabled) { document.body.classList.add('frameless'); // draggable area document @@ -86,9 +99,7 @@ module.exports = (store, __exports) => { } // window buttons - if ( - !(store('mods')['e1692c29-475e-437b-b7ff-3eee872e1a42'] || {}).enabled - ) { + if (!tabsEnabled) { const buttons = require('./buttons.js')(store); document .querySelector('.notion-topbar > div[style*="display: flex"]') @@ -185,9 +196,7 @@ module.exports = (store, __exports) => { '--theme--code_inline-background', ].map((rule) => [rule, getStyle(rule)]) ); - if ( - (store('mods')['e1692c29-475e-437b-b7ff-3eee872e1a42'] || {}).enabled - ) { + if (tabsEnabled) { electron.ipcRenderer.sendToHost( 'enhancer:set-tab-theme', [ @@ -213,7 +222,7 @@ module.exports = (store, __exports) => { ); electron.ipcRenderer.on('enhancer:get-menu-theme', setThemeVars); - if ((store('mods')['e1692c29-475e-437b-b7ff-3eee872e1a42'] || {}).enabled) { + if (tabsEnabled) { let tab_title = ''; __electronApi.setWindowTitle = (title) => { if (tab_title !== title) { diff --git a/mods/core/create.js b/mods/core/createWindow.js similarity index 100% rename from mods/core/create.js rename to mods/core/createWindow.js diff --git a/mods/core/mod.js b/mods/core/mod.js index 701e2a8..1d3bd3f 100644 --- a/mods/core/mod.js +++ b/mods/core/mod.js @@ -83,7 +83,8 @@ module.exports = { ], hacks: { 'main/main.js': require('./tray.js'), - 'main/createWindow.js': require('./create.js'), + 'main/systemMenu.js': require('./systemMenu.js'), + 'main/createWindow.js': require('./createWindow.js'), 'renderer/index.js': require('./render.js'), 'renderer/preload.js': require('./client.js'), }, diff --git a/mods/core/render.js b/mods/core/render.js index d21d8df..1e8c2d5 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -42,7 +42,7 @@ module.exports = (store, __exports) => { searching: false, searchingPeekView: false, zoomFactor: 1, - tabs: new Map([[0, true]]), + tabs: new Map([[0, ['notion.so', true]]]), }; this.$titlebar = null; this.$dragging = null; @@ -84,42 +84,42 @@ module.exports = (store, __exports) => { ) || [] ); }; - document.addEventListener('dragstart', (event) => { - if (!this.$titlebar) return; - this.$dragging = getTab(event.target)[0]; - event.target.style.opacity = 0.5; - }); - document.addEventListener('dragend', (event) => { - if (!this.$titlebar) return; - event.target.style.opacity = ''; - }); - document.addEventListener('dragover', (event) => { - if (!this.$titlebar) return; - event.preventDefault(); - document - .querySelectorAll('.dragged-over') - .forEach((el) => el.classList.remove('dragged-over')); - const tab = getTab(event.target); - if (tab[1]) tab[1].classList.add('dragged-over'); - }); - document.addEventListener('drop', (event) => { - if (!this.$titlebar || this.$dragging === null) return; - event.preventDefault(); - document - .querySelectorAll('.dragged-over') - .forEach((el) => el.classList.remove('dragged-over')); - document - .querySelectorAll('.slideIn') - .forEach((el) => el.classList.remove('slideIn')); - const from = getTab(this.views.tabs[+this.$dragging]), - to = getTab(event.target); - if (!from[1].classList.contains('new') && from[0] !== to[0]) - to[1].parentElement.insertBefore(from[1], to[1]); - this.$dragging = null; - document - .querySelector('#tabs') - .appendChild(document.querySelector('.tab.new')); - }); + // document.addEventListener('dragstart', (event) => { + // if (!this.$titlebar) return; + // this.$dragging = getTab(event.target)[0]; + // event.target.style.opacity = 0.5; + // }); + // document.addEventListener('dragend', (event) => { + // if (!this.$titlebar) return; + // event.target.style.opacity = ''; + // }); + // document.addEventListener('dragover', (event) => { + // if (!this.$titlebar) return; + // event.preventDefault(); + // document + // .querySelectorAll('.dragged-over') + // .forEach((el) => el.classList.remove('dragged-over')); + // const tab = getTab(event.target); + // if (tab[1]) tab[1].classList.add('dragged-over'); + // }); + // document.addEventListener('drop', (event) => { + // if (!this.$titlebar || this.$dragging === null) return; + // event.preventDefault(); + // document + // .querySelectorAll('.dragged-over') + // .forEach((el) => el.classList.remove('dragged-over')); + // document + // .querySelectorAll('.slideIn') + // .forEach((el) => el.classList.remove('slideIn')); + // const from = getTab(this.views.tabs[+this.$dragging]), + // to = getTab(event.target); + // if (!from[1].classList.contains('new') && from[0] !== to[0]) + // to[1].parentElement.insertBefore(from[1], to[1]); + // this.$dragging = null; + // document + // .querySelector('#tabs') + // .appendChild(document.querySelector('.tab.new')); + // }); document.addEventListener('keyup', (event) => { if (!electron.remote.getCurrentWindow().isFocused()) return; // switch between tabs via key modifier @@ -129,7 +129,22 @@ module.exports = (store, __exports) => { let triggered = true; for (let prop in select_tab_modifier) if (select_tab_modifier[prop] !== event[prop]) triggered = false; - if (triggered && [1, 2, 3, 4, 5, 6, 7, 8, 9].includes(+event.key)) + if ( + triggered && + [ + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'ArrowRight', + 'ArrowLeft', + ].includes(event.key) + ) this.selectTab(event.key); // create/close tab keybindings const new_tab_keybinding = toKeyEvent( @@ -192,58 +207,64 @@ module.exports = (store, __exports) => { newTab() { let id = 0; const list = new Map(this.state.tabs); - while (this.state.tabs.get(id)) id++; + while (this.state.tabs.get(id) && this.state.tabs.get(id)[1]) id++; list.delete(id); this.openTab(id, list, true); } openTab(id, state = new Map(this.state.tabs), load) { - if (!id && id !== 0) return; + if (!id && id !== 0) { + if (this.views.current.$el().style.display === 'flex') return; + id = [...state].find(([id, [title, open]]) => open)[0]; + } + const current_src = this.views.current.$el().src; this.views.current.id = id; - this.setState({ tabs: state.set(id, true) }, async () => { - this.focusTab(); - if (load) { - await new Promise((res, rej) => { - let attempt; - attempt = setInterval(() => { - if (!document.body.contains(this.views.html[id])) return; - clearInterval(attempt); - res(); - }, 50); - }); - this.views.html[id].style.opacity = '0'; - let unhide; - unhide = () => { - this.views.html[id].style.opacity = ''; - this.views.html[id].removeEventListener( - 'did-stop-loading', - unhide + this.setState( + { + tabs: state.set(id, [ + state.get(id) ? state.get(id)[0] : 'notion.so', + true, + ]), + }, + async () => { + this.focusTab(); + if (load) { + await new Promise((res, rej) => { + let attempt; + attempt = setInterval(() => { + if (!document.body.contains(this.views.html[id])) return; + clearInterval(attempt); + res(); + }, 50); + }); + this.views.html[id].style.opacity = '0'; + let unhide; + unhide = () => { + this.views.html[id].style.opacity = ''; + this.views.html[id].removeEventListener( + 'did-stop-loading', + unhide + ); + }; + this.views.html[id].addEventListener('did-stop-loading', unhide); + this.views.html[id].loadURL( + store().default_page + ? idToNotionURL(store().default_page) + : current_src ); - }; - this.views.html[id].addEventListener('did-stop-loading', unhide); - this.views.html[id].loadURL( - store().default_page - ? idToNotionURL(store().default_page) - : this.views.current.$el().src - ); - // this.views.html[id].getWebContents().openDevTools(); + // this.views.html[id].getWebContents().openDevTools(); + } } - }); + ); } closeTab(id) { if ((!id && id !== 0) || !this.state.tabs.get(id)) return; + console.log(id); const list = new Map(this.state.tabs); - list.delete(id); - list.set(id, false); - if (![...list].filter(([id, open]) => open).length) + list.set(id, [list.get(id)[0], false]); + console.log(list); + if (![...list].filter(([id, [title, open]]) => open).length) return electron.remote.getCurrentWindow().close(); - while ( - !list.get(this.views.current.id) || - this.views.current.id === id - ) { - this.views.current.id = this.views.current.id - 1; - if (this.views.current.id < 0) this.views.current.id = list.size - 1; - } - this.setState({ tabs: list }, this.focusTab.bind(this)); + this.openTab(null, list); } focusTab() { if (this.views.active === this.views.current.id) return; @@ -263,18 +284,28 @@ module.exports = (store, __exports) => { } } selectTab(num) { - num = +num; - if (num == 9) { - document - .querySelector('#tabs') - .children[ - document.querySelector('#tabs').children.length - 2 - ].click(); - } else if ( - document.querySelector('#tabs').children[num - 1] && - document.querySelector('#tabs').children.length > num - ) { - document.querySelector('#tabs').children[num - 1].click(); + if (num === 'ArrowLeft') { + const prev = document.querySelector('.tab.current') + .previousElementSibling; + if (prev) prev.click(); + } else if (num === 'ArrowRight') { + const next = document.querySelector('.tab.current') + .nextElementSibling; + if (next && !next.classList.contains('new')) next.click(); + } else { + num = +num; + if (num == 9) { + document + .querySelector('#tabs') + .children[ + document.querySelector('#tabs').children.length - 2 + ].click(); + } else if ( + document.querySelector('#tabs').children[num - 1] && + document.querySelector('#tabs').children.length > num + ) { + document.querySelector('#tabs').children[num - 1].click(); + } } } @@ -285,9 +316,15 @@ module.exports = (store, __exports) => { document.body.style.setProperty(style[0], style[1]); break; case 'enhancer:set-tab-title': - if (this.views.tabs[event.target.id]) { - this.views.tabs[event.target.id].children[0].innerText = - event.args[0]; + if (this.state.tabs.get(event.target.id)) { + const list = new Map(this.state.tabs); + list.set(event.target.id, [ + event.args[0], + this.state.tabs.get(event.target.id)[1], + ]); + this.setState({ + tabs: list, + }); const electronWindow = electron.remote.getCurrentWindow(); if ( event.target.id == this.views.current.id && @@ -550,6 +587,7 @@ module.exports = (store, __exports) => { } renderTitlebar() { + console.log('title'); return React.createElement( 'header', { @@ -568,25 +606,24 @@ module.exports = (store, __exports) => { 'div', { id: 'tabs' }, ...[...this.state.tabs] - .filter(([id, open]) => open) - .map(([id, open]) => + .filter(([id, [title, open]]) => open) + .map(([id, [title, open]]) => React.createElement( 'button', { - draggable: true, className: - 'tab slideIn' + - (id === this.views.current.id ? ' current' : ''), + 'tab' + (id === this.views.current.id ? ' current' : ''), + draggable: true, + 'data-linked': id, onClick: (e) => { if (!e.target.classList.contains('close')) this.openTab(id); }, ref: ($tab) => { this.views.tabs[id] = $tab; - this.focusTab(); }, }, - React.createElement('span', {}, 'notion.so'), + React.createElement('span', {}, title), React.createElement( 'span', { @@ -614,7 +651,7 @@ module.exports = (store, __exports) => { } renderNotionContainer() { this.views.react = Object.fromEntries( - [...this.state.tabs].map(([id, open]) => { + [...this.state.tabs].map(([id, [title, open]]) => { return [ id, this.views.react[id] || diff --git a/mods/core/systemMenu.js b/mods/core/systemMenu.js index e69de29..d301476 100644 --- a/mods/core/systemMenu.js +++ b/mods/core/systemMenu.js @@ -0,0 +1,476 @@ +/* + * notion-enhancer + * (c) 2020 dragonwocky (https://dragonwocky.me/) + * under the MIT license + */ + +'use strict'; + +module.exports = (store, __exports) => { + const electron = require('electron'), + fs = require('fs-extra'), + { __notion } = require('../../pkg/helpers.js'), + createWindow = require(`${__notion}/app/main/createWindow.js`), + config = require(`${__notion}/app/config.js`), + notion_intl = require(`${__notion}/app/shared/notion-intl/index.js`), + localizationHelper = require(`${__notion}/app/helpers/localizationHelper.js`), + isMac = process.platform === 'darwin', + // why is it inversed? i have no idea, but for some reason this is what works + tabsEnabled = !(store('mods')['e1692c29-475e-437b-b7ff-3eee872e1a42'] || {}) + .enabled, + menuMessages = notion_intl.defineMessages({ + fileMenuTitle: { + id: 'desktopTopbar.fileMenu.title', + defaultMessage: 'File', + }, + editMenuTitle: { + id: 'desktopTopbar.editMenu.title', + defaultMessage: 'Edit', + }, + viewMenuTitle: { + id: 'desktopTopbar.viewMenu.title', + defaultMessage: 'View', + }, + windowMenuTitle: { + id: 'desktopTopbar.windowMenu.title', + defaultMessage: 'Window', + }, + helpTitle: { + id: 'desktopTopbar.helpMenu.title', + defaultMessage: 'Help', + }, + newWindow: { + id: 'desktopTopbar.fileMenu.newWindow', + defaultMessage: 'New Window', + }, + closeWindow: { + id: 'desktopTopbar.fileMenu.close', + defaultMessage: 'Close Window', + }, + quit: { + id: 'desktopTopbar.fileMenu.quit', + defaultMessage: 'Exit', + }, + undo: { + id: 'desktopTopbar.editMenu.undo', + defaultMessage: 'Undo', + }, + redo: { + id: 'desktopTopbar.editMenu.redo', + defaultMessage: 'Redo', + }, + cut: { + id: 'desktopTopbar.editMenu.cut', + defaultMessage: 'Cut', + }, + copy: { + id: 'desktopTopbar.editMenu.copy', + defaultMessage: 'Copy', + }, + paste: { + id: 'desktopTopbar.editMenu.paste', + defaultMessage: 'Paste', + }, + selectAll: { + id: 'desktopTopbar.editMenu.selectAll', + defaultMessage: 'Select All', + }, + startSpeaking: { + id: 'desktopTopbar.editMenu.speech.startSpeaking', + defaultMessage: 'Start Speaking', + }, + stopSpeaking: { + id: 'desktopTopbar.editMenu.speech.stopSpeaking', + defaultMessage: 'Stop Speaking', + }, + speech: { + id: 'desktopTopbar.editMenu.speech', + defaultMessage: 'Speech', + }, + reload: { + id: 'desktopTopbar.viewMenu.reload', + defaultMessage: 'Reload', + }, + togglefullscreen: { + id: 'desktopTopbar.viewMenu.togglefullscreen', + defaultMessage: 'Toggle Full Screen', + }, + toggleDevTools: { + id: 'desktopTopbar.toggleDevTools', + defaultMessage: 'Toggle Developer Tools', + }, + toggleWindowDevTools: { + id: 'desktopTopbar.toggleWindowDevTools', + defaultMessage: 'Toggle Window Developer Tools', + }, + maximize: { + id: 'desktopTopbar.windowMenu.maximize', + defaultMessage: 'Maximize', + }, + minimize: { + id: 'desktopTopbar.windowMenu.minimize', + defaultMessage: 'Minimize', + }, + zoom: { + id: 'desktopTopbar.windowMenu.zoom', + defaultMessage: 'Zoom', + }, + front: { + id: 'desktopTopbar.windowMenu.front', + defaultMessage: 'Front', + }, + close: { + id: 'desktopTopbar.windowMenu.close', + defaultMessage: 'Close', + }, + help: { + id: 'desktopTopbar.helpMenu.openHelpAndSupport', + defaultMessage: 'Open Help & Support', + }, + reset: { + id: 'desktopTopbar.appMenu.resetAppAndClearData', + defaultMessage: 'Reset App & Clear Local Data', + }, + about: { + id: 'desktopTopbar.appMenu.about', + defaultMessage: 'About Notion', + }, + services: { + id: 'desktopTopbar.appMenu.services', + defaultMessage: 'Services', + }, + hide: { id: 'desktopTopbar.appMenu.hide', defaultMessage: 'Hide Notion' }, + hideOthers: { + id: 'desktopTopbar.appMenu.hideOthers', + defaultMessage: 'Hide Others', + }, + unhide: { + id: 'desktopTopbar.appMenu.unhide', + defaultMessage: 'Show All', + }, + quitMac: { id: 'desktopTopbar.appMenu.quit', defaultMessage: 'Quit' }, + }), + escapeAmpersand = (message) => message.replace(/&/g, '&&'); + __exports.setupSystemMenu = (locale) => { + const intl = localizationHelper.createIntlShape(locale), + fileMenu = { + role: 'fileMenu', + label: escapeAmpersand(intl.formatMessage(menuMessages.fileMenuTitle)), + submenu: isMac + ? [ + { + label: escapeAmpersand( + intl.formatMessage(menuMessages.newWindow) + ), + accelerator: 'CmdOrCtrl+Shift+N', + click: () => createWindow.createWindow(), + }, + ...(tabsEnabled + ? [ + { + role: 'close', + label: escapeAmpersand( + intl.formatMessage(menuMessages.closeWindow) + ), + }, + ] + : []), + ] + : [ + { + label: escapeAmpersand( + intl.formatMessage(menuMessages.newWindow) + ), + accelerator: 'CmdOrCtrl+Shift+N', + click: () => createWindow.createWindow(), + }, + ...(tabsEnabled + ? [ + { + role: 'quit', + label: escapeAmpersand( + intl.formatMessage(menuMessages.quit) + ), + }, + ] + : []), + ], + }, + editMenu = { + role: 'editMenu', + label: escapeAmpersand(intl.formatMessage(menuMessages.editMenuTitle)), + submenu: isMac + ? [ + { + role: 'undo', + label: escapeAmpersand(intl.formatMessage(menuMessages.undo)), + }, + { + role: 'redo', + label: escapeAmpersand(intl.formatMessage(menuMessages.redo)), + }, + { type: 'separator' }, + { + role: 'cut', + label: escapeAmpersand(intl.formatMessage(menuMessages.cut)), + }, + { + role: 'copy', + label: escapeAmpersand(intl.formatMessage(menuMessages.copy)), + }, + { + role: 'paste', + label: escapeAmpersand(intl.formatMessage(menuMessages.paste)), + }, + { + role: 'selectAll', + label: escapeAmpersand( + intl.formatMessage(menuMessages.selectAll) + ), + }, + { type: 'separator' }, + { + label: escapeAmpersand(intl.formatMessage(menuMessages.speech)), + submenu: [ + { + role: 'startSpeaking', + label: escapeAmpersand( + intl.formatMessage(menuMessages.startSpeaking) + ), + }, + { + role: 'stopSpeaking', + label: escapeAmpersand( + intl.formatMessage(menuMessages.stopSpeaking) + ), + }, + ], + }, + ] + : [ + { + role: 'undo', + label: escapeAmpersand(intl.formatMessage(menuMessages.undo)), + }, + { + role: 'redo', + label: escapeAmpersand(intl.formatMessage(menuMessages.redo)), + }, + { type: 'separator' }, + { + role: 'cut', + label: escapeAmpersand(intl.formatMessage(menuMessages.cut)), + }, + { + role: 'copy', + label: escapeAmpersand(intl.formatMessage(menuMessages.copy)), + }, + { + role: 'paste', + label: escapeAmpersand(intl.formatMessage(menuMessages.paste)), + }, + { type: 'separator' }, + { + role: 'selectAll', + label: escapeAmpersand( + intl.formatMessage(menuMessages.selectAll) + ), + }, + ], + }, + viewMenu = { + role: 'viewMenu', + label: escapeAmpersand(intl.formatMessage(menuMessages.viewMenuTitle)), + submenu: [ + { + label: escapeAmpersand(intl.formatMessage(menuMessages.reload)), + accelerator: 'CmdOrCtrl+R', + click() { + const focusedWebContents = electron.webContents.getFocusedWebContents(); + if (focusedWebContents) { + if (focusedWebContents.hostWebContents) { + for (const webContentsInstance of electron.webContents.getAllWebContents()) { + if ( + webContentsInstance.hostWebContents === + focusedWebContents.hostWebContents + ) { + webContentsInstance.reload(); + } + } + } else { + focusedWebContents.reload(); + } + } + }, + }, + { + label: escapeAmpersand( + intl.formatMessage(menuMessages.toggleDevTools) + ), + accelerator: isMac ? 'Alt+Command+I' : 'Ctrl+Shift+I', + click() { + let focusedWebContents = electron.webContents.getFocusedWebContents(); + if (focusedWebContents) { + const focusedWebContentsUrl = focusedWebContents.getURL(); + if ( + focusedWebContentsUrl.startsWith('file://') && + focusedWebContentsUrl.endsWith('/search.html') + ) { + const notionWebviewWebContents = electron.webContents + .getAllWebContents() + .find( + (webContentsInstance) => + webContentsInstance.hostWebContents === + focusedWebContents.hostWebContents && + webContentsInstance !== focusedWebContents + ); + if (notionWebviewWebContents) { + focusedWebContents = notionWebviewWebContents; + } + } + focusedWebContents.toggleDevTools(); + } + }, + }, + { + label: escapeAmpersand( + intl.formatMessage(menuMessages.toggleWindowDevTools) + ), + accelerator: isMac ? 'Shift+Alt+Command+I' : 'Alt+Ctrl+Shift+I', + visible: false, + click(menuItem, focusedWindow) { + if (focusedWindow) { + focusedWindow.webContents.toggleDevTools(); + } + }, + }, + { type: 'separator' }, + { + role: 'togglefullscreen', + label: escapeAmpersand( + intl.formatMessage(menuMessages.togglefullscreen) + ), + }, + ], + }, + windowMenu = { + role: 'windowMenu', + label: escapeAmpersand( + intl.formatMessage(menuMessages.windowMenuTitle) + ), + submenu: isMac + ? [ + { + role: 'minimize', + label: escapeAmpersand( + intl.formatMessage(menuMessages.minimize) + ), + }, + { + role: 'zoom', + label: escapeAmpersand(intl.formatMessage(menuMessages.zoom)), + }, + { type: 'separator' }, + { + role: 'front', + label: escapeAmpersand(intl.formatMessage(menuMessages.front)), + }, + ] + : [ + { + role: 'minimize', + label: escapeAmpersand( + intl.formatMessage(menuMessages.minimize) + ), + }, + { + label: escapeAmpersand( + intl.formatMessage(menuMessages.maximize) + ), + click(item, focusedWindow) { + if (focusedWindow) { + if (focusedWindow.isMaximized()) { + focusedWindow.unmaximize(); + } else { + focusedWindow.maximize(); + } + } + }, + }, + ...(tabsEnabled + ? [ + { + role: 'close', + label: escapeAmpersand( + intl.formatMessage(menuMessages.close) + ), + }, + ] + : []), + ], + }, + helpMenu = { + role: 'help', + label: escapeAmpersand(intl.formatMessage(menuMessages.helpTitle)), + submenu: [ + { + label: escapeAmpersand(intl.formatMessage(menuMessages.help)), + click() { + electron.shell.openExternal(config.default.baseURL + '/help'); + }, + }, + ], + }, + appMenu = { + role: 'appMenu', + submenu: [ + { + role: 'about', + label: escapeAmpersand(intl.formatMessage(menuMessages.about)), + }, + { type: 'separator' }, + { + label: escapeAmpersand(intl.formatMessage(menuMessages.reset)), + async click(item, focusedWindow) { + await fs.remove(electron.app.getPath('userData')); + electron.app.relaunch(); + electron.app.exit(); + }, + }, + { type: 'separator' }, + { + role: 'services', + label: escapeAmpersand(intl.formatMessage(menuMessages.services)), + }, + { type: 'separator' }, + { + role: 'hide', + label: escapeAmpersand(intl.formatMessage(menuMessages.hide)), + }, + { + role: 'hideOthers', + label: escapeAmpersand(intl.formatMessage(menuMessages.hideOthers)), + }, + { + role: 'unhide', + label: escapeAmpersand(intl.formatMessage(menuMessages.unhide)), + }, + ...(tabsEnabled + ? [ + { type: 'separator' }, + { + role: 'quit', + label: escapeAmpersand( + intl.formatMessage(menuMessages.quitMac) + ), + }, + ] + : []), + ], + }, + template = [fileMenu, editMenu, viewMenu, windowMenu, helpMenu]; + if (isMac) template.unshift(appMenu); + const menu = electron.Menu.buildFromTemplate(template); + electron.Menu.setApplicationMenu(menu); + }; +}; diff --git a/mods/core/tray.js b/mods/core/tray.js index cbd62d4..db9942e 100644 --- a/mods/core/tray.js +++ b/mods/core/tray.js @@ -87,7 +87,7 @@ module.exports = (store, __exports) => { /\\/g, '/' )}/app/node_modules/electron-window-state/index.js`)({ - file: 'enhancerMenu.windowState.json', + file: 'menu.windowstate.json', path: helpers.__data, defaultWidth: 275, defaultHeight: 600, @@ -172,7 +172,7 @@ module.exports = (store, __exports) => { type: 'normal', label: 'New Window', click: () => { - require('./create.js')( + require('./createWindow.js')( store, require(path.resolve( `${helpers.__notion}/app/main/createWindow.js` diff --git a/mods/tabs/mod.js b/mods/tabs/mod.js index a738d00..7e9d7dc 100644 --- a/mods/tabs/mod.js +++ b/mods/tabs/mod.js @@ -19,9 +19,19 @@ module.exports = { options: [ { key: 'select_modifier', - label: 'tab select modifier (key+1, +2, +3, ... +9):', + label: + 'tab select modifier (key+1, +2, +3, ... +9 and key+left/right arrows):', type: 'select', - value: ['Alt', 'Command', 'Control', 'Shift', 'Super'], + value: [ + 'Alt', + 'Command', + 'Control', + 'Super', + 'Alt+Shift', + 'Command+Shift', + 'Control+Shift', + 'Super+Shift', + ], }, { key: 'new_tab', From 796fac94661ca989baf6031a681d65809ae669ee Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Thu, 15 Oct 2020 22:34:51 +1100 Subject: [PATCH 5/7] fix tab opening/closing/titles --- mods/core/render.js | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/mods/core/render.js b/mods/core/render.js index 1e8c2d5..86bb569 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -213,7 +213,7 @@ module.exports = (store, __exports) => { } openTab(id, state = new Map(this.state.tabs), load) { if (!id && id !== 0) { - if (this.views.current.$el().style.display === 'flex') return; + if (state.get(this.views.current.id)[1]) return; id = [...state].find(([id, [title, open]]) => open)[0]; } const current_src = this.views.current.$el().src; @@ -258,13 +258,16 @@ module.exports = (store, __exports) => { } closeTab(id) { if ((!id && id !== 0) || !this.state.tabs.get(id)) return; - console.log(id); const list = new Map(this.state.tabs); list.set(id, [list.get(id)[0], false]); - console.log(list); if (![...list].filter(([id, [title, open]]) => open).length) return electron.remote.getCurrentWindow().close(); - this.openTab(null, list); + this.openTab( + this.views.current.id === id + ? null + : [...list].find(([id, [title, open]]) => open)[0], + list + ); } focusTab() { if (this.views.active === this.views.current.id) return; @@ -316,15 +319,16 @@ module.exports = (store, __exports) => { document.body.style.setProperty(style[0], style[1]); break; case 'enhancer:set-tab-title': - if (this.state.tabs.get(event.target.id)) { - const list = new Map(this.state.tabs); - list.set(event.target.id, [ - event.args[0], - this.state.tabs.get(event.target.id)[1], - ]); + if (this.state.tabs.get(+event.target.id)) { this.setState({ - tabs: list, + tabs: new Map( + this.state.tabs.set(+event.target.id, [ + event.args[0], + this.state.tabs.get(+event.target.id)[1], + ]) + ), }); + // this.forceUpdate(); const electronWindow = electron.remote.getCurrentWindow(); if ( event.target.id == this.views.current.id && @@ -587,7 +591,6 @@ module.exports = (store, __exports) => { } renderTitlebar() { - console.log('title'); return React.createElement( 'header', { From b10ec8f136fa6d857a2add8b5f2307a313a18125 Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Thu, 15 Oct 2020 23:48:54 +1100 Subject: [PATCH 6/7] fix tab reordering and animations --- mods/core/createWindow.js | 2 +- mods/core/render.js | 107 ++++++++++++++++++++++---------------- 2 files changed, 63 insertions(+), 46 deletions(-) diff --git a/mods/core/createWindow.js b/mods/core/createWindow.js index fb37b5a..21e729c 100644 --- a/mods/core/createWindow.js +++ b/mods/core/createWindow.js @@ -79,7 +79,7 @@ module.exports = (store, __exports) => { }); electron.app.on('before-quit', () => (intended_quit = true)); window.loadURL(__exports.getIndexUrl(relativeUrl)); - window.webContents.openDevTools(); + // window.webContents.openDevTools(); return window; }; return __exports.createWindow; diff --git a/mods/core/render.js b/mods/core/render.js index 86bb569..f5765fe 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -43,6 +43,7 @@ module.exports = (store, __exports) => { searchingPeekView: false, zoomFactor: 1, tabs: new Map([[0, ['notion.so', true]]]), + slideIn: new Set(), }; this.$titlebar = null; this.$dragging = null; @@ -74,52 +75,62 @@ module.exports = (store, __exports) => { // draggable re-ordering const getTab = ($el) => { + if ($el.tagName !== 'BUTTON') $el = $el.parentElement; if ($el.innerText === '+') return [null, document.querySelector('.tab.new')]; - if ($el.innerText === '×') $el = $el.parentElement; - if (!$el.innerText.endsWith('×')) $el = $el.parentElement; - return ( - Object.entries(this.views.tabs).find( - ([id, $node]) => $node === $el - ) || [] + const tab = Object.entries(this.views.tabs).find( + ([id, $node]) => $node === $el ); + return tab ? [+tab[0], tab[1]] : []; }; - // document.addEventListener('dragstart', (event) => { - // if (!this.$titlebar) return; - // this.$dragging = getTab(event.target)[0]; - // event.target.style.opacity = 0.5; - // }); - // document.addEventListener('dragend', (event) => { - // if (!this.$titlebar) return; - // event.target.style.opacity = ''; - // }); - // document.addEventListener('dragover', (event) => { - // if (!this.$titlebar) return; - // event.preventDefault(); - // document - // .querySelectorAll('.dragged-over') - // .forEach((el) => el.classList.remove('dragged-over')); - // const tab = getTab(event.target); - // if (tab[1]) tab[1].classList.add('dragged-over'); - // }); - // document.addEventListener('drop', (event) => { - // if (!this.$titlebar || this.$dragging === null) return; - // event.preventDefault(); - // document - // .querySelectorAll('.dragged-over') - // .forEach((el) => el.classList.remove('dragged-over')); - // document - // .querySelectorAll('.slideIn') - // .forEach((el) => el.classList.remove('slideIn')); - // const from = getTab(this.views.tabs[+this.$dragging]), - // to = getTab(event.target); - // if (!from[1].classList.contains('new') && from[0] !== to[0]) - // to[1].parentElement.insertBefore(from[1], to[1]); - // this.$dragging = null; - // document - // .querySelector('#tabs') - // .appendChild(document.querySelector('.tab.new')); - // }); + document.addEventListener('dragstart', (event) => { + if (!this.$titlebar) return; + this.$dragging = getTab(event.target)[0]; + event.target.style.opacity = 0.5; + }); + document.addEventListener('dragend', (event) => { + if (!this.$titlebar) return; + event.target.style.opacity = ''; + }); + document.addEventListener('dragover', (event) => { + if (!this.$titlebar) return; + event.preventDefault(); + document + .querySelectorAll('.dragged-over') + .forEach((el) => el.classList.remove('dragged-over')); + const tab = getTab(event.target); + if (tab[1]) tab[1].classList.add('dragged-over'); + }); + document.addEventListener('drop', (event) => { + if (!this.$titlebar || this.$dragging === null) return; + event.preventDefault(); + document + .querySelectorAll('.dragged-over') + .forEach((el) => el.classList.remove('dragged-over')); + const from = getTab(this.views.tabs[+this.$dragging]), + to = getTab(event.target); + if (from[0] !== to[0]) { + if (to[1].classList.contains('new')) { + const list = new Map(this.state.tabs); + list.delete(from[0]); + list.set(from[0], this.state.tabs.get(from[0])); + this.setState({ tabs: list }); + } else { + const list = [...this.state.tabs], + fromIndex = list.findIndex( + ([id, [title, open]]) => id === from[0] + ), + toIndex = list.findIndex(([id, [title, open]]) => id === to[0]); + list.splice( + toIndex > fromIndex ? toIndex - 1 : toIndex, + 0, + list.splice(fromIndex, 1)[0] + ); + this.setState({ tabs: new Map(list) }); + } + } + this.$dragging = null; + }); document.addEventListener('keyup', (event) => { if (!electron.remote.getCurrentWindow().isFocused()) return; // switch between tabs via key modifier @@ -224,6 +235,7 @@ module.exports = (store, __exports) => { state.get(id) ? state.get(id)[0] : 'notion.so', true, ]), + slideIn: load ? this.state.slideIn.add(id) : this.state.slideIn, }, async () => { this.focusTab(); @@ -251,6 +263,11 @@ module.exports = (store, __exports) => { ? idToNotionURL(store().default_page) : current_src ); + setTimeout(() => { + const slideIn = new Set(this.state.slideIn); + slideIn.delete(id); + this.setState({ slideIn }); + }, 100); // this.views.html[id].getWebContents().openDevTools(); } } @@ -328,7 +345,6 @@ module.exports = (store, __exports) => { ]) ), }); - // this.forceUpdate(); const electronWindow = electron.remote.getCurrentWindow(); if ( event.target.id == this.views.current.id && @@ -615,9 +631,10 @@ module.exports = (store, __exports) => { 'button', { className: - 'tab' + (id === this.views.current.id ? ' current' : ''), + 'tab' + + (id === this.views.current.id ? ' current' : '') + + (this.state.slideIn.has(id) ? ' slideIn' : ''), draggable: true, - 'data-linked': id, onClick: (e) => { if (!e.target.classList.contains('close')) this.openTab(id); From ed5ededcbe45776e0a763cdb46aba75c10371dca Mon Sep 17 00:00:00 2001 From: dragonwocky Date: Thu, 15 Oct 2020 23:59:18 +1100 Subject: [PATCH 7/7] better tab picking on close: find closest/next instead of jumping to first --- mods/core/render.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mods/core/render.js b/mods/core/render.js index f5765fe..7f15aff 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -225,7 +225,12 @@ module.exports = (store, __exports) => { openTab(id, state = new Map(this.state.tabs), load) { if (!id && id !== 0) { if (state.get(this.views.current.id)[1]) return; - id = [...state].find(([id, [title, open]]) => open)[0]; + const currentIndex = [...state].findIndex( + ([id, [title, open]]) => id === this.views.current.id + ); + id = ([...state].find( + ([id, [title, open]], tabIndex) => open && tabIndex > currentIndex + ) || [...state].find(([id, [title, open]]) => open))[0]; } const current_src = this.views.current.$el().src; this.views.current.id = id; @@ -280,9 +285,7 @@ module.exports = (store, __exports) => { if (![...list].filter(([id, [title, open]]) => open).length) return electron.remote.getCurrentWindow().close(); this.openTab( - this.views.current.id === id - ? null - : [...list].find(([id, [title, open]]) => open)[0], + this.views.current.id === id ? null : this.views.current.id, list ); }