The list of notes and the note being written are one screen now, two panes: the notes on the left, the open one on the right, side by side where there is room and one at a time on a phone, where the back button returns to the list. The search box moved into the top of that list, and its results *are* the list — searching is a way of finding a note, not a separate place to be, and a tab for it was a tab too many. Emptying the box brings the whole list back. Opening a hit opens that day at the lesson that matched, rather than at the top of a day with six of them. A row has to say what the note holds, so the listing carries it: the subjects a day covers, how many lessons, and the first line actually written in it. One request for the whole list rather than one per note. `plainText` is now one rule in one place for wherever a note is shown rather than edited — the search snippet and the list row both went through their own half-copy of it, and the row's copy rendered a table as `| | |` and left `_Fazit_` wearing its markers. It strips one leading marker, not each in turn, because `## 1. Deutsch` keeps its lesson number and the list rule was eating it. Driven in Firefox at both widths: the list, the search, opening a hit, the jump to the lesson, and the phone's list-then-note. 390 unit tests, 116/117 smoke. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
144 lines
6.9 KiB
HTML
144 lines
6.9 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="#1f6feb">
|
||
<title>Schulcloud — Notizen</title>
|
||
<link rel="icon" href="icon.svg" type="image/svg+xml">
|
||
<link rel="manifest" href="manifest.webmanifest">
|
||
<link rel="stylesheet" href="app.css">
|
||
</head>
|
||
<body>
|
||
<noscript>Diese Seite braucht JavaScript.</noscript>
|
||
|
||
<!-- Login. Shown until /app/session says otherwise; everything else stays hidden. -->
|
||
<section id="login" class="screen" hidden>
|
||
<form id="login-form" class="card">
|
||
<h1>Anmelden</h1>
|
||
<label for="password">Passwort</label>
|
||
<input id="password" name="password" type="password" autocomplete="current-password" required autofocus>
|
||
<button type="submit">Anmelden</button>
|
||
<p id="login-error" class="error" role="alert" aria-live="assertive"></p>
|
||
</form>
|
||
</section>
|
||
|
||
<div id="app" class="screen" hidden>
|
||
<header>
|
||
<nav class="tabs">
|
||
<button type="button" id="tab-notes" class="tab" aria-current="page">Notizen</button>
|
||
<button type="button" id="tab-settings" class="tab">Einstellungen</button>
|
||
</nav>
|
||
</header>
|
||
|
||
<!-- Notes: one school day per note, one heading per lesson. -->
|
||
<!-- Two panes: the notes on the left, the open one on the right. Side by
|
||
side where there is room; one at a time on a phone, where `data-pane`
|
||
says which, and the back button returns to the list. -->
|
||
<main id="view-notes" class="view notes" data-pane="list">
|
||
<aside class="rail">
|
||
<div class="rail-head">
|
||
<form id="search-form" class="searchbar" role="search">
|
||
<input id="search-input" type="search" inputmode="search" autocomplete="off"
|
||
placeholder="Durchsuchen" aria-label="Notizen durchsuchen">
|
||
</form>
|
||
<button type="button" id="today" aria-label="Heutiger Tag" title="Heutiger Tag">+</button>
|
||
</div>
|
||
<p id="rail-status" class="status" role="status" aria-live="polite"></p>
|
||
<div id="rail-list" class="rail-list"></div>
|
||
</aside>
|
||
|
||
<section class="detail">
|
||
<button type="button" id="back" class="back">‹ Notizen</button>
|
||
<div class="daybar">
|
||
<button type="button" id="prev" aria-label="Vorheriger Tag">‹</button>
|
||
<div class="daybar-centre">
|
||
<strong id="day-title">…</strong>
|
||
<input id="day-date" type="date" aria-label="Datum">
|
||
</div>
|
||
<button type="button" id="next" aria-label="Nächster Tag">›</button>
|
||
</div>
|
||
|
||
<p id="day-status" class="status" role="status" aria-live="polite"></p>
|
||
<p id="day-conflict" class="conflict" role="alert" hidden></p>
|
||
|
||
<!-- The toolbar writes the Markdown so nobody has to type it. Every button
|
||
carries a word as well as a glyph, because the glyph is the thing a
|
||
screen reader cannot read and a stranger cannot guess. -->
|
||
<div id="toolbar" class="toolbar" role="toolbar" aria-label="Formatierung">
|
||
<button type="button" data-command="h2" aria-pressed="false" aria-label="Stunde (Überschrift)" title="Stunde (Überschrift)"><b>H2</b></button>
|
||
<button type="button" data-command="h3" aria-pressed="false" aria-label="Zwischenüberschrift" title="Zwischenüberschrift"><b>H3</b></button>
|
||
<span class="sep" aria-hidden="true"></span>
|
||
<button type="button" data-command="bold" aria-pressed="false" aria-label="Fett" title="Fett (Strg+B)"><b>F</b></button>
|
||
<button type="button" data-command="italic" aria-pressed="false" aria-label="Kursiv" title="Kursiv (Strg+I)"><i>K</i></button>
|
||
<button type="button" data-command="strike" aria-pressed="false" aria-label="Durchgestrichen" title="Durchgestrichen"><s>S</s></button>
|
||
<button type="button" data-command="code" aria-label="Code" title="Code (Strg+E)"><code><></code></button>
|
||
<span class="sep" aria-hidden="true"></span>
|
||
<button type="button" data-command="ul" aria-pressed="false" aria-label="Aufzählung" title="Aufzählung">• —</button>
|
||
<button type="button" data-command="ol" aria-pressed="false" aria-label="Nummerierte Liste" title="Nummerierte Liste">1. —</button>
|
||
<button type="button" data-command="task" aria-label="Kästchen zum Abhaken" title="Kästchen zum Abhaken">☐</button>
|
||
<button type="button" data-command="quote" aria-pressed="false" aria-label="Zitat" title="Zitat">❝</button>
|
||
<span class="sep" aria-hidden="true"></span>
|
||
<button type="button" data-command="link" aria-label="Link" title="Link (Strg+K)">🔗</button>
|
||
<button type="button" data-command="table" aria-label="Tabelle" title="Tabelle">▦</button>
|
||
<span class="sep" aria-hidden="true"></span>
|
||
<button type="button" data-command="mode" aria-pressed="false" aria-label="Markdown bearbeiten" title="Markdown bearbeiten">MD</button>
|
||
</div>
|
||
|
||
<p id="editor-hint" class="hint" role="status" hidden></p>
|
||
|
||
<!-- The formatted document, and the same note as Markdown. Exactly one of
|
||
the two is visible; both hold the whole note. -->
|
||
<div id="editor" class="editor" contenteditable="true" spellcheck="true" autocapitalize="sentences"
|
||
role="textbox" aria-multiline="true" aria-label="Notizen des Tages"
|
||
data-placeholder="Noch nichts für diesen Tag."></div>
|
||
<textarea id="source" class="source" hidden spellcheck="false" autocapitalize="off"
|
||
aria-label="Notizen des Tages als Markdown"></textarea>
|
||
|
||
<div class="actions">
|
||
<button type="button" id="save">Speichern</button>
|
||
<button type="button" id="fill" hidden>Stunden ergänzen</button>
|
||
<span id="lessons-hint" class="hint"></span>
|
||
</div>
|
||
|
||
<!-- A note that is not a school day — one from the import, a page of
|
||
revision — has no day to open, so it is shown rather than edited. -->
|
||
<article id="note-preview" class="note-preview" hidden>
|
||
<h2 id="note-preview-title"></h2>
|
||
<p id="note-preview-path" class="hint"></p>
|
||
<div id="note-preview-body" class="editor" aria-readonly="true"></div>
|
||
</article>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- Settings: the Schulcloud token, and what the server is doing. -->
|
||
<main id="view-settings" class="view" hidden>
|
||
<section class="card">
|
||
<h2>Schulcloud-Token</h2>
|
||
<p id="token-state" class="status">…</p>
|
||
<ol class="steps">
|
||
<li>In einem privaten Fenster bei der Schulcloud anmelden.</li>
|
||
<li>DevTools → Application → Cookies → Wert des Cookies <code>jwt</code> kopieren.</li>
|
||
<li>Hier einsetzen und speichern. Der Server prüft ihn erst bei der Schulcloud.</li>
|
||
<li><strong>Das private Fenster schließen</strong> — offen gelassen meldet es den Token nach etwa zwei Stunden ab.</li>
|
||
</ol>
|
||
<form id="token-form">
|
||
<label for="jwt">Neuer jwt-Cookie</label>
|
||
<input id="jwt" type="password" autocomplete="off" spellcheck="false">
|
||
<button type="submit">Token ersetzen</button>
|
||
</form>
|
||
<p id="token-result" class="status" role="status" aria-live="polite"></p>
|
||
</section>
|
||
|
||
<section class="card">
|
||
<h2>Server</h2>
|
||
<dl id="server-state"></dl>
|
||
<button type="button" id="logout">Abmelden</button>
|
||
</section>
|
||
</main>
|
||
</div>
|
||
|
||
<script type="module" src="app.js"></script>
|
||
</body>
|
||
</html>
|