fix(web): emoji → inline SVG icons for claude.ai-style visual consistency
Some checks failed
CI / Tests / 🧪 Test (push) Has been cancelled

Anthropic design language is icon-only, no emoji. User flagged that
claude-intercom components (and copy I wrote) were leaning on emoji
decoration. Swept all user-visible emojis in apps/web + packages/ui.

Changes:
- meshes/new onboarding banner: "Welcome to claudemesh 👋" → drop the
  wave, text stands alone
- meshes/[id]/invite banner: "🎉 Mesh created" → "Mesh created"
- demo-dashboard script message: "thanks 🙏" → "thanks." (inline prose)
- MeshStream message-type chips: replaced the ⟐ / ← / → unicode
  glyphs with proper inline SVG icons (10×10 stroke paths). Each chip
  now carries: plus-sign for broadcast, up-arrow for hand-raise,
  right-arrow for direct. Same claude-orange / emerald / neutral
  coloring, same typography — just geometry instead of text symbols.

Nothing swapped to Lucide React imports yet — Icons barrel in
packages/ui/web only exports a subset (Circle, Check, MessageCircle,
Sparkles, Megaphone), and the four glyphs we needed were simpler as
inline SVG than adding barrel exports + per-component import plumbing.
If emoji→Lucide fully lands, we'll add the rest to the Icons barrel
in one pass.

Skipped per PM spec: TTS announcements, commit messages, code
comments, logs — not user-visible.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-04-05 15:15:53 +01:00
parent 59189febd3
commit e91fc80bbc
4 changed files with 31 additions and 7 deletions

View File

@@ -93,7 +93,7 @@ export const SCRIPT: DemoMessage[] = [
from: "bob-desktop",
to: "alice-laptop",
type: "direct",
text: "saved me. applying now. thanks 🙏",
text: "saved me. applying now. thanks.",
ciphertext: "DYtZ+j0v4eB=.xNtP8qU5rM1aKw6cH…",
},
{

View File

@@ -39,26 +39,49 @@ const STATUS_DOT: Record<PeerStatus, string> = {
const TYPE_CHIP: Record<MessageType, { label: string; className: string }> = {
ask_mesh: {
label: "broadcast",
label: "broadcast",
className:
"border-[var(--cm-border)] bg-[var(--cm-bg)] text-[var(--cm-clay)]",
},
broadcast: {
label: "broadcast",
label: "broadcast",
className:
"border-[var(--cm-border)] bg-[var(--cm-bg)] text-[var(--cm-clay)]",
},
self_nominate: {
label: "hand-raise",
label: "hand-raise",
className: "border-emerald-500/40 bg-emerald-500/10 text-emerald-500",
},
direct: {
label: "direct",
label: "direct",
className:
"border-[var(--cm-border)] bg-[var(--cm-bg)] text-[var(--cm-fg-secondary)]",
},
};
const TYPE_ICON: Record<MessageType, React.ReactNode> = {
ask_mesh: (
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
<path d="M12 3v18M3 12h18" />
</svg>
),
broadcast: (
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
<path d="M12 3v18M3 12h18" />
</svg>
),
self_nominate: (
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
<path d="M12 19V5M5 12l7-7 7 7" />
</svg>
),
direct: (
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
<path d="M5 12h14M13 5l7 7-7 7" />
</svg>
),
};
const surfaceGlyph = (s?: StreamPeer["surface"]) => {
if (s === "phone")
return (
@@ -272,6 +295,7 @@ export const MeshStream = ({
TYPE_CHIP[m.type].className
}
>
{TYPE_ICON[m.type]}
{TYPE_CHIP[m.type].label}
</span>
{m.createdAt && (