All checks were successful
Build & Deploy / deploy (push) Successful in 1m14s
Fehler: claude-haiku-4-5 lehnt output_config.effort mit einem 400 ab, jede Karte lief in einen Lesefehler. effort und der server-seitige Fallback werden jetzt nur an Modelle geschickt, die sie annehmen; ein unbekanntes Modell mit engerem Parametersatz wird einmal ohne Zusatzparameter wiederholt, statt die Karte zu verlieren. Tests decken die Zuordnung ab. Design: Grau kommt als Hierarchiestufe dazu. Drei Ebenen für Fläche (weiß / grau gefüllt / schwarz), Text (schwarz / --ink-2 / --ink-3) und Linie (3px / 1px schwarz / graue Haarlinie). Vorher trug alles dieselbe 3px-Kante und dasselbe Schwarz, dadurch war keine Ordnung erkennbar. Konkret: nicht gewählte Filter treten zurück, Listenzeilen bekommen drei Textstufen und Statuspillen statt einer gleichförmigen Zeile, das Kopfband über Listen ist grau hinterlegt, zweitrangige und zerstörende Aktionen sind leiser als die primäre. iOS: Datumsfelder zentrieren ihren Wert und sacken in der Höhe ein. Die WebKit-Pseudoelemente ziehen sie auf die Form der übrigen Felder. Dazu die Domain in der Dokumentation auf scanner.lucas-orth.de. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
137 lines
5.5 KiB
HTML
137 lines
5.5 KiB
HTML
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||
<meta name="theme-color" content="#000000">
|
||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||
<meta name="apple-mobile-web-app-title" content="Karten">
|
||
<title>Visitenkarten Scanner</title>
|
||
<link rel="manifest" href="/manifest.webmanifest">
|
||
<link rel="apple-touch-icon" href="/static/icons/icon-192.png">
|
||
<link rel="icon" href="/static/icons/icon-192.png">
|
||
<link rel="stylesheet" href="/static/style.css">
|
||
</head>
|
||
<body>
|
||
|
||
<div class="app">
|
||
<header class="topbar">
|
||
<span class="mark" aria-hidden="true">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.2">
|
||
<rect x="2" y="5" width="20" height="14"></rect>
|
||
<path d="M6 10h5M6 14h8"></path>
|
||
</svg>
|
||
</span>
|
||
<span class="wordmark">
|
||
<span class="display d-md">Visitenkarten</span>
|
||
<span class="label">Scanner</span>
|
||
</span>
|
||
<span class="spacer"></span>
|
||
<button class="chip" id="logout-button" hidden>Abmelden</button>
|
||
</header>
|
||
|
||
<main>
|
||
<!-- ------------------------------------------------------------- Scan -->
|
||
<section class="screen stack" id="screen-scan">
|
||
<div class="block-invert">
|
||
<p class="label">Stapel oder Einzelkarte</p>
|
||
<h1 class="display d-xl" style="margin-top:8px">Karten<br>erfassen</h1>
|
||
<p class="muted" style="margin:12px 0 0">
|
||
Karten nebeneinander auf einen dunklen, einfarbigen Untergrund legen,
|
||
Handy parallel darüber halten. Ein Foto genügt für den ganzen Tisch.
|
||
</p>
|
||
<div class="figures">
|
||
<span class="figure">
|
||
<span class="label">Erfasst</span>
|
||
<span class="display d-lg mono-num" id="figure-total">0</span>
|
||
</span>
|
||
<span class="figure">
|
||
<span class="label">Nicht exportiert</span>
|
||
<span class="display d-lg mono-num" id="figure-open">0</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<label class="btn btn-primary" for="input-camera">
|
||
Foto aufnehmen <span class="arrow">→</span>
|
||
<input id="input-camera" type="file" accept="image/*" capture="environment" hidden>
|
||
</label>
|
||
<label class="btn btn-quiet" for="input-library">
|
||
Aus Fotos wählen <span class="arrow">↗</span>
|
||
<input id="input-library" type="file" accept="image/*" hidden>
|
||
</label>
|
||
|
||
<p class="hint">
|
||
Die Kamera liefert die volle Auflösung – bei zwanzig Karten auf einem Foto
|
||
ist das der Unterschied zwischen lesbar und nicht lesbar.
|
||
</p>
|
||
|
||
<div id="scan-result"></div>
|
||
</section>
|
||
|
||
<!-- ------------------------------------------------------------ Karten -->
|
||
<section class="screen stack" id="screen-cards" hidden>
|
||
<div class="search">
|
||
<input id="search-input" type="search" placeholder="Name, Firma, Ort, Notiz …"
|
||
autocomplete="off" enterkeyhint="search">
|
||
<button id="search-clear" type="button" aria-label="Suche leeren">×</button>
|
||
</div>
|
||
<div class="chips" id="filter-chips">
|
||
<button class="chip" data-filter="alle" aria-pressed="true">Alle</button>
|
||
<button class="chip" data-filter="offen" aria-pressed="false">Nicht exportiert</button>
|
||
<button class="chip" data-filter="unvollstaendig" aria-pressed="false">Unvollständig</button>
|
||
<button class="chip" data-filter="erinnerung" aria-pressed="false">Mit Erinnerung</button>
|
||
</div>
|
||
<div id="cards-list"></div>
|
||
</section>
|
||
|
||
<!-- ------------------------------------------------------------ Detail -->
|
||
<section class="screen stack" id="screen-detail" hidden></section>
|
||
|
||
<!-- ------------------------------------------------------ Erinnerungen -->
|
||
<section class="screen stack" id="screen-reminders" hidden>
|
||
<div class="section-label"><span class="label">Erinnerungen</span></div>
|
||
<div id="reminders-list"></div>
|
||
</section>
|
||
</main>
|
||
|
||
<nav class="tabs" role="tablist">
|
||
<button class="tab" role="tab" data-route="scan" aria-selected="true">Scan</button>
|
||
<button class="tab" role="tab" data-route="karten" aria-selected="false">
|
||
<span class="count mono-num" id="tab-count-cards">0</span>Karten
|
||
</button>
|
||
<button class="tab" role="tab" data-route="erinnerungen" aria-selected="false">
|
||
<span class="count mono-num" id="tab-count-reminders">0</span>Termine
|
||
</button>
|
||
</nav>
|
||
</div>
|
||
|
||
<!-- ------------------------------------------------------------------ Login -->
|
||
<div class="overlay" id="login-overlay" hidden>
|
||
<form class="block stack" id="login-form">
|
||
<p class="label muted">Zugang</p>
|
||
<h2 class="display d-lg">Anmelden</h2>
|
||
<label class="field">
|
||
<span class="label">Passwort</span>
|
||
<input type="password" id="login-password" autocomplete="current-password" required>
|
||
</label>
|
||
<button class="btn btn-primary" type="submit">Weiter <span class="arrow">→</span></button>
|
||
<p class="hint" id="login-error" hidden></p>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- -------------------------------------------------------------- Fortschritt -->
|
||
<div class="overlay" id="busy-overlay" hidden>
|
||
<div class="block-invert stack" style="text-align:center">
|
||
<div class="spinner" style="margin:0 auto"></div>
|
||
<p class="label" id="busy-text">Karten werden gelesen</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toast" id="toast" hidden></div>
|
||
|
||
<script src="/static/app.js"></script>
|
||
</body>
|
||
</html>
|