mirror of https://github.com/VERT-sh/VERT.git
308 lines
8.0 KiB
Svelte
308 lines
8.0 KiB
Svelte
<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,
|
|
motion,
|
|
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 { writable } from "svelte/store";
|
|
let { children } = $props();
|
|
|
|
let shouldGoBack = writable(false);
|
|
let navbar = $state<HTMLDivElement>();
|
|
let hover = $state(false);
|
|
|
|
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 maybeNavToHome = (e: DragEvent) => {
|
|
if (e.dataTransfer?.types.includes("Files")) {
|
|
e.preventDefault();
|
|
goto("/");
|
|
}
|
|
};
|
|
|
|
onMount(() => {
|
|
const mouseEnter = () => {
|
|
hover = true;
|
|
};
|
|
|
|
const mouseLeave = () => {
|
|
hover = false;
|
|
};
|
|
|
|
navbar?.addEventListener("mouseenter", mouseEnter);
|
|
navbar?.addEventListener("mouseleave", mouseLeave);
|
|
|
|
isMobile.set(window.innerWidth <= 768);
|
|
window.addEventListener("resize", () => {
|
|
isMobile.set(window.innerWidth <= 768);
|
|
});
|
|
|
|
motion.set(localStorage.getItem("motion") !== "false"); // defaults to true if not set
|
|
theme.set(
|
|
(localStorage.getItem("theme") as "light" | "dark") || "light",
|
|
);
|
|
});
|
|
|
|
let goingLeft = $state(false);
|
|
|
|
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>
|
|
<title>VERT.sh</title>
|
|
<meta name="theme-color" content="#F2ABEE" />
|
|
<meta
|
|
name="title"
|
|
content="VERT.sh — Free, fast, and awesome file convert"
|
|
/>
|
|
<meta
|
|
name="description"
|
|
content="With VERT you can convert image and audio files to and from PNG, JPG, WEBP, MP3, WAV, FLAC, and more. No ads, no tracking, open source, and all processing is done on your device."
|
|
/>
|
|
<meta property="og:type" content="website" />
|
|
<meta
|
|
property="og:title"
|
|
content="VERT.sh — Free, fast, and awesome file convert"
|
|
/>
|
|
<meta
|
|
property="og:description"
|
|
content="With VERT you can convert image and audio files to and from PNG, JPG, WEBP, MP3, WAV, FLAC, and more. No ads, no tracking, open source, and all processing is done on your device."
|
|
/>
|
|
<meta property="og:image" content={featuredImage} />
|
|
<meta property="twitter:card" content="summary_large_image" />
|
|
<meta
|
|
property="twitter:title"
|
|
content="VERT.sh — Free, fast, and awesome file convert"
|
|
/>
|
|
<meta
|
|
property="twitter:description"
|
|
content="With VERT you can convert image and audio files to and from PNG, JPG, WEBP, MP3, WAV, FLAC, and more. No ads, no tracking, open source, and all processing is done on your device."
|
|
/>
|
|
<meta property="twitter:image" content={featuredImage} />
|
|
{#if PUB_PLAUSIBLE_URL}<script
|
|
defer
|
|
data-domain={PUB_HOSTNAME || "vert.sh"}
|
|
src="{PUB_PLAUSIBLE_URL}/js/script.pageview-props.tagged-events.js"
|
|
></script>{/if}
|
|
<script src="/coi-serviceworker.min.js"></script>
|
|
</svelte:head>
|
|
|
|
<div class="flex flex-col min-h-screen h-full">
|
|
<!-- 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 p-8">
|
|
<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>
|
|
|
|
<!-- Desktop navbar -->
|
|
<div class="hidden md:flex p-8 w-screen justify-center z-50">
|
|
<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-36 md:pb-0"
|
|
in:fade={{
|
|
duration,
|
|
easing: quintOut,
|
|
delay: $isMobile ? 0 : 100,
|
|
}}
|
|
out:fade={{
|
|
duration,
|
|
easing: quintOut,
|
|
delay: $isMobile ? 0 : 200,
|
|
}}
|
|
>
|
|
{@render children()}
|
|
</div>
|
|
</div>
|
|
{/key}
|
|
</div>
|
|
|
|
<div>
|
|
<div
|
|
class="hidden md:block w-full h-14 border-t border-separator relative mt-12"
|
|
>
|
|
<Footer
|
|
class="w-full h-full"
|
|
items={{
|
|
//"Privacy policy": "#",
|
|
"Source code": "https://github.com/not-nullptr/VERT",
|
|
"Discord server": "https://discord.gg/kqevGxYPak",
|
|
}}
|
|
/>
|
|
</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>
|
|
</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}
|