« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/static
diff options
context:
space:
mode:
Diffstat (limited to 'src/static')
-rw-r--r--src/static/css/miscellany.css2
-rw-r--r--src/static/css/responsive.css2
-rw-r--r--src/static/css/search.css63
-rw-r--r--src/static/css/tooltips.css8
-rw-r--r--src/static/js/client/index.js2
-rw-r--r--src/static/js/client/sidebar-search.js109
6 files changed, 135 insertions, 51 deletions
diff --git a/src/static/css/miscellany.css b/src/static/css/miscellany.css
index 70120a33..dcdd72ca 100644
--- a/src/static/css/miscellany.css
+++ b/src/static/css/miscellany.css
@@ -478,7 +478,9 @@
     font-weight: normal;
     color: var(--primary-color);
   }
+}
 
+@layer interaction {
   summary > span:hover {
     cursor: pointer;
     text-decoration: underline;
diff --git a/src/static/css/responsive.css b/src/static/css/responsive.css
index 86cd7eb6..38e4188a 100644
--- a/src/static/css/responsive.css
+++ b/src/static/css/responsive.css
@@ -106,7 +106,7 @@
   }
 
   .wiki-search-sidebar-box {
-    max-height: max(245px, 60vh, calc(100vh - 205px));
+    --keep-viewport-visible: 205px;
   }
 
   /* End duplicated for "sidebars in content column" */
diff --git a/src/static/css/search.css b/src/static/css/search.css
index f421803b..3c56eed6 100644
--- a/src/static/css/search.css
+++ b/src/static/css/search.css
@@ -5,11 +5,17 @@
     padding: 1px 0 0 0;
 
     z-index: 100;
-    max-height: calc(100vh - 20px);
+
+    --keep-viewport-visible: 125px;
+    max-height: max(245px, 60vh, calc(100vh - var(--keep-viewport-visible)));
 
     display: flex;
     flex-direction: column;
   }
