Files
Schulcloud-MCP/src/http/app/index.html
MechaCat02 48c6cf39d5 Lay the notes screen out like a notes app
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>
2026-09-21 18:22:47 +02:00

144 lines
6.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>&lt;&gt;</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">&nbsp;</button>
<button type="button" data-command="ol" aria-pressed="false" aria-label="Nummerierte Liste" title="Nummerierte Liste">1.&nbsp;</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>