feat(ui): replace @ant-design/icons with Lucide

- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
feat(ui): replace @ant-design/icons with Lucide
- Add frontend/src/icons.tsx adapter (Ant *Outlined names → lucide-react)
- Rewrite all page/component imports
- Drop @ant-design/icons; add lucide-react
- CSS keyframes for optional spin prop
This commit is contained in:
kazeyukiro committed 2026-09-22 16:13:34 +00:00
1 parent 99e240d6bd
commit 4dfbdca143
20 files changed
+191 -19

No files matched your search

+2 -2
View File
@@ -11,15 +11,15 @@
"test:unit": "node --experimental-strip-types --test src/utils/*.test.mjs"
},
"dependencies": {
"@ant-design/icons": "^6.3.2",
"@monaco-editor/react": "^4.7.0",
"antd": "^6.5.4",
"axios": "^1.8.4",
"dayjs": "^1.11.19",
"lucide-react": "^0.544.0",
"qrcode": "^1.5.4",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-router-dom": "^7.18.2",
"dayjs": "^1.11.19",
"zustand": "^5.0.3"
},
"devDependencies": {
+1 -1
View File
@@ -6,7 +6,7 @@ import {
UserOutlined,
GlobalOutlined,
BgColorsOutlined,
} from '@ant-design/icons';
} from '../icons';
import { useAuthStore } from '../stores/authStore';
import { useThemeStore, ThemeMode } from '../stores/themeStore';
import { useI18n, LOCALE_OPTIONS, type Locale } from '../i18n';
@@ -3,7 +3,7 @@ import { message,
Form, Input, InputNumber, Select, Switch, Divider, Alert, Space, Typography, Button, Card, Radio,
} from 'antd';
import { generateMaterial } from '../api/listeners';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { MinusCircleOutlined, PlusOutlined } from '../icons';
import { useI18n } from '../i18n';
import RealityTargetFields from './RealityTargetFields';
+1 -1
View File
@@ -1,5 +1,5 @@
import { Alert, Button, Descriptions, Drawer, Space, Table, Tag, Typography } from 'antd';
import { ReloadOutlined } from '@ant-design/icons';
import { ReloadOutlined } from '../icons';
import type { ListenerRuntime } from '../api/listenerRuntime';
import type { Listener } from '../api/nodes';
import { listenerAvailability, listenerDiagnosticReason } from '../utils/listenerAvailability';
+1 -1
View File
@@ -14,7 +14,7 @@ import {
ProfileOutlined,
ControlOutlined,
LogoutOutlined,
} from '@ant-design/icons';
} from '../icons';
import { useLocation, useNavigate } from 'react-router-dom';
import { useI18n } from '../i18n';
import { useAuthStore } from '../stores/authStore';
+1 -1
View File
@@ -13,7 +13,7 @@ import {
ControlOutlined,
ToolOutlined,
LogoutOutlined,
} from '@ant-design/icons';
} from '../icons';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAuthStore } from '../stores/authStore';
import { useI18n } from '../i18n';
+166
View File
@@ -0,0 +1,166 @@
/**
* Panel icons — Lucide under the hood, Ant Design–style *Outlined names for drop-in replacement.
* Import from `../icons` or `../../icons` instead of `@ant-design/icons`.
*/
import React from 'react';
import type { LucideProps } from 'lucide-react';
import {
Plus,
RefreshCw,
Trash2,
Pencil,
Globe,
Palette,
Users,
Link2,
Share2,
Copy,
LayoutDashboard,
FileText,
Server,
User,
Lock,
Shield,
PlayCircle,
Square,
RotateCcw,
Download,
Send,
Eraser,
MoreHorizontal,
QrCode,
Save,
BadgeCheck,
LayoutGrid,
Boxes,
MonitorPlay,
GitFork,
Rocket,
SlidersHorizontal,
Wrench,
LogOut,
ArrowLeft,
Undo2,
HeartPulse,
RefreshCcw,
Monitor,
HardDrive,
LogIn,
LineChart,
Check,
GitBranch,
History,
Power,
FileDiff,
Info,
CloudDownload,
CloudUpload,
Cable,
Settings,
Bell,
Network,
Timer,
PanelLeftClose,
PanelLeftOpen,
MinusCircle,
} from 'lucide-react';
type IconProps = LucideProps & {
/** Ant Design icons often pass style.fontSize — map to Lucide `size`. */
style?: React.CSSProperties & { fontSize?: number | string };
className?: string;
twoToneColor?: string;
spin?: boolean;
rotate?: number;
};
function wrap(Icon: React.ComponentType<LucideProps>, displayName: string) {
const Comp = React.forwardRef<SVGSVGElement, IconProps>(function LucideAntIcon(
{ style, className, spin, rotate, size, ...rest },
ref,
) {
const fontSize = style?.fontSize;
const resolvedSize =
size ??
(typeof fontSize === 'number' ? fontSize : typeof fontSize === 'string' && fontSize.endsWith('px') ? parseFloat(fontSize) : 16);
const mergedStyle: React.CSSProperties = {
...style,
...(spin ? { animation: 'spin 1s linear infinite' } : null),
...(rotate != null ? { transform: `rotate(${rotate}deg)` } : null),
verticalAlign: style?.verticalAlign ?? 'middle',
};
return (
<Icon
ref={ref}
size={resolvedSize}
strokeWidth={1.75}
className={className}
style={mergedStyle}
aria-hidden
{...rest}
/>
);
});
Comp.displayName = displayName;
return Comp;
}
export const PlusOutlined = wrap(Plus, 'PlusOutlined');
export const ReloadOutlined = wrap(RefreshCw, 'ReloadOutlined');
export const DeleteOutlined = wrap(Trash2, 'DeleteOutlined');
export const EditOutlined = wrap(Pencil, 'EditOutlined');
export const GlobalOutlined = wrap(Globe, 'GlobalOutlined');
export const BgColorsOutlined = wrap(Palette, 'BgColorsOutlined');
export const TeamOutlined = wrap(Users, 'TeamOutlined');
export const LinkOutlined = wrap(Link2, 'LinkOutlined');
export const ShareAltOutlined = wrap(Share2, 'ShareAltOutlined');
export const CopyOutlined = wrap(Copy, 'CopyOutlined');
export const DashboardOutlined = wrap(LayoutDashboard, 'DashboardOutlined');
export const ProfileOutlined = wrap(FileText, 'ProfileOutlined');
export const CloudServerOutlined = wrap(Server, 'CloudServerOutlined');
export const UserOutlined = wrap(User, 'UserOutlined');
export const LockOutlined = wrap(Lock, 'LockOutlined');
export const SafetyOutlined = wrap(Shield, 'SafetyOutlined');
export const PlayCircleOutlined = wrap(PlayCircle, 'PlayCircleOutlined');
export const StopOutlined = wrap(Square, 'StopOutlined');
export const RedoOutlined = wrap(RotateCcw, 'RedoOutlined');
export const DownloadOutlined = wrap(Download, 'DownloadOutlined');
export const SendOutlined = wrap(Send, 'SendOutlined');
export const ClearOutlined = wrap(Eraser, 'ClearOutlined');
export const MoreOutlined = wrap(MoreHorizontal, 'MoreOutlined');
export const QrcodeOutlined = wrap(QrCode, 'QrcodeOutlined');
export const FileTextOutlined = wrap(FileText, 'FileTextOutlined');
export const SaveOutlined = wrap(Save, 'SaveOutlined');
export const SafetyCertificateOutlined = wrap(BadgeCheck, 'SafetyCertificateOutlined');
export const AppstoreOutlined = wrap(LayoutGrid, 'AppstoreOutlined');
export const DeploymentUnitOutlined = wrap(Boxes, 'DeploymentUnitOutlined');
export const FundProjectionScreenOutlined = wrap(MonitorPlay, 'FundProjectionScreenOutlined');
export const ForkOutlined = wrap(GitFork, 'ForkOutlined');
export const RocketOutlined = wrap(Rocket, 'RocketOutlined');
export const ControlOutlined = wrap(SlidersHorizontal, 'ControlOutlined');
export const ToolOutlined = wrap(Wrench, 'ToolOutlined');
export const LogoutOutlined = wrap(LogOut, 'LogoutOutlined');
export const ArrowLeftOutlined = wrap(ArrowLeft, 'ArrowLeftOutlined');
export const RollbackOutlined = wrap(Undo2, 'RollbackOutlined');
export const MedicineBoxOutlined = wrap(HeartPulse, 'MedicineBoxOutlined');
export const CloudSyncOutlined = wrap(RefreshCcw, 'CloudSyncOutlined');
export const DesktopOutlined = wrap(Monitor, 'DesktopOutlined');
export const HddOutlined = wrap(HardDrive, 'HddOutlined');
export const LoginOutlined = wrap(LogIn, 'LoginOutlined');
export const FundOutlined = wrap(LineChart, 'FundOutlined');
export const CheckOutlined = wrap(Check, 'CheckOutlined');
export const BranchesOutlined = wrap(GitBranch, 'BranchesOutlined');
export const HistoryOutlined = wrap(History, 'HistoryOutlined');
export const PoweroffOutlined = wrap(Power, 'PoweroffOutlined');
export const DiffOutlined = wrap(FileDiff, 'DiffOutlined');
export const InfoCircleOutlined = wrap(Info, 'InfoCircleOutlined');
export const CloudDownloadOutlined = wrap(CloudDownload, 'CloudDownloadOutlined');
export const CloudUploadOutlined = wrap(CloudUpload, 'CloudUploadOutlined');
export const ApiOutlined = wrap(Cable, 'ApiOutlined');
export const SettingOutlined = wrap(Settings, 'SettingOutlined');
export const BellOutlined = wrap(Bell, 'BellOutlined');
export const ClusterOutlined = wrap(Network, 'ClusterOutlined');
export const FieldTimeOutlined = wrap(Timer, 'FieldTimeOutlined');
export const MenuFoldOutlined = wrap(PanelLeftClose, 'MenuFoldOutlined');
export const MenuUnfoldOutlined = wrap(PanelLeftOpen, 'MenuUnfoldOutlined');
export const MinusCircleOutlined = wrap(MinusCircle, 'MinusCircleOutlined');
+1 -1
View File
@@ -14,7 +14,7 @@ import {
HddOutlined,
LoginOutlined,
ReloadOutlined,
} from '@ant-design/icons';
} from '../icons';
import {
fetchCluster,
createClusterNode,
+1 -1
View File
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Card, Table, Button, Space, Modal, Form, Input, Select, message, Popconfirm, Tabs } from 'antd';
import { PlusOutlined, DeleteOutlined, EditOutlined, DownloadOutlined, CheckOutlined, FileTextOutlined } from '@ant-design/icons';
import { PlusOutlined, DeleteOutlined, EditOutlined, DownloadOutlined, CheckOutlined, FileTextOutlined } from '../icons';
import {
fetchProxies, createProxy, updateProxy, deleteProxy,
fetchConfigYAML, generateConfig, validateConfigYAML, applyConfigYAML, rollbackConfig,
+1 -1
View File
@@ -1,6 +1,6 @@
import { useState, useEffect, useRef } from 'react';
import { Alert, Button, Card, Descriptions, Modal, Select, Space, Spin, Steps, Typography, message } from 'antd';
import { PlayCircleOutlined, StopOutlined, RedoOutlined, DownloadOutlined, RollbackOutlined } from '@ant-design/icons';
import { PlayCircleOutlined, StopOutlined, RedoOutlined, DownloadOutlined, RollbackOutlined } from '../icons';
import { coreAPI, type CoreStatus, type CoreRelease, type CoreUpdateStatus } from '../api/core';
import { isCanceledError } from '../api/client';
import { useI18n } from '../i18n';
+1 -1
View File
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Card, Row, Col, Statistic, Button, Space, Tag, Progress, Typography, message, theme } from 'antd';
import { PlayCircleOutlined, StopOutlined, RedoOutlined } from '@ant-design/icons';
import { PlayCircleOutlined, StopOutlined, RedoOutlined } from '../icons';
import { fetchDashboard, startMihomo, stopMihomo, restartMihomo } from '../api/system';
import { isCanceledError } from '../api/client';
import { useI18n } from '../i18n';
+1 -1
View File
@@ -1,7 +1,7 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { Table, Button, Space, Tag, Modal, Form, Input,
InputNumber, Select, Switch, message, Popconfirm, Tooltip, Card, Tabs, Descriptions, Divider, Dropdown, Checkbox, Spin, Alert } from 'antd';
import { PlusOutlined, ReloadOutlined, QrcodeOutlined, DeleteOutlined, EditOutlined, CopyOutlined, BranchesOutlined, HistoryOutlined, SaveOutlined, PoweroffOutlined, DiffOutlined, MoreOutlined, SafetyCertificateOutlined } from '@ant-design/icons';
import { PlusOutlined, ReloadOutlined, QrcodeOutlined, DeleteOutlined, EditOutlined, CopyOutlined, BranchesOutlined, HistoryOutlined, SaveOutlined, PoweroffOutlined, DiffOutlined, MoreOutlined, SafetyCertificateOutlined } from '../icons';
import {
fetchListeners, createListener, quickCreateListener, updateListener, deleteListener, reloadListener, exportNodeURI, normalizeId, Listener,
} from '../api/nodes';
+1 -1
View File
@@ -7,7 +7,7 @@ import {
BgColorsOutlined,
SafetyOutlined,
ArrowLeftOutlined,
} from '@ant-design/icons';
} from '../icons';
import { useNavigate, useLocation } from 'react-router-dom';
import { login } from '../api/auth';
import { useAuthStore } from '../stores/authStore';
+1 -1
View File
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Card, List, Tag, Button, Space, Empty, Spin, message, theme } from 'antd';
import { ReloadOutlined, ClearOutlined } from '@ant-design/icons';
import { ReloadOutlined, ClearOutlined } from '../icons';
import dayjs from 'dayjs';
import client from '../api/client';
import { useI18n } from '../i18n';
+1 -1
View File
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Card, Table, Button, Space, Modal, Form, Input, InputNumber, Select, message, Popconfirm } from 'antd';
import { PlusOutlined, DeleteOutlined, SaveOutlined } from '@ant-design/icons';
import { PlusOutlined, DeleteOutlined, SaveOutlined } from '../icons';
import { fetchGroups, saveGroups, fetchRules, saveRules, GroupEntry } from '../api/routing';
import { useI18n } from '../i18n';
import useIsMobile from '../hooks/useIsMobile';
+1 -1
View File
@@ -48,7 +48,7 @@ import {
ProfileOutlined,
CloudServerOutlined,
FieldTimeOutlined,
} from '@ant-design/icons';
} from '../icons';
import {
downloadBackup,
restoreDatabase,
+1 -1
View File
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
Alert, Button, Card, Collapse, Empty, Input, Select, Space, Spin, Tabs, Tag, Typography, message,
} from 'antd';
import { CopyOutlined, QrcodeOutlined, ReloadOutlined, LinkOutlined } from '@ant-design/icons';
import { CopyOutlined, QrcodeOutlined, ReloadOutlined, LinkOutlined } from '../icons';
import { useSearchParams } from 'react-router-dom';
import { useI18n } from '../i18n';
import useIsMobile from '../hooks/useIsMobile';
+1 -1
View File
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Card, Table, Tag, Space, Statistic, Row, Col, message, Button } from 'antd';
import { ReloadOutlined } from '@ant-design/icons';
import { ReloadOutlined } from '../icons';
import { fetchTrafficStatus, fetchTrafficUsers, fetchConnections, UserTraffic, ConnectionView, TrafficStatus } from '../api/traffic';
import { useI18n } from '../i18n';
import PageHeader from '../components/PageHeader';
+1 -1
View File
@@ -3,7 +3,7 @@ import {
Card, Table, Button, Space, Modal, Form, Input, Switch, message, Popconfirm, Select, Tag,
InputNumber, DatePicker, Progress, Tooltip, Dropdown, Checkbox, Spin,
} from 'antd';
import { PlusOutlined, DeleteOutlined, EditOutlined, LinkOutlined, ClearOutlined, ShareAltOutlined, CopyOutlined, MoreOutlined, FundOutlined } from '@ant-design/icons';
import { PlusOutlined, DeleteOutlined, EditOutlined, LinkOutlined, ClearOutlined, ShareAltOutlined, CopyOutlined, MoreOutlined, FundOutlined } from '../icons';
import dayjs from 'dayjs';
import {
fetchUsers, createUser, updateUser, deleteUser, resetUserTraffic, deleteDepletedUsers, batchUsers,
+6
View File
@@ -1189,3 +1189,9 @@ html.dark .app-header-bar,
padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)) !important;
}
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}