+
+  #banner.short ~ * .wiki-search-sidebar-box {
+    --keep-viewport-visible: 180px;
+  }
 }
 
 @layer material {
@@ -32,17 +38,20 @@
 
 /* Interactions with other sidebar boxes */
 
-@layer interaction {
-  /* This is to say, any sidebar that's *not*
-   * the first sidebar after the search box.
+@layer layout {
+  /* This is to say, any sidebar that's *not* the first sidebar
+   * after the search box, effectively squishing the rest of the
+   * boxes a bit tighter together.
    */
   .wiki-search-sidebar-box.showing-results + .sidebar ~ .sidebar {
-    margin-top: 5px;
+    margin-top: 8px;
   }
+}
 
+@layer interaction {
   .wiki-search-sidebar-box.showing-results ~ .sidebar:not(:hover) {
     opacity: 0.8;
-    filter: brightness(0.7);
+    filter: brightness(0.85);
   }
 }
 
@@ -191,6 +200,8 @@
 @layer layout {
   .wiki-search-context-container {
     padding: 2px 12px 4px;
+    padding-left: calc(12px + 1.2ch);
+    text-indent: -1.2ch;
   }
 }
 
@@ -322,11 +333,51 @@
 
 @layer layout {
   .wiki-search-results-container {
+    position: relative;
     margin-bottom: 0;
     padding: 2px;
   }
 }
 
+@layer interaction {
+  .wiki-search-results-container::before,
+  .wiki-search-results-container::after {
+    content: "";
+    display: block;
+    position: sticky;
+    pointer-events: none;
+    z-index: 1;
+  }
+
+  .wiki-search-result:hover {
+    z-index: 2;
+  }
+
+  /* Shadow along top edge */
+
+  .wiki-search-results-container > :first-child {
+    margin-top: -4px;
+  }
+
+  .wiki-search-results-container::before {
+    height: 8px; top: -2px;
+    background: linear-gradient(to bottom, black, black 50%, transparent);
+    opacity: 0.4;
+  }
+
+  /* Shadow along bottom edge */
+
+  .wiki-search-results-container > :last-child {
+    margin-bottom: -10px;
+  }
+
+  .wiki-search-results-container::after {
+    height: 16px; bottom: -2px;
+    background: linear-gradient(to top, black, black 30%, transparent);
+    opacity: 0.4;
+  }
+}
+
 /* Basic result styling, including interactions */
 
 @layer layout {
diff --git a/src/static/css/tooltips.css b/src/static/css/tooltips.css
index 644430b7..116c9181 100644
--- a/src/static/css/tooltips.css
+++ b/src/static/css/tooltips.css
@@ -416,10 +416,6 @@
     display: inline-block;
   }
 
-  .content-tooltip-guy:not(.has-link) .hoverable {
-    cursor: default;
-  }
-
   .content-tooltip-guy.has-link .text-with-tooltip-interaction-cue {
     text-decoration-color: var(--primary-color);
   }
@@ -438,6 +434,10 @@
 }
 
 @layer interaction {
+  .content-tooltip-guy:not(.has-link) .hoverable {
+    cursor: default;
+  }
+
   .content-tooltip-guy .hoverable a {
     text-decoration-color: transparent;
     text-decoration-style: dotted;
diff --git a/src/static/js/client/index.js b/src/static/js/client/index.js
index 16ebe89f..cd617bea 100644
--- a/src/static/js/client/index.js
+++ b/src/static/js/client/index.js
@@ -133,7 +133,7 @@ for (const module of modules) {
             break;
 
           case 'boolean':
-            formatRead = Boolean;
+            formatRead = value => value === 'true' ? true : false;
             formatWrite = String;
             break;
 
diff --git a/src/static/js/client/sidebar-search.js b/src/static/js/client/sidebar-search.js
index 8b29cf63..7b01cb00 100644
--- a/src/static/js/client/sidebar-search.js
+++ b/src/static/js/client/sidebar-search.js
@@ -38,6 +38,9 @@ export const info = {
   searchLabel: null,
   searchInput: null,
 
+  contextContainer: null,
+  contextBackLink: null,
+
   progressRule: null,
   progressContainer: null,
   progressLabel: null,
@@ -46,9 +49,6 @@ export const info = {
   failedRule: null,
   failedContainer: null,
 
-  contextContainer: null,
-  contextBackLink: null,
-
   filterContainer: null,
   albumFilterLink: null,
   artistFilterLink: null,
@@ -106,6 +106,8 @@ export const info = {
     recallingRecentSearch: null,
     recallingRecentSearchFromMouse: null,
 
+    justPerformedActiveQuery: false,
+
     currentValue: null,
 
     workerStatus: null,
@@ -127,6 +129,7 @@ export const info = {
     activeQueryContextPageName: {type: 'string'},
     activeQueryContextPagePathname: {type: 'string'},
     activeQueryContextPageColor: {type: 'string'},
+    zapActiveQueryContext: {type: 'boolean'},
 
     activeQueryResults: {
       type: 'json',
@@ -163,6 +166,8 @@ export function* bindSessionStorage() {
     yield 'activeQueryContextPageName';
     yield 'activeQueryContextPagePathname';
     yield 'activeQueryContextPageColor';
+    yield 'zapActiveQueryContext';
+
     yield 'activeQueryResults';
     yield 'activeFilterType';
     yield 'resultsScrollOffset';
@@ -302,6 +307,25 @@ export function addInternalListeners() {
 export function mutatePageContent() {
   if (!info.searchBox) return;
 
+  // Context section
+
+  info.contextContainer =
+    document.createElement('div');
+
+  info.contextContainer.classList.add('wiki-search-context-container');
+
+  info.contextBackLink =
+    document.createElement('a');
+
+  info.contextContainer.appendChild(
+    templateContent(info.backString, {
+      page: info.contextBackLink,
+    }));
+
+  cssProp(info.contextContainer, 'display', 'none');
+
+  info.searchBox.appendChild(info.contextContainer);
+
   // Progress section
 
   info.progressRule =
@@ -355,25 +379,6 @@ export function mutatePageContent() {
   info.searchBox.appendChild(info.failedRule);
   info.searchBox.appendChild(info.failedContainer);
 
-  // Context section
-
-  info.contextContainer =
-    document.createElement('div');
-
-  info.contextContainer.classList.add('wiki-search-context-container');
-
-  info.contextBackLink =
-    document.createElement('a');
-
-  info.contextContainer.appendChild(
-    templateContent(info.backString, {
-      page: info.contextBackLink,
-    }));
-
-  cssProp(info.contextContainer, 'display', 'none');
-
-  info.searchBox.appendChild(info.contextContainer);
-
   // Filter section
 
   info.filterContainer =
@@ -582,7 +587,6 @@ export function addPageListeners() {
     clearSidebarSearch();
     clearSidebarFilter();
     possiblyHideSearchSidebarColumn();
-    restoreSidebarSearchColumn();
   });
 
   forEachFilter((type, filterLink) => {
@@ -728,6 +732,7 @@ async function activateSidebarSearch(query) {
     return;
   }
 
+  state.justPerformedActiveQuery = true;
   state.searchStage = 'complete';
   updateSidebarSearchStatus();
 
@@ -750,6 +755,20 @@ function recordActiveQueryContext() {
   const {session} = info;
 
   if (document.documentElement.dataset.urlKey === 'localized.home') {
+    session.activeQueryContextPageName = null;
+    session.activeQueryContextPagePathname = null;
+    session.activeQueryContextPageColor = null;
+    session.zapActiveQueryContext = true;
+    return;
+  }
+
+  // Zapping means subsequent searches don't record context.
+  if (session.zapActiveQueryContext) {
+    return;
+  }
+
+  // We also don't overwrite existing context.
+  if (session.activeQueryContextPagePathname) {
     return;
   }
 
@@ -779,12 +798,24 @@ function clearSidebarSearch() {
   info.searchInput.value = '';
 
   state.searchStage = null;
+  state.justPerformedActiveQuery = false;
+
+  clearActiveQuery();
+
+  hideSidebarSearchResults();
+}
+
+function clearActiveQuery() {
+  const {session} = info;
 
   session.activeQuery = null;
   session.activeQueryResults = null;
   session.resultsScrollOffset = null;
 
-  hideSidebarSearchResults();
+  session.activeQueryContextPageName = null;
+  session.activeQueryContextPagePathname = null;
+  session.activeQueryContextPageColor = null;
+  session.zapActiveQueryContext = false;
 }
 
 function clearSidebarFilter() {
@@ -1355,6 +1386,8 @@ function hideSidebarSearchResults() {
 
   cssProp(info.endSearchRule, 'display', 'none');
   cssProp(info.endSearchLine, 'display', 'none');
+
+  restoreSidebarSearchColumn();
 }
 
 function focusFirstSidebarSearchResult() {
@@ -1438,7 +1471,7 @@ function possiblyHideSearchSidebarColumn() {
 // This should be called after results are shown, since it checks the
 // elements added to understand the current search state.
 function tidySidebarSearchColumn() {
-  const {state} = info;
+  const {session, state} = info;
 
   // Don't *re-tidy* the sidebar if we've already tidied it to display
   // some results. This flag will get cleared if the search is dismissed
@@ -1447,17 +1480,24 @@ function tidySidebarSearchColumn() {
     return;
   }
 
-  const here = location.href.replace(/\/$/, '');
+  const hrefHere = location.href.replace(/\/$/, '');
   const currentPageIsResult =
     Array.from(info.results.querySelectorAll('a'))
       .some(link => {
-        const there = link.href.replace(/\/$/, '');
-        return here === there;
+        const hrefThere = link.href.replace(/\/$/, '');
+        return hrefHere === hrefThere;
       });
 
+  const currentPageIsContext =
+    location.pathname === session.activeQueryContextPagePathname;
+
   // Don't tidy the sidebar if you've navigated to some other page than
   // what's in the current result list.
-  if (!currentPageIsResult) {
+  if (
+    !state.justPerformedActiveQuery &&
+    !currentPageIsResult &&
+    !currentPageIsContext
+  ) {
     return;
   }
 
@@ -1537,16 +1577,7 @@ function considerRecallingRecentSidebarSearch() {
 }
 
 function forgetRecentSidebarSearch() {
-  const {session} = info;
-
-  session.activeQuery = null;
-
-  session.activeQueryContextPageName = null;
-  session.activeQueryContextPagePathname = null;
-  session.activeQueryContextPageColor = null;
-
-  session.activeQueryResults = null;
-
+  clearActiveQuery();
   clearSidebarFilter();
 }