CluPilotCloud/resources/views/livewire/admin/host-terminal.blade.php

117 lines
6.6 KiB
PHP

{{-- Die Bühne liegt ÜBER dem Terminal, nicht daneben.
Bis hierher waren es zwei Geschwister, von denen abwechselnd eines
`hidden` trug: erst der Vorspann, dann der Schirm. Das trug genau einmal
beim Aufbau. Für alles danach fehlte die Rückfahrkarte, und was der
Betreiber beim Abbruch sah, war eine rote ANSI-Zeile mitten in der eigenen
Ausgabe: die einzige Stelle im Produkt, an der eine Meldung nicht gestaltet
war, sondern getippt.
Als Überlagerung kann dieselbe Bühne dreimal auftreten beim Verbinden,
beim Abbruch, beim Ende und die Sitzung darunter bleibt stehen, statt
gelöscht zu werden. Was auf ihr steht, kommt aus den Sprachdateien; die
Meldungen, die erst der Browser kennt, reisen als JSON in
`data-stage-messages` mit, damit auch sie dort stehen und nicht im Skript. --}}
@php
// Ein Grund, den schon der Server kennt (kein Schlüssel hinterlegt, Host
// noch nicht übernommen), steht sofort auf der Bühne. Sonst beginnt sie mit
// dem Vorspann. Derselbe Bau, anderer Text, anderer Ton.
$stageTitle = $problem !== ''
? __('hosts.terminal.problem.'.$problem.'.title')
: __('hosts.terminal.stage.connecting.title', ['host' => $host->name]);
$stageNote = $problem !== ''
? __('hosts.terminal.problem.'.$problem.'.note')
: __('hosts.terminal.stage.connecting.note');
// Was der Browser erst später braucht. Welcher Schlüssel wann gilt, steht
// in resources/js/terminal.js neben den Schließcodes der Brücke.
$messages = [
'ended' => [
'title' => __('hosts.terminal.stage.ended.title'),
'note' => __('hosts.terminal.stage.ended.note', ['host' => $host->name]),
],
'lost' => [
'title' => __('hosts.terminal.stage.lost.title'),
'note' => __('hosts.terminal.stage.lost.note', ['host' => $host->name]),
],
'rejected' => [
'title' => __('hosts.terminal.stage.rejected.title'),
'note' => __('hosts.terminal.stage.rejected.note'),
],
'unreachable' => [
'title' => __('hosts.terminal.stage.unreachable.title', ['host' => $host->name]),
'note' => __('hosts.terminal.stage.unreachable.note', ['host' => $host->name]),
],
];
@endphp
<div class="relative flex h-screen w-screen flex-col overflow-hidden bg-ink"
data-terminal
data-ticket="{{ $ticket }}">
{{-- wire:ignore: xterms eigener DOM-Baum liegt in einem von Livewire
verwalteten Baum. Heute hat die Komponente keine Aktion, die einen
Re-Render auslöst aber das erste `wire:`-irgendwas auf dieser Seite
würde xterm sonst beim nächsten Umlauf löschen. --}}
<div data-terminal-screen wire:ignore class="flex-1 overflow-hidden"></div>
<div data-terminal-stage
class="absolute inset-0 z-10 flex flex-col items-center justify-center gap-6 bg-ink px-6 text-center"
data-stage-messages="{{ json_encode($messages, JSON_UNESCAPED_UNICODE) }}">
{{-- Schriftgrafik, keine Bilddatei deshalb `role="img"` mit einem
lesbaren Namen statt `aria-hidden`: ein Screenreader soll "CluPilot"
hören, nicht die einzelnen Zeichen der Zeichnung.
Vollblöcke, nicht `_ / \ |`. Die erste Fassung war eine gewöhnliche
Figlet-Zeichnung, und die funktioniert nur in einer echten
Terminalschrift: sie setzt darauf, dass der Unterstrich einer Zeile
den Strich der nächsten berührt. In IBM Plex Mono sitzt der
Unterstrich tiefer bei enger Zeilenhöhe verschmierte das Wort, bei
weiter zerfiel es in Einzelteile. Beides im Browser durchgemessen,
beides unlesbar. `█` füllt seine Zelle ganz aus und stapelt deshalb
in jeder Schrift sauber.
Immer Akzentfarbe, auch im Fehlerfall: Dunkelrot auf Fast-Schwarz
hatte kaum Kontrast, und eine Wortmarke, die ihre Farbe wechselt, ist
ohnehin keine Statuslampe was los ist, sagt die Zeile darunter.
8px am Telefon: bei 11px ist die Zeichnung 403px breit und schöbe auf
einem schmalen Schirm die Seite zur Seite. --}}
<pre data-stage-mark
class="select-none font-mono text-[8px] leading-none text-accent sm:text-[11px]"
role="img" aria-label="CluPilot"> ██████ ██ ██ ██ ██████ ██ ██ ██████ ████████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██████ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██████ ███████ ██████ ██ ██ ███████ ██████ ██</pre>
{{-- aria-live: die Bühne tauscht ihren Text aus, ohne dass die Seite neu
lädt. Ohne diesen Hinweis erführe ein Screenreader vom Abbruch
nichts für ihn stünde das Fenster weiter beim Vorspann. --}}
<div class="max-w-sm space-y-2" aria-live="polite">
<p data-stage-title class="text-sm font-semibold text-bg">{{ $stageTitle }}</p>
<p data-stage-note class="text-xs leading-relaxed text-bg opacity-70">{{ $stageNote }}</p>
</div>
{{-- Neu laden statt neu verbinden: das Ticket gilt dreißig Sekunden und
genau einmal, ein zweiter Anlauf mit demselben wäre keiner. Der
Knopf ist beim Vorspann verborgen und kommt erst, wenn ein neuer
Versuch überhaupt etwas ändern kann bei „kein Schlüssel
hinterlegt" ändert er nichts, dort bleibt er weg. Was er tut, hängt
terminal.js an; ein `onclick` im Markup wäre Verhalten an der
Stelle, an der sonst nur Gestalt steht.
`hidden` sitzt am Wrapper, nicht am Knopf: `x-ui.button` bringt
`inline-flex` mit, und beide Klassen haben dieselbe Spezifität —
wer gewinnt, entschiede dann die Reihenfolge im Stylesheet. Dieselbe
Falle wie bei `size-4`/`size-5` in R18, und sie ist hier mit einem
zusätzlichen Element billiger umgangen als nachgewiesen. --}}
<div data-stage-retry @class(['hidden' => $problem !== 'unknown'])>
<x-ui.button data-stage-retry-button variant="secondary" size="sm">
{{ __('hosts.terminal.stage.retry') }}
</x-ui.button>
</div>
</div>
</div>