From ea53f672ee86b84de093f41bd230956e68f036b4 Mon Sep 17 00:00:00 2001
From: dragonwocky <thedragonring.bod@gmail.com>
Date: Thu, 30 Sep 2021 20:59:32 +1000
Subject: [PATCH] options in menu sidebar + new hotkey input

---
 extension/api/_.mjs                           |   4 +-
 extension/api/env.mjs                         |   4 +-
 extension/api/registry.mjs                    |   4 +-
 extension/api/storage.mjs                     |   6 +-
 extension/api/web.mjs                         |  25 +-
 .../mod.json                                  |  59 +-
 .../client.css                                |   2 +-
 .../client.mjs                                |   5 +-
 .../markdown.css                              |   4 +-
 .../menu-old.css                              | 513 ------------------
 .../menu.mjs                                  | 322 +++++++++--
 .../mod.json                                  |   6 +-
 .../styles.mjs                                |  62 ++-
 .../theme.css                                 |  20 +-
 .../variables.css                             |   8 +-
 extension/worker.js                           |  10 +-
 16 files changed, 416 insertions(+), 638 deletions(-)
 delete mode 100644 extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu-old.css

diff --git a/extension/api/_.mjs b/extension/api/_.mjs
index bd0e39d..b56733e 100644
--- a/extension/api/_.mjs
+++ b/extension/api/_.mjs
@@ -10,13 +10,13 @@
 
 /** environment-specific methods and constants */
 export * as env from './env.mjs';
+/** environment-specific filesystem reading */
+export * as fs from './fs.mjs';
 /** environment-specific data persistence */
 export * as storage from './storage.mjs';
 
 /** helpers for formatting or parsing text */
 export * as fmt from './fmt.mjs';
-/** environment-specific filesystem reading */
-export * as fs from './fs.mjs';
 /** interactions with the enhancer's repository of mods */
 export * as registry from './registry.mjs';
 /** pattern and type validators */
diff --git a/extension/api/env.mjs b/extension/api/env.mjs
index db7be08..59ebc88 100644
--- a/extension/api/env.mjs
+++ b/extension/api/env.mjs
@@ -15,13 +15,13 @@
  * the environment/platform name code is currently being executed in
  * @constant {string}
  */
-export const name = 'extension';
+export const name = 'chrome';
 
 /**
  * all environments/platforms currently supported by the enhancer
  * @constant {array<string>}
  */
-export const supported = ['linux', 'win32', 'darwin', 'extension'];
+export const supported = ['linux', 'win32', 'darwin', 'chrome', 'firefox'];
 
 /**
  * the current version of the enhancer
diff --git a/extension/api/registry.mjs b/extension/api/registry.mjs
index 910d4ae..d79a694 100644
--- a/extension/api/registry.mjs
+++ b/extension/api/registry.mjs
@@ -26,7 +26,7 @@ export const core = [
 ];
 
 /** all available configuration types */
