feat: optimize scan flow with WebP compression and fix admin metrics visibility

This commit is contained in:
2025-12-22 10:15:29 +01:00
parent f0588418c8
commit 5e35710b67
19 changed files with 477 additions and 332 deletions

123
.aiideas
View File

@@ -1,103 +1,28 @@
Rolle: Du bist ein UI - Designer mit Fokus auf "Modern Minimalist" Design(Stilrichtung: Linear, Teenage Engineering, Vercel).Ziel: Redesign der Whisky - App "DramLog".Wir verabschieden uns vom klassischen "Luxus-Look"(Gold / Serifen) und nutzen einen "Industrial Dark" Stil.
Act as a Senior TypeScript/Next.js Developer.
Design Rules & Tokens:
I need a robust client-side image processing utility (an "Image Agent") to optimize user uploads before sending them to an LLM or Supabase.
Color Palette(Tailwind):
**Task:**
Create a utility file `src/utils/image-processing.ts`.
This file should export a function `processImageForAI` that uses the library `browser-image-compression`.
Bg - App: bg - zinc - 950(Ein sehr dunkles, warmes Grau, kein hartes Schwarz).
**Requirements:**
1. **Input:** The function takes a raw `File` object (from an HTML input).
2. **Processing Logic:**
- Resize the image to a maximum of **1024x1024** pixels (maintain aspect ratio).
- Convert the image to **WebP** format.
- Limit the file size to approx **0.4MB**.
- Enable `useWebWorker: true` to prevent UI freezing.
3. **Output:** The function must return a Promise that resolves to an object with this interface:
```typescript
interface ProcessedImage {
file: File; // The compressed WebP file (ready for Supabase storage)
base64: string; // The Base64 string (ready for LLM API calls)
originalFile: File; // Pass through the original file
}
```
4. **Helper:** Include a helper function to convert the resulting Blob/File to a Base64 string correctly.
5. **Edge Cases:** Handle errors gracefully (try/catch) and ensure the returned `file` has the correct `.webp` extension and mime type.
Bg - Card: bg - zinc - 900(Deutlich abgesetzt vom Hintergrund).
Text - Primary: text - zinc - 50(Fast Weiß, hoher Kontrast).
Text - Secondary: text - zinc - 400(Mittelgrau für Labels).
Accent: text - orange - 500(Ein sattes, mattes Orange für Highlights) und bg - orange - 600 für Primary Buttons.Keine Verläufe / Gradients, sondern flache("flat") Farben.
Typography:
Nutze Inter oder DM Sans für alles.
Headlines: font - bold tracking - tight(Enger Buchstabenabstand, wirkt kompakt und modern).
Labels: uppercase text - xs tracking - widest font - semibold(Technischer Look).
Component: Whisky Card(Clean Split):
Kein Text mehr über dem Bild!
Top: Bild(Aspect Ratio 4: 3 oder 16: 9), rounded - t - xl.
Bottom: Info - Block(p - 4 bg - zinc - 900 rounded - b - xl).
Inhalt: Whisky Name(Bold, White), darunter Destillerie(Orange, Small).
Tags: Kleine "Pills" mit bg - zinc - 800 text - zinc - 300.
Component: Dashboard Stats:
Minimalistisch.Nur die Zahl(riesig, z.B.text - 4xl font - bold text - white) und darunter das Label(text - zinc - 500).
Keine Boxen, keine Rahmen. "Data Ink Ratio" optimieren.
Component: Floating Navigation(The Capsule):
Statt einer durchgehenden Leiste unten, nutze eine "Floating Capsule".
Eine abgerundete "Insel"(rounded - full) die ca. 20px über dem unteren Bildschirmrand schwebt.
Breite: ca. 90 % des Screens oder max - w - md.
Farbe: bg - zinc - 800 / 90 backdrop - blur - md border border - zinc - 700.
Scan Button: In der Mitte der Kapsel, Kreis in bg - orange - 600(Flat, kein Schatten), weißes Icon.
Code - Snippet für die "Industrial Capsule Navigation":
JavaScript
import { Home, Grid, Scan, User } from 'lucide-react';
export const NavigationCapsule = () => {
return (
<div className= "fixed bottom-6 left-1/2 -translate-x-1/2 w-[90%] max-w-sm z-50" >
<div className="flex items-center justify-between px-2 py-2 bg-zinc-900/90 backdrop-blur-lg border border-zinc-800 rounded-full shadow-2xl" >
{/* Left Item */ }
< button className = "p-3 text-zinc-400 hover:text-white transition-colors" >
<Home size={ 22 } strokeWidth = { 2.5} />
</button>
{/* Left Item */ }
<button className="p-3 text-zinc-400 hover:text-white transition-colors" >
<Grid size={ 22 } strokeWidth = { 2.5} />
</button>
{/* PRIMARY ACTION - The "Industrial Button" */ }
<button className="flex items-center justify-center w-14 h-14 rounded-full bg-orange-600 text-white hover:bg-orange-500 active:scale-95 transition-all mx-2" >
<Scan size={ 26 } strokeWidth = { 2.5} />
</button>
{/* Right Item */ }
<button className="p-3 text-zinc-400 hover:text-white transition-colors" >
<User size={ 22 } strokeWidth = { 2.5} />
</button>
{/* Right Item (Settings/More) */ }
<button className="p-3 text-zinc-400 hover:text-white transition-colors" >
<div className="w-1 h-1 bg-current rounded-full mb-1" />
<div className="w-1 h-1 bg-current rounded-full" />
</button>
</div>
</div>
);
};
Aufgabe: Setze die bestehenden Views(Dashboard und Liste) mit diesen neuen "Industrial Dark" Regeln um.Sorge für klare Kontraste durch zinc - 950 vs zinc - 900 Flächen.
Was dieser Look ändert:
Lesbarkeit: Durch den zinc - 900 Hintergrund der Karten hebt sich der weiße Text extrem gut ab.Kein "Text auf unruhigem Foto" - Problem mehr.
Modernität: Das "Pill" - Menü(Capsule) sieht aus wie bei modernen iOS Apps(Dynamic Island Ästhetik).
Ehrlichkeit: Es versucht nicht, "altes Geld"(Gold / Serifen) zu imitieren, sondern wirkt wie ein modernes Werkzeug für Enthusiasten.
**Step 1:** Give me the `npm install` command to add the necessary library.
**Step 2:** Write the complete `src/utils/image-processing.ts` code with proper JSDoc comments.