From 85636647bd1911273827854130b40a40fdda1ed1 Mon Sep 17 00:00:00 2001 From: dragonwocky <thedragonring.bod@gmail.com> Date: Tue, 6 Oct 2020 10:15:30 +1100 Subject: [PATCH 01/15] 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 <thedragonring.bod@gmail.com> Date: Tue, 6 Oct 2020 11:47:33 +1100 Subject: [PATCH 02/15] 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 <thedragonring.bod@gmail.com> Date: Tue, 6 Oct 2020 22:12:25 +1100 Subject: [PATCH 03/15] 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 <thedragonring.bod@gmail.com> Date: Wed, 7 Oct 2020 23:58:22 +1100 Subject: [PATCH 04/15] 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) => { ]()}</button>`; } 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 <thedragonring.bod@gmail.com> (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 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" file="currentColor" viewBox="0 0 250 250"><path d="M124.859 234.52L67.5474 135.736H102.683V12.184H147.323V135.736H182.459L124.859 234.52Z" file="currentColor"/></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" fill="currentColor" viewBox="0 0 250 250"><path d="M124.859 234.52L67.5474 135.736H102.683V12.184H147.323V135.736H182.459L124.859 234.52Z" fill="currentColor"/></svg> \ 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 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" file="currentColor" viewBox="0 0 250 250"><path d="M102.683 234.52V110.968H67.5474L124.859 12.184L182.459 110.968H147.323V234.52H102.683Z" file="currentColor"/></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" fill="currentColor" viewBox="0 0 250 250"><path d="M102.683 234.52V110.968H67.5474L124.859 12.184L182.459 110.968H147.323V234.52H102.683Z" fill="currentColor"/></svg> \ 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 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" file="currentColor" viewBox="0 0 250 250"><path d="M14.7346 227.26V7.03998H235.215V227.26H14.7346ZM46.4546 195.8H203.495V70.48H46.4546V195.8Z" file="currentColor"/></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" fill="currentColor" viewBox="0 0 250 250"><path d="M14.7346 227.26V7.03998H235.215V227.26H14.7346ZM46.4546 195.8H203.495V70.48H46.4546V195.8Z" fill="currentColor"/></svg> \ 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 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" file="currentColor" viewBox="0 0 250 250"><path d="M16.1311 225.96V76.72H84.5111V8.07999H233.751V157.32H165.371V225.96H16.1311ZM110.771 53.58V76.72H165.371V131.32H207.491V53.58H110.771ZM42.3911 199.96H139.111V122.22H42.3911V199.96Z" file="currentColor"/></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" fill="currentColor" viewBox="0 0 250 250"><path d="M16.1311 225.96V76.72H84.5111V8.07999H233.751V157.32H165.371V225.96H16.1311ZM110.771 53.58V76.72H165.371V131.32H207.491V53.58H110.771ZM42.3911 199.96H139.111V122.22H42.3911V199.96Z" fill="currentColor"/></svg> \ 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 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" file="currentColor" viewBox="0 0 250 250"><path d="M17.8021 138.04V106.072H232.074V138.04H17.8021Z" file="currentColor"/></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" fill="currentColor" viewBox="0 0 250 250"><path d="M17.8021 138.04V106.072H232.074V138.04H17.8021Z" fill="currentColor"/></svg> \ 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 @@ <link rel="stylesheet" href="./css/menu.css" /> </head> <body> - <header id="menu-titlebar"></header> + <header id="titlebar"></header> <main> <div id="alerts"></div> <div id="search"> diff --git a/mods/core/menu.js b/mods/core/menu.js index d5e72b4..547a617 100644 --- a/mods/core/menu.js +++ b/mods/core/menu.js @@ -21,7 +21,7 @@ window['__start'] = async () => { tiling_mode: store('0f0bf8b6-eae6-4273-b307-8fc43f2ee082').tiling_mode, frameless: true, })); - document.querySelector('#menu-titlebar').appendChild(buttons.element); + document.querySelector('#titlebar').appendChild(buttons.element); document.defaultView.addEventListener('keyup', (event) => { if (event.code === 'F5') location.reload(); @@ -54,8 +54,8 @@ window['__start'] = async () => { document.querySelector('#search > input').focus(); }); - electron.ipcRenderer.send('enhancer:get-theme-vars'); - electron.ipcRenderer.on('enhancer:set-theme-vars', (event, theme) => { + electron.ipcRenderer.send('enhancer:get-menu-theme'); + electron.ipcRenderer.on('enhancer:set-menu-theme', (event, theme) => { for (const style of theme) document.body.style.setProperty(style[0], style[1]); }); diff --git a/mods/core/mod.js b/mods/core/mod.js index 70bbd29..9859812 100644 --- a/mods/core/mod.js +++ b/mods/core/mod.js @@ -14,6 +14,12 @@ module.exports = { version: require('../../package.json').version, author: 'dragonwocky', options: [ + { + key: 'tabs', + label: 'tabbable windows', + type: 'toggle', + value: false, + }, { key: 'openhidden', label: 'hide app on open', diff --git a/mods/core/render.js b/mods/core/render.js index 1e3f4a1..5a85227 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -6,8 +6,11 @@ 'use strict'; +const { dirname } = require('path'); + const url = require('url'), path = require('path'), + electron = require('electron'), { __notion } = require('../../pkg/helpers.js'), config = require(`${__notion}/app/config.js`), constants = require(`${__notion}/app/shared/constants.js`), @@ -27,7 +30,7 @@ const insertCSP = ` `; module.exports = (store, __exports) => { - if (!store().tabs) { + if (store().tabs) { class Index extends React.PureComponent { constructor() { super(...arguments); @@ -36,32 +39,23 @@ module.exports = (store, __exports) => { searching: false, searchingPeekView: false, zoomFactor: 1, - tabs: [], + tabIDs: [], }; - this.$currentTab; - this.tabCache = { + this.$titlebar = null; + this.tabs = { + $current: null, react: {}, active: [], loading: [], }; - this.notionElm = []; - this.loadedElms = []; - this.reactTabs = {}; - this.handleNotionRef = ($notion) => { - this.tabCache.loading.push($notion); - }; this.$search = null; - this.handleSearchRef = (searchElm) => { - this.$search = searchElm; - }; this.handleReload = () => { this.setState({ error: false }); - setTimeout(() => { - this.tabCache.loading.forEach(($notion) => { - if ($notion.isWaitingForResponse()) $notion.reload(); - }); - }, 50); + this.tabs.loading.forEach(($notion) => { + if ($notion.isWaitingForResponse()) $notion.reload(); + }); }; + this.setTheme = this.setTheme.bind(this); this.startSearch = this.startSearch.bind(this); this.stopSearch = this.stopSearch.bind(this); this.nextSearch = this.nextSearch.bind(this); @@ -70,29 +64,40 @@ module.exports = (store, __exports) => { this.doneSearch = this.doneSearch.bind(this); window['tab'] = (id) => { if (!id && id !== 0) return; - this.setState({ tabs: [...new Set([...this.state.tabs, id])] }); + this.setState({ tabIDs: [...new Set([...this.state.tabIDs, id])] }); setTimeout(() => { this.loadListeners(); this.blurListeners(); if (document.querySelector(`#tab-${id}`)) { - this.tabCache.active.forEach(($notion) => { + this.tabs.active.forEach(($notion) => { $notion.style.display = 'none'; }); - this.$currentTab = document.querySelector(`#tab-${id}`); - this.$currentTab.style.display = 'flex'; + this.tabs.$current = document.querySelector(`#tab-${id}`); + this.tabs.$current.style.display = 'flex'; this.focusListeners(); } }, 1000); }; } componentDidMount() { + const buttons = require('./buttons.js')(() => ({ + '72886371-dada-49a7-9afc-9f275ecf29d3': { + enabled: ( + store('mods')['72886371-dada-49a7-9afc-9f275ecf29d3'] || {} + ).enabled, + }, + tiling_mode: store('0f0bf8b6-eae6-4273-b307-8fc43f2ee082') + .tiling_mode, + frameless: true, + })); + this.$titlebar.appendChild(buttons.element); this.loadListeners(); + } - try { - electron.remote.getCurrentWindow().on('focus', (e) => { - this.$currentTab.focus(); - }); - } catch {} + setTheme(event) { + if (event.channel !== 'enhancer:set-tab-theme') return; + for (const style of event.args[0]) + document.body.style.setProperty(style[0], style[1]); } startSearch(isPeekView) { this.setState({ @@ -111,18 +116,18 @@ module.exports = (store, __exports) => { searching: false, }); this.lastSearchQuery = undefined; - this.$currentTab.getWebContents().stopFindInPage('clearSelection'); - notionIpc.sendIndexToNotion(this.$currentTab, 'search:stopped'); + this.tabs.$current.getWebContents().stopFindInPage('clearSelection'); + notionIpc.sendIndexToNotion(this.tabs.$current, 'search:stopped'); } nextSearch(query) { - this.$currentTab.getWebContents().findInPage(query, { + this.tabs.$current.getWebContents().findInPage(query, { forward: true, findNext: query === this.lastSearchQuery, }); this.lastSearchQuery = query; } prevSearch(query) { - this.$currentTab.getWebContents().findInPage(query, { + this.tabs.$current.getWebContents().findInPage(query, { forward: false, findNext: query === this.lastSearchQuery, }); @@ -130,79 +135,81 @@ module.exports = (store, __exports) => { } clearSearch() { this.lastSearchQuery = undefined; - this.$currentTab.getWebContents().stopFindInPage('clearSelection'); + this.tabs.$current.getWebContents().stopFindInPage('clearSelection'); } doneSearch() { this.lastSearchQuery = undefined; - this.$currentTab.getWebContents().stopFindInPage('clearSelection'); + this.tabs.$current.getWebContents().stopFindInPage('clearSelection'); this.setState({ searching: false }); if (document.activeElement instanceof HTMLElement) { document.activeElement.blur(); } - this.$currentTab.focus(); - notionIpc.sendIndexToNotion(this.$currentTab, 'search:stopped'); + this.tabs.$current.focus(); + notionIpc.sendIndexToNotion(this.tabs.$current, 'search:stopped'); } - blurListeners() { - if (!this.$currentTab) return; - if (this.state.searching) this.stopSearch(); - notionIpc.receiveIndexFromNotion.removeListener( - this.$currentTab, + focusListeners() { + this.tabs.$current.addEventListener('ipc-message', this.setTheme); + notionIpc.receiveIndexFromNotion.addListener( + this.tabs.$current, 'search:start', this.startSearch ); - notionIpc.receiveIndexFromNotion.removeListener( - this.$currentTab, + notionIpc.receiveIndexFromNotion.addListener( + this.tabs.$current, 'search:stop', this.stopSearch ); - notionIpc.receiveIndexFromSearch.removeListener( + notionIpc.receiveIndexFromSearch.addListener( this.$search, 'search:next', this.nextSearch ); - notionIpc.receiveIndexFromSearch.removeListener( + notionIpc.receiveIndexFromSearch.addListener( this.$search, 'search:prev', this.prevSearch ); - notionIpc.receiveIndexFromSearch.removeListener( + notionIpc.receiveIndexFromSearch.addListener( this.$search, 'search:clear', this.clearSearch ); - notionIpc.receiveIndexFromSearch.removeListener( + notionIpc.receiveIndexFromSearch.addListener( this.$search, 'search:stop', this.doneSearch ); } - focusListeners() { - notionIpc.receiveIndexFromNotion.addListener( - this.$currentTab, + blurListeners() { + if (!this.tabs.$current) return; + if (this.state.searching) this.stopSearch(); + this.tabs.$current.removeEventListener('ipc-message', this.setTheme); + notionIpc.receiveIndexFromNotion.removeListener( + this.tabs.$current, 'search:start', this.startSearch ); - notionIpc.receiveIndexFromNotion.addListener( - this.$currentTab, + notionIpc.receiveIndexFromNotion.removeListener( + this.tabs.$current, 'search:stop', this.stopSearch ); - notionIpc.receiveIndexFromSearch.addListener( + notionIpc.receiveIndexFromSearch.removeListener( this.$search, 'search:next', this.nextSearch ); - notionIpc.receiveIndexFromSearch.addListener( + notionIpc.receiveIndexFromSearch.removeListener( this.$search, 'search:prev', this.prevSearch ); - notionIpc.receiveIndexFromSearch.addListener( + notionIpc.receiveIndexFromSearch.removeListener( this.$search, 'search:clear', this.clearSearch ); - notionIpc.receiveIndexFromSearch.addListener( + notionIpc.receiveIndexFromSearch.removeListener( this.$search, 'search:stop', this.doneSearch @@ -210,10 +217,10 @@ module.exports = (store, __exports) => { } loadListeners() { if (!this.$search) return; - this.tabCache.loading - .filter(($notion) => !this.tabCache.active.includes($notion)) + this.tabs.loading + .filter(($notion) => !this.tabs.active.includes($notion)) .forEach(($notion) => { - this.tabCache.active.push($notion); + this.tabs.active.push($notion); $notion.addEventListener('did-fail-load', (error) => { // logger.info('Failed to load:', error); if ( @@ -326,16 +333,90 @@ module.exports = (store, __exports) => { sendFullScreenChangeEvent ); }); - this.tabCache.loading = []; + this.tabs.loading = []; + } + + renderTitlebar() { + return React.createElement( + 'header', + { + id: 'titlebar', + ref: ($titlebar) => { + this.$titlebar = $titlebar; + }, + }, + React.createElement('div', { id: 'tabs' }) + ); + } + renderNotionContainer() { + this.tabs.react = Object.fromEntries( + this.state.tabIDs.map((id) => { + return [ + id, + this.tabs.react[id] || + React.createElement('webview', { + className: 'notion', + id: `tab-${id}`, + style: { + width: '100%', + height: '100%', + display: 'none', + }, + ref: ($notion) => { + this.tabs.loading.push($notion); + }, + partition: constants.electronSessionPartition, + preload: path.resolve(`${__notion}/app/renderer/preload.js`), + src: this.props.notionUrl, + }), + ]; + }) + ); + return React.createElement( + 'div', + { + style: { + flexGrow: 1, + display: this.state.error ? 'none' : 'flex', + }, + }, + ...Object.values(this.tabs.react) + ); } renderSearchContainer() { return React.createElement( 'div', - { style: this.getSearchContainerStyle() }, + { + 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, + }, + }, React.createElement('webview', { id: 'search', - style: this.getSearchWebviewStyle(), - ref: this.handleSearchRef, + style: { + width: '100%', + height: '100%', + transition: `transform 70ms ease-${ + this.state.searching ? 'out' : 'in' + }`, + transform: `translateY(${this.state.searching ? '0' : '-100'}%)`, + pointerEvents: this.state.searching ? 'auto' : 'none', + }, + ref: ($search) => { + this.$search = $search; + }, partition: constants.electronSessionPartition, preload: `file://${path.resolve( `${__notion}/app/renderer/search.js` @@ -346,41 +427,45 @@ module.exports = (store, __exports) => { }) ); } - renderNotionContainer() { - this.reactTabs = Object.fromEntries( - this.state.tabs.map((id) => { - return [ - id, - this.reactTabs[id] || - React.createElement('webview', { - className: 'notion', - id: `tab-${id}`, - 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() }, - ...Object.values(this.reactTabs) - ); - } renderErrorContainer() { return React.createElement( 'div', - { style: this.getErrorContainerStyle() }, + { + 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', + }, + }, React.createElement('img', { - style: Index.frontImageStyle, + style: { + width: 300, + maxWidth: '100%', + }, src: './onboarding-offline.png', }), React.createElement( 'div', - { style: Index.frontMessageStyle }, + { + style: { + paddingTop: 16, + paddingBottom: 16, + textAlign: 'center', + lineHeight: 1.4, + fontSize: 17, + letterSpacing: '-0.01em', + color: '#424241', + fontWeight: 500, + }, + }, React.createElement( 'div', null, @@ -407,7 +492,24 @@ module.exports = (store, __exports) => { null, React.createElement( 'button', - { style: Index.reloadButtonStyle, onClick: this.handleReload }, + { + style: { + 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, + }, + onClick: this.handleReload, + }, React.createElement(notion_intl.FormattedMessage, { id: 'desktopLogin.offline.retryConnectingToInternetButton.label', @@ -417,9 +519,6 @@ module.exports = (store, __exports) => { ) ); } - renderDragRegion() { - return React.createElement('div', { style: Index.dragRegionStyle }); - } render() { const notionLocale = localizationHelper.getNotionLocaleFromElectronLocale( window.navigator.language @@ -430,7 +529,7 @@ module.exports = (store, __exports) => { locale: notionLocale, messages: notionLocale === 'ko-KR' ? koMessages : {}, }, - this.renderDragRegion(), + this.renderTitlebar(), this.renderNotionContainer(), this.renderSearchContainer(), this.renderErrorContainer() @@ -438,113 +537,11 @@ module.exports = (store, __exports) => { this.loadListeners(); 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%', - display: 'none', - }; - Index.dragRegionStyle = { - position: 'absolute', - zIndex: 9999, - top: 0, - left: 0, - right: 0, - height: 2, - pointerEvents: 'none', - WebkitAppRegion: 'drag', - }; window['__start'] = () => { + document.head.innerHTML += `<link rel="stylesheet" href="${__dirname}/css/tabs.css" />`; + const parsed = url.parse(window.location.href, true), notionUrl = parsed.query.path || @@ -556,6 +553,7 @@ module.exports = (store, __exports) => { delete parsed.query; const plainUrl = url.format(parsed); window.history.replaceState(undefined, undefined, plainUrl); + document.title = localizationHelper .createIntlShape( localizationHelper.getNotionLocaleFromElectronLocale( @@ -570,11 +568,12 @@ module.exports = (store, __exports) => { }, }).documentTitle ); - const rootElm = document.getElementById('root'); + const $root = document.getElementById('root'); ReactDOM.render( React.createElement(Index, { notionUrl: notionUrl }), - rootElm + $root ); + tab(0); }; } else { diff --git a/mods/core/tray.js b/mods/core/tray.js index 871cbdb..173581c 100644 --- a/mods/core/tray.js +++ b/mods/core/tray.js @@ -28,15 +28,15 @@ module.exports = (store, __exports) => { }) ); - electron.ipcMain.on('enhancer:set-theme-vars', (event, arg) => { + electron.ipcMain.on('enhancer:set-menu-theme', (event, arg) => { if (!enhancer_menu) return; - enhancer_menu.webContents.send('enhancer:set-theme-vars', arg); + enhancer_menu.webContents.send('enhancer:set-menu-theme', arg); }); - electron.ipcMain.on('enhancer:get-theme-vars', (event, arg) => { + electron.ipcMain.on('enhancer:get-menu-theme', (event, arg) => { electron.webContents .getAllWebContents() .forEach((webContents) => - webContents.send('enhancer:get-theme-vars', arg) + webContents.send('enhancer:get-menu-theme', arg) ); }); diff --git a/pkg/loader.js b/pkg/loader.js index 9607c39..00c7d27 100644 --- a/pkg/loader.js +++ b/pkg/loader.js @@ -93,7 +93,7 @@ module.exports = function (__file, __exports) { (...args) => !args.length ? store(mod.id, mod.defaults) - : args.length === 1 + : args.length === 1 && typeof args[0] === 'object' ? store(mod.id, { ...mod.defaults, ...args[0] }) : store(args[0], { ...mod.defaults, ...args[1] }), __exports From 39ecd12943c0e834a968702d246b627d0a490f1a Mon Sep 17 00:00:00 2001 From: dragonwocky <thedragonring.bod@gmail.com> Date: Thu, 8 Oct 2020 09:58:35 +1100 Subject: [PATCH 05/15] menu will now respect integrated titlebar setting --- CHANGELOG.md | 1 + mods/core/menu.js | 2 +- mods/core/render.js | 13 +------------ mods/core/tray.js | 2 +- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c20b2d2..1f94910 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ a flexibility update. - 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. +- improved: menu will now respect integrated titlebar setting. - 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/menu.js b/mods/core/menu.js index 547a617..d59481f 100644 --- a/mods/core/menu.js +++ b/mods/core/menu.js @@ -19,7 +19,7 @@ window['__start'] = async () => { .enabled, }, tiling_mode: store('0f0bf8b6-eae6-4273-b307-8fc43f2ee082').tiling_mode, - frameless: true, + frameless: store('0f0bf8b6-eae6-4273-b307-8fc43f2ee082').frameless, })); document.querySelector('#titlebar').appendChild(buttons.element); diff --git a/mods/core/render.js b/mods/core/render.js index 5a85227..d958942 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -6,8 +6,6 @@ 'use strict'; -const { dirname } = require('path'); - const url = require('url'), path = require('path'), electron = require('electron'), @@ -80,16 +78,7 @@ module.exports = (store, __exports) => { }; } componentDidMount() { - const buttons = require('./buttons.js')(() => ({ - '72886371-dada-49a7-9afc-9f275ecf29d3': { - enabled: ( - store('mods')['72886371-dada-49a7-9afc-9f275ecf29d3'] || {} - ).enabled, - }, - tiling_mode: store('0f0bf8b6-eae6-4273-b307-8fc43f2ee082') - .tiling_mode, - frameless: true, - })); + const buttons = require('./buttons.js')(store); this.$titlebar.appendChild(buttons.element); this.loadListeners(); } diff --git a/mods/core/tray.js b/mods/core/tray.js index 173581c..25be7e9 100644 --- a/mods/core/tray.js +++ b/mods/core/tray.js @@ -88,7 +88,7 @@ module.exports = (store, __exports) => { electron.shell.openExternal(JSON.stringify(window_state)); enhancer_menu = new electron.BrowserWindow({ show: true, - frame: false, + frame: !store().frameless, titleBarStyle: 'hiddenInset', x: window_state.x || From ec0d5517bceff05b5ec6a9c15f6f9a8878d7f588 Mon Sep 17 00:00:00 2001 From: dragonwocky <thedragonring.bod@gmail.com> Date: Thu, 8 Oct 2020 11:05:25 +1100 Subject: [PATCH 06/15] #143 remove focus mode footer from neutral theme --- CHANGELOG.md | 1 + mods/focus-mode/mod.js | 2 +- mods/focus-mode/styles.css | 5 +++++ mods/neutral/mod.js | 2 +- mods/neutral/styles.css | 11 ----------- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f94910..0b19209 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ a flexibility update. - bugfix: toc blocks can have text colours. - bugfix: bypass preview extension works with the back/forward keyboard shortcuts. - bugfix: (maybe) fix csp issues under proxy. +- bugfix: remove focus mode footer from neutral theme. - tweak: sticky table/list rows. - extension: "material ocean" = an oceanic colour palette. diff --git a/mods/focus-mode/mod.js b/mods/focus-mode/mod.js index 3f61241..10994ac 100644 --- a/mods/focus-mode/mod.js +++ b/mods/focus-mode/mod.js @@ -13,6 +13,6 @@ module.exports = { name: 'focus mode', desc: 'hide the titlebar/menubar if the sidebar is closed (will be shown on hover).', - version: '0.1.0', + version: '0.1.1', author: 'arecsu', }; diff --git a/mods/focus-mode/styles.css b/mods/focus-mode/styles.css index 77f14b5..c71829f 100644 --- a/mods/focus-mode/styles.css +++ b/mods/focus-mode/styles.css @@ -5,6 +5,11 @@ * under the MIT license */ +/* add space at the bottom of the main frame when sidebar is hidden + * -- matches space at top for titlebar */ +.notion-dark-theme .notion-frame { + transition: height 100ms ease 0s; +} .notion-sidebar-container[style*='width: 0px;'] + .notion-frame { height: calc( 100% - (var(--configured--dragarea_height, 10px) + 45px) diff --git a/mods/neutral/mod.js b/mods/neutral/mod.js index 8f1533a..a695dc9 100644 --- a/mods/neutral/mod.js +++ b/mods/neutral/mod.js @@ -12,7 +12,7 @@ module.exports = { tags: ['theme', 'dark'], name: 'neutral', desc: 'smoother colours and fonts, designed to be more pleasing to the eye.', - version: '0.1.3', + version: '0.1.4', author: 'arecsu', fonts: [ 'https://rsms.me/inter/inter.css', diff --git a/mods/neutral/styles.css b/mods/neutral/styles.css index 8b28df9..5f6c242 100644 --- a/mods/neutral/styles.css +++ b/mods/neutral/styles.css @@ -143,17 +143,6 @@ padding-top: 5px !important; } */ -/* add space at the bottom of the main frame when sidebar is hidden - * -- matches space at top for titlebar */ -.notion-dark-theme .notion-frame { - transition: height 300ms ease 0s; -} -.notion-dark-theme - .notion-sidebar-container[style*='width: 0px;'] - + .notion-frame { - height: calc(100vh - 40px) !important; -} - /* hide sidebar "new page" button */ .notion-dark-theme .notion-sidebar From 5ae9aed26082ee53edf8e1084db96063d13e5daf Mon Sep 17 00:00:00 2001 From: dragonwocky <thedragonring.bod@gmail.com> Date: Thu, 8 Oct 2020 22:50:27 +1100 Subject: [PATCH 07/15] functional tabs: needs more ux work --- mods/core/client.js | 71 ++++---- mods/core/css/menu.css | 10 +- mods/core/css/scrollbars.css | 1 + mods/core/css/tabs.css | 94 +++++++++-- mods/core/render.js | 306 +++++++++++++++++++++++++---------- 5 files changed, 351 insertions(+), 131 deletions(-) diff --git a/mods/core/client.js b/mods/core/client.js index aa1f1bf..7c557c4 100644 --- a/mods/core/client.js +++ b/mods/core/client.js @@ -39,10 +39,9 @@ module.exports = (store, __exports) => { if (store().frameless && !store().tiling_mode && !store().tabs) { document.body.classList.add('frameless'); // draggable area - const dragarea = helpers.createElement( - '<div class="window-dragarea"></div>' - ); - document.querySelector('.notion-topbar').prepend(dragarea); + document + .querySelector('.notion-topbar') + .prepend(helpers.createElement('<div class="window-dragarea"></div>')); document.documentElement.style.setProperty( '--configured--dragarea_height', `${store().dragarea_height + 2}px` @@ -70,7 +69,7 @@ module.exports = (store, __exports) => { document.querySelector('.notion-app-inner') ).getPropertyValue(prop); - // ctrl+f theming + // external theming document.defaultView.addEventListener('keydown', (event) => { if ((event.ctrlKey || event.metaKey) && event.key === 'f') { notionIpc.sendNotionToIndex('search:set-theme', { @@ -99,7 +98,6 @@ module.exports = (store, __exports) => { } }); - // enhancer menu function setThemeVars() { electron.ipcRenderer.send( 'enhancer:set-menu-theme', @@ -144,35 +142,44 @@ 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)]) - ); + if (store().tabs) { + electron.ipcRenderer.sendToHost( + 'enhancer:set-tab-theme', + [ + '--theme--main', + '--theme--dragarea', + '--theme--font_sans', + '--theme--table-border', + '--theme--interactive_hover', + '--theme--interactive_hover-border', + '--theme--button_close', + '--theme--button_close-fill', + '--theme--selected', + '--theme--option_hover-color', + '--theme--option_hover-background', + '--theme--text', + ].map((rule) => [rule, getStyle(rule)]) + ); + } } setThemeVars(); - const theme_observer = new MutationObserver(setThemeVars); - theme_observer.observe(document.querySelector('.notion-app-inner'), { - attributes: true, - }); + new MutationObserver(setThemeVars).observe( + document.querySelector('.notion-app-inner'), + { attributes: true } + ); electron.ipcRenderer.on('enhancer:get-menu-theme', setThemeVars); - if (!store().tabs) { - const sidebar_observer = new MutationObserver(setSidebarWidth); - sidebar_observer.observe(document.querySelector('.notion-sidebar'), { - attributes: true, - }); + if (store().tabs) { + let tab_title = ''; + __electronApi.setWindowTitle = (title) => { + if (tab_title !== title) { + tab_title = title; + electron.ipcRenderer.sendToHost('enhancer:set-tab-title', title); + } + }; + } else if (store().frameless && !store().tiling_mode) { let sidebar_width; function setSidebarWidth(list) { - if (!store().frameless && store().tiling_mode) return; const new_sidebar_width = list[0].target.style.height === 'auto' ? '0px' @@ -185,7 +192,11 @@ module.exports = (store, __exports) => { ); } } + new MutationObserver(setSidebarWidth).observe( + document.querySelector('.notion-sidebar'), + { attributes: true } + ); + setSidebarWidth([{ target: document.querySelector('.notion-sidebar') }]); } - setSidebarWidth([{ target: document.querySelector('.notion-sidebar') }]); } }; diff --git a/mods/core/css/menu.css b/mods/core/css/menu.css index 2c393c8..57e9c54 100644 --- a/mods/core/css/menu.css +++ b/mods/core/css/menu.css @@ -50,11 +50,11 @@ body:not([style]) > * { body:not([style])::after { content: ''; position: absolute; - left: calc(50vw - 15px); - top: calc(50vh - 15px); - width: 30px; - height: 30px; - border: 4px solid rgb(34, 34, 34); + left: calc(50% - 13px); + top: calc(50% + 10px); + width: 18px; + height: 18px; + border: 4px solid rgb(34, 34, 34, 0.5); border-top-color: transparent; border-radius: 50%; animation: spin 0.8s linear infinite; diff --git a/mods/core/css/scrollbars.css b/mods/core/css/scrollbars.css index 2525fb5..2286f9a 100644 --- a/mods/core/css/scrollbars.css +++ b/mods/core/css/scrollbars.css @@ -11,6 +11,7 @@ .smooth-scrollbars ::-webkit-scrollbar { width: 8px; /* vertical */ height: 8px; /* horizontal */ + -webkit-app-region: no-drag; } .smooth-scrollbars ::-webkit-scrollbar-corner { background-color: transparent; /* overlap */ diff --git a/mods/core/css/tabs.css b/mods/core/css/tabs.css index 2e30eb1..01ae6f5 100644 --- a/mods/core/css/tabs.css +++ b/mods/core/css/tabs.css @@ -23,18 +23,40 @@ transform: rotate(360deg); } } +@keyframes tabSlideIn { + from { + width: 0; + } + to { + width: 8.5em; + } +} -body:not([style*='--theme']) > * { +body:not([style*='--theme']):not(.error) > * { opacity: 0; } -body:not([style*='--theme'])::after { +body:not([style*='--theme']):not(.error)::after { content: ''; position: absolute; - left: calc(50vw - 25px); - top: calc(50vh - 25px); - width: 50px; - height: 50px; - border: 4px solid rgb(34, 34, 34); + left: calc(50% - 15px); + top: calc(50% + 10px); + width: 18px; + height: 18px; + border: 4px solid rgb(34, 34, 34, 0.5); + border-top-color: transparent; + border-radius: 50%; + animation: spin 0.8s linear infinite; +} +body[style*='--theme']::after { + z-index: 1; + content: ''; + position: absolute; + left: calc(50% - 15px); + top: calc(50% + 10px); + width: 18px; + height: 18px; + opacity: 0.5; + border: 4px solid var(--theme--text); border-top-color: transparent; border-radius: 50%; animation: spin 0.8s linear infinite; @@ -43,6 +65,8 @@ body:not([style*='--theme'])::after { html, body, #root { + background: var(--theme--main); + position: relative; height: 100%; margin: 0; } @@ -63,7 +87,6 @@ body, #titlebar { display: flex; flex-shrink: 1; - padding: 0.5em 0.15em; user-select: none; -webkit-app-region: drag; background: var(--theme--dragarea); @@ -73,8 +96,61 @@ body, -webkit-app-region: no-drag; } #titlebar .window-buttons-area { - margin: auto 0.4em auto auto; + margin: 0.5em 0.55em 0.5em auto; } #titlebar .window-buttons-area:empty { display: none; } + +#tabs { + margin-top: auto; +} +#tabs .tab { + display: inline-flex; + background: var(--theme--main); + border: none; + font-size: 1.15em; + padding: 0.2em 0.4em; + text-align: left; + border-bottom: 4px solid var(--theme--table-border); +} +#tabs .tab:first-child { + margin-top: 0.5em; +} +#tabs .tab:not(.new) span:not(.close) { + width: 8.5em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + animation: tabSlideIn 100ms ease-in-out; +} +#tabs .tab .close { + padding: 0 0.35em 0.1em 0.3em; + margin-left: auto; + font-weight: bold; +} +#tabs .tab.current { + background: var(--theme--selected); +} +#tabs .tab.new { + background: none; + border: none; + margin-left: -0.1em; +} +#tabs .tab.new span { + padding: 0 0.35em 0.1em 0.3em; + font-weight: bold; +} +#tabs .tab .close:hover, +#tabs .tab.new span:hover { + background: var(--theme--option_hover-background); + color: var(--theme--option_hover-color); + border-radius: 5px; +} + +.notion { + z-index: 2; + width: 100%; + height: 100%; + display: none; +} diff --git a/mods/core/render.js b/mods/core/render.js index d958942..124d726 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -37,45 +37,33 @@ module.exports = (store, __exports) => { searching: false, searchingPeekView: false, zoomFactor: 1, - tabIDs: [], + tabs: new Map([[0, true]]), }; this.$titlebar = null; - this.tabs = { - $current: null, + this.views = { + current: { + $el: () => this.views.html[this.views.current.id], + id: 0, + }, react: {}, - active: [], - loading: [], + html: {}, + loaded: {}, + tabs: {}, }; this.$search = null; this.handleReload = () => { this.setState({ error: false }); - this.tabs.loading.forEach(($notion) => { + Object.values(this.views.html).forEach(($notion) => { if ($notion.isWaitingForResponse()) $notion.reload(); }); }; - this.setTheme = this.setTheme.bind(this); + this.communicateWithView = this.communicateWithView.bind(this); 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({ tabIDs: [...new Set([...this.state.tabIDs, id])] }); - setTimeout(() => { - this.loadListeners(); - this.blurListeners(); - if (document.querySelector(`#tab-${id}`)) { - this.tabs.active.forEach(($notion) => { - $notion.style.display = 'none'; - }); - this.tabs.$current = document.querySelector(`#tab-${id}`); - this.tabs.$current.style.display = 'flex'; - this.focusListeners(); - } - }, 1000); - }; } componentDidMount() { const buttons = require('./buttons.js')(store); @@ -83,10 +71,105 @@ module.exports = (store, __exports) => { this.loadListeners(); } - setTheme(event) { - if (event.channel !== 'enhancer:set-tab-theme') return; - for (const style of event.args[0]) - document.body.style.setProperty(style[0], style[1]); + newTab() { + let id = 0, + state = new Map(this.state.tabs); + while (this.state.tabs.get(id)) id++; + state.delete(id); + if (this.views.html[id]) { + 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(this.views.current.$el().src); + } + this.openTab(id, state); + } + openTab(id, state = new Map(this.state.tabs)) { + if (!id && id !== 0) return; + this.views.current.id = id; + this.setState({ tabs: state.set(id, true) }, this.focusTab.bind(this)); + } + closeTab(id) { + if ((!id && id !== 0) || !this.state.tabs.get(id)) return; + if ([...this.state.tabs].filter(([id, open]) => open).length === 1) + return electron.remote.getCurrentWindow().close(); + while ( + !this.state.tabs.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 = this.state.tabs.size - 1; + } + this.setState( + { tabs: new Map(this.state.tabs).set(id, false) }, + this.focusTab.bind(this) + ); + } + focusTab() { + this.loadListeners(); + this.blurListeners(); + this.focusListeners(); + for (const id in this.views.loaded) { + if (this.views.loaded.hasOwnProperty(id) && this.views.loaded[id]) { + this.views.loaded[id].style.display = + id == this.views.current.id && this.state.tabs.get(+id) + ? 'flex' + : 'none'; + } + } + } + + communicateWithView(event) { + if (event.channel === 'enhancer:set-tab-theme') { + for (const style of event.args[0]) + document.body.style.setProperty(style[0], style[1]); + } + + if ( + event.channel === 'enhancer:set-tab-title' && + this.views.tabs[event.target.id] + ) { + this.views.tabs[event.target.id].children[0].innerText = + event.args[0]; + } + + 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.addListener('app-command', (e, cmd) => { + const webContents = this.views.current.$el().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 = this.views.current.$el().getWebContents(); + if (dir === 'left' && webContents.canGoBack()) { + webContents.goBack(); + } else if (dir === 'right' && webContents.canGoForward()) { + webContents.goForward(); + } + }); } startSearch(isPeekView) { this.setState({ @@ -105,46 +188,64 @@ module.exports = (store, __exports) => { searching: false, }); this.lastSearchQuery = undefined; - this.tabs.$current.getWebContents().stopFindInPage('clearSelection'); - notionIpc.sendIndexToNotion(this.tabs.$current, 'search:stopped'); + this.views.current + .$el() + .getWebContents() + .stopFindInPage('clearSelection'); + notionIpc.sendIndexToNotion(this.views.current.$el(), 'search:stopped'); } nextSearch(query) { - this.tabs.$current.getWebContents().findInPage(query, { - forward: true, - findNext: query === this.lastSearchQuery, - }); + this.views.current + .$el() + .getWebContents() + .findInPage(query, { + forward: true, + findNext: query === this.lastSearchQuery, + }); this.lastSearchQuery = query; } prevSearch(query) { - this.tabs.$current.getWebContents().findInPage(query, { - forward: false, - findNext: query === this.lastSearchQuery, - }); + this.views.current + .$el() + .getWebContents() + .findInPage(query, { + forward: false, + findNext: query === this.lastSearchQuery, + }); this.lastSearchQuery = query; } clearSearch() { this.lastSearchQuery = undefined; - this.tabs.$current.getWebContents().stopFindInPage('clearSelection'); + this.views.current + .$el() + .getWebContents() + .stopFindInPage('clearSelection'); } doneSearch() { this.lastSearchQuery = undefined; - this.tabs.$current.getWebContents().stopFindInPage('clearSelection'); + this.views.current + .$el() + .getWebContents() + .stopFindInPage('clearSelection'); this.setState({ searching: false }); if (document.activeElement instanceof HTMLElement) { document.activeElement.blur(); } - this.tabs.$current.focus(); - notionIpc.sendIndexToNotion(this.tabs.$current, 'search:stopped'); + this.views.current.$el().focus(); + notionIpc.sendIndexToNotion(this.views.current.$el(), 'search:stopped'); } focusListeners() { - this.tabs.$current.addEventListener('ipc-message', this.setTheme); + if (!this.views.current.$el() || !this.$search) return; + this.views.current + .$el() + .addEventListener('ipc-message', this.communicateWithView); notionIpc.receiveIndexFromNotion.addListener( - this.tabs.$current, + this.views.current.$el(), 'search:start', this.startSearch ); notionIpc.receiveIndexFromNotion.addListener( - this.tabs.$current, + this.views.current.$el(), 'search:stop', this.stopSearch ); @@ -170,16 +271,18 @@ module.exports = (store, __exports) => { ); } blurListeners() { - if (!this.tabs.$current) return; + if (!this.views.current.$el() || !this.$search) return; if (this.state.searching) this.stopSearch(); - this.tabs.$current.removeEventListener('ipc-message', this.setTheme); + this.views.current + .$el() + .removeEventListener('ipc-message', this.communicateWithView); notionIpc.receiveIndexFromNotion.removeListener( - this.tabs.$current, + this.views.current.$el(), 'search:start', this.startSearch ); notionIpc.receiveIndexFromNotion.removeListener( - this.tabs.$current, + this.views.current.$el(), 'search:stop', this.stopSearch ); @@ -206,10 +309,10 @@ module.exports = (store, __exports) => { } loadListeners() { if (!this.$search) return; - this.tabs.loading - .filter(($notion) => !this.tabs.active.includes($notion)) - .forEach(($notion) => { - this.tabs.active.push($notion); + Object.entries(this.views.html) + .filter(([id, $notion]) => !this.views.loaded[id] && $notion) + .forEach(([id, $notion]) => { + this.views.loaded[id] = $notion; $notion.addEventListener('did-fail-load', (error) => { // logger.info('Failed to load:', error); if ( @@ -280,25 +383,6 @@ module.exports = (store, __exports) => { this.handleReload(); return; } - 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, @@ -322,7 +406,6 @@ module.exports = (store, __exports) => { sendFullScreenChangeEvent ); }); - this.tabs.loading = []; } renderTitlebar() { @@ -334,25 +417,64 @@ module.exports = (store, __exports) => { this.$titlebar = $titlebar; }, }, - React.createElement('div', { id: 'tabs' }) + React.createElement( + 'div', + { id: 'tabs' }, + ...[...this.state.tabs] + .filter(([id, open]) => open) + .map(([id, open]) => + React.createElement( + 'button', + { + className: + 'tab' + (id === this.views.current.id ? ' current' : ''), + 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', + { + className: 'close', + onClick: () => { + this.closeTab(id); + }, + }, + '×' + ) + ) + ), + React.createElement( + 'button', + { + className: 'tab new', + onClick: () => { + this.newTab(); + }, + }, + React.createElement('span', {}, '+') + ) + ) ); } renderNotionContainer() { - this.tabs.react = Object.fromEntries( - this.state.tabIDs.map((id) => { + this.views.react = Object.fromEntries( + [...this.state.tabs].map(([id, open]) => { return [ id, - this.tabs.react[id] || + this.views.react[id] || React.createElement('webview', { className: 'notion', - id: `tab-${id}`, - style: { - width: '100%', - height: '100%', - display: 'none', - }, + id, ref: ($notion) => { - this.tabs.loading.push($notion); + this.views.html[id] = $notion; + this.focusTab(); }, partition: constants.electronSessionPartition, preload: path.resolve(`${__notion}/app/renderer/preload.js`), @@ -369,7 +491,7 @@ module.exports = (store, __exports) => { display: this.state.error ? 'none' : 'flex', }, }, - ...Object.values(this.tabs.react) + ...Object.values(this.views.react) ); } renderSearchContainer() { @@ -405,6 +527,7 @@ module.exports = (store, __exports) => { }, ref: ($search) => { this.$search = $search; + this.focusTab(); }, partition: constants.electronSessionPartition, preload: `file://${path.resolve( @@ -516,13 +639,24 @@ module.exports = (store, __exports) => { notion_intl.IntlProvider, { locale: notionLocale, - messages: notionLocale === 'ko-KR' ? koMessages : {}, + messages: + notionLocale === 'ko-KR' + ? koMessages + : { + 'desktopLogin.offline.title': + 'Welcome to <strong>Notion</strong>!', + 'desktopLogin.offline.message': + 'Connect to the internet to get started.', + 'desktopLogin.offline.retryConnectingToInternetButton.label': + 'Try again', + }, }, this.renderTitlebar(), this.renderNotionContainer(), this.renderSearchContainer(), this.renderErrorContainer() ); + document.body.classList[this.state.error ? 'add' : 'remove']('error'); this.loadListeners(); return result; } @@ -562,8 +696,6 @@ module.exports = (store, __exports) => { React.createElement(Index, { notionUrl: notionUrl }), $root ); - - tab(0); }; } else { const __start = window['__start']; From 3c71e945a315b1366cd7867ed49e18dc03d85658 Mon Sep 17 00:00:00 2001 From: Mimi Shahzad <68070585+mimi-shahzad@users.noreply.github.com> Date: Thu, 8 Oct 2020 18:03:41 -0400 Subject: [PATCH 08/15] Dracula theme (#145) A theme created based on the official Dracula Theme palette found https://draculatheme.com/contribute/. --- bin.js | 0 mods/dracula-theme/dracula.css | 188 +++++++++++++++++++++++++++++++ mods/dracula-theme/mod.js | 22 ++++ package-lock.json | 198 +++++++++++++++++++++++++++++++++ 4 files changed, 408 insertions(+) mode change 100644 => 100755 bin.js create mode 100644 mods/dracula-theme/dracula.css create mode 100644 mods/dracula-theme/mod.js create mode 100644 package-lock.json diff --git a/bin.js b/bin.js old mode 100644 new mode 100755 diff --git a/mods/dracula-theme/dracula.css b/mods/dracula-theme/dracula.css new file mode 100644 index 0000000..cdc333a --- /dev/null +++ b/mods/dracula-theme/dracula.css @@ -0,0 +1,188 @@ +/* + * Dracula Theme Palette + * (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/) + * (c) 2020 u/mimi-shahzad + * (c) 2020 Dracula Theme + * under the MIT license + */ + +:root { + --theme_dark--main: #282a36; + --theme_dark--sidebar: #282a36; + --theme_dark--overlay: #282a36; + --theme_dark--dragarea: #282a36; + + --theme_dark--font_sans: -apple-system, BlinkMacSystemFont, + 'Segoe UI', Helvetica, 'Apple Color Emoji', Arial, sans-serif, + 'Segoe UI Emoji', 'Segoe UI Symbol'; + + --theme_dark--scrollbar: #282a36; + --theme_dark--scrollbar_hover: #6272a4; + + --theme_dark--card: #6272a4; + --theme_dark--gallery: #282a36; + --theme_dark--table-border: #6272a4; + --theme_dark--interactive_hover: #282a36; + --theme_dark--button_close: #ff5555; + + --theme_dark--selected: #454158; + --theme_dark--primary: #bd93f9; + --theme_dark--primary_hover: #8be9fd; + --theme_dark--primary_click: #bd93f9; + --theme_dark--primary_indicator: #8be9fd; + + --theme_dark--option_active-background: var(--theme_dark--primary); + --theme_dark--option_hover-background: var(--theme_dark--primary_hover); + + --theme_dark--danger_text: #ff5555; + --theme_dark--danger_border: #ffb86c; + + --theme_dark--text: #f8f8f2; + --theme_dark--text_ui: #f8f8f2; + --theme_dark--text_ui_info: #f8f8f2; + + --theme_dark--text_gray: #454158; + --theme_dark--text_brown: #6272a4; + --theme_dark--text_orange: #ffb86c; + --theme_dark--text_yellow: #f1fa8c; + --theme_dark--text_green: #50fa7b; + --theme_dark--text_blue: #8be9fd; + --theme_dark--text_purple: #bd93f9; + --theme_dark--text_pink: #ff79c6; + --theme_dark--text_red: #ff5555; + + --theme_dark--select-text: #000000; + --theme_dark--select_gray: #454158; + --theme_dark--select_brown: #6272a4; + --theme_dark--select_orange: #ffb86c; + --theme_dark--select_yellow: #f1fa8c; + --theme_dark--select_green: #50fa7b; + --theme_dark--select_blue: #8be9fd; + --theme_dark--select_purple: #bd93f9; + --theme_dark--select_pink: #ff79c6; + --theme_dark--select_red: #ff5555; + + --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--line-text: #000000; + --theme_dark--line_gray: #454158; + --theme_dark--line_brown: #6272a4; + --theme_dark--line_orange: #ffb86c; + --theme_dark--line_yellow: #f1fa8c; + --theme_dark--line_green: #50fa7b; + --theme_dark--line_blue: #8be9fd; + --theme_dark--line_purple: #bd93f9; + --theme_dark--line_pink: #ff79c6; + --theme_dark--line_red: #ff5555; + + --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: #50fa7b; + --theme_dark--code_inline-background:#44475a; + --theme_dark--code-text: var(--theme_dark--text); + --theme_dark--code-background: #44475a; + --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_ui); + --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 img[src*='/images/onboarding/use-case-note.png'], +.notion-dark-theme + img[src*='/images/onboarding/team-features-illustration.png'] { + filter: invert(1) !important; +} +.notion-dark-theme img[src*='/images/onboarding/checked.svg'] { + filter: hue-rotate(45deg) !important; +} +.notion-dark-theme + img[style*='display: block; object-fit: cover; border-radius: 100%; width: 90px; height: 90px;'], +.notion-dark-theme + img[style*='display: block; object-fit: cover; border-radius: 3px; width: 56.832px; height: 56.832px; transition: opacity 100ms ease-out 0s;'] { + transition: filter 0.4s ease !important; +} +.notion-dark-theme + img[style*='display: block; object-fit: cover; border-radius: 100%; width: 90px; height: 90px;']:hover, +.notion-dark-theme + img[style*='display: block; object-fit: cover; border-radius: 3px; width: 56.832px; height: 56.832px; transition: opacity 100ms ease-out 0s;']:hover { + filter: brightness(1.2); +} + +.notion-dark-theme + [style*='font-family: Fira Code, Menlo, Courier, monospace;'] { + filter: hue-rotate(170deg) !important; +} + +.notion-dark-theme + .notion-token-remove-button[role*='button'][tabindex*='0']:hover, +.notion-dark-theme .notion-record-icon { + background: transparent !important; +} + +.notion-dark-theme .notion-focusable:focus-within, +.notion-dark-theme .notion-to_do-block > div > div > div[style*='background:'], +.notion-dark-theme div[role='button'], +[style*='height: 4px;'] + > .notion-selectable.notion-collection_view_page-block + > *, +.notion-dark-theme + .notion-calendar-view-day[style*='background: #282a36;'], +.DayPicker-Day--today, +.notion-dark-theme + .DayPicker:not(.DayPicker--interactionDisabled) + .DayPicker-Day--outside:hover, +.notion-dark-theme + .DayPicker:not(.DayPicker--interactionDisabled) + .DayPicker-Day:not(.DayPicker-Day--disabled):not(.DayPicker-Day--value) + .DayPicker-Day.DayPicker-Day--start.DayPicker-Day--selected, +.notion-dark-theme .DayPicker-Day.DayPicker-Day--range.DayPicker-Day--start, +.notion-dark-theme .DayPicker-Day.DayPicker-Day--range.DayPicker-Day--end { + transition: color 0.4s ease, background 0.4s ease, box-shadow 0.4s ease !important; +} + +.notion-dark-theme [style*='background: #282a36;'], +.notion-dark-theme + [style*='background: rgb(80, 85, 88);'][style*='color: rgba(255, 255, 255, 0.7)'], +.notion-dark-theme + [style*='background: rgb(80, 85, 88);'][style*='width: 18px;'][style*='height: 18px;'], +.notion-dark-theme + [style*='box-shadow: rgba(15, 15, 15, 0.1) 0px 0px 0px 1px, rgba(15, 15, 15, 0.2) 0px 5px 10px, rgba(15, 15, 15, 0.4) 0px 15px 40px;'], +.notion-dark-theme [style*='background: rgba(151, 154, 155, 0.5);'], +.notion-dark-theme [style*='background: rgba(147, 114, 100, 0.5)'], +.notion-dark-theme [style*='background: rgba(255, 163, 68, 0.5)'], +.notion-dark-theme [style*='background: rgba(255, 220, 73, 0.5)'], +.notion-dark-theme [style*='background: rgba(77, 171, 154, 0.5)'], +.notion-dark-theme [style*='background: rgba(82, 156, 202, 0.5)'], +.notion-dark-theme [style*='background: rgba(154, 109, 215, 0.5)'], +.notion-dark-theme [style*='background: rgba(226, 85, 161, 0.5)'], +.notion-dark-theme [style*='background: rgba(255, 115, 105, 0.5)'] { + box-shadow: 0 2px 4px rgb(0 0 0 / 66%) !important; +} diff --git a/mods/dracula-theme/mod.js b/mods/dracula-theme/mod.js new file mode 100644 index 0000000..6a3fc2b --- /dev/null +++ b/mods/dracula-theme/mod.js @@ -0,0 +1,22 @@ +/* + * dracula + * (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/) + * (c) 2020 u/mimi-shahzad + * (c) 2020 Dracula Theme + * under the MIT license + */ + +'use strict'; + +module.exports = { + id: '033bff54-50ba-4cec-bdc0-b2ca7e307086', + tags: ['theme', 'dark'], + name: 'dracula', + desc: 'a theme based on the popular Dracula color palette originally by Zeno Rocha and friends. ', + version: '0.1', + author: { + name: 'mimi-shahzad', + link: 'https://github.com/mimi-shahzad', + avatar: 'https://secure.gravatar.com/avatar/86c98dec3a06245dbf2291deb44441f5', + } +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a9ea556 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,198 @@ +{ + "name": "notion-enhancer", + "version": "0.9.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@jsdevtools/file-path-filter": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@jsdevtools/file-path-filter/-/file-path-filter-3.0.2.tgz", + "integrity": "sha512-+SbZG6stIE/nRF2PpRnubtuzhh4pouDsk/hEWwM5mKsSKlFfr4ziAE5VMogGG/K++i9NHbUTxxW0y4vdM678ew==", + "requires": { + "glob-to-regexp": "^0.4.1" + } + }, + "@jsdevtools/readdir-enhanced": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@jsdevtools/readdir-enhanced/-/readdir-enhanced-6.0.4.tgz", + "integrity": "sha512-I6D6Omu6C7XWHzvlVbXeCS0FSxYYQ13XzdrFuo1K30unnRSpdt9AxY2KyJZbYJyfI2uNNidqDkG9/K/y699AjA==", + "requires": { + "@jsdevtools/file-path-filter": "^3.0.2" + } + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "optional": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "optional": true + }, + "@types/node": { + "version": "14.11.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz", + "integrity": "sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==", + "optional": true + }, + "asar": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/asar/-/asar-3.0.3.tgz", + "integrity": "sha512-k7zd+KoR+n8pl71PvgElcoKHrVNiSXtw7odKbyNpmgKe7EGRF9Pnu3uLOukD37EvavKwVFxOUpqXTIZC5B5Pmw==", + "requires": { + "@types/glob": "^7.1.1", + "chromium-pickle-js": "^0.2.0", + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + } + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "cac": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.6.1.tgz", + "integrity": "sha512-uhki4T3Ax68hw7Dufi0bATVAF8ayBSwOKUEJHjObPrUN4tlQ8Lf7oljpTje/mArLxYN0D743c2zJt4C1bVTCqg==" + }, + "chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha1-BKEGZywYsIWrd02YPfo+oTjyIgU=" + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "readdir-enhanced": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/readdir-enhanced/-/readdir-enhanced-6.0.4.tgz", + "integrity": "sha512-MWY048D/nEpHwqdnsBiUxpqjJPkEw2i2RmY5gM2Gadn0rkHS/DhUBqrYTkOqKHF4RoUlYZZ8GnP4ymlRGuo30A==", + "requires": { + "@jsdevtools/readdir-enhanced": "6.0.4" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} From 09069e03e918379a3bcc28d8aa6f8e568acd78c8 Mon Sep 17 00:00:00 2001 From: dragonwocky <thedragonring.bod@gmail.com> Date: Fri, 9 Oct 2020 20:42:34 +1100 Subject: [PATCH 09/15] draggable/nicer-looking tabs + icon --- mods/core/client.js | 3 +- mods/core/css/tabs.css | 28 ++++++- mods/core/render.js | 184 +++++++++++++++++++++++++---------------- pkg/apply.js | 5 +- pkg/remove.js | 5 +- 5 files changed, 148 insertions(+), 77 deletions(-) diff --git a/mods/core/client.js b/mods/core/client.js index 7c557c4..5ae7a0e 100644 --- a/mods/core/client.js +++ b/mods/core/client.js @@ -154,9 +154,8 @@ module.exports = (store, __exports) => { '--theme--interactive_hover-border', '--theme--button_close', '--theme--button_close-fill', + '--theme--option_active-background', '--theme--selected', - '--theme--option_hover-color', - '--theme--option_hover-background', '--theme--text', ].map((rule) => [rule, getStyle(rule)]) ); diff --git a/mods/core/css/tabs.css b/mods/core/css/tabs.css index 01ae6f5..7de4934 100644 --- a/mods/core/css/tabs.css +++ b/mods/core/css/tabs.css @@ -11,7 +11,7 @@ word-break: break-word; text-decoration: none; text-size-adjust: 100%; - font-family: var(--theme--font_sans); + font-family: var(--theme--font_sans) !important; outline-color: var(--theme--table-border); } @@ -65,7 +65,7 @@ body[style*='--theme']::after { html, body, #root { - background: var(--theme--main); + background: var(--theme--main) !important; position: relative; height: 100%; margin: 0; @@ -105,6 +105,16 @@ body, #tabs { margin-top: auto; } +#tabs::before { + content: ''; + height: 1.25em; + width: 1.25em; + display: inline-block; + margin: auto 1em -0.25em 1em; + background-size: contain; + background-image: url('enhancement://core/icons/mac+linux.png'); + background-repeat: no-repeat; +} #tabs .tab { display: inline-flex; background: var(--theme--main); @@ -113,6 +123,7 @@ body, padding: 0.2em 0.4em; text-align: left; border-bottom: 4px solid var(--theme--table-border); + opacity: 0.8; } #tabs .tab:first-child { margin-top: 0.5em; @@ -122,6 +133,8 @@ body, white-space: nowrap; overflow: hidden; text-overflow: ellipsis; +} +#tabs .tab.slideIn span:not(.close) { animation: tabSlideIn 100ms ease-in-out; } #tabs .tab .close { @@ -130,7 +143,9 @@ body, font-weight: bold; } #tabs .tab.current { + opacity: 1; background: var(--theme--selected); + border-bottom: 4px solid var(--theme--option_active-background); } #tabs .tab.new { background: none; @@ -141,12 +156,17 @@ body, padding: 0 0.35em 0.1em 0.3em; font-weight: bold; } +#tabs .tab:hover { + opacity: 1; +} #tabs .tab .close:hover, #tabs .tab.new span:hover { - background: var(--theme--option_hover-background); - color: var(--theme--option_hover-color); + background: var(--theme--table-border); border-radius: 5px; } +#tabs .tab.dragged-over { + box-shadow: inset 4px 0 0 0 var(--theme--selected); +} .notion { z-index: 2; diff --git a/mods/core/render.js b/mods/core/render.js index 124d726..619c91f 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -40,6 +40,7 @@ module.exports = (store, __exports) => { tabs: new Map([[0, true]]), }; this.$titlebar = null; + this.$dragging = null; this.views = { current: { $el: () => this.views.html[this.views.current.id], @@ -64,79 +65,56 @@ module.exports = (store, __exports) => { this.prevSearch = this.prevSearch.bind(this); this.clearSearch = this.clearSearch.bind(this); this.doneSearch = this.doneSearch.bind(this); + + // draggable re-ordering + const getTab = ($el) => { + 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 + ) || [] + ); + }; + 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[1].classList.contains('new') && from[0] !== to[0]) + to[1].parentElement.insertBefore(from[1], to[1]); + from[1].classList.remove('slideIn'); + this.$dragging = null; + }); } + componentDidMount() { const buttons = require('./buttons.js')(store); this.$titlebar.appendChild(buttons.element); this.loadListeners(); - } - - newTab() { - let id = 0, - state = new Map(this.state.tabs); - while (this.state.tabs.get(id)) id++; - state.delete(id); - if (this.views.html[id]) { - 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(this.views.current.$el().src); - } - this.openTab(id, state); - } - openTab(id, state = new Map(this.state.tabs)) { - if (!id && id !== 0) return; - this.views.current.id = id; - this.setState({ tabs: state.set(id, true) }, this.focusTab.bind(this)); - } - closeTab(id) { - if ((!id && id !== 0) || !this.state.tabs.get(id)) return; - if ([...this.state.tabs].filter(([id, open]) => open).length === 1) - return electron.remote.getCurrentWindow().close(); - while ( - !this.state.tabs.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 = this.state.tabs.size - 1; - } - this.setState( - { tabs: new Map(this.state.tabs).set(id, false) }, - this.focusTab.bind(this) - ); - } - focusTab() { - this.loadListeners(); - this.blurListeners(); - this.focusListeners(); - for (const id in this.views.loaded) { - if (this.views.loaded.hasOwnProperty(id) && this.views.loaded[id]) { - this.views.loaded[id].style.display = - id == this.views.current.id && this.state.tabs.get(+id) - ? 'flex' - : 'none'; - } - } - } - - communicateWithView(event) { - if (event.channel === 'enhancer:set-tab-theme') { - for (const style of event.args[0]) - document.body.style.setProperty(style[0], style[1]); - } - - if ( - event.channel === 'enhancer:set-tab-title' && - this.views.tabs[event.target.id] - ) { - this.views.tabs[event.target.id].children[0].innerText = - event.args[0]; - } let electronWindow; try { @@ -171,6 +149,72 @@ module.exports = (store, __exports) => { } }); } + + newTab() { + let id = 0; + const list = new Map(this.state.tabs); + while (this.state.tabs.get(id)) id++; + list.delete(id); + if (this.views.html[id]) { + 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(this.views.current.$el().src); + } + this.openTab(id, list); + } + openTab(id, state = new Map(this.state.tabs)) { + if (!id && id !== 0) return; + this.views.current.id = id; + this.setState({ tabs: state.set(id, true) }, this.focusTab.bind(this)); + } + closeTab(id) { + if ((!id && id !== 0) || !this.state.tabs.get(id)) return; + const list = new Map(this.state.tabs); + list.delete(id); + list.set(id, false); + if (![...list].filter(([id, 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)); + } + focusTab() { + this.loadListeners(); + this.blurListeners(); + this.focusListeners(); + for (const id in this.views.loaded) { + if (this.views.loaded.hasOwnProperty(id) && this.views.loaded[id]) { + this.views.loaded[id].style.display = + id == this.views.current.id && this.state.tabs.get(+id) + ? 'flex' + : 'none'; + } + } + } + + communicateWithView(event) { + if (event.channel === 'enhancer:set-tab-theme') { + for (const style of event.args[0]) + document.body.style.setProperty(style[0], style[1]); + } + if ( + event.channel === 'enhancer:set-tab-title' && + this.views.tabs[event.target.id] + ) { + this.views.tabs[event.target.id].children[0].innerText = + event.args[0]; + } + } startSearch(isPeekView) { this.setState({ searching: true, @@ -426,8 +470,10 @@ module.exports = (store, __exports) => { React.createElement( 'button', { + draggable: true, className: - 'tab' + (id === this.views.current.id ? ' current' : ''), + 'tab slideIn' + + (id === this.views.current.id ? ' current' : ''), onClick: (e) => { if (!e.target.classList.contains('close')) this.openTab(id); diff --git a/pkg/apply.js b/pkg/apply.js index 96f3746..168193a 100644 --- a/pkg/apply.js +++ b/pkg/apply.js @@ -117,7 +117,10 @@ module.exports = async function ({ overwrite_version, friendly_errors } = {}) { `file access forbidden - ${ process.platform === 'win32' ? 'make sure your user has elevated permissions.' - : `try running "sudo chmod a+wr -R ${err.path}"` + : `try running "sudo chmod a+wr -R ${err.path.replace( + 'Notion.app', + 'Notion' + )}"` }` ); } else if (['EIO', 'EBUSY'].includes(err.code) && friendly_errors) { diff --git a/pkg/remove.js b/pkg/remove.js index 4f54abb..a9c3696 100644 --- a/pkg/remove.js +++ b/pkg/remove.js @@ -119,7 +119,10 @@ module.exports = async function ({ `file access forbidden - ${ process.platform === 'win32' ? 'make sure your user has elevated permissions.' - : `try running "sudo chmod a+wr -R ${err.path}"` + : `try running "sudo chmod a+wr -R ${err.path.replace( + 'Notion.app', + 'Notion' + )}"` }` ); } else if (['EIO', 'EBUSY'].includes(err.code) && friendly_errors) { From b8b4af4f89ba3be648dc00bf768948394cf2a5d6 Mon Sep 17 00:00:00 2001 From: dragonwocky <thedragonring.bod@gmail.com> Date: Fri, 9 Oct 2020 20:56:21 +1100 Subject: [PATCH 10/15] bugfixes so dracula will actually load --- mods/core/client.js | 4 ++++ mods/core/css/menu.css | 4 ++++ mods/dracula-theme/mod.js | 14 +++++--------- mods/dracula-theme/{dracula.css => styles.css} | 14 ++++++-------- 4 files changed, 19 insertions(+), 17 deletions(-) rename mods/dracula-theme/{dracula.css => styles.css} (94%) diff --git a/mods/core/client.js b/mods/core/client.js index 5ae7a0e..7152958 100644 --- a/mods/core/client.js +++ b/mods/core/client.js @@ -135,9 +135,13 @@ module.exports = (store, __exports) => { '--theme--select_red', '--theme--line_text', '--theme--line_yellow', + '--theme--line_yellow-text', '--theme--line_green', + '--theme--line_green-text', '--theme--line_blue', + '--theme--line_blue-text', '--theme--line_red', + '--theme--line_red-text', '--theme--code_inline-text', '--theme--code_inline-background', ].map((rule) => [rule, getStyle(rule)]) diff --git a/mods/core/css/menu.css b/mods/core/css/menu.css index 57e9c54..1f36cf7 100644 --- a/mods/core/css/menu.css +++ b/mods/core/css/menu.css @@ -146,6 +146,7 @@ s { color: var(--theme--select_red); } #alerts .error { + color: var(--theme--line_red-text); background: var(--theme--line_red); border-color: var(--theme--select_red); } @@ -153,6 +154,7 @@ s { color: var(--theme--select_yellow); } #alerts .warning { + color: var(--theme--line_yellow-text); background: var(--theme--line_yellow); border-color: var(--theme--select_yellow); } @@ -160,6 +162,7 @@ s { color: var(--theme--select_blue); } #alerts .info { + color: var(--theme--line_blue-text); background: var(--theme--line_blue); border-color: var(--theme--select_blue); } @@ -168,6 +171,7 @@ s { color: var(--theme--select_green); } #alerts .success { + color: var(--theme--line_green-text); background: var(--theme--line_green); border-color: var(--theme--select_green); } diff --git a/mods/dracula-theme/mod.js b/mods/dracula-theme/mod.js index 6a3fc2b..cd3668a 100644 --- a/mods/dracula-theme/mod.js +++ b/mods/dracula-theme/mod.js @@ -1,6 +1,5 @@ /* - * dracula - * (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/) + * dracula-theme * (c) 2020 u/mimi-shahzad * (c) 2020 Dracula Theme * under the MIT license @@ -12,11 +11,8 @@ module.exports = { id: '033bff54-50ba-4cec-bdc0-b2ca7e307086', tags: ['theme', 'dark'], name: 'dracula', - desc: 'a theme based on the popular Dracula color palette originally by Zeno Rocha and friends. ', - version: '0.1', - author: { - name: 'mimi-shahzad', - link: 'https://github.com/mimi-shahzad', - avatar: 'https://secure.gravatar.com/avatar/86c98dec3a06245dbf2291deb44441f5', - } + desc: + 'a theme based on the popular dracula color palette originally by zeno rocha and friends. ', + version: '0.1.0', + author: 'mimi-shahzad', }; diff --git a/mods/dracula-theme/dracula.css b/mods/dracula-theme/styles.css similarity index 94% rename from mods/dracula-theme/dracula.css rename to mods/dracula-theme/styles.css index cdc333a..67e9a74 100644 --- a/mods/dracula-theme/dracula.css +++ b/mods/dracula-theme/styles.css @@ -1,6 +1,5 @@ /* - * Dracula Theme Palette - * (c) 2020 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/) + * dracula-theme * (c) 2020 u/mimi-shahzad * (c) 2020 Dracula Theme * under the MIT license @@ -12,9 +11,9 @@ --theme_dark--overlay: #282a36; --theme_dark--dragarea: #282a36; - --theme_dark--font_sans: -apple-system, BlinkMacSystemFont, - 'Segoe UI', Helvetica, 'Apple Color Emoji', Arial, sans-serif, - 'Segoe UI Emoji', 'Segoe UI Symbol'; + --theme_dark--font_sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', + Helvetica, 'Apple Color Emoji', Arial, sans-serif, 'Segoe UI Emoji', + 'Segoe UI Symbol'; --theme_dark--scrollbar: #282a36; --theme_dark--scrollbar_hover: #6272a4; @@ -96,7 +95,7 @@ --theme_dark--callout_red: var(--theme_dark--line_red); --theme_dark--code_inline-text: #50fa7b; - --theme_dark--code_inline-background:#44475a; + --theme_dark--code_inline-background: #44475a; --theme_dark--code-text: var(--theme_dark--text); --theme_dark--code-background: #44475a; --theme_dark--code_function: var(--theme_dark--text_blue); @@ -153,8 +152,7 @@ [style*='height: 4px;'] > .notion-selectable.notion-collection_view_page-block > *, -.notion-dark-theme - .notion-calendar-view-day[style*='background: #282a36;'], +.notion-dark-theme .notion-calendar-view-day[style*='background: #282a36;'], .DayPicker-Day--today, .notion-dark-theme .DayPicker:not(.DayPicker--interactionDisabled) From 61206db05aceac08eb6377b2f4f52ec4e93d43f4 Mon Sep 17 00:00:00 2001 From: dragonwocky <thedragonring.bod@gmail.com> Date: Sun, 11 Oct 2020 15:28:56 +1100 Subject: [PATCH 11/15] bugfixes: match up some styling better, EACCES dest chmodding, csp re-allow fonts --- CHANGELOG.md | 10 +++- README.md | 30 +++++++++-- mods/core/css/theme.css | 101 +++++++++++++++++++++++++++--------- mods/core/css/variables.css | 21 ++++++++ mods/core/render.js | 2 +- mods/core/tray.js | 35 +++++++++---- package.json | 1 + pkg/apply.js | 9 +++- pkg/remove.js | 9 +++- yarn.lock | 5 ++ 10 files changed, 180 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b19209..703bdcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ a flexibility update. variables can be modified.) - new: in-page columns disabled/wrapped and wider pages when the window is narrower than 600px for improved responsiveness. +- new: relaunch button in tray menu. - improved: a core mod option to make transitions snappy/0s. - improved: menu will now respect integrated titlebar setting. - bugfix: removed messenger emoji set as the provider no longer supports it. @@ -28,8 +29,15 @@ a flexibility update. - bugfix: bypass preview extension works with the back/forward keyboard shortcuts. - bugfix: (maybe) fix csp issues under proxy. - bugfix: remove focus mode footer from neutral theme. +- bugfix: improvements to the colour theming, particularly to make real- and fake-light/dark + modes (as applied by the night shift extension) look consistent. - tweak: sticky table/list rows. -- extension: "material ocean" = an oceanic colour palette. +- theme: "material ocean" = an oceanic colour palette. +- theme: "dracula" = a theme based on the popular dracula color palette + originally by zeno rocha and friends. +- extension: "tabs" = have multiple notion pages open in a single window. + +a fork of notion-deb-builder that does generate an app.asar has been created and is once again supported. ### v0.9.1 (2020-09-26) diff --git a/README.md b/README.md index 080124b..bd7aa25 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ for support, join the [discord server](https://discord.gg/sFWPXtA). - the [official windows/mac releases](https://notion.so/desktop). - the arch linux AUR [notion-app](https://aur.archlinux.org/packages/notion-app/) package. - the linux [notion-app](https://github.com/jaredallard/notion-app) installer. +- [@haydn-jones](https://github.com/haydn-jones/)'s fork of the + linux [notion-deb-builder](https://github.com/haydn-jones/notion-deb-builder). (it can also be run from the wsl to apply enhancements to the windows app.) @@ -31,10 +33,22 @@ a chrome extension may be coming soon for web client support. during installation/removal, make sure no notion processes are running! (check your task manager.) -**win10, macOS** +**win10** -1. [install node.js](https://nodejs.org/en/download/) (_a computer restart may be required here._) -2. execute `npm i -g notion-enhancer` in the terminal/command prompt. +[install node.js](https://nodejs.org/en/download/) (_a computer restart may be required here_), +then execute `npm i -g notion-enhancer` in the command prompt. + +**macOS** + +[install node.js](https://nodejs.org/en/download/) (_a computer restart may be required here_), +then execute the following lines in the terminal: + +``` +sudo chmod -R a+wr /usr/local/lib/node_modules +sudo chmod -R a+wr /usr/local/bin +sudo chmod -R a+wr /Applications/Notion/Contents/Resources +npm i -g notion-enhancer +``` **debian/ubuntu, chromeOS, WSL (to modify the win10 app)** @@ -81,6 +95,14 @@ Options: -v, --version : display version number ``` +### faq + +**the themes aren't working?** + +if you pick a dark theme it will only be applied if notion is in dark mode, +and if you pick a light theme it will only work if notion is in light mode. +do `CMD/CTRL+SHIFT+L` to toggle between them. + **is this against notion's terms of service? can i get in trouble for using it?** definitely not! i contacted their support team to check, and the response was awesome: @@ -92,7 +114,7 @@ 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 `ALT+E`. +the tray/menubar icon or with `OPTION/ALT+E`.  diff --git a/mods/core/css/theme.css b/mods/core/css/theme.css index 7778954..735fad2 100644 --- a/mods/core/css/theme.css +++ b/mods/core/css/theme.css @@ -9,20 +9,25 @@ /** app **/ +.notion-body, +.notion-body.dark [style*='background: rgb(47, 52, 55)'], +.notion-body.dark [style*='background-color: rgb(47, 52, 55)'], +.notion-body:not(.dark) + .notion-light-theme + [style*='background: white']:not(.notion-help-button), +.notion-body:not(.dark) + .notion-dark-theme + [style*='background: white']:not(.notion-help-button):not([style*='box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 3px 6px, rgba(15, 15, 15, 0.2) 0px 9px 24px;']), +.notion-body:not(.dark) [style*='background-color: white'] { + background: var(--theme--main) !important; +} +.notion-sidebar > div, .notion-body.dark [style*='background: rgb(55, 60, 63)'], .notion-body.dark [style*='background: rgb(120, 123, 123)'], .notion-body:not(.dark) [style*='background: rgb(247, 246, 243)'], .notion-body:not(.dark) [style*='background: rgb(223, 223, 222)'] { background: var(--theme--sidebar) !important; } -.notion-body, -.notion-body.dark [style*='background: rgb(47, 52, 55)'], -.notion-body.dark [style*='background-color: rgb(47, 52, 55)'], -.notion-body:not(.dark) - [style*='background: white']:not(.notion-help-button):not([style*='box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 3px 6px, rgba(15, 15, 15, 0.2) 0px 9px 24px;']), -.notion-body:not(.dark) [style*='background-color: white'] { - background: var(--theme--main) !important; -} [style*='background: rgba(15, 15, 15, 0.6)'] { background: var(--theme--overlay) !important; } @@ -195,7 +200,8 @@ > a[style*='background: white'], .notion-body:not(.dark) [style*='background: rgb(247, 246, 243)'], .notion-body:not(.dark) - [style*='box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 3px 6px, rgba(15, 15, 15, 0.2) 0px 9px 24px;'] { + .notion-dark-theme + [style*='background: white'][style*='box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 3px 6px, rgba(15, 15, 15, 0.2) 0px 9px 24px;'] { background: var(--theme--card) !important; } .notion-body.dark @@ -206,19 +212,36 @@ [style*='background: rgba(55, 53, 47, 0.024)'] { background: var(--theme--gallery) !important; } +.notion-body.dark .notion-scroller > [style*='rgb(55, 60, 63)'], +.notion-body:not(.dark) [style*='background: rgba(242, 241, 238, 0.6)'] { + background: var(--theme--select_input) !important; +} .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'], + [style*='box-shadow: rgba(255, 255, 255, 0.14) 0px -1px inset;'], .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; + [style*='box-shadow: rgba(55, 53, 47, 0.16) 0px -1px 0px inset'] { + box-shadow: rgba(55, 53, 47, 0.16) 0px -1px inset !important; +} + +.notion-body.dark [style*='box-shadow: rgba(255, 255, 255, 0.07) 0px 1px 0px'], +.notion-body:not(.dark) + [style*='box-shadow: rgba(55, 53, 47, 0.09) 0px 1px 0px'] { + box-shadow: var(--theme--ui-border) 0px 1px 0px !important; +} +.notion-body.dark + [style*='box-shadow: rgba(255, 255, 255, 0.14) 0px 1px 0px inset'], +.notion-body:not(.dark) + [style*='box-shadow: rgba(55, 53, 47, 0.16) 0px 1px 0px inset'] { + box-shadow: var(--theme--table-border) 0px 1px 0px inset !important; } .notion-body.dark [style*='box-shadow: rgb(47, 52, 55) -3px 0px 0px'] { box-shadow: var(--theme--main) -3px 0px 0px !important; } +.notion-body:not(.dark) [style*='box-shadow: white -3px 0px 0px;'] { + box-shadow: none !important; +} .notion-body.dark [style*='box-shadow: rgb(47, 52, 55) -3px 0px 0px, rgba(255, 255, 255, 0.14) 0px 1px 0px'], .notion-body:not(.dark) @@ -226,7 +249,7 @@ .notion-body:not(.dark) [style*='box-shadow: rgba(255, 255, 255, 0.07) 0px -1px 0px'] { box-shadow: var(--theme--main) -3px 0px 0px, - var(--theme--table-border) 0px 1px 0px !important; + var(--theme--ui-border) 0px 1px 0px !important; } .notion-body.dark [style*='border-top: 1px solid rgba(255, 255, 255,'], @@ -254,7 +277,7 @@ .notion-body.dark [style*='box-shadow: rgba(55, 53, 47, 0.09) 0px -1px 0px'], .notion-body:not(.dark) [style*='box-shadow: rgba(55, 53, 47, 0.09) 0px -1px 0px'] { - box-shadow: var(--theme--table-border) 0px -1px 0px !important; + box-shadow: var(--theme--ui-border) 0px -1px 0px !important; } .notion-body.dark [style*='border-left: 1px solid rgba(255, 255, 255,'], .notion-body.dark @@ -263,12 +286,6 @@ .notion-body:not(.dark) [style*='border-left: 1px solid rgba(55, 53, 47,'] { border-left: 1px solid var(--theme--table-border) !important; } -.notion-body.dark - [style*='box-shadow: rgba(255, 255, 255, 0.14) 0px 1px 0px inset'], -.notion-body:not(.dark) - [style*='box-shadow: rgba(55, 53, 47, 0.16) 0px 1px 0px inset'] { - box-shadow: var(--theme--table-border) 0px 1px 0px inset !important; -} .notion-body.dark [style*='box-shadow: rgba(255, 255, 255, 0.14) 1px 0px 0px inset'], .notion-body:not(.dark) @@ -296,6 +313,7 @@ .notion-body.dark [style*='background: rgb(71, 76, 80)'], .notion-body.dark [style*='background: rgb(80, 85, 88)'], .notion-body.dark [style*='background: rgb(98, 102, 104)'], +.notion-body.dark [style*='height: 1px; background: rgba(255, 255, 255, 0.07)'], .notion-body:not(.dark) [style*='background: rgba(55, 53, 47,'], .notion-body:not(.dark) [style*='background: rgb(239, 239, 238)'], .notion-body:not(.dark) [style*='background: rgba(206, 205, 202, 0.5)'] { @@ -395,6 +413,19 @@ background: var(--theme--primary_indicator) !important; } +.notion-body.dark + [style*='box-shadow: rgba(15, 15, 15, 0.1) 0px 0px 0px 1px, rgba(15, 15, 15, 0.2) 0px 3px 6px, rgba(15, 15, 15, 0.4) 0px 9px 24px'], +.notion-body:not(.dark) + [style*='box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 3px 6px, rgba(15, 15, 15, 0.2) 0px 9px 24px'] { + box-shadow: var(--theme--box-shadow_strong) !important; +} +.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: rgba(15, 15, 15, 0.1) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 2px 4px'] { + box-shadow: var(--theme--box-shadow) !important; +} + .notion-to_do-block > div [role='button']:hover, .notion-to_do-block > div [role='button']:hover .checkboxSquare, .notion-to_do-block > div [role='button']:hover .check { @@ -444,18 +475,38 @@ .notion-body:not(.dark) [style*='color: rgba(25, 23, 17, 0.6)'] { color: var(--theme--text_ui) !important; } +::placeholder { + opacity: 1 !important; +} +::placeholder, +[style*='-webkit-text-fill-color:'], .notion-body.dark [style*='color: rgba(255, 255, 255, 0.4)'], -.notion-body:not(.dark) [style*='color: rgba(55, 53, 47, 0.4)'] { +.notion-body.dark [style*='color: rgba(255, 255, 255, 0.4)']::before, +.notion-body:not(.dark) [style*='color: rgba(55, 53, 47, 0.4)'], +.notion-body:not(.dark) [style*='color: rgba(55, 53, 47, 0.4)']::before { color: var(--theme--text_ui_info) !important; + -webkit-text-fill-color: var(--theme--text_ui_info) !important; } .notion-body.dark [style*='fill: rgb(202, 204, 206)'] { fill: var(--theme--text) !important; } -.notion-body.dark [style*='fill: rgba(202, 204, 206,'], + +.notion-body.dark [style*='fill: rgba(255, 255, 255, 0.6)'], .notion-body:not(.dark) [style*='fill: rgba(55, 53, 47, 0.8)'], -.notion-body:not(.dark) [style*='fill: rgba(55, 53, 47,'] { +.notion-body:not(.dark) [style*='fill: rgba(55, 53, 47, 0.6)'], +.notion-body:not(.dark) [style*='fill: rgba(25, 23, 17, 0.6)'] { fill: var(--theme--text_ui) !important; } +.notion-body.dark [style*='fill: rgba(202, 204, 206, 0.6)'], +.notion-body.dark [style*='fill: rgba(202, 204, 206, 0.4)'], +.notion-body:not(.dark) [style*='fill: rgba(55, 53, 47, 0.4)'], +.notion-body:not(.dark) [style*='fill: rgba(55, 53, 47, 0.3)'] { + fill: var(--theme--text_ui_info) !important; +} +.notion-body.dark [style*='border-color:rgba(255,255,255,0.4);opacity:0.7'], +.notion-body:not(.dark) [style*='border-color:rgba(55,53,47,0.4);opacity:0.7'] { + border-color: var(--theme--text_ui_info) !important; +} .notion-body.dark [style*='caret-color: rgba(255, 255, 255, 0.9)'], .notion-body:not(.dark) [style*='caret-color: rgb(55, 53, 47)'] { caret-color: var(--theme--text) !important; diff --git a/mods/core/css/variables.css b/mods/core/css/variables.css index 76e4bbd..d394665 100644 --- a/mods/core/css/variables.css +++ b/mods/core/css/variables.css @@ -14,6 +14,10 @@ --theme_dark--sidebar: rgb(55, 60, 63); --theme_dark--overlay: rgba(15, 15, 15, 0.6); --theme_dark--dragarea: #272d2f; + --theme_dark--box-shadow: rgba(15, 15, 15, 0.2) 0px 0px 0px 1px, + rgba(15, 15, 15, 0.2) 0px 2px 4px; + --theme_dark--box-shadow_strong: rgba(15, 15, 15, 0.1) 0px 0px 0px 1px, + rgba(15, 15, 15, 0.2) 0px 3px 6px, rgba(15, 15, 15, 0.4) 0px 9px 24px; --theme_dark--page_normal-width: 900px; --theme_dark--page_full-width: 100%; --theme_dark--page-padding: calc(96px + env(safe-area-inset-left)); @@ -48,7 +52,9 @@ --theme_dark--card: rgb(63, 68, 71); --theme_dark--gallery: rgba(255, 255, 255, 0.05); + --theme_dark--select_input: rgb(55, 60, 63); --theme_dark--table-border: rgba(255, 255, 255, 0.1); + --theme_dark--ui-border: rgba(255, 255, 255, 0.07); --theme_dark--interactive_hover: rgb(71, 76, 80); --theme_dark--interactive_hover-border: transparent; --theme_dark--button_close: #e81123; @@ -189,6 +195,10 @@ --theme_light--sidebar: rgb(247, 246, 243); --theme_light--overlay: rgba(15, 15, 15, 0.6); --theme_light--dragarea: rgba(55, 53, 47, 0.04); + --theme_light--box-shadow: rgba(15, 15, 15, 0.1) 0px 0px 0px 1px, + rgba(15, 15, 15, 0.1) 0px 2px 4px; + --theme_light--box-shadow_strong: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, + rgba(15, 15, 15, 0.1) 0px 3px 6px, rgba(15, 15, 15, 0.2) 0px 9px 24px; --theme_light--page_normal-width: 900px; --theme_light--page_full-width: 100%; --theme_light--page-padding: calc(96px + env(safe-area-inset-left)); @@ -223,7 +233,9 @@ --theme_light--card: rgb(247, 247, 247); --theme_light--gallery: rgba(55, 53, 47, 0.024); + --theme_light--select_input: rgba(242, 241, 238, 0.6); --theme_light--table-border: rgba(55, 53, 47, 0.16); + --theme_light--ui-border: rgba(55, 53, 47, 0.09); --theme_light--interactive_hover: rgb(239, 239, 239); --theme_light--interactive_hover-border: transparent; --theme_light--button_close: #e81123; @@ -247,6 +259,7 @@ --theme_light--text: rgb(55, 53, 47); --theme_light--text_ui: rgba(55, 53, 47, 0.6); + --theme_light--text_ui: rgba(55, 53, 47, 0.6); --theme_light--text_ui_info: rgba(55, 53, 47, 0.4); --theme_light--text_gray: rgb(155, 154, 151); @@ -364,6 +377,8 @@ --theme--sidebar: var(--theme_dark--sidebar); --theme--overlay: var(--theme_dark--overlay); --theme--dragarea: var(--theme_dark--dragarea); + --theme--box-shadow: var(--theme_dark--box-shadow); + --theme--box-shadow_strong: var(--theme_dark--box-shadow_strong); --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); @@ -389,7 +404,9 @@ --theme--scrollbar_hover: var(--theme_dark--scrollbar_hover); --theme--card: var(--theme_dark--card); --theme--gallery: var(--theme_dark--gallery); + --theme--select_input: var(--theme_dark--select_input); --theme--table-border: var(--theme_dark--table-border); + --theme--ui-border: var(--theme_dark--ui-border); --theme--interactive_hover: var(--theme_dark--interactive_hover); --theme--interactive_hover-border: var( --theme_dark--interactive_hover-border @@ -524,6 +541,8 @@ --theme--sidebar: var(--theme_light--sidebar); --theme--overlay: var(--theme_light--overlay); --theme--dragarea: var(--theme_light--dragarea); + --theme--box-shadow: var(--theme_light--box-shadow); + --theme--box-shadow_strong: var(--theme_light--box-shadow_strong); --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); @@ -549,7 +568,9 @@ --theme--scrollbar_hover: var(--theme_light--scrollbar_hover); --theme--card: var(--theme_light--card); --theme--gallery: var(--theme_light--gallery); + --theme--select_input: var(--theme_light--select_input); --theme--table-border: var(--theme_light--table-border); + --theme--ui-border: var(--theme_light--ui-border); --theme--interactive_hover: var(--theme_light--interactive_hover); --theme--interactive_hover-border: var( --theme_light--interactive_hover-border diff --git a/mods/core/render.js b/mods/core/render.js index 619c91f..0ac5969 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -23,7 +23,7 @@ const url = require('url'), 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:"; + 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: enhancement: https: http:; 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: http:; frame-src https: http:; media-src https: http:"; document.head.appendChild(csp); `; diff --git a/mods/core/tray.js b/mods/core/tray.js index 25be7e9..2b50971 100644 --- a/mods/core/tray.js +++ b/mods/core/tray.js @@ -17,6 +17,8 @@ module.exports = (store, __exports) => { helpers = require('../../pkg/helpers.js'); electron.app.on('ready', () => { + // tray + tray = new electron.Tray( is_win ? path.resolve(`${__dirname}/icons/windows.ico`) @@ -28,6 +30,8 @@ module.exports = (store, __exports) => { }) ); + // menu + electron.ipcMain.on('enhancer:set-menu-theme', (event, arg) => { if (!enhancer_menu) return; enhancer_menu.webContents.send('enhancer:set-menu-theme', arg); @@ -111,6 +115,19 @@ module.exports = (store, __exports) => { }); } + electron.globalShortcut.register(store().menu_toggle, () => { + if ( + electron.BrowserWindow.getAllWindows() + .filter((win) => win.getTitle() !== 'notion-enhancer menu') + .some((win) => win.isFocused()) + ) { + openExtensionMenu(); + } else if (enhancer_menu && enhancer_menu.isFocused()) + enhancer_menu.close(); + }); + + // tray + const contextMenu = electron.Menu.buildFromTemplate([ { type: 'normal', @@ -185,6 +202,13 @@ module.exports = (store, __exports) => { { type: 'separator', }, + { + label: 'Relaunch', + click: () => { + electron.app.relaunch(); + electron.app.quit(); + }, + }, { label: 'Quit', role: 'quit', @@ -193,16 +217,7 @@ module.exports = (store, __exports) => { tray.setContextMenu(contextMenu); tray.setToolTip('Notion'); - electron.globalShortcut.register(store().menu_toggle, () => { - if ( - electron.BrowserWindow.getAllWindows() - .filter((win) => win.getTitle() !== 'notion-enhancer menu') - .some((win) => win.isFocused()) - ) { - openExtensionMenu(); - } else if (enhancer_menu && enhancer_menu.isFocused()) - enhancer_menu.close(); - }); + // hotkey function showWindows() { const windows = electron.BrowserWindow.getAllWindows(); diff --git a/package.json b/package.json index aaa8e97..a71d9c9 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "asar": "^3.0.3", "cac": "^6.5.12", "fs-extra": "^9.0.1", + "keyboardevent-from-electron-accelerator": "^2.0.0", "readdir-enhanced": "^6.0.3" } } diff --git a/pkg/apply.js b/pkg/apply.js index 168193a..586cb7a 100644 --- a/pkg/apply.js +++ b/pkg/apply.js @@ -120,7 +120,14 @@ module.exports = async function ({ overwrite_version, friendly_errors } = {}) { : `try running "sudo chmod a+wr -R ${err.path.replace( 'Notion.app', 'Notion' - )}"` + )}" ${ + err.dest + ? `and "sudo chmod a+wr -R ${err.dest.replace( + 'Notion.app', + 'Notion' + )}"` + : '' + }` }` ); } else if (['EIO', 'EBUSY'].includes(err.code) && friendly_errors) { diff --git a/pkg/remove.js b/pkg/remove.js index a9c3696..cb25f73 100644 --- a/pkg/remove.js +++ b/pkg/remove.js @@ -122,7 +122,14 @@ module.exports = async function ({ : `try running "sudo chmod a+wr -R ${err.path.replace( 'Notion.app', 'Notion' - )}"` + )}" ${ + err.dest + ? `and "sudo chmod a+wr -R ${err.dest.replace( + 'Notion.app', + 'Notion' + )}"` + : '' + }` }` ); } else if (['EIO', 'EBUSY'].includes(err.code) && friendly_errors) { diff --git a/yarn.lock b/yarn.lock index 42d4db4..0b9ca31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -143,6 +143,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +keyboardevent-from-electron-accelerator@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/keyboardevent-from-electron-accelerator/-/keyboardevent-from-electron-accelerator-2.0.0.tgz#ace21b1aa4e47148815d160057f9edb66567c50c" + integrity sha512-iQcmNA0M4ETMNi0kG/q0h/43wZk7rMeKYrXP7sqKIJbHkTU8Koowgzv+ieR/vWJbOwxx5nDC3UnudZ0aLSu4VA== + minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" From d75368b020fd404546f2bc0d4bbbdb466e89d0e3 Mon Sep 17 00:00:00 2001 From: dragonwocky <thedragonring.bod@gmail.com> Date: Sun, 11 Oct 2020 16:02:45 +1100 Subject: [PATCH 12/15] use keyup listeners instead of a globalShortcut for the enhancements menu toggle --- CHANGELOG.md | 1 + mods/core/client.js | 9 ++++++++- mods/core/menu.js | 18 ++++++++++++++++-- mods/core/tray.js | 14 +++----------- pkg/apply.js | 4 ++-- pkg/remove.js | 4 ++-- 6 files changed, 32 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 703bdcd..94a8738 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ a flexibility update. - new: relaunch button in tray menu. - improved: a core mod option to make transitions snappy/0s. - 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. - 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 7152958..4d683ca 100644 --- a/mods/core/client.js +++ b/mods/core/client.js @@ -13,11 +13,18 @@ module.exports = (store, __exports) => { notionIpc = require(`${helpers.__notion.replace( /\\/g, '/' - )}/app/helpers/notionIpc.js`); + )}/app/helpers/notionIpc.js`), + { toKeyEvent } = require('keyboardevent-from-electron-accelerator'); // additional hotkeys document.defaultView.addEventListener('keyup', (event) => { if (event.code === 'F5') location.reload(); + // open menu on hotkey toggle + const hotkey = toKeyEvent(store().menu_toggle); + let triggered = true; + for (let prop in hotkey) + if (hotkey[prop] !== event[prop]) triggered = false; + if (triggered) electron.ipcRenderer.send('enhancer:open-menu'); }); const attempt_interval = setInterval(enhance, 500); diff --git a/mods/core/menu.js b/mods/core/menu.js index d59481f..5925e28 100644 --- a/mods/core/menu.js +++ b/mods/core/menu.js @@ -10,7 +10,8 @@ const store = require('../../pkg/store.js'), helpers = require('../../pkg/helpers.js'), fs = require('fs-extra'), path = require('path'), - electron = require('electron'); + electron = require('electron'), + { toKeyEvent } = require('keyboardevent-from-electron-accelerator'); window['__start'] = async () => { const buttons = require('./buttons.js')(() => ({ @@ -141,9 +142,22 @@ window['__start'] = async () => { document.addEventListener('keyup', (event) => { if ( $popup.classList.contains('visible') && - [13, 27].includes(event.keyCode) + ['Enter', 'Escape'].includes(event.key) ) $popup.classList.remove('visible'); + // close window on hotkey toggle + console.log(); + const hotkey = toKeyEvent( + store('0f0bf8b6-eae6-4273-b307-8fc43f2ee082', { + menu_toggle: modules.loaded + .find((m) => m.id === '0f0bf8b6-eae6-4273-b307-8fc43f2ee082') + .options.find((o) => o.key === 'menu_toggle').value, + }).menu_toggle + ); + let triggered = true; + for (let prop in hotkey) + if (hotkey[prop] !== event[prop]) triggered = false; + if (triggered) electron.remote.getCurrentWindow().close(); }); let colorpicker_target = null; const $colorpicker = colorjoe diff --git a/mods/core/tray.js b/mods/core/tray.js index 2b50971..0fd4c04 100644 --- a/mods/core/tray.js +++ b/mods/core/tray.js @@ -32,6 +32,9 @@ module.exports = (store, __exports) => { // menu + electron.ipcMain.on('enhancer:open-menu', (event, arg) => { + openExtensionMenu(); + }); electron.ipcMain.on('enhancer:set-menu-theme', (event, arg) => { if (!enhancer_menu) return; enhancer_menu.webContents.send('enhancer:set-menu-theme', arg); @@ -115,17 +118,6 @@ module.exports = (store, __exports) => { }); } - electron.globalShortcut.register(store().menu_toggle, () => { - if ( - electron.BrowserWindow.getAllWindows() - .filter((win) => win.getTitle() !== 'notion-enhancer menu') - .some((win) => win.isFocused()) - ) { - openExtensionMenu(); - } else if (enhancer_menu && enhancer_menu.isFocused()) - enhancer_menu.close(); - }); - // tray const contextMenu = electron.Menu.buildFromTemplate([ diff --git a/pkg/apply.js b/pkg/apply.js index 586cb7a..efb34ff 100644 --- a/pkg/apply.js +++ b/pkg/apply.js @@ -117,12 +117,12 @@ module.exports = async function ({ overwrite_version, friendly_errors } = {}) { `file access forbidden - ${ process.platform === 'win32' ? 'make sure your user has elevated permissions.' - : `try running "sudo chmod a+wr -R ${err.path.replace( + : `try running "sudo chmod -R a+wr ${err.path.replace( 'Notion.app', 'Notion' )}" ${ err.dest - ? `and "sudo chmod a+wr -R ${err.dest.replace( + ? `and "sudo chmod -R a+wr ${err.dest.replace( 'Notion.app', 'Notion' )}"` diff --git a/pkg/remove.js b/pkg/remove.js index cb25f73..41cea0d 100644 --- a/pkg/remove.js +++ b/pkg/remove.js @@ -119,12 +119,12 @@ module.exports = async function ({ `file access forbidden - ${ process.platform === 'win32' ? 'make sure your user has elevated permissions.' - : `try running "sudo chmod a+wr -R ${err.path.replace( + : `try running "sudo chmod -R a+wr ${err.path.replace( 'Notion.app', 'Notion' )}" ${ err.dest - ? `and "sudo chmod a+wr -R ${err.dest.replace( + ? `and "sudo chmod -R a+wr ${err.dest.replace( 'Notion.app', 'Notion' )}"` From 3493bfac244ed486383f73e2008ab8ffcc7835d8 Mon Sep 17 00:00:00 2001 From: dragonwocky <thedragonring.bod@gmail.com> Date: Sun, 11 Oct 2020 23:31:09 +1100 Subject: [PATCH 13/15] enhancer icon next to tabs opens menu + less aggressive tab focusing so searching can actually work --- mods/core/css/tabs.css | 10 ++++++---- mods/core/render.js | 44 ++++++++++++++++++++++++++++-------------- pkg/apply.js | 2 +- pkg/remove.js | 2 +- 4 files changed, 38 insertions(+), 20 deletions(-) diff --git a/mods/core/css/tabs.css b/mods/core/css/tabs.css index 7de4934..250a01b 100644 --- a/mods/core/css/tabs.css +++ b/mods/core/css/tabs.css @@ -94,6 +94,8 @@ body, #titlebar button { color: var(--theme--text); -webkit-app-region: no-drag; + border: none; + background-color: transparent; } #titlebar .window-buttons-area { margin: 0.5em 0.55em 0.5em auto; @@ -102,10 +104,7 @@ body, display: none; } -#tabs { - margin-top: auto; -} -#tabs::before { +#open-enhancer-menu::before { content: ''; height: 1.25em; width: 1.25em; @@ -115,6 +114,9 @@ body, background-image: url('enhancement://core/icons/mac+linux.png'); background-repeat: no-repeat; } +#tabs { + margin-top: auto; +} #tabs .tab { display: inline-flex; background: var(--theme--main); diff --git a/mods/core/render.js b/mods/core/render.js index 0ac5969..5c7b6ab 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -42,6 +42,7 @@ module.exports = (store, __exports) => { this.$titlebar = null; this.$dragging = null; this.views = { + active: null, current: { $el: () => this.views.html[this.views.current.id], id: 0, @@ -189,15 +190,19 @@ module.exports = (store, __exports) => { this.setState({ tabs: list }, this.focusTab.bind(this)); } focusTab() { + if (this.views.active === this.views.current.id) return; this.loadListeners(); this.blurListeners(); this.focusListeners(); for (const id in this.views.loaded) { if (this.views.loaded.hasOwnProperty(id) && this.views.loaded[id]) { - this.views.loaded[id].style.display = - id == this.views.current.id && this.state.tabs.get(+id) - ? 'flex' - : 'none'; + const selected = + id == this.views.current.id && this.state.tabs.get(+id); + this.views.loaded[id].style.display = selected ? 'flex' : 'none'; + if (selected) { + this.views.active = this.views.current.id; + this.views.loaded[id].focus(); + } } } } @@ -216,15 +221,19 @@ module.exports = (store, __exports) => { } } 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'); + 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'); @@ -461,6 +470,12 @@ module.exports = (store, __exports) => { this.$titlebar = $titlebar; }, }, + React.createElement('button', { + id: 'open-enhancer-menu', + onClick: (e) => { + electron.ipcRenderer.send('enhancer:open-menu'); + }, + }), React.createElement( 'div', { id: 'tabs' }, @@ -556,8 +571,9 @@ module.exports = (store, __exports) => { ? 37 : 45) * this.state.zoomFactor, right: (48 - 24) * this.state.zoomFactor, - width: 440 * this.state.zoomFactor, + width: 460 * this.state.zoomFactor, height: 72 * this.state.zoomFactor, + zIndex: 99, }, }, React.createElement('webview', { diff --git a/pkg/apply.js b/pkg/apply.js index efb34ff..d773356 100644 --- a/pkg/apply.js +++ b/pkg/apply.js @@ -122,7 +122,7 @@ module.exports = async function ({ overwrite_version, friendly_errors } = {}) { 'Notion' )}" ${ err.dest - ? `and "sudo chmod -R a+wr ${err.dest.replace( + ? `and/or "sudo chmod -R a+wr ${err.dest.replace( 'Notion.app', 'Notion' )}"` diff --git a/pkg/remove.js b/pkg/remove.js index 41cea0d..de15650 100644 --- a/pkg/remove.js +++ b/pkg/remove.js @@ -124,7 +124,7 @@ module.exports = async function ({ 'Notion' )}" ${ err.dest - ? `and "sudo chmod -R a+wr ${err.dest.replace( + ? `and/or "sudo chmod -R a+wr ${err.dest.replace( 'Notion.app', 'Notion' )}"` From 45bc46aae48a1c999e45b049d88a410964a044f6 Mon Sep 17 00:00:00 2001 From: dragonwocky <thedragonring.bod@gmail.com> Date: Sun, 11 Oct 2020 23:38:03 +1100 Subject: [PATCH 14/15] change window title to match page name instead of just 'Notion Desktop' --- mods/core/render.js | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/mods/core/render.js b/mods/core/render.js index 5c7b6ab..44e3045 100644 --- a/mods/core/render.js +++ b/mods/core/render.js @@ -9,6 +9,7 @@ const url = require('url'), path = require('path'), electron = require('electron'), + browserWindow = electron.remote.getCurrentWindow(), { __notion } = require('../../pkg/helpers.js'), config = require(`${__notion}/app/config.js`), constants = require(`${__notion}/app/shared/constants.js`), @@ -218,6 +219,11 @@ module.exports = (store, __exports) => { ) { this.views.tabs[event.target.id].children[0].innerText = event.args[0]; + if ( + event.target.id == this.views.current.id && + browserWindow.getTitle() !== event.args[0] + ) + browserWindow.setTitle(event.args[0]); } } startSearch(isPeekView) { @@ -420,41 +426,25 @@ module.exports = (store, __exports) => { 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; - } const sendFullScreenChangeEvent = () => { notionIpc.sendIndexToNotion( $notion, 'notion:full-screen-changed' ); }; - electronWindow.addListener( + browserWindow.addListener( 'enter-full-screen', sendFullScreenChangeEvent ); - electronWindow.addListener( + browserWindow.addListener( 'leave-full-screen', sendFullScreenChangeEvent ); - electronWindow.addListener( + browserWindow.addListener( 'enter-html-full-screen', sendFullScreenChangeEvent ); - electronWindow.addListener( + browserWindow.addListener( 'leave-html-full-screen', sendFullScreenChangeEvent ); From add5bb8d9c58456e5d72c78d7b58bf55f665bf8f Mon Sep 17 00:00:00 2001 From: Alejandro Romano <alejandro9r@gmail.com> Date: Sun, 11 Oct 2020 16:27:16 -0300 Subject: [PATCH 15/15] Add font sizing to page previews (#153) Font sizes remained the same as default for page previews. They are not affected by custom font sizes. This change takes the same variables the full open page and apply it. Tested and working 10/10 Full open pages: .notion-frame Overlay, preview pages: .notion-overlay-container (and .notion-scroller.vertical WITHOUT .horizontal) --- mods/core/css/theme.css | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mods/core/css/theme.css b/mods/core/css/theme.css index 735fad2..faeac8f 100644 --- a/mods/core/css/theme.css +++ b/mods/core/css/theme.css @@ -152,7 +152,8 @@ [style*='SFMono-Regular'] { font-family: var(--theme--font_code) !important; } -.notion-frame .notion-page-block div[placeholder='Untitled'] { +.notion-frame .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; @@ -172,15 +173,16 @@ var(--theme--font_body-size) * (var(--theme--font_heading3-size) / 1em) ) !important; } -.notion-frame .notion-scroller.vertical.horizontal [style*='font-size: 14px'] { +.notion-frame .notion-scroller.vertical.horizontal [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-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-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=' '] {