feat: swap icons to phosphor

This commit is contained in:
Wlad Meixner
2026-09-18 11:42:57 +02:00
parent 4881d20355
commit bb8a1a533c
27 changed files with 226 additions and 181 deletions
+3 -3
View File
@@ -7,6 +7,7 @@
"dependencies": {
"@base-ui/react": "^1.8.0",
"@hookform/resolvers": "^5.2.2",
"@phosphor-icons/react": "^2.1.10",
"@tanstack/react-table": "^9.2.4",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -15,7 +16,6 @@
"date-fns": "^4.1.0",
"embla-carousel-react": "^8.6.0",
"input-otp": "^1.4.2",
"lucide-react": "^0.553.0",
"next-themes": "^0.4.6",
"react-day-picker": "^10.0.1",
"react-hook-form": "^7.66.0",
@@ -296,6 +296,8 @@
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
"@phosphor-icons/react": ["@phosphor-icons/react@2.1.10", "", { "peerDependencies": { "react": ">= 16.8", "react-dom": ">= 16.8" } }, "sha512-vt8Tvq8GLjheAZZYa+YG/pW7HDbov8El/MANW8pOAz4eGxrwhnbfrQZq0Cp4q8zBEu8NIhHdnr+r8thnfRSNYA=="],
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
"@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="],
@@ -1054,8 +1056,6 @@
"lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="],
"lucide-react": ["lucide-react@0.553.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-BRgX5zrWmNy/lkVAe0dXBgd7XQdZ3HTf+Hwe3c9WK6dqgnj9h+hxV+MDncM88xDWlCq27+TKvHGE70ViODNILw=="],
"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=="],
+1 -1
View File
@@ -17,7 +17,7 @@
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide",
"iconLibrary": "phosphor",
"rtl": false,
"menuColor": "default-translucent",
"menuAccent": "subtle",
+1 -1
View File
@@ -58,6 +58,7 @@
"dependencies": {
"@base-ui/react": "^1.8.0",
"@hookform/resolvers": "^5.2.2",
"@phosphor-icons/react": "^2.1.10",
"@tanstack/react-table": "^9.2.4",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -66,7 +67,6 @@
"date-fns": "^4.1.0",
"embla-carousel-react": "^8.6.0",
"input-otp": "^1.4.2",
"lucide-react": "^0.553.0",
"next-themes": "^0.4.6",
"react-day-picker": "^10.0.1",
"react-hook-form": "^7.66.0",
+3 -3
View File
@@ -1,6 +1,6 @@
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
import { CaretDownIcon, CaretUpIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
return (
@@ -44,11 +44,11 @@ function AccordionTrigger({
{...props}
>
{children}
<ChevronDownIcon
<CaretDownIcon
data-slot="accordion-trigger-icon"
className="fui:pointer-events-none fui:shrink-0 fui:group-aria-expanded/accordion-trigger:hidden"
/>
<ChevronUpIcon
<CaretUpIcon
data-slot="accordion-trigger-icon"
className="fui:pointer-events-none fui:hidden fui:shrink-0 fui:group-aria-expanded/accordion-trigger:inline"
/>
+3 -3
View File
@@ -1,7 +1,7 @@
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
import { CaretRightIcon, DotsThreeIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
import type * as React from "react";
function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
@@ -87,7 +87,7 @@ function BreadcrumbSeparator({
className={cn("fui:[&>svg]:size-3.5", className)}
{...props}
>
{children ?? <ChevronRightIcon />}
{children ?? <CaretRightIcon />}
</li>
);
}
@@ -107,7 +107,7 @@ function BreadcrumbEllipsis({
)}
{...props}
>
<MoreHorizontalIcon />
<DotsThreeIcon />
<span className="fui:sr-only">More</span>
</span>
);
+8 -11
View File
@@ -1,9 +1,9 @@
import { cn } from "cn";
import {
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
} from "lucide-react";
CaretDownIcon,
CaretLeftIcon,
CaretRightIcon,
} from "@phosphor-icons/react";
import { cn } from "cn";
import * as React from "react";
import {
type DayButton,
@@ -154,7 +154,7 @@ function Calendar({
Chevron: ({ className, orientation, ...props }) => {
if (orientation === "left") {
return (
<ChevronLeftIcon
<CaretLeftIcon
className={cn("fui:size-4", className)}
{...props}
/>
@@ -163,7 +163,7 @@ function Calendar({
if (orientation === "right") {
return (
<ChevronRightIcon
<CaretRightIcon
className={cn("fui:size-4", className)}
{...props}
/>
@@ -171,10 +171,7 @@ function Calendar({
}
return (
<ChevronDownIcon
className={cn("fui:size-4", className)}
{...props}
/>
<CaretDownIcon className={cn("fui:size-4", className)} {...props} />
);
},
DayButton: ({ ...props }) => (
+3 -3
View File
@@ -1,8 +1,8 @@
import { CaretLeftIcon, CaretRightIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import useEmblaCarousel, {
type UseEmblaCarouselType,
} from "embla-carousel-react";
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
import * as React from "react";
import { Button } from "@/components/button";
@@ -192,7 +192,7 @@ function CarouselPrevious({
onClick={scrollPrev}
{...props}
>
<ChevronLeftIcon />
<CaretLeftIcon />
<span className="fui:sr-only">Previous slide</span>
</Button>
);
@@ -222,7 +222,7 @@ function CarouselNext({
onClick={scrollNext}
{...props}
>
<ChevronRightIcon />
<CaretRightIcon />
<span className="fui:sr-only">Next slide</span>
</Button>
);
+9
View File
@@ -370,3 +370,12 @@ export {
ChartLegendContent,
ChartStyle,
};
// The marks, axes and grids come from recharts itself; only the container,
// tooltip and legend are wrapped above. Re-exporting them from this module —
// rather than from an entry point of their own — is what keeps there being one
// recharts in the graph: a bundler pre-bundling two entry points that each
// depend on recharts produces two copies of it, and recharts 3 holds its chart
// state in a React context, so marks from one copy render nothing inside a
// container from the other.
export * from "recharts";
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
import { CheckIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { CheckIcon } from "lucide-react";
import * as React from "react";
import { Label } from "@/components/label";
+2 -2
View File
@@ -1,6 +1,6 @@
import { CheckIcon, MagnifyingGlassIcon } from "@phosphor-icons/react";
import { Command as CommandPrimitive } from "cmdk";
import { cn } from "cn";
import { CheckIcon, SearchIcon } from "lucide-react";
import type * as React from "react";
import {
Dialog,
@@ -76,7 +76,7 @@ function CommandInput({
{...props}
/>
<InputGroupAddon>
<SearchIcon className="fui:size-4 fui:shrink-0 fui:opacity-50" />
<MagnifyingGlassIcon className="fui:size-4 fui:shrink-0 fui:opacity-50" />
</InputGroupAddon>
</InputGroup>
</div>
+2 -2
View File
@@ -1,6 +1,6 @@
import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu";
import { CaretRightIcon, CheckIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { CheckIcon, ChevronRightIcon } from "lucide-react";
import type * as React from "react";
function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) {
@@ -134,7 +134,7 @@ function ContextMenuSubTrigger({
{...props}
>
{children}
<ChevronRightIcon className="fui:ml-auto" />
<CaretRightIcon className="fui:ml-auto" />
</ContextMenuPrimitive.SubmenuTrigger>
);
}
+18 -18
View File
@@ -1,5 +1,16 @@
"use client";
import {
ArrowDownIcon,
ArrowUpIcon,
CaretDoubleLeftIcon,
CaretDoubleRightIcon,
CaretLeftIcon,
CaretRightIcon,
CaretUpDownIcon,
MagnifyingGlassIcon,
SlidersHorizontalIcon,
} from "@phosphor-icons/react";
import {
type Column,
type ColumnDef,
@@ -28,17 +39,6 @@ import {
useTable,
} from "@tanstack/react-table";
import { cn } from "cn";
import {
ArrowDownIcon,
ArrowUpIcon,
ChevronLeftIcon,
ChevronRightIcon,
ChevronsLeftIcon,
ChevronsRightIcon,
ChevronsUpDownIcon,
SearchIcon,
Settings2Icon,
} from "lucide-react";
import * as React from "react";
import { Button } from "@/components/button";
@@ -159,7 +159,7 @@ function DataTableColumnHeader<
? ArrowUpIcon
: sorted === "desc"
? ArrowDownIcon
: ChevronsUpDownIcon;
: CaretUpDownIcon;
return (
<div
@@ -446,7 +446,7 @@ function DataTable<
)}
>
<InputGroupAddon>
<SearchIcon />
<MagnifyingGlassIcon />
</InputGroupAddon>
<InputGroupInput
value={globalFilter}
@@ -468,7 +468,7 @@ function DataTable<
size={toolbarSize}
className="fui:ml-auto"
>
<Settings2Icon data-icon="inline-start" />
<SlidersHorizontalIcon data-icon="inline-start" />
Columns
</Button>
}
@@ -616,7 +616,7 @@ function DataTable<
onClick={() => table.firstPage()}
disabled={!table.getCanPreviousPage()}
>
<ChevronsLeftIcon />
<CaretDoubleLeftIcon />
<span className="fui:sr-only">First page</span>
</Button>
<Button
@@ -625,7 +625,7 @@ function DataTable<
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
<ChevronLeftIcon />
<CaretLeftIcon />
<span className="fui:sr-only">Previous page</span>
</Button>
<Button
@@ -634,7 +634,7 @@ function DataTable<
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
<ChevronRightIcon />
<CaretRightIcon />
<span className="fui:sr-only">Next page</span>
</Button>
<Button
@@ -643,7 +643,7 @@ function DataTable<
onClick={() => table.lastPage()}
disabled={!table.getCanNextPage()}
>
<ChevronsRightIcon />
<CaretDoubleRightIcon />
<span className="fui:sr-only">Last page</span>
</Button>
</div>
+1 -1
View File
@@ -1,8 +1,8 @@
"use client";
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
import { XIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { XIcon } from "lucide-react";
import type * as React from "react";
import { Button } from "@/components/button";
+2 -2
View File
@@ -1,6 +1,6 @@
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
import { CaretRightIcon, CheckIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { CheckIcon, ChevronRightIcon } from "lucide-react";
import type * as React from "react";
function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
@@ -119,7 +119,7 @@ function DropdownMenuSubTrigger({
{...props}
>
{children}
<ChevronRightIcon className="fui:ml-auto" />
<CaretRightIcon className="fui:ml-auto" />
</MenuPrimitive.SubmenuTrigger>
);
}
+6 -2
View File
@@ -1,6 +1,10 @@
import {
CalendarIcon,
MagnifyingGlassIcon,
XIcon,
} from "@phosphor-icons/react";
import { cn } from "cn";
import { format } from "date-fns";
import { CalendarIcon, SearchIcon, XIcon } from "lucide-react";
import * as React from "react";
import { Button } from "@/components/button";
import { Calendar } from "@/components/calendar";
@@ -161,7 +165,7 @@ function FilterSearch({
at that size and shrinks it for a compact bar. */}
<InputGroup className={filterControlHeight[size]}>
<InputGroupAddon>
<SearchIcon />
<MagnifyingGlassIcon />
</InputGroupAddon>
<InputGroupInput
id={id}
+1 -1
View File
@@ -1,6 +1,6 @@
import { MinusIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { OTPInput, OTPInputContext } from "input-otp";
import { MinusIcon } from "lucide-react";
import * as React from "react";
function InputOTP({
+1 -1
View File
@@ -2,8 +2,8 @@
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
import { Menubar as MenubarPrimitive } from "@base-ui/react/menubar";
import { CheckIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { CheckIcon } from "lucide-react";
import type * as React from "react";
import {
DropdownMenu,
+2 -2
View File
@@ -1,7 +1,7 @@
import { NavigationMenu as NavigationMenuPrimitive } from "@base-ui/react/navigation-menu";
import { CaretDownIcon } from "@phosphor-icons/react";
import { cva } from "class-variance-authority";
import { cn } from "cn";
import { ChevronDownIcon } from "lucide-react";
function NavigationMenu({
align = "start",
@@ -70,7 +70,7 @@ function NavigationMenuTrigger({
{...props}
>
{children}{" "}
<ChevronDownIcon
<CaretDownIcon
className="fui:relative fui:top-px fui:ml-1 fui:size-3 fui:transition fui:duration-300 fui:group-data-popup-open/navigation-menu-trigger:rotate-180 fui:group-data-open/navigation-menu-trigger:rotate-180"
aria-hidden="true"
/>
+8 -8
View File
@@ -1,9 +1,9 @@
import { cn } from "cn";
import {
ChevronLeftIcon,
ChevronRightIcon,
MoreHorizontalIcon,
} from "lucide-react";
CaretLeftIcon,
CaretRightIcon,
DotsThreeIcon,
} from "@phosphor-icons/react";
import { cn } from "cn";
import type * as React from "react";
import { Button } from "@/components/button";
@@ -78,7 +78,7 @@ function PaginationPrevious({
className={cn("fui:pl-2!", className)}
{...props}
>
<ChevronLeftIcon data-icon="inline-start" />
<CaretLeftIcon data-icon="inline-start" />
<span className="fui:hidden fui:sm:block">{text}</span>
</PaginationLink>
);
@@ -97,7 +97,7 @@ function PaginationNext({
{...props}
>
<span className="fui:hidden fui:sm:block">{text}</span>
<ChevronRightIcon data-icon="inline-end" />
<CaretRightIcon data-icon="inline-end" />
</PaginationLink>
);
}
@@ -116,7 +116,7 @@ function PaginationEllipsis({
)}
{...props}
>
<MoreHorizontalIcon />
<DotsThreeIcon />
<span className="fui:sr-only">More pages</span>
</span>
);
+4 -4
View File
@@ -1,8 +1,8 @@
"use client";
import { Select as SelectPrimitive } from "@base-ui/react/select";
import { CaretDownIcon, CaretUpIcon, CheckIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import type * as React from "react";
const Select = SelectPrimitive.Root;
@@ -48,7 +48,7 @@ function SelectTrigger({
{children}
<SelectPrimitive.Icon
render={
<ChevronDownIcon className="fui:pointer-events-none fui:size-4 fui:text-muted-foreground" />
<CaretDownIcon className="fui:pointer-events-none fui:size-4 fui:text-muted-foreground" />
}
/>
</SelectPrimitive.Trigger>
@@ -170,7 +170,7 @@ function SelectScrollUpButton({
)}
{...props}
>
<ChevronUpIcon />
<CaretUpIcon />
</SelectPrimitive.ScrollUpArrow>
);
}
@@ -188,7 +188,7 @@ function SelectScrollDownButton({
)}
{...props}
>
<ChevronDownIcon />
<CaretDownIcon />
</SelectPrimitive.ScrollDownArrow>
);
}
+1 -1
View File
@@ -1,6 +1,6 @@
import { Dialog as SheetPrimitive } from "@base-ui/react/dialog";
import { XIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { XIcon } from "lucide-react";
import type * as React from "react";
import { Button } from "@/components/button";
+2 -2
View File
@@ -2,9 +2,9 @@
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
import { SidebarSimpleIcon } from "@phosphor-icons/react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "cn";
import { PanelLeftIcon } from "lucide-react";
import * as React from "react";
import { Button } from "@/components/button";
import { Input } from "@/components/input";
@@ -268,7 +268,7 @@ function SidebarTrigger({
}}
{...props}
>
<PanelLeftIcon />
<SidebarSimpleIcon />
<span className="fui:sr-only">Toggle Sidebar</span>
</Button>
);
+9 -9
View File
@@ -1,12 +1,12 @@
"use client";
import {
CircleCheckIcon,
CheckCircleIcon,
InfoIcon,
Loader2Icon,
OctagonXIcon,
TriangleAlertIcon,
} from "lucide-react";
SpinnerIcon,
WarningIcon,
WarningOctagonIcon,
} from "@phosphor-icons/react";
import { useTheme } from "next-themes";
import { Toaster as Sonner, type ToasterProps } from "sonner";
@@ -18,11 +18,11 @@ const Toaster = ({ ...props }: ToasterProps) => {
theme={theme as ToasterProps["theme"]}
className="fui:toaster fui:group"
icons={{
success: <CircleCheckIcon className="fui:size-4" />,
success: <CheckCircleIcon className="fui:size-4" />,
info: <InfoIcon className="fui:size-4" />,
warning: <TriangleAlertIcon className="fui:size-4" />,
error: <OctagonXIcon className="fui:size-4" />,
loading: <Loader2Icon className="fui:size-4 fui:animate-spin" />,
warning: <WarningIcon className="fui:size-4" />,
error: <WarningOctagonIcon className="fui:size-4" />,
loading: <SpinnerIcon className="fui:size-4 fui:animate-spin" />,
}}
style={
{
+2 -2
View File
@@ -1,9 +1,9 @@
import { SpinnerIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { Loader2Icon } from "lucide-react";
function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
return (
<Loader2Icon
<SpinnerIcon
data-slot="spinner"
role="status"
aria-label="Loading"
+2 -2
View File
@@ -1,5 +1,5 @@
import { CheckIcon, MinusIcon, XIcon } from "@phosphor-icons/react";
import { cn } from "cn";
import { CheckIcon, MinusIcon, XIcon } from "lucide-react";
import type * as React from "react";
import { Badge } from "@/components/badge";
@@ -123,7 +123,7 @@ function TagListCell({
empty?: React.ReactNode;
}) {
if (values.length === 0) {
return empty !== undefined ? <>{empty}</> : <EmptyCell />;
return empty !== undefined ? empty : <EmptyCell />;
}
return (
+37 -2
View File
@@ -1,2 +1,37 @@
// Re-export all lucide-react icons
export * from "lucide-react";
// Re-export all phosphor icons
// lucide-react exposed its component type as `LucideIcon`; phosphor calls it `Icon`.
export type { Icon as LucideIcon } from "@phosphor-icons/react";
export * from "@phosphor-icons/react";
// Compatibility aliases for consumers written against lucide-react naming.
// Phosphor has no same-named export for these; each alias points at the
// closest phosphor glyph so existing call sites keep resolving.
export {
ArrowCounterClockwiseIcon as RotateCcwIcon,
ArrowsClockwiseIcon as RefreshCwIcon,
CaretDoubleLeftIcon as ChevronsLeftIcon,
CaretDoubleRightIcon as ChevronsRightIcon,
CaretDownIcon as ChevronDownIcon,
CaretLeftIcon as ChevronLeftIcon,
CaretRightIcon as ChevronRightIcon,
CaretUpDownIcon as ChevronsUpDownIcon,
CaretUpIcon as ChevronUpIcon,
CheckCircleIcon as CircleCheckIcon,
CircleWavyIcon as BadgeIcon,
ClockCounterClockwiseIcon as HistoryIcon,
CloudArrowUpIcon as CloudUploadIcon,
CubeIcon as BoxesIcon,
DotsThreeIcon as MoreHorizontalIcon,
GearIcon as SettingsIcon,
GridFourIcon as LayoutGridIcon,
MagnifyingGlassIcon as SearchIcon,
ScalesIcon as ScaleIcon,
SealPercentIcon as TicketPercentIcon,
SidebarSimpleIcon as PanelLeftIcon,
SpinnerIcon as Loader2Icon,
SquaresFourIcon as LayoutDashboardIcon,
StackIcon as LayersIcon,
TrashIcon as Trash2Icon,
WarningIcon as TriangleAlertIcon,
WarningOctagonIcon as OctagonXIcon,
} from "@phosphor-icons/react";
+94 -94
View File
@@ -1,39 +1,39 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import {
Activity,
ArrowDownRight,
ArrowUpRight,
BadgeCheck,
BarChart3,
Bell,
Building2,
ChevronRight,
ChevronsUpDown,
CircleAlert,
Command as CommandIcon,
CreditCard,
DollarSign,
Download,
Ellipsis,
Eye,
FileText,
Inbox,
LayoutDashboard,
LifeBuoy,
LogOut,
Package,
Pencil,
Plus,
Rocket,
Search,
Send,
Settings,
ShoppingCart,
Sparkles,
Trash2,
TrendingUp,
Users,
} from "lucide-react";
ActivityIcon,
ArrowDownRightIcon,
ArrowUpRightIcon,
BellIcon,
BuildingsIcon,
CaretRightIcon,
CaretUpDownIcon,
ChartBarIcon,
CircleWavyCheckIcon,
CommandIcon,
CreditCardIcon,
CurrencyDollarIcon,
DotsThreeIcon,
DownloadIcon,
EyeIcon,
FileTextIcon,
GearIcon,
LifebuoyIcon,
MagnifyingGlassIcon,
PackageIcon,
PaperPlaneTiltIcon,
PencilIcon,
PlusIcon,
RocketIcon,
ShoppingCartIcon,
SignOutIcon,
SparkleIcon,
SquaresFourIcon,
TrashIcon,
TrayIcon,
TrendUpIcon,
UsersIcon,
WarningCircleIcon,
} from "@phosphor-icons/react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import * as React from "react";
import {
Area,
@@ -421,7 +421,7 @@ const stats = [
delta: "+18.2%",
trending: "up" as const,
hint: "vs. previous 30 days",
icon: DollarSign,
icon: CurrencyDollarIcon,
progress: 78,
},
{
@@ -430,7 +430,7 @@ const stats = [
delta: "+9.4%",
trending: "up" as const,
hint: "412 new this month",
icon: Users,
icon: UsersIcon,
progress: 64,
},
{
@@ -439,7 +439,7 @@ const stats = [
delta: "+2.1%",
trending: "up" as const,
hint: "peak 1,540 at 14:00",
icon: Activity,
icon: ActivityIcon,
progress: 41,
},
{
@@ -448,7 +448,7 @@ const stats = [
delta: "-0.6%",
trending: "down" as const,
hint: "lowest in 6 months",
icon: TrendingUp,
icon: TrendUpIcon,
progress: 22,
},
];
@@ -464,7 +464,7 @@ function AppSidebar() {
render={
<SidebarMenuButton size="lg" tooltip="Switch workspace">
<div className="fui:flex fui:aspect-square fui:size-8 fui:items-center fui:justify-center fui:rounded-lg fui:bg-sidebar-primary fui:text-sidebar-primary-foreground">
<Building2 className="fui:size-4" />
<BuildingsIcon className="fui:size-4" />
</div>
<div className="fui:grid fui:flex-1 fui:text-left fui:text-sm fui:leading-tight">
<span className="fui:truncate fui:font-medium">
@@ -474,7 +474,7 @@ function AppSidebar() {
Enterprise
</span>
</div>
<ChevronsUpDown className="fui:ml-auto fui:size-4" />
<CaretUpDownIcon className="fui:ml-auto fui:size-4" />
</SidebarMenuButton>
}
/>
@@ -482,12 +482,12 @@ function AppSidebar() {
<DropdownMenuGroup>
<DropdownMenuLabel>Workspaces</DropdownMenuLabel>
<DropdownMenuItem>
<Building2 />
<BuildingsIcon />
Foomo Inc.
<DropdownMenuShortcut>⌘1</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<Rocket />
<RocketIcon />
Skunkworks
<DropdownMenuShortcut>⌘2</DropdownMenuShortcut>
</DropdownMenuItem>
@@ -495,7 +495,7 @@ function AppSidebar() {
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<Plus />
<PlusIcon />
New workspace
</DropdownMenuItem>
</DropdownMenuGroup>
@@ -511,13 +511,13 @@ function AppSidebar() {
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton isActive tooltip="Dashboard">
<LayoutDashboard />
<SquaresFourIcon />
<span>Dashboard</span>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton tooltip="Analytics">
<BarChart3 />
<ChartBarIcon />
<span>Analytics</span>
</SidebarMenuButton>
</SidebarMenuItem>
@@ -527,9 +527,9 @@ function AppSidebar() {
<CollapsibleTrigger
render={
<SidebarMenuButton tooltip="Projects">
<Package />
<PackageIcon />
<span>Projects</span>
<ChevronRight className="fui:ml-auto fui:size-4 fui:transition-transform fui:duration-200 fui:group-data-open/collapsible:rotate-90" />
<CaretRightIcon className="fui:ml-auto fui:size-4 fui:transition-transform fui:duration-200 fui:group-data-open/collapsible:rotate-90" />
</SidebarMenuButton>
}
/>
@@ -557,14 +557,14 @@ function AppSidebar() {
<SidebarMenuItem>
<SidebarMenuButton tooltip="Customers">
<Users />
<UsersIcon />
<span>Customers</span>
</SidebarMenuButton>
<SidebarMenuBadge>128</SidebarMenuBadge>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton tooltip="Orders">
<ShoppingCart />
<ShoppingCartIcon />
<span>Orders</span>
</SidebarMenuButton>
<SidebarMenuBadge>12</SidebarMenuBadge>
@@ -579,20 +579,20 @@ function AppSidebar() {
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton tooltip="Invoices">
<FileText />
<FileTextIcon />
<span>Invoices</span>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton tooltip="Billing">
<CreditCard />
<CreditCardIcon />
<span>Billing</span>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton tooltip="Settings">
<Settings />
<span>Settings</span>
<SidebarMenuButton tooltip="GearIcon">
<GearIcon />
<span>GearIcon</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
@@ -603,7 +603,7 @@ function AppSidebar() {
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton size="sm" tooltip="Support">
<LifeBuoy />
<LifebuoyIcon />
<span>Support</span>
</SidebarMenuButton>
</SidebarMenuItem>
@@ -625,7 +625,7 @@ function AppSidebar() {
lena@foomo.org
</span>
</div>
<ChevronsUpDown className="fui:ml-auto fui:size-4" />
<CaretUpDownIcon className="fui:ml-auto fui:size-4" />
</SidebarMenuButton>
}
/>
@@ -640,22 +640,22 @@ function AppSidebar() {
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<Sparkles />
<SparkleIcon />
Upgrade to Pro
</DropdownMenuItem>
<DropdownMenuItem>
<BadgeCheck />
<CircleWavyCheckIcon />
Account
</DropdownMenuItem>
<DropdownMenuItem>
<CreditCard />
<CreditCardIcon />
Billing
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<LogOut />
<SignOutIcon />
Log out
</DropdownMenuItem>
</DropdownMenuGroup>
@@ -697,8 +697,8 @@ function DashboardHeader({ onOpenCommand }: { onOpenCommand: () => void }) {
onClick={onOpenCommand}
className="fui:hidden fui:w-64 fui:justify-start fui:font-normal fui:text-muted-foreground fui:lg:inline-flex"
>
<Search data-icon="inline-start" />
<span>Search everything…</span>
<MagnifyingGlassIcon data-icon="inline-start" />
<span>MagnifyingGlassIcon everything…</span>
<KbdGroup className="fui:ml-auto">
<Kbd>⌘</Kbd>
<Kbd>K</Kbd>
@@ -746,11 +746,11 @@ function DashboardHeader({ onOpenCommand }: { onOpenCommand: () => void }) {
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
<BadgeCheck />
<CircleWavyCheckIcon />
Profile
</DropdownMenuItem>
<DropdownMenuItem>
<Settings />
<GearIcon />
Preferences
<DropdownMenuShortcut>⌘,</DropdownMenuShortcut>
</DropdownMenuItem>
@@ -758,7 +758,7 @@ function DashboardHeader({ onOpenCommand }: { onOpenCommand: () => void }) {
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem variant="destructive">
<LogOut />
<SignOutIcon />
Log out
</DropdownMenuItem>
</DropdownMenuGroup>
@@ -774,19 +774,19 @@ const notifications = [
title: "Payment failed",
body: "Sara Lindqvist's card was declined.",
time: "5h ago",
icon: CircleAlert,
icon: WarningCircleIcon,
},
{
title: "New enterprise lead",
body: "Northwind requested a demo.",
time: "1d ago",
icon: Rocket,
icon: RocketIcon,
},
{
title: "Deploy succeeded",
body: "storefront@v2.14.0 is live.",
time: "2d ago",
icon: BadgeCheck,
icon: CircleWavyCheckIcon,
},
];
@@ -796,7 +796,7 @@ function NotificationsMenu() {
<DropdownMenuTrigger
render={
<Button variant="ghost" size="icon" className="fui:relative">
<Bell />
<BellIcon />
<span className="fui:absolute fui:top-1.5 fui:right-1.5 fui:size-2 fui:rounded-full fui:bg-destructive" />
<span className="fui:sr-only">Notifications</span>
</Button>
@@ -849,9 +849,9 @@ function StatCards() {
</span>
<Badge variant="secondary">
{stat.trending === "up" ? (
<ArrowUpRight data-icon="inline-start" />
<ArrowUpRightIcon data-icon="inline-start" />
) : (
<ArrowDownRight data-icon="inline-start" />
<ArrowDownRightIcon data-icon="inline-start" />
)}
{stat.delta}
</Badge>
@@ -1088,7 +1088,7 @@ const orderColumns = [
<DropdownMenuTrigger
render={
<Button variant="ghost" size="icon-sm">
<Ellipsis />
<DotsThreeIcon />
<span className="fui:sr-only">Actions for {row.original.id}</span>
</Button>
}
@@ -1096,15 +1096,15 @@ const orderColumns = [
<DropdownMenuContent align="end" className="fui:w-44">
<DropdownMenuGroup>
<DropdownMenuItem>
<Eye />
<EyeIcon />
View invoice
</DropdownMenuItem>
<DropdownMenuItem>
<Pencil />
<PencilIcon />
Edit
</DropdownMenuItem>
<DropdownMenuItem>
<Send />
<PaperPlaneTiltIcon />
Resend email
</DropdownMenuItem>
</DropdownMenuGroup>
@@ -1133,7 +1133,7 @@ function OrdersTableCard() {
<CardAction>
<div className="fui:flex fui:items-center fui:gap-2">
<Button variant="outline" size="sm">
<Download data-icon="inline-start" />
<DownloadIcon data-icon="inline-start" />
Export
</Button>
<NewProjectDialog />
@@ -1145,7 +1145,7 @@ function OrdersTableCard() {
columns={orderColumns}
data={orders}
getRowId={(order) => order.id}
searchable="Search invoices…"
searchable="MagnifyingGlassIcon invoices…"
hideableColumns
enableRowSelection
onRowSelectionChange={setSelected}
@@ -1167,7 +1167,7 @@ function DeleteOrderDialog({ invoice }: { invoice: string }) {
variant="destructive"
onSelect={(event) => event.preventDefault()}
>
<Trash2 />
<TrashIcon />
Delete
</DropdownMenuItem>
}
@@ -1199,7 +1199,7 @@ function NewProjectDialog() {
<DialogTrigger
render={
<Button size="sm">
<Plus data-icon="inline-start" />
<PlusIcon data-icon="inline-start" />
New project
</Button>
}
@@ -1216,7 +1216,7 @@ function NewProjectDialog() {
<FieldLabel htmlFor="project-name">Name</FieldLabel>
<InputGroup>
<InputGroupAddon>
<Package />
<PackageIcon />
</InputGroupAddon>
<InputGroupInput id="project-name" placeholder="storefront-eu" />
</InputGroup>
@@ -1360,7 +1360,7 @@ function ReportsTab() {
{reports.map((report) => (
<Item key={report.title} variant="outline">
<ItemMedia variant="icon">
<FileText />
<FileTextIcon />
</ItemMedia>
<ItemContent>
<ItemTitle>{report.title}</ItemTitle>
@@ -1391,7 +1391,7 @@ function AuditTab() {
<Empty className="fui:border">
<EmptyHeader>
<EmptyMedia variant="icon">
<Inbox />
<TrayIcon />
</EmptyMedia>
<EmptyTitle>Nothing to audit yet</EmptyTitle>
<EmptyDescription>
@@ -1401,7 +1401,7 @@ function AuditTab() {
</EmptyHeader>
<EmptyContent>
<Button variant="outline" size="sm">
<Settings data-icon="inline-start" />
<GearIcon data-icon="inline-start" />
Configure audit retention
</Button>
</EmptyContent>
@@ -1423,7 +1423,7 @@ function CommandPalette({
open={open}
onOpenChange={onOpenChange}
title="Command palette"
description="Search for a command to run"
description="MagnifyingGlassIcon for a command to run"
>
{/*
* CommandDialog only renders <Dialog><DialogContent>{children}</…>.
@@ -1437,28 +1437,28 @@ function CommandPalette({
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Navigation">
<CommandItem>
<LayoutDashboard />
<SquaresFourIcon />
Dashboard
<CommandShortcut>⌘D</CommandShortcut>
</CommandItem>
<CommandItem>
<BarChart3 />
<ChartBarIcon />
Analytics
<CommandShortcut>⌘A</CommandShortcut>
</CommandItem>
<CommandItem>
<Users />
<UsersIcon />
Customers
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Actions">
<CommandItem onSelect={() => toast.info("Invite sent")}>
<Plus />
<PlusIcon />
Invite teammate
</CommandItem>
<CommandItem onSelect={() => toast.info("Export queued")}>
<Download />
<DownloadIcon />
Export invoices
</CommandItem>
</CommandGroup>
@@ -1474,7 +1474,7 @@ function InviteDialog() {
<DialogTrigger
render={
<Button size="sm">
<Plus data-icon="inline-start" />
<PlusIcon data-icon="inline-start" />
Invite
</Button>
}
@@ -1499,7 +1499,7 @@ function InviteDialog() {
<DialogFooter>
<Button variant="outline">Cancel</Button>
<Button onClick={() => toast.success("Invitations sent")}>
Send invites
PaperPlaneTiltIcon invites
</Button>
</DialogFooter>
</DialogContent>
@@ -1608,7 +1608,7 @@ function Dashboard({ sidebarOpen = true, loading = false }: DashboardProps) {
})
}
>
<Send data-icon="inline-start" />
<PaperPlaneTiltIcon data-icon="inline-start" />
Email report
</Button>
<InviteDialog />
@@ -1616,7 +1616,7 @@ function Dashboard({ sidebarOpen = true, loading = false }: DashboardProps) {
</div>
<Alert>
<Sparkles />
<SparkleIcon />
<AlertTitle>Usage-based billing is now available</AlertTitle>
<AlertDescription>
Switch any project to metered pricing and only pay for what you