@allbluecn/web-app 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/package.json +230 -30
  2. package/src/components/iteration/auto-schedule-dialog.tsx +150 -0
  3. package/src/components/iteration/burndown-chart.tsx +63 -0
  4. package/src/components/iteration/constants.ts +28 -0
  5. package/src/components/iteration/create-iteration-dialog.tsx +140 -0
  6. package/src/components/iteration/iteration-card.tsx +60 -0
  7. package/src/components/iteration/iteration-editor.tsx +116 -0
  8. package/src/components/iteration/iteration-progress-bar.tsx +44 -0
  9. package/src/components/iteration/iteration-status-badge.tsx +33 -0
  10. package/src/components/knowledge/dialog/knowledge-form-dialog.tsx +21 -30
  11. package/src/components/layout/sidebar-03/__tests__/nav-workspace.test.tsx +2 -2
  12. package/src/components/layout/sidebar-03/nav-workspace.tsx +2 -2
  13. package/src/components/project/create-project-dialog.tsx +44 -57
  14. package/src/components/shared/__tests__/lucide-curated-icons.test.ts +83 -0
  15. package/src/components/shared/__tests__/lucide-icon-data.test.ts +131 -0
  16. package/src/components/shared/__tests__/lucide-icon-picker.test.tsx +197 -0
  17. package/src/components/shared/lucide-icon-picker/curated-icons.ts +478 -0
  18. package/src/components/shared/lucide-icon-picker/icon-data.ts +109 -0
  19. package/src/components/shared/lucide-icon-picker/index.tsx +82 -0
  20. package/src/components/shared/lucide-icon-picker/lucide-icon-by-name.tsx +78 -0
  21. package/src/components/shared/lucide-icon-picker/panel.tsx +163 -0
  22. package/src/components/story/__tests__/constants.test.ts +255 -0
  23. package/src/components/story/ai/story-ai-panel.tsx +23 -15
  24. package/src/components/story/ai/story-ai-preview-list.tsx +19 -0
  25. package/src/components/story/constants.ts +33 -1
  26. package/src/components/story/create-story-dialog.tsx +30 -10
  27. package/src/components/story/detail/__tests__/categories.test.tsx +62 -0
  28. package/src/components/story/detail/__tests__/dependencies-button.test.tsx +49 -0
  29. package/src/components/story/detail/activity-timeline.tsx +11 -4
  30. package/src/components/story/detail/story-detail-body.tsx +89 -38
  31. package/src/components/story/detail/story-detail-toolbar/associated-attachments-panel.tsx +118 -9
  32. package/src/components/story/detail/story-detail-toolbar/children.tsx +7 -4
  33. package/src/components/story/detail/story-detail-toolbar/dependency-panel.tsx +67 -7
  34. package/src/components/story/detail/story-detail-toolbar.tsx +6 -1
  35. package/src/components/story/detail/story-properties.tsx +21 -4
  36. package/src/components/story/display/__tests__/group-fields.test.ts +107 -0
  37. package/src/components/story/display/group-resolver.tsx +2 -2
  38. package/src/components/story/inline-editors/__tests__/dependency-type-select.test.tsx +155 -0
  39. package/src/components/story/inline-editors/__tests__/labels-editor.test.tsx +155 -0
  40. package/src/components/story/inline-editors/__tests__/priority-editor.test.tsx +173 -0
  41. package/src/components/story/inline-editors/__tests__/state-editor.test.tsx +174 -0
  42. package/src/components/story/inline-editors/dependency-type-select.tsx +180 -0
  43. package/src/components/story/inline-editors/index.ts +2 -1
  44. package/src/components/story/inline-editors/labels-editor.tsx +159 -3
  45. package/src/components/story/inline-editors/story-select-dialog.tsx +22 -59
  46. package/src/components/story/peek-panel.tsx +121 -21
  47. package/src/components/story/relations/link-manage-dialog.tsx +2 -1
  48. package/src/components/story/relations/story-ref-row.tsx +17 -27
  49. package/src/components/story/story-panel-header.tsx +25 -19
  50. package/src/components/story/story-toolbar.tsx +3 -3
  51. package/src/components/story/transfer-story-popover.tsx +2 -2
  52. package/src/components/story/types.ts +1 -0
  53. package/src/components/story/views/create-view-dialog.tsx +3 -3
  54. package/src/components/story/views/story-list/__tests__/group-header.test.tsx +219 -0
  55. package/src/components/story/views/story-list/group.tsx +1 -1
  56. package/src/components/story/views/story-list/inline-story-creator.tsx +2 -2
  57. package/src/components/story/views/story-list/row.tsx +1 -1
  58. package/src/components/workspace/create-workspace-dialog.tsx +41 -49
  59. package/src/lib/__tests__/project-display-id.test.ts +8 -5
  60. package/src/lib/changelog/sdk-versions.ts +20 -20
  61. package/src/lib/iteration/__tests__/status.test.ts +41 -0
  62. package/src/lib/iteration/status.ts +28 -0
  63. package/src/lib/project-display-id.ts +14 -5
  64. package/src/lib/project-module-meta.ts +77 -0
  65. package/src/lib/utils.d.ts +1 -1
  66. package/src/providers/index.tsx +6 -0
  67. package/src/routeTree.gen.ts +54 -0
  68. package/src/routes/__root.tsx +0 -8
  69. package/src/routes/_nav/knowledge/index.lazy.tsx +2 -2
  70. package/src/routes/_nav/projects/$projectId/$storyId/route.lazy.tsx +52 -25
  71. package/src/routes/_nav/projects/$projectId/$storyId/route.tsx +6 -3
  72. package/src/routes/_nav/projects/$projectId/index.lazy.tsx +32 -15
  73. package/src/routes/_nav/projects/$projectId/iterations/$iterationId/route.lazy.tsx +289 -0
  74. package/src/routes/_nav/projects/$projectId/iterations/$iterationId/route.tsx +27 -0
  75. package/src/routes/_nav/projects/$projectId/iterations/index.lazy.tsx +111 -0
  76. package/src/routes/_nav/projects/$projectId/iterations/index.tsx +24 -0
  77. package/src/routes/_nav/projects/$projectId/route.tsx +4 -2
  78. package/src/routes/_nav/projects/$projectId/settings/route.lazy.tsx +4 -4
  79. package/src/routes/_nav/stories/$storyId/route.lazy.tsx +5 -1
  80. package/src/routes/_nav/stories/$storyId/route.tsx +4 -0
  81. package/src/routes/_nav/workspaces/$workspaceId/route.lazy.tsx +3 -3
  82. package/src/routes/_nav/workspaces/$workspaceId/settings/route.lazy.tsx +4 -4
  83. package/src/routes/_nav/workspaces/index.lazy.tsx +3 -3
  84. package/src/server/serverFns/iteration/__tests__/auto-schedule-core.test.ts +62 -0
  85. package/src/server/serverFns/iteration/__tests__/burndown-core.test.ts +90 -0
  86. package/src/server/serverFns/iteration/__tests__/iteration-crud.test.ts +211 -0
  87. package/src/server/serverFns/iteration/__tests__/iteration-stories.test.ts +155 -0
  88. package/src/server/serverFns/iteration/__tests__/iteration-transfer.test.ts +136 -0
  89. package/src/server/serverFns/iteration/auto-schedule-core.ts +54 -0
  90. package/src/server/serverFns/iteration/auto-schedule-internal.ts +88 -0
  91. package/src/server/serverFns/iteration/burndown-core.ts +60 -0
  92. package/src/server/serverFns/iteration/index.ts +22 -0
  93. package/src/server/serverFns/iteration/iteration-auto-schedule.ts +66 -0
  94. package/src/server/serverFns/iteration/iteration-burndown.ts +70 -0
  95. package/src/server/serverFns/iteration/iteration-crud.ts +208 -0
  96. package/src/server/serverFns/iteration/iteration-stories.ts +111 -0
  97. package/src/server/serverFns/iteration/iteration-transfer.ts +42 -0
  98. package/src/server/serverFns/iteration/schemas.ts +58 -0
  99. package/src/server/serverFns/iteration/transfer-internal.ts +62 -0
  100. package/src/server/serverFns/project/module-overview.ts +109 -0
  101. package/src/server/serverFns/project.ts +2 -2
  102. package/src/server/serverFns/story/__tests__/label-suggest-fn.test.ts +100 -0
  103. package/src/server/serverFns/story/__tests__/labels.test.ts +67 -0
  104. package/src/server/serverFns/story/__tests__/story-dependencies.test.ts +106 -2
  105. package/src/server/serverFns/story/index.ts +3 -0
  106. package/src/server/serverFns/story/story-assoc.ts +36 -4
  107. package/src/server/serverFns/story/story-attachments.ts +20 -2
  108. package/src/{components/project/project-icon.tsx → server/serverFns/story/story-crud/label-palette.ts} +16 -19
  109. package/src/server/serverFns/story/story-crud/label-suggest-core.ts +88 -0
  110. package/src/server/serverFns/story/story-crud/label-suggest.ts +38 -0
  111. package/src/{components/knowledge/knowledge-icon.tsx → server/serverFns/story/story-crud/label-upsert.ts} +13 -19
  112. package/src/server/serverFns/story/story-crud/labels.ts +3 -5
  113. package/src/server/serverFns/story/story-crud.ts +32 -2
  114. package/src/server/serverFns/story/story-dependencies.ts +123 -2
  115. package/src/server/serverFns/story/story-links.ts +30 -6
  116. package/src/server/serverFns/story/story-transfer.ts +5 -4
  117. package/src/server/serverFns/story/types.ts +1 -0
  118. package/src/types/project.ts +5 -5
  119. package/src/components/project/project-animated-icon.tsx +0 -73
  120. package/src/components/shared/icon-packs/index.ts +0 -1
  121. package/src/components/shared/icon-packs/knowledge.ts +0 -1
  122. package/src/components/shared/icon-packs/prd.ts +0 -1
  123. package/src/components/shared/icon-packs/project.ts +0 -1
  124. package/src/components/shared/icon-picker.tsx +0 -1
  125. package/src/lib/project-mock.ts +0 -156
