mirror of https://github.com/VERT-sh/VERT.git
Separate menu into custom component
This commit is contained in:
parent
b724f066ba
commit
df4c009ac8
|
@ -0,0 +1,76 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { page } from "$app/stores";
|
||||||
|
import { fly } from "svelte/transition";
|
||||||
|
import { duration } from "$lib/animation";
|
||||||
|
import { quintOut } from "svelte/easing";
|
||||||
|
import type { Writable } from "svelte/store";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
links: {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
activeMatch: (pathname: string) => boolean;
|
||||||
|
}[];
|
||||||
|
shouldGoBack: Writable<boolean> | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let { links, shouldGoBack = null }: Props = $props();
|
||||||
|
|
||||||
|
let navWidth = $state(1);
|
||||||
|
let linkCount = $derived(links.length);
|
||||||
|
let activeLinkIndex = $derived(
|
||||||
|
links.findIndex((i) => i.activeMatch($page.url.pathname)),
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:clientWidth={navWidth}
|
||||||
|
class="w-full flex bg-background relative h-16"
|
||||||
|
>
|
||||||
|
{#if activeLinkIndex !== -1}
|
||||||
|
<div
|
||||||
|
class="absolute pointer-events-none top-1 bg-foreground h-[calc(100%-8px)] rounded-xl"
|
||||||
|
style="width: {navWidth / linkCount - 8}px; left: {(navWidth /
|
||||||
|
linkCount) *
|
||||||
|
activeLinkIndex +
|
||||||
|
4}px; transition: {duration - 200}ms ease left;"
|
||||||
|
></div>
|
||||||
|
{/if}
|
||||||
|
{#each links as { name, url } (url)}
|
||||||
|
<a
|
||||||
|
class="w-1/2 px-2 h-[calc(100%-16px)] mt-2 flex items-center justify-center rounded-xl relative font-display overflow-hidden"
|
||||||
|
href={url}
|
||||||
|
onclick={() => {
|
||||||
|
if (shouldGoBack) {
|
||||||
|
const currentIndex = links.findIndex((i) =>
|
||||||
|
i.activeMatch($page.url.pathname),
|
||||||
|
);
|
||||||
|
const nextIndex = links.findIndex((i) =>
|
||||||
|
i.activeMatch(url),
|
||||||
|
);
|
||||||
|
$shouldGoBack = nextIndex < currentIndex;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="grid grid-cols-1 grid-rows-1">
|
||||||
|
{#key name}
|
||||||
|
<span
|
||||||
|
class="mix-blend-difference invert col-start-1 row-start-1 text-center"
|
||||||
|
in:fly={{
|
||||||
|
duration,
|
||||||
|
easing: quintOut,
|
||||||
|
y: -50,
|
||||||
|
}}
|
||||||
|
out:fly={{
|
||||||
|
duration,
|
||||||
|
easing: quintOut,
|
||||||
|
y: 50,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</span>
|
||||||
|
{/key}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
</div>
|
|
@ -5,28 +5,40 @@
|
||||||
import { quintOut } from "svelte/easing";
|
import { quintOut } from "svelte/easing";
|
||||||
import { files } from "$lib/store/index.svelte";
|
import { files } from "$lib/store/index.svelte";
|
||||||
import Logo from "$lib/components/visual/svg/Logo.svelte";
|
import Logo from "$lib/components/visual/svg/Logo.svelte";
|
||||||
import { fly } from "svelte/transition";
|
|
||||||
import featuredImage from "$lib/assets/VERT_Feature.webp";
|
import featuredImage from "$lib/assets/VERT_Feature.webp";
|
||||||
import { PUB_HOSTNAME, PUB_PLAUSIBLE_URL } from "$env/static/public";
|
import { PUB_HOSTNAME, PUB_PLAUSIBLE_URL } from "$env/static/public";
|
||||||
|
import FancyMenu from "$lib/components/functional/FancyMenu.svelte";
|
||||||
|
import { writable } from "svelte/store";
|
||||||
let { children, data } = $props();
|
let { children, data } = $props();
|
||||||
|
|
||||||
let navWidth = $state(1);
|
let shouldGoBack = writable(false);
|
||||||
let shouldGoBack = $state(false);
|
|
||||||
|
|
||||||
const links = $derived<{
|
const links = $derived<
|
||||||
[key: string]: string;
|
{
|
||||||
}>({
|
name: string;
|
||||||
Upload: "/",
|
url: string;
|
||||||
[files.files.length > 0
|
activeMatch: (pathname: string) => boolean;
|
||||||
? `Convert (${files.files.length})`
|
}[]
|
||||||
: `Convert`]: "/convert",
|
>([
|
||||||
About: "/about",
|
{
|
||||||
});
|
name: "Upload",
|
||||||
|
url: "/",
|
||||||
const linkCount = $derived(Object.keys(links).length);
|
activeMatch: (pathname) => pathname === "/",
|
||||||
const linkIndex = $derived(
|
},
|
||||||
Object.keys(links).findIndex((link) => links[link] === data.pathname),
|
{
|
||||||
);
|
name:
|
||||||
|
files.files.length > 0
|
||||||
|
? `Convert (${files.files.length})`
|
||||||
|
: `Convert`,
|
||||||
|
url: "/convert",
|
||||||
|
activeMatch: (pathname) => pathname === "/convert",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "About",
|
||||||
|
url: "/about",
|
||||||
|
activeMatch: (pathname) => pathname.startsWith("/about"),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
const maybeNavToHome = (e: DragEvent) => {
|
const maybeNavToHome = (e: DragEvent) => {
|
||||||
if (e.dataTransfer?.types.includes("Files")) {
|
if (e.dataTransfer?.types.includes("Files")) {
|
||||||
|
@ -78,54 +90,7 @@
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<FancyMenu {links} {shouldGoBack} />
|
||||||
bind:clientWidth={navWidth}
|
|
||||||
class="w-full flex bg-background relative h-16"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="absolute pointer-events-none top-1 bg-foreground h-[calc(100%-8px)] rounded-xl"
|
|
||||||
style="width: {navWidth / linkCount - 8}px; left: {(navWidth /
|
|
||||||
linkCount) *
|
|
||||||
linkIndex +
|
|
||||||
4}px; transition: {duration - 200}ms ease left;"
|
|
||||||
></div>
|
|
||||||
{#each Object.entries(links) as [name, link] (link)}
|
|
||||||
<a
|
|
||||||
class="w-1/2 px-2 h-[calc(100%-16px)] mt-2 flex items-center justify-center rounded-xl relative font-display overflow-hidden"
|
|
||||||
href={link}
|
|
||||||
onclick={() => {
|
|
||||||
const keys = Object.keys(links);
|
|
||||||
const currentIndex = keys.findIndex(
|
|
||||||
(key) => links[key] === data.pathname,
|
|
||||||
);
|
|
||||||
const nextIndex = keys.findIndex(
|
|
||||||
(key) => links[key] === link,
|
|
||||||
);
|
|
||||||
shouldGoBack = nextIndex < currentIndex;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class="grid grid-cols-1 grid-rows-1">
|
|
||||||
{#key name}
|
|
||||||
<span
|
|
||||||
class="mix-blend-difference invert col-start-1 row-start-1 text-center"
|
|
||||||
in:fly={{
|
|
||||||
duration,
|
|
||||||
easing: quintOut,
|
|
||||||
y: -50,
|
|
||||||
}}
|
|
||||||
out:fly={{
|
|
||||||
duration,
|
|
||||||
easing: quintOut,
|
|
||||||
y: 50,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{name}
|
|
||||||
</span>
|
|
||||||
{/key}
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full max-w-screen-lg grid grid-cols-1 grid-rows-1 relative">
|
<div class="w-full max-w-screen-lg grid grid-cols-1 grid-rows-1 relative">
|
||||||
{#key data.pathname}
|
{#key data.pathname}
|
||||||
|
@ -137,7 +102,7 @@
|
||||||
easing: quintOut,
|
easing: quintOut,
|
||||||
blurMultiplier: 12,
|
blurMultiplier: 12,
|
||||||
x: {
|
x: {
|
||||||
start: !shouldGoBack ? 250 : -250,
|
start: !$shouldGoBack ? 250 : -250,
|
||||||
end: 0,
|
end: 0,
|
||||||
},
|
},
|
||||||
scale: {
|
scale: {
|
||||||
|
@ -151,7 +116,7 @@
|
||||||
blurMultiplier: 12,
|
blurMultiplier: 12,
|
||||||
x: {
|
x: {
|
||||||
start: 0,
|
start: 0,
|
||||||
end: !shouldGoBack ? -250 : 250,
|
end: !$shouldGoBack ? -250 : 250,
|
||||||
},
|
},
|
||||||
scale: {
|
scale: {
|
||||||
start: 1,
|
start: 1,
|
||||||
|
|
Loading…
Reference in New Issue