Update layout

Sidebar now animates properly. Navigation has progressive blur behind it on scroll
This commit is contained in:
Justin Edmund 2025-09-24 00:45:28 -07:00
parent 06a91bd532
commit b564a5e5e0
4 changed files with 134 additions and 90 deletions

View file

@ -21,7 +21,7 @@
const { open = false, title, onclose, children, headerActions }: Props = $props() const { open = false, title, onclose, children, headerActions }: Props = $props()
</script> </script>
<aside class="sidebar" class:open style:--sidebar-width={open ? SIDEBAR_WIDTH : '0'}> <aside class="sidebar" class:open style:--sidebar-width={SIDEBAR_WIDTH}>
{#if title} {#if title}
<SidebarHeader {title} {onclose} actions={headerActions} /> <SidebarHeader {title} {onclose} actions={headerActions} />
{/if} {/if}
@ -50,42 +50,56 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-shrink: 0; flex-shrink: 0;
width: 0; width: var(--sidebar-width);
overflow: hidden; overflow: hidden;
transition: width $duration-slide ease-in-out; transform: translateX(100%);
opacity: 0;
transition:
transform $duration-slide ease-in-out,
opacity $duration-slide ease-in-out;
z-index: 50; z-index: 50;
&.open { &.open {
width: var(--sidebar-width); transform: translateX(0);
opacity: 1;
} }
.sidebar-content { .sidebar-content {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
padding: $unit-2x;
// Smooth scrolling // Smooth scrolling
scroll-behavior: smooth; scroll-behavior: smooth;
// Better scrollbar styling to match main content // Use overlay scrollbars that auto-hide
overflow-y: overlay;
// Thin, minimal scrollbar styling
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 8px; width: 10px;
} }
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
background: var(--bg-secondary, #f1f1f1); background: transparent;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background: var(--border-primary, #888); background: rgba(0, 0, 0, 0.2);
border-radius: 4px; border-radius: 10px;
border: 2px solid transparent;
background-clip: padding-box;
&:hover { &:hover {
background: var(--text-secondary, #555); background: rgba(0, 0, 0, 0.4);
background-clip: padding-box;
} }
} }
// Firefox scrollbar styling
scrollbar-width: thin;
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
// Improve mobile scrolling performance // Improve mobile scrolling performance
@media (max-width: 768px) { @media (max-width: 768px) {
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
@ -95,17 +109,10 @@
// Mobile styles - overlay approach // Mobile styles - overlay approach
@media (max-width: 768px) { @media (max-width: 768px) {
z-index: 100; z-index: 100;
transform: translateX(100%);
transition:
transform $duration-slide ease-in-out,
width 0s;
width: 90vw !important; width: 90vw !important;
max-width: 400px; max-width: 400px;
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15); box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
// Mobile already uses transform, no additional changes needed
&.open {
transform: translateX(0);
}
} }
} }
</style> </style>

View file

