refactor: migrate all Lucide icons to Phosphor + remove lucide-react (PR4)
Unified icon library: - Create src/components/ui/icon.tsx as centralized icon re-export + size constants - Migrate all 20+ files from lucide-react to @phosphor-icons/react - Remove lucide-react from package.json dependencies - Upgrade ESLint lucide-react rule from warn → error Icon mappings applied: CheckIcon → Check, ChevronDown → CaretDown, ChevronUp → CaretUp, ChevronRight → CaretRight, X → X, Search → MagnifyingGlass, Loader2 → SpinnerGap, CornerDownLeft → ArrowElbowDownLeft, Image → Image, Brain → Brain, Terminal → Terminal, Book → Book, Dot → DotOutline, Circle → Circle Files migrated: ui/ (6), ai-elements/ (11), layout/ (3) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
d9f2e6d614
commit
27bf396cd3
24 files changed
+107
-84
No files matched your search
+2
-2
@@ -62,7 +62,7 @@ const eslintConfig = defineConfig([
|
||||
files: ["src/**/*.{ts,tsx}"],
|
||||
rules: {
|
||||
"no-restricted-imports": [
|
||||
"warn",
|
||||
"error",
|
||||
{
|
||||
patterns: [
|
||||
{
|
||||
@@ -100,7 +100,7 @@ const eslintConfig = defineConfig([
|
||||
message: "Pattern components must be pure presentation — no hooks imports.",
|
||||
},
|
||||
{
|
||||
group: ["@/lib/*", "@/lib"],
|
||||
group: ["@/lib/*", "!@/lib/utils"],
|
||||
message: "Pattern components must be pure presentation — no lib imports. Use @/lib/utils for cn() only.",
|
||||
},
|
||||
],
|
||||
|
||||
Generated
-1
@@ -35,7 +35,6 @@
|
||||
"cmdk": "^1.1.1",
|
||||
"discord.js": "^14.25.1",
|
||||
"electron-updater": "^6.8.3",
|
||||
"lucide-react": "^0.563.0",
|
||||
"markdown-it": "^14.1.1",
|
||||
"motion": "^12.33.0",
|
||||
"nanoid": "^5.1.6",
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
"cmdk": "^1.1.1",
|
||||
"discord.js": "^14.25.1",
|
||||
"electron-updater": "^6.8.3",
|
||||
"lucide-react": "^0.563.0",
|
||||
"markdown-it": "^14.1.1",
|
||||
"motion": "^12.33.0",
|
||||
"nanoid": "^5.1.6",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
import type { Icon as PhosphorIcon } from "@phosphor-icons/react";
|
||||
import type { ComponentProps, HTMLAttributes } from "react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { XIcon } from "lucide-react";
|
||||
import { X } from "@phosphor-icons/react";
|
||||
|
||||
export type ArtifactProps = HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
@@ -59,7 +59,7 @@ export const ArtifactClose = ({
|
||||
variant={variant}
|
||||
{...props}
|
||||
>
|
||||
{children ?? <XIcon className="size-4" />}
|
||||
{children ?? <X className="size-4" />}
|
||||
<span className="sr-only">Close</span>
|
||||
</Button>
|
||||
);
|
||||
@@ -94,7 +94,7 @@ export const ArtifactActions = ({
|
||||
export type ArtifactActionProps = ComponentProps<typeof Button> & {
|
||||
tooltip?: string;
|
||||
label?: string;
|
||||
icon?: LucideIcon;
|
||||
icon?: PhosphorIcon;
|
||||
};
|
||||
|
||||
export const ArtifactAction = ({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
import type { Icon as PhosphorIcon } from "@phosphor-icons/react";
|
||||
import type { ComponentProps, ReactNode } from "react";
|
||||
|
||||
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { BrainIcon, ChevronDownIcon, DotIcon } from "lucide-react";
|
||||
import { Brain, CaretDown, DotOutline } from "@phosphor-icons/react";
|
||||
import { createContext, memo, useContext, useMemo } from "react";
|
||||
|
||||
interface ChainOfThoughtContextValue {
|
||||
@@ -86,11 +86,11 @@ export const ChainOfThoughtHeader = memo(
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<BrainIcon className="size-4" />
|
||||
<Brain className="size-4" />
|
||||
<span className="flex-1 text-left">
|
||||
{children ?? "Chain of Thought"}
|
||||
</span>
|
||||
<ChevronDownIcon
|
||||
<CaretDown
|
||||
className={cn(
|
||||
"size-4 transition-transform",
|
||||
isOpen ? "rotate-180" : "rotate-0"
|
||||
@@ -103,7 +103,7 @@ export const ChainOfThoughtHeader = memo(
|
||||
);
|
||||
|
||||
export type ChainOfThoughtStepProps = ComponentProps<"div"> & {
|
||||
icon?: LucideIcon;
|
||||
icon?: PhosphorIcon;
|
||||
label: ReactNode;
|
||||
description?: ReactNode;
|
||||
status?: "complete" | "active" | "pending";
|
||||
@@ -118,7 +118,7 @@ const stepStatusStyles = {
|
||||
export const ChainOfThoughtStep = memo(
|
||||
({
|
||||
className,
|
||||
icon: Icon = DotIcon,
|
||||
icon: Icon = DotOutline,
|
||||
label,
|
||||
description,
|
||||
status = "complete",
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useThemeFamily } from "@/lib/theme/context";
|
||||
import { resolveShikiTheme, resolveShikiThemes, SHIKI_DEFAULT_LIGHT, SHIKI_DEFAULT_DARK } from "@/lib/theme/code-themes";
|
||||
import { CheckIcon, CopyIcon } from "lucide-react";
|
||||
import { Check, Copy } from "@phosphor-icons/react";
|
||||
import {
|
||||
createContext,
|
||||
memo,
|
||||
@@ -526,7 +526,7 @@ export const CodeBlockCopyButton = ({
|
||||
[]
|
||||
);
|
||||
|
||||
const Icon = isCopied ? CheckIcon : CopyIcon;
|
||||
const Icon = isCopied ? Check : Copy;
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { ComponentProps } from "react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ArrowDownIcon, DownloadIcon } from "lucide-react";
|
||||
import { ArrowDown, DownloadSimple } from "@phosphor-icons/react";
|
||||
import { useCallback } from "react";
|
||||
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
|
||||
|
||||
@@ -94,7 +94,7 @@ export const ConversationScrollButton = ({
|
||||
variant="outline"
|
||||
{...props}
|
||||
>
|
||||
<ArrowDownIcon className="size-4" />
|
||||
<ArrowDown className="size-4" />
|
||||
</Button>
|
||||
)
|
||||
);
|
||||
@@ -161,7 +161,7 @@ export const ConversationDownload = ({
|
||||
variant="outline"
|
||||
{...props}
|
||||
>
|
||||
{children ?? <DownloadIcon className="size-4" />}
|
||||
{children ?? <DownloadSimple className="size-4" />}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@@ -19,7 +19,7 @@ import { cjk } from "@streamdown/cjk";
|
||||
import { createCodePlugin } from "@streamdown/code";
|
||||
import { math } from "@streamdown/math";
|
||||
import { mermaid } from "@streamdown/mermaid";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
||||
import { CaretLeft, CaretRight } from "@phosphor-icons/react";
|
||||
import {
|
||||
createContext,
|
||||
memo,
|
||||
@@ -271,7 +271,7 @@ export const MessageBranchPrevious = ({
|
||||
variant="ghost"
|
||||
{...props}
|
||||
>
|
||||
{children ?? <ChevronLeftIcon size={14} />}
|
||||
{children ?? <CaretLeft size={14} />}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@@ -294,7 +294,7 @@ export const MessageBranchNext = ({
|
||||
variant="ghost"
|
||||
{...props}
|
||||
>
|
||||
{children ?? <ChevronRightIcon size={14} />}
|
||||
{children ?? <CaretRight size={14} />}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -56,12 +56,12 @@ import {
|
||||
} from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
CornerDownLeftIcon,
|
||||
ImageIcon,
|
||||
PlusIcon,
|
||||
SquareIcon,
|
||||
XIcon,
|
||||
} from "lucide-react";
|
||||
ArrowElbowDownLeft,
|
||||
Image,
|
||||
Plus,
|
||||
Square,
|
||||
X,
|
||||
} from "@phosphor-icons/react";
|
||||
import { nanoid } from "nanoid";
|
||||
import {
|
||||
Children,
|
||||
@@ -353,7 +353,7 @@ export const PromptInputActionAddAttachments = ({
|
||||
|
||||
return (
|
||||
<DropdownMenuItem {...props} onSelect={handleSelect}>
|
||||
<ImageIcon className="mr-2 size-4" /> {label}
|
||||
<Image className="mr-2 size-4" /> {label}
|
||||
</DropdownMenuItem>
|
||||
);
|
||||
};
|
||||
@@ -1062,7 +1062,7 @@ export const PromptInputActionMenuTrigger = ({
|
||||
}: PromptInputActionMenuTriggerProps) => (
|
||||
<DropdownMenuTrigger asChild>
|
||||
<PromptInputButton className={className} {...props}>
|
||||
{children ?? <PlusIcon className="size-4" />}
|
||||
{children ?? <Plus className="size-4" />}
|
||||
</PromptInputButton>
|
||||
</DropdownMenuTrigger>
|
||||
);
|
||||
@@ -1107,14 +1107,14 @@ export const PromptInputSubmit = ({
|
||||
}: PromptInputSubmitProps) => {
|
||||
const isGenerating = status === "submitted" || status === "streaming";
|
||||
|
||||
let Icon = <CornerDownLeftIcon className="size-4" />;
|
||||
let Icon = <ArrowElbowDownLeft className="size-4" />;
|
||||
|
||||
if (status === "submitted") {
|
||||
Icon = <Spinner />;
|
||||
} else if (status === "streaming") {
|
||||
Icon = <SquareIcon className="size-4" />;
|
||||
Icon = <Square className="size-4" />;
|
||||
} else if (status === "error") {
|
||||
Icon = <XIcon className="size-4" />;
|
||||
Icon = <X className="size-4" />;
|
||||
}
|
||||
|
||||
const handleClick = useCallback(
|
||||
|
||||
@@ -13,7 +13,7 @@ import { cjk } from "@streamdown/cjk";
|
||||
import { code } from "@streamdown/code";
|
||||
import { math } from "@streamdown/math";
|
||||
import { mermaid } from "@streamdown/mermaid";
|
||||
import { BrainIcon, ChevronDownIcon } from "lucide-react";
|
||||
import { Brain, CaretDown } from "@phosphor-icons/react";
|
||||
import {
|
||||
createContext,
|
||||
memo,
|
||||
@@ -184,9 +184,9 @@ export const ReasoningTrigger = memo(
|
||||
>
|
||||
{children ?? (
|
||||
<>
|
||||
<BrainIcon className="size-4" />
|
||||
<Brain className="size-4" />
|
||||
{getThinkingMessage(isStreaming, duration)}
|
||||
<ChevronDownIcon
|
||||
<CaretDown
|
||||
className={cn(
|
||||
"size-4 transition-transform",
|
||||
isOpen ? "rotate-180" : "rotate-0"
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { BookIcon, ChevronDownIcon } from "lucide-react";
|
||||
import { Book, CaretDown } from "@phosphor-icons/react";
|
||||
|
||||
export type SourcesProps = ComponentProps<"div">;
|
||||
|
||||
@@ -36,7 +36,7 @@ export const SourcesTrigger = ({
|
||||
{children ?? (
|
||||
<>
|
||||
<p className="font-medium">Used {count} sources</p>
|
||||
<ChevronDownIcon className="h-4 w-4" />
|
||||
<CaretDown className="h-4 w-4" />
|
||||
</>
|
||||
)}
|
||||
</CollapsibleTrigger>
|
||||
@@ -70,7 +70,7 @@ export const Source = ({ href, title, children, ...props }: SourceProps) => (
|
||||
>
|
||||
{children ?? (
|
||||
<>
|
||||
<BookIcon className="h-4 w-4" />
|
||||
<Book className="h-4 w-4" />
|
||||
<span className="block font-medium">{title}</span>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ChevronDownIcon, SearchIcon } from "lucide-react";
|
||||
import { CaretDown, MagnifyingGlass } from "@phosphor-icons/react";
|
||||
|
||||
export type TaskItemFileProps = ComponentProps<"div">;
|
||||
|
||||
@@ -59,9 +59,9 @@ export const TaskTrigger = ({
|
||||
<CollapsibleTrigger asChild className={cn("group", className)} {...props}>
|
||||
{children ?? (
|
||||
<div className="flex w-full cursor-pointer items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground">
|
||||
<SearchIcon className="size-4" />
|
||||
<MagnifyingGlass className="size-4" />
|
||||
<p className="text-sm">{title}</p>
|
||||
<ChevronDownIcon className="size-4 transition-transform group-data-[state=open]:rotate-180" />
|
||||
<CaretDown className="size-4 transition-transform group-data-[state=open]:rotate-180" />
|
||||
</div>
|
||||
)}
|
||||
</CollapsibleTrigger>
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { ComponentProps, HTMLAttributes } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import Ansi from "ansi-to-react";
|
||||
import { CheckIcon, CopyIcon, TerminalIcon, Trash2Icon } from "lucide-react";
|
||||
import { Check, Copy, Terminal as TerminalIcon, Trash } from "@phosphor-icons/react";
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
@@ -191,7 +191,7 @@ export const TerminalCopyButton = ({
|
||||
[]
|
||||
);
|
||||
|
||||
const Icon = isCopied ? CheckIcon : CopyIcon;
|
||||
const Icon = isCopied ? Check : Copy;
|
||||
|
||||
return (
|
||||
<Button
|
||||
@@ -233,7 +233,7 @@ export const TerminalClearButton = ({
|
||||
variant="ghost"
|
||||
{...props}
|
||||
>
|
||||
{children ?? <Trash2Icon size={14} />}
|
||||
{children ?? <Trash size={14} />}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -11,13 +11,13 @@ import {
|
||||
} from "@/components/ui/collapsible";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
CheckCircleIcon,
|
||||
ChevronDownIcon,
|
||||
CircleIcon,
|
||||
ClockIcon,
|
||||
WrenchIcon,
|
||||
XCircleIcon,
|
||||
} from "lucide-react";
|
||||
CheckCircle,
|
||||
CaretDown,
|
||||
Circle,
|
||||
Clock,
|
||||
Wrench,
|
||||
XCircle,
|
||||
} from "@phosphor-icons/react";
|
||||
import { createContext, isValidElement, useContext, useState } from "react";
|
||||
|
||||
import { CodeBlock } from "./code-block";
|
||||
@@ -73,13 +73,13 @@ const statusLabels: Record<ToolPart["state"], string> = {
|
||||
};
|
||||
|
||||
const statusIcons: Record<ToolPart["state"], ReactNode> = {
|
||||
"approval-requested": <ClockIcon className="size-4 text-yellow-600" />,
|
||||
"approval-responded": <CheckCircleIcon className="size-4 text-blue-600" />,
|
||||
"input-available": <ClockIcon className="size-4 animate-pulse" />,
|
||||
"input-streaming": <CircleIcon className="size-4" />,
|
||||
"output-available": <CheckCircleIcon className="size-4 text-green-600" />,
|
||||
"output-denied": <XCircleIcon className="size-4 text-orange-600" />,
|
||||
"output-error": <XCircleIcon className="size-4 text-red-600" />,
|
||||
"approval-requested": <Clock className="size-4 text-yellow-600" />,
|
||||
"approval-responded": <CheckCircle className="size-4 text-blue-600" />,
|
||||
"input-available": <Clock className="size-4 animate-pulse" />,
|
||||
"input-streaming": <Circle className="size-4" />,
|
||||
"output-available": <CheckCircle className="size-4 text-green-600" />,
|
||||
"output-denied": <XCircle className="size-4 text-orange-600" />,
|
||||
"output-error": <XCircle className="size-4 text-red-600" />,
|
||||
};
|
||||
|
||||
export const getStatusBadge = (status: ToolPart["state"]) => (
|
||||
@@ -109,11 +109,11 @@ export const ToolHeader = ({
|
||||
{...props}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<WrenchIcon className="size-4 text-muted-foreground" />
|
||||
<Wrench className="size-4 text-muted-foreground" />
|
||||
<span className="font-medium text-sm">{title ?? derivedName}</span>
|
||||
{getStatusBadge(state)}
|
||||
</div>
|
||||
<ChevronDownIcon className="size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" />
|
||||
<CaretDown className="size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" />
|
||||
</CollapsibleTrigger>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,8 +14,9 @@ import {
|
||||
Plus,
|
||||
FolderOpen,
|
||||
UserCircle,
|
||||
Columns,
|
||||
X,
|
||||
} from "@phosphor-icons/react";
|
||||
import { Columns2, X } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
@@ -453,7 +454,7 @@ export function ChatListPanel({ open, width }: ChatListPanelProps) {
|
||||
{isSplitActive && (
|
||||
<div className="mb-2 rounded-lg border border-border/60 bg-muted/30 p-1.5">
|
||||
<div className="flex items-center gap-1.5 px-2 py-1">
|
||||
<Columns2 className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<Columns className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<span className="text-xs font-medium text-muted-foreground">{t('split.splitGroup')}</span>
|
||||
</div>
|
||||
<div className="mt-0.5 flex flex-col gap-0.5">
|
||||
@@ -660,7 +661,7 @@ export function ChatListPanel({ open, width }: ChatListPanelProps) {
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Columns2 className="h-3.5 w-3.5" />
|
||||
<Columns className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
)}
|
||||
{/* Streaming indicator: hidden when hover shows split icon */}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { CircleAlert } from "lucide-react";
|
||||
import { WarningCircle } from "@phosphor-icons/react";
|
||||
import { useTranslation } from "@/hooks/useTranslation";
|
||||
|
||||
interface ErrorBoundaryProps {
|
||||
@@ -30,7 +30,7 @@ function ErrorFallback({
|
||||
<div className="flex h-full w-full items-center justify-center bg-background p-8">
|
||||
<div className="flex max-w-md flex-col items-center gap-4 text-center">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-destructive/10 text-destructive">
|
||||
<CircleAlert size={24} />
|
||||
<WarningCircle size={24} />
|
||||
</div>
|
||||
|
||||
<h2 className="text-lg font-semibold text-foreground">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { X } from "lucide-react";
|
||||
import { X } from "@phosphor-icons/react";
|
||||
import type { Message, MessagesResponse, ChatSession } from "@/types";
|
||||
import { ChatView } from "@/components/chat/ChatView";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import * as React from "react"
|
||||
import { Command as CommandPrimitive } from "cmdk"
|
||||
import { SearchIcon } from "lucide-react"
|
||||
import { MagnifyingGlass } from "@phosphor-icons/react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import {
|
||||
@@ -69,7 +69,7 @@ function CommandInput({
|
||||
data-slot="command-input-wrapper"
|
||||
className="flex h-9 items-center gap-2 border-b px-3"
|
||||
>
|
||||
<SearchIcon className="size-4 shrink-0 opacity-50" />
|
||||
<MagnifyingGlass className="size-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
data-slot="command-input"
|
||||
className={cn(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { XIcon } from "lucide-react"
|
||||
import { X } from "@phosphor-icons/react"
|
||||
import { Dialog as DialogPrimitive } from "radix-ui"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
@@ -72,7 +72,7 @@ function DialogContent({
|
||||
data-slot="dialog-close"
|
||||
className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
||||
>
|
||||
<XIcon />
|
||||
<X />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
|
||||
import { Check, CaretRight, Circle } from "@phosphor-icons/react"
|
||||
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
@@ -100,7 +100,7 @@ function DropdownMenuCheckboxItem({
|
||||
>
|
||||
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
<Check className="size-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
@@ -135,7 +135,7 @@ function DropdownMenuRadioItem({
|
||||
>
|
||||
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<CircleIcon className="size-2 fill-current" />
|
||||
<Circle className="size-2" weight="fill" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
@@ -217,7 +217,7 @@ function DropdownMenuSubTrigger({
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRightIcon className="ml-auto size-4" />
|
||||
<CaretRight className="ml-auto size-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Unified icon re-exports + size constants for the project
|
||||
export {
|
||||
Check,
|
||||
X,
|
||||
CaretDown,
|
||||
CaretUp,
|
||||
CaretRight,
|
||||
MagnifyingGlass,
|
||||
SpinnerGap,
|
||||
ArrowElbowDownLeft,
|
||||
Image,
|
||||
Brain,
|
||||
Terminal,
|
||||
Book,
|
||||
DotOutline,
|
||||
Circle,
|
||||
Plus,
|
||||
Copy,
|
||||
Trash,
|
||||
} from "@phosphor-icons/react";
|
||||
|
||||
export type { Icon, IconProps } from "@phosphor-icons/react";
|
||||
|
||||
export const ICON_SIZE = { sm: 14, md: 16, lg: 20, xl: 24 } as const;
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
||||
import { Check, CaretDown, CaretUp } from "@phosphor-icons/react"
|
||||
import { Select as SelectPrimitive } from "radix-ui"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
@@ -44,7 +44,7 @@ function SelectTrigger({
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDownIcon className="size-4 opacity-50" />
|
||||
<CaretDown className="size-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
)
|
||||
@@ -119,7 +119,7 @@ function SelectItem({
|
||||
className="absolute right-2 flex size-3.5 items-center justify-center"
|
||||
>
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
<Check className="size-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
@@ -153,7 +153,7 @@ function SelectScrollUpButton({
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUpIcon className="size-4" />
|
||||
<CaretUp className="size-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
)
|
||||
}
|
||||
@@ -171,7 +171,7 @@ function SelectScrollDownButton({
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDownIcon className="size-4" />
|
||||
<CaretDown className="size-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { XIcon } from "lucide-react"
|
||||
import { X } from "@phosphor-icons/react"
|
||||
import { Dialog as SheetPrimitive } from "radix-ui"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
@@ -76,7 +76,7 @@ function SheetContent({
|
||||
{children}
|
||||
{showCloseButton && (
|
||||
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none">
|
||||
<XIcon className="size-4" />
|
||||
<X className="size-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</SheetPrimitive.Close>
|
||||
)}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Loader2Icon } from "lucide-react"
|
||||
import { SpinnerGap } from "@phosphor-icons/react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
|
||||
return (
|
||||
<Loader2Icon
|
||||
<SpinnerGap
|
||||
role="status"
|
||||
aria-label="Loading"
|
||||
className={cn("size-4 animate-spin", className)}
|
||||
|
||||
Reference in new issue
Block a user