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:
@@ -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} />
|
||||
|
||||
Reference in New Issue
Block a user