clay-server 2.27.0-beta.11 โ†’ 2.27.0-beta.13

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.
@@ -0,0 +1,1449 @@
1
+ // sidebar-projects.js - Project icon strip, context menus, emoji picker, drag-and-drop, worktree modal
2
+ // Extracted from sidebar.js (PR-36)
3
+
4
+ import { escapeHtml } from './utils.js';
5
+ import { iconHtml, refreshIcons } from './icons.js';
6
+ import { openProjectSettings } from './project-settings.js';
7
+ import { triggerShare } from './qrcode.js';
8
+ import { parseEmojis } from './markdown.js';
9
+
10
+ var _ctx = null;
11
+
12
+ // --- Project state ---
13
+ var cachedProjectList = [];
14
+ var cachedCurrentSlug = null;
15
+
16
+ // --- Project context menu ---
17
+ var projectCtxMenu = null;
18
+
19
+ // --- Project Access Popover ---
20
+ var projectAccessPopover = null;
21
+
22
+ // --- Emoji picker ---
23
+ var emojiPickerEl = null;
24
+
25
+ // --- Drag-and-drop state ---
26
+ var draggedSlug = null;
27
+ var draggedEl = null;
28
+
29
+ // --- Worktree folder collapse state (persisted in localStorage) ---
30
+ var wtCollapsed = {};
31
+ try {
32
+ wtCollapsed = JSON.parse(localStorage.getItem("clay-wt-collapsed") || "{}");
33
+ } catch (e) {}
34
+
35
+ var EMOJI_CATEGORIES = [
36
+ { id: "frequent", icon: "๐Ÿ•", label: "Frequent", emojis: [
37
+ "๐Ÿ˜€","๐Ÿ˜Ž","๐Ÿค“","๐Ÿง ","๐Ÿ’ก","๐Ÿ”ฅ","โšก","๐Ÿš€",
38
+ "๐ŸŽฏ","๐ŸŽฎ","๐ŸŽจ","๐ŸŽต","๐Ÿ“ฆ","๐Ÿ“","๐Ÿ“","๐Ÿ’ป",
39
+ "๐Ÿ–ฅ๏ธ","โŒจ๏ธ","๐Ÿ”ง","๐Ÿ› ๏ธ","โš™๏ธ","๐Ÿงช","๐Ÿ”ฌ","๐Ÿงฌ",
40
+ "๐ŸŒ","๐ŸŒฑ","๐ŸŒŠ","๐ŸŒธ","๐Ÿ€","๐ŸŒˆ","โ˜€๏ธ","๐ŸŒ™",
41
+ "๐Ÿฑ","๐Ÿถ","๐Ÿผ","๐ŸฆŠ","๐Ÿฆ‹","๐Ÿ","๐Ÿ™","๐Ÿฆ„",
42
+ "๐Ÿ•","๐Ÿ”","โ˜•","๐Ÿฉ","๐ŸŽ","๐Ÿ‡","๐Ÿง","๐Ÿฃ",
43
+ "โค๏ธ","๐Ÿ’œ","๐Ÿ’™","๐Ÿ’š","๐Ÿ’›","๐Ÿงก","๐Ÿค","๐Ÿ–ค",
44
+ "โญ","โœจ","๐Ÿ’Ž","๐Ÿ†","๐Ÿ‘‘","๐ŸŽช","๐ŸŽญ","๐Ÿƒ",
45
+ ]},
46
+ { id: "smileys", icon: "๐Ÿ˜€", label: "Smileys & People", emojis: [
47
+ "๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿ˜…","๐Ÿคฃ","๐Ÿ˜‚",
48
+ "๐Ÿ™‚","๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿฅฐ","๐Ÿ˜","๐Ÿคฉ","๐Ÿ˜˜","๐Ÿ˜—",
49
+ "๐Ÿ˜š","๐Ÿ˜™","๐Ÿฅฒ","๐Ÿ˜‹","๐Ÿ˜›","๐Ÿ˜œ","๐Ÿคช","๐Ÿ˜",
50
+ "๐Ÿค‘","๐Ÿค—","๐Ÿคญ","๐Ÿซข","๐Ÿคซ","๐Ÿค”","๐Ÿซก","๐Ÿค",
51
+ "๐Ÿคจ","๐Ÿ˜","๐Ÿ˜‘","๐Ÿ˜ถ","๐Ÿซฅ","๐Ÿ˜","๐Ÿ˜’","๐Ÿ™„",
52
+ "๐Ÿ˜ฌ","๐Ÿคฅ","๐Ÿ˜Œ","๐Ÿ˜”","๐Ÿ˜ช","๐Ÿคค","๐Ÿ˜ด","๐Ÿ˜ท",
53
+ "๐Ÿค’","๐Ÿค•","๐Ÿคข","๐Ÿคฎ","๐Ÿฅด","๐Ÿ˜ต","๐Ÿคฏ","๐Ÿฅณ",
54
+ "๐Ÿฅธ","๐Ÿ˜Ž","๐Ÿค“","๐Ÿง","๐Ÿ˜•","๐Ÿซค","๐Ÿ˜Ÿ","๐Ÿ™",
55
+ "๐Ÿ˜ฎ","๐Ÿ˜ฏ","๐Ÿ˜ฒ","๐Ÿ˜ณ","๐Ÿฅบ","๐Ÿฅน","๐Ÿ˜ฆ","๐Ÿ˜ง",
56
+ "๐Ÿ˜จ","๐Ÿ˜ฐ","๐Ÿ˜ฅ","๐Ÿ˜ข","๐Ÿ˜ญ","๐Ÿ˜ฑ","๐Ÿ˜–","๐Ÿ˜ฃ",
57
+ "๐Ÿ˜ž","๐Ÿ˜“","๐Ÿ˜ฉ","๐Ÿ˜ซ","๐Ÿฅฑ","๐Ÿ˜ค","๐Ÿ˜ก","๐Ÿ˜ ",
58
+ "๐Ÿคฌ","๐Ÿ˜ˆ","๐Ÿ‘ฟ","๐Ÿ’€","โ˜ ๏ธ","๐Ÿ’ฉ","๐Ÿคก","๐Ÿ‘น",
59
+ "๐Ÿ‘บ","๐Ÿ‘ป","๐Ÿ‘ฝ","๐Ÿ‘พ","๐Ÿค–","๐Ÿ˜บ","๐Ÿ˜ธ","๐Ÿ˜น",
60
+ "๐Ÿ˜ป","๐Ÿ˜ผ","๐Ÿ˜ฝ","๐Ÿ™€","๐Ÿ˜ฟ","๐Ÿ˜พ","๐Ÿ™ˆ","๐Ÿ™‰",
61
+ "๐Ÿ™Š","๐Ÿ‘‹","๐Ÿคš","๐Ÿ–๏ธ","โœ‹","๐Ÿ––","๐Ÿซฑ","๐Ÿซฒ",
62
+ "๐Ÿซณ","๐Ÿซด","๐Ÿ‘Œ","๐ŸคŒ","๐Ÿค","โœŒ๏ธ","๐Ÿคž","๐Ÿซฐ",
63
+ "๐ŸคŸ","๐Ÿค˜","๐Ÿค™","๐Ÿ‘ˆ","๐Ÿ‘‰","๐Ÿ‘†","๐Ÿ–•","๐Ÿ‘‡",
64
+ "โ˜๏ธ","๐Ÿซต","๐Ÿ‘","๐Ÿ‘Ž","โœŠ","๐Ÿ‘Š","๐Ÿค›","๐Ÿคœ",
65
+ "๐Ÿ‘","๐Ÿ™Œ","๐Ÿซถ","๐Ÿ‘","๐Ÿคฒ","๐Ÿค","๐Ÿ™","๐Ÿ’ช",
66
+ ]},
67
+ { id: "animals", icon: "๐Ÿป", label: "Animals & Nature", emojis: [
68
+ "๐Ÿถ","๐Ÿฑ","๐Ÿญ","๐Ÿน","๐Ÿฐ","๐ŸฆŠ","๐Ÿป","๐Ÿผ",
69
+ "๐Ÿปโ€โ„๏ธ","๐Ÿจ","๐Ÿฏ","๐Ÿฆ","๐Ÿฎ","๐Ÿท","๐Ÿฝ","๐Ÿธ",
70
+ "๐Ÿต","๐Ÿ™ˆ","๐Ÿ™‰","๐Ÿ™Š","๐Ÿ’","๐Ÿ”","๐Ÿง","๐Ÿฆ",
71
+ "๐Ÿค","๐Ÿฃ","๐Ÿฅ","๐Ÿฆ†","๐Ÿฆ…","๐Ÿฆ‰","๐Ÿฆ‡","๐Ÿบ",
72
+ "๐Ÿ—","๐Ÿด","๐Ÿฆ„","๐Ÿ","๐Ÿชฑ","๐Ÿ›","๐Ÿฆ‹","๐ŸŒ",
73
+ "๐Ÿž","๐Ÿœ","๐Ÿชฐ","๐Ÿชฒ","๐Ÿชณ","๐ŸฆŸ","๐Ÿฆ—","๐Ÿ•ท๏ธ",
74
+ "๐Ÿฆ‚","๐Ÿข","๐Ÿ","๐ŸฆŽ","๐Ÿฆ–","๐Ÿฆ•","๐Ÿ™","๐Ÿฆ‘",
75
+ "๐Ÿฆ","๐Ÿฆž","๐Ÿฆ€","๐Ÿชธ","๐Ÿก","๐Ÿ ","๐ŸŸ","๐Ÿฌ",
76
+ "๐Ÿณ","๐Ÿ‹","๐Ÿฆˆ","๐ŸŠ","๐Ÿ…","๐Ÿ†","๐Ÿฆ“","๐Ÿซ",
77
+ "๐Ÿฆ","๐Ÿฆง","๐Ÿฆฃ","๐Ÿ˜","๐Ÿฆ›","๐Ÿฆ","๐Ÿช","๐Ÿซ",
78
+ "๐Ÿฆ’","๐Ÿฆ˜","๐Ÿฆฌ","๐Ÿƒ","๐Ÿ‚","๐Ÿ„","๐ŸŽ","๐Ÿ–",
79
+ "๐Ÿ","๐Ÿ‘","๐Ÿฆ™","๐Ÿ","๐ŸฆŒ","๐ŸซŽ","๐Ÿ•","๐Ÿฉ",
80
+ "๐Ÿฆฎ","๐Ÿ•โ€๐Ÿฆบ","๐Ÿˆ","๐Ÿˆโ€โฌ›","๐Ÿชถ","๐Ÿ“","๐Ÿฆƒ","๐Ÿฆค",
81
+ "๐Ÿฆš","๐Ÿฆœ","๐Ÿฆข","๐Ÿชฟ","๐Ÿฆฉ","๐Ÿ•Š๏ธ","๐Ÿ‡","๐Ÿฆ",
82
+ "๐Ÿฆจ","๐Ÿฆก","๐Ÿฆซ","๐Ÿฆฆ","๐Ÿฆฅ","๐Ÿ","๐Ÿ€","๐Ÿฟ๏ธ",
83
+ "๐Ÿฆ”","๐ŸŒต","๐ŸŽ„","๐ŸŒฒ","๐ŸŒณ","๐ŸŒด","๐Ÿชต","๐ŸŒฑ",
84
+ "๐ŸŒฟ","โ˜˜๏ธ","๐Ÿ€","๐ŸŽ","๐Ÿชด","๐ŸŽ‹","๐Ÿƒ","๐Ÿ‚",
85
+ "๐Ÿ","๐Ÿชบ","๐Ÿชน","๐Ÿ„","๐ŸŒพ","๐Ÿ’","๐ŸŒท","๐ŸŒน",
86
+ "๐Ÿฅ€","๐Ÿชป","๐ŸŒบ","๐ŸŒธ","๐ŸŒผ","๐ŸŒป","๐ŸŒž","๐ŸŒ",
87
+ "๐ŸŒ›","๐ŸŒœ","๐ŸŒš","๐ŸŒ•","๐ŸŒ–","๐ŸŒ—","๐ŸŒ˜","๐ŸŒ‘",
88
+ "๐ŸŒ’","๐ŸŒ“","๐ŸŒ”","๐ŸŒ™","๐ŸŒŽ","๐ŸŒ","๐ŸŒ","๐Ÿช",
89
+ "๐Ÿ’ซ","โญ","๐ŸŒŸ","โœจ","โšก","โ˜„๏ธ","๐Ÿ’ฅ","๐Ÿ”ฅ",
90
+ "๐ŸŒช๏ธ","๐ŸŒˆ","โ˜€๏ธ","๐ŸŒค๏ธ","โ›…","๐ŸŒฅ๏ธ","โ˜๏ธ","๐ŸŒฆ๏ธ",
91
+ "๐ŸŒง๏ธ","โ›ˆ๏ธ","๐ŸŒฉ๏ธ","โ„๏ธ","โ˜ƒ๏ธ","โ›„","๐ŸŒฌ๏ธ","๐Ÿ’จ",
92
+ "๐Ÿ’ง","๐Ÿ’ฆ","๐Ÿซง","โ˜”","โ˜‚๏ธ","๐ŸŒŠ","๐ŸŒซ๏ธ",
93
+ ]},
94
+ { id: "food", icon: "๐Ÿ”", label: "Food & Drink", emojis: [
95
+ "๐Ÿ‡","๐Ÿˆ","๐Ÿ‰","๐ŸŠ","๐Ÿ‹","๐ŸŒ","๐Ÿ","๐Ÿฅญ",
96
+ "๐ŸŽ","๐Ÿ","๐Ÿ","๐Ÿ‘","๐Ÿ’","๐Ÿ“","๐Ÿซ","๐Ÿฅ",
97
+ "๐Ÿ…","๐Ÿซ’","๐Ÿฅฅ","๐Ÿฅ‘","๐Ÿ†","๐Ÿฅ”","๐Ÿฅ•","๐ŸŒฝ",
98
+ "๐ŸŒถ๏ธ","๐Ÿซ‘","๐Ÿฅ’","๐Ÿฅฌ","๐Ÿฅฆ","๐Ÿง„","๐Ÿง…","๐Ÿฅœ",
99
+ "๐Ÿซ˜","๐ŸŒฐ","๐Ÿซš","๐Ÿซ›","๐Ÿž","๐Ÿฅ","๐Ÿฅ–","๐Ÿซ“",
100
+ "๐Ÿฅจ","๐Ÿฅฏ","๐Ÿฅž","๐Ÿง‡","๐Ÿง€","๐Ÿ–","๐Ÿ—","๐Ÿฅฉ",
101
+ "๐Ÿฅ“","๐Ÿ”","๐ŸŸ","๐Ÿ•","๐ŸŒญ","๐Ÿฅช","๐ŸŒฎ","๐ŸŒฏ",
102
+ "๐Ÿซ”","๐Ÿฅ™","๐Ÿง†","๐Ÿฅš","๐Ÿณ","๐Ÿฅ˜","๐Ÿฒ","๐Ÿซ•",
103
+ "๐Ÿฅฃ","๐Ÿฅ—","๐Ÿฟ","๐Ÿงˆ","๐Ÿง‚","๐Ÿฅซ","๐Ÿฑ","๐Ÿ˜",
104
+ "๐Ÿ™","๐Ÿš","๐Ÿ›","๐Ÿœ","๐Ÿ","๐Ÿ ","๐Ÿข","๐Ÿฃ",
105
+ "๐Ÿค","๐Ÿฅ","๐Ÿฅฎ","๐Ÿก","๐ŸฅŸ","๐Ÿฅ ","๐Ÿฅก","๐Ÿฆ€",
106
+ "๐Ÿฆž","๐Ÿฆ","๐Ÿฆ‘","๐Ÿฆช","๐Ÿฆ","๐Ÿง","๐Ÿจ","๐Ÿฉ",
107
+ "๐Ÿช","๐ŸŽ‚","๐Ÿฐ","๐Ÿง","๐Ÿฅง","๐Ÿซ","๐Ÿฌ","๐Ÿญ",
108
+ "๐Ÿฎ","๐Ÿฏ","๐Ÿผ","๐Ÿฅ›","โ˜•","๐Ÿซ–","๐Ÿต","๐Ÿถ",
109
+ "๐Ÿพ","๐Ÿท","๐Ÿธ","๐Ÿน","๐Ÿบ","๐Ÿป","๐Ÿฅ‚","๐Ÿฅƒ",
110
+ "๐Ÿซ—","๐Ÿฅค","๐Ÿง‹","๐Ÿงƒ","๐Ÿง‰","๐ŸงŠ",
111
+ ]},
112
+ { id: "activity", icon: "โšฝ", label: "Activity", emojis: [
113
+ "โšฝ","๐Ÿ€","๐Ÿˆ","โšพ","๐ŸฅŽ","๐ŸŽพ","๐Ÿ","๐Ÿ‰",
114
+ "๐Ÿฅ","๐ŸŽฑ","๐Ÿช€","๐Ÿ“","๐Ÿธ","๐Ÿ’","๐Ÿ‘","๐Ÿฅ",
115
+ "๐Ÿ","๐Ÿชƒ","๐Ÿฅ…","โ›ณ","๐Ÿช","๐Ÿ›","๐Ÿน","๐ŸŽฃ",
116
+ "๐Ÿคฟ","๐ŸฅŠ","๐Ÿฅ‹","๐ŸŽฝ","๐Ÿ›น","๐Ÿ›ผ","๐Ÿ›ท","โ›ธ๏ธ",
117
+ "๐ŸฅŒ","๐ŸŽฟ","โ›ท๏ธ","๐Ÿ‚","๐Ÿช‚","๐Ÿ‹๏ธ","๐Ÿคธ","๐Ÿคบ",
118
+ "โ›น๏ธ","๐Ÿคพ","๐ŸŒ๏ธ","๐Ÿ‡","๐Ÿง˜","๐Ÿ„","๐ŸŠ","๐Ÿคฝ",
119
+ "๐Ÿšฃ","๐Ÿง—","๐Ÿšต","๐Ÿšด","๐ŸŽช","๐Ÿคน","๐ŸŽญ","๐ŸŽจ",
120
+ "๐ŸŽฌ","๐ŸŽค","๐ŸŽง","๐ŸŽผ","๐ŸŽน","๐Ÿฅ","๐Ÿช˜","๐ŸŽท",
121
+ "๐ŸŽบ","๐Ÿช—","๐ŸŽธ","๐Ÿช•","๐ŸŽป","๐Ÿชˆ","๐ŸŽฒ","โ™Ÿ๏ธ",
122
+ "๐ŸŽฏ","๐ŸŽณ","๐ŸŽฎ","๐Ÿ•น๏ธ","๐Ÿงฉ","๐Ÿชฉ",
123
+ ]},
124
+ { id: "travel", icon: "๐Ÿš—", label: "Travel & Places", emojis: [
125
+ "๐Ÿš—","๐Ÿš•","๐Ÿš™","๐ŸšŒ","๐ŸšŽ","๐ŸŽ๏ธ","๐Ÿš“","๐Ÿš‘",
126
+ "๐Ÿš’","๐Ÿš","๐Ÿ›ป","๐Ÿšš","๐Ÿš›","๐Ÿšœ","๐Ÿ›ต","๐Ÿ๏ธ",
127
+ "๐Ÿ›บ","๐Ÿšฒ","๐Ÿ›ด","๐Ÿ›น","๐Ÿš","๐Ÿ›ฃ๏ธ","๐Ÿ›ค๏ธ","โ›ฝ",
128
+ "๐Ÿ›ž","๐Ÿšจ","๐Ÿšฅ","๐Ÿšฆ","๐Ÿ›‘","๐Ÿšง","โš“","๐Ÿ›Ÿ",
129
+ "โ›ต","๐Ÿ›ถ","๐Ÿšค","๐Ÿ›ณ๏ธ","โ›ด๏ธ","๐Ÿ›ฅ๏ธ","๐Ÿšข","โœˆ๏ธ",
130
+ "๐Ÿ›ฉ๏ธ","๐Ÿ›ซ","๐Ÿ›ฌ","๐Ÿช‚","๐Ÿ’บ","๐Ÿš","๐ŸšŸ","๐Ÿš ",
131
+ "๐Ÿšก","๐Ÿ›ฐ๏ธ","๐Ÿš€","๐Ÿ›ธ","๐Ÿ ","๐Ÿก","๐Ÿ˜๏ธ","๐Ÿš๏ธ",
132
+ "๐Ÿ—๏ธ","๐Ÿญ","๐Ÿข","๐Ÿฌ","๐Ÿฃ","๐Ÿค","๐Ÿฅ","๐Ÿฆ",
133
+ "๐Ÿจ","๐Ÿช","๐Ÿซ","๐Ÿฉ","๐Ÿ’’","๐Ÿ›๏ธ","โ›ช","๐Ÿ•Œ",
134
+ "๐Ÿ›•","๐Ÿ•","โ›ฉ๏ธ","๐Ÿ•‹","โ›ฒ","โ›บ","๐ŸŒ","๐ŸŒƒ",
135
+ "๐Ÿ™๏ธ","๐ŸŒ„","๐ŸŒ…","๐ŸŒ†","๐ŸŒ‡","๐ŸŒ‰","๐Ÿ—ผ","๐Ÿ—ฝ",
136
+ "๐Ÿ—ป","๐Ÿ•๏ธ","๐ŸŽ ","๐ŸŽก","๐ŸŽข","๐Ÿ–๏ธ","๐Ÿ๏ธ","๐Ÿœ๏ธ",
137
+ "๐ŸŒ‹","โ›ฐ๏ธ","๐Ÿ—บ๏ธ","๐Ÿงญ","๐Ÿ”๏ธ",
138
+ ]},
139
+ { id: "objects", icon: "๐Ÿ’ก", label: "Objects", emojis: [
140
+ "โŒš","๐Ÿ“ฑ","๐Ÿ“ฒ","๐Ÿ’ป","โŒจ๏ธ","๐Ÿ–ฅ๏ธ","๐Ÿ–จ๏ธ","๐Ÿ–ฑ๏ธ",
141
+ "๐Ÿ–ฒ๏ธ","๐Ÿ•น๏ธ","๐Ÿ—œ๏ธ","๐Ÿ’ฝ","๐Ÿ’พ","๐Ÿ’ฟ","๐Ÿ“€","๐Ÿ“ผ",
142
+ "๐Ÿ“ท","๐Ÿ“ธ","๐Ÿ“น","๐ŸŽฅ","๐Ÿ“ฝ๏ธ","๐ŸŽž๏ธ","๐Ÿ“ž","โ˜Ž๏ธ",
143
+ "๐Ÿ“Ÿ","๐Ÿ“ ","๐Ÿ“บ","๐Ÿ“ป","๐ŸŽ™๏ธ","๐ŸŽš๏ธ","๐ŸŽ›๏ธ","๐Ÿงญ",
144
+ "โฑ๏ธ","โฒ๏ธ","โฐ","๐Ÿ•ฐ๏ธ","โŒ›","โณ","๐Ÿ“ก","๐Ÿ”‹",
145
+ "๐Ÿชซ","๐Ÿ”Œ","๐Ÿ’ก","๐Ÿ”ฆ","๐Ÿ•ฏ๏ธ","๐Ÿช”","๐Ÿงฏ","๐Ÿ›ข๏ธ",
146
+ "๐Ÿ›๏ธ","๐Ÿ’ฐ","๐Ÿ’ด","๐Ÿ’ต","๐Ÿ’ถ","๐Ÿ’ท","๐Ÿช™","๐Ÿ’ธ",
147
+ "๐Ÿ’ณ","๐Ÿงพ","๐Ÿ’น","โœ‰๏ธ","๐Ÿ“ง","๐Ÿ“จ","๐Ÿ“ฉ","๐Ÿ“ค",
148
+ "๐Ÿ“ฅ","๐Ÿ“ฆ","๐Ÿ“ซ","๐Ÿ“ฌ","๐Ÿ“ญ","๐Ÿ“ฎ","๐Ÿ—ณ๏ธ","โœ๏ธ",
149
+ "โœ’๏ธ","๐Ÿ–‹๏ธ","๐Ÿ–Š๏ธ","๐Ÿ–Œ๏ธ","๐Ÿ–๏ธ","๐Ÿ“","๐Ÿ’ผ","๐Ÿ“",
150
+ "๐Ÿ“‚","๐Ÿ—‚๏ธ","๐Ÿ“…","๐Ÿ“†","๐Ÿ—’๏ธ","๐Ÿ—“๏ธ","๐Ÿ“‡","๐Ÿ“ˆ",
151
+ "๐Ÿ“‰","๐Ÿ“Š","๐Ÿ“‹","๐Ÿ“Œ","๐Ÿ“","๐Ÿ“Ž","๐Ÿ–‡๏ธ","๐Ÿ“",
152
+ "๐Ÿ“","โœ‚๏ธ","๐Ÿ—ƒ๏ธ","๐Ÿ—„๏ธ","๐Ÿ—‘๏ธ","๐Ÿ”’","๐Ÿ”“","๐Ÿ”",
153
+ "๐Ÿ”","๐Ÿ”‘","๐Ÿ—๏ธ","๐Ÿ”จ","๐Ÿช“","โ›๏ธ","โš’๏ธ","๐Ÿ› ๏ธ",
154
+ "๐Ÿ—ก๏ธ","โš”๏ธ","๐Ÿ’ฃ","๐Ÿชƒ","๐Ÿน","๐Ÿ›ก๏ธ","๐Ÿชš","๐Ÿ”ง",
155
+ "๐Ÿช›","๐Ÿ”ฉ","โš™๏ธ","๐Ÿ—œ๏ธ","โš–๏ธ","๐Ÿฆฏ","๐Ÿ”—","โ›“๏ธ",
156
+ "๐Ÿช","๐Ÿงฐ","๐Ÿงฒ","๐Ÿชœ","โš—๏ธ","๐Ÿงช","๐Ÿงซ","๐Ÿงฌ",
157
+ "๐Ÿ”ฌ","๐Ÿ”ญ","๐Ÿ“ก","๐Ÿ’‰","๐Ÿฉธ","๐Ÿ’Š","๐Ÿฉน","๐Ÿฉผ",
158
+ "๐Ÿฉบ","๐Ÿฉป","๐Ÿšช","๐Ÿ›—","๐Ÿชž","๐ŸชŸ","๐Ÿ›๏ธ","๐Ÿ›‹๏ธ",
159
+ "๐Ÿช‘","๐Ÿšฝ","๐Ÿช ","๐Ÿšฟ","๐Ÿ›","๐Ÿชค","๐Ÿช’","๐Ÿงด",
160
+ "๐Ÿงท","๐Ÿงน","๐Ÿงบ","๐Ÿงป","๐Ÿชฃ","๐Ÿงผ","๐Ÿซง","๐Ÿชฅ",
161
+ "๐Ÿงฝ","๐Ÿงฏ","๐Ÿ›’","๐Ÿšฌ","โšฐ๏ธ","๐Ÿชฆ","โšฑ๏ธ","๐Ÿงฟ",
162
+ "๐Ÿชฌ","๐Ÿ—ฟ","๐Ÿชง","๐Ÿชช",
163
+ ]},
164
+ { id: "symbols", icon: "โค๏ธ", label: "Symbols", emojis: [
165
+ "โค๏ธ","๐Ÿงก","๐Ÿ’›","๐Ÿ’š","๐Ÿ’™","๐Ÿ’œ","๐Ÿ–ค","๐Ÿค",
166
+ "๐ŸคŽ","๐Ÿ’”","โค๏ธโ€๐Ÿ”ฅ","โค๏ธโ€๐Ÿฉน","โฃ๏ธ","๐Ÿ’•","๐Ÿ’ž","๐Ÿ’“",
167
+ "๐Ÿ’—","๐Ÿ’–","๐Ÿ’˜","๐Ÿ’","๐Ÿ’Ÿ","โ˜ฎ๏ธ","โœ๏ธ","โ˜ช๏ธ",
168
+ "๐Ÿ•‰๏ธ","โ˜ธ๏ธ","๐Ÿชฏ","โœก๏ธ","๐Ÿ”ฏ","๐Ÿ•Ž","โ˜ฏ๏ธ","โ˜ฆ๏ธ",
169
+ "๐Ÿ›","โ›Ž","โ™ˆ","โ™‰","โ™Š","โ™‹","โ™Œ","โ™",
170
+ "โ™Ž","โ™","โ™","โ™‘","โ™’","โ™“","๐Ÿ†”","โš›๏ธ",
171
+ "๐Ÿ‰‘","โ˜ข๏ธ","โ˜ฃ๏ธ","๐Ÿ“ด","๐Ÿ“ณ","๐Ÿˆถ","๐Ÿˆš","๐Ÿˆธ",
172
+ "๐Ÿˆบ","๐Ÿˆท๏ธ","โœด๏ธ","๐Ÿ†š","๐Ÿ’ฎ","๐Ÿ‰","ใŠ™๏ธ","ใŠ—๏ธ",
173
+ "๐Ÿˆด","๐Ÿˆต","๐Ÿˆน","๐Ÿˆฒ","๐Ÿ…ฐ๏ธ","๐Ÿ…ฑ๏ธ","๐Ÿ†Ž","๐Ÿ†‘",
174
+ "๐Ÿ…พ๏ธ","๐Ÿ†˜","โŒ","โญ•","๐Ÿ›‘","โ›”","๐Ÿ“›","๐Ÿšซ",
175
+ "๐Ÿ’ฏ","๐Ÿ’ข","โ™จ๏ธ","๐Ÿšท","๐Ÿšฏ","๐Ÿšณ","๐Ÿšฑ","๐Ÿ”ž",
176
+ "๐Ÿ“ต","๐Ÿšญ","โ—","โ•","โ“","โ”","โ€ผ๏ธ","โ‰๏ธ",
177
+ "๐Ÿ”…","๐Ÿ”†","ใ€ฝ๏ธ","โš ๏ธ","๐Ÿšธ","๐Ÿ”ฑ","โšœ๏ธ","๐Ÿ”ฐ",
178
+ "โ™ป๏ธ","โœ…","๐Ÿˆฏ","๐Ÿ’น","โ‡๏ธ","โœณ๏ธ","โŽ","๐ŸŒ",
179
+ "๐Ÿ’ ","โ“‚๏ธ","๐ŸŒ€","๐Ÿ’ค","๐Ÿง","๐Ÿšพ","โ™ฟ","๐Ÿ…ฟ๏ธ",
180
+ "๐Ÿ›—","๐Ÿˆณ","๐Ÿˆ‚๏ธ","๐Ÿ›‚","๐Ÿ›ƒ","๐Ÿ›„","๐Ÿ›…","๐Ÿšน",
181
+ "๐Ÿšบ","๐Ÿšผ","โšง๏ธ","๐Ÿšป","๐Ÿšฎ","๐ŸŽฆ","๐Ÿ“ถ","๐Ÿˆ",
182
+ "๐Ÿ”ฃ","โ„น๏ธ","๐Ÿ”ค","๐Ÿ”ก","๐Ÿ” ","๐Ÿ†–","๐Ÿ†—","๐Ÿ†™",
183
+ "๐Ÿ†’","๐Ÿ†•","๐Ÿ†“","0๏ธโƒฃ","1๏ธโƒฃ","2๏ธโƒฃ","3๏ธโƒฃ","4๏ธโƒฃ",
184
+ "5๏ธโƒฃ","6๏ธโƒฃ","7๏ธโƒฃ","8๏ธโƒฃ","9๏ธโƒฃ","๐Ÿ”Ÿ","๐Ÿ”ข","#๏ธโƒฃ",
185
+ "*๏ธโƒฃ","โ๏ธ","โ–ถ๏ธ","โธ๏ธ","โฏ๏ธ","โน๏ธ","โบ๏ธ","โญ๏ธ",
186
+ "โฎ๏ธ","โฉ","โช","โซ","โฌ","โ—€๏ธ","๐Ÿ”ผ","๐Ÿ”ฝ",
187
+ "โžก๏ธ","โฌ…๏ธ","โฌ†๏ธ","โฌ‡๏ธ","โ†—๏ธ","โ†˜๏ธ","โ†™๏ธ","โ†–๏ธ",
188
+ "โ†•๏ธ","โ†”๏ธ","โ†ฉ๏ธ","โ†ช๏ธ","โคด๏ธ","โคต๏ธ","๐Ÿ”€","๐Ÿ”",
189
+ "๐Ÿ”‚","๐Ÿ”„","๐Ÿ”ƒ","๐ŸŽต","๐ŸŽถ","โœ–๏ธ","โž•","โž–",
190
+ "โž—","๐ŸŸฐ","โ™พ๏ธ","๐Ÿ’ฒ","๐Ÿ’ฑ","โ„ข๏ธ","ยฉ๏ธ","ยฎ๏ธ",
191
+ "ใ€ฐ๏ธ","โžฐ","โžฟ","๐Ÿ”š","๐Ÿ”™","๐Ÿ”›","๐Ÿ”","๐Ÿ”œ",
192
+ "โœ”๏ธ","โ˜‘๏ธ","๐Ÿ”˜","๐Ÿ”ด","๐ŸŸ ","๐ŸŸก","๐ŸŸข","๐Ÿ”ต",
193
+ "๐ŸŸฃ","โšซ","โšช","๐ŸŸค","๐Ÿ”บ","๐Ÿ”ป","๐Ÿ”ธ","๐Ÿ”น",
194
+ "๐Ÿ”ถ","๐Ÿ”ท","๐Ÿ”ณ","๐Ÿ”ฒ","โ–ช๏ธ","โ–ซ๏ธ","โ—พ","โ—ฝ",
195
+ "โ—ผ๏ธ","โ—ป๏ธ","๐ŸŸฅ","๐ŸŸง","๐ŸŸจ","๐ŸŸฉ","๐ŸŸฆ","๐ŸŸช",
196
+ "โฌ›","โฌœ","๐ŸŸซ","๐Ÿ”ˆ","๐Ÿ”‡","๐Ÿ”‰","๐Ÿ”Š","๐Ÿ””",
197
+ "๐Ÿ”•","๐Ÿ“ฃ","๐Ÿ“ข","๐Ÿ‘๏ธโ€๐Ÿ—จ๏ธ","๐Ÿ’ฌ","๐Ÿ’ญ","๐Ÿ—ฏ๏ธ","โ™ ๏ธ",
198
+ "โ™ฃ๏ธ","โ™ฅ๏ธ","โ™ฆ๏ธ","๐Ÿƒ","๐ŸŽด","๐Ÿ€„","๐Ÿ•","๐Ÿ•‘",
199
+ "๐Ÿ•’","๐Ÿ•“","๐Ÿ•”","๐Ÿ••","๐Ÿ•–","๐Ÿ•—","๐Ÿ•˜","๐Ÿ•™","๐Ÿ•š","๐Ÿ•›",
200
+ ]},
201
+ { id: "flags", icon: "๐Ÿ", label: "Flags", emojis: [
202
+ "๐Ÿ","๐Ÿšฉ","๐ŸŽŒ","๐Ÿด","๐Ÿณ๏ธ","๐Ÿณ๏ธโ€๐ŸŒˆ","๐Ÿณ๏ธโ€โšง๏ธ","๐Ÿดโ€โ˜ ๏ธ",
203
+ "๐Ÿ‡ฆ๐Ÿ‡จ","๐Ÿ‡ฆ๐Ÿ‡ฉ","๐Ÿ‡ฆ๐Ÿ‡ช","๐Ÿ‡ฆ๐Ÿ‡ซ","๐Ÿ‡ฆ๐Ÿ‡ฌ","๐Ÿ‡ฆ๐Ÿ‡ฎ","๐Ÿ‡ฆ๐Ÿ‡ฑ","๐Ÿ‡ฆ๐Ÿ‡ฒ",
204
+ "๐Ÿ‡ฆ๐Ÿ‡ด","๐Ÿ‡ฆ๐Ÿ‡ถ","๐Ÿ‡ฆ๐Ÿ‡ท","๐Ÿ‡ฆ๐Ÿ‡ธ","๐Ÿ‡ฆ๐Ÿ‡น","๐Ÿ‡ฆ๐Ÿ‡บ","๐Ÿ‡ฆ๐Ÿ‡ผ","๐Ÿ‡ฆ๐Ÿ‡ฝ",
205
+ "๐Ÿ‡ฆ๐Ÿ‡ฟ","๐Ÿ‡ง๐Ÿ‡ฆ","๐Ÿ‡ง๐Ÿ‡ง","๐Ÿ‡ง๐Ÿ‡ฉ","๐Ÿ‡ง๐Ÿ‡ช","๐Ÿ‡ง๐Ÿ‡ซ","๐Ÿ‡ง๐Ÿ‡ฌ","๐Ÿ‡ง๐Ÿ‡ญ",
206
+ "๐Ÿ‡ง๐Ÿ‡ฎ","๐Ÿ‡ง๐Ÿ‡ฏ","๐Ÿ‡ง๐Ÿ‡ฑ","๐Ÿ‡ง๐Ÿ‡ฒ","๐Ÿ‡ง๐Ÿ‡ณ","๐Ÿ‡ง๐Ÿ‡ด","๐Ÿ‡ง๐Ÿ‡ถ","๐Ÿ‡ง๐Ÿ‡ท",
207
+ "๐Ÿ‡ง๐Ÿ‡ธ","๐Ÿ‡ง๐Ÿ‡น","๐Ÿ‡ง๐Ÿ‡ป","๐Ÿ‡ง๐Ÿ‡ผ","๐Ÿ‡ง๐Ÿ‡พ","๐Ÿ‡ง๐Ÿ‡ฟ","๐Ÿ‡จ๐Ÿ‡ฆ","๐Ÿ‡จ๐Ÿ‡จ",
208
+ "๐Ÿ‡จ๐Ÿ‡ฉ","๐Ÿ‡จ๐Ÿ‡ซ","๐Ÿ‡จ๐Ÿ‡ฌ","๐Ÿ‡จ๐Ÿ‡ญ","๐Ÿ‡จ๐Ÿ‡ฎ","๐Ÿ‡จ๐Ÿ‡ฐ","๐Ÿ‡จ๐Ÿ‡ฑ","๐Ÿ‡จ๐Ÿ‡ฒ",
209
+ "๐Ÿ‡จ๐Ÿ‡ณ","๐Ÿ‡จ๐Ÿ‡ด","๐Ÿ‡จ๐Ÿ‡ต","๐Ÿ‡จ๐Ÿ‡ท","๐Ÿ‡จ๐Ÿ‡บ","๐Ÿ‡จ๐Ÿ‡ป","๐Ÿ‡จ๐Ÿ‡ผ","๐Ÿ‡จ๐Ÿ‡ฝ",
210
+ "๐Ÿ‡จ๐Ÿ‡พ","๐Ÿ‡จ๐Ÿ‡ฟ","๐Ÿ‡ฉ๐Ÿ‡ช","๐Ÿ‡ฉ๐Ÿ‡ฌ","๐Ÿ‡ฉ๐Ÿ‡ฏ","๐Ÿ‡ฉ๐Ÿ‡ฐ","๐Ÿ‡ฉ๐Ÿ‡ฒ","๐Ÿ‡ฉ๐Ÿ‡ด",
211
+ "๐Ÿ‡ฉ๐Ÿ‡ฟ","๐Ÿ‡ช๐Ÿ‡ฆ","๐Ÿ‡ช๐Ÿ‡จ","๐Ÿ‡ช๐Ÿ‡ช","๐Ÿ‡ช๐Ÿ‡ฌ","๐Ÿ‡ช๐Ÿ‡ญ","๐Ÿ‡ช๐Ÿ‡ท","๐Ÿ‡ช๐Ÿ‡ธ",
212
+ "๐Ÿ‡ช๐Ÿ‡น","๐Ÿ‡ช๐Ÿ‡บ","๐Ÿ‡ซ๐Ÿ‡ฎ","๐Ÿ‡ซ๐Ÿ‡ฏ","๐Ÿ‡ซ๐Ÿ‡ฐ","๐Ÿ‡ซ๐Ÿ‡ฒ","๐Ÿ‡ซ๐Ÿ‡ด","๐Ÿ‡ซ๐Ÿ‡ท",
213
+ "๐Ÿ‡ฌ๐Ÿ‡ฆ","๐Ÿ‡ฌ๐Ÿ‡ง","๐Ÿ‡ฌ๐Ÿ‡ฉ","๐Ÿ‡ฌ๐Ÿ‡ช","๐Ÿ‡ฌ๐Ÿ‡ซ","๐Ÿ‡ฌ๐Ÿ‡ฌ","๐Ÿ‡ฌ๐Ÿ‡ญ","๐Ÿ‡ฌ๐Ÿ‡ฎ",
214
+ "๐Ÿ‡ฌ๐Ÿ‡ฑ","๐Ÿ‡ฌ๐Ÿ‡ฒ","๐Ÿ‡ฌ๐Ÿ‡ณ","๐Ÿ‡ฌ๐Ÿ‡ต","๐Ÿ‡ฌ๐Ÿ‡ถ","๐Ÿ‡ฌ๐Ÿ‡ท","๐Ÿ‡ฌ๐Ÿ‡ธ","๐Ÿ‡ฌ๐Ÿ‡น",
215
+ "๐Ÿ‡ฌ๐Ÿ‡บ","๐Ÿ‡ฌ๐Ÿ‡ผ","๐Ÿ‡ฌ๐Ÿ‡พ","๐Ÿ‡ญ๐Ÿ‡ฐ","๐Ÿ‡ญ๐Ÿ‡ฒ","๐Ÿ‡ญ๐Ÿ‡ณ","๐Ÿ‡ญ๐Ÿ‡ท","๐Ÿ‡ญ๐Ÿ‡น",
216
+ "๐Ÿ‡ญ๐Ÿ‡บ","๐Ÿ‡ฎ๐Ÿ‡จ","๐Ÿ‡ฎ๐Ÿ‡ฉ","๐Ÿ‡ฎ๐Ÿ‡ช","๐Ÿ‡ฎ๐Ÿ‡ฑ","๐Ÿ‡ฎ๐Ÿ‡ฒ","๐Ÿ‡ฎ๐Ÿ‡ณ","๐Ÿ‡ฎ๐Ÿ‡ด",
217
+ "๐Ÿ‡ฎ๐Ÿ‡ถ","๐Ÿ‡ฎ๐Ÿ‡ท","๐Ÿ‡ฎ๐Ÿ‡ธ","๐Ÿ‡ฎ๐Ÿ‡น","๐Ÿ‡ฏ๐Ÿ‡ช","๐Ÿ‡ฏ๐Ÿ‡ฒ","๐Ÿ‡ฏ๐Ÿ‡ด","๐Ÿ‡ฏ๐Ÿ‡ต",
218
+ "๐Ÿ‡ฐ๐Ÿ‡ช","๐Ÿ‡ฐ๐Ÿ‡ฌ","๐Ÿ‡ฐ๐Ÿ‡ญ","๐Ÿ‡ฐ๐Ÿ‡ฎ","๐Ÿ‡ฐ๐Ÿ‡ฒ","๐Ÿ‡ฐ๐Ÿ‡ณ","๐Ÿ‡ฐ๐Ÿ‡ต","๐Ÿ‡ฐ๐Ÿ‡ท",
219
+ "๐Ÿ‡ฐ๐Ÿ‡ผ","๐Ÿ‡ฐ๐Ÿ‡พ","๐Ÿ‡ฐ๐Ÿ‡ฟ","๐Ÿ‡ฑ๐Ÿ‡ฆ","๐Ÿ‡ฑ๐Ÿ‡ง","๐Ÿ‡ฑ๐Ÿ‡จ","๐Ÿ‡ฑ๐Ÿ‡ฎ","๐Ÿ‡ฑ๐Ÿ‡ฐ",
220
+ "๐Ÿ‡ฑ๐Ÿ‡ท","๐Ÿ‡ฑ๐Ÿ‡ธ","๐Ÿ‡ฑ๐Ÿ‡น","๐Ÿ‡ฑ๐Ÿ‡บ","๐Ÿ‡ฑ๐Ÿ‡ป","๐Ÿ‡ฑ๐Ÿ‡พ","๐Ÿ‡ฒ๐Ÿ‡ฆ","๐Ÿ‡ฒ๐Ÿ‡จ",
221
+ "๐Ÿ‡ฒ๐Ÿ‡ฉ","๐Ÿ‡ฒ๐Ÿ‡ช","๐Ÿ‡ฒ๐Ÿ‡ซ","๐Ÿ‡ฒ๐Ÿ‡ฌ","๐Ÿ‡ฒ๐Ÿ‡ญ","๐Ÿ‡ฒ๐Ÿ‡ฐ","๐Ÿ‡ฒ๐Ÿ‡ฑ","๐Ÿ‡ฒ๐Ÿ‡ฒ",
222
+ "๐Ÿ‡ฒ๐Ÿ‡ณ","๐Ÿ‡ฒ๐Ÿ‡ด","๐Ÿ‡ฒ๐Ÿ‡ต","๐Ÿ‡ฒ๐Ÿ‡ถ","๐Ÿ‡ฒ๐Ÿ‡ท","๐Ÿ‡ฒ๐Ÿ‡ธ","๐Ÿ‡ฒ๐Ÿ‡น","๐Ÿ‡ฒ๐Ÿ‡บ",
223
+ "๐Ÿ‡ฒ๐Ÿ‡ป","๐Ÿ‡ฒ๐Ÿ‡ผ","๐Ÿ‡ฒ๐Ÿ‡ฝ","๐Ÿ‡ฒ๐Ÿ‡พ","๐Ÿ‡ฒ๐Ÿ‡ฟ","๐Ÿ‡ณ๐Ÿ‡ฆ","๐Ÿ‡ณ๐Ÿ‡จ","๐Ÿ‡ณ๐Ÿ‡ช",
224
+ "๐Ÿ‡ณ๐Ÿ‡ซ","๐Ÿ‡ณ๐Ÿ‡ฌ","๐Ÿ‡ณ๐Ÿ‡ฎ","๐Ÿ‡ณ๐Ÿ‡ฑ","๐Ÿ‡ณ๐Ÿ‡ด","๐Ÿ‡ณ๐Ÿ‡ต","๐Ÿ‡ณ๐Ÿ‡ท","๐Ÿ‡ณ๐Ÿ‡บ",
225
+ "๐Ÿ‡ณ๐Ÿ‡ฟ","๐Ÿ‡ด๐Ÿ‡ฒ","๐Ÿ‡ต๐Ÿ‡ฆ","๐Ÿ‡ต๐Ÿ‡ช","๐Ÿ‡ต๐Ÿ‡ซ","๐Ÿ‡ต๐Ÿ‡ฌ","๐Ÿ‡ต๐Ÿ‡ญ","๐Ÿ‡ต๐Ÿ‡ฐ",
226
+ "๐Ÿ‡ต๐Ÿ‡ฑ","๐Ÿ‡ต๐Ÿ‡ฒ","๐Ÿ‡ต๐Ÿ‡ณ","๐Ÿ‡ต๐Ÿ‡ท","๐Ÿ‡ต๐Ÿ‡ธ","๐Ÿ‡ต๐Ÿ‡น","๐Ÿ‡ต๐Ÿ‡ผ","๐Ÿ‡ต๐Ÿ‡พ",
227
+ "๐Ÿ‡ถ๐Ÿ‡ฆ","๐Ÿ‡ท๐Ÿ‡ช","๐Ÿ‡ท๐Ÿ‡ด","๐Ÿ‡ท๐Ÿ‡ธ","๐Ÿ‡ท๐Ÿ‡บ","๐Ÿ‡ท๐Ÿ‡ผ","๐Ÿ‡ธ๐Ÿ‡ฆ","๐Ÿ‡ธ๐Ÿ‡ง",
228
+ "๐Ÿ‡ธ๐Ÿ‡จ","๐Ÿ‡ธ๐Ÿ‡ฉ","๐Ÿ‡ธ๐Ÿ‡ช","๐Ÿ‡ธ๐Ÿ‡ฌ","๐Ÿ‡ธ๐Ÿ‡ญ","๐Ÿ‡ธ๐Ÿ‡ฎ","๐Ÿ‡ธ๐Ÿ‡ฏ","๐Ÿ‡ธ๐Ÿ‡ฐ",
229
+ "๐Ÿ‡ธ๐Ÿ‡ฑ","๐Ÿ‡ธ๐Ÿ‡ฒ","๐Ÿ‡ธ๐Ÿ‡ณ","๐Ÿ‡ธ๐Ÿ‡ด","๐Ÿ‡ธ๐Ÿ‡ท","๐Ÿ‡ธ๐Ÿ‡ธ","๐Ÿ‡ธ๐Ÿ‡น","๐Ÿ‡ธ๐Ÿ‡ป",
230
+ "๐Ÿ‡ธ๐Ÿ‡ฝ","๐Ÿ‡ธ๐Ÿ‡พ","๐Ÿ‡ธ๐Ÿ‡ฟ","๐Ÿ‡น๐Ÿ‡ฆ","๐Ÿ‡น๐Ÿ‡จ","๐Ÿ‡น๐Ÿ‡ฉ","๐Ÿ‡น๐Ÿ‡ซ","๐Ÿ‡น๐Ÿ‡ฌ",
231
+ "๐Ÿ‡น๐Ÿ‡ญ","๐Ÿ‡น๐Ÿ‡ฏ","๐Ÿ‡น๐Ÿ‡ฐ","๐Ÿ‡น๐Ÿ‡ฑ","๐Ÿ‡น๐Ÿ‡ฒ","๐Ÿ‡น๐Ÿ‡ณ","๐Ÿ‡น๐Ÿ‡ด","๐Ÿ‡น๐Ÿ‡ท",
232
+ "๐Ÿ‡น๐Ÿ‡น","๐Ÿ‡น๐Ÿ‡ป","๐Ÿ‡น๐Ÿ‡ผ","๐Ÿ‡น๐Ÿ‡ฟ","๐Ÿ‡บ๐Ÿ‡ฆ","๐Ÿ‡บ๐Ÿ‡ฌ","๐Ÿ‡บ๐Ÿ‡ฒ","๐Ÿ‡บ๐Ÿ‡ณ",
233
+ "๐Ÿ‡บ๐Ÿ‡ธ","๐Ÿ‡บ๐Ÿ‡พ","๐Ÿ‡บ๐Ÿ‡ฟ","๐Ÿ‡ป๐Ÿ‡ฆ","๐Ÿ‡ป๐Ÿ‡จ","๐Ÿ‡ป๐Ÿ‡ช","๐Ÿ‡ป๐Ÿ‡ฌ","๐Ÿ‡ป๐Ÿ‡ฎ",
234
+ "๐Ÿ‡ป๐Ÿ‡ณ","๐Ÿ‡ป๐Ÿ‡บ","๐Ÿ‡ผ๐Ÿ‡ซ","๐Ÿ‡ผ๐Ÿ‡ธ","๐Ÿ‡ฝ๐Ÿ‡ฐ","๐Ÿ‡พ๐Ÿ‡ช","๐Ÿ‡พ๐Ÿ‡น","๐Ÿ‡ฟ๐Ÿ‡ฆ",
235
+ "๐Ÿ‡ฟ๐Ÿ‡ฒ","๐Ÿ‡ฟ๐Ÿ‡ผ",
236
+ ]},
237
+ ];
238
+
239
+ export function initSidebarProjects(ctx) {
240
+ _ctx = ctx;
241
+
242
+ // Close project ctx menu and emoji picker on document click
243
+ document.addEventListener("click", function () {
244
+ closeProjectCtxMenu();
245
+ closeEmojiPicker();
246
+ });
247
+
248
+ // Initialize icon strip buttons
249
+ var addBtn = document.getElementById("icon-strip-add");
250
+ if (addBtn) {
251
+ addBtn.addEventListener("click", function () {
252
+ if (_ctx.openAddProjectModal) {
253
+ _ctx.openAddProjectModal();
254
+ } else {
255
+ var modal = _ctx.$("add-project-modal");
256
+ if (modal) modal.classList.remove("hidden");
257
+ }
258
+ });
259
+ addBtn.addEventListener("mouseenter", function () { _ctx.showIconTooltip(addBtn, "Add project"); });
260
+ addBtn.addEventListener("mouseleave", _ctx.hideIconTooltip);
261
+ }
262
+
263
+ var exploreBtn = document.getElementById("icon-strip-explore");
264
+ if (exploreBtn) {
265
+ exploreBtn.addEventListener("click", function () {
266
+ var fileBrowserBtn = _ctx.$("file-browser-btn");
267
+ if (fileBrowserBtn) fileBrowserBtn.click();
268
+ });
269
+ exploreBtn.addEventListener("mouseenter", function () { _ctx.showIconTooltip(exploreBtn, "File browser"); });
270
+ exploreBtn.addEventListener("mouseleave", _ctx.hideIconTooltip);
271
+ }
272
+
273
+ // Tooltip + click for home icon
274
+ var homeIcon = document.querySelector(".icon-strip-home");
275
+ if (homeIcon) {
276
+ homeIcon.addEventListener("mouseenter", function () { _ctx.showIconTooltip(homeIcon, "Clay"); });
277
+ homeIcon.addEventListener("mouseleave", _ctx.hideIconTooltip);
278
+ homeIcon.addEventListener("click", function (e) {
279
+ e.preventDefault();
280
+ if (_ctx.showHomeHub) _ctx.showHomeHub();
281
+ });
282
+ homeIcon.style.cursor = "pointer";
283
+ }
284
+
285
+ // Chevron dropdown on project name
286
+ var dropdownBtn = document.getElementById("title-bar-project-dropdown");
287
+ if (dropdownBtn) {
288
+ dropdownBtn.addEventListener("click", function (e) {
289
+ e.stopPropagation();
290
+ var current = null;
291
+ for (var i = 0; i < cachedProjectList.length; i++) {
292
+ if (cachedProjectList[i].slug === cachedCurrentSlug) {
293
+ current = cachedProjectList[i];
294
+ break;
295
+ }
296
+ }
297
+ if (!current) return;
298
+
299
+ if (projectCtxMenu) {
300
+ closeProjectCtxMenu();
301
+ dropdownBtn.classList.remove("open");
302
+ return;
303
+ }
304
+ dropdownBtn.classList.add("open");
305
+ showProjectCtxMenu(dropdownBtn, current.slug, current.name, current.icon, "below");
306
+ var observer = new MutationObserver(function () {
307
+ if (!projectCtxMenu) {
308
+ dropdownBtn.classList.remove("open");
309
+ observer.disconnect();
310
+ }
311
+ });
312
+ observer.observe(document.body, { childList: true });
313
+ });
314
+ }
315
+
316
+ return {
317
+ renderIconStrip: renderIconStrip,
318
+ renderProjectList: renderProjectList,
319
+ updateBadge: updateProjectBadge,
320
+ getEmojiCategories: getEmojiCategories
321
+ };
322
+ }
323
+
324
+ // --- Getters for cached state (used by mobile sheet in sidebar.js) ---
325
+ export function getCachedProjectList() { return cachedProjectList; }
326
+ export function getCachedCurrentSlug() { return cachedCurrentSlug; }
327
+
328
+ function getProjectAbbrev(name) {
329
+ if (!name) return "?";
330
+ var words = name.replace(/[^a-zA-Z0-9\s]/g, "").trim().split(/\s+/);
331
+ if (words.length >= 2) {
332
+ return (words[0][0] + words[1][0]).toUpperCase();
333
+ }
334
+ return name.substring(0, 2).toUpperCase();
335
+ }
336
+
337
+ export { getProjectAbbrev };
338
+
339
+ // --- Project Access Popover ---
340
+
341
+ function closeAccessOnOutside(e) {
342
+ if (projectAccessPopover && !projectAccessPopover.contains(e.target)) closeProjectAccessPopover();
343
+ }
344
+ function closeAccessOnEscape(e) {
345
+ if (e.key === "Escape") closeProjectAccessPopover();
346
+ }
347
+
348
+ function closeProjectAccessPopover() {
349
+ if (projectAccessPopover) {
350
+ projectAccessPopover.remove();
351
+ projectAccessPopover = null;
352
+ document.removeEventListener("click", closeAccessOnOutside);
353
+ document.removeEventListener("keydown", closeAccessOnEscape);
354
+ }
355
+ }
356
+
357
+ function showProjectAccessPopover(anchorEl, slug) {
358
+ closeProjectAccessPopover();
359
+
360
+ var popover = document.createElement("div");
361
+ popover.className = "project-access-popover";
362
+ popover.innerHTML = '<div class="project-access-loading">Loading...</div>';
363
+ popover.addEventListener("click", function (e) { e.stopPropagation(); });
364
+ document.body.appendChild(popover);
365
+ projectAccessPopover = popover;
366
+
367
+ requestAnimationFrame(function () {
368
+ var rect = anchorEl.getBoundingClientRect();
369
+ popover.style.position = "fixed";
370
+ popover.style.left = (rect.right + 8) + "px";
371
+ popover.style.top = rect.top + "px";
372
+ popover.style.zIndex = "9999";
373
+ var popRect = popover.getBoundingClientRect();
374
+ if (popRect.right > window.innerWidth - 8) {
375
+ popover.style.left = (rect.left - popRect.width - 8) + "px";
376
+ }
377
+ if (popRect.bottom > window.innerHeight - 8) {
378
+ popover.style.top = (window.innerHeight - popRect.height - 8) + "px";
379
+ }
380
+ });
381
+
382
+ setTimeout(function () {
383
+ document.addEventListener("click", closeAccessOnOutside);
384
+ document.addEventListener("keydown", closeAccessOnEscape);
385
+ }, 0);
386
+
387
+ Promise.all([
388
+ fetch("/api/admin/projects/" + encodeURIComponent(slug) + "/access").then(function (r) { return r.json(); }),
389
+ fetch("/api/admin/users").then(function (r) { return r.json(); }),
390
+ ]).then(function (results) {
391
+ var access = results[0];
392
+ var usersData = results[1];
393
+ if (access.error || usersData.error) {
394
+ popover.innerHTML = '<div class="project-access-loading">Failed to load</div>';
395
+ return;
396
+ }
397
+ renderAccessPopover(popover, slug, access, usersData.users || []);
398
+ }).catch(function () {
399
+ popover.innerHTML = '<div class="project-access-loading">Failed to load</div>';
400
+ });
401
+ }
402
+
403
+ function renderAccessPopover(popover, slug, access, allUsers) {
404
+ var visibility = access.visibility || "public";
405
+ var allowedUsers = access.allowedUsers || [];
406
+ var ownerId = access.ownerId;
407
+
408
+ var selectableUsers = allUsers.filter(function (u) { return u.id !== ownerId; });
409
+
410
+ var html = '';
411
+ html += '<div class="project-access-header">';
412
+ html += '<span class="project-access-title">Project Access</span>';
413
+ html += '<button class="project-access-close">&times;</button>';
414
+ html += '</div>';
415
+
416
+ html += '<div class="project-access-section">';
417
+ html += '<label class="project-access-label">Visibility</label>';
418
+ html += '<div class="project-access-vis-row">';
419
+ html += '<button class="project-access-vis-btn' + (visibility === "private" ? ' active' : '') + '" data-vis="private">';
420
+ html += iconHtml("lock") + ' Private';
421
+ html += '</button>';
422
+ html += '<button class="project-access-vis-btn' + (visibility === "public" ? ' active' : '') + '" data-vis="public">';
423
+ html += iconHtml("globe") + ' Public';
424
+ html += '</button>';
425
+ html += '</div>';
426
+ html += '</div>';
427
+
428
+ html += '<div class="project-access-section project-access-users-section"' + (visibility !== "private" ? ' style="display:none"' : '') + '>';
429
+ html += '<label class="project-access-label">Allowed Users</label>';
430
+ html += '<div class="project-access-user-list">';
431
+ for (var i = 0; i < selectableUsers.length; i++) {
432
+ var u = selectableUsers[i];
433
+ var checked = allowedUsers.indexOf(u.id) !== -1 ? " checked" : "";
434
+ html += '<label class="project-access-user-item">';
435
+ html += '<input type="checkbox" data-uid="' + u.id + '"' + checked + '>';
436
+ html += '<span>' + escapeHtml(u.displayName || u.username || u.id) + '</span>';
437
+ html += '</label>';
438
+ }
439
+ if (selectableUsers.length === 0) {
440
+ html += '<div class="project-access-empty">No other users</div>';
441
+ }
442
+ html += '</div>';
443
+ html += '</div>';
444
+
445
+ popover.innerHTML = html;
446
+ refreshIcons();
447
+
448
+ popover.querySelector(".project-access-close").addEventListener("click", function () {
449
+ closeProjectAccessPopover();
450
+ });
451
+
452
+ popover.querySelectorAll(".project-access-vis-btn").forEach(function (btn) {
453
+ btn.addEventListener("click", function () {
454
+ var newVis = btn.dataset.vis;
455
+ popover.querySelectorAll(".project-access-vis-btn").forEach(function (b) { b.classList.remove("active"); });
456
+ btn.classList.add("active");
457
+ var usersSection = popover.querySelector(".project-access-users-section");
458
+ if (usersSection) usersSection.style.display = newVis === "private" ? "" : "none";
459
+ fetch("/api/admin/projects/" + encodeURIComponent(slug) + "/visibility", {
460
+ method: "PUT",
461
+ headers: { "Content-Type": "application/json" },
462
+ body: JSON.stringify({ visibility: newVis }),
463
+ });
464
+ });
465
+ });
466
+
467
+ popover.querySelectorAll('.project-access-user-item input[type="checkbox"]').forEach(function (cb) {
468
+ cb.addEventListener("change", function () {
469
+ var selected = [];
470
+ popover.querySelectorAll('.project-access-user-item input[type="checkbox"]:checked').forEach(function (c) {
471
+ selected.push(c.dataset.uid);
472
+ });
473
+ fetch("/api/admin/projects/" + encodeURIComponent(slug) + "/users", {
474
+ method: "PUT",
475
+ headers: { "Content-Type": "application/json" },
476
+ body: JSON.stringify({ allowedUsers: selected }),
477
+ });
478
+ });
479
+ });
480
+ }
481
+
482
+ // --- Project context menu ---
483
+
484
+ export function closeProjectCtxMenu() {
485
+ if (projectCtxMenu) {
486
+ projectCtxMenu.remove();
487
+ projectCtxMenu = null;
488
+ }
489
+ }
490
+
491
+ function showIconCtxMenu(anchorEl, slug, name) {
492
+ closeProjectCtxMenu();
493
+ if (_ctx.closeUserCtxMenu) _ctx.closeUserCtxMenu();
494
+ closeEmojiPicker();
495
+
496
+ var menu = document.createElement("div");
497
+ menu.className = "project-ctx-menu";
498
+
499
+ var isWorktree = slug.indexOf("--") !== -1;
500
+
501
+ if (isWorktree) {
502
+ var removeWtItem = document.createElement("button");
503
+ removeWtItem.className = "project-ctx-item project-ctx-delete";
504
+ removeWtItem.innerHTML = iconHtml("trash-2") + " <span>Remove Worktree</span>";
505
+ removeWtItem.addEventListener("click", function (e) {
506
+ e.stopPropagation();
507
+ closeProjectCtxMenu();
508
+ if (_ctx.ws && _ctx.connected) {
509
+ _ctx.ws.send(JSON.stringify({ type: "remove_project_check", slug: slug, name: name || slug }));
510
+ }
511
+ });
512
+ menu.appendChild(removeWtItem);
513
+ } else {
514
+ var iconItem = document.createElement("button");
515
+ iconItem.className = "project-ctx-item";
516
+ iconItem.innerHTML = iconHtml("smile") + " <span>Set Icon</span>";
517
+ iconItem.addEventListener("click", function (e) {
518
+ e.stopPropagation();
519
+ closeProjectCtxMenu();
520
+ showEmojiPicker(slug, anchorEl);
521
+ });
522
+ menu.appendChild(iconItem);
523
+
524
+ var wtItem = document.createElement("button");
525
+ wtItem.className = "project-ctx-item";
526
+ wtItem.innerHTML = iconHtml("git-branch") + " <span>Add Worktree</span>";
527
+ wtItem.addEventListener("click", function (e) {
528
+ e.stopPropagation();
529
+ closeProjectCtxMenu();
530
+ showWorktreeModal(slug, name || slug);
531
+ });
532
+ menu.appendChild(wtItem);
533
+ }
534
+
535
+ document.body.appendChild(menu);
536
+ projectCtxMenu = menu;
537
+ refreshIcons();
538
+
539
+ requestAnimationFrame(function () {
540
+ var rect = anchorEl.getBoundingClientRect();
541
+ menu.style.position = "fixed";
542
+ menu.style.left = (rect.right + 6) + "px";
543
+ menu.style.top = rect.top + "px";
544
+ var menuRect = menu.getBoundingClientRect();
545
+ if (menuRect.right > window.innerWidth - 8) {
546
+ menu.style.left = (rect.left - menuRect.width - 6) + "px";
547
+ }
548
+ if (menuRect.bottom > window.innerHeight - 8) {
549
+ menu.style.top = (window.innerHeight - menuRect.height - 8) + "px";
550
+ }
551
+ });
552
+ }
553
+
554
+ function showProjectCtxMenu(anchorEl, slug, name, icon, position) {
555
+ closeProjectCtxMenu();
556
+ if (_ctx.closeUserCtxMenu) _ctx.closeUserCtxMenu();
557
+ closeEmojiPicker();
558
+
559
+ var menu = document.createElement("div");
560
+ menu.className = "project-ctx-menu";
561
+
562
+ // --- Set Icon ---
563
+ var iconItem = document.createElement("button");
564
+ iconItem.className = "project-ctx-item";
565
+ iconItem.innerHTML = iconHtml("smile") + " <span>Set Icon</span>";
566
+ iconItem.addEventListener("click", function (e) {
567
+ e.stopPropagation();
568
+ closeProjectCtxMenu();
569
+ showEmojiPicker(slug, anchorEl);
570
+ });
571
+ menu.appendChild(iconItem);
572
+
573
+ // --- Project Settings ---
574
+ if (!_ctx.permissions || _ctx.permissions.projectSettings !== false) {
575
+ var settingsItem = document.createElement("button");
576
+ settingsItem.className = "project-ctx-item";
577
+ settingsItem.innerHTML = iconHtml("settings") + " <span>Project Settings</span>";
578
+ settingsItem.addEventListener("click", function (e) {
579
+ e.stopPropagation();
580
+ closeProjectCtxMenu();
581
+ openProjectSettings(slug, { slug: slug, name: name, icon: icon, projectOwnerId: _ctx.projectOwnerId });
582
+ });
583
+ menu.appendChild(settingsItem);
584
+ }
585
+
586
+ var sep1 = document.createElement("div");
587
+ sep1.className = "project-ctx-separator";
588
+ menu.appendChild(sep1);
589
+
590
+ // --- Share ---
591
+ var shareItem = document.createElement("button");
592
+ shareItem.className = "project-ctx-item";
593
+ shareItem.innerHTML = iconHtml("share") + " <span>Share</span>";
594
+ shareItem.addEventListener("click", function (e) {
595
+ e.stopPropagation();
596
+ closeProjectCtxMenu();
597
+ triggerShare();
598
+ });
599
+ menu.appendChild(shareItem);
600
+
601
+ // --- Manage Access ---
602
+ if (_ctx.multiUser && slug.indexOf("--") === -1) {
603
+ var isProjectOwner = _ctx.myUserId && _ctx.projectOwnerId && _ctx.myUserId === _ctx.projectOwnerId;
604
+ var isAdmin = _ctx.permissions && _ctx.permissions.projectSettings !== false;
605
+ if (isProjectOwner || isAdmin) {
606
+ var accessItem = document.createElement("button");
607
+ accessItem.className = "project-ctx-item";
608
+ accessItem.innerHTML = iconHtml("users") + " <span>Manage Access</span>";
609
+ accessItem.addEventListener("click", function (e) {
610
+ e.stopPropagation();
611
+ closeProjectCtxMenu();
612
+ showProjectAccessPopover(anchorEl, slug);
613
+ });
614
+ menu.appendChild(accessItem);
615
+ }
616
+ }
617
+
618
+ var sep2 = document.createElement("div");
619
+ sep2.className = "project-ctx-separator";
620
+ menu.appendChild(sep2);
621
+
622
+ // --- Add Worktree ---
623
+ var wtItem = document.createElement("button");
624
+ wtItem.className = "project-ctx-item";
625
+ wtItem.innerHTML = iconHtml("git-branch") + " <span>Add Worktree</span>";
626
+ wtItem.addEventListener("click", function (e) {
627
+ e.stopPropagation();
628
+ closeProjectCtxMenu();
629
+ showWorktreeModal(slug, name || slug);
630
+ });
631
+ menu.appendChild(wtItem);
632
+
633
+ if (!_ctx.permissions || _ctx.permissions.deleteProject !== false) {
634
+ var sep3 = document.createElement("div");
635
+ sep3.className = "project-ctx-separator";
636
+ menu.appendChild(sep3);
637
+
638
+ var deleteItem = document.createElement("button");
639
+ deleteItem.className = "project-ctx-item project-ctx-delete";
640
+ deleteItem.innerHTML = iconHtml("trash-2") + " <span>Remove Project</span>";
641
+ deleteItem.addEventListener("click", function (e) {
642
+ e.stopPropagation();
643
+ closeProjectCtxMenu();
644
+ if (_ctx.ws && _ctx.connected) {
645
+ _ctx.ws.send(JSON.stringify({ type: "remove_project_check", slug: slug, name: name }));
646
+ }
647
+ });
648
+ menu.appendChild(deleteItem);
649
+ }
650
+
651
+ document.body.appendChild(menu);
652
+ projectCtxMenu = menu;
653
+ refreshIcons();
654
+
655
+ requestAnimationFrame(function () {
656
+ var rect = anchorEl.getBoundingClientRect();
657
+ menu.style.position = "fixed";
658
+ if (position === "below") {
659
+ menu.style.left = rect.left + "px";
660
+ menu.style.top = (rect.bottom + 4) + "px";
661
+ } else {
662
+ menu.style.left = (rect.right + 6) + "px";
663
+ menu.style.top = rect.top + "px";
664
+ }
665
+ var menuRect = menu.getBoundingClientRect();
666
+ if (menuRect.right > window.innerWidth - 8) {
667
+ menu.style.left = (rect.left - menuRect.width - 6) + "px";
668
+ }
669
+ if (menuRect.bottom > window.innerHeight - 8) {
670
+ menu.style.top = (window.innerHeight - menuRect.height - 8) + "px";
671
+ }
672
+ });
673
+ }
674
+
675
+ // --- Emoji picker ---
676
+
677
+ function closeEmojiPicker() {
678
+ if (emojiPickerEl) {
679
+ emojiPickerEl.remove();
680
+ emojiPickerEl = null;
681
+ }
682
+ }
683
+
684
+ function showEmojiPicker(slug, anchorEl) {
685
+ closeEmojiPicker();
686
+
687
+ var picker = document.createElement("div");
688
+ picker.className = "emoji-picker";
689
+ picker.addEventListener("click", function (e) { e.stopPropagation(); });
690
+
691
+ var header = document.createElement("div");
692
+ header.className = "emoji-picker-header";
693
+ header.textContent = "Choose Icon";
694
+
695
+ var removeBtn = document.createElement("button");
696
+ removeBtn.className = "emoji-picker-remove";
697
+ removeBtn.textContent = "Remove";
698
+ removeBtn.addEventListener("click", function (e) {
699
+ e.stopPropagation();
700
+ closeEmojiPicker();
701
+ if (_ctx.ws && _ctx.connected) {
702
+ _ctx.ws.send(JSON.stringify({ type: "set_project_icon", slug: slug, icon: null }));
703
+ }
704
+ });
705
+ header.appendChild(removeBtn);
706
+ picker.appendChild(header);
707
+
708
+ var tabBar = document.createElement("div");
709
+ tabBar.className = "emoji-picker-tabs";
710
+ var tabBtns = [];
711
+
712
+ for (var t = 0; t < EMOJI_CATEGORIES.length; t++) {
713
+ (function (cat, idx) {
714
+ var tab = document.createElement("button");
715
+ tab.className = "emoji-picker-tab" + (idx === 0 ? " active" : "");
716
+ tab.textContent = cat.icon;
717
+ tab.title = cat.label;
718
+ tab.addEventListener("click", function (e) {
719
+ e.stopPropagation();
720
+ switchCategory(idx);
721
+ });
722
+ tabBar.appendChild(tab);
723
+ tabBtns.push(tab);
724
+ })(EMOJI_CATEGORIES[t], t);
725
+ }
726
+ parseEmojis(tabBar);
727
+ picker.appendChild(tabBar);
728
+
729
+ var scrollArea = document.createElement("div");
730
+ scrollArea.className = "emoji-picker-scroll";
731
+
732
+ var grid = document.createElement("div");
733
+ grid.className = "emoji-picker-grid";
734
+ scrollArea.appendChild(grid);
735
+ picker.appendChild(scrollArea);
736
+
737
+ function buildGrid(emojis) {
738
+ grid.innerHTML = "";
739
+ for (var i = 0; i < emojis.length; i++) {
740
+ (function (emoji) {
741
+ var btn = document.createElement("button");
742
+ btn.className = "emoji-picker-item";
743
+ btn.textContent = emoji;
744
+ btn.addEventListener("click", function (e) {
745
+ e.stopPropagation();
746
+ closeEmojiPicker();
747
+ if (_ctx.ws && _ctx.connected) {
748
+ _ctx.ws.send(JSON.stringify({ type: "set_project_icon", slug: slug, icon: emoji }));
749
+ }
750
+ });
751
+ grid.appendChild(btn);
752
+ })(emojis[i]);
753
+ }
754
+ parseEmojis(grid);
755
+ scrollArea.scrollTop = 0;
756
+ }
757
+
758
+ function switchCategory(idx) {
759
+ for (var j = 0; j < tabBtns.length; j++) {
760
+ tabBtns[j].classList.toggle("active", j === idx);
761
+ }
762
+ buildGrid(EMOJI_CATEGORIES[idx].emojis);
763
+ }
764
+
765
+ buildGrid(EMOJI_CATEGORIES[0].emojis);
766
+
767
+ document.body.appendChild(picker);
768
+ emojiPickerEl = picker;
769
+
770
+ requestAnimationFrame(function () {
771
+ var rect = anchorEl.getBoundingClientRect();
772
+ picker.style.left = (rect.right + 6) + "px";
773
+ picker.style.top = rect.top + "px";
774
+ var pRect = picker.getBoundingClientRect();
775
+ if (pRect.right > window.innerWidth - 8) {
776
+ picker.style.left = (rect.left - pRect.width - 6) + "px";
777
+ }
778
+ if (pRect.bottom > window.innerHeight - 8) {
779
+ picker.style.top = (window.innerHeight - pRect.height - 8) + "px";
780
+ }
781
+ });
782
+ }
783
+
784
+ // --- Rename prompt ---
785
+ function showProjectRename(slug, currentName) {
786
+ var nameEl = document.getElementById("title-bar-project-name");
787
+ if (!nameEl) return;
788
+
789
+ var input = document.createElement("input");
790
+ input.type = "text";
791
+ input.className = "project-rename-input";
792
+ input.value = currentName || "";
793
+
794
+ var originalText = nameEl.textContent;
795
+ nameEl.textContent = "";
796
+ nameEl.appendChild(input);
797
+ input.focus();
798
+ input.select();
799
+
800
+ var committed = false;
801
+
802
+ function commitRename() {
803
+ if (committed) return;
804
+ committed = true;
805
+ var newName = input.value.trim();
806
+ if (newName && newName !== currentName && _ctx.ws && _ctx.connected) {
807
+ _ctx.ws.send(JSON.stringify({ type: "set_project_title", slug: slug, title: newName }));
808
+ nameEl.textContent = newName;
809
+ } else {
810
+ nameEl.textContent = originalText;
811
+ }
812
+ }
813
+
814
+ input.addEventListener("keydown", function (e) {
815
+ e.stopPropagation();
816
+ if (e.key === "Enter") { e.preventDefault(); commitRename(); }
817
+ if (e.key === "Escape") { e.preventDefault(); committed = true; nameEl.textContent = originalText; }
818
+ });
819
+ input.addEventListener("blur", commitRename);
820
+ input.addEventListener("click", function (e) { e.stopPropagation(); });
821
+ }
822
+
823
+ // --- Drag-and-drop ---
824
+
825
+ function showTrashZone() {
826
+ var addBtn = document.getElementById("icon-strip-add");
827
+ if (!addBtn) return;
828
+ addBtn.style.display = "none";
829
+
830
+ var existing = document.getElementById("icon-strip-trash");
831
+ if (existing) existing.remove();
832
+
833
+ var trash = document.createElement("div");
834
+ trash.id = "icon-strip-trash";
835
+ trash.className = "icon-strip-trash";
836
+ trash.innerHTML = iconHtml("trash-2");
837
+ addBtn.parentNode.insertBefore(trash, addBtn.nextSibling);
838
+ refreshIcons();
839
+
840
+ trash.addEventListener("mouseenter", function () { _ctx.showIconTooltip(trash, "Remove project"); });
841
+ trash.addEventListener("mouseleave", _ctx.hideIconTooltip);
842
+
843
+ trash.addEventListener("dragover", function (e) {
844
+ e.preventDefault();
845
+ e.dataTransfer.dropEffect = "move";
846
+ trash.classList.add("drag-hover");
847
+ });
848
+ trash.addEventListener("dragleave", function () {
849
+ trash.classList.remove("drag-hover");
850
+ });
851
+ trash.addEventListener("drop", function (e) {
852
+ e.preventDefault();
853
+ trash.classList.remove("drag-hover");
854
+ var slug = e.dataTransfer.getData("text/plain");
855
+ if (slug && _ctx.ws && _ctx.connected) {
856
+ _ctx.ws.send(JSON.stringify({ type: "remove_project_check", slug: slug }));
857
+ }
858
+ });
859
+ }
860
+
861
+ function hideTrashZone() {
862
+ var trash = document.getElementById("icon-strip-trash");
863
+ if (trash) trash.remove();
864
+ var addBtn = document.getElementById("icon-strip-add");
865
+ if (addBtn) addBtn.style.display = "";
866
+ }
867
+
868
+ function clearDragIndicators() {
869
+ var items = document.querySelectorAll(".icon-strip-item.drag-over-above, .icon-strip-item.drag-over-below");
870
+ for (var i = 0; i < items.length; i++) {
871
+ items[i].classList.remove("drag-over-above", "drag-over-below");
872
+ }
873
+ }
874
+
875
+ function setupDragHandlers(el, slug) {
876
+ el.setAttribute("draggable", "true");
877
+
878
+ el.addEventListener("dragstart", function (e) {
879
+ draggedSlug = slug;
880
+ draggedEl = el;
881
+ e.dataTransfer.effectAllowed = "move";
882
+ e.dataTransfer.setData("text/plain", slug);
883
+
884
+ var ghost = document.createElement("div");
885
+ ghost.textContent = el.textContent.trim().split("\n")[0];
886
+ ghost.style.cssText = "position:fixed;left:-200px;top:-200px;width:38px;height:38px;border-radius:12px;" +
887
+ "background:var(--accent);color:#fff;display:flex;align-items:center;justify-content:center;" +
888
+ "font-size:15px;font-weight:600;pointer-events:none;z-index:-1;";
889
+ document.body.appendChild(ghost);
890
+ e.dataTransfer.setDragImage(ghost, 19, 19);
891
+ setTimeout(function () { ghost.remove(); }, 0);
892
+
893
+ setTimeout(function () { el.classList.add("dragging"); }, 0);
894
+ _ctx.hideIconTooltip();
895
+ showTrashZone();
896
+ });
897
+
898
+ el.addEventListener("dragover", function (e) {
899
+ e.preventDefault();
900
+ if (!draggedSlug || draggedSlug === slug) return;
901
+ e.dataTransfer.dropEffect = "move";
902
+
903
+ clearDragIndicators();
904
+ var rect = el.getBoundingClientRect();
905
+ var midY = rect.top + rect.height / 2;
906
+ if (e.clientY < midY) {
907
+ el.classList.add("drag-over-above");
908
+ } else {
909
+ el.classList.add("drag-over-below");
910
+ }
911
+ });
912
+
913
+ el.addEventListener("dragleave", function () {
914
+ el.classList.remove("drag-over-above", "drag-over-below");
915
+ });
916
+
917
+ el.addEventListener("drop", function (e) {
918
+ e.preventDefault();
919
+ clearDragIndicators();
920
+ if (!draggedSlug || draggedSlug === slug) return;
921
+
922
+ var rect = el.getBoundingClientRect();
923
+ var midY = rect.top + rect.height / 2;
924
+ var insertBefore = e.clientY < midY;
925
+
926
+ var container = document.getElementById("icon-strip-projects");
927
+ var items = container.querySelectorAll(".icon-strip-item");
928
+ var slugs = [];
929
+ for (var i = 0; i < items.length; i++) {
930
+ if (items[i].dataset.slug !== draggedSlug) {
931
+ slugs.push(items[i].dataset.slug);
932
+ }
933
+ }
934
+ var targetIdx = slugs.indexOf(slug);
935
+ if (!insertBefore) targetIdx++;
936
+ slugs.splice(targetIdx, 0, draggedSlug);
937
+
938
+ if (_ctx.ws && _ctx.connected) {
939
+ _ctx.ws.send(JSON.stringify({ type: "reorder_projects", slugs: slugs }));
940
+ }
941
+ });
942
+
943
+ el.addEventListener("dragend", function () {
944
+ el.classList.remove("dragging");
945
+ clearDragIndicators();
946
+ draggedSlug = null;
947
+ draggedEl = null;
948
+ hideTrashZone();
949
+ });
950
+ }
951
+
952
+ // --- Worktree folder collapse ---
953
+
954
+ function setWtCollapsed(slug, collapsed) {
955
+ wtCollapsed[slug] = collapsed;
956
+ try { localStorage.setItem("clay-wt-collapsed", JSON.stringify(wtCollapsed)); } catch (e) {}
957
+ }
958
+
959
+ function groupProjects(projects) {
960
+ var parents = [];
961
+ var wtByParent = {};
962
+ for (var i = 0; i < projects.length; i++) {
963
+ var p = projects[i];
964
+ if (p.isWorktree && p.parentSlug) {
965
+ if (!wtByParent[p.parentSlug]) wtByParent[p.parentSlug] = [];
966
+ wtByParent[p.parentSlug].push(p);
967
+ } else {
968
+ parents.push(p);
969
+ }
970
+ }
971
+ return { parents: parents, wtByParent: wtByParent };
972
+ }
973
+
974
+ // --- Icon item creation ---
975
+
976
+ function createIconItem(p, currentSlug) {
977
+ var currentDmUserId = _ctx.getCurrentDmUserId ? _ctx.getCurrentDmUserId() : null;
978
+ var el = document.createElement("a");
979
+ var isActive = p.slug === currentSlug && !currentDmUserId;
980
+ el.className = "icon-strip-item" + (isActive ? " active" : "");
981
+ el.href = "/p/" + p.slug + "/";
982
+ el.dataset.slug = p.slug;
983
+
984
+ if (p.icon) {
985
+ var emojiSpan = document.createElement("span");
986
+ emojiSpan.className = "project-emoji";
987
+ emojiSpan.textContent = p.icon;
988
+ parseEmojis(emojiSpan);
989
+ el.appendChild(emojiSpan);
990
+ } else {
991
+ el.appendChild(document.createTextNode(getProjectAbbrev(p.name)));
992
+ }
993
+
994
+ var pill = document.createElement("span");
995
+ pill.className = "icon-strip-pill";
996
+ el.appendChild(pill);
997
+
998
+ var statusDot = document.createElement("span");
999
+ statusDot.className = "icon-strip-status";
1000
+ if (p.isProcessing) statusDot.classList.add("processing");
1001
+ el.appendChild(statusDot);
1002
+
1003
+ var projectBadge = document.createElement("span");
1004
+ projectBadge.className = "icon-strip-project-badge";
1005
+ if (p.unread > 0 && !isActive) {
1006
+ projectBadge.textContent = p.unread > 99 ? "99+" : String(p.unread);
1007
+ projectBadge.classList.add("has-unread");
1008
+ }
1009
+ el.appendChild(projectBadge);
1010
+
1011
+ if (p.pendingPermissions > 0 && !isActive) {
1012
+ el.classList.add("has-pending-perm");
1013
+ }
1014
+
1015
+ (function (name, elem) {
1016
+ elem.addEventListener("mouseenter", function () { _ctx.showIconTooltip(elem, name); });
1017
+ elem.addEventListener("mouseleave", _ctx.hideIconTooltip);
1018
+ })(p.name, el);
1019
+
1020
+ (function (slug) {
1021
+ el.addEventListener("click", function (e) {
1022
+ e.preventDefault();
1023
+ if (_ctx.switchProject) _ctx.switchProject(slug);
1024
+ });
1025
+ })(p.slug);
1026
+
1027
+ return el;
1028
+ }
1029
+
1030
+ // --- Worktree creation modal ---
1031
+
1032
+ function showWorktreeModal(parentSlug, parentName) {
1033
+ var existing = document.getElementById("wt-modal-container");
1034
+ if (existing) existing.remove();
1035
+
1036
+ var container = document.createElement("div");
1037
+ container.id = "wt-modal-container";
1038
+
1039
+ var overlay = document.createElement("div");
1040
+ overlay.className = "wt-modal-overlay";
1041
+ container.appendChild(overlay);
1042
+
1043
+ var modal = document.createElement("div");
1044
+ modal.className = "wt-modal";
1045
+
1046
+ var title = document.createElement("div");
1047
+ title.className = "wt-modal-title";
1048
+ title.textContent = "Add Worktree \u2014 " + parentName;
1049
+ modal.appendChild(title);
1050
+
1051
+ var branchLabel = document.createElement("label");
1052
+ branchLabel.className = "wt-modal-label";
1053
+ branchLabel.textContent = "Branch name";
1054
+ modal.appendChild(branchLabel);
1055
+
1056
+ var branchInput = document.createElement("input");
1057
+ branchInput.type = "text";
1058
+ branchInput.className = "wt-modal-input";
1059
+ branchInput.placeholder = "feat/my-feature";
1060
+ branchInput.autocomplete = "off";
1061
+ branchInput.spellcheck = false;
1062
+ modal.appendChild(branchInput);
1063
+
1064
+ var baseLabel = document.createElement("label");
1065
+ baseLabel.className = "wt-modal-label";
1066
+ baseLabel.textContent = "Base branch";
1067
+ modal.appendChild(baseLabel);
1068
+
1069
+ var baseSelect = document.createElement("select");
1070
+ baseSelect.className = "wt-modal-input";
1071
+ var defaultOpt = document.createElement("option");
1072
+ defaultOpt.value = "main";
1073
+ defaultOpt.textContent = "main";
1074
+ baseSelect.appendChild(defaultOpt);
1075
+ modal.appendChild(baseSelect);
1076
+
1077
+ fetch("/p/" + parentSlug + "/api/branches")
1078
+ .then(function (res) { return res.json(); })
1079
+ .then(function (data) {
1080
+ baseSelect.innerHTML = "";
1081
+ var branches = data.branches || ["main"];
1082
+ var defBranch = data.defaultBranch || "main";
1083
+ for (var i = 0; i < branches.length; i++) {
1084
+ var opt = document.createElement("option");
1085
+ opt.value = branches[i];
1086
+ opt.textContent = branches[i];
1087
+ if (branches[i] === defBranch) opt.selected = true;
1088
+ baseSelect.appendChild(opt);
1089
+ }
1090
+ })
1091
+ .catch(function () {});
1092
+
1093
+ var errorDiv = document.createElement("div");
1094
+ errorDiv.className = "wt-modal-error";
1095
+ modal.appendChild(errorDiv);
1096
+
1097
+ var actions = document.createElement("div");
1098
+ actions.className = "wt-modal-actions";
1099
+
1100
+ var cancelBtn = document.createElement("button");
1101
+ cancelBtn.className = "wt-modal-btn";
1102
+ cancelBtn.textContent = "Cancel";
1103
+ actions.appendChild(cancelBtn);
1104
+
1105
+ var createBtn = document.createElement("button");
1106
+ createBtn.className = "wt-modal-btn primary";
1107
+ createBtn.textContent = "Create";
1108
+ actions.appendChild(createBtn);
1109
+
1110
+ modal.appendChild(actions);
1111
+ container.appendChild(modal);
1112
+ document.body.appendChild(container);
1113
+ branchInput.focus();
1114
+
1115
+ function closeModal() { container.remove(); }
1116
+
1117
+ function doCreate() {
1118
+ var branch = branchInput.value.trim();
1119
+ var base = baseSelect.value.trim() || null;
1120
+ if (!branch) {
1121
+ errorDiv.textContent = "Branch name is required";
1122
+ errorDiv.classList.add("visible");
1123
+ return;
1124
+ }
1125
+ var dirName = branch.replace(/\//g, "-");
1126
+ createBtn.disabled = true;
1127
+ createBtn.textContent = "Creating...";
1128
+ errorDiv.classList.remove("visible");
1129
+
1130
+ if (_ctx.ws && _ctx.connected) {
1131
+ _ctx.ws.send(JSON.stringify({
1132
+ type: "create_worktree",
1133
+ branch: branch,
1134
+ dirName: dirName,
1135
+ baseBranch: base
1136
+ }));
1137
+ }
1138
+
1139
+ var handler = function (event) {
1140
+ var msg;
1141
+ try { msg = JSON.parse(event.data); } catch (e) { return; }
1142
+ if (msg.type === "create_worktree_result") {
1143
+ _ctx.ws.removeEventListener("message", handler);
1144
+ if (msg.ok) {
1145
+ closeModal();
1146
+ if (msg.slug && _ctx.switchProject) _ctx.switchProject(msg.slug);
1147
+ } else {
1148
+ createBtn.disabled = false;
1149
+ createBtn.textContent = "Create";
1150
+ errorDiv.textContent = msg.error || "Failed to create worktree";
1151
+ errorDiv.classList.add("visible");
1152
+ }
1153
+ }
1154
+ };
1155
+ _ctx.ws.addEventListener("message", handler);
1156
+ }
1157
+
1158
+ overlay.addEventListener("click", closeModal);
1159
+ cancelBtn.addEventListener("click", closeModal);
1160
+ createBtn.addEventListener("click", doCreate);
1161
+ branchInput.addEventListener("keydown", function (e) {
1162
+ if (e.key === "Enter") doCreate();
1163
+ if (e.key === "Escape") closeModal();
1164
+ });
1165
+ baseSelect.addEventListener("keydown", function (e) {
1166
+ if (e.key === "Enter") doCreate();
1167
+ if (e.key === "Escape") closeModal();
1168
+ });
1169
+ }
1170
+
1171
+ // --- Render icon strip ---
1172
+
1173
+ export function renderIconStrip(projects, currentSlug) {
1174
+ cachedProjectList = projects;
1175
+ cachedCurrentSlug = currentSlug;
1176
+
1177
+ var container = document.getElementById("icon-strip-projects");
1178
+ if (!container) return;
1179
+ container.innerHTML = "";
1180
+
1181
+ var currentDmUserId = _ctx.getCurrentDmUserId ? _ctx.getCurrentDmUserId() : null;
1182
+ var grouped = groupProjects(projects);
1183
+
1184
+ for (var i = 0; i < grouped.parents.length; i++) {
1185
+ var p = grouped.parents[i];
1186
+ var worktrees = grouped.wtByParent[p.slug] || [];
1187
+ var hasWorktrees = worktrees.length > 0;
1188
+
1189
+ if (!hasWorktrees) {
1190
+ var el = createIconItem(p, currentSlug);
1191
+ (function (slug, name, elem) {
1192
+ elem.addEventListener("contextmenu", function (e) {
1193
+ e.preventDefault();
1194
+ e.stopPropagation();
1195
+ showIconCtxMenu(elem, slug, name);
1196
+ });
1197
+ })(p.slug, p.name || p.slug, el);
1198
+ setupDragHandlers(el, p.slug);
1199
+ container.appendChild(el);
1200
+ continue;
1201
+ }
1202
+
1203
+ // Folder group for parent + worktrees
1204
+ var folder = document.createElement("div");
1205
+ folder.className = "icon-strip-group";
1206
+ folder.dataset.parentSlug = p.slug;
1207
+ if (wtCollapsed[p.slug]) folder.classList.add("collapsed");
1208
+
1209
+ if (!p.isProcessing) {
1210
+ for (var wpi = 0; wpi < worktrees.length; wpi++) {
1211
+ if (worktrees[wpi].isProcessing) { p.isProcessing = true; break; }
1212
+ }
1213
+ }
1214
+
1215
+ var header = createIconItem(p, currentSlug);
1216
+ header.classList.add("folder-header");
1217
+ (function (slug, name, elem) {
1218
+ elem.addEventListener("contextmenu", function (e) {
1219
+ e.preventDefault();
1220
+ e.stopPropagation();
1221
+ showIconCtxMenu(elem, slug, name);
1222
+ });
1223
+ })(p.slug, p.name || p.slug, header);
1224
+ setupDragHandlers(header, p.slug);
1225
+
1226
+ var chevron = document.createElement("span");
1227
+ chevron.className = "icon-strip-group-chevron";
1228
+ chevron.innerHTML = '<i data-lucide="git-branch"></i>';
1229
+ (function (parentSlug, folderEl) {
1230
+ chevron.addEventListener("click", function (e) {
1231
+ e.preventDefault();
1232
+ e.stopPropagation();
1233
+ var nowCollapsed = folderEl.classList.toggle("collapsed");
1234
+ setWtCollapsed(parentSlug, nowCollapsed);
1235
+ });
1236
+ chevron.addEventListener("contextmenu", function (e) {
1237
+ e.preventDefault();
1238
+ e.stopPropagation();
1239
+ });
1240
+ })(p.slug, folder);
1241
+ chevron.setAttribute("data-tip", "Toggle worktrees");
1242
+ header.appendChild(chevron);
1243
+ folder.appendChild(header);
1244
+
1245
+ var itemsContainer = document.createElement("div");
1246
+ itemsContainer.className = "icon-strip-group-items";
1247
+
1248
+ for (var wi = 0; wi < worktrees.length; wi++) {
1249
+ (function (wt) {
1250
+ var wtEl = document.createElement("a");
1251
+ var isWtActive = wt.slug === currentSlug && !currentDmUserId;
1252
+ var isAccessible = wt.worktreeAccessible !== false;
1253
+ wtEl.className = "icon-strip-wt-item" + (isWtActive ? " active" : "") + (!isAccessible ? " wt-disabled" : "");
1254
+ wtEl.href = "/p/" + wt.slug + "/";
1255
+ wtEl.dataset.slug = wt.slug;
1256
+
1257
+ var abbrev = document.createElement("span");
1258
+ abbrev.className = "wt-branch-abbrev";
1259
+ abbrev.textContent = getProjectAbbrev(wt.name);
1260
+ wtEl.appendChild(abbrev);
1261
+
1262
+ var wtStatus = document.createElement("span");
1263
+ wtStatus.className = "icon-strip-status";
1264
+ if (wt.isProcessing) wtStatus.classList.add("processing");
1265
+ wtEl.appendChild(wtStatus);
1266
+
1267
+ var tooltipText = wt.name;
1268
+ if (!isAccessible) {
1269
+ tooltipText += " (outside project path, cannot be accessed)";
1270
+ }
1271
+ (function (text, elem) {
1272
+ elem.addEventListener("mouseenter", function () { _ctx.showIconTooltip(elem, text); });
1273
+ elem.addEventListener("mouseleave", _ctx.hideIconTooltip);
1274
+ })(tooltipText, wtEl);
1275
+
1276
+ if (isAccessible) {
1277
+ (function (slug) {
1278
+ wtEl.addEventListener("click", function (e) {
1279
+ e.preventDefault();
1280
+ if (_ctx.switchProject) _ctx.switchProject(slug);
1281
+ });
1282
+ })(wt.slug);
1283
+ } else {
1284
+ wtEl.addEventListener("click", function (e) {
1285
+ e.preventDefault();
1286
+ });
1287
+ }
1288
+
1289
+ if (isAccessible) {
1290
+ (function (slug, name, elem) {
1291
+ elem.addEventListener("contextmenu", function (e) {
1292
+ e.preventDefault();
1293
+ e.stopPropagation();
1294
+ showIconCtxMenu(elem, slug, name);
1295
+ });
1296
+ })(wt.slug, wt.name, wtEl);
1297
+ } else {
1298
+ wtEl.addEventListener("contextmenu", function (e) {
1299
+ e.preventDefault();
1300
+ e.stopPropagation();
1301
+ });
1302
+ }
1303
+
1304
+ if (wt.pendingPermissions > 0 && !isWtActive) {
1305
+ wtEl.classList.add("has-pending-perm");
1306
+ }
1307
+
1308
+ itemsContainer.appendChild(wtEl);
1309
+ })(worktrees[wi]);
1310
+ }
1311
+
1312
+ var hasWtPendingPerm = false;
1313
+ for (var wpi2 = 0; wpi2 < worktrees.length; wpi2++) {
1314
+ if (worktrees[wpi2].pendingPermissions > 0) { hasWtPendingPerm = true; break; }
1315
+ }
1316
+ if (hasWtPendingPerm) folder.classList.remove("collapsed");
1317
+
1318
+ var addBtn = document.createElement("button");
1319
+ addBtn.className = "icon-strip-group-add";
1320
+ addBtn.textContent = "+";
1321
+ (function (parentSlug, parentName, btn) {
1322
+ btn.addEventListener("click", function (e) {
1323
+ e.preventDefault();
1324
+ e.stopPropagation();
1325
+ showWorktreeModal(parentSlug, parentName);
1326
+ });
1327
+ btn.addEventListener("mouseenter", function () { _ctx.showIconTooltip(btn, "New worktree"); });
1328
+ btn.addEventListener("mouseleave", _ctx.hideIconTooltip);
1329
+ })(p.slug, p.name, addBtn);
1330
+ itemsContainer.appendChild(addBtn);
1331
+
1332
+ folder.appendChild(itemsContainer);
1333
+ container.appendChild(folder);
1334
+ }
1335
+
1336
+ // Update home icon active state
1337
+ var homeIcon = document.querySelector(".icon-strip-home");
1338
+ if (homeIcon) {
1339
+ if ((!currentSlug || projects.length === 0) && !currentDmUserId) {
1340
+ homeIcon.classList.add("active");
1341
+ } else {
1342
+ homeIcon.classList.remove("active");
1343
+ }
1344
+ }
1345
+
1346
+ renderProjectList(projects, currentSlug);
1347
+
1348
+ try { lucide.createIcons({ nodes: [container] }); } catch (e) {}
1349
+ }
1350
+
1351
+ function renderProjectList(projects, currentSlug) {
1352
+ var list = document.getElementById("project-list");
1353
+ if (!list) return;
1354
+ list.innerHTML = "";
1355
+
1356
+ var grouped = groupProjects(projects);
1357
+
1358
+ for (var i = 0; i < grouped.parents.length; i++) {
1359
+ var p = grouped.parents[i];
1360
+ var worktrees = grouped.wtByParent[p.slug] || [];
1361
+
1362
+ if (worktrees.length === 0) {
1363
+ list.appendChild(createMobileProjectItem(p, currentSlug, false));
1364
+ continue;
1365
+ }
1366
+
1367
+ var folderDiv = document.createElement("div");
1368
+ folderDiv.className = "mobile-project-folder";
1369
+ if (wtCollapsed[p.slug]) folderDiv.classList.add("collapsed");
1370
+
1371
+ var headerEl = createMobileProjectItem(p, currentSlug, false);
1372
+ var chevron = document.createElement("span");
1373
+ chevron.className = "mobile-folder-chevron";
1374
+ chevron.innerHTML = "&#9660;";
1375
+ (function (parentSlug, fDiv) {
1376
+ chevron.addEventListener("click", function (e) {
1377
+ e.preventDefault();
1378
+ e.stopPropagation();
1379
+ var nowCollapsed = fDiv.classList.toggle("collapsed");
1380
+ setWtCollapsed(parentSlug, nowCollapsed);
1381
+ });
1382
+ })(p.slug, folderDiv);
1383
+ headerEl.appendChild(chevron);
1384
+ folderDiv.appendChild(headerEl);
1385
+
1386
+ var wtList = document.createElement("div");
1387
+ wtList.className = "mobile-folder-items";
1388
+ for (var wi = 0; wi < worktrees.length; wi++) {
1389
+ var isAccessible = worktrees[wi].worktreeAccessible !== false;
1390
+ var wtItem = createMobileProjectItem(worktrees[wi], currentSlug, true);
1391
+ if (!isAccessible) wtItem.classList.add("wt-disabled");
1392
+ if (!isAccessible) {
1393
+ wtItem.addEventListener("click", function (e) { e.preventDefault(); e.stopPropagation(); });
1394
+ }
1395
+ wtList.appendChild(wtItem);
1396
+ }
1397
+ folderDiv.appendChild(wtList);
1398
+ list.appendChild(folderDiv);
1399
+ }
1400
+ }
1401
+
1402
+ function createMobileProjectItem(p, currentSlug, isWorktree) {
1403
+ var el = document.createElement("button");
1404
+ el.className = "mobile-project-item" + (p.slug === currentSlug ? " active" : "") + (isWorktree ? " wt-item" : "");
1405
+
1406
+ var abbrev = document.createElement("span");
1407
+ abbrev.className = "mobile-project-abbrev";
1408
+ if (p.icon) {
1409
+ abbrev.textContent = p.icon;
1410
+ parseEmojis(abbrev);
1411
+ } else {
1412
+ abbrev.textContent = getProjectAbbrev(p.name);
1413
+ }
1414
+ el.appendChild(abbrev);
1415
+
1416
+ var name = document.createElement("span");
1417
+ name.className = "mobile-project-name";
1418
+ name.textContent = p.name;
1419
+ el.appendChild(name);
1420
+
1421
+ if (p.isProcessing) {
1422
+ var dot = document.createElement("span");
1423
+ dot.className = "mobile-project-processing";
1424
+ el.appendChild(dot);
1425
+ }
1426
+
1427
+ el.addEventListener("click", function () {
1428
+ if (_ctx.switchProject) _ctx.switchProject(p.slug);
1429
+ if (_ctx.closeSidebar) _ctx.closeSidebar();
1430
+ });
1431
+
1432
+ return el;
1433
+ }
1434
+
1435
+ export function getEmojiCategories() { return EMOJI_CATEGORIES; }
1436
+
1437
+ export function updateProjectBadge(slug, count) {
1438
+ var icon = document.querySelector('.icon-strip-item[data-slug="' + slug + '"]');
1439
+ if (!icon) return;
1440
+ var badge = icon.querySelector(".icon-strip-project-badge");
1441
+ if (!badge) return;
1442
+ if (count > 0) {
1443
+ badge.textContent = count > 99 ? "99+" : String(count);
1444
+ badge.classList.add("has-unread");
1445
+ } else {
1446
+ badge.textContent = "";
1447
+ badge.classList.remove("has-unread");
1448
+ }
1449
+ }