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>
78 lines
2.9 KiB
TypeScript
78 lines
2.9 KiB
TypeScript
/**
|
||
* 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);
|
||
});
|