-export const optionTypes = ['toggle', 'select', 'text', 'number', 'color', 'file'];
+export const optionTypes = ['toggle', 'select', 'text', 'number', 'color', 'file', 'hotkey'];
 
 /** the root database for the current profile */
 export const profile = storage.db([
@@ -201,6 +201,7 @@ async function validate(mod) {
               );
               break;
             case 'text':
+            case 'hotkey':
               tests.push(check('options.option.value', option.value, 'string'));
               break;
             case 'number':
@@ -299,6 +300,7 @@ export const optionDefault = async (id, key) => {
     case 'text':
     case 'number':
     case 'color':
+    case 'hotkey':
       return opt.value;
     case 'select':
       return opt.values[0];
diff --git a/extension/api/storage.mjs b/extension/api/storage.mjs
index 15a63a2..848646b 100644
--- a/extension/api/storage.mjs
+++ b/extension/api/storage.mjs
@@ -24,7 +24,7 @@ export const get = (path, fallback = undefined) => {
   if (!path.length) return fallback;
   const namespace = path.shift();
   return new Promise((res, rej) =>
-    chrome.storage.sync.get(async (values) => {
+    chrome.storage.local.get(async (values) => {
       let value = values[namespace];
       do {
         if (value === undefined) {
@@ -54,7 +54,7 @@ export const set = (path, value) => {
       }
       const pathClone = [...path],
         namespace = path.shift();
-      chrome.storage.sync.get(async (values) => {
+      chrome.storage.local.get(async (values) => {
         const update = values[namespace] ?? {};
         let pointer = update,
           old;
@@ -68,7 +68,7 @@ export const set = (path, value) => {
           pointer[key] = pointer[key] ?? {};
           pointer = pointer[key];
         }
-        chrome.storage.sync.set({ [namespace]: update }, () => {
+        chrome.storage.local.set({ [namespace]: update }, () => {
           _onChangeListeners.forEach((listener) =>
             listener({ type: 'set', path: pathClone, new: value, old })
           );
diff --git a/extension/api/web.mjs b/extension/api/web.mjs
index c4ab25c..2439cf4 100644
--- a/extension/api/web.mjs
+++ b/extension/api/web.mjs
@@ -190,7 +190,8 @@ export const tooltip = ($ref, text) => {
         color: var(--theme--ui_tooltip-description);
       }
     </style>`;
-    render(document.head, _$tooltip, _$tooltipStylesheet);
+    render(document.head, _$tooltipStylesheet);
+    render(document.body, _$tooltip);
   }
   text = md.render(text);
   $ref.addEventListener('mouseover', (event) => {
@@ -199,8 +200,7 @@ export const tooltip = ($ref, text) => {
   });
   $ref.addEventListener('mousemove', (event) => {
     _$tooltip.style.top = event.clientY - _$tooltip.clientHeight + 'px';
-    _$tooltip.style.left =
-      event.clientX < window.innerWidth / 2 ? event.clientX + 20 + 'px' : '';
+    _$tooltip.style.left = event.clientX - _$tooltip.clientWidth + 'px';
   });
   $ref.addEventListener('mouseout', (event) => {
     _$tooltip.style.display = '';
@@ -218,20 +218,23 @@ export const addHotkeyListener = (keys, callback) => {
   if (typeof keys === 'string') keys = keys.split('+');
   if (!_hotkeyEvent) {
     _hotkeyEvent = document.addEventListener('keyup', (event) => {
+      if (document.activeElement.nodeName === 'INPUT') return;
       for (const hotkey of _hotkeyEventListeners) {
-        const matchesEvent = hotkey.keys.every((key) => {
+        const pressed = hotkey.keys.every((key) => {
+          key = key.toLowerCase();
           const modifiers = {
-            altKey: 'alt',
-            ctrlKey: 'ctrl',
-            metaKey: 'meta',
-            shiftKey: 'shift',
+            metaKey: ['meta', 'os', 'win', 'cmd', 'command'],
+            ctrlKey: ['ctrl', 'control'],
+            shiftKey: ['shift'],
+            altKey: ['alt'],
           };
           for (const modifier in modifiers) {
-            if (key.toLowerCase() === modifiers[modifier] && event[modifier]) return true;
+            const pressed = modifiers[modifier].includes(key) && event[modifier];
+            if (pressed) return true;
           }
-          if (key.toLowerCase() === event.key.toLowerCase()) return true;
+          if (key === event.key.toLowerCase()) return true;
         });
-        if (matchesEvent) hotkey.callback();
+        if (pressed) hotkey.callback();
       }
     });
   }
diff --git a/extension/repo/bypass-preview@cb6fd684-f113-4a7a-9423-8f0f0cff069f/mod.json b/extension/repo/bypass-preview@cb6fd684-f113-4a7a-9423-8f0f0cff069f/mod.json
index 1d0cfb4..042abe5 100644
--- a/extension/repo/bypass-preview@cb6fd684-f113-4a7a-9423-8f0f0cff069f/mod.json
+++ b/extension/repo/bypass-preview@cb6fd684-f113-4a7a-9423-8f0f0cff069f/mod.json
@@ -3,6 +3,7 @@
   "id": "cb6fd684-f113-4a7a-9423-8f0f0cff069f",
   "version": "0.2.0",
   "description": "go straight to the normal full view when opening a page.",
+  "preview": "https://cdn.pixabay.com/photo/2021/09/17/15/17/fruit-6633086_960_720.jpg",
   "tags": ["extension", "automation"],
   "authors": [
     {
@@ -10,6 +11,12 @@
       "email": "thedragonring.bod@gmail.com",
       "homepage": "https://dragonwocky.me/",
       "avatar": "https://dragonwocky.me/avatar.jpg"
+    },
+    {
+      "name": "fake person",
+      "email": "thedragonring.bod@gmail.com",
+      "homepage": "https://dragonwocky.me/",
+      "avatar": "https://cdn.pixabay.com/photo/2015/04/20/13/28/lizard-731336_960_720.jpg"
     }
   ],
   "js": {
@@ -18,5 +25,55 @@
   "css": {
     "client": ["client.css"]
   },
-  "options": []
+  "options": [
+    {
+      "type": "toggle",
+      "key": "toggle",
+      "label": "toggle",
+      "tooltip": "toggle",
+      "value": true
+    },
+    {
+      "type": "select",
+      "key": "select",
+      "label": "select",
+      "tooltip": "select",
+      "values": ["option A", "option B", "option C"]
+    },
+    {
+      "type": "text",
+      "key": "text",
+      "label": "text",
+      "tooltip": "text",
+      "value": "default"
+    },
+    {
+      "type": "hotkey",
+      "key": "hotkey",
+      "label": "hotkey",
+      "tooltip": "hotkey",
+      "value": "Ctrl+Shift+H"
+    },
+    {
+      "type": "number",
+      "key": "number",
+      "label": "number",
+      "tooltip": "number",
+      "value": 14
+    },
+    {
+      "type": "color",
+      "key": "color",
+      "label": "color",
+      "tooltip": "color",
+      "value": "rgba(125, 26, 250, 0.7)"
+    },
+    {
+      "type": "file",
+      "key": "file",
+      "label": "file",
+      "tooltip": "file",
+      "extensions": [".css"]
+    }
+  ]
 }
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.css b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.css
index 75087fb..e21c00a 100644
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.css
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.css
@@ -9,7 +9,7 @@
   -webkit-user-select: none;
   transition: background 20ms ease-in 0s;
   cursor: pointer;
-  color: var(--theme--text_ui);
+  color: var(--theme--text_secondary);
 }
 .enhancer--sidebarMenuLink:hover {
   background: var(--theme--ui_interactive-hover);
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.mjs b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.mjs
index d7b15db..5ed2368 100644
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.mjs
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/client.mjs
@@ -14,9 +14,10 @@ export default async function (api, db) {
   const updateTheme = () =>
     db.set(['theme'], document.querySelector('.notion-dark-theme') ? 'dark' : 'light');
   web.addDocumentObserver((mutation) => {
-    if (mutation.target === document.body) updateTheme();
+    if (mutation.target === document.body && document.hasFocus()) updateTheme();
   });
-  updateTheme();
+  if (document.hasFocus()) updateTheme();
+  document.addEventListener('visibilitychange', updateTheme);
 
   const sidebarSelector = '.notion-sidebar-container .notion-sidebar > div:nth-child(4)';
   await web.whenReady([sidebarSelector]);
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/markdown.css b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/markdown.css
index b2247b7..dc41b90 100644
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/markdown.css
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/markdown.css
@@ -49,7 +49,7 @@
 .markdown.markdown-inline a {
   opacity: 0.7;
   text-decoration: none;
-  border-bottom: 0.05em solid var(--theme--text_ui);
+  border-bottom: 0.05em solid var(--theme--text_secondary);
 }
 .markdown.markdown-inline a:hover {
   opacity: 0.9;
@@ -145,7 +145,7 @@
 }
 .markdown .code-toolbar .toolbar-item > * {
   padding: 0.25rem 0.35rem;
-  color: var(--theme--text_ui);
+  color: var(--theme--text_secondary);
   font-size: 11px;
   font-family: inherit;
 }
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu-old.css b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu-old.css
deleted file mode 100644
index 98f4498..0000000
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu-old.css
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * notion-enhancer core: menu
- * (c) 2021 dragonwocky <thedragonring.bod@gmail.com> (https://dragonwocky.me/)
- * (https://notion-enhancer.github.io/) under the MIT license
- */
-
-* {
-  box-sizing: border-box;
-  word-break: break-word;
-  text-size-adjust: 100%;
-  -webkit-text-size-adjust: 100%;
-  font-size: inherit;
-  font-family: inherit;
-  fill: currentColor;
-}
-
-html {
-  transition: opacity 50ms ease-out;
-  font-size: var(--theme--font_body-size);
-}
-html[class] {
-  opacity: 1 !important;
-}
-
-body {
-  padding: 2rem 2.5rem;
-  position: relative;
-  margin: 0;
-  background: var(--theme--sidebar);
-  color: var(--theme--text);
-  font-family: var(--theme--font_sans);
-  min-height: 100vh;
-}
-body a {
-  color: inherit;
-}
-
-header {
-  display: flex;
-  flex-wrap: wrap;
-  margin-bottom: 1.25rem;
-}
-header > * {
-  margin: 0 1.25rem 0.1em 0;
-  font-size: var(--theme--font_heading1-size);
-}
-header h1 a {
-  text-decoration: none;
-}
-header h1 img {
-  width: 0.95em;
-  height: 0.95em;
-  margin-right: 0.5em;
-  margin-bottom: -0.1em;
-}
-header h1 svg {
-  width: 1em;
-  height: 1em;
-  padding-top: 0.3em;
-  margin-right: 0.2em;
-}
-header h1 svg[data-icon='info'] {
-  margin-right: 0em;
-}
-header h1 svg[data-icon='code'] {
-  margin-right: 0.3em;
-}
-
-img[data-view-target='notion'] {
-  cursor: pointer;
-}
-
-main {
-  display: grid;
-  grid-gap: 1.25em;
-  grid-template-columns: 1fr;
-  opacity: 1;
-  transition: opacity 200ms ease-out;
-}
-@media (min-width: 550px) {
-  main {
-    grid-template-columns: 1fr 1fr;
-  }
-  main > .action--buttons {
-    grid-column: span 2;
-  }
-  [data-view='mod'] main .library--card,
-  .documentation--body {
-    max-height: calc(100vh - 10rem);
-    overflow-y: auto;
-  }
-  [data-view='mod'] {
-    overflow: hidden;
-    height: 100vh;
-  }
-}
-@media (min-width: 850px) {
-  main {
-    grid-template-columns: 1fr 1fr 1fr;
-  }
-  main > .action--buttons {
-    grid-column: span 3;
-  }
-  [data-view='mod'] main > .documentation--body {
-    grid-column: span 2;
-  }
-}
-@media (min-width: 1350px) {
-  main {
-    grid-template-columns: 1fr 1fr 1fr 1fr;
-  }
-  main > .action--buttons {
-    grid-column: span 4;
-  }
-  [data-view='mod'] main > .documentation--body {
-    grid-column: span 3;
-  }
-}
-@media (min-width: 2050px) {
-  main {
-    grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
-  }
-  main > .action--buttons {
-    grid-column: span 5;
-  }
-  [data-view='mod'] main > .documentation--body {
-    grid-column: span 4;
-  }
-}
-main article {
-  border-radius: 5px;
-  box-shadow: rgb(0 0 0 / 10%) 0px 20px 25px -5px, rgb(0 0 0 / 4%) 0px 10px 10px -5px;
-  border: 1px solid var(--theme--divider);
-  background: var(--theme--page);
-}
-main article img {
-  max-width: 100%;
-}
-
-.action--buttons,
-.library--expand {
-  margin: 0;
-  display: flex;
-  flex-wrap: wrap;
-  gap: 0.53em;
-}
-.library--expand a {
-  margin-left: auto;
-}
-.action--buttons a,
-.library--expand a {
-  border-radius: 3px;
-  padding: 0.35rem 0.45rem;
-  text-decoration: none;
-  display: flex;
-}
-.action--buttons .action--alert {
-  cursor: pointer;
-  border-radius: 3px;
-  padding: 0.35rem 0.45rem;
-  background: var(--theme--block_grey);
-  color: var(--theme--block_grey-text);
-  border: none;
-  pointer-events: none;
-  opacity: 0;
-  transition: opacity 200ms ease-in-out;
-}
-.action--buttons .action--alert[data-triggered] {
-  pointer-events: all;
-  opacity: 1;
-}
-.action--buttons .action--alert[data-triggered]:hover {
-  background: none;
-  color: var(--theme--block_grey-text);
-  box-shadow: var(--theme--block_grey) 0px 0px 0px 1px inset;
-}
-.action--buttons span,
-.library--expand span {
-  color: var(--theme--text_property);
-}
-.action--buttons a:hover,
-.action--buttons a.action--active,
-.library--expand a:hover {
-  background: var(--theme--button-hover);
-}
-.action--buttons svg,
-.library--expand svg {
-  width: 1em;
-  height: 1em;
-  padding-top: 2px;
-  margin-right: 0.3rem;
-}
-.action--buttons svg *,
-.library--expand svg * {
-  fill: var(--theme--text_property);
-}
-
-.library--preview {
-  border-bottom: 1px solid var(--theme--divider);
-}
-.library--version {
-  font-weight: normal;
-  font-size: var(--theme--font_ui-size);
-  border-radius: 5px;
-  padding: 0.125rem 0.25rem;
-  background: var(--theme--tag_default);
-  color: var(--theme--tag_default-text);
-}
-.library--description {
-  font-size: 1rem;
-  margin: 0.25rem 0;
-}
-.library--tags,
-.library--authors {
-  padding: 0;
-  list-style-type: none;
-  display: flex;
-  flex-wrap: wrap;
-  margin: 0.5em 0;
-}
-.library--tags li {
-  font-size: var(--theme--font_ui-size);
-  margin: 0 0.5rem 0 0;
-  opacity: 0.7;
-}
-.library--authors li {
-  font-size: var(--theme--font_ui-size);
-  margin: 0 0.5rem 0 0;
-}
-.library--authors a {
-  font-size: var(--theme--font_ui-size);
-  text-decoration: none;
-  border-radius: 5px;
-  padding: 0.125rem 0.25rem 0.25rem 0;
-}
-.library--authors img {
-  height: 1em;
-  width: 1em;
-  margin-bottom: 0.15625em;
-  display: inline-block;
-  vertical-align: middle;
-  border-radius: 50%;
-  object-fit: cover;
-}
-
-.library--options {
-  border-top: 1px solid var(--theme--divider);
-}
-.library--toggle_label,
-.library--select_label,
-.library--text_label,
-.library--number_label,
-.library--color_label,
-.library--file_label {
-  margin: 0.6rem 0;
-  display: block;
-  appearance: none;
-  font-size: var(--theme--font_ui-size);
-}
-.library--toggle_label *,
-.library--select_label *,
-.library--text_label *,
-.library--number_label *,
-.library--color_label *,
-.library--file_label * {
-  appearance: none;
-  font-family: var(--theme--font_sans);
-  font-size: var(--theme--font_ui-size);
-  color: var(--theme--text);
-}
-label p:not([class]),
-label p > span:not([class]),
-label > span:not([class]) {
-  font-size: 1rem;
-}
-label [data-icon='fa/solid/question-circle'] {
-  height: var(--theme--font_ui_small-size);
-  width: var(--theme--font_ui_small-size);
-  margin-left: 0.25em;
-  margin-bottom: -1px;
-}
-.library--toggle_label > p,
-.library--toggle_label > p,
-.library--select_label > p,
-.library--text_label > p,
-.library--number_label > p,
-.library--color_label > p,
-.library--file_label > p {
-  margin: 0.6rem 0;
-}
-.library--toggle_label > :not(input) {
-  align-items: center;
-  display: flex;
-  --toggle--bg: var(--theme--toggle_off);
-  --toggle--translation: 0%;
-}
-.library--toggle_label > :not(input) .library--toggle {
-  position: relative;
-  margin: auto 0 auto auto;
-  min-width: 2.25rem;
-  width: 2.25rem;
-  height: 1.25rem;
-  display: block;
-  border-radius: 40px;
-  background: var(--toggle--bg);
-  cursor: pointer;
-}
-.library--toggle_label > :not(input) .library--toggle::after {
-  content: '';
-  transition: transform 200ms ease-out, background 200ms ease-out;
-  height: 0.8rem;
-  width: 0.8rem;
-  left: 0.325rem;
-  top: 0.2rem;
-  position: absolute;
-  border-radius: 100%;
-  background: var(--theme--toggle_dot);
-  transform: translateX(var(--toggle--translation));
-}
-.library--toggle_label input[type='checkbox']:checked + :not(input) {
-  --toggle--bg: var(--theme--toggle_on);
-  --toggle--translation: 100%;
-}
-.library--toggle_label:focus-within .library--toggle,
-.library--file_label:focus-within .library--file,
-.library--color_label:focus-within .library--color,
-.library--select_label .library--select:focus-within {
-  outline: -webkit-focus-ring-color auto 1px;
-}
-.library--toggle_label input,
-.library--file_label input {
-  position: absolute;
-  width: 1px;
-  height: 1px;
-  padding: 0;
-  margin: -1px;
-  overflow: hidden;
-  clip: rect(0, 0, 0, 0);
-  white-space: nowrap;
-  border-width: 0;
-}
-.library--text_label textarea {
-  resize: none;
-  min-height: calc(1em + 16px);
-  height: var(--txt--scroll-height);
-}
-.library--text_label textarea,
-.library--number_label input,
-.library--select_label .library--select,
-.library--color_label .library--color,
-.library--file_label .library--file {
-  width: 100%;
-  padding: 6px 8px;
-  background: var(--theme--input);
-  border-radius: 3px;
-  border: none;
-  box-shadow: var(--theme--input-border) 0px 0px 0px 1px inset;
-}
-.library--select_label .library--select select,
-.library--color_label .library--color input {
-  outline: none;
-  cursor: pointer;
-}
-.library--color_label .library--color input {
-  border-radius: 0;
-}
-.library--select_label .library--select select option {
-  background: var(--theme--tag_select);
-}
-.library--select_label .library--select,
-.library--color_label .library--color,
-.library--file_label .library--file {
-  padding: 0;
-  display: flex;
-  cursor: pointer;
-}
-.library--select_label .library--select > :first-child,
-.library--color_label .library--color > :first-child,
-.library--file_label .library--file > :first-child {
-  display: flex;
-  padding: 6px 8px;
-  background: var(--theme--input-border);
-}
-.library--select_label .library--select > :first-child svg,
-.library--color_label .library--color > :first-child svg,
-.library--file_label .library--file > :first-child svg {
-  width: 0.9em;
-  margin: auto 0;
-}
-.library--select_label .library--select > :first-child svg *,
-.library--color_label .library--color > :first-child svg *,
-.library--file_label .library--file > :first-child svg * {
-  color: var(--theme--input_icon);
-}
-.library--select_label .library--select > :last-child,
-.library--color_label .library--color > :last-child,
-.library--file_label .library--file > :last-child {
-  margin: auto 0;
-  padding: 6px 8px;
-  width: 100%;
-  height: 100%;
-  border: none;
-  background: none;
-}
-.library--file_label .library--file_title {
-  display: flex;
-}
-.library--file_title .library--file_remove {
-  margin-top: auto;
-  padding-top: 0.2em;
-  margin-left: auto;
-}
-.library--file_title .library--file_remove svg {
-  cursor: pointer;
-  width: 0.8em;
-}
-.library--title,
-.library--title h2 {
-  margin: 0;
-  font-size: var(--theme--font_ui-size);
-}
-.library--title h2 > span {
-  font-size: var(--theme--font_heading2-size);
-}
-
-.library--card > div {
-  padding: 1rem;
-}
-[data-view='mod'] main .library--card {
-  overflow-x: auto;
-}
-.documentation--body {
-  padding: 1rem 2rem;
-  font-size: 1rem;
-  overflow-x: auto;
-}
-
-.notifications {
-  position: absolute;
-  bottom: 1.5rem;
-  right: 1.5rem;
-}
-.notification {
-  background: var(--theme--block_grey);
-  color: var(--theme--block_grey-text);
-  max-width: calc(100vw - 3rem);
-  width: 25rem;
-  font-size: var(--theme--font_ui-size);
-  border-top: 4px currentColor solid;
-  border-bottom-left-radius: 3px;
-  border-bottom-right-radius: 3px;
-  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06) !important;
-  padding: 1.25em 1.5em;
-  display: flex;
-  margin-top: 1rem;
-  position: relative;
-  transition: opacity 200ms ease-in-out, transform 115ms ease-out 200ms,
-    margin-top 115ms ease-out 200ms;
-  transform: scaleY(1);
-  transform-origin: 100% 100%;
-  opacity: 0;
-}
-.notification :not(.notification--dismiss) > svg {
-  height: 1.5rem;
-  width: 1.5rem;
-  margin-top: 0.25rem;
-  margin-right: 1rem;
-}
-.notification h3 {
-  margin: 0 0 0.25rem 0;
-  font-weight: bold;
-}
-.notification p {
-  margin: 0.25rem 0 0.5rem 0;
-}
-.notification .notification--dismiss {
-  position: absolute;
-  top: 0.5rem;
-  right: 0.75rem;
-  background: none;
-  border: none;
-  padding: 0.15rem 0 0.15rem 0.5rem;
-  width: var(--theme--font_body-size);
-  color: currentColor;
-  cursor: pointer;
-  transition: opacity 200ms ease-in-out;
-  opacity: 0;
-}
-.notification .notification--dismiss svg {
-  width: 100%;
-}
-.notification:hover .notification--dismiss,
-.notification:focus-within .notification--dismiss {
-  opacity: 1;
-}
-
-::-webkit-scrollbar {
-  background: transparent;
-  width: 10px;
-  height: 10px;
-}
-::-webkit-scrollbar-track {
-  background: var(--theme--scrollbar_track);
-}
-::-webkit-scrollbar-corner {
-  background: var(--theme--scrollbar_track);
-}
-::-webkit-scrollbar-thumb {
-  background: var(--theme--scrollbar_thumb);
-}
-::-webkit-scrollbar-thumb:hover {
-  background: var(--theme--scrollbar_thumb-hover);
-}
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.mjs b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.mjs
index 873f44d..ccf4a15 100644
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.mjs
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/menu.mjs
@@ -29,6 +29,11 @@ const loadTheme = async () => {
 document.addEventListener('visibilitychange', loadTheme);
 loadTheme();
 
+window.addEventListener('beforeunload', (event) => {
+  // trigger input save
+  document.activeElement.blur();
+});
+
 const notifications = {
   $container: web.html`<div class="notifications-container"></div>`,
   cache: await db.get(['notifications'], []),
@@ -72,10 +77,10 @@ const notifications = {
     );
     return $notification;
   },
-  _changes: false,
-  changes() {
-    if (this._changes) return;
-    this._changes = true;
+  _onChange: false,
+  onChange() {
+    if (this._onChange) return;
+    this._onChange = true;
     const $notification = this.add({
       icon: 'refresh-cw',
       message: 'Reload to apply changes.',
@@ -112,7 +117,7 @@ const components = {
     class="mod-preview"
     src="${web.escape(url)}"
     alt=""
-  />`,
+  >`,
   title: (title) => web.html`<h4 class="mod-title"><span>${web.escape(title)}</span></h4>`,
   version: (version) => web.html`<span class="mod-version">v${web.escape(version)}</span>`,
   tags: (tags) => {
@@ -126,40 +131,256 @@ const components = {
     ${fmt.md.renderInline(description)}
   </p>`,
   authors: (authors) => {
-    const author = (author) => web.html`<a class="mod-author" href="${web.escape(
-      author.homepage
-    )}">
+    const author = (author) => web.html`<a
+      class="mod-author"
+      href="${web.escape(author.homepage)}"
+      target="_blank"
+    >
       <img class="mod-author-avatar"
         src="${web.escape(author.avatar)}" alt="${web.escape(author.name)}'s avatar"
-      /> <span>${web.escape(author.name)}</span>
+      > <span>${web.escape(author.name)}</span>
     </a>`;
     return web.render(web.html`<p class="mod-authors-container"></p>`, ...authors.map(author));
   },
-  toggle: (checked) => {
-    const $label = web.html`<label tabindex="0" class="toggle-label-full"></label>`,
-      $input = web.html`<input tabindex="-1" type="checkbox" class="toggle-check-right"
-        ${checked ? 'checked' : ''}/>`;
+  toggle: (label, checked) => {
+    const $label = web.html`<label tabindex="0" class="toggle-label">
+      <span>${web.escape(label)}</span>
+    </label>`,
+      $input = web.html`<input tabindex="-1" type="checkbox" class="toggle-check"
+        ${checked ? 'checked' : ''}>`,
+      $feature = web.html`<span class="toggle-box toggle-feature"></span>`;
     $label.addEventListener('keyup', (event) => {
       if (['Enter', ' '].includes(event.key)) $input.checked = !$input.checked;
     });
-    return web.render(
-      $label,
-      $input,
-      web.html`<span class="toggle-box toggle-feature"></span>`
-    );
+    return web.render($label, $input, $feature);
   },
 };
 
+const $main = web.html`<main class="main"></main>`,
+  $sidebar = web.html`<article class="sidebar"></article>`,
+  $options = web.html`<div class="options-container">
+    <p class="options-empty">Select a mod to view and configure its options.</p>
+  </div>`;
+
+const options = {
+  toggle: async (mod, opt) => {
+    const checked = await registry.profile.get([mod.id, opt.key], opt.value),
+      $toggle = components.toggle(opt.label, checked),
+      $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
+      $label = $toggle.children[0],
+      $input = $toggle.children[1];
+    if (opt.tooltip) {
+      $label.prepend($tooltip);
+      web.tooltip($tooltip, opt.tooltip);
+    }
+    $input.addEventListener('change', async (event) => {
+      await registry.profile.set([mod.id, opt.key], $input.checked);
+      notifications.onChange();
+    });
+    return $toggle;
+  },
+  select: async (mod, opt) => {
+    const value = await registry.profile.get([mod.id, opt.key], opt.values[0]),
+      $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
+      $label = web.render(
+        web.html`<label class="input-label"></label>`,
+        web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
+      ),
+      $select = web.html`<select class="input">
+        ${opt.values
+          .map(
+            (option) =>
+              web.raw`<option
+                class="select-option"
+                value="${web.escape(option)}"
+                ${option === value ? 'selected' : ''}
+              >${web.escape(option)}</option>`
+          )
+          .join('')}
+      </select>`,
+      $icon = web.html`${web.icon('chevron-down', { class: 'input-icon' })}`;
+    if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+    $select.addEventListener('change', async (event) => {
+      await registry.profile.set([mod.id, opt.key], $select.value);
+      notifications.onChange();
+    });
+    return web.render($label, $select, $icon);
+  },
+  text: async (mod, opt) => {
+    const value = await registry.profile.get([mod.id, opt.key], opt.value),
+      $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
+      $label = web.render(
+        web.html`<label class="input-label"></label>`,
+        web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
+      ),
+      $input = web.html`<input type="text" class="input" value="${web.escape(value)}">`,
+      $icon = web.html`${web.icon('type', { class: 'input-icon' })}`;
+    if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+    $input.addEventListener('change', async (event) => {
+      await registry.profile.set([mod.id, opt.key], $input.value);
+      notifications.onChange();
+    });
+    return web.render($label, $input, $icon);
+  },
+  number: async (mod, opt) => {
+    const value = await registry.profile.get([mod.id, opt.key], opt.value),
+      $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
+      $label = web.render(
+        web.html`<label class="input-label"></label>`,
+        web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
+      ),
+      $input = web.html`<input type="number" class="input" value="${value}">`,
+      $icon = web.html`${web.icon('hash', { class: 'input-icon' })}`;
+    if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+    $input.addEventListener('change', async (event) => {
+      await registry.profile.set([mod.id, opt.key], $input.value);
+      notifications.onChange();
+    });
+    return web.render($label, $input, $icon);
+  },
+  color: async (mod, opt) => {
+    const value = await registry.profile.get([mod.id, opt.key], opt.value),
+      $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
+      $label = web.render(
+        web.html`<label class="input-label"></label>`,
+        web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
+      ),
+      $input = web.html`<input type="text" class="input">`,
+      $icon = web.html`${web.icon('droplet', { class: 'input-icon' })}`,
+      paint = () => {
+        $input.style.background = $picker.toBackground();
+        $input.style.color = $picker.isLight() ? '#000' : '#fff';
+        $input.style.padding = '';
+      },
+      $picker = new web.jscolor($input, {
+        value,
+        format: 'rgba',
+        previewSize: 0,
+        borderRadius: 3,
+        borderColor: 'var(--theme--ui_divider)',
+        controlBorderColor: 'var(--theme--ui_divider)',
+        backgroundColor: 'var(--theme--bg)',
+        onInput: paint,
+        onChange: paint,
+      });
+    if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+    $input.addEventListener('change', async (event) => {
+      await registry.profile.set([mod.id, opt.key], $input.value);
+      notifications.onChange();
+    });
+    paint();
+    return web.render($label, $input, $icon);
+  },
+  file: async (mod, opt) => {
+    const { filename } = (await registry.profile.get([mod.id, opt.key], {})) || {},
+      $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
+      $label = web.render(
+        web.html`<label class="input-label"></label>`,
+        web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
+      ),
+      $pseudo = web.html`<span class="input"><span class="input-placeholder">Upload file...</span></span>`,
+      $input = web.html`<input type="file" class="hidden" accept=${web.escape(
+        opt.extensions.join(',')
+      )}>`,
+      $icon = web.html`${web.icon('file', { class: 'input-icon' })}`,
+      $filename = web.html`<span>${web.escape(filename || 'none')}</span>`,
+      $latest = web.render(web.html`<button class="file-latest">Latest: </button>`, $filename);
+    if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+    $input.addEventListener('change', (event) => {
+      const file = event.target.files[0],
+        reader = new FileReader();
+      reader.onload = async (progress) => {
+        $filename.innerText = file.name;
+        await registry.profile.set([mod.id, opt.key], {
+          filename: file.name,
+          content: progress.currentTarget.result,
+        });
+        notifications.onChange();
+      };
+      reader.readAsText(file);
+    });
+    $latest.addEventListener('click', (event) => {
+      $filename.innerText = 'none';
+      registry.profile.set([mod.id, opt.key], {});
+    });
+    return web.render(
+      web.html`<div></div>`,
+      web.render($label, $input, $pseudo, $icon),
+      $latest
+    );
+  },
+  hotkey: async (mod, opt) => {
+    const value = await registry.profile.get([mod.id, opt.key], opt.value),
+      $tooltip = web.html`${web.icon('info', { class: 'input-tooltip' })}`,
+      $label = web.render(
+        web.html`<label class="input-label"></label>`,
+        web.render(web.html`<p></p>`, opt.tooltip ? $tooltip : '', opt.label)
+      ),
+      $input = web.html`<input type="text" class="input" value="${web.escape(value)}">`,
+      $icon = web.html`${web.icon('command', { class: 'input-icon' })}`;
+    if (opt.tooltip) web.tooltip($tooltip, opt.tooltip);
+    $input.addEventListener('keydown', async (event) => {
+      event.preventDefault();
+      const pressed = [],
+        modifiers = {
+          metaKey: 'Meta',
+          ctrlKey: 'Control',
+          altKey: 'Alt',
+          shiftKey: 'Shift',
+        };
+      for (const modifier in modifiers) {
+        if (event[modifier]) pressed.push(modifiers[modifier]);
+      }
+      const empty = ['Backspace', 'Delete'].includes(event.key) && !pressed.length;
+      if (!empty && !pressed.includes(event.key)) {
+        let key = event.key;
+        if (key === ' ') key = 'Space';
+        if (key.length === 1) key = event.key.toUpperCase();
+        pressed.push(key);
+      }
+      $input.value = pressed.join('+');
+      await registry.profile.set([mod.id, opt.key], $input.value);
+      notifications.onChange();
+    });
+    return web.render($label, $input, $icon);
+  },
+};
+
+components.options = async (mod) => {
+  const $fragment = document.createDocumentFragment();
+  for (const opt of mod.options) {
+    web.render($fragment, await options[opt.type](mod, opt));
+  }
+  if (!mod.options.length) {
+    web.render($fragment, web.html`<p class="options-empty">No options.</p>`);
+  }
+  return $fragment;
+};
+
 components.mod = async (mod) => {
-  const $toggle = components.toggle(await registry.enabled(mod.id));
+  const $mod = web.html`<div class="mod"></div>`,
+    $toggle = components.toggle('', await registry.enabled(mod.id));
   $toggle.addEventListener('change', (event) => {
     registry.profile.set(['_mods', mod.id], event.target.checked);
-    notifications.changes();
+    notifications.onChange();
+  });
+  $mod.addEventListener('click', async (event) => {
+    if ($mod.className === 'mod-selected') return;
+    for (const $selected of document.querySelectorAll('.mod-selected')) {
+      $selected.className = 'mod';
+    }
+    $mod.className = 'mod-selected';
+    web.render(
+      web.empty($options),
+      web.render(components.title(mod.name), components.version(mod.version)),
+      components.tags(mod.tags),
+      await components.options(mod)
+    );
   });
   return web.render(
     web.html`<article class="mod-container"></article>`,
     web.render(
-      web.html`<div class="mod"></div>`,
+      $mod,
       mod.preview
         ? components.preview(
             mod.preview.startsWith('http')
@@ -179,36 +400,41 @@ components.mod = async (mod) => {
   );
 };
 
+components._$modListCache = {};
 components.modList = async (category) => {
-  const $search = web.html`<input type="search" class="search"
+  if (!components._$modListCache[category]) {
+    const $search = web.html`<input type="search" class="search"
     placeholder="Search ('/' to focus)">`,
-    $list = web.html`<div class="mods-list"></div>`,
-    mods = await registry.list(
-      (mod) => mod.environments.includes(env.name) && mod.tags.includes(category)
-    );
-  web.addHotkeyListener(['/'], () => $search.focus());
-  $search.addEventListener('input', (event) => {
-    const query = $search.value.toLowerCase();
-    for (const $mod of $list.children) {
-      const matches = !query || $mod.innerText.toLowerCase().includes(query);
-      $mod.classList[matches ? 'remove' : 'add']('hidden');
+      $list = web.html`<div class="mods-list"></div>`,
+      mods = await registry.list(
+        (mod) => mod.environments.includes(env.name) && mod.tags.includes(category)
+      );
+    web.addHotkeyListener(['/'], () => $search.focus());
+    $search.addEventListener('input', (event) => {
+      const query = $search.value.toLowerCase();
+      for (const $mod of $list.children) {
+        const matches = !query || $mod.innerText.toLowerCase().includes(query);
+        $mod.classList[matches ? 'remove' : 'add']('hidden');
+      }
+    });
+    for (const mod of mods) {
+      mod.tags = mod.tags.filter((tag) => tag !== category);
+      web.render($list, await components.mod(mod));
+      mod.tags.unshift(category);
     }
-  });
-  for (const mod of mods) {
-    mod.tags = mod.tags.filter((tag) => tag !== category);
-    web.render($list, await components.mod(mod));
-    mod.tags.unshift(category);
+    components._$modListCache[category] = web.render(
+      web.html`<div></div>`,
+      web.render(
+        web.html`<label class="search-container"></label>`,
+        $search,
+        web.html`${web.icon('search', { class: 'input-icon' })}`
+      ),
+      $list
+    );
   }
-  return web.render(
-    web.html`<div></div>`,
-    web.render(web.html`<div class="search-container"></div>`, $search),
-    $list
-  );
+  return components._$modListCache[category];
 };
 
-const $main = web.html`<main class="main"></main>`,
-  $sidebar = web.html`<article class="sidebar"></article>`;
-
 const $notionNavItem = web.html`<h1 class="nav-notion">
     ${(await fs.getText('icon/colour.svg')).replace(
       /width="\d+" height="\d+"/,
@@ -221,7 +447,7 @@ $notionNavItem.children[0].addEventListener('click', env.focusNotion);
 const $coreNavItem = web.html`<a href="?view=core" class="nav-item">core</a>`,
   $extensionsNavItem = web.html`<a href="?view=extensions" class="nav-item">extensions</a>`,
   $themesNavItem = web.html`<a href="?view=themes" class="nav-item">themes</a>`,
-  $supportNavItem = web.html`<a href="https://discord.gg/sFWPXtA" class="nav-item">support</a>`;
+  $communityNavItem = web.html`<a href="https://discord.gg/sFWPXtA" class="nav-item">community</a>`;
 
 web.render(
   document.body,
@@ -235,11 +461,11 @@ web.render(
         $coreNavItem,
         $extensionsNavItem,
         $themesNavItem,
-        $supportNavItem
+        $communityNavItem
       ),
       $main
     ),
-    $sidebar
+    web.render($sidebar, $options)
   )
 );
 
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/mod.json b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/mod.json
index a7ac01b..0aa7b7f 100644
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/mod.json
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/mod.json
@@ -21,11 +21,11 @@
   },
   "options": [
     {
-      "type": "text",
+      "type": "hotkey",
       "key": "hotkey",
-      "label": "toggle hotkey",
+      "label": "toggle focus hotkey",
       "value": "Ctrl+Alt+E",
-      "tooltip": "toggles focus between notion & the enhancer menu"
+      "tooltip": "switches between notion & the enhancer menu"
     }
   ]
 }
diff --git a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/styles.mjs b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/styles.mjs
index 2160aa2..f46b10f 100644
--- a/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/styles.mjs
+++ b/extension/repo/menu@a6621988-551d-495a-97d8-3c568bca2e9e/styles.mjs
@@ -29,49 +29,57 @@ const customClasses = {
   'notification': ([color = 'default']) =>
     apply`p-2 ${
       color === 'default'
-        ? 'bg-tag text-tag-text hover:bg-interactive-hover border border-notion-divider'
+        ? 'bg-tag text-tag-text hover:bg-interactive-hover border border-divider'
         : `bg-${color}-tag text-${color}-tag-text border border-${color}-text hover:bg-${color}-text`
     } flex items-center rounded-full mt-3 shadow-md cursor-pointer`,
   'notification-text': apply`font-semibold mx-2 flex-auto`,
   'notification-icon': apply`fill-current opacity-75 h-4 w-4 mx-2`,
   'body-container': apply`flex w-full h-full overflow-hidden`,
   'content-container': apply`h-full w-full-96`,
-  'nav': apply`px-4 py-3 flex flex-wrap items-center border-b border-notion-divider h-48 sm:h-32 lg:h-16`,
+  'nav': apply`px-4 py-3 flex flex-wrap items-center border-b border-divider h-48 sm:h-32 lg:h-16`,
   'nav-notion': apply`flex items-center font-semibold text-xl cursor-pointer select-none mr-4
       ml-4 sm:mb-4 md:w-full lg:(w-auto ml-0 mb-0)`,
   'nav-notion-icon': apply`h-12 w-12 mr-5 sm:(h-6 w-6 mr-3)`,
-  'nav-item': apply`ml-4 px-3 py-2 rounded-md text-sm font-medium bg-interactive hover:bg-interactive-hover`,
-  'nav-item-selected': apply`ml-4 px-3 py-2 rounded-md text-sm font-medium ring-1 ring-notion-divider bg-notion-secondary`,
+  'nav-item': apply`ml-4 px-3 py-2 rounded-md text-sm font-medium hover:bg-interactive-hover focus:bg-interactive-active`,
+  'nav-item-selected': apply`ml-4 px-3 py-2 rounded-md text-sm font-medium ring-1 ring-divider bg-notion-secondary`,
   'main': apply`transition px-4 py-3 overflow-y-auto max-h-full-48 sm:max-h-full-32 lg:max-h-full-16`,
-  'sidebar': apply`h-full w-96 bg-notion-secondary border-l border-notion-divider`,
   'mods-list': apply`flex flex-wrap`,
   'mod-container': apply`w-full md:w-1/2 lg:w-1/3 xl:w-1/4 2xl:w-1/5 px-2.5 py-2.5 box-border`,
   'mod': apply`relative h-full w-full flex flex-col overflow-hidden rounded-lg shadow-lg
-      bg-notion-secondary border border-notion-divider`,
-  'mod-body': apply`px-4 py-3 flex flex-col flex-auto`,
+    bg-notion-secondary border border-divider cursor-pointer`,
+  'mod-selected': apply`mod ring ring-accent-blue-active`,
+  'mod-body': apply`px-4 py-3 flex flex-col flex-auto children:cursor-pointer`,
   'mod-preview': apply`object-cover w-full h-32`,
   'mod-title': apply`mb-2 text-xl font-semibold tracking-tight flex items-center`,
   'mod-version': apply`mt-px ml-3 p-1 font-normal text-xs leading-none bg-tag text-tag-text rounded`,
-  'mod-tags': apply`text-foreground-ui mb-2 text-xs`,
+  'mod-tags': apply`text-foreground-secondary mb-2 text-xs`,
   'mod-description': apply`mb-2 text-sm`,
   'mod-authors-container': apply`text-sm font-medium`,
   'mod-author': apply`flex items-center mb-2`,
   'mod-author-avatar': apply`inline object-cover w-5 h-5 rounded-full mr-2`,
-  'toggle-box': apply`w-9 h-5 p-0.5 flex items-center bg-toggle-off rounded-full duration-300 ease-in-out`,
-  'toggle-label': apply`relative text-sm`,
-  'toggle-label-full': apply`relative text-sm flex w-full mt-auto`,
-  'toggle-check': apply`appearance-none checked:sibling:(bg-toggle-on after::translate-x-4)`,
-  'toggle-check-right': apply`appearance-none ml-auto checked:sibling:(bg-toggle-on after::translate-x-4)`,
-  'toggle-feature': apply`after::(${pseudoContent} w-4 h-4 bg-toggle-feature rounded-full duration-300)`,
-  'search-container': apply`mx-2.5 my-2.5`,
-  'search': apply`transition block w-full px-3 py-2 text-sm rounded-md flex bg-notion-input text-foreground
-      hover:(ring ring-accent-blue-hover) focus:(outline-none ring ring-accent-blue-active)`,
+  'toggle-box': apply`w-9 h-5 p-0.5 flex items-center bg-toggle-off rounded-full duration-300 ease-in-out cursor-pointer`,
+  'toggle-label': apply`relative text-sm flex w-full mt-auto`,
+  'toggle-check': apply`appearance-none ml-auto checked:sibling:(bg-toggle-on after::translate-x-4)`,
+  'toggle-feature': apply`after::(${pseudoContent} w-4 h-4 bg-toggle-feature rounded-full duration-300) cursor-pointer`,
+  'sidebar': apply`h-full w-96 px-4 pt-3 pb-32 flex flex-col bg-notion-secondary border-l border-divider`,
+  'options-container': apply`px-4 py-3 shadow-inner rounded-lg bg-notion border border-divider space-y-3`,
+  'options-empty': apply`text-sm text-foreground-secondary`,
+  'input-label': apply`block text-sm mt-2 relative`,
+  'input': apply`transition block w-full mt-2 pl-3 pr-14 py-2 text-sm rounded-md flex bg-input text-foreground
+    appearance-none placeholder-foreground-secondary ring-1 ring-divider focus:(outline-none ring ring-accent-blue-active)`,
+  'input-tooltip': apply`h-4 w-4 -mt-1 inline-block mr-2`,
+  'input-icon': apply`absolute w-11 h-9 right-0 bottom-0 py-2 px-3 bg-notion-secondary rounded-r-md text-icon`,
+  'input-placeholder': apply`text-foreground-secondary`,
+  'select-option': apply`bg-notion-secondary`,
+  'file-latest': apply`block w-full text-left text-foreground-secondary text-xs mt-2 hover:line-through cursor-pointer`,
+  'search-container': apply`block mx-2.5 my-2.5 relative`,
+  'search': apply`input pr-12`,
 };
 
 setup({
   preflight: {
     html: apply`w-full h-full`,
-    body: apply`w-full h-full bg-notion-bg font-sans text-foreground`,
+    body: apply`w-full h-full bg-notion font-sans text-foreground`,
   },
   theme: {
     fontFamily: {
@@ -79,18 +87,16 @@ setup({
       mono: ['var(--theme--font_mono)'],
     },
     colors: {
-      'notion': {
-        'bg': 'var(--theme--bg)',
-        'secondary': 'var(--theme--bg_secondary)',
-        'popup': 'var(--theme--bg_popup)',
-        'divider': 'var(--theme--ui_divider)',
-        'input': 'var(--theme--ui_input)',
-      },
+      'notion': 'var(--theme--bg)',
+      'notion-secondary': 'var(--theme--bg_secondary)',
+      'notion-popup': 'var(--theme--bg_popup)',
+      'divider': 'var(--theme--ui_divider)',
+      'input': 'var(--theme--ui_input)',
       'icon': 'var(--theme--icon)',
-      'icon-ui': 'var(--theme--icon_ui)',
+      'icon-secondary': 'var(--theme--icon_secondary)',
       'foreground': 'var(--theme--text)',
-      'foreground-ui': 'var(--theme--text_ui)',
-      'interactive': 'var(--theme--ui_interactive)',
+      'foreground-secondary': 'var(--theme--text_secondary)',
+      'interactive-active': 'var(--theme--ui_interactive-active)',
       'interactive-hover': 'var(--theme--ui_interactive-hover)',
       'tag': 'var(--theme--tag_default)',
       'tag-text': 'var(--theme--tag_default-text)',
diff --git a/extension/repo/theming@0f0bf8b6-eae6-4273-b307-8fc43f2ee082/theme.css b/extension/repo/theming@0f0bf8b6-eae6-4273-b307-8fc43f2ee082/theme.css
index 38983ec..95123c7 100644
--- a/extension/repo/theming@0f0bf8b6-eae6-4273-b307-8fc43f2ee082/theme.css
+++ b/extension/repo/theming@0f0bf8b6-eae6-4273-b307-8fc43f2ee082/theme.css
@@ -4,10 +4,6 @@
  * (https://notion-enhancer.github.io/) under the MIT license
  */
 
-/* 
-grey vs text_ui in light mode (check change cover hover text)
-*/
-
 /** layout **/
 
 .notion-frame .notion-scroller [style*='env(safe-area-inset-'][style*=' width: 900px'],
@@ -466,7 +462,7 @@ body,
 }
 .DayPicker-Day--outside,
 .DayPicker-Weekday {
-  color: var(--theme--text_ui) !important;
+  color: var(--theme--text_secondary) !important;
 }
 .notion-timeline-view [style*='height: 100%; border-right: 1px solid rgb(211, 79, 67);'] {
   border-right: 1px solid var(--theme--accent_red) !important;
@@ -713,7 +709,7 @@ body,
 .notion-body:not(.dark) [style*='fill: rgb(55, 53, 47)'],
 .notion-body:not(.dark)
   [style*='fill: rgba(55, 53, 47, 0.']:not([style*='fill: rgba(55, 53, 47, 0.8)']) {
-  fill: var(--theme--icon_ui) !important;
+  fill: var(--theme--icon_secondary) !important;
 }
 .alarmClock {
   fill: currentColor !important;
@@ -750,13 +746,13 @@ body,
   .notion-focusable[role='button'][style*='font-size: 14px; border-radius: 3px; box-shadow:']:last-child
   svg
   + div {
-  color: var(--theme--text_ui) !important;
+  color: var(--theme--text_secondary) !important;
 }
 .notion-page-mention-token__title {
-  border-bottom: 0.05em solid var(--theme--text_ui) !important;
+  border-bottom: 0.05em solid var(--theme--text_secondary) !important;
 }
 .notion-to_do-block [placeholder='To-do'][style*='text-decoration: line-through'] {
-  text-decoration: line-through var(--theme--text_ui) !important;
+  text-decoration: line-through var(--theme--text_secondary) !important;
 }
 .notion-body.dark [style*=' color: rgba(255, 255, 255, 0.4)'],
 .notion-body.dark [style^='color: rgba(255, 255, 255, 0.4)'],
@@ -765,15 +761,15 @@ body,
 .notion-page-controls,
 .notion-page-details-controls,
 .notion-calendar-view-day {
-  color: var(--theme--text_ui) !important;
+  color: var(--theme--text_secondary) !important;
 }
 .notion-body.dark [style*='-webkit-text-fill-color: rgba(255, 255, 255, 0.4)'],
 .notion-body:not(.dark) [style*='-webkit-text-fill-color: rgba(55, 53, 47, 0.4)'] {
-  -webkit-text-fill-color: var(--theme--text_ui) !important;
+  -webkit-text-fill-color: var(--theme--text_secondary) !important;
 }
 .notion-body.dark [style*='border-color:rgba(255,255,255,0.4)'],
 .notion-body:not(.dark) [style*='border-color:rgba(55,53,47,0.4)'] {
-  border-color: var(--theme--text_ui) !important;
+  border-color: var(--theme--text_secondary) !important;
 }
 
 .notion-body.dark [style*='background: rgb(80, 85, 88)']:not([role='button']),
diff --git a/extension/repo/theming@0f0bf8b6-eae6-4273-b307-8fc43f2ee082/variables.css b/extension/repo/theming@0f0bf8b6-eae6-4273-b307-8fc43f2ee082/variables.css
index 1c5deba..241edee 100644
--- a/extension/repo/theming@0f0bf8b6-eae6-4273-b307-8fc43f2ee082/variables.css
+++ b/extension/repo/theming@0f0bf8b6-eae6-4273-b307-8fc43f2ee082/variables.css
@@ -57,10 +57,10 @@
   --theme--ui_tooltip-description: rgba(206, 205, 202, 0.6);
 
   --theme--icon: rgba(55, 53, 47, 0.8);
-  --theme--icon_ui: rgba(55, 53, 47, 0.4);
+  --theme--icon_secondary: rgba(55, 53, 47, 0.4);
 
   --theme--text: rgb(55, 43, 47);
-  --theme--text_ui: rgba(55, 43, 47, 0.6);
+  --theme--text_secondary: rgba(55, 43, 47, 0.6);
   --theme--text_grey: rgb(155, 154, 151);
   --theme--text_brown: rgb(100, 71, 58);
   --theme--text_orange: rgb(217, 115, 13);
@@ -221,10 +221,10 @@
   --theme--ui_tooltip-description: rgba(47, 52, 55, 0.6);
 
   --theme--icon: rgba(202, 204, 206);
-  --theme--icon_ui: rgb(202, 204, 206, 0.6);
+  --theme--icon_secondary: rgb(202, 204, 206, 0.6);
 
   --theme--text: rgba(255, 255, 255, 0.9);
-  --theme--text_ui: rgba(255, 255, 255, 0.6);
+  --theme--text_secondary: rgba(255, 255, 255, 0.6);
   --theme--text_grey: rgba(151, 154, 155, 0.95);
   --theme--text_brown: rgb(147, 114, 100);
   --theme--text_orange: rgb(255, 163, 68);
diff --git a/extension/worker.js b/extension/worker.js
index df68e8a..c2024ae 100644
--- a/extension/worker.js
+++ b/extension/worker.js
@@ -18,11 +18,11 @@ chrome.action.onClicked.addListener(focusMenu);
 
 async function focusNotion() {
   const tabs = await chrome.tabs.query({ windowId: chrome.windows.WINDOW_ID_CURRENT }),
-    notion = tabs.find(
-      (tab) =>
-        new URL(tab.url).host.endsWith('.notion.so') ||
-        new URL(tab.url).host.endsWith('.notion.site')
-    );
+    notion = tabs.find((tab) => {
+      const url = new URL(tab.url),
+        matches = url.host.endsWith('.notion.so') || url.host.endsWith('.notion.site');
+      return matches;
+    });
   if (notion) {
     chrome.tabs.highlight({ 'tabs': notion.index });
   } else chrome.tabs.create({ url: 'https://notion.so/' });