@@ -0,0 +1,478 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ // 精选图标名单:按 spec 三规则(否定变体去反 / 语义相近留常用 / 成组留代表)
19
+ // 由 AI 按语义域清单生成 + 人工校对,显式维护(增删直接改此文件)。
20
+ // 机械禁则由 lucide-curated-icons.test.ts 强制校验。
21
+
22
+ import {
23
+ Accessibility, Activity, Ambulance, Ampersand, Anchor, Angry, Aperture, Archive, ArrowDown, ArrowDownLeft,
24
+ ArrowDownRight, ArrowLeft, ArrowRight, ArrowUp, ArrowUpLeft, ArrowUpRight, Asterisk, AtSign, Atom, AudioLines,
25
+ Award, BadgeCheck, Bandage, Banknote, Barcode, Bath, Battery, BatteryCharging, Bed, BedDouble,
26
+ Beer, Bell, BellPlus, BellRing, Bike, Binary, Binoculars, Bird, Bold, Book,
27
+ BookA, BookAlert, BookCheck, BookOpen, Bookmark, Braces, Brain, Briefcase, BriefcaseBusiness, Bug,
28
+ Building, Bus, Cake, Calculator, Calendar, CalendarArrowDown, CalendarArrowUp, CalendarCheck, CalendarClock, CalendarDays,
29
+ CalendarPlus, Camera, Car, CaseUpper, Cat, ChartArea, ChartColumn, ChartLine, ChartPie, Check,
30
+ CheckCheck, ChefHat, CircleCheck, CircleDollarSign, CircleDot, CircleMinus, CirclePlus, Clapperboard, Clipboard, ClipboardCheck,
31
+ ClipboardPaste, Clock, Cloud, CloudBackup, CloudCheck, CloudDownload, CloudFog, CloudLightning, CloudRain, CloudSnow,
32
+ CloudSun, CloudUpload, Club, Code, CodeXml, Coffee, Coins, Compass, Component, Contact,
33
+ Container, Contrast, Copy, Copyright, Cpu, CreditCard, Crown, CupSoda, Database, Diamond,
34
+ Divide, Dna, Dog, DollarSign, DoorClosed, DoorOpen, Download, Droplet, Dumbbell, Equal,
35
+ EthernetPort, ExternalLink, Eye, Factory, FastForward, File, FileArchive, FileBadge, FileBox, FileCheck,
36
+ FileClock, FileCode, FilePlus, FileText, Files, Film, Fish, Flag, FlaskConical, Flower,
37
+ Folder, FolderCheck, FolderClock, FolderClosed, FolderCode, FolderGit, FolderHeart, FolderKanban, FolderOpen, FolderPlus,
38
+ FolderRoot, FolderSearch, FolderSync, FolderTree, Frown, Funnel, Gamepad, Gauge, Gift, Ghost,
39
+ GitBranch, GitCommitHorizontal, GitCommitVertical, GitCompare, GitFork, GitGraph, GitMerge, Globe, GraduationCap, Grid2x2Check,
40
+ Grid2x2Plus, Guitar, Hammer, HardDrive, Hash, Headphones, Headset, Heart, HeartPulse, Helicopter,
41
+ Hexagon, Hospital, Hourglass, IdCard, Image, ImageDown, ImagePlus, ImageUp, Images, Inbox,
42
+ Infinity, Info, Italic, Joystick, Key, KeyRound, Keyboard, Lamp, Landmark, Laptop,
43
+ Laugh, Layers, LayoutDashboard, LayoutFreeform, LayoutGrid, LayoutList, LayoutPanelLeft, LayoutTemplate, Leaf, Library,
44
+ Lightbulb, Link, List, ListChecks, ListOrdered, Loader, LoaderCircle, LoaderPinwheel, LocateFixed, Lock,
45
+ LogIn, LogOut, Luggage, Mail, MailCheck, MailOpen, MailPlus, MailSearch, MailWarning, Mailbox,
46
+ Map, MapPin, Medal, Megaphone, Meh, MessageCircle, MessageCircleCheck, MessageCircleHeart, MessageCircleMore, MessageCirclePlus,
47
+ MessageCircleQuestionMark, MessageSquare, MessageSquareCheck, MessageSquareCode, MessageSquareLock, MessagesSquare, Mic, Microscope, Minus, Monitor,
48
+ Moon, Mountain, MountainSnow, Mouse, MousePointer, MousePointerClick, Music, Navigation, Network, Newspaper,
49
+ Nfc, Octagon, PaintBucket, Paintbrush, Palette, PanelTop, PartyPopper, Pause, PenLine, PenTool,
50
+ Pencil, Percent, PersonStanding, Phone, PhoneCall, Piano, PiggyBank, Pill, Pizza, Plane,
51
+ Play, Plus, Printer, Puzzle, QrCode, Rabbit, Radio, Rainbow, Receipt, Refrigerator,
52
+ Reply, Rewind, Rocket, Route, Sailboat, Satellite, Save, Scan, ScanBarcode, ScanFace,
53
+ ScanLine, ScanSearch, ScanText, School, Search, SearchAlert, SearchCode, Send, Server, Shapes,
54
+ Shield, ShieldAlert, ShieldCheck, Ship, ShoppingBag, ShoppingBasket, ShoppingCart, Sigma, Signal, Signpost,
55
+ Siren, SkipBack, SkipForward, Slash, SlidersHorizontal, Smartphone, Smile, Skull, Snowflake, Sofa,
56
+ Spade, Sparkles, Spline, Sprout, Square, SquarePen, SquareTerminal, Stamp, Star, StarCheck,
57
+ StarHalf, StarMinus, StarPlus, Stethoscope, Store, Strikethrough, Sun, Sunrise, Sunset, SwatchBook,
58
+ Syringe, Table, TableOfContents, Tablet, Tag, Tags, Target, Tent, Terminal, TestTube,
59
+ TextCursor, Thermometer, ThumbsDown, ThumbsUp, Ticket, Timer, ToyBrick, TrainFront, TreePine, Trees,
60
+ TrendingDown, TrendingUp, Triangle, TriangleAlert, Trophy, Truck, Turtle, Type, Umbrella, Underline,
61
+ Unlink, Upload, User, UserCheck, UserCog, UserMinus, UserPlus, UserRound, UserSearch, Users,
62
+ UsersRound, Utensils, Video, Volleyball, Volume, Wallet, WashingMachine, Watch, Wifi, Wind,
63
+ Wine, Workflow, Wrench, Zap,
64
+ } from "lucide-react";
65
+
66
+ import type { CuratedIcon } from "./icon-data";
67
+
68
+ export const CURATED_ICONS: CuratedIcon[] = [
69
+ { name: "arrow-up", Icon: ArrowUp, zh: ["上箭头", "向上"] },
70
+ { name: "arrow-down", Icon: ArrowDown, zh: ["下箭头", "向下"] },
71
+ { name: "arrow-left", Icon: ArrowLeft, zh: ["左箭头", "向左"] },
72
+ { name: "arrow-right", Icon: ArrowRight, zh: ["右箭头", "向右"] },
73
+ { name: "arrow-up-left", Icon: ArrowUpLeft, zh: ["左上箭头"] },
74
+ { name: "arrow-up-right", Icon: ArrowUpRight, zh: ["右上箭头"] },
75
+ { name: "arrow-down-left", Icon: ArrowDownLeft, zh: ["左下箭头"] },
76
+ { name: "arrow-down-right", Icon: ArrowDownRight, zh: ["右下箭头"] },
77
+ { name: "briefcase", Icon: Briefcase, zh: ["公文包"] },
78
+ { name: "briefcase-business", Icon: BriefcaseBusiness, zh: ["商务公文包"] },
79
+ { name: "building", Icon: Building, zh: ["办公楼"] },
80
+ { name: "landmark", Icon: Landmark, zh: ["地标"] },
81
+ { name: "factory", Icon: Factory, zh: ["工厂"] },
82
+ { name: "store", Icon: Store, zh: ["商店"] },
83
+ { name: "calculator", Icon: Calculator, zh: ["计算器"] },
84
+ { name: "wallet", Icon: Wallet, zh: ["钱包"] },
85
+ { name: "credit-card", Icon: CreditCard, zh: ["信用卡"] },
86
+ { name: "banknote", Icon: Banknote, zh: ["纸币"] },
87
+ { name: "coins", Icon: Coins, zh: ["硬币"] },
88
+ { name: "circle-dollar-sign", Icon: CircleDollarSign, zh: ["美元符号"] },
89
+ { name: "dollar-sign", Icon: DollarSign, zh: ["美元"] },
90
+ { name: "receipt", Icon: Receipt, zh: ["收据"] },
91
+ { name: "piggy-bank", Icon: PiggyBank, zh: ["存钱罐"] },
92
+ { name: "percent", Icon: Percent, zh: ["百分比"] },
93
+ { name: "chart-column", Icon: ChartColumn, zh: ["柱状图"] },
94
+ { name: "chart-pie", Icon: ChartPie, zh: ["饼图"] },
95
+ { name: "chart-line", Icon: ChartLine, zh: ["折线图"] },
96
+ { name: "chart-area", Icon: ChartArea, zh: ["面积图"] },
97
+ { name: "trending-up", Icon: TrendingUp, zh: ["上升趋势"] },
98
+ { name: "trending-down", Icon: TrendingDown, zh: ["下降趋势"] },
99
+ { name: "heart-pulse", Icon: HeartPulse, zh: ["心跳"] },
100
+ { name: "stethoscope", Icon: Stethoscope, zh: ["听诊器"] },
101
+ { name: "pill", Icon: Pill, zh: ["药丸"] },
102
+ { name: "syringe", Icon: Syringe, zh: ["注射器"] },
103
+ { name: "hospital", Icon: Hospital, zh: ["医院"] },
104
+ { name: "bandage", Icon: Bandage, zh: ["绷带"] },
105
+ { name: "brain", Icon: Brain, zh: ["大脑"] },
106
+ { name: "graduation-cap", Icon: GraduationCap, zh: ["学位帽"] },
107
+ { name: "school", Icon: School, zh: ["学校"] },
108
+ { name: "library", Icon: Library, zh: ["图书馆"] },
109
+ { name: "book", Icon: Book, zh: ["书"] },
110
+ { name: "book-open", Icon: BookOpen, zh: ["打开的书"] },
111
+ { name: "flask-conical", Icon: FlaskConical, zh: ["锥形瓶"] },
112
+ { name: "microscope", Icon: Microscope, zh: ["显微镜"] },
113
+ { name: "atom", Icon: Atom, zh: ["原子"] },
114
+ { name: "dna", Icon: Dna, zh: ["DNA"] },
115
+ { name: "test-tube", Icon: TestTube, zh: ["试管"] },
116
+ { name: "code", Icon: Code, zh: ["代码"] },
117
+ { name: "code-xml", Icon: CodeXml, zh: ["XML代码"] },
118
+ { name: "terminal", Icon: Terminal, zh: ["终端"] },
119
+ { name: "square-terminal", Icon: SquareTerminal, zh: ["方终端"] },
120
+ { name: "cpu", Icon: Cpu, zh: ["CPU"] },
121
+ { name: "database", Icon: Database, zh: ["数据库"] },
122
+ { name: "server", Icon: Server, zh: ["服务器"] },
123
+ { name: "cloud", Icon: Cloud, zh: ["云"] },
124
+ { name: "bug", Icon: Bug, zh: ["Bug"] },
125
+ { name: "component", Icon: Component, zh: ["组件"] },
126
+ { name: "braces", Icon: Braces, zh: ["花括号"] },
127
+ { name: "workflow", Icon: Workflow, zh: ["工作流"] },
128
+ { name: "git-branch", Icon: GitBranch, zh: ["分支"] },
129
+ { name: "layers", Icon: Layers, zh: ["图层"] },
130
+ { name: "palette", Icon: Palette, zh: ["调色板"] },
131
+ { name: "paintbrush", Icon: Paintbrush, zh: ["画笔"] },
132
+ { name: "paint-bucket", Icon: PaintBucket, zh: ["油漆桶"] },
133
+ { name: "camera", Icon: Camera, zh: ["相机"] },
134
+ { name: "image", Icon: Image, zh: ["图片"] },
135
+ { name: "film", Icon: Film, zh: ["胶片"] },
136
+ { name: "music", Icon: Music, zh: ["音乐"] },
137
+ { name: "piano", Icon: Piano, zh: ["钢琴"] },
138
+ { name: "guitar", Icon: Guitar, zh: ["吉他"] },
139
+ { name: "audio-lines", Icon: AudioLines, zh: ["音频线"] },
140
+ { name: "video", Icon: Video, zh: ["视频"] },
141
+ { name: "mic", Icon: Mic, zh: ["麦克风"] },
142
+ { name: "shapes", Icon: Shapes, zh: ["形状"] },
143
+ { name: "pen-tool", Icon: PenTool, zh: ["钢笔工具"] },
144
+ { name: "coffee", Icon: Coffee, zh: ["咖啡"] },
145
+ { name: "utensils", Icon: Utensils, zh: ["餐具"] },
146
+ { name: "chef-hat", Icon: ChefHat, zh: ["厨师帽"] },
147
+ { name: "pizza", Icon: Pizza, zh: ["披萨"] },
148
+ { name: "cake", Icon: Cake, zh: ["蛋糕"] },
149
+ { name: "beer", Icon: Beer, zh: ["啤酒"] },
150
+ { name: "wine", Icon: Wine, zh: ["葡萄酒"] },
151
+ { name: "cup-soda", Icon: CupSoda, zh: ["汽水杯"] },
152
+ { name: "car", Icon: Car, zh: ["汽车"] },
153
+ { name: "bus", Icon: Bus, zh: ["公交车"] },
154
+ { name: "truck", Icon: Truck, zh: ["卡车"] },
155
+ { name: "plane", Icon: Plane, zh: ["飞机"] },
156
+ { name: "train-front", Icon: TrainFront, zh: ["火车头"] },
157
+ { name: "bike", Icon: Bike, zh: ["自行车"] },
158
+ { name: "sailboat", Icon: Sailboat, zh: ["帆船"] },
159
+ { name: "ship", Icon: Ship, zh: ["船"] },
160
+ { name: "helicopter", Icon: Helicopter, zh: ["直升机"] },
161
+ { name: "ambulance", Icon: Ambulance, zh: ["救护车"] },
162
+ { name: "rocket", Icon: Rocket, zh: ["火箭"] },
163
+ { name: "dumbbell", Icon: Dumbbell, zh: ["哑铃"] },
164
+ { name: "volleyball", Icon: Volleyball, zh: ["排球"] },
165
+ { name: "gamepad", Icon: Gamepad, zh: ["手柄"] },
166
+ { name: "joystick", Icon: Joystick, zh: ["摇杆"] },
167
+ { name: "trophy", Icon: Trophy, zh: ["奖杯"] },
168
+ { name: "medal", Icon: Medal, zh: ["勋章"] },
169
+ { name: "award", Icon: Award, zh: ["奖章"] },
170
+ { name: "sprout", Icon: Sprout, zh: ["幼苗"] },
171
+ { name: "leaf", Icon: Leaf, zh: ["叶子"] },
172
+ { name: "flower", Icon: Flower, zh: ["花"] },
173
+ { name: "trees", Icon: Trees, zh: ["树林"] },
174
+ { name: "tree-pine", Icon: TreePine, zh: ["松树"] },
175
+ { name: "shield", Icon: Shield, zh: ["盾牌"] },
176
+ { name: "shield-check", Icon: ShieldCheck, zh: ["确认盾牌"] },
177
+ { name: "crown", Icon: Crown, zh: ["王冠"] },
178
+ { name: "sparkles", Icon: Sparkles, zh: ["闪光"] },
179
+ { name: "lightbulb", Icon: Lightbulb, zh: ["灯泡"] },
180
+ { name: "file", Icon: File, zh: ["文件"] },
181
+ { name: "file-text", Icon: FileText, zh: ["文本文件"] },
182
+ { name: "file-code", Icon: FileCode, zh: ["代码文件"] },
183
+ { name: "file-plus", Icon: FilePlus, zh: ["新增文件"] },
184
+ { name: "file-check", Icon: FileCheck, zh: ["确认文件"] },
185
+ { name: "files", Icon: Files, zh: ["多文件"] },
186
+ { name: "file-archive", Icon: FileArchive, zh: ["压缩包"] },
187
+ { name: "folder", Icon: Folder, zh: ["文件夹"] },
188
+ { name: "folder-open", Icon: FolderOpen, zh: ["打开文件夹"] },
189
+ { name: "folder-plus", Icon: FolderPlus, zh: ["新建文件夹"] },
190
+ { name: "folder-tree", Icon: FolderTree, zh: ["文件夹树"] },
191
+ { name: "archive", Icon: Archive, zh: ["归档"] },
192
+ { name: "folder-kanban", Icon: FolderKanban, zh: ["看板文件夹"] },
193
+ { name: "folder-git", Icon: FolderGit, zh: ["Git文件夹"] },
194
+ { name: "folder-heart", Icon: FolderHeart, zh: ["收藏文件夹"] },
195
+ { name: "folder-check", Icon: FolderCheck, zh: ["已确认文件夹"] },
196
+ { name: "folder-clock", Icon: FolderClock, zh: ["时钟文件夹"] },
197
+ { name: "folder-closed", Icon: FolderClosed, zh: ["关闭文件夹"] },
198
+ { name: "folder-code", Icon: FolderCode, zh: ["代码文件夹"] },
199
+ { name: "folder-search", Icon: FolderSearch, zh: ["搜索文件夹"] },
200
+ { name: "folder-sync", Icon: FolderSync, zh: ["同步文件夹"] },
201
+ { name: "folder-root", Icon: FolderRoot, zh: ["根文件夹"] },
202
+ { name: "file-badge", Icon: FileBadge, zh: ["徽章文件"] },
203
+ { name: "file-box", Icon: FileBox, zh: ["盒文件"] },
204
+ { name: "file-clock", Icon: FileClock, zh: ["时钟文件"] },
205
+ { name: "pencil", Icon: Pencil, zh: ["铅笔", "编辑"] },
206
+ { name: "pen-line", Icon: PenLine, zh: ["钢笔"] },
207
+ { name: "square-pen", Icon: SquarePen, zh: ["方笔"] },
208
+ { name: "save", Icon: Save, zh: ["保存"] },
209
+ { name: "copy", Icon: Copy, zh: ["复制"] },
210
+ { name: "clipboard", Icon: Clipboard, zh: ["剪贴板"] },
211
+ { name: "clipboard-check", Icon: ClipboardCheck, zh: ["确认剪贴板"] },
212
+ { name: "clipboard-paste", Icon: ClipboardPaste, zh: ["粘贴剪贴板"] },
213
+ { name: "type", Icon: Type, zh: ["文字"] },
214
+ { name: "bold", Icon: Bold, zh: ["粗体"] },
215
+ { name: "italic", Icon: Italic, zh: ["斜体"] },
216
+ { name: "underline", Icon: Underline, zh: ["下划线"] },
217
+ { name: "strikethrough", Icon: Strikethrough, zh: ["删除线"] },
218
+ { name: "list", Icon: List, zh: ["列表"] },
219
+ { name: "list-ordered", Icon: ListOrdered, zh: ["有序列表"] },
220
+ { name: "list-checks", Icon: ListChecks, zh: ["待办列表"] },
221
+ { name: "text-cursor", Icon: TextCursor, zh: ["光标"] },
222
+ { name: "case-upper", Icon: CaseUpper, zh: ["大写"] },
223
+ { name: "search", Icon: Search, zh: ["搜索"] },
224
+ { name: "search-code", Icon: SearchCode, zh: ["代码搜索"] },
225
+ { name: "funnel", Icon: Funnel, zh: ["漏斗", "筛选"] },
226
+ { name: "sliders-horizontal", Icon: SlidersHorizontal, zh: ["水平滑块"] },
227
+ { name: "scan-search", Icon: ScanSearch, zh: ["扫描搜索"] },
228
+ { name: "search-alert", Icon: SearchAlert, zh: ["告警搜索"] },
229
+ { name: "layout-grid", Icon: LayoutGrid, zh: ["网格布局"] },
230
+ { name: "layout-list", Icon: LayoutList, zh: ["列表布局"] },
231
+ { name: "layout-dashboard", Icon: LayoutDashboard, zh: ["仪表布局"] },
232
+ { name: "layout-panel-left", Icon: LayoutPanelLeft, zh: ["左面板布局"] },
233
+ { name: "layout-template", Icon: LayoutTemplate, zh: ["模板布局"] },
234
+ { name: "layout-freeform", Icon: LayoutFreeform, zh: ["自由布局"] },
235
+ { name: "grid-2x-2-check", Icon: Grid2x2Check, zh: ["二乘二检查"] },
236
+ { name: "grid-2x-2-plus", Icon: Grid2x2Plus, zh: ["二乘二新增"] },
237
+ { name: "table", Icon: Table, zh: ["表格"] },
238
+ { name: "table-of-contents", Icon: TableOfContents, zh: ["目录"] },
239
+ { name: "panel-top", Icon: PanelTop, zh: ["顶部面板"] },
240
+ { name: "message-circle", Icon: MessageCircle, zh: ["圆形消息"] },
241
+ { name: "message-square", Icon: MessageSquare, zh: ["方形消息"] },
242
+ { name: "messages-square", Icon: MessagesSquare, zh: ["多方消息"] },
243
+ { name: "message-circle-plus", Icon: MessageCirclePlus, zh: ["新增消息"] },
244
+ { name: "send", Icon: Send, zh: ["发送"] },
245
+ { name: "reply", Icon: Reply, zh: ["回复"] },
246
+ { name: "message-circle-check", Icon: MessageCircleCheck, zh: ["已读消息"] },
247
+ { name: "message-circle-heart", Icon: MessageCircleHeart, zh: ["爱心消息"] },
248
+ { name: "message-circle-more", Icon: MessageCircleMore, zh: ["更多消息"] },
249
+ { name: "message-square-check", Icon: MessageSquareCheck, zh: ["确认消息"] },
250
+ { name: "message-square-code", Icon: MessageSquareCode, zh: ["代码消息"] },
251
+ { name: "message-square-lock", Icon: MessageSquareLock, zh: ["加密消息"] },
252
+ { name: "message-circle-question-mark", Icon: MessageCircleQuestionMark, zh: ["问号消息"] },
253
+ { name: "mail", Icon: Mail, zh: ["邮件"] },
254
+ { name: "mail-open", Icon: MailOpen, zh: ["已读邮件"] },
255
+ { name: "mail-plus", Icon: MailPlus, zh: ["新增邮件"] },
256
+ { name: "inbox", Icon: Inbox, zh: ["收件箱"] },
257
+ { name: "at-sign", Icon: AtSign, zh: ["at符号"] },
258
+ { name: "mail-search", Icon: MailSearch, zh: ["搜索邮件"] },
259
+ { name: "mailbox", Icon: Mailbox, zh: ["邮箱"] },
260
+ { name: "mail-check", Icon: MailCheck, zh: ["确认邮件"] },
261
+ { name: "mail-warning", Icon: MailWarning, zh: ["警告邮件"] },
262
+ { name: "phone", Icon: Phone, zh: ["电话"] },
263
+ { name: "phone-call", Icon: PhoneCall, zh: ["通话"] },
264
+ { name: "volume", Icon: Volume, zh: ["音量"] },
265
+ { name: "headphones", Icon: Headphones, zh: ["耳机"] },
266
+ { name: "play", Icon: Play, zh: ["播放"] },
267
+ { name: "pause", Icon: Pause, zh: ["暂停"] },
268
+ { name: "square", Icon: Square, zh: ["停止"] },
269
+ { name: "skip-forward", Icon: SkipForward, zh: ["快进"] },
270
+ { name: "skip-back", Icon: SkipBack, zh: ["快退"] },
271
+ { name: "fast-forward", Icon: FastForward, zh: ["快进"] },
272
+ { name: "rewind", Icon: Rewind, zh: ["快退"] },
273
+ { name: "images", Icon: Images, zh: ["多图片"] },
274
+ { name: "image-plus", Icon: ImagePlus, zh: ["新增图片"] },
275
+ { name: "aperture", Icon: Aperture, zh: ["光圈"] },
276
+ { name: "clapperboard", Icon: Clapperboard, zh: ["场记板"] },
277
+ { name: "image-down", Icon: ImageDown, zh: ["下载图片"] },
278
+ { name: "image-up", Icon: ImageUp, zh: ["上传图片"] },
279
+ { name: "headset", Icon: Headset, zh: ["头戴耳机"] },
280
+ { name: "newspaper", Icon: Newspaper, zh: ["报纸"] },
281
+ { name: "ticket", Icon: Ticket, zh: ["票"] },
282
+ { name: "shopping-cart", Icon: ShoppingCart, zh: ["购物车"] },
283
+ { name: "shopping-bag", Icon: ShoppingBag, zh: ["购物袋"] },
284
+ { name: "shopping-basket", Icon: ShoppingBasket, zh: ["购物篮"] },
285
+ { name: "tag", Icon: Tag, zh: ["标签"] },
286
+ { name: "tags", Icon: Tags, zh: ["多标签"] },
287
+ { name: "gift", Icon: Gift, zh: ["礼物"] },
288
+ { name: "activity", Icon: Activity, zh: ["活动"] },
289
+ { name: "gauge", Icon: Gauge, zh: ["仪表盘"] },
290
+ { name: "sigma", Icon: Sigma, zh: ["Sigma"] },
291
+ { name: "hash", Icon: Hash, zh: ["哈希"] },
292
+ { name: "binary", Icon: Binary, zh: ["二进制"] },
293
+ { name: "user", Icon: User, zh: ["用户"] },
294
+ { name: "user-round", Icon: UserRound, zh: ["圆形用户"] },
295
+ { name: "users", Icon: Users, zh: ["多用户"] },
296
+ { name: "users-round", Icon: UsersRound, zh: ["多圆形用户"] },
297
+ { name: "user-plus", Icon: UserPlus, zh: ["新增用户"] },
298
+ { name: "user-check", Icon: UserCheck, zh: ["确认用户"] },
299
+ { name: "user-cog", Icon: UserCog, zh: ["设置用户"] },
300
+ { name: "contact", Icon: Contact, zh: ["联系人"] },
301
+ { name: "id-card", Icon: IdCard, zh: ["身份证"] },
302
+ { name: "person-standing", Icon: PersonStanding, zh: ["站立的人"] },
303
+ { name: "accessibility", Icon: Accessibility, zh: ["无障碍"] },
304
+ { name: "user-minus", Icon: UserMinus, zh: ["减少用户"] },
305
+ { name: "user-search", Icon: UserSearch, zh: ["搜索用户"] },
306
+ { name: "network", Icon: Network, zh: ["网络"] },
307
+ { name: "link", Icon: Link, zh: ["链接"] },
308
+ { name: "unlink", Icon: Unlink, zh: ["取消链接"] },
309
+ { name: "external-link", Icon: ExternalLink, zh: ["外链"] },
310
+ { name: "git-merge", Icon: GitMerge, zh: ["合并"] },
311
+ { name: "git-fork", Icon: GitFork, zh: ["分叉"] },
312
+ { name: "git-graph", Icon: GitGraph, zh: ["提交图"] },
313
+ { name: "git-commit-horizontal", Icon: GitCommitHorizontal, zh: ["水平提交"] },
314
+ { name: "git-commit-vertical", Icon: GitCommitVertical, zh: ["垂直提交"] },
315
+ { name: "git-compare", Icon: GitCompare, zh: ["比较"] },
316
+ { name: "shield-alert", Icon: ShieldAlert, zh: ["警告盾牌"] },
317
+ { name: "lock", Icon: Lock, zh: ["锁"] },
318
+ { name: "key", Icon: Key, zh: ["钥匙"] },
319
+ { name: "key-round", Icon: KeyRound, zh: ["圆钥匙"] },
320
+ { name: "eye", Icon: Eye, zh: ["眼睛"] },
321
+ { name: "badge-check", Icon: BadgeCheck, zh: ["确认徽章"] },
322
+ { name: "scan-face", Icon: ScanFace, zh: ["人脸识别"] },
323
+ { name: "clock", Icon: Clock, zh: ["时钟"] },
324
+ { name: "watch", Icon: Watch, zh: ["手表"] },
325
+ { name: "timer", Icon: Timer, zh: ["定时器"] },
326
+ { name: "hourglass", Icon: Hourglass, zh: ["沙漏"] },
327
+ { name: "calendar", Icon: Calendar, zh: ["日历"] },
328
+ { name: "calendar-days", Icon: CalendarDays, zh: ["多日日历"] },
329
+ { name: "calendar-clock", Icon: CalendarClock, zh: ["日历时钟"] },
330
+ { name: "calendar-plus", Icon: CalendarPlus, zh: ["新增日历"] },
331
+ { name: "calendar-check", Icon: CalendarCheck, zh: ["确认日历"] },
332
+ { name: "calendar-arrow-down", Icon: CalendarArrowDown, zh: ["日历下箭头"] },
333
+ { name: "calendar-arrow-up", Icon: CalendarArrowUp, zh: ["日历上箭头"] },
334
+ { name: "bell", Icon: Bell, zh: ["铃铛"] },
335
+ { name: "bell-ring", Icon: BellRing, zh: ["响铃"] },
336
+ { name: "bell-plus", Icon: BellPlus, zh: ["新增铃铛"] },
337
+ { name: "megaphone", Icon: Megaphone, zh: ["扩音器"] },
338
+ { name: "siren", Icon: Siren, zh: ["警报"] },
339
+ { name: "triangle-alert", Icon: TriangleAlert, zh: ["警告三角"] },
340
+ { name: "info", Icon: Info, zh: ["信息"] },
341
+ { name: "zap", Icon: Zap, zh: ["闪电"] },
342
+ { name: "check", Icon: Check, zh: ["勾选"] },
343
+ { name: "check-check", Icon: CheckCheck, zh: ["双勾选"] },
344
+ { name: "circle-check", Icon: CircleCheck, zh: ["圆形勾选"] },
345
+ { name: "circle-minus", Icon: CircleMinus, zh: ["圆形减号"] },
346
+ { name: "minus", Icon: Minus, zh: ["减号"] },
347
+ { name: "plus", Icon: Plus, zh: ["加号"] },
348
+ { name: "circle-plus", Icon: CirclePlus, zh: ["圆形加号"] },
349
+ { name: "loader", Icon: Loader, zh: ["加载"] },
350
+ { name: "loader-circle", Icon: LoaderCircle, zh: ["圆形加载"] },
351
+ { name: "circle-dot", Icon: CircleDot, zh: ["圆形点"] },
352
+ { name: "loader-pinwheel", Icon: LoaderPinwheel, zh: ["风车加载"] },
353
+ { name: "monitor", Icon: Monitor, zh: ["显示器"] },
354
+ { name: "laptop", Icon: Laptop, zh: ["笔记本"] },
355
+ { name: "smartphone", Icon: Smartphone, zh: ["智能手机"] },
356
+ { name: "tablet", Icon: Tablet, zh: ["平板"] },
357
+ { name: "keyboard", Icon: Keyboard, zh: ["键盘"] },
358
+ { name: "mouse", Icon: Mouse, zh: ["鼠标"] },
359
+ { name: "printer", Icon: Printer, zh: ["打印机"] },
360
+ { name: "hard-drive", Icon: HardDrive, zh: ["硬盘"] },
361
+ { name: "battery", Icon: Battery, zh: ["电池"] },
362
+ { name: "battery-charging", Icon: BatteryCharging, zh: ["充电电池"] },
363
+ { name: "mouse-pointer", Icon: MousePointer, zh: ["鼠标指针"] },
364
+ { name: "mouse-pointer-click", Icon: MousePointerClick, zh: ["点击指针"] },
365
+ { name: "wifi", Icon: Wifi, zh: ["WiFi"] },
366
+ { name: "globe", Icon: Globe, zh: ["地球"] },
367
+ { name: "radio", Icon: Radio, zh: ["收音机"] },
368
+ { name: "satellite", Icon: Satellite, zh: ["卫星"] },
369
+ { name: "signal", Icon: Signal, zh: ["信号"] },
370
+ { name: "nfc", Icon: Nfc, zh: ["NFC"] },
371
+ { name: "ethernet-port", Icon: EthernetPort, zh: ["网口"] },
372
+ { name: "wrench", Icon: Wrench, zh: ["扳手"] },
373
+ { name: "hammer", Icon: Hammer, zh: ["锤子"] },
374
+ { name: "puzzle", Icon: Puzzle, zh: ["拼图"] },
375
+ { name: "cloud-upload", Icon: CloudUpload, zh: ["上传云"] },
376
+ { name: "cloud-download", Icon: CloudDownload, zh: ["下载云"] },
377
+ { name: "upload", Icon: Upload, zh: ["上传"] },
378
+ { name: "download", Icon: Download, zh: ["下载"] },
379
+ { name: "cloud-check", Icon: CloudCheck, zh: ["确认云"] },
380
+ { name: "cloud-backup", Icon: CloudBackup, zh: ["云备份"] },
381
+ { name: "container", Icon: Container, zh: ["容器"] },
382
+ { name: "anchor", Icon: Anchor, zh: ["锚"] },
383
+ { name: "star", Icon: Star, zh: ["星标"] },
384
+ { name: "heart", Icon: Heart, zh: ["爱心"] },
385
+ { name: "bookmark", Icon: Bookmark, zh: ["书签"] },
386
+ { name: "flag", Icon: Flag, zh: ["旗帜"] },
387
+ { name: "party-popper", Icon: PartyPopper, zh: ["派对炮"] },
388
+ { name: "thumbs-up", Icon: ThumbsUp, zh: ["点赞"] },
389
+ { name: "star-check", Icon: StarCheck, zh: ["确认星标"] },
390
+ { name: "star-half", Icon: StarHalf, zh: ["半星"] },
391
+ { name: "star-minus", Icon: StarMinus, zh: ["减星"] },
392
+ { name: "star-plus", Icon: StarPlus, zh: ["加星"] },
393
+ { name: "thumbs-down", Icon: ThumbsDown, zh: ["踩"] },
394
+ { name: "smile", Icon: Smile, zh: ["微笑"] },
395
+ { name: "frown", Icon: Frown, zh: ["愁眉"] },
396
+ { name: "meh", Icon: Meh, zh: ["一般"] },
397
+ { name: "laugh", Icon: Laugh, zh: ["大笑"] },
398
+ { name: "angry", Icon: Angry, zh: ["愤怒"] },
399
+ { name: "map", Icon: Map, zh: ["地图"] },
400
+ { name: "map-pin", Icon: MapPin, zh: ["地图钉"] },
401
+ { name: "navigation", Icon: Navigation, zh: ["导航"] },
402
+ { name: "compass", Icon: Compass, zh: ["指南针"] },
403
+ { name: "route", Icon: Route, zh: ["路线"] },
404
+ { name: "signpost", Icon: Signpost, zh: ["路标"] },
405
+ { name: "locate-fixed", Icon: LocateFixed, zh: ["固定定位"] },
406
+ { name: "target", Icon: Target, zh: ["靶心"] },
407
+ { name: "sun", Icon: Sun, zh: ["太阳"] },
408
+ { name: "moon", Icon: Moon, zh: ["月亮"] },
409
+ { name: "cloud-sun", Icon: CloudSun, zh: ["云太阳"] },
410
+ { name: "cloud-rain", Icon: CloudRain, zh: ["云雨"] },
411
+ { name: "cloud-snow", Icon: CloudSnow, zh: ["云雪"] },
412
+ { name: "cloud-lightning", Icon: CloudLightning, zh: ["雷电云"] },
413
+ { name: "rainbow", Icon: Rainbow, zh: ["彩虹"] },
414
+ { name: "umbrella", Icon: Umbrella, zh: ["雨伞"] },
415
+ { name: "snowflake", Icon: Snowflake, zh: ["雪花"] },
416
+ { name: "thermometer", Icon: Thermometer, zh: ["温度计"] },
417
+ { name: "wind", Icon: Wind, zh: ["风"] },
418
+ { name: "droplet", Icon: Droplet, zh: ["水滴"] },
419
+ { name: "cloud-fog", Icon: CloudFog, zh: ["雾云"] },
420
+ { name: "bird", Icon: Bird, zh: ["鸟"] },
421
+ { name: "dog", Icon: Dog, zh: ["狗"] },
422
+ { name: "cat", Icon: Cat, zh: ["猫"] },
423
+ { name: "fish", Icon: Fish, zh: ["鱼"] },
424
+ { name: "rabbit", Icon: Rabbit, zh: ["兔子"] },
425
+ { name: "turtle", Icon: Turtle, zh: ["海龟"] },
426
+ { name: "luggage", Icon: Luggage, zh: ["行李箱"] },
427
+ { name: "tent", Icon: Tent, zh: ["帐篷"] },
428
+ { name: "mountain", Icon: Mountain, zh: ["山"] },
429
+ { name: "mountain-snow", Icon: MountainSnow, zh: ["雪山"] },
430
+ { name: "binoculars", Icon: Binoculars, zh: ["望远镜"] },
431
+ { name: "sunrise", Icon: Sunrise, zh: ["日出"] },
432
+ { name: "sunset", Icon: Sunset, zh: ["日落"] },
433
+ { name: "bed", Icon: Bed, zh: ["床"] },
434
+ { name: "bed-double", Icon: BedDouble, zh: ["双人床"] },
435
+ { name: "sofa", Icon: Sofa, zh: ["沙发"] },
436
+ { name: "lamp", Icon: Lamp, zh: ["灯"] },
437
+ { name: "door-open", Icon: DoorOpen, zh: ["开门"] },
438
+ { name: "door-closed", Icon: DoorClosed, zh: ["关门"] },
439
+ { name: "bath", Icon: Bath, zh: ["浴缸"] },
440
+ { name: "refrigerator", Icon: Refrigerator, zh: ["冰箱"] },
441
+ { name: "washing-machine", Icon: WashingMachine, zh: ["洗衣机"] },
442
+ { name: "book-a", Icon: BookA, zh: ["A书"] },
443
+ { name: "book-alert", Icon: BookAlert, zh: ["告警书"] },
444
+ { name: "book-check", Icon: BookCheck, zh: ["确认书"] },
445
+ { name: "spade", Icon: Spade, zh: ["黑桃"] },
446
+ { name: "diamond", Icon: Diamond, zh: ["方块"] },
447
+ { name: "club", Icon: Club, zh: ["梅花"] },
448
+ { name: "toy-brick", Icon: ToyBrick, zh: ["积木"] },
449
+ { name: "triangle", Icon: Triangle, zh: ["三角形"] },
450
+ { name: "hexagon", Icon: Hexagon, zh: ["六边形"] },
451
+ { name: "octagon", Icon: Octagon, zh: ["八边形"] },
452
+ { name: "spline", Icon: Spline, zh: ["样条"] },
453
+ { name: "contrast", Icon: Contrast, zh: ["对比度"] },
454
+ { name: "swatch-book", Icon: SwatchBook, zh: ["色卡本"] },
455
+ { name: "qr-code", Icon: QrCode, zh: ["二维码"] },
456
+ { name: "barcode", Icon: Barcode, zh: ["条码"] },
457
+ { name: "scan", Icon: Scan, zh: ["扫描"] },
458
+ { name: "scan-line", Icon: ScanLine, zh: ["扫描线"] },
459
+ { name: "scan-text", Icon: ScanText, zh: ["扫描文本"] },
460
+ { name: "scan-barcode", Icon: ScanBarcode, zh: ["扫描条码"] },
461
+ { name: "log-in", Icon: LogIn, zh: ["登录"] },
462
+ { name: "log-out", Icon: LogOut, zh: ["登出"] },
463
+ { name: "stamp", Icon: Stamp, zh: ["印章"] },
464
+ { name: "asterisk", Icon: Asterisk, zh: ["星号"] },
465
+ { name: "equal", Icon: Equal, zh: ["等于"] },
466
+ { name: "divide", Icon: Divide, zh: ["除"] },
467
+ { name: "slash", Icon: Slash, zh: ["斜杠"] },
468
+ { name: "infinity", Icon: Infinity, zh: ["无穷"] },
469
+ { name: "ampersand", Icon: Ampersand, zh: ["与号"] },
470
+ { name: "copyright", Icon: Copyright, zh: ["版权"] },
471
+ { name: "ghost", Icon: Ghost, zh: ["幽灵"] },
472
+ { name: "skull", Icon: Skull, zh: ["骷髅"] },
473
+ ];
474
+
475
+ /** name → 条目 查找表(LucideIconByName 渲染用) */
476
+ export const CURATED_ICON_MAP: Record<string, CuratedIcon> = Object.fromEntries(
477
+ CURATED_ICONS.map((icon) => [icon.name, icon])
478
+ );
@@ -0,0 +1,109 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ import type { LucideIcon } from "lucide-react";
19
+
20
+ export interface CuratedIcon {
21
+ /** kebab-case Lucide 官方名,如 "folder-kanban" */
22
+ name: string;
23
+ Icon: LucideIcon;
24
+ /** 中文搜索关键词(精选集 100% 覆盖) */
25
+ zh: string[];
26
+ }
27
+
28
+ export interface IconSearchEntry extends CuratedIcon {
29
+ /** kebab 名按 "-" 分词,如 folder-kanban → ["folder", "kanban"] */
30
+ words: string[];
31
+ }
32
+
33
+ const RECENT_KEY = "allblue.ui.lucide-icon-picker.recent";
34
+ const RECENT_LIMIT = 16;
35
+
36
+ /** PascalCase(icons map 键)→ kebab-case(官方名),与 lucide 官方 tag 生成规则对齐 */
37
+ export function pascalToKebab(pascal: string): string {
38
+ return pascal
39
+ .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
40
+ .replace(/([A-Z]+)([A-Z][a-z0-9])/g, "$1-$2")
41
+ .replace(/([a-z])(\d)/g, "$1-$2")
42
+ .toLowerCase();
43
+ }
44
+
45
+ /** query 含 CJK 字符则走中文词表匹配 */
46
+ export function isCJK(query: string): boolean {
47
+ return /[\u4e00-\u9fff]/.test(query);
48
+ }
49
+
50
+ export function buildSearchIndex(icons: CuratedIcon[]): IconSearchEntry[] {
51
+ return icons.map((icon) => ({
52
+ ...icon,
53
+ words: icon.name.split("-"),
54
+ }));
55
+ }
56
+
57
+ export function filterIcons(
58
+ query: string,
59
+ index: IconSearchEntry[]
60
+ ): IconSearchEntry[] {
61
+ const q = query.trim().toLowerCase();
62
+ if (!q) return index;
63
+ if (isCJK(q)) {
64
+ return index.filter((e) => e.zh.some((k) => k.includes(q)));
65
+ }
66
+ return index.filter(
67
+ (e) => e.name.includes(q) || e.words.some((w) => w.startsWith(q))
68
+ );
69
+ }
70
+
71
+ export function getRecentIcons(): string[] {
72
+ if (typeof window === "undefined") return [];
73
+ try {
74
+ const raw = window.localStorage.getItem(RECENT_KEY);
75
+ const parsed: unknown = raw ? JSON.parse(raw) : [];
76
+ if (!Array.isArray(parsed)) return [];
77
+ return parsed.filter((x): x is string => typeof x === "string");
78
+ } catch {
79
+ return [];
80
+ }
81
+ }
82
+
83
+ export function pushRecentIcon(name: string): string[] {
84
+ const next = [name, ...getRecentIcons().filter((n) => n !== name)].slice(
85
+ 0,
86
+ RECENT_LIMIT
87
+ );
88
+ if (typeof window !== "undefined") {
89
+ try {
90
+ window.localStorage.setItem(RECENT_KEY, JSON.stringify(next));
91
+ } catch {
92
+ // localStorage 不可用(隐私模式等)时静默降级,仅本次会话内存态
93
+ }
94
+ }
95
+ return next;
96
+ }
97
+
98
+ /** 清理最近使用中已失效(不在精选名单)的记录,返回清理后的列表 */
99
+ export function pruneRecentIcons(validNames: Set<string>): string[] {
100
+ const next = getRecentIcons().filter((n) => validNames.has(n));
101
+ if (typeof window !== "undefined") {
102
+ try {
103
+ window.localStorage.setItem(RECENT_KEY, JSON.stringify(next));
104
+ } catch {
105
+ // localStorage 不可用时静默降级
106
+ }
107
+ }
108
+ return next;
109
+ }