fix(ui): Mic- und Anhang-Icon sichtbar, Warte-Cursor blinkt

Zwei Stellen, an denen die Oberfläche tot wirkte.

Mic und Anhang waren grau: 🎙 und 📎 sind in den Emoji-Fonts fest
eingefärbt, `color` greift bei ihnen nicht. Damit liefen auch die
vorhandenen Zustandsregeln ins Leere — .btn-mic.recording (rot) und
.transcribing (orange) färbten nur den Rahmen, nie das Icon. Jetzt SVG in
currentColor, dazu ein akzentfarbener Rahmen, damit Mic, Anhang und
"Senden" als eine Gruppe lesbar sind.

Der Platzhalter vor dem ersten Token war ein statisches ▍ und sah nach
Stillstand aus, obwohl die Antwort lief — bei kaltem Modell dauert das
mehrere Sekunden. Blinkt jetzt über das vorhandene blink-Keyframe.
Eigene Klasse .stream-caret, weil .caret schon das Aufklapp-Dreieck des
Denkprozesses ist und sonst mitgeblinkt hätte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015AUP4R3rgq4XwVs4bVf7uh
This commit is contained in:
Jeuner 2026-08-28 15:16:14 +02:00
parent 8a489dfc5c
commit a36e366b58
3 changed files with 71 additions and 8 deletions

View file

@ -127,9 +127,17 @@ export function ChatMessage({
) : null
) : (
<div className="msg-content markdown">
<ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeHighlight]}>
{message.content || "▍"}
</ReactMarkdown>
{message.content ? (
<ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeHighlight]}>
{message.content}
</ReactMarkdown>
) : (
// Noch kein Token da. Der Cursor blinkt, damit die Wartezeit — bei
// kaltem Modell mehrere Sekunden — nicht wie ein Stillstand wirkt.
<span className="stream-caret" role="status" aria-label="Antwort wird erzeugt">
</span>
)}
</div>
)}
</div>

View file

@ -105,6 +105,51 @@ async function readAsTextAttachment(file: File): Promise<TextAttachment> {
};
}
/**
* Icons als SVG statt Emoji.
*
* 🎙 und 📎 sind in den Emoji-Fonts fest grau eingefärbt `color` greift bei
* ihnen nicht. Damit blieben auch die Zustandsfarben unten wirkungslos
* (Aufnahme rot, Transkription orange): sie färbten nur den Rahmen. Als SVG
* mit `currentColor` zieht die Farbe wieder durch.
*/
const ICON = {
width: 18,
height: 18,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
strokeWidth: 1.8,
strokeLinecap: "round" as const,
strokeLinejoin: "round" as const,
};
function MicIcon() {
return (
<svg {...ICON} aria-hidden="true">
<rect x="9" y="2.5" width="6" height="11" rx="3" />
<path d="M5 11a7 7 0 0 0 14 0" />
<path d="M12 18v3M8.5 21h7" />
</svg>
);
}
function RecordIcon() {
return (
<svg {...ICON} aria-hidden="true">
<circle cx="12" cy="12" r="5.5" fill="currentColor" stroke="none" />
</svg>
);
}
function ClipIcon() {
return (
<svg {...ICON} aria-hidden="true">
<path d="M21.44 11.05l-9.19 9.19a5.5 5.5 0 0 1-7.78-7.78l9.19-9.19a3.5 3.5 0 0 1 4.95 4.95l-9.2 9.19a1.5 1.5 0 0 1-2.12-2.12l8.49-8.49" />
</svg>
);
}
export function Composer({
streaming,
disabled,
@ -311,7 +356,7 @@ export function Composer({
}
disabled={transcribing || disabled}
>
{recording ? "●" : transcribing ? "…" : "🎙"}
{recording ? <RecordIcon /> : transcribing ? "…" : <MicIcon />}
</button>
<button
@ -320,7 +365,7 @@ export function Composer({
disabled={disabled}
title="Bild oder Textdatei anhängen (auch per Einfügen oder Drag & Drop)"
>
📎
<ClipIcon />
</button>
<input
ref={fileRef}

View file

@ -69,6 +69,14 @@ body {
}
}
/* Platzhalter, solange eine Antwort noch kein Token geliefert hat.
Eigener Name: .caret ist schon das Aufklapp-Dreieck des Denkprozesses. */
.stream-caret {
display: inline-block;
color: var(--accent);
animation: blink 1.1s steps(2) infinite;
}
.btn-new,
.btn-settings,
.btn-send {
@ -414,7 +422,7 @@ body {
.btn-mic {
flex-shrink: 0;
font-size: 17px;
color: var(--text-dim);
color: var(--accent);
}
.btn-mic:hover:not(:disabled) {
@ -607,7 +615,9 @@ body {
font-size: 17px;
line-height: 1;
background: transparent;
border: 1px solid var(--border, #30363d);
/* Akzentfarbener Rahmen, damit Mic/Anhang und "Senden" als eine Gruppe
lesbar sind "Senden" bleibt durch seine Füllung die Primäraktion. */
border: 1px solid var(--accent-dim);
border-radius: 8px;
cursor: pointer;
color: var(--text-dim);
@ -635,7 +645,7 @@ body {
}
.btn-attach {
color: var(--text-dim);
color: var(--accent);
}
.msg-images {