Fehler melden mit Screenshot und Markierung, Sammlung für Bearbeiter

Käfer-Button unten rechts: nimmt den sichtbaren Bildschirm mit html2canvas
(selbst gehostet) auf, Vorschau mit roten Rechtecken, Beschreibung, Name
optional, Senden ohne Anmeldung. Aus offenen Dialogen heraus wird der
Dialog selbst aufgenommen. Bearbeiter sehen die Meldungen unter „Fehler"
mit Zähler, kopieren einen fertigen Claude-Prompt und den Screenshot.

Serverseitig: Pfade nur in exakter Schreibweise, /api standardmäßig nur
für Bearbeiter mit ausdrücklicher Freigabeliste, Bremse zählt jeden
Versuch vor dem Lesen großer Bodies, X-Forwarded-For nur von vertrauten
Proxys, Nutzertext im Prompt eingezäunt. HTTP-Tests für die Sperren.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ferdi2goandClaude Fable 5.1 committed 2026-10-15 08:19:46 +00:00
1 parent 6a3c68aaac
commit 4ec23ccd25
15 files changed
+877 -36

No files matched your search

+49 -7
View File
@@ -88,14 +88,17 @@ svg.icon { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-w
.topbar nav { flex-wrap: nowrap; overflow-x: auto; width: 100%; margin: 0 -16px; padding: 0 8px; scrollbar-width: none; }
.topbar nav::-webkit-scrollbar { display: none; }
.topbar nav a { min-height: 44px; padding: 0 10px; font-size: 13px; white-space: nowrap; }
.topbar-action { margin-left: auto; margin-block: 8px; }
/* Titel und Anmelden in einer Zeile, Navigation darunter: zwei Zeilen statt drei */
.topbar h1 { order: 0; }
.topbar-action { order: 1; margin-left: auto; margin-block: 8px; }
.topbar nav { order: 2; }
}
button:focus-visible, input:focus-visible, select:focus-visible, .button:focus-visible, .day:focus-visible, .avatar[tabindex]:focus-visible {
button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, .button:focus-visible, .day:focus-visible, .avatar[tabindex]:focus-visible {
outline: 2px solid var(--tradeo-blue); outline-offset: 2px;
}
main { padding: 24px 16px 48px; max-width: 1120px; margin: 0 auto; }
@media (min-width: 720px) { main { padding: 32px 24px 64px; } }
main { padding: 24px 16px 96px; max-width: 1120px; margin: 0 auto; }
@media (min-width: 720px) { main { padding: 32px 24px 96px; } }
.view > h2 { margin-bottom: 24px; }
h3 { margin: 32px 0 12px; }
@@ -106,13 +109,16 @@ h3 { margin: 32px 0 12px; }
.form-grid h3 { margin: 0; }
label { display: flex; flex-direction: column; gap: 6px; font-size: 13px; font-weight: 500; color: var(--text-2); }
label.inline { flex-direction: row; align-items: center; gap: 10px; color: var(--text); font-weight: 400; font-size: 14px; }
label > input:not([type="checkbox"]), label > select { width: 100%; min-width: 0; max-width: 100%; }
label > input:not([type="checkbox"]), label > select, label > textarea { width: 100%; min-width: 0; max-width: 100%; }
textarea { resize: vertical; line-height: 1.45; }
button.link { display: inline; min-height: 0; padding: 0; border: 0; background: none; font-size: inherit; color: var(--tradeo-blue); text-decoration: underline; text-underline-offset: 2px; }
button.link:hover { background: none; }
.form-grid > *, .dialog-form > *, .row > label { min-width: 0; }
input, select, button, .button {
input, select, textarea, button, .button {
font: inherit; font-size: 15px; color: var(--text); background: var(--white);
border: 1px solid var(--line-2); border-radius: var(--radius); padding: 8px 12px; min-height: 40px;
}
input::placeholder { color: var(--text-3); }
input::placeholder, textarea::placeholder { color: var(--text-3); }
input[type="checkbox"] { min-height: 0; width: 18px; height: 18px; margin: 0; accent-color: var(--tradeo-blue); }
fieldset.checks { border: 1px solid var(--line); border-radius: var(--radius); display: flex; flex-wrap: wrap; gap: 12px 24px; padding: 12px 16px 16px; margin: 0; }
fieldset.checks legend { font-size: 13px; font-weight: 500; color: var(--text-2); padding: 0 4px; }
@@ -264,6 +270,42 @@ dialog::backdrop { background: rgba(18, 46, 69, .4); }
.contacts-list label { flex-direction: row; align-items: center; gap: 12px; color: var(--text); flex: 1; cursor: pointer; font-weight: 400; font-size: 14px; }
.contacts-tools { display: flex; gap: 8px; }
/* Fehler melden: Käfer-Button unten rechts und kompaktes Panel darüber */
.bug-button {
position: fixed; right: 16px; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); z-index: 25;
width: 48px; height: 48px; padding: 0; border-radius: 50%; border: 0;
background: var(--tradeo-blue); color: var(--white); box-shadow: 0 4px 12px rgba(18, 46, 69, .24);
}
.bug-button:hover { background: var(--tradeo-blue); box-shadow: 0 6px 16px rgba(18, 46, 69, .32); }
.bug-button svg { width: 24px; height: 24px; }
.bug-button[aria-expanded="true"] { box-shadow: inset 0 0 0 999px rgba(255, 255, 255, .12), 0 4px 12px rgba(18, 46, 69, .24); }
/* Das Panel ist ein modaler Dialog: so liegt es auch über anderen offenen Dialogen und Escape schließt es */
dialog.bug-panel {
position: fixed; inset: auto 16px calc(76px + env(safe-area-inset-bottom, 0px)) auto; margin: 0;
width: min(400px, calc(100vw - 32px)); max-height: calc(100vh - 100px); overflow: auto;
padding: 16px; display: grid; gap: 10px;
}
dialog.bug-panel:not([open]) { display: none; }
dialog.bug-panel::backdrop { background: rgba(18, 46, 69, .18); }
.dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.dialog-head h2 { margin: 0; }
.dialog-bug { width: 36px; min-height: 36px; padding: 0; color: var(--text-2); }
.dialog-bug svg { width: 20px; height: 20px; }
.bug-panel h2 { font-size: 16px; }
.bug-panel .hint { margin: 0; }
.bug-shot { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--tint-1); }
.bug-shot canvas { display: block; width: auto; max-width: 100%; max-height: 45vh; height: auto; margin: 0 auto; cursor: crosshair; touch-action: none; }
.bug-form { display: grid; gap: 10px; }
.bug-form textarea { min-height: 72px; }
.bug-list li { align-items: flex-start; }
.bug-thumb { display: block; width: 160px; max-width: 100%; flex-shrink: 0; }
.bug-thumb img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: 4px; }
.bug-text { white-space: pre-wrap; overflow-wrap: anywhere; }
.bug-meta { color: var(--text-2); font-size: 13px; margin-top: 4px; }
.bug-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.bug-actions button { min-height: 34px; padding: 0 12px; font-size: 13px; }
@media (max-width: 560px) { .bug-thumb { width: 100%; } }
.toast {
position: fixed; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); left: 50%; transform: translateX(-50%);
background: var(--tradeo-blue); color: var(--white); padding: 10px 16px; border-radius: var(--radius); font-size: 14px; z-index: 20; max-width: 90vw;