This commit is contained in:
2025-08-31 12:12:04 +02:00
parent f6643b712b
commit dbf53a9c30
13 changed files with 906 additions and 0 deletions

22
templates/alerts.gohtml Normal file
View File

@@ -0,0 +1,22 @@
{{define "title"}}Warnungen Kücheninventar{{end}}
{{define "content"}}
<h2>Produkte unter Mindestbestand</h2>
{{if .Below}}
<table class="table">
<thead><tr><th>Produkt</th><th>Aktuell</th><th>Min</th><th>Händler</th><th></th></tr></thead>
<tbody>
{{range .Below}}
<tr>
<td><a href="/products/{{.ID}}">{{.Name}}</a></td>
<td>{{.CurrentStock}}</td>
<td>{{.MinStock}}</td>
<td>{{.PreferredVendor}}</td>
<td><a class="btn sm" href="/shopping-list">Zur Einkaufsliste</a></td>
</tr>
{{end}}
</tbody>
</table>
{{else}}
<p class="muted">Alles gut, keine Unterschreitungen.</p>
{{end}}
{{end}}

29
templates/base.gohtml Normal file
View File

@@ -0,0 +1,29 @@
{{define "base"}}
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>{{block "title" .}}Kücheninventar{{end}}</title>
<link rel="stylesheet" href="/assets/style.css"/>
</head>
<body>
<header class="container">
<h1>🍳 Kücheninventar</h1>
<nav>
<a href="/">Dashboard</a>
<a href="/products">Produkte</a>
<a href="/alerts">Warnungen{{if .Alerts}} ({{.Alerts}}){{end}}</a>
<a href="/shopping-list">Einkaufsliste</a>
</nav>
</header>
<main class="container">
{{template "flash" .}}
{{block "content" .}}{{end}}
</main>
<footer class="container muted">
<p>© {{now | printf "%d"}} Lokale Demo-App (Go + SQLite). Bilder bleiben lokal.</p>
</footer>
</body>
</html>
{{end}}

View File

@@ -0,0 +1,39 @@
{{define "title"}}Dashboard Kücheninventar{{end}}
{{define "content"}}
<section class="card">
<h2>Nächste ablaufende Einheit</h2>
{{if .Next}}
<div class="flex-between">
<div>
<strong>{{.Next.Product.Name}}</strong>
{{if .Next.Product.Manufacturer}}<span class="muted"> {{.Next.Product.Manufacturer}}</span>{{end}}<br/>
<span>Ablaufdatum: {{dateHuman .Next.ExpiryDate}}</span>
</div>
<form method="post" action="/units/{{.Next.ID}}/checkout?from=/">
<button class="btn danger">Ausbuchen</button>
</form>
</div>
{{else}}
<p class="muted">Keine Einheiten auf Lager.</p>
{{end}}
</section>
<section class="card">
<h2>Produkte</h2>
<div class="grid">
{{range .Products}}
<a class="product" href="/products/{{.ID}}">
{{if .ImagePath}}<img src="{{.ImagePath}}" alt="{{.Name}}"/>
{{else}}<div class="placeholder">Kein Bild</div>{{end}}
<div class="meta">
<div class="name">{{.Name}}</div>
{{if .Manufacturer}}<div class="muted">{{.Manufacturer}}</div>{{end}}
<div class="stock {{if and (gt .MinStock 0) (lt .CurrentStock .MinStock)}}warn{{end}}">Bestand: {{.CurrentStock}}{{if gt .MinStock 0}} / Min {{.MinStock}}{{end}}</div>
</div>
</a>
{{end}}
</div>
<div class="actions"><a class="btn" href="/products/create">+ Produkt anlegen</a></div>
</section>
{{end}}

View File

@@ -0,0 +1,3 @@
{{define "flash"}}
{{/* Platzhalter für Nachrichten */}}
{{end}}

View File

@@ -0,0 +1,18 @@
{{define "title"}}Produkt anlegen Kücheninventar{{end}}
{{define "content"}}
<section class="card">
<h2>Neues Produkt</h2>
<form method="post" enctype="multipart/form-data" action="/products/create">
<div class="form-grid">
<label>Name*<input required name="name"/></label>
<label>Hersteller<input name="manufacturer"/></label>
<label>Größe / Inhalt<input name="size" placeholder="z.B. 500 g"/></label>
<label>Bevorzugter Händler<input name="preferred_vendor" placeholder="z.B. REWE"/></label>
<label>Mindestbestand<input type="number" min="0" name="min_stock" value="0"/></label>
<label>Bild (Datei)<input type="file" name="image_file" accept="image/*"/></label>
<label>Oder Bild-URL<input type="url" name="image_url" placeholder="https://…"/></label>
</div>
<button class="btn">Anlegen</button>
</form>
</section>
{{end}}

View File

