mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-05 12:22:28 +00:00
Merge pull request #329 from PR0M3TH3AN/codex/implement-collapsible-sidebar-on-desktop
Improve desktop sidebar collapse behavior
This commit is contained in:
13 files changed
+645
-303
No files matched your search
@@ -70,6 +70,11 @@ Document the run in PR descriptions so QA can cross-reference results.
|
||||
* **Probing:** Lightweight `HEAD`/`GET` requests should back `probeUrl()` so dead URLs can be hidden or flagged without blocking the UI.
|
||||
* **Extensibility:** Future work (live streams, NIP-96 uploads, analytics) should preserve the URL-first strategy and magnet safety rules above.
|
||||
* **Sidebar layering:** Keep the fixed sidebar below every modal and overlay. Respect the `--z-sidebar*` tokens so dialogs always render on top of the navigation.
|
||||
* **Static asset cache busting:** The CDN aggressively caches `components/sidebar.html` and CSS/JS bundles. Update `config/asset-version.js` and keep the `?v=` query strings in `index.html` (and iframe form shells) in sync whenever you change sidebar markup, scripts, or styles. The fetch helpers in `js/index.js` already append `cache: "no-store"`; reuse them for new partials so desktop collapses ship immediately without waiting on manual cache clears.
|
||||
* **View partial cache busting:** The `views/*.html` files are served from the same CDN tier and require the asset version suffix as well. `js/viewManager.js` now appends `?v=<ASSET_VERSION>` when loading views—keep that helper in place so layout or styling updates propagate on the first refresh.
|
||||
* **Sidebar overflow styling:** `#sidebar` now owns vertical scrolling with `overflow-y: auto` while keeping `overflow-x: visible` so the gradient panel’s drop shadow can spill onto the page. The nested `.sidebar-scroll` wrapper must remain `overflow: visible`; do not reintroduce hidden overflow on any ancestor or the shadow will clip again.
|
||||
* **Collapsed rail padding:** The collapsed rail keeps icons full-size by pairing reduced padding on `.sidebar__inner` and `.sidebar-panel` with the shared `--sidebar-control-size` (2.75 rem). Update the trio together so the 4 rem rail still fits the circular toggle/dropup buttons without squishing the gradients.
|
||||
* **Collapsed nav width:** Collapsed links rely on `width: var(--sidebar-control-size)` plus `margin-inline: auto` to keep every glyph aligned with the circular toggle and footer trigger. Preserve that sizing or the icons will drift off the gradient panel.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<title>bitvid Whitelist Application Form</title>
|
||||
<!-- Link to your main stylesheet -->
|
||||
<link rel="stylesheet" href="../../css/style.css" />
|
||||
<link rel="stylesheet" href="../../css/style.css?v=2024.10.22" />
|
||||
<style>
|
||||
/* Override for form page to match modal field styling */
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<title>bitvid Bug Report Form</title>
|
||||
<!-- Link to your main stylesheet -->
|
||||
<link rel="stylesheet" href="../../css/style.css" />
|
||||
<link rel="stylesheet" href="../../css/style.css?v=2024.10.22" />
|
||||
<style>
|
||||
/* Override for form page to match modal field styling */
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<title>bitvid Content Appeals Form</title>
|
||||
<!-- Link to your main stylesheet -->
|
||||
<link rel="stylesheet" href="../../css/style.css" />
|
||||
<link rel="stylesheet" href="../../css/style.css?v=2024.10.22" />
|
||||
<style>
|
||||
/* Override for form page to match modal field styling */
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<title>bitvid General Feedback Form</title>
|
||||
<!-- Link to your main stylesheet -->
|
||||
<link rel="stylesheet" href="../../css/style.css" />
|
||||
<link rel="stylesheet" href="../../css/style.css?v=2024.10.22" />
|
||||
<style>
|
||||
/* Override for form page to match modal field styling */
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8" />
|
||||
<title>bitvid Feature Request Form</title>
|
||||
<!-- Link to your main stylesheet -->
|
||||
<link rel="stylesheet" href="../../css/style.css" />
|
||||
<link rel="stylesheet" href="../../css/style.css?v=2024.10.22" />
|
||||
<style>
|
||||
/* Override for form page to match modal field styling */
|
||||
|
||||
|
||||
+116
-129
@@ -5,25 +5,27 @@
|
||||
-->
|
||||
<aside
|
||||
id="sidebar"
|
||||
class="bg-gray-900 text-white transition-transform duration-300 ease-in-out fixed top-0 left-0 w-64 h-screen overflow-y-auto fade-in fade-in-delay-100"
|
||||
class="fade-in fade-in-delay-100 sidebar-collapsed"
|
||||
data-state="collapsed"
|
||||
>
|
||||
<div class="flex flex-col h-full">
|
||||
<!-- Top Navigation Links -->
|
||||
<div class="flex-1 overflow-y-auto px-4">
|
||||
<div class="bg-gray-800 rounded-lg shadow-md mt-4 p-4">
|
||||
<div class="hidden md:flex justify-end mb-2">
|
||||
<div class="sidebar__inner">
|
||||
<div class="sidebar-scroll">
|
||||
<!-- Primary navigation -->
|
||||
<section class="sidebar-panel sidebar-panel--primary">
|
||||
<div class="sidebar-panel__header">
|
||||
<button
|
||||
id="sidebarCollapseToggle"
|
||||
type="button"
|
||||
class="flex items-center space-x-2 text-sm font-semibold text-gray-100"
|
||||
class="sidebar-collapse-toggle"
|
||||
aria-controls="sidebar"
|
||||
aria-expanded="true"
|
||||
aria-expanded="false"
|
||||
aria-label="Expand sidebar"
|
||||
title="Expand sidebar"
|
||||
>
|
||||
<span class="sr-only">Toggle sidebar</span>
|
||||
<span class="sidebar-toggle-label">Collapse</span>
|
||||
<svg
|
||||
data-sidebar-chevron
|
||||
class="w-4 h-4 transform transition-transform duration-300"
|
||||
class="sidebar-collapse-toggle__icon sidebar-toggle-icon--rotated"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
@@ -36,144 +38,141 @@
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<nav class="flex flex-col space-y-2">
|
||||
<a
|
||||
href="#view=most-recent-videos"
|
||||
class="flex items-center py-2 px-4 hover:bg-gray-700 rounded font-semibold"
|
||||
>
|
||||
<nav class="sidebar-nav" aria-label="Primary">
|
||||
<a href="#view=most-recent-videos" class="sidebar-nav-link" title="Recent">
|
||||
<img
|
||||
src="assets/svg/recent-icon.svg"
|
||||
alt="Recent"
|
||||
class="w-6 h-6 mr-3 flex-shrink-0"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">Recent</span>
|
||||
</a>
|
||||
<a
|
||||
href="#view=explore"
|
||||
class="flex items-center py-2 px-4 hover:bg-gray-700 rounded font-semibold"
|
||||
>
|
||||
<a href="#view=explore" class="sidebar-nav-link" title="Explore">
|
||||
<img
|
||||
src="assets/svg/explore-icon.svg"
|
||||
alt="Explore"
|
||||
class="w-6 h-6 mr-3 flex-shrink-0"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">Explore</span>
|
||||
</a>
|
||||
<a
|
||||
href="#view=history"
|
||||
class="flex items-center py-2 px-4 hover:bg-gray-700 rounded font-semibold"
|
||||
>
|
||||
<a href="#view=history" class="sidebar-nav-link" title="History">
|
||||
<img
|
||||
src="assets/svg/history-icon.svg"
|
||||
alt="History"
|
||||
class="w-6 h-6 mr-3 flex-shrink-0"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">History</span>
|
||||
</a>
|
||||
<a
|
||||
id="subscriptionsLink"
|
||||
href="#view=subscriptions"
|
||||
class="hidden flex items-center py-2 px-4 hover:bg-gray-700 rounded font-semibold"
|
||||
class="sidebar-nav-link hidden"
|
||||
title="Subscriptions"
|
||||
>
|
||||
<img
|
||||
src="assets/svg/subscriptions-icon.svg"
|
||||
alt="Subscriptions"
|
||||
class="w-6 h-6 mr-3 flex-shrink-0"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">Subscriptions</span>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer Links Toggle -->
|
||||
<div class="md:mt-auto">
|
||||
<div class="p-4">
|
||||
<!-- Footer Links Toggle -->
|
||||
<footer class="sidebar-footer" data-footer-state="collapsed">
|
||||
<button
|
||||
id="footerDropdownButton"
|
||||
type="button"
|
||||
class="flex items-center w-full py-2 px-4 bg-gray-800 hover:bg-gray-700 text-sm font-semibold text-gray-100 rounded shadow-md focus:outline-none transition-colors duration-200"
|
||||
class="sidebar-dropup-trigger"
|
||||
aria-expanded="false"
|
||||
aria-controls="footerLinksContainer"
|
||||
>
|
||||
<!-- Arrow on the left side -->
|
||||
<img
|
||||
src="assets/svg/ellipsis.svg"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon sidebar-dropup-trigger__glyph"
|
||||
/>
|
||||
<span id="footerDropdownText" class="sidebar-text">More</span>
|
||||
<svg
|
||||
id="footerDropdownIcon"
|
||||
class="w-4 h-4 mr-2 transform transition-transform duration-300"
|
||||
class="sidebar-dropup-trigger__chevron"
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
|
||||
<path d="M6 9l6 6 6-6" />
|
||||
</svg>
|
||||
<span id="footerDropdownText">More</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Footer Links Container -->
|
||||
<div id="footerLinksContainer" class="hidden">
|
||||
<hr class="border-gray-700" />
|
||||
<div class="p-4">
|
||||
<nav class="space-y-2 text-sm opacity-70">
|
||||
<a
|
||||
href="#view=about"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
>
|
||||
<!-- Footer Links Container -->
|
||||
<div
|
||||
id="footerLinksContainer"
|
||||
class="sidebar-dropup-panel"
|
||||
aria-hidden="true"
|
||||
data-state="collapsed"
|
||||
>
|
||||
<nav class="sidebar-dropup-panel__inner" aria-label="Secondary">
|
||||
<a href="#view=about" class="sidebar-nav-link sidebar-nav-link--sub" title="About">
|
||||
<img
|
||||
src="assets/svg/about-icon.svg"
|
||||
alt="About"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">About</span>
|
||||
</a>
|
||||
<a
|
||||
href="#view=community-guidelines"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
class="sidebar-nav-link sidebar-nav-link--sub"
|
||||
title="Community Guidelines"
|
||||
>
|
||||
<img
|
||||
src="assets/svg/guidelines-icon.svg"
|
||||
alt="Guidelines"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">Guidelines</span>
|
||||
</a>
|
||||
<a
|
||||
href="#view=getting-started"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
class="sidebar-nav-link sidebar-nav-link--sub"
|
||||
title="Getting Started"
|
||||
>
|
||||
<img
|
||||
src="assets/svg/getting-started-icon.svg"
|
||||
alt="Getting Started"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">Getting Started</span>
|
||||
</a>
|
||||
<a
|
||||
href="#view=roadmap"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
>
|
||||
<a href="#view=roadmap" class="sidebar-nav-link sidebar-nav-link--sub" title="Roadmap">
|
||||
<img
|
||||
src="assets/svg/roadmap-icon.svg"
|
||||
alt="Roadmap"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">Roadmap</span>
|
||||
</a>
|
||||
<a
|
||||
href="#view=blog"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
>
|
||||
<a href="#view=blog" class="sidebar-nav-link sidebar-nav-link--sub" title="Blog">
|
||||
<img
|
||||
src="assets/svg/blog-icon.svg"
|
||||
alt="Blog"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">Blog</span>
|
||||
</a>
|
||||
@@ -181,12 +180,14 @@
|
||||
href="https://primal.net/p/npub13yarr7j6vjqjjkahd63dmr27curypehx45ucue286ac7sft27y0srnpmpe"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
class="sidebar-nav-link sidebar-nav-link--sub"
|
||||
title="Nostr"
|
||||
>
|
||||
<img
|
||||
src="assets/svg/nostr-icon.svg"
|
||||
alt="Nostr"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">Nostr</span>
|
||||
</a>
|
||||
@@ -194,12 +195,14 @@
|
||||
href="https://github.com/PR0M3TH3AN/bitvid"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
class="sidebar-nav-link sidebar-nav-link--sub"
|
||||
title="GitHub"
|
||||
>
|
||||
<img
|
||||
src="assets/svg/github-icon.svg"
|
||||
alt="GitHub"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">GitHub</span>
|
||||
</a>
|
||||
@@ -207,12 +210,14 @@
|
||||
href="torrent/beacon.html"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
class="sidebar-nav-link sidebar-nav-link--sub"
|
||||
title="βeacon"
|
||||
>
|
||||
<img
|
||||
src="assets/svg/beacon-icon.svg"
|
||||
alt="βeacon"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">βeacon</span>
|
||||
</a>
|
||||
@@ -220,34 +225,32 @@
|
||||
href="https://beta.bitvid.network/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
class="sidebar-nav-link sidebar-nav-link--sub"
|
||||
title="Beta"
|
||||
>
|
||||
<img
|
||||
src="assets/svg/beta-icon.svg"
|
||||
alt="Beta"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">Beta</span>
|
||||
</a>
|
||||
<a
|
||||
href="#view=links"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
>
|
||||
<a href="#view=links" class="sidebar-nav-link sidebar-nav-link--sub" title="Links">
|
||||
<img
|
||||
src="assets/svg/links-icon.svg"
|
||||
alt="Links"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">Links</span>
|
||||
</a>
|
||||
<a
|
||||
href="#view=ipns"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
>
|
||||
<a href="#view=ipns" class="sidebar-nav-link sidebar-nav-link--sub" title="IPNS">
|
||||
<img
|
||||
src="assets/svg/ipns-icon.svg"
|
||||
alt="IPNS"
|
||||
class="w-5 h-5 mr-3"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">IPNS</span>
|
||||
</a>
|
||||
@@ -255,36 +258,20 @@
|
||||
href="https://bitvid.network/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="flex items-center hover:bg-gray-800 px-4 py-2 rounded"
|
||||
class="sidebar-nav-link sidebar-nav-link--sub"
|
||||
title="DNS"
|
||||
>
|
||||
<img src="assets/svg/dns-icon.svg" alt="DNS" class="w-5 h-5 mr-3" />
|
||||
<img
|
||||
src="assets/svg/dns-icon.svg"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="sidebar-icon"
|
||||
/>
|
||||
<span class="sidebar-text">DNS</span>
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var btn = document.getElementById("footerDropdownButton");
|
||||
var footerLinks = document.getElementById("footerLinksContainer");
|
||||
if (btn && footerLinks) {
|
||||
btn.addEventListener("click", function () {
|
||||
footerLinks.classList.toggle("hidden");
|
||||
var isHidden = footerLinks.classList.contains("hidden");
|
||||
btn.setAttribute("aria-expanded", String(!isHidden));
|
||||
var icon = document.getElementById("footerDropdownIcon");
|
||||
var textSpan = document.getElementById("footerDropdownText");
|
||||
if (textSpan) {
|
||||
textSpan.textContent = isHidden ? "More" : "Less";
|
||||
}
|
||||
if (icon) {
|
||||
icon.classList.toggle("rotate-180", !isHidden);
|
||||
}
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</aside>
|
||||
@@ -0,0 +1 @@
|
||||
export const ASSET_VERSION = "2024.10.22";
|
||||
+360
-109
@@ -1,10 +1,18 @@
|
||||
:root {
|
||||
--color-bg: #0f172a;
|
||||
/*
|
||||
Core palette tokens used across the application.
|
||||
--color-page keeps the primary content surface neutral while --color-surface
|
||||
powers the dark shells (sidebar, dialogs, cards).
|
||||
*/
|
||||
--color-page: #ffffff;
|
||||
--color-surface: #0f172a;
|
||||
--color-bg: var(--color-surface);
|
||||
--color-card: #1e293b;
|
||||
--color-primary: #fe0032;
|
||||
--color-secondary: #ff93a5;
|
||||
--color-card-critical: #3f0b13;
|
||||
--color-text: #f8fafc;
|
||||
--color-text-strong: #0f172a;
|
||||
--color-muted: #94a3b8;
|
||||
--shadow-sm: 0 0.0625rem 0.125rem 0 rgb(0 0 0 / 0.05);
|
||||
--shadow-md: 0 0.25rem 0.375rem -0.0625rem rgb(0 0 0 / 0.1);
|
||||
@@ -21,6 +29,10 @@
|
||||
--z-modal-overlay: 70;
|
||||
--z-modal-content: 90;
|
||||
--z-modal-player: 120;
|
||||
--sidebar-width-expanded: 16rem;
|
||||
--sidebar-width-collapsed: 4rem;
|
||||
--sidebar-width: var(--sidebar-width-expanded);
|
||||
--sidebar-control-size: 2.75rem;
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -60,14 +72,23 @@ html {
|
||||
/* Core Styles */
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
background-color: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-page);
|
||||
color: var(--color-text-strong);
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden; /* Disable horizontal scrolling */
|
||||
}
|
||||
|
||||
#app {
|
||||
/*
|
||||
Keep the primary content surface aligned with the page background so the
|
||||
sidebar styling does not bleed into the video grid.
|
||||
*/
|
||||
background-color: var(--color-page);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
header {
|
||||
margin-bottom: 2rem;
|
||||
padding: 1rem 0;
|
||||
@@ -1448,22 +1469,271 @@ footer a:hover {
|
||||
}
|
||||
|
||||
/* Sidebar default states */
|
||||
#sidebarContainer {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 16rem; /* Tailwind's w-64 */
|
||||
width: var(--sidebar-width);
|
||||
min-width: var(--sidebar-width);
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
background-color: #0f172a;
|
||||
background-color: transparent;
|
||||
color: var(--color-text);
|
||||
overflow-x: visible;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-gutter: stable both-edges;
|
||||
transition: width 200ms ease, transform 0.3s ease, box-shadow 0.3s ease;
|
||||
/* Keep below modal stacks so dialogs overlay the drawer. */
|
||||
z-index: var(--z-sidebar);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
#sidebar .sidebar__inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 1.5rem 1.25rem 1.75rem;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
/*
|
||||
Allow the gradient panel shadow to breathe outside the rail while a nested
|
||||
scroll container handles overflow.
|
||||
*/
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/*
|
||||
The scroll wrapper keeps nav + footer together while leaving overflow
|
||||
visible so the gradient card shadow is never clipped.
|
||||
*/
|
||||
.sidebar-scroll {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
flex: 1 1 auto;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.sidebar-panel {
|
||||
background: linear-gradient(
|
||||
160deg,
|
||||
rgba(30, 41, 59, 0.92) 0%,
|
||||
rgba(15, 23, 42, 0.92) 100%
|
||||
);
|
||||
border: 1px solid rgba(148, 163, 184, 0.18);
|
||||
border-radius: 1rem;
|
||||
box-shadow: 0 1.25rem 2.5rem rgba(15, 23, 42, 0.35);
|
||||
padding: 1.25rem 1rem;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.sidebar-panel--primary {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.sidebar-panel__header {
|
||||
display: none;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.sidebar-collapse-toggle {
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--sidebar-control-size);
|
||||
height: var(--sidebar-control-size);
|
||||
border-radius: 9999px;
|
||||
border: 1px solid rgba(148, 163, 184, 0.2);
|
||||
background: rgba(148, 163, 184, 0.08);
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
transition: background 180ms ease, color 180ms ease, border-color 180ms ease;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sidebar-collapse-toggle:hover {
|
||||
background: rgba(148, 163, 184, 0.18);
|
||||
border-color: rgba(148, 163, 184, 0.35);
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.sidebar-collapse-toggle:focus-visible {
|
||||
outline: 0.125rem solid var(--color-secondary);
|
||||
outline-offset: 0.25rem;
|
||||
}
|
||||
|
||||
.sidebar-collapse-toggle__icon {
|
||||
width: 1.125rem;
|
||||
height: 1.125rem;
|
||||
transition: transform 200ms ease;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
opacity: 1;
|
||||
transition: opacity 160ms ease;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar-nav-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.625rem 0.875rem;
|
||||
min-height: var(--sidebar-control-size);
|
||||
border-radius: 0.875rem;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
color: rgba(226, 232, 240, 0.94);
|
||||
text-decoration: none;
|
||||
transition: background 160ms ease, color 160ms ease, transform 160ms ease;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.sidebar-nav-link:hover {
|
||||
background: rgba(148, 163, 184, 0.18);
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.sidebar-nav-link:focus-visible {
|
||||
outline: 0.125rem solid var(--color-secondary);
|
||||
outline-offset: 0.25rem;
|
||||
}
|
||||
|
||||
.sidebar-nav-link--sub {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
color: rgba(226, 232, 240, 0.82);
|
||||
padding-block: 0.55rem;
|
||||
}
|
||||
|
||||
.sidebar-icon {
|
||||
/* Lock icon sizing so the glyphs remain steady during collapse/expand. */
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
min-width: 1.5rem;
|
||||
min-height: 1.5rem;
|
||||
flex-shrink: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
margin-top: auto;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.sidebar-dropup-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
width: 100%;
|
||||
padding: 0.75rem 0.875rem;
|
||||
min-height: var(--sidebar-control-size);
|
||||
border-radius: 0.875rem;
|
||||
border: 1px solid rgba(148, 163, 184, 0.18);
|
||||
background: rgba(30, 41, 59, 0.85);
|
||||
color: rgba(226, 232, 240, 0.9);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
|
||||
box-sizing: border-box;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sidebar-dropup-trigger:hover {
|
||||
background: rgba(51, 65, 85, 0.95);
|
||||
border-color: rgba(148, 163, 184, 0.32);
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.sidebar-dropup-trigger:focus-visible {
|
||||
outline: 0.125rem solid var(--color-secondary);
|
||||
outline-offset: 0.25rem;
|
||||
}
|
||||
|
||||
.sidebar-dropup-trigger__glyph {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.sidebar-dropup-trigger__chevron {
|
||||
width: 1.125rem;
|
||||
height: 1.125rem;
|
||||
transition: transform 180ms ease;
|
||||
}
|
||||
|
||||
.sidebar-dropup-trigger__chevron.is-rotated,
|
||||
.sidebar-dropup-trigger[aria-expanded="true"] .sidebar-dropup-trigger__chevron {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.sidebar-dropup-panel {
|
||||
background: rgba(15, 23, 42, 0.88);
|
||||
border: 1px solid rgba(148, 163, 184, 0.18);
|
||||
border-radius: 0.875rem;
|
||||
box-shadow: 0 1.5rem 3rem rgba(15, 23, 42, 0.4);
|
||||
padding: 0.75rem 0.5rem;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: calc(100% + 0.75rem);
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
transform: translateY(0.5rem);
|
||||
transition: opacity 160ms ease, transform 160ms ease, visibility 160ms ease;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.sidebar-dropup-panel[data-state="expanded"] {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
pointer-events: auto;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.sidebar-dropup-panel__inner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
#sidebar[data-footer-state="expanded"] .sidebar-nav {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#sidebar[data-footer-state="collapsed"] .sidebar-nav {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#sidebar.sidebar-open {
|
||||
box-shadow: 0 0.75rem 1.5rem rgba(15, 23, 42, 0.45);
|
||||
}
|
||||
@@ -1491,7 +1761,7 @@ body.sidebar-open #sidebarOverlay {
|
||||
@media (max-width: 767px) {
|
||||
#sidebar {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
width: min(16rem, calc(100vw - 3rem));
|
||||
width: min(var(--sidebar-width-expanded), calc(100vw - 3rem));
|
||||
}
|
||||
/* When the sidebar-open class is added, slide the sidebar in */
|
||||
#sidebar.sidebar-open {
|
||||
@@ -1505,11 +1775,18 @@ body.sidebar-open #sidebarOverlay {
|
||||
|
||||
/* Desktop (min-width: 768px): Always show the sidebar */
|
||||
@media (min-width: 768px) {
|
||||
.sidebar-panel__header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.sidebar-collapse-toggle {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
transform: translateX(0) !important;
|
||||
width: 16rem;
|
||||
overflow-x: hidden;
|
||||
transition: width 200ms ease, transform 0.3s ease, box-shadow 0.3s ease;
|
||||
width: var(--sidebar-width);
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#sidebar.sidebar-open {
|
||||
@@ -1520,53 +1797,74 @@ body.sidebar-open #sidebarOverlay {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.sidebar-collapsed #sidebar,
|
||||
#app {
|
||||
margin-left: var(--sidebar-width);
|
||||
transition: margin-left 200ms ease;
|
||||
}
|
||||
|
||||
body.sidebar-collapsed,
|
||||
#sidebar.sidebar-collapsed {
|
||||
width: 4rem;
|
||||
--sidebar-width: var(--sidebar-width-collapsed);
|
||||
}
|
||||
|
||||
body.sidebar-expanded #sidebar,
|
||||
body.sidebar-expanded,
|
||||
#sidebar.sidebar-expanded {
|
||||
width: 16rem;
|
||||
--sidebar-width: var(--sidebar-width-expanded);
|
||||
}
|
||||
|
||||
body.sidebar-collapsed #sidebar a,
|
||||
#sidebar.sidebar-collapsed a {
|
||||
body.sidebar-collapsed #sidebar .sidebar-nav-link,
|
||||
#sidebar.sidebar-collapsed .sidebar-nav-link {
|
||||
/*
|
||||
Keep icons centered in the collapsed rail without resizing them.
|
||||
*/
|
||||
justify-content: center;
|
||||
padding-inline: 1rem;
|
||||
width: var(--sidebar-control-size);
|
||||
padding: 0;
|
||||
margin-inline: auto;
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
body.sidebar-expanded #sidebar a,
|
||||
#sidebar.sidebar-expanded a {
|
||||
body.sidebar-expanded #sidebar .sidebar-nav-link,
|
||||
#sidebar.sidebar-expanded .sidebar-nav-link {
|
||||
justify-content: flex-start;
|
||||
padding-inline: 1rem;
|
||||
}
|
||||
|
||||
body.sidebar-collapsed #sidebar a > img,
|
||||
body.sidebar-collapsed #sidebar a svg,
|
||||
#sidebar.sidebar-collapsed a > img,
|
||||
#sidebar.sidebar-collapsed a svg {
|
||||
margin-right: 0;
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
|
||||
body.sidebar-expanded #sidebar a > img,
|
||||
body.sidebar-expanded #sidebar a svg,
|
||||
#sidebar.sidebar-expanded a > img,
|
||||
#sidebar.sidebar-expanded a svg {
|
||||
margin-right: 0.75rem;
|
||||
margin-inline-end: 0.75rem;
|
||||
}
|
||||
|
||||
body.sidebar-collapsed #sidebar .sidebar-text,
|
||||
body.sidebar-collapsed #sidebar .sidebar-toggle-label,
|
||||
#sidebar.sidebar-collapsed .sidebar-text,
|
||||
#sidebar.sidebar-collapsed .sidebar-toggle-label {
|
||||
#sidebar.sidebar-collapsed .sidebar-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sidebar.sidebar-expanded .sidebar-toggle-label {
|
||||
display: inline;
|
||||
body.sidebar-collapsed #sidebar .sidebar__inner,
|
||||
#sidebar.sidebar-collapsed .sidebar__inner {
|
||||
/*
|
||||
Keep enough breathing room for the panel shadow while widening the
|
||||
interior track so var(--sidebar-control-size) controls stay perfectly
|
||||
round.
|
||||
*/
|
||||
padding-inline: 0.25rem;
|
||||
}
|
||||
|
||||
body.sidebar-collapsed #sidebar .sidebar-panel,
|
||||
#sidebar.sidebar-collapsed .sidebar-panel {
|
||||
/*
|
||||
Mirror the outer adjustment so the gradient card retains its rounded
|
||||
edges without squeezing the icon rail or clipping the control diameter.
|
||||
*/
|
||||
padding-inline: 0.375rem;
|
||||
}
|
||||
|
||||
body.sidebar-collapsed #sidebar .sidebar-panel__header,
|
||||
#sidebar.sidebar-collapsed .sidebar-panel__header {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
body.sidebar-collapsed #sidebar .sidebar-collapse-toggle,
|
||||
#sidebar.sidebar-collapsed .sidebar-collapse-toggle {
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
#sidebar .sidebar-toggle-icon--rotated {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
body.sidebar-collapsed #sidebar .sidebar-toggle-icon--rotated,
|
||||
@@ -1574,81 +1872,34 @@ body.sidebar-open #sidebarOverlay {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
body.sidebar-expanded #sidebar .sidebar-toggle-icon--rotated,
|
||||
#sidebar.sidebar-expanded .sidebar-toggle-icon--rotated {
|
||||
transform: rotate(180deg);
|
||||
body.sidebar-collapsed #sidebar .sidebar-dropup-trigger {
|
||||
/*
|
||||
Align the "More" control with the centered icon rail while keeping its
|
||||
padding consistent so the glyph does not scale between states.
|
||||
*/
|
||||
justify-content: center;
|
||||
width: var(--sidebar-control-size);
|
||||
height: var(--sidebar-control-size);
|
||||
padding: 0;
|
||||
margin-inline: auto;
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
body.sidebar-collapsed #app {
|
||||
margin-left: 4rem !important;
|
||||
body.sidebar-collapsed #sidebar .sidebar-dropup-trigger .sidebar-text,
|
||||
#sidebar.sidebar-collapsed .sidebar-dropup-trigger .sidebar-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.sidebar-expanded #app {
|
||||
margin-left: 16rem !important;
|
||||
body.sidebar-collapsed #sidebar .sidebar-dropup-trigger__chevron {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.sidebar-collapsed #sidebar .sidebar-dropup-trigger__glyph,
|
||||
#sidebar.sidebar-collapsed .sidebar-dropup-trigger__glyph {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Example: customizing the border & background in the sidebar */
|
||||
#sidebar hr {
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* Sidebar drop-up menu styling */
|
||||
.sidebar-dropup {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.sidebar-dropup-panel {
|
||||
background-color: #1f2937; /* gray-800 */
|
||||
border: 0.0625rem solid rgba(148, 163, 184, 0.25);
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 1.125rem 2.1875rem rgba(15, 23, 42, 0.45);
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
transform: translateY(1rem);
|
||||
transition: max-height 0.35s ease, opacity 0.25s ease, transform 0.35s ease;
|
||||
}
|
||||
|
||||
.sidebar-dropup-panel__inner {
|
||||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
.sidebar-dropup-panel--expanded {
|
||||
max-height: 40rem;
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.sidebar-dropup-trigger {
|
||||
align-items: center;
|
||||
background: linear-gradient(135deg, rgba(59, 130, 246, 0.25), rgba(14, 116, 144, 0.35));
|
||||
border: 0.0625rem solid rgba(148, 163, 184, 0.35);
|
||||
border-radius: 9999px;
|
||||
color: #f8fafc;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.75rem 1.25rem;
|
||||
transition: box-shadow 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sidebar-dropup-trigger:hover,
|
||||
.sidebar-dropup-trigger:focus {
|
||||
border-color: rgba(148, 163, 184, 0.6);
|
||||
box-shadow: 0 0.75rem 1.875rem rgba(37, 99, 235, 0.25);
|
||||
outline: none;
|
||||
transform: translateY(-0.0625rem);
|
||||
}
|
||||
|
||||
.sidebar-dropup-trigger__content {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
.edit-field-button {
|
||||
align-items: center;
|
||||
background-color: #1f2937;
|
||||
|
||||
@@ -1 +1 @@
|
||||
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media (min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@mediLine truncated
|
||||
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media (min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@mediLine truncated
|
||||
+24
-18
@@ -45,12 +45,17 @@
|
||||
<meta name="theme-color" content="#0f172a" />
|
||||
|
||||
<!-- Styles -->
|
||||
<script src="js/tracking.js" defer></script>
|
||||
<link href="css/tailwind.generated.css" rel="stylesheet" />
|
||||
<link href="css/style.css" rel="stylesheet" />
|
||||
<link href="css/markdown.css" rel="stylesheet" />
|
||||
<!--
|
||||
Cache busting: keep these query strings in sync with config/asset-version.js
|
||||
so browsers pick up the latest sidebar markup and styling without
|
||||
hard-refreshing around CDN caches.
|
||||
-->
|
||||
<script src="js/tracking.js?v=2024.10.22" defer></script>
|
||||
<link href="css/tailwind.generated.css?v=2024.10.22" rel="stylesheet" />
|
||||
<link href="css/style.css?v=2024.10.22" rel="stylesheet" />
|
||||
<link href="css/markdown.css?v=2024.10.22" rel="stylesheet" />
|
||||
</head>
|
||||
<body class="bg-gray-100">
|
||||
<body class="sidebar-collapsed">
|
||||
<!--
|
||||
SIDEBAR CONTAINER:
|
||||
The <aside id="sidebar"> inside handles visibility.
|
||||
@@ -64,8 +69,9 @@
|
||||
|
||||
<!--
|
||||
MAIN CONTENT:
|
||||
md:ml-64 ensures content is shifted on desktop so the pinned sidebar doesn't overlap.
|
||||
On mobile we float the sidebar over the content and dim the background overlay.
|
||||
Desktop spacing now follows the --sidebar-width custom property so the layout stays in
|
||||
sync with the collapsible rail. On mobile we float the sidebar over the content and dim
|
||||
the background overlay.
|
||||
-->
|
||||
<!--
|
||||
`fade-in` is scrubbed by js/index.js after the first animation so that
|
||||
@@ -73,7 +79,7 @@
|
||||
elements that should animate exactly once on initial paint.
|
||||
-->
|
||||
|
||||
<div id="app" class="md:ml-64 px-4 py-8 min-h-screen flex flex-col fade-in">
|
||||
<div id="app" class="px-4 py-8 min-h-screen flex flex-col fade-in">
|
||||
<!-- Header -->
|
||||
<header class="mb-8 flex items-center w-full">
|
||||
<!-- Mobile hamburger button (hidden on md+) -->
|
||||
@@ -205,16 +211,16 @@
|
||||
|
||||
<!-- Additional Scripts -->
|
||||
<!-- Bootstraps nostr-tools before other modules rely on nostrToolsReady -->
|
||||
<script type="module" src="js/nostrToolsBootstrap.js"></script>
|
||||
<script type="module" src="js/config.js"></script>
|
||||
<script type="module" src="js/lists.js"></script>
|
||||
<script type="module" src="js/accessControl.js"></script>
|
||||
<script type="module" src="js/webtorrent.js"></script>
|
||||
<script type="module" src="js/nostr.js"></script>
|
||||
<script type="module" src="js/viewManager.js"></script>
|
||||
<script type="module" src="js/bootstrap.js"></script>
|
||||
<script type="module" src="js/disclaimer.js"></script>
|
||||
<script type="module" src="js/index.js"></script>
|
||||
<script type="module" src="js/nostrToolsBootstrap.js?v=2024.10.22"></script>
|
||||
<script type="module" src="js/config.js?v=2024.10.22"></script>
|
||||
<script type="module" src="js/lists.js?v=2024.10.22"></script>
|
||||
<script type="module" src="js/accessControl.js?v=2024.10.22"></script>
|
||||
<script type="module" src="js/webtorrent.js?v=2024.10.22"></script>
|
||||
<script type="module" src="js/nostr.js?v=2024.10.22"></script>
|
||||
<script type="module" src="js/viewManager.js?v=2024.10.22"></script>
|
||||
<script type="module" src="js/bootstrap.js?v=2024.10.22"></script>
|
||||
<script type="module" src="js/disclaimer.js?v=2024.10.22"></script>
|
||||
<script type="module" src="js/index.js?v=2024.10.22"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
|
||||
</body>
|
||||
|
||||
+122
-40
@@ -1,6 +1,7 @@
|
||||
// js/index.js
|
||||
|
||||
import { validateInstanceConfig } from "../config/validate-config.js";
|
||||
import { ASSET_VERSION } from "../config/asset-version.js";
|
||||
import "./bufferPolyfill.js";
|
||||
import Application from "./app.js";
|
||||
import { setApplication, setApplicationReady } from "./applicationContext.js";
|
||||
@@ -102,13 +103,26 @@ document.addEventListener("animationend", handleFadeInAnimationComplete, true);
|
||||
document.addEventListener("animationcancel", handleFadeInAnimationComplete, true);
|
||||
|
||||
// 1) Load modals (login, application, etc.)
|
||||
const withAssetVersion = (url) => {
|
||||
if (typeof url !== "string" || url.length === 0) {
|
||||
return url;
|
||||
}
|
||||
|
||||
const separator = url.includes("?") ? "&" : "?";
|
||||
return `${url}${separator}v=${encodeURIComponent(ASSET_VERSION)}`;
|
||||
};
|
||||
|
||||
const fetchPartial = async (url) => {
|
||||
const response = await fetch(withAssetVersion(url), { cache: "no-store" });
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load " + url);
|
||||
}
|
||||
return response.text();
|
||||
};
|
||||
|
||||
async function loadModal(url) {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load " + url);
|
||||
}
|
||||
const html = await response.text();
|
||||
const html = await fetchPartial(url);
|
||||
// Remove analytics loader tags from modal partials to avoid duplicate pageview events.
|
||||
const sanitizedHtml = html.replace(
|
||||
/<script\b[^>]*src=["'][^"']*tracking\.js[^"']*["'][^>]*>\s*<\/script>/gi,
|
||||
@@ -126,11 +140,7 @@ async function loadModal(url) {
|
||||
// 2) Load sidebar
|
||||
async function loadSidebar(url, containerId) {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load " + url);
|
||||
}
|
||||
const html = await response.text();
|
||||
const html = await fetchPartial(url);
|
||||
document.getElementById(containerId).innerHTML = html;
|
||||
console.log(url, "loaded into", containerId);
|
||||
} catch (err) {
|
||||
@@ -141,11 +151,7 @@ async function loadSidebar(url, containerId) {
|
||||
// 3) Load the disclaimer (now separate)
|
||||
async function loadDisclaimer(url, containerId) {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load " + url);
|
||||
}
|
||||
const html = await response.text();
|
||||
const html = await fetchPartial(url);
|
||||
document.getElementById(containerId).insertAdjacentHTML("beforeend", html);
|
||||
console.log(url, "disclaimer loaded into", containerId);
|
||||
} catch (err) {
|
||||
@@ -170,24 +176,34 @@ async function bootstrapInterface() {
|
||||
|
||||
const sidebar = document.getElementById("sidebar");
|
||||
const collapseToggle = document.getElementById("sidebarCollapseToggle");
|
||||
if (sidebar && !sidebar.hasAttribute("data-footer-state")) {
|
||||
sidebar.setAttribute("data-footer-state", "collapsed");
|
||||
}
|
||||
if (!collapseToggle) {
|
||||
console.warn("Sidebar collapse toggle not found; skipping density controls.");
|
||||
}
|
||||
const collapseChevron = collapseToggle?.querySelector("[data-sidebar-chevron]");
|
||||
const collapseLabel = collapseToggle?.querySelector(".sidebar-toggle-label");
|
||||
|
||||
const mobileMenuBtn = document.getElementById("mobileMenuBtn");
|
||||
const sidebarOverlay = document.getElementById("sidebarOverlay");
|
||||
|
||||
const SIDEBAR_COLLAPSED_STORAGE_KEY = "sidebarCollapsed";
|
||||
let isSidebarCollapsed = false;
|
||||
const SIDEBAR_WIDTH_EXPANDED = "16rem";
|
||||
const SIDEBAR_WIDTH_COLLAPSED = "4rem";
|
||||
const DEFAULT_SIDEBAR_COLLAPSED = true;
|
||||
let isSidebarCollapsed = DEFAULT_SIDEBAR_COLLAPSED;
|
||||
let isFooterDropupExpanded = false;
|
||||
let syncFooterDropupFn = null;
|
||||
|
||||
const readStoredSidebarCollapsed = () => {
|
||||
try {
|
||||
return localStorage.getItem(SIDEBAR_COLLAPSED_STORAGE_KEY) === "true";
|
||||
const storedValue = localStorage.getItem(SIDEBAR_COLLAPSED_STORAGE_KEY);
|
||||
if (storedValue === null) {
|
||||
return DEFAULT_SIDEBAR_COLLAPSED;
|
||||
}
|
||||
return storedValue === "true";
|
||||
} catch (error) {
|
||||
console.warn("Unable to read sidebar collapse state from storage:", error);
|
||||
return false;
|
||||
return DEFAULT_SIDEBAR_COLLAPSED;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -203,28 +219,47 @@ async function bootstrapInterface() {
|
||||
};
|
||||
|
||||
const applySidebarDensity = (collapsed) => {
|
||||
const targets = [sidebar, document.body].filter(
|
||||
const widthTargets = [document.documentElement, document.body].filter(
|
||||
(element) => element instanceof HTMLElement,
|
||||
);
|
||||
if (sidebar instanceof HTMLElement) {
|
||||
widthTargets.push(sidebar);
|
||||
}
|
||||
const appShell = document.getElementById("app");
|
||||
if (appShell instanceof HTMLElement) {
|
||||
widthTargets.push(appShell);
|
||||
}
|
||||
const state = collapsed ? "collapsed" : "expanded";
|
||||
const nextWidth = collapsed
|
||||
? SIDEBAR_WIDTH_COLLAPSED
|
||||
: SIDEBAR_WIDTH_EXPANDED;
|
||||
|
||||
targets.forEach((element) => {
|
||||
element.classList.toggle("sidebar-collapsed", collapsed);
|
||||
element.classList.toggle("sidebar-expanded", !collapsed);
|
||||
element.setAttribute("data-state", state);
|
||||
widthTargets.forEach((element) => {
|
||||
element.style.setProperty("--sidebar-width", nextWidth);
|
||||
});
|
||||
|
||||
[sidebar, document.body]
|
||||
.filter((element) => element instanceof HTMLElement)
|
||||
.forEach((element) => {
|
||||
element.classList.toggle("sidebar-collapsed", collapsed);
|
||||
element.classList.toggle("sidebar-expanded", !collapsed);
|
||||
element.setAttribute("data-state", state);
|
||||
});
|
||||
|
||||
if (collapseToggle) {
|
||||
const actionLabel = collapsed ? "Expand sidebar" : "Collapse sidebar";
|
||||
collapseToggle.setAttribute("aria-expanded", collapsed ? "false" : "true");
|
||||
collapseToggle.setAttribute("data-state", state);
|
||||
collapseToggle.setAttribute("aria-label", actionLabel);
|
||||
collapseToggle.setAttribute("title", actionLabel);
|
||||
}
|
||||
|
||||
if (collapseChevron instanceof HTMLElement) {
|
||||
collapseChevron.classList.toggle("rotate-180", collapsed);
|
||||
}
|
||||
|
||||
if (collapseLabel) {
|
||||
collapseLabel.textContent = collapsed ? "Expand" : "Collapse";
|
||||
if (
|
||||
collapsed &&
|
||||
isFooterDropupExpanded &&
|
||||
typeof syncFooterDropupFn === "function"
|
||||
) {
|
||||
syncFooterDropupFn(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -335,17 +370,64 @@ async function bootstrapInterface() {
|
||||
}
|
||||
|
||||
const footerDropdownButton = document.getElementById("footerDropdownButton");
|
||||
if (footerDropdownButton) {
|
||||
footerDropdownButton.addEventListener("click", () => {
|
||||
const footerLinksContainer = document.getElementById("footerLinksContainer");
|
||||
if (!footerLinksContainer) return;
|
||||
footerLinksContainer.classList.toggle("hidden");
|
||||
if (footerLinksContainer.classList.contains("hidden")) {
|
||||
footerDropdownButton.innerHTML = "More ▼";
|
||||
} else {
|
||||
footerDropdownButton.innerHTML = "Less ▲";
|
||||
const footerLinksContainer = document.getElementById("footerLinksContainer");
|
||||
const footerDropdownLabel = document.getElementById("footerDropdownText");
|
||||
const footerDropdownIcon = document.getElementById("footerDropdownIcon");
|
||||
|
||||
if (footerDropdownButton && footerLinksContainer) {
|
||||
const sidebarFooter = footerDropdownButton.closest(".sidebar-footer");
|
||||
|
||||
syncFooterDropupFn = (expanded) => {
|
||||
const nextState = expanded ? "expanded" : "collapsed";
|
||||
const actionLabel = expanded ? "Show fewer sidebar links" : "Show more sidebar links";
|
||||
|
||||
footerDropdownButton.setAttribute("aria-expanded", expanded ? "true" : "false");
|
||||
footerDropdownButton.dataset.state = nextState;
|
||||
footerDropdownButton.setAttribute("aria-label", actionLabel);
|
||||
footerDropdownButton.setAttribute("title", actionLabel);
|
||||
|
||||
if (footerDropdownLabel) {
|
||||
footerDropdownLabel.textContent = expanded ? "Less" : "More";
|
||||
}
|
||||
|
||||
if (footerDropdownIcon) {
|
||||
footerDropdownIcon.classList.toggle("is-rotated", expanded);
|
||||
}
|
||||
|
||||
footerLinksContainer.classList.remove("hidden");
|
||||
footerLinksContainer.setAttribute("aria-hidden", expanded ? "false" : "true");
|
||||
footerLinksContainer.dataset.state = nextState;
|
||||
|
||||
if (sidebar) {
|
||||
sidebar.setAttribute("data-footer-state", nextState);
|
||||
}
|
||||
|
||||
if (sidebarFooter instanceof HTMLElement) {
|
||||
sidebarFooter.dataset.footerState = nextState;
|
||||
}
|
||||
isFooterDropupExpanded = expanded;
|
||||
};
|
||||
|
||||
footerDropdownButton.addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
const expanded = footerDropdownButton.getAttribute("aria-expanded") === "true";
|
||||
|
||||
if (isSidebarCollapsed && !expanded) {
|
||||
const nextCollapsed = false;
|
||||
isSidebarCollapsed = nextCollapsed;
|
||||
applySidebarDensity(nextCollapsed);
|
||||
persistSidebarCollapsed(nextCollapsed);
|
||||
}
|
||||
|
||||
if (typeof syncFooterDropupFn === "function") {
|
||||
syncFooterDropupFn(!expanded);
|
||||
}
|
||||
});
|
||||
|
||||
const initialExpanded = footerDropdownButton.getAttribute("aria-expanded") === "true";
|
||||
if (typeof syncFooterDropupFn === "function") {
|
||||
syncFooterDropupFn(initialExpanded);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
+11
-1
@@ -2,9 +2,19 @@
|
||||
import { initChannelProfileView } from "./channelProfile.js";
|
||||
import { subscriptions } from "./subscriptions.js";
|
||||
import { getApplication } from "./applicationContext.js";
|
||||
import { ASSET_VERSION } from "../config/asset-version.js";
|
||||
|
||||
const TRACKING_SCRIPT_PATTERN = /(?:^|\/)tracking\.js(?:$|\?)/;
|
||||
|
||||
const withAssetVersion = (url) => {
|
||||
if (typeof url !== "string" || url.length === 0) {
|
||||
return url;
|
||||
}
|
||||
|
||||
const separator = url.includes("?") ? "&" : "?";
|
||||
return `${url}${separator}v=${encodeURIComponent(ASSET_VERSION)}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Load a partial view by URL into the #viewContainer.
|
||||
*/
|
||||
@@ -15,7 +25,7 @@ export async function loadView(viewUrl) {
|
||||
app.prepareForViewLoad();
|
||||
}
|
||||
|
||||
const res = await fetch(viewUrl);
|
||||
const res = await fetch(withAssetVersion(viewUrl), { cache: "no-store" });
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to load view: ${res.status}`);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user