Files
lernbar/scripts/symbole.ts
Florian WildeandClaude Opus 5 2babef9293 Baustein 10a: PWA, Offlinebetrieb, Druckansichten
Installierbar: Manifest, Symbole aus dem eigenen Zeichen erzeugt
(scripts/symbole.ts, kein Bilddienst), Verknuepfungen zu Lernmodus,
Berichtsheft und Handouts.

Offline gilt eine Regel, und die steht im Dienstarbeiter: Nur das
Lernmaterial liegt im Browserspeicher - Handouts, Merkkarten, Glossar,
die eigene Woche. Lernzielkontrollen, Berichtsheft, Bewertungen,
Feedbackgespraeche, Anhaenge und jedes PDF niemals. Das ist keine
Sparsamkeit: Was im Browsercache liegt, ist an der serverseitigen
Rechtepruefung vorbei.

Bewertungen ohne Netz gehen in eine Warteschlange und werden
nachgereicht. Die Schlange haengt an der Benutzerkennung, nicht am
Geraet - auf einem geteilten Werkstattgeraet bekaeme sonst der Zweite
die offenen Bewertungen des Ersten aufs Konto. Der Tag der Bewertung
kommt vom Geraet und wird auf heute gedeckelt (tagDerBewertung, 4
Tests): Eine vorgestellte Uhr darf das Wiederholen nicht wegstellen.

Druck: Wer die dunkle Fassung eingestellt hatte, druckte bisher schwarze
Flaechen. Im Druck wird jetzt die komplette helle Palette gesetzt, dazu
A4-Raender, keine Umbrueche mitten in Karten und Zeilen, aufgeklappte
details. Druckknoepfe bei Handout, Glossar und Auswertung.

Durchstich in scripts/pruefungen/baustein-10.mjs mit echtem Abschalten
des Netzes: 33 Pruefungen, darunter der Nachweis, dass nichts
Bewertungsrelevantes im Speicher landet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 15:47:06 +02:00

78 lines
2.9 KiB
TypeScript
Raw Permalink 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.
/**
* Erzeugt die Symbole für die installierte Anwendung aus dem Zeichen selbst –
* ohne Bilddienst, ohne Netz.
*
* npm run symbole
*
* Zwei Fassungen, weil Android sie unterschiedlich behandelt:
*
* symbol-192.png / symbol-512.png das Zeichen, wie es ist
* symbol-maskabel-512.png derselbe Inhalt, aber randvoll auf
* Petrol und nach innen gerückt. Android
* schneidet das Symbol in eine eigene
* Form – ein Kreis, ein Tropfen, was das
* Gerät gerade mag. Was zu weit außen
* liegt, ist dann weg.
*/
import fs from 'node:fs';
import path from 'node:path';
import { chromium } from '@playwright/test';
const ZIEL = path.join(process.cwd(), 'public');
/** Das Zeichen. Gleicher Inhalt wie `public/lernbar.svg`. */
function zeichen(randAnteil: number, eckenRadius: number): string {
// Die drei Balken liegen im Original in einem Feld von 64 × 64 Punkten.
// `randAnteil` rückt sie nach innen, ohne den Grund zu verkleinern.
const innen = 64 * (1 - 2 * randAnteil);
const versatz = 64 * randAnteil;
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<rect width="64" height="64" rx="${eckenRadius}" fill="#1F4E5F"/>
<g transform="translate(${versatz} ${versatz}) scale(${innen / 64})">
<rect x="14" y="16" width="10" height="32" rx="2" fill="#EDF3F5"/>
<rect x="27" y="16" width="10" height="32" rx="2" fill="#EDF3F5"/>
<rect x="40" y="16" width="10" height="32" rx="2" fill="#D98A2B"/>
</g>
</svg>`;
}
type Auftrag = { datei: string; groesse: number; svg: string };
const auftraege: Auftrag[] = [
{ datei: 'symbol-192.png', groesse: 192, svg: zeichen(0, 12) },
{ datei: 'symbol-512.png', groesse: 512, svg: zeichen(0, 12) },
// Randvoll und nach innen gerückt: der Beschnitt darf nichts abschneiden.
{ datei: 'symbol-maskabel-512.png', groesse: 512, svg: zeichen(0.14, 0) },
];
async function main() {
const browser = await chromium.launch();
for (const auftrag of auftraege) {
const seite = await browser.newPage({
viewport: { width: auftrag.groesse, height: auftrag.groesse },
deviceScaleFactor: 1,
});
await seite.setContent(
`<!doctype html><style>html,body{margin:0;padding:0}svg{display:block;width:100vw;height:100vh}</style>${auftrag.svg}`,
);
const datei = path.join(ZIEL, auftrag.datei);
await seite.screenshot({ path: datei, omitBackground: false });
await seite.close();
console.log(` public/${auftrag.datei} (${auftrag.groesse}×${auftrag.groesse}, ${fs.statSync(datei).size} Bytes)`);
}
await browser.close();
console.log('Symbole erzeugt.');
}
main().catch((fehler) => {
console.error('Die Symbole konnten nicht erzeugt werden.');
console.error(fehler instanceof Error ? fehler.message : fehler);
process.exit(1);
});