diff --git a/CLAUDE.md b/CLAUDE.md
index d313269..8b37a6f 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -51,6 +51,12 @@ After completing the code, ask the user if they want a playground link. Only cal
- **NEVER** write `@media (prefers-color-scheme: dark)` or `:global(:root[data-theme="dark"])` override blocks — semantic variables handle both themes automatically
- **NEVER** use `var(--font-default-dark)` or `var(--accent-dark)` — these are legacy
+### Primary interactive elements
+- Background: `var(--color-primary)` (nord10 light / nord8 dark)
+- Hover: `var(--color-primary-hover)`
+- Active: `var(--color-primary-active)`
+- Text on primary bg: `var(--color-text-on-primary)`
+
### Accent colors (OK to use directly, they work in both themes)
- `var(--blue)`, `var(--red)`, `var(--green)`, `var(--orange)` — named accent colors
- `var(--nord10)`, `var(--nord11)`, `var(--nord12)`, `var(--nord14)` — OK for hover states of accent-colored buttons only
diff --git a/package.json b/package.json
index 08679dc..560b46a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "homepage",
- "version": "1.16.0",
+ "version": "1.17.0",
"private": true,
"type": "module",
"scripts": {
diff --git a/src/lib/components/fitness/FoodSearch.svelte b/src/lib/components/fitness/FoodSearch.svelte
index a4e54bf..fcb5c51 100644
--- a/src/lib/components/fitness/FoodSearch.svelte
+++ b/src/lib/components/fitness/FoodSearch.svelte
@@ -12,6 +12,7 @@
* showDetailLinks?: boolean,
* autofocus?: boolean,
* confirmLabel?: string,
+ * initialResults?: any[],
* }}
*/
let {
@@ -21,6 +22,7 @@
showDetailLinks = true,
autofocus = false,
confirmLabel = undefined,
+ initialResults = undefined,
} = $props();
const lang = $derived(detectFitnessLang($page.url.pathname));
@@ -28,11 +30,27 @@
const isEn = $derived(lang === 'en');
const btnLabel = $derived(confirmLabel ?? t('log_food', lang));
+ // SVG ring constants
+ const RADIUS = 28;
+ const ARC_DEGREES = 300;
+ const ARC_LENGTH = (ARC_DEGREES / 360) * 2 * Math.PI * RADIUS;
+ const ARC_ROTATE = 120;
+ function strokeOffset(percent) {
+ return ARC_LENGTH - (Math.min(percent, 100) / 100) * ARC_LENGTH;
+ }
+
// --- Search state ---
let query = $state('');
- let results = $state([]);
+ let results = $state(initialResults ?? []);
let loading = $state(false);
let timeout = $state(null);
+ const isPrefilledMode = $derived(initialResults != null);
+ let filterQuery = $state('');
+ const displayResults = $derived(
+ isPrefilledMode && filterQuery
+ ? results.filter(r => r.name.toLowerCase().includes(filterQuery.toLowerCase()))
+ : results
+ );
// --- Selection state ---
let selected = $state(null);
@@ -92,6 +110,37 @@
return qty;
});
+ /** Scaled nutrient values for the preview */
+ const previewNutrients = $derived.by(() => {
+ if (!selected?.per100g || !previewGrams) return null;
+ const s = previewGrams / 100;
+ const n = selected.per100g;
+ return {
+ calories: Math.round((n.calories ?? 0) * s),
+ protein: (n.protein ?? 0) * s,
+ fat: (n.fat ?? 0) * s,
+ carbs: (n.carbs ?? 0) * s,
+ saturatedFat: (n.saturatedFat ?? 0) * s,
+ sugars: (n.sugars ?? 0) * s,
+ fiber: (n.fiber ?? 0) * s,
+ };
+ });
+
+ const macroPercent = $derived.by(() => {
+ if (!selected?.per100g) return { protein: 0, fat: 0, carbs: 0 };
+ const n = selected.per100g;
+ const proteinCal = (n.protein ?? 0) * 4;
+ const fatCal = (n.fat ?? 0) * 9;
+ const carbsCal = (n.carbs ?? 0) * 4;
+ const total = proteinCal + fatCal + carbsCal;
+ if (total === 0) return { protein: 0, fat: 0, carbs: 0 };
+ return {
+ protein: Math.round(proteinCal / total * 100),
+ fat: Math.round(fatCal / total * 100),
+ carbs: 100 - Math.round(proteinCal / total * 100) - Math.round(fatCal / total * 100),
+ };
+ });
+
function confirm() {
if (!selected) return;
const grams = resolveGrams();
@@ -354,36 +403,47 @@
{/if}
{:else if !selected}
-
-
-
- {#if query}
-
+ {#if isPrefilledMode}
+ {#if results.length > 3}
+
{/if}
- {#if browser}
-
- {/if}
-
+ {:else}
+
+
+
+ {#if query}
+
+ {/if}
+ {#if browser}
+
+ {/if}
+
+ {/if}
{#if scanError}
{scanError}
{/if}
{#if loading}
{t('loading', lang)}
{/if}
- {#if results.length > 0}
+ {#if displayResults.length > 0}
- {#each results as item}
+ {#each displayResults as item}
{#if showFavorites}