Finanzmanager/src/Views/layout/kopf.php
fds2610-bot d1db40fa55 Fix #126: Taschenrechner an den Betragsfeldern
Jedes Zahlenfeld (inputmode="decimal") zeigt rechts ein Rechnersymbol.
Klick darauf oder Alt+R öffnet einen Taschenrechner mit Grundrechenarten
und Klammern, komplett per Tastatur bedienbar: Ziffern, + - * / ( ),
Backspace, Entf, Pfeiltasten, C löscht alles, = setzt das Ergebnis ein,
Enter überträgt ins Feld, Escape schließt und fokussiert das Feld. Das
Ergebnis steht nach jedem Tastendruck unter der Rechnung.

Das Symbol ist ein Hintergrundbild (kein Wrapper-Element, kein Eingriff in
die Layouts); gerechnet wird mit eigenem Parser statt eval. In modalen
Dialogen wandert der Rechner mit hinein. Stück/Kurs übernehmen 6,
Zinssätze 3 Nachkommastellen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 02:22:18 +02:00

103 lines
5.2 KiB
PHP
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.

<?php
use Finanzmanager\View;
/** @var string $titel */
/** @var array $flash */
/** @var string|null $aktuellerPfad */
/** @var array|null $benutzer */
$navigation = [
['pfad' => '/', 'name' => 'Cockpit', 'icon' => '⌂'],
['pfad' => '/konten', 'name' => 'Kontenübersicht', 'icon' => '▤'],
['pfad' => '/banking', 'name' => 'Online-Banking', 'icon' => '⇊'],
['pfad' => '/zahlungsverkehr', 'name' => 'Zahlungsverkehr', 'icon' => '⇄'],
['pfad' => '/auswertungen', 'name' => 'Auswertungen', 'icon' => '◱'],
['pfad' => '/planung', 'name' => 'Planung', 'icon' => '◷'],
['pfad' => '/wertpapiere', 'name' => 'Wertpapiere', 'icon' => '↗'],
// Termine und Verträge haben keinen eigenen Menüpunkt mehr, sind aber weiter
// erreichbar – deshalb leuchtet für sie die Verwaltung, unter der sie hängen.
['pfad' => '/verwaltung', 'name' => 'Verwaltung', 'icon' => '⚙', 'auch' => ['/termine', '/vertraege']],
];
// Ob die Seitenleiste eingeklappt ist, merkt sich ein Cookie. Das Skript
// setzt es beim Umschalten; hier entscheidet es schon beim Rendern, damit die
// breite Leiste nicht bei jedem Seitenwechsel kurz aufblitzt.
$eingeklappt = ($_COOKIE['seitenleiste'] ?? '') === 'eingeklappt';
/** @param list<string> $auch */
$istAktiv = static function (string $pfad, array $auch = []) use ($aktuellerPfad): bool {
if (!is_string($aktuellerPfad)) {
return false;
}
if ($pfad === '/') {
return $aktuellerPfad === '/' || $aktuellerPfad === '';
}
foreach ([$pfad, ...$auch] as $kandidat) {
if (str_starts_with($aktuellerPfad, $kandidat)) {
return true;
}
}
return false;
};
?>
<!DOCTYPE html>
<html lang="de"<?= ($thema = View::thema()) !== '' ? ' data-thema="' . View::h($thema) . '"' : '' ?>>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?= View::h($titel ?? 'Finanzmanager') ?> – Finanzmanager</title>
<link rel="stylesheet" href="/static/app.css">
<!-- Nur hier eingebunden: Ein zweites Mal im Fuß ließe jeden Handler doppelt
laufen – Rückfragen kämen zweimal, Menüs entstünden zweimal. -->
<script src="/static/app.js" defer></script>
<!-- Der Taschenrechner hängt an jedem Zahlenfeld jeder Seite; betrag.js
liefert ihm das Lesen deutscher Beträge. -->
<script src="/static/betrag.js" defer></script>
<script src="/static/rechner.js" defer></script>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><rect width='16' height='16' rx='3' fill='%231d6fb8'/><text x='8' y='12.5' font-size='12' font-weight='bold' text-anchor='middle' fill='white' font-family='sans-serif'>€</text></svg>">
</head>
<body>
<?php include __DIR__ . '/meldungen.php'; ?>
<div class="rahmen<?= $eingeklappt ? ' eingeklappt' : '' ?>">
<nav class="seitenleiste" id="seitenleiste" aria-label="Hauptnavigation">
<!-- Die Marke ist zugleich der Schalter: Ein Klick schiebt die
Seitenleiste auf Symbolbreite zusammen und wieder auf. -->
<button type="button" class="seitenleisten-marke" data-seitenleiste-schalter
aria-controls="seitenleiste" aria-expanded="<?= $eingeklappt ? 'false' : 'true' ?>"
title="<?= $eingeklappt ? 'Seitenleiste ausklappen' : 'Seitenleiste einklappen' ?>">
<img src="/static/coinstack.png" alt="" class="marken-symbol">
<span class="marken-text">Finanz<span>manager</span></span>
</button>
<ul>
<?php foreach ($navigation as $eintrag): ?>
<li>
<?php /* title bleibt hinten: Der Navigationstest prüft href und
class in dieser Reihenfolge unmittelbar hintereinander. */ ?>
<a href="<?= View::h($eintrag['pfad']) ?>"
class="<?= $istAktiv($eintrag['pfad'], $eintrag['auch'] ?? []) ? 'aktiv' : '' ?>"
title="<?= View::h($eintrag['name']) ?>">
<span class="icon" aria-hidden="true"><?= $eintrag['icon'] ?></span>
<span class="beschriftung"><?= View::h($eintrag['name']) ?></span>
</a>
</li>
<?php endforeach; ?>
</ul>
</nav>
<div class="hauptbereich">
<header class="werkzeugleiste">
<h1><?= View::h($titel ?? 'Finanzmanager') ?></h1>
<div class="werkzeuge">
<a href="/einstellungen" class="werkzeug" title="Einstellungen">⚙ Einstellungen</a>
<?php if (!empty($benutzer)): ?>
<span class="benutzer"><?= View::h($benutzer['anzeigename'] ?: $benutzer['benutzername']) ?></span>
<form method="post" action="/logout" class="inline">
<input type="hidden" name="csrf_token" value="<?= View::h($csrfToken ?? '') ?>">
<button type="submit" class="werkzeug">Abmelden</button>
</form>
<?php endif; ?>
</div>
</header>
<main class="inhalt">