feat: sliding navbar

This commit is contained in:
not-nullptr 2024-11-16 11:51:41 +00:00
parent c88112d226
commit ef20f76a85
2 changed files with 88 additions and 22 deletions

View File

@ -7,6 +7,8 @@
import { theme } from "$lib/store/index.svelte"; import { theme } from "$lib/store/index.svelte";
import { blur, duration } from "$lib/animation"; import { blur, duration } from "$lib/animation";
import { quintOut } from "svelte/easing"; import { quintOut } from "svelte/easing";
import { browser } from "$app/environment";
import type { SvelteComponent } from "svelte";
type Props = { type Props = {
items: { items: {
@ -19,17 +21,32 @@
}; };
let { items }: Props = $props(); let { items }: Props = $props();
let links = $state<HTMLAnchorElement[]>([]);
let container = $state<HTMLDivElement>();
let containerRect = $derived(container?.getBoundingClientRect());
$effect(() => {
$inspect(containerRect);
});
const linkRects = $derived(links.map((l) => l.getBoundingClientRect()));
const selectedIndex = $derived(
items.findIndex((i) => i.activeMatch($page.url.pathname)),
);
</script> </script>
{#snippet link(item: (typeof items)[0])} {#snippet link(item: (typeof items)[0], index: number)}
{@const Icon = item.icon} {@const Icon = item.icon}
<a <a
bind:this={links[index]}
href={item.url} href={item.url}
aria-label={item.name} aria-label={item.name}
class={clsx( class={clsx(
"w-32 h-full rounded-xl flex items-center justify-center gap-3 overflow-hidden", "w-32 h-full relative z-10 rounded-xl flex items-center justify-center gap-3 overflow-hidden",
{ {
"bg-panel-accented": item.activeMatch($page.url.pathname), "bg-panel-accented":
item.activeMatch($page.url.pathname) && !browser,
}, },
)} )}
> >
@ -117,23 +134,36 @@
</a> </a>
{/snippet} {/snippet}
<Panel class="w-fit h-20 flex items-center gap-3"> <div bind:this={container}>
<div <Panel class="w-fit h-20 flex items-center gap-3 relative">
class="w-32 h-full bg-accent rounded-xl flex items-center justify-center" {#if linkRects[selectedIndex]}
> <div
<div class="h-5 w-full"> class="absolute bg-panel-accented rounded-xl"
<Logo /> style="width: {linkRects[selectedIndex]
.width}px; height: {linkRects[selectedIndex]
.height}px; top: {linkRects[selectedIndex].top -
32}px; left: {linkRects[selectedIndex].left -
(containerRect?.left ||
0)}px; transition: left var(--transition) {duration}ms, top var(--transition) {duration}ms;"
></div>
{/if}
<div
class="w-32 h-full bg-accent rounded-xl flex items-center justify-center"
>
<div class="h-5 w-full">
<Logo />
</div>
</div> </div>
</div> {#each items as item, i (item.url)}
{#each items as item (item.url)} {@render link(item, i)}
{@render link(item)} {/each}
{/each} <div class="w-0.5 bg-separator h-full"></div>
<div class="w-0.5 bg-separator h-full"></div> <button
<button onclick={theme.toggle}
onclick={theme.toggle} class="w-14 h-full flex items-center justify-center"
class="w-14 h-full flex items-center justify-center" >
> <SunIcon class="dynadark:hidden block" />
<SunIcon class="dynadark:hidden block" /> <MoonIcon class="dynadark:block hidden" />
<MoonIcon class="dynadark:block hidden" /> </button>
</button> </Panel>
</Panel> </div>

View File

@ -1,6 +1,8 @@
<script lang="ts"> <script lang="ts">
import { blur, duration } from "$lib/animation";
import Dropdown from "$lib/components/functional/Dropdown.svelte"; import Dropdown from "$lib/components/functional/Dropdown.svelte";
import Uploader from "$lib/components/functional/Uploader.svelte"; import Uploader from "$lib/components/functional/Uploader.svelte";
import ProgressiveBlur from "$lib/components/visual/effects/ProgressiveBlur.svelte";
import Panel from "$lib/components/visual/Panel.svelte"; import Panel from "$lib/components/visual/Panel.svelte";
import ProgressBar from "$lib/components/visual/ProgressBar.svelte"; import ProgressBar from "$lib/components/visual/ProgressBar.svelte";
import { files } from "$lib/store/index.svelte"; import { files } from "$lib/store/index.svelte";
@ -12,6 +14,7 @@
RotateCwIcon, RotateCwIcon,
XIcon, XIcon,
} from "lucide-svelte"; } from "lucide-svelte";
import { quintOut } from "svelte/easing";
</script> </script>
{#snippet fileItem(file: VertFile, index: number)} {#snippet fileItem(file: VertFile, index: number)}
@ -107,3 +110,36 @@
{/if} {/if}
</div> </div>
</div> </div>
<div
class="fixed w-screen h-screen opacity-75 overflow-hidden top-0 left-0 -z-50 pointer-events-none grid grid-cols-1 grid-rows-1"
>
{#if files.files.length === 1}
<div
class="w-full relative"
transition:blur={{
blurMultiplier: 24,
duration,
easing: quintOut,
scale: {
start: 1.02,
end: 1,
},
}}
>
<img
class="object-cover w-full h-full blur-xs"
src={files.files[0].blobUrl}
alt={files.files[0].name}
/>
<div class="absolute bottom-0 left-0 w-full h-full">
<ProgressiveBlur
direction="bottom"
endIntensity={256}
iterations={8}
fadeTo="var(--bg)"
/>
</div>
</div>
{/if}
</div>