Skip to content

Commit f2dc79f

Browse files
Migrate from material + lucide to @untitledui/icons (#2093)
* Migrate from deprecated Icon component to @untitledui/icons - Replace all string-based Icon component usages with direct ReactNode imports from @untitledui/icons - Update component interfaces to accept icon: ReactNode instead of icon: string - Update JSX to render icon components directly, wrapping in <span> with [&>svg]:size-X where needed - Remove @deco/ui/components/icon.tsx dependency from all files - Fix unavailable icon names: Brain01→Stars01, FileOutput→File01, Bot→MessageChatSquare, PanelLeft→Menu01, ChevronsUpDown→ChevronSelectorVertical, Pause→PauseCircle * updating sizes * updating icons * fix --------- Co-authored-by: rafavalls <valls@deco.cx>
1 parent 38456e0 commit f2dc79f

104 files changed

Lines changed: 606 additions & 752 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/mesh/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
},
3737
"dependencies": {
3838
"@ai-sdk/mcp": "^1.0.0",
39+
"@untitledui/icons": "^0.0.19",
3940
"@xyflow/react": "^12.10.0",
4041
"kysely": "^0.28.8",
4142
"kysely-bun-worker": "^0.6.0"
@@ -96,7 +97,6 @@
9697
"idb-keyval": "^6.2.2",
9798
"input-otp": "^1.4.2",
9899
"jose": "^6.0.11",
99-
"lucide-react": "^0.552.0",
100100
"nanoid": "^5.1.6",
101101
"pg": "^8.16.3",
102102
"react": "^19.2.0",

apps/mesh/src/web/components/chat/chat-panel.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { DecoChatAside } from "@deco/ui/components/deco-chat-aside.tsx";
1414
import { DecoChatEmptyState } from "@deco/ui/components/deco-chat-empty-state.tsx";
1515
import { DecoChatInputV2 } from "@deco/ui/components/deco-chat-input-v2.tsx";
1616
import { DecoChatModelSelectorRich } from "@deco/ui/components/deco-chat-model-selector-rich.tsx";
17-
import { Icon } from "@deco/ui/components/icon.tsx";
17+
import { X, Plus, CpuChip02 } from "@untitledui/icons";
1818
import { Metadata } from "@deco/ui/types/chat-metadata.ts";
1919
import { useNavigate } from "@tanstack/react-router";
2020
import { type ChatInit, DefaultChatTransport, type UIMessage } from "ai";
@@ -301,7 +301,7 @@ export function ChatPanel() {
301301
title: gateway.title,
302302
icon: gateway.icon,
303303
description: gateway.description,
304-
fallbackIcon: "network_node", // Consistent with gateways page
304+
fallbackIcon: <CpuChip02 />, // Consistent with gateways page
305305
}));
306306

