Refactor environment variable declarations and update asset references in SvelteKit project. Removed unused variables and updated client entry points and stylesheets for improved performance.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { browser } from "$app/environment";
|
||||
import * as Table from "$lib/components/ui/table";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "$lib/components/ui/card";
|
||||
import { Card, CardContent } from "$lib/components/ui/card";
|
||||
import type { StackqItem } from "$lib/types/items";
|
||||
|
||||
let { data }: { data: { items: StackqItem[]; itemsForParent: { id: string; Item: string; SKU: string }[] } } = $props();
|
||||
@@ -46,10 +46,6 @@
|
||||
<span class="text-muted-foreground text-sm">{items.length} items</span>
|
||||
</div>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Stackq_Items</CardTitle>
|
||||
<p class="text-muted-foreground text-sm">PocketBase collection. Enable JS for create/edit/delete.</p>
|
||||
</CardHeader>
|
||||
<CardContent class="p-0">
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import { enhance } from "$app/forms";
|
||||
import { Camera, X } from "@lucide/svelte";
|
||||
import { UOM_OPTIONS, CATAGORY_OPTIONS, SUB_CATAGORY_OPTIONS } from "$lib/constants/items";
|
||||
import type { StackqItem } from "$lib/types/items";
|
||||
|
||||
@@ -37,6 +38,83 @@
|
||||
const defaultParent = $derived(item?.Parent ?? "");
|
||||
const defaultHasParent = $derived(!!item?.Has_Parent);
|
||||
const defaultStock = $derived(!!item?.Stock);
|
||||
|
||||
let skuValue = $state("");
|
||||
let showScanner = $state(false);
|
||||
let scanError = $state<string | null>(null);
|
||||
let videoEl = $state<HTMLVideoElement | undefined>(undefined);
|
||||
let stream: MediaStream | null = null;
|
||||
let scanRAF = 0;
|
||||
|
||||
$effect(() => {
|
||||
skuValue = defaultSku;
|
||||
});
|
||||
|
||||
const hasBarcodeDetector = $derived(typeof globalThis !== "undefined" && "BarcodeDetector" in globalThis);
|
||||
|
||||
async function startScan() {
|
||||
scanError = null;
|
||||
if (!hasBarcodeDetector) {
|
||||
scanError = "Barcode scan is not supported in this browser. Try Chrome or Edge.";
|
||||
showScanner = true;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } });
|
||||
showScanner = true;
|
||||
} catch (e) {
|
||||
scanError = e instanceof Error ? e.message : "Could not access camera.";
|
||||
showScanner = true;
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if (!showScanner || !stream || !videoEl) return;
|
||||
videoEl.srcObject = stream;
|
||||
videoEl.play().then(() => scanLoop()).catch(() => {});
|
||||
return () => {
|
||||
if (videoEl.srcObject) videoEl.srcObject = null;
|
||||
};
|
||||
});
|
||||
|
||||
function scanLoop() {
|
||||
if (!showScanner || !videoEl || !("BarcodeDetector" in globalThis)) return;
|
||||
const detector = new (globalThis as unknown as { BarcodeDetector: typeof BarcodeDetector }).BarcodeDetector();
|
||||
async function detect() {
|
||||
if (!showScanner || !videoEl || videoEl.readyState < 2) {
|
||||
scanRAF = requestAnimationFrame(detect);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const barcodes = await detector.detect(videoEl);
|
||||
if (barcodes.length > 0) {
|
||||
skuValue = barcodes[0].rawValue;
|
||||
stopScan();
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// ignore frame errors
|
||||
}
|
||||
scanRAF = requestAnimationFrame(detect);
|
||||
}
|
||||
detect();
|
||||
}
|
||||
|
||||
function stopScan() {
|
||||
showScanner = false;
|
||||
scanError = null;
|
||||
if (scanRAF) {
|
||||
cancelAnimationFrame(scanRAF);
|
||||
scanRAF = 0;
|
||||
}
|
||||
if (stream) {
|
||||
stream.getTracks().forEach((t) => t.stop());
|
||||
stream = null;
|
||||
}
|
||||
if (videoEl && videoEl.srcObject) {
|
||||
videoEl.srcObject = null;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form
|
||||
@@ -61,10 +139,42 @@
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="SKU">SKU</Label>
|
||||
<Input id="SKU" name="SKU" value={defaultSku} />
|
||||
<div class="flex gap-2">
|
||||
<Input id="SKU" name="SKU" bind:value={skuValue} class="flex-1" />
|
||||
<Button type="button" variant="outline" size="icon" onclick={startScan} title="Scan barcode">
|
||||
<Camera class="size-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if showScanner}
|
||||
<div
|
||||
class="bg-background/95 fixed inset-0 z-50 flex flex-col items-center justify-center gap-4 p-4 backdrop-blur-sm"
|
||||
role="dialog"
|
||||
aria-label="Scan barcode"
|
||||
>
|
||||
<div class="flex w-full max-w-sm flex-col gap-2">
|
||||
{#if scanError}
|
||||
<p class="text-destructive text-sm">{scanError}</p>
|
||||
{:else}
|
||||
<video
|
||||
bind:this={videoEl}
|
||||
class="border-input w-full rounded-lg border"
|
||||
muted
|
||||
playsinline
|
||||
></video>
|
||||
{/if}
|
||||
<div class="flex gap-2">
|
||||
<Button type="button" variant="outline" class="flex-1" onclick={stopScan}>
|
||||
<X class="mr-2 size-4" />
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="Description">Description</Label>
|
||||
<Input id="Description" name="Description" value={defaultDesc} />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import * as Table from "$lib/components/ui/table";
|
||||
import { Badge } from "$lib/components/ui/badge";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "$lib/components/ui/card";
|
||||
import { Card, CardContent } from "$lib/components/ui/card";
|
||||
import * as Dialog from "$lib/components/ui/dialog";
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||
import { enhance } from "$app/forms";
|
||||
@@ -88,12 +88,6 @@
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Stackq_Items</CardTitle>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
PocketBase collection: full CRUD.
|
||||
</p>
|
||||
</CardHeader>
|
||||
<CardContent class="p-0">
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
|
||||
@@ -3,8 +3,8 @@ import type { Actions, PageServerLoad } from "./$types";
|
||||
|
||||
function safeRedirectTo(searchParams: URLSearchParams): string {
|
||||
const to = searchParams.get("redirectTo");
|
||||
if (!to || typeof to !== "string") return "/";
|
||||
if (!to.startsWith("/") || to.startsWith("//")) return "/";
|
||||
if (!to || typeof to !== "string") return "/items";
|
||||
if (!to.startsWith("/") || to.startsWith("//")) return "/items";
|
||||
return to;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user