1import { iconNames, type IconName } from "lucide-react/dynamic";
2export { PROJECT_ICON_COLORS, projectIconColorClassName } from "./projectIconColors";
3
4const POPULAR_PROJECT_ICONS = [
5 "folder-code",
6 "code-2",
7 "terminal",
8 "globe-2",
9 "server",
10 "database",
11 "bot",
12 "sparkles",
13 "smartphone",
14 "monitor",
15 "cloud-cog",
16 "package",
17 "book-open",
18 "flask-conical",
19 "shield-check",
20 "rocket",
21 "gamepad-2",
22 "music",
23 "image",
24 "shopping-bag",
25 "git-branch",
26 "workflow",
27 "wrench",
28 "layers-3",
29] as const satisfies ReadonlyArray<IconName>;
30
31export const PROJECT_EMOJIS: ReadonlyArray<{ readonly emoji: string; readonly label: string }> = [
32 { emoji: "๐Ÿ’ป", label: "Computer" },
33 { emoji: "๐Ÿ› ๏ธ", label: "Tools" },
34 { emoji: "๐Ÿš€", label: "Rocket" },
35 { emoji: "๐Ÿค–", label: "Robot" },
36 { emoji: "โœจ", label: "Sparkles" },
37 { emoji: "โšก", label: "Lightning" },
38 { emoji: "๐ŸŒ", label: "Web" },
39 { emoji: "๐Ÿ“ฑ", label: "Mobile" },
40 { emoji: "๐Ÿ–ฅ๏ธ", label: "Desktop" },
41 { emoji: "โŒจ๏ธ", label: "Keyboard" },
42 { emoji: "โš™๏ธ", label: "Gear" },
43 { emoji: "๐Ÿ—„๏ธ", label: "Database" },
44 { emoji: "โ˜๏ธ", label: "Cloud" },
45 { emoji: "๐Ÿ“ฆ", label: "Package" },
46 { emoji: "๐Ÿ“š", label: "Books" },
47 { emoji: "๐Ÿงช", label: "Test tube" },
48 { emoji: "๐Ÿ”’", label: "Lock" },
49 { emoji: "๐ŸŽฎ", label: "Game" },
50 { emoji: "๐ŸŽต", label: "Music" },
51 { emoji: "๐ŸŽฌ", label: "Movie" },
52 { emoji: "๐Ÿ–ผ๏ธ", label: "Picture" },
53 { emoji: "๐Ÿ›๏ธ", label: "Shopping" },
54 { emoji: "๐Ÿ”ฅ", label: "Fire" },
55 { emoji: "๐Ÿ’ก", label: "Idea" },
56 { emoji: "๐Ÿงฉ", label: "Puzzle" },
57 { emoji: "๐Ÿ“Š", label: "Chart" },
58 { emoji: "๐Ÿง ", label: "Brain" },
59 { emoji: "๐Ÿฆ„", label: "Unicorn" },
60 { emoji: "๐Ÿ™", label: "Octopus" },
61 { emoji: "๐ŸŒฑ", label: "Seedling" },
62];
63
64export function filterProjectIconNames(query: string): ReadonlyArray<IconName> {
65 const normalized = query.trim().toLowerCase().replaceAll(/\s+/g, "-");
66 if (!normalized) return POPULAR_PROJECT_ICONS;
67 return iconNames.filter((name) => name.includes(normalized)).slice(0, 60);
68}
69
70export function firstEmoji(value: string): string | null {
71 const trimmed = value.trim();
72 if (!trimmed) return null;
73 const segments = new Intl.Segmenter(undefined, { granularity: "grapheme" }).segment(trimmed);
74 const segment = segments[Symbol.iterator]().next().value?.segment;
75 const isFlag = /^\p{Regional_Indicator}{2}$/u.test(segment ?? "");
76 const isKeycap = /^[#*0-9]\uFE0F?\u20E3$/u.test(segment ?? "");
77 if (!segment || (!/\p{Extended_Pictographic}/u.test(segment) && !isFlag && !isKeycap)) {
78 return null;
79 }
80 return segment;
81}