From d5a38c80ea5e72556b8b7aa13da779669e7aafcd Mon Sep 17 00:00:00 2001
From: dragonwocky <thedragonring.bod@gmail.com>
Date: Sun, 5 Dec 2021 13:38:58 +1100
Subject: [PATCH] prevent topbar collapse, api.electron, treat menu as hideable
 window

---
 repo/always-on-top/button.mjs        |  4 +--
 repo/integrated-titlebar/buttons.css | 15 +++++++++
 repo/integrated-titlebar/buttons.mjs | 16 +++++-----
 repo/integrated-titlebar/client.mjs  | 13 +++++---
 repo/integrated-titlebar/menu.mjs    | 11 ++++---
 repo/menu/menu.mjs                   |  7 ++--
 repo/registry.json                   |  6 ++--
 repo/tabs/mod.json                   | 48 ++++++++++++++++++++++++++++
 repo/theming/patches.css             |  7 ++++
 repo/tray/client.mjs                 |  8 ++---
 repo/tray/createWindow.cjs           |  8 ++---
 repo/tray/main.cjs                   |  8 -----
 repo/view-scale/client.css           | 14 ++++----
 repo/view-scale/client.mjs           | 11 ++++---
 14 files changed, 123 insertions(+), 53 deletions(-)
 create mode 100644 repo/tabs/mod.json

diff --git a/repo/always-on-top/button.mjs b/repo/always-on-top/button.mjs
index 1d5dc91..ce2225e 100644
--- a/repo/always-on-top/button.mjs
+++ b/repo/always-on-top/button.mjs
@@ -32,11 +32,11 @@ export const createButton = async ({ web, components }, db) => {
 
   $pin.addEventListener('click', () => {
     $pin.replaceWith($unpin);
-    __enhancerElectronApi.browser.setAlwaysOnTop(true);
+    electron.browser.setAlwaysOnTop(true);
   });
   $unpin.addEventListener('click', () => {
     $unpin.replaceWith($pin);
-    __enhancerElectronApi.browser.setAlwaysOnTop(false);
+    electron.browser.setAlwaysOnTop(false);
   });
 
   return $button;
diff --git a/repo/integrated-titlebar/buttons.css b/repo/integrated-titlebar/buttons.css
index 68abbf0..7eac2c9 100644
--- a/repo/integrated-titlebar/buttons.css
+++ b/repo/integrated-titlebar/buttons.css
@@ -9,6 +9,7 @@
   display: block;
   -webkit-app-region: drag;
   background: var(--theme--bg_secondary);
+  height: var(--integrated_titlebar--dragarea-height);
 }
 
 .integrated_titlebar--buttons {
@@ -56,3 +57,17 @@
   background: var(--theme--accent_red);
   color: var(--theme--accent_red-text);
 }
+
+.notion-update-sidebar [style*='margin-top: 45px;'] {
+  margin-top: calc(45px + var(--integrated_titlebar--dragarea-height, 0px)) !important;
+}
+.notion-topbar {
+  height: calc(45px + var(--integrated_titlebar--dragarea-height, 0px)) !important;
+}
+.notion-frame {
+  height: calc(100vh - 45px - var(--integrated_titlebar--dragarea-height, 0px)) !important;
+}
+
+body > .body-container {
+  height: calc(100% - var(--integrated_titlebar--dragarea-height, 0px)) !important;
+}
diff --git a/repo/integrated-titlebar/buttons.mjs b/repo/integrated-titlebar/buttons.mjs
index f8f04db..e0f3fe0 100644
--- a/repo/integrated-titlebar/buttons.mjs
+++ b/repo/integrated-titlebar/buttons.mjs
@@ -6,7 +6,7 @@
 
 'use strict';
 
