diff --git a/apps/web/DESIGN.md b/apps/web/DESIGN.md index 703bd5b3..711bd1c6 100644 --- a/apps/web/DESIGN.md +++ b/apps/web/DESIGN.md @@ -45,6 +45,13 @@ Fixed rem scale (not fluid in product UI): `--fs-12 … --fs-64`. Line heights `.t-body/.t-body-sm/.t-caption/.t-micro/.t-eyebrow/.t-mono/.t-link`. Base body is `--fs-15` / weight 500 with `ss01`. Product headings stay fixed. +## Icons + +Generic interface glyphs use Hugeicons Free through `src/shared/ui/icons.tsx`, with +`currentColor` and a 1.5px stroke by default. Use its semantic exports rather than +importing an icon library at a route. Brand marks, provider/channel logos, favicons, +and product illustrations remain owned assets rather than UI glyphs. + ## Spacing & Radius Spacing scale `--s-1 (4px) … --s-24 (96px)`. Radius `--r-xs 4 / -sm 6 / -md 10 / -lg 14 diff --git a/apps/web/package.json b/apps/web/package.json index e0bf3cce..fc047e23 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -33,7 +33,6 @@ "boring-avatars": "^2.0.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^1.31.0", "motion": "^12.40.0", "react": "^19.2.8", "react-dom": "^19.2.8", diff --git a/apps/web/src/app/hugeicon.tsx b/apps/web/src/app/hugeicon.tsx index ac8f54f7..3fd0defe 100644 --- a/apps/web/src/app/hugeicon.tsx +++ b/apps/web/src/app/hugeicon.tsx @@ -1,26 +1,2 @@ -import { HugeiconsIcon } from "@hugeicons/react"; -import type { HugeiconsIconProps, IconSvgElement } from "@hugeicons/react"; -import type { ComponentType, Ref } from "react"; - -type HugeiconProps = Omit & { - ref?: Ref; -}; - -export type AppIcon = ComponentType; - -export function createHugeicon(icon: IconSvgElement, displayName: string): AppIcon { - function AppHugeicon({ - color = "currentColor", - ref, - strokeWidth = 1.5, - ...props - }: HugeiconProps) { - return ( - - ); - } - - AppHugeicon.displayName = displayName; - - return AppHugeicon; -} +export { createHugeicon } from "@/shared/ui/icons"; +export type { AppIcon } from "@/shared/ui/icons"; diff --git a/apps/web/src/app/route-registry.tsx b/apps/web/src/app/route-registry.tsx index 19e430b0..7f3eb86d 100644 --- a/apps/web/src/app/route-registry.tsx +++ b/apps/web/src/app/route-registry.tsx @@ -1,4 +1,3 @@ -import { FileQuestion } from "lucide-react"; import { lazy } from "react"; import type { ComponentType, ReactElement, ReactNode } from "react"; import { Link, Navigate, useParams, useRoutes } from "react-router-dom"; @@ -7,6 +6,7 @@ import type { RouteObject } from "react-router-dom"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; import { EmptyState } from "@/shared/ui/empty-state"; +import { FileQuestion } from "@/shared/ui/icons"; import { GuestRoute, OnboardingRoute, ProtectedRoute } from "./route-guards"; diff --git a/apps/web/src/domains/environment/components/environment-cli-callout.tsx b/apps/web/src/domains/environment/components/environment-cli-callout.tsx index df9863c0..47e74b2d 100644 --- a/apps/web/src/domains/environment/components/environment-cli-callout.tsx +++ b/apps/web/src/domains/environment/components/environment-cli-callout.tsx @@ -1,9 +1,9 @@ -import { Terminal } from "lucide-react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { CommandBlock } from "@/shared/ui/command-block"; +import { Terminal } from "@/shared/ui/icons"; export const ENVIRONMENT_CLI_CREATE_COMMAND = "mosoo console environments create-environment"; diff --git a/apps/web/src/domains/environment/components/environment-form-controls.tsx b/apps/web/src/domains/environment/components/environment-form-controls.tsx index 237410db..554ef615 100644 --- a/apps/web/src/domains/environment/components/environment-form-controls.tsx +++ b/apps/web/src/domains/environment/components/environment-form-controls.tsx @@ -2,7 +2,6 @@ import type { EnvironmentNetworkPolicy, EnvironmentPackageManager, } from "@mosoo/contracts/environment"; -import { Check, ChevronDown } from "lucide-react"; import type { ReactNode } from "react"; import { useTranslation } from "@/shared/i18n"; @@ -12,6 +11,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; +import { Check, ChevronDown } from "@/shared/ui/icons"; import { isTruthy } from "../../../shared/lib/truthiness"; import { diff --git a/apps/web/src/domains/environment/components/environment-form.tsx b/apps/web/src/domains/environment/components/environment-form.tsx index ac6d0daa..1a057409 100644 --- a/apps/web/src/domains/environment/components/environment-form.tsx +++ b/apps/web/src/domains/environment/components/environment-form.tsx @@ -1,9 +1,9 @@ import { isWritableEnvironmentPackageManager } from "@mosoo/contracts/environment"; -import { Check, Plus, Trash2 } from "lucide-react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Button } from "@/shared/ui/button"; +import { Check, Plus, Trash2 } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { Label } from "@/shared/ui/label"; import { Switch } from "@/shared/ui/switch"; diff --git a/apps/web/src/features/file-preview/file-preview-content.tsx b/apps/web/src/features/file-preview/file-preview-content.tsx index 9fdb9a99..8e93439d 100644 --- a/apps/web/src/features/file-preview/file-preview-content.tsx +++ b/apps/web/src/features/file-preview/file-preview-content.tsx @@ -1,5 +1,4 @@ import { useQuery } from "@tanstack/react-query"; -import { Download, FileQuestion, LoaderCircle } from "lucide-react"; import type { ReactElement } from "react"; import { createFileDownload, readFileText } from "@/domains/file/api/file-download-client"; @@ -7,6 +6,7 @@ import { fileKeys } from "@/domains/file/api/files"; import type { ListedFileEntry } from "@/domains/file/api/files"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { Download, FileQuestion, LoaderCircle } from "@/shared/ui/icons"; import { StaticMarkdown } from "@/shared/ui/static-markdown"; import { diff --git a/apps/web/src/features/help/help-docs-dialog.tsx b/apps/web/src/features/help/help-docs-dialog.tsx index a56a5929..172aa75d 100644 --- a/apps/web/src/features/help/help-docs-dialog.tsx +++ b/apps/web/src/features/help/help-docs-dialog.tsx @@ -1,4 +1,3 @@ -import { ArrowUpRight, BookOpen, Search } from "lucide-react"; import { useMemo, useRef, useState } from "react"; import { HELP_DOCS, HELP_DOCS_HOME_URL, searchHelpDocs } from "@/shared/config/help-docs"; @@ -12,6 +11,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { ArrowUpRight, BookOpen, Search } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { ScrollArea } from "@/shared/ui/scroll-area"; diff --git a/apps/web/src/features/help/help-menu.tsx b/apps/web/src/features/help/help-menu.tsx index 283a723e..6348a423 100644 --- a/apps/web/src/features/help/help-menu.tsx +++ b/apps/web/src/features/help/help-menu.tsx @@ -1,8 +1,8 @@ -import { HelpCircle } from "lucide-react"; import { lazy, Suspense, useEffect, useState } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { HelpCircle } from "@/shared/ui/icons"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip"; // Loaded on demand the first time Help is opened. The dialog drags in the Radix diff --git a/apps/web/src/features/session-chat/assistant-ui/session-message-parts.tsx b/apps/web/src/features/session-chat/assistant-ui/session-message-parts.tsx index 9635c23b..0869cf26 100644 --- a/apps/web/src/features/session-chat/assistant-ui/session-message-parts.tsx +++ b/apps/web/src/features/session-chat/assistant-ui/session-message-parts.tsx @@ -1,10 +1,10 @@ import { ActionBarPrimitive, MessagePrimitive, useAuiState } from "@assistant-ui/react"; import type { ReasoningMessagePartComponent, TextMessagePartComponent } from "@assistant-ui/react"; -import { ChevronRight, Copy } from "lucide-react"; import type { ReactElement } from "react"; import { useState } from "react"; import { useTranslation } from "@/shared/i18n"; +import { ChevronRight, Copy } from "@/shared/ui/icons"; import { Markdown } from "@/shared/ui/markdown"; import { SessionToolPart } from "./session-tool-part"; diff --git a/apps/web/src/features/session-chat/assistant-ui/session-thread-composer.tsx b/apps/web/src/features/session-chat/assistant-ui/session-thread-composer.tsx index 3fabffb3..626c3aa7 100644 --- a/apps/web/src/features/session-chat/assistant-ui/session-thread-composer.tsx +++ b/apps/web/src/features/session-chat/assistant-ui/session-thread-composer.tsx @@ -1,5 +1,4 @@ import { ComposerPrimitive, ThreadPrimitive } from "@assistant-ui/react"; -import { ArrowUp, FileText, Paperclip } from "lucide-react"; import type React from "react"; import type { ReactElement } from "react"; @@ -8,6 +7,7 @@ import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { isTruthy } from "@/shared/lib/truthiness"; import { Button } from "@/shared/ui/button"; +import { ArrowUp, FileText, Paperclip } from "@/shared/ui/icons"; import type { SessionResourceMention } from "../session-resource-mentions"; diff --git a/apps/web/src/features/session-chat/tool-call-card.tsx b/apps/web/src/features/session-chat/tool-call-card.tsx index 9ad30572..411d055a 100644 --- a/apps/web/src/features/session-chat/tool-call-card.tsx +++ b/apps/web/src/features/session-chat/tool-call-card.tsx @@ -1,7 +1,7 @@ -import { ChevronRight, Loader2, ShieldAlert } from "lucide-react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; +import { ChevronRight, Loader2, ShieldAlert } from "@/shared/ui/icons"; import { isTruthy } from "../../shared/lib/truthiness"; export interface ToolCall { diff --git a/apps/web/src/routes/agent/agent-detail.route.tsx b/apps/web/src/routes/agent/agent-detail.route.tsx index 869d8dc6..8901d846 100644 --- a/apps/web/src/routes/agent/agent-detail.route.tsx +++ b/apps/web/src/routes/agent/agent-detail.route.tsx @@ -1,4 +1,3 @@ -import { ArrowLeft, Settings } from "lucide-react"; import { lazy, Suspense, useCallback, useEffect, useMemo, useState } from "react"; import type { ReactElement } from "react"; import { useNavigate, useParams, useSearchParams } from "react-router-dom"; @@ -9,6 +8,7 @@ import { useAuth } from "@/domains/auth/use-auth"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Button } from "@/shared/ui/button"; +import { ArrowLeft, Settings } from "@/shared/ui/icons"; import { isTruthy } from "../../shared/lib/truthiness"; import { canShowAgentDebugMenuItem } from "./agent-debug-menu-policy"; diff --git a/apps/web/src/routes/agent/agent-list.route.tsx b/apps/web/src/routes/agent/agent-list.route.tsx index 5c92bafb..6780b7dd 100644 --- a/apps/web/src/routes/agent/agent-list.route.tsx +++ b/apps/web/src/routes/agent/agent-list.route.tsx @@ -1,4 +1,3 @@ -import { Bot, Plus, Upload } from "lucide-react"; import { useEffect, useMemo, useReducer } from "react"; import { useNavigate, useSearchParams } from "react-router-dom"; @@ -8,6 +7,7 @@ import { useAuth } from "@/domains/auth/use-auth"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; import { EmptyState } from "@/shared/ui/empty-state"; +import { Bot, Plus, Upload } from "@/shared/ui/icons"; import { ListPageContent, ListPageSearch, diff --git a/apps/web/src/routes/agent/components/agent-id-badge.tsx b/apps/web/src/routes/agent/components/agent-id-badge.tsx index 3581a24c..88eaf5a9 100644 --- a/apps/web/src/routes/agent/components/agent-id-badge.tsx +++ b/apps/web/src/routes/agent/components/agent-id-badge.tsx @@ -1,4 +1,3 @@ -import { Check, Copy } from "lucide-react"; import type { ReactElement } from "react"; import { useState } from "react"; @@ -6,6 +5,7 @@ import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { writeClipboardText } from "@/shared/lib/clipboard"; import { Button } from "@/shared/ui/button"; +import { Check, Copy } from "@/shared/ui/icons"; export function AgentIdBadge({ agentId, diff --git a/apps/web/src/routes/agent/components/agent-readiness-blockers-banner.tsx b/apps/web/src/routes/agent/components/agent-readiness-blockers-banner.tsx index 350a4435..695dad82 100644 --- a/apps/web/src/routes/agent/components/agent-readiness-blockers-banner.tsx +++ b/apps/web/src/routes/agent/components/agent-readiness-blockers-banner.tsx @@ -1,5 +1,4 @@ import type { AgentReadiness } from "@mosoo/contracts/agent"; -import { ExternalLink } from "lucide-react"; import type { ReactElement } from "react"; import { Link } from "react-router-dom"; @@ -11,6 +10,7 @@ import { } from "@/domains/vendor-credential/model/provider-readiness-copy"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { ExternalLink } from "@/shared/ui/icons"; function readinessBlockMessages( readiness: AgentReadiness | null, diff --git a/apps/web/src/routes/agent/components/agent-row-actions.tsx b/apps/web/src/routes/agent/components/agent-row-actions.tsx index a437f454..da7f11ca 100644 --- a/apps/web/src/routes/agent/components/agent-row-actions.tsx +++ b/apps/web/src/routes/agent/components/agent-row-actions.tsx @@ -1,5 +1,4 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { Copy, Download, MoreHorizontal, Pencil, Settings, Trash2 } from "lucide-react"; import { useState } from "react"; import type { ReactElement } from "react"; import { useNavigate } from "react-router-dom"; @@ -24,6 +23,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; +import { Copy, Download, MoreHorizontal, Pencil, Settings, Trash2 } from "@/shared/ui/icons"; import type { Agent } from "../agent.types"; diff --git a/apps/web/src/routes/agent/components/agent-session-panel-header.tsx b/apps/web/src/routes/agent/components/agent-session-panel-header.tsx index 01d1ebde..0a0db272 100644 --- a/apps/web/src/routes/agent/components/agent-session-panel-header.tsx +++ b/apps/web/src/routes/agent/components/agent-session-panel-header.tsx @@ -1,10 +1,10 @@ -import { Plus, RotateCcw } from "lucide-react"; import type React from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Badge } from "@/shared/ui/badge"; import { Button } from "@/shared/ui/button"; +import { Plus, RotateCcw } from "@/shared/ui/icons"; import type { SessionControlMode } from "./agent-session-panel-rules"; import { sessionIndicatorClassName } from "./agent-session-panel-status"; diff --git a/apps/web/src/routes/agent/components/agent-session-panel.tsx b/apps/web/src/routes/agent/components/agent-session-panel.tsx index 6700bef2..52340750 100644 --- a/apps/web/src/routes/agent/components/agent-session-panel.tsx +++ b/apps/web/src/routes/agent/components/agent-session-panel.tsx @@ -1,7 +1,6 @@ import { AssistantRuntimeProvider } from "@assistant-ui/react"; import type { AgentReadiness } from "@mosoo/contracts/agent"; import { useQueryClient } from "@tanstack/react-query"; -import { ShieldAlert, X } from "lucide-react"; import { useCallback, useRef } from "react"; import { sessionResourcesQueryKey } from "@/domains/session/api/session-resources"; @@ -21,6 +20,7 @@ import { uploadSessionResource } from "@/features/session-files/session-resource import { toProjectId, toSessionId } from "@/routes/typed-id"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { ShieldAlert, X } from "@/shared/ui/icons"; import { isTruthy } from "../../../shared/lib/truthiness"; import { AgentReadinessBlockersBanner } from "./agent-readiness-blockers-banner"; diff --git a/apps/web/src/routes/agent/components/consume-mode.tsx b/apps/web/src/routes/agent/components/consume-mode.tsx index f4eb296e..1bb71e0c 100644 --- a/apps/web/src/routes/agent/components/consume-mode.tsx +++ b/apps/web/src/routes/agent/components/consume-mode.tsx @@ -1,9 +1,9 @@ -import { ArrowLeft, Settings } from "lucide-react"; import type { ReactElement } from "react"; import { useNavigate } from "react-router-dom"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { ArrowLeft, Settings } from "@/shared/ui/icons"; import type { Agent } from "../agent.types"; import { getRuntimeInfo } from "../runtime-catalog"; diff --git a/apps/web/src/routes/agent/components/cost-tab.tsx b/apps/web/src/routes/agent/components/cost-tab.tsx index adc050ab..d32142ce 100644 --- a/apps/web/src/routes/agent/components/cost-tab.tsx +++ b/apps/web/src/routes/agent/components/cost-tab.tsx @@ -1,5 +1,4 @@ import { useQuery } from "@tanstack/react-query"; -import { BarChart3, Download, ExternalLink } from "lucide-react"; import { useState } from "react"; import type { ReactElement, ReactNode } from "react"; import { Link } from "react-router-dom"; @@ -21,6 +20,7 @@ import type { CostRange, CostRunPurpose } from "@/routes/cost/cost-model"; import { toAgentId, toProjectId } from "@/routes/typed-id"; import { getCurrentLocale, useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { BarChart3, Download, ExternalLink } from "@/shared/ui/icons"; const COST_RANGE_KEYS = { "7d": "cost.range7d", diff --git a/apps/web/src/routes/agent/components/create-agent-launcher.tsx b/apps/web/src/routes/agent/components/create-agent-launcher.tsx index fe0c69c9..9c193a9e 100644 --- a/apps/web/src/routes/agent/components/create-agent-launcher.tsx +++ b/apps/web/src/routes/agent/components/create-agent-launcher.tsx @@ -1,6 +1,5 @@ import type { ProjectId } from "@mosoo/contracts/id"; import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { Loader2 } from "lucide-react"; import { useMemo, useState } from "react"; import type { FormEvent, ReactElement } from "react"; import { useNavigate } from "react-router-dom"; @@ -13,6 +12,7 @@ import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Button } from "@/shared/ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/shared/ui/dialog"; +import { Loader2 } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { Label } from "@/shared/ui/label"; diff --git a/apps/web/src/routes/agent/components/editor/environment-picker.tsx b/apps/web/src/routes/agent/components/editor/environment-picker.tsx index f3841ccb..53f84d0c 100644 --- a/apps/web/src/routes/agent/components/editor/environment-picker.tsx +++ b/apps/web/src/routes/agent/components/editor/environment-picker.tsx @@ -1,6 +1,5 @@ import { Popover } from "@base-ui/react/popover"; import type { EnvironmentSummary } from "@mosoo/contracts/environment"; -import { Box, Check, ExternalLink, Plus, Star } from "lucide-react"; import { useState } from "react"; import type { ReactElement } from "react"; import { Link } from "react-router-dom"; @@ -9,6 +8,7 @@ import { CreateEnvironmentDialog } from "@/domains/environment/components/create import { useProjectEnvironmentsQuery } from "@/domains/environment/query/environment-queries"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { Box, Check, ExternalLink, Plus, Star } from "@/shared/ui/icons"; import { Label } from "@/shared/ui/label"; import { diff --git a/apps/web/src/routes/agent/components/editor/form-sections.tsx b/apps/web/src/routes/agent/components/editor/form-sections.tsx index 1ef06e52..a9eea2f4 100644 --- a/apps/web/src/routes/agent/components/editor/form-sections.tsx +++ b/apps/web/src/routes/agent/components/editor/form-sections.tsx @@ -1,7 +1,6 @@ -import { AlertTriangle } from "lucide-react"; - import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { AlertTriangle } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { Label } from "@/shared/ui/label"; diff --git a/apps/web/src/routes/agent/components/editor/markdown-preview-dialog.tsx b/apps/web/src/routes/agent/components/editor/markdown-preview-dialog.tsx index 3b915d4f..181fd41d 100644 --- a/apps/web/src/routes/agent/components/editor/markdown-preview-dialog.tsx +++ b/apps/web/src/routes/agent/components/editor/markdown-preview-dialog.tsx @@ -1,7 +1,7 @@ -import { FileText } from "lucide-react"; import type { ReactElement, ReactNode } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/shared/ui/dialog"; +import { FileText } from "@/shared/ui/icons"; export function MarkdownPreviewDialog({ badge = null, diff --git a/apps/web/src/routes/agent/components/editor/mcp-bindings-field.tsx b/apps/web/src/routes/agent/components/editor/mcp-bindings-field.tsx index c55e820c..e3a326b4 100644 --- a/apps/web/src/routes/agent/components/editor/mcp-bindings-field.tsx +++ b/apps/web/src/routes/agent/components/editor/mcp-bindings-field.tsx @@ -1,5 +1,4 @@ import type { McpServerWithCredential as PoolServer } from "@mosoo/contracts/mcp"; -import { ExternalLink, Plus, X } from "lucide-react"; import { useMemo, useState } from "react"; import { Link } from "react-router-dom"; @@ -14,6 +13,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; +import { ExternalLink, Plus, X } from "@/shared/ui/icons"; import { Switch } from "@/shared/ui/switch"; import { isTruthy } from "../../../../shared/lib/truthiness"; diff --git a/apps/web/src/routes/agent/components/editor/model-picker-field.tsx b/apps/web/src/routes/agent/components/editor/model-picker-field.tsx index 8558e9e9..4c3a854a 100644 --- a/apps/web/src/routes/agent/components/editor/model-picker-field.tsx +++ b/apps/web/src/routes/agent/components/editor/model-picker-field.tsx @@ -1,5 +1,4 @@ import { useQuery } from "@tanstack/react-query"; -import { ChevronDown } from "lucide-react"; import type { ReactElement } from "react"; import { toProjectId } from "@/routes/typed-id"; @@ -13,6 +12,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; +import { ChevronDown } from "@/shared/ui/icons"; import { Label } from "@/shared/ui/label"; import { listAvailableAgentModels } from "../../../../domains/vendor-credential/api/vendor-credential-client"; diff --git a/apps/web/src/routes/agent/components/editor/model-picker-ui.tsx b/apps/web/src/routes/agent/components/editor/model-picker-ui.tsx index 286d7181..29add96e 100644 --- a/apps/web/src/routes/agent/components/editor/model-picker-ui.tsx +++ b/apps/web/src/routes/agent/components/editor/model-picker-ui.tsx @@ -1,4 +1,3 @@ -import { ExternalLink } from "lucide-react"; import type { ReactElement } from "react"; import { Link } from "react-router-dom"; @@ -10,6 +9,7 @@ import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Badge } from "@/shared/ui/badge"; import { DropdownMenuItem } from "@/shared/ui/dropdown-menu"; +import { ExternalLink } from "@/shared/ui/icons"; import type { ResolvedModelEntry } from "../../../../domains/vendor-credential/api/vendor-credential-client"; diff --git a/apps/web/src/routes/agent/components/editor/runtime-advanced-settings-field.tsx b/apps/web/src/routes/agent/components/editor/runtime-advanced-settings-field.tsx index 47e97312..5d490212 100644 --- a/apps/web/src/routes/agent/components/editor/runtime-advanced-settings-field.tsx +++ b/apps/web/src/routes/agent/components/editor/runtime-advanced-settings-field.tsx @@ -3,12 +3,12 @@ import type { AgentBuiltInToolConfig } from "@mosoo/contracts/agent"; import { normalizeAgentBuiltInTools } from "@mosoo/contracts/agent"; import type { RuntimeAdvancedSettingDefinition } from "@mosoo/runtime-catalog"; import { listRuntimeAdvancedSettings } from "@mosoo/runtime-catalog"; -import { ChevronDown } from "lucide-react"; import { useState } from "react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { ChevronDown } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { Label } from "@/shared/ui/label"; diff --git a/apps/web/src/routes/agent/components/editor/skills-field.tsx b/apps/web/src/routes/agent/components/editor/skills-field.tsx index baf43bfb..e34136ac 100644 --- a/apps/web/src/routes/agent/components/editor/skills-field.tsx +++ b/apps/web/src/routes/agent/components/editor/skills-field.tsx @@ -1,5 +1,4 @@ import type { SkillSummary } from "@mosoo/contracts/skill"; -import { ExternalLink, Plus } from "lucide-react"; import { useState } from "react"; import type { ReactElement } from "react"; import { Link } from "react-router-dom"; @@ -13,6 +12,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; +import { ExternalLink, Plus } from "@/shared/ui/icons"; import { SkillFileCountBadge } from "@/shared/ui/skill-file-count-badge"; import type { SkillInfo } from "../../agent.types"; diff --git a/apps/web/src/routes/agent/components/import-agent-package-dialog.tsx b/apps/web/src/routes/agent/components/import-agent-package-dialog.tsx index 0f9a6efe..d5fc65f6 100644 --- a/apps/web/src/routes/agent/components/import-agent-package-dialog.tsx +++ b/apps/web/src/routes/agent/components/import-agent-package-dialog.tsx @@ -1,6 +1,5 @@ import type { FileId } from "@mosoo/contracts/id"; import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { AlertTriangle, CheckCircle2, FileArchive, Upload } from "lucide-react"; import { useRef, useState } from "react"; import type { ChangeEvent, ReactElement } from "react"; @@ -18,6 +17,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { AlertTriangle, CheckCircle2, FileArchive, Upload } from "@/shared/ui/icons"; import { isTruthy } from "../../../shared/lib/truthiness"; import { PackageResolutionIssueCard } from "./package-resolution-issue-card"; diff --git a/apps/web/src/routes/agent/components/kind-selector.tsx b/apps/web/src/routes/agent/components/kind-selector.tsx index e922e9cd..566e9901 100644 --- a/apps/web/src/routes/agent/components/kind-selector.tsx +++ b/apps/web/src/routes/agent/components/kind-selector.tsx @@ -3,11 +3,20 @@ import { listAgentKindRuntimePolicies, } from "@mosoo/contracts/agent"; import type { AgentKind } from "@mosoo/contracts/agent"; -import { ChevronDown, Bot, Zap, Lock, Sparkles, Layers, AlertTriangle, Target } from "lucide-react"; import { useState } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { + ChevronDown, + Bot, + Zap, + Lock, + Sparkles, + Layers, + AlertTriangle, + Target, +} from "@/shared/ui/icons"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip"; const CARDS = listAgentKindRuntimePolicies(); diff --git a/apps/web/src/routes/agent/components/logs-tab.tsx b/apps/web/src/routes/agent/components/logs-tab.tsx index 1d9e71b9..3f1a0273 100644 --- a/apps/web/src/routes/agent/components/logs-tab.tsx +++ b/apps/web/src/routes/agent/components/logs-tab.tsx @@ -1,6 +1,5 @@ import type { SessionSummary } from "@mosoo/contracts/session"; import { useQuery } from "@tanstack/react-query"; -import { ArrowLeft, ChevronRight } from "lucide-react"; import type { ComponentProps, ReactElement } from "react"; import { useCallback } from "react"; import { useSearchParams } from "react-router-dom"; @@ -15,6 +14,7 @@ import { getCurrentLocale, useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Badge } from "@/shared/ui/badge"; import { Button } from "@/shared/ui/button"; +import { ArrowLeft, ChevronRight } from "@/shared/ui/icons"; import { ScrollArea } from "@/shared/ui/scroll-area"; import { SessionEventFeed } from "@/shared/ui/session-events"; diff --git a/apps/web/src/routes/agent/components/session-diagnostics-panel.tsx b/apps/web/src/routes/agent/components/session-diagnostics-panel.tsx index 1ca9e47e..cfbd8592 100644 --- a/apps/web/src/routes/agent/components/session-diagnostics-panel.tsx +++ b/apps/web/src/routes/agent/components/session-diagnostics-panel.tsx @@ -1,11 +1,11 @@ import type { SessionSummary } from "@mosoo/contracts/session"; -import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from "lucide-react"; import type { ReactElement } from "react"; import { useState } from "react"; import type { AgentSessionDiagnosticsQuery } from "@/gql/graphql"; import { useTranslation } from "@/shared/i18n"; import { Badge } from "@/shared/ui/badge"; +import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp } from "@/shared/ui/icons"; import { ScrollArea } from "@/shared/ui/scroll-area"; type AgentSessionDiagnostics = AgentSessionDiagnosticsQuery["agentSessionDiagnostics"]; diff --git a/apps/web/src/routes/agent/components/settings-dialog-danger-zone.tsx b/apps/web/src/routes/agent/components/settings-dialog-danger-zone.tsx index b7329bfb..8198149f 100644 --- a/apps/web/src/routes/agent/components/settings-dialog-danger-zone.tsx +++ b/apps/web/src/routes/agent/components/settings-dialog-danger-zone.tsx @@ -1,6 +1,5 @@ import { agentKindSupportsResetState } from "@mosoo/contracts/agent"; import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { LockKeyhole, PowerOff, RotateCcw, Trash2, XCircle } from "lucide-react"; import { useState } from "react"; import { resetAgentState, unpublishAgent } from "@/domains/agent/api/agent-client"; @@ -15,6 +14,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { LockKeyhole, PowerOff, RotateCcw, Trash2, XCircle } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import type { Agent } from "../agent.types"; diff --git a/apps/web/src/routes/agent/components/settings-dialog-package-actions.tsx b/apps/web/src/routes/agent/components/settings-dialog-package-actions.tsx index 605df8c5..297e4552 100644 --- a/apps/web/src/routes/agent/components/settings-dialog-package-actions.tsx +++ b/apps/web/src/routes/agent/components/settings-dialog-package-actions.tsx @@ -1,5 +1,4 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { Copy, Download, Upload } from "lucide-react"; import type { ReactElement } from "react"; import { useState } from "react"; import { useNavigate } from "react-router-dom"; @@ -10,6 +9,7 @@ import { createFileDownload } from "@/domains/file/api/file-download-client"; import { toAgentId, toProjectId } from "@/routes/typed-id"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { Copy, Download, Upload } from "@/shared/ui/icons"; import type { Agent } from "../agent.types"; import { ImportAgentPackageDialog } from "./import-agent-package-dialog"; diff --git a/apps/web/src/routes/agent/components/terminal-mode.tsx b/apps/web/src/routes/agent/components/terminal-mode.tsx index 357f7fa5..ba896359 100644 --- a/apps/web/src/routes/agent/components/terminal-mode.tsx +++ b/apps/web/src/routes/agent/components/terminal-mode.tsx @@ -3,14 +3,15 @@ import type { ConnectionState } from "@cloudflare/sandbox/xterm"; import { getAgentKindRuntimePolicy } from "@mosoo/contracts/agent"; import { FitAddon } from "@xterm/addon-fit"; import { Terminal as XTermTerminal } from "@xterm/xterm"; -import { Circle, RefreshCw, Terminal as TerminalIcon, TriangleAlert } from "lucide-react"; import { useCallback, useEffect, useRef, useSyncExternalStore } from "react"; import type { ReactElement, RefObject } from "react"; -import "@xterm/xterm/css/xterm.css"; import { useTranslation } from "@/shared/i18n"; + +import "@xterm/xterm/css/xterm.css"; import { cn } from "@/shared/lib/class-names"; import { Button } from "@/shared/ui/button"; +import { Circle, RefreshCw, Terminal as TerminalIcon, TriangleAlert } from "@/shared/ui/icons"; import type { Agent } from "../agent.types"; import { installTerminalReconnectClearGuard } from "../terminal-reconnect-buffer"; diff --git a/apps/web/src/routes/agent/components/versions-tab.tsx b/apps/web/src/routes/agent/components/versions-tab.tsx index e5fc7ae3..5bf40eeb 100644 --- a/apps/web/src/routes/agent/components/versions-tab.tsx +++ b/apps/web/src/routes/agent/components/versions-tab.tsx @@ -1,8 +1,8 @@ -import { GitBranch } from "lucide-react"; import type { ReactElement } from "react"; import { useFormatDate, useTranslation } from "@/shared/i18n"; import { Badge } from "@/shared/ui/badge"; +import { GitBranch } from "@/shared/ui/icons"; import { ScrollArea } from "@/shared/ui/scroll-area"; import type { Agent } from "../agent.types"; diff --git a/apps/web/src/routes/agent/lifecycle/api-access-panel.tsx b/apps/web/src/routes/agent/lifecycle/api-access-panel.tsx index dca5a017..49c0752a 100644 --- a/apps/web/src/routes/agent/lifecycle/api-access-panel.tsx +++ b/apps/web/src/routes/agent/lifecycle/api-access-panel.tsx @@ -1,4 +1,3 @@ -import { BookOpen, Check, Code, Copy, KeyRound } from "lucide-react"; import { useMemo, useState } from "react"; import type { ReactElement, ReactNode } from "react"; import { Link } from "react-router-dom"; @@ -7,6 +6,7 @@ import { useTranslation } from "@/shared/i18n"; import { writeClipboardText } from "@/shared/lib/clipboard"; import { Button } from "@/shared/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/shared/ui/dialog"; +import { BookOpen, Check, Code, Copy, KeyRound } from "@/shared/ui/icons"; import type { Agent } from "../agent.types"; import { buildAgentDistribution } from "./distribution-info"; diff --git a/apps/web/src/routes/agent/lifecycle/kind-fork-dialog.tsx b/apps/web/src/routes/agent/lifecycle/kind-fork-dialog.tsx index b8a9efdb..fdf4ae8a 100644 --- a/apps/web/src/routes/agent/lifecycle/kind-fork-dialog.tsx +++ b/apps/web/src/routes/agent/lifecycle/kind-fork-dialog.tsx @@ -1,5 +1,3 @@ -import { ArrowRight, Bot, Check, Info, Plus, X, Zap } from "lucide-react"; - import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; import { @@ -10,6 +8,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { ArrowRight, Bot, Check, Info, Plus, X, Zap } from "@/shared/ui/icons"; import type { AgentKind } from "../agent.types"; diff --git a/apps/web/src/routes/agent/lifecycle/live-config-action-dialog.tsx b/apps/web/src/routes/agent/lifecycle/live-config-action-dialog.tsx index 30cd176d..f433b01c 100644 --- a/apps/web/src/routes/agent/lifecycle/live-config-action-dialog.tsx +++ b/apps/web/src/routes/agent/lifecycle/live-config-action-dialog.tsx @@ -1,5 +1,4 @@ import type { AgentConfigChangeAction } from "@mosoo/contracts/agent-config-change-plan"; -import { AlertTriangle, Lock, ShieldCheck } from "lucide-react"; import { useState } from "react"; import { useTranslation } from "@/shared/i18n"; @@ -13,6 +12,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { AlertTriangle, Lock, ShieldCheck } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; /** diff --git a/apps/web/src/routes/agent/lifecycle/pending-changes-banner.tsx b/apps/web/src/routes/agent/lifecycle/pending-changes-banner.tsx index 9808756c..ecaa0c89 100644 --- a/apps/web/src/routes/agent/lifecycle/pending-changes-banner.tsx +++ b/apps/web/src/routes/agent/lifecycle/pending-changes-banner.tsx @@ -1,9 +1,9 @@ -import { ShieldCheck, Undo2 } from "lucide-react"; import { useState } from "react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { ShieldCheck, Undo2 } from "@/shared/ui/icons"; import type { Agent } from "../agent.types"; import { isAutoSaveEligible } from "../components/editor/use-auto-save"; diff --git a/apps/web/src/routes/agent/lifecycle/publish-menu.tsx b/apps/web/src/routes/agent/lifecycle/publish-menu.tsx index df3fa112..b0d9953c 100644 --- a/apps/web/src/routes/agent/lifecycle/publish-menu.tsx +++ b/apps/web/src/routes/agent/lifecycle/publish-menu.tsx @@ -1,4 +1,3 @@ -import { Check, ChevronDown, Code, Copy, Inbox, Upload } from "lucide-react"; import type { ReactElement } from "react"; import { useMemo, useState } from "react"; @@ -13,6 +12,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; +import { Check, ChevronDown, Code, Copy, Inbox, Upload } from "@/shared/ui/icons"; import type { Agent } from "../agent.types"; import { buildAgentDistribution, buildAgentInstructionPrompt } from "./distribution-info"; diff --git a/apps/web/src/routes/agent/lifecycle/publish-success-modal.tsx b/apps/web/src/routes/agent/lifecycle/publish-success-modal.tsx index dd03d46c..dc874de6 100644 --- a/apps/web/src/routes/agent/lifecycle/publish-success-modal.tsx +++ b/apps/web/src/routes/agent/lifecycle/publish-success-modal.tsx @@ -1,4 +1,3 @@ -import { ArrowRight, Check, Globe } from "lucide-react"; import { useMemo } from "react"; import { useTranslation } from "@/shared/i18n"; @@ -10,6 +9,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { ArrowRight, Check, Globe } from "@/shared/ui/icons"; import { Separator } from "@/shared/ui/separator"; import type { Agent } from "../agent.types"; diff --git a/apps/web/src/routes/cli-auth/cli-auth.route.tsx b/apps/web/src/routes/cli-auth/cli-auth.route.tsx index 7e549a4a..e0c51991 100644 --- a/apps/web/src/routes/cli-auth/cli-auth.route.tsx +++ b/apps/web/src/routes/cli-auth/cli-auth.route.tsx @@ -1,10 +1,10 @@ -import { AlertCircle, CheckCircle2, KeyRound, Loader2 } from "lucide-react"; import { useState } from "react"; import { useSearchParams } from "react-router-dom"; import { confirmCliOAuthDeviceFlow } from "@/domains/auth/api/cli-oauth-client"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { AlertCircle, CheckCircle2, KeyRound, Loader2 } from "@/shared/ui/icons"; export function CliAuthPage() { const { t } = useTranslation(); diff --git a/apps/web/src/routes/cost/cost-agents-panel.tsx b/apps/web/src/routes/cost/cost-agents-panel.tsx index d1f7193d..61d6ab6f 100644 --- a/apps/web/src/routes/cost/cost-agents-panel.tsx +++ b/apps/web/src/routes/cost/cost-agents-panel.tsx @@ -1,8 +1,8 @@ -import { ExternalLink } from "lucide-react"; import { Link } from "react-router-dom"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { ExternalLink } from "@/shared/ui/icons"; import { agentCostChange, diff --git a/apps/web/src/routes/cost/cost-page-header.tsx b/apps/web/src/routes/cost/cost-page-header.tsx index ae872733..667f4f43 100644 --- a/apps/web/src/routes/cost/cost-page-header.tsx +++ b/apps/web/src/routes/cost/cost-page-header.tsx @@ -1,8 +1,7 @@ -import { Download } from "lucide-react"; - import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Button } from "@/shared/ui/button"; +import { Download } from "@/shared/ui/icons"; import { downloadCsv } from "./cost-csv"; import { diff --git a/apps/web/src/routes/cost/cost.route.tsx b/apps/web/src/routes/cost/cost.route.tsx index 2e51a371..c3cb96b6 100644 --- a/apps/web/src/routes/cost/cost.route.tsx +++ b/apps/web/src/routes/cost/cost.route.tsx @@ -1,11 +1,11 @@ import { useQuery } from "@tanstack/react-query"; -import { BarChart3 } from "lucide-react"; import { useState } from "react"; import { fetchProjectCost } from "@/domains/cost/api/cost-client"; import type { CostRunPurpose } from "@/domains/cost/api/cost-client"; import { toProjectId } from "@/routes/typed-id"; import { useTranslation } from "@/shared/i18n"; +import { BarChart3 } from "@/shared/ui/icons"; import { useAppSession } from "../../app/session-provider"; import { CostAgentsPanel } from "./cost-agents-panel"; diff --git a/apps/web/src/routes/environments/environment-badges.tsx b/apps/web/src/routes/environments/environment-badges.tsx index d7524937..3e85c1cd 100644 --- a/apps/web/src/routes/environments/environment-badges.tsx +++ b/apps/web/src/routes/environments/environment-badges.tsx @@ -1,7 +1,6 @@ -import { Star } from "lucide-react"; - import { useTranslation } from "@/shared/i18n"; import { Badge } from "@/shared/ui/badge"; +import { Star } from "@/shared/ui/icons"; export function EnvironmentBadges({ environment, diff --git a/apps/web/src/routes/environments/environment-detail-page.tsx b/apps/web/src/routes/environments/environment-detail-page.tsx index a3acdb6e..9b790924 100644 --- a/apps/web/src/routes/environments/environment-detail-page.tsx +++ b/apps/web/src/routes/environments/environment-detail-page.tsx @@ -1,5 +1,4 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { Lock, Star } from "lucide-react"; import { useMemo, useState } from "react"; import { Link } from "react-router-dom"; @@ -22,6 +21,7 @@ import { import { toEnvironmentId, toProjectId } from "@/routes/typed-id"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { Lock, Star } from "@/shared/ui/icons"; import { isTruthy } from "../../shared/lib/truthiness"; import { EnvironmentBadges } from "./environment-badges"; diff --git a/apps/web/src/routes/environments/environment-list-table.tsx b/apps/web/src/routes/environments/environment-list-table.tsx index 9ca798c4..183f1ad8 100644 --- a/apps/web/src/routes/environments/environment-list-table.tsx +++ b/apps/web/src/routes/environments/environment-list-table.tsx @@ -1,5 +1,4 @@ import type { EnvironmentSummary } from "@mosoo/contracts/environment"; -import { GitFork, MoreHorizontal, Trash2 } from "lucide-react"; import { useState } from "react"; import type { ReactElement } from "react"; import { Link } from "react-router-dom"; @@ -22,6 +21,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; +import { GitFork, MoreHorizontal, Trash2 } from "@/shared/ui/icons"; import { EnvironmentBadges } from "./environment-badges"; diff --git a/apps/web/src/routes/environments/environments-list-page.tsx b/apps/web/src/routes/environments/environments-list-page.tsx index 6916a3dc..07439cc7 100644 --- a/apps/web/src/routes/environments/environments-list-page.tsx +++ b/apps/web/src/routes/environments/environments-list-page.tsx @@ -1,5 +1,4 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { Box, Plus } from "lucide-react"; import { useMemo, useState } from "react"; import { useAppSession } from "@/app/session-provider"; @@ -17,6 +16,7 @@ import { toEnvironmentId, toProjectId } from "@/routes/typed-id"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; import { EmptyState } from "@/shared/ui/empty-state"; +import { Box, Plus } from "@/shared/ui/icons"; import { ListPageContent, ListPageSearch, ListPageToolbar } from "@/shared/ui/list-page"; import { PageHeader } from "@/shared/ui/page-header"; diff --git a/apps/web/src/routes/files/file-preview-dialog.tsx b/apps/web/src/routes/files/file-preview-dialog.tsx index 29d1ae72..a9eaa35c 100644 --- a/apps/web/src/routes/files/file-preview-dialog.tsx +++ b/apps/web/src/routes/files/file-preview-dialog.tsx @@ -1,4 +1,3 @@ -import { Download } from "lucide-react"; import type { ReactElement } from "react"; import { createFileDownload } from "@/domains/file/api/file-download-client"; @@ -13,6 +12,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { Download } from "@/shared/ui/icons"; interface FilePreviewDialogProps { file: ListedFileEntry; diff --git a/apps/web/src/routes/files/files.route.tsx b/apps/web/src/routes/files/files.route.tsx index e630db1b..6be8e867 100644 --- a/apps/web/src/routes/files/files.route.tsx +++ b/apps/web/src/routes/files/files.route.tsx @@ -1,5 +1,4 @@ import { useQuery } from "@tanstack/react-query"; -import { Download, FileStack, RefreshCw } from "lucide-react"; import type { ReactElement } from "react"; import { useMemo, useState } from "react"; @@ -15,6 +14,7 @@ import { cn } from "@/shared/lib/class-names"; import { Badge } from "@/shared/ui/badge"; import { Button } from "@/shared/ui/button"; import { EmptyState } from "@/shared/ui/empty-state"; +import { Download, FileStack, RefreshCw } from "@/shared/ui/icons"; import { ListPageContent, ListPageSearch, diff --git a/apps/web/src/routes/files/thread-filter.tsx b/apps/web/src/routes/files/thread-filter.tsx index 4e058e76..b1ec33b5 100644 --- a/apps/web/src/routes/files/thread-filter.tsx +++ b/apps/web/src/routes/files/thread-filter.tsx @@ -1,4 +1,3 @@ -import { Check, ChevronDown, Copy } from "lucide-react"; import type { MouseEvent, ReactElement } from "react"; import { useState } from "react"; @@ -11,6 +10,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; +import { Check, ChevronDown, Copy } from "@/shared/ui/icons"; import type { FilesAgentOption, FilesSessionOption } from "./files-list-model"; diff --git a/apps/web/src/routes/integrations/mcp/add-mcp-dialog.tsx b/apps/web/src/routes/integrations/mcp/add-mcp-dialog.tsx index 7ade9938..bdd29a05 100644 --- a/apps/web/src/routes/integrations/mcp/add-mcp-dialog.tsx +++ b/apps/web/src/routes/integrations/mcp/add-mcp-dialog.tsx @@ -1,4 +1,3 @@ -import { ChevronDown } from "lucide-react"; import { useReducer } from "react"; import { useTranslation } from "@/shared/i18n"; @@ -12,6 +11,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { ChevronDown } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { Label } from "@/shared/ui/label"; import { Textarea } from "@/shared/ui/textarea"; diff --git a/apps/web/src/routes/integrations/mcp/mcp-list-item.tsx b/apps/web/src/routes/integrations/mcp/mcp-list-item.tsx index 57d246ae..49bac903 100644 --- a/apps/web/src/routes/integrations/mcp/mcp-list-item.tsx +++ b/apps/web/src/routes/integrations/mcp/mcp-list-item.tsx @@ -1,5 +1,3 @@ -import { MoreHorizontal, Pencil, Power, PowerOff, Trash2, Unplug } from "lucide-react"; - import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Button } from "@/shared/ui/button"; @@ -10,6 +8,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; +import { MoreHorizontal, Pencil, Power, PowerOff, Trash2, Unplug } from "@/shared/ui/icons"; import { authTypeLabel, statusText } from "./format"; import { IconAvatar } from "./icon-avatar"; diff --git a/apps/web/src/routes/integrations/mcp/mcp-tab.tsx b/apps/web/src/routes/integrations/mcp/mcp-tab.tsx index 2981224c..b8f7c559 100644 --- a/apps/web/src/routes/integrations/mcp/mcp-tab.tsx +++ b/apps/web/src/routes/integrations/mcp/mcp-tab.tsx @@ -1,9 +1,9 @@ -import { Plus, Search, Zap } from "lucide-react"; import { Fragment, useMemo, useReducer } from "react"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; import { EmptyState } from "@/shared/ui/empty-state"; +import { Plus, Search, Zap } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { PageHeader } from "@/shared/ui/page-header"; diff --git a/apps/web/src/routes/integrations/mcp/oauth-connect-dialog.tsx b/apps/web/src/routes/integrations/mcp/oauth-connect-dialog.tsx index e48c1319..19c69db0 100644 --- a/apps/web/src/routes/integrations/mcp/oauth-connect-dialog.tsx +++ b/apps/web/src/routes/integrations/mcp/oauth-connect-dialog.tsx @@ -1,5 +1,4 @@ import type { McpOAuthFlowState, StartMcpOAuthPayload } from "@mosoo/contracts/mcp"; -import { Check, ExternalLink, Loader2 } from "lucide-react"; import { useCallback, useEffect, useRef, useState } from "react"; import { useTranslation } from "@/shared/i18n"; @@ -12,6 +11,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { Check, ExternalLink, Loader2 } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { Label } from "@/shared/ui/label"; diff --git a/apps/web/src/routes/integrations/skills/skills-sh-catalog.tsx b/apps/web/src/routes/integrations/skills/skills-sh-catalog.tsx index 478c13ba..f56a0b8e 100644 --- a/apps/web/src/routes/integrations/skills/skills-sh-catalog.tsx +++ b/apps/web/src/routes/integrations/skills/skills-sh-catalog.tsx @@ -1,15 +1,4 @@ import type { SkillsShCatalogSkill, SkillsShCatalogView } from "@mosoo/contracts/skill"; -import { - ArrowLeft, - ArrowRight, - Check, - ExternalLink, - Flame, - Info, - RefreshCw, - TrendingUp, -} from "lucide-react"; -import type { LucideIcon } from "lucide-react"; import { useEffect, useMemo, useReducer, useState } from "react"; import { useSkillsShCatalogQuery } from "@/domains/skill/query/skill-queries"; @@ -26,6 +15,17 @@ import { DialogTitle, } from "@/shared/ui/dialog"; import { EmptyState } from "@/shared/ui/empty-state"; +import { + ArrowLeft, + ArrowRight, + Check, + ExternalLink, + Flame, + Info, + RefreshCw, + TrendingUp, +} from "@/shared/ui/icons"; +import type { AppIcon } from "@/shared/ui/icons"; import { Switch } from "@/shared/ui/switch"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip"; @@ -502,7 +502,7 @@ function CatalogViewButton({ onClick, }: { active: boolean; - icon: LucideIcon; + icon: AppIcon; label: string; onClick: () => void; }) { diff --git a/apps/web/src/routes/integrations/skills/skills-tab.tsx b/apps/web/src/routes/integrations/skills/skills-tab.tsx index 7088ef17..2e855503 100644 --- a/apps/web/src/routes/integrations/skills/skills-tab.tsx +++ b/apps/web/src/routes/integrations/skills/skills-tab.tsx @@ -1,11 +1,11 @@ -import { Compass, Library, Search, Sparkles, Upload } from "lucide-react"; -import type { LucideIcon } from "lucide-react"; import { useMemo, useState } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Button } from "@/shared/ui/button"; import { EmptyState } from "@/shared/ui/empty-state"; +import { Compass, Library, Search, Sparkles, Upload } from "@/shared/ui/icons"; +import type { AppIcon } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { PageHeader } from "@/shared/ui/page-header"; @@ -206,7 +206,7 @@ function SkillsModeButton({ onClick, }: { active: boolean; - icon: LucideIcon; + icon: AppIcon; label: string; onClick: () => void; }) { diff --git a/apps/web/src/routes/login/auth-card.tsx b/apps/web/src/routes/login/auth-card.tsx index 1a5f860a..5e7a13fb 100644 --- a/apps/web/src/routes/login/auth-card.tsx +++ b/apps/web/src/routes/login/auth-card.tsx @@ -1,8 +1,8 @@ -import { Loader2 } from "lucide-react"; import type { CSSProperties, ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { Loader2 } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { Separator } from "@/shared/ui/separator"; diff --git a/apps/web/src/routes/login/topbar.tsx b/apps/web/src/routes/login/topbar.tsx index 256758db..5851bfb0 100644 --- a/apps/web/src/routes/login/topbar.tsx +++ b/apps/web/src/routes/login/topbar.tsx @@ -1,9 +1,9 @@ import { MOSOO_MARKETING_ORIGIN } from "@mosoo/contracts/origin"; -import { ArrowLeft } from "lucide-react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { LocaleSwitcher } from "@/shared/i18n/locale-switcher"; +import { ArrowLeft } from "@/shared/ui/icons"; function Brand(): ReactElement { return ( diff --git a/apps/web/src/routes/onboarding/onboarding.route.tsx b/apps/web/src/routes/onboarding/onboarding.route.tsx index adde030e..46c104ec 100644 --- a/apps/web/src/routes/onboarding/onboarding.route.tsx +++ b/apps/web/src/routes/onboarding/onboarding.route.tsx @@ -1,9 +1,9 @@ import { sleepPromise } from "@mosoo/effects"; -import { Loader2 } from "lucide-react"; import { useCallback, useEffect, useReducer } from "react"; import { useNavigate } from "react-router-dom"; import { useTranslation } from "@/shared/i18n"; +import { Loader2 } from "@/shared/ui/icons"; import { captureProductEvent, PRODUCT_ANALYTICS_EVENTS } from "../../analytics/product-analytics"; import { useAppSession } from "../../app/session-provider"; diff --git a/apps/web/src/routes/org/org-settings.route.tsx b/apps/web/src/routes/org/org-settings.route.tsx index 993a7d2a..9f06fa72 100644 --- a/apps/web/src/routes/org/org-settings.route.tsx +++ b/apps/web/src/routes/org/org-settings.route.tsx @@ -1,4 +1,3 @@ -import { Check, Loader2 } from "lucide-react"; import { useEffect, useState } from "react"; import { useAppSession } from "@/app/session-provider"; @@ -7,6 +6,7 @@ import { useTranslation } from "@/shared/i18n"; import { isTruthy } from "@/shared/lib/truthiness"; import { Button } from "@/shared/ui/button"; import { CommandBlock } from "@/shared/ui/command-block"; +import { Check, Loader2 } from "@/shared/ui/icons"; // Org-layer General settings — the account/billing shell's identity. export function OrgSettingsPage() { diff --git a/apps/web/src/routes/project-overview/onboarding-steps.tsx b/apps/web/src/routes/project-overview/onboarding-steps.tsx index c0172ac7..a90d0517 100644 --- a/apps/web/src/routes/project-overview/onboarding-steps.tsx +++ b/apps/web/src/routes/project-overview/onboarding-steps.tsx @@ -1,4 +1,3 @@ -import { ArrowUpRight, Check, ChevronRight } from "lucide-react"; import type { ReactElement } from "react"; import { useState } from "react"; import { Link } from "react-router-dom"; @@ -10,6 +9,7 @@ import { writeClipboardText } from "@/shared/lib/clipboard"; import { Badge } from "@/shared/ui/badge"; import { RuntimeIcon } from "@/shared/ui/brand-icons"; import { CopyCheckIcon } from "@/shared/ui/copy-check-icon"; +import { ArrowUpRight, Check, ChevronRight } from "@/shared/ui/icons"; import { buildOnboardingSetupPrompt } from "./onboarding-setup-prompt"; import { useOnboardingProgress } from "./use-onboarding-progress"; diff --git a/apps/web/src/routes/project-overview/project-overview-install.tsx b/apps/web/src/routes/project-overview/project-overview-install.tsx index 6e8af0b4..77df4caa 100644 --- a/apps/web/src/routes/project-overview/project-overview-install.tsx +++ b/apps/web/src/routes/project-overview/project-overview-install.tsx @@ -1,4 +1,3 @@ -import { MousePointerClick, SquareTerminal } from "lucide-react"; import type { ReactElement } from "react"; import { useState } from "react"; @@ -7,6 +6,7 @@ import { cn } from "@/shared/lib/class-names"; import { writeClipboardText } from "@/shared/lib/clipboard"; import { Button } from "@/shared/ui/button"; import { CopyCheckIcon } from "@/shared/ui/copy-check-icon"; +import { MousePointerClick, SquareTerminal } from "@/shared/ui/icons"; import { INSTALL_COMMAND } from "./onboarding-setup-prompt"; import { DocsAction, OnboardingActions, OnboardingSteps } from "./onboarding-steps"; diff --git a/apps/web/src/routes/project-overview/project-overview.route.tsx b/apps/web/src/routes/project-overview/project-overview.route.tsx index 8815faab..30be2318 100644 --- a/apps/web/src/routes/project-overview/project-overview.route.tsx +++ b/apps/web/src/routes/project-overview/project-overview.route.tsx @@ -1,8 +1,8 @@ -import { Bot, Box, KeyRound } from "lucide-react"; import { Link } from "react-router-dom"; import { useAppSession } from "@/app/session-provider"; import { useTranslation } from "@/shared/i18n"; +import { Bot, Box, KeyRound } from "@/shared/ui/icons"; import { ProjectIdBadge } from "@/shared/ui/project-id-badge"; import { ProjectOverviewInstallGuide } from "./project-overview-install"; diff --git a/apps/web/src/routes/project-settings/general-tab.tsx b/apps/web/src/routes/project-settings/general-tab.tsx index a0e6dc94..a065ee58 100644 --- a/apps/web/src/routes/project-settings/general-tab.tsx +++ b/apps/web/src/routes/project-settings/general-tab.tsx @@ -1,6 +1,5 @@ import type { ProjectSummary } from "@mosoo/contracts/project"; import { useQueryClient } from "@tanstack/react-query"; -import { Check, Loader2 } from "lucide-react"; import { useState } from "react"; import { useAppSession } from "@/app/session-provider"; @@ -11,6 +10,7 @@ import { useTranslation } from "@/shared/i18n"; import { isTruthy } from "@/shared/lib/truthiness"; import { Button } from "@/shared/ui/button"; import { CommandBlock } from "@/shared/ui/command-block"; +import { Check, Loader2 } from "@/shared/ui/icons"; import { SettingsTabBody, SettingsTabHeader } from "../settings/settings-tab-layout"; diff --git a/apps/web/src/routes/project-settings/project-settings-nav.tsx b/apps/web/src/routes/project-settings/project-settings-nav.tsx index 27cac896..30bf8659 100644 --- a/apps/web/src/routes/project-settings/project-settings-nav.tsx +++ b/apps/web/src/routes/project-settings/project-settings-nav.tsx @@ -1,12 +1,12 @@ -import { BarChart3, Box } from "lucide-react"; -import type { LucideIcon } from "lucide-react"; import { NavLink } from "react-router-dom"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { BarChart3, Box } from "@/shared/ui/icons"; +import type { AppIcon } from "@/shared/ui/icons"; interface ProjectSettingsNavItem { - icon: LucideIcon; + icon: AppIcon; labelKey: string; path: string; } diff --git a/apps/web/src/routes/projects/projects-list.route.tsx b/apps/web/src/routes/projects/projects-list.route.tsx index e7c67e60..8d8e841a 100644 --- a/apps/web/src/routes/projects/projects-list.route.tsx +++ b/apps/web/src/routes/projects/projects-list.route.tsx @@ -1,6 +1,5 @@ import type { ProjectSummary } from "@mosoo/contracts/project"; import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { ChevronRight, Plus, Search } from "lucide-react"; import { useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; @@ -11,6 +10,7 @@ import { projectKeys } from "@/domains/project/query/project-queries"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/shared/ui/dialog"; +import { ChevronRight, Plus, Search } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { ProjectIdBadge } from "@/shared/ui/project-id-badge"; diff --git a/apps/web/src/routes/providers/provider-test-status.tsx b/apps/web/src/routes/providers/provider-test-status.tsx index d1a29828..d92ea4a9 100644 --- a/apps/web/src/routes/providers/provider-test-status.tsx +++ b/apps/web/src/routes/providers/provider-test-status.tsx @@ -1,7 +1,7 @@ -import { Check } from "lucide-react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; +import { Check } from "@/shared/ui/icons"; type TestConnectionState = "failure" | "idle" | "running" | "success"; diff --git a/apps/web/src/routes/providers/providers-tab.tsx b/apps/web/src/routes/providers/providers-tab.tsx index 3ba08c24..f7f5fa02 100644 --- a/apps/web/src/routes/providers/providers-tab.tsx +++ b/apps/web/src/routes/providers/providers-tab.tsx @@ -1,7 +1,6 @@ import { PUBLIC_VENDORS, getVendor } from "@mosoo/runtime-catalog"; import type { RuntimeCatalogVendor } from "@mosoo/runtime-catalog"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { Pencil, Plus, Trash2 } from "lucide-react"; import type { ReactElement } from "react"; import { useId, useMemo, useState } from "react"; @@ -29,6 +28,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { Pencil, Plus, Trash2 } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { PageHeader } from "@/shared/ui/page-header"; diff --git a/apps/web/src/routes/settings/access-tokens-tab.tsx b/apps/web/src/routes/settings/access-tokens-tab.tsx index 02e95a83..404451d7 100644 --- a/apps/web/src/routes/settings/access-tokens-tab.tsx +++ b/apps/web/src/routes/settings/access-tokens-tab.tsx @@ -1,6 +1,5 @@ import type { PersonalAccessTokenSummary } from "@mosoo/contracts/auth"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { ExternalLink, KeyRound, Loader2, Plus, Trash2 } from "lucide-react"; import { useReducer } from "react"; import { @@ -12,6 +11,7 @@ import { MOSOO_API_REFERENCE_URL } from "@/shared/config/external-links"; import { getCurrentLocale, useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; import { CopyCheckIcon } from "@/shared/ui/copy-check-icon"; +import { ExternalLink, KeyRound, Loader2, Plus, Trash2 } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; import { isTruthy } from "../../shared/lib/truthiness"; diff --git a/apps/web/src/routes/settings/profile-tab.tsx b/apps/web/src/routes/settings/profile-tab.tsx index c58035ca..16fa390f 100644 --- a/apps/web/src/routes/settings/profile-tab.tsx +++ b/apps/web/src/routes/settings/profile-tab.tsx @@ -1,8 +1,8 @@ -import { Check, Loader2, Upload } from "lucide-react"; import { useEffect, useReducer, useRef } from "react"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { Check, Loader2, Upload } from "@/shared/ui/icons"; import { useAppSession } from "../../app/session-provider"; import { uploadAccountAvatar } from "../../domains/file/api/account-avatar-client"; diff --git a/apps/web/src/routes/settings/settings-nav.tsx b/apps/web/src/routes/settings/settings-nav.tsx index 8cdb2b6c..b8b7def4 100644 --- a/apps/web/src/routes/settings/settings-nav.tsx +++ b/apps/web/src/routes/settings/settings-nav.tsx @@ -1,12 +1,12 @@ -import type { LucideIcon } from "lucide-react"; -import { KeyRound, User } from "lucide-react"; import { NavLink } from "react-router-dom"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import type { AppIcon } from "@/shared/ui/icons"; +import { KeyRound, User } from "@/shared/ui/icons"; interface SettingsNavItem { - icon: LucideIcon; + icon: AppIcon; labelKey: string; path: string; } diff --git a/apps/web/src/routes/threads/compose/new-dialog.tsx b/apps/web/src/routes/threads/compose/new-dialog.tsx index 1168a036..11f365bc 100644 --- a/apps/web/src/routes/threads/compose/new-dialog.tsx +++ b/apps/web/src/routes/threads/compose/new-dialog.tsx @@ -1,17 +1,4 @@ import type { AgentSummary } from "@mosoo/contracts/agent"; -import { - ArrowUpRight, - Bot, - Check, - ChevronDown, - FileText, - Maximize2, - Minimize2, - Paperclip, - Plus, - Send, - X, -} from "lucide-react"; import { useMemo, useReducer, useRef } from "react"; import type { ReactElement } from "react"; import { useNavigate } from "react-router-dom"; @@ -33,6 +20,19 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; +import { + ArrowUpRight, + Bot, + Check, + ChevronDown, + FileText, + Maximize2, + Minimize2, + Paperclip, + Plus, + Send, + X, +} from "@/shared/ui/icons"; import { Textarea } from "@/shared/ui/textarea"; import { AgentAvatar } from "../agent-avatar"; diff --git a/apps/web/src/routes/threads/controller.tsx b/apps/web/src/routes/threads/controller.tsx index 9a3e07d3..c3a6939f 100644 --- a/apps/web/src/routes/threads/controller.tsx +++ b/apps/web/src/routes/threads/controller.tsx @@ -1,4 +1,3 @@ -import { Inbox, Plus } from "lucide-react"; import { useCallback, useMemo } from "react"; import type { ReactElement } from "react"; @@ -7,6 +6,7 @@ import type { ListedFileEntry } from "@/domains/file/api/files"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; import { EmptyState } from "@/shared/ui/empty-state"; +import { Inbox, Plus } from "@/shared/ui/icons"; import { ListPageContent, ListPageToolbar, ListPageToolbarSpacer } from "@/shared/ui/list-page"; import { PageHeader } from "@/shared/ui/page-header"; diff --git a/apps/web/src/routes/threads/detail/artifact-preview-sheet.tsx b/apps/web/src/routes/threads/detail/artifact-preview-sheet.tsx index d6038ff3..85fa302e 100644 --- a/apps/web/src/routes/threads/detail/artifact-preview-sheet.tsx +++ b/apps/web/src/routes/threads/detail/artifact-preview-sheet.tsx @@ -1,4 +1,3 @@ -import { Download } from "lucide-react"; import type { ReactElement } from "react"; import { createFileDownload } from "@/domains/file/api/file-download-client"; @@ -6,6 +5,7 @@ import type { ListedFileEntry } from "@/domains/file/api/files"; import { FilePreviewContent, formatFileSize } from "@/features/file-preview/file-preview-content"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { Download } from "@/shared/ui/icons"; import { Sheet, SheetContent, SheetTitle } from "@/shared/ui/sheet"; export function ArtifactPreviewSheet({ diff --git a/apps/web/src/routes/threads/detail/run-failure-notice.tsx b/apps/web/src/routes/threads/detail/run-failure-notice.tsx index ebd6d6d7..a18c5baf 100644 --- a/apps/web/src/routes/threads/detail/run-failure-notice.tsx +++ b/apps/web/src/routes/threads/detail/run-failure-notice.tsx @@ -1,9 +1,9 @@ import type { SessionRunStatus, SessionRunSummary } from "@mosoo/contracts/session-run"; -import { ChevronRight, CircleX } from "lucide-react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { Button } from "@/shared/ui/button"; +import { ChevronRight, CircleX } from "@/shared/ui/icons"; interface ThreadRunFailureDetails { code: string | null; diff --git a/apps/web/src/routes/threads/detail/view.tsx b/apps/web/src/routes/threads/detail/view.tsx index c8a47b1d..87038516 100644 --- a/apps/web/src/routes/threads/detail/view.tsx +++ b/apps/web/src/routes/threads/detail/view.tsx @@ -4,19 +4,6 @@ import type { SessionMessage, SessionProcessEvent, } from "@mosoo/contracts/session"; -import { - Archive, - ArrowLeft, - ChevronRight, - CornerDownLeft, - Inbox, - MoreHorizontal, - Paperclip, - Pin, - PinOff, - RotateCcw, - Trash2, -} from "lucide-react"; import { useMemo, useState } from "react"; import type { ReactElement } from "react"; @@ -34,6 +21,19 @@ import { DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; import { EmptyState } from "@/shared/ui/empty-state"; +import { + Archive, + ArrowLeft, + ChevronRight, + CornerDownLeft, + Inbox, + MoreHorizontal, + Paperclip, + Pin, + PinOff, + RotateCcw, + Trash2, +} from "@/shared/ui/icons"; import { Markdown } from "@/shared/ui/markdown"; import type { MarkdownLinkResolver } from "@/shared/ui/markdown"; import { Textarea } from "@/shared/ui/textarea"; diff --git a/apps/web/src/routes/threads/list/view.tsx b/apps/web/src/routes/threads/list/view.tsx index 6c228d51..32aca6e5 100644 --- a/apps/web/src/routes/threads/list/view.tsx +++ b/apps/web/src/routes/threads/list/view.tsx @@ -1,3 +1,10 @@ +import { useState } from "react"; +import type { ReactElement } from "react"; + +import { useTranslation } from "@/shared/i18n"; +import { cn } from "@/shared/lib/class-names"; +import { Button } from "@/shared/ui/button"; +import { EmptyState } from "@/shared/ui/empty-state"; import { Archive, Bell, @@ -8,14 +15,7 @@ import { PinOff, Plus, Trash2, -} from "lucide-react"; -import { useState } from "react"; -import type { ReactElement } from "react"; - -import { useTranslation } from "@/shared/i18n"; -import { cn } from "@/shared/lib/class-names"; -import { Button } from "@/shared/ui/button"; -import { EmptyState } from "@/shared/ui/empty-state"; +} from "@/shared/ui/icons"; import { AgentAvatar } from "../agent-avatar"; import { getNotificationPermission, formatShortRelative } from "../model/format"; diff --git a/apps/web/src/routes/threads/process-modal/modal.tsx b/apps/web/src/routes/threads/process-modal/modal.tsx index bcc908f4..7ad17c52 100644 --- a/apps/web/src/routes/threads/process-modal/modal.tsx +++ b/apps/web/src/routes/threads/process-modal/modal.tsx @@ -1,5 +1,4 @@ import type { AgentSummary } from "@mosoo/contracts/agent"; -import { Check, Copy } from "lucide-react"; import { useState } from "react"; import type { ReactElement } from "react"; @@ -13,6 +12,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { Check, Copy } from "@/shared/ui/icons"; import { SessionEventDrawerCore } from "@/shared/ui/session-events"; import { AgentAvatar } from "../agent-avatar"; diff --git a/apps/web/src/routes/threads/process-modal/process-event-row.tsx b/apps/web/src/routes/threads/process-modal/process-event-row.tsx index d6e082e9..842f5512 100644 --- a/apps/web/src/routes/threads/process-modal/process-event-row.tsx +++ b/apps/web/src/routes/threads/process-modal/process-event-row.tsx @@ -1,8 +1,8 @@ -import { ChevronRight } from "lucide-react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { ChevronRight } from "@/shared/ui/icons"; import { getSessionEventChipTone, getSessionEventLabel } from "@/shared/ui/session-events"; import type { ThreadProcessEvent } from "../model/process"; diff --git a/apps/web/src/routes/threads/thread-state-icon.tsx b/apps/web/src/routes/threads/thread-state-icon.tsx index 5b9f4737..ea2f0c42 100644 --- a/apps/web/src/routes/threads/thread-state-icon.tsx +++ b/apps/web/src/routes/threads/thread-state-icon.tsx @@ -1,7 +1,7 @@ -import { CheckCircle2, CircleDashed, CircleX } from "lucide-react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; +import { CheckCircle2, CircleDashed, CircleX } from "@/shared/ui/icons"; import type { ThreadStateGlyph } from "./model/thread"; diff --git a/apps/web/src/shared/ui/command-block.tsx b/apps/web/src/shared/ui/command-block.tsx index c39d39c8..ecc85e63 100644 --- a/apps/web/src/shared/ui/command-block.tsx +++ b/apps/web/src/shared/ui/command-block.tsx @@ -1,10 +1,10 @@ -import { Check, Copy } from "lucide-react"; import type { ReactElement } from "react"; import { useState } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { writeClipboardText } from "@/shared/lib/clipboard"; +import { Check, Copy } from "@/shared/ui/icons"; // A copyable terminal command / code line. The leading prompt (default "$") is // decorative and never copied — only `command` lands on the clipboard. diff --git a/apps/web/src/shared/ui/copy-check-icon.tsx b/apps/web/src/shared/ui/copy-check-icon.tsx index c7dfae65..2eb0c6db 100644 --- a/apps/web/src/shared/ui/copy-check-icon.tsx +++ b/apps/web/src/shared/ui/copy-check-icon.tsx @@ -1,7 +1,7 @@ -import { Check, Copy } from "lucide-react"; import type { ReactElement } from "react"; import { cn } from "@/shared/lib/class-names"; +import { Check, Copy } from "@/shared/ui/icons"; /** * Copy-button glyph: the copy and check icons stacked in one grid cell, diff --git a/apps/web/src/shared/ui/dialog.tsx b/apps/web/src/shared/ui/dialog.tsx index ef50a22d..20ab72df 100644 --- a/apps/web/src/shared/ui/dialog.tsx +++ b/apps/web/src/shared/ui/dialog.tsx @@ -1,10 +1,10 @@ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"; -import { XIcon } from "lucide-react"; import type { ComponentProps, ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Button } from "@/shared/ui/button"; +import { XIcon } from "@/shared/ui/icons"; function Dialog({ ...props }: ComponentProps): ReactElement { return ; diff --git a/apps/web/src/shared/ui/empty-state.tsx b/apps/web/src/shared/ui/empty-state.tsx index 21eb4f4c..5e16b347 100644 --- a/apps/web/src/shared/ui/empty-state.tsx +++ b/apps/web/src/shared/ui/empty-state.tsx @@ -1,7 +1,7 @@ -import type { LucideIcon } from "lucide-react"; import type { ReactElement, ReactNode } from "react"; import { cn } from "@/shared/lib/class-names"; +import type { AppIcon } from "@/shared/ui/icons"; export function EmptyState({ icon: Icon, @@ -11,7 +11,7 @@ export function EmptyState({ children, className, }: { - icon: LucideIcon; + icon: AppIcon; title: ReactNode; description?: ReactNode; action?: ReactNode; diff --git a/apps/web/src/shared/ui/icons.tsx b/apps/web/src/shared/ui/icons.tsx new file mode 100644 index 00000000..b24296fa --- /dev/null +++ b/apps/web/src/shared/ui/icons.tsx @@ -0,0 +1,189 @@ +import Add01Icon from "@hugeicons/core-free-icons/Add01Icon"; +import Alert01Icon from "@hugeicons/core-free-icons/Alert01Icon"; +import AlertCircleIcon from "@hugeicons/core-free-icons/AlertCircleIcon"; +import AnalyticsUpIcon from "@hugeicons/core-free-icons/AnalyticsUpIcon"; +import ArchiveIcon from "@hugeicons/core-free-icons/ArchiveIcon"; +import ArrowLeft01Icon from "@hugeicons/core-free-icons/ArrowLeft01Icon"; +import ArrowRight01Icon from "@hugeicons/core-free-icons/ArrowRight01Icon"; +import ArrowUp01Icon from "@hugeicons/core-free-icons/ArrowUp01Icon"; +import ArrowUpRight01Icon from "@hugeicons/core-free-icons/ArrowUpRight01Icon"; +import AttachmentIcon from "@hugeicons/core-free-icons/AttachmentIcon"; +import BarChartIcon from "@hugeicons/core-free-icons/BarChartIcon"; +import BellIcon from "@hugeicons/core-free-icons/BellIcon"; +import BookOpen01Icon from "@hugeicons/core-free-icons/BookOpen01Icon"; +import BotIcon from "@hugeicons/core-free-icons/BotIcon"; +import BoxIcon from "@hugeicons/core-free-icons/BoxIcon"; +import Cancel01Icon from "@hugeicons/core-free-icons/Cancel01Icon"; +import CancelCircleIcon from "@hugeicons/core-free-icons/CancelCircleIcon"; +import CheckIcon from "@hugeicons/core-free-icons/CheckIcon"; +import CheckmarkCircle02Icon from "@hugeicons/core-free-icons/CheckmarkCircle02Icon"; +import ChevronDownIcon from "@hugeicons/core-free-icons/ChevronDownIcon"; +import ChevronLeftIcon from "@hugeicons/core-free-icons/ChevronLeftIcon"; +import ChevronRightIcon from "@hugeicons/core-free-icons/ChevronRightIcon"; +import ChevronUpIcon from "@hugeicons/core-free-icons/ChevronUpIcon"; +import CircleDashedIcon from "@hugeicons/core-free-icons/CircleDashedIcon"; +import CircleIcon from "@hugeicons/core-free-icons/CircleIcon"; +import CircleXIcon from "@hugeicons/core-free-icons/CircleXIcon"; +import Clock03Icon from "@hugeicons/core-free-icons/Clock03Icon"; +import CodeIcon from "@hugeicons/core-free-icons/CodeIcon"; +import CompassIcon from "@hugeicons/core-free-icons/CompassIcon"; +import ComputerTerminal01Icon from "@hugeicons/core-free-icons/ComputerTerminal01Icon"; +import Copy01Icon from "@hugeicons/core-free-icons/Copy01Icon"; +import CornerDownLeftIcon from "@hugeicons/core-free-icons/CornerDownLeftIcon"; +import CursorPointer02Icon from "@hugeicons/core-free-icons/CursorPointer02Icon"; +import Delete02Icon from "@hugeicons/core-free-icons/Delete02Icon"; +import Download01Icon from "@hugeicons/core-free-icons/Download01Icon"; +import ExternalLinkIcon from "@hugeicons/core-free-icons/ExternalLinkIcon"; +import File02Icon from "@hugeicons/core-free-icons/File02Icon"; +import FileArchiveIcon from "@hugeicons/core-free-icons/FileArchiveIcon"; +import FileQuestionMarkIcon from "@hugeicons/core-free-icons/FileQuestionMarkIcon"; +import FileStackIcon from "@hugeicons/core-free-icons/FileStackIcon"; +import FlameIcon from "@hugeicons/core-free-icons/FlameIcon"; +import GitBranchIcon from "@hugeicons/core-free-icons/GitBranchIcon"; +import GitForkIcon from "@hugeicons/core-free-icons/GitForkIcon"; +import GlobeIcon from "@hugeicons/core-free-icons/GlobeIcon"; +import Grid2X2Icon from "@hugeicons/core-free-icons/Grid2X2Icon"; +import HelpCircleIcon from "@hugeicons/core-free-icons/HelpCircleIcon"; +import InboxIcon from "@hugeicons/core-free-icons/InboxIcon"; +import InformationCircleIcon from "@hugeicons/core-free-icons/InformationCircleIcon"; +import Key02Icon from "@hugeicons/core-free-icons/Key02Icon"; +import Layers01Icon from "@hugeicons/core-free-icons/Layers01Icon"; +import LibraryIcon from "@hugeicons/core-free-icons/LibraryIcon"; +import ListViewIcon from "@hugeicons/core-free-icons/ListViewIcon"; +import Loading02Icon from "@hugeicons/core-free-icons/Loading02Icon"; +import Loading03Icon from "@hugeicons/core-free-icons/Loading03Icon"; +import LockIcon from "@hugeicons/core-free-icons/LockIcon"; +import LockKeyIcon from "@hugeicons/core-free-icons/LockKeyIcon"; +import Maximize02Icon from "@hugeicons/core-free-icons/Maximize02Icon"; +import Minimize02Icon from "@hugeicons/core-free-icons/Minimize02Icon"; +import MoreHorizontalIcon from "@hugeicons/core-free-icons/MoreHorizontalIcon"; +import PencilIcon from "@hugeicons/core-free-icons/PencilIcon"; +import PinIcon from "@hugeicons/core-free-icons/PinIcon"; +import PinOffIcon from "@hugeicons/core-free-icons/PinOffIcon"; +import PlugSocketIcon from "@hugeicons/core-free-icons/PlugSocketIcon"; +import PowerIcon from "@hugeicons/core-free-icons/PowerIcon"; +import PowerOffIcon from "@hugeicons/core-free-icons/PowerOffIcon"; +import RefreshIcon from "@hugeicons/core-free-icons/RefreshIcon"; +import RotateLeft01Icon from "@hugeicons/core-free-icons/RotateLeft01Icon"; +import Search01Icon from "@hugeicons/core-free-icons/Search01Icon"; +import SecurityCheckIcon from "@hugeicons/core-free-icons/SecurityCheckIcon"; +import SecurityWarningIcon from "@hugeicons/core-free-icons/SecurityWarningIcon"; +import SentIcon from "@hugeicons/core-free-icons/SentIcon"; +import Settings02Icon from "@hugeicons/core-free-icons/Settings02Icon"; +import SparklesIcon from "@hugeicons/core-free-icons/SparklesIcon"; +import StarIcon from "@hugeicons/core-free-icons/StarIcon"; +import Target01Icon from "@hugeicons/core-free-icons/Target01Icon"; +import Undo02Icon from "@hugeicons/core-free-icons/Undo02Icon"; +import Upload01Icon from "@hugeicons/core-free-icons/Upload01Icon"; +import UserIcon from "@hugeicons/core-free-icons/UserIcon"; +import ZapIcon from "@hugeicons/core-free-icons/ZapIcon"; +import { HugeiconsIcon } from "@hugeicons/react"; +import type { HugeiconsIconProps, IconSvgElement } from "@hugeicons/react"; +import type { ComponentType, Ref } from "react"; + +type IconProps = Omit & { + ref?: Ref; +}; + +export type AppIcon = ComponentType; + +export function createHugeicon(icon: IconSvgElement, displayName: string): AppIcon { + function AppHugeicon({ color = "currentColor", ref, strokeWidth = 1.5, ...props }: IconProps) { + return ( + + ); + } + + AppHugeicon.displayName = displayName; + + return AppHugeicon; +} + +export const AlertCircle = /* @__PURE__ */ createHugeicon(AlertCircleIcon, "AlertCircle"); +export const AlertTriangle = /* @__PURE__ */ createHugeicon(Alert01Icon, "AlertTriangle"); +export const Archive = /* @__PURE__ */ createHugeicon(ArchiveIcon, "Archive"); +export const ArrowLeft = /* @__PURE__ */ createHugeicon(ArrowLeft01Icon, "ArrowLeft"); +export const ArrowRight = /* @__PURE__ */ createHugeicon(ArrowRight01Icon, "ArrowRight"); +export const ArrowUp = /* @__PURE__ */ createHugeicon(ArrowUp01Icon, "ArrowUp"); +export const ArrowUpRight = /* @__PURE__ */ createHugeicon(ArrowUpRight01Icon, "ArrowUpRight"); +export const BarChart3 = /* @__PURE__ */ createHugeicon(BarChartIcon, "BarChart3"); +export const Bell = /* @__PURE__ */ createHugeicon(BellIcon, "Bell"); +export const BookOpen = /* @__PURE__ */ createHugeicon(BookOpen01Icon, "BookOpen"); +export const Bot = /* @__PURE__ */ createHugeicon(BotIcon, "Bot"); +export const Box = /* @__PURE__ */ createHugeicon(BoxIcon, "Box"); +export const Check = /* @__PURE__ */ createHugeicon(CheckIcon, "Check"); +export const CheckCircle2 = /* @__PURE__ */ createHugeicon(CheckmarkCircle02Icon, "CheckCircle2"); +export const ChevronDown = /* @__PURE__ */ createHugeicon(ChevronDownIcon, "ChevronDown"); +export const ChevronLeft = /* @__PURE__ */ createHugeicon(ChevronLeftIcon, "ChevronLeft"); +export const ChevronRight = /* @__PURE__ */ createHugeicon(ChevronRightIcon, "ChevronRight"); +export const ChevronUp = /* @__PURE__ */ createHugeicon(ChevronUpIcon, "ChevronUp"); +export const Circle = /* @__PURE__ */ createHugeicon(CircleIcon, "Circle"); +export const CircleDashed = /* @__PURE__ */ createHugeicon(CircleDashedIcon, "CircleDashed"); +export const CircleX = /* @__PURE__ */ createHugeicon(CircleXIcon, "CircleX"); +export const Clock3 = /* @__PURE__ */ createHugeicon(Clock03Icon, "Clock3"); +export const Code = /* @__PURE__ */ createHugeicon(CodeIcon, "Code"); +export const Compass = /* @__PURE__ */ createHugeicon(CompassIcon, "Compass"); +export const Copy = /* @__PURE__ */ createHugeicon(Copy01Icon, "Copy"); +export const CornerDownLeft = /* @__PURE__ */ createHugeicon(CornerDownLeftIcon, "CornerDownLeft"); +export const Download = /* @__PURE__ */ createHugeicon(Download01Icon, "Download"); +export const ExternalLink = /* @__PURE__ */ createHugeicon(ExternalLinkIcon, "ExternalLink"); +export const FileArchive = /* @__PURE__ */ createHugeicon(FileArchiveIcon, "FileArchive"); +export const FileQuestion = /* @__PURE__ */ createHugeicon(FileQuestionMarkIcon, "FileQuestion"); +export const FileStack = /* @__PURE__ */ createHugeicon(FileStackIcon, "FileStack"); +export const FileText = /* @__PURE__ */ createHugeicon(File02Icon, "FileText"); +export const Flame = /* @__PURE__ */ createHugeicon(FlameIcon, "Flame"); +export const GitBranch = /* @__PURE__ */ createHugeicon(GitBranchIcon, "GitBranch"); +export const GitFork = /* @__PURE__ */ createHugeicon(GitForkIcon, "GitFork"); +export const Globe = /* @__PURE__ */ createHugeicon(GlobeIcon, "Globe"); +export const Grid2X2 = /* @__PURE__ */ createHugeicon(Grid2X2Icon, "Grid2X2"); +export const HelpCircle = /* @__PURE__ */ createHugeicon(HelpCircleIcon, "HelpCircle"); +export const Inbox = /* @__PURE__ */ createHugeicon(InboxIcon, "Inbox"); +export const Info = /* @__PURE__ */ createHugeicon(InformationCircleIcon, "Info"); +export const KeyRound = /* @__PURE__ */ createHugeicon(Key02Icon, "KeyRound"); +export const Layers = /* @__PURE__ */ createHugeicon(Layers01Icon, "Layers"); +export const Library = /* @__PURE__ */ createHugeicon(LibraryIcon, "Library"); +export const List = /* @__PURE__ */ createHugeicon(ListViewIcon, "List"); +export const Loader2 = /* @__PURE__ */ createHugeicon(Loading02Icon, "Loader2"); +export const LoaderCircle = /* @__PURE__ */ createHugeicon(Loading03Icon, "LoaderCircle"); +export const Lock = /* @__PURE__ */ createHugeicon(LockIcon, "Lock"); +export const LockKeyhole = /* @__PURE__ */ createHugeicon(LockKeyIcon, "LockKeyhole"); +export const Maximize2 = /* @__PURE__ */ createHugeicon(Maximize02Icon, "Maximize2"); +export const Minimize2 = /* @__PURE__ */ createHugeicon(Minimize02Icon, "Minimize2"); +export const MoreHorizontal = /* @__PURE__ */ createHugeicon(MoreHorizontalIcon, "MoreHorizontal"); +export const MousePointerClick = /* @__PURE__ */ createHugeicon( + CursorPointer02Icon, + "MousePointerClick", +); +export const Paperclip = /* @__PURE__ */ createHugeicon(AttachmentIcon, "Paperclip"); +export const Pencil = /* @__PURE__ */ createHugeicon(PencilIcon, "Pencil"); +export const Pin = /* @__PURE__ */ createHugeicon(PinIcon, "Pin"); +export const PinOff = /* @__PURE__ */ createHugeicon(PinOffIcon, "PinOff"); +export const Plus = /* @__PURE__ */ createHugeicon(Add01Icon, "Plus"); +export const Power = /* @__PURE__ */ createHugeicon(PowerIcon, "Power"); +export const PowerOff = /* @__PURE__ */ createHugeicon(PowerOffIcon, "PowerOff"); +export const RefreshCw = /* @__PURE__ */ createHugeicon(RefreshIcon, "RefreshCw"); +export const RotateCcw = /* @__PURE__ */ createHugeicon(RotateLeft01Icon, "RotateCcw"); +export const Search = /* @__PURE__ */ createHugeicon(Search01Icon, "Search"); +export const Send = /* @__PURE__ */ createHugeicon(SentIcon, "Send"); +export const Settings = /* @__PURE__ */ createHugeicon(Settings02Icon, "Settings"); +export const ShieldAlert = /* @__PURE__ */ createHugeicon(SecurityWarningIcon, "ShieldAlert"); +export const ShieldCheck = /* @__PURE__ */ createHugeicon(SecurityCheckIcon, "ShieldCheck"); +export const Sparkles = /* @__PURE__ */ createHugeicon(SparklesIcon, "Sparkles"); +export const SquareTerminal = /* @__PURE__ */ createHugeicon( + ComputerTerminal01Icon, + "SquareTerminal", +); +export const Star = /* @__PURE__ */ createHugeicon(StarIcon, "Star"); +export const Target = /* @__PURE__ */ createHugeicon(Target01Icon, "Target"); +export const Terminal = /* @__PURE__ */ createHugeicon(ComputerTerminal01Icon, "Terminal"); +export const Trash2 = /* @__PURE__ */ createHugeicon(Delete02Icon, "Trash2"); +export const TrendingUp = /* @__PURE__ */ createHugeicon(AnalyticsUpIcon, "TrendingUp"); +export const TriangleAlert = /* @__PURE__ */ createHugeicon(Alert01Icon, "TriangleAlert"); +export const Undo2 = /* @__PURE__ */ createHugeicon(Undo02Icon, "Undo2"); +export const Unplug = /* @__PURE__ */ createHugeicon(PlugSocketIcon, "Unplug"); +export const Upload = /* @__PURE__ */ createHugeicon(Upload01Icon, "Upload"); +export const User = /* @__PURE__ */ createHugeicon(UserIcon, "User"); +export const X = /* @__PURE__ */ createHugeicon(Cancel01Icon, "X"); +export const XCircle = /* @__PURE__ */ createHugeicon(CancelCircleIcon, "XCircle"); +export const XIcon = X; +export const Zap = /* @__PURE__ */ createHugeicon(ZapIcon, "Zap"); diff --git a/apps/web/src/shared/ui/list-page.tsx b/apps/web/src/shared/ui/list-page.tsx index f4ff5f70..98bc8887 100644 --- a/apps/web/src/shared/ui/list-page.tsx +++ b/apps/web/src/shared/ui/list-page.tsx @@ -1,7 +1,7 @@ -import { Search } from "lucide-react"; import type { ReactElement, ReactNode } from "react"; import { cn } from "@/shared/lib/class-names"; +import { Search } from "@/shared/ui/icons"; import { Input } from "@/shared/ui/input"; export function ListPageToolbar({ diff --git a/apps/web/src/shared/ui/markdown.tsx b/apps/web/src/shared/ui/markdown.tsx index f80ba738..8922321b 100644 --- a/apps/web/src/shared/ui/markdown.tsx +++ b/apps/web/src/shared/ui/markdown.tsx @@ -1,4 +1,3 @@ -import { FileText } from "lucide-react"; import { useMemo } from "react"; import type { ComponentProps, ReactElement } from "react"; import { Streamdown, defaultRehypePlugins } from "streamdown"; @@ -6,6 +5,7 @@ import type { Components } from "streamdown"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { FileText } from "@/shared/ui/icons"; interface MarkdownProps { children: string; diff --git a/apps/web/src/shared/ui/project-id-badge.tsx b/apps/web/src/shared/ui/project-id-badge.tsx index f86ee7a5..94d2055a 100644 --- a/apps/web/src/shared/ui/project-id-badge.tsx +++ b/apps/web/src/shared/ui/project-id-badge.tsx @@ -1,4 +1,3 @@ -import { Check, Copy } from "lucide-react"; import type { MouseEvent, ReactElement } from "react"; import { useState } from "react"; @@ -6,6 +5,7 @@ import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { writeClipboardText } from "@/shared/lib/clipboard"; import { Button } from "@/shared/ui/button"; +import { Check, Copy } from "@/shared/ui/icons"; export function ProjectIdBadge({ projectId, diff --git a/apps/web/src/shared/ui/select.tsx b/apps/web/src/shared/ui/select.tsx index 9a0e02fa..8d1a7bf6 100644 --- a/apps/web/src/shared/ui/select.tsx +++ b/apps/web/src/shared/ui/select.tsx @@ -1,8 +1,8 @@ import { Select as SelectPrimitive } from "@base-ui/react/select"; -import { Check, ChevronDown } from "lucide-react"; import type { ComponentProps, ReactElement } from "react"; import { cn } from "@/shared/lib/class-names"; +import { Check, ChevronDown } from "@/shared/ui/icons"; function Select({ modal = false, diff --git a/apps/web/src/shared/ui/session-events/domain-filter-bar.tsx b/apps/web/src/shared/ui/session-events/domain-filter-bar.tsx index 74ec52e8..a419d25e 100644 --- a/apps/web/src/shared/ui/session-events/domain-filter-bar.tsx +++ b/apps/web/src/shared/ui/session-events/domain-filter-bar.tsx @@ -1,8 +1,8 @@ -import { AlertTriangle } from "lucide-react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { AlertTriangle } from "@/shared/ui/icons"; import { SESSION_EVENT_DOMAIN_TONE, diff --git a/apps/web/src/shared/ui/session-events/feed-turn-card.tsx b/apps/web/src/shared/ui/session-events/feed-turn-card.tsx index d37d21f1..cd02c552 100644 --- a/apps/web/src/shared/ui/session-events/feed-turn-card.tsx +++ b/apps/web/src/shared/ui/session-events/feed-turn-card.tsx @@ -1,10 +1,10 @@ import type { SessionProcessEvent } from "@mosoo/contracts/session"; -import { ChevronRight, Clock3 } from "lucide-react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; import { Button } from "@/shared/ui/button"; +import { ChevronRight, Clock3 } from "@/shared/ui/icons"; import { getSessionEventChipTone, diff --git a/apps/web/src/shared/ui/session-events/feed-turn-drawer.tsx b/apps/web/src/shared/ui/session-events/feed-turn-drawer.tsx index 16c3ea8f..c205080a 100644 --- a/apps/web/src/shared/ui/session-events/feed-turn-drawer.tsx +++ b/apps/web/src/shared/ui/session-events/feed-turn-drawer.tsx @@ -1,5 +1,4 @@ import type { SessionProcessEvent } from "@mosoo/contracts/session"; -import { ChevronRight } from "lucide-react"; import { useMemo, useState } from "react"; import type { ReactElement } from "react"; @@ -14,6 +13,7 @@ import { DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; +import { ChevronRight } from "@/shared/ui/icons"; import { getSessionEventChipTone, diff --git a/apps/web/src/shared/ui/sheet.tsx b/apps/web/src/shared/ui/sheet.tsx index 20330500..f88fe3a1 100644 --- a/apps/web/src/shared/ui/sheet.tsx +++ b/apps/web/src/shared/ui/sheet.tsx @@ -1,9 +1,9 @@ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"; -import { XIcon } from "lucide-react"; import type { ComponentProps, ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { XIcon } from "@/shared/ui/icons"; function Sheet({ ...props }: ComponentProps): ReactElement { return ; diff --git a/apps/web/src/shared/ui/view-toggle.tsx b/apps/web/src/shared/ui/view-toggle.tsx index e707ca2c..52885500 100644 --- a/apps/web/src/shared/ui/view-toggle.tsx +++ b/apps/web/src/shared/ui/view-toggle.tsx @@ -1,8 +1,8 @@ -import { Grid2X2, List } from "lucide-react"; import type { ReactElement } from "react"; import { useTranslation } from "@/shared/i18n"; import { cn } from "@/shared/lib/class-names"; +import { Grid2X2, List } from "@/shared/ui/icons"; type ViewMode = "list" | "grid"; diff --git a/apps/web/tests/agent-terminal-entry-boundary.test.ts b/apps/web/tests/agent-terminal-entry-boundary.test.ts index a975122b..309d0c92 100644 --- a/apps/web/tests/agent-terminal-entry-boundary.test.ts +++ b/apps/web/tests/agent-terminal-entry-boundary.test.ts @@ -11,7 +11,6 @@ describe("Agent terminal entry boundary", () => { const terminalButtonIndex = source.indexOf('aria-label={t("agent.openTerminal")}'); const gatedEntryIndex = source.lastIndexOf("canUseTerminal &&", terminalButtonIndex); - expect(source).toContain('import { ArrowLeft, Settings } from "lucide-react";'); expect(source).not.toContain("TerminalSquare"); expect(terminalButtonIndex).toBeGreaterThan(-1); expect(gatedEntryIndex).toBeGreaterThan(-1); diff --git a/bun.lock b/bun.lock index 56761b11..5b8afa7e 100644 --- a/bun.lock +++ b/bun.lock @@ -100,7 +100,6 @@ "boring-avatars": "^2.0.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^1.31.0", "motion": "^12.40.0", "react": "^19.2.8", "react-dom": "^19.2.8", @@ -2120,8 +2119,6 @@ "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "lucide-react": ["lucide-react@1.31.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-G8u2eEtoHUnUa9f8lbvqDhCiORMnYLdUEo06EEG9MQvHQrInKcX3Pa2TH39MM5qyzRcWETxB0+aOwAPI1g1kEg=="], - "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], diff --git a/docs/plans/2026-09-03-hugeicons-migration-design.md b/docs/plans/2026-09-03-hugeicons-migration-design.md new file mode 100644 index 00000000..4a363377 --- /dev/null +++ b/docs/plans/2026-09-03-hugeicons-migration-design.md @@ -0,0 +1,33 @@ +# Hugeicons migration design + +## Decision + +Mosoo Console and Mosoo Computer will use Hugeicons for every generic product +interface icon. The two applications keep their own components and build +systems; this is a shared visual contract, not a shared component package. + +## Scope + +- Replace `lucide-react` imports in `apps/web` with a local Hugeicons adapter. +- Replace `@phosphor-icons/react` imports in Mosoo Computer with its local + Hugeicons adapter. +- Keep product marks, provider/channel logos, favicons, illustrations, and + runtime-generated SVG as assets rather than reclassifying them as UI icons. +- Preserve each use site's accessible name, tooltip, disabled state, keyboard + behavior, loading behavior, and layout dimensions. + +## Contract + +Both adapters render `@hugeicons/react` with the free icon set and default to +`currentColor` with a 1.5px stroke. Call sites use semantic aliases so that a +future brand glyph change is localized to the adapter instead of spread across +product routes. + +## Acceptance and release + +There must be no production source import from Lucide or Phosphor after the +migration. Each repository must pass its typecheck, tests, and production build +before its PR is merged. Console production uses the web-only deployment path +because this visual-only change must not deploy the API or touch D1; Computer +uses its existing Worker deployment path. After each deployment, smoke-test the +public application and the affected console shell.