From 91189dfd2f4cb32e205117b327e0ae7a0c2dd716 Mon Sep 17 00:00:00 2001
From: Emile Bangma <github@emilebangma.com>
Date: Mon, 03 Feb 2025 14:25:42 +0000
Subject: [PATCH] feat(explorer): collapsible mobile explorer (#1471)

---
 quartz/components/styles/explorer.scss |  193 +++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 182 insertions(+), 11 deletions(-)

diff --git a/quartz/components/styles/explorer.scss b/quartz/components/styles/explorer.scss
index 28e9f9b..531e9ff 100644
--- a/quartz/components/styles/explorer.scss
+++ b/quartz/components/styles/explorer.scss
@@ -1,5 +1,86 @@
-button#explorer {
-  all: unset;
+@use "../../styles/variables.scss" as *;
+
+@media all and ($mobile) {
+  .page > #quartz-body {
+    // Shift page position when toggling Explorer on mobile.
+    & > :not(.sidebar.left:has(.explorer)) {
+      transform: translateX(0);
+      transition: transform 300ms ease-in-out;
+    }
+    &.lock-scroll > :not(.sidebar.left:has(.explorer)) {
+      transform: translateX(100dvw);
+      transition: transform 300ms ease-in-out;
+    }
+
+    // Sticky top bar (stays in place when scrolling down on mobile).
+    .sidebar.left:has(.explorer) {
+      box-sizing: border-box;
+      position: sticky;
+      background-color: var(--light);
+    }
+
+    // Hide Explorer on mobile until done loading.
+    // Prevents ugly animation on page load.
+    .hide-until-loaded ~ #explorer-content {
+      display: none;
+    }
+  }
+}
+
+.explorer {
+  display: flex;
+  height: 100%;
+  flex-direction: column;
+  overflow-y: hidden;
+
+  @media all and ($mobile) {
+    order: -1;
+    height: initial;
+    overflow: hidden;
+    flex-shrink: 0;
+    align-self: flex-start;
+  }
+
+  button#mobile-explorer {
+    display: none;
+  }
+
+  button#desktop-explorer {
+    display: flex;
+  }
+
+  @media all and ($mobile) {
+    button#mobile-explorer {
+      display: flex;
+    }
+
+    button#desktop-explorer {
+      display: none;
+    }
+  }
+
+  &.desktop-only {
+    @media all and not ($mobile) {
+      display: flex;
+    }
+  }
+
+  /*&:after {
+    pointer-events: none;
+    content: "";
+    width: 100%;
+    height: 50px;
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    opacity: 1;
+    transition: opacity 0.3s ease;
+    background: linear-gradient(transparent 0px, var(--light));
+  }*/
+}
+
+button#mobile-explorer,
+button#desktop-explorer {
   background-color: transparent;
   border: none;
   text-align: left;
@@ -9,7 +90,7 @@
   display: flex;
   align-items: center;
 
-  & h1 {
+  & h2 {
     font-size: 1rem;
     display: inline-block;
     margin: 0;
@@ -43,12 +124,20 @@
 #explorer-content {
   list-style: none;
   overflow: hidden;
-  max-height: none;
-  transition: max-height 0.35s ease;
+  overflow-y: auto;
+  max-height: 0px;
+  transition:
+    max-height 0.35s ease,
+    visibility 0s linear 0.35s;
   margin-top: 0.5rem;
+  visibility: hidden;
 
-  &.collapsed > .overflow::after {
-    opacity: 0;
+  &.collapsed {
+    max-height: 100%;
+    transition:
+      max-height 0.35s ease,
+      visibility 0s linear 0s;
+    visibility: visible;
   }
 
   & ul {
@@ -59,12 +148,17 @@
       max-height 0.35s ease,
       transform 0.35s ease,
       opacity 0.2s ease;
+
     & li > a {
       color: var(--dark);
       opacity: 0.75;
       pointer-events: all;
     }
   }
+
+  > #explorer-ul {
+    max-height: none;
+  }
 }
 
 svg {
@@ -85,7 +179,7 @@
     color: var(--secondary);
     font-family: var(--headerFont);
     font-size: 0.95rem;
-    font-weight: 600;
+    font-weight: $semiBoldWeight;
     line-height: 1.5rem;
     display: inline-block;
   }
@@ -106,11 +200,11 @@
     align-items: center;
     font-family: var(--headerFont);
 
-    & p {
+    & span {
       font-size: 0.95rem;
       display: inline-block;
       color: var(--secondary);
-      font-weight: 600;
+      font-weight: $semiBoldWeight;
       margin: 0;
       line-height: 1.5rem;
       pointer-events: none;
@@ -126,7 +220,7 @@
   backface-visibility: visible;
 }
 
-div:has(> .folder-outer:not(.open)) > .folder-container > svg {
+li:has(> .folder-outer:not(.open)) > .folder-container > svg {
   transform: rotate(-90deg);
 }
 
@@ -144,3 +238,80 @@
   // remove default margin from li
   margin: 0;
 }
+
+.explorer {
+  @media all and ($mobile) {
+    #explorer-content {
+      box-sizing: border-box;
+      overscroll-behavior: none;
+      z-index: 100;
+      position: absolute;
+      top: 0;
+      background-color: var(--light);
+      max-width: 100dvw;
+      left: -100dvw;
+      width: 100%;
+      transition: transform 300ms ease-in-out;
+      overflow: hidden;
+      padding: $topSpacing 2rem 2rem;
+      height: 100dvh;
+      max-height: 100dvh;
+      margin-top: 0;
+      visibility: hidden;
+
+      &:not(.collapsed) {
+        transform: translateX(100dvw);
+        visibility: visible;
+      }
+
+      ul.overflow {
+        max-height: 100%;
+        width: 100%;
+      }
+
+      &.collapsed {
+        transform: translateX(0);
+        visibility: visible;
+      }
+    }
+
+    #mobile-explorer {
+      margin: 5px;
+      z-index: 101;
+
+      &:not(.collapsed) .lucide-menu {
+        transform: rotate(-90deg);
+        transition: transform 200ms ease-in-out;
+      }
+
+      .lucide-menu {
+        stroke: var(--darkgray);
+        transition: transform 200ms ease;
+
+        &:hover {
+          stroke: var(--dark);
+        }
+      }
+    }
+  }
+}
+
+.no-scroll {
+  opacity: 0;
+  overflow: hidden;
+}
+
+html:has(.no-scroll) {
+  overflow: hidden;
+}
+
+@media all and not ($mobile) {
+  .no-scroll {
+    opacity: 1 !important;
+    overflow: auto !important;
+  }
+
+  html:has(.no-scroll) {
+    overflow: auto !important;
+  }
+}

--
Gitblit v1.10.0