mirror of https://github.com/VERT-sh/VERT.git
chore: componetize stuff in +layout.svelte
This commit is contained in:
parent
e9b8bb26dc
commit
21ed03960b
|
@ -1,22 +1,23 @@
|
|||
<script lang="ts">
|
||||
type Props = {
|
||||
class: string;
|
||||
items: { [name: string]: string };
|
||||
};
|
||||
import { GITHUB_URL_VERT, DISCORD_URL } from "$lib/consts";
|
||||
|
||||
const { class: classList, items }: Props = $props();
|
||||
const items = Object.entries({
|
||||
//"Privacy policy": "#",
|
||||
"Source code": GITHUB_URL_VERT,
|
||||
"Discord server": DISCORD_URL,
|
||||
});
|
||||
|
||||
const year = new Date().getFullYear();
|
||||
|
||||
const links = $derived(Object.entries(items));
|
||||
</script>
|
||||
|
||||
<footer class={classList}>
|
||||
<footer
|
||||
class="hidden md:block w-full h-14 border-t border-separator fixed bottom-0 mt-12"
|
||||
>
|
||||
<div
|
||||
class="w-full h-full flex items-center justify-center text-muted gap-3 relative"
|
||||
>
|
||||
<p>© {year} VERT.</p>
|
||||
{#each links as [name, url] (name)}
|
||||
{#each items as [name, url] (name)}
|
||||
<!-- bullet point -->
|
||||
<p>•</p>
|
||||
<a
|
|
@ -0,0 +1,71 @@
|
|||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import { duration } from "$lib/animation";
|
||||
import VertVBig from "$lib/assets/vert-bg.svg?component";
|
||||
import { files, gradientColor, showGradient } from "$lib/store/index.svelte";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import { fade } from "svelte/transition";
|
||||
</script>
|
||||
|
||||
{#if page.url.pathname === "/"}
|
||||
<div
|
||||
class="fixed -z-30 top-0 left-0 w-screen h-screen flex items-center justify-center overflow-hidden"
|
||||
>
|
||||
<VertVBig
|
||||
class="fill-[--fg] opacity-10 dynadark:opacity-5 scale-[200%] md:scale-[80%]"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
id="gradient-bg"
|
||||
class="fixed top-0 left-0 w-screen h-screen -z-40 pointer-events-none"
|
||||
style="background: var(--bg-gradient);"
|
||||
></div>
|
||||
{:else if page.url.pathname === "/convert" && $showGradient}
|
||||
<div
|
||||
id="gradient-bg"
|
||||
class="fixed top-0 left-0 w-screen h-screen -z-40 pointer-events-none"
|
||||
style="background: var(--bg-gradient-{$gradientColor || 'pink'});"
|
||||
></div>
|
||||
{:else if page.url.pathname === "/convert" && files.files.length === 1 && files.files[0].blobUrl}
|
||||
<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 scale-105"
|
||||
>
|
||||
<div
|
||||
class="w-full relative"
|
||||
transition:fade={{
|
||||
duration,
|
||||
easing: quintOut,
|
||||
}}
|
||||
>
|
||||
<img
|
||||
class="object-cover w-full h-full blur-md"
|
||||
src={files.files[0].blobUrl}
|
||||
alt={files.files[0].name}
|
||||
/>
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full h-full"
|
||||
style="background: var(--bg-gradient-image);"
|
||||
></div>
|
||||
<!-- <div class="absolute bottom-0 left-0 w-full h-full">
|
||||
<ProgressiveBlur
|
||||
direction="bottom"
|
||||
endIntensity={256}
|
||||
iterations={8}
|
||||
fadeTo="var(--bg)"
|
||||
/>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
{:else if page.url.pathname === "/settings"}
|
||||
<div
|
||||
id="gradient-bg"
|
||||
class="fixed top-0 left-0 w-screen h-screen -z-40 pointer-events-none"
|
||||
style="background: var(--bg-gradient-blue);"
|
||||
></div>
|
||||
{:else if page.url.pathname === "/about"}
|
||||
<div
|
||||
id="gradient-bg"
|
||||
class="fixed top-0 left-0 w-screen h-screen -z-40 pointer-events-none"
|
||||
style="background: var(--bg-gradient-pink);"
|
||||
></div>
|
||||
{/if}
|
|
@ -0,0 +1,18 @@
|
|||
<script>
|
||||
import Logo from "$lib/components/visual/svg/Logo.svelte";
|
||||
</script>
|
||||
|
||||
<div class="flex md:hidden justify-center items-center pb-8 pt-4">
|
||||
<a
|
||||
class="flex items-center justify-center bg-panel p-2 rounded-[20px] shadow-panel"
|
||||
href="/"
|
||||
>
|
||||
<div
|
||||
class="h-14 bg-accent rounded-[14px] flex items-center justify-center"
|
||||
>
|
||||
<div class="w-28 h-5">
|
||||
<Logo />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
|
@ -2,24 +2,56 @@
|
|||
import { browser } from "$app/environment";
|
||||
import { page } from "$app/state";
|
||||
import { duration, fade } from "$lib/animation";
|
||||
import { effects, setTheme } from "$lib/store/index.svelte";
|
||||
import { effects, files, goingLeft, setTheme } from "$lib/store/index.svelte";
|
||||
import clsx from "clsx";
|
||||
import { MoonIcon, SunIcon } from "lucide-svelte";
|
||||
import {
|
||||
InfoIcon,
|
||||
MoonIcon,
|
||||
RefreshCw,
|
||||
SettingsIcon,
|
||||
SunIcon,
|
||||
UploadIcon,
|
||||
} from "lucide-svelte";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import Panel from "../visual/Panel.svelte";
|
||||
import Logo from "../visual/svg/Logo.svelte";
|
||||
import Panel from "../../visual/Panel.svelte";
|
||||
import Logo from "../../visual/svg/Logo.svelte";
|
||||
import { beforeNavigate } from "$app/navigation";
|
||||
|
||||
type Props = {
|
||||
items: {
|
||||
const items = $derived<
|
||||
{
|
||||
name: string;
|
||||
url: string;
|
||||
activeMatch: (pathname: string) => boolean;
|
||||
icon: any;
|
||||
badge?: number;
|
||||
}[];
|
||||
};
|
||||
|
||||
let { items }: Props = $props();
|
||||
}[]
|
||||
>([
|
||||
{
|
||||
name: "Upload",
|
||||
url: "/",
|
||||
activeMatch: (pathname) => pathname === "/",
|
||||
icon: UploadIcon,
|
||||
},
|
||||
{
|
||||
name: "Convert",
|
||||
url: "/convert",
|
||||
activeMatch: (pathname) => pathname === "/convert",
|
||||
icon: RefreshCw,
|
||||
badge: files.files.length,
|
||||
},
|
||||
{
|
||||
name: "Settings",
|
||||
url: "/settings",
|
||||
activeMatch: (pathname) => pathname.startsWith("/settings"),
|
||||
icon: SettingsIcon,
|
||||
},
|
||||
{
|
||||
name: "About",
|
||||
url: "/about",
|
||||
activeMatch: (pathname) => pathname.startsWith("/about"),
|
||||
icon: InfoIcon,
|
||||
},
|
||||
]);
|
||||
|
||||
let links = $state<HTMLAnchorElement[]>([]);
|
||||
let container = $state<HTMLDivElement>();
|
||||
|
@ -33,6 +65,20 @@
|
|||
const selectedIndex = $derived(
|
||||
items.findIndex((i) => i.activeMatch(page.url.pathname)),
|
||||
);
|
||||
|
||||
beforeNavigate((e) => {
|
||||
const oldIndex = items.findIndex((i) =>
|
||||
i.activeMatch(e.from?.url.pathname || ""),
|
||||
);
|
||||
const newIndex = items.findIndex((i) =>
|
||||
i.activeMatch(e.to?.url.pathname || ""),
|
||||
);
|
||||
if (newIndex < oldIndex) {
|
||||
goingLeft.set(true)
|
||||
} else {
|
||||
goingLeft.set(false)
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{#snippet link(item: (typeof items)[0], index: number)}
|
|
@ -0,0 +1,7 @@
|
|||
<script lang="ts">
|
||||
import Navbar from "./Base.svelte";
|
||||
</script>
|
||||
|
||||
<div class="hidden md:flex p-8 w-screen justify-center">
|
||||
<Navbar />
|
||||
</div>
|
|
@ -0,0 +1,9 @@
|
|||
<script lang="ts">
|
||||
import Navbar from "./Base.svelte";
|
||||
</script>
|
||||
|
||||
<div class="fixed md:hidden bottom-0 left-0 w-screen p-8 justify-center z-50">
|
||||
<div class="flex flex-col justify-center items-center">
|
||||
<Navbar />
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,2 @@
|
|||
export { default as Desktop } from "./Desktop.svelte";
|
||||
export { default as Mobile } from "./Mobile.svelte";
|
|
@ -0,0 +1,44 @@
|
|||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import { duration } from "$lib/animation";
|
||||
import { goingLeft, isMobile } from "$lib/store/index.svelte";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import { fly, fade } from "$lib/animation";
|
||||
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
<div class="grid grid-rows-1 grid-cols-1 h-full flex-grow">
|
||||
{#key page.url.pathname}
|
||||
<div
|
||||
class="row-start-1 col-start-1"
|
||||
in:fly={{
|
||||
x: $goingLeft ? -window.innerWidth : window.innerWidth,
|
||||
duration,
|
||||
easing: quintOut,
|
||||
delay: 25,
|
||||
}}
|
||||
out:fly={{
|
||||
x: $goingLeft ? window.innerWidth : -window.innerWidth,
|
||||
duration,
|
||||
easing: quintOut,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex flex-col h-full pb-32"
|
||||
in:fade={{
|
||||
duration,
|
||||
easing: quintOut,
|
||||
delay: $isMobile ? 0 : 100,
|
||||
}}
|
||||
out:fade={{
|
||||
duration,
|
||||
easing: quintOut,
|
||||
delay: $isMobile ? 0 : 200,
|
||||
}}
|
||||
>
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
{/key}
|
||||
</div>
|
|
@ -0,0 +1,4 @@
|
|||
export { default as Footer } from './Footer.svelte';
|
||||
export { default as Gradients } from './Gradients.svelte';
|
||||
export { default as MobileLogo } from './MobileLogo.svelte';
|
||||
export { default as PageContent } from './PageContent.svelte';
|
|
@ -229,6 +229,7 @@ export function setEffects(effectsEnabled: boolean) {
|
|||
export const files = new Files();
|
||||
export const showGradient = writable(true);
|
||||
export const gradientColor = writable("");
|
||||
export const goingLeft = writable(false);
|
||||
|
||||
export const isMobile = writable(false);
|
||||
export const effects = writable(true);
|
||||
|
|
|
@ -1,82 +1,31 @@
|
|||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import { beforeNavigate, goto } from "$app/navigation";
|
||||
import { PUB_HOSTNAME, PUB_PLAUSIBLE_URL } from "$env/static/public";
|
||||
import { duration, fly } from "$lib/animation";
|
||||
import VertVBig from "$lib/assets/vert-bg.svg?component";
|
||||
import featuredImage from "$lib/assets/VERT_Feature.webp";
|
||||
import Navbar from "$lib/components/functional/Navbar.svelte";
|
||||
import Footer from "$lib/components/visual/Footer.svelte";
|
||||
import Logo from "$lib/components/visual/svg/Logo.svelte";
|
||||
|
||||
import { fade } from "$lib/animation";
|
||||
import {
|
||||
files,
|
||||
gradientColor,
|
||||
isMobile,
|
||||
effects,
|
||||
showGradient,
|
||||
theme,
|
||||
} from "$lib/store/index.svelte";
|
||||
import {
|
||||
InfoIcon,
|
||||
RefreshCw,
|
||||
SettingsIcon,
|
||||
UploadIcon,
|
||||
} from "lucide-svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import "../app.scss";
|
||||
import { DISCORD_URL, GITHUB_URL_VERT, VERT_NAME } from "$lib/consts";
|
||||
import { type Toast as ToastType, toasts } from "$lib/store/ToastProvider";
|
||||
import { goto } from "$app/navigation";
|
||||
|
||||
import { PUB_HOSTNAME, PUB_PLAUSIBLE_URL } from "$env/static/public";
|
||||
import { duration } from "$lib/animation";
|
||||
import featuredImage from "$lib/assets/VERT_Feature.webp";
|
||||
import * as Layout from "$lib/components/layout";
|
||||
import * as Navbar from "$lib/components/layout/Navbar";
|
||||
import Toast from "$lib/components/visual/Toast.svelte";
|
||||
|
||||
import { fade } from "$lib/animation";
|
||||
import { files, isMobile, effects, theme } from "$lib/store/index.svelte";
|
||||
import { VERT_NAME } from "$lib/consts";
|
||||
import { type Toast as ToastType, toasts } from "$lib/store/ToastProvider";
|
||||
import { Settings } from "$lib/sections/settings/index.svelte";
|
||||
import "../app.scss";
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
let dropping = $state(false);
|
||||
let goingLeft = $state(false);
|
||||
let toastList = $state<ToastType[]>([]);
|
||||
|
||||
toasts.subscribe((value) => {
|
||||
toastList = value as ToastType[];
|
||||
});
|
||||
|
||||
const items = $derived<
|
||||
{
|
||||
name: string;
|
||||
url: string;
|
||||
activeMatch: (pathname: string) => boolean;
|
||||
icon: any;
|
||||
badge?: number;
|
||||
}[]
|
||||
>([
|
||||
{
|
||||
name: "Upload",
|
||||
url: "/",
|
||||
activeMatch: (pathname) => pathname === "/",
|
||||
icon: UploadIcon,
|
||||
},
|
||||
{
|
||||
name: "Convert",
|
||||
url: "/convert",
|
||||
activeMatch: (pathname) => pathname === "/convert",
|
||||
icon: RefreshCw,
|
||||
badge: files.files.length,
|
||||
},
|
||||
{
|
||||
name: "Settings",
|
||||
url: "/settings",
|
||||
activeMatch: (pathname) => pathname.startsWith("/settings"),
|
||||
icon: SettingsIcon,
|
||||
},
|
||||
{
|
||||
name: "About",
|
||||
url: "/about",
|
||||
activeMatch: (pathname) => pathname.startsWith("/about"),
|
||||
icon: InfoIcon,
|
||||
},
|
||||
]);
|
||||
|
||||
const dropFiles = (e: DragEvent) => {
|
||||
e.preventDefault();
|
||||
dropping = false;
|
||||
|
@ -103,20 +52,6 @@
|
|||
|
||||
Settings.instance.load();
|
||||
});
|
||||
|
||||
beforeNavigate((e) => {
|
||||
const oldIndex = items.findIndex((i) =>
|
||||
i.activeMatch(e.from?.url.pathname || ""),
|
||||
);
|
||||
const newIndex = items.findIndex((i) =>
|
||||
i.activeMatch(e.to?.url.pathname || ""),
|
||||
);
|
||||
if (newIndex < oldIndex) {
|
||||
goingLeft = true;
|
||||
} else {
|
||||
goingLeft = false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -158,6 +93,7 @@
|
|||
<script src="/coi-serviceworker.min.js"></script>
|
||||
</svelte:head>
|
||||
|
||||
<!-- FIXME: if user resizes between desktop/mobile, highlight of page disappears (only shows on original size) -->
|
||||
<div
|
||||
class="flex flex-col min-h-screen h-full"
|
||||
ondrop={dropFiles}
|
||||
|
@ -179,64 +115,12 @@
|
|||
></div>
|
||||
{/if}
|
||||
|
||||
<!-- FIXME: if user resizes between desktop/mobile, highlight of page disappears (only shows on original size) -->
|
||||
<div>
|
||||
<!-- Mobile logo -->
|
||||
<div class="flex md:hidden justify-center items-center pb-8 pt-4">
|
||||
<a
|
||||
class="flex items-center justify-center bg-panel p-2 rounded-[20px] shadow-panel"
|
||||
href="/"
|
||||
>
|
||||
<div
|
||||
class="h-14 bg-accent rounded-[14px] flex items-center justify-center"
|
||||
>
|
||||
<div class="w-28 h-5">
|
||||
<Logo />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<Layout.MobileLogo />
|
||||
<Navbar.Desktop />
|
||||
</div>
|
||||
|
||||
<!-- Desktop navbar -->
|
||||
<div class="hidden md:flex p-8 w-screen justify-center">
|
||||
<Navbar {items} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-rows-1 grid-cols-1 h-full flex-grow">
|
||||
{#key page.url.pathname}
|
||||
<div
|
||||
class="row-start-1 col-start-1"
|
||||
in:fly={{
|
||||
x: goingLeft ? -window.innerWidth : window.innerWidth,
|
||||
duration,
|
||||
easing: quintOut,
|
||||
delay: 25,
|
||||
}}
|
||||
out:fly={{
|
||||
x: goingLeft ? window.innerWidth : -window.innerWidth,
|
||||
duration,
|
||||
easing: quintOut,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex flex-col h-full pb-32"
|
||||
in:fade={{
|
||||
duration,
|
||||
easing: quintOut,
|
||||
delay: $isMobile ? 0 : 100,
|
||||
}}
|
||||
out:fade={{
|
||||
duration,
|
||||
easing: quintOut,
|
||||
delay: $isMobile ? 0 : 200,
|
||||
}}
|
||||
>
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
{/key}
|
||||
</div>
|
||||
<Layout.PageContent {children} />
|
||||
|
||||
<div class="fixed bottom-28 md:bottom-0 right-0 p-4 space-y-4 z-50">
|
||||
{#each toastList as { id, type, message, durations }}
|
||||
|
@ -245,93 +129,13 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<div
|
||||
class="hidden md:block w-full h-14 border-t border-separator fixed bottom-0 mt-12"
|
||||
>
|
||||
<Footer
|
||||
class="w-full h-full"
|
||||
items={{
|
||||
//"Privacy policy": "#",
|
||||
"Source code": GITHUB_URL_VERT,
|
||||
"Discord server": DISCORD_URL,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Mobile navbar -->
|
||||
<div
|
||||
class="fixed md:hidden bottom-0 left-0 w-screen p-8 justify-center z-50"
|
||||
>
|
||||
<div class="flex flex-col justify-center items-center">
|
||||
<Navbar {items} />
|
||||
</div>
|
||||
</div>
|
||||
<Layout.Footer />
|
||||
<Navbar.Mobile />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gradients placed here to prevent it overlapping in transitions -->
|
||||
{#if page.url.pathname === "/"}
|
||||
<div
|
||||
class="fixed -z-30 top-0 left-0 w-screen h-screen flex items-center justify-center overflow-hidden"
|
||||
>
|
||||
<VertVBig
|
||||
class="fill-[--fg] opacity-10 dynadark:opacity-5 scale-[200%] md:scale-[80%]"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
id="gradient-bg"
|
||||
class="fixed top-0 left-0 w-screen h-screen -z-40 pointer-events-none"
|
||||
style="background: var(--bg-gradient);"
|
||||
></div>
|
||||
{:else if page.url.pathname === "/convert" && $showGradient}
|
||||
<div
|
||||
id="gradient-bg"
|
||||
class="fixed top-0 left-0 w-screen h-screen -z-40 pointer-events-none"
|
||||
style="background: var(--bg-gradient-{$gradientColor || 'pink'});"
|
||||
></div>
|
||||
{:else if page.url.pathname === "/convert" && files.files.length === 1 && files.files[0].blobUrl}
|
||||
<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 scale-105"
|
||||
>
|
||||
<div
|
||||
class="w-full relative"
|
||||
transition:fade={{
|
||||
duration,
|
||||
easing: quintOut,
|
||||
}}
|
||||
>
|
||||
<img
|
||||
class="object-cover w-full h-full blur-md"
|
||||
src={files.files[0].blobUrl}
|
||||
alt={files.files[0].name}
|
||||
/>
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full h-full"
|
||||
style="background: var(--bg-gradient-image);"
|
||||
></div>
|
||||
<!-- <div class="absolute bottom-0 left-0 w-full h-full">
|
||||
<ProgressiveBlur
|
||||
direction="bottom"
|
||||
endIntensity={256}
|
||||
iterations={8}
|
||||
fadeTo="var(--bg)"
|
||||
/>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
{:else if page.url.pathname === "/settings"}
|
||||
<div
|
||||
id="gradient-bg"
|
||||
class="fixed top-0 left-0 w-screen h-screen -z-40 pointer-events-none"
|
||||
style="background: var(--bg-gradient-blue);"
|
||||
></div>
|
||||
{:else if page.url.pathname === "/about"}
|
||||
<div
|
||||
id="gradient-bg"
|
||||
class="fixed top-0 left-0 w-screen h-screen -z-40 pointer-events-none"
|
||||
style="background: var(--bg-gradient-pink);"
|
||||
></div>
|
||||
{/if}
|
||||
<Layout.Gradients />
|
||||
|
||||
<style>
|
||||
.dragoverlay {
|
||||
|
|
Loading…
Reference in New Issue