SHA256
147 lines
5.5 KiB
HTML
147 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" />
|
||
<title>crushdb</title>
|
||
<link rel="stylesheet" href="/static/style.css" />
|
||
</head>
|
||
<body>
|
||
<h1>crushdb</h1>
|
||
<p class="tagline">Verschlüsselte Datensätze zwischen zwei Personen</p>
|
||
|
||
<section id="flash" class="flash" aria-live="polite"></section>
|
||
|
||
<!-- First visit: NO records exist yet → user chooses a new passphrase -->
|
||
<section id="setup" hidden>
|
||
<form id="setup-form" autocomplete="off">
|
||
<h2>Willkommen bei crushdb!</h2>
|
||
<p class="intro">
|
||
Du benutzt crushdb zum ersten Mal. Wähle jetzt eine Passphrase –
|
||
sie ist das Master-Passwort für alle deine Daten. Es gibt keine
|
||
Zurücksetzung, speichere sie sicher!
|
||
</p>
|
||
<label>Neue Passphrase
|
||
<input type="password" id="setup-pass1" autocomplete="new-password"
|
||
required minlength="8" placeholder="mindestens 8 Zeichen" />
|
||
</label>
|
||
<label>Passphrase wiederholen
|
||
<input type="password" id="setup-pass2" autocomplete="new-password"
|
||
required placeholder="gleiche Passphrase nochmal" />
|
||
</label>
|
||
<button type="submit" id="setup-btn">Konto einrichten →</button>
|
||
<p id="setup-progress" class="hint" hidden>Schlüssel wird abgeleitet …</p>
|
||
<p class="hint">
|
||
Wichtig: Die Passphrase wird <strong>nicht am Server gespeichert</strong>.
|
||
Sie bleibt nur in deinem Browser-Arbeitsspeicher. Wer sie vergisst,
|
||
verliert Zugriff auf alle Daten (absichtlich so).
|
||
</p>
|
||
</form>
|
||
</section>
|
||
|
||
<!-- Returning user: records exist but are undecryptable → enter passphrase -->
|
||
<section id="unlock">
|
||
<form id="unlock-form" autocomplete="off">
|
||
<h2>Entsperren</h2>
|
||
<p class="intro">
|
||
Du hast bereits verschlüsselte Datensätze hinterlegt.
|
||
Gib deine Passphrase ein, um sie zu lesen.
|
||
</p>
|
||
<label>Passphrase
|
||
<input type="password" id="passphrase" autocomplete="current-password"
|
||
required placeholder="deine Passphrase …" />
|
||
</label>
|
||
<button type="submit" id="unlock-btn">Entsperren</button>
|
||
<p id="unlock-progress" class="hint" hidden>Schlüssel wird abgeleitet …</p>
|
||
<p class="hint">
|
||
Die Passphrase verlässt niemals deinen Browser. Sie wird per
|
||
Argon2id lokal abgeleitet und nur im Arbeitsspeicher gehalten.
|
||
</p>
|
||
</form>
|
||
</section>
|
||
|
||
<!-- main app, hidden until unlocked -->
|
||
<section id="app" hidden>
|
||
<div class="toolbar">
|
||
<button id="new-btn" type="button">+ Neuer Datensatz</button>
|
||
<button id="lock-btn" type="button">Sperren</button>
|
||
</div>
|
||
|
||
<div class="filters">
|
||
<input id="filter-text" type="search"
|
||
placeholder="Suchen … (z. B. „Andrea“ oder „Kaffee“)"
|
||
aria-label="Datensätze durchsuchen" />
|
||
<select id="filter-person" aria-label="Nach Person filtern">
|
||
<option value="">Alle Personen</option>
|
||
</select>
|
||
<select id="filter-action" aria-label="Nach Aktion filtern">
|
||
<option value="">Alle Aktionen</option>
|
||
</select>
|
||
<button id="filter-reset" type="button" class="secondary">Filter zurücksetzen</button>
|
||
<span id="filter-count" class="filter-count"></span>
|
||
</div>
|
||
|
||
<table id="records">
|
||
<thead>
|
||
<tr>
|
||
<th>Person A</th>
|
||
<th>Person B</th>
|
||
<th>Start</th>
|
||
<th>Ende</th>
|
||
<th>Anlass</th>
|
||
<th>Endgrund</th>
|
||
<th>Aktion</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</section>
|
||
|
||
<!-- create/edit modal -->
|
||
<div id="editor-backdrop" hidden>
|
||
<form id="editor" autocomplete="off">
|
||
<h2 id="editor-title">Neuer Datensatz</h2>
|
||
<label>Person A
|
||
<input id="f-persona" type="text" required maxlength="120"
|
||
list="dl-person" placeholder="wählen oder neu tippen …" />
|
||
</label>
|
||
<label>Person B
|
||
<input id="f-personb" type="text" required maxlength="120"
|
||
list="dl-person" placeholder="wählen oder neu tippen …" />
|
||
</label>
|
||
<label>Start (optional, beliebiger Text)
|
||
<input id="f-tsstart" type="text" maxlength="120"
|
||
placeholder="z. B. 12.03.2026, Sommer 2025, unbekannt …" />
|
||
</label>
|
||
<label>Ende (optional, beliebiger Text)
|
||
<input id="f-tsend" type="text" maxlength="120"
|
||
placeholder="z. B. laufend, unbekannt, März 2026 …" />
|
||
</label>
|
||
<label>Anlass (optional)
|
||
<input id="f-startcause" type="text" maxlength="300"
|
||
placeholder="womit/warum es begann, z. B. gemeinsam geplante Reise …" />
|
||
</label>
|
||
<label>Endgrund (optional)
|
||
<input id="f-endcause" type="text" maxlength="300"
|
||
placeholder="warum es endete, z. B. zurückgezahlt, abgelaufen …" />
|
||
</label>
|
||
<label>Aktion
|
||
<input id="f-action" type="text" required maxlength="500"
|
||
list="dl-action" placeholder="wählen oder neu tippen …" />
|
||
</label>
|
||
<div class="actions">
|
||
<button type="submit">Speichern</button>
|
||
<button type="button" id="editor-cancel">Abbrechen</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- suggestion lists for the editor's dropdown inputs (filled by ui.js) -->
|
||
<datalist id="dl-person"></datalist>
|
||
<datalist id="dl-action"></datalist>
|
||
|
||
<script type="module" src="/static/ui.js"></script>
|
||
</body>
|
||
</html>
|