-export const createWindowButtons = async ({ web, components }, db) => {
+export const createWindowButtons = async ({ electron, web, components }, db) => {
   let minimizeIcon = (await db.get(['minimize_icon'])) || (await components.feather('minus')),
     maximizeIcon = (await db.get(['maximize_icon'])) || (await components.feather('maximize')),
     unmaximizeIcon =
@@ -48,21 +48,21 @@ export const createWindowButtons = async ({ web, components }, db) => {
       ${closeIcon}
     </button>`;
 
-  $minimize.addEventListener('click', () => __enhancerElectronApi.browser.minimize());
-  $maximize.addEventListener('click', () => __enhancerElectronApi.browser.maximize());
-  $unmaximize.addEventListener('click', () => __enhancerElectronApi.browser.unmaximize());
-  $close.addEventListener('click', () => __enhancerElectronApi.browser.close());
-  __enhancerElectronApi.browser.on('maximize', () => {
+  $minimize.addEventListener('click', () => electron.browser.minimize());
+  $maximize.addEventListener('click', () => electron.browser.maximize());
+  $unmaximize.addEventListener('click', () => electron.browser.unmaximize());
+  $close.addEventListener('click', () => electron.browser.close());
+  electron.browser.on('maximize', () => {
     $maximize.replaceWith($unmaximize);
   });
-  __enhancerElectronApi.browser.on('unmaximize', () => {
+  electron.browser.on('unmaximize', () => {
     $unmaximize.replaceWith($maximize);
   });
 
   web.render(
     $windowButtons,
     $minimize,
-    __enhancerElectronApi.browser.isMaximized() ? $unmaximize : $maximize,
+    electron.browser.isMaximized() ? $unmaximize : $maximize,
     $close
   );
   return $windowButtons;
diff --git a/repo/integrated-titlebar/client.mjs b/repo/integrated-titlebar/client.mjs
index 75eef97..4b91f06 100644
--- a/repo/integrated-titlebar/client.mjs
+++ b/repo/integrated-titlebar/client.mjs
@@ -9,7 +9,7 @@
 import { createWindowButtons } from './buttons.mjs';
 
 export default async function (api, db) {
-  const { web } = api,
+  const { web, electron } = api,
     tilingMode = await db.get(['tiling']),
     dragareaHeight = await db.get(['dragarea_height']),
     sidebarSelector = '.notion-sidebar',
@@ -32,20 +32,23 @@ export default async function (api, db) {
           : '0px';
     if (newSidebarWidth !== sidebarWidth) {
       sidebarWidth = newSidebarWidth;
-      __enhancerElectronApi.sendMessageToHost('sidebar-width', sidebarWidth);
+      electron.sendMessageToHost('sidebar-width', sidebarWidth);
     }
     if (newPanelWidth !== panelWidth) {
       panelWidth = newPanelWidth;
-      __enhancerElectronApi.sendMessageToHost('panel-width', panelWidth);
+      electron.sendMessageToHost('panel-width', panelWidth);
     }
   };
   web.addDocumentObserver(updateDragareaOffsets);
 
   await web.whenReady([topbarSelector, topbarActionsSelector]);
   const $topbar = document.querySelector(topbarSelector),
-    $dragarea = web.html`<div class="integrated_titlebar--dragarea" style="height:${dragareaHeight}px"></div>`;
-  $topbar.style.height = `${45 + dragareaHeight}px`;
+    $dragarea = web.html`<div class="integrated_titlebar--dragarea"></div>`;
   $topbar.prepend($dragarea);
+  document.documentElement.style.setProperty(
+    '--integrated_titlebar--dragarea-height',
+    dragareaHeight + 'px'
+  );
 
   const $topbarActions = document.querySelector(topbarActionsSelector),
     $windowButtons = await createWindowButtons(api, db);
diff --git a/repo/integrated-titlebar/menu.mjs b/repo/integrated-titlebar/menu.mjs
index 2ca7391..da86839 100644
--- a/repo/integrated-titlebar/menu.mjs
+++ b/repo/integrated-titlebar/menu.mjs
@@ -12,15 +12,16 @@ export default async function (api, db) {
   const { web } = api,
     tilingMode = await db.get(['tiling']),
     dragareaHeight = await db.get(['dragarea_height']),
-    bodyContainerSelector = '.body-container',
     sidebarSelector = '.sidebar';
   if (tilingMode) return;
 
-  await web.whenReady([bodyContainerSelector, sidebarSelector]);
-  const $bodyContainer = document.querySelector(bodyContainerSelector),
-    $dragarea = web.html`<div class="integrated_titlebar--dragarea" style="height:${dragareaHeight}px"></div>`;
+  await web.whenReady([sidebarSelector]);
+  const $dragarea = web.html`<div class="integrated_titlebar--dragarea"></div>`;
   document.body.prepend($dragarea);
-  $bodyContainer.style.height = `calc(100% - ${dragareaHeight}px)`;
+  document.documentElement.style.setProperty(
+    '--integrated_titlebar--dragarea-height',
+    dragareaHeight + 'px'
+  );
 
   const $sidebar = document.querySelector(sidebarSelector),
     $windowButtons = await createWindowButtons(api, db);
diff --git a/repo/menu/menu.mjs b/repo/menu/menu.mjs
index 374818f..c9968f3 100644
--- a/repo/menu/menu.mjs
+++ b/repo/menu/menu.mjs
@@ -13,7 +13,7 @@ import * as router from './router.mjs';
 import './styles.mjs';
 
 (async () => {
-  const { env, fs, storage, registry, web, components } = api;
+  const { env, fs, storage, electron, registry, web, components } = api;
 
   for (const mod of await registry.list((mod) => registry.enabled(mod.id))) {
     for (const sheet of mod.css?.menu || []) {
@@ -28,11 +28,14 @@ import './styles.mjs';
   if (errors.length) {
     console.log('[notion-enhancer] registry errors:');
     console.table(errors);
-    notifications.add({
+    const $errNotification = await notifications.add({
       icon: 'alert-circle',
       message: 'Failed to load mods (check console).',
       color: 'red',
     });
+    if (['win32', 'linux', 'darwin'].includes(env.name)) {
+      $errNotification.addEventListener('click', () => electron.browser.openDevTools());
+    }
   }
 
   const db = await registry.db('a6621988-551d-495a-97d8-3c568bca2e9e'),
diff --git a/repo/registry.json b/repo/registry.json
index 0656bd5..b861688 100644
--- a/repo/registry.json
+++ b/repo/registry.json
@@ -3,13 +3,15 @@
   "theming",
   "components",
 
+  "tweaks",
+  "font-chooser",
+
   "integrated-titlebar",
   "tray",
+  "tabs",
   "always-on-top",
   "view-scale",
 
-  "tweaks",
-  "font-chooser",
   "outliner",
   "scroll-to-top",
   "indentation-lines",
diff --git a/repo/tabs/mod.json b/repo/tabs/mod.json
new file mode 100644
index 0000000..c418628
--- /dev/null
+++ b/repo/tabs/mod.json
@@ -0,0 +1,48 @@
+{
+  "name": "tabs",
+  "id": "e1692c29-475e-437b-b7ff-3eee872e1a42",
+  "environments": ["linux", "win32", "darwin"],
+  "version": "0.3.0",
+  "description": "open multiple notion pages in a single window.",
+  "tags": ["extension", "app"],
+  "authors": [
+    {
+      "name": "dragonwocky",
+      "email": "thedragonring.bod@gmail.com",
+      "homepage": "https://dragonwocky.me/",
+      "avatar": "https://dragonwocky.me/avatar.jpg"
+    }
+  ],
+  "css": {},
+  "js": {},
+  "options": [
+    {
+      "key": "select_modifier",
+      "label": "tab select modifier",
+      "tooltip": "**usage: `Modifier+1` to `Modifier+9`, `Modifier+ArrowLeft` and `Modifier+ArrowRight`**",
+      "type": "select",
+      "values": [
+        "Alt",
+        "Command",
+        "Control",
+        "Super",
+        "Alt+Shift",
+        "Command+Shift",
+        "Control+Shift",
+        "Super+Shift"
+      ]
+    },
+    {
+      "type": "hotkey",
+      "key": "new_tab",
+      "label": "new tab hotkey",
+      "value": "Control+T"
+    },
+    {
+      "type": "hotkey",
+      "key": "close_tab",
+      "label": "close tab hotkey",
+      "value": "Control+W"
+    }
+  ]
+}
diff --git a/repo/theming/patches.css b/repo/theming/patches.css
index 59511db..36ce28e 100644
--- a/repo/theming/patches.css
+++ b/repo/theming/patches.css
@@ -95,6 +95,13 @@
   background: transparent !important;
 }
 
+.notion-topbar-action-buttons {
+  width: auto !important;
+}
+.notion-cursor-listener > [style*='z-index: 102'] {
+  z-index: 99 !important;
+}
+
 /* typography */
 
 [style*='Segoe UI'] {
diff --git a/repo/tray/client.mjs b/repo/tray/client.mjs
index c4b934a..cc2bd0d 100644
--- a/repo/tray/client.mjs
+++ b/repo/tray/client.mjs
@@ -4,14 +4,14 @@
  * (https://notion-enhancer.github.io/) under the MIT license
  */
 
-export default async function ({ env, web }, db) {
+export default async function ({ electron, env, web }, db) {
   const runInBackground = await db.get(['run_in_background']);
   if (!runInBackground) return;
 
   // force new window creation on create new window hotkey
   // hotkey is built into notion, so can't be changed,
   // but is broken by this mod's window duplication prevention
-  web.addHotkeyListener([env.name === 'darwin' ? 'Meta' : 'Ctrl', 'Shift', 'N'], () => {
-    __enhancerElectronApi.sendMessage('create-new-window');
-  });
+  web.addHotkeyListener([env.name === 'darwin' ? 'Meta' : 'Ctrl', 'Shift', 'N'], () =>
+    electron.sendMessage('create-new-window')
+  );
 }
diff --git a/repo/tray/createWindow.cjs b/repo/tray/createWindow.cjs
index b339cd3..4756313 100644
--- a/repo/tray/createWindow.cjs
+++ b/repo/tray/createWindow.cjs
@@ -8,13 +8,12 @@
 
 module.exports = async function ({ env }, db, __exports, __eval) {
   const electron = require('electron'),
-    { isMenuOpen } = require('notion-enhancer/worker.cjs'),
     urlHelpers = env.notionRequire('helpers/urlHelpers'),
     runInBackground = await db.get(['run_in_background']);
   if (!runInBackground) return;
 
   let appQuit = false;
-  electron.app.on('before-quit', () => {
+  electron.app.once('before-quit', () => {
     appQuit = true;
   });
 
@@ -27,9 +26,8 @@ module.exports = async function ({ env }, db, __exports, __eval) {
       // hijack close event to hide instead
       const window = notionCreateWindow(relativeUrl, args);
       window.prependListener('close', (e) => {
-        const isLastNotionWindow =
-          electron.BrowserWindow.getAllWindows().length === (isMenuOpen() ? 2 : 1);
-        if (!appQuit && isLastNotionWindow) {
+        const isLastWindow = electron.BrowserWindow.getAllWindows().length === 1;
+        if (!appQuit && isLastWindow) {
           window.hide();
           e.preventDefault();
           throw new Error('<fake error>: prevent window close');
diff --git a/repo/tray/main.cjs b/repo/tray/main.cjs
index 813ff8b..15b49fa 100644
--- a/repo/tray/main.cjs
+++ b/repo/tray/main.cjs
@@ -105,11 +105,3 @@ module.exports = async function ({ env, registry }, db, __exports, __eval) {
   ]);
   tray.setContextMenu(contextMenu);
 };
-
-// hide on open
-// maybe only do once to hide first window?
-
-// exports.createWindow = (...args) => {
-//   warmWindowState.warmedWindow = true;
-//   createWindow(...args);
-// };
diff --git a/repo/view-scale/client.css b/repo/view-scale/client.css
index 72ade4c..5fe2128 100644
--- a/repo/view-scale/client.css
+++ b/repo/view-scale/client.css
@@ -9,7 +9,7 @@
   border: 1px solid var(--theme--ui_divider);
   border-radius: 9999px !important;
   margin: 0 4px;
-  padding: 0 4px;
+  padding: 0 5px 0 4px;
   align-items: center;
   justify-content: center;
   display: flex;
@@ -51,7 +51,7 @@
 
 .view_scale--counter {
   font-size: 14px;
-  margin: auto 0;
+  margin: auto 4px auto 0;
   width: 5ch;
   text-align: right;
 }
@@ -64,9 +64,9 @@
   align-items: center;
   justify-content: center;
   flex-shrink: 0;
-  border-radius: 3px;
-  height: 28px;
-  width: 33px;
+  border-radius: 9999px;
+  height: 20px;
+  width: 20px;
   padding: 0 0.25px 0 0;
 
   margin-left: 2px;
@@ -83,6 +83,6 @@
 }
 .view_scale--button svg {
   display: block;
-  width: 20px;
-  height: 20px;
+  width: 14px;
+  height: 14px;
 }
diff --git a/repo/view-scale/client.mjs b/repo/view-scale/client.mjs
index d48aa9b..d1ebf84 100644
--- a/repo/view-scale/client.mjs
+++ b/repo/view-scale/client.mjs
@@ -5,16 +5,16 @@
  * (https://notion-enhancer.github.io/) under the MIT license
  */
 
-export default async function ({ web, components }, db) {
+export default async function ({ electron, web, components }, db) {
   let zoomFactor = (await db.get(['default_zoom'])) / 100,
     updateScale = () => {};
-  __enhancerElectronApi.webFrame.setZoomFactor(zoomFactor);
+  electron.webFrame.setZoomFactor(zoomFactor);
 
   const zoomOffset = (await db.get(['offset'])) / 100,
     zoomMin = 0.5,
     zoomMax = 2,
-    getZoomFactor = () => __enhancerElectronApi.webFrame.getZoomFactor(),
-    setZoomFactor = (zoomFactor) => __enhancerElectronApi.webFrame.setZoomFactor(zoomFactor),
+    getZoomFactor = () => electron.webFrame.getZoomFactor(),
+    setZoomFactor = (zoomFactor) => electron.webFrame.setZoomFactor(zoomFactor),
     zoomPlus = (multiplier = 1) => {
       zoomFactor = Math.min(getZoomFactor() + zoomOffset * multiplier, zoomMax);
       setZoomFactor(zoomFactor);
@@ -42,7 +42,8 @@ export default async function ({ web, components }, db) {
 
   const showVisualSlider = await db.get(['ui']);
   if (showVisualSlider) {
-    const topbarActionsSelector = '.notion-topbar-action-buttons';
+    const topbarActionsSelector =
+      '.notion-topbar-action-buttons > div[style="display: flex;"]';
     await web.whenReady([topbarActionsSelector]);
 
     const $topbarActions = document.querySelector(topbarActionsSelector),