feat(icon): Phosphor glyph card — hero + real-UI-size strip (T-313)

The icon card renders each glyph at a hero size plus a continuous sample
strip (10–48px) so legibility is judged at the sizes the app uses, with the
entry's optional label + description and a per-entry or card-level color.
Wired end to end: icon.show publishes on the `icon` bus, the Claude
extension injects an IconMessage, and conversation_view paints the card
(display-only, D-78). en+nl catalogs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-29 13:10:53 +02:00
co-authored by Claude Opus 4.8
parent 9a2b4e9eca
commit 281fb2a869
10 changed files with 205 additions and 1 deletions
@@ -19,6 +19,7 @@ import 'package:clide/builtin/claude/src/claude_status.dart' show shortModelLabe
import 'package:clide/builtin/claude/src/conversation_card.dart';
import 'package:clide/builtin/claude/src/conversation_controller.dart';
import 'package:clide/builtin/claude/src/file_tail_follower.dart';
import 'package:clide/builtin/claude/src/icon_card.dart';
import 'package:clide/builtin/claude/src/image_thumbnail.dart';
import 'package:clide/builtin/claude/src/prompt_card.dart';
import 'package:clide/builtin/claude/src/transcript_reader.dart';
@@ -705,6 +706,7 @@ class _ConversationTurn extends StatelessWidget {
ToolResultMessage() => _toolResult(context, i),
ImageMessage() => _image(context, i),
DrawingMessage() => _drawing(context, i),
IconMessage() => _icon(context, i),
};
}
@@ -735,6 +737,17 @@ class _ConversationTurn extends StatelessWidget {
);
}
/// A driven-in Phosphor glyph card (T-313): each glyph at a hero size plus a
/// real-UI-size strip, with optional label/description/color. Display-only
/// per D-78 — selection happens in the interaction zone, not on the card.
Widget _icon(BuildContext context, IconMessage m) {
return ConversationCard(
accent: tokens.globalTextMuted,
label: ClideSettings.i18n.string(context, 'conversation.label.icon', namespace: 'builtin.claude', placeholder: 'icons'),
body: IconGlyphCard(entries: m.entries, defaultColor: m.color),
);
}
/// A driven-in image card (T-249): the image rendered inline, clide-owned
/// (Flutter's [Image.file], no third-party viewer), display-only per D-78.
/// Bounded so a large image scales down to the pane width and never pushes
@@ -1319,5 +1332,7 @@ String _summarizeActivity(BuildContext context, ConversationItem item) {
return '${label('conversation.label.image', 'image')} $path';
case DrawingMessage(label: final cardLabel):
return '${label('conversation.label.drawing', 'drawing')}${cardLabel != null ? ' $cardLabel' : ''}';
case IconMessage(:final entries):
return '${label('conversation.label.icon', 'icons')} ${entries.map((e) => e.name).join(', ')}';
}
}