@ -18,55 +18,71 @@
</script> </script>
<div class="sidebar-header"> <div class="sidebar-header">
<div class="header-left">
{#if actions}
{@render actions()}
{/if}
</div>
<h2 class="sidebar-title">{title}</h2> <h2 class="sidebar-title">{title}</h2>
{#if actions} <div class="header-right">
<div class="header-actions"> {#if onclose}
{@render actions()} <button onclick={onclose} class="close-button" aria-label="Close sidebar">
</div> {@html closeIcon}
{/if} </button>
{/if}
{#if onclose} </div>
<button
onclick={onclose}
class="close-button"
aria-label="Close sidebar"
>
{@html closeIcon}
</button>
{/if}
</div> </div>
<style lang="scss"> <style lang="scss">
@use '$src/themes/spacing' as *; @use '$src/themes/spacing' as *;
@use '$src/themes/colors' as *; @use '$src/themes/colors' as *;
@use '$src/themes/typography' as *; @use '$src/themes/typography' as *;
@use '$src/themes/layout' as *;
.sidebar-header { .sidebar-header {
display: flex; display: flex;
align-items: center; align-items: center;
gap: $unit; justify-content: space-between;
min-height: $nav-height;
padding: $unit-2x; padding: $unit-2x;
border-bottom: 1px solid var(--border-primary); border-bottom: 1px solid var(--border-primary);
flex-shrink: 0; flex-shrink: 0;
background: var(--bg-primary); background: var(--bg-primary);
.sidebar-title { // Match mobile navigation height
flex: 1; @media (max-width: 768px) {
margin: 0; min-height: $nav-height-mobile;
font-size: $font-large;
font-weight: $bold;
color: var(--text-primary);
} }
.header-actions { .header-left,
.header-right {
width: 32px; // Same width as close button for balance
flex-shrink: 0;
display: flex; display: flex;
gap: $unit;
align-items: center; align-items: center;
justify-content: center;
}
.header-left {
justify-content: flex-start;
}
.header-right {
justify-content: flex-end;
}
.sidebar-title {
margin: 0;
font-size: $font-regular;
font-weight: $medium;
color: var(--text-primary);
text-align: center;
flex: 1;
} }
.close-button { .close-button {
margin-left: $unit;
padding: $unit; padding: $unit;
background: transparent; background: transparent;
border: none; border: none;
@ -76,10 +92,11 @@
justify-content: center; justify-content: center;
border-radius: 4px; border-radius: 4px;
color: var(--text-secondary); color: var(--text-secondary);
transition: background-color 0.2s, color 0.2s; transition:
background-color 0.2s,
color 0.2s;
width: 32px; width: 32px;
height: 32px; height: 32px;
flex-shrink: 0;
:global(svg) { :global(svg) {
width: 14px; width: 14px;
@ -97,4 +114,4 @@
} }
} }
} }
</style> </style>

View file

@ -46,11 +46,11 @@
<Tooltip.Provider> <Tooltip.Provider>
<div class="app-container" class:sidebar-open={sidebar.isOpen}> <div class="app-container" class:sidebar-open={sidebar.isOpen}>
<div class="nav-wrapper">
<Navigation isAuthenticated={data?.isAuthenticated} username={data?.account?.username} role={data?.account?.role} />
</div>
<div class="main-pane"> <div class="main-pane">
<div class="nav-blur-background"></div>
<div class="main-navigation">
<Navigation isAuthenticated={data?.isAuthenticated} username={data?.account?.username} role={data?.account?.role} />
</div>
<main class="main-content"> <main class="main-content">
{@render children?.()} {@render children?.()}
</main> </main>
@ -87,23 +87,26 @@
position: relative; position: relative;
overflow: hidden; overflow: hidden;
// Fixed navigation wrapper with blur effect // Main pane with content
.nav-wrapper { .main-pane {
position: fixed; flex: 1;
top: 0; display: flex;
left: 0; flex-direction: column;
right: 0; min-width: 0;
z-index: 100; transition: margin-right $duration-slide ease-in-out;
width: 100vw; position: relative;
height: 100%;
// Single blur layer with gradient mask for progressive effect // Blur background that shifts with main pane
&::before { .nav-blur-background {
content: ''; position: fixed;
position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
height: 80px; // Taller to test the progressive effect height: 80px; // Taller to test the progressive effect
z-index: 1; // Lower z-index so scrollbar appears above
pointer-events: none;
transition: right $duration-slide ease-in-out;
// Color gradient for the background // Color gradient for the background
background: linear-gradient( background: linear-gradient(
@ -131,67 +134,80 @@
black 40%, black 40%,
transparent 100% transparent 100%
); );
pointer-events: none;
z-index: 1;
} }
// Navigation content above the blur layer // Navigation wrapper - fixed but shifts with main-pane
:global(nav) { .main-navigation {
position: relative; position: fixed;
z-index: 2; top: 0;
left: 0;
right: 0;
z-index: 10; // Above blur but below scrollbar
transition: right $duration-slide ease-in-out;
pointer-events: auto;
} }
}
// Main pane with content // Main content area with independent scroll
.main-pane {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
transition: margin-right $duration-slide ease-in-out;
position: relative;
height: 100%;
// Main content area with independent scroll - content starts at top
.main-content { .main-content {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
position: relative; position: relative;
padding-top: 56px; // Space for fixed navigation to match blur height padding-top: 80px; // Space for fixed navigation (matching test height)
z-index: 2; // Ensure scrollbar is above blur background
// Smooth scrolling // Smooth scrolling
scroll-behavior: smooth; scroll-behavior: smooth;
// Better scrollbar styling // Use overlay scrollbars that auto-hide on macOS
overflow-y: overlay;
// Thin, minimal scrollbar styling
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 8px; width: 10px;
} }
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
background: var(--bg-secondary, #f1f1f1); background: transparent;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background: var(--border-primary, #888); background: rgba(0, 0, 0, 0.2);
border-radius: 4px; border-radius: 10px;
border: 2px solid transparent;
background-clip: padding-box;
&:hover { &:hover {
background: var(--text-secondary, #555); background: rgba(0, 0, 0, 0.4);
background-clip: padding-box;
} }
} }
// Firefox scrollbar styling
scrollbar-width: thin;
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
} }
} }
// When sidebar is open, adjust main pane width // When sidebar is open, adjust main pane and navigation
&.sidebar-open { &.sidebar-open {
.main-pane { .main-pane {
margin-right: var(--sidebar-width, 420px); margin-right: var(--sidebar-width, 420px);
// Blur background and navigation shift with the main pane
.nav-blur-background,
.main-navigation {
right: var(--sidebar-width, 420px);
}
// Mobile: don't adjust margin, use overlay // Mobile: don't adjust margin, use overlay
@media (max-width: 768px) { @media (max-width: 768px) {
margin-right: 0; margin-right: 0;
.nav-blur-background,
.main-navigation {
right: 0; // Don't shift on mobile
}
} }
} }
} }

View file

@ -1,5 +1,9 @@
@use 'spacing'; @use 'spacing';
// Navigation and header heights
$nav-height: 76px;
$nav-height-mobile: 60px;
// Scale factors // Scale factors
$scale-wide: scale(1.05, 1.05); $scale-wide: scale(1.05, 1.05);
$scale-tall: scale(1.012, 1.012); $scale-tall: scale(1.012, 1.012);