visuals
This commit is contained in:
@@ -117,10 +117,13 @@
|
||||
|
||||
<Dialog.Footer class="mt-4">
|
||||
<div class="flex justify-between w-full">
|
||||
<Button variant="destructive"
|
||||
onclick={() => {approveDenyItem({id: item?.id || 0, approved: false}); invalidateAll();}}>
|
||||
<Dialog.Close
|
||||
type="button"
|
||||
class={buttonVariants({ variant: "destructive" })}
|
||||
onclick={async () => {await approveDenyItem({ id: item?.id || 0, approved: false }); await invalidateAll(); }}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</Dialog.Close>
|
||||
|
||||
<div>
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<script>
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
|
||||
export let src = '/mdev_triangle_loading.riv';
|
||||
export let stateMachine = null;
|
||||
export let size = 120;
|
||||
|
||||
|
||||
let canvas;
|
||||
let riveInstance;
|
||||
|
||||
onMount(async () => {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
const mod = await import('@rive-app/canvas');
|
||||
|
||||
// Handle BOTH CJS and ESM shapes safely
|
||||
const Rive = mod?.Rive || mod?.default?.Rive || mod?.default;
|
||||
|
||||
if (!Rive) {
|
||||
console.error('Rive failed to load:', mod);
|
||||
return;
|
||||
}
|
||||
|
||||
riveInstance = new Rive({
|
||||
src,
|
||||
canvas,
|
||||
autoplay: true,
|
||||
// stateMachines: stateMachine || undefined,
|
||||
onLoad: () => {
|
||||
riveInstance.resizeDrawingSurfaceToCanvas();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
riveInstance?.cleanup?.();
|
||||
});
|
||||
</script>
|
||||
|
||||
<canvas bind:this={canvas} width={size} height={size} />
|
||||
@@ -6,7 +6,7 @@
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import * as Field from '$lib/components/ui/field';
|
||||
import { fileToBase64 } from '$lib/shared';
|
||||
|
||||
import LoadingSpinner from './loading-spinner.svelte';
|
||||
import ImageUpload from '$lib/components/custom/image-upload/image-upload.svelte';
|
||||
import { genDescription } from '$lib/db/items.remote';
|
||||
import { EMAIL_REGEX_STRING } from '$lib/consts';
|
||||
@@ -18,6 +18,7 @@
|
||||
let isGenerating = $state(false);
|
||||
|
||||
async function onSelect(file: File) {
|
||||
|
||||
isGenerating = true;
|
||||
|
||||
const base64 = await fileToBase64(file);
|
||||
@@ -69,7 +70,11 @@
|
||||
/>
|
||||
</Field.Field>
|
||||
|
||||
<RadioGroup.Root name="location" bind:value={itemLocation}>
|
||||
|
||||
<RadioGroup.Root name="location" bind:value={itemLocation} required>
|
||||
<Field.Label for="location">
|
||||
Where is it? <span class="text-error">*</span>
|
||||
</Field.Label>
|
||||
<div class="flex items-center space-x-2">
|
||||
<RadioGroup.Item value="finderPossession" id="finderPossession" />
|
||||
<Label for="finderPossession">
|
||||
@@ -115,8 +120,11 @@
|
||||
</Dialog.Root>
|
||||
|
||||
|
||||
{#if isGenerating}
|
||||
<div class="fixed inset-0 bg-black/75 z-999999 w-screen h-screen justify-center items-center flex">
|
||||
<p class="text-6xl text-primary">Loading...</p>
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
class="fixed inset-0 bg-black/75 z-[999999] w-screen h-screen flex justify-center items-center transition-opacity duration-150"
|
||||
class:opacity-0={!isGenerating}
|
||||
class:pointer-events-none={!isGenerating}
|
||||
>
|
||||
<LoadingSpinner size={150} />
|
||||
<p class="text-6xl ml-4">Loading...</p>
|
||||
</div>
|
||||
|
||||
+141
-45
@@ -56,69 +56,165 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mx-auto max-w-6xl px-6 py-20" aria-labelledby="info-cards-heading">
|
||||
<h2 id="info-cards-heading" class="sr-only">Information</h2>
|
||||
<div class="grid gap-8 md:grid-cols-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle id="found-item-heading">Found an Item?</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent
|
||||
class="space-y-3 text-sm text-muted-foreground"
|
||||
aria-labelledby="found-item-heading"
|
||||
>
|
||||
<p>
|
||||
Turn it in digitally in less than a minute. Add a description and where you found it.
|
||||
<!-- FEATURES -->
|
||||
<section class="mx-auto max-w-6xl px-6 py-12" aria-labelledby="features-heading">
|
||||
<h2 id="features-heading" class="text-2xl font-semibold text-center mb-12">
|
||||
Everything you need to get items back fast
|
||||
</h2>
|
||||
|
||||
<div class="grid gap-12 md:grid-cols-2 items-center">
|
||||
<!-- Left visual / emphasis block -->
|
||||
<div class="space-y-6">
|
||||
<div class="rounded-2xl border bg-muted/30 p-6">
|
||||
<h3 class="font-semibold text-lg">Built for speed</h3>
|
||||
<p class="text-sm text-muted-foreground mt-2">
|
||||
Report and browse items in seconds. The entire flow is designed to reduce friction.
|
||||
</p>
|
||||
<Button
|
||||
class="mt-2 w-full"
|
||||
variant="outline"
|
||||
onclick={openCreateDialog}
|
||||
aria-label="Submit a found item"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="rounded-2xl border bg-muted/20 p-6">
|
||||
<h3 class="font-semibold text-lg">Organized listings</h3>
|
||||
<p class="text-sm text-muted-foreground mt-2">
|
||||
Items are structured by location and category so nothing gets buried.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-2xl border bg-muted/10 p-6">
|
||||
<h3 class="font-semibold text-lg">Trusted process</h3>
|
||||
<p class="text-sm text-muted-foreground mt-2">
|
||||
Every submission is reviewed before it’s visible.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right visual anchor -->
|
||||
<div class="rounded-2xl border p-10 bg-gradient-to-br from-primary/10 to-transparent">
|
||||
<h3 class="text-xl font-semibold">Designed for school life</h3>
|
||||
<p class="text-sm text-muted-foreground mt-4">
|
||||
Backpacks, phones, notebooks, jackets — the things that actually get lost daily.
|
||||
Everything here is tuned for real student use, not generic “lost & found” systems.
|
||||
</p>
|
||||
|
||||
<div class="mt-6 text-xs text-muted-foreground">
|
||||
Over <span class="font-medium text-foreground">120+</span> items successfully returned
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- HOW IT WORKS (Vertical Timeline Style) -->
|
||||
<section class="mx-auto max-w-4xl px-6 py-12" aria-labelledby="how-heading">
|
||||
<h2 id="how-heading" class="text-2xl font-semibold text-center mb-12">
|
||||
How it works
|
||||
</h2>
|
||||
|
||||
<div class="relative border-l pl-8 space-y-10">
|
||||
<div class="relative">
|
||||
<div class="absolute -left-[40px] top-1 h-4 w-4 rounded-full bg-primary"></div>
|
||||
<h3 class="font-semibold">Someone finds something</h3>
|
||||
<p class="text-sm text-muted-foreground mt-1">
|
||||
An item is discovered in a classroom, hallway, locker room, or common area.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<div class="absolute -left-[40px] top-1 h-4 w-4 rounded-full bg-primary/70"></div>
|
||||
<h3 class="font-semibold">It gets submitted</h3>
|
||||
<p class="text-sm text-muted-foreground mt-1">
|
||||
A quick submission captures what it is and where it was found.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="relative">
|
||||
<div class="absolute -left-[40px] top-1 h-4 w-4 rounded-full bg-primary/40"></div>
|
||||
<h3 class="font-semibold">It makes its way home</h3>
|
||||
<p class="text-sm text-muted-foreground mt-1">
|
||||
The owner identifies it and retrieves it through staff.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ACTION / INFO (Staggered Bento Style Instead of 3 Equal Cards) -->
|
||||
<section class="mx-auto max-w-6xl px-6 py-24" aria-labelledby="info-heading">
|
||||
<h2 id="info-heading" class="sr-only">Actions</h2>
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-6">
|
||||
<!-- Large primary card -->
|
||||
<Card class="">
|
||||
<CardHeader>
|
||||
<CardTitle>Found something?</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-4 text-sm text-muted-foreground">
|
||||
<p>
|
||||
Help return it in under a minute. Every submission makes a difference.
|
||||
</p>
|
||||
<Button variant="outline" class="w-full" onclick={openCreateDialog}>
|
||||
Submit Item
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<!-- Side card -->
|
||||
<Card class="">
|
||||
<CardHeader>
|
||||
<CardTitle id="lost-item-heading">Lost Something?</CardTitle>
|
||||
<CardTitle>Looking for yours?</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent
|
||||
class="space-y-3 text-sm text-muted-foreground"
|
||||
aria-labelledby="lost-item-heading"
|
||||
>
|
||||
<CardContent class="space-y-4 text-sm text-muted-foreground">
|
||||
<p>
|
||||
Browse items that have been turned in by students and staff.
|
||||
Check the live list of items turned in around school.
|
||||
</p>
|
||||
<a
|
||||
href="/items"
|
||||
class={cn(buttonVariants({ variant: 'outline', size: 'lg' }), 'mt-2 w-full')}
|
||||
aria-label="Browse found items"
|
||||
class={cn(buttonVariants({ variant: 'outline' }), 'w-full')}
|
||||
>
|
||||
Browse Items
|
||||
Browse
|
||||
</a>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle id="safe-heading">Safe & Effective</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent
|
||||
class="space-y-3 text-sm text-muted-foreground"
|
||||
aria-labelledby="safe-heading"
|
||||
>
|
||||
<p>
|
||||
Managed by Waukesha West staff. Items are reviewed before being listed.
|
||||
</p>
|
||||
<p>
|
||||
We've returned 120+ items back to their owners!
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<!-- Wide bottom emphasis card -->
|
||||
<Card class="md:col-span-3 border-muted bg-muted/20 mt-6">
|
||||
<CardContent class=" flex flex-col md:flex-row md:items-center md:justify-between gap-4">
|
||||
<div>
|
||||
<h3 class="font-semibold">Built on trust</h3>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
A simple system powered by students and staff working together.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="text-sm text-muted-foreground">
|
||||
<span class="font-medium text-foreground">120+</span> items returned and counting
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</section>
|
||||
|
||||
<!-- IMPORTANT DISCLAIMER -->
|
||||
<section class="mx-auto max-w-6xl px-6 pb-20" aria-labelledby="policy-heading">
|
||||
<Card class="border-amber-500/40 bg-amber-500/5">
|
||||
<CardHeader>
|
||||
<CardTitle id="policy-heading">Important Notice</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="text-sm text-muted-foreground space-y-3">
|
||||
<p>
|
||||
This platform is intended for everyday personal items such as notebooks, clothing,
|
||||
water bottles, and similar belongings commonly misplaced at school.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Items of significant monetary, legal, or sensitive value (including but not limited to cash,
|
||||
credit cards, IDs, or high-value electronics) should <strong>not</strong> be handled through
|
||||
this system.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Such items must be immediately reported to the main office or appropriate school staff for
|
||||
proper handling and documentation.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</section>
|
||||
|
||||
<section class="mx-auto max-w-6xl px-6 pb-24" aria-labelledby="staff-heading">
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
}
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
</script>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4">
|
||||
|
||||
Reference in New Issue
Block a user