@@ -0,0 +1,79 @@
{{define "title"}}Produkt Kücheninventar{{end}}
{{define "content"}}
<section class="card">
<div class="flex-between">
<div class="flex">
{{if .Product.ImagePath}}<img class="cover" src="{{.Product.ImagePath}}" alt="{{.Product.Name}}"/>
{{else}}<div class="cover placeholder">Kein Bild</div>{{end}}
<div>
<h2>{{.Product.Name}}</h2>
{{if .Product.Manufacturer}}<div class="muted">{{.Product.Manufacturer}}</div>{{end}}
{{if .Product.Size}}<div>Größe: {{.Product.Size}}</div>{{end}}
<div>Bevorzugter Händler: {{if .Product.PreferredVendor}}{{.Product.PreferredVendor}}{{else}}{{end}}</div>
<div>Bestand: <strong>{{.Product.CurrentStock}}</strong>{{if gt .Product.MinStock 0}} / Min {{.Product.MinStock}}{{end}}</div>
</div>
</div>
<form method="post" action="/products/{{.Product.ID}}">
<div class="form-inline">
<label>Min:<input type="number" min="0" name="min_stock" value="{{.Product.MinStock}}"/></label>
<label>Händler:<input name="preferred_vendor" value="{{.Product.PreferredVendor}}"/></label>
<label>Größe:<input name="size" value="{{.Product.Size}}"/></label>
<label>Hersteller:<input name="manufacturer" value="{{.Product.Manufacturer}}"/></label>
<button class="btn">Speichern</button>
</div>
</form>
</div>
</section>
<section class="card">
<h3>Nächste ablaufende Einheit</h3>
{{if .Next}}
<div class="flex-between">
<div><span>Ablaufdatum: {{dateHuman .Next.ExpiryDate}}</span></div>
<form method="post" action="/units/{{.Next.ID}}/checkout?from=/products/{{.Product.ID}}">
<button class="btn danger">Ausbuchen</button>
</form>
</div>
{{else}}
<p class="muted">Keine Einheiten vorhanden.</p>
{{end}}
</section>
<section class="card">
<h3>Einheiten</h3>
{{if .Units}}
<table class="table">
<thead><tr><th>#</th><th>Ablaufdatum</th><th>Aktion</th></tr></thead>
<tbody>
{{range .Units}}
<tr>
<td>{{.ID}}</td>
<td>{{dateHuman .ExpiryDate}}</td>
<td>
<form method="post" action="/units/{{.ID}}/checkout?from=/products/{{$.Product.ID}}">
<button class="btn sm">Ausbuchen</button>
</form>
</td>
</tr>
{{end}}
</tbody>
</table>
{{else}}
<p class="muted">Noch keine Einheiten angelegt.</p>
{{end}}
<details>
<summary>Einheiten hinzufügen</summary>
<form method="post" action="/products/{{.Product.ID}}/add-units">
<div class="form-inline">
<label>Menge:<input type="number" min="1" value="1" name="quantity"/></label>
<label>Ablaufdatum:<input type="date" name="expiry_date" required/></label>
<button class="btn">Hinzufügen</button>
</div>
</form>
</details>
</section>
{{end}}

20
templates/products.gohtml Normal file
View File

@@ -0,0 +1,20 @@
{{define "title"}}Produkte Kücheninventar{{end}}
{{define "content"}}
<div class="actions"><a class="btn" href="/products/create">+ Produkt anlegen</a></div>
<table class="table">
<thead><tr><th>Bild</th><th>Produkt</th><th>Hersteller</th><th>Größe</th><th>Händler</th><th>Bestand</th><th>Min</th></tr></thead>
<tbody>
{{range .Products}}
<tr>
<td class="tinyimg">{{if .ImagePath}}<img src="{{.ImagePath}}" alt="{{.Name}}"/>{{end}}</td>
<td><a href="/products/{{.ID}}">{{.Name}}</a></td>
<td>{{.Manufacturer}}</td>
<td>{{.Size}}</td>
<td>{{.PreferredVendor}}</td>
<td>{{.CurrentStock}}</td>
<td>{{.MinStock}}</td>
</tr>
{{end}}
</tbody>
</table>
{{end}}

View File

@@ -0,0 +1,26 @@
{{define "title"}}Einkaufsliste Kücheninventar{{end}}
{{define "content"}}
<h2>Einkaufsliste nach Händler</h2>
{{if .Vendors}}
{{range .Vendors}}
<section class="card">
<h3>{{.}}</h3>
<table class="table">
<thead><tr><th>Produkt</th><th>Hersteller</th><th>Größe</th><th>Benötigt</th></tr></thead>
<tbody>
{{range (index $.Groups .)}}
<tr>
<td><a href="/products/{{.Product.ID}}">{{.Product.Name}}</a></td>
<td>{{.Product.Manufacturer}}</td>
<td>{{.Product.Size}}</td>
<td><strong>{{.Needed}}</strong></td>
</tr>
{{end}}
</tbody>
</table>
</section>
{{end}}
{{else}}
<p class="muted">Keine offenen Bedarfe alle Mindestbestände sind erfüllt.</p>
{{end}}
{{end}}