Initial Commit
This commit is contained in:
+23
@@ -0,0 +1,23 @@
|
||||
node_modules
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
.wrangler
|
||||
/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"plugin": [
|
||||
"@sveltejs/opencode"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"$schema": "https://svelte.dev/opencode/schema.json"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||
"ignorePatterns": [],
|
||||
"sortImports": true,
|
||||
"printWidth": 80
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["typescript", "unicorn", "oxc"],
|
||||
"categories": {
|
||||
"correctness": "error"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-expressions": "off",
|
||||
"consistent-type-imports": "error"
|
||||
},
|
||||
"ignorePatterns": [".direnv/**/*", ".svelte-kit/**/*"],
|
||||
"env": {
|
||||
"builtin": true
|
||||
}
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"svelte.svelte-vscode",
|
||||
"bradlc.vscode-tailwindcss"
|
||||
]
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"servers": {
|
||||
"svelte": {
|
||||
"url": "https://mcp.svelte.dev/mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.css": "tailwindcss"
|
||||
},
|
||||
"i18n-ally.localesPaths": ["src/lib/locales"],
|
||||
"i18n-ally.keystyle": "nested",
|
||||
"i18n-ally.sourceLanguage": "en"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
## Project Configuration
|
||||
|
||||
- **Language**: TypeScript
|
||||
- **Package Manager**: bun
|
||||
- **Add-ons**: tailwindcss, sveltekit-adapter, mcp
|
||||
|
||||
---
|
||||
|
||||
You are able to use the Svelte MCP server, where you have access to comprehensive Svelte 5 and SvelteKit documentation. Here's how to use the available tools effectively:
|
||||
|
||||
## Available Svelte MCP Tools:
|
||||
|
||||
### 1. list-sections
|
||||
|
||||
Use this FIRST to discover all available documentation sections. Returns a structured list with titles, use_cases, and paths.
|
||||
When asked about Svelte or SvelteKit topics, ALWAYS use this tool at the start of the chat to find relevant sections.
|
||||
|
||||
### 2. get-documentation
|
||||
|
||||
Retrieves full documentation content for specific sections. Accepts single or multiple sections.
|
||||
After calling the list-sections tool, you MUST analyze the returned documentation sections (especially the use_cases field) and then use the get-documentation tool to fetch ALL documentation sections that are relevant for the user's task.
|
||||
|
||||
### 3. svelte-autofixer
|
||||
|
||||
Analyzes Svelte code and returns issues and suggestions.
|
||||
You MUST use this tool whenever writing Svelte code before sending it to the user. Keep calling it until no issues or suggestions are returned.
|
||||
|
||||
### 4. playground-link
|
||||
|
||||
Generates a Svelte Playground link with the provided code.
|
||||
After completing the code, ask the user if they want a playground link. Only call this tool after user confirmation and NEVER if code was written to files in their project.
|
||||
@@ -0,0 +1,12 @@
|
||||
# HotFridge
|
||||
|
||||
- WebApp
|
||||
- food expiry tracking app
|
||||
- AI-powered scan that scans placed out items on table to suggest list of items to add with Icon, Name, Estimated Expiry and Calories. User can edit it before approving to add.
|
||||
- Notification for near-expired food.2
|
||||
- Marking items as used so it will be moved to "Out of stock" cart so that user can bring that to buying checklist
|
||||
- Algorithmized guides based on existing items and near expiry for preserving and recipes and more
|
||||
|
||||
ของในตู้เย็นเยอะเกินไป ทำให้หาของยาก อาหารบางอย่างเก็บไว้นานจนเสียจนอาจส่งกลิ่นเหม็น ไม่มีที่ใส่อาหารใหม่
|
||||
ปัญหาตู้เย็นเต็มจากของเก่าและของใหม่ทับถมกัน
|
||||
เว็บแอปติดตามวันหมดอายุอาหาร ช่วยจัดการวัตถุดิบในตู้เย็นด้วย AI สแกนอาหาร แจ้งเตือนของใกล้หมดอายุ จัดทำเช็กลิสต์ซื้อของ และแนะนำการถนอมอาหารหรือสูตรอาหารจากวัตถุดิบที่มีอยู่
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "https://shadcn-svelte.com/schema.json",
|
||||
"tailwind": {
|
||||
"css": "src/routes/layout.css",
|
||||
"baseColor": "neutral"
|
||||
},
|
||||
"aliases": {
|
||||
"components": "$lib/components",
|
||||
"utils": "$lib/utils",
|
||||
"ui": "$lib/components/ui",
|
||||
"hooks": "$lib/hooks",
|
||||
"lib": "$lib"
|
||||
},
|
||||
"typescript": true,
|
||||
"registry": "https://shadcn-svelte.com/registry",
|
||||
"style": "vega",
|
||||
"iconLibrary": "lucide",
|
||||
"menuColor": "default",
|
||||
"menuAccent": "subtle"
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "hotfridge",
|
||||
"version": "0.0.1",
|
||||
"devDependencies": {
|
||||
"@fontsource-variable/inter": "^5.2.8",
|
||||
"@lucide/svelte": "^1.23.0",
|
||||
"@sveltejs/adapter-static": "^3.0.10",
|
||||
"@sveltejs/kit": "^2.57.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
||||
"@tailwindcss/vite": "^4.2.2",
|
||||
"@types/bun": "^1.3.13",
|
||||
"@vite-pwa/sveltekit": "^1.1.0",
|
||||
"clsx": "^2.1.1",
|
||||
"mode-watcher": "^1.1.0",
|
||||
"shadcn-svelte": "^1.2.7",
|
||||
"svelte": "^5.55.2",
|
||||
"svelte-check": "^4.4.6",
|
||||
"svelte-i18n": "^4.0.1",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"tailwind-variants": "^3.2.2",
|
||||
"tailwindcss": "^4.2.2",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "^6.0.2",
|
||||
"vite": "^8.0.7"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"prepare": "svelte-kit sync || echo ''",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
/// <reference types="vite-plugin-pwa/info" />
|
||||
/// <reference types="vite-plugin-pwa" />
|
||||
/// <reference types="vite-plugin-pwa/client" />
|
||||
|
||||
// See https://svelte.dev/docs/kit/types#app.d.ts
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface PageState {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="text-scale" content="scale" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
|
||||
<body data-sveltekit-preload-data="hover" class="font-google-sans">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// src/i18n.js
|
||||
import { getLocaleFromNavigator, init, register } from "svelte-i18n";
|
||||
|
||||
register("en", () => import("$lib/locales/en.json"));
|
||||
register("th", () => import("$lib/locales/th.json"));
|
||||
|
||||
init({
|
||||
fallbackLocale: "en",
|
||||
initialLocale: getLocaleFromNavigator(),
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="107" height="128" viewBox="0 0 107 128"><title>svelte-logo</title><path d="M94.157 22.819c-10.4-14.885-30.94-19.297-45.792-9.835L22.282 29.608A29.92 29.92 0 0 0 8.764 49.65a31.5 31.5 0 0 0 3.108 20.231 30 30 0 0 0-4.477 11.183 31.9 31.9 0 0 0 5.448 24.116c10.402 14.887 30.942 19.297 45.791 9.835l26.083-16.624A29.92 29.92 0 0 0 98.235 78.35a31.53 31.53 0 0 0-3.105-20.232 30 30 0 0 0 4.474-11.182 31.88 31.88 0 0 0-5.447-24.116" style="fill:#ff3e00"/><path d="M45.817 106.582a20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.503 18 18 0 0 1 .624-2.435l.49-1.498 1.337.981a33.6 33.6 0 0 0 10.203 5.098l.97.294-.09.968a5.85 5.85 0 0 0 1.052 3.878 6.24 6.24 0 0 0 6.695 2.485 5.8 5.8 0 0 0 1.603-.704L69.27 76.28a5.43 5.43 0 0 0 2.45-3.631 5.8 5.8 0 0 0-.987-4.371 6.24 6.24 0 0 0-6.698-2.487 5.7 5.7 0 0 0-1.6.704l-9.953 6.345a19 19 0 0 1-5.296 2.326 20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.502 17.99 17.99 0 0 1 8.13-12.052l26.081-16.623a19 19 0 0 1 5.3-2.329 20.72 20.72 0 0 1 22.237 8.243 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-.624 2.435l-.49 1.498-1.337-.98a33.6 33.6 0 0 0-10.203-5.1l-.97-.294.09-.968a5.86 5.86 0 0 0-1.052-3.878 6.24 6.24 0 0 0-6.696-2.485 5.8 5.8 0 0 0-1.602.704L37.73 51.72a5.42 5.42 0 0 0-2.449 3.63 5.79 5.79 0 0 0 .986 4.372 6.24 6.24 0 0 0 6.698 2.486 5.8 5.8 0 0 0 1.602-.704l9.952-6.342a19 19 0 0 1 5.295-2.328 20.72 20.72 0 0 1 22.237 8.242 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-8.13 12.053l-26.081 16.622a19 19 0 0 1-5.3 2.328" style="fill:#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,93 @@
|
||||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
const { active = true }: { active?: boolean } = $props();
|
||||
|
||||
let cameraStream = $state<MediaStream>();
|
||||
let width = $state<number>(0);
|
||||
let height = $state<number>(0);
|
||||
let canvas = $state<HTMLCanvasElement>();
|
||||
let video = $state<HTMLVideoElement>();
|
||||
|
||||
let isStarting = $state(false);
|
||||
let facingMode = $state<"user" | "environment">("environment");
|
||||
|
||||
async function startCamera() {
|
||||
if (cameraStream || isStarting) return;
|
||||
if (!navigator.mediaDevices?.getUserMedia) return;
|
||||
|
||||
isStarting = true;
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
video: {
|
||||
facingMode: { ideal: facingMode },
|
||||
},
|
||||
});
|
||||
if (!active) {
|
||||
stream.getTracks().map((track) => track.stop());
|
||||
return;
|
||||
}
|
||||
cameraStream = stream;
|
||||
} catch (error) {
|
||||
console.error("Error accessing the camera:", error);
|
||||
} finally {
|
||||
isStarting = false;
|
||||
}
|
||||
}
|
||||
|
||||
function stopCamera() {
|
||||
if (!cameraStream) return;
|
||||
cameraStream.getTracks().map((track) => track.stop());
|
||||
cameraStream = undefined;
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (active) startCamera();
|
||||
return () => stopCamera();
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (active) {
|
||||
startCamera();
|
||||
} else {
|
||||
stopCamera();
|
||||
}
|
||||
});
|
||||
|
||||
export function takePicture() {
|
||||
if (!canvas) return console.error("No canvas");
|
||||
const context = canvas.getContext("2d");
|
||||
if (!context) return console.error("No context");
|
||||
if (!video) return console.error("No video");
|
||||
context.drawImage(video, 0, 0, width, height);
|
||||
|
||||
const imageDataUrl = canvas.toDataURL("image/png");
|
||||
return imageDataUrl;
|
||||
}
|
||||
|
||||
export async function switchCamera() {
|
||||
facingMode = facingMode === "user" ? "environment" : "user";
|
||||
stopCamera();
|
||||
await startCamera();
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if active}
|
||||
<video
|
||||
autoplay
|
||||
playsinline
|
||||
srcobject={cameraStream}
|
||||
bind:videoWidth={width}
|
||||
bind:videoHeight={height}
|
||||
bind:this={video}
|
||||
class={cn(
|
||||
"fixed -z-10 top-0 left-0 min-w-full min-h-full object-cover transition-transform scale-x-100",
|
||||
facingMode === "user" ? "-scale-x-100" : "",
|
||||
)}
|
||||
></video>
|
||||
{:else}
|
||||
<div class="fixed -z-10 top-0 left-0 min-w-full min-h-full bg-black"></div>
|
||||
{/if}
|
||||
|
||||
<canvas style="display:none;" {width} {height} bind:this={canvas}></canvas>
|
||||
@@ -0,0 +1,30 @@
|
||||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
import type { LucideIcon } from "@lucide/svelte";
|
||||
import type { ResolvedPathname } from "$app/types";
|
||||
import { page } from "$app/state";
|
||||
|
||||
const {
|
||||
label,
|
||||
href,
|
||||
icon: Icon,
|
||||
}: {
|
||||
label: string;
|
||||
href: ResolvedPathname;
|
||||
icon: LucideIcon;
|
||||
} = $props();
|
||||
|
||||
const selected = $derived(page.url.pathname.startsWith(href));
|
||||
</script>
|
||||
|
||||
<a
|
||||
class={cn(
|
||||
"flex flex-col gap-1 items-center opacity-50 transition-opacity w-11",
|
||||
selected && "opacity-100",
|
||||
)}
|
||||
data-sveltekit-preload-code="eager"
|
||||
{href}
|
||||
>
|
||||
<Icon />
|
||||
<span class="text-xs">{label}</span>
|
||||
</a>
|
||||
@@ -0,0 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/state";
|
||||
import { cn } from "$lib/utils";
|
||||
import ScanIcon from "@lucide/svelte/icons/scan-search";
|
||||
|
||||
const selected = $derived(page.url.pathname === "/app/scan");
|
||||
</script>
|
||||
|
||||
<a
|
||||
class={cn(
|
||||
"flex flex-col gap-1 items-center rounded-full bg-blue-500 text-white p-3 transition-colors",
|
||||
selected && "dark:bg-white bg-black dark:text-blue-500",
|
||||
)}
|
||||
href="/app/scan"
|
||||
>
|
||||
<ScanIcon />
|
||||
</a>
|
||||
@@ -0,0 +1 @@
|
||||
// place files you want to import through the `$lib` alias in this folder.
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"nav": {
|
||||
"home": "Home",
|
||||
"search": "Search",
|
||||
"scan": "Scan",
|
||||
"guide": "Guide",
|
||||
"settings": "Settings"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"nav": {
|
||||
"home": "หน้าหลัก",
|
||||
"search": "ค้นหา",
|
||||
"scan": "สแกน",
|
||||
"guide": "ไกด์",
|
||||
"settings": "การตั้งค่า"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T;
|
||||
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
|
||||
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
|
||||
@@ -0,0 +1 @@
|
||||
export const prerender = true;
|
||||
@@ -0,0 +1,46 @@
|
||||
<script lang="ts">
|
||||
import "./layout.css";
|
||||
import "../i18n";
|
||||
import { ModeWatcher } from "mode-watcher";
|
||||
import favicon from "$lib/assets/favicon.svg";
|
||||
import { isLoading } from "svelte-i18n";
|
||||
import { pwaInfo } from "virtual:pwa-info";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let { children } = $props();
|
||||
|
||||
const webManifestLink = $derived(pwaInfo ? pwaInfo.webManifest.linkTag : "");
|
||||
|
||||
onMount(async () => {
|
||||
if (pwaInfo) {
|
||||
const { registerSW } = await import("virtual:pwa-register");
|
||||
registerSW({
|
||||
immediate: true,
|
||||
onRegistered(r) {
|
||||
// uncomment following code if you want check for updates
|
||||
// r && setInterval(() => {
|
||||
// console.log('Checking for sw update')
|
||||
// r.update()
|
||||
// }, 20000 /* 20s for testing purposes */)
|
||||
console.log(`SW Registered: ${r}`);
|
||||
},
|
||||
onRegisterError(error) {
|
||||
console.log("SW registration error", error);
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>HotFridge</title>
|
||||
<link rel="icon" href={favicon} />
|
||||
<meta name="darkreader" content="disable" />
|
||||
{@html webManifestLink}
|
||||
</svelte:head>
|
||||
<ModeWatcher />
|
||||
{#if $isLoading}
|
||||
Loading
|
||||
{:else}
|
||||
{@render children()}
|
||||
{/if}
|
||||
@@ -0,0 +1,2 @@
|
||||
<h1>Welcome to SvelteKit</h1>
|
||||
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
|
||||
@@ -0,0 +1,9 @@
|
||||
<script lang="ts">
|
||||
import NavbarWrapper from "./navbar.svelte";
|
||||
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
<NavbarWrapper>
|
||||
{@render children()}
|
||||
</NavbarWrapper>
|
||||
@@ -0,0 +1 @@
|
||||
hello world
|
||||
@@ -0,0 +1 @@
|
||||
guide here
|
||||
@@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { locale, locales } from "svelte-i18n";
|
||||
</script>
|
||||
|
||||
<select bind:value={$locale}>
|
||||
{#each $locales as locale}
|
||||
<option value={locale}>{locale}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
import NavButton from "$lib/components/nav/nav-button.svelte";
|
||||
import NavCam from "$lib/components/nav/nav-cam.svelte";
|
||||
import HomeIcon from "@lucide/svelte/icons/house";
|
||||
import SearchIcon from "@lucide/svelte/icons/search";
|
||||
import GuideIcon from "@lucide/svelte/icons/book-image";
|
||||
import SettingsIcon from "@lucide/svelte/icons/settings";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
let { children } = $props();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="content">
|
||||
{@render children()}
|
||||
</div>
|
||||
<div class="navbar flex items-center justify-evenly bg-sidebar">
|
||||
<NavButton label={$_("nav.home")} icon={HomeIcon} href="/app/home" />
|
||||
<NavButton label={$_("nav.search")} icon={SearchIcon} href="/app/search" />
|
||||
<NavCam />
|
||||
<NavButton label={$_("nav.guide")} icon={GuideIcon} href="/app/guide" />
|
||||
<NavButton
|
||||
label={$_("nav.settings")}
|
||||
icon={SettingsIcon}
|
||||
href="/app/settings"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.navbar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-bottom: 64px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,14 @@
|
||||
<script lang="ts">
|
||||
import Camera from "$lib/components/camera.svelte";
|
||||
import SwitchCamera from "@lucide/svelte/icons/switch-camera";
|
||||
let camera = $state<Camera>();
|
||||
</script>
|
||||
|
||||
<Camera bind:this={camera} />
|
||||
<div
|
||||
class="flex absolute left-1/2 -translate-x-1/2 bottom-16 justify-center rounded-full bg-black/50 p-2"
|
||||
>
|
||||
<button onclick={() => camera?.switchCamera()}>
|
||||
<SwitchCamera />
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
search here
|
||||
@@ -0,0 +1,9 @@
|
||||
<script>
|
||||
import { locale, locales } from "svelte-i18n";
|
||||
</script>
|
||||
|
||||
<select bind:value={$locale}>
|
||||
{#each $locales as locale}
|
||||
<option value={locale}>{locale}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -0,0 +1,139 @@
|
||||
@import 'tailwindcss';
|
||||
@import "tw-animate-css";
|
||||
@import "shadcn-svelte/tailwind.css";
|
||||
@import "@fontsource-variable/inter";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
:root {
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.87 0 0);
|
||||
--chart-2: oklch(0.556 0 0);
|
||||
--chart-3: oklch(0.439 0 0);
|
||||
--chart-4: oklch(0.371 0 0);
|
||||
--chart-5: oklch(0.269 0 0);
|
||||
--radius: 0.625rem;
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.145 0 0);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.205 0 0);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.205 0 0);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.922 0 0);
|
||||
--primary-foreground: oklch(0.205 0 0);
|
||||
--secondary: oklch(0.269 0 0);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.269 0 0);
|
||||
--muted-foreground: oklch(0.708 0 0);
|
||||
--accent: oklch(0.269 0 0);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.556 0 0);
|
||||
--chart-1: oklch(0.87 0 0);
|
||||
--chart-2: oklch(0.556 0 0);
|
||||
--chart-3: oklch(0.439 0 0);
|
||||
--chart-4: oklch(0.371 0 0);
|
||||
--chart-5: oklch(0.269 0 0);
|
||||
--sidebar: oklch(0.205 0 0);
|
||||
--sidebar-foreground: oklch(0.985 0 0);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.269 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.556 0 0);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--font-sans: 'Inter Variable', sans-serif;
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-ring: var(--ring);
|
||||
--color-input: var(--input);
|
||||
--color-border: var(--border);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-card: var(--card);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-background: var(--background);
|
||||
--radius-sm: calc(var(--radius) * 0.6);
|
||||
--radius-md: calc(var(--radius) * 0.8);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) * 1.4);
|
||||
--radius-2xl: calc(var(--radius) * 1.8);
|
||||
--radius-3xl: calc(var(--radius) * 2.2);
|
||||
--radius-4xl: calc(var(--radius) * 2.6);
|
||||
--font-google-sans: "Google Sans", sans-serif;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
html {
|
||||
@apply font-sans;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Google Sans";
|
||||
font-style: normal;
|
||||
font-weight: 400 500 600;
|
||||
font-display: swap;
|
||||
src:
|
||||
local(""),
|
||||
url("/fonts/google_sans.woff2") format("woff2");
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,18 @@
|
||||
import adapter from '@sveltejs/adapter-static';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
compilerOptions: {
|
||||
experimental: {
|
||||
async: true,
|
||||
},
|
||||
// Force runes mode for the project, except for libraries. Can be removed in svelte 6.
|
||||
runes: ({ filename }) => filename.split(/[/\\]/).includes('node_modules') ? undefined : true
|
||||
},
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
experimental: { remoteFunctions: true },
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rewriteRelativeImportExtensions": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
}
|
||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||
//
|
||||
// To make changes to top-level options such as include and exclude, we recommend extending
|
||||
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import { SvelteKitPWA } from "@vite-pwa/sveltekit";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
tailwindcss(),
|
||||
sveltekit(),
|
||||
SvelteKitPWA({
|
||||
registerType: "autoUpdate",
|
||||
scope: "/app",
|
||||
manifest: {
|
||||
name: "HotFridge",
|
||||
short_name: "HotFridge",
|
||||
display: "standalone",
|
||||
background_color: "#222222",
|
||||
theme_color: "#ffffff",
|
||||
start_url: "/app",
|
||||
},
|
||||
workbox: {
|
||||
navigateFallback: "/app",
|
||||
globDirectory: "dist",
|
||||
globPatterns: ["app/**/*.{js,css,html,png,svg}"],
|
||||
},
|
||||
}),
|
||||
],
|
||||
server: { allowedHosts: ["nyx.neko-piranha.ts.net"] },
|
||||
});
|
||||
Reference in New Issue
Block a user