mirror of https://github.com/VERT-sh/VERT.git
feat: homepage
This commit is contained in:
parent
70a17df7bf
commit
0370ff3abf
|
@ -12,6 +12,7 @@
|
|||
"lint": "prettier --check . && eslint ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@poppanator/sveltekit-svg": "^5.0.0",
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import "@poppanator/sveltekit-svg/dist/svg";
|
||||
|
||||
type EventPayload = {
|
||||
readonly n: string;
|
||||
readonly u: Location["href"];
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Host+Grotesk:ital,wght@0,300..800;1,300..800&family=Radio+Canada+Big:ital,wght@0,400..700;1,400..700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
|
|
55
src/app.scss
55
src/app.scss
|
@ -7,10 +7,10 @@
|
|||
@import url(@fontsource/azeret-mono/600.css);
|
||||
|
||||
:root {
|
||||
--font-body: "Lexend", system-ui, -apple-system, BlinkMacSystemFont,
|
||||
--font-body: "Host Grotesk", system-ui, -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans",
|
||||
"Helvetica Neue", sans-serif;
|
||||
--font-display: "Azeret Mono", var(--font-body);
|
||||
--font-display: "Radio Canada Big", var(--font-body);
|
||||
--transition: linear(
|
||||
0,
|
||||
0.006,
|
||||
|
@ -27,6 +27,7 @@
|
|||
1.017 63.9%,
|
||||
1.001
|
||||
);
|
||||
--shadow-panel: 0 4px 6px 0 hsla(0, 0%, 0%, 0.15);
|
||||
}
|
||||
|
||||
@mixin light {
|
||||
|
@ -43,19 +44,35 @@
|
|||
}
|
||||
|
||||
@mixin dark {
|
||||
--accent-bg: hsl(304, 41%, 21%);
|
||||
--accent-fg: hsl(303, 73%, 81%);
|
||||
--bg: hsl(0, 0%, 8%);
|
||||
--bg-transparent: hsla(0, 0%, 8%, 0.8);
|
||||
--fg: hsl(0, 0%, 90%);
|
||||
// general
|
||||
--accent: hsl(303, 73%, 81%);
|
||||
|
||||
// foregrounds
|
||||
--fg: hsl(0, 0%, 100%);
|
||||
--fg-muted: hsl(0, 0%, 50%);
|
||||
--fg-muted-alt: hsl(0, 0%, 25%);
|
||||
--fg-highlight: hsl(303, 64%, 65%);
|
||||
--fg-failure: hsl(0, 67%, 80%);
|
||||
--bg-gradient: linear-gradient(to bottom, #c800ff0c, #c800ff00),
|
||||
linear-gradient(to bottom left, #0015ff0c, #0015ff00 50%),
|
||||
linear-gradient(to bottom right, #ff001e18, #ff001e00 50%);
|
||||
--fg-on-accent: hsl(0, 0%, 0%);
|
||||
|
||||
// backgrounds
|
||||
--bg: hsl(220, 5%, 12%);
|
||||
--bg-gradient: linear-gradient(
|
||||
to bottom,
|
||||
hsla(287, 100%, 50%, 0.1),
|
||||
hsla(287, 100%, 50%, 0)
|
||||
),
|
||||
linear-gradient(
|
||||
to bottom left,
|
||||
hsla(235, 100%, 50%, 0.07),
|
||||
hsla(235, 100%, 50%, 0) 50%
|
||||
),
|
||||
linear-gradient(
|
||||
to bottom right,
|
||||
hsla(353, 100%, 50%, 0.07),
|
||||
hsla(353, 100%, 50%, 0) 50%
|
||||
);
|
||||
color-scheme: dark;
|
||||
--bg-panel: hsl(225, 4%, 18%);
|
||||
--bg-panel-accented: color-mix(in srgb, var(--accent) 12%, transparent);
|
||||
--bg-separator: hsl(214, 4%, 32%);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
@ -79,9 +96,10 @@
|
|||
}
|
||||
|
||||
body {
|
||||
@apply text-foreground bg-background font-body overflow-x-hidden;
|
||||
@apply text-foreground font-body font-semibold overflow-x-hidden;
|
||||
width: 100vw;
|
||||
background: var(--bg-gradient);
|
||||
background-color: var(--bg);
|
||||
background-size: 100vw 100vh;
|
||||
}
|
||||
|
||||
|
@ -101,4 +119,13 @@ body {
|
|||
.btn-highlight {
|
||||
@apply bg-accent-background text-accent-foreground border-accent-background;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
@apply font-display font-semibold;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<svg width="1389" height="1080" viewBox="0 0 1389 1080" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M418.719 1080L0.480804 0H2.62554L420.863 1080H418.719Z" fill="url(#paint0_linear_6_220)" fill-opacity="0.1"/>
|
||||
<path d="M829.044 1080L412.359 0H410.215L826.9 1080H829.044Z" fill="url(#paint1_linear_6_220)" fill-opacity="0.1"/>
|
||||
<path d="M788.673 555.925L987.856 0H989.981L790.985 555.402L1064.61 827.169L1386.13 0H1388.27L1065.37 830.741L788.673 555.925Z" fill="url(#paint2_linear_6_220)" fill-opacity="0.1"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_6_220" x1="694.377" y1="0" x2="694.377" y2="1080" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white"/>
|
||||
<stop offset="0.75" stop-color="white"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_6_220" x1="694.377" y1="0" x2="694.377" y2="1080" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white"/>
|
||||
<stop offset="0.75" stop-color="white"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_6_220" x1="694.377" y1="0" x2="694.377" y2="1080" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white"/>
|
||||
<stop offset="0.75" stop-color="white"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,54 @@
|
|||
<script lang="ts">
|
||||
import { onMount, type SvelteComponentTyped } from "svelte";
|
||||
import Panel from "../visual/Panel.svelte";
|
||||
import Logo from "../visual/svg/Logo.svelte";
|
||||
import clsx from "clsx";
|
||||
import { page } from "$app/stores";
|
||||
import { MoonIcon, SunIcon } from "lucide-svelte";
|
||||
import { theme } from "$lib/store/index.svelte";
|
||||
|
||||
type Props = {
|
||||
items: {
|
||||
name: string;
|
||||
url: string;
|
||||
activeMatch: (pathname: string) => boolean;
|
||||
icon: any;
|
||||
}[];
|
||||
};
|
||||
|
||||
let { items }: Props = $props();
|
||||
</script>
|
||||
|
||||
<Panel class="w-fit h-20 flex items-center gap-3">
|
||||
<div
|
||||
class="w-32 h-full bg-accent rounded-xl flex items-center justify-center"
|
||||
>
|
||||
<div class="h-5 w-full">
|
||||
<Logo />
|
||||
</div>
|
||||
</div>
|
||||
{#each items as item (item.url)}
|
||||
{@const Icon = item.icon}
|
||||
<a
|
||||
href={item.url}
|
||||
aria-label={item.name}
|
||||
class={clsx(
|
||||
"w-32 h-full rounded-xl flex items-center justify-center gap-3",
|
||||
{
|
||||
"bg-panel-accented": item.activeMatch($page.url.pathname),
|
||||
},
|
||||
)}
|
||||
>
|
||||
<Icon />
|
||||
<p>{item.name}</p>
|
||||
</a>
|
||||
{/each}
|
||||
<div class="w-0.5 bg-separator h-full"></div>
|
||||
<button
|
||||
onclick={theme.toggle}
|
||||
class="w-14 h-full flex items-center justify-center"
|
||||
>
|
||||
<SunIcon class="dynadark:hidden block" />
|
||||
<MoonIcon class="dynadark:block hidden" />
|
||||
</button>
|
||||
</Panel>
|
|
@ -1,121 +1,23 @@
|
|||
<script lang="ts">
|
||||
import { Upload } from "lucide-svelte";
|
||||
import clsx from "clsx";
|
||||
import { onMount } from "svelte";
|
||||
import { UploadIcon } from "lucide-svelte";
|
||||
import Panel from "../visual/Panel.svelte";
|
||||
|
||||
let fileList = $state<FileList>();
|
||||
let dragBtn = $state<HTMLButtonElement>();
|
||||
|
||||
interface Props {
|
||||
files: File[] | undefined;
|
||||
onupload?: () => void;
|
||||
isMobile: boolean;
|
||||
acceptedFormats?: string[];
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if (!fileList) return;
|
||||
files = Array.from(fileList);
|
||||
});
|
||||
|
||||
let fileInput = $state<HTMLInputElement>();
|
||||
let dragOver = $state(false);
|
||||
|
||||
let { files = $bindable(), onupload, isMobile, acceptedFormats }: Props = $props();
|
||||
|
||||
function upload() {
|
||||
if (!fileInput) return;
|
||||
fileInput.click();
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const handler = (e: Event) => e.preventDefault();
|
||||
if (!dragBtn) return;
|
||||
dragBtn.addEventListener("dragenter", handler);
|
||||
dragBtn.addEventListener("dragstart", handler);
|
||||
dragBtn.addEventListener("dragend", handler);
|
||||
dragBtn.addEventListener("dragleave", handler);
|
||||
dragBtn.addEventListener("dragover", handler);
|
||||
dragBtn.addEventListener("drag", handler);
|
||||
dragBtn.addEventListener("drop", handler);
|
||||
|
||||
return () => {
|
||||
if (!dragBtn) return;
|
||||
dragBtn.removeEventListener("dragenter", handler);
|
||||
dragBtn.removeEventListener("dragstart", handler);
|
||||
dragBtn.removeEventListener("dragend", handler);
|
||||
dragBtn.removeEventListener("dragleave", handler);
|
||||
dragBtn.removeEventListener("dragover", handler);
|
||||
dragBtn.removeEventListener("drag", handler);
|
||||
dragBtn.removeEventListener("drop", handler);
|
||||
type Props = {
|
||||
class?: string;
|
||||
};
|
||||
});
|
||||
|
||||
function drop(event: DragEvent) {
|
||||
event.preventDefault();
|
||||
dragOver = false;
|
||||
if (!event.dataTransfer) return;
|
||||
if (!files) files = Array.from(event.dataTransfer.files);
|
||||
else files.push(...Array.from(event.dataTransfer.files));
|
||||
onupload?.();
|
||||
return true;
|
||||
}
|
||||
|
||||
function addFiles() {
|
||||
if (!fileInput) return;
|
||||
if (!fileInput.files) return;
|
||||
if (!files) files = Array.from(fileInput.files);
|
||||
else files.push(...Array.from(fileInput.files));
|
||||
onupload?.();
|
||||
}
|
||||
const { class: classList }: Props = $props();
|
||||
</script>
|
||||
|
||||
<button
|
||||
bind:this={dragBtn}
|
||||
onclick={upload}
|
||||
ondragover={() => (dragOver = true)}
|
||||
ondragleave={() => (dragOver = false)}
|
||||
class={clsx(
|
||||
"file-uploader",
|
||||
"w-full h-80 flex items-center justify-center cursor-pointer",
|
||||
"border-2 border-solid border-foreground-muted-alt rounded-2xl",
|
||||
"hover:scale-95 hover:opacity-70 transition-all duration-150 ease-out",
|
||||
{
|
||||
"scale-95 opacity-70 blur-xs": dragOver,
|
||||
},
|
||||
)}
|
||||
class:_drag-over={dragOver}
|
||||
ondrop={drop}
|
||||
>
|
||||
<button class={classList}>
|
||||
<Panel class="flex justify-center items-center w-full h-full flex-col">
|
||||
<div
|
||||
class="file-uploader-center flex items-center justify-center flex-col transition-all duration-150 ease-out px-8"
|
||||
class="w-16 h-16 bg-accent rounded-full flex items-center justify-center p-4"
|
||||
>
|
||||
<div
|
||||
class="size-16 rounded-full text-accent-foreground bg-accent-background flex items-center justify-center"
|
||||
>
|
||||
<Upload class="size-8" />
|
||||
<UploadIcon class="w-full h-full text-on-accent" />
|
||||
</div>
|
||||
<h2 class="font-display text-2xl mt-6">
|
||||
{isMobile ? "Tap" : "Drop or click"} to upload files
|
||||
<h2 class="text-center text-2xl font-semibold mt-4">
|
||||
Drop or click to upload
|
||||
</h2>
|
||||
<p class="text-foreground-muted mt-4">
|
||||
All processing is done on your device. No file or size limit.
|
||||
</p>
|
||||
</div>
|
||||
</Panel>
|
||||
</button>
|
||||
|
||||
<input
|
||||
type="file"
|
||||
class="hidden"
|
||||
bind:this={fileInput}
|
||||
onchange={addFiles}
|
||||
accept={acceptedFormats?.join(",") ?? "*"}
|
||||
multiple
|
||||
/>
|
||||
|
||||
<style>
|
||||
.file-uploader:hover .file-uploader-center,
|
||||
.file-uploader._drag-over .file-uploader-center {
|
||||
@apply scale-105;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<script lang="ts">
|
||||
type Props = {
|
||||
class: string;
|
||||
items: { [name: string]: string };
|
||||
};
|
||||
|
||||
const { class: classList, items }: Props = $props();
|
||||
|
||||
const year = new Date().getFullYear();
|
||||
|
||||
const links = $derived(Object.entries(items));
|
||||
</script>
|
||||
|
||||
<footer class={classList}>
|
||||
<div
|
||||
class="w-full h-full flex items-center justify-center text-muted gap-3"
|
||||
>
|
||||
<p>© {year} VERT.</p>
|
||||
{#each links as [name, url] (name)}
|
||||
<!-- bullet point -->
|
||||
<p>•</p>
|
||||
<a target="_blank" class="hover:underline" href={url}>{name}</a>
|
||||
{/each}
|
||||
</div>
|
||||
</footer>
|
|
@ -0,0 +1,14 @@
|
|||
<script lang="ts">
|
||||
import type { Snippet } from "svelte";
|
||||
|
||||
type Props = {
|
||||
class?: string;
|
||||
children: Snippet<[]>;
|
||||
};
|
||||
|
||||
const { class: classList, children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="bg-panel {classList} p-3 rounded-2.5xl shadow-panel">
|
||||
{@render children?.()}
|
||||
</div>
|
|
@ -8,20 +8,42 @@ class Files {
|
|||
}
|
||||
|
||||
class Theme {
|
||||
public dark = $state(false);
|
||||
public toggle = () => {
|
||||
this.dark = !this.dark;
|
||||
private _dark = $state(false);
|
||||
public get dark() {
|
||||
return this._dark;
|
||||
}
|
||||
public set dark(value: boolean) {
|
||||
this._dark = value;
|
||||
if (!browser) return;
|
||||
JSCookie.set("theme", this.dark ? "dark" : "light", {
|
||||
path: "/",
|
||||
sameSite: "lax",
|
||||
expires: 2147483647,
|
||||
});
|
||||
log(["theme"], `set to ${this.dark ? "dark" : "light"}`);
|
||||
if (browser) {
|
||||
window.plausible("Theme set", {
|
||||
props: { theme: theme.dark ? "dark" : "light" },
|
||||
});
|
||||
if (value) {
|
||||
document.documentElement.classList.add("dark");
|
||||
document.documentElement.classList.remove("light");
|
||||
JSCookie.set("theme", "dark", {
|
||||
path: "/",
|
||||
sameSite: "lax",
|
||||
expires: 2147483647,
|
||||
});
|
||||
} else {
|
||||
document.documentElement.classList.add("light");
|
||||
document.documentElement.classList.remove("dark");
|
||||
JSCookie.set("theme", "light", {
|
||||
path: "/",
|
||||
sameSite: "lax",
|
||||
expires: 2147483647,
|
||||
});
|
||||
}
|
||||
}
|
||||
public toggle = () => {
|
||||
this.dark = !this.dark;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -13,27 +13,39 @@
|
|||
} from "$env/static/public";
|
||||
import FancyMenu from "$lib/components/functional/FancyMenu.svelte";
|
||||
import { writable } from "svelte/store";
|
||||
import { MoonIcon, SunIcon } from "lucide-svelte";
|
||||
import {
|
||||
InfoIcon,
|
||||
MoonIcon,
|
||||
RefreshCwIcon,
|
||||
SettingsIcon,
|
||||
SunIcon,
|
||||
UploadIcon,
|
||||
} from "lucide-svelte";
|
||||
import { browser } from "$app/environment";
|
||||
import JSCookie from "js-cookie";
|
||||
import { onMount } from "svelte";
|
||||
import Panel from "$lib/components/visual/Panel.svelte";
|
||||
import Navbar from "$lib/components/functional/Navbar.svelte";
|
||||
import Footer from "$lib/components/visual/Footer.svelte";
|
||||
let { children, data } = $props();
|
||||
|
||||
let shouldGoBack = writable(false);
|
||||
let navbar = $state<HTMLDivElement>();
|
||||
let hover = $state(false);
|
||||
|
||||
const links = $derived<
|
||||
const items = $derived<
|
||||
{
|
||||
name: string;
|
||||
url: string;
|
||||
activeMatch: (pathname: string) => boolean;
|
||||
icon: any;
|
||||
}[]
|
||||
>([
|
||||
{
|
||||
name: "Upload",
|
||||
url: "/",
|
||||
activeMatch: (pathname) => pathname === "/",
|
||||
icon: UploadIcon,
|
||||
},
|
||||
{
|
||||
name:
|
||||
|
@ -42,11 +54,19 @@
|
|||
: `Convert`,
|
||||
url: "/convert",
|
||||
activeMatch: (pathname) => pathname === "/convert",
|
||||
icon: RefreshCwIcon,
|
||||
},
|
||||
{
|
||||
name: "Settings",
|
||||
url: "/settings",
|
||||
activeMatch: (pathname) => pathname.startsWith("/settings"),
|
||||
icon: SettingsIcon,
|
||||
},
|
||||
{
|
||||
name: "About",
|
||||
url: "/about",
|
||||
activeMatch: (pathname) => pathname.startsWith("/about"),
|
||||
icon: InfoIcon,
|
||||
},
|
||||
]);
|
||||
|
||||
|
@ -57,27 +77,6 @@
|
|||
}
|
||||
};
|
||||
|
||||
$effect(() => {
|
||||
if (!browser) return;
|
||||
if (theme.dark) {
|
||||
document.documentElement.classList.add("dark");
|
||||
document.documentElement.classList.remove("light");
|
||||
JSCookie.set("theme", "dark", {
|
||||
path: "/",
|
||||
sameSite: "lax",
|
||||
expires: 2147483647,
|
||||
});
|
||||
} else {
|
||||
document.documentElement.classList.add("light");
|
||||
document.documentElement.classList.remove("dark");
|
||||
JSCookie.set("theme", "light", {
|
||||
path: "/",
|
||||
sameSite: "lax",
|
||||
expires: 2147483647,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
const mouseEnter = () => {
|
||||
hover = true;
|
||||
|
@ -104,182 +103,21 @@
|
|||
></script>{/if}
|
||||
</svelte:head>
|
||||
|
||||
<div
|
||||
role="main"
|
||||
class="w-full h-full max-w-screen-lg mx-auto p-4"
|
||||
ondragenter={maybeNavToHome}
|
||||
>
|
||||
<div class="flex justify-center mb-5 lg:hidden">
|
||||
<a
|
||||
href="/"
|
||||
class="px-4 relative h-14 mr-3 justify-center items-center bg-accent-background fill-accent-foreground rounded-xl md:hidden flex"
|
||||
>
|
||||
<div class="h-6 relative w-24 items-center flex justify-center">
|
||||
<Logo />
|
||||
{#if PUB_ENV === "nightly"}
|
||||
<div
|
||||
class="absolute -top-6 -left-10 px-2 py-1 w-fit bg-foreground-highlight text-accent-background rotate-[-10deg] rounded-xl"
|
||||
style="font-family: Comic Sans MS, sans-serif;"
|
||||
>
|
||||
NIGHTLY
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</a>
|
||||
<div class="fixed top-8 left-0 w-full flex justify-center">
|
||||
<Navbar {items} />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="w-full max-w-screen-md p-1 border-solid border-2 rounded-2xl border-foreground-muted-alt flex mb-10 mx-auto lg:mt-5"
|
||||
bind:this={navbar}
|
||||
>
|
||||
<div class="md:p-1">
|
||||
<a
|
||||
href="/"
|
||||
class="px-3 relative w-full h-full mr-3 justify-center items-center bg-accent-background fill-accent-foreground rounded-xl md:flex hidden"
|
||||
>
|
||||
<div class="h-6 w-24 items-center flex justify-center relative">
|
||||
<Logo />
|
||||
{#if PUB_ENV === "nightly"}
|
||||
<div
|
||||
class="absolute -top-6 -left-10 px-2 py-1 w-fit bg-foreground-highlight text-accent-background rotate-[-10deg] rounded-xl"
|
||||
style="font-family: Comic Sans MS, sans-serif;"
|
||||
>
|
||||
NIGHTLY
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<FancyMenu {links} {shouldGoBack} />
|
||||
<div class="h-16 px-4 flex items-center">
|
||||
<button onclick={theme.toggle} class="grid-cols-1 grid-rows-1 grid">
|
||||
<!-- {#if theme.dark}
|
||||
<div
|
||||
class="w-full h-full flex items-center justify-center row-start-1 col-start-1"
|
||||
>
|
||||
<MoonIcon />
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="w-full h-full flex items-center justify-center row-start-1 col-start-1"
|
||||
>
|
||||
<SunIcon />
|
||||
</div>
|
||||
{/if} -->
|
||||
{#if browser}
|
||||
{#if theme.dark}
|
||||
<div
|
||||
in:blur={{
|
||||
blurMultiplier: 1,
|
||||
duration,
|
||||
easing: quintOut,
|
||||
scale: {
|
||||
start: 0.5,
|
||||
end: 1,
|
||||
},
|
||||
}}
|
||||
out:blur={{
|
||||
blurMultiplier: 1,
|
||||
duration,
|
||||
easing: quintOut,
|
||||
scale: {
|
||||
start: 1,
|
||||
end: 1.5,
|
||||
},
|
||||
}}
|
||||
class="w-full h-full flex items-center justify-center row-start-1 col-start-1"
|
||||
>
|
||||
<MoonIcon class="w-8" />
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
in:blur={{
|
||||
blurMultiplier: 1,
|
||||
duration,
|
||||
easing: quintOut,
|
||||
scale: {
|
||||
start: 0.5,
|
||||
end: 1,
|
||||
},
|
||||
}}
|
||||
out:blur={{
|
||||
blurMultiplier: 1,
|
||||
duration,
|
||||
easing: quintOut,
|
||||
scale: {
|
||||
start: 1,
|
||||
end: 1.5,
|
||||
},
|
||||
}}
|
||||
class="w-full h-full flex items-center justify-center row-start-1 col-start-1"
|
||||
>
|
||||
<SunIcon class="w-8" />
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div
|
||||
class="w-full h-full flex items-center justify-center row-start-1 col-start-1 dynadark:hidden"
|
||||
>
|
||||
<SunIcon class="w-8" />
|
||||
</div>
|
||||
<div
|
||||
class="w-full h-full hidden items-center justify-center row-start-1 col-start-1 dynadark:flex"
|
||||
>
|
||||
<MoonIcon class="w-8" />
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full max-w-screen-lg grid grid-cols-1 grid-rows-1 relative">
|
||||
{#key data.pathname}
|
||||
<div class="w-full">
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full"
|
||||
style={hover ? "will-change: opacity, blur, transform" : ""}
|
||||
in:blur={{
|
||||
duration,
|
||||
easing: quintOut,
|
||||
blurMultiplier: 12,
|
||||
x: {
|
||||
start: !$shouldGoBack ? 250 : -250,
|
||||
end: 0,
|
||||
},
|
||||
y: {
|
||||
start: 100,
|
||||
end: 0,
|
||||
},
|
||||
scale: {
|
||||
start: 0.75,
|
||||
end: 1,
|
||||
},
|
||||
origin: "top center",
|
||||
}}
|
||||
out:blur={{
|
||||
duration,
|
||||
easing: quintOut,
|
||||
blurMultiplier: 12,
|
||||
x: {
|
||||
start: 0,
|
||||
end: !$shouldGoBack ? -250 : 250,
|
||||
},
|
||||
y: {
|
||||
start: 0,
|
||||
end: 100,
|
||||
},
|
||||
scale: {
|
||||
start: 1,
|
||||
end: 0.75,
|
||||
},
|
||||
origin: "top center",
|
||||
}}
|
||||
>
|
||||
<div class="pb-20">
|
||||
<div class="w-screen h-screen">
|
||||
{@render children()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/key}
|
||||
</div>
|
||||
|
||||
<div class="-mt-14 w-full h-14">
|
||||
<Footer
|
||||
class="w-full h-full"
|
||||
items={{
|
||||
"Privacy Policy": "#",
|
||||
"Source Code": "#",
|
||||
"Discord Server": "#",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -5,4 +5,32 @@
|
|||
//
|
||||
// ship fast n break things !!
|
||||
// -- nullptr
|
||||
|
||||
import VertVBig from "$lib/assets/vert-bg.svg?component";
|
||||
import Uploader from "$lib/components/functional/Uploader.svelte";
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="fixed -z-50 top-0 left-0 w-full h-full flex items-center justify-center overflow-hidden"
|
||||
>
|
||||
<VertVBig class="fill-[--fg] opacity-50" />
|
||||
</div>
|
||||
|
||||
<div class="w-full h-full flex items-center justify-center">
|
||||
<div class="max-w-5xl w-full">
|
||||
<div class="flex items-center h-[266px] gap-24">
|
||||
<div class="flex-grow w-full">
|
||||
<h1 class="text-6xl tracking-tight leading-[72px] mb-6">
|
||||
The file converter you'll love.
|
||||
</h1>
|
||||
<p class="font-normal text-xl text-muted">
|
||||
All processing done on your device. No file size limit, no
|
||||
ads, and completely open source.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex-grow w-full h-full">
|
||||
<Uploader class="w-full h-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,15 +5,21 @@ export default {
|
|||
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
background: "var(--bg)",
|
||||
backgroundColor: {
|
||||
panel: "var(--bg-panel)",
|
||||
"panel-accented": "var(--bg-panel-accented)",
|
||||
separator: "var(--bg-separator)",
|
||||
},
|
||||
textColor: {
|
||||
foreground: "var(--fg)",
|
||||
"foreground-muted": "var(--fg-muted)",
|
||||
"foreground-muted-alt": "var(--fg-muted-alt)",
|
||||
"foreground-failure": "var(--fg-failure)",
|
||||
"foreground-highlight": "var(--fg-highlight)",
|
||||
"accent-background": "var(--accent-bg)",
|
||||
"accent-foreground": "var(--accent-fg)",
|
||||
muted: "var(--fg-muted)",
|
||||
"on-accent": "var(--fg-on-accent)",
|
||||
},
|
||||
colors: {
|
||||
accent: "var(--accent)",
|
||||
},
|
||||
boxShadow: {
|
||||
panel: "var(--shadow-panel)",
|
||||
},
|
||||
fontFamily: {
|
||||
display: "var(--font-display)",
|
||||
|
@ -22,6 +28,9 @@ export default {
|
|||
blur: {
|
||||
xs: "2px",
|
||||
},
|
||||
borderRadius: {
|
||||
"2.5xl": "1.25rem",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import { defineConfig } from "vite";
|
||||
import svg from "@poppanator/sveltekit-svg";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
|
@ -17,6 +18,19 @@ export default defineConfig({
|
|||
});
|
||||
},
|
||||
},
|
||||
svg({
|
||||
includePaths: ["./src/lib/assets"],
|
||||
svgoOptions: {
|
||||
multipass: true,
|
||||
plugins: [
|
||||
{
|
||||
name: "preset-default",
|
||||
params: { overrides: { removeViewBox: false } },
|
||||
},
|
||||
{ name: "removeAttrs", params: { attrs: "(fill|stroke)" } },
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
optimizeDeps: {
|
||||
exclude: [
|
||||
|
|
Loading…
Reference in New Issue