- );
-}
diff --git a/app/orderfromtable/page.tsx b/app/orderfromtable/page.tsx
deleted file mode 100644
index a4afb5b..0000000
--- a/app/orderfromtable/page.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import { Suspense } from 'react';
-import Navbar from '@/components/Navbar';
-import OrderFromTableClient from './OrderFromTableClient';
-
-/**
- * Server wrapper for /orderfromtable
- *
- * We must wrap any component that uses useSearchParams() in a Suspense boundary
- * (Next.js 16 requirement for pages that read search params).
- *
- * This keeps the actual ordering UI fully client-side while satisfying the framework.
- */
-export default function OrderFromTablePage() {
- return (
-
-
-
{language === 'sv' ? 'SHAHI-SÄTTET' : 'THE SHAHI WAY'}
-
{language === 'sv' ? 'Mer än en måltid.\nEtt ögonblick av Shahi.' : 'More than a meal.\nA moment of Shahi.'}
-
-
-
- {(language === 'sv' ? [
- { title: "Den Legendariska Buffén", desc: "Vår berömda lunchbuffé har över 20 roterande rätter — curry, biryani, färsk naan och sötsaker." },
- { title: "Shahi Sötsaker", desc: "Hemgjord mithai dagligen. Från färsk jalebi till rasmalai — det perfekta söta avslutet." },
- { title: "Varm Gästfrihet", desc: "Oavsett om du är här för en snabb lunch eller familjefest, behandlas du alltid som shahi." },
- ] : [
- { title: "The Legendary Buffet", desc: "Our famous lunch buffet features over 20 rotating dishes — curries, biryanis, fresh naan, and sweets." },
- { title: "Shahi Sweets", desc: "Homemade mithai made daily. From fresh Jalebi to Rasmalai — the perfect sweet ending." },
- { title: "Warm Hospitality", desc: "Whether you're here for a quick lunch or a family celebration, you will always be treated like Shahi." },
- ]).map((item, index) => (
-
- );
-}
diff --git a/app/screen1/page.tsx b/app/screen1/page.tsx
deleted file mode 100644
index a4d1856..0000000
--- a/app/screen1/page.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import type { Metadata } from 'next';
-import ScreenDisplay from '@/components/ScreenDisplay';
-
-export const metadata: Metadata = {
- title: 'Shahi Kitchen | Display Screen 1',
- description: 'In-restaurant menu visualization — Screen 1',
- robots: {
- index: false,
- follow: false,
- },
-};
-
-export default function Screen1Page() {
- // Early inline script: ensures html/body get kiosk no-scrollbar rules BEFORE React hydrates.
- // Makes screen1 a perfectly clean full-window display (no web browser scrollbar) even on first paint / F11.
- // Pairs with the .screen-root + useEffect in ScreenDisplay for robustness.
- return (
- <>
-
-
- >
- );
-}
diff --git a/app/screen2/page.tsx b/app/screen2/page.tsx
deleted file mode 100644
index c6707de..0000000
--- a/app/screen2/page.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import type { Metadata } from 'next';
-import ScreenDisplay from '@/components/ScreenDisplay';
-
-export const metadata: Metadata = {
- title: 'Shahi Kitchen | Display Screen 2',
- description: 'In-restaurant menu visualization — Screen 2',
- robots: {
- index: false,
- follow: false,
- },
-};
-
-export default function Screen2Page() {
- // Early inline script: ensures html/body get kiosk no-scrollbar rules BEFORE React hydrates.
- // Makes screen2 a perfectly clean full-window display (no web browser scrollbar) even on first paint / F11.
- // Pairs with the .screen-root + useEffect in ScreenDisplay for robustness.
- return (
- <>
-
-
- >
- );
-}
diff --git a/app/screen3/page.tsx b/app/screen3/page.tsx
deleted file mode 100644
index 10b9ae4..0000000
--- a/app/screen3/page.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import type { Metadata } from 'next';
-import OrderDisplay from '@/components/OrderDisplay';
-
-export const metadata: Metadata = {
- title: 'Shahi Kitchen | Live Order Display',
- description: 'Live kitchen order board — in-house tables & online delivery (Foodora etc.) for customers and riders. Real-time status.',
- robots: {
- index: false,
- follow: false,
- },
-};
-
-export default function Screen3Page() {
- // Early inline script: ensures html/body get kiosk no-scrollbar rules BEFORE React hydrates.
- // Makes screen3 a perfectly clean full-window display (no web browser scrollbar) even on first paint / F11.
- // Pairs with .screen-root for the order board.
- return (
- <>
-
-
- >
- );
-}
diff --git a/application/cart/cart-line-builder.ts b/application/cart/cart-line-builder.ts
deleted file mode 100644
index f053f0e..0000000
--- a/application/cart/cart-line-builder.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import type { MenuItem } from '@/domain/menu/entities';
-import type { NewOrderLine } from '@/domain/shared/order-line';
-import {
- SWEETS_HALF_KG_PRICE,
- SWEETS_KG_PRICE,
-} from '@/domain/sweets/pricing';
-
-export function buildCartLineFromMenuItem(item: MenuItem): NewOrderLine {
- if (item.pricing === 'weight') {
- return {
- id: item.id,
- name: item.name,
- price: item.pricePerHalfKg ?? SWEETS_HALF_KG_PRICE,
- image: item.image,
- pricingMode: 'weight',
- pricePerKg: item.pricePerKg ?? SWEETS_KG_PRICE,
- pricePerHalfKg: item.pricePerHalfKg ?? SWEETS_HALF_KG_PRICE,
- };
- }
-
- return {
- id: item.id,
- name: item.name,
- price: item.price,
- image: item.image,
- pricingMode: 'standard',
- };
-}
\ No newline at end of file
diff --git a/application/language/language-use-cases.ts b/application/language/language-use-cases.ts
deleted file mode 100644
index c92c070..0000000
--- a/application/language/language-use-cases.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import {
- DEFAULT_LANGUAGE,
- isLanguage,
- type Language,
-} from '@/domain/language/entities';
-import type { LanguageRepository } from '@/domain/language/repository';
-
-export function detectBrowserLanguage(): Language {
- if (typeof navigator === 'undefined') return DEFAULT_LANGUAGE;
-
- const browserLang = navigator.language.toLowerCase();
- if (browserLang.startsWith('sv')) return 'sv';
- if (browserLang.startsWith('ar')) return 'ar';
- if (browserLang.startsWith('tr')) return 'tr';
- if (browserLang.startsWith('hi')) return 'hi';
- if (browserLang.startsWith('ur')) return 'ur';
- if (browserLang.startsWith('en')) return 'en';
- return DEFAULT_LANGUAGE;
-}
-
-export function resolveInitialLanguage(repository: LanguageRepository): Language {
- const saved = repository.load();
- if (saved && isLanguage(saved)) return saved;
- return detectBrowserLanguage();
-}
-
-export function persistLanguage(repository: LanguageRepository, language: Language): void {
- repository.save(language);
-}
\ No newline at end of file
diff --git a/application/media/asset-resolver.ts b/application/media/asset-resolver.ts
deleted file mode 100644
index 33e1a61..0000000
--- a/application/media/asset-resolver.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import type { MenuItem } from '@/domain/menu/entities';
-import {
- MEDIA_FOLDERS,
- SITE_ASSETS,
- mediaUrl,
-} from '@/infrastructure/assets/site-assets';
-
-export type PosterVariant = 'standard' | 'optimized';
-
-/** Strip .mp4 extension from a video filename */
-export function videoBaseName(videoFilename: string): string {
- return videoFilename.replace(/\.mp4$/i, '');
-}
-
-/** Full URL for a dish image filename (e.g. "butter-chicken.jpg") */
-export function dishImageUrl(filename: string): string {
- return mediaUrl(MEDIA_FOLDERS.dishes, filename);
-}
-
-/** Poster URL derived from a video filename */
-export function dishPosterFromVideo(
- videoFilename: string,
- variant: PosterVariant = 'standard'
-): string {
- const base = videoBaseName(videoFilename);
- const suffix = variant === 'optimized' ? '-optimized-poster.jpg' : '-poster.jpg';
- return mediaUrl(MEDIA_FOLDERS.dishes, `${base}${suffix}`);
-}
-
-/** Primary logo used in navbar, footer, login, etc. */
-export function logoUrl(): string {
- return SITE_ASSETS.logo.primary;
-}
-
-/** Hero banner video sources for homepage */
-export function heroBannerSources() {
- return {
- mobileWebm: SITE_ASSETS.banner.mobileWebm,
- mobileMp4: SITE_ASSETS.banner.mobileMp4,
- desktopMp4: SITE_ASSETS.banner.desktopMp4,
- };
-}
-
-/** Chef expression images for PlayfulHeroScene */
-export function chefExpressionUrl(expression: 'wink' | 'smile' | 'normal'): string {
- const map = {
- wink: SITE_ASSETS.animation.chefWink,
- smile: SITE_ASSETS.animation.chefSmile,
- normal: SITE_ASSETS.animation.chefNormal,
- };
- return map[expression];
-}
-
-/** Resolve primary poster path for a menu item */
-export function getMenuPosterSrc(
- item: MenuItem,
- variant: PosterVariant = 'standard'
-): string {
- if (item.video) {
- return dishPosterFromVideo(item.video, variant);
- }
- if (item.image) {
- return dishImageUrl(item.image);
- }
- return variant === 'optimized'
- ? SITE_ASSETS.dishes.defaultPoster
- : SITE_ASSETS.fallbacks.dishPoster;
-}
-
-/** Poster candidates for progressive fallback in UI `` */
-export function getMenuPosterCandidates(item: MenuItem): string[] {
- if (!item.video) {
- return item.image
- ? [dishImageUrl(item.image), SITE_ASSETS.fallbacks.logo]
- : [SITE_ASSETS.fallbacks.logo];
- }
-
- const base = videoBaseName(item.video);
- return [
- dishPosterFromVideo(item.video, 'standard'),
- dishPosterFromVideo(item.video, 'optimized'),
- ...(item.image ? [dishImageUrl(item.image)] : []),
- mediaUrl(MEDIA_FOLDERS.dishes, `${base}.jpg`),
- SITE_ASSETS.dishes.defaultPoster,
- SITE_ASSETS.fallbacks.dishPoster,
- ];
-}
-
-/** Full video URL for a menu item */
-export function getMenuVideoSrc(item: MenuItem): string | null {
- if (!item.video) return null;
- return mediaUrl(MEDIA_FOLDERS.videos, item.video);
-}
-
-/** Optimized + fallback video sources for kiosk displays */
-export function getMenuVideoSources(videoFilename: string) {
- if (!videoFilename) {
- return { webm: '', mp4: '', fallback: '' };
- }
- const base = videoBaseName(videoFilename);
- return {
- webm: mediaUrl(MEDIA_FOLDERS.videos, `${base}-optimized.webm`),
- mp4: mediaUrl(MEDIA_FOLDERS.videos, `${base}-optimized.mp4`),
- fallback: mediaUrl(MEDIA_FOLDERS.videos, `${base}.mp4`),
- };
-}
-
-/** Apply next fallback src in an img onError handler */
-export function applyNextImageFallback(
- target: HTMLImageElement,
- candidates: string[],
- currentSrc: string
-): void {
- const currentIndex = candidates.indexOf(currentSrc);
- const nextIndex = currentIndex >= 0 ? currentIndex + 1 : 0;
- if (nextIndex < candidates.length) {
- target.src = candidates[nextIndex];
- }
-}
-
-// Re-export registry for direct access when needed
-export { SITE_ASSETS, MEDIA_FOLDERS, mediaUrl } from '@/infrastructure/assets/site-assets';
\ No newline at end of file
diff --git a/application/menu/filter-menu.ts b/application/menu/filter-menu.ts
deleted file mode 100644
index 36aead9..0000000
--- a/application/menu/filter-menu.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import type { MenuCategory, MenuFilter, MenuItem } from '@/domain/menu/entities';
-
-export function filterMenuCategories(
- categories: MenuCategory[],
- filter: MenuFilter
-): MenuCategory[] {
- const query = filter.searchQuery?.toLowerCase().trim() ?? '';
-
- return categories
- .map((category) => {
- if (filter.categoryId && filter.categoryId !== 'All' && category.id !== filter.categoryId) {
- return { ...category, items: [] };
- }
-
- let items = category.items;
-
- if (query) {
- items = items.filter(
- (item) =>
- item.name.toLowerCase().includes(query) ||
- (item.description?.toLowerCase().includes(query) ?? false)
- );
- }
-
- if (filter.vegetarianOnly) {
- items = items.filter((item) => item.isVegetarian);
- }
-
- return { ...category, items };
- })
- .filter((category) => category.items.length > 0);
-}
-
-export function filterMenuItems(items: MenuItem[], filter: MenuFilter): MenuItem[] {
- const query = filter.searchQuery?.toLowerCase().trim() ?? '';
-
- return items.filter((item) => {
- if (filter.vegetarianOnly && !item.isVegetarian) return false;
- if (!query) return true;
- return (
- item.name.toLowerCase().includes(query) ||
- (item.description?.toLowerCase().includes(query) ?? false)
- );
- });
-}
\ No newline at end of file
diff --git a/application/menu/menu-media.ts b/application/menu/menu-media.ts
deleted file mode 100644
index c50c229..0000000
--- a/application/menu/menu-media.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * @deprecated Import from `@/application/media/asset-resolver` instead.
- * Kept for backward compatibility.
- */
-export {
- getMenuPosterSrc,
- getMenuPosterCandidates,
- getMenuVideoSrc,
- getMenuVideoSources,
- dishImageUrl,
- dishPosterFromVideo,
- type PosterVariant,
-} from '@/application/media/asset-resolver';
\ No newline at end of file
diff --git a/application/messaging/ports.ts b/application/messaging/ports.ts
deleted file mode 100644
index c93cf70..0000000
--- a/application/messaging/ports.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-/** Port: external messaging channel (WhatsApp, SMS, etc.). */
-export interface MessagingGateway {
- openWhatsApp(message: string): void;
-}
\ No newline at end of file
diff --git a/application/messaging/whatsapp-message-builder.ts b/application/messaging/whatsapp-message-builder.ts
deleted file mode 100644
index 5e53761..0000000
--- a/application/messaging/whatsapp-message-builder.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import type { BookingDetails } from '@/domain/booking/entities';
-import { isBookingComplete } from '@/domain/booking/validation';
-import type { Language } from '@/domain/language/entities';
-import {
- calculateOrderTotal,
- formatOrderLinesForMessage,
- type OrderLine,
-} from '@/domain/shared/order-line';
-import { PICKUP_LEAD_TIME_MINUTES } from '@/domain/shared/constants';
-
-export interface CartDrawerCopy {
- messageHello: string;
- messageIntro: string;
- messageConfirm: string;
- messageTotal: string;
- messageThanks: string;
-}
-
-export interface BookingLocationCopy {
- askim: string;
- backaplan: string;
-}
-
-export function getSuggestedPickupTime(language: Language, from: Date = new Date()): string {
- const suggested = new Date(from.getTime() + PICKUP_LEAD_TIME_MINUTES * 60 * 1000);
- const timeLocale =
- language === 'sv' ? 'sv-SE' :
- language === 'ar' ? 'ar-SA' :
- language === 'tr' ? 'tr-TR' :
- 'en-GB';
- return suggested.toLocaleTimeString(timeLocale, { hour: '2-digit', minute: '2-digit' });
-}
-
-export function buildCartWhatsAppMessage(
- items: OrderLine[],
- copy: CartDrawerCopy,
- language: Language
-): string | null {
- if (items.length === 0) return null;
-
- const lines = formatOrderLinesForMessage(items);
- const total = calculateOrderTotal(items);
- const suggestedTime = getSuggestedPickupTime(language);
-
- return `${copy.messageHello}
-
-${copy.messageIntro}
-
-${lines}
-${copy.messageConfirm.replace('{time}', suggestedTime)}
-
-${copy.messageTotal}: ${total} kr
-
-${copy.messageThanks}`;
-}
-
-export function buildBookingWhatsAppMessage(
- booking: BookingDetails,
- preOrder: OrderLine[],
- locationCopy: BookingLocationCopy
-): string | null {
- if (!isBookingComplete(booking)) return null;
-
- const locationLabel =
- booking.location === 'askim' ? locationCopy.askim : locationCopy.backaplan;
-
- const itemsText =
- preOrder.length > 0
- ? formatOrderLinesForMessage(preOrder).replace(/ — /g, ' — ')
- : 'None';
-
- const totalText =
- preOrder.length > 0 ? `\nPre-order total: ${calculateOrderTotal(preOrder)} kr\n` : '';
-
- return `Hello Shahi Kitchen 👋
-
-Table Reservation Inquiry:
-
-Name: ${booking.name}
-Phone: ${booking.phone}
-Email: ${booking.email || 'N/A'}
-Location: ${locationLabel}
-Date: ${booking.date}
-Time: ${booking.time}
-Guests: ${booking.guests}
-Special Requests: ${booking.notes || 'None'}
-
-Pre-ordered items:
-${itemsText}${totalText}
-Please confirm table availability and pre-order.
-
-Thank you!`;
-}
\ No newline at end of file
diff --git a/application/table-order/table-order-use-cases.ts b/application/table-order/table-order-use-cases.ts
deleted file mode 100644
index 06e14ab..0000000
--- a/application/table-order/table-order-use-cases.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import type { Branch } from '@/domain/table/table-id';
-import type { OrderLine } from '@/domain/shared/order-line';
-
-export interface TableOrderPayload {
- branch: Branch;
- tableNumber: string;
- tableIdentifier: string;
- items: OrderLine[];
- notes?: string;
- createdAt: string;
-}
-
-export function buildTableOrderPayload(
- branch: Branch,
- tableNumber: string,
- tableIdentifier: string,
- items: OrderLine[],
- notes?: string
-): TableOrderPayload {
- return {
- branch,
- tableNumber,
- tableIdentifier,
- items,
- notes: notes?.trim() || undefined,
- createdAt: new Date().toISOString(),
- };
-}
\ No newline at end of file
diff --git a/components/ButterChicken3D.tsx b/components/ButterChicken3D.tsx
deleted file mode 100644
index d1570a4..0000000
--- a/components/ButterChicken3D.tsx
+++ /dev/null
@@ -1,320 +0,0 @@
-'use client';
-
-import { Canvas, useFrame } from '@react-three/fiber';
-import { OrbitControls, Environment } from '@react-three/drei';
-import { Suspense, useMemo, useRef } from 'react';
-import * as THREE from 'three';
-
-// ================== SMOKE PARTICLES ==================
-function SmokeParticles({ count = 120 }: { count?: number }) {
- const pointsRef = useRef(null!);
-
- const particles = useMemo(() => {
- const positions = new Float32Array(count * 3);
- const velocities = new Float32Array(count * 3);
- const ages = new Float32Array(count);
- const sizes = new Float32Array(count);
-
- for (let i = 0; i < count; i++) {
- const i3 = i * 3;
-
- // Start around the top of the gravy
- positions[i3 + 0] = (Math.random() - 0.5) * 2.2;
- positions[i3 + 1] = 0.6 + Math.random() * 0.3;
- positions[i3 + 2] = (Math.random() - 0.5) * 2.0;
-
- velocities[i3 + 0] = (Math.random() - 0.5) * 0.008;
- velocities[i3 + 1] = 0.012 + Math.random() * 0.018;
- velocities[i3 + 2] = (Math.random() - 0.5) * 0.008;
-
- ages[i] = Math.random() * 3.5;
- sizes[i] = 0.12 + Math.random() * 0.18;
- }
-
- return { positions, velocities, ages, sizes };
- }, [count]);
-
- useFrame((state, delta) => {
- const points = pointsRef.current;
- if (!points) return;
-
- const pos = points.geometry.attributes.position as THREE.BufferAttribute;
- const posArray = pos.array as Float32Array;
-
- for (let i = 0; i < count; i++) {
- const i3 = i * 3;
-
- // Age and reset
- particles.ages[i] += delta * 0.9;
-
- if (particles.ages[i] > 3.8) {
- // Respawn at the top of the gravy
- particles.ages[i] = 0;
- posArray[i3 + 0] = (Math.random() - 0.5) * 2.1;
- posArray[i3 + 1] = 0.55 + Math.random() * 0.15;
- posArray[i3 + 2] = (Math.random() - 0.5) * 1.9;
- particles.velocities[i3 + 0] = (Math.random() - 0.5) * 0.009;
- particles.velocities[i3 + 1] = 0.014 + Math.random() * 0.02;
- } else {
- // Rise with some turbulence
- posArray[i3 + 0] += particles.velocities[i3 + 0] + Math.sin(state.clock.elapsedTime * 1.5 + i) * 0.002;
- posArray[i3 + 1] += particles.velocities[i3 + 1];
- posArray[i3 + 2] += particles.velocities[i3 + 2] + Math.cos(state.clock.elapsedTime * 1.2 + i) * 0.002;
-
- // Slow down as it rises
- particles.velocities[i3 + 1] *= 0.992;
- }
- }
-
- pos.needsUpdate = true;
- });
-
- const geometry = useMemo(() => {
- const geo = new THREE.BufferGeometry();
- geo.setAttribute('position', new THREE.BufferAttribute(particles.positions, 3));
- return geo;
- }, [particles.positions]);
-
- return (
-
-
-
- );
-}
-
-// ================== BOWL ==================
-function Bowl() {
- return (
-
- {/* Outer bowl */}
-
-
-
-
-
- {/* Inner bowl wall */}
-
-
-
-
-
- {/* Bowl bottom inside */}
-
-
-
-
-
- );
-}
-
-// ================== GRAVY ==================
-function Gravy() {
- return (
-
- {/* Main thick gravy */}
-
-
-
-
-
- {/* Creamy top layer */}
-
-
-
-
-
- {/* Glossy highlights layer */}
-
-
-
-
-
- );
-}
-
-// ================== CHICKEN PIECES ==================
-function ChickenPieces() {
- const pieces = [
- { pos: [0.6, 0.45, 0.1], rot: [0.6, 1.2, 0.3], scale: 1.0 },
- { pos: [-0.75, 0.38, 0.55], rot: [-0.4, -0.9, 0.5], scale: 0.95 },
- { pos: [0.15, 0.52, -0.85], rot: [0.9, 0.4, -0.6], scale: 1.05 },
- { pos: [-0.55, 0.42, -0.4], rot: [-0.7, 1.6, 0.2], scale: 0.9 },
- { pos: [0.9, 0.35, -0.55], rot: [0.3, -1.1, -0.4], scale: 0.98 },
- { pos: [-0.2, 0.48, 0.75], rot: [-0.5, 0.7, 0.8], scale: 0.92 },
- ];
-
- return (
- <>
- {pieces.map((p, i) => (
-
- {/* Main chicken body */}
-
-
-
-
-
- {/* Extra volume */}
-
-
-
-
-
- ))}
- >
- );
-}
-
-// ================== HERBS & SPICES ==================
-function Toppings() {
- return (
- <>
- {/* Green herbs */}
- {Array.from({ length: 18 }).map((_, i) => {
- const angle = i * 0.7 + (i % 3) * 0.3;
- const radius = 0.55 + (i % 4) * 0.22;
- return (
-
-
-
-
- );
- })}
-
- {/* Small spice bits */}
- {Array.from({ length: 26 }).map((_, i) => (
-
-
-
-
- ))}
- >
- );
-}
-
-// ================== MAIN MODEL ==================
-function ButterChickenModel() {
- return (
-
-
-
-
-
-
- {/* Rising Smoke */}
-
-
- );
-}
-
-// ================== MAIN EXPORT ==================
-export default function ButterChicken3D() {
- return (
-
-
-
-
- DRAG TO ROTATE • SCROLL TO ZOOM
-
-
- );
-}
diff --git a/components/CartContext.tsx b/components/CartContext.tsx
deleted file mode 100644
index 4dbda4a..0000000
--- a/components/CartContext.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * @deprecated Import from `@/presentation/providers/cart-provider`.
- * Kept for backward compatibility during Clean Architecture migration.
- */
-export {
- CartProvider,
- useCart,
- type CartItem,
-} from '@/presentation/providers/cart-provider';
\ No newline at end of file
diff --git a/components/CartDrawer.tsx b/components/CartDrawer.tsx
deleted file mode 100644
index 5ff8d98..0000000
--- a/components/CartDrawer.tsx
+++ /dev/null
@@ -1,230 +0,0 @@
-'use client';
-
-/**
- * =============================================================================
- * CART DRAWER (SLIDE-IN BASKET PANEL)
- * =============================================================================
- *
- * This is the visual "basket" that slides in from the right when the user
- * clicks the cart icon in the navbar or the "View Cart" toast action.
- *
- * KEY DESIGN CHOICES:
- * - Fixed position, full-height, max-w-md (beautiful on both mobile and desktop)
- * - Backdrop click closes it (standard mobile pattern)
- * - z-[990] sits above almost everything (including the sticky category nav) (below mobile menu)
- * - All cart mutations go through the context — this component is "dumb" UI only
- *
- * THE ORDERING FLOW (very important for restaurant context):
- * Instead of a traditional Stripe checkout, we generate a pre-filled WhatsApp
- * message containing every line item + quantities + grand total.
- * This matches the restaurant's current real-world ordering process.
- * The number 46739381089 is the same one used in the homepage reservation form.
- *
- * FUTURE ENHANCEMENTS (documented here so nothing is forgotten):
- * - Add "Special requests" textarea per order
- * - Show estimated preparation time
- * - Allow "Order for later" date/time picker
- * - Split "Pickup" vs "Delivery" with different messaging
- * - After WhatsApp opens, optionally clear the cart (or keep it — current choice)
- */
-
-import Link from 'next/link';
-import { buildCartWhatsAppMessage } from '@/application/messaging/whatsapp-message-builder';
-import {
- calculateLineTotal,
- formatLineQuantityLabel,
-} from '@/domain/shared/order-line';
-import { RESTAURANT_CONTACT } from '@/domain/shared/constants';
-import { container } from '@/infrastructure/di/container';
-import { useCart } from '@/presentation/providers/cart-provider';
-import { useLanguage } from '@/presentation/providers/language-provider';
-import { getTranslation } from '@/presentation/i18n/translations';
-
-export default function CartDrawer() {
- const {
- items,
- isOpen,
- closeCart,
- totalPrice,
- removeFromCart,
- updateQuantity,
- clearCart
- } = useCart();
-
- const { language } = useLanguage();
- const t = getTranslation(language);
-
- /**
- * WHATSAPP DEEP LINK ORDERING
- *
- * Builds a human-readable, copy-paste friendly message that the restaurant staff
- * can immediately understand and action.
- *
- * The format deliberately mirrors how the restaurant currently receives orders
- * over the phone or via Instagram DMs.
- */
- const orderViaWhatsApp = () => {
- const message = buildCartWhatsAppMessage(items, t.cartDrawer, language);
- if (!message) return;
- container.messagingGateway.openWhatsApp(message);
- };
-
- // Guard clause — drawer only renders when explicitly opened via context
- if (!isOpen) return null;
-
- return (
- <>
- {/* SEMI-TRANSPARENT BACKDROP */}
- {/* Clicking anywhere outside the drawer closes it (standard mobile pattern) */}
-
-
- {/* THE ACTUAL DRAWER — slides in from right */}
- {/* z-[990] ensures it sits above sticky nav, category pills, and most other UI (below mobile menu) */}
-
- {/* HEADER — Title + item count + quick clear + close button */}
-
- );
- };
-
- // Reel settings for screen3 vertical marquees - dynamic with zoom like screen2
- // Fixed card height in px so that browser zoom in/out changes how many cards fit vertically in the column (less when zoom in, more when zoom out).
- // The reel viewport uses 100% of available column height (after section header) to fill the screen with no whitespace.
- const REEL_CARD_HEIGHT = 120; // px per order card - tune for ~3-5 at 100% on 43" TV. Zoom affects visible count.
- const REEL_TIME_PER_ITEM = 6; // seconds per order in the animation - slow upward movement
-
- return (
-
-
-
- {/* Mesmerizing top bar - luxurious, welcoming, eye-catching for customers & riders. Taller, pulsing LIVE, centered tagline, elegant depth for 43" kiosk appeal. */}
-
-
- {/* Stats bar - beautiful metrics with motion - three sections */}
-
-
-
-
-
-
{restaurantOrders.length}
-
RESTAURANT ORDERS
-
-
-
-
-
-
{deliveryOrders.length}
-
DELIVERY PARTNERS
-
-
-
-
-
-
{pickupOrders.length}
-
PICKUP ORDERS (WA/PHONE)
-
-
-
-
-
- AVERAGE PREP TIME
- 12-16 MIN
-
-
-
-
-
- {/* Main beautiful content area - THREE COLUMNS with vertical reels filling entire remaining screen height */}
- {/* Reels use h-full after fixed headers; cards fixed px height => zoom in: fewer visible per column, zoom out: more visible. No white space, max top to bottom like screen2 max left to right. */}
-
-
- );
-}
-
-export default function ScreenDisplay({ screen }: ScreenDisplayProps) {
- const { language } = useLanguage();
- const t = getTranslation(language);
-
- const screenLabel = screen === 1 ? t.screen.display1 : t.screen.display2;
- const isScreen1 = screen === 1;
-
- // Filtered data for this screen
- const screenCategories = useMemo(() => {
- const ids = isScreen1 ? SCREEN1_CATEGORY_IDS : SCREEN2_CATEGORY_IDS;
- return menuCategories.filter((c) => ids.includes(c.id));
- }, [isScreen1]);
-
- // Cycle through ALL items for this screen, one by one in the large hero (not just signatures)
- const cyclingItems = useMemo(() => {
- return screenCategories.flatMap((category) => category.items);
- }, [screenCategories]);
-
- // Cycling through all menu items (large top animation)
- const [currentIndex, setCurrentIndex] = useState(0);
- const current = cyclingItems[currentIndex] || cyclingItems[0];
-
- const heroTiltRef = useRef(null);
-
- // Auto cycle through every item (large top hero shows all, one by one)
- const CYCLE_INTERVAL_MS = 8200;
- useEffect(() => {
- const id = setInterval(() => {
- setCurrentIndex((i) => (i + 1) % cyclingItems.length);
- }, CYCLE_INTERVAL_MS);
- return () => clearInterval(id);
- }, [cyclingItems.length]);
-
- // Beautiful 3D tilt on hero (like signature cards on homepage)
- useEffect(() => {
- const el = heroTiltRef.current;
- if (!el) return;
-
- const onMouseMove = (e: MouseEvent) => {
- const rect = el.getBoundingClientRect();
- const x = ((e.clientX - rect.left) / rect.width - 0.5) * 2;
- const y = ((e.clientY - rect.top) / rect.height - 0.5) * 2;
-
- gsap.to(el, {
- rotationY: x * 7,
- rotationX: -y * 5.5,
- transformPerspective: 1400,
- duration: 0.36,
- ease: 'power2.out',
- overwrite: true,
- });
- };
-
- const onMouseLeave = () => {
- gsap.to(el, {
- rotationY: 0,
- rotationX: 0,
- duration: 1.35,
- ease: 'elastic.out(1, 0.48)',
- });
- };
-
- el.addEventListener('mousemove', onMouseMove);
- el.addEventListener('mouseleave', onMouseLeave);
-
- return () => {
- el.removeEventListener('mousemove', onMouseMove);
- el.removeEventListener('mouseleave', onMouseLeave);
- };
- }, []);
-
- // Professional kiosk mode for screen1/screen2:
- // Force clean fullscreen-like window (no side scrollbars) even in F11 or kiosk browser.
- // Applies to html/body so the window itself has no scrollbar.
- // User zooms the browser in/out to change reel density (# visible items) instead of scrolling.
- // Cleanup restores previous state (good if ever navigating away in dev).
- useEffect(() => {
- const htmlEl = document.documentElement;
- const bodyEl = document.body;
-
- const prevHtmlClass = htmlEl.className;
- const prevBodyClass = bodyEl.className;
- const prevHtmlOverflow = htmlEl.style.overflow;
- const prevBodyOverflow = bodyEl.style.overflow;
-
- htmlEl.classList.add('screen-kiosk');
- bodyEl.classList.add('screen-kiosk');
- htmlEl.style.overflow = 'hidden';
- bodyEl.style.overflow = 'hidden';
-
- return () => {
- // restore
- htmlEl.style.overflow = prevHtmlOverflow;
- bodyEl.style.overflow = prevBodyOverflow;
- // remove only if we added (simple: toggle off)
- htmlEl.classList.remove('screen-kiosk');
- bodyEl.classList.remove('screen-kiosk');
- };
- }, []);
-
- const translatedDesc = current ? ((t as any).menuDescriptions?.[current.id] || current.description) : '';
-
- // =====================================================
- // CONTINUOUS MENU REEL (one line, loop like a film reel) - items move LEFT
- // Enter from RIGHT, exit LEFT. Number of visible items is dynamic (more when zoom out, fewer when zoom in).
- // The reel viewport is always full width (edge to edge, no max-w), no side whitespace.
- // Posters only (no videos) for seamless movement. Numbers for easy ordering (screen1:1-26, screen2:27+).
- // CSS marquee for stable seamless poster reel.
- // Card sizes fixed px for consistent distance viewing; # visible auto-adjusts to current container width on zoom.
- // Sized large for 43" TV distance viewing in restaurant.
- // =====================================================
- const allMenuItemsForReel = screenCategories.flatMap((c) => c.items);
- const numItems = allMenuItemsForReel.length;
- const startNumber = isScreen1 ? 1 : 27;
- // Duplicate for seamless infinite loop (scroll 50% to repeat perfectly)
- const reelItems = [...allMenuItemsForReel, ...allMenuItemsForReel];
-
- // Card width tuned for 43" screen (~1920px), 3 visible + gaps ~1872px at default zoom.
- // Poster 320px + bottom ~70px (py-5 + one-line name+right price) so cards fill the ~390px reel band vertically.
- const REEL_CARD_WIDTH = 620; // px
- const REEL_CARD_GAP = 16; // px (Tailwind gap-4)
-
- // ReelCard: large poster + number+name on left, price on right (opposite side, same line) so price is always clearly visible as cards move left in the reel. Sized big for 43" TV distance viewing.
- function ReelCard({ item, number }: { item: MenuItem; number: number }) {
- const numStr = String(number).padStart(2, '0');
-
- return (
-
-
-
-
- {/* Prominent number badge for easy ordering by number e.g. "give me number 13" */}
-
- {numStr}
-
-
-
-
- {numStr}. {item.name}
-
-
- {item.price} kr
-
-
-
- );
- }
-
- return (
-
-
-
- {/* Elegant top bar */}
-
-
-
SHAHI KITCHEN
-
- {screenLabel}
-
-
-
-
-
-
-
ASKIM • BACKAPLAN
-
-
{t.screen.prepared.toUpperCase()}
-
-
-
- {/* HERO — Large cycling animation showing ALL items one by one (not just signatures).
- flex-1 so it absorbs extra viewport height on tall displays / when zoomed out.
- On short effective viewports (zoomed in) it shrinks gracefully; text sized for fit. */}
-
-
- {/* Media switches with crossfade + fresh start each cycle. Video when available, else large animated poster (Ken Burns). */}
-
- {current && (
- current.video ? (
-
-
-
- ) : (
- {
- applyNextImageFallback(
- e.currentTarget,
- getMenuPosterCandidates(current),
- e.currentTarget.src
- );
- }}
- />
- )
- )}
-
-
- {/* Rich overlays for text legibility + luxury feel (stay on top of changing media) */}
-
-
-
-
- {/* Animated dish info */}
-
-
- {current && (
-
-
- {t.screen.menuTitle}
-
-
-
- {current.name}
-
-
-
-
- {current.price}
-
-
KR
-
-
-
- {translatedDesc}
-
-
-
- {t.screen.prepared}
-
-
- )}
-
-
-
- {/* Cycle progress + counter (clean for many items) */}
-
-
{currentIndex + 1} / {cyclingItems.length}
-
-
-
-
-
-
- {/* MENU REEL - continuous LEFT-moving reel (items move left: enter from right, exit left), entire menu in one line.
- Dynamic # of items visible based on zoom (more when zoomed out). Always full width edge-to-edge (no side whitespace).
- ~8s per item, seamless loop with posters only. Fixed band height so layout sums <=100vh with flex-1 hero. */}
-
-
-
THE MENU • REEL
-
-
- {/* Full-width viewport for the reel; cards will fill based on container width. Height tuned to match card (poster + bottom text area) so items fill the band vertically with no large empty space under as they rotate left. */}
-
- >
- );
-}
\ No newline at end of file
diff --git a/dish-video-prompts.md b/dish-video-prompts.md
deleted file mode 100644
index cce41f0..0000000
--- a/dish-video-prompts.md
+++ /dev/null
@@ -1,79 +0,0 @@
-# Shahi Kitchen - High Quality Video Prompts (Realistic + Web Optimized)
-
-Use these prompts in Grok's video generation (or similar tools).
-
-**Recommended settings for all videos:**
-- Duration: 5 seconds
-- Resolution: 480p or 540p
-- Style: Photorealistic, professional food photography
-- Motion: Natural, subtle, loop-friendly
-- Target file size after optimization: 500–900 KB
-
----
-
-## Butter Chicken
-
-Photorealistic close-up of authentic Indian Butter Chicken in a traditional dark bowl. Rich, glossy, creamy orange-red tomato gravy with tender chicken pieces. Delicate natural steam gently rising from the hot dish. Warm, soft restaurant lighting with beautiful golden highlights on the sauce. Shot from a 3/4 angle, highly appetizing and luxurious. Shallow depth of field. Smooth 5-second loop, web optimized.
-
-## Samosa Chat
-
-Photorealistic close-up of Indian Samosa Chaat. Crispy broken samosas topped with chickpeas, yogurt, colorful chutneys, sev, onions and pomegranate. Fresh, vibrant street food presentation. Natural daylight or warm restaurant lighting. Shallow depth of field, highly detailed and appetizing. Smooth 5-second loop, web optimized.
-
-## Palak Paneer
-
-Photorealistic close-up of Palak Paneer. Fresh vibrant green spinach gravy with soft white paneer cubes, garnished with cream and ginger. Subtle natural steam rising. Warm elegant restaurant lighting. Professional food photography, shallow depth of field. Smooth 5-second loop, web optimized.
-
-## Malai Kofta
-
-Photorealistic close-up of Malai Kofta in rich creamy cashew gravy. Soft golden vegetable dumplings, garnished with cream and nuts. Gentle steam rising. Luxurious warm lighting. High-end Indian restaurant food photography style. Shallow depth of field. Smooth 5-second loop, web optimized.
-
-## Daal Makhani
-
-Photorealistic close-up of Daal Makhani. Thick, creamy, buttery black lentils with rich tomato gravy. Glossy surface with subtle steam. Warm cozy restaurant lighting. Professional appetizing food photography. Shallow depth of field. Smooth 5-second loop, web optimized.
-
-## Lahore Chana
-
-Photorealistic close-up of Lahore Chana (spiced chickpeas). Tangy onion-tomato gravy with chickpeas, garnished with green chilies, ginger and cilantro. Natural steam rising. Warm vibrant lighting. Traditional Punjabi restaurant style. Shallow depth of field. Smooth 5-second loop, web optimized.
-
-## Lamm Palak
-
-Photorealistic close-up of Lamm Palak. Tender lamb pieces in creamy spinach gravy, garnished with cream and ginger. Subtle steam. Warm rich lighting. Professional Indian restaurant food photography. Shallow depth of field. Smooth 5-second loop, web optimized.
-
-## Bong Nihari
-
-Photorealistic close-up of traditional Bong Nihari (slow-cooked shank). Rich aromatic gravy with tender meat, garnished with fresh ginger, green chilies and cilantro. Natural steam. Warm, moody, authentic Pakistani restaurant lighting. Highly detailed and appetizing. Smooth 5-second loop, web optimized.
-
-## Shami Sandwich
-
-Photorealistic close-up of a Shami Sandwich cut in half. Spiced shami kebab in soft bread with onions, chutney and fresh herbs. Appetizing cross-section view. Warm natural lighting. Professional street food / cafe photography style. Short 5-second loop, web optimized.
-
-## Kebab Roll
-
-Photorealistic close-up of a Kebab Roll cut open. Juicy seekh kebab inside soft naan with onions, chutney and salad. Slight steam and fresh ingredients visible. Warm appetizing lighting. Professional fast-casual food photography. Smooth 5-second loop, web optimized.
-
-## Falafel Roll
-
-Photorealistic close-up of a Falafel Roll cut in half. Crispy falafel with fresh vegetables, tahini and chutney inside soft flatbread. Vibrant and fresh presentation. Warm natural lighting. Professional street food photography style. Short 5-second loop, web optimized.
-
-## Paneer Roll
-
-Photorealistic close-up of a Paneer Roll cut open. Grilled paneer tikka with vegetables and sauces inside soft naan. Appetizing cross-section. Warm restaurant lighting. Professional food photography. Smooth 5-second loop, web optimized.
-
-## Namakpare
-
-Photorealistic close-up of traditional Namakpare (savory fried snacks). Golden-brown crunchy diamond-shaped pieces. Fresh, crispy texture. Warm traditional Indian lighting. Professional sweet shop photography style. Short 5-second loop, web optimized.
-
-## Rasmalai
-
-Photorealistic close-up of Rasmalai. Soft spongy cottage cheese dumplings floating in rich saffron and cardamom sweet milk. Garnished with pistachios and saffron strands. Creamy luxurious texture. Elegant warm lighting. High-end Indian dessert photography. Smooth 5-second loop, web optimized.
-
----
-
-## Notes for Generation
-
-- Always mention "photorealistic, professional food photography, shallow depth of field".
-- For dishes with steam/sizzle/pouring, explicitly mention "natural delicate steam rising" or "subtle motion".
-- Keep prompts focused on the dish itself (minimal background).
-- After generation, optimize heavily using the optimization script or ffmpeg (see `optimize-videos.sh`).
-
-Use these prompts when regenerating videos for better realism.
\ No newline at end of file
diff --git a/docs/CLEAN-ARCHITECTURE.md b/docs/CLEAN-ARCHITECTURE.md
new file mode 100644
index 0000000..05d551e
--- /dev/null
+++ b/docs/CLEAN-ARCHITECTURE.md
@@ -0,0 +1,365 @@
+# Kött Gård — Clean Architecture Guide
+
+This document explains **what we changed**, **why**, and **how to work in the new structure**.
+
+---
+
+## What is Clean Architecture?
+
+Clean Architecture splits code into **layers**. Inner layers hold business rules. Outer layers hold frameworks (React, Next.js, Zustand, localStorage).
+
+**Golden rule:** Dependencies point **inward only**.
+
+```
+Presentation → Application → Domain
+Infrastructure → Application → Domain
+
+Domain imports NOTHING from outside itself.
+```
+
+---
+
+## Before vs After
+
+### Before (mixed responsibilities)
+
+```
+page.tsx → filter products, calculate delivery fee, create orders
+store/cart.ts → persistence + merge logic + totals
+lib/products.ts → data + queries in one file
+```
+
+Problems:
+- Delivery fee `total > 500 ? 0 : 49` was copy-pasted in cart **and** checkout
+- Shop filtering logic lived inside the React page
+- Hard to swap localStorage for a real API later
+
+### After (separated layers)
+
+| Layer | Folder | Job |
+|-------|--------|-----|
+| **Domain** | `src/domain/` | Business rules — cart math, delivery fee, order IDs |
+| **Application** | `src/application/` | Use cases + ports (interfaces) |
+| **Infrastructure** | `src/infrastructure/` | Zustand, product data file, i18n adapter |
+| **Presentation** | `src/app/`, `src/components/`, `src/presentation/hooks/` | UI only — calls use cases |
+
+---
+
+## Layer diagram
+
+```mermaid
+flowchart TB
+ subgraph Presentation
+ P1[app/pages]
+ P2[components]
+ P3[presentation/hooks]
+ end
+
+ subgraph Application
+ A1[use-cases]
+ A2[ports interfaces]
+ A3[container.ts]
+ end
+
+ subgraph Domain
+ D1[entities]
+ D2[domain services]
+ end
+
+ subgraph Infrastructure
+ I1[Zustand stores]
+ I2[InMemoryProductRepository]
+ I3[products.data.ts]
+ end
+
+ P1 --> P3
+ P3 --> A3
+ A3 --> A1
+ A1 --> A2
+ A1 --> D2
+ A2 -.implemented by.- I1
+ A2 -.implemented by.- I2
+ I2 --> I3
+ D2 --> D1
+```
+
+---
+
+## Step-by-step: what we did
+
+### Step 1 — Domain entities (`src/domain/entities/`)
+
+**What:** Moved `Product`, `CartItem`, `Order`, `User`, etc. from `types/` into the domain.
+
+**Why:** Entities are the core vocabulary of the business. They must not depend on React or Next.js.
+
+**Example:** `Product` describes a meat item (price, category, slug) — not how it is rendered.
+
+```
+src/domain/entities/index.ts
+```
+
+`src/types/index.ts` now **re-exports** domain entities so old imports still work.
+
+---
+
+### Step 2 — Domain services (`src/domain/services/`)
+
+**What:** Pure functions / classes for business rules.
+
+| Service | Rule extracted from |
+|---------|---------------------|
+| `CartDomainService` | `store/cart.ts` — add item, merge duplicates, totals |
+| `DeliveryFeeService` | `cart/page.tsx` + `checkout/page.tsx` — 49 kr fee, free over 500 kr |
+| `CustomizationDomainService` | `lib/customization.ts` — cut styles, cart line keys |
+| `OrderDomainService` | `checkout/page.tsx` — order ID format, order object shape |
+| `AuthDomainService` | `store/auth.ts` — demo password check, user creation |
+| `CatalogDomainService` | `shop/page.tsx` — filter by category, search, sort |
+
+**Why:** One place per rule. Change delivery threshold once → cart and checkout both update.
+
+**Example — delivery fee (single source of truth):**
+
+```typescript
+// src/domain/constants/commerce.ts
+export const FREE_DELIVERY_THRESHOLD_SEK = 500;
+export const STANDARD_DELIVERY_FEE_SEK = 49;
+
+// src/domain/services/DeliveryFeeService.ts
+static calculateDeliveryFee(subtotal: number): number {
+ return subtotal > FREE_DELIVERY_THRESHOLD_SEK ? 0 : STANDARD_DELIVERY_FEE_SEK;
+}
+```
+
+---
+
+### Step 3 — Application ports (`src/application/ports/`)
+
+**What:** TypeScript **interfaces** describing what the app needs — not how it is stored.
+
+| Port | Contract |
+|------|----------|
+| `IProductRepository` | `findAll()`, `findBySlug()`, `findFeatured()` |
+| `ICartRepository` | `getItems()`, `addItem()`, `clearCart()` |
+| `IAuthRepository` | `login()`, `register()`, `addOrder()` |
+| `IWishlistRepository` | `toggleItem()`, `isInWishlist()` |
+| `ITranslationService` | `translate(key)` |
+
+**Why:** Today products live in a static array. Tomorrow they might come from Shopify or a database. **Only the infrastructure adapter changes** — use cases stay the same.
+
+---
+
+### Step 4 — Use cases (`src/application/use-cases/`)
+
+**What:** One class per user action. Orchestrates domain + ports.
+
+| Use case | Replaces logic in |
+|----------|-------------------|
+| `FilterProductsUseCase` | Shop page filtering/sorting |
+| `GetProductBySlugUseCase` | `getProductBySlug()` calls |
+| `LocalizeProductUseCase` | `lib/product-i18n.ts` |
+| `AddToCartUseCase` | Cart add button |
+| `GetCartSummaryUseCase` | Cart totals + delivery |
+| `PlaceOrderUseCase` | Checkout submit handler |
+| `LoginUseCase` / `RegisterUseCase` | Login page |
+
+**Example — checkout flow:**
+
+```
+User clicks Pay
+ → PlaceOrderUseCase.execute()
+ → OrderDomainService.createOrder() [domain]
+ → authRepository.addOrder() [port]
+ → cartRepository.clearCart() [port]
+```
+
+File: `src/application/use-cases/checkout/PlaceOrder.ts`
+
+---
+
+### Step 5 — Infrastructure (`src/infrastructure/`)
+
+**What:** Concrete implementations of ports + framework code.
+
+| File | Role |
+|------|------|
+| `data/products.data.ts` | Static 16-product catalog |
+| `repositories/InMemoryProductRepository.ts` | Implements `IProductRepository` |
+| `persistence/zustand/cartStore.ts` | Zustand + `ZustandCartRepository` |
+| `persistence/zustand/authStore.ts` | Auth persistence + demo user |
+| `persistence/zustand/wishlistStore.ts` | Wishlist persistence |
+| `i18n/I18nTranslationService.ts` | Wraps existing `i18n/` dictionaries |
+
+**Why Zustand stays:** It is an **infrastructure detail** (browser storage). The application layer only sees `ICartRepository`.
+
+---
+
+### Step 6 — Composition root (`src/application/container.ts`)
+
+**What:** One file that wires everything together.
+
+```typescript
+export const container = new ApplicationContainer();
+// container.addToCart.execute(...)
+// container.getCartSummary.execute()
+// container.placeOrder.execute(...)
+```
+
+**Why:** Pages and hooks do not `new InMemoryProductRepository()` themselves. That would couple UI to infrastructure. The container is the **only** place that knows concrete classes.
+
+---
+
+### Step 7 — Presentation hooks (`src/presentation/hooks/`)
+
+**What:** React-friendly API on top of the container.
+
+| Hook | Use in |
+|------|--------|
+| `useCart()` | Cart page, Header, product page |
+| `useAuth()` | Login, account, checkout |
+| `useWishlist()` | Product card, wishlist page |
+| `useCheckout()` | Checkout submit |
+| `useCatalogFilter()` | Shop page |
+
+**Example:**
+
+```typescript
+// Old (page knew about Zustand internals + business math)
+const { getTotal } = useCartStore();
+const deliveryFee = total > 500 ? 0 : 49;
+
+// New (page uses use case result)
+const { summary } = useCart();
+const { subtotal, deliveryFee, grandTotal } = summary;
+```
+
+---
+
+### Step 8 — Backward-compatible facades
+
+Old paths still work so nothing breaks silently:
+
+| Old import | Now points to |
+|------------|---------------|
+| `@/types` | `@/domain/entities` |
+| `@/lib/customization` | `CustomizationDomainService` |
+| `@/lib/products` | `container.productRepository` |
+| `@/store/cart` | infrastructure + `useCart` hook |
+
+---
+
+## New folder map
+
+```
+src/
+├── domain/
+│ ├── entities/ # Product, Order, CartItem…
+│ ├── constants/ # FREE_DELIVERY_THRESHOLD_SEK
+│ └── services/ # CartDomainService, DeliveryFeeService…
+│
+├── application/
+│ ├── ports/ # IProductRepository, ICartRepository…
+│ ├── use-cases/ # AddToCart, PlaceOrder, FilterProducts…
+│ ├── dtos/ # LocalizedProduct, CartSummary
+│ └── container.ts # ★ wires everything
+│
+├── infrastructure/
+│ ├── data/ # products.data.ts, demo-orders.data.ts
+│ ├── repositories/ # InMemoryProductRepository
+│ ├── persistence/zustand/ # Stores + repository adapters
+│ └── i18n/ # I18nTranslationService
+│
+├── presentation/
+│ └── hooks/ # useCart, useAuth, useCatalog…
+│
+├── app/ # Thin pages (UI + hooks)
+├── components/ # Visual components
+├── hooks/useTranslation.ts # Still used for t('key')
+├── lib/ # Facades (backward compat)
+├── store/ # Re-exports (backward compat)
+└── types/ # Re-exports (backward compat)
+```
+
+---
+
+## How to add a feature (cheat sheet)
+
+### Change delivery fee rule
+1. Edit `src/domain/constants/commerce.ts`
+2. Done — `GetCartSummaryUseCase` and `PlaceOrderUseCase` pick it up automatically
+
+### Add a new product
+1. Add entry in `src/infrastructure/data/products.data.ts`
+2. Add translations in `src/i18n/locales/*.ts`
+
+### Add a new page action (e.g. "apply coupon")
+1. Add rule in `src/domain/services/` if it is business logic
+2. Add port method if it needs storage
+3. Create `src/application/use-cases/cart/ApplyCoupon.ts`
+4. Register in `container.ts`
+5. Expose via `useCart()` or new hook
+6. Call from page/component
+
+### Replace static products with an API
+1. Create `src/infrastructure/repositories/ApiProductRepository.ts` implementing `IProductRepository`
+2. In `container.ts`, swap `InMemoryProductRepository` → `ApiProductRepository`
+3. **No changes** to shop page, use cases, or domain
+
+---
+
+## Dependency rules (memorize this)
+
+| Layer | Can import |
+|-------|------------|
+| Domain | Only domain |
+| Application | Domain + its own ports/DTOs |
+| Infrastructure | Application ports + Domain |
+| Presentation | Application container + hooks + React |
+
+| Layer | Cannot import |
+|-------|---------------|
+| Domain | React, Next, Zustand, `app/`, `components/` |
+| Application | Zustand, `page.tsx`, JSX |
+| Use cases | Concrete repositories (only interfaces) |
+
+---
+
+## Request flow example: Add to cart
+
+```mermaid
+sequenceDiagram
+ participant Page as product/page.tsx
+ participant Hook as useCart()
+ participant UC as AddToCartUseCase
+ participant Repo as ZustandCartRepository
+ participant Domain as CartDomainService
+ participant Store as Zustand persist
+
+ Page->>Hook: addItem(product, customization, label)
+ Hook->>UC: execute(...)
+ UC->>Repo: addItem(...)
+ Repo->>Domain: addItem(items, product, ...)
+ Domain-->>Repo: newItems[]
+ Repo->>Store: setItems(newItems)
+ Store-->>Page: React re-render
+```
+
+---
+
+## Verify the project
+
+```bash
+cd /Users/apple/Desktop/code/Kottgard
+npm run build # must pass
+npm run dev # test at http://localhost:3000
+```
+
+Demo login: `demo@kottgard.se` / `demo123`
+
+---
+
+## Further reading
+
+- Uncle Bob — Clean Architecture (concentric circles diagram)
+- This project's annotated code: `docs/annotated/src/`
+- Beginner folder map: `~/Desktop/Kottgard-Project-Learn/`
\ No newline at end of file
diff --git a/docs/Kottgard-Website-Guide.docx b/docs/Kottgard-Website-Guide.docx
new file mode 100644
index 0000000..52037ae
Binary files /dev/null and b/docs/Kottgard-Website-Guide.docx differ
diff --git a/docs/annotate-all.mjs b/docs/annotate-all.mjs
new file mode 100644
index 0000000..c1e6eea
--- /dev/null
+++ b/docs/annotate-all.mjs
@@ -0,0 +1,195 @@
+/**
+ * Generates line-by-line annotated copies of every src/ file.
+ * Output: docs/annotated/src/** (mirrors src/ structure)
+ * Run: node docs/annotate-all.mjs
+ */
+import fs from 'fs';
+import path from 'path';
+import { fileURLToPath } from 'url';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const ROOT = path.join(__dirname, '..');
+const SRC = path.join(ROOT, 'src');
+const OUT = path.join(__dirname, 'annotated', 'src');
+
+function explainLine(line, lineNum, relPath) {
+ const t = line.trim();
+ const indent = line.match(/^(\s*)/)[1];
+
+ if (t === '') return `${indent}// (blank line — separates logical blocks for readability)`;
+ if (t.startsWith('/**') || t.startsWith('*') || t.startsWith('*/'))
+ return `${indent}// Block comment — documents the file or function below`;
+ if (t.startsWith('//')) return line;
+
+ if (t === "'use client';" || t === '"use client";')
+ return `${indent}// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)`;
+ if (t.startsWith('import type '))
+ return `${indent}// Type-only import — erased at compile time; no JavaScript bundle cost`;
+ if (t.startsWith('import ')) {
+ if (t.includes("from 'react'") || t.includes('from "react"'))
+ return `${indent}// Import React — core UI library (components, hooks, JSX)`;
+ if (t.includes('next/link'))
+ return `${indent}// Next.js Link — fast client-side navigation without full page reload`;
+ if (t.includes('next/image'))
+ return `${indent}// Next.js Image — optimized images (lazy load, WebP/AVIF)`;
+ if (t.includes('next/navigation'))
+ return `${indent}// Next.js App Router hooks — useRouter, useParams, useSearchParams`;
+ if (t.includes('next/font'))
+ return `${indent}// Self-hosted Google fonts — better performance than external CSS`;
+ if (t.includes('lucide-react'))
+ return `${indent}// Lucide icons — lightweight SVG icon components`;
+ if (t.includes('zustand'))
+ return `${indent}// Zustand — simple global state store (cart, auth, locale)`;
+ if (t.includes('@/'))
+ return `${indent}// Import project module (@/ alias = src/ folder in tsconfig)`;
+ if (t.includes("'./") || t.includes('"./'))
+ return `${indent}// Import from a relative file in the same project`;
+ return `${indent}// Import external package or local module`;
+ }
+
+ if (t.startsWith('export type ') || t.startsWith('export interface '))
+ return `${indent}// Export TypeScript type — defines data shape used across the app`;
+ if (t.startsWith('interface '))
+ return `${indent}// TypeScript interface — contract for object properties and methods`;
+ if (t.startsWith('type '))
+ return `${indent}// TypeScript type alias — union or shorthand for complex types`;
+ if (t.startsWith('export default function'))
+ return `${indent}// Default export — main component/page Next.js or other files import`;
+ if (t.startsWith('export function'))
+ return `${indent}// Named export — utility function other files can import`;
+ if (t.startsWith('export const '))
+ return `${indent}// Named export constant — shared config/data imported elsewhere`;
+ if (t.startsWith('const ') && t.includes('= create<'))
+ return `${indent}// Create Zustand store — global state hook (useXxxStore)`;
+ if (t.startsWith('const ') && t.includes('useState'))
+ return `${indent}// React useState — local component state that triggers re-render on change`;
+ if (t.startsWith('const ') && t.includes('useMemo'))
+ return `${indent}// React useMemo — cache expensive computed value until dependencies change`;
+ if (t.startsWith('const ') && t.includes('useCallback'))
+ return `${indent}// React useCallback — stable function reference for useEffect/useMemo deps`;
+ if (t.startsWith('const ') && t.includes('useEffect'))
+ return `${indent}// React useEffect — run side effect after render (sync URL, redirect, etc.)`;
+ if (t.startsWith('const ') && t.includes('useRouter'))
+ return `${indent}// Next.js router — programmatic navigation (router.push)`;
+ if (t.startsWith('const ') && t.includes('useSearchParams'))
+ return `${indent}// Read URL query string (?category=beef&q=steak)`;
+ if (t.startsWith('const ') && t.includes('useParams'))
+ return `${indent}// Read dynamic route segment ([slug] from URL)`;
+ if (t.startsWith('const ') && t.includes('useTranslation'))
+ return `${indent}// Custom hook — returns t() translator and current locale`;
+ if (t.startsWith('const ') && t.includes('useCartStore') || t.startsWith('const ') && t.includes('useAuthStore') || t.startsWith('const ') && t.includes('useWishlistStore') || t.startsWith('const ') && t.includes('useLocaleStore'))
+ return `${indent}// Zustand selector — subscribe to slice of global store`;
+ if (t.startsWith('function '))
+ return `${indent}// Function declaration — reusable logic in this file`;
+ if (t.startsWith('return ('))
+ return `${indent}// Return JSX — describes UI tree React renders to the DOM`;
+ if (t.startsWith('return '))
+ return `${indent}// Return value from function`;
+ if (t.startsWith('if (') || t.startsWith('} else if ('))
+ return `${indent}// Conditional branch — different behavior based on runtime value`;
+ if (t.startsWith('switch ('))
+ return `${indent}// Switch — multiple branches on one variable (e.g. sort order)`;
+ if (t.startsWith('case '))
+ return `${indent}// Switch case — handle one specific value`;
+ if (t.startsWith('default:'))
+ return `${indent}// Switch default — fallback when no case matches`;
+ if (t.startsWith('useEffect('))
+ return `${indent}// Side effect hook — runs after paint; deps array controls when it re-runs`;
+ if (t.includes('.map('))
+ return `${indent}// Array.map — transform each item (often render a list of components)`;
+ if (t.includes('.filter('))
+ return `${indent}// Array.filter — keep items matching condition (search, category)`;
+ if (t.includes('.sort('))
+ return `${indent}// Array.sort — reorder items (price, name, featured)`;
+ if (t.includes('.find('))
+ return `${indent}// Array.find — get first matching item or undefined`;
+ if (t.includes('.reduce('))
+ return `${indent}// Array.reduce — accumulate single value (cart total, item count)`;
+ if (t.startsWith('<') && !t.startsWith('<>'))
+ return `${indent}// JSX element — HTML-like tag becomes React component in browser`;
+ if (t.startsWith('<>') || t === '>')
+ return `${indent}// React Fragment — group elements without extra wrapper DOM node`;
+ if (t.startsWith('{/*'))
+ return `${indent}// JSX comment — not visible in browser`;
+ if (t.startsWith('className='))
+ return `${indent}// Tailwind CSS utility classes — styling (colors, spacing, layout)`;
+ if (t.startsWith('href='))
+ return `${indent}// Link target URL — internal route or external https://`;
+ if (t.startsWith('onClick='))
+ return `${indent}// Click handler — runs when user clicks (must be client component)`;
+ if (t.startsWith('onChange='))
+ return `${indent}// Change handler — runs when input/select value changes`;
+ if (t.startsWith('aria-'))
+ return `${indent}// Accessibility attribute — screen readers and assistive tech`;
+ if (t.startsWith('}'))
+ return `${indent}// Closing brace — end of block (function, if, object, JSX)`;
+ if (t.startsWith(']') || t.startsWith('];'))
+ return `${indent}// End of array literal`;
+ if (t.endsWith(',') && !t.includes('//'))
+ return `${indent}// Property or array item — trailing comma allowed in TypeScript`;
+ if (relPath.includes('locales/') && t.match(/^\s{2}\w+:/))
+ return `${indent}// i18n translation section — keys used by t('section.key') in components`;
+ if (relPath.includes('locales/') && t.includes("name:") || relPath.includes('locales/') && t.includes("title:"))
+ return `${indent}// Translated UI string for current language (sv / en / ur)`;
+ if (relPath.includes('products.ts'))
+ return `${indent}// Product catalog entry — demo data shown in shop and product pages`;
+ if (t.includes('persist('))
+ return `${indent}// Zustand persist — save store to localStorage between visits`;
+
+ return `${indent}// Line ${lineNum}: ${t.length > 60 ? t.slice(0, 57) + '...' : t || 'code'}`;
+}
+
+function annotateFile(content, relPath) {
+ const lines = content.split('\n');
+ const ext = relPath.endsWith('.tsx') ? 'tsx' : 'ts';
+ const header = [
+ `/**`,
+ ` * ANNOTATED COPY — every line explained`,
+ ` * Source: src/${relPath}`,
+ ` * NOT used by the app — read this to learn how the real file works`,
+ ` */`,
+ '',
+ ];
+
+ const body = lines.map((line, i) => {
+ const comment = explainLine(line, i + 1, relPath);
+ if (line.trim().startsWith('//') && comment === line) return line;
+ if (line.trim() === '' && comment.includes('blank')) return comment;
+ return `${comment}\n${line}`;
+ });
+
+ return header.join('\n') + body.join('\n') + '\n';
+}
+
+function walk(dir, base = '') {
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
+ let count = 0;
+ for (const e of entries) {
+ const rel = base ? `${base}/${e.name}` : e.name;
+ const full = path.join(dir, e.name);
+ if (e.isDirectory()) {
+ count += walk(full, rel);
+ } else if (/\.(ts|tsx)$/.test(e.name)) {
+ const content = fs.readFileSync(full, 'utf8');
+ const annotated = annotateFile(content, rel);
+ const outName = e.name.replace(/\.(tsx?)$/, '.annotated.$1');
+ const outDir = path.join(OUT, base);
+ fs.mkdirSync(outDir, { recursive: true });
+ fs.writeFileSync(path.join(outDir, outName), annotated);
+ count++;
+ }
+ }
+ return count;
+}
+
+// Remove old flat annotated files (replaced by src/ mirror)
+const oldFlat = path.join(__dirname, 'annotated');
+for (const f of fs.readdirSync(oldFlat)) {
+ if (f.endsWith('.annotated.ts') || f.endsWith('.annotated.tsx')) {
+ if (!f.startsWith('0')) continue;
+ try { fs.unlinkSync(path.join(oldFlat, f)); } catch (_) {}
+ }
+}
+
+const n = walk(SRC);
+console.log(`Annotated ${n} files → docs/annotated/src/`);
\ No newline at end of file
diff --git a/docs/annotated/README.md b/docs/annotated/README.md
new file mode 100644
index 0000000..3e892f2
--- /dev/null
+++ b/docs/annotated/README.md
@@ -0,0 +1,63 @@
+# Annotated Source Code — Every Line Explained
+
+This folder contains **annotated copies** of **every** file in `src/`. Each line of the original code is followed or preceded by a comment explaining:
+
+- **What** the syntax means (TypeScript, React, Next.js)
+- **Why** it exists in the Kött Gård project
+
+Production code in `src/` stays clean. Learning comments live here only.
+
+## Regenerate all annotations
+
+```bash
+node docs/annotate-all.mjs
+```
+
+Run this after you change source files to refresh the annotated copies.
+
+## Folder mirror
+
+```
+docs/annotated/src/ ← you are here (annotated)
+src/ ← real app code (no line comments)
+```
+
+| Annotated path | Original path |
+|----------------|---------------|
+| `docs/annotated/src/app/page.annotated.tsx` | `src/app/page.tsx` |
+| `docs/annotated/src/lib/products.annotated.ts` | `src/lib/products.ts` |
+| `docs/annotated/src/store/cart.annotated.ts` | `src/store/cart.ts` |
+| … | (52 files total) |
+
+## File categories
+
+| Folder | What it contains |
+|--------|------------------|
+| `app/` | Pages and routes (Next.js App Router) |
+| `components/` | Reusable UI (home sections, layout, product cards) |
+| `lib/` | Data, images, constants, helpers |
+| `store/` | Zustand global state (cart, auth, wishlist, locale) |
+| `i18n/` | Translations (Swedish, English, Urdu) |
+| `hooks/` | Custom React hooks |
+| `types/` | TypeScript interfaces |
+
+## How to read
+
+1. Open the **original** file in `src/` in your editor.
+2. Open the matching **`.annotated.ts`** or **`.annotated.tsx`** file side-by-side.
+3. Read the gray `//` comment above each line, then the code.
+
+## Programming languages in this project
+
+| Language | Role |
+|----------|------|
+| **TypeScript** | Types catch errors before run; interfaces for Product, Cart, Order |
+| **React 18** | Components + JSX UI; hooks for state and effects |
+| **Next.js 13** | File-based routing, layouts, metadata, image optimization |
+| **Tailwind CSS** | Utility classes for burgundy/cream/gold design |
+| **Zustand** | Global stores with `persist` → localStorage |
+
+## Related documents
+
+- Word guide: `docs/Kottgard-Website-Guide.docx`
+- Visual guide: `../kottgard documentation/16-website-visual-and-code-guide.md`
\ No newline at end of file
diff --git a/docs/annotated/src/app/about/page.annotated.tsx b/docs/annotated/src/app/about/page.annotated.tsx
new file mode 100644
index 0000000..011e6e1
--- /dev/null
+++ b/docs/annotated/src/app/about/page.annotated.tsx
@@ -0,0 +1,249 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/about/page.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Lucide icons — lightweight SVG icon components
+import { ShieldCheck, Leaf, Award, Truck, Phone, Mail, MapPin } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import external package or local module
+import {
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_ADDRESS,
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_EMAIL,
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_PHONE_DISPLAY,
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_HOURS,
+// Closing brace — end of block (function, if, object, JSX)
+} from '@/lib/constants';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function AboutPage() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+ // Line 15: const telHref = `tel:${SITE_PHONE_DISPLAY.replace(/\s/g, ...
+ const telHref = `tel:${SITE_PHONE_DISPLAY.replace(/\s/g, '')}`;
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 22: {t('about.title', { name: t('site.name') })}
+ {t('about.title', { name: t('site.name') })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.subtitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.ourStory')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 32: {t('about.storyP1', { name: t('site.name') })}
+ {t('about.storyP1', { name: t('site.name') })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.storyP2')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.halalTitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 43: {t('about.halalDesc', { name: t('site.name') })}
+ {t('about.halalDesc', { name: t('site.name') })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 49: {[
+ {[
+ // Property or array item — trailing comma allowed in TypeScript
+ { icon: Leaf, title: t('about.freshDaily'), desc: t('about.freshDailyDesc') },
+ // Line 51: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: Award,
+ // Property or array item — trailing comma allowed in TypeScript
+ title: t('about.premiumQuality'),
+ // Property or array item — trailing comma allowed in TypeScript
+ desc: t('about.premiumQualityDesc'),
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 56: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: Truck,
+ // Property or array item — trailing comma allowed in TypeScript
+ title: t('about.fastDelivery'),
+ // Property or array item — trailing comma allowed in TypeScript
+ desc: t('about.fastDeliveryDesc'),
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Array.map — transform each item (often render a list of components)
+ ].map((item) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{item.title}
+ // JSX element — HTML-like tag becomes React component in browser
+
{item.desc}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 67: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.deliveryTitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.delivery1')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.delivery2')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.delivery3')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.delivery4')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.contactTitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 99: {SITE_ADDRESS}
+ {SITE_ADDRESS}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 101: {t('footer.hours', { hours: SITE_HOURS })}
+ {t('footer.hours', { hours: SITE_HOURS })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // Line 110: {t('cta.button')} →
+ {t('cta.button')} →
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.privacyTitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.privacyText')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.termsTitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('about.termsText')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 126: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/account/page.annotated.tsx b/docs/annotated/src/app/account/page.annotated.tsx
new file mode 100644
index 0000000..1d2073c
--- /dev/null
+++ b/docs/annotated/src/app/account/page.annotated.tsx
@@ -0,0 +1,321 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/account/page.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import React — core UI library (components, hooks, JSX)
+import { useEffect } from 'react';
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Next.js App Router hooks — useRouter, useParams, useSearchParams
+import { useRouter } from 'next/navigation';
+// Lucide icons — lightweight SVG icon components
+import { User, Package, MapPin, Phone, Mail, LogOut, Heart } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useAuthStore } from '@/store/auth';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { formatPrice, formatDate, getFormatLocale } from '@/lib/utils';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { localizeProduct } from '@/lib/product-i18n';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function AccountPage() {
+ // Next.js router — programmatic navigation (router.push)
+ const router = useRouter();
+ // Zustand selector — subscribe to slice of global store
+ const { user, isAuthenticated, orders, logout } = useAuthStore();
+ // Custom hook — returns t() translator and current locale
+ const { t, locale } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Side effect hook — runs after paint; deps array controls when it re-runs
+ useEffect(() => {
+ // Conditional branch — different behavior based on runtime value
+ if (!isAuthenticated) {
+ // Line 20: router.push('/login');
+ router.push('/login');
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Closing brace — end of block (function, if, object, JSX)
+ }, [isAuthenticated, router]);
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (!isAuthenticated || !user) {
+ // Return value from function
+ return null;
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Line 28: const handleLogout = () => {
+ const handleLogout = () => {
+ // Line 29: logout();
+ logout();
+ // Line 30: router.push('/');
+ router.push('/');
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // Line 33: const fmt = (n: number) => formatPrice(n, getFormatLocale...
+ const fmt = (n: number) => formatPrice(n, getFormatLocale(locale));
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('account.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('account.welcome', { name: user.name })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{user.name}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 55: {t('account.memberSince', { date: formatDate(user.created...
+ {t('account.memberSince', { date: formatDate(user.createdAt) })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 63: {user.email}
+ {user.email}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 67: {user.phone}
+ {user.phone}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 71: {user.address.street}, {user.address.city}, {user.address...
+ {user.address.street}, {user.address.city}, {user.address.state}{' '}
+ // Line 72: {user.address.zip}
+ {user.address.zip}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 83: {t('account.myWishlist')}
+ {t('account.myWishlist')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 100: {t('account.orderHistory')}
+ {t('account.orderHistory')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // Line 104: {orders.length === 0 ? (
+ {orders.length === 0 ? (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('account.noOrders')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 111: ) : (
+ ) : (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {orders.map((order) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{order.id}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 122: {formatDate(order.createdAt)}
+ {formatDate(order.createdAt)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{fmt(order.total)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 128: {t(`orderStatus.${order.status}`)}
+ {t(`orderStatus.${order.status}`)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {order.items.map((item) => {
+ // Line 134: const localized = localizeProduct(item.product, t);
+ const localized = localizeProduct(item.product, t);
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // Line 144: {localized.name} × {item.quantity}
+ {localized.name} × {item.quantity}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 146: ({item.customizationLabel})
+ ({item.customizationLabel})
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {fmt(item.product.price * item.quantity)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 151: );
+ );
+ // Closing brace — end of block (function, if, object, JSX)
+ })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 155: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 157: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 163: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/cart/page.annotated.tsx b/docs/annotated/src/app/cart/page.annotated.tsx
new file mode 100644
index 0000000..710a3cb
--- /dev/null
+++ b/docs/annotated/src/app/cart/page.annotated.tsx
@@ -0,0 +1,348 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/cart/page.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import project module (@/ alias = src/ folder in tsconfig)
+import AppImage from '@/components/ui/AppImage';
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Lucide icons — lightweight SVG icon components
+import { Minus, Plus, Trash2, ShoppingBag, ArrowRight } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useCartStore } from '@/store/cart';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { formatPrice, getFormatLocale } from '@/lib/utils';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { localizeProduct } from '@/lib/product-i18n';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function CartPage() {
+ // Zustand selector — subscribe to slice of global store
+ const { items, updateQuantity, removeItem, getTotal } = useCartStore();
+ // Custom hook — returns t() translator and current locale
+ const { t, locale } = useTranslation();
+ // Line 15: const total = getTotal();
+ const total = getTotal();
+ // Line 16: const deliveryFee = total > 500 ? 0 : 49;
+ const deliveryFee = total > 500 ? 0 : 49;
+ // Line 17: const grandTotal = total + deliveryFee;
+ const grandTotal = total + deliveryFee;
+ // Line 18: const fmt = (n: number) => formatPrice(n, getFormatLocale...
+ const fmt = (n: number) => formatPrice(n, getFormatLocale(locale));
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (items.length === 0) {
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 27: {t('cart.empty')}
+ {t('cart.empty')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('cart.emptyHint')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 36: );
+ );
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('cart.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 45: {t('cart.itemsCount', { count: items.length })}
+ {t('cart.itemsCount', { count: items.length })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {items.map((item) => {
+ // Line 54: const localized = localizeProduct(item.product, t);
+ const localized = localizeProduct(item.product, t);
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ />
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // Line 74: {localized.name}
+ {localized.name}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 77: {t(`categories.${item.product.category}.name`)}
+ {t(`categories.${item.product.category}.name`)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 91: {t('cart.customization')}
+ {t('cart.customization')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 94: {item.customizationLabel}
+ {item.customizationLabel}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 108: {item.quantity}
+ {item.quantity}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 119: {fmt(item.product.price * item.quantity)}
+ {fmt(item.product.price * item.quantity)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 124: );
+ );
+ // Closing brace — end of block (function, if, object, JSX)
+ })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 131: {t('cart.orderSummary')}
+ {t('cart.orderSummary')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {t('cart.subtotal')}
+ // JSX element — HTML-like tag becomes React component in browser
+ {fmt(total)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {t('cart.delivery')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 142: {deliveryFee === 0 ? (
+ {deliveryFee === 0 ? (
+ // JSX element — HTML-like tag becomes React component in browser
+ {t('cart.free')}
+ // Line 144: ) : (
+ ) : (
+ // Line 145: fmt(deliveryFee)
+ fmt(deliveryFee)
+ // Line 146: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 149: {deliveryFee > 0 && (
+ {deliveryFee > 0 && (
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('cart.freeDeliveryHint')}
+ // Line 151: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {t('cart.total')}
+ // JSX element — HTML-like tag becomes React component in browser
+ {fmt(grandTotal)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // Line 170: {t('cart.continueShopping')}
+ {t('cart.continueShopping')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 177: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/checkout/page.annotated.tsx b/docs/annotated/src/app/checkout/page.annotated.tsx
new file mode 100644
index 0000000..cbfc348
--- /dev/null
+++ b/docs/annotated/src/app/checkout/page.annotated.tsx
@@ -0,0 +1,701 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/checkout/page.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import React — core UI library (components, hooks, JSX)
+import { useState } from 'react';
+// Next.js App Router hooks — useRouter, useParams, useSearchParams
+import { useRouter } from 'next/navigation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import AppImage from '@/components/ui/AppImage';
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Lucide icons — lightweight SVG icon components
+import { Lock, CreditCard, Truck, CheckCircle, ChevronLeft } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useCartStore } from '@/store/cart';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useAuthStore } from '@/store/auth';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { formatPrice, getFormatLocale } from '@/lib/utils';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { localizeProduct } from '@/lib/product-i18n';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { Order } from '@/types';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function CheckoutPage() {
+ // Next.js router — programmatic navigation (router.push)
+ const router = useRouter();
+ // Zustand selector — subscribe to slice of global store
+ const { items, getTotal, clearCart } = useCartStore();
+ // Zustand selector — subscribe to slice of global store
+ const { user, isAuthenticated, addOrder } = useAuthStore();
+ // Custom hook — returns t() translator and current locale
+ const { t, locale } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // React useState — local component state that triggers re-render on change
+ const [paymentMethod, setPaymentMethod] = useState('card');
+ // React useState — local component state that triggers re-render on change
+ const [isProcessing, setIsProcessing] = useState(false);
+ // React useState — local component state that triggers re-render on change
+ const [orderComplete, setOrderComplete] = useState(false);
+ // React useState — local component state that triggers re-render on change
+ const [orderId, setOrderId] = useState('');
+// (blank line — separates logical blocks for readability)
+ // React useState — local component state that triggers re-render on change
+ const [form, setForm] = useState({
+ // Property or array item — trailing comma allowed in TypeScript
+ name: user?.name || '',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: user?.email || '',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: user?.phone || '',
+ // Property or array item — trailing comma allowed in TypeScript
+ street: user?.address.street || '',
+ // Property or array item — trailing comma allowed in TypeScript
+ city: user?.address.city || '',
+ // Property or array item — trailing comma allowed in TypeScript
+ state: user?.address.state || '',
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: user?.address.zip || '',
+ // Property or array item — trailing comma allowed in TypeScript
+ cardNumber: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ expiry: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ cvv: '',
+ // Closing brace — end of block (function, if, object, JSX)
+ });
+// (blank line — separates logical blocks for readability)
+ // Line 40: const total = getTotal();
+ const total = getTotal();
+ // Line 41: const deliveryFee = total > 500 ? 0 : 49;
+ const deliveryFee = total > 500 ? 0 : 49;
+ // Line 42: const grandTotal = total + deliveryFee;
+ const grandTotal = total + deliveryFee;
+ // Line 43: const fmt = (n: number) => formatPrice(n, getFormatLocale...
+ const fmt = (n: number) => formatPrice(n, getFormatLocale(locale));
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (items.length === 0 && !orderComplete) {
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('checkout.noItems')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 53: );
+ );
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (orderComplete) {
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 63: {t('checkout.orderConfirmed')}
+ {t('checkout.orderConfirmed')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('checkout.thankYou')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 67: {t('checkout.orderId', { id: orderId })}
+ {t('checkout.orderId', { id: orderId })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 78: );
+ );
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Line 81: const handleSubmit = async (e: React.FormEvent) => {
+ const handleSubmit = async (e: React.FormEvent) => {
+ // Line 82: e.preventDefault();
+ e.preventDefault();
+ // Line 83: setIsProcessing(true);
+ setIsProcessing(true);
+// (blank line — separates logical blocks for readability)
+ // Line 85: await new Promise((resolve) => setTimeout(resolve, 1500));
+ await new Promise((resolve) => setTimeout(resolve, 1500));
+// (blank line — separates logical blocks for readability)
+ // Line 87: const newOrderId = `KG-${Date.now().toString(36).toUpperC...
+ const newOrderId = `KG-${Date.now().toString(36).toUpperCase()}`;
+ // Line 88: const order: Order = {
+ const order: Order = {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: newOrderId,
+ // Property or array item — trailing comma allowed in TypeScript
+ items: [...items],
+ // Property or array item — trailing comma allowed in TypeScript
+ total: grandTotal,
+ // Property or array item — trailing comma allowed in TypeScript
+ status: 'confirmed',
+ // Property or array item — trailing comma allowed in TypeScript
+ createdAt: new Date().toISOString(),
+ // Line 94: deliveryAddress: {
+ deliveryAddress: {
+ // Property or array item — trailing comma allowed in TypeScript
+ street: form.street,
+ // Property or array item — trailing comma allowed in TypeScript
+ city: form.city,
+ // Property or array item — trailing comma allowed in TypeScript
+ state: form.state,
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: form.zip,
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Property or array item — trailing comma allowed in TypeScript
+ paymentMethod,
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // Line 103: addOrder(order);
+ addOrder(order);
+ // Line 104: clearCart();
+ clearCart();
+ // Line 105: setOrderId(newOrderId);
+ setOrderId(newOrderId);
+ // Line 106: setOrderComplete(true);
+ setOrderComplete(true);
+ // Line 107: setIsProcessing(false);
+ setIsProcessing(false);
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // Line 110: const updateField = (field: string, value: string) => {
+ const updateField = (field: string, value: string) => {
+ // Line 111: setForm((prev) => ({ ...prev, [field]: value }));
+ setForm((prev) => ({ ...prev, [field]: value }));
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 122: {t('checkout.backToCart')}
+ {t('checkout.backToCart')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('checkout.title')}
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 359: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/layout.annotated.tsx b/docs/annotated/src/app/layout.annotated.tsx
new file mode 100644
index 0000000..f7bdd0c
--- /dev/null
+++ b/docs/annotated/src/app/layout.annotated.tsx
@@ -0,0 +1,174 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/layout.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Type-only import — erased at compile time; no JavaScript bundle cost
+import type { Metadata } from 'next';
+// Self-hosted Google fonts — better performance than external CSS
+import { Inter, Playfair_Display, Noto_Nastaliq_Urdu } from 'next/font/google';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import LanguageBanner from '@/components/layout/LanguageBanner';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Header from '@/components/layout/Header';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Footer from '@/components/layout/Footer';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import LocaleAttributes from '@/components/layout/LocaleAttributes';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { SITE_NAME } from '@/lib/constants';
+// Import from a relative file in the same project
+import './globals.css';
+// (blank line — separates logical blocks for readability)
+// Line 10: const inter = Inter({
+const inter = Inter({
+ // Property or array item — trailing comma allowed in TypeScript
+ subsets: ['latin'],
+ // Property or array item — trailing comma allowed in TypeScript
+ variable: '--font-inter',
+ // Property or array item — trailing comma allowed in TypeScript
+ display: 'swap',
+// Closing brace — end of block (function, if, object, JSX)
+});
+// (blank line — separates logical blocks for readability)
+// Line 16: const playfair = Playfair_Display({
+const playfair = Playfair_Display({
+ // Property or array item — trailing comma allowed in TypeScript
+ subsets: ['latin'],
+ // Property or array item — trailing comma allowed in TypeScript
+ variable: '--font-playfair',
+ // Property or array item — trailing comma allowed in TypeScript
+ display: 'swap',
+// Closing brace — end of block (function, if, object, JSX)
+});
+// (blank line — separates logical blocks for readability)
+// Line 22: const notoUrdu = Noto_Nastaliq_Urdu({
+const notoUrdu = Noto_Nastaliq_Urdu({
+ // Property or array item — trailing comma allowed in TypeScript
+ subsets: ['arabic'],
+ // Property or array item — trailing comma allowed in TypeScript
+ variable: '--font-urdu',
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: ['400', '500', '600', '700'],
+ // Property or array item — trailing comma allowed in TypeScript
+ display: 'swap',
+// Closing brace — end of block (function, if, object, JSX)
+});
+// (blank line — separates logical blocks for readability)
+// Line 29: const siteDescription =
+const siteDescription =
+ // Line 30: 'Premium 100% Halal meat delivery. Fresh and frozen chick...
+ 'Premium 100% Halal meat delivery. Fresh and frozen chicken, beef, lamb, and fish — customized to your preference and delivered to your door.';
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const viewport = {
+ // Property or array item — trailing comma allowed in TypeScript
+ themeColor: '#8B1F1F',
+// Closing brace — end of block (function, if, object, JSX)
+};
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const metadata: Metadata = {
+ // Line 37: title: {
+ title: {
+ // Switch default — fallback when no case matches
+ default: `${SITE_NAME} — Premium Halal Meat Delivery`,
+ // Property or array item — trailing comma allowed in TypeScript
+ template: `%s | ${SITE_NAME}`,
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Property or array item — trailing comma allowed in TypeScript
+ description: siteDescription,
+ // Line 42: keywords: [
+ keywords: [
+ // Property or array item — trailing comma allowed in TypeScript
+ 'halal meat',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'halal chicken',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'halal beef',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'halal lamb',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'meat delivery',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'fresh meat',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Kött Gård',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'kottgard',
+ // End of array literal
+ ],
+ // Line 52: openGraph: {
+ openGraph: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: `${SITE_NAME} — Premium Halal Meat Delivery`,
+ // Property or array item — trailing comma allowed in TypeScript
+ description: siteDescription,
+ // Property or array item — trailing comma allowed in TypeScript
+ type: 'website',
+ // Property or array item — trailing comma allowed in TypeScript
+ locale: 'sv_SE',
+ // Property or array item — trailing comma allowed in TypeScript
+ siteName: SITE_NAME,
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 59: robots: {
+ robots: {
+ // Property or array item — trailing comma allowed in TypeScript
+ index: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ follow: true,
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// Closing brace — end of block (function, if, object, JSX)
+};
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function RootLayout({
+ // Property or array item — trailing comma allowed in TypeScript
+ children,
+// Closing brace — end of block (function, if, object, JSX)
+}: {
+ // Line 68: children: React.ReactNode;
+ children: React.ReactNode;
+// Closing brace — end of block (function, if, object, JSX)
+}) {
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {children}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 87: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/login/page.annotated.tsx b/docs/annotated/src/app/login/page.annotated.tsx
new file mode 100644
index 0000000..cc846e5
--- /dev/null
+++ b/docs/annotated/src/app/login/page.annotated.tsx
@@ -0,0 +1,384 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/login/page.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import React — core UI library (components, hooks, JSX)
+import { useState } from 'react';
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Next.js App Router hooks — useRouter, useParams, useSearchParams
+import { useRouter } from 'next/navigation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useAuthStore } from '@/store/auth';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { DEMO_EMAIL } from '@/lib/constants';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function LoginPage() {
+ // Next.js router — programmatic navigation (router.push)
+ const router = useRouter();
+ // Zustand selector — subscribe to slice of global store
+ const { login, register } = useAuthStore();
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+ // React useState — local component state that triggers re-render on change
+ const [isRegister, setIsRegister] = useState(false);
+ // React useState — local component state that triggers re-render on change
+ const [error, setError] = useState('');
+ // React useState — local component state that triggers re-render on change
+ const [form, setForm] = useState({
+ // Property or array item — trailing comma allowed in TypeScript
+ name: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ password: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ street: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ city: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ state: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: '',
+ // Closing brace — end of block (function, if, object, JSX)
+ });
+// (blank line — separates logical blocks for readability)
+ // Line 28: const handleSubmit = (e: React.FormEvent) => {
+ const handleSubmit = (e: React.FormEvent) => {
+ // Line 29: e.preventDefault();
+ e.preventDefault();
+ // Line 30: setError('');
+ setError('');
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (isRegister) {
+ // Line 33: const success = register({
+ const success = register({
+ // Property or array item — trailing comma allowed in TypeScript
+ name: form.name,
+ // Property or array item — trailing comma allowed in TypeScript
+ email: form.email,
+ // Property or array item — trailing comma allowed in TypeScript
+ password: form.password,
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: form.phone,
+ // Line 38: address: {
+ address: {
+ // Property or array item — trailing comma allowed in TypeScript
+ street: form.street,
+ // Property or array item — trailing comma allowed in TypeScript
+ city: form.city,
+ // Property or array item — trailing comma allowed in TypeScript
+ state: form.state,
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: form.zip,
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ });
+ // Conditional branch — different behavior based on runtime value
+ if (success) router.push('/account');
+ // Closing brace — end of block (function, if, object, JSX)
+ } else {
+ // Line 47: const success = login(form.email, form.password);
+ const success = login(form.email, form.password);
+ // Conditional branch — different behavior based on runtime value
+ if (success) {
+ // Line 49: router.push('/account');
+ router.push('/account');
+ // Closing brace — end of block (function, if, object, JSX)
+ } else {
+ // Line 51: setError(t('auth.invalidCredentials', { email: DEMO_EMAIL...
+ setError(t('auth.invalidCredentials', { email: DEMO_EMAIL }));
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 62: {t('site.initials')}
+ {t('site.initials')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 66: {isRegister ? t('auth.createAccount') : t('auth.welcomeBa...
+ {isRegister ? t('auth.createAccount') : t('auth.welcomeBack')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 69: {isRegister
+ {isRegister
+ // Line 70: ? t('auth.joinTagline', { name: t('site.name') })
+ ? t('auth.joinTagline', { name: t('site.name') })
+ // Line 71: : t('auth.signInTagline', { name: t('site.name') })}
+ : t('auth.signInTagline', { name: t('site.name') })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // Line 185: {!isRegister && (
+ {!isRegister && (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 188: {t('auth.demo', { email: DEMO_EMAIL })}
+ {t('auth.demo', { email: DEMO_EMAIL })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 191: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 195: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/not-found.annotated.tsx b/docs/annotated/src/app/not-found.annotated.tsx
new file mode 100644
index 0000000..c7ca617
--- /dev/null
+++ b/docs/annotated/src/app/not-found.annotated.tsx
@@ -0,0 +1,44 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/not-found.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function NotFound() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 13: {t('notFound.title')}
+ {t('notFound.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('notFound.message')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 20: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/page.annotated.tsx b/docs/annotated/src/app/page.annotated.tsx
new file mode 100644
index 0000000..bcdbc38
--- /dev/null
+++ b/docs/annotated/src/app/page.annotated.tsx
@@ -0,0 +1,58 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/page.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Hero from '@/components/home/Hero';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import TrustBadges from '@/components/home/TrustBadges';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import AboutPreview from '@/components/home/AboutPreview';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import CategoryGrid from '@/components/home/CategoryGrid';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import FeaturedProducts from '@/components/home/FeaturedProducts';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import HowItWorks from '@/components/home/HowItWorks';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import WeeklyOffers from '@/components/home/WeeklyOffers';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import SocialFollow from '@/components/home/SocialFollow';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import ContactPreview from '@/components/home/ContactPreview';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import CTA from '@/components/home/CTA';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function HomePage() {
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // React Fragment — group elements without extra wrapper DOM node
+ <>
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ >
+ // Line 26: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/product/[slug]/page.annotated.tsx b/docs/annotated/src/app/product/[slug]/page.annotated.tsx
new file mode 100644
index 0000000..8de12cb
--- /dev/null
+++ b/docs/annotated/src/app/product/[slug]/page.annotated.tsx
@@ -0,0 +1,434 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/product/[slug]/page.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import React — core UI library (components, hooks, JSX)
+import { useState } from 'react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import AppImage from '@/components/ui/AppImage';
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Next.js App Router hooks — useRouter, useParams, useSearchParams
+import { notFound, useParams } from 'next/navigation';
+// Import external package or local module
+import {
+ // Property or array item — trailing comma allowed in TypeScript
+ ShoppingCart,
+ // Property or array item — trailing comma allowed in TypeScript
+ Heart,
+ // Property or array item — trailing comma allowed in TypeScript
+ ChevronLeft,
+ // Property or array item — trailing comma allowed in TypeScript
+ Minus,
+ // Property or array item — trailing comma allowed in TypeScript
+ Plus,
+ // Property or array item — trailing comma allowed in TypeScript
+ Check,
+ // Property or array item — trailing comma allowed in TypeScript
+ ShieldCheck,
+// Closing brace — end of block (function, if, object, JSX)
+} from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import CustomizationSelector from '@/components/product/CustomizationSelector';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { getProductBySlug } from '@/lib/products';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { getDefaultCustomization, getCustomizationLabel } from '@/lib/customization';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { localizeProduct } from '@/lib/product-i18n';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { formatPrice, getFormatLocale } from '@/lib/utils';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useCartStore } from '@/store/cart';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useWishlistStore } from '@/store/wishlist';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { ProductCustomization } from '@/types';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function ProductPage() {
+ // Read dynamic route segment ([slug] from URL)
+ const params = useParams();
+ // Line 29: const slug = params.slug as string;
+ const slug = params.slug as string;
+ // Line 30: const rawProduct = getProductBySlug(slug);
+ const rawProduct = getProductBySlug(slug);
+ // Custom hook — returns t() translator and current locale
+ const { t, locale } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // React useState — local component state that triggers re-render on change
+ const [customization, setCustomization] = useState(
+ // Line 34: rawProduct ? getDefaultCustomization(rawProduct.category)...
+ rawProduct ? getDefaultCustomization(rawProduct.category) : { type: 'fish' }
+ // Line 35: );
+ );
+ // React useState — local component state that triggers re-render on change
+ const [quantity, setQuantity] = useState(1);
+ // React useState — local component state that triggers re-render on change
+ const [selectedImage, setSelectedImage] = useState(0);
+ // React useState — local component state that triggers re-render on change
+ const [added, setAdded] = useState(false);
+// (blank line — separates logical blocks for readability)
+ // Zustand selector — subscribe to slice of global store
+ const addItem = useCartStore((s) => s.addItem);
+ // Zustand selector — subscribe to slice of global store
+ const { isInWishlist, toggleItem } = useWishlistStore();
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (!rawProduct) {
+ // Line 44: notFound();
+ notFound();
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Line 47: const product = localizeProduct(rawProduct, t);
+ const product = localizeProduct(rawProduct, t);
+ // Line 48: const inWishlist = isInWishlist(product.id);
+ const inWishlist = isInWishlist(product.id);
+// (blank line — separates logical blocks for readability)
+ // Line 50: const handleAddToCart = () => {
+ const handleAddToCart = () => {
+ // Line 51: const label = getCustomizationLabel(customization, t);
+ const label = getCustomizationLabel(customization, t);
+ // Line 52: addItem(rawProduct, customization, label, quantity);
+ addItem(rawProduct, customization, label, quantity);
+ // Line 53: setAdded(true);
+ setAdded(true);
+ // Line 54: setTimeout(() => setAdded(false), 2000);
+ setTimeout(() => setAdded(false), 2000);
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 65: {t('product.backToShop')}
+ {t('product.backToShop')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ />
+ // Line 79: {product.badge && (
+ {product.badge && (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 81: {product.badge}
+ {product.badge}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 83: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 85: {product.images.length > 1 && (
+ {product.images.length > 1 && (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {product.images.map((img, i) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 99: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 101: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // Line 110: {t(`categories.${product.category}.name`)}
+ {t(`categories.${product.category}.name`)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 112: {product.inStock ? (
+ {product.inStock ? (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {t('product.inStock')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 116: ) : (
+ ) : (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 118: {t('product.outOfStock')}
+ {t('product.outOfStock')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 120: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 124: {product.name}
+ {product.name}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
{product.description}
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 131: {formatPrice(product.price, getFormatLocale(locale))}
+ {formatPrice(product.price, getFormatLocale(locale))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {product.priceUnit}
+ // Line 134: {product.weight && (
+ {product.weight && (
+ // JSX element — HTML-like tag becomes React component in browser
+ · {product.weight}
+ // Line 136: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {t('product.halalTrust')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ />
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('product.yourSelection')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 153: {getCustomizationLabel(customization, t)}
+ {getCustomizationLabel(customization, t)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {quantity}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 213: {t('product.aboutProduct')}
+ {t('product.aboutProduct')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 216: {product.longDescription}
+ {product.longDescription}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 223: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/shop/layout.annotated.tsx b/docs/annotated/src/app/shop/layout.annotated.tsx
new file mode 100644
index 0000000..a99c244
--- /dev/null
+++ b/docs/annotated/src/app/shop/layout.annotated.tsx
@@ -0,0 +1,48 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/shop/layout.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import React — core UI library (components, hooks, JSX)
+import { Suspense } from 'react';
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const metadata = {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Shop',
+ // Line 5: description:
+ description:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Browse premium halal chicken, beef, lamb, and fish. Customized cuts delivered fresh to your door.',
+// Closing brace — end of block (function, if, object, JSX)
+};
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function ShopLayout({
+ // Property or array item — trailing comma allowed in TypeScript
+ children,
+// Closing brace — end of block (function, if, object, JSX)
+}: {
+ // Line 12: children: React.ReactNode;
+ children: React.ReactNode;
+// Closing brace — end of block (function, if, object, JSX)
+}) {
+ // Return value from function
+ return }>{children};
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Function declaration — reusable logic in this file
+function ShopLoading() {
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 22: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/shop/page.annotated.tsx b/docs/annotated/src/app/shop/page.annotated.tsx
new file mode 100644
index 0000000..d23ddcf
--- /dev/null
+++ b/docs/annotated/src/app/shop/page.annotated.tsx
@@ -0,0 +1,275 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/shop/page.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import React — core UI library (components, hooks, JSX)
+import { useCallback, useEffect, useMemo, useState } from 'react';
+// Next.js App Router hooks — useRouter, useParams, useSearchParams
+import { useRouter, useSearchParams } from 'next/navigation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import ProductCard from '@/components/product/ProductCard';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import ShopFilters from '@/components/shop/ShopFilters';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { products } from '@/lib/products';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { localizeProduct } from '@/lib/product-i18n';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { Category, SortOption } from '@/types';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// (blank line — separates logical blocks for readability)
+// Line 12: const CATEGORIES: Category[] = ['chicken', 'beef', 'lamb'...
+const CATEGORIES: Category[] = ['chicken', 'beef', 'lamb', 'fish'];
+// (blank line — separates logical blocks for readability)
+// Function declaration — reusable logic in this file
+function parseCategory(value: string | null): Category | 'all' {
+ // Return value from function
+ return CATEGORIES.includes(value as Category) ? (value as Category) : 'all';
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function ShopPage() {
+ // Next.js router — programmatic navigation (router.push)
+ const router = useRouter();
+ // Read URL query string (?category=beef&q=steak)
+ const searchParams = useSearchParams();
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // React useState — local component state that triggers re-render on change
+ const [selectedCategory, setSelectedCategory] = useState(
+ // Line 24: parseCategory(searchParams.get('category'))
+ parseCategory(searchParams.get('category'))
+ // Line 25: );
+ );
+ // React useState — local component state that triggers re-render on change
+ const [sortBy, setSortBy] = useState('featured');
+ // React useState — local component state that triggers re-render on change
+ const [searchQuery, setSearchQuery] = useState(searchParams.get('q') || '');
+// (blank line — separates logical blocks for readability)
+ // Side effect hook — runs after paint; deps array controls when it re-runs
+ useEffect(() => {
+ // Line 30: setSelectedCategory(parseCategory(searchParams.get('categ...
+ setSelectedCategory(parseCategory(searchParams.get('category')));
+ // Line 31: setSearchQuery(searchParams.get('q') || '');
+ setSearchQuery(searchParams.get('q') || '');
+ // Closing brace — end of block (function, if, object, JSX)
+ }, [searchParams]);
+// (blank line — separates logical blocks for readability)
+ // React useCallback — stable function reference for useEffect/useMemo deps
+ const pushParams = useCallback(
+ // Line 35: (updates: { category?: Category | 'all'; q?: string }) => {
+ (updates: { category?: Category | 'all'; q?: string }) => {
+ // Line 36: const params = new URLSearchParams(searchParams.toString());
+ const params = new URLSearchParams(searchParams.toString());
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (updates.category !== undefined) {
+ // Conditional branch — different behavior based on runtime value
+ if (updates.category === 'all') params.delete('category');
+ // Line 40: else params.set('category', updates.category);
+ else params.set('category', updates.category);
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (updates.q !== undefined) {
+ // Conditional branch — different behavior based on runtime value
+ if (updates.q) params.set('q', updates.q);
+ // Line 45: else params.delete('q');
+ else params.delete('q');
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Line 48: const qs = params.toString();
+ const qs = params.toString();
+ // Line 49: router.push(qs ? `/shop?${qs}` : '/shop', { scroll: false...
+ router.push(qs ? `/shop?${qs}` : '/shop', { scroll: false });
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 51: [router, searchParams]
+ [router, searchParams]
+ // Line 52: );
+ );
+// (blank line — separates logical blocks for readability)
+ // Line 54: const handleCategoryChange = (category: Category | 'all')...
+ const handleCategoryChange = (category: Category | 'all') => {
+ // Line 55: setSelectedCategory(category);
+ setSelectedCategory(category);
+ // Line 56: pushParams({ category });
+ pushParams({ category });
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // Line 59: const handleSearchChange = (query: string) => {
+ const handleSearchChange = (query: string) => {
+ // Line 60: setSearchQuery(query);
+ setSearchQuery(query);
+ // Line 61: pushParams({ q: query });
+ pushParams({ q: query });
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // React useMemo — cache expensive computed value until dependencies change
+ const filteredProducts = useMemo(() => {
+ // Array.map — transform each item (often render a list of components)
+ let result = products.map((p) => localizeProduct(p, t));
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (selectedCategory !== 'all') {
+ // Array.filter — keep items matching condition (search, category)
+ result = result.filter((p) => p.category === selectedCategory);
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (searchQuery.trim()) {
+ // Line 72: const query = searchQuery.toLowerCase();
+ const query = searchQuery.toLowerCase();
+ // Array.filter — keep items matching condition (search, category)
+ result = result.filter(
+ // Line 74: (p) =>
+ (p) =>
+ // Line 75: p.name.toLowerCase().includes(query) ||
+ p.name.toLowerCase().includes(query) ||
+ // Line 76: p.description.toLowerCase().includes(query) ||
+ p.description.toLowerCase().includes(query) ||
+ // Line 77: p.tags.some((tag) => tag.includes(query))
+ p.tags.some((tag) => tag.includes(query))
+ // Line 78: );
+ );
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Switch — multiple branches on one variable (e.g. sort order)
+ switch (sortBy) {
+ // Switch case — handle one specific value
+ case 'price-asc':
+ // Array.sort — reorder items (price, name, featured)
+ result.sort((a, b) => a.price - b.price);
+ // Line 84: break;
+ break;
+ // Switch case — handle one specific value
+ case 'price-desc':
+ // Array.sort — reorder items (price, name, featured)
+ result.sort((a, b) => b.price - a.price);
+ // Line 87: break;
+ break;
+ // Switch case — handle one specific value
+ case 'name':
+ // Array.sort — reorder items (price, name, featured)
+ result.sort((a, b) => a.name.localeCompare(b.name));
+ // Line 90: break;
+ break;
+ // Switch case — handle one specific value
+ case 'featured':
+ // Switch default — fallback when no case matches
+ default:
+ // Array.sort — reorder items (price, name, featured)
+ result.sort((a, b) => (b.featured ? 1 : 0) - (a.featured ? 1 : 0));
+ // Line 94: break;
+ break;
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Return value from function
+ return result;
+ // Closing brace — end of block (function, if, object, JSX)
+ }, [selectedCategory, sortBy, searchQuery, t]);
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('shop.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('shop.subtitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 126: {filteredProducts.length === 0 ? (
+ {filteredProducts.length === 0 ? (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 129: {t('shop.noProducts')}
+ {t('shop.noProducts')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('shop.noProductsHint')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 133: ) : (
+ ) : (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {filteredProducts.map((product) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 137: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 139: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 144: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/app/wishlist/page.annotated.tsx b/docs/annotated/src/app/wishlist/page.annotated.tsx
new file mode 100644
index 0000000..342c762
--- /dev/null
+++ b/docs/annotated/src/app/wishlist/page.annotated.tsx
@@ -0,0 +1,103 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/app/wishlist/page.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Lucide icons — lightweight SVG icon components
+import { Heart } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import ProductCard from '@/components/product/ProductCard';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useWishlistStore } from '@/store/wishlist';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { localizeProduct } from '@/lib/product-i18n';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function WishlistPage() {
+ // Zustand selector — subscribe to slice of global store
+ const items = useWishlistStore((s) => s.items);
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+ // Array.map — transform each item (often render a list of components)
+ const localizedItems = items.map((p) => localizeProduct(p, t));
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('wishlist.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 22: {t('wishlist.saved', { count: items.length })}
+ {t('wishlist.saved', { count: items.length })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 28: {items.length === 0 ? (
+ {items.length === 0 ? (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 34: {t('wishlist.empty')}
+ {t('wishlist.empty')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('wishlist.emptyHint')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 41: ) : (
+ ) : (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {localizedItems.map((product) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 45: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 47: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 50: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/home/AboutPreview.annotated.tsx b/docs/annotated/src/components/home/AboutPreview.annotated.tsx
new file mode 100644
index 0000000..fc65567
--- /dev/null
+++ b/docs/annotated/src/components/home/AboutPreview.annotated.tsx
@@ -0,0 +1,132 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/home/AboutPreview.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import project module (@/ alias = src/ folder in tsconfig)
+import AppImage from '@/components/ui/AppImage';
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Lucide icons — lightweight SVG icon components
+import { ArrowRight } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { IMAGES } from '@/lib/images';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function AboutPreview() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Line 13: const stats = [
+ const stats = [
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: t('aboutPreview.statHalal'), label: t('aboutPreview.statHalalLabel') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: t('aboutPreview.statDays'), label: t('aboutPreview.statDaysLabel') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: t('aboutPreview.statDelivery'), label: t('aboutPreview.statDeliveryLabel') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: t('aboutPreview.statFresh'), label: t('aboutPreview.statFreshLabel') },
+ // End of array literal
+ ];
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 26: {t('aboutPreview.label')}
+ {t('aboutPreview.label')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('aboutPreview.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('aboutPreview.p1')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('aboutPreview.p2')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('aboutPreview.p3')}
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {stats.map((stat) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
{stat.value}
+ // JSX element — HTML-like tag becomes React component in browser
+
{stat.label}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 42: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ />
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 66: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/home/CTA.annotated.tsx b/docs/annotated/src/components/home/CTA.annotated.tsx
new file mode 100644
index 0000000..948d723
--- /dev/null
+++ b/docs/annotated/src/components/home/CTA.annotated.tsx
@@ -0,0 +1,95 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/home/CTA.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Lucide icons — lightweight SVG icon components
+import { ArrowRight, MessageCircle } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { WHATSAPP_URL } from '@/lib/constants';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function CTA() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 21: {t('cta.title')}
+ {t('cta.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('cta.subtitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 46: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/home/CategoryGrid.annotated.tsx b/docs/annotated/src/components/home/CategoryGrid.annotated.tsx
new file mode 100644
index 0000000..5c29451
--- /dev/null
+++ b/docs/annotated/src/components/home/CategoryGrid.annotated.tsx
@@ -0,0 +1,110 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/home/CategoryGrid.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import project module (@/ alias = src/ folder in tsconfig)
+import AppImage from '@/components/ui/AppImage';
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Lucide icons — lightweight SVG icon components
+import { ArrowRight } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { CATEGORY_IDS, CATEGORY_IMAGES } from '@/lib/constants';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Default export — main component/page Next.js or other files import
+export default function CategoryGrid() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('categories.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('categories.subtitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {CATEGORY_IDS.map((id) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ />
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 38: {t(`categories.${id}.name`)}
+ {t(`categories.${id}.name`)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 41: {t(`categories.${id}.description`)}
+ {t(`categories.${id}.description`)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 44: {t('categories.shop', { name: t(`categories.${id}.name`) })}
+ {t('categories.shop', { name: t(`categories.${id}.name`) })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 49: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 53: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/home/ContactPreview.annotated.tsx b/docs/annotated/src/components/home/ContactPreview.annotated.tsx
new file mode 100644
index 0000000..5d42c0f
--- /dev/null
+++ b/docs/annotated/src/components/home/ContactPreview.annotated.tsx
@@ -0,0 +1,233 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/home/ContactPreview.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Lucide icons — lightweight SVG icon components
+import { Phone, MapPin, Clock, MessageCircle, ExternalLink } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Logo from '@/components/ui/Logo';
+// Import external package or local module
+import {
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_ADDRESS,
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_PHONE_DISPLAY,
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_HOURS,
+ // Property or array item — trailing comma allowed in TypeScript
+ WHATSAPP_URL,
+ // Property or array item — trailing comma allowed in TypeScript
+ MAPS_URL,
+// Closing brace — end of block (function, if, object, JSX)
+} from '@/lib/constants';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function ContactPreview() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+ // Line 18: const telHref = `tel:+46725855050`;
+ const telHref = `tel:+46725855050`;
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 26: {t('contact.label')}
+ {t('contact.label')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 29: {t('contact.title')}
+ {t('contact.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 37: {t('contact.addressLabel')}
+ {t('contact.addressLabel')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{SITE_ADDRESS}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 46: {t('contact.phoneLabel')}
+ {t('contact.phoneLabel')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 116: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/home/FeaturedProducts.annotated.tsx b/docs/annotated/src/components/home/FeaturedProducts.annotated.tsx
new file mode 100644
index 0000000..95511c9
--- /dev/null
+++ b/docs/annotated/src/components/home/FeaturedProducts.annotated.tsx
@@ -0,0 +1,89 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/home/FeaturedProducts.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import ProductCard from '@/components/product/ProductCard';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { getFeaturedProducts } from '@/lib/products';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Lucide icons — lightweight SVG icon components
+import { ArrowRight } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { localizeProduct } from '@/lib/product-i18n';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function FeaturedProducts() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+ // Line 13: const featured = getFeaturedProducts()
+ const featured = getFeaturedProducts()
+ // Line 14: .slice(0, 4)
+ .slice(0, 4)
+ // Array.map — transform each item (often render a list of components)
+ .map((p) => localizeProduct(p, t));
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 23: {t('featured.label')}
+ {t('featured.label')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('featured.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('featured.subtitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {featured.map((product) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 39: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 43: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/home/Hero.annotated.tsx b/docs/annotated/src/components/home/Hero.annotated.tsx
new file mode 100644
index 0000000..a04fb9a
--- /dev/null
+++ b/docs/annotated/src/components/home/Hero.annotated.tsx
@@ -0,0 +1,184 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/home/Hero.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import AppImage from '@/components/ui/AppImage';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Logo from '@/components/ui/Logo';
+// Lucide icons — lightweight SVG icon components
+import { ArrowRight, ShieldCheck, MapPin, Clock } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { IMAGES } from '@/lib/images';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { SITE_LOCATION, SITE_HOURS, SITE_ADDRESS, WHATSAPP_URL } from '@/lib/constants';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function Hero() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ />
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{SITE_LOCATION}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('hero.taglineShort')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 45: {t('hero.badge')}
+ {t('hero.badge')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 50: {t('hero.title')}
+ {t('hero.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 54: {t('hero.subtitleShort')}
+ {t('hero.subtitleShort')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 58: {t('hero.subtitle')}
+ {t('hero.subtitle')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 64: {t('hero.hours', { hours: SITE_HOURS })}
+ {t('hero.hours', { hours: SITE_HOURS })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 68: {SITE_ADDRESS}
+ {SITE_ADDRESS}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 94: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/home/HowItWorks.annotated.tsx b/docs/annotated/src/components/home/HowItWorks.annotated.tsx
new file mode 100644
index 0000000..871ba0c
--- /dev/null
+++ b/docs/annotated/src/components/home/HowItWorks.annotated.tsx
@@ -0,0 +1,139 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/home/HowItWorks.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Lucide icons — lightweight SVG icon components
+import { MessageCircle, ClipboardCheck, Store } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Button from '@/components/ui/Button';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { WHATSAPP_URL } from '@/lib/constants';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function HowItWorks() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Line 11: const steps = [
+ const steps = [
+ // Line 12: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: MessageCircle,
+ // Property or array item — trailing comma allowed in TypeScript
+ step: '01',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: t('howItWorks.step1Title'),
+ // Property or array item — trailing comma allowed in TypeScript
+ description: t('howItWorks.step1Desc'),
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 18: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: ClipboardCheck,
+ // Property or array item — trailing comma allowed in TypeScript
+ step: '02',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: t('howItWorks.step2Title'),
+ // Property or array item — trailing comma allowed in TypeScript
+ description: t('howItWorks.step2Desc'),
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 24: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: Store,
+ // Property or array item — trailing comma allowed in TypeScript
+ step: '03',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: t('howItWorks.step3Title'),
+ // Property or array item — trailing comma allowed in TypeScript
+ description: t('howItWorks.step3Desc'),
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // End of array literal
+ ];
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 37: {t('howItWorks.label')}
+ {t('howItWorks.label')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 40: {t('howItWorks.title')}
+ {t('howItWorks.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {steps.map((step) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 51: {t('howItWorks.step', { n: step.step })}
+ {t('howItWorks.step', { n: step.step })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{step.title}
+ // JSX element — HTML-like tag becomes React component in browser
+
{step.description}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 56: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 69: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/home/SocialFollow.annotated.tsx b/docs/annotated/src/components/home/SocialFollow.annotated.tsx
new file mode 100644
index 0000000..d5fff53
--- /dev/null
+++ b/docs/annotated/src/components/home/SocialFollow.annotated.tsx
@@ -0,0 +1,132 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/home/SocialFollow.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Lucide icons — lightweight SVG icon components
+import { Facebook, Instagram, MessageCircle } from 'lucide-react';
+// Import external package or local module
+import {
+ // Property or array item — trailing comma allowed in TypeScript
+ FACEBOOK_URL,
+ // Property or array item — trailing comma allowed in TypeScript
+ INSTAGRAM_URL,
+ // Property or array item — trailing comma allowed in TypeScript
+ WHATSAPP_URL,
+// Closing brace — end of block (function, if, object, JSX)
+} from '@/lib/constants';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// (blank line — separates logical blocks for readability)
+// Line 11: const socialLinks = [
+const socialLinks = [
+ // Line 12: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ key: 'facebook',
+ // Property or array item — trailing comma allowed in TypeScript
+ href: FACEBOOK_URL,
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: Facebook,
+ // Line 16: className:
+ className:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'border-blue-600/20 bg-blue-600/10 text-blue-700 hover:border-blue-600/40 hover:bg-blue-600/15',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 19: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ key: 'instagram',
+ // Property or array item — trailing comma allowed in TypeScript
+ href: INSTAGRAM_URL,
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: Instagram,
+ // Line 23: className:
+ className:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'border-pink-600/20 bg-pink-600/10 text-pink-700 hover:border-pink-600/40 hover:bg-pink-600/15',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 26: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ key: 'whatsapp',
+ // Property or array item — trailing comma allowed in TypeScript
+ href: WHATSAPP_URL,
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: MessageCircle,
+ // Line 30: className:
+ className:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'border-green-600/20 bg-green-600/10 text-green-700 hover:border-green-600/40 hover:bg-green-600/15',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// End of array literal
+] as const;
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function SocialFollow() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 43: {t('social.label')}
+ {t('social.label')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('social.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('social.subtitle')}
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 65: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/home/TrustBadges.annotated.tsx b/docs/annotated/src/components/home/TrustBadges.annotated.tsx
new file mode 100644
index 0000000..d118659
--- /dev/null
+++ b/docs/annotated/src/components/home/TrustBadges.annotated.tsx
@@ -0,0 +1,109 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/home/TrustBadges.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Lucide icons — lightweight SVG icon components
+import { ShieldCheck, Leaf, Award } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function TrustBadges() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Line 10: const badges = [
+ const badges = [
+ // Line 11: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: ShieldCheck,
+ // Property or array item — trailing comma allowed in TypeScript
+ title: t('trust.halal'),
+ // Property or array item — trailing comma allowed in TypeScript
+ description: t('trust.halalDesc'),
+ // Property or array item — trailing comma allowed in TypeScript
+ href: '/about#halal',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 17: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: Leaf,
+ // Property or array item — trailing comma allowed in TypeScript
+ title: t('trust.fresh'),
+ // Property or array item — trailing comma allowed in TypeScript
+ description: t('trust.freshDesc'),
+ // Property or array item — trailing comma allowed in TypeScript
+ href: '/about#delivery',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 23: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ icon: Award,
+ // Property or array item — trailing comma allowed in TypeScript
+ title: t('trust.premium'),
+ // Property or array item — trailing comma allowed in TypeScript
+ description: t('trust.premiumDesc'),
+ // Property or array item — trailing comma allowed in TypeScript
+ href: '/about',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // End of array literal
+ ];
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {badges.map((badge) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 45: {badge.title}
+ {badge.title}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{badge.description}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 49: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 53: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/home/WeeklyOffers.annotated.tsx b/docs/annotated/src/components/home/WeeklyOffers.annotated.tsx
new file mode 100644
index 0000000..cb7fb78
--- /dev/null
+++ b/docs/annotated/src/components/home/WeeklyOffers.annotated.tsx
@@ -0,0 +1,255 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/home/WeeklyOffers.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import AppImage from '@/components/ui/AppImage';
+// Lucide icons — lightweight SVG icon components
+import { MessageCircle, ArrowRight } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { weeklyOffers } from '@/lib/offers';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { IMAGES } from '@/lib/images';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { whatsappOrderUrl } from '@/lib/constants';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { formatPrice, getFormatLocale } from '@/lib/utils';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function WeeklyOffers() {
+ // Custom hook — returns t() translator and current locale
+ const { t, locale } = useTranslation();
+ // Line 14: const fmt = (n: number) => formatPrice(n, getFormatLocale...
+ const fmt = (n: number) => formatPrice(n, getFormatLocale(locale));
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 22: {t('offers.label')}
+ {t('offers.label')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('offers.title')}
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('offers.subtitle')}
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {weeklyOffers.map((offer) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ />
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // Line 55: {t(`offers.badge.${offer.badgeKey}`)}
+ {t(`offers.badge.${offer.badgeKey}`)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 61: {t(`${offer.nameKey}.name`)}
+ {t(`${offer.nameKey}.name`)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 67: {offer.originalPrice != null && (
+ {offer.originalPrice != null && (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 69: {t('offers.was')}: {fmt(offer.originalPrice)}/
+ {t('offers.was')}: {fmt(offer.originalPrice)}/
+ // Line 70: {t(`priceUnit.${offer.priceUnitKey}`)}
+ {t(`priceUnit.${offer.priceUnitKey}`)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 72: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 74: {offer.originalPrice != null && (
+ {offer.originalPrice != null && (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 76: {t('offers.now')}
+ {t('offers.now')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 78: )}
+ )}
+ // Line 79: {fmt(offer.price)}
+ {fmt(offer.price)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 81: /{t(`priceUnit.${offer.priceUnitKey}`)}
+ /{t(`priceUnit.${offer.priceUnitKey}`)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 107: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('offers.disclaimer')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ />
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 129: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/layout/Footer.annotated.tsx b/docs/annotated/src/components/layout/Footer.annotated.tsx
new file mode 100644
index 0000000..e7d745f
--- /dev/null
+++ b/docs/annotated/src/components/layout/Footer.annotated.tsx
@@ -0,0 +1,355 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/layout/Footer.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Lucide icons — lightweight SVG icon components
+import { ShieldCheck, Leaf, Award, Phone, Mail, MapPin, Facebook, Instagram, MessageCircle } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Logo from '@/components/ui/Logo';
+// Import external package or local module
+import {
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_PHONE_DISPLAY,
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_ADDRESS,
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_HOURS,
+ // Property or array item — trailing comma allowed in TypeScript
+ SITE_EMAIL,
+ // Property or array item — trailing comma allowed in TypeScript
+ FACEBOOK_URL,
+ // Property or array item — trailing comma allowed in TypeScript
+ INSTAGRAM_URL,
+ // Property or array item — trailing comma allowed in TypeScript
+ WHATSAPP_URL,
+// Closing brace — end of block (function, if, object, JSX)
+} from '@/lib/constants';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function Footer() {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Line 20: const footerLinks = {
+ const footerLinks = {
+ // Line 21: shop: [
+ shop: [
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.chicken'), href: '/shop?category=chicken' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.beef'), href: '/shop?category=beef' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.lamb'), href: '/shop?category=lamb' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.fish'), href: '/shop?category=fish' },
+ // End of array literal
+ ],
+ // Line 27: company: [
+ company: [
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.about'), href: '/about' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.halalCert'), href: '/about#halal' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.delivery'), href: '/about#delivery' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.contact'), href: '/about#contact' },
+ // End of array literal
+ ],
+ // Line 33: account: [
+ account: [
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.myAccount'), href: '/account' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.orderHistory'), href: '/account#orders' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.wishlist'), href: '/wishlist' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { label: t('nav.cart'), href: '/cart' },
+ // End of array literal
+ ],
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 178: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/layout/Header.annotated.tsx b/docs/annotated/src/components/layout/Header.annotated.tsx
new file mode 100644
index 0000000..fb48a2f
--- /dev/null
+++ b/docs/annotated/src/components/layout/Header.annotated.tsx
@@ -0,0 +1,254 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/layout/Header.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Import React — core UI library (components, hooks, JSX)
+import { useState } from 'react';
+// Lucide icons — lightweight SVG icon components
+import { ShoppingCart, Heart, User, Menu, X, Search } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useCartStore } from '@/store/cart';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useWishlistStore } from '@/store/wishlist';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useAuthStore } from '@/store/auth';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import Logo from '@/components/ui/Logo';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { SITE_LOCATION } from '@/lib/constants';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function Header() {
+ // React useState — local component state that triggers re-render on change
+ const [mobileOpen, setMobileOpen] = useState(false);
+ // Zustand selector — subscribe to slice of global store
+ const cartCount = useCartStore((s) => s.getItemCount());
+ // Zustand selector — subscribe to slice of global store
+ const wishlistCount = useWishlistStore((s) => s.items.length);
+ // Zustand selector — subscribe to slice of global store
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Line 20: const navLinks = [
+ const navLinks = [
+ // Property or array item — trailing comma allowed in TypeScript
+ { href: '/shop', label: t('nav.shop') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { href: '/shop?category=chicken', label: t('nav.chicken') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { href: '/shop?category=beef', label: t('nav.beef') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { href: '/shop?category=lamb', label: t('nav.lamb') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { href: '/shop?category=fish', label: t('nav.fish') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { href: '/about', label: t('nav.about') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { href: '/about#contact', label: t('nav.contact') },
+ // End of array literal
+ ];
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 38: {t('site.name')}
+ {t('site.name')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 41: {SITE_LOCATION}
+ {SITE_LOCATION}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 73: {wishlistCount > 0 && (
+ {wishlistCount > 0 && (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 75: {wishlistCount}
+ {wishlistCount}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 77: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 86: {cartCount > 0 && (
+ {cartCount > 0 && (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 88: {cartCount}
+ {cartCount}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 90: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // Line 112: {mobileOpen && (
+ {mobileOpen && (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 127: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 129: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/layout/LanguageBanner.annotated.tsx b/docs/annotated/src/components/layout/LanguageBanner.annotated.tsx
new file mode 100644
index 0000000..fc3e292
--- /dev/null
+++ b/docs/annotated/src/components/layout/LanguageBanner.annotated.tsx
@@ -0,0 +1,129 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/layout/LanguageBanner.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Lucide icons — lightweight SVG icon components
+import { Globe } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { LOCALES, Locale } from '@/i18n/types';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useLocaleStore } from '@/store/locale';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { cn } from '@/lib/utils';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function LanguageBanner() {
+ // Zustand selector — subscribe to slice of global store
+ const { locale, setLocale } = useLocaleStore();
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {t('languageBanner.choose')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // Array.map — transform each item (often render a list of components)
+ {LOCALES.map((lang) => {
+ // Line 31: const active = locale === lang.code;
+ const active = locale === lang.code;
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 58: );
+ );
+ // Closing brace — end of block (function, if, object, JSX)
+ })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 63: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/layout/LanguageSwitcher.annotated.tsx b/docs/annotated/src/components/layout/LanguageSwitcher.annotated.tsx
new file mode 100644
index 0000000..e2cb42c
--- /dev/null
+++ b/docs/annotated/src/components/layout/LanguageSwitcher.annotated.tsx
@@ -0,0 +1,135 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/layout/LanguageSwitcher.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import React — core UI library (components, hooks, JSX)
+import { useState, useRef, useEffect } from 'react';
+// Lucide icons — lightweight SVG icon components
+import { Globe, Check } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { LOCALES, Locale } from '@/i18n/types';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useLocaleStore } from '@/store/locale';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { cn } from '@/lib/utils';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function LanguageSwitcher() {
+ // React useState — local component state that triggers re-render on change
+ const [open, setOpen] = useState(false);
+ // Line 12: const ref = useRef(null);
+ const ref = useRef(null);
+ // Zustand selector — subscribe to slice of global store
+ const { locale, setLocale } = useLocaleStore();
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Array.find — get first matching item or undefined
+ const current = LOCALES.find((l) => l.code === locale);
+// (blank line — separates logical blocks for readability)
+ // Side effect hook — runs after paint; deps array controls when it re-runs
+ useEffect(() => {
+ // Function declaration — reusable logic in this file
+ function handleClick(e: MouseEvent) {
+ // Conditional branch — different behavior based on runtime value
+ if (ref.current && !ref.current.contains(e.target as Node)) {
+ // Line 21: setOpen(false);
+ setOpen(false);
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Line 24: document.addEventListener('mousedown', handleClick);
+ document.addEventListener('mousedown', handleClick);
+ // Return JSX — describes UI tree React renders to the DOM
+ return () => document.removeEventListener('mousedown', handleClick);
+ // Closing brace — end of block (function, if, object, JSX)
+ }, []);
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // Line 39: {open && (
+ {open && (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {LOCALES.map((lang) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 63: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 65: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 67: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/layout/LocaleAttributes.annotated.tsx b/docs/annotated/src/components/layout/LocaleAttributes.annotated.tsx
new file mode 100644
index 0000000..9a56120
--- /dev/null
+++ b/docs/annotated/src/components/layout/LocaleAttributes.annotated.tsx
@@ -0,0 +1,33 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/layout/LocaleAttributes.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import React — core UI library (components, hooks, JSX)
+import { useEffect } from 'react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useLocaleStore } from '@/store/locale';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { getHtmlLang, isRtl } from '@/i18n';
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function LocaleAttributes() {
+ // Zustand selector — subscribe to slice of global store
+ const locale = useLocaleStore((s) => s.locale);
+// (blank line — separates logical blocks for readability)
+ // Side effect hook — runs after paint; deps array controls when it re-runs
+ useEffect(() => {
+ // Line 11: document.documentElement.lang = getHtmlLang(locale);
+ document.documentElement.lang = getHtmlLang(locale);
+ // Line 12: document.documentElement.dir = isRtl(locale) ? 'rtl' : 'l...
+ document.documentElement.dir = isRtl(locale) ? 'rtl' : 'ltr';
+ // Closing brace — end of block (function, if, object, JSX)
+ }, [locale]);
+// (blank line — separates logical blocks for readability)
+ // Return value from function
+ return null;
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/product/CustomizationSelector.annotated.tsx b/docs/annotated/src/components/product/CustomizationSelector.annotated.tsx
new file mode 100644
index 0000000..89e5e9c
--- /dev/null
+++ b/docs/annotated/src/components/product/CustomizationSelector.annotated.tsx
@@ -0,0 +1,202 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/product/CustomizationSelector.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { Category, ProductCustomization } from '@/types';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { CUT_COUNTS, CUTTING_STYLE_KEYS } from '@/lib/constants';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { updateMeatCustomization } from '@/lib/customization';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { cn } from '@/lib/utils';
+// Lucide icons — lightweight SVG icon components
+import { Scissors, Hash } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// (blank line — separates logical blocks for readability)
+// TypeScript interface — contract for object properties and methods
+interface CustomizationSelectorProps {
+ // Line 11: category: Category;
+ category: Category;
+ // Line 12: customization: ProductCustomization;
+ customization: ProductCustomization;
+ // Line 13: onChange: (customization: ProductCustomization) => void;
+ onChange: (customization: ProductCustomization) => void;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function CustomizationSelector({
+ // Property or array item — trailing comma allowed in TypeScript
+ category,
+ // Property or array item — trailing comma allowed in TypeScript
+ customization,
+ // Property or array item — trailing comma allowed in TypeScript
+ onChange,
+// Closing brace — end of block (function, if, object, JSX)
+}: CustomizationSelectorProps) {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (category === 'fish') {
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('product.fishNote')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 28: );
+ );
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Line 31: const meat = updateMeatCustomization(customization, categ...
+ const meat = updateMeatCustomization(customization, category, {});
+ // Line 32: const selectedCuts = meat.cuts;
+ const selectedCuts = meat.cuts;
+ // Line 33: const selectedStyle = meat.cuttingStyle;
+ const selectedStyle = meat.cuttingStyle;
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 41: {t('product.howManyCuts')}
+ {t('product.howManyCuts')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {CUT_COUNTS.map((cuts) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 61: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('product.howManyCutsHint')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 70: {t('product.selectCutting')}
+ {t('product.selectCutting')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {CUTTING_STYLE_KEYS.map((style) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 92: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 95: {t('product.selectCuttingHint', {
+ {t('product.selectCuttingHint', {
+ // Property or array item — trailing comma allowed in TypeScript
+ category: t(`categories.${category}.name`),
+ // Closing brace — end of block (function, if, object, JSX)
+ })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 101: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/product/ProductCard.annotated.tsx b/docs/annotated/src/components/product/ProductCard.annotated.tsx
new file mode 100644
index 0000000..52c1fcd
--- /dev/null
+++ b/docs/annotated/src/components/product/ProductCard.annotated.tsx
@@ -0,0 +1,174 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/product/ProductCard.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import project module (@/ alias = src/ folder in tsconfig)
+import AppImage from '@/components/ui/AppImage';
+// Next.js Link — fast client-side navigation without full page reload
+import Link from 'next/link';
+// Lucide icons — lightweight SVG icon components
+import { Heart, ShoppingCart } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { LocalizedProduct } from '@/lib/product-i18n';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { formatPrice, getFormatLocale } from '@/lib/utils';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useWishlistStore } from '@/store/wishlist';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { cn } from '@/lib/utils';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { products } from '@/lib/products';
+// (blank line — separates logical blocks for readability)
+// TypeScript interface — contract for object properties and methods
+interface ProductCardProps {
+ // Line 14: product: LocalizedProduct;
+ product: LocalizedProduct;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function ProductCard({ product }: ProductCardProps) {
+ // Zustand selector — subscribe to slice of global store
+ const { isInWishlist, toggleItem } = useWishlistStore();
+ // Custom hook — returns t() translator and current locale
+ const { t, locale } = useTranslation();
+ // Array.find — get first matching item or undefined
+ const rawProduct = products.find((p) => p.id === product.id)!;
+ // Line 21: const inWishlist = isInWishlist(product.id);
+ const inWishlist = isInWishlist(product.id);
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ />
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 35: {product.badge && (
+ {product.badge && (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 37: {product.badge}
+ {product.badge}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 39: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 55: {t(`categories.${product.category}.name`)}
+ {t(`categories.${product.category}.name`)}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 57: {product.weight && (
+ {product.weight && (
+ // JSX element — HTML-like tag becomes React component in browser
+ · {product.weight}
+ // Line 59: )}
+ )}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 64: {product.name}
+ {product.name}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
{product.description}
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 73: {formatPrice(product.price, getFormatLocale(locale))}
+ {formatPrice(product.price, getFormatLocale(locale))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ {product.priceUnit}
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 88: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/shop/ShopFilters.annotated.tsx b/docs/annotated/src/components/shop/ShopFilters.annotated.tsx
new file mode 100644
index 0000000..69473e5
--- /dev/null
+++ b/docs/annotated/src/components/shop/ShopFilters.annotated.tsx
@@ -0,0 +1,214 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/shop/ShopFilters.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { Category, SortOption } from '@/types';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { cn } from '@/lib/utils';
+// Lucide icons — lightweight SVG icon components
+import { SlidersHorizontal } from 'lucide-react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useTranslation } from '@/hooks/useTranslation';
+// (blank line — separates logical blocks for readability)
+// TypeScript interface — contract for object properties and methods
+interface ShopFiltersProps {
+ // Line 9: selectedCategory: Category | 'all';
+ selectedCategory: Category | 'all';
+ // Line 10: onCategoryChange: (category: Category | 'all') => void;
+ onCategoryChange: (category: Category | 'all') => void;
+ // Line 11: sortBy: SortOption;
+ sortBy: SortOption;
+ // Line 12: onSortChange: (sort: SortOption) => void;
+ onSortChange: (sort: SortOption) => void;
+ // Line 13: searchQuery: string;
+ searchQuery: string;
+ // Line 14: onSearchChange: (query: string) => void;
+ onSearchChange: (query: string) => void;
+ // Line 15: totalResults: number;
+ totalResults: number;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function ShopFilters({
+ // Property or array item — trailing comma allowed in TypeScript
+ selectedCategory,
+ // Property or array item — trailing comma allowed in TypeScript
+ onCategoryChange,
+ // Property or array item — trailing comma allowed in TypeScript
+ sortBy,
+ // Property or array item — trailing comma allowed in TypeScript
+ onSortChange,
+ // Property or array item — trailing comma allowed in TypeScript
+ searchQuery,
+ // Property or array item — trailing comma allowed in TypeScript
+ onSearchChange,
+ // Property or array item — trailing comma allowed in TypeScript
+ totalResults,
+// Closing brace — end of block (function, if, object, JSX)
+}: ShopFiltersProps) {
+ // Custom hook — returns t() translator and current locale
+ const { t } = useTranslation();
+// (blank line — separates logical blocks for readability)
+ // Line 29: const categories: { value: Category | 'all'; label: strin...
+ const categories: { value: Category | 'all'; label: string }[] = [
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: 'all', label: t('shop.all') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: 'chicken', label: t('nav.chicken') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: 'beef', label: t('nav.beef') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: 'lamb', label: t('nav.lamb') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: 'fish', label: t('nav.fish') },
+ // End of array literal
+ ];
+// (blank line — separates logical blocks for readability)
+ // Line 37: const sortOptions: { value: SortOption; label: string }[]...
+ const sortOptions: { value: SortOption; label: string }[] = [
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: 'featured', label: t('shop.sortFeatured') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: 'price-asc', label: t('shop.sortPriceAsc') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: 'price-desc', label: t('shop.sortPriceDesc') },
+ // Property or array item — trailing comma allowed in TypeScript
+ { value: 'name', label: t('shop.sortName') },
+ // End of array literal
+ ];
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('shop.filters')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 52: {t('shop.productsFound', { count: totalResults })}
+ {t('shop.productsFound', { count: totalResults })}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+ onSearchChange(e.target.value)}
+ // Tailwind CSS utility classes — styling (colors, spacing, layout)
+ className="input-field"
+ // Line 67: />
+ />
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
{t('shop.category')}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Array.map — transform each item (often render a list of components)
+ {categories.map((cat) => (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 86: ))}
+ ))}
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+// (blank line — separates logical blocks for readability)
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 108: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/ui/AppImage.annotated.tsx b/docs/annotated/src/components/ui/AppImage.annotated.tsx
new file mode 100644
index 0000000..138aaf4
--- /dev/null
+++ b/docs/annotated/src/components/ui/AppImage.annotated.tsx
@@ -0,0 +1,25 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/ui/AppImage.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js Image — optimized images (lazy load, WebP/AVIF)
+import Image, { ImageProps } from 'next/image';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { IMAGE_QUALITY } from '@/lib/images';
+// (blank line — separates logical blocks for readability)
+// TypeScript type alias — union or shorthand for complex types
+type AppImageProps = ImageProps & {
+ // Line 5: quality?: number;
+ quality?: number;
+// Closing brace — end of block (function, if, object, JSX)
+};
+// (blank line — separates logical blocks for readability)
+// Block comment — documents the file or function below
+/** Site-wide Image wrapper with consistent high quality defaults */
+// Default export — main component/page Next.js or other files import
+export default function AppImage({ quality = IMAGE_QUALITY, ...props }: AppImageProps) {
+ // Return value from function
+ return ;
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/components/ui/Button.annotated.tsx b/docs/annotated/src/components/ui/Button.annotated.tsx
new file mode 100644
index 0000000..2597ddc
--- /dev/null
+++ b/docs/annotated/src/components/ui/Button.annotated.tsx
@@ -0,0 +1,76 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/ui/Button.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { cn } from '@/lib/utils';
+// Import React — core UI library (components, hooks, JSX)
+import { ButtonHTMLAttributes, forwardRef } from 'react';
+// (blank line — separates logical blocks for readability)
+// TypeScript interface — contract for object properties and methods
+interface ButtonProps extends ButtonHTMLAttributes {
+ // Line 5: variant?: 'primary' | 'secondary' | 'gold' | 'ghost';
+ variant?: 'primary' | 'secondary' | 'gold' | 'ghost';
+ // Line 6: size?: 'sm' | 'md' | 'lg';
+ size?: 'sm' | 'md' | 'lg';
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Line 9: const Button = forwardRef(
+const Button = forwardRef(
+ // Line 10: ({ className, variant = 'primary', size = 'md', children,...
+ ({ className, variant = 'primary', size = 'md', children, ...props }, ref) => {
+ // Line 11: const variants = {
+ const variants = {
+ // Property or array item — trailing comma allowed in TypeScript
+ primary: 'btn-primary',
+ // Property or array item — trailing comma allowed in TypeScript
+ secondary: 'btn-secondary',
+ // Property or array item — trailing comma allowed in TypeScript
+ gold: 'btn-gold',
+ // Line 15: ghost:
+ ghost:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'inline-flex items-center justify-center gap-2 rounded-lg px-4 py-2 text-sm font-medium text-gray-600 transition-colors hover:bg-gray-100 hover:text-brand-700',
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // Line 19: const sizes = {
+ const sizes = {
+ // Property or array item — trailing comma allowed in TypeScript
+ sm: 'px-4 py-2 text-xs',
+ // Property or array item — trailing comma allowed in TypeScript
+ md: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ lg: 'px-8 py-4 text-base',
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// (blank line — separates logical blocks for readability)
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 33: );
+ );
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// Line 35: );
+);
+// (blank line — separates logical blocks for readability)
+// Line 37: Button.displayName = 'Button';
+Button.displayName = 'Button';
+// Line 38: export default Button;
+export default Button;
diff --git a/docs/annotated/src/components/ui/Logo.annotated.tsx b/docs/annotated/src/components/ui/Logo.annotated.tsx
new file mode 100644
index 0000000..97448fe
--- /dev/null
+++ b/docs/annotated/src/components/ui/Logo.annotated.tsx
@@ -0,0 +1,74 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/components/ui/Logo.tsx
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import project module (@/ alias = src/ folder in tsconfig)
+import AppImage from '@/components/ui/AppImage';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { IMAGES } from '@/lib/images';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { cn } from '@/lib/utils';
+// (blank line — separates logical blocks for readability)
+// TypeScript interface — contract for object properties and methods
+interface LogoProps {
+ // Line 6: size?: 'sm' | 'md' | 'lg';
+ size?: 'sm' | 'md' | 'lg';
+ // Line 7: className?: string;
+ className?: string;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Line 10: const sizes = {
+const sizes = {
+ // Property or array item — trailing comma allowed in TypeScript
+ sm: 'h-10 w-10',
+ // Property or array item — trailing comma allowed in TypeScript
+ md: 'h-12 w-12',
+ // Property or array item — trailing comma allowed in TypeScript
+ lg: 'h-20 w-20',
+// Closing brace — end of block (function, if, object, JSX)
+};
+// (blank line — separates logical blocks for readability)
+// Default export — main component/page Next.js or other files import
+export default function Logo({ size = 'md', className }: LogoProps) {
+ // Return JSX — describes UI tree React renders to the DOM
+ return (
+ // JSX element — HTML-like tag becomes React component in browser
+
+ >
+ // JSX element — HTML-like tag becomes React component in browser
+
+ />
+ // JSX element — HTML-like tag becomes React component in browser
+
+ // Line 35: );
+ );
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/hooks/useTranslation.annotated.ts b/docs/annotated/src/hooks/useTranslation.annotated.ts
new file mode 100644
index 0000000..b053e14
--- /dev/null
+++ b/docs/annotated/src/hooks/useTranslation.annotated.ts
@@ -0,0 +1,27 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/hooks/useTranslation.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Next.js: this file runs in the BROWSER (needs useState, onClick, localStorage, etc.)
+'use client';
+// (blank line — separates logical blocks for readability)
+// Import React — core UI library (components, hooks, JSX)
+import { useMemo } from 'react';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { createTranslator } from '@/i18n';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { useLocaleStore } from '@/store/locale';
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function useTranslation() {
+ // Zustand selector — subscribe to slice of global store
+ const locale = useLocaleStore((s) => s.locale);
+// (blank line — separates logical blocks for readability)
+ // React useMemo — cache expensive computed value until dependencies change
+ const t = useMemo(() => createTranslator(locale), [locale]);
+// (blank line — separates logical blocks for readability)
+ // Return value from function
+ return { t, locale };
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/i18n/index.annotated.ts b/docs/annotated/src/i18n/index.annotated.ts
new file mode 100644
index 0000000..65c21b3
--- /dev/null
+++ b/docs/annotated/src/i18n/index.annotated.ts
@@ -0,0 +1,85 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/i18n/index.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import from a relative file in the same project
+import { Locale, TranslationDict } from './types';
+// Import from a relative file in the same project
+import { en } from './locales/en';
+// Import from a relative file in the same project
+import { sv } from './locales/sv';
+// Import from a relative file in the same project
+import { ur } from './locales/ur';
+// (blank line — separates logical blocks for readability)
+// Line 6: const dictionaries: Record = { e...
+const dictionaries: Record = { en, sv, ur };
+// (blank line — separates logical blocks for readability)
+// Function declaration — reusable logic in this file
+function resolve(obj: TranslationDict, path: string): string {
+ // Line 9: const keys = path.split('.');
+ const keys = path.split('.');
+ // Line 10: let current: string | TranslationDict = obj;
+ let current: string | TranslationDict = obj;
+// (blank line — separates logical blocks for readability)
+ // Line 12: for (const key of keys) {
+ for (const key of keys) {
+ // Conditional branch — different behavior based on runtime value
+ if (typeof current !== 'object' || current === null || !(key in current)) {
+ // Return value from function
+ return path;
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Line 16: current = current[key];
+ current = current[key];
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Return value from function
+ return typeof current === 'string' ? current : path;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function createTranslator(locale: Locale) {
+ // Line 23: const dict = dictionaries[locale] ?? dictionaries.en;
+ const dict = dictionaries[locale] ?? dictionaries.en;
+// (blank line — separates logical blocks for readability)
+ // Return value from function
+ return function t(path: string, params?: Record): string {
+ // Line 26: let text = resolve(dict, path);
+ let text = resolve(dict, path);
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (params) {
+ // Line 29: Object.entries(params).forEach(([key, value]) => {
+ Object.entries(params).forEach(([key, value]) => {
+ // Line 30: text = text.replace(new RegExp(`\\{${key}\\}`, 'g'), Stri...
+ text = text.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value));
+ // Closing brace — end of block (function, if, object, JSX)
+ });
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+// (blank line — separates logical blocks for readability)
+ // Return value from function
+ return text;
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function isRtl(locale: Locale): boolean {
+ // Return value from function
+ return locale === 'ur';
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function getHtmlLang(locale: Locale): string {
+ // Line 43: const map: Record = { en: 'en', sv: 'sv',...
+ const map: Record = { en: 'en', sv: 'sv', ur: 'ur' };
+ // Return value from function
+ return map[locale];
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/i18n/locales/en.annotated.ts b/docs/annotated/src/i18n/locales/en.annotated.ts
new file mode 100644
index 0000000..57248d5
--- /dev/null
+++ b/docs/annotated/src/i18n/locales/en.annotated.ts
@@ -0,0 +1,934 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/i18n/locales/en.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import external package or local module
+import { TranslationDict } from '../types';
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const en: TranslationDict = {
+ // Line 4: site: {
+ site: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Kött Gård',
+ // Property or array item — trailing comma allowed in TypeScript
+ tagline: 'Premium Halal',
+ // Line 7: description:
+ description:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium 100% Halal meat delivery. Fresh and frozen chicken, beef, lamb, and fish — customized to your preference and delivered to your door.',
+ // Property or array item — trailing comma allowed in TypeScript
+ metaTitle: 'Premium Halal Meat Delivery',
+ // Property or array item — trailing comma allowed in TypeScript
+ initials: 'KG',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: 'hello@kottgard.se',
+ // Property or array item — trailing comma allowed in TypeScript
+ demoEmail: 'demo@kottgard.se',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 14: nav: {
+ nav: {
+ // Property or array item — trailing comma allowed in TypeScript
+ shop: 'Shop',
+ // Property or array item — trailing comma allowed in TypeScript
+ chicken: 'Chicken',
+ // Property or array item — trailing comma allowed in TypeScript
+ beef: 'Beef',
+ // Property or array item — trailing comma allowed in TypeScript
+ lamb: 'Lamb',
+ // Property or array item — trailing comma allowed in TypeScript
+ fish: 'Fish',
+ // Property or array item — trailing comma allowed in TypeScript
+ about: 'About Us',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalCert: 'Halal Certification',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery: 'Delivery Info',
+ // Property or array item — trailing comma allowed in TypeScript
+ contact: 'Contact',
+ // Property or array item — trailing comma allowed in TypeScript
+ myAccount: 'My Account',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderHistory: 'Order History',
+ // Property or array item — trailing comma allowed in TypeScript
+ wishlist: 'Wishlist',
+ // Property or array item — trailing comma allowed in TypeScript
+ cart: 'Cart',
+ // Property or array item — trailing comma allowed in TypeScript
+ privacy: 'Privacy Policy',
+ // Property or array item — trailing comma allowed in TypeScript
+ terms: 'Terms of Service',
+ // Property or array item — trailing comma allowed in TypeScript
+ searchProducts: 'Search products',
+ // Property or array item — trailing comma allowed in TypeScript
+ toggleMenu: 'Toggle menu',
+ // Property or array item — trailing comma allowed in TypeScript
+ account: 'Account',
+ // Property or array item — trailing comma allowed in TypeScript
+ language: 'Language',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 35: languageBanner: {
+ languageBanner: {
+ // Property or array item — trailing comma allowed in TypeScript
+ choose: 'Choose your language',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 38: hero: {
+ hero: {
+ // Property or array item — trailing comma allowed in TypeScript
+ badge: '100% Halal Certified',
+ // Property or array item — trailing comma allowed in TypeScript
+ taglineShort: 'Naturally Pure',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Premium Halal Meat',
+ // Property or array item — trailing comma allowed in TypeScript
+ titleHighlight: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ titleEnd: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitleShort: 'Fresh. Quality. Reliable.',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Halal certified · Fresh daily · Home delivery · Open every day',
+ // Property or array item — trailing comma allowed in TypeScript
+ hours: 'Open every day {hours}',
+ // Property or array item — trailing comma allowed in TypeScript
+ location: 'Tingvallavägen 11, Märsta',
+ // Property or array item — trailing comma allowed in TypeScript
+ shopNow: 'Browse Our Selection',
+ // Property or array item — trailing comma allowed in TypeScript
+ browseChicken: 'Browse Chicken',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'Order via WhatsApp',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 53: aboutPreview: {
+ aboutPreview: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'About Us',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: "Märsta's Finest Butcher Shop",
+ // Property or array item — trailing comma allowed in TypeScript
+ p1: 'Kött Gård is more than a butcher shop — we are a promise of quality. All our meat is 100% Halal certified and delivered fresh every day.',
+ // Property or array item — trailing comma allowed in TypeScript
+ p2: 'We source lamb from Ireland and New Zealand, chicken and beef from reputable producers, and help you find the right cut for dinner, celebrations, or Sunday roast.',
+ // Property or array item — trailing comma allowed in TypeScript
+ p3: 'Visit us at Tingvallavägen, tell us what you are looking for — we cut and pack to your specifications.',
+ // Property or array item — trailing comma allowed in TypeScript
+ statHalal: '100%',
+ // Property or array item — trailing comma allowed in TypeScript
+ statHalalLabel: 'Halal certified',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDays: '7 days',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDaysLabel: 'Open weekly',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDelivery: 'Daily',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDeliveryLabel: 'Delivery',
+ // Property or array item — trailing comma allowed in TypeScript
+ statFresh: 'Fresh',
+ // Property or array item — trailing comma allowed in TypeScript
+ statFreshLabel: 'Every day',
+ // Property or array item — trailing comma allowed in TypeScript
+ readMore: 'Read more about us',
+ // Property or array item — trailing comma allowed in TypeScript
+ imageAlt: 'Fresh meat cuts on a cutting board from Kött Gård',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 70: trust: {
+ trust: {
+ // Property or array item — trailing comma allowed in TypeScript
+ halal: '100% Halal',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalDesc: 'Certified halal sourcing with full traceability and compliance.',
+ // Property or array item — trailing comma allowed in TypeScript
+ fresh: 'Fresh Daily',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshDesc: 'Sourced fresh every morning and delivered at peak quality.',
+ // Property or array item — trailing comma allowed in TypeScript
+ premium: 'Premium Quality',
+ // Property or array item — trailing comma allowed in TypeScript
+ premiumDesc: 'Hand-selected cuts from trusted farms, prepared by expert butchers.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 78: categories: {
+ categories: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Our Selection',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitle: 'Hand-picked meat — every day. Fresh delivery. Halal. Cut to order.',
+ // Property or array item — trailing comma allowed in TypeScript
+ shop: 'Shop {name}',
+ // Line 82: chicken: {
+ chicken: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Chicken',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Breast fillet, wings, drumsticks and whole chicken. Fresh every morning.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 86: beef: {
+ beef: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Beef & Veal',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Mince, bone marrow and premium cuts. High marbling, consistent quality.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 90: lamb: {
+ lamb: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Lamb',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Shoulder, neck, roast and rack. From Ireland and New Zealand.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 94: fish: {
+ fish: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Fish',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Fresh catch, cleaned and ready to cook.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 99: featured: {
+ featured: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Curated Selection',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Featured Products',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitle: 'Our most popular cuts, loved by families across the city.',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewAll: 'View All',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 105: howItWorks: {
+ howItWorks: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Order',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'How easy it is to order',
+ // Property or array item — trailing comma allowed in TypeScript
+ step1Title: 'Contact us',
+ // Line 109: step1Desc:
+ step1Desc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Send us a WhatsApp message with what you want — we reply quickly.',
+ // Property or array item — trailing comma allowed in TypeScript
+ step2Title: 'We confirm',
+ // Line 112: step2Desc:
+ step2Desc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'We confirm your order, give you the price, and tell you when it is ready.',
+ // Property or array item — trailing comma allowed in TypeScript
+ step3Title: 'Pick up or delivery',
+ // Line 115: step3Desc:
+ step3Desc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Pick up in store at Tingvallavägen 11 or choose home delivery.',
+ // Property or array item — trailing comma allowed in TypeScript
+ step: 'Step {n}',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'Order on WhatsApp',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 120: offers: {
+ offers: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Order',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Weekly offers',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'We update regularly with fresh deals. Follow us on social media for the latest prices.',
+ // Property or array item — trailing comma allowed in TypeScript
+ disclaimer: 'Price valid while supplies last',
+ // Property or array item — trailing comma allowed in TypeScript
+ was: 'Was',
+ // Property or array item — trailing comma allowed in TypeScript
+ now: 'NOW',
+ // Property or array item — trailing comma allowed in TypeScript
+ order: 'Order',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewProduct: 'View product',
+ // Line 130: badge: {
+ badge: {
+ // Property or array item — trailing comma allowed in TypeScript
+ fresh: 'FRESH',
+ // Property or array item — trailing comma allowed in TypeScript
+ halal: 'HALAL',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 134: items: {
+ items: {
+ // Property or array item — trailing comma allowed in TypeScript
+ chickenWings: { name: 'Fresh chicken wings PL' },
+ // Property or array item — trailing comma allowed in TypeScript
+ lambSteak: { name: 'Fresh lamb roast Ireland' },
+ // Property or array item — trailing comma allowed in TypeScript
+ beefMince: { name: 'Beef mince 5% fat IRL' },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 140: social: {
+ social: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Follow us',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Follow us',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ '1,100+ followers on Facebook · 249 posts · Daily updates',
+ // Property or array item — trailing comma allowed in TypeScript
+ facebook: 'Facebook',
+ // Property or array item — trailing comma allowed in TypeScript
+ instagram: 'Instagram',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'WhatsApp',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 149: contact: {
+ contact: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Contact',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Visit us',
+ // Property or array item — trailing comma allowed in TypeScript
+ addressLabel: 'Address',
+ // Property or array item — trailing comma allowed in TypeScript
+ phoneLabel: 'Phone',
+ // Property or array item — trailing comma allowed in TypeScript
+ hoursLabel: 'Opening hours',
+ // Property or array item — trailing comma allowed in TypeScript
+ hoursValue: 'Every day: {hours}',
+ // Property or array item — trailing comma allowed in TypeScript
+ writeUs: 'Message us',
+ // Property or array item — trailing comma allowed in TypeScript
+ callUs: 'Call us',
+ // Property or array item — trailing comma allowed in TypeScript
+ openMaps: 'Open in Google Maps',
+ // Property or array item — trailing comma allowed in TypeScript
+ learnMore: 'Contact details',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 161: cta: {
+ cta: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Ready for Premium Halal Meat?',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Order today and experience the difference of truly fresh, customized halal meat delivered to your doorstep.',
+ // Property or array item — trailing comma allowed in TypeScript
+ button: 'Browse Our Selection',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'Order on WhatsApp',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 168: shop: {
+ shop: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Shop All Products',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitle: 'Premium halal meat, customized to your preference',
+ // Property or array item — trailing comma allowed in TypeScript
+ noProducts: 'No products found',
+ // Property or array item — trailing comma allowed in TypeScript
+ noProductsHint: 'Try adjusting your filters or search query',
+ // Property or array item — trailing comma allowed in TypeScript
+ filters: 'Filters',
+ // Property or array item — trailing comma allowed in TypeScript
+ productsFound: '{count} products found',
+ // Property or array item — trailing comma allowed in TypeScript
+ search: 'Search',
+ // Property or array item — trailing comma allowed in TypeScript
+ searchPlaceholder: 'Search products...',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'Category',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortBy: 'Sort By',
+ // Property or array item — trailing comma allowed in TypeScript
+ all: 'All',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortFeatured: 'Featured',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortPriceAsc: 'Price: Low to High',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortPriceDesc: 'Price: High to Low',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortName: 'Name A–Z',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 185: product: {
+ product: {
+ // Property or array item — trailing comma allowed in TypeScript
+ backToShop: 'Back to Shop',
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: 'In Stock',
+ // Property or array item — trailing comma allowed in TypeScript
+ outOfStock: 'Out of Stock',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalTrust: '100% Halal certified · Fresh daily · Premium quality',
+ // Property or array item — trailing comma allowed in TypeScript
+ yourSelection: 'Your selection',
+ // Property or array item — trailing comma allowed in TypeScript
+ aboutProduct: 'About This Product',
+ // Property or array item — trailing comma allowed in TypeScript
+ addToCart: 'Add to Cart',
+ // Property or array item — trailing comma allowed in TypeScript
+ addedToCart: 'Added to Cart',
+ // Property or array item — trailing comma allowed in TypeScript
+ decreaseQty: 'Decrease quantity',
+ // Property or array item — trailing comma allowed in TypeScript
+ increaseQty: 'Increase quantity',
+ // Property or array item — trailing comma allowed in TypeScript
+ removeWishlist: 'Remove from wishlist',
+ // Property or array item — trailing comma allowed in TypeScript
+ addWishlist: 'Add to wishlist',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewProduct: 'View {name}',
+ // Property or array item — trailing comma allowed in TypeScript
+ pieces: '{count} pieces',
+ // Property or array item — trailing comma allowed in TypeScript
+ standardCut: 'Standard cut',
+ // Property or array item — trailing comma allowed in TypeScript
+ howManyCuts: 'How Many Cuts Do You Want?',
+ // Property or array item — trailing comma allowed in TypeScript
+ howManyCutsHint: 'Select the number of cuts for your order',
+ // Property or array item — trailing comma allowed in TypeScript
+ cutsAndStyle: '{cuts} cuts · {style}',
+ // Property or array item — trailing comma allowed in TypeScript
+ selectCutting: 'Select Cutting Style',
+ // Property or array item — trailing comma allowed in TypeScript
+ selectCuttingHint: 'Our butchers will prepare your {category} exactly to your preferred cut',
+ // Line 206: fishNote:
+ fishNote:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Fish products are prepared with our standard professional cut — cleaned, scaled, and ready to cook.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 209: cutting: {
+ cutting: {
+ // Property or array item — trailing comma allowed in TypeScript
+ nihari: 'Nihari cut',
+ // Property or array item — trailing comma allowed in TypeScript
+ karahi: 'Karahi cut',
+ // Property or array item — trailing comma allowed in TypeScript
+ qeema: 'Qeema (minced)',
+ // Property or array item — trailing comma allowed in TypeScript
+ boneless: 'Boneless',
+ // Property or array item — trailing comma allowed in TypeScript
+ steak: 'Steak cut',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 216: priceUnit: {
+ priceUnit: {
+ // Property or array item — trailing comma allowed in TypeScript
+ perBird: 'per bird',
+ // Property or array item — trailing comma allowed in TypeScript
+ perPack: 'per pack',
+ // Property or array item — trailing comma allowed in TypeScript
+ perKg: 'per kg',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 221: badges: {
+ badges: {
+ // Property or array item — trailing comma allowed in TypeScript
+ bestseller: 'Bestseller',
+ // Property or array item — trailing comma allowed in TypeScript
+ chefsPick: "Chef's Pick",
+ // Property or array item — trailing comma allowed in TypeScript
+ premium: 'Premium',
+ // Property or array item — trailing comma allowed in TypeScript
+ popular: 'Popular',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshCatch: 'Fresh Catch',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 228: products: {
+ products: {
+ // Line 229: 'chicken-whole': {
+ 'chicken-whole': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Whole Chicken',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Farm-fresh whole halal chicken, perfect for roasting or curry.',
+ // Line 232: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Our whole chickens are sourced from certified halal farms and delivered at peak freshness. Each bird is hand-selected for quality, with tender meat and clean processing. Choose your preferred piece count and we will prepare it exactly how you need.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 235: 'chicken-breast': {
+ 'chicken-breast': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Chicken Breast',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Lean, boneless chicken breast — ideal for grilling and healthy meals.',
+ // Line 238: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium boneless chicken breast, trimmed and ready to cook. Perfect for kebabs, stir-fries, and healthy weeknight dinners. Select your piece count and enjoy consistent quality every time.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 241: 'chicken-thighs': {
+ 'chicken-thighs': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Chicken Thighs',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Juicy halal chicken thighs with rich flavor for curries and grills.',
+ // Line 244: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Our chicken thighs are known for their succulence and depth of flavor. Whether you are making a traditional karahi or a weekend BBQ, these thighs deliver every time.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 247: 'chicken-wings': {
+ 'chicken-wings': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Chicken Wings',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Party-ready halal chicken wings for frying, baking, or grilling.',
+ // Line 250: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Crispy, flavorful chicken wings prepared halal and delivered fresh. A crowd favorite for game nights and family gatherings.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 253: 'beef-nihari': {
+ 'beef-nihari': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Beef for Nihari',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Slow-cook ready beef cuts, perfect for traditional nihari.',
+ // Line 256: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Specially selected beef cuts ideal for slow-cooked nihari. Rich in collagen and flavor, these cuts break down beautifully over hours of simmering for an authentic, melt-in-your-mouth experience.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 259: 'beef-steak': {
+ 'beef-steak': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Premium Beef Steak',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Restaurant-quality halal steak cuts for the perfect sear.',
+ // Line 262: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Hand-cut premium beef steaks from the finest halal sources. Marbled, tender, and ready for your grill or cast-iron pan. Choose your preferred cutting style.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 265: 'beef-mince': {
+ 'beef-mince': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Beef Mince',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Fresh halal beef mince for kebabs, burgers, and qeema.',
+ // Line 268: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Finely ground halal beef mince with the perfect fat ratio for juicy kebabs, flavorful qeema, and homemade burgers. Ground fresh daily.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 271: 'beef-boneless': {
+ 'beef-boneless': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Boneless Beef Cubes',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Versatile boneless beef cubes for karahi, biryani, and stews.',
+ // Line 274: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Uniform boneless beef cubes cut to perfection for quick-cooking dishes. Ideal for karahi, pulao, and stir-fries where consistent sizing matters.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 277: 'lamb-shoulder': {
+ 'lamb-shoulder': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Lamb Shoulder',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Rich, flavorful lamb shoulder for slow roasts and curries.',
+ // Line 280: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium halal lamb shoulder with beautiful marbling. Perfect for slow-roasted feasts, hearty curries, and traditional family meals. Customized to your preferred cut.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 283: 'lamb-leg': {
+ 'lamb-leg': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Lamb Leg',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Tender lamb leg for roasts, grills, and special occasions.',
+ // Line 286: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Whole or portioned lamb leg from certified halal sources. A centerpiece cut for Eid celebrations, dinner parties, and Sunday roasts.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 289: 'lamb-chops': {
+ 'lamb-chops': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Lamb Chops',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Premium lamb chops for grilling and fine dining at home.',
+ // Line 292: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Thick-cut halal lamb chops with perfect fat caps for grilling. Restaurant quality, delivered to your kitchen.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 295: 'lamb-mince': {
+ 'lamb-mince': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Lamb Mince',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Fresh halal lamb mince for kebabs, samosas, and qeema.',
+ // Line 298: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Finely ground lamb mince with rich flavor. Essential for seekh kebabs, lamb qeema, and stuffed parathas.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 301: 'fish-salmon': {
+ 'fish-salmon': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Atlantic Salmon Fillet',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Buttery salmon fillets, skin-on and ready to pan-sear.',
+ // Line 304: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium Atlantic salmon fillets with rich omega-3 content. Cleaned, portioned, and vacuum-sealed for maximum freshness.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 307: 'fish-rohu': {
+ 'fish-rohu': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Rohu Fish',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Whole rohu fish, cleaned and scaled — a South Asian favorite.',
+ // Line 310: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Fresh rohu fish, a staple in South Asian cuisine. Cleaned, scaled, and gutted. Perfect for fish curry, fried fish, and traditional recipes.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 313: 'fish-prawns': {
+ 'fish-prawns': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Jumbo Prawns',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Large shell-on prawns for grilling, curries, and biryanis.',
+ // Line 316: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium jumbo prawns, deveined and ready to cook. Sweet, firm flesh that holds up beautifully in curries and tandoori preparations.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 319: 'fish-basa': {
+ 'fish-basa': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Basa Fillet',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Mild, flaky basa fillets — perfect for beginners and kids.',
+ // Line 322: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Boneless basa fillets with a mild, delicate flavor. Easy to cook and versatile — great for fish tacos, baking, and light curries.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 326: cart: {
+ cart: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Your Cart',
+ // Property or array item — trailing comma allowed in TypeScript
+ itemsCount: '{count} item(s) in your cart',
+ // Property or array item — trailing comma allowed in TypeScript
+ empty: 'Your cart is empty',
+ // Property or array item — trailing comma allowed in TypeScript
+ emptyHint: 'Browse our premium halal selection and add items to your cart.',
+ // Property or array item — trailing comma allowed in TypeScript
+ startShopping: 'Start Shopping',
+ // Property or array item — trailing comma allowed in TypeScript
+ customization: 'Customization:',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderSummary: 'Order Summary',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtotal: 'Subtotal',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery: 'Delivery',
+ // Property or array item — trailing comma allowed in TypeScript
+ free: 'Free',
+ // Property or array item — trailing comma allowed in TypeScript
+ freeDeliveryHint: 'Free delivery on orders over 500 kr',
+ // Property or array item — trailing comma allowed in TypeScript
+ total: 'Total',
+ // Property or array item — trailing comma allowed in TypeScript
+ proceedCheckout: 'Proceed to Checkout',
+ // Property or array item — trailing comma allowed in TypeScript
+ continueShopping: 'Continue Shopping',
+ // Property or array item — trailing comma allowed in TypeScript
+ removeItem: 'Remove item',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 343: checkout: {
+ checkout: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Secure Checkout',
+ // Property or array item — trailing comma allowed in TypeScript
+ backToCart: 'Back to Cart',
+ // Property or array item — trailing comma allowed in TypeScript
+ noItems: 'No items to checkout',
+ // Property or array item — trailing comma allowed in TypeScript
+ goToShop: 'Go to Shop',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderConfirmed: 'Order Confirmed!',
+ // Property or array item — trailing comma allowed in TypeScript
+ thankYou: 'Thank you for your order. Your premium halal meat is being prepared.',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderId: 'Order ID: {id}',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewOrders: 'View Orders',
+ // Property or array item — trailing comma allowed in TypeScript
+ haveAccount: 'Have an account?',
+ // Property or array item — trailing comma allowed in TypeScript
+ signIn: 'Sign in',
+ // Property or array item — trailing comma allowed in TypeScript
+ fasterCheckout: 'for faster checkout.',
+ // Property or array item — trailing comma allowed in TypeScript
+ deliveryDetails: 'Delivery Details',
+ // Property or array item — trailing comma allowed in TypeScript
+ fullName: 'Full Name',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: 'Email',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: 'Phone',
+ // Property or array item — trailing comma allowed in TypeScript
+ street: 'Street Address',
+ // Property or array item — trailing comma allowed in TypeScript
+ city: 'City',
+ // Property or array item — trailing comma allowed in TypeScript
+ state: 'State',
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: 'ZIP Code',
+ // Property or array item — trailing comma allowed in TypeScript
+ payment: 'Payment',
+ // Property or array item — trailing comma allowed in TypeScript
+ creditCard: 'Credit Card',
+ // Property or array item — trailing comma allowed in TypeScript
+ cashOnDelivery: 'Cash on Delivery',
+ // Property or array item — trailing comma allowed in TypeScript
+ cardNumber: 'Card Number',
+ // Property or array item — trailing comma allowed in TypeScript
+ expiry: 'Expiry',
+ // Property or array item — trailing comma allowed in TypeScript
+ cvv: 'CVV',
+ // Property or array item — trailing comma allowed in TypeScript
+ qty: 'Qty: {count}',
+ // Property or array item — trailing comma allowed in TypeScript
+ processing: 'Processing...',
+ // Property or array item — trailing comma allowed in TypeScript
+ pay: 'Pay {amount}',
+ // Property or array item — trailing comma allowed in TypeScript
+ secure: 'Secure 256-bit SSL encryption',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 374: auth: {
+ auth: {
+ // Property or array item — trailing comma allowed in TypeScript
+ welcomeBack: 'Welcome Back',
+ // Property or array item — trailing comma allowed in TypeScript
+ createAccount: 'Create Account',
+ // Property or array item — trailing comma allowed in TypeScript
+ joinTagline: 'Join {name} for a premium shopping experience',
+ // Property or array item — trailing comma allowed in TypeScript
+ signInTagline: 'Sign in to your {name} account',
+ // Property or array item — trailing comma allowed in TypeScript
+ fullName: 'Full Name',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: 'Email',
+ // Property or array item — trailing comma allowed in TypeScript
+ password: 'Password',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: 'Phone',
+ // Property or array item — trailing comma allowed in TypeScript
+ street: 'Street Address',
+ // Property or array item — trailing comma allowed in TypeScript
+ city: 'City',
+ // Property or array item — trailing comma allowed in TypeScript
+ state: 'State',
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: 'ZIP Code',
+ // Property or array item — trailing comma allowed in TypeScript
+ signIn: 'Sign In',
+ // Property or array item — trailing comma allowed in TypeScript
+ register: 'Create Account',
+ // Property or array item — trailing comma allowed in TypeScript
+ hasAccount: 'Already have an account? Sign in',
+ // Property or array item — trailing comma allowed in TypeScript
+ noAccount: "Don't have an account? Register",
+ // Property or array item — trailing comma allowed in TypeScript
+ invalidCredentials: 'Invalid email or password. Try {email} / demo123',
+ // Property or array item — trailing comma allowed in TypeScript
+ demo: 'Demo: {email} / demo123',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 394: account: {
+ account: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'My Account',
+ // Property or array item — trailing comma allowed in TypeScript
+ welcome: 'Welcome back, {name}',
+ // Property or array item — trailing comma allowed in TypeScript
+ memberSince: 'Member since {date}',
+ // Property or array item — trailing comma allowed in TypeScript
+ myWishlist: 'My Wishlist',
+ // Property or array item — trailing comma allowed in TypeScript
+ signOut: 'Sign Out',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderHistory: 'Order History',
+ // Property or array item — trailing comma allowed in TypeScript
+ noOrders: 'No orders yet',
+ // Property or array item — trailing comma allowed in TypeScript
+ startShopping: 'Start Shopping',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 404: wishlist: {
+ wishlist: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'My Wishlist',
+ // Property or array item — trailing comma allowed in TypeScript
+ saved: '{count} saved item(s)',
+ // Property or array item — trailing comma allowed in TypeScript
+ empty: 'Your wishlist is empty',
+ // Property or array item — trailing comma allowed in TypeScript
+ emptyHint: 'Save your favorite products to buy them later.',
+ // Property or array item — trailing comma allowed in TypeScript
+ browse: 'Browse Products',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 411: about: {
+ about: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'About {name}',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Bringing premium, 100% Halal meat to your table — fresh, customized, and delivered with care.',
+ // Property or array item — trailing comma allowed in TypeScript
+ ourStory: 'Our Story',
+ // Line 416: storyP1:
+ storyP1:
+ // Property or array item — trailing comma allowed in TypeScript
+ '{name} was founded with a simple mission: make premium halal meat accessible to every family, without compromising on quality, freshness, or religious compliance. We understand that for many households, the right cut prepared the right way is not a luxury — it is essential.',
+ // Line 418: storyP2:
+ storyP2:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'From selecting piece counts for chicken to choosing Nihari or Karahi cuts for beef and lamb, we put customization at the heart of every order. Our expert butchers prepare each order by hand, and our temperature-controlled delivery ensures your meat arrives as fresh as the day it was cut.',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalTitle: 'Halal Certification',
+ // Line 421: halalDesc:
+ halalDesc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Every product at {name} is sourced from certified halal suppliers. Our supply chain is fully traceable, and we maintain strict compliance with halal slaughter and processing standards. We work exclusively with farms and processors that share our commitment to ethical, religiously compliant meat production.',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshDaily: 'Fresh Daily',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshDailyDesc: 'Sourced every morning from trusted farms',
+ // Property or array item — trailing comma allowed in TypeScript
+ premiumQuality: 'Premium Quality',
+ // Property or array item — trailing comma allowed in TypeScript
+ premiumQualityDesc: 'Hand-selected cuts by expert butchers',
+ // Property or array item — trailing comma allowed in TypeScript
+ fastDelivery: 'Fast Delivery',
+ // Property or array item — trailing comma allowed in TypeScript
+ fastDeliveryDesc: 'Temperature-controlled same-day delivery',
+ // Property or array item — trailing comma allowed in TypeScript
+ deliveryTitle: 'Delivery Information',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery1: 'We deliver within a 25-mile radius of our processing facility.',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery2: 'Orders placed before 2 PM are eligible for same-day delivery.',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery3: 'Free delivery on orders over 500 kr. Standard delivery fee: 49 kr.',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery4: 'All products are vacuum-sealed and transported in insulated packaging.',
+ // Property or array item — trailing comma allowed in TypeScript
+ contactTitle: 'Contact Us',
+ // Property or array item — trailing comma allowed in TypeScript
+ address: 'Tingvallavägen 11, 195 31 Märsta',
+ // Property or array item — trailing comma allowed in TypeScript
+ privacyTitle: 'Privacy Policy',
+ // Line 437: privacyText:
+ privacyText:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'We collect only the information needed to process your orders and improve our service — name, contact details, and delivery address. We do not sell your data to third parties. Payment details are handled securely by our payment partners.',
+ // Property or array item — trailing comma allowed in TypeScript
+ termsTitle: 'Terms of Service',
+ // Line 440: termsText:
+ termsText:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'All prices are shown in SEK and may change without notice. Orders are subject to availability. Halal certification applies to all meat products listed. Delivery times are estimates and may vary during peak periods.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 443: footer: {
+ footer: {
+ // Line 444: tagline:
+ tagline:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium 100% Halal meat delivery. Fresh, customized cuts delivered to your door with uncompromising quality.',
+ // Property or array item — trailing comma allowed in TypeScript
+ shop: 'Shop',
+ // Property or array item — trailing comma allowed in TypeScript
+ company: 'Company',
+ // Property or array item — trailing comma allowed in TypeScript
+ contact: 'Contact',
+ // Property or array item — trailing comma allowed in TypeScript
+ rights: 'All rights reserved.',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: '072-585 50 50',
+ // Property or array item — trailing comma allowed in TypeScript
+ hours: 'Open every day {hours}',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 453: notFound: {
+ notFound: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: '404',
+ // Property or array item — trailing comma allowed in TypeScript
+ message: 'Page not found',
+ // Property or array item — trailing comma allowed in TypeScript
+ goHome: 'Go Home',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 458: orderStatus: {
+ orderStatus: {
+ // Property or array item — trailing comma allowed in TypeScript
+ pending: 'pending',
+ // Property or array item — trailing comma allowed in TypeScript
+ confirmed: 'confirmed',
+ // Property or array item — trailing comma allowed in TypeScript
+ preparing: 'preparing',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'out-for-delivery': 'out for delivery',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivered: 'delivered',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// Closing brace — end of block (function, if, object, JSX)
+};
diff --git a/docs/annotated/src/i18n/locales/sv.annotated.ts b/docs/annotated/src/i18n/locales/sv.annotated.ts
new file mode 100644
index 0000000..b4b824a
--- /dev/null
+++ b/docs/annotated/src/i18n/locales/sv.annotated.ts
@@ -0,0 +1,934 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/i18n/locales/sv.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import external package or local module
+import { TranslationDict } from '../types';
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const sv: TranslationDict = {
+ // Line 4: site: {
+ site: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Kött Gård',
+ // Property or array item — trailing comma allowed in TypeScript
+ tagline: 'Premium Halal',
+ // Line 7: description:
+ description:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium 100 % halal köttleverans. Färskt och fryst kyckling, nötkött, lamm och fisk — anpassat efter dina önskemål och levererat till din dörr.',
+ // Property or array item — trailing comma allowed in TypeScript
+ metaTitle: 'Premium Halal Köttleverans',
+ // Property or array item — trailing comma allowed in TypeScript
+ initials: 'KG',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: 'hello@kottgard.se',
+ // Property or array item — trailing comma allowed in TypeScript
+ demoEmail: 'demo@kottgard.se',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 14: nav: {
+ nav: {
+ // Property or array item — trailing comma allowed in TypeScript
+ shop: 'Butik',
+ // Property or array item — trailing comma allowed in TypeScript
+ chicken: 'Kyckling',
+ // Property or array item — trailing comma allowed in TypeScript
+ beef: 'Nötkött',
+ // Property or array item — trailing comma allowed in TypeScript
+ lamb: 'Lamm',
+ // Property or array item — trailing comma allowed in TypeScript
+ fish: 'Fisk',
+ // Property or array item — trailing comma allowed in TypeScript
+ about: 'Om oss',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalCert: 'Halalcertifiering',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery: 'Leveransinfo',
+ // Property or array item — trailing comma allowed in TypeScript
+ contact: 'Kontakt',
+ // Property or array item — trailing comma allowed in TypeScript
+ myAccount: 'Mitt konto',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderHistory: 'Orderhistorik',
+ // Property or array item — trailing comma allowed in TypeScript
+ wishlist: 'Önskelista',
+ // Property or array item — trailing comma allowed in TypeScript
+ cart: 'Varukorg',
+ // Property or array item — trailing comma allowed in TypeScript
+ privacy: 'Integritetspolicy',
+ // Property or array item — trailing comma allowed in TypeScript
+ terms: 'Användarvillkor',
+ // Property or array item — trailing comma allowed in TypeScript
+ searchProducts: 'Sök produkter',
+ // Property or array item — trailing comma allowed in TypeScript
+ toggleMenu: 'Växla meny',
+ // Property or array item — trailing comma allowed in TypeScript
+ account: 'Konto',
+ // Property or array item — trailing comma allowed in TypeScript
+ language: 'Språk',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 35: languageBanner: {
+ languageBanner: {
+ // Property or array item — trailing comma allowed in TypeScript
+ choose: 'Välj språk',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 38: hero: {
+ hero: {
+ // Property or array item — trailing comma allowed in TypeScript
+ badge: '100 % Halal-certifierat',
+ // Property or array item — trailing comma allowed in TypeScript
+ taglineShort: 'Naturligt Rent',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Premium Halal Kött',
+ // Property or array item — trailing comma allowed in TypeScript
+ titleHighlight: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ titleEnd: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitleShort: 'Färskt. Kvalitet. Tillförlitligt.',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Halal-certifierat · Färskt dagligen · Hemleverans · Öppet alla dagar',
+ // Property or array item — trailing comma allowed in TypeScript
+ hours: 'Öppet alla dagar {hours}',
+ // Property or array item — trailing comma allowed in TypeScript
+ location: 'Tingvallavägen 11, Märsta',
+ // Property or array item — trailing comma allowed in TypeScript
+ shopNow: 'Se vårt sortiment',
+ // Property or array item — trailing comma allowed in TypeScript
+ browseChicken: 'Bläddra kyckling',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'Beställ via WhatsApp',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 53: aboutPreview: {
+ aboutPreview: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Om oss',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Märstas finaste köttbutik',
+ // Property or array item — trailing comma allowed in TypeScript
+ p1: 'Kött Gård är mer än en köttbutik — vi är ett löfte om kvalitet. Allt vårt kött är 100 % Halal-certifierat och färskt levererat varje dag.',
+ // Property or array item — trailing comma allowed in TypeScript
+ p2: 'Vi handlar lamm från Irland och Nya Zeeland, kyckling och nötkött från välrenommerade producenter, och hjälper dig hitta rätt detalj för middagen, festen eller söndagssteken.',
+ // Property or array item — trailing comma allowed in TypeScript
+ p3: 'Kom in i butiken på Tingvallavägen, prata med oss om vad du letar efter — vi styckar och packar efter dina önskemål.',
+ // Property or array item — trailing comma allowed in TypeScript
+ statHalal: '100 %',
+ // Property or array item — trailing comma allowed in TypeScript
+ statHalalLabel: 'Halal-certifierat',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDays: '7 dagar',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDaysLabel: 'Öppet i veckan',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDelivery: 'Daglig',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDeliveryLabel: 'Leverans',
+ // Property or array item — trailing comma allowed in TypeScript
+ statFresh: 'Färskt',
+ // Property or array item — trailing comma allowed in TypeScript
+ statFreshLabel: 'Varje dag',
+ // Property or array item — trailing comma allowed in TypeScript
+ readMore: 'Läs mer om oss',
+ // Property or array item — trailing comma allowed in TypeScript
+ imageAlt: 'Färska köttdetaljer på skärbräda från Kött Gård',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 70: trust: {
+ trust: {
+ // Property or array item — trailing comma allowed in TypeScript
+ halal: '100 % Halal',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalDesc: 'Certifierad halal-källa med full spårbarhet och efterlevnad.',
+ // Property or array item — trailing comma allowed in TypeScript
+ fresh: 'Färskt Dagligen',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshDesc: 'Hämtas färskt varje morgon och levereras i toppskick.',
+ // Property or array item — trailing comma allowed in TypeScript
+ premium: 'Premiumkvalitet',
+ // Property or array item — trailing comma allowed in TypeScript
+ premiumDesc: 'Handplockade styckningar från betrodda gårdar, förberedda av expertslaktare.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 78: categories: {
+ categories: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Vårt sortiment',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitle: 'Handplockat kött — varje dag. Färskt levererat. Halal. Styckat efter önskemål.',
+ // Property or array item — trailing comma allowed in TypeScript
+ shop: 'Handla {name}',
+ // Line 82: chicken: {
+ chicken: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Kyckling',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Kycklingbröstfilé, vingar, klubba och hel kyckling. Färsk varje morgon.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 86: beef: {
+ beef: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Nötkött & Kalv',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Nötfärs, kalv bone marrow och premiumskär. Hög marmorering, jämn kvalitet.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 90: lamb: {
+ lamb: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Lamm',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Lammbringa, lammhals, lammstek och lammrygg. Från Irland och Nya Zeeland.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 94: fish: {
+ fish: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Fisk',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Färsk fångst, rengjord och redo att tillagas.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 99: featured: {
+ featured: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Utvalt Sortiment',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Utvalda Produkter',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitle: 'Våra mest populära styckningar, älskade av familjer i hela staden.',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewAll: 'Visa alla',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 105: howItWorks: {
+ howItWorks: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Beställ',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Så enkelt beställer du',
+ // Property or array item — trailing comma allowed in TypeScript
+ step1Title: 'Kontakta oss',
+ // Line 109: step1Desc:
+ step1Desc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Skicka ett meddelande på WhatsApp med vad du vill ha — vi svarar snabbt.',
+ // Property or array item — trailing comma allowed in TypeScript
+ step2Title: 'Vi bekräftar',
+ // Line 112: step2Desc:
+ step2Desc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Vi bekräftar din beställning, ger pris och säger när den är klar.',
+ // Property or array item — trailing comma allowed in TypeScript
+ step3Title: 'Hämta eller leverans',
+ // Line 115: step3Desc:
+ step3Desc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Hämta i butik på Tingvallavägen 11 eller välj hemleverans.',
+ // Property or array item — trailing comma allowed in TypeScript
+ step: 'Steg {n}',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'Beställ på WhatsApp',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 120: offers: {
+ offers: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Beställ',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Veckans erbjudanden',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Vi uppdaterar löpande med färska erbjudanden. Följ oss på sociala medier för senaste priserna.',
+ // Property or array item — trailing comma allowed in TypeScript
+ disclaimer: 'Pris gäller så långt lagret räcker',
+ // Property or array item — trailing comma allowed in TypeScript
+ was: 'Före',
+ // Property or array item — trailing comma allowed in TypeScript
+ now: 'NU',
+ // Property or array item — trailing comma allowed in TypeScript
+ order: 'Beställ',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewProduct: 'Visa produkt',
+ // Line 130: badge: {
+ badge: {
+ // Property or array item — trailing comma allowed in TypeScript
+ fresh: 'FÄRSK',
+ // Property or array item — trailing comma allowed in TypeScript
+ halal: 'HALAL',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 134: items: {
+ items: {
+ // Property or array item — trailing comma allowed in TypeScript
+ chickenWings: { name: 'Kycklingvingar färsk PL' },
+ // Property or array item — trailing comma allowed in TypeScript
+ lambSteak: { name: 'Lammstek färsk Ireland' },
+ // Property or array item — trailing comma allowed in TypeScript
+ beefMince: { name: 'Nötfärs 5% fett IRL' },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 140: social: {
+ social: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Följ oss',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Följ oss',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ '1 100+ följare på Facebook · 249 inlägg · Dagliga uppdateringar',
+ // Property or array item — trailing comma allowed in TypeScript
+ facebook: 'Facebook',
+ // Property or array item — trailing comma allowed in TypeScript
+ instagram: 'Instagram',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'WhatsApp',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 149: contact: {
+ contact: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'Kontakt',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Besök oss',
+ // Property or array item — trailing comma allowed in TypeScript
+ addressLabel: 'Adress',
+ // Property or array item — trailing comma allowed in TypeScript
+ phoneLabel: 'Telefon',
+ // Property or array item — trailing comma allowed in TypeScript
+ hoursLabel: 'Öppettider',
+ // Property or array item — trailing comma allowed in TypeScript
+ hoursValue: 'Alla dagar: {hours}',
+ // Property or array item — trailing comma allowed in TypeScript
+ writeUs: 'Skriv till oss',
+ // Property or array item — trailing comma allowed in TypeScript
+ callUs: 'Ring oss',
+ // Property or array item — trailing comma allowed in TypeScript
+ openMaps: 'Öppna i Google Maps',
+ // Property or array item — trailing comma allowed in TypeScript
+ learnMore: 'Kontaktuppgifter',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 161: cta: {
+ cta: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Redo för Premium Halal Kött?',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Beställ idag och upplev skillnaden med verkligt färskt, anpassat halal kött levererat till din dörr.',
+ // Property or array item — trailing comma allowed in TypeScript
+ button: 'Se vårt sortiment',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'Beställ på WhatsApp',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 168: shop: {
+ shop: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Alla Produkter',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitle: 'Premium halal kött, anpassat efter dina önskemål',
+ // Property or array item — trailing comma allowed in TypeScript
+ noProducts: 'Inga produkter hittades',
+ // Property or array item — trailing comma allowed in TypeScript
+ noProductsHint: 'Prova att justera dina filter eller sökfråga',
+ // Property or array item — trailing comma allowed in TypeScript
+ filters: 'Filter',
+ // Property or array item — trailing comma allowed in TypeScript
+ productsFound: '{count} produkter hittades',
+ // Property or array item — trailing comma allowed in TypeScript
+ search: 'Sök',
+ // Property or array item — trailing comma allowed in TypeScript
+ searchPlaceholder: 'Sök produkter...',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'Kategori',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortBy: 'Sortera efter',
+ // Property or array item — trailing comma allowed in TypeScript
+ all: 'Alla',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortFeatured: 'Utvalda',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortPriceAsc: 'Pris: Lägst till högst',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortPriceDesc: 'Pris: Högst till lägst',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortName: 'Namn A–Ö',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 185: product: {
+ product: {
+ // Property or array item — trailing comma allowed in TypeScript
+ backToShop: 'Tillbaka till butiken',
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: 'I lager',
+ // Property or array item — trailing comma allowed in TypeScript
+ outOfStock: 'Slut i lager',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalTrust: '100 % Halal-certifierad · Färskt dagligen · Premiumkvalitet',
+ // Property or array item — trailing comma allowed in TypeScript
+ yourSelection: 'Ditt val',
+ // Property or array item — trailing comma allowed in TypeScript
+ aboutProduct: 'Om denna produkt',
+ // Property or array item — trailing comma allowed in TypeScript
+ addToCart: 'Lägg i varukorg',
+ // Property or array item — trailing comma allowed in TypeScript
+ addedToCart: 'Tillagd i varukorg',
+ // Property or array item — trailing comma allowed in TypeScript
+ decreaseQty: 'Minska antal',
+ // Property or array item — trailing comma allowed in TypeScript
+ increaseQty: 'Öka antal',
+ // Property or array item — trailing comma allowed in TypeScript
+ removeWishlist: 'Ta bort från önskelista',
+ // Property or array item — trailing comma allowed in TypeScript
+ addWishlist: 'Lägg till i önskelista',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewProduct: 'Visa {name}',
+ // Property or array item — trailing comma allowed in TypeScript
+ pieces: '{count} bitar',
+ // Property or array item — trailing comma allowed in TypeScript
+ standardCut: 'Standardstyckning',
+ // Property or array item — trailing comma allowed in TypeScript
+ howManyCuts: 'Hur Många Styckningar Vill Du Ha?',
+ // Property or array item — trailing comma allowed in TypeScript
+ howManyCutsHint: 'Välj antal styckningar för din beställning',
+ // Property or array item — trailing comma allowed in TypeScript
+ cutsAndStyle: '{cuts} styckningar · {style}',
+ // Property or array item — trailing comma allowed in TypeScript
+ selectCutting: 'Välj skärstil',
+ // Property or array item — trailing comma allowed in TypeScript
+ selectCuttingHint: 'Våra slaktare förbereder ditt {category} exakt enligt din önskade styckning',
+ // Line 206: fishNote:
+ fishNote:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Fiskprodukter förbereds med vår standard professionella styckning — rengjord, fjällad och redo att tillagas.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 209: cutting: {
+ cutting: {
+ // Property or array item — trailing comma allowed in TypeScript
+ nihari: 'Nihari-styckning',
+ // Property or array item — trailing comma allowed in TypeScript
+ karahi: 'Karahi-styckning',
+ // Property or array item — trailing comma allowed in TypeScript
+ qeema: 'Qeema (färs)',
+ // Property or array item — trailing comma allowed in TypeScript
+ boneless: 'Benfri',
+ // Property or array item — trailing comma allowed in TypeScript
+ steak: 'Biffstyckning',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 216: priceUnit: {
+ priceUnit: {
+ // Property or array item — trailing comma allowed in TypeScript
+ perBird: 'per kyckling',
+ // Property or array item — trailing comma allowed in TypeScript
+ perPack: 'per förpackning',
+ // Property or array item — trailing comma allowed in TypeScript
+ perKg: 'per kg',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 221: badges: {
+ badges: {
+ // Property or array item — trailing comma allowed in TypeScript
+ bestseller: 'Bästsäljare',
+ // Property or array item — trailing comma allowed in TypeScript
+ chefsPick: 'Kockens val',
+ // Property or array item — trailing comma allowed in TypeScript
+ premium: 'Premium',
+ // Property or array item — trailing comma allowed in TypeScript
+ popular: 'Populär',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshCatch: 'Färsk fångst',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 228: products: {
+ products: {
+ // Line 229: 'chicken-whole': {
+ 'chicken-whole': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Hel Kyckling',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Gårdsfärsk hel halal kyckling, perfekt för stekning eller curry.',
+ // Line 232: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Våra hela kycklingar kommer från certifierade halalgårdar och levereras i toppskick. Varje fågel är handplockad för kvalitet, med mört kött och ren bearbetning. Välj önskat antal bitar så förbereder vi den precis som du behöver.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 235: 'chicken-breast': {
+ 'chicken-breast': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Kycklingbröst',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Magert, benfritt kycklingbröst — idealiskt för grillning och hälsosamma måltider.',
+ // Line 238: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium benfritt kycklingbröst, trimmat och redo att tillagas. Perfekt för kebab, wok och hälsosamma vardagsmiddagar. Välj antal bitar och njut av konsekvent kvalitet varje gång.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 241: 'chicken-thighs': {
+ 'chicken-thighs': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Kycklinglår',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Saftiga halal kycklinglår med rik smak för curry och grill.',
+ // Line 244: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Våra kycklinglår är kända för sin saftighet och djupa smak. Oavsett om du lagar traditionell karahi eller helg-BBQ levererar dessa lår varje gång.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 247: 'chicken-wings': {
+ 'chicken-wings': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Kycklingvingar',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Festfärdiga halal kycklingvingar för stekning, bakning eller grillning.',
+ // Line 250: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Krispiga, smakrika kycklingvingar tillagade enligt halal och levererade färskt. En favorit för matchkvällar och familjesammankomster.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 253: 'beef-nihari': {
+ 'beef-nihari': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Nötkött för Nihari',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Långkoksklara nötköttsstyckningar, perfekta för traditionell nihari.',
+ // Line 256: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Särskilt utvalda nötköttsstyckningar idealiska för långkokt nihari. Rika på kollagen och smak, dessa styckningar bryts ner vackert under timmar av sjudning för en autentisk, smältande upplevelse.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 259: 'beef-steak': {
+ 'beef-steak': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Premium Nötbiff',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Restaurangkvalitet halal biffstyckningar för perfekt stekyta.',
+ // Line 262: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Handskurna premium biffar från de finaste halal-källorna. Marmorering, mörhet och redo för din grill eller gjutjärnspanna. Välj önskad skärstil.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 265: 'beef-mince': {
+ 'beef-mince': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Nötfärs',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Färsk halal nötfärs för kebab, burgare och qeema.',
+ // Line 268: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Finmalen halal nötfärs med perfekt fettförhållande för saftiga kebab, smakrik qeema och hemlagade burgare. Malas färskt dagligen.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 271: 'beef-boneless': {
+ 'beef-boneless': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Benfria Nötköttskuber',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Mångsidiga benfria nötköttskuber för karahi, biryani och grytor.',
+ // Line 274: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Enhetliga benfria nötköttskuber skurna till perfektion för snabbkokta rätter. Idealiska för karahi, pulao och wok där konsekvent storlek är viktigt.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 277: 'lamb-shoulder': {
+ 'lamb-shoulder': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Lammbog',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Rik, smakrik lammbog för långstekning och curry.',
+ // Line 280: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium halal lammbog med vacker marmorering. Perfekt för långstekta festmåltider, rejäla curryrätter och traditionella familjemiddagar. Anpassad efter din önskade styckning.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 283: 'lamb-leg': {
+ 'lamb-leg': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Lammlägg',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Mört lammlägg för stekning, grillning och speciella tillfällen.',
+ // Line 286: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Hela eller portionerade lammlägg från certifierade halal-källor. En centerstyckning för Eid-firanden, middagsbjudningar och söndagsstek.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 289: 'lamb-chops': {
+ 'lamb-chops': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Lammkotletter',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Premium lammkotletter för grillning och finmiddag hemma.',
+ // Line 292: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Tjockskurna halal lammkotletter med perfekt fettlock för grillning. Restaurangkvalitet, levererad till ditt kök.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 295: 'lamb-mince': {
+ 'lamb-mince': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Lammfärs',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Färsk halal lammfärs för kebab, samosas och qeema.',
+ // Line 298: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Finmalen lammfärs med rik smak. Nödvändig för seekh kebab, lamm qeema och fyllda parathas.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 301: 'fish-salmon': {
+ 'fish-salmon': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Atlantisk Laxfilé',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Smörig laxfilé, med skinn och redo att steka i panna.',
+ // Line 304: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium atlantisk laxfilé med rikt omega-3-innehåll. Rengjord, portionerad och vakuumförpackad för maximal färskhet.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 307: 'fish-rohu': {
+ 'fish-rohu': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Rohu-fisk',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Hel rohu-fisk, rengjord och fjällad — en sydasiatisk favorit.',
+ // Line 310: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Färsk rohu-fisk, en stapel i sydasiatisk matlagning. Rengjord, fjällad och urtagen. Perfekt för fiskcurry, stekt fisk och traditionella recept.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 313: 'fish-prawns': {
+ 'fish-prawns': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Jätteräkor',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Stora räkor med skal för grillning, curry och biryani.',
+ // Line 316: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium jätteräkor, urtagna och redo att tillagas. Söt, fast kött som håller sig vackert i curry och tandoori-rätter.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 319: 'fish-basa': {
+ 'fish-basa': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Basa-filé',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'Mild, flagnig basa-filé — perfekt för nybörjare och barn.',
+ // Line 322: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Benfria basa-filéer med mild, delikat smak. Lätt att tillaga och mångsidig — utmärkt för fisk-tacos, bakning och lätta curryrätter.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 326: cart: {
+ cart: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Din Varukorg',
+ // Property or array item — trailing comma allowed in TypeScript
+ itemsCount: '{count} artikel/artiklar i din varukorg',
+ // Property or array item — trailing comma allowed in TypeScript
+ empty: 'Din varukorg är tom',
+ // Property or array item — trailing comma allowed in TypeScript
+ emptyHint: 'Bläddra i vårt premium halal-sortiment och lägg till artiklar.',
+ // Property or array item — trailing comma allowed in TypeScript
+ startShopping: 'Börja handla',
+ // Property or array item — trailing comma allowed in TypeScript
+ customization: 'Anpassning:',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderSummary: 'Ordersammanfattning',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtotal: 'Delsumma',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery: 'Leverans',
+ // Property or array item — trailing comma allowed in TypeScript
+ free: 'Gratis',
+ // Property or array item — trailing comma allowed in TypeScript
+ freeDeliveryHint: 'Fri leverans på beställningar över 500 kr',
+ // Property or array item — trailing comma allowed in TypeScript
+ total: 'Totalt',
+ // Property or array item — trailing comma allowed in TypeScript
+ proceedCheckout: 'Gå till kassan',
+ // Property or array item — trailing comma allowed in TypeScript
+ continueShopping: 'Fortsätt handla',
+ // Property or array item — trailing comma allowed in TypeScript
+ removeItem: 'Ta bort artikel',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 343: checkout: {
+ checkout: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Säker Kassa',
+ // Property or array item — trailing comma allowed in TypeScript
+ backToCart: 'Tillbaka till varukorg',
+ // Property or array item — trailing comma allowed in TypeScript
+ noItems: 'Inga artiklar att betala',
+ // Property or array item — trailing comma allowed in TypeScript
+ goToShop: 'Gå till butiken',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderConfirmed: 'Beställning bekräftad!',
+ // Property or array item — trailing comma allowed in TypeScript
+ thankYou: 'Tack för din beställning. Ditt premium halal kött förbereds.',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderId: 'Order-ID: {id}',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewOrders: 'Visa beställningar',
+ // Property or array item — trailing comma allowed in TypeScript
+ haveAccount: 'Har du ett konto?',
+ // Property or array item — trailing comma allowed in TypeScript
+ signIn: 'Logga in',
+ // Property or array item — trailing comma allowed in TypeScript
+ fasterCheckout: 'för snabbare utcheckning.',
+ // Property or array item — trailing comma allowed in TypeScript
+ deliveryDetails: 'Leveransuppgifter',
+ // Property or array item — trailing comma allowed in TypeScript
+ fullName: 'Fullständigt namn',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: 'E-post',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: 'Telefon',
+ // Property or array item — trailing comma allowed in TypeScript
+ street: 'Gatuadress',
+ // Property or array item — trailing comma allowed in TypeScript
+ city: 'Stad',
+ // Property or array item — trailing comma allowed in TypeScript
+ state: 'Län',
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: 'Postnummer',
+ // Property or array item — trailing comma allowed in TypeScript
+ payment: 'Betalning',
+ // Property or array item — trailing comma allowed in TypeScript
+ creditCard: 'Kreditkort',
+ // Property or array item — trailing comma allowed in TypeScript
+ cashOnDelivery: 'Kontant vid leverans',
+ // Property or array item — trailing comma allowed in TypeScript
+ cardNumber: 'Kortnummer',
+ // Property or array item — trailing comma allowed in TypeScript
+ expiry: 'Giltig till',
+ // Property or array item — trailing comma allowed in TypeScript
+ cvv: 'CVV',
+ // Property or array item — trailing comma allowed in TypeScript
+ qty: 'Antal: {count}',
+ // Property or array item — trailing comma allowed in TypeScript
+ processing: 'Bearbetar...',
+ // Property or array item — trailing comma allowed in TypeScript
+ pay: 'Betala {amount}',
+ // Property or array item — trailing comma allowed in TypeScript
+ secure: 'Säker 256-bitars SSL-kryptering',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 374: auth: {
+ auth: {
+ // Property or array item — trailing comma allowed in TypeScript
+ welcomeBack: 'Välkommen tillbaka',
+ // Property or array item — trailing comma allowed in TypeScript
+ createAccount: 'Skapa konto',
+ // Property or array item — trailing comma allowed in TypeScript
+ joinTagline: 'Gå med i {name} för en premium shoppingupplevelse',
+ // Property or array item — trailing comma allowed in TypeScript
+ signInTagline: 'Logga in på ditt {name}-konto',
+ // Property or array item — trailing comma allowed in TypeScript
+ fullName: 'Fullständigt namn',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: 'E-post',
+ // Property or array item — trailing comma allowed in TypeScript
+ password: 'Lösenord',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: 'Telefon',
+ // Property or array item — trailing comma allowed in TypeScript
+ street: 'Gatuadress',
+ // Property or array item — trailing comma allowed in TypeScript
+ city: 'Stad',
+ // Property or array item — trailing comma allowed in TypeScript
+ state: 'Län',
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: 'Postnummer',
+ // Property or array item — trailing comma allowed in TypeScript
+ signIn: 'Logga in',
+ // Property or array item — trailing comma allowed in TypeScript
+ register: 'Skapa konto',
+ // Property or array item — trailing comma allowed in TypeScript
+ hasAccount: 'Har du redan ett konto? Logga in',
+ // Property or array item — trailing comma allowed in TypeScript
+ noAccount: 'Har du inget konto? Registrera dig',
+ // Property or array item — trailing comma allowed in TypeScript
+ invalidCredentials: 'Ogiltig e-post eller lösenord. Prova {email} / demo123',
+ // Property or array item — trailing comma allowed in TypeScript
+ demo: 'Demo: {email} / demo123',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 394: account: {
+ account: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Mitt Konto',
+ // Property or array item — trailing comma allowed in TypeScript
+ welcome: 'Välkommen tillbaka, {name}',
+ // Property or array item — trailing comma allowed in TypeScript
+ memberSince: 'Medlem sedan {date}',
+ // Property or array item — trailing comma allowed in TypeScript
+ myWishlist: 'Min önskelista',
+ // Property or array item — trailing comma allowed in TypeScript
+ signOut: 'Logga ut',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderHistory: 'Orderhistorik',
+ // Property or array item — trailing comma allowed in TypeScript
+ noOrders: 'Inga beställningar ännu',
+ // Property or array item — trailing comma allowed in TypeScript
+ startShopping: 'Börja handla',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 404: wishlist: {
+ wishlist: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Min Önskelista',
+ // Property or array item — trailing comma allowed in TypeScript
+ saved: '{count} sparad(e) artikel/artiklar',
+ // Property or array item — trailing comma allowed in TypeScript
+ empty: 'Din önskelista är tom',
+ // Property or array item — trailing comma allowed in TypeScript
+ emptyHint: 'Spara dina favoritprodukter för att köpa dem senare.',
+ // Property or array item — trailing comma allowed in TypeScript
+ browse: 'Bläddra produkter',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 411: about: {
+ about: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'Om {name}',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Vi levererar premium 100 % halal kött till ditt bord — färskt, anpassat och med omsorg.',
+ // Property or array item — trailing comma allowed in TypeScript
+ ourStory: 'Vår Historia',
+ // Line 416: storyP1:
+ storyP1:
+ // Property or array item — trailing comma allowed in TypeScript
+ '{name} grundades med ett enkelt uppdrag: göra premium halal kött tillgängligt för varje familj, utan att kompromissa med kvalitet, färskhet eller religiös efterlevnad. Vi förstår att för många hushåll är rätt styckning tillagad på rätt sätt inte en lyx — det är nödvändigt.',
+ // Line 418: storyP2:
+ storyP2:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Från att välja antal bitar för kyckling till att välja Nihari- eller Karahi-styckning för nötkött och lamm, sätter vi anpassning i centrum för varje beställning. Våra expertslaktare förbereder varje order för hand, och vår temperaturkontrollerade leverans säkerställer att ditt kött anländer lika färskt som dagen det styckades.',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalTitle: 'Halalcertifiering',
+ // Line 421: halalDesc:
+ halalDesc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Varje produkt hos {name} kommer från certifierade halal-leverantörer. Vår leveranskedja är fullt spårbar och vi upprätthåller strikt efterlevnad av halal-slakt och -bearbetningsstandarder. Vi arbetar uteslutande med gårdar och bearbetare som delar vårt engagemang för etiskt, religiöst korrekt köttproduktion.',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshDaily: 'Färskt Dagligen',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshDailyDesc: 'Hämtas varje morgon från betrodda gårdar',
+ // Property or array item — trailing comma allowed in TypeScript
+ premiumQuality: 'Premiumkvalitet',
+ // Property or array item — trailing comma allowed in TypeScript
+ premiumQualityDesc: 'Handplockade styckningar av expertslaktare',
+ // Property or array item — trailing comma allowed in TypeScript
+ fastDelivery: 'Snabb Leverans',
+ // Property or array item — trailing comma allowed in TypeScript
+ fastDeliveryDesc: 'Temperaturkontrollerad leverans samma dag',
+ // Property or array item — trailing comma allowed in TypeScript
+ deliveryTitle: 'Leveransinformation',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery1: 'Vi levererar inom en radie på 40 km från vår anläggning.',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery2: 'Beställningar före kl. 14 är berättigade till leverans samma dag.',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery3: 'Fri leverans på beställningar över 500 kr. Standardleverans: 49 kr.',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery4: 'Alla produkter vakuumförpackas och transporteras i isolerad förpackning.',
+ // Property or array item — trailing comma allowed in TypeScript
+ contactTitle: 'Kontakta Oss',
+ // Property or array item — trailing comma allowed in TypeScript
+ address: 'Tingvallavägen 11, 195 31 Märsta',
+ // Property or array item — trailing comma allowed in TypeScript
+ privacyTitle: 'Integritetspolicy',
+ // Line 437: privacyText:
+ privacyText:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Vi samlar endast den information som behövs för att behandla dina beställningar — namn, kontaktuppgifter och leveransadress. Vi säljer inte dina uppgifter till tredje part. Betalningsuppgifter hanteras säkert av våra betalpartners.',
+ // Property or array item — trailing comma allowed in TypeScript
+ termsTitle: 'Användarvillkor',
+ // Line 440: termsText:
+ termsText:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Alla priser visas i SEK och kan ändras utan föregående meddelande. Beställningar är beroende av tillgång. Halalcertifiering gäller för alla köttprodukter. Leveranstider är uppskattningar och kan variera under högtrafik.',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 443: footer: {
+ footer: {
+ // Line 444: tagline:
+ tagline:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Premium 100 % halal köttleverans. Färskt, anpassat kött levererat till din dörr med kompromisslös kvalitet.',
+ // Property or array item — trailing comma allowed in TypeScript
+ shop: 'Butik',
+ // Property or array item — trailing comma allowed in TypeScript
+ company: 'Företag',
+ // Property or array item — trailing comma allowed in TypeScript
+ contact: 'Kontakt',
+ // Property or array item — trailing comma allowed in TypeScript
+ rights: 'Alla rättigheter förbehållna.',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: '072-585 50 50',
+ // Property or array item — trailing comma allowed in TypeScript
+ hours: 'Öppet alla dagar {hours}',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 453: notFound: {
+ notFound: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: '404',
+ // Property or array item — trailing comma allowed in TypeScript
+ message: 'Sidan hittades inte',
+ // Property or array item — trailing comma allowed in TypeScript
+ goHome: 'Gå till startsidan',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 458: orderStatus: {
+ orderStatus: {
+ // Property or array item — trailing comma allowed in TypeScript
+ pending: 'väntande',
+ // Property or array item — trailing comma allowed in TypeScript
+ confirmed: 'bekräftad',
+ // Property or array item — trailing comma allowed in TypeScript
+ preparing: 'förbereds',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'out-for-delivery': 'ute för leverans',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivered: 'levererad',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// Closing brace — end of block (function, if, object, JSX)
+};
diff --git a/docs/annotated/src/i18n/locales/ur.annotated.ts b/docs/annotated/src/i18n/locales/ur.annotated.ts
new file mode 100644
index 0000000..e46ae99
--- /dev/null
+++ b/docs/annotated/src/i18n/locales/ur.annotated.ts
@@ -0,0 +1,936 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/i18n/locales/ur.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import external package or local module
+import { TranslationDict } from '../types';
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const ur: TranslationDict = {
+ // Line 4: site: {
+ site: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'کوٹ گارڈ',
+ // Property or array item — trailing comma allowed in TypeScript
+ tagline: 'پریمیم حلال',
+ // Line 7: description:
+ description:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'پریمیم 100% حلال گوشت کی ڈیلیوری۔ تازہ اور منجمد مرغی، گائے کا گوشت، بکرے کا گوشت اور مچھلی — آپ کی پسند کے مطابق تیار کر کے آپ کے دروازے تک پہنچائی جاتی ہے۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ metaTitle: 'پریمیم حلال گوشت ڈیلیوری',
+ // Property or array item — trailing comma allowed in TypeScript
+ initials: 'KG',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: 'hello@kottgard.se',
+ // Property or array item — trailing comma allowed in TypeScript
+ demoEmail: 'demo@kottgard.se',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 14: nav: {
+ nav: {
+ // Property or array item — trailing comma allowed in TypeScript
+ shop: 'خریداری',
+ // Property or array item — trailing comma allowed in TypeScript
+ chicken: 'مرغی',
+ // Property or array item — trailing comma allowed in TypeScript
+ beef: 'گائے کا گوشت',
+ // Property or array item — trailing comma allowed in TypeScript
+ lamb: 'بکرے کا گوشت',
+ // Property or array item — trailing comma allowed in TypeScript
+ fish: 'مچھلی',
+ // Property or array item — trailing comma allowed in TypeScript
+ about: 'ہمارے بارے میں',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalCert: 'حلال سرٹیفیکیشن',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery: 'ڈیلیوری کی معلومات',
+ // Property or array item — trailing comma allowed in TypeScript
+ contact: 'رابطہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ myAccount: 'میرا اکاؤنٹ',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderHistory: 'آرڈر کی تاریخ',
+ // Property or array item — trailing comma allowed in TypeScript
+ wishlist: 'پسندیدہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ cart: 'ٹوکری',
+ // Property or array item — trailing comma allowed in TypeScript
+ privacy: 'رازداری کی پالیسی',
+ // Property or array item — trailing comma allowed in TypeScript
+ terms: 'شرائط و ضوابط',
+ // Property or array item — trailing comma allowed in TypeScript
+ searchProducts: 'مصنوعات تلاش کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ toggleMenu: 'مینو کھولیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ account: 'اکاؤنٹ',
+ // Property or array item — trailing comma allowed in TypeScript
+ language: 'زبان',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 35: languageBanner: {
+ languageBanner: {
+ // Property or array item — trailing comma allowed in TypeScript
+ choose: 'اپنی زبان منتخب کریں',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 38: hero: {
+ hero: {
+ // Property or array item — trailing comma allowed in TypeScript
+ badge: '100% حلال تصدیق شدہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ taglineShort: 'قدرتی طور پر خالص',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'پریمیم حلال گوشت',
+ // Property or array item — trailing comma allowed in TypeScript
+ titleHighlight: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ titleEnd: '',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitleShort: 'تازہ۔ معیار۔ قابل اعتماد۔',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'حلال تصدیق شدہ · روزانہ تازہ · گھر کی ڈیلیوری · ہر دن کھلا',
+ // Property or array item — trailing comma allowed in TypeScript
+ hours: 'ہر دن کھلا {hours}',
+ // Property or array item — trailing comma allowed in TypeScript
+ location: 'Tingvallavägen 11, Märsta',
+ // Property or array item — trailing comma allowed in TypeScript
+ shopNow: 'ہمارا مجموعہ دیکھیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ browseChicken: 'مرغی دیکھیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'واٹس ایپ سے آرڈر کریں',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 53: aboutPreview: {
+ aboutPreview: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'ہمارے بارے میں',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'مائرسٹا کی بہترین گوشت کی دکان',
+ // Property or array item — trailing comma allowed in TypeScript
+ p1: 'کوٹ گارڈ صرف ایک گوشت کی دکان نہیں — ہم معیار کا وعدہ ہیں۔ ہمارا تمام گوشت 100% حلال تصدیق شدہ ہے اور روزانہ تازہ پہنچایا جاتا ہے۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ p2: 'ہم آئرلینڈ اور نیوزی لینڈ سے بکرے کا گوشت، معتبر پیدا کنندگان سے مرغی اور گائے کا گوشت حاصل کرتے ہیں، اور آپ کو رات کے کھانے، تقریب یا اتوار کی روست کے لیے صحیح کٹ تلاش کرنے میں مدد کرتے ہیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ p3: 'Tingvallavägen پر ہماری دکان میں آئیں، بتائیں آپ کیا تلاش کر رہے ہیں — ہم آپ کی خواہش کے مطابق کاٹتے اور پیک کرتے ہیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ statHalal: '100%',
+ // Property or array item — trailing comma allowed in TypeScript
+ statHalalLabel: 'حلال تصدیق شدہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDays: '7 دن',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDaysLabel: 'ہفتے میں کھلا',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDelivery: 'روزانہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ statDeliveryLabel: 'ڈیلیوری',
+ // Property or array item — trailing comma allowed in TypeScript
+ statFresh: 'تازہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ statFreshLabel: 'ہر دن',
+ // Property or array item — trailing comma allowed in TypeScript
+ readMore: 'مزید پڑھیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ imageAlt: 'کوٹ گارڈ سے تازہ گوشت کی کٹس',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 70: trust: {
+ trust: {
+ // Property or array item — trailing comma allowed in TypeScript
+ halal: '100% حلال',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalDesc: 'مکمل سراغ رسانی اور تعمیل کے ساتھ تصدیق شدہ حلال ذرائع۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ fresh: 'روزانہ تازہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshDesc: 'ہر صبح تازہ حاصل کیا جاتا ہے اور بہترین حالت میں پہنچایا جاتا ہے۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ premium: 'پریمیم معیار',
+ // Property or array item — trailing comma allowed in TypeScript
+ premiumDesc: 'قابل اعتماد فارموں سے منتخب کردہ کٹس، ماہر قصابوں کے ذریعے تیار۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 78: categories: {
+ categories: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'زمرے کے لحاظ سے خریداری',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'روزمرہ کی مرغی سے لے کر پریمیم بکرے کے کٹlets تک — ہر کٹ آپ کی پسند کے مطابق۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ shop: '{name} خریدیں',
+ // Line 83: chicken: {
+ chicken: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'مرغی',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'فارم سے تازہ حلال مرغی، آپ کی پسند کے مطابق کاٹی گئی',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 87: beef: {
+ beef: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'گائے کا گوشت',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'روایتی اور جدید کٹس میں پریمیم حلال گائے کا گوشت',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 91: lamb: {
+ lamb: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'بکرے کا گوشت',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'ہر موقع کے لیے نرم حلال بکرے کا گوشت',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 95: fish: {
+ fish: {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'مچھلی',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'تازہ پکڑ، صاف کی گئی اور پکانے کے لیے تیار',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 100: featured: {
+ featured: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'منتخب مجموعہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'نمایاں مصنوعات',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitle: 'ہماری سب سے مقبول کٹس، شہر بھر کے خاندانوں کی پسندیدہ۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewAll: 'سب دیکھیں',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 106: howItWorks: {
+ howItWorks: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'آرڈر',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'آرڈر کرنا کتنا آسان ہے',
+ // Property or array item — trailing comma allowed in TypeScript
+ step1Title: 'ہم سے رابطہ کریں',
+ // Line 110: step1Desc:
+ step1Desc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'واٹس ایپ پر پیغام بھیجیں کہ آپ کیا چاہتے ہیں — ہم جلدی جواب دیتے ہیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ step2Title: 'ہم تصدیق کرتے ہیں',
+ // Line 113: step2Desc:
+ step2Desc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'ہم آپ کے آرڈر کی تصدیق کرتے ہیں، قیمت بتاتے ہیں اور بتاتے ہیں کہ کب تیار ہوگا۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ step3Title: 'وصول یا ڈیلیوری',
+ // Line 116: step3Desc:
+ step3Desc:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'Tingvallavägen 11 پر دکان سے وصول کریں یا گھر کی ڈیلیوری منتخب کریں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ step: 'مرحلہ {n}',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'واٹس ایپ پر آرڈر کریں',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 121: offers: {
+ offers: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'آرڈر',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'ہفتہ وار پیشکشیں',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'ہم مسلسل تازہ پیشکشوں کے ساتھ اپ ڈیٹ کرتے ہیں۔ تازہ ترین قیمتوں کے لیے سوشل میڈیا پر فالو کریں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ disclaimer: 'قیمت اس وقت تک جب تک اسٹاک موجود ہے',
+ // Property or array item — trailing comma allowed in TypeScript
+ was: 'پہلے',
+ // Property or array item — trailing comma allowed in TypeScript
+ now: 'اب',
+ // Property or array item — trailing comma allowed in TypeScript
+ order: 'آرڈر',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewProduct: 'مصنوعات دیکھیں',
+ // Line 131: badge: {
+ badge: {
+ // Property or array item — trailing comma allowed in TypeScript
+ fresh: 'تازہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ halal: 'حلال',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 135: items: {
+ items: {
+ // Property or array item — trailing comma allowed in TypeScript
+ chickenWings: { name: 'تازہ چکن ونگز PL' },
+ // Property or array item — trailing comma allowed in TypeScript
+ lambSteak: { name: 'تازہ لیمب روست آئرلینڈ' },
+ // Property or array item — trailing comma allowed in TypeScript
+ beefMince: { name: 'بیف منس 5% چکنائی IRL' },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 141: social: {
+ social: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'ہمیں فالو کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'ہمیں فالو کریں',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'فیس بک پر 1,100+ فالوورز · 249 پوسٹس · روزانہ اپ ڈیٹس',
+ // Property or array item — trailing comma allowed in TypeScript
+ facebook: 'فیس بک',
+ // Property or array item — trailing comma allowed in TypeScript
+ instagram: 'انسٹاگرام',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'واٹس ایپ',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 150: contact: {
+ contact: {
+ // Property or array item — trailing comma allowed in TypeScript
+ label: 'رابطہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'ہم سے ملیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ addressLabel: 'پتہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ phoneLabel: 'فون',
+ // Property or array item — trailing comma allowed in TypeScript
+ hoursLabel: 'اوقات',
+ // Property or array item — trailing comma allowed in TypeScript
+ hoursValue: 'ہر دن: {hours}',
+ // Property or array item — trailing comma allowed in TypeScript
+ writeUs: 'ہمیں لکھیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ callUs: 'ہمیں کال کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ openMaps: 'گوگل میپس میں کھولیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ learnMore: 'رابطے کی تفصیلات',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 162: cta: {
+ cta: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'پریمیم حلال گوشت کے لیے تیار ہیں؟',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'آج ہی آرڈر کریں اور حقیقی تازہ، حسب ضرورت حلال گوشت کا فرق محسوس کریں جو آپ کے دروازے تک پہنچایا جائے۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ button: 'ہمارا مجموعہ دیکھیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsapp: 'واٹس ایپ پر آرڈر کریں',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 169: shop: {
+ shop: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'تمام مصنوعات',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtitle: 'پریمیم حلال گوشت، آپ کی پسند کے مطابق',
+ // Property or array item — trailing comma allowed in TypeScript
+ noProducts: 'کوئی مصنوعات نہیں ملیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ noProductsHint: 'اپنے فلٹرز یا تلاش کی کوشش کو ایڈجسٹ کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ filters: 'فلٹرز',
+ // Property or array item — trailing comma allowed in TypeScript
+ productsFound: '{count} مصنوعات ملیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ search: 'تلاش',
+ // Property or array item — trailing comma allowed in TypeScript
+ searchPlaceholder: 'مصنوعات تلاش کریں...',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'زمرہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortBy: 'ترتیب دیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ all: 'سب',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortFeatured: 'نمایاں',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortPriceAsc: 'قیمت: کم سے زیادہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortPriceDesc: 'قیمت: زیادہ سے کم',
+ // Property or array item — trailing comma allowed in TypeScript
+ sortName: 'نام الف سے ی',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 186: product: {
+ product: {
+ // Property or array item — trailing comma allowed in TypeScript
+ backToShop: 'خریداری پر واپس',
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: 'دستیاب',
+ // Property or array item — trailing comma allowed in TypeScript
+ outOfStock: 'اسٹاک ختم',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalTrust: '100% حلال تصدیق شدہ · روزانہ تازہ · پریمیم معیار',
+ // Property or array item — trailing comma allowed in TypeScript
+ yourSelection: 'آپ کا انتخاب',
+ // Property or array item — trailing comma allowed in TypeScript
+ aboutProduct: 'اس مصنوع کے بارے میں',
+ // Property or array item — trailing comma allowed in TypeScript
+ addToCart: 'ٹوکری میں شامل کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ addedToCart: 'ٹوکری میں شامل ہو گیا',
+ // Property or array item — trailing comma allowed in TypeScript
+ decreaseQty: 'مقدار کم کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ increaseQty: 'مقدار بڑھائیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ removeWishlist: 'پسندیدہ سے ہٹائیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ addWishlist: 'پسندیدہ میں شامل کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewProduct: '{name} دیکھیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ pieces: '{count} ٹکڑے',
+ // Property or array item — trailing comma allowed in TypeScript
+ standardCut: 'معیاری کٹ',
+ // Property or array item — trailing comma allowed in TypeScript
+ howManyCuts: 'آپ کتنے کٹ چاہتے ہیں؟',
+ // Property or array item — trailing comma allowed in TypeScript
+ howManyCutsHint: 'اپنے آرڈر کے لیے کٹوں کی تعداد منتخب کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ cutsAndStyle: '{cuts} کٹ · {style}',
+ // Property or array item — trailing comma allowed in TypeScript
+ selectCutting: 'کاٹنے کا انداز منتخب کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ selectCuttingHint: 'ہمارے قصاب آپ کے {category} کو بالکل آپ کی پسند کے مطابق تیار کریں گے',
+ // Line 207: fishNote:
+ fishNote:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'مچھلی کی مصنوعات ہمارے معیاری پیشہ ورانہ کٹ سے تیار کی جاتی ہیں — صاف، چھلکے اتارے اور پکانے کے لیے تیار۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 210: cutting: {
+ cutting: {
+ // Property or array item — trailing comma allowed in TypeScript
+ nihari: 'نہاری کٹ',
+ // Property or array item — trailing comma allowed in TypeScript
+ karahi: 'کڑاہی کٹ',
+ // Property or array item — trailing comma allowed in TypeScript
+ qeema: 'قیمہ (کима)',
+ // Property or array item — trailing comma allowed in TypeScript
+ boneless: 'بغیر ہڈی',
+ // Property or array item — trailing comma allowed in TypeScript
+ steak: 'اسٹیک کٹ',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 217: priceUnit: {
+ priceUnit: {
+ // Property or array item — trailing comma allowed in TypeScript
+ perBird: 'فی مرغی',
+ // Property or array item — trailing comma allowed in TypeScript
+ perPack: 'فی پیک',
+ // Property or array item — trailing comma allowed in TypeScript
+ perKg: 'فی کلو',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 222: badges: {
+ badges: {
+ // Property or array item — trailing comma allowed in TypeScript
+ bestseller: 'سب سے زیادہ فروخت',
+ // Property or array item — trailing comma allowed in TypeScript
+ chefsPick: 'شیف کی پسند',
+ // Property or array item — trailing comma allowed in TypeScript
+ premium: 'پریمیم',
+ // Property or array item — trailing comma allowed in TypeScript
+ popular: 'مقبول',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshCatch: 'تازہ پکڑ',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 229: products: {
+ products: {
+ // Line 230: 'chicken-whole': {
+ 'chicken-whole': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'پوری مرغی',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'فارم سے تازہ پوری حلال مرغی، بھوننے یا کڑی کے لیے بہترین۔',
+ // Line 233: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'ہماری پوری مرغیاں تصدیق شدہ حلال فارموں سے حاصل کی جاتی ہیں اور بہترین تازگی میں پہنچائی جاتی ہیں۔ ہر پرندہ معیار کے لیے ہاتھ سے منتخب کیا جاتا ہے، نرم گوشت اور صاف پروسیسنگ کے ساتھ۔ اپنی پسندیدہ ٹکڑوں کی تعداد منتخب کریں اور ہم اسے بالکل ویسے تیار کریں گے جیسا آپ چاہیں۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 236: 'chicken-breast': {
+ 'chicken-breast': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'مرغی کا سینہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'دبلا، بغیر ہڈی کا مرغی کا سینہ — گرل اور صحت مند کھانوں کے لیے بہترین۔',
+ // Line 239: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'پریمیم بغیر ہڈی کا مرغی کا سینہ، تراشا ہوا اور پکانے کے لیے تیار۔ کباب، سٹیر فرائی اور صحت مند ہفتے کی رات کے کھانوں کے لیے بہترین۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 242: 'chicken-thighs': {
+ 'chicken-thighs': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'مرغی کی ران',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'کڑی اور گرل کے لیے بھرپور ذائقے والی رس بھرے حلال مرغی کی ران۔',
+ // Line 245: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'ہماری مرغی کی ران اپنی رس اور گہرے ذائقے کے لیے مشہور ہے۔ چاہے روایتی کڑاہی بنائیں یا ہفتے کے آخر میں BBQ، یہ ران ہر بار بہترین نتائج دیتی ہے۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 248: 'chicken-wings': {
+ 'chicken-wings': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'مرغی کے بازو',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'تلی، بیکنگ یا گرل کے لیے پارٹی کے لیے تیار حلال مرغی کے بازو۔',
+ // Line 251: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'کرکرے، ذائقے دار مرغی کے بازو حلال طریقے سے تیار اور تازہ پہنچائے جاتے ہیں۔ میچ کی راتوں اور خاندانی محفلوں کی پسندیدہ۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 254: 'beef-nihari': {
+ 'beef-nihari': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'نہاری کے لیے گائے کا گوشت',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'آہستہ پکانے کے لیے تیار گائے کے گوشت کے کٹس، روایتی نہاری کے لیے بہترین۔',
+ // Line 257: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'خاص طور پر منتخب گائے کے گوشت کے کٹس جو آہستہ پکی ہوئی نہاری کے لیے بہترین ہیں۔ کولیجن اور ذائقے سے بھرپور، یہ کٹس گھنٹوں کی دھیمی آنچ پر خوبصورتی سے گل جاتے ہیں۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 260: 'beef-steak': {
+ 'beef-steak': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'پریمیم گائے کا اسٹیک',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'ریستوران معیار کے حلال اسٹیک کٹس، بہترین سیک کے لیے۔',
+ // Line 263: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'بہترین حلال ذرائع سے ہاتھ سے کاٹے گئے پریمیم اسٹیک۔ چربیلے، نرم اور آپ کی گرل یا کاسٹ آئرن پین کے لیے تیار۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 266: 'beef-mince': {
+ 'beef-mince': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'گائے کا قیمہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'کباب، برگر اور قیمہ کے لیے تازہ حلال گائے کا قیمہ۔',
+ // Line 269: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'باریک پیسا ہوا حلال گائے کا قیمہ بہترین چربی کے تناسب کے ساتھ رسیلے کباب، ذائقے دار قیمہ اور گھریلو برگرز کے لیے۔ روزانہ تازہ پیسا جاتا ہے۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 272: 'beef-boneless': {
+ 'beef-boneless': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'بغیر ہڈی کے گائے کے مکعب',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'کڑاہی، بریانی اور اسٹیو کے لیے کثیر الاستعمال بغیر ہڈی کے مکعب۔',
+ // Line 275: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'یکساں بغیر ہڈی کے گائے کے مکعب تیز پکوان کے لیے کامل سائز میں کاٹے گئے۔ کڑاہی، پلاؤ اور سٹیر فرائی کے لیے بہترین۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 278: 'lamb-shoulder': {
+ 'lamb-shoulder': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'بکرے کا کندھا',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'آہستہ بھوننے اور کڑی کے لیے بھرپور ذائقے والا بکرے کا کندھا۔',
+ // Line 281: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'خوبصورت چربی کے نمونے والے پریمیم حلال بکرے کا کندھا۔ آہستہ بھونی ہوئی دعوتوں، بھرپور کڑیوں اور روایتی خاندانی کھانوں کے لیے بہترین۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 284: 'lamb-leg': {
+ 'lamb-leg': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'بکرے کی ٹانگ',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'بھوننے، گرل اور خاص مواقع کے لیے نرم بکرے کی ٹانگ۔',
+ // Line 287: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'تصدیق شدہ حلال ذرائع سے پوری یا حصوں میں بکرے کی ٹانگ۔ عید کی تقریبات، ڈنر پارٹیوں اور اتوار کی بھوننے کے لیے مرکزی کٹ۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 290: 'lamb-chops': {
+ 'lamb-chops': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'بکرے کے کٹlets',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'گرل اور گھر میں فائن ڈائننگ کے لیے پریمیم بکرے کے کٹlets۔',
+ // Line 293: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'موٹے کاٹے گئے حلال بکرے کے کٹlets گرل کے لیے بہترین چربی کی تہہ کے ساتھ۔ ریستوران معیار، آپ کے باورچی خانے تک پہنچایا گیا۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 296: 'lamb-mince': {
+ 'lamb-mince': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'بکرے کا قیمہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'کباب، سموسے اور قیمہ کے لیے تازہ حلال بکرے کا قیمہ۔',
+ // Line 299: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'باریک پیسا ہوا بکرے کا قیمہ بھرپور ذائقے کے ساتھ۔ سیخ کباب، بکرے کا قیمہ اور بھرے ہوئے پراٹھوں کے لیے ضروری۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 302: 'fish-salmon': {
+ 'fish-salmon': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'اٹلانٹک سامن فلیٹ',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'مکھن جیسے نرم سامن فلیٹس، جلد سمیت اور پین میں سیکنے کے لیے تیار۔',
+ // Line 305: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'پریمیم اٹلانٹک سامن فلیٹس بھرپور اومیگا 3 کے ساتھ۔ صاف، حصوں میں تقسیم اور زیادہ سے زیادہ تازگی کے لیے ویکیوم سیلڈ۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 308: 'fish-rohu': {
+ 'fish-rohu': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'روہو مچھلی',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'پوری روہو مچھلی، صاف اور چھلکے اتارے — جنوبی ایشیائی پسندیدہ۔',
+ // Line 311: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'تازہ روہو مچھلی، جنوبی ایشیائی کھانوں کا ایک بنیادی جزو۔ صاف، چھلکے اتارے اور اندر صاف کی گئی۔ مچھلی کی کڑی، تلی ہوئی مچھلی اور روایتی ترکیبوں کے لیے بہترین۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 314: 'fish-prawns': {
+ 'fish-prawns': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'بڑی جھینگے',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'گرل، کڑی اور بریانی کے لیے بڑے چھلکے سمیت جھینگے۔',
+ // Line 317: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'پریمیم بڑی جھینگے، صاف کی گئی اور پکانے کے لیے تیار۔ میٹھا، مضبوط گوشت جو کڑی اور تندوری تیاریوں میں خوبصورتی سے کھڑا رہتا ہے۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 320: 'fish-basa': {
+ 'fish-basa': {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'باسا فلیٹ',
+ // Property or array item — trailing comma allowed in TypeScript
+ description: 'ہلکا، پرت دار باسا فلیٹس — ابتدائیوں اور بچوں کے لیے بہترین۔',
+ // Line 323: longDescription:
+ longDescription:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'بغیر ہڈی کے باسا فلیٹس ہلکے، نفیس ذائقے کے ساتھ۔ پکانا آسان اور کثیر الاستعمال — مچھلی کے ٹیکو، بیکنگ اور ہلکی کڑیوں کے لیے بہترین۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 327: cart: {
+ cart: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'آپ کی ٹوکری',
+ // Property or array item — trailing comma allowed in TypeScript
+ itemsCount: 'آپ کی ٹوکری میں {count} آئٹم',
+ // Property or array item — trailing comma allowed in TypeScript
+ empty: 'آپ کی ٹوکری خالی ہے',
+ // Property or array item — trailing comma allowed in TypeScript
+ emptyHint: 'ہمارے پریمیم حلال مجموعے میں سے دیکھیں اور آئٹمز شامل کریں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ startShopping: 'خریداری شروع کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ customization: 'حسب ضرورت:',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderSummary: 'آرڈر کا خلاصہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ subtotal: 'ذیلی کل',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery: 'ڈیلیوری',
+ // Property or array item — trailing comma allowed in TypeScript
+ free: 'مفت',
+ // Property or array item — trailing comma allowed in TypeScript
+ freeDeliveryHint: '500 کرون سے زیادہ کے آرڈرز پر مفت ڈیلیوری',
+ // Property or array item — trailing comma allowed in TypeScript
+ total: 'کل',
+ // Property or array item — trailing comma allowed in TypeScript
+ proceedCheckout: 'چیک آؤٹ پر جائیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ continueShopping: 'خریداری جاری رکھیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ removeItem: 'آئٹم ہٹائیں',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 344: checkout: {
+ checkout: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'محفوظ چیک آؤٹ',
+ // Property or array item — trailing comma allowed in TypeScript
+ backToCart: 'ٹوکری پر واپس',
+ // Property or array item — trailing comma allowed in TypeScript
+ noItems: 'چیک آؤٹ کے لیے کوئی آئٹم نہیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ goToShop: 'خریداری پر جائیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderConfirmed: 'آرڈر کی تصدیق ہو گئی!',
+ // Property or array item — trailing comma allowed in TypeScript
+ thankYou: 'آپ کے آرڈر کا شکریہ۔ آپ کا پریمیم حلال گوشت تیار کیا جا رہا ہے۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderId: 'آرڈر آئی ڈی: {id}',
+ // Property or array item — trailing comma allowed in TypeScript
+ viewOrders: 'آرڈرز دیکھیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ haveAccount: 'اکاؤنٹ ہے؟',
+ // Property or array item — trailing comma allowed in TypeScript
+ signIn: 'سائن ان کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ fasterCheckout: 'تیز چیک آؤٹ کے لیے۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ deliveryDetails: 'ڈیلیوری کی تفصیلات',
+ // Property or array item — trailing comma allowed in TypeScript
+ fullName: 'پورا نام',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: 'ای میل',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: 'فون',
+ // Property or array item — trailing comma allowed in TypeScript
+ street: 'گلی کا پتہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ city: 'شہر',
+ // Property or array item — trailing comma allowed in TypeScript
+ state: 'صوبہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: 'پوسٹل کوڈ',
+ // Property or array item — trailing comma allowed in TypeScript
+ payment: 'ادائیگی',
+ // Property or array item — trailing comma allowed in TypeScript
+ creditCard: 'کریڈٹ کارڈ',
+ // Property or array item — trailing comma allowed in TypeScript
+ cashOnDelivery: 'ڈیلیوری پر نقد',
+ // Property or array item — trailing comma allowed in TypeScript
+ cardNumber: 'کارڈ نمبر',
+ // Property or array item — trailing comma allowed in TypeScript
+ expiry: 'میعاد',
+ // Property or array item — trailing comma allowed in TypeScript
+ cvv: 'CVV',
+ // Property or array item — trailing comma allowed in TypeScript
+ qty: 'مقدار: {count}',
+ // Property or array item — trailing comma allowed in TypeScript
+ processing: 'پروسیسنگ...',
+ // Property or array item — trailing comma allowed in TypeScript
+ pay: '{amount} ادا کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ secure: 'محفوظ 256 بٹ SSL انکرپشن',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 375: auth: {
+ auth: {
+ // Property or array item — trailing comma allowed in TypeScript
+ welcomeBack: 'خوش آمدید',
+ // Property or array item — trailing comma allowed in TypeScript
+ createAccount: 'اکاؤنٹ بنائیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ joinTagline: 'پریمیم شاپنگ کے تجربے کے لیے {name} میں شامل ہوں',
+ // Property or array item — trailing comma allowed in TypeScript
+ signInTagline: 'اپنے {name} اکاؤنٹ میں سائن ان کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ fullName: 'پورا نام',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: 'ای میل',
+ // Property or array item — trailing comma allowed in TypeScript
+ password: 'پاس ورڈ',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: 'فون',
+ // Property or array item — trailing comma allowed in TypeScript
+ street: 'گلی کا پتہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ city: 'شہر',
+ // Property or array item — trailing comma allowed in TypeScript
+ state: 'صوبہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: 'پوسٹل کوڈ',
+ // Property or array item — trailing comma allowed in TypeScript
+ signIn: 'سائن ان',
+ // Property or array item — trailing comma allowed in TypeScript
+ register: 'اکاؤنٹ بنائیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ hasAccount: 'پہلے سے اکاؤنٹ ہے؟ سائن ان کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ noAccount: 'اکاؤنٹ نہیں ہے؟ رجسٹر کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ invalidCredentials: 'غلط ای میل یا پاس ورڈ۔ {email} / demo123 آزمائیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ demo: 'ڈیمو: {email} / demo123',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 395: account: {
+ account: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'میرا اکاؤنٹ',
+ // Property or array item — trailing comma allowed in TypeScript
+ welcome: 'خوش آمدید، {name}',
+ // Property or array item — trailing comma allowed in TypeScript
+ memberSince: '{date} سے رکن',
+ // Property or array item — trailing comma allowed in TypeScript
+ myWishlist: 'میری پسندیدہ فہرست',
+ // Property or array item — trailing comma allowed in TypeScript
+ signOut: 'سائن آؤٹ',
+ // Property or array item — trailing comma allowed in TypeScript
+ orderHistory: 'آرڈر کی تاریخ',
+ // Property or array item — trailing comma allowed in TypeScript
+ noOrders: 'ابھی تک کوئی آرڈر نہیں',
+ // Property or array item — trailing comma allowed in TypeScript
+ startShopping: 'خریداری شروع کریں',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 405: wishlist: {
+ wishlist: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: 'میری پسندیدہ فہرست',
+ // Property or array item — trailing comma allowed in TypeScript
+ saved: '{count} محفوظ آئٹم',
+ // Property or array item — trailing comma allowed in TypeScript
+ empty: 'آپ کی پسندیدہ فہرست خالی ہے',
+ // Property or array item — trailing comma allowed in TypeScript
+ emptyHint: 'اپنی پسندیدہ مصنوعات محفوظ کریں تاکہ بعد میں خرید سکیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ browse: 'مصنوعات دیکھیں',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 412: about: {
+ about: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: '{name} کے بارے میں',
+ // Translated UI string for current language (sv / en / ur)
+ subtitle:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'پریمیم 100% حلال گوشت آپ کی میز تک — تازہ، حسب ضرورت اور احتیاط سے پہنچایا گیا۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ ourStory: 'ہماری کہانی',
+ // Line 417: storyP1:
+ storyP1:
+ // Property or array item — trailing comma allowed in TypeScript
+ '{name} ایک سادہ مشن کے ساتھ قائم ہوا: ہر خاندان کے لیے پریمیم حلال گوشت قابل رسائی بنانا، معیار، تازگی یا مذہبی تعمیل سے سمجھوتہ کیے بغیر۔ ہم سمجھتے ہیں کہ بہت سے گھروں کے لیے صحیح کٹ صحیح طریقے سے تیار کرنا عیش نہیں — یہ ضروری ہے۔',
+ // Line 419: storyP2:
+ storyP2:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'مرغی کے لیے ٹکڑوں کی تعداد منتخب کرنے سے لے کر گائے اور بکرے کے گوشت کے لیے نہاری یا کڑاہی کٹس کا انتخاب کرنے تک، ہم ہر آرڈر کے مرکز میں حسب ضرورت بناتے ہیں۔ ہمارے ماہر قصاب ہر آرڈر ہاتھ سے تیار کرتے ہیں، اور ہماری درجہ حرارت کنٹرولڈ ڈیلیوری یقینی بناتی ہے کہ آپ کا گوشت اسی دن کی طرح تازہ پہنچے جیسے کاٹا گیا تھا۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ halalTitle: 'حلال سرٹیفیکیشن',
+ // Line 422: halalDesc:
+ halalDesc:
+ // Property or array item — trailing comma allowed in TypeScript
+ '{name} کی ہر مصنوع تصدیق شدہ حلال سپلائرز سے حاصل کی جاتی ہے۔ ہمارا سپلائی چین مکمل طور پر قابل سراغ ہے، اور ہم حلال ذبح اور پروسیسنگ کے معیارات کی سخت تعمیل برقرار رکھتے ہیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshDaily: 'روزانہ تازہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ freshDailyDesc: 'ہر صبح قابل اعتماد فارموں سے حاصل',
+ // Property or array item — trailing comma allowed in TypeScript
+ premiumQuality: 'پریمیم معیار',
+ // Property or array item — trailing comma allowed in TypeScript
+ premiumQualityDesc: 'ماہر قصابوں کے ذریعے منتخب کردہ کٹس',
+ // Property or array item — trailing comma allowed in TypeScript
+ fastDelivery: 'تیز ڈیلیوری',
+ // Property or array item — trailing comma allowed in TypeScript
+ fastDeliveryDesc: 'درجہ حرارت کنٹرولڈ اسی دن کی ڈیلیوری',
+ // Property or array item — trailing comma allowed in TypeScript
+ deliveryTitle: 'ڈیلیوری کی معلومات',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery1: 'ہم اپنی پروسیسنگ سہولت سے 40 کلومیٹر کے دائرے میں ڈیلیوری کرتے ہیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery2: 'دوپہر 2 بجے سے پہلے کے آرڈرز اسی دن کی ڈیلیوری کے اہل ہیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery3: '500 کرون سے زیادہ کے آرڈرز پر مفت ڈیلیوری۔ معیاری ڈیلیوری فیس: 49 کرون۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivery4: 'تمام مصنوعات ویکیوم سیلڈ اور انسولیٹڈ پیکجنگ میں منتقل کی جاتی ہیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ contactTitle: 'ہم سے رابطہ کریں',
+ // Property or array item — trailing comma allowed in TypeScript
+ address: 'Tingvallavägen 11, 195 31 Märsta',
+ // Property or array item — trailing comma allowed in TypeScript
+ privacyTitle: 'رازداری کی پالیسی',
+ // Line 438: privacyText:
+ privacyText:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'ہم صرف وہ معلومات جمع کرتے ہیں جو آپ کے آرڈرز پر کارروائی کے لیے ضروری ہیں — نام، رابطے کی تفصیلات اور ڈیلیوری کا پتہ۔ ہم آپ کا ڈیٹا تیسرے فریق کو نہیں بیچتے۔ ادائیگی کی تفصیلات محفوظ طریقے سے ہمارے پارٹنرز کے ذریعے سنبھالی جاتی ہیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ termsTitle: 'سروس کی شرائط',
+ // Line 441: termsText:
+ termsText:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'تمام قیمتیں SEK میں دکھائی جاتی ہیں اور بغیر اطلاع کے تبدیل ہو سکتی ہیں۔ آرڈرز دستیابی پر منحصر ہیں۔ تمام گوشت کی مصنوعات پر حلال سرٹیفیکیشن لاگو ہوتا ہے۔ ڈیلیوری کے اوقات تخمینے ہیں اور مصروف اوقات میں مختلف ہو سکتے ہیں۔',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 444: footer: {
+ footer: {
+ // Line 445: tagline:
+ tagline:
+ // Property or array item — trailing comma allowed in TypeScript
+ 'پریمیم 100% حلال گوشت ڈیلیوری۔ تازہ، حسب ضرورت کٹس آپ کے دروازے تک بغیر کسی سمجھوتے کے معیار کے ساتھ پہنچائی جاتی ہیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ shop: 'خریداری',
+ // Property or array item — trailing comma allowed in TypeScript
+ company: 'کمپنی',
+ // Property or array item — trailing comma allowed in TypeScript
+ contact: 'رابطہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ rights: 'جملہ حقوق محفوظ ہیں۔',
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: '072-585 50 50',
+ // Property or array item — trailing comma allowed in TypeScript
+ hours: 'ہر دن کھلا {hours}',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 454: notFound: {
+ notFound: {
+ // Property or array item — trailing comma allowed in TypeScript
+ title: '404',
+ // Property or array item — trailing comma allowed in TypeScript
+ message: 'صفحہ نہیں ملا',
+ // Property or array item — trailing comma allowed in TypeScript
+ goHome: 'ہوم پر جائیں',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 459: orderStatus: {
+ orderStatus: {
+ // Property or array item — trailing comma allowed in TypeScript
+ pending: 'زیر التوا',
+ // Property or array item — trailing comma allowed in TypeScript
+ confirmed: 'تصدیق شدہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ preparing: 'تیاری میں',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'out-for-delivery': 'ڈیلیوری کے لیے روانہ',
+ // Property or array item — trailing comma allowed in TypeScript
+ delivered: 'پہنچا دیا گیا',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// Closing brace — end of block (function, if, object, JSX)
+};
diff --git a/docs/annotated/src/i18n/types.annotated.ts b/docs/annotated/src/i18n/types.annotated.ts
new file mode 100644
index 0000000..f1e93fb
--- /dev/null
+++ b/docs/annotated/src/i18n/types.annotated.ts
@@ -0,0 +1,28 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/i18n/types.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Export TypeScript type — defines data shape used across the app
+export type Locale = 'en' | 'sv' | 'ur';
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const LOCALES: { code: Locale; label: string; nativeLabel: string }[] = [
+ // Property or array item — trailing comma allowed in TypeScript
+ { code: 'sv', label: 'Swedish', nativeLabel: 'Svenska' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { code: 'en', label: 'English', nativeLabel: 'English' },
+ // Property or array item — trailing comma allowed in TypeScript
+ { code: 'ur', label: 'Urdu', nativeLabel: 'اردو' },
+// End of array literal
+];
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const DEFAULT_LOCALE: Locale = 'sv';
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export interface TranslationDict {
+ // Line 12: [key: string]: string | TranslationDict;
+ [key: string]: string | TranslationDict;
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/lib/constants.annotated.ts b/docs/annotated/src/lib/constants.annotated.ts
new file mode 100644
index 0000000..4ef893c
--- /dev/null
+++ b/docs/annotated/src/lib/constants.annotated.ts
@@ -0,0 +1,74 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/lib/constants.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { CutCount, CuttingStyleKey } from '@/types';
+// Import from a relative file in the same project
+import { IMAGES } from './images';
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const CUT_COUNTS: CutCount[] = [4, 8, 10, 12];
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const CUTTING_STYLE_KEYS: CuttingStyleKey[] = [
+ // Property or array item — trailing comma allowed in TypeScript
+ 'nihari',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'karahi',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'qeema',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'boneless',
+ // Property or array item — trailing comma allowed in TypeScript
+ 'steak',
+// End of array literal
+];
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const MEAT_CATEGORIES = ['chicken', 'beef', 'lamb'] as const;
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const CATEGORY_IDS = ['chicken', 'beef', 'lamb', 'fish'] as const;
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const CATEGORY_IMAGES = IMAGES.categories;
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const SITE_NAME = 'Kött Gård';
+// Named export constant — shared config/data imported elsewhere
+export const SITE_EMAIL = 'hello@kottgard.se';
+// Named export constant — shared config/data imported elsewhere
+export const DEMO_EMAIL = 'demo@kottgard.se';
+// Named export constant — shared config/data imported elsewhere
+export const SITE_PHONE = '+46 72 585 50 50';
+// Named export constant — shared config/data imported elsewhere
+export const SITE_PHONE_DISPLAY = '072-585 50 50';
+// Named export constant — shared config/data imported elsewhere
+export const SITE_ADDRESS = 'Tingvallavägen 11, 195 31 Märsta';
+// Named export constant — shared config/data imported elsewhere
+export const SITE_LOCATION = 'Märsta · Sverige';
+// Named export constant — shared config/data imported elsewhere
+export const SITE_HOURS = '10:00–19:00';
+// Named export constant — shared config/data imported elsewhere
+export const FACEBOOK_URL = 'https://www.facebook.com/kottgard/';
+// Named export constant — shared config/data imported elsewhere
+export const INSTAGRAM_URL = 'https://www.instagram.com/kottgard';
+// Named export constant — shared config/data imported elsewhere
+export const MAPS_URL = 'https://share.google/fUkkhDNlhDTcImKo5';
+// (blank line — separates logical blocks for readability)
+// Line 32: const WHATSAPP_BASE = 'Hej Kött Gård! Jag vill beställa';
+const WHATSAPP_BASE = 'Hej Kött Gård! Jag vill beställa';
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function whatsappOrderUrl(product?: string): string {
+ // Line 35: const text = product ? `${WHATSAPP_BASE} ${product}.` : `...
+ const text = product ? `${WHATSAPP_BASE} ${product}.` : `${WHATSAPP_BASE}.`;
+ // Return value from function
+ return `https://wa.me/46725855050?text=${encodeURIComponent(text)}`;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const WHATSAPP_URL = whatsappOrderUrl();
diff --git a/docs/annotated/src/lib/customization.annotated.ts b/docs/annotated/src/lib/customization.annotated.ts
new file mode 100644
index 0000000..9718c71
--- /dev/null
+++ b/docs/annotated/src/lib/customization.annotated.ts
@@ -0,0 +1,114 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/lib/customization.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { Category, MeatCustomization, ProductCustomization } from '@/types';
+// (blank line — separates logical blocks for readability)
+// TypeScript type alias — union or shorthand for complex types
+type Translator = (path: string, params?: Record) => string;
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function getDefaultCustomization(category: Category): ProductCustomization {
+ // Conditional branch — different behavior based on runtime value
+ if (category === 'fish') {
+ // Return value from function
+ return { type: 'fish' };
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Return value from function
+ return {
+ // Property or array item — trailing comma allowed in TypeScript
+ type: category,
+ // Property or array item — trailing comma allowed in TypeScript
+ cuts: 8,
+ // Property or array item — trailing comma allowed in TypeScript
+ cuttingStyle: 'karahi',
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function getCustomizationKey(customization: ProductCustomization): string {
+ // Conditional branch — different behavior based on runtime value
+ if (customization.type === 'fish') {
+ // Return value from function
+ return 'standard';
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Return value from function
+ return `cuts-${customization.cuts}::${customization.cuttingStyle}`;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function getCustomizationLabel(
+ // Property or array item — trailing comma allowed in TypeScript
+ customization: ProductCustomization,
+ // Line 25: t: Translator
+ t: Translator
+// Line 26: ): string {
+): string {
+ // Conditional branch — different behavior based on runtime value
+ if (customization.type === 'fish') {
+ // Return value from function
+ return t('product.standardCut');
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Return value from function
+ return t('product.cutsAndStyle', {
+ // Property or array item — trailing comma allowed in TypeScript
+ cuts: customization.cuts,
+ // Property or array item — trailing comma allowed in TypeScript
+ style: t(`cutting.${customization.cuttingStyle}`),
+ // Closing brace — end of block (function, if, object, JSX)
+ });
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function getCartItemKey(
+ // Property or array item — trailing comma allowed in TypeScript
+ productId: string,
+ // Line 38: customization: ProductCustomization
+ customization: ProductCustomization
+// Line 39: ): string {
+): string {
+ // Return value from function
+ return `${productId}::${getCustomizationKey(customization)}`;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function updateMeatCustomization(
+ // Property or array item — trailing comma allowed in TypeScript
+ current: ProductCustomization,
+ // Property or array item — trailing comma allowed in TypeScript
+ category: Category,
+ // Line 46: update: Partial>
+// Line 47: ): MeatCustomization {
+): MeatCustomization {
+ // Line 48: const base =
+ const base =
+ // Line 49: current.type !== 'fish' && current.type === category
+ current.type !== 'fish' && current.type === category
+ // Line 50: ? current
+ ? current
+ // Line 51: : (getDefaultCustomization(category) as MeatCustomization);
+ : (getDefaultCustomization(category) as MeatCustomization);
+// (blank line — separates logical blocks for readability)
+ // Return value from function
+ return {
+ // Property or array item — trailing comma allowed in TypeScript
+ type: category as MeatCustomization['type'],
+ // Property or array item — trailing comma allowed in TypeScript
+ cuts: update.cuts ?? base.cuts,
+ // Property or array item — trailing comma allowed in TypeScript
+ cuttingStyle: update.cuttingStyle ?? base.cuttingStyle,
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/lib/demo-orders.annotated.ts b/docs/annotated/src/lib/demo-orders.annotated.ts
new file mode 100644
index 0000000..1d832a4
--- /dev/null
+++ b/docs/annotated/src/lib/demo-orders.annotated.ts
@@ -0,0 +1,128 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/lib/demo-orders.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { Order } from '@/types';
+// Import from a relative file in the same project
+import { products } from './products';
+// Import from a relative file in the same project
+import { getDefaultCustomization, getCartItemKey } from './customization';
+// (blank line — separates logical blocks for readability)
+// Function declaration — reusable logic in this file
+function orderItem(
+ // Property or array item — trailing comma allowed in TypeScript
+ productId: string,
+ // Property or array item — trailing comma allowed in TypeScript
+ quantity: number,
+ // Line 8: customizationLabel: string
+ customizationLabel: string
+// Line 9: ) {
+) {
+ // Array.find — get first matching item or undefined
+ const product = products.find((p) => p.id === productId)!;
+ // Line 11: const customization = getDefaultCustomization(product.cat...
+ const customization = getDefaultCustomization(product.category);
+ // Return value from function
+ return {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: getCartItemKey(productId, customization),
+ // Property or array item — trailing comma allowed in TypeScript
+ product,
+ // Property or array item — trailing comma allowed in TypeScript
+ quantity,
+ // Property or array item — trailing comma allowed in TypeScript
+ customization,
+ // Property or array item — trailing comma allowed in TypeScript
+ customizationLabel,
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Line 21: const demoAddress = {
+const demoAddress = {
+ // Property or array item — trailing comma allowed in TypeScript
+ street: 'Tingvallavägen 11',
+ // Property or array item — trailing comma allowed in TypeScript
+ city: 'Märsta',
+ // Property or array item — trailing comma allowed in TypeScript
+ state: 'Stockholm',
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: '195 31',
+// Closing brace — end of block (function, if, object, JSX)
+};
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const DEMO_ORDERS: Order[] = [
+ // Line 29: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'KG-2026-0042',
+ // Line 31: items: [
+ items: [
+ // Property or array item — trailing comma allowed in TypeScript
+ orderItem('beef-steak', 2, '8 cuts · Karahi'),
+ // Property or array item — trailing comma allowed in TypeScript
+ orderItem('lamb-shoulder', 1, '8 cuts · Nihari'),
+ // End of array literal
+ ],
+ // Property or array item — trailing comma allowed in TypeScript
+ total: 647,
+ // Property or array item — trailing comma allowed in TypeScript
+ status: 'delivered',
+ // Property or array item — trailing comma allowed in TypeScript
+ createdAt: '2026-06-10T14:30:00.000Z',
+ // Property or array item — trailing comma allowed in TypeScript
+ deliveryAddress: demoAddress,
+ // Property or array item — trailing comma allowed in TypeScript
+ paymentMethod: 'card',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 41: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'KG-2026-0051',
+ // Line 43: items: [
+ items: [
+ // Property or array item — trailing comma allowed in TypeScript
+ orderItem('chicken-whole', 2, '8 cuts · Karahi'),
+ // Property or array item — trailing comma allowed in TypeScript
+ orderItem('beef-mince', 1, '8 cuts · Qeema'),
+ // Property or array item — trailing comma allowed in TypeScript
+ orderItem('fish-prawns', 1, 'Standard cut'),
+ // End of array literal
+ ],
+ // Property or array item — trailing comma allowed in TypeScript
+ total: 556,
+ // Property or array item — trailing comma allowed in TypeScript
+ status: 'out-for-delivery',
+ // Property or array item — trailing comma allowed in TypeScript
+ createdAt: '2026-06-16T09:15:00.000Z',
+ // Property or array item — trailing comma allowed in TypeScript
+ deliveryAddress: demoAddress,
+ // Property or array item — trailing comma allowed in TypeScript
+ paymentMethod: 'swish',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 54: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'KG-2026-0058',
+ // Property or array item — trailing comma allowed in TypeScript
+ items: [orderItem('lamb-leg', 1, '8 cuts · Steak'), orderItem('fish-salmon', 1, 'Standard cut')],
+ // Property or array item — trailing comma allowed in TypeScript
+ total: 418,
+ // Property or array item — trailing comma allowed in TypeScript
+ status: 'preparing',
+ // Property or array item — trailing comma allowed in TypeScript
+ createdAt: '2026-06-17T08:00:00.000Z',
+ // Property or array item — trailing comma allowed in TypeScript
+ deliveryAddress: demoAddress,
+ // Property or array item — trailing comma allowed in TypeScript
+ paymentMethod: 'card',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// End of array literal
+];
diff --git a/docs/annotated/src/lib/images.annotated.ts b/docs/annotated/src/lib/images.annotated.ts
new file mode 100644
index 0000000..3a7df26
--- /dev/null
+++ b/docs/annotated/src/lib/images.annotated.ts
@@ -0,0 +1,170 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/lib/images.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Block comment — documents the file or function below
+/**
+ // Block comment — documents the file or function below
+ * All imagery: raw, fresh, uncooked meat & seafood only.
+ // Block comment — documents the file or function below
+ * High-quality Unsplash photos (verified URLs).
+ // Block comment — documents the file or function below
+ */
+// (blank line — separates logical blocks for readability)
+// TypeScript type alias — union or shorthand for complex types
+type UnsplashOptions = {
+ // Line 7: height?: number;
+ height?: number;
+ // Line 8: crop?: 'center' | 'top' | 'bottom' | 'entropy';
+ crop?: 'center' | 'top' | 'bottom' | 'entropy';
+// Closing brace — end of block (function, if, object, JSX)
+};
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function unsplashUrl(
+ // Property or array item — trailing comma allowed in TypeScript
+ path: string,
+ // Property or array item — trailing comma allowed in TypeScript
+ width: number,
+ // Line 14: options?: UnsplashOptions
+ options?: UnsplashOptions
+// Line 15: ): string {
+): string {
+ // Line 16: const id = path.startsWith('photo-') ? path : `photo-${pa...
+ const id = path.startsWith('photo-') ? path : `photo-${path}`;
+ // Line 17: const params = new URLSearchParams({
+ const params = new URLSearchParams({
+ // Property or array item — trailing comma allowed in TypeScript
+ auto: 'format',
+ // Property or array item — trailing comma allowed in TypeScript
+ fit: 'crop',
+ // Property or array item — trailing comma allowed in TypeScript
+ w: String(width),
+ // Property or array item — trailing comma allowed in TypeScript
+ q: '90',
+ // Closing brace — end of block (function, if, object, JSX)
+ });
+ // Conditional branch — different behavior based on runtime value
+ if (options?.height) params.set('h', String(options.height));
+ // Conditional branch — different behavior based on runtime value
+ if (options?.crop) params.set('crop', options.crop);
+ // Return value from function
+ return `https://images.unsplash.com/${id}?${params.toString()}`;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Block comment — documents the file or function below
+/** Verified raw-meat & seafood Unsplash IDs */
+// Line 29: const RAW = {
+const RAW = {
+ // Property or array item — trailing comma allowed in TypeScript
+ butcherCounter: 'photo-1607623814075-e51df1bdc82f',
+ // Property or array item — trailing comma allowed in TypeScript
+ meatPrep: 'photo-1529692236671-f1f6cf9683ba',
+ // Property or array item — trailing comma allowed in TypeScript
+ chickenPieces: 'photo-1587593810167-a84920ea0781',
+ // Property or array item — trailing comma allowed in TypeScript
+ rawChicken: 'photo-1621996346565-e3dbc646d9a9',
+ // Property or array item — trailing comma allowed in TypeScript
+ beefSteaks: 'photo-1558030006-450675393462',
+ // Property or array item — trailing comma allowed in TypeScript
+ beefRibeye: 'photo-1559847844-5315695dadae',
+ // Property or array item — trailing comma allowed in TypeScript
+ lambRack: 'photo-1615937657715-bc7b4b7962c1',
+ // Property or array item — trailing comma allowed in TypeScript
+ beefCubes: 'photo-1546833999-b9f581a1996d',
+ // Property or array item — trailing comma allowed in TypeScript
+ beefMince: 'photo-1603048297172-c92544798d5a',
+ // Property or array item — trailing comma allowed in TypeScript
+ lambLeg: 'photo-1544025162-d76694265947',
+ // Property or array item — trailing comma allowed in TypeScript
+ lambChops: 'photo-1574672280600-4accfa5b6f98',
+ // Property or array item — trailing comma allowed in TypeScript
+ salmonFillet: 'photo-1544551763-46a013bb70d5',
+ // Property or array item — trailing comma allowed in TypeScript
+ rawPrawns: 'photo-1565680018434-b513d5e5fd47',
+ // Property or array item — trailing comma allowed in TypeScript
+ seafoodDisplay: 'photo-1504674900247-0877df9cc836',
+// Closing brace — end of block (function, if, object, JSX)
+} as const;
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const IMAGES = {
+ // Property or array item — trailing comma allowed in TypeScript
+ logo: '/images/kottgard-logo.jpeg',
+ // Property or array item — trailing comma allowed in TypeScript
+ hero: unsplashUrl(RAW.butcherCounter, 2560),
+ // Property or array item — trailing comma allowed in TypeScript
+ aboutMeat: unsplashUrl(RAW.meatPrep, 1920),
+ // Line 50: categories: {
+ categories: {
+ // Property or array item — trailing comma allowed in TypeScript
+ chicken: unsplashUrl(RAW.chickenPieces, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ beef: unsplashUrl(RAW.beefSteaks, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ lamb: unsplashUrl(RAW.lambRack, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ fish: unsplashUrl(RAW.salmonFillet, 1400),
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 56: products: {
+ products: {
+ // Property or array item — trailing comma allowed in TypeScript
+ 'chicken-whole': unsplashUrl(RAW.rawChicken, 1400),
+ // Line 58: 'chicken-breast': unsplashUrl(RAW.chickenPieces, 1400, {
+ 'chicken-breast': unsplashUrl(RAW.chickenPieces, 1400, {
+ // Property or array item — trailing comma allowed in TypeScript
+ height: 1000,
+ // Property or array item — trailing comma allowed in TypeScript
+ crop: 'center',
+ // Closing brace — end of block (function, if, object, JSX)
+ }),
+ // Line 62: 'chicken-thighs': unsplashUrl(RAW.rawChicken, 1400, {
+ 'chicken-thighs': unsplashUrl(RAW.rawChicken, 1400, {
+ // Property or array item — trailing comma allowed in TypeScript
+ height: 1100,
+ // Property or array item — trailing comma allowed in TypeScript
+ crop: 'entropy',
+ // Closing brace — end of block (function, if, object, JSX)
+ }),
+ // Line 66: 'chicken-wings': unsplashUrl(RAW.chickenPieces, 1400, {
+ 'chicken-wings': unsplashUrl(RAW.chickenPieces, 1400, {
+ // Property or array item — trailing comma allowed in TypeScript
+ height: 900,
+ // Property or array item — trailing comma allowed in TypeScript
+ crop: 'top',
+ // Closing brace — end of block (function, if, object, JSX)
+ }),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'beef-nihari': unsplashUrl(RAW.beefCubes, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'beef-steak': unsplashUrl(RAW.beefRibeye, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'beef-mince': unsplashUrl(RAW.beefMince, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'beef-boneless': unsplashUrl(RAW.beefSteaks, 1400, { height: 1000, crop: 'center' }),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'lamb-shoulder': unsplashUrl(RAW.lambRack, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'lamb-leg': unsplashUrl(RAW.lambLeg, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'lamb-chops': unsplashUrl(RAW.lambChops, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'lamb-mince': unsplashUrl(RAW.lambChops, 1400, { height: 1000, crop: 'center' }),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'fish-salmon': unsplashUrl(RAW.salmonFillet, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'fish-rohu': unsplashUrl(RAW.seafoodDisplay, 1400, { height: 1100, crop: 'entropy' }),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'fish-prawns': unsplashUrl(RAW.rawPrawns, 1400),
+ // Property or array item — trailing comma allowed in TypeScript
+ 'fish-basa': unsplashUrl(RAW.salmonFillet, 1400, { height: 900, crop: 'center' }),
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// Closing brace — end of block (function, if, object, JSX)
+} as const;
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const IMAGE_QUALITY = 90;
diff --git a/docs/annotated/src/lib/offers.annotated.ts b/docs/annotated/src/lib/offers.annotated.ts
new file mode 100644
index 0000000..47d3146
--- /dev/null
+++ b/docs/annotated/src/lib/offers.annotated.ts
@@ -0,0 +1,78 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/lib/offers.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { WeeklyOffer } from '@/types';
+// Import from a relative file in the same project
+import { IMAGES } from './images';
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const weeklyOffers: WeeklyOffer[] = [
+ // Line 5: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'chicken-wings-pl',
+ // Property or array item — trailing comma allowed in TypeScript
+ nameKey: 'offers.items.chickenWings',
+ // Property or array item — trailing comma allowed in TypeScript
+ badgeKey: 'fresh',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 49.99,
+ // Property or array item — trailing comma allowed in TypeScript
+ originalPrice: 59.99,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: IMAGES.products['chicken-wings'],
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsappProduct: 'Kycklingvingar färsk PL',
+ // Property or array item — trailing comma allowed in TypeScript
+ productSlug: 'chicken-wings',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 16: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'lamb-steak-ireland',
+ // Property or array item — trailing comma allowed in TypeScript
+ nameKey: 'offers.items.lambSteak',
+ // Property or array item — trailing comma allowed in TypeScript
+ badgeKey: 'halal',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 204.99,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: IMAGES.categories.lamb,
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsappProduct: 'Lammstek färsk Ireland',
+ // Property or array item — trailing comma allowed in TypeScript
+ productSlug: 'lamb-leg',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Line 26: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'beef-mince-irl',
+ // Property or array item — trailing comma allowed in TypeScript
+ nameKey: 'offers.items.beefMince',
+ // Property or array item — trailing comma allowed in TypeScript
+ badgeKey: 'fresh',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 139.99,
+ // Property or array item — trailing comma allowed in TypeScript
+ originalPrice: 159.99,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: IMAGES.products['beef-mince'],
+ // Property or array item — trailing comma allowed in TypeScript
+ whatsappProduct: 'Nötfärs 5% fett IRL',
+ // Property or array item — trailing comma allowed in TypeScript
+ productSlug: 'beef-mince',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// End of array literal
+];
diff --git a/docs/annotated/src/lib/product-i18n.annotated.ts b/docs/annotated/src/lib/product-i18n.annotated.ts
new file mode 100644
index 0000000..199b92f
--- /dev/null
+++ b/docs/annotated/src/lib/product-i18n.annotated.ts
@@ -0,0 +1,88 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/lib/product-i18n.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { Product } from '@/types';
+// (blank line — separates logical blocks for readability)
+// TypeScript type alias — union or shorthand for complex types
+type Translator = (path: string, params?: Record) => string;
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export interface LocalizedProduct {
+ // Line 6: id: string;
+ id: string;
+ // Line 7: slug: string;
+ slug: string;
+ // Line 8: category: Product['category'];
+ category: Product['category'];
+ // Line 9: name: string;
+ name: string;
+ // Line 10: description: string;
+ description: string;
+ // Line 11: longDescription: string;
+ longDescription: string;
+ // Line 12: price: number;
+ price: number;
+ // Line 13: priceUnit: string;
+ priceUnit: string;
+ // Line 14: image: string;
+ image: string;
+ // Line 15: images: string[];
+ images: string[];
+ // Line 16: badge?: string;
+ badge?: string;
+ // Line 17: inStock: boolean;
+ inStock: boolean;
+ // Line 18: featured: boolean;
+ featured: boolean;
+ // Line 19: weight?: string;
+ weight?: string;
+ // Line 20: tags: string[];
+ tags: string[];
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function localizeProduct(product: Product, t: Translator): LocalizedProduct {
+ // Line 24: const base = `products.${product.id}`;
+ const base = `products.${product.id}`;
+// (blank line — separates logical blocks for readability)
+ // Return value from function
+ return {
+ // Property or array item — trailing comma allowed in TypeScript
+ ...product,
+ // Property or array item — trailing comma allowed in TypeScript
+ name: t(`${base}.name`),
+ // Property or array item — trailing comma allowed in TypeScript
+ description: t(`${base}.description`),
+ // Property or array item — trailing comma allowed in TypeScript
+ longDescription: t(`${base}.longDescription`),
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnit: t(`priceUnit.${product.priceUnitKey}`),
+ // Property or array item — trailing comma allowed in TypeScript
+ badge: product.badgeKey ? t(`badges.${product.badgeKey}`) : undefined,
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function localizeCategory(
+ // Property or array item — trailing comma allowed in TypeScript
+ categoryId: Product['category'],
+ // Line 38: t: Translator
+ t: Translator
+// Line 39: ): { name: string; description: string } {
+): { name: string; description: string } {
+ // Return value from function
+ return {
+ // Property or array item — trailing comma allowed in TypeScript
+ name: t(`categories.${categoryId}.name`),
+ // Property or array item — trailing comma allowed in TypeScript
+ description: t(`categories.${categoryId}.description`),
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/lib/products.annotated.ts b/docs/annotated/src/lib/products.annotated.ts
new file mode 100644
index 0000000..9cb8922
--- /dev/null
+++ b/docs/annotated/src/lib/products.annotated.ts
@@ -0,0 +1,464 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/lib/products.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { Product } from '@/types';
+// Import from a relative file in the same project
+import { IMAGES } from './images';
+// (blank line — separates logical blocks for readability)
+// Product catalog entry — demo data shown in shop and product pages
+const P = IMAGES.products;
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const products: Product[] = [
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'chicken-whole',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'whole-chicken',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'chicken',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 129,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perBird',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['chicken-whole'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['chicken-whole'], P['chicken-breast']],
+ // Property or array item — trailing comma allowed in TypeScript
+ badgeKey: 'bestseller',
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '1.2–1.5 kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'whole', 'popular'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'chicken-breast',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'chicken-breast',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'chicken',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 99,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perPack',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['chicken-breast'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['chicken-breast'], P['chicken-whole']],
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '500g–1kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'boneless', 'lean'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'chicken-thighs',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'chicken-thighs',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'chicken',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 85,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perPack',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['chicken-thighs'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['chicken-thighs']],
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: false,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '500g–1kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'juicy'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'chicken-wings',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'chicken-wings',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'chicken',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 79,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perPack',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['chicken-wings'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['chicken-wings']],
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: false,
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'party'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'beef-nihari',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'beef-for-nihari',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'beef',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 149,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['beef-nihari'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['beef-nihari'], P['beef-steak']],
+ // Property or array item — trailing comma allowed in TypeScript
+ badgeKey: 'chefsPick',
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '1 kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'traditional'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'beef-steak',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'premium-beef-steak',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'beef',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 229,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['beef-steak'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['beef-steak'], P['beef-nihari']],
+ // Property or array item — trailing comma allowed in TypeScript
+ badgeKey: 'premium',
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '1 kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['premium', 'steak'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'beef-mince',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'beef-mince',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'beef',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 119,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['beef-mince'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['beef-mince']],
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: false,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '500g–1kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'mince'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'beef-boneless',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'boneless-beef-cubes',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'beef',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 169,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['beef-boneless'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['beef-boneless']],
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: false,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '1 kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'boneless'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'lamb-shoulder',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'lamb-shoulder',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'lamb',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 189,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['lamb-shoulder'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['lamb-shoulder'], P['lamb-leg']],
+ // Property or array item — trailing comma allowed in TypeScript
+ badgeKey: 'popular',
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '1 kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'traditional'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'lamb-leg',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'lamb-leg',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'lamb',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 219,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['lamb-leg'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['lamb-leg']],
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '1–2 kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['premium', 'roast'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'lamb-chops',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'lamb-chops',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'lamb',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 249,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['lamb-chops'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['lamb-chops']],
+ // Property or array item — trailing comma allowed in TypeScript
+ badgeKey: 'premium',
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: false,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '500g',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['premium', 'grill'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'lamb-mince',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'lamb-mince',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'lamb',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 159,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['lamb-mince'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['lamb-mince']],
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: false,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '500g–1kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'mince'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'fish-salmon',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'atlantic-salmon-fillet',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'fish',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 199,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['fish-salmon'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['fish-salmon'], P['fish-rohu']],
+ // Property or array item — trailing comma allowed in TypeScript
+ badgeKey: 'freshCatch',
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '500g',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'fillet'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'fish-rohu',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'rohu-fish',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'fish',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 119,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['fish-rohu'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['fish-rohu']],
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '1–1.5 kg',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'whole'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'fish-prawns',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'jumbo-prawns',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'fish',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 179,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['fish-prawns'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['fish-prawns']],
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: false,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '500g',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'seafood'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Product catalog entry — demo data shown in shop and product pages
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'fish-basa',
+ // Property or array item — trailing comma allowed in TypeScript
+ slug: 'basa-fillet',
+ // Property or array item — trailing comma allowed in TypeScript
+ category: 'fish',
+ // Property or array item — trailing comma allowed in TypeScript
+ price: 109,
+ // Property or array item — trailing comma allowed in TypeScript
+ priceUnitKey: 'perKg',
+ // Property or array item — trailing comma allowed in TypeScript
+ image: P['fish-basa'],
+ // Property or array item — trailing comma allowed in TypeScript
+ images: [P['fish-basa']],
+ // Property or array item — trailing comma allowed in TypeScript
+ inStock: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ featured: false,
+ // Property or array item — trailing comma allowed in TypeScript
+ weight: '500g',
+ // Property or array item — trailing comma allowed in TypeScript
+ tags: ['fresh', 'fillet', 'mild'],
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// End of array literal
+];
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function getProductBySlug(slug: string): Product | undefined {
+ // Return value from function
+ return products.find((p) => p.slug === slug);
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function getProductsByCategory(category: string): Product[] {
+ // Return value from function
+ return products.filter((p) => p.category === category);
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function getFeaturedProducts(): Product[] {
+ // Return value from function
+ return products.filter((p) => p.featured);
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/lib/utils.annotated.ts b/docs/annotated/src/lib/utils.annotated.ts
new file mode 100644
index 0000000..01f9796
--- /dev/null
+++ b/docs/annotated/src/lib/utils.annotated.ts
@@ -0,0 +1,59 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/lib/utils.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Import external package or local module
+import { clsx, type ClassValue } from 'clsx';
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function cn(...inputs: ClassValue[]) {
+ // Return value from function
+ return clsx(inputs);
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function formatPrice(price: number, locale = 'sv-SE'): string {
+ // Return value from function
+ return new Intl.NumberFormat(locale, {
+ // Property or array item — trailing comma allowed in TypeScript
+ style: 'currency',
+ // Property or array item — trailing comma allowed in TypeScript
+ currency: 'SEK',
+ // Closing brace — end of block (function, if, object, JSX)
+ }).format(price);
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function getFormatLocale(locale: string): string {
+ // Line 15: const map: Record = {
+ const map: Record = {
+ // Property or array item — trailing comma allowed in TypeScript
+ en: 'en-US',
+ // Property or array item — trailing comma allowed in TypeScript
+ sv: 'sv-SE',
+ // Property or array item — trailing comma allowed in TypeScript
+ ur: 'ur-PK',
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+ // Return value from function
+ return map[locale] ?? 'en-US';
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function formatDate(date: string): string {
+ // Return value from function
+ return new Intl.DateTimeFormat('en-US', {
+ // Property or array item — trailing comma allowed in TypeScript
+ year: 'numeric',
+ // Property or array item — trailing comma allowed in TypeScript
+ month: 'long',
+ // Property or array item — trailing comma allowed in TypeScript
+ day: 'numeric',
+ // Closing brace — end of block (function, if, object, JSX)
+ }).format(new Date(date));
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/annotated/src/store/auth.annotated.ts b/docs/annotated/src/store/auth.annotated.ts
new file mode 100644
index 0000000..d145a73
--- /dev/null
+++ b/docs/annotated/src/store/auth.annotated.ts
@@ -0,0 +1,179 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/store/auth.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Zustand — simple global state store (cart, auth, locale)
+import { create } from 'zustand';
+// Zustand — simple global state store (cart, auth, locale)
+import { persist } from 'zustand/middleware';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { Address, Order, User } from '@/types';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { DEMO_EMAIL } from '@/lib/constants';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { DEMO_ORDERS } from '@/lib/demo-orders';
+// (blank line — separates logical blocks for readability)
+// TypeScript interface — contract for object properties and methods
+interface AuthState {
+ // Line 8: user: User | null;
+ user: User | null;
+ // Line 9: orders: Order[];
+ orders: Order[];
+ // Line 10: isAuthenticated: boolean;
+ isAuthenticated: boolean;
+ // Line 11: login: (email: string, password: string) => boolean;
+ login: (email: string, password: string) => boolean;
+ // Line 12: register: (data: {
+ register: (data: {
+ // Line 13: name: string;
+ name: string;
+ // Line 14: email: string;
+ email: string;
+ // Line 15: password: string;
+ password: string;
+ // Line 16: phone: string;
+ phone: string;
+ // Line 17: address: Address;
+ address: Address;
+ // Closing brace — end of block (function, if, object, JSX)
+ }) => boolean;
+ // Line 19: logout: () => void;
+ logout: () => void;
+ // Line 20: updateProfile: (data: Partial) => void;
+ updateProfile: (data: Partial) => void;
+ // Line 21: addOrder: (order: Order) => void;
+ addOrder: (order: Order) => void;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Line 24: const DEMO_USER: User = {
+const DEMO_USER: User = {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: 'demo-1',
+ // Property or array item — trailing comma allowed in TypeScript
+ name: 'Ahmed Khan',
+ // Property or array item — trailing comma allowed in TypeScript
+ email: DEMO_EMAIL,
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: '+46 72 585 50 50',
+ // Line 29: address: {
+ address: {
+ // Property or array item — trailing comma allowed in TypeScript
+ street: 'Tingvallavägen 11',
+ // Property or array item — trailing comma allowed in TypeScript
+ city: 'Märsta',
+ // Property or array item — trailing comma allowed in TypeScript
+ state: 'Stockholm',
+ // Property or array item — trailing comma allowed in TypeScript
+ zip: '195 31',
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Property or array item — trailing comma allowed in TypeScript
+ createdAt: '2025-03-15T10:00:00.000Z',
+// Closing brace — end of block (function, if, object, JSX)
+};
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const useAuthStore = create()(
+ // Zustand persist — save store to localStorage between visits
+ persist(
+ // Line 40: (set, get) => ({
+ (set, get) => ({
+ // Property or array item — trailing comma allowed in TypeScript
+ user: null,
+ // Property or array item — trailing comma allowed in TypeScript
+ orders: [],
+ // Property or array item — trailing comma allowed in TypeScript
+ isAuthenticated: false,
+// (blank line — separates logical blocks for readability)
+ // Line 45: login: (email, password) => {
+ login: (email, password) => {
+ // Conditional branch — different behavior based on runtime value
+ if (email === DEMO_EMAIL && password === 'demo123') {
+ // Line 47: const existingOrders = get().orders;
+ const existingOrders = get().orders;
+ // Line 48: set({
+ set({
+ // Property or array item — trailing comma allowed in TypeScript
+ user: DEMO_USER,
+ // Property or array item — trailing comma allowed in TypeScript
+ isAuthenticated: true,
+ // Property or array item — trailing comma allowed in TypeScript
+ orders: existingOrders.length > 0 ? existingOrders : DEMO_ORDERS,
+ // Closing brace — end of block (function, if, object, JSX)
+ });
+ // Return value from function
+ return true;
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Line 55: const stored = get().user;
+ const stored = get().user;
+ // Conditional branch — different behavior based on runtime value
+ if (stored && stored.email === email) {
+ // Line 57: set({ isAuthenticated: true });
+ set({ isAuthenticated: true });
+ // Return value from function
+ return true;
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Return value from function
+ return false;
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// (blank line — separates logical blocks for readability)
+ // Line 63: register: (data) => {
+ register: (data) => {
+ // Line 64: const user: User = {
+ const user: User = {
+ // Property or array item — trailing comma allowed in TypeScript
+ id: `user-${Date.now()}`,
+ // Property or array item — trailing comma allowed in TypeScript
+ name: data.name,
+ // Property or array item — trailing comma allowed in TypeScript
+ email: data.email,
+ // Property or array item — trailing comma allowed in TypeScript
+ phone: data.phone,
+ // Property or array item — trailing comma allowed in TypeScript
+ address: data.address,
+ // Property or array item — trailing comma allowed in TypeScript
+ createdAt: new Date().toISOString(),
+ // Closing brace — end of block (function, if, object, JSX)
+ };
+ // Line 72: set({ user, isAuthenticated: true });
+ set({ user, isAuthenticated: true });
+ // Return value from function
+ return true;
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// (blank line — separates logical blocks for readability)
+ // Property or array item — trailing comma allowed in TypeScript
+ logout: () => set({ isAuthenticated: false }),
+// (blank line — separates logical blocks for readability)
+ // Line 78: updateProfile: (data) => {
+ updateProfile: (data) => {
+ // Line 79: const current = get().user;
+ const current = get().user;
+ // Conditional branch — different behavior based on runtime value
+ if (current) {
+ // Line 81: set({ user: { ...current, ...data } });
+ set({ user: { ...current, ...data } });
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// (blank line — separates logical blocks for readability)
+ // Line 85: addOrder: (order) => {
+ addOrder: (order) => {
+ // Line 86: set({ orders: [order, ...get().orders] });
+ set({ orders: [order, ...get().orders] });
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ }),
+ // Line 89: { name: 'kott-gard-auth' }
+ { name: 'kott-gard-auth' }
+ // Line 90: )
+ )
+// Line 91: );
+);
diff --git a/docs/annotated/src/store/cart.annotated.ts b/docs/annotated/src/store/cart.annotated.ts
new file mode 100644
index 0000000..1b9a0fa
--- /dev/null
+++ b/docs/annotated/src/store/cart.annotated.ts
@@ -0,0 +1,164 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/store/cart.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Zustand — simple global state store (cart, auth, locale)
+import { create } from 'zustand';
+// Zustand — simple global state store (cart, auth, locale)
+import { persist } from 'zustand/middleware';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { CartItem, Product, ProductCustomization } from '@/types';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { getCartItemKey } from '@/lib/customization';
+// (blank line — separates logical blocks for readability)
+// TypeScript interface — contract for object properties and methods
+interface CartState {
+ // Line 7: items: CartItem[];
+ items: CartItem[];
+ // Line 8: addItem: (
+ addItem: (
+ // Property or array item — trailing comma allowed in TypeScript
+ product: Product,
+ // Property or array item — trailing comma allowed in TypeScript
+ customization: ProductCustomization,
+ // Property or array item — trailing comma allowed in TypeScript
+ customizationLabel: string,
+ // Line 12: quantity?: number
+ quantity?: number
+ // Line 13: ) => void;
+ ) => void;
+ // Line 14: removeItem: (id: string) => void;
+ removeItem: (id: string) => void;
+ // Line 15: updateQuantity: (id: string, quantity: number) => void;
+ updateQuantity: (id: string, quantity: number) => void;
+ // Line 16: clearCart: () => void;
+ clearCart: () => void;
+ // Line 17: getTotal: () => number;
+ getTotal: () => number;
+ // Line 18: getItemCount: () => number;
+ getItemCount: () => number;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const useCartStore = create()(
+ // Zustand persist — save store to localStorage between visits
+ persist(
+ // Line 23: (set, get) => ({
+ (set, get) => ({
+ // Property or array item — trailing comma allowed in TypeScript
+ items: [],
+// (blank line — separates logical blocks for readability)
+ // Line 26: addItem: (product, customization, customizationLabel, qua...
+ addItem: (product, customization, customizationLabel, quantity = 1) => {
+ // Line 27: const id = getCartItemKey(product.id, customization);
+ const id = getCartItemKey(product.id, customization);
+ // Line 28: const label = customizationLabel;
+ const label = customizationLabel;
+ // Array.find — get first matching item or undefined
+ const existing = get().items.find((item) => item.id === id);
+// (blank line — separates logical blocks for readability)
+ // Conditional branch — different behavior based on runtime value
+ if (existing) {
+ // Line 32: set({
+ set({
+ // Array.map — transform each item (often render a list of components)
+ items: get().items.map((item) =>
+ // Line 34: item.id === id
+ item.id === id
+ // Line 35: ? { ...item, quantity: item.quantity + quantity }
+ ? { ...item, quantity: item.quantity + quantity }
+ // Line 36: : item
+ : item
+ // Property or array item — trailing comma allowed in TypeScript
+ ),
+ // Closing brace — end of block (function, if, object, JSX)
+ });
+ // Closing brace — end of block (function, if, object, JSX)
+ } else {
+ // Line 40: set({
+ set({
+ // Line 41: items: [
+ items: [
+ // Property or array item — trailing comma allowed in TypeScript
+ ...get().items,
+ // Line 43: {
+ {
+ // Property or array item — trailing comma allowed in TypeScript
+ id,
+ // Property or array item — trailing comma allowed in TypeScript
+ product,
+ // Property or array item — trailing comma allowed in TypeScript
+ quantity,
+ // Property or array item — trailing comma allowed in TypeScript
+ customization,
+ // Property or array item — trailing comma allowed in TypeScript
+ customizationLabel: label,
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // End of array literal
+ ],
+ // Closing brace — end of block (function, if, object, JSX)
+ });
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// (blank line — separates logical blocks for readability)
+ // Line 55: removeItem: (id) => {
+ removeItem: (id) => {
+ // Array.filter — keep items matching condition (search, category)
+ set({ items: get().items.filter((item) => item.id !== id) });
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// (blank line — separates logical blocks for readability)
+ // Line 59: updateQuantity: (id, quantity) => {
+ updateQuantity: (id, quantity) => {
+ // Conditional branch — different behavior based on runtime value
+ if (quantity <= 0) {
+ // Line 61: get().removeItem(id);
+ get().removeItem(id);
+ // Line 62: return;
+ return;
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Line 64: set({
+ set({
+ // Array.map — transform each item (often render a list of components)
+ items: get().items.map((item) =>
+ // Line 66: item.id === id ? { ...item, quantity } : item
+ item.id === id ? { ...item, quantity } : item
+ // Property or array item — trailing comma allowed in TypeScript
+ ),
+ // Closing brace — end of block (function, if, object, JSX)
+ });
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// (blank line — separates logical blocks for readability)
+ // Property or array item — trailing comma allowed in TypeScript
+ clearCart: () => set({ items: [] }),
+// (blank line — separates logical blocks for readability)
+ // Line 73: getTotal: () =>
+ getTotal: () =>
+ // Array.reduce — accumulate single value (cart total, item count)
+ get().items.reduce(
+ // Property or array item — trailing comma allowed in TypeScript
+ (sum, item) => sum + item.product.price * item.quantity,
+ // Line 76: 0
+ 0
+ // Property or array item — trailing comma allowed in TypeScript
+ ),
+// (blank line — separates logical blocks for readability)
+ // Line 79: getItemCount: () =>
+ getItemCount: () =>
+ // Array.reduce — accumulate single value (cart total, item count)
+ get().items.reduce((sum, item) => sum + item.quantity, 0),
+ // Closing brace — end of block (function, if, object, JSX)
+ }),
+ // Line 82: { name: 'kott-gard-cart' }
+ { name: 'kott-gard-cart' }
+ // Line 83: )
+ )
+// Line 84: );
+);
diff --git a/docs/annotated/src/store/locale.annotated.ts b/docs/annotated/src/store/locale.annotated.ts
new file mode 100644
index 0000000..8ba905d
--- /dev/null
+++ b/docs/annotated/src/store/locale.annotated.ts
@@ -0,0 +1,39 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/store/locale.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Zustand — simple global state store (cart, auth, locale)
+import { create } from 'zustand';
+// Zustand — simple global state store (cart, auth, locale)
+import { persist } from 'zustand/middleware';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { DEFAULT_LOCALE, Locale } from '@/i18n/types';
+// (blank line — separates logical blocks for readability)
+// TypeScript interface — contract for object properties and methods
+interface LocaleState {
+ // Line 6: locale: Locale;
+ locale: Locale;
+ // Line 7: setLocale: (locale: Locale) => void;
+ setLocale: (locale: Locale) => void;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const useLocaleStore = create()(
+ // Zustand persist — save store to localStorage between visits
+ persist(
+ // Line 12: (set) => ({
+ (set) => ({
+ // Property or array item — trailing comma allowed in TypeScript
+ locale: DEFAULT_LOCALE,
+ // Property or array item — trailing comma allowed in TypeScript
+ setLocale: (locale) => set({ locale }),
+ // Closing brace — end of block (function, if, object, JSX)
+ }),
+ // Line 16: { name: 'kott-gard-locale' }
+ { name: 'kott-gard-locale' }
+ // Line 17: )
+ )
+// Line 18: );
+);
diff --git a/docs/annotated/src/store/wishlist.annotated.ts b/docs/annotated/src/store/wishlist.annotated.ts
new file mode 100644
index 0000000..0efec67
--- /dev/null
+++ b/docs/annotated/src/store/wishlist.annotated.ts
@@ -0,0 +1,81 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/store/wishlist.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Zustand — simple global state store (cart, auth, locale)
+import { create } from 'zustand';
+// Zustand — simple global state store (cart, auth, locale)
+import { persist } from 'zustand/middleware';
+// Import project module (@/ alias = src/ folder in tsconfig)
+import { Product } from '@/types';
+// (blank line — separates logical blocks for readability)
+// TypeScript interface — contract for object properties and methods
+interface WishlistState {
+ // Line 6: items: Product[];
+ items: Product[];
+ // Line 7: addItem: (product: Product) => void;
+ addItem: (product: Product) => void;
+ // Line 8: removeItem: (productId: string) => void;
+ removeItem: (productId: string) => void;
+ // Line 9: isInWishlist: (productId: string) => boolean;
+ isInWishlist: (productId: string) => boolean;
+ // Line 10: toggleItem: (product: Product) => void;
+ toggleItem: (product: Product) => void;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Named export constant — shared config/data imported elsewhere
+export const useWishlistStore = create()(
+ // Zustand persist — save store to localStorage between visits
+ persist(
+ // Line 15: (set, get) => ({
+ (set, get) => ({
+ // Property or array item — trailing comma allowed in TypeScript
+ items: [],
+// (blank line — separates logical blocks for readability)
+ // Line 18: addItem: (product) => {
+ addItem: (product) => {
+ // Conditional branch — different behavior based on runtime value
+ if (!get().isInWishlist(product.id)) {
+ // Line 20: set({ items: [...get().items, product] });
+ set({ items: [...get().items, product] });
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// (blank line — separates logical blocks for readability)
+ // Line 24: removeItem: (productId) => {
+ removeItem: (productId) => {
+ // Array.filter — keep items matching condition (search, category)
+ set({ items: get().items.filter((p) => p.id !== productId) });
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+// (blank line — separates logical blocks for readability)
+ // Line 28: isInWishlist: (productId) =>
+ isInWishlist: (productId) =>
+ // Property or array item — trailing comma allowed in TypeScript
+ get().items.some((p) => p.id === productId),
+// (blank line — separates logical blocks for readability)
+ // Line 31: toggleItem: (product) => {
+ toggleItem: (product) => {
+ // Conditional branch — different behavior based on runtime value
+ if (get().isInWishlist(product.id)) {
+ // Line 33: get().removeItem(product.id);
+ get().removeItem(product.id);
+ // Closing brace — end of block (function, if, object, JSX)
+ } else {
+ // Line 35: get().addItem(product);
+ get().addItem(product);
+ // Closing brace — end of block (function, if, object, JSX)
+ }
+ // Closing brace — end of block (function, if, object, JSX)
+ },
+ // Closing brace — end of block (function, if, object, JSX)
+ }),
+ // Line 39: { name: 'kott-gard-wishlist' }
+ { name: 'kott-gard-wishlist' }
+ // Line 40: )
+ )
+// Line 41: );
+);
diff --git a/docs/annotated/src/types/index.annotated.ts b/docs/annotated/src/types/index.annotated.ts
new file mode 100644
index 0000000..5daa183
--- /dev/null
+++ b/docs/annotated/src/types/index.annotated.ts
@@ -0,0 +1,168 @@
+/**
+ * ANNOTATED COPY — every line explained
+ * Source: src/types/index.ts
+ * NOT used by the app — read this to learn how the real file works
+ */
+// Export TypeScript type — defines data shape used across the app
+export type Category = 'chicken' | 'beef' | 'lamb' | 'fish';
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export type CutCount = 4 | 8 | 10 | 12;
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export type CuttingStyleKey = 'nihari' | 'karahi' | 'qeema' | 'boneless' | 'steak';
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export type MeatCategory = 'chicken' | 'beef' | 'lamb';
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export interface MeatCustomization {
+ // Line 10: type: MeatCategory;
+ type: MeatCategory;
+ // Line 11: cuts: CutCount;
+ cuts: CutCount;
+ // Line 12: cuttingStyle: CuttingStyleKey;
+ cuttingStyle: CuttingStyleKey;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export type ProductCustomization = MeatCustomization | { type: 'fish' };
+// (blank line — separates logical blocks for readability)
+// Named export — utility function other files can import
+export function isMeatCustomization(
+ // Line 18: customization: ProductCustomization
+ customization: ProductCustomization
+// Line 19: ): customization is MeatCustomization {
+): customization is MeatCustomization {
+ // Return value from function
+ return customization.type !== 'fish';
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export type PriceUnitKey = 'perBird' | 'perPack' | 'perKg';
+// Export TypeScript type — defines data shape used across the app
+export type BadgeKey = 'bestseller' | 'chefsPick' | 'premium' | 'popular' | 'freshCatch';
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export interface Product {
+ // Line 27: id: string;
+ id: string;
+ // Line 28: slug: string;
+ slug: string;
+ // Line 29: category: Category;
+ category: Category;
+ // Line 30: price: number;
+ price: number;
+ // Line 31: priceUnitKey: PriceUnitKey;
+ priceUnitKey: PriceUnitKey;
+ // Line 32: image: string;
+ image: string;
+ // Line 33: images: string[];
+ images: string[];
+ // Line 34: badgeKey?: BadgeKey;
+ badgeKey?: BadgeKey;
+ // Line 35: inStock: boolean;
+ inStock: boolean;
+ // Line 36: featured: boolean;
+ featured: boolean;
+ // Line 37: weight?: string;
+ weight?: string;
+ // Line 38: tags: string[];
+ tags: string[];
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export interface CartItem {
+ // Line 42: id: string;
+ id: string;
+ // Line 43: product: Product;
+ product: Product;
+ // Line 44: quantity: number;
+ quantity: number;
+ // Line 45: customization: ProductCustomization;
+ customization: ProductCustomization;
+ // Line 46: customizationLabel: string;
+ customizationLabel: string;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export interface User {
+ // Line 50: id: string;
+ id: string;
+ // Line 51: name: string;
+ name: string;
+ // Line 52: email: string;
+ email: string;
+ // Line 53: phone: string;
+ phone: string;
+ // Line 54: address: Address;
+ address: Address;
+ // Line 55: createdAt: string;
+ createdAt: string;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export interface Address {
+ // Line 59: street: string;
+ street: string;
+ // Line 60: city: string;
+ city: string;
+ // Line 61: state: string;
+ state: string;
+ // Line 62: zip: string;
+ zip: string;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export interface Order {
+ // Line 66: id: string;
+ id: string;
+ // Line 67: items: CartItem[];
+ items: CartItem[];
+ // Line 68: total: number;
+ total: number;
+ // Line 69: status: 'pending' | 'confirmed' | 'preparing' | 'out-for-...
+ status: 'pending' | 'confirmed' | 'preparing' | 'out-for-delivery' | 'delivered';
+ // Line 70: createdAt: string;
+ createdAt: string;
+ // Line 71: deliveryAddress: Address;
+ deliveryAddress: Address;
+ // Line 72: paymentMethod: string;
+ paymentMethod: string;
+// Closing brace — end of block (function, if, object, JSX)
+}
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export type SortOption = 'featured' | 'price-asc' | 'price-desc' | 'name';
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export type OfferBadgeKey = 'fresh' | 'halal';
+// (blank line — separates logical blocks for readability)
+// Export TypeScript type — defines data shape used across the app
+export interface WeeklyOffer {
+ // Line 80: id: string;
+ id: string;
+ // Line 81: nameKey: string;
+ nameKey: string;
+ // Line 82: badgeKey: OfferBadgeKey;
+ badgeKey: OfferBadgeKey;
+ // Line 83: price: number;
+ price: number;
+ // Line 84: originalPrice?: number;
+ originalPrice?: number;
+ // Line 85: priceUnitKey: PriceUnitKey;
+ priceUnitKey: PriceUnitKey;
+ // Line 86: image: string;
+ image: string;
+ // Line 87: whatsappProduct: string;
+ whatsappProduct: string;
+ // Line 88: productSlug: string;
+ productSlug: string;
+// Closing brace — end of block (function, if, object, JSX)
+}
diff --git a/docs/generate-guide-docx.mjs b/docs/generate-guide-docx.mjs
new file mode 100644
index 0000000..8a43e95
--- /dev/null
+++ b/docs/generate-guide-docx.mjs
@@ -0,0 +1,272 @@
+/**
+ * Generates Kottgard-Website-Guide.docx
+ * Run: node docs/generate-guide-docx.mjs
+ */
+import fs from 'fs';
+import path from 'path';
+import { fileURLToPath } from 'url';
+import {
+ Document,
+ Packer,
+ Paragraph,
+ TextRun,
+ Table,
+ TableRow,
+ TableCell,
+ HeadingLevel,
+ AlignmentType,
+ BorderStyle,
+ WidthType,
+ ShadingType,
+ PageBreak,
+ LevelFormat,
+} from 'docx';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const outPath = path.join(__dirname, 'Kottgard-Website-Guide.docx');
+
+const border = { style: BorderStyle.SINGLE, size: 1, color: 'CCCCCC' };
+const borders = { top: border, bottom: border, left: border, right: border };
+const tableWidth = 9360;
+
+function cell(text, width, fill = 'FFFFFF') {
+ return new TableCell({
+ borders,
+ width: { size: width, type: WidthType.DXA },
+ shading: { fill, type: ShadingType.CLEAR },
+ margins: { top: 80, bottom: 80, left: 120, right: 120 },
+ children: [new Paragraph({ children: [new TextRun(text)] })],
+ });
+}
+
+function headerRow(cols, widths) {
+ return new TableRow({
+ children: cols.map((t, i) => cell(t, widths[i], 'D5E8F0')),
+ });
+}
+
+function dataRow(cols, widths) {
+ return new TableRow({
+ children: cols.map((t, i) => cell(t, widths[i])),
+ });
+}
+
+function table(columnWidths, rows) {
+ return new Table({
+ width: { size: tableWidth, type: WidthType.DXA },
+ columnWidths,
+ rows,
+ });
+}
+
+function h1(text) {
+ return new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun(text)] });
+}
+function h2(text) {
+ return new Paragraph({ heading: HeadingLevel.HEADING_2, children: [new TextRun(text)] });
+}
+function p(text) {
+ return new Paragraph({ spacing: { after: 200 }, children: [new TextRun(text)] });
+}
+function bullet(ref, text) {
+ return new Paragraph({
+ numbering: { reference: ref, level: 0 },
+ children: [new TextRun(text)],
+ });
+}
+
+const doc = new Document({
+ styles: {
+ default: { document: { run: { font: 'Arial', size: 22 } } },
+ paragraphStyles: [
+ {
+ id: 'Heading1',
+ name: 'Heading 1',
+ basedOn: 'Normal',
+ next: 'Normal',
+ quickFormat: true,
+ run: { size: 32, bold: true, font: 'Arial' },
+ paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 },
+ },
+ {
+ id: 'Heading2',
+ name: 'Heading 2',
+ basedOn: 'Normal',
+ next: 'Normal',
+ quickFormat: true,
+ run: { size: 26, bold: true, font: 'Arial' },
+ paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 },
+ },
+ ],
+ },
+ numbering: {
+ config: [
+ {
+ reference: 'bullets',
+ levels: [
+ {
+ level: 0,
+ format: LevelFormat.BULLET,
+ text: '\u2022',
+ alignment: AlignmentType.LEFT,
+ style: { paragraph: { indent: { left: 720, hanging: 360 } } },
+ },
+ ],
+ },
+ ],
+ },
+ sections: [
+ {
+ properties: {
+ page: {
+ size: { width: 12240, height: 15840 },
+ margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 },
+ },
+ },
+ children: [
+ new Paragraph({
+ alignment: AlignmentType.CENTER,
+ spacing: { after: 400 },
+ children: [
+ new TextRun({ text: 'Kött Gård', bold: true, size: 48 }),
+ ],
+ }),
+ new Paragraph({
+ alignment: AlignmentType.CENTER,
+ spacing: { after: 600 },
+ children: [
+ new TextRun({
+ text: 'Website Visual & Programming Guide',
+ size: 32,
+ color: '8B1F1F',
+ }),
+ ],
+ }),
+ p('Premium Halal meat e-commerce — Märsta, Sweden'),
+ p('Document version: June 2026'),
+ p('Companion files: docs/annotated/ (line-by-line code comments)'),
+
+ new Paragraph({ children: [new PageBreak()] }),
+
+ h1('1. What is this website?'),
+ p(
+ 'Kött Gård is a Next.js e-commerce front-end for ordering fresh Halal chicken, beef, lamb, and fish. Customers browse products, customize cuts (Nihari, Karahi, piece counts), add to cart, checkout, and view order history. Languages: Swedish, English, Urdu (RTL).'
+ ),
+
+ h2('Demo login'),
+ table(
+ [3120, 6240],
+ [
+ headerRow(['Field', 'Value'], [3120, 6240]),
+ dataRow(['Email', 'demo@kottgard.se'], [3120, 6240]),
+ dataRow(['Password', 'demo123'], [3120, 6240]),
+ dataRow(['Orders', '3 sample orders in Account'], [3120, 6240]),
+ ]
+ ),
+
+ h1('2. Homepage layout (visual map)'),
+ p('When a customer opens https://kottgard.se/, they scroll through these sections:'),
+ table(
+ [800, 2200, 3160, 3200],
+ [
+ headerRow(['#', 'Section', 'File', 'Customer action'], [800, 2200, 3160, 3200]),
+ dataRow(['1', 'Hero', 'Hero.tsx', 'Shop now / WhatsApp'], [800, 2200, 3160, 3200]),
+ dataRow(['2', 'Trust badges', 'TrustBadges.tsx', 'Click → About'], [800, 2200, 3160, 3200]),
+ dataRow(['3', 'About preview', 'AboutPreview.tsx', 'Read more → /about'], [800, 2200, 3160, 3200]),
+ dataRow(['4', 'Categories', 'CategoryGrid.tsx', 'Chicken/Beef/Lamb/Fish'], [800, 2200, 3160, 3200]),
+ dataRow(['5', 'Featured', 'FeaturedProducts.tsx', 'Product cards'], [800, 2200, 3160, 3200]),
+ dataRow(['6', 'How it works', 'HowItWorks.tsx', 'Order steps'], [800, 2200, 3160, 3200]),
+ dataRow(['7', 'Weekly offers', 'WeeklyOffers.tsx', 'Deals → products'], [800, 2200, 3160, 3200]),
+ dataRow(['8', 'CTA', 'CTA.tsx', 'Browse selection'], [800, 2200, 3160, 3200]),
+ dataRow(['9', 'Social', 'SocialFollow.tsx', 'Facebook / Instagram'], [800, 2200, 3160, 3200]),
+ dataRow(['10', 'Contact', 'ContactPreview.tsx', 'Map / phone / about'], [800, 2200, 3160, 3200]),
+ ]
+ ),
+
+ h1('3. All pages & routes'),
+ table(
+ [2800, 3360, 3200],
+ [
+ headerRow(['URL', 'File', 'Description'], [2800, 3360, 3200]),
+ dataRow(['/', 'app/page.tsx', 'Homepage'], [2800, 3360, 3200]),
+ dataRow(['/shop', 'app/shop/page.tsx', 'Catalog + search + filters'], [2800, 3360, 3200]),
+ dataRow(['/product/[slug]', 'app/product/[slug]/page.tsx', 'Detail + customize'], [2800, 3360, 3200]),
+ dataRow(['/cart', 'app/cart/page.tsx', 'Shopping cart'], [2800, 3360, 3200]),
+ dataRow(['/checkout', 'app/checkout/page.tsx', 'Place order (demo)'], [2800, 3360, 3200]),
+ dataRow(['/login', 'app/login/page.tsx', 'Auth'], [2800, 3360, 3200]),
+ dataRow(['/account', 'app/account/page.tsx', 'Profile + orders'], [2800, 3360, 3200]),
+ dataRow(['/wishlist', 'app/wishlist/page.tsx', 'Saved items'], [2800, 3360, 3200]),
+ dataRow(['/about', 'app/about/page.tsx', 'Company + privacy + terms'], [2800, 3360, 3200]),
+ ]
+ ),
+
+ new Paragraph({ children: [new PageBreak()] }),
+
+ h1('4. Programming languages & frameworks'),
+ h2('TypeScript'),
+ p(
+ 'TypeScript adds types to JavaScript. Example: Product interface ensures every product has id, slug, price. The compiler errors if you typo product.slugg.'
+ ),
+ h2('React'),
+ p(
+ 'React builds UI from components (functions returning JSX). State (useState) updates what users see. Props pass data parent → child.'
+ ),
+ h2('Next.js 13 App Router'),
+ bullet('bullets', 'app/ folder = routes. page.tsx = page, layout.tsx = wrapper.'),
+ bullet('bullets', 'Server Components default — less JavaScript sent to browser.'),
+ bullet('bullets', "'use client' = component runs in browser (hooks, clicks)."),
+ h2('Zustand'),
+ p(
+ 'Global stores: useCartStore, useAuthStore, useWishlistStore. persist middleware saves to localStorage so cart survives refresh.'
+ ),
+ h2('Tailwind CSS'),
+ p(
+ 'Classes like bg-brand-700 text-white px-4 py-2 style elements. Colors defined in tailwind.config.ts (burgundy, cream, gold).'
+ ),
+
+ h1('5. Data flow diagram (text)'),
+ p('Homepage → Shop (filter URL) → Product page → addItem() → Cart store → Checkout → Order in Auth store → Account page'),
+ p('Images: lib/images.ts → products.ts → ProductCard / Hero → AppImage → next/image → Unsplash CDN'),
+ p('Text: i18n/locales/sv|en|ur.ts → useTranslation() → t("key") in components'),
+
+ h1('6. Annotated code (line-by-line)'),
+ p('Location: Kottgard/docs/annotated/'),
+ table(
+ [4200, 5160],
+ [
+ headerRow(['File', 'Explains'], [4200, 5160]),
+ dataRow(['01-homepage.annotated.tsx', 'How homepage composes sections'], [4200, 5160]),
+ dataRow(['02-root-layout.annotated.tsx', 'Fonts, SEO, shell layout'], [4200, 5160]),
+ dataRow(['03-shop-page.annotated.tsx', 'URL sync, useMemo filtering'], [4200, 5160]),
+ dataRow(['04-header.annotated.tsx', 'Navigation + Zustand badges'], [4200, 5160]),
+ dataRow(['05-images.annotated.ts', 'Unsplash URL builder'], [4200, 5160]),
+ dataRow(['06-cart-store.annotated.ts', 'Cart logic + persist'], [4200, 5160]),
+ ]
+ ),
+ p(
+ 'Each line has comments explaining WHAT the code does and WHY. These are learning copies — not imported by the live app.'
+ ),
+
+ h1('7. Brand colors'),
+ table(
+ [3120, 3120, 3120],
+ [
+ headerRow(['Name', 'Hex', 'Use'], [3120, 3120, 3120]),
+ dataRow(['Burgundy (brand)', '#8B1F1F', 'Header, buttons, footer'], [3120, 3120, 3120]),
+ dataRow(['Cream', 'Warm off-white', 'Page backgrounds'], [3120, 3120, 3120]),
+ dataRow(['Gold', 'Accent', 'Prices, badges, CTAs'], [3120, 3120, 3120]),
+ ]
+ ),
+
+ h1('8. How to run locally'),
+ bullet('bullets', 'npm install'),
+ bullet('bullets', 'npm run dev → http://localhost:3000'),
+ bullet('bullets', 'npm run build → production check'),
+ ],
+ },
+ ],
+});
+
+const buffer = await Packer.toBuffer(doc);
+fs.writeFileSync(outPath, buffer);
+console.log('Written:', outPath);
\ No newline at end of file
diff --git a/domain/booking/entities.ts b/domain/booking/entities.ts
deleted file mode 100644
index 27e078c..0000000
--- a/domain/booking/entities.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { OrderLine } from '../shared/order-line';
-
-export type BranchLocation = 'askim' | 'backaplan' | '';
-
-export interface BookingDetails {
- location: BranchLocation;
- date: string;
- time: string;
- guests: string;
- name: string;
- phone: string;
- email: string;
- notes: string;
-}
-
-export type PreOrderLine = OrderLine;
-
-export interface BookingInquiry {
- booking: BookingDetails;
- preOrder: PreOrderLine[];
-}
\ No newline at end of file
diff --git a/domain/booking/validation.ts b/domain/booking/validation.ts
deleted file mode 100644
index ee4212f..0000000
--- a/domain/booking/validation.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import type { BookingDetails } from './entities';
-
-export function isBookingComplete(booking: BookingDetails): boolean {
- return !!(
- booking.location &&
- booking.date &&
- booking.time &&
- booking.guests &&
- booking.name &&
- booking.phone
- );
-}
\ No newline at end of file
diff --git a/domain/cart/cart-domain.ts b/domain/cart/cart-domain.ts
deleted file mode 100644
index 9798ecb..0000000
--- a/domain/cart/cart-domain.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import {
- addOrderLine,
- calculateOrderItemCount,
- calculateOrderTotal,
- updateOrderLineQuantity,
-} from '../shared/order-line';
-import type { CartAction, CartState } from './entities';
-
-/** Pure cart state machine — no React, no localStorage. */
-export function cartReducer(state: CartState, action: CartAction): CartState {
- switch (action.type) {
- case 'ADD_ITEM':
- return { ...state, items: addOrderLine(state.items, action.payload) };
-
- case 'REMOVE_ITEM':
- return {
- ...state,
- items: state.items.filter((item) => item.id !== action.payload),
- };
-
- case 'UPDATE_QUANTITY':
- return {
- ...state,
- items: updateOrderLineQuantity(
- state.items,
- action.payload.id,
- action.payload.quantity
- ),
- };
-
- case 'CLEAR_CART':
- return { ...state, items: [] };
-
- case 'RESTORE_ITEMS':
- return { ...state, items: action.payload };
-
- case 'TOGGLE_CART':
- return { ...state, isOpen: !state.isOpen };
-
- case 'OPEN_CART':
- return { ...state, isOpen: true };
-
- case 'CLOSE_CART':
- return { ...state, isOpen: false };
-
- default:
- return state;
- }
-}
-
-export function getCartTotals(items: CartState['items']) {
- return {
- totalItems: calculateOrderItemCount(items),
- totalPrice: calculateOrderTotal(items),
- };
-}
\ No newline at end of file
diff --git a/domain/cart/entities.ts b/domain/cart/entities.ts
deleted file mode 100644
index b7e01b1..0000000
--- a/domain/cart/entities.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import type { OrderLine, NewOrderLine } from '../shared/order-line';
-
-export type CartItem = OrderLine;
-export type NewCartItem = NewOrderLine;
-
-export interface CartState {
- items: CartItem[];
- isOpen: boolean;
-}
-
-export type CartAction =
- | { type: 'ADD_ITEM'; payload: NewCartItem }
- | { type: 'REMOVE_ITEM'; payload: string }
- | { type: 'UPDATE_QUANTITY'; payload: { id: string; quantity: number } }
- | { type: 'CLEAR_CART' }
- | { type: 'TOGGLE_CART' }
- | { type: 'OPEN_CART' }
- | { type: 'CLOSE_CART' }
- | { type: 'RESTORE_ITEMS'; payload: CartItem[] };
\ No newline at end of file
diff --git a/domain/cart/repository.ts b/domain/cart/repository.ts
deleted file mode 100644
index fd95428..0000000
--- a/domain/cart/repository.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import type { CartItem } from './entities';
-
-/** Port: cart persistence (implemented by infrastructure). */
-export interface CartRepository {
- load(): CartItem[];
- save(items: CartItem[]): void;
-}
\ No newline at end of file
diff --git a/domain/catering/catering-packages.ts b/domain/catering/catering-packages.ts
deleted file mode 100644
index 2b822a7..0000000
--- a/domain/catering/catering-packages.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import type { CateringPackage } from './entities';
-
-/**
- * Catering packages — price per head in SEK (kr).
- * Dish IDs reference domain/catering/dish-catalog.ts.
- */
-export const cateringPackages: CateringPackage[] = [
- {
- id: 'silver',
- name: 'Silver Package',
- description:
- 'A refined introduction to Shahi catering — one signature curry, dal, rice, naan and fresh salad. Ideal for office lunches and intimate gatherings.',
- pricePerHead: 189,
- currency: 'SEK',
- includedDishes: [
- 'butter-chicken',
- 'dal',
- 'plain-rice',
- 'naan',
- 'salad',
- ],
- image: 'butter-chicken.jpg',
- },
- {
- id: 'gold',
- name: 'Gold Package',
- description:
- 'Our most popular celebration menu — biryani, two curries, a vegetarian classic, rice, naan, raita and salad. Perfect for weddings and family events.',
- pricePerHead: 249,
- currency: 'SEK',
- includedDishes: [
- 'chicken-biryani',
- 'butter-chicken',
- 'lamb-karahi',
- 'palak-paneer',
- 'plain-rice',
- 'naan',
- 'raita',
- 'salad',
- ],
- image: 'chicken-biryani.jpg',
- highlight: true,
- },
- {
- id: 'royal',
- name: 'Royal Shahi Package',
- description:
- 'The full Shahi experience — biryani, tikka masala, premium lamb, seekh kebab, paneer, dal, and complete sides. For grand occasions that demand royalty.',
- pricePerHead: 329,
- currency: 'SEK',
- includedDishes: [
- 'chicken-biryani',
- 'chicken-tikka-masala',
- 'butter-chicken',
- 'lamb-korma',
- 'seekh-kebab',
- 'shahi-paneer',
- 'dal',
- 'plain-rice',
- 'naan',
- 'raita',
- 'salad',
- ],
- image: 'lamm-karahi.jpg',
- },
-];
\ No newline at end of file
diff --git a/domain/catering/dish-catalog.ts b/domain/catering/dish-catalog.ts
deleted file mode 100644
index 6611900..0000000
--- a/domain/catering/dish-catalog.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import type { CateringDish, CateringDishCategory } from './entities';
-
-/**
- * Master catalog of dishes available for catering packages.
- * IDs match the catering brief exactly.
- */
-export const CATERING_DISH_CATALOG: CateringDish[] = [
- // Lamb
- { id: 'lamb-vindaloo', name: 'Lamb Vindaloo', category: 'lamb', image: 'lamm-vindaloo.jpg' },
- { id: 'lamb-karahi', name: 'Lamb Karahi', category: 'lamb', image: 'lamm-karahi.jpg' },
- { id: 'lamb-korma', name: 'Lamb Korma', category: 'lamb', image: 'lamm-rogan-josh.jpg' },
- { id: 'lamb-achari', name: 'Lamb Achari', category: 'lamb', image: 'lamm-vindaloo.jpg' },
-
- // Chicken
- { id: 'chicken-tikka-masala', name: 'Chicken Tikka Masala', category: 'chicken', image: 'chicken-tikka.jpg' },
- { id: 'butter-chicken', name: 'Butter Chicken', category: 'chicken', image: 'butter-chicken.jpg' },
- { id: 'chicken-korma', name: 'Chicken Korma', category: 'chicken', image: 'butter-chicken.jpg' },
- { id: 'chicken-karahi', name: 'Chicken Karahi', category: 'chicken', image: 'chicken-karahi.jpg' },
- { id: 'chicken-achari', name: 'Chicken Achari', category: 'chicken', image: 'chicken-karahi.jpg' },
- { id: 'chicken-biryani', name: 'Chicken Biryani', category: 'chicken', image: 'chicken-biryani.jpg' },
-
- // Beef
- { id: 'shami-kebab', name: 'Shami Kebab', category: 'beef', image: 'shami-sandwich.jpg' },
- { id: 'seekh-kebab', name: 'Seekh Kebab', category: 'beef', image: 'kebab-roll.jpg' },
- { id: 'beef-karahi', name: 'Beef Karahi', category: 'beef', image: 'bong-nihari.jpg' },
-
- // Vegetarian
- { id: 'dal', name: 'Dal', category: 'vegetarian', image: 'daal-makhani.jpg' },
- { id: 'palak-paneer', name: 'Palak Paneer', category: 'vegetarian', image: 'palak-paneer.jpg' },
- { id: 'shahi-paneer', name: 'Shahi Paneer', category: 'vegetarian', image: 'shahi-paneer.jpg' },
- { id: 'sabzi', name: 'Sabzi', category: 'vegetarian', image: 'lahore-chana.jpg' },
-
- // Sides
- { id: 'plain-rice', name: 'Plain Rice', category: 'sides', image: 'chicken-biryani.jpg' },
- { id: 'naan', name: 'Naan', category: 'sides', image: 'keema-naan.jpg' },
- { id: 'salad', name: 'Salad', category: 'sides', image: 'chana-chaat.jpg' },
- { id: 'raita', name: 'Raita', category: 'sides', image: 'mango-lassi.jpg' },
-];
-
-export const CATERING_CATEGORY_ORDER: CateringDishCategory[] = [
- 'lamb',
- 'chicken',
- 'beef',
- 'vegetarian',
- 'sides',
-];
-
-export function getCateringDishById(id: string): CateringDish | undefined {
- return CATERING_DISH_CATALOG.find((d) => d.id === id);
-}
-
-export function groupDishesByCategory(
- dishIds: string[]
-): Record {
- const grouped: Record = {
- lamb: [],
- chicken: [],
- beef: [],
- vegetarian: [],
- sides: [],
- };
-
- for (const id of dishIds) {
- const dish = getCateringDishById(id);
- if (dish) grouped[dish.category].push(dish);
- }
-
- return grouped;
-}
\ No newline at end of file
diff --git a/domain/catering/entities.ts b/domain/catering/entities.ts
deleted file mode 100644
index ec87763..0000000
--- a/domain/catering/entities.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-export type CateringDishCategory =
- | 'lamb'
- | 'chicken'
- | 'beef'
- | 'vegetarian'
- | 'sides';
-
-export interface CateringDish {
- id: string;
- name: string;
- category: CateringDishCategory;
- /** Optional link to an existing menu poster in /public/images/dishes/ */
- image?: string;
-}
-
-export interface CateringPackage {
- id: string;
- name: string;
- description: string;
- pricePerHead: number;
- currency: 'SEK';
- includedDishes: string[];
- image?: string;
- highlight?: boolean;
-}
\ No newline at end of file
diff --git a/domain/kitchen-order/entities.ts b/domain/kitchen-order/entities.ts
deleted file mode 100644
index 8a3e12f..0000000
--- a/domain/kitchen-order/entities.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-export interface KitchenOrderItem {
- name: string;
- qty: number;
-}
-
-export type OrderSource = 'table' | 'foodora' | 'uber' | 'wolt' | 'pickup' | 'other';
-
-export type OrderStatus = 'received' | 'review' | 'preparing' | 'packing' | 'ready';
-
-export interface KitchenOrder {
- id: string;
- source: OrderSource;
- label: string;
- customer: string;
- items: KitchenOrderItem[];
- status: OrderStatus;
- receivedAt: Date;
- etaMinutes: number;
-}
-
-export const ORDER_STATUS_PIPELINE: readonly OrderStatus[] = [
- 'received',
- 'review',
- 'preparing',
- 'packing',
- 'ready',
-] as const;
\ No newline at end of file
diff --git a/domain/language/entities.ts b/domain/language/entities.ts
deleted file mode 100644
index 2507e33..0000000
--- a/domain/language/entities.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-export type Language = 'en' | 'sv' | 'hi' | 'ur' | 'ar' | 'tr';
-
-export const SUPPORTED_LANGUAGES: readonly Language[] = [
- 'sv',
- 'en',
- 'ar',
- 'tr',
- 'hi',
- 'ur',
-] as const;
-
-export const DEFAULT_LANGUAGE: Language = 'sv';
-
-export const RTL_LANGUAGES: readonly Language[] = ['ar', 'ur'] as const;
-
-export function isLanguage(value: string): value is Language {
- return (SUPPORTED_LANGUAGES as readonly string[]).includes(value);
-}
-
-export function isRtlLanguage(language: Language): boolean {
- return (RTL_LANGUAGES as readonly string[]).includes(language);
-}
-
-export interface LanguageOption {
- code: Language;
- name: string;
- native: string;
- flag: string;
-}
\ No newline at end of file
diff --git a/domain/language/repository.ts b/domain/language/repository.ts
deleted file mode 100644
index 7671e3c..0000000
--- a/domain/language/repository.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import type { Language } from './entities';
-
-/** Port: language preference persistence. */
-export interface LanguageRepository {
- load(): Language | null;
- save(language: Language): void;
-}
\ No newline at end of file
diff --git a/domain/menu/entities.ts b/domain/menu/entities.ts
deleted file mode 100644
index 873da68..0000000
--- a/domain/menu/entities.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-export type MenuPricingMode = 'standard' | 'weight';
-
-export interface MenuItem {
- id: string;
- name: string;
- description?: string;
- price: number;
- image?: string;
- video?: string;
- isVegetarian?: boolean;
- /** Weight-based sweets: 90 kr / ½ kg, 179 kr / kg (kulfi stays standard). */
- pricing?: MenuPricingMode;
- pricePerHalfKg?: number;
- pricePerKg?: number;
-}
-
-export interface MenuCategory {
- id: string;
- name: string;
- items: MenuItem[];
-}
-
-export interface MenuFilter {
- categoryId?: string;
- searchQuery?: string;
- vegetarianOnly?: boolean;
-}
\ No newline at end of file
diff --git a/domain/menu/repository.ts b/domain/menu/repository.ts
deleted file mode 100644
index bda6a7b..0000000
--- a/domain/menu/repository.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import type { MenuCategory, MenuItem } from './entities';
-
-/** Port: menu data access (implemented by infrastructure). */
-export interface MenuRepository {
- getCategories(): MenuCategory[];
- getAllItems(): MenuItem[];
- findItemById(id: string): MenuItem | undefined;
-}
\ No newline at end of file
diff --git a/domain/shared/constants.ts b/domain/shared/constants.ts
deleted file mode 100644
index 0edc251..0000000
--- a/domain/shared/constants.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/** Restaurant contact & persistence keys — domain constants (no framework deps). */
-
-export const RESTAURANT_CONTACT = {
- whatsappNumber: '46739381089',
- phonePrimary: '031288910',
- phoneMobile: '0739381089',
- email: 'hello@shahikitchen.se',
- website: 'https://shahikitchen.se',
-} as const;
-
-export const STORAGE_KEYS = {
- cart: 'shahi-kitchen-cart',
- wishlist: 'shahi-kitchen-wishlist',
- language: 'shahi-kitchen-language',
-} as const;
-
-export const PICKUP_LEAD_TIME_MINUTES = 30;
\ No newline at end of file
diff --git a/domain/shared/order-line.ts b/domain/shared/order-line.ts
deleted file mode 100644
index 06c056c..0000000
--- a/domain/shared/order-line.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import {
- calculateSweetsWeightTotal,
- formatSweetWeightLabel,
-} from '../sweets/pricing';
-
-/** Shared order-line model used by cart, pre-order, and table orders. */
-
-export type OrderPricingMode = 'standard' | 'weight';
-
-export interface OrderLine {
- id: string;
- name: string;
- price: number;
- quantity: number;
- image?: string;
- pricingMode?: OrderPricingMode;
- pricePerKg?: number;
- pricePerHalfKg?: number;
-}
-
-export type NewOrderLine = Omit;
-
-export function addOrderLine(lines: OrderLine[], item: NewOrderLine): OrderLine[] {
- const existing = lines.find((line) => line.id === item.id);
- if (existing) {
- return lines.map((line) =>
- line.id === item.id ? { ...line, quantity: line.quantity + 1 } : line
- );
- }
- return [...lines, { ...item, quantity: 1 }];
-}
-
-export function updateOrderLineQuantity(
- lines: OrderLine[],
- id: string,
- quantity: number
-): OrderLine[] {
- if (quantity <= 0) {
- return lines.filter((line) => line.id !== id);
- }
- return lines.map((line) => (line.id === id ? { ...line, quantity } : line));
-}
-
-export function removeOrderLine(lines: OrderLine[], id: string): OrderLine[] {
- return lines.filter((line) => line.id !== id);
-}
-
-export function calculateLineTotal(line: OrderLine): number {
- if (line.pricingMode === 'weight') {
- return calculateSweetsWeightTotal(line.quantity);
- }
- return line.price * line.quantity;
-}
-
-export function calculateOrderTotal(lines: OrderLine[]): number {
- return lines.reduce((sum, line) => sum + calculateLineTotal(line), 0);
-}
-
-export function calculateOrderItemCount(lines: OrderLine[]): number {
- return lines.reduce((sum, line) => sum + line.quantity, 0);
-}
-
-export function formatOrderLinesForMessage(lines: OrderLine[]): string {
- return lines
- .map((line) => {
- const total = calculateLineTotal(line);
- if (line.pricingMode === 'weight') {
- const weight = formatSweetWeightLabel(line.quantity);
- return `${line.name} (${weight}) — ${total} kr`;
- }
- return `${line.quantity} × ${line.name} — ${total} kr`;
- })
- .join('\n');
-}
-
-export function formatLineQuantityLabel(line: OrderLine): string {
- if (line.pricingMode === 'weight') {
- return formatSweetWeightLabel(line.quantity);
- }
- return String(line.quantity);
-}
\ No newline at end of file
diff --git a/domain/sweets/pricing.ts b/domain/sweets/pricing.ts
deleted file mode 100644
index 98dffc3..0000000
--- a/domain/sweets/pricing.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/** Weight-based mithai pricing (all sweets except kulfi). */
-
-export const SWEETS_HALF_KG_PRICE = 90;
-export const SWEETS_KG_PRICE = 179;
-export const KULFI_MENU_ID = 'kulfi';
-
-/** quantity = number of half-kg portions */
-export function calculateSweetsWeightTotal(halfKgUnits: number): number {
- const fullKg = Math.floor(halfKgUnits / 2);
- const halfRemainder = halfKgUnits % 2;
- return fullKg * SWEETS_KG_PRICE + halfRemainder * SWEETS_HALF_KG_PRICE;
-}
-
-export function halfKgUnitsToKg(halfKgUnits: number): number {
- return halfKgUnits * 0.5;
-}
-
-export function formatSweetWeightLabel(halfKgUnits: number): string {
- const kg = halfKgUnitsToKg(halfKgUnits);
- return kg === 0.5 ? '0.5 kg' : `${kg} kg`;
-}
\ No newline at end of file
diff --git a/domain/table/table-id.ts b/domain/table/table-id.ts
deleted file mode 100644
index 7e04b0c..0000000
--- a/domain/table/table-id.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-export type Branch = 'askim' | 'backaplan';
-
-export interface ValidTableId {
- valid: true;
- branch: Branch;
- tableNumber: string;
- tableIdentifier: string;
-}
-
-export interface InvalidTableId {
- valid: false;
- reason: 'missing' | 'format' | 'range';
-}
-
-export type ParsedTableId = ValidTableId | InvalidTableId;
-
-const TABLE_ID_PATTERN = /^(backaplan|askim)-([0-9]{3})$/;
-const MIN_TABLE = 1;
-const MAX_TABLE = 40;
-
-/** Domain rule: parse and validate QR table identifiers. */
-export function parseTableId(raw: string | null | undefined): ParsedTableId {
- if (!raw) {
- return { valid: false, reason: 'missing' };
- }
-
- const match = raw.match(TABLE_ID_PATTERN);
- if (!match) {
- return { valid: false, reason: 'format' };
- }
-
- const branch = match[1] as Branch;
- const tableNum = parseInt(match[2], 10);
-
- if (tableNum < MIN_TABLE || tableNum > MAX_TABLE) {
- return { valid: false, reason: 'range' };
- }
-
- return {
- valid: true,
- branch,
- tableNumber: match[2],
- tableIdentifier: raw,
- };
-}
\ No newline at end of file
diff --git a/domain/wishlist/entities.ts b/domain/wishlist/entities.ts
deleted file mode 100644
index d61b999..0000000
--- a/domain/wishlist/entities.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-export interface WishlistItem {
- id: string;
- name: string;
- price: number;
- image?: string;
-}
-
-export type NewWishlistItem = WishlistItem;
-
-export interface WishlistState {
- items: WishlistItem[];
- isOpen: boolean;
-}
-
-export type WishlistAction =
- | { type: 'TOGGLE_ITEM'; payload: NewWishlistItem }
- | { type: 'REMOVE_ITEM'; payload: string }
- | { type: 'CLEAR_WISHLIST' }
- | { type: 'TOGGLE_DRAWER' }
- | { type: 'OPEN_DRAWER' }
- | { type: 'CLOSE_DRAWER' }
- | { type: 'RESTORE_ITEMS'; payload: WishlistItem[] };
\ No newline at end of file
diff --git a/domain/wishlist/repository.ts b/domain/wishlist/repository.ts
deleted file mode 100644
index 7b112e6..0000000
--- a/domain/wishlist/repository.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import type { WishlistItem } from './entities';
-
-export interface WishlistRepository {
- load(): WishlistItem[];
- save(items: WishlistItem[]): void;
-}
\ No newline at end of file
diff --git a/domain/wishlist/wishlist-domain.ts b/domain/wishlist/wishlist-domain.ts
deleted file mode 100644
index b3c9d66..0000000
--- a/domain/wishlist/wishlist-domain.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import type { WishlistAction, WishlistItem, WishlistState } from './entities';
-
-export function wishlistReducer(state: WishlistState, action: WishlistAction): WishlistState {
- switch (action.type) {
- case 'TOGGLE_ITEM': {
- const exists = state.items.some((item) => item.id === action.payload.id);
- if (exists) {
- return {
- ...state,
- items: state.items.filter((item) => item.id !== action.payload.id),
- };
- }
- return { ...state, items: [...state.items, action.payload] };
- }
-
- case 'REMOVE_ITEM':
- return {
- ...state,
- items: state.items.filter((item) => item.id !== action.payload),
- };
-
- case 'CLEAR_WISHLIST':
- return { ...state, items: [] };
-
- case 'RESTORE_ITEMS':
- return { ...state, items: action.payload };
-
- case 'TOGGLE_DRAWER':
- return { ...state, isOpen: !state.isOpen };
-
- case 'OPEN_DRAWER':
- return { ...state, isOpen: true };
-
- case 'CLOSE_DRAWER':
- return { ...state, isOpen: false };
-
- default:
- return state;
- }
-}
-
-export function isInWishlist(items: WishlistItem[], id: string): boolean {
- return items.some((item) => item.id === id);
-}
-
-export function getWishlistCount(items: WishlistItem[]): number {
- return items.length;
-}
\ No newline at end of file
diff --git a/ecosystem.config.cjs b/ecosystem.config.cjs
deleted file mode 100644
index 8e4ee35..0000000
--- a/ecosystem.config.cjs
+++ /dev/null
@@ -1,24 +0,0 @@
-module.exports = {
- apps: [
- {
- name: 'shahikitchen',
- cwd: '/var/www/shahikitchen.se',
- script: 'npm',
- args: 'run start',
- env: {
- NODE_ENV: 'production',
- PORT: 3001
- },
- instances: 1,
- exec_mode: 'fork',
- max_memory_restart: '700M',
- error_file: '/home/deploy/.pm2/logs/shahikitchen-error.log',
- out_file: '/home/deploy/.pm2/logs/shahikitchen-out.log',
- log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
- kill_timeout: 8000,
- autorestart: true,
- watch: false,
- min_uptime: '10s'
- }
- ]
-};
\ No newline at end of file
diff --git a/eslint.config.mjs b/eslint.config.mjs
deleted file mode 100644
index 05e726d..0000000
--- a/eslint.config.mjs
+++ /dev/null
@@ -1,18 +0,0 @@
-import { defineConfig, globalIgnores } from "eslint/config";
-import nextVitals from "eslint-config-next/core-web-vitals";
-import nextTs from "eslint-config-next/typescript";
-
-const eslintConfig = defineConfig([
- ...nextVitals,
- ...nextTs,
- // Override default ignores of eslint-config-next.
- globalIgnores([
- // Default ignores of eslint-config-next:
- ".next/**",
- "out/**",
- "build/**",
- "next-env.d.ts",
- ]),
-]);
-
-export default eslintConfig;
diff --git a/extract-video-posters.sh b/extract-video-posters.sh
deleted file mode 100755
index 1c310af..0000000
--- a/extract-video-posters.sh
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/bin/bash
-
-# ======================================================
-# Extract First Frame as Poster for All Videos
-# ======================================================
-# This script goes through all .mp4 and .webm files in the current
-# folder and extracts the very first frame as a high-quality poster image.
-#
-# Usage:
-# cd /home/khan/code/shahikitchen/public/videos
-# bash /home/khan/code/shahikitchen/extract-video-posters.sh
-#
-# Requirements:
-# - ffmpeg installed
-#
-# Output:
-# For butter-chicken-steam.mp4 → butter-chicken-steam-poster.jpg
-# (You can then update your menu data or code to use these posters)
-# ======================================================
-
-set -e
-
-echo "Extracting first frame posters from videos..."
-echo ""
-
-for file in *.mp4 *.webm; do
- if [ ! -f "$file" ]; then
- continue
- fi
-
- base="${file%.*}"
- output="${base}-poster.jpg"
-
- # Skip if poster already exists
- if [ -f "$output" ]; then
- echo "→ Skipping $file (poster already exists)"
- continue
- fi
-
- echo "→ Extracting poster from: $file"
-
- ffmpeg -y -i "$file" -ss 0.1 -vframes 1 -q:v 2 "$output" 2>/dev/null
-
- if [ -f "$output" ]; then
- echo " Created: $output"
- else
- echo " Failed to create poster for $file"
- fi
-done
-
-echo ""
-echo "✅ Done extracting posters!"
-echo ""
-echo "You can now update your menu cards to use *-poster.jpg instead of the original dish photos"
-echo "for better visual consistency between static state and video."
\ No newline at end of file
diff --git a/ftp-images/bilder-bp/bong-nihari/bild/IMG_0133.png b/ftp-images/bilder-bp/bong-nihari/bild/IMG_0133.png
deleted file mode 100644
index 3e098d1..0000000
Binary files a/ftp-images/bilder-bp/bong-nihari/bild/IMG_0133.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/bong-nihari/description.txt b/ftp-images/bilder-bp/bong-nihari/description.txt
deleted file mode 100755
index c1d5925..0000000
--- a/ftp-images/bilder-bp/bong-nihari/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Slow-cooked beef shank in a rich, aromatic gravy, traditionally served with naan.
diff --git a/ftp-images/bilder-bp/bong-nihari/price.txt b/ftp-images/bilder-bp/bong-nihari/price.txt
deleted file mode 100755
index aa34eab..0000000
--- a/ftp-images/bilder-bp/bong-nihari/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-199
diff --git a/ftp-images/bilder-bp/butter-chicken/bild/00D79F0B-D0AF-4CA8-AD54-78E777FF10A8.png b/ftp-images/bilder-bp/butter-chicken/bild/00D79F0B-D0AF-4CA8-AD54-78E777FF10A8.png
deleted file mode 100644
index aafc68c..0000000
Binary files a/ftp-images/bilder-bp/butter-chicken/bild/00D79F0B-D0AF-4CA8-AD54-78E777FF10A8.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/butter-chicken/description.txt b/ftp-images/bilder-bp/butter-chicken/description.txt
deleted file mode 100755
index 1770508..0000000
--- a/ftp-images/bilder-bp/butter-chicken/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Tender chicken in a creamy tomato and butter gravy with mild spices.
diff --git a/ftp-images/bilder-bp/butter-chicken/price.txt b/ftp-images/bilder-bp/butter-chicken/price.txt
deleted file mode 100755
index 15c44e9..0000000
--- a/ftp-images/bilder-bp/butter-chicken/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-149
diff --git a/ftp-images/bilder-bp/cappuccino/description.txt b/ftp-images/bilder-bp/cappuccino/description.txt
deleted file mode 100755
index f14bdb8..0000000
--- a/ftp-images/bilder-bp/cappuccino/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Espresso topped with steamed milk and thick foam.
diff --git a/ftp-images/bilder-bp/cappuccino/price.txt b/ftp-images/bilder-bp/cappuccino/price.txt
deleted file mode 100755
index 95f9650..0000000
--- a/ftp-images/bilder-bp/cappuccino/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-49
diff --git a/ftp-images/bilder-bp/chana-chat/bild/IMG_1304.jpeg b/ftp-images/bilder-bp/chana-chat/bild/IMG_1304.jpeg
deleted file mode 100644
index d336bbe..0000000
Binary files a/ftp-images/bilder-bp/chana-chat/bild/IMG_1304.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/chana-chat/description.txt b/ftp-images/bilder-bp/chana-chat/description.txt
deleted file mode 100755
index 3001555..0000000
--- a/ftp-images/bilder-bp/chana-chat/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Tangy spiced chickpeas mixed with potatoes, onions, tomatoes and chutneys.
diff --git a/ftp-images/bilder-bp/chana-chat/price.txt b/ftp-images/bilder-bp/chana-chat/price.txt
deleted file mode 100755
index b5489e5..0000000
--- a/ftp-images/bilder-bp/chana-chat/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-69
diff --git a/ftp-images/bilder-bp/chicken-biryani/bild/4D682043-6FF6-42EA-BF86-016A5EBBD816.png b/ftp-images/bilder-bp/chicken-biryani/bild/4D682043-6FF6-42EA-BF86-016A5EBBD816.png
deleted file mode 100644
index d7378e3..0000000
Binary files a/ftp-images/bilder-bp/chicken-biryani/bild/4D682043-6FF6-42EA-BF86-016A5EBBD816.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/chicken-biryani/description.txt b/ftp-images/bilder-bp/chicken-biryani/description.txt
deleted file mode 100755
index 56b531a..0000000
--- a/ftp-images/bilder-bp/chicken-biryani/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Fragrant aged basmati rice layered with tender spiced chicken, saffron and caramelized onions.
diff --git a/ftp-images/bilder-bp/chicken-biryani/price.txt b/ftp-images/bilder-bp/chicken-biryani/price.txt
deleted file mode 100755
index 15c44e9..0000000
--- a/ftp-images/bilder-bp/chicken-biryani/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-149
diff --git a/ftp-images/bilder-bp/chicken-haleem/bild/9941EE57-6CC1-48EB-A4D1-1699EB55589E.png b/ftp-images/bilder-bp/chicken-haleem/bild/9941EE57-6CC1-48EB-A4D1-1699EB55589E.png
deleted file mode 100644
index 7a24ab6..0000000
Binary files a/ftp-images/bilder-bp/chicken-haleem/bild/9941EE57-6CC1-48EB-A4D1-1699EB55589E.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/chicken-haleem/description.txt b/ftp-images/bilder-bp/chicken-haleem/description.txt
deleted file mode 100755
index 4033d08..0000000
--- a/ftp-images/bilder-bp/chicken-haleem/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Slow-cooked shredded chicken with lentils, wheat and aromatic spices.
diff --git a/ftp-images/bilder-bp/chicken-haleem/price.txt b/ftp-images/bilder-bp/chicken-haleem/price.txt
deleted file mode 100755
index 15c44e9..0000000
--- a/ftp-images/bilder-bp/chicken-haleem/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-149
diff --git a/ftp-images/bilder-bp/chicken-karahi/bild/124AC7DA-7FD6-4F76-BD6A-E4B17514B918.png b/ftp-images/bilder-bp/chicken-karahi/bild/124AC7DA-7FD6-4F76-BD6A-E4B17514B918.png
deleted file mode 100644
index 4b10392..0000000
Binary files a/ftp-images/bilder-bp/chicken-karahi/bild/124AC7DA-7FD6-4F76-BD6A-E4B17514B918.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/chicken-karahi/description.txt b/ftp-images/bilder-bp/chicken-karahi/description.txt
deleted file mode 100755
index bec1721..0000000
--- a/ftp-images/bilder-bp/chicken-karahi/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Wok-tossed chicken in a robust tomato, chili and ginger gravy.
diff --git a/ftp-images/bilder-bp/chicken-karahi/price.txt b/ftp-images/bilder-bp/chicken-karahi/price.txt
deleted file mode 100755
index 15c44e9..0000000
--- a/ftp-images/bilder-bp/chicken-karahi/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-149
diff --git a/ftp-images/bilder-bp/chicken-tikka/bild/IMG_0134.png b/ftp-images/bilder-bp/chicken-tikka/bild/IMG_0134.png
deleted file mode 100644
index f9fe572..0000000
Binary files a/ftp-images/bilder-bp/chicken-tikka/bild/IMG_0134.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/chicken-tikka/description.txt b/ftp-images/bilder-bp/chicken-tikka/description.txt
deleted file mode 100755
index 033988a..0000000
--- a/ftp-images/bilder-bp/chicken-tikka/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Boneless chicken pieces marinated in yogurt and spices, grilled in a tandoor.
diff --git a/ftp-images/bilder-bp/chicken-tikka/price.txt b/ftp-images/bilder-bp/chicken-tikka/price.txt
deleted file mode 100755
index 15c44e9..0000000
--- a/ftp-images/bilder-bp/chicken-tikka/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-149
diff --git a/ftp-images/bilder-bp/coca-cola/description.txt b/ftp-images/bilder-bp/coca-cola/description.txt
deleted file mode 100755
index 022de9e..0000000
--- a/ftp-images/bilder-bp/coca-cola/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Classic chilled cola soft drink.
diff --git a/ftp-images/bilder-bp/coca-cola/price.txt b/ftp-images/bilder-bp/coca-cola/price.txt
deleted file mode 100755
index f04c001..0000000
--- a/ftp-images/bilder-bp/coca-cola/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-29
diff --git a/ftp-images/bilder-bp/coffee/description.txt b/ftp-images/bilder-bp/coffee/description.txt
deleted file mode 100755
index 3997594..0000000
--- a/ftp-images/bilder-bp/coffee/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Freshly brewed hot coffee.
diff --git a/ftp-images/bilder-bp/coffee/price.txt b/ftp-images/bilder-bp/coffee/price.txt
deleted file mode 100755
index a272009..0000000
--- a/ftp-images/bilder-bp/coffee/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-39
diff --git a/ftp-images/bilder-bp/daal-makhani/bild/6CB2DF4F-43B5-4DA7-8784-97BB44694BBA.png b/ftp-images/bilder-bp/daal-makhani/bild/6CB2DF4F-43B5-4DA7-8784-97BB44694BBA.png
deleted file mode 100644
index d4c4aba..0000000
Binary files a/ftp-images/bilder-bp/daal-makhani/bild/6CB2DF4F-43B5-4DA7-8784-97BB44694BBA.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/daal-makhani/description.txt b/ftp-images/bilder-bp/daal-makhani/description.txt
deleted file mode 100755
index 28af818..0000000
--- a/ftp-images/bilder-bp/daal-makhani/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Slow-cooked black lentils in a buttery, creamy tomato gravy with aromatic spices.
diff --git a/ftp-images/bilder-bp/daal-makhani/price.txt b/ftp-images/bilder-bp/daal-makhani/price.txt
deleted file mode 100755
index 897bdc8..0000000
--- a/ftp-images/bilder-bp/daal-makhani/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-139
diff --git a/ftp-images/bilder-bp/energy-drink/description.txt b/ftp-images/bilder-bp/energy-drink/description.txt
deleted file mode 100755
index 76d733d..0000000
--- a/ftp-images/bilder-bp/energy-drink/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Caffeinated beverage for an instant energy boost.
diff --git a/ftp-images/bilder-bp/energy-drink/price.txt b/ftp-images/bilder-bp/energy-drink/price.txt
deleted file mode 100755
index a272009..0000000
--- a/ftp-images/bilder-bp/energy-drink/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-39
diff --git a/ftp-images/bilder-bp/falafel-roll/bild/003915D6-1E52-4447-8135-BA3BC55B1314.png b/ftp-images/bilder-bp/falafel-roll/bild/003915D6-1E52-4447-8135-BA3BC55B1314.png
deleted file mode 100644
index f53a340..0000000
Binary files a/ftp-images/bilder-bp/falafel-roll/bild/003915D6-1E52-4447-8135-BA3BC55B1314.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/falafel-roll/description.txt b/ftp-images/bilder-bp/falafel-roll/description.txt
deleted file mode 100755
index acf3ac7..0000000
--- a/ftp-images/bilder-bp/falafel-roll/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Crispy falafel wrapped in naan with vegetables, hummus and tangy sauces.
diff --git a/ftp-images/bilder-bp/falafel-roll/price.txt b/ftp-images/bilder-bp/falafel-roll/price.txt
deleted file mode 100755
index 3ad5abd..0000000
--- a/ftp-images/bilder-bp/falafel-roll/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-99
diff --git a/ftp-images/bilder-bp/gajar-halwa/bild/97CE537C-67C3-4CCB-9292-9DB7C2A79791.png b/ftp-images/bilder-bp/gajar-halwa/bild/97CE537C-67C3-4CCB-9292-9DB7C2A79791.png
deleted file mode 100644
index 1f200fe..0000000
Binary files a/ftp-images/bilder-bp/gajar-halwa/bild/97CE537C-67C3-4CCB-9292-9DB7C2A79791.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/gajar-halwa/description.txt b/ftp-images/bilder-bp/gajar-halwa/description.txt
deleted file mode 100755
index d037f15..0000000
--- a/ftp-images/bilder-bp/gajar-halwa/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Sweet carrot pudding cooked slowly with milk, sugar, ghee and nuts.
diff --git a/ftp-images/bilder-bp/gajar-halwa/price.txt b/ftp-images/bilder-bp/gajar-halwa/price.txt
deleted file mode 100755
index 15c44e9..0000000
--- a/ftp-images/bilder-bp/gajar-halwa/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-149
diff --git a/ftp-images/bilder-bp/jalebi/bild/29853DEB-6999-4D29-87F2-665CAA09C4CA.png b/ftp-images/bilder-bp/jalebi/bild/29853DEB-6999-4D29-87F2-665CAA09C4CA.png
deleted file mode 100644
index 2af4ced..0000000
Binary files a/ftp-images/bilder-bp/jalebi/bild/29853DEB-6999-4D29-87F2-665CAA09C4CA.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/jalebi/description.txt b/ftp-images/bilder-bp/jalebi/description.txt
deleted file mode 100755
index d9c6a66..0000000
--- a/ftp-images/bilder-bp/jalebi/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Crispy golden saffron spirals soaked in fragrant sugar syrup.
diff --git a/ftp-images/bilder-bp/jalebi/price.txt b/ftp-images/bilder-bp/jalebi/price.txt
deleted file mode 100755
index 078fa0f..0000000
--- a/ftp-images/bilder-bp/jalebi/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-119
diff --git a/ftp-images/bilder-bp/juice/description.txt b/ftp-images/bilder-bp/juice/description.txt
deleted file mode 100755
index 39c9c65..0000000
--- a/ftp-images/bilder-bp/juice/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Fresh fruit juice, typically mango or other seasonal flavors.
diff --git a/ftp-images/bilder-bp/juice/price.txt b/ftp-images/bilder-bp/juice/price.txt
deleted file mode 100755
index 209e3ef..0000000
--- a/ftp-images/bilder-bp/juice/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-20
diff --git a/ftp-images/bilder-bp/kebab-pizza/bild/CD7DAD53-5C9C-451E-9F9C-054448992738.png b/ftp-images/bilder-bp/kebab-pizza/bild/CD7DAD53-5C9C-451E-9F9C-054448992738.png
deleted file mode 100644
index a67b7b3..0000000
Binary files a/ftp-images/bilder-bp/kebab-pizza/bild/CD7DAD53-5C9C-451E-9F9C-054448992738.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/kebab-pizza/description.txt b/ftp-images/bilder-bp/kebab-pizza/description.txt
deleted file mode 100755
index 362d69d..0000000
--- a/ftp-images/bilder-bp/kebab-pizza/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Pizza with minced meat kebab topping, cheese, onions and aromatic spices.
diff --git a/ftp-images/bilder-bp/kebab-pizza/price.txt b/ftp-images/bilder-bp/kebab-pizza/price.txt
deleted file mode 100755
index 078fa0f..0000000
--- a/ftp-images/bilder-bp/kebab-pizza/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-119
diff --git a/ftp-images/bilder-bp/kebab-roll/bild/E2704FBA-52EB-4FDC-9E12-85526DD18347.png b/ftp-images/bilder-bp/kebab-roll/bild/E2704FBA-52EB-4FDC-9E12-85526DD18347.png
deleted file mode 100644
index 10bedb6..0000000
Binary files a/ftp-images/bilder-bp/kebab-roll/bild/E2704FBA-52EB-4FDC-9E12-85526DD18347.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/kebab-roll/description.txt b/ftp-images/bilder-bp/kebab-roll/description.txt
deleted file mode 100755
index 373c336..0000000
--- a/ftp-images/bilder-bp/kebab-roll/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Spiced minced meat kebab wrapped in naan with chutney, salad and sauces.
diff --git a/ftp-images/bilder-bp/kebab-roll/price.txt b/ftp-images/bilder-bp/kebab-roll/price.txt
deleted file mode 100755
index 3ad5abd..0000000
--- a/ftp-images/bilder-bp/kebab-roll/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-99
diff --git a/ftp-images/bilder-bp/keema-naan-starter/bild/CCD1634C-61D1-4FBB-B515-0079AC441C0E.png b/ftp-images/bilder-bp/keema-naan-starter/bild/CCD1634C-61D1-4FBB-B515-0079AC441C0E.png
deleted file mode 100644
index cc65d52..0000000
Binary files a/ftp-images/bilder-bp/keema-naan-starter/bild/CCD1634C-61D1-4FBB-B515-0079AC441C0E.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/keema-naan-starter/description.txt b/ftp-images/bilder-bp/keema-naan-starter/description.txt
deleted file mode 100755
index 28b2987..0000000
--- a/ftp-images/bilder-bp/keema-naan-starter/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Soft naan bread stuffed with spiced minced meat, baked until golden.
diff --git a/ftp-images/bilder-bp/keema-naan-starter/price.txt b/ftp-images/bilder-bp/keema-naan-starter/price.txt
deleted file mode 100755
index 78eb67c..0000000
--- a/ftp-images/bilder-bp/keema-naan-starter/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-75
diff --git a/ftp-images/bilder-bp/kulfi/bild/IMG_1245.jpeg b/ftp-images/bilder-bp/kulfi/bild/IMG_1245.jpeg
deleted file mode 100644
index 40245dd..0000000
Binary files a/ftp-images/bilder-bp/kulfi/bild/IMG_1245.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/kulfi/description.txt b/ftp-images/bilder-bp/kulfi/description.txt
deleted file mode 100755
index 9d2e075..0000000
--- a/ftp-images/bilder-bp/kulfi/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Creamy traditional frozen milk dessert with cardamom, pistachios and saffron.
diff --git a/ftp-images/bilder-bp/kulfi/price.txt b/ftp-images/bilder-bp/kulfi/price.txt
deleted file mode 100755
index a272009..0000000
--- a/ftp-images/bilder-bp/kulfi/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-39
diff --git a/ftp-images/bilder-bp/lahore-chana/bild/A1648A3B-CCC4-4DFB-89D5-61D1BEC00113.png b/ftp-images/bilder-bp/lahore-chana/bild/A1648A3B-CCC4-4DFB-89D5-61D1BEC00113.png
deleted file mode 100644
index 551b2e9..0000000
Binary files a/ftp-images/bilder-bp/lahore-chana/bild/A1648A3B-CCC4-4DFB-89D5-61D1BEC00113.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/lahore-chana/description.txt b/ftp-images/bilder-bp/lahore-chana/description.txt
deleted file mode 100755
index 80b9cc3..0000000
--- a/ftp-images/bilder-bp/lahore-chana/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Spiced chickpeas cooked in a tangy onion-tomato gravy with traditional Punjabi spices.
diff --git a/ftp-images/bilder-bp/lahore-chana/price.txt b/ftp-images/bilder-bp/lahore-chana/price.txt
deleted file mode 100755
index 897bdc8..0000000
--- a/ftp-images/bilder-bp/lahore-chana/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-139
diff --git a/ftp-images/bilder-bp/lahore-pizza/bild/E5A130B9-9FAA-4D7F-A089-6A910A06BDF0.png b/ftp-images/bilder-bp/lahore-pizza/bild/E5A130B9-9FAA-4D7F-A089-6A910A06BDF0.png
deleted file mode 100644
index 944a153..0000000
Binary files a/ftp-images/bilder-bp/lahore-pizza/bild/E5A130B9-9FAA-4D7F-A089-6A910A06BDF0.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/lahore-pizza/description.txt b/ftp-images/bilder-bp/lahore-pizza/description.txt
deleted file mode 100755
index c7f1fd2..0000000
--- a/ftp-images/bilder-bp/lahore-pizza/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Pizza topped with spiced chicken, onions and special Lahori sauces on a crispy base.
diff --git a/ftp-images/bilder-bp/lahore-pizza/price.txt b/ftp-images/bilder-bp/lahore-pizza/price.txt
deleted file mode 100755
index 078fa0f..0000000
--- a/ftp-images/bilder-bp/lahore-pizza/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-119
diff --git a/ftp-images/bilder-bp/lahore-sizzler/bild/IMG_0159.jpeg b/ftp-images/bilder-bp/lahore-sizzler/bild/IMG_0159.jpeg
deleted file mode 100644
index 089100c..0000000
Binary files a/ftp-images/bilder-bp/lahore-sizzler/bild/IMG_0159.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/lahore-sizzler/description.txt b/ftp-images/bilder-bp/lahore-sizzler/description.txt
deleted file mode 100755
index 1cebd36..0000000
--- a/ftp-images/bilder-bp/lahore-sizzler/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Sizzling platter of marinated chicken with vegetables and spicy sauces.
diff --git a/ftp-images/bilder-bp/lahore-sizzler/price.txt b/ftp-images/bilder-bp/lahore-sizzler/price.txt
deleted file mode 100755
index fb402ef..0000000
--- a/ftp-images/bilder-bp/lahore-sizzler/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-169
diff --git a/ftp-images/bilder-bp/lamm-karahi/description.txt b/ftp-images/bilder-bp/lamm-karahi/description.txt
deleted file mode 100755
index ee145dd..0000000
--- a/ftp-images/bilder-bp/lamm-karahi/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Lamb pieces stir-fried in a wok with tomatoes, ginger, garlic and spices.
diff --git a/ftp-images/bilder-bp/lamm-karahi/price.txt b/ftp-images/bilder-bp/lamm-karahi/price.txt
deleted file mode 100755
index a14f8d5..0000000
--- a/ftp-images/bilder-bp/lamm-karahi/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-179
diff --git a/ftp-images/bilder-bp/lamm-palak/bild/IMG_0129.png b/ftp-images/bilder-bp/lamm-palak/bild/IMG_0129.png
deleted file mode 100644
index 46edff9..0000000
Binary files a/ftp-images/bilder-bp/lamm-palak/bild/IMG_0129.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/lamm-palak/description.txt b/ftp-images/bilder-bp/lamm-palak/description.txt
deleted file mode 100755
index 40e7f9b..0000000
--- a/ftp-images/bilder-bp/lamm-palak/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Tender lamb cooked with fresh spinach in a mild, flavorful gravy.
diff --git a/ftp-images/bilder-bp/lamm-palak/price.txt b/ftp-images/bilder-bp/lamm-palak/price.txt
deleted file mode 100755
index a14f8d5..0000000
--- a/ftp-images/bilder-bp/lamm-palak/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-179
diff --git a/ftp-images/bilder-bp/lamm-rogan-josh/description.txt b/ftp-images/bilder-bp/lamm-rogan-josh/description.txt
deleted file mode 100755
index 69981db..0000000
--- a/ftp-images/bilder-bp/lamm-rogan-josh/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Aromatic lamb curry simmered in a rich yogurt and Kashmiri spice gravy.
diff --git a/ftp-images/bilder-bp/lamm-rogan-josh/price.txt b/ftp-images/bilder-bp/lamm-rogan-josh/price.txt
deleted file mode 100755
index aa34eab..0000000
--- a/ftp-images/bilder-bp/lamm-rogan-josh/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-199
diff --git a/ftp-images/bilder-bp/lamm-vindaloo/bild/6027E1DC-D2A5-4A13-9FCB-F0005B682C62.png b/ftp-images/bilder-bp/lamm-vindaloo/bild/6027E1DC-D2A5-4A13-9FCB-F0005B682C62.png
deleted file mode 100644
index 0b976ca..0000000
Binary files a/ftp-images/bilder-bp/lamm-vindaloo/bild/6027E1DC-D2A5-4A13-9FCB-F0005B682C62.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/lamm-vindaloo/description.txt b/ftp-images/bilder-bp/lamm-vindaloo/description.txt
deleted file mode 100755
index de46b35..0000000
--- a/ftp-images/bilder-bp/lamm-vindaloo/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Spicy and tangy lamb curry in a vinegar and chili-based sauce.
diff --git a/ftp-images/bilder-bp/lamm-vindaloo/price.txt b/ftp-images/bilder-bp/lamm-vindaloo/price.txt
deleted file mode 100755
index a14f8d5..0000000
--- a/ftp-images/bilder-bp/lamm-vindaloo/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-179
diff --git a/ftp-images/bilder-bp/latte/description.txt b/ftp-images/bilder-bp/latte/description.txt
deleted file mode 100755
index 0387100..0000000
--- a/ftp-images/bilder-bp/latte/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Espresso coffee with steamed milk and a light layer of foam.
diff --git a/ftp-images/bilder-bp/latte/price.txt b/ftp-images/bilder-bp/latte/price.txt
deleted file mode 100755
index 95f9650..0000000
--- a/ftp-images/bilder-bp/latte/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-49
diff --git a/ftp-images/bilder-bp/malai-kofta/bild/D9172531-87EF-4BF8-AA8A-1F9EFA15BFA3.png b/ftp-images/bilder-bp/malai-kofta/bild/D9172531-87EF-4BF8-AA8A-1F9EFA15BFA3.png
deleted file mode 100644
index 4312b65..0000000
Binary files a/ftp-images/bilder-bp/malai-kofta/bild/D9172531-87EF-4BF8-AA8A-1F9EFA15BFA3.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/malai-kofta/bild/IMG_0160.jpeg b/ftp-images/bilder-bp/malai-kofta/bild/IMG_0160.jpeg
deleted file mode 100644
index 9f4045c..0000000
Binary files a/ftp-images/bilder-bp/malai-kofta/bild/IMG_0160.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/malai-kofta/description.txt b/ftp-images/bilder-bp/malai-kofta/description.txt
deleted file mode 100755
index e639089..0000000
--- a/ftp-images/bilder-bp/malai-kofta/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Soft vegetable koftas simmered in a rich and creamy onion-tomato gravy with mild spices.
diff --git a/ftp-images/bilder-bp/malai-kofta/price.txt b/ftp-images/bilder-bp/malai-kofta/price.txt
deleted file mode 100755
index 897bdc8..0000000
--- a/ftp-images/bilder-bp/malai-kofta/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-139
diff --git a/ftp-images/bilder-bp/mango-lassi/description.txt b/ftp-images/bilder-bp/mango-lassi/description.txt
deleted file mode 100755
index bc04650..0000000
--- a/ftp-images/bilder-bp/mango-lassi/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Refreshing sweet yogurt drink blended with ripe mango and cardamom.
diff --git a/ftp-images/bilder-bp/mango-lassi/price.txt b/ftp-images/bilder-bp/mango-lassi/price.txt
deleted file mode 100755
index ea90ee3..0000000
--- a/ftp-images/bilder-bp/mango-lassi/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-45
diff --git a/ftp-images/bilder-bp/masala-chai/description.txt b/ftp-images/bilder-bp/masala-chai/description.txt
deleted file mode 100755
index 14915e7..0000000
--- a/ftp-images/bilder-bp/masala-chai/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Traditional spiced tea brewed with milk, cardamom, ginger and aromatic spices.
diff --git a/ftp-images/bilder-bp/masala-chai/price.txt b/ftp-images/bilder-bp/masala-chai/price.txt
deleted file mode 100755
index a272009..0000000
--- a/ftp-images/bilder-bp/masala-chai/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-39
diff --git a/ftp-images/bilder-bp/namakpare/bild/0E213352-9497-43D3-8455-BCCC47E2F4BE.png b/ftp-images/bilder-bp/namakpare/bild/0E213352-9497-43D3-8455-BCCC47E2F4BE.png
deleted file mode 100644
index 4af0111..0000000
Binary files a/ftp-images/bilder-bp/namakpare/bild/0E213352-9497-43D3-8455-BCCC47E2F4BE.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/namakpare/description.txt b/ftp-images/bilder-bp/namakpare/description.txt
deleted file mode 100755
index c09d64b..0000000
--- a/ftp-images/bilder-bp/namakpare/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Crispy, savory fried flour snacks seasoned with carom seeds and salt.
diff --git a/ftp-images/bilder-bp/namakpare/price.txt b/ftp-images/bilder-bp/namakpare/price.txt
deleted file mode 100755
index c8b255f..0000000
--- a/ftp-images/bilder-bp/namakpare/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-135
diff --git a/ftp-images/bilder-bp/palak-paneer/bild/88C5A618-F396-49DC-B07E-0719D8CE9731.png b/ftp-images/bilder-bp/palak-paneer/bild/88C5A618-F396-49DC-B07E-0719D8CE9731.png
deleted file mode 100644
index 62cac1d..0000000
Binary files a/ftp-images/bilder-bp/palak-paneer/bild/88C5A618-F396-49DC-B07E-0719D8CE9731.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/palak-paneer/description.txt b/ftp-images/bilder-bp/palak-paneer/description.txt
deleted file mode 100755
index 42a9e7e..0000000
--- a/ftp-images/bilder-bp/palak-paneer/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Cottage cheese cooked in a creamy spinach gravy with mild spices and aromatic herbs.
diff --git a/ftp-images/bilder-bp/palak-paneer/price.txt b/ftp-images/bilder-bp/palak-paneer/price.txt
deleted file mode 100755
index 897bdc8..0000000
--- a/ftp-images/bilder-bp/palak-paneer/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-139
diff --git a/ftp-images/bilder-bp/paneer-roll/bild/2BF341EB-962E-4738-A04E-883E95E840FE.png b/ftp-images/bilder-bp/paneer-roll/bild/2BF341EB-962E-4738-A04E-883E95E840FE.png
deleted file mode 100644
index eccb2e9..0000000
Binary files a/ftp-images/bilder-bp/paneer-roll/bild/2BF341EB-962E-4738-A04E-883E95E840FE.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/paneer-roll/description.txt b/ftp-images/bilder-bp/paneer-roll/description.txt
deleted file mode 100755
index bf684ea..0000000
--- a/ftp-images/bilder-bp/paneer-roll/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Grilled paneer cubes wrapped in naan with spices, chutney and fresh vegetables.
diff --git a/ftp-images/bilder-bp/paneer-roll/price.txt b/ftp-images/bilder-bp/paneer-roll/price.txt
deleted file mode 100755
index 3ad5abd..0000000
--- a/ftp-images/bilder-bp/paneer-roll/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-99
diff --git a/ftp-images/bilder-bp/panipuri/description.txt b/ftp-images/bilder-bp/panipuri/description.txt
deleted file mode 100755
index 459a086..0000000
--- a/ftp-images/bilder-bp/panipuri/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Crispy hollow puris filled with spiced chickpeas and potatoes, served with tangy tamarind water.
diff --git a/ftp-images/bilder-bp/panipuri/price.txt b/ftp-images/bilder-bp/panipuri/price.txt
deleted file mode 100755
index b5489e5..0000000
--- a/ftp-images/bilder-bp/panipuri/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-69
diff --git a/ftp-images/bilder-bp/paye/bild/IMG_1261.png b/ftp-images/bilder-bp/paye/bild/IMG_1261.png
deleted file mode 100644
index 7c7db6c..0000000
Binary files a/ftp-images/bilder-bp/paye/bild/IMG_1261.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/paye/description.txt b/ftp-images/bilder-bp/paye/description.txt
deleted file mode 100755
index 34fd0ea..0000000
--- a/ftp-images/bilder-bp/paye/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Slow-simmered lamb trotters in a thick, spicy and flavorful gravy.
diff --git a/ftp-images/bilder-bp/paye/price.txt b/ftp-images/bilder-bp/paye/price.txt
deleted file mode 100755
index 15c44e9..0000000
--- a/ftp-images/bilder-bp/paye/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-149
diff --git a/ftp-images/bilder-bp/pepsi-fanta/description.txt b/ftp-images/bilder-bp/pepsi-fanta/description.txt
deleted file mode 100755
index a2d851c..0000000
--- a/ftp-images/bilder-bp/pepsi-fanta/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Refreshing cola or orange flavored carbonated beverage.
diff --git a/ftp-images/bilder-bp/pepsi-fanta/price.txt b/ftp-images/bilder-bp/pepsi-fanta/price.txt
deleted file mode 100755
index f04c001..0000000
--- a/ftp-images/bilder-bp/pepsi-fanta/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-29
diff --git a/ftp-images/bilder-bp/peshawari-pizza/description.txt b/ftp-images/bilder-bp/peshawari-pizza/description.txt
deleted file mode 100755
index 12f75fb..0000000
--- a/ftp-images/bilder-bp/peshawari-pizza/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Naan-style pizza with tender meat, nuts, raisins and Peshawari spices.
diff --git a/ftp-images/bilder-bp/peshawari-pizza/price.txt b/ftp-images/bilder-bp/peshawari-pizza/price.txt
deleted file mode 100755
index 078fa0f..0000000
--- a/ftp-images/bilder-bp/peshawari-pizza/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-119
diff --git a/ftp-images/bilder-bp/rasmalai/bild/F57AE553-5357-425D-B4A9-F8D770F7CF31.png b/ftp-images/bilder-bp/rasmalai/bild/F57AE553-5357-425D-B4A9-F8D770F7CF31.png
deleted file mode 100644
index 5406029..0000000
Binary files a/ftp-images/bilder-bp/rasmalai/bild/F57AE553-5357-425D-B4A9-F8D770F7CF31.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/rasmalai/description.txt b/ftp-images/bilder-bp/rasmalai/description.txt
deleted file mode 100755
index b69bae9..0000000
--- a/ftp-images/bilder-bp/rasmalai/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Soft cheese dumplings soaked in chilled sweetened milk with cardamom and saffron.
diff --git a/ftp-images/bilder-bp/rasmalai/price.txt b/ftp-images/bilder-bp/rasmalai/price.txt
deleted file mode 100755
index ea90ee3..0000000
--- a/ftp-images/bilder-bp/rasmalai/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-45
diff --git a/ftp-images/bilder-bp/samosa-aloo/bild/E89E8B27-96F4-4461-AB0A-32DE2EDA09E7.png b/ftp-images/bilder-bp/samosa-aloo/bild/E89E8B27-96F4-4461-AB0A-32DE2EDA09E7.png
deleted file mode 100644
index 05dbf9e..0000000
Binary files a/ftp-images/bilder-bp/samosa-aloo/bild/E89E8B27-96F4-4461-AB0A-32DE2EDA09E7.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/samosa-aloo/description.txt b/ftp-images/bilder-bp/samosa-aloo/description.txt
deleted file mode 100755
index 5de810f..0000000
--- a/ftp-images/bilder-bp/samosa-aloo/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Crispy fried triangular pastries filled with spiced potatoes and peas.
diff --git a/ftp-images/bilder-bp/samosa-aloo/price.txt b/ftp-images/bilder-bp/samosa-aloo/price.txt
deleted file mode 100755
index a787364..0000000
--- a/ftp-images/bilder-bp/samosa-aloo/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-34
diff --git a/ftp-images/bilder-bp/samosa-chat/bild/433BF17B-BF2C-44A1-ADAF-64BC8EBE1DAF.png b/ftp-images/bilder-bp/samosa-chat/bild/433BF17B-BF2C-44A1-ADAF-64BC8EBE1DAF.png
deleted file mode 100644
index 8eaa3b1..0000000
Binary files a/ftp-images/bilder-bp/samosa-chat/bild/433BF17B-BF2C-44A1-ADAF-64BC8EBE1DAF.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/samosa-chat/description.txt b/ftp-images/bilder-bp/samosa-chat/description.txt
deleted file mode 100755
index 841d0af..0000000
--- a/ftp-images/bilder-bp/samosa-chat/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Crispy samosas topped with spicy chickpeas, yogurt, chutneys and fresh herbs.
diff --git a/ftp-images/bilder-bp/samosa-chat/price.txt b/ftp-images/bilder-bp/samosa-chat/price.txt
deleted file mode 100755
index 8643cf6..0000000
--- a/ftp-images/bilder-bp/samosa-chat/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-89
diff --git a/ftp-images/bilder-bp/samosa-keema/bild/IMG_0176.jpeg b/ftp-images/bilder-bp/samosa-keema/bild/IMG_0176.jpeg
deleted file mode 100644
index fbfebf5..0000000
Binary files a/ftp-images/bilder-bp/samosa-keema/bild/IMG_0176.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/samosa-keema/description.txt b/ftp-images/bilder-bp/samosa-keema/description.txt
deleted file mode 100755
index 7bc73b3..0000000
--- a/ftp-images/bilder-bp/samosa-keema/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Flaky pastries stuffed with spiced minced meat filling.
diff --git a/ftp-images/bilder-bp/samosa-keema/price.txt b/ftp-images/bilder-bp/samosa-keema/price.txt
deleted file mode 100755
index a272009..0000000
--- a/ftp-images/bilder-bp/samosa-keema/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-39
diff --git a/ftp-images/bilder-bp/shahi-burger/bild/6CB0C654-7F44-42A5-AAA3-59BF7D1B14C9.png b/ftp-images/bilder-bp/shahi-burger/bild/6CB0C654-7F44-42A5-AAA3-59BF7D1B14C9.png
deleted file mode 100644
index 5c98b08..0000000
Binary files a/ftp-images/bilder-bp/shahi-burger/bild/6CB0C654-7F44-42A5-AAA3-59BF7D1B14C9.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/shahi-burger/description.txt b/ftp-images/bilder-bp/shahi-burger/description.txt
deleted file mode 100755
index c408dce..0000000
--- a/ftp-images/bilder-bp/shahi-burger/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Juicy spiced meat patty in a soft bun with special sauces, lettuce and tomatoes.
diff --git a/ftp-images/bilder-bp/shahi-burger/price.txt b/ftp-images/bilder-bp/shahi-burger/price.txt
deleted file mode 100755
index 078fa0f..0000000
--- a/ftp-images/bilder-bp/shahi-burger/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-119
diff --git a/ftp-images/bilder-bp/shahi-paneer/bild/99578611-B6BE-4C43-998F-A3D2CC65B5BB.png b/ftp-images/bilder-bp/shahi-paneer/bild/99578611-B6BE-4C43-998F-A3D2CC65B5BB.png
deleted file mode 100644
index a809b05..0000000
Binary files a/ftp-images/bilder-bp/shahi-paneer/bild/99578611-B6BE-4C43-998F-A3D2CC65B5BB.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/shahi-paneer/description.txt b/ftp-images/bilder-bp/shahi-paneer/description.txt
deleted file mode 100755
index 0a7349a..0000000
--- a/ftp-images/bilder-bp/shahi-paneer/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Soft cottage cheese in a rich, creamy cashew and tomato gravy with Indian spices.
diff --git a/ftp-images/bilder-bp/shahi-paneer/price.txt b/ftp-images/bilder-bp/shahi-paneer/price.txt
deleted file mode 100755
index 897bdc8..0000000
--- a/ftp-images/bilder-bp/shahi-paneer/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-139
diff --git a/ftp-images/bilder-bp/shami-sandwich/bild/5F78D473-1159-4FF7-9A5D-86686B6D29CA.png b/ftp-images/bilder-bp/shami-sandwich/bild/5F78D473-1159-4FF7-9A5D-86686B6D29CA.png
deleted file mode 100644
index e109f1e..0000000
Binary files a/ftp-images/bilder-bp/shami-sandwich/bild/5F78D473-1159-4FF7-9A5D-86686B6D29CA.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/shami-sandwich/description.txt b/ftp-images/bilder-bp/shami-sandwich/description.txt
deleted file mode 100755
index 3e6d1ed..0000000
--- a/ftp-images/bilder-bp/shami-sandwich/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Spiced minced meat shami kebab patties served in bread with chutney and onions.
diff --git a/ftp-images/bilder-bp/shami-sandwich/price.txt b/ftp-images/bilder-bp/shami-sandwich/price.txt
deleted file mode 100755
index 3ad5abd..0000000
--- a/ftp-images/bilder-bp/shami-sandwich/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-99
diff --git a/ftp-images/bilder-bp/sprite-ramlosa/description.txt b/ftp-images/bilder-bp/sprite-ramlosa/description.txt
deleted file mode 100755
index aaf3910..0000000
--- a/ftp-images/bilder-bp/sprite-ramlosa/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Crisp lemon-lime soda or sparkling mineral water.
diff --git a/ftp-images/bilder-bp/sprite-ramlosa/price.txt b/ftp-images/bilder-bp/sprite-ramlosa/price.txt
deleted file mode 100755
index f04c001..0000000
--- a/ftp-images/bilder-bp/sprite-ramlosa/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-29
diff --git a/ftp-images/bilder-bp/sweets/Shakar paray/IMG_0210.jpeg b/ftp-images/bilder-bp/sweets/Shakar paray/IMG_0210.jpeg
deleted file mode 100644
index d5210ea..0000000
Binary files a/ftp-images/bilder-bp/sweets/Shakar paray/IMG_0210.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/badam-barfi/bild/IMG_1399.jpeg b/ftp-images/bilder-bp/sweets/badam-barfi/bild/IMG_1399.jpeg
deleted file mode 100644
index bd1b52a..0000000
Binary files a/ftp-images/bilder-bp/sweets/badam-barfi/bild/IMG_1399.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/baisan-barfi/bild/IMG_1403.jpeg b/ftp-images/bilder-bp/sweets/baisan-barfi/bild/IMG_1403.jpeg
deleted file mode 100644
index 7586179..0000000
Binary files a/ftp-images/bilder-bp/sweets/baisan-barfi/bild/IMG_1403.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/baisan-patisa/bild/IMG_1401.jpeg b/ftp-images/bilder-bp/sweets/baisan-patisa/bild/IMG_1401.jpeg
deleted file mode 100644
index b96b1b2..0000000
Binary files a/ftp-images/bilder-bp/sweets/baisan-patisa/bild/IMG_1401.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/cham-cham/bild/IMG_1407.jpeg b/ftp-images/bilder-bp/sweets/cham-cham/bild/IMG_1407.jpeg
deleted file mode 100644
index 5c4950e..0000000
Binary files a/ftp-images/bilder-bp/sweets/cham-cham/bild/IMG_1407.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/chochlate-barfi/bild/IMG_1402.jpeg b/ftp-images/bilder-bp/sweets/chochlate-barfi/bild/IMG_1402.jpeg
deleted file mode 100644
index 382a39a..0000000
Binary files a/ftp-images/bilder-bp/sweets/chochlate-barfi/bild/IMG_1402.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/coconut-barfi/bild/IMG_1398.jpeg b/ftp-images/bilder-bp/sweets/coconut-barfi/bild/IMG_1398.jpeg
deleted file mode 100644
index dd699bb..0000000
Binary files a/ftp-images/bilder-bp/sweets/coconut-barfi/bild/IMG_1398.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/cream-gulab-jaman/bild/IMG_1408.jpeg b/ftp-images/bilder-bp/sweets/cream-gulab-jaman/bild/IMG_1408.jpeg
deleted file mode 100644
index 7a6ace5..0000000
Binary files a/ftp-images/bilder-bp/sweets/cream-gulab-jaman/bild/IMG_1408.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/gajar-barfi/bild/IMG_1397.jpeg b/ftp-images/bilder-bp/sweets/gajar-barfi/bild/IMG_1397.jpeg
deleted file mode 100644
index 65623a2..0000000
Binary files a/ftp-images/bilder-bp/sweets/gajar-barfi/bild/IMG_1397.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/gulab-jaman/bild/IMG_1416.jpeg b/ftp-images/bilder-bp/sweets/gulab-jaman/bild/IMG_1416.jpeg
deleted file mode 100644
index 2d4b3c2..0000000
Binary files a/ftp-images/bilder-bp/sweets/gulab-jaman/bild/IMG_1416.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/habshi-halwa/bild/IMG_1412.jpeg b/ftp-images/bilder-bp/sweets/habshi-halwa/bild/IMG_1412.jpeg
deleted file mode 100644
index 4f0120a..0000000
Binary files a/ftp-images/bilder-bp/sweets/habshi-halwa/bild/IMG_1412.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/laddu/bild/IMG_1413.jpeg b/ftp-images/bilder-bp/sweets/laddu/bild/IMG_1413.jpeg
deleted file mode 100644
index 018b3ea..0000000
Binary files a/ftp-images/bilder-bp/sweets/laddu/bild/IMG_1413.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/lambay-gulab-jaman/bild/IMG_1415.jpeg b/ftp-images/bilder-bp/sweets/lambay-gulab-jaman/bild/IMG_1415.jpeg
deleted file mode 100644
index 4a03cce..0000000
Binary files a/ftp-images/bilder-bp/sweets/lambay-gulab-jaman/bild/IMG_1415.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/milk-cake-akhrot/bild/IMG_1418.jpeg b/ftp-images/bilder-bp/sweets/milk-cake-akhrot/bild/IMG_1418.jpeg
deleted file mode 100644
index 8f3efa5..0000000
Binary files a/ftp-images/bilder-bp/sweets/milk-cake-akhrot/bild/IMG_1418.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/milk-cake-khajoor/bild/IMG_1406.jpeg b/ftp-images/bilder-bp/sweets/milk-cake-khajoor/bild/IMG_1406.jpeg
deleted file mode 100644
index 9a6d5f5..0000000
Binary files a/ftp-images/bilder-bp/sweets/milk-cake-khajoor/bild/IMG_1406.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/milk-cake-plain/bild/IMG_1411.jpeg b/ftp-images/bilder-bp/sweets/milk-cake-plain/bild/IMG_1411.jpeg
deleted file mode 100644
index 3b2ed54..0000000
Binary files a/ftp-images/bilder-bp/sweets/milk-cake-plain/bild/IMG_1411.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/namak-paray/bild/IMG_0209.jpeg b/ftp-images/bilder-bp/sweets/namak-paray/bild/IMG_0209.jpeg
deleted file mode 100644
index 23a003b..0000000
Binary files a/ftp-images/bilder-bp/sweets/namak-paray/bild/IMG_0209.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/paira/bild/IMG_1414.jpeg b/ftp-images/bilder-bp/sweets/paira/bild/IMG_1414.jpeg
deleted file mode 100644
index e761f54..0000000
Binary files a/ftp-images/bilder-bp/sweets/paira/bild/IMG_1414.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/patisa/bild/IMG_1400.jpeg b/ftp-images/bilder-bp/sweets/patisa/bild/IMG_1400.jpeg
deleted file mode 100644
index 5202c88..0000000
Binary files a/ftp-images/bilder-bp/sweets/patisa/bild/IMG_1400.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/pink-barfi/bild/IMG_1405.jpeg b/ftp-images/bilder-bp/sweets/pink-barfi/bild/IMG_1405.jpeg
deleted file mode 100644
index 2c14718..0000000
Binary files a/ftp-images/bilder-bp/sweets/pink-barfi/bild/IMG_1405.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/pistacho-barfi/bild/IMG_0208.jpeg b/ftp-images/bilder-bp/sweets/pistacho-barfi/bild/IMG_0208.jpeg
deleted file mode 100644
index 688117e..0000000
Binary files a/ftp-images/bilder-bp/sweets/pistacho-barfi/bild/IMG_0208.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/plain-barfi/bild/IMG_1398.jpeg b/ftp-images/bilder-bp/sweets/plain-barfi/bild/IMG_1398.jpeg
deleted file mode 100644
index dd699bb..0000000
Binary files a/ftp-images/bilder-bp/sweets/plain-barfi/bild/IMG_1398.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/qalakand/bild/IMG_1404.jpeg b/ftp-images/bilder-bp/sweets/qalakand/bild/IMG_1404.jpeg
deleted file mode 100644
index b11aaeb..0000000
Binary files a/ftp-images/bilder-bp/sweets/qalakand/bild/IMG_1404.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/ras-gulay/bild/IMG_1410.jpeg b/ftp-images/bilder-bp/sweets/ras-gulay/bild/IMG_1410.jpeg
deleted file mode 100644
index fce1a17..0000000
Binary files a/ftp-images/bilder-bp/sweets/ras-gulay/bild/IMG_1410.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/round-gulab-jaman/bild/IMG_1416.jpeg b/ftp-images/bilder-bp/sweets/round-gulab-jaman/bild/IMG_1416.jpeg
deleted file mode 100644
index 2d4b3c2..0000000
Binary files a/ftp-images/bilder-bp/sweets/round-gulab-jaman/bild/IMG_1416.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/sweets/shahi-tukra/bild/IMG_1409.jpeg b/ftp-images/bilder-bp/sweets/shahi-tukra/bild/IMG_1409.jpeg
deleted file mode 100644
index fb5c7e5..0000000
Binary files a/ftp-images/bilder-bp/sweets/shahi-tukra/bild/IMG_1409.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/tea/description.txt b/ftp-images/bilder-bp/tea/description.txt
deleted file mode 100755
index b719bd4..0000000
--- a/ftp-images/bilder-bp/tea/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Traditional hot black tea, served plain or with milk.
diff --git a/ftp-images/bilder-bp/tea/price.txt b/ftp-images/bilder-bp/tea/price.txt
deleted file mode 100755
index 64bb6b7..0000000
--- a/ftp-images/bilder-bp/tea/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-30
diff --git a/ftp-images/bilder-bp/tikka-boti-pizza/bild/2D7E1FAC-D62A-4991-B08B-4EED8D1D20E8.png b/ftp-images/bilder-bp/tikka-boti-pizza/bild/2D7E1FAC-D62A-4991-B08B-4EED8D1D20E8.png
deleted file mode 100644
index b7055cb..0000000
Binary files a/ftp-images/bilder-bp/tikka-boti-pizza/bild/2D7E1FAC-D62A-4991-B08B-4EED8D1D20E8.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/tikka-boti-pizza/description.txt b/ftp-images/bilder-bp/tikka-boti-pizza/description.txt
deleted file mode 100755
index 8e997e3..0000000
--- a/ftp-images/bilder-bp/tikka-boti-pizza/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Pizza featuring grilled chicken tikka, cheese, tomatoes and fresh herbs.
diff --git a/ftp-images/bilder-bp/tikka-boti-pizza/price.txt b/ftp-images/bilder-bp/tikka-boti-pizza/price.txt
deleted file mode 100755
index 078fa0f..0000000
--- a/ftp-images/bilder-bp/tikka-boti-pizza/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-119
diff --git a/ftp-images/bilder-bp/tikka-boti-roll/bild/42EB7D04-689C-49AE-B0D2-0EE0F5D929B7.png b/ftp-images/bilder-bp/tikka-boti-roll/bild/42EB7D04-689C-49AE-B0D2-0EE0F5D929B7.png
deleted file mode 100644
index ec25b65..0000000
Binary files a/ftp-images/bilder-bp/tikka-boti-roll/bild/42EB7D04-689C-49AE-B0D2-0EE0F5D929B7.png and /dev/null differ
diff --git a/ftp-images/bilder-bp/tikka-boti-roll/description.txt b/ftp-images/bilder-bp/tikka-boti-roll/description.txt
deleted file mode 100755
index 1e52e8b..0000000
--- a/ftp-images/bilder-bp/tikka-boti-roll/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Grilled chicken tikka wrapped in soft naan with mint chutney and onions.
diff --git a/ftp-images/bilder-bp/tikka-boti-roll/price.txt b/ftp-images/bilder-bp/tikka-boti-roll/price.txt
deleted file mode 100755
index 3ad5abd..0000000
--- a/ftp-images/bilder-bp/tikka-boti-roll/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-99
diff --git a/ftp-images/bilder-bp/veg-pizza/bild/IMG_0185.jpeg b/ftp-images/bilder-bp/veg-pizza/bild/IMG_0185.jpeg
deleted file mode 100644
index 9cd0395..0000000
Binary files a/ftp-images/bilder-bp/veg-pizza/bild/IMG_0185.jpeg and /dev/null differ
diff --git a/ftp-images/bilder-bp/veg-pizza/description.txt b/ftp-images/bilder-bp/veg-pizza/description.txt
deleted file mode 100755
index 6ee0fb8..0000000
--- a/ftp-images/bilder-bp/veg-pizza/description.txt
+++ /dev/null
@@ -1 +0,0 @@
-Vegetarian pizza loaded with fresh vegetables, cheese and tomato sauce.
diff --git a/ftp-images/bilder-bp/veg-pizza/price.txt b/ftp-images/bilder-bp/veg-pizza/price.txt
deleted file mode 100755
index e2a9fee..0000000
--- a/ftp-images/bilder-bp/veg-pizza/price.txt
+++ /dev/null
@@ -1 +0,0 @@
-109
diff --git a/ftp-images/menu/ShahiMenu.pdf b/ftp-images/menu/ShahiMenu.pdf
deleted file mode 100644
index 8a0c013..0000000
--- a/ftp-images/menu/ShahiMenu.pdf
+++ /dev/null
@@ -1,337 +0,0 @@
-%PDF-1.3
-%
-1 0 obj
-<<
-/Producer (pypdf)
->>
-endobj
-2 0 obj
-<<
-/Type /Pages
-/Count 6
-/Kids [ 4 0 R 9 0 R 14 0 R 17 0 R 20 0 R 23 0 R ]
->>
-endobj
-3 0 obj
-<<
-/Type /Catalog
-/Pages 2 0 R
->>
-endobj
-4 0 obj
-<<
-/Contents 5 0 R
-/MediaBox [ 0 0 864 1152 ]
-/Resources <<
-/Font 6 0 R
-/ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
-/XObject <<
-/FormXob.c4a784aebef7f1e17ac1238f3cf085f8 8 0 R
->>
->>
-/Rotate 0
-/Trans <<
->>
-/Type /Page
-/Parent 2 0 R
->>
-endobj
-5 0 obj
-<<
-/Filter [ /ASCII85Decode /FlateDecode ]
-/Length 130
->>
-stream
-GapA.0b/gi&4Fop:GF3s`[pZ2-r?a+E^=IlDhkE5rut
-endstream
-endobj
-6 0 obj
-<<
-/F1 7 0 R
->>
-endobj
-7 0 obj
-<<
-/BaseFont /Helvetica
-/Encoding /WinAnsiEncoding
-/Name /F1
-/Subtype /Type1
-/Type /Font
->>
-endobj
-8 0 obj
-<<
-/BitsPerComponent 8
-/ColorSpace /DeviceRGB
-/Filter [ /ASCII85Decode /DCTDecode ]
-/Height 1152
-/Subtype /Image
-/Type /XObject
-/Width 864
-/Length 625528
->>
-stream
-s4IA1")(,JBk@>F8P(B3#QOi)!rrf3!W[HG!!"bS!!#(]!WXMH!!'#"!!$_g"98H&!!(=Gz!!#r3B5V."F`M%S+Ac!GFD,A\;GgLiH;mI(A5-l=:j?,8ASu]FBlcs:1GhpQ8Td?M0fVaJ7oj\-DKKr887P5.:IJ;o8S`3RCbK`\=BJ!m2IUed>%MPrF(K*"91Wen3B1\+:IIiT=_;Y?1eV7j0hcFm794)*75oNG^+*[Dg?)!0NW6d;)q?o0Q07!8k`kk1HAEK85)!#Fa?k_9iOYO9Je\A7RV5_BJDe-Gstk^F%fY];-$1`E)e\gFDGVJ2Hj]P=_glMF>6-?Dbs8K9N=AjH"/OHAM6PR:.J2r7X%NVG'5leCJJk+;ce6EAjL_n7QEqQA4p!"0331(3AaKC@:Ek\C.MB:<`OBaEa^nH<]F](7SQ?_CeA\U:bXhH8m4\\BfIhh1.X,uA7JY[1H@=:6>oG@H"^i"3G_/rA4e^R4TI8l3&i[%2e"@K2D@'A1h8OW/Ri9G2D&As@5_^X@Uq/I0Jrh2!/?XA!.P"L!9!qYz!'sON8P&m^!)mTEDIIX0Eb.9S:fChFBPC(:;--J<<(TJg9l*a)GZdXMDKdaJF%f"Y1f/EgF[@T53(\9`&6Q<3Gq]:E'[TN=@IL]C.;9LG]#3RH"pD7=)gi03DFZNDaAJ;9P7$T3E0]`9K4nPH;IO7<(KDN1cK);6ubP,0gRO>79OqX9NQO;<_#u*%T`sCJekh0gdg::f)(('N1FuaVZ:2r*h=*[eX6$b%N3C[ao934nB"2>&3&,M1824%R@odS*3Al"IDb55"BP1d7CdquH8i9=+s53kg8k)BA!!**#!!*'#!!*&R!(-_f!ai`&\eCE.%f\,!;ioB+]k3(smlLFH:o_%qPq"add_uLk[!!<6&!+Ya065u@kqE>'NOJHurVOeK%r#pV6(n.fDQd0^X71uTbN(Dn#.-7:2j.Q'+C3&s#e6q'R884cEP<)lt#=BSg;A7]@cBPD4&FEMbNG^4UeK7nr5LPUeEP*;,qQC!u,R\HRQV5C/hWN*81['d?O\@K2f_o0O6a2lBFdaQ^rf%8R-g>_/RjlYail0@j2o_%qPq"addg&MN`!<<05!tbMt!;uiseNV<-j#`_2IP&dPT/7uBEi(?"i7P[#61a@!JgJfTeSCcn*/2P7Ep1o"[rIZZDZ$Ea$9+J-OY4g6,[Ej[/!#+'MXsQFVjCNWqd=#:+3OPE1$pnB\psGJn>fimV3.]k=*'`5Glg]bIMcG3m%1o8o5sG7\_5N#pWL>PMjM56^^*pbDUlN&aj'l.t-Gee:!-1%K[Rb1K)ZibdMSn"0a>e^a+'a!N9"T].."^Ur,TAsL6@Y;EbB/6P#/u&F=^S$K7T1HiA&Yu>Z@cSL#Y="=21*YF3^"_W\^gU4n3_fZEo_k^`%p:e-,A,=:ntra-F)<7dIarrCLr8I09]0aE`(@p8D6op:O&FH;,>,k3GQ%*`X:pNjHtDHVS0"D$I&J]@8(iGpste'msh!"O6T`#!_1LpW)mmOU$Fdo#ugZ>b":LgA9Y'Q*n!4ul4RI[g3@!qD/FPE[+@@QWu[F?39q,i$AN(/l(/DK7<]dh[BTG,i#D+ppfHE$U\<"Eg^F'b.DB,'5.GU5I@iqj5lr)hK$r&nJ-o%[Gb3lRjg&mUf#UiML>m)f]eJ03F+cRP-SR[<&O^.-M')S.oq6W*W2i4F>]]Lh%K^pn?L(Y<^'n2kJ5RQHaSN;1CX3TIS+^#9E)ioe5fNFu2Z[to\r3d#tFm'_4](p3s[<4aU4ZstD:1>MplX*\%!-29DM-.9\7co'!ohq5fIg4$"B=R_7SP:j\c2]-Ob_i3,!'_q8upj&OIJ:&Z>Y,-&W51AK(Am'?6]q*6tj^8[gH:5uiA.4J%B?qL$:,,h"GF6ftIe,8Ppm^e7b?D?]eo)hKT)%/-UU>_MEAXKY$AtGXZ#2,DD(-B#PYi$L3nQbLcqap]rdEK0K]rOqAFJU7n([CP#7QDDt%FYd&kXRbeVYEgC#D0U_!7aU0/,k8(Z*^H_%p+0<`+U[Q=S,b(2^:!JqKlMX2\60h?>-\?]DG"lo31E[j6^if_XG^t=]I2r$bN@m3a`qOaW+?b_`s18&&Z]rpnGpK5e4>n$H?])&mGg.P[uSFElaklVo^@tUcSb$29GVPiU;_5nC?EPHtK]i>eG+5>A5[*o#p22$>+G@b8EDp!$R@:SgtZ,Mj1d1U6aYJSCXu?^?2>M4t6D9d-T_T>LiX-BVC)qAU$^,Z(7o@JocH]!s%2Bp@3pW.qm?_-WffW[dN[YMb'9SS?OP(N>aQV.R4qE^a/GJGRM@f!!iKKGZN:!n?0;Q=0l+,C:4p:[a7I=b8btQAn__jAXnf0(>;pK!3'.ci;WfN#..>8sCIseTJTW)9PjbrrB7e'iXg\pk7<6L>a^q2dRIh=Efi[:c%[/l(3.%*B<9Zf"EHKh\9EWYdq>lD[-!:n]6&+p?!<>j^8M*P5M=9P7nL,j!(l.1[t]C\^RXo&F'02A)bFt[(,bMOaN3D:!W/%.Soo]#6=Ql8&$WHW7fXsTD9EphaoVke\3d97C&(.2>f\tql(,eJSk&Do/6pT!*4tt`sp[/j!(7Z`.&SG9lbM*dX3jEnKU-\jl%_K@D&o-_**VW4Gr>T2>nW6=#X;)_Q@@a[d!d`igA4If!d,"Oiugt!\LO=N!0AXK9p%<$X:L),4Joiiler0&U5nqA=lbL.o*/BZTr@n>CX=D*m?SM4gpfAeNB1p(ugEU#G?2j8^UGc1&._%O39>7DqJQQYo#kD\"mY5Ak$^VU9j_EL*O7FENlDV*T.eRO+`XdW'/7V_sAjMXTcU7UQ\H,=cPL]XTr)p;RY&u[a_m:r6amp#,$pN'kL3+a&Krn_6nV%`P9$Im+ZZVW!F+>m[dn[J1ttIh-Et@,GB!uc3Ye0<"=Sqn:AEVEEUr&J-DGup4T]u/Nf'M;J)NL>RYlIdp=[\8[2Z1LE`^W7mk4'P4.ucV@nI*7O4'Rr*\;(5$OADC'J/aXgnUZiRUhpLT+7P%]-]$rH*Omrp$[B;D(W8NN>ki5.ZEUdO)r(he9<".[i,6'J@-dmi'do[!F<2LO]LD>M;P#NM=JhpmZUkCX4?G-RM5T2pR&JE*-Rj&E4!m85d!CiXQej%XkJR<"(MUXk#D4)d=n)FkRjFio]#tl#dAM6B-*t*jG,n**4D0bn-_-Xf]O[RurrC:,:#pJ?qm5O$jb0siihQPQWGof`,F@&9SY9Fi@#TaX$Hl^V2?uNh"r\@!'hY>3$A(JSR9AY)rNWg..CdD0"%OOHY'_7@Cj.[[r&s5b6k_GNYR>na;'&lf2J_p/&iY5@=lhDfCmSHg`i:@c,,j=ODK8eBO_2(gFXI$K`q(j_>$f=i_L&/ZM3?2TAhT%gW%7ik2>5%\XUf@ram0<7]I&Q.\6VW`bV/BEGk+=qo5G-Y7i[@MVkemO.uXSKSr@PHmahW"653;,jf[6ZR&;ANnX<@o,KV+Al;%,DB=`qZsOr%2^RrrBlY)K)IQ^nQ(,Wj]q>\!GHY"9>rjb]f3X'gKT-eXT^PQeWY)0;4X9`D;OY)NrWn^CYWnrd6ckXF)=6$d[0U7iZI02_;nAbAh6QXSWB1(cI7_ii+&5@Hn/b[d7k!9e9&m'X'6%1HTRlCdk0RB:H-D*70QrXG,@k,80rn.Z/UfGpmUrp2YttI[u#,2[SdDaGD3PcQ7S\G$imGBRValq)(*ceUA347882jLU?^>KC71SYd[pPI(uQt$:>$-Y=;G?9L*9><q*@o$j07WErpnt*Q2@XqnuKaK\s0pO2J#"n8>J^(K9N1I>ZWQJY-cP9[+hLi(:GUfb^0/fIR?T'h?-4/"ad!Mu6,qZo\YTHW"FbdoQ/_eljYgS[$renk2SIjsYrh$Oc)pb/tbZm+C0!G/YgS@?_L7CA"KY4Ce>`DrTXel'eN+fhbBprr@i`.r>8-=NXkDW3OChbVk%X9_RRXZILgjcO9M?d`jX6&'oO"8"4`tp\&As-d=*U#o]StPRpttG]$&4W&`0m\N]0S$+7P%5PC2cOr[%udrUc8m=!tu'E8%MIAnB0A"fn[FG@`5sd)jH$YBiiZVWj>r6A[VdK6"TMs4IfId%uPL:JiBu$Hf:.E)&EW;%6-ljZocCY&^;#^1&ED)&<'*,7g"X_90F'*f9n*bS6Ce.Zql[R[3a04h!7-5MHak>8M+HAhPXQ4c5IX'KF\,]b-E#mb_!_m:Gp\SM;^W!(H)Di(&5pogV4][T&6WBQfKk_A0=p5'S/V0>hRO8u:_&WgO.GSJsEjq'V))RQ0M.;Qo'(3P+*0@!D?pHk8?jEs?0C^F1+55.='$4]$L)I-=T?+RLO%Hdm->U/fI=aHthhdB]83dJ3e71AXHpp]cK>'RuFap\_4Ba&S1I`CJ6"B&Ao&Ykc/$tJ\#""L.iC.l=;3%e/8cJcrbTg,sAup:HLjgh&dlmlI\CJ6/Y?3#2`u8(ErX5%srgDa;Ba,M4GMo:r`?;?,i(7?YG\61&dOK1?M#33'!'#ARMam8LnK>&_cl9?1E/T]o>QIA8dQR^b7*"+;P?nt&,-m*Re'pFgD,G5eF]Hr`]19DoLU6=Bj/\7QG_g*`WYqh9m;2e_&hm,fG:P%E2TC"<$;bK=]V"#)S=m=dXl*n,;mk[_&4sMcrEmlD^^ZI-BNWB/rgNDtA+1?BKY-cAX;o`&L>&+nQEFl2giO+j".f9!+>AF8L*.chX&,9;t0%+*bn".AEUrrD%9c&IC^88Vqfr#Z>^a@9%8,*JjTP/ICg>+`(uUL!36GlH%J`U:G!4]5S[2\A@l4%K`.914%0+Y+YY5Wn56#//J_rM=rWC;(e(dj3H0/X6rQ4[:X$e&`WIQGTRt[IQQ`pL=>IhS+$%%\2do<0C&T..CeOELid2T07GB`S\(8M5+8#iZ1t7hd_7,>Fe?5.l/U:$tLd=6&*DK$EtOGE$a!4+TB`VNgq%TnW/4'-FpaHm*Ss=>o&Y!JQ*)4<=Z[U'9[?d?BX1_4p#t>kuQ/U[4SNL+o=Hs@2>7l-*5*O!L,9TZ+f+`Grr;t+fg4p!/+^rIgQ)uC>TW90;_#eV:LZFrQ!S27qiUbE*<;D^b0o`eImE)M$7PO6(J&+1=gm+CGBmA7L^U:P%Hp7DQLqY,/&gW#r9l=e8A)FjuNtE0-!*]=m$eT(sE2l)Bn]1$Bil`/r%hH.(iinA/?FM&`rYl6#e#>AMEi7V@^MC-+%'#f]FZ\r;ZZINt?B(5&D@^NngU2YtEO;YluE%%=hJPF_'s>DH$6&%mGu:MSVRGDnAn%"(k"]FQ*JE@.N!D_&XJIc^qhEt=NJBSfj4+IN3hnpo'2c`Z,P'_m(dV%0&nG\15+;mNk:gA_.INGU;:&Kjp=Z*q)JmgKcFVCP^5;bD(65O5jbe>$Q!AO(g1$EdYC:5k>oA/*<@^j%'-93^l1b)Df%cZD"bb$R>[^J@HHung0gccGApVTc9-(WaW(!Wh3BZXJ14Lh&DP9q"LFGGrWT`frW2l0PQD-Kf&jqEDWeY@W@ndTBQh\n=>B@_MVC%8UlS"TXSJSnsK]9sP`Dp&=MdiU$;D)H7c,?q^:ce#f_UHt\.?K5.Fma,5@bYfYd#C+qn%#bg?cU$hW5Du6sQ+H`D_m_T!&?(@\nX4si\Xh6M]Ja2N"AR(]DnL;';GChWN<+$/gfJ4O47%CBqa//J=i:/,NM;H$GODTHjO,2BOfl:jY>L[bMe?O?Lk_&DCU,YM>n,?VLB@)V+U`;<5]#!?MuB,Jm+Btc+mbH/[*V-Nf]6h'^3Yl=^D[^Y1QW-?GV]#P\6#Y*_l[aF\dSk8QYT7aitpj;&KU#/DQo_TJCCuP?JF%:-n%*2t00a3#&!p$dhGJKsXWT%2YmoRoLIqIE*L7XUH*/8Fa((_!.2`-H2^nTnF4G>$JMOD`;RtRPKLJ:+2'Vb#S#k%]mBR"A=K2),niQKm%#m&O#nAX03,(C!?^u^S`Eu\V3*1#r,T+F5%?\_[GlM`.#(PeK[Qhl.51.&n[&F%&BTM)<5CB3AjQ4HEZYq35OLnX/C>jd!Si5X*D3+bt#u69kE#B5O1lYX=0p%KK`%D`(E'V\e\,IV$cQ4Ua^(JKa7ehj81&O26`j8r$?H2S*D(u>9m_[!hDXGWG4%F9o68^7$i="=Dc?#`gF%Y&-4K$+>)?0\N.i[ul.%W!p)jp\XlL.0OL<7Q!"PY[f-n:#@2AJ_IC(Co$S+a)<0;=fN3f]%+[=a:sea,/-,dY%%i2WhAp\)#D4?7QDKpKm\`\HW2C/N9=69neeMlDMm9U7d@8B9Q+.SglUO$`@`[qkM+lGdN)Dfk2D>r!jVWV'J\F,3uHn8ks!dLLg^4(6t]drcahg@^5W^*%/EhD7eCBoksg>sD)kiH&oFm6t#aW*C*MjgjGQOfJ5c?[)D[Wa>)G?VpO*nT'*f=C,_!'mqlKHr<3$CTFF3j2c8^=]!)#!$Qs]!scP8*ini*p5";;jh%aO81d])k>B^3NSGfU0o:F>r57tG>b4H#oh>tUc\lod.p)7aOVIP9%>Lp'VV??I(4nqB5[%`!gP8V'G3iiK!j4d'kPkMqc[r5N]K:Q#WRg!BQAHhmBbnZ?+E_A87dQ%iM/87\ntRQmj0_ad'm[iLla_VH6-@T%*;6/t"87M&:gXc>ppphMm`ECVi7otk\4r"/a/K.A:=]b3c",K)?2^\66fMB:SSi['o]puaXCAPuLsY(ZG*$8O"7L8#-Q&t8(AJg=D)r1Eg1^32pUVZNghN:*EI>V-anp0WTEfL/JL[;(_&*=8U[^RfSQk+:M)9&O_qIhmT"AuVEcis;9;QV2":a_1ig[@"$SRP?!#>0b)"`eK,eT`2eWMm=[ZTu"j=GHuo-0@Q\/<"!ij7O]^D?ID+O@.aj270]"\@4ip+Nl1%I-I.'tBMRClX1/3e>OjpgZY[^9MN$Vh==n$++Da;CU[[8bS-JP8Lg?OtH&@7FQ"e]2cCOdj*4U4r1VdHkcbY&&XMU`gI^RP>BRE.%Uae_S?pM_Vc!OOnZ'enj',?itlC4^n5/>G'JGmMnV,W7iQ\W`0s`4=q"Y>B[N09h,"OdrhVI]L`NU2O@@U]RiI879JVe!]Tah#sC?$Uj,PJ!imG1`L)ZOQK/=3K-m(01h^QQ2l\q$NB[0IJ@g>oHpsZ!_H2KuVP$9G`Li':BP0?S(fPnC@(mZ+bWS4lGa,6?knScC[!\66PbLMo(B(E[SqA$>.Eu6%qO@PDX#\E1436<;p=(gR:qeq)[T)^u8iTn#O=+.0pB,!OELtXeU?JiZr&r7,OndHKamsYUOBhWJ7@Bd4h0=c3"3U?"Y\nn;r,dg#Mtcb!h1_KDQ)s?+:^\oY,UhG4]:XRVm]QO0BcdQW$$iOq5=L_QFbs!H$eqW,bXi`^S)`>4(D=&liIOA36XG3"0+UFFg?Muleu^6f9!m%fY"eI),EhqF`tG-r)jn5d%KgRa#E4eI37F=7Ea@\EhL&8soVHYcmqrp+.0*J>8!hJ_F-[b1gOZtu369'G\FKS!m1H.=?9]#pWC"$k8ruO"AS0+#/\?S@ER.MfHI^M&mh"]s$1OgeCScMskk_J`tR8sZE#AZNNg!gXD2]5*cM-(]9XA%eQlC]3ZPH-5B#oTrD#]:j$1T?92ZZ[WlK='jZ&,7/KD*UB6HQ45>M1C3c?*f8C_fQohB@,dVQ!_oBajrWEdOa9.3"cW[T2*aN-O04C^$,Mb2u2D87b]"e,dD'2:%!U&A@SXXj;VP-Igo'6tgN2h'Q*_aMiU"]YrG8:&*MV.#kR%_C>oJd7WQ'2mYLRIoQ3Sp5c3;G*a,c7W[aA>EH!0KW!p,/osP()]eJ*'+YRPPVq?5NCGnFsgYqPT8bhJ"V(8=mr"/TG\:UGR$ONH6#DD/e9\(iTf#7GuE0`u[@lrnHC=#==_WR2p8Ji3-4u`7niLeg?:sa*-@(rjr#3N@I2&F4Z!O`%aI]0(C/N#G5PrJlOOIp\jqQ@BK[t";DqLdZ-bCDSP:\Hc5@n;pmU.5=,&bXtH!:=ALOF>>KBb??.9qoJaY(-,bVUn#t^:P@W4FS<1IrJ$#G*NDl^gVnR1,KfoW1'E`Wi#e1'B.*YZe]IGX$XfY)^8kHu%/Q)"*UI8^qQ_i*0AlS$IXuT96e:EZ-8J0u4!UF1\l\UuS1bk)B*LmVs/BWN=fVrLR,ngoI502i4HRA.=jc"+XT9(`nGqJa%Okn;H;0`'$T`r]>r'1ttE&ND!:&PM,`NrIGaEFiX+)WbHP6G(6=/Ar)pjo[aO*He_r#AUt0nK#$%\r'a^gS$ES-o$@fpI;5M3!AiEffk\!iP,YCS)SV'W;'HPk,ftkiVQ-:)0IH;,J)F$5W=sii'sQO.)>n/J7.FFoPf%YR(7PlC=:]1,Gt^3@^@!NPZFVb4Y,PgM6409FR\sXSkODM^Ba`sRnX.,P?tZ(o-MUbb/e$HA])%5XuR^iO.b^[I;`2R`pB&cj^bqDCl7;g1,eL[StH\@:JY`,7KQ\fS1>JM*!m/ES^==Im8/?o[tjjFPD:?A\31p/^sLiOE_'-N#.;n+Ejk7hM?p6T5ZKE1)O7iD(\l?rB1P)=2eS1mARWSfRq6+)80>QXk0M\_/n54+:!HN/m8KE&l7#2r5I_pk>`kUMKDT5\Ks_V!.\DWYJ/Mq*@-,^_lC_%:_'0Di#;);e`hXLotULF"GZ]EPO^*;?7XXD]&YIOe-7V-cP!<Eo2"`Y9ZU2FU'cL3IGH]UUd)a&/0([V=_rrN\FQf\DSbD+E:Z:H&rgdTcDNc1\$g"V1A\$Ti\aPZoA2C15*A;E&'R,VM62Y'V+F,Vm)d(@mikeqG9k<%X0_qeer6b)X1T8U+H*B..5bAh;UN@5T,?9GRULL6<<5rpZpi?jj-J[qb^3[D?+5uL*&$,!0R[]e\)YdNr-[%:gRj?f&7lDfg5KJfeLh`5e+9p?MO7C*g+o#u/onK1(cCHi+o$]e4'c+(F5Fs.`0UE'KS5X=G&rq,*o)+mG^_)h#=ud#>m1X1*^B&C$?mP91&elPBjg7$F"24FU!F]r)D94*[FM&L%CWTcDf7!&!'+W]cq7.M:*griB%U>MjR1uBHVa0eLcdEN\IXSi>G6OW>!KCLH&4L^srXRo(1\?\F6921)SR`#`/.']%T(^/lO=EF8kk24-NnH.G0FO[^X*=\S,W,fmL@h;Ej3PfM5=[?o#*dBQd%uDA1XF/]1f;1&DCmZl6,[W9%1c>9OQEnN=k8gt?7DF9IbG35ZZZ@B-N90=[p;UAiU?!DNOip?Saq`J%cLrJ5<'RYU0\MAn;3b.auoZ^$CnIP>A=+]6j7;,)/OVdppP'iZCQ!F:7g$R.+dZVLL8b0`*EF2qFIu6I9m98DfIu5>T5D/Vn$Ma51&F1.DAX[@@gMg;s&o#N+hY31'pEZ%i&/HNL,N,.&;n:LB!NPo_G^%()-Ia;6Ros$oCO"C*Q,%+)O])mn8;%']5k6WS,9C]tGh;Y7Z!$7sfAKJ%`p18]Dr*rYFq?^<#6=X"XZUt-1g84CnT^qSICsL[Oaf#_SDs_4l?F9go@C1<)Qq5Q^[MlpLr7:#a6ts9/a>8Ml95u%'Lb+s:LOa*I6HP+laCBBaYDKer10oTccS&8p$)5IIu>U3hBB8Rbc>lgb%r[WR9.Xi$c`b@g_TGsb/n.VSEBn7]N4X`?bhYIc#bIs&=`Q-E6i)Ir2u":"U>1/(`[L7N]G'mBtkC8qHp)"iYUpXA9tN`'-'?%H-KQ13-Z]Fn!"/.H@#2)l>h5N+g"D@qPbHg,R8Y`bH>V&%Y9S`bds2/QDgNqrSt1G!`VG,c^;=#&OAEIt"pDEC7_;e\T?:TN\hL!Y-$[4F?<^m)ged]^Y2LTKaR/m)H)OKaA[UaGlUj(&)u4-_kl2$/aQWMEmbhJX07qKmHReo!W?a'Gk^o'9hdL]Ert,I)$;4bE(8lp('AOVi"#bef!lql'+53E\magDm[F;!t(-N^%d^U\AEe"t$a+<=b'EQ#P(!5^34oLBnF[;tk(KT#?+^sNg?JI8YCiXr":2=b=ieQlY,Z_d!7`!g6L::$(3+Y7XNe7Q^oJt0;auG2QS!%-"/_$OADIrR5.+J0=HfOQ#Gk]4-&ZkX@nCWb(T[`C5egIhY=N[4_!S-:oK42hR`Y4S&ZlL5!lZsY2]JXQdHgNF)8TbuQqu6XK<#7&pDXSq%B\>>3`Z9lY3.-+L17I.9iAUXq[2VHZJgZ\5OG-1'*lAA8]E1p71or$ONhVg2usqN?-8@$D%B>F9paI'ji/J0aHfRNq(n1fidMb;IM&ObNp#\H1Af!,Oggc#d,Q^&&A]E+T%L74cMG"'1p.$igA<_^g\1gD50e#mAMo^`<'NBfFTUqhjQ@>eOPVN:_%DXl1erkL1K!Qn_(j'[7C>+s1L`i#;GpAMXZBA[`"VhYO#T75@T_V]j&(l5.]2P_5H*Z0PPolRVF1D@7Kc-BT:=G?S2:-$o(I)>TGfGOkXUg\58V-eIJF-5?@_ZUPYZPtrPP)#B9MAaP:1&&d:7I/9n*0ga2[iLOVrB(\4B_1J8:,USHc`Es_J'-G'!/p81l=22-s6\+W>S]Jjg!-A/udcWG#e$hHq_9$Or\j/i33QU['s_]a,qa04e?&KW+@6+aJ0)3BpRWhIpbec7K19TS:.1;+NNRQXunuh2V'1=J$0$]5U./JVc'V1.W=``bmc8Rd.:V$)Wlh6?\gc3NqGpOp):]#_d(oP8dR,'Sm$k5.,;d=fDlp_c:Q<-c\D.C&j.rcNMtP+.;u0&@3+CO$HQ+:(,iX5h]Fr1-&"*nWWqHA%..b83<&u1F5BV:nG#(>\KJ4D7kAq"CA[o_;RAMh>monN)PuY499I^q10TVZWY"fJ'5BNchrbCFJEdFrr=f+5?PYip:oUH&&pMHVhap!,thMj:H@g[>\(4p.LUN+[^"mB7LFeK.pLrI?eO2NIO*A>$tYlW&R*4/9ga]CME'Eh'4Dqrq;:9rS\3k_LJRGYp(u2@(iHu)@r#%Wj&Y[Y@@(b?Y!1>r0cX]&'hNj(I_s,#Sj*?`/;VWY4sZ*F?n($jp;e;nqp`[P<;m.f\c2YlN9HHD6'Vf`l=\"k?K)93F&2br7JgNR]iN3n+I2r8kY(L"'A1e(2%?oBk[KRl[l6Z5oaMX1.e=a;jL4F:&uLhTI/8PnBU/Ps2bJ)oER!Lig,UHrKQb>.N,L0;Q&)D'%kT6EqjMka;b^5SR]:]iYh;`FdnMlh2@0KM?IUk/pSPQ2^iAU;Yt%\E!N=?lWern"01T?PNM?@NR'=8GkOQUh8M%_;_LA)`#2#p-B\%icCX?7Fn@(WP?!-<_BGFWr%`.NgcTXIhCu8kRdO.me%NI6;'t`9-#S^U.N+HZ;GY"W3-iSWh=4b+Nn_-\Xcg^08a<0](c[,TC@:'M**A*+LTW[8Tf(VC\eu*"[KCC,4ZufG-(LmPB0;0UKlQi$2r=2dB7puB@Y$=^:0VRcZ%GA3gFDkq,%a+i)c\6aGjQ+,k<*@EL_K-GdC39IHCAj54JJ/'&)e4dj;.ee#/'($er,]*6"aCEb)bkN$'5.A/eDj\U5"p)6VuRiBR5R^K8r!>ePPa@%-iL":iF6%BIb%j8]k?n2'O208.)Jb?4MZi@B0o>mQb^a*)g!BET@%FPQp"H=O?mRHH4YXmK[l=+3UVc=pWFa3,&pftBRBAb$?DHt^.^-\5_$;=F\)R\,;H$0\LP]&55U33b>Jg6'^h\:aA^e:XFfanqG4Was0"$$_;?C?B-&uQkZ8GU%Kbpd1_\h'36i:g"SL9fX%hr\K.OgBc4sMuFGCieZ??md\9k`8UleiKRMr%%/kiJU@Em=+dh7DMW!%/+ne#%QYV*&"lV(]?7_Mi3-o6r$H[B=27$tJ>B$W=[KMTP8Y/M>=oSQ0MrfI)Um?f!Vr\U*FT5lK):D5hd>hb2Q`95J`Q@CksRO`t<.)!26S\`_Wed]B,/N`T_E38E14iuQt5`6Ws;9ph7,`0s.9`,)L7=iceV:e3s;^uq6U4Yp3oYJjk!9,4\[r)9Dl5pA?Kr$:gRHNAa^X-2?iKuR5'NuZOQf3;.&EI@7[aO%9`DO^.-_YS(0Y,QDLBU4d^1L&P;@<<]+&oc!!%e%0i,^--!8U'1_)u->Kr\r64R<1aRrAW'/^9Y6mjWp9q)i0hq7(`#kV#5eT'e2sqcc,>Sg4F(K_QibMia,FMPAE9cj!355f.tO:i*7f8I`r?#EheFq&_;^G0io3CMGt3h)P(>uQjFUS=!86.JH02K3:DjI[6Cb2+.PCI/P=#.:_f(BMnH["!fD=("nkU:UGIO%_rSQ^^7#2^`'iipP.S0aDNh2$c^E%P4:s`b$AFT9KN(L[qH^:;kYq!o!,A>n!>Do?jL#L)?jM2tPH>a_s4XZf[eb#6_;X36p*>RF%$??i$hPB^63U1B)=P(8.8Z&>=US2pM87L6r,b?`=TS*"6mKitYh7`UJji5QZC2[H'/O?nS.p1QRoUch4^C,.1/S@kn[uWuJ:%jcsdR>@5Z#rXo?%F9$1<:,DO9S!2,-LhcnV"KDHDe].]+@37Dr$j"@sMR9eej.C#Iq7jd6uS)bXj\2cCk5]nesAS;R#tuW-1+K7Q4?a`.&-[QMqfOIN.TV`hd0^-,A%aZk_.=HTM?q6+Ft"_4/[(fML3<)#6H];Ec<"0%/0./M<2TJQI&ZnJc-EJjp%kjuCH&f<%<01=.m=ZPA,<`Zlo_nHi`L:nWD0r0)^eht+"LiUJYQ6's[\mZ1Vde9'"GhcjdjIYV\I1?i?6^4+ahJjms)[V._JdDG/V]1PK,E1:"50$8;`GC]\C@\G29G#e\=e/`Ko2Dr/JrB-S0Bb7fhdH4W[2[sDoKMEW(d5UO"IaosQ]pq%h2PpML9OdprO_MI.9-`e?3p=.\nGP8V-j<"uH4lH4,FLm+AIN44]ZWflQF`=s(R264oc2mh&TLR!*N:$Cm=k2n%,UDmqOX9\-/,&Y?BH%M`)4;\-,^GK8Q<"->jTDso#K$e'rXIUg]$93HR&+a0pkai.q+2rLnDA>XB-;Y$bOKf7aL$gDCSjZJAO@DP\*Mp23+7Co3#V0ga"OL;XU"S&`R;/`?[:t'WUU&-iLTFmCi=HC8G,,49i"a:T(nd(Q6nduPH0FL=W+G&',\lb.`S?DI5f&ud&fE!B,]W&EHQ=+UplL%e!giO9-^T+Jc!:u%"_Rk\?@':`npop]TM=*=3D&c]5)_NSr,PGn93`&5?bN0gRRpEBf]"Yt5$2GX"G7NnpiF=9\%9;+i*R,^RPk#K?g9PrB\&L8$]D&k5B2g]q*7s(6!++J(W[Gp8(W2!as<#)?&mj^\B>k@/%f5]B[6g(mI#4t/TpN52V-mUCT(`34'@W'/j<1K*h.12%/s8&E)Tq\5Id&:Up]>lH0U\['eMNlRX]rHbs'+S=XAY]>u/[e9.0oG7Tk>AIAP[-pIhOs0F;WPn`.Xh!"(ha5,%JHiZ70Q2*EV9e1Mfi>t[ZR7%71Z'BT9FU6[p#A;795I=Ls=L-V&R+Gg6*Q"U*sKVIXQ#s8hiF8Z-:h.hEH$crjlY#id&'r(4LJ.]8Ab$]4Aph,4\$k/fsUF#ITGe.p!aaN>Pj,#leV<_2A3]E+_HgOShY,uZP&j&SdLD!ogl+'efY2B?`.L%F.G`PdIrr@^ORr8mD^#Y!oUKUgQ!fF5'#b*;sYp^E(%A]QBiBRoYL6J`e*OiACc.oZ(TsHZW!#%=I0iA56TR+)k7X=/3%%\a>+f33nQF`TPNdbj8lfU:eF2I*%E\]]loej@Tc8D),gIrP>=);kBfC6X%Z_act'eCn7]EVn&nNgk&*k)TM&\FuX6.]PBurPOpVO*12gPOS>,Fb.7*glfQL^%6,C:U%+SpW4+'UR>C6%?MK2/`3(oFU"T3i#.gR^W1U[>IE##p!BlC+lb(5nt8Z%&]W>!mZUq(Fq^QsaVR$JPodo.nCh[fK#d!Q`6"[oZqjg9%!,T[R6)9^s15,Z_A=KgVXAKJ6C/m4@No6%D8h%M--i9V=DUp4\Nf/+OdOl9r_"K0+6Z$X!Q44mrZ'L\Ois>D3:Qk_T/p5PZ*ZFJhrkXHrY;*_XjL;Z/49*q'TsIHR[lQ>Bn#ff-b"cUZ2N7*.qB44cY9kBfC]/-8h_k1'n].Q/&qG\#/9CJoXYj2.+@HIOO^P[lu1*_Kd_NT\4UigI(\eIUW=0,*p%QJ_MQ4.l^C2gop-'Fd9M"[Goi6n.jH%)&J#2fA7->ZS;7WE?]9*"Hr,(JWH-7Y*SM=`P2]8Ih,\,UJ\>IDJj%2P-Uh$"B%Y3#p9EIK.kG82Go2/_]Kh]a.=*uDQN$Q4s9+:1*gl8Zc^9a"7uNN#IdBH?DHHG"2K6LZ0PF+pDtP2$d3a@4n"j]i88sF1>1T)g$d38nGTCGFiF8Q0i4qhWo3[7'p]"`YSh?K;-I(:MLBW`Zjn)]mF6?&sE650hHl'pVRG`'N#C[Zm:EI^Trjc7JP!HGZ;83UFS%_HsL`k6ZXcbMa^p_>.G-\F%TXmG#a9r:]B$"=5qcAlnX7d[l!!B$,N:)^HqTPuT\:Mk;LM!R%$$+6M@':_JTL-`H1A)U2h)6b1J;WfDhe/tLpZ/pUDXoJ;OJ]X[l=VO/dH.=<1uAA%j-WYgs)h8R],p+nM[e%AlHNp-e/uH/YZ@K[9]0sFc;3P0^"Ve]-D1'mb&l9Iu2m^S)RcqC7:*-KR)R,(R,r)KoC1sQ@E@h]jo1Q:?@]5[OKeYi;C2Z0pOPjl2_l+"c#kCUDrBKcmqr-'K5QooFl_()<$0"ac;]`YM&3?73E[-u^!TIBsh&pKUAp2WSNWVB$kKRMD&-i=-XV2b.WVE(F;UX&O&>DT-cL%,l`Wg]r:=GdgCVTWJn6#"&_"`QP(W+PVG]uk_P>o0F/frlqc;HuuR7GKACZIhoGmad\%WTG5i13reShn*8/"!*\^FeQYKDfKb,40lS$:4R]AT:tHs-4ZXM^o[B?*'!P.%PWV9SFdH@2&-`/,6o]';);"HZ1XI(;+eVe\>KL;"eRWTr'][Cl?1`,Q0[Lk-_$Jjq[=j5o>7H/N\?idV@"qA,7'3m;%$bGE#%UUgLgA_91^LH$sXmN/mu3#lq_aj68rEG8Y,d9/s)F1q,D!65Oaia9T_7R%pk7FlV;7fE]>2X$J#p3,L20tX`a1V5;?6cmD0gKkKPr>g8Wn/a_^h!^HE*\51f>?Q6p_qNo(eC-YOMYM]e<4/r*TDd@mJA&Jq"=q#O<"I@p+M[Q6oaOYH?SB(O#.)\:R)dOZ3\;&(^qcGP`q=2u%=]>=$hh'R8M#L@\]a@r^HJ:[J?(>".3fh4uW^V"WNtPM[,Lpc:5f32jZjUq6R+=s((Z0U+BY*0a?&=+.jAJ&"2\iE(p/IiW<2*W;b?]6Nu86L.K0-]R)i)[$u$UrR_I^dXJqP(/jOn>lC,I9TD*nK&$%Z,tPhTQ%*Gm%,UbDib+1`#2-*CRc]LrV8mRnb3=1f51'B<;j'&OH\OSQeb$kXii'R:G`Ufa]lQ#@hs'm4:GE30SAu]M:2n1)T?l*'1X9s3oC%a;gl*7-Z?9S