307307
const handleSendMessage = async (text: string) => {
@@ -383,8 +383,7 @@ export function ChatPanel() {
383383
className="flex size-6 items-center justify-center rounded-full p-1 hover:bg-transparent transition-colors group cursor-pointer"
384384
title="Close chat"
385385
>
386-
<Icon
387-
name="close"
386+
<X
388387
size={16}
389388
className="text-muted-foreground group-hover:text-foreground transition-colors"
390389
/>
@@ -423,7 +422,7 @@ export function ChatPanel() {
423422
icon={selectedGateway?.icon}
424423
name={selectedGateway?.title || "deco chat"}
425424
size="xs"
426-
fallbackIcon="network_node"
425+
fallbackIcon={<CpuChip02 size={12} />}
427426
/>
428427
<span className="text-sm font-medium">
429428
{selectedGateway?.title || "deco chat"}
@@ -439,8 +438,7 @@ export function ChatPanel() {
439438
className="flex size-6 items-center justify-center rounded-full p-1 hover:bg-transparent group cursor-pointer"
440439
title="New chat"
441440
>
442-
<Icon
443-
name="add"
441+
<Plus
444442
size={16}
445443
className="text-muted-foreground group-hover:text-foreground transition-colors"
446444
/>
@@ -452,8 +450,7 @@ export function ChatPanel() {
452450
className="flex size-6 items-center justify-center rounded-full p-1 hover:bg-transparent transition-colors group cursor-pointer"
453451
title="Close chat"
454452
>
455-
<Icon
456-
name="close"
453+
<X
457454
size={16}
458455
className="text-muted-foreground group-hover:text-foreground transition-colors"
459456
/>
@@ -474,7 +471,7 @@ export function ChatPanel() {
474471
icon={selectedGateway?.icon}
475472
name={selectedGateway?.title || "deco chat"}
476473
size="lg"
477-
fallbackIcon="network_node"
474+
fallbackIcon={<CpuChip02 size={32} />}
478475
className="size-[60px]! rounded-[18px]!"
479476
/>
480477
}

apps/mesh/src/web/components/chat/gateway-selector.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { GatewayEntity } from "@/tools/gateway/schema";
2-
import { Icon } from "@deco/ui/components/icon.tsx";
2+
import { Check, SearchMd, CpuChip02 } from "@untitledui/icons";
33
import { IntegrationIcon } from "@/web/components/integration-icon.tsx";
44
import {
55
ResponsiveSelect,
@@ -8,11 +8,11 @@ import {
88
ResponsiveSelectValue,
99
} from "@deco/ui/components/responsive-select.tsx";
1010
import { cn } from "@deco/ui/lib/utils.ts";
11-
import { useState } from "react";
11+
import { useState, type ReactNode } from "react";
1212

1313
export interface GatewayInfo
1414
extends Pick<GatewayEntity, "id" | "title" | "description" | "icon"> {
15-
fallbackIcon?: string; // Material Symbol name to use when icon is not available
15+
fallbackIcon?: ReactNode; // Icon to use when icon is not available
1616
}
1717

1818
function GatewayItemContent({
@@ -34,7 +34,7 @@ function GatewayItemContent({
3434
icon={gateway.icon}
3535
name={gateway.title}
3636
size="sm"
37-
fallbackIcon={gateway.fallbackIcon || "network_node"}
37+
fallbackIcon={gateway.fallbackIcon ?? <CpuChip02 />}
3838
className="size-10"
3939
/>
4040

@@ -45,7 +45,7 @@ function GatewayItemContent({
4545
{gateway.title}
4646
</span>
4747
{isSelected && (
48-
<Icon name="check" size={16} className="text-foreground shrink-0" />
48+
<Check size={16} className="text-foreground shrink-0" />
4949
)}
5050
</div>
5151
{gateway.description && (
@@ -75,7 +75,7 @@ function SelectedGatewayDisplay({
7575
icon={gateway.icon}
7676
name={gateway.title}
7777
size="xs"
78-
fallbackIcon={gateway.fallbackIcon || "network_node"}
78+
fallbackIcon={gateway.fallbackIcon ?? <CpuChip02 />}
7979
className="size-5"
8080
/>
8181
<span className="text-sm font-medium text-foreground truncate">
@@ -143,7 +143,7 @@ export function GatewaySelector({
143143
{/* Search/Header area could go here if needed */}
144144
<div className="border-b px-4 py-3 bg-background/95 backdrop-blur sticky top-0 z-10">
145145
<div className="flex items-center gap-2 text-muted-foreground">
146-
<Icon name="search" size={16} />
146+
<SearchMd size={16} />
147147
<span className="text-sm">Search for a gateway...</span>
148148
</div>
149149
</div>

apps/mesh/src/web/components/chat/message-assistant.tsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { cn } from "@deco/ui/lib/utils.ts";
22
import { Metadata } from "@deco/ui/types/chat-metadata.ts";
33
import type { DynamicToolUIPart, ToolUIPart } from "ai";
4-
import { Icon } from "@deco/ui/components/icon.tsx";
5-
import { useEffect, useRef, useState } from "react";
4+
import { useEffect, useRef, useState, type ReactNode } from "react";
5+
import { Target04, Stars01, Lightbulb01 } from "@untitledui/icons";
66
import { MessageProps } from "./message-user.tsx";
77
import { MessageReasoningPart } from "./parts/reasoning-part.tsx";
88
import { MessageTextPart } from "./parts/text-part.tsx";
@@ -12,17 +12,19 @@ import { UsageStats } from "./usage-stats.tsx";
1212
type ThinkingStage = "planning" | "thinking";
1313

1414
interface ThinkingStageConfig {
15-
icon: string;
15+
icon: ReactNode;
1616
label: string;
1717
}
1818

1919
const THINKING_STAGES: Record<ThinkingStage, ThinkingStageConfig> = {
2020
planning: {
21-
icon: "track_changes",
21+
icon: (
22+
<Target04 className="text-muted-foreground animate-pulse" size={20} />
23+
),
2224
label: "Planning next moves",
2325
},
2426
thinking: {
25-
icon: "psychology",
27+
icon: <Stars01 className="text-muted-foreground animate-pulse" size={20} />,
2628
label: "Thinking",
2729
},
2830
};
@@ -47,11 +49,7 @@ function TypingIndicator() {
4749

4850
return (
4951
<div className="flex items-center gap-2 py-2">
50-
<Icon
51-
name={config.icon}
52-
className="text-muted-foreground animate-pulse"
53-
size={20}
54-
/>
52+
{config.icon}
5553
<span className="text-sm font-medium text-muted-foreground text-shimmer">
5654
{config.label}...
5755
</span>
@@ -64,7 +62,7 @@ function ThoughtSummary({ duration }: { duration: number }) {
6462

6563
return (
6664
<div className="flex items-center gap-2 py-2 opacity-60">
67-
<Icon name="lightbulb" className="text-muted-foreground" size={16} />
65+
<Lightbulb01 className="text-muted-foreground" size={16} />
6866
<span className="text-xs text-muted-foreground">
6967
Thought · {seconds}s
7068
</span>

apps/mesh/src/web/components/chat/message-user.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { cn } from "@deco/ui/lib/utils.ts";
44
import { Metadata } from "@deco/ui/types/chat-metadata.ts";
55
import { MessageTextPart } from "./parts/text-part.tsx";
66
import { MessageListContext } from "./message-list.tsx";
7-
import { Icon } from "@deco/ui/components/icon.tsx";
7+
import { ChevronUp, ChevronDown } from "@untitledui/icons";
88
import { Button } from "@deco/ui/components/button.tsx";
99

1010
export interface MessageProps<T extends Metadata> {
@@ -91,10 +91,11 @@ export function MessageUser<T extends Metadata>({
9191
size="xs"
9292
className="text-xs w-full text-muted-foreground hover:text-foreground"
9393
>
94-
<Icon
95-
name={isExpanded ? "expand_less" : "expand_more"}
96-
className="text-sm"
97-
/>
94+
{isExpanded ? (
95+
<ChevronUp className="text-sm" />
96+
) : (
97+
<ChevronDown className="text-sm" />
98+
)}
9899
</Button>
99100
</div>
100101
)}

apps/mesh/src/web/components/chat/parts/reasoning-part.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ReasoningUIPart } from "ai";
22
import { useEffect, useReducer } from "react";
33
import { cn } from "@deco/ui/lib/utils.ts";
4-
import { Icon } from "@deco/ui/components/icon.tsx";
4+
import { Stars01, ChevronDown } from "@untitledui/icons";
55
import { MemoizedMarkdown } from "@deco/ui/components/chat/chat-markdown.tsx";
66

77
interface ReasoningPartProps {
@@ -62,8 +62,7 @@ export function MessageReasoningPart({ part, id }: ReasoningPartProps) {
6262
onClick={handleToggle}
6363
className="flex items-center gap-2 py-2 transition-colors cursor-pointer"
6464
>
65-
<Icon
66-
name="psychology"
65+
<Stars01
6766
className={cn(
6867
"text-muted-foreground transition-opacity",
6968
isPartStreaming && "animate-pulse",
@@ -77,8 +76,7 @@ export function MessageReasoningPart({ part, id }: ReasoningPartProps) {
7776
>
7877
Agent thinking
7978
</span>
80-
<Icon
81-
name="expand_more"
79+
<ChevronDown
8280
className={cn(
8381
"text-muted-foreground transition-transform duration-200",
8482
isExpanded ? "rotate-180" : "",

apps/mesh/src/web/components/chat/parts/text-part.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useState } from "react";
22
import { useCopy } from "@deco/ui/hooks/use-copy.ts";
33
import { Button } from "@deco/ui/components/button.tsx";
44
import { MemoizedMarkdown } from "@deco/ui/components/chat/chat-markdown.tsx";
5-
import { Icon } from "@deco/ui/components/icon.tsx";
5+
import { Check, Copy01 } from "@untitledui/icons";
66

77
interface MessageTextPartProps {
88
id: string;
@@ -37,13 +37,9 @@ export function MessageTextPart({
3737
className="text-muted-foreground hover:text-foreground px-2 py-1 h-auto whitespace-nowrap"
3838
>
3939
{isCopied ? (
40-
<>
41-
<Icon name="check" className="mr-1 text-sm" />
42-
</>
40+
<Check className="mr-1 text-sm" />
4341
) : (
44-
<>
45-
<Icon name="content_copy" className="mr-1 text-sm" />
46-
</>
42+
<Copy01 className="mr-1 text-sm" />
4743
)}
4844
</Button>
4945
</div>

apps/mesh/src/web/components/chat/parts/tool-call-part.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Icon } from "@deco/ui/components/icon.tsx";
1+
import { AlertCircle, Terminal } from "@untitledui/icons";
22
import { cn } from "@deco/ui/lib/utils.ts";
33
import type { DynamicToolUIPart, ToolUIPart } from "ai";
44
import { ToolOutputRenderer } from "./tool-outputs/tool-output-renderer.tsx";
@@ -16,13 +16,11 @@ export function ToolCallPart({ part }: ToolCallPartProps) {
1616
return (
1717
<div className="flex flex-col gap-1.5 py-1">
1818
<div className="flex items-center gap-2 text-xs font-medium text-muted-foreground">
19-
<Icon
20-
name={state === "output-error" ? "error" : "terminal"}
21-
className={cn(
22-
"h-3.5 w-3.5",
23-
state === "output-error" && "text-destructive",
24-
)}
25-
/>
19+
{state === "output-error" ? (
20+
<AlertCircle className="h-3.5 w-3.5 text-destructive" />
21+
) : (
22+
<Terminal className="h-3.5 w-3.5" />
23+
)}
2624
<span className={cn(state === "output-error" && "text-destructive/90")}>
2725
{state === "input-streaming" && `Streaming ${toolName} arguments...`}
2826
{state === "input-available" && `Calling ${toolName}...`}

apps/mesh/src/web/components/chat/parts/tool-outputs/tool-output-renderer.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ConnectionCard } from "@/web/components/connections/connection-card.tsx
22
import { useConnection } from "@/web/hooks/collections/use-connection";
33
import { useProjectContext } from "@/web/providers/project-context-provider";
44
import { Button } from "@deco/ui/components/button.tsx";
5-
import { Icon } from "@deco/ui/components/icon.tsx";
5+
import { LinkExternal01, Copy01 } from "@untitledui/icons";
66
import { useNavigate } from "@tanstack/react-router";
77
import { toast } from "sonner";
88

@@ -106,7 +106,7 @@ function ConnectionRenderer({
106106
className="hover:text-foreground transition-colors"
107107
title="Open connection"
108108
>
109-
<Icon name="open_in_new" size={12} />
109+
<LinkExternal01 size={12} />
110110
</button>
111111
</div>
112112
);
@@ -161,7 +161,7 @@ function CopyButton({ text }: { text: string }) {
161161
className="h-5 w-5 hover:bg-background/50"
162162
onClick={handleCopy}
163163
>
164-
<Icon name="content_copy" size={12} />
164+
<Copy01 size={12} />
165165
</Button>
166166
);
167167
}

apps/mesh/src/web/components/chat/usage-stats.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
TooltipTrigger,
44
TooltipContent,
55
} from "@deco/ui/components/tooltip.tsx";
6-
import { Icon } from "@deco/ui/components/icon.tsx";
6+
import { Coins01 } from "@untitledui/icons";
77
import { Metadata } from "@deco/ui/types/chat-metadata.ts";
88
import { calculateUsageStats } from "@/web/lib/usage-utils.ts";
99

@@ -23,7 +23,7 @@ export function UsageStats({ messages }: UsageStatsProps) {
2323
type="button"
2424
className="ml-auto shrink-0 flex items-center gap-1 text-[11px] text-muted-foreground/60 font-mono tabular-nums hover:text-muted-foreground transition-colors"
2525
>
26-
<Icon name="token" size={12} className="opacity-60" />
26+
<Coins01 size={12} className="opacity-60" />
2727
<span className="hidden md:inline">
2828
{totalTokens.toLocaleString()}
2929
</span>

0 commit comments

Comments
 (0)