From 7bafbedc67792dd418588bb62bda14b6812e826a Mon Sep 17 00:00:00 2001
From: dragonwocky <thedragonring.bod@gmail.com>
Date: Mon, 16 Jan 2023 19:29:53 +1100
Subject: [PATCH] feat(menu): add reload btn to footer, move return to category
 btn to footer

---
 src/core/menu/components.mjs | 46 +++++++++++++++++-------
 src/core/menu/menu.css       |  1 +
 src/core/menu/menu.mjs       | 68 ++++++++++++++++++++++++++----------
 3 files changed, 84 insertions(+), 31 deletions(-)

diff --git a/src/core/menu/components.mjs b/src/core/menu/components.mjs
index b7566b1..6ed9401 100644
--- a/src/core/menu/components.mjs
+++ b/src/core/menu/components.mjs
@@ -55,6 +55,17 @@ function SidebarButton({ id, icon, ...props }, ...children) {
   return $el;
 }
 
+function Footer({}, ...children) {
+  const { html } = globalThis.__enhancerApi;
+  return html`<div
+    class="flex w-full px-[60px] py-[16px]
+    border-t-(& [color:var(--theme--fg-border)])
+    bg-[color:var(--theme--bg-primary)]"
+  >
+    ${children}
+  </div>`;
+}
+
 function View({ id }, ...children) {
   const { html } = globalThis.__enhancerApi,
     $el = html`<article
@@ -122,10 +133,10 @@ function View({ id }, ...children) {
   return $el;
 }
 
-function List({ description }, ...children) {
+function List({ id, description }, ...children) {
   const { html } = globalThis.__enhancerApi;
   return html`<div class="flex flex-col gap-y-[14px]">
-    <${Search} items=${children} />
+    <${Search} type=${id} items=${children} />
     <p
       class="notion-enhancer--menu-description
       text-([12px] [color:var(--theme--fg-secondary)])"
@@ -135,13 +146,15 @@ function List({ description }, ...children) {
   </div>`;
 }
 
-function Search({ items, oninput, ...props }) {
+function Search({ type, items, oninput, ...props }) {
   const { html, addKeyListener } = globalThis.__enhancerApi,
     $search = html`<${Input}
       size="lg"
       type="text"
+      placeholder="Search ${items.length} ${items.length === 1
+        ? type.replace(/s$/, "")
+        : type} (Press '/' to focus)"
       icon="search"
-      placeholder="Search ('/' to focus)"
       oninput=${(event) => {
         oninput?.(event);
         const query = event.target.value.toLowerCase();
@@ -251,7 +264,7 @@ function Option({ type, value, description, _get, _set, ...props }) {
       return html`<h4
         class="notion-enhancer--menu-heading font-semibold
         mb-[16px] mt-[48px] first:mt-0 pb-[12px] text-[16px]
-        border-b border-b-[color:var(--theme--fg-border)]"
+        border-b-(& [color:var(--theme--fg-border)])"
       >
         ${label}
       </h4>`;
@@ -296,17 +309,23 @@ function Option({ type, value, description, _get, _set, ...props }) {
   <//>`;
 }
 
-function Button({ icon, ...props }, children) {
-  const { html } = globalThis.__enhancerApi;
+function Button({ primary, icon, class: cls, ...props }, children) {
+  const { html } = globalThis.__enhancerApi,
+    $icon = icon
+      ? html`<i class="i-${icon} w-[18px] h-[18px] mr-[8px]"></i>`
+      : "";
   return html`<button
-    class="mt-[14px] first:mt-0 mb-[14px] last:mb-0
-    flex items-center h-[32px] px-[12px] rounded-[4px]
-    cursor-pointer border-(& [color:var(--theme--fg-border)])
-    transition duration-[20ms] hover:bg-[color:var(--theme--bg-hover)]"
+    class="flex items-center h-[32px] px-[12px] ${cls}
+    rounded-[4px] transition duration-[20ms] ${primary
+      ? `text-[color:var(--theme--accent-primary_contrast)]
+      font-medium bg-[color:var(--theme--accent-primary)]
+      hover:bg-[color:var(--theme--accent-primary\\_hover)]`
+      : `border-(& [color:var(--theme--fg-border)])
+      hover:bg-[color:var(--theme--bg-hover)]`}"
     ...${props}
   >
-    <i class="i-${icon} w-[18px] h-[18px]"></i>
-    <span class="ml-[8px] text-[14px]">${children}</span>
+    ${$icon}
+    <span class="text-[14px]">${children}</span>
   </button>`;
 }
 
@@ -680,6 +699,7 @@ export {
   Sidebar,
   SidebarSection,
   SidebarButton,
+  Footer,
   View,
   List,
   Mod,
diff --git a/src/core/menu/menu.css b/src/core/menu/menu.css
index bd93803..90f0a8f 100644
--- a/src/core/menu/menu.css
+++ b/src/core/menu/menu.css
@@ -44,6 +44,7 @@ body {
   height: 100vh;
   color: var(--theme--fg-primary);
   font-family: var(--theme--font-sans);
+  overflow: hidden;
 }
 
 body > #skeleton {
diff --git a/src/core/menu/menu.mjs b/src/core/menu/menu.mjs
index 5155a06..509cd02 100644
--- a/src/core/menu/menu.mjs
+++ b/src/core/menu/menu.mjs
@@ -9,6 +9,7 @@ import {
   Sidebar,
   SidebarSection,
   SidebarButton,
+  Footer,
   View,
   List,
   Mod,
@@ -61,18 +62,18 @@ const renderSidebar = (items, categories) => {
     }
     return $sidebar;
   },
-  renderList = async (mods, description) => {
+  renderList = async (id, mods, description) => {
     const { html, getProfile, initDatabase } = globalThis.__enhancerApi,
       enabledMods = initDatabase([await getProfile(), "enabledMods"]);
     mods = mods.map(async (mod) => {
       const _get = () => enabledMods.get(mod.id),
         _set = async (enabled) => {
           await enabledMods.set(mod.id, enabled);
-          setState({ rerender: true });
+          setState({ rerender: true, databaseUpdated: true });
         };
       return html`<${Mod} ...${{ ...mod, _get, _set }} />`;
     });
-    return html`<${List} description=${description}>
+    return html`<${List} ...${{ id, description }}>
       ${await Promise.all(mods)}
     <//>`;
   },
@@ -98,7 +99,7 @@ const renderSidebar = (items, categories) => {
       const _get = () => db.get(opt.key),
         _set = async (value) => {
           await db.set(opt.key, value);
-          setState({ rerender: true });
+          setState({ rerender: true, databaseUpdated: true });
         };
       return html`<${Option} ...${{ ...opt, _get, _set }} />`;
     });
@@ -115,17 +116,9 @@ const renderSidebar = (items, categories) => {
         const _get = () => enabledMods.get(mod.id),
           _set = async (enabled) => {
             await enabledMods.set(mod.id, enabled);
-            setState({ rerender: true });
+            setState({ rerender: true, databaseUpdated: true });
           };
         return html`<${View} id=${mod.id}>
-          <${Button}
-            icon="chevron-left"
-            onclick=${() => {
-              setState({ transition: "slide-to-left", view: category.id });
-            }}
-          >
-            ${category.title}
-          <//>
           <${Mod} ...${{ ...mod, options: [], _get, _set }} />
           ${await renderOptions(mod)}
         <//>`;
@@ -134,8 +127,8 @@ const renderSidebar = (items, categories) => {
   };
 
 const render = async () => {
-  const { html, getCore, getThemes } = globalThis.__enhancerApi,
-    { getExtensions, getIntegrations } = globalThis.__enhancerApi,
+  const { html, reloadApp, getCore } = globalThis.__enhancerApi,
+    { getThemes, getExtensions, getIntegrations } = globalThis.__enhancerApi,
     [icon, renderStarted] = getState(["icon", "renderStarted"]);
   if (!html || !getCore || !icon || renderStarted) return;
   setState({ renderStarted: true });
@@ -210,18 +203,57 @@ const render = async () => {
     ];
 
   // view wrapper necessary for transitions
-  const $views = html`<div class="relative overflow-hidden">
+  const $views = html`<div class="grow relative overflow-hidden">
     <${View} id="welcome">welcome<//>
     <${View} id="core">${await renderOptions(await getCore())}<//>
   </div>`;
   for (const { id, title, description, mods } of categories) {
-    const $list = await renderList(mods, description),
+    const $list = await renderList(id, mods, description),
       $mods = await renderMods({ id, title }, mods);
     $views.append(html`<${View} id=${id}>${$list}<//>`, ...$mods);
   }
 
+  categories.forEach((c) => {
+    c.button = html`<${Button}
+      icon="chevron-left"
+      onclick=${() => setState({ transition: "slide-to-left", view: c.id })}
+    >
+      ${c.title}
+    <//>`;
+  });
+  const $reload = html`<${Button}
+      primary
+      class="ml-auto"
+      icon="refresh-cw"
+      onclick=${() => reloadApp()}
+      style="display: none"
+    >
+      Reload & Apply Changes
+    <//>`,
+    $footer = html`<${Footer}>${categories.map((c) => c.button)}${$reload}<//>`,
+    $main = html`<div class="flex flex-col overflow-hidden transition-[height]">
+      ${$views} ${$footer}
+    </div>`,
+    updateFooter = () => {
+      const buttons = [...$footer.children],
+        renderFooter = buttons.some(($el) => $el.style.display === "");
+      $main.style.height = renderFooter ? "100%" : "calc(100% + 65px)";
+    };
+  useState(["view"], ([view]) => {
+    for (const { mods, button } of categories) {
+      const renderButton = mods.some((mod) => mod.id === view);
+      button.style.display = renderButton ? "" : "none";
+      updateFooter();
+    }
+  });
+  useState(["databaseUpdated"], ([databaseUpdated]) => {
+    if (!databaseUpdated) return;
+    $reload.style.display = "";
+    updateFooter();
+  });
+
   const $skeleton = document.querySelector("#skeleton");
-  $skeleton.replaceWith(renderSidebar(sidebar, categories), $views);
+  $skeleton.replaceWith(renderSidebar(sidebar, categories), $main);
 };
 
 window.addEventListener("focus", () => setState({ rerender: true }));