react-os-shell 2.7.0 → 2.8.0

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 (33) hide show
  1. package/dist/{Browser-YEOBTPST.js → Browser-LVWMQSR3.js} +4 -4
  2. package/dist/{Browser-YEOBTPST.js.map → Browser-LVWMQSR3.js.map} +1 -1
  3. package/dist/{Documents-D7UN7W6P.js → Documents-AEZKXAW3.js} +3 -3
  4. package/dist/{Documents-D7UN7W6P.js.map → Documents-AEZKXAW3.js.map} +1 -1
  5. package/dist/{Files-VXHZY7NY.js → Files-3WHYRZI6.js} +7 -7
  6. package/dist/{Files-VXHZY7NY.js.map → Files-3WHYRZI6.js.map} +1 -1
  7. package/dist/{Notepad-THWCG35G.js → Notepad-R2OY27CY.js} +3 -3
  8. package/dist/{Notepad-THWCG35G.js.map → Notepad-R2OY27CY.js.map} +1 -1
  9. package/dist/Preview-F75CICNY.js +9 -0
  10. package/dist/{Preview-5SOLJFFK.js.map → Preview-F75CICNY.js.map} +1 -1
  11. package/dist/{Sidebar-BW7SYNBA.js → Sidebar-PY762ANK.js} +3 -3
  12. package/dist/Sidebar-PY762ANK.js.map +1 -0
  13. package/dist/{Spreadsheet-UVBEPLQB.js → Spreadsheet-P4MBJWSH.js} +4 -4
  14. package/dist/{Spreadsheet-UVBEPLQB.js.map → Spreadsheet-P4MBJWSH.js.map} +1 -1
  15. package/dist/apps/index.js +12 -12
  16. package/dist/{chunk-UATWDGLV.js → chunk-4YBNDCJV.js} +3 -3
  17. package/dist/{chunk-UATWDGLV.js.map → chunk-4YBNDCJV.js.map} +1 -1
  18. package/dist/{chunk-YZEQWMO5.js → chunk-BLYEAKGC.js} +4 -4
  19. package/dist/{chunk-YZEQWMO5.js.map → chunk-BLYEAKGC.js.map} +1 -1
  20. package/dist/{chunk-AAKIF7SW.js → chunk-KQBZLA6K.js} +3 -3
  21. package/dist/{chunk-AAKIF7SW.js.map → chunk-KQBZLA6K.js.map} +1 -1
  22. package/dist/{chunk-FX77XLQZ.js → chunk-SAKVRVNB.js} +4 -4
  23. package/dist/{chunk-FX77XLQZ.js.map → chunk-SAKVRVNB.js.map} +1 -1
  24. package/dist/{chunk-MJIMKMSJ.js → chunk-XGWARUR7.js} +3 -3
  25. package/dist/{chunk-MJIMKMSJ.js.map → chunk-XGWARUR7.js.map} +1 -1
  26. package/dist/{chunk-LD2JBHD3.js → chunk-ZW2JB5CK.js} +3 -3
  27. package/dist/{chunk-LD2JBHD3.js.map → chunk-ZW2JB5CK.js.map} +1 -1
  28. package/dist/index.js +7 -7
  29. package/dist/styles.css +187 -2
  30. package/dist/themes.css +244 -0
  31. package/package.json +4 -3
  32. package/dist/Preview-5SOLJFFK.js +0 -9
  33. package/dist/Sidebar-BW7SYNBA.js.map +0 -1
@@ -0,0 +1,244 @@
1
+ /**
2
+ * react-os-shell theme variants — accent + surface-tint remaps for the
3
+ * pink / green / grey / blue themes and the user-picked custom accent.
4
+ *
5
+ * useTheme() stamps `data-theme="<name>"` on <html> and, when the user
6
+ * picks a custom accent color, `data-custom-accent` plus the --accent-*
7
+ * shade scale. This file turns those attributes into looks by remapping
8
+ * the blue accent utilities (bg-blue-600 buttons, text-blue-700 links,
9
+ * focus rings, checkbox accents) and tinting the neutral gray surfaces.
10
+ *
11
+ * styles.css imports this file, so plain `import 'react-os-shell/styles.css'`
12
+ * already includes it. It is exported standalone ("react-os-shell/themes.css")
13
+ * only for consumers that build their CSS granularly.
14
+ *
15
+ * Dark-theme remaps are NOT here — they live in styles.css, because dark
16
+ * is a readability baseline rather than an accent variant.
17
+ *
18
+ * Upstreamed 2026-06-13 from the admin portal's index.css so all three
19
+ * EFFICIENT portals + the demo share one source of truth.
20
+ */
21
+
22
+ /* ═══════════════════════════════════════════════════
23
+ Theme: Pink
24
+ Swaps the blue accent to pink/rose throughout
25
+ ═══════════════════════════════════════════════════ */
26
+
27
+ /* Accent backgrounds */
28
+ [data-theme="pink"] .bg-blue-600 { background-color: #db2777 !important; }
29
+ [data-theme="pink"] .bg-blue-700 { background-color: #be185d !important; }
30
+ [data-theme="pink"] .bg-blue-500 { background-color: #ec4899 !important; }
31
+ [data-theme="pink"] .bg-blue-100 { background-color: #fce7f3 !important; }
32
+ [data-theme="pink"] .bg-blue-50 { background-color: #fdf2f8 !important; }
33
+
34
+ /* Accent text */
35
+ [data-theme="pink"] .text-blue-600 { color: #db2777 !important; }
36
+ [data-theme="pink"] .text-blue-700 { color: #be185d !important; }
37
+ [data-theme="pink"] .text-blue-800 { color: #9d174d !important; }
38
+ [data-theme="pink"] .text-blue-500 { color: #ec4899 !important; }
39
+
40
+ /* Accent borders */
41
+ [data-theme="pink"] .border-blue-600 { border-color: #db2777 !important; }
42
+ [data-theme="pink"] .border-blue-500 { border-color: #ec4899 !important; }
43
+ [data-theme="pink"] .border-blue-400 { border-color: #f472b6 !important; }
44
+ [data-theme="pink"] .border-blue-300 { border-color: #f9a8d4 !important; }
45
+ [data-theme="pink"] .border-blue-200 { border-color: #fbcfe8 !important; }
46
+
47
+ /* Accent hover */
48
+ [data-theme="pink"] .hover\:bg-blue-700:hover { background-color: #be185d !important; }
49
+ [data-theme="pink"] .hover\:bg-blue-100:hover { background-color: #fce7f3 !important; }
50
+ [data-theme="pink"] .hover\:bg-blue-50:hover { background-color: #fdf2f8 !important; }
51
+ [data-theme="pink"] .hover\:text-blue-800:hover { color: #9d174d !important; }
52
+ [data-theme="pink"] .hover\:border-blue-300:hover { border-color: #f9a8d4 !important; }
53
+
54
+ /* Focus rings */
55
+ [data-theme="pink"] .focus\:border-blue-500:focus { border-color: #ec4899 !important; }
56
+ [data-theme="pink"] .focus\:ring-blue-500:focus { --tw-ring-color: #ec4899 !important; }
57
+
58
+ /* Checkbox accent */
59
+ [data-theme="pink"] input[type="checkbox"].text-blue-600 { accent-color: #db2777; }
60
+ [data-theme="pink"] input[type="range"].accent-blue-600 { accent-color: #db2777; }
61
+
62
+ /* Ring colors */
63
+ [data-theme="pink"] .ring-blue-300 { --tw-ring-color: #f9a8d4 !important; }
64
+
65
+ /* Pink tint on backgrounds */
66
+ [data-theme="pink"] .bg-white { background-color: #fff5f9 !important; }
67
+ [data-theme="pink"] .bg-gray-100 { background-color: #fce7f3 !important; }
68
+ [data-theme="pink"] .bg-gray-50 { background-color: #fdf2f8 !important; }
69
+ [data-theme="pink"] .bg-gray-200 { background-color: #fbcfe8 !important; }
70
+
71
+ /* Pink tint on borders — kept light to distinguish from accent */
72
+ [data-theme="pink"] .border-gray-200 { border-color: #fce7f3 !important; }
73
+ [data-theme="pink"] .border-gray-300 { border-color: #fbcfe8 !important; }
74
+ [data-theme="pink"] .border-gray-100 { border-color: #fdf2f8 !important; }
75
+ [data-theme="pink"] .divide-gray-200 > :not(:last-child) { border-color: #fce7f3 !important; }
76
+ [data-theme="pink"] .divide-gray-100 > :not(:last-child) { border-color: #fdf2f8 !important; }
77
+
78
+ /* Pink hover states */
79
+ [data-theme="pink"] .hover\:bg-gray-50:hover { background-color: #fdf2f8 !important; }
80
+ [data-theme="pink"] .hover\:bg-gray-100:hover { background-color: #fce7f3 !important; }
81
+ [data-theme="pink"] .hover\:bg-gray-200:hover { background-color: #fbcfe8 !important; }
82
+
83
+
84
+ /* ═══════════════════════════════════════════════════
85
+ Theme: Green
86
+ Swaps the blue accent to green/emerald throughout
87
+ ═══════════════════════════════════════════════════ */
88
+
89
+ /* Accent backgrounds */
90
+ [data-theme="green"] .bg-blue-600 { background-color: #059669 !important; }
91
+ [data-theme="green"] .bg-blue-700 { background-color: #047857 !important; }
92
+ [data-theme="green"] .bg-blue-500 { background-color: #10b981 !important; }
93
+ [data-theme="green"] .bg-blue-100 { background-color: #d1fae5 !important; }
94
+ [data-theme="green"] .bg-blue-50 { background-color: #ecfdf5 !important; }
95
+
96
+ /* Accent text */
97
+ [data-theme="green"] .text-blue-600 { color: #059669 !important; }
98
+ [data-theme="green"] .text-blue-700 { color: #047857 !important; }
99
+ [data-theme="green"] .text-blue-800 { color: #065f46 !important; }
100
+ [data-theme="green"] .text-blue-500 { color: #10b981 !important; }
101
+
102
+ /* Accent borders */
103
+ [data-theme="green"] .border-blue-600 { border-color: #059669 !important; }
104
+ [data-theme="green"] .border-blue-500 { border-color: #10b981 !important; }
105
+ [data-theme="green"] .border-blue-400 { border-color: #34d399 !important; }
106
+ [data-theme="green"] .border-blue-300 { border-color: #6ee7b7 !important; }
107
+ [data-theme="green"] .border-blue-200 { border-color: #a7f3d0 !important; }
108
+
109
+ /* Accent hover */
110
+ [data-theme="green"] .hover\:bg-blue-700:hover { background-color: #047857 !important; }
111
+ [data-theme="green"] .hover\:bg-blue-100:hover { background-color: #d1fae5 !important; }
112
+ [data-theme="green"] .hover\:bg-blue-50:hover { background-color: #ecfdf5 !important; }
113
+ [data-theme="green"] .hover\:text-blue-800:hover { color: #065f46 !important; }
114
+ [data-theme="green"] .hover\:border-blue-300:hover { border-color: #6ee7b7 !important; }
115
+
116
+ /* Focus rings */
117
+ [data-theme="green"] .focus\:border-blue-500:focus { border-color: #10b981 !important; }
118
+ [data-theme="green"] .focus\:ring-blue-500:focus { --tw-ring-color: #10b981 !important; }
119
+
120
+ /* Checkbox accent */
121
+ [data-theme="green"] input[type="checkbox"].text-blue-600 { accent-color: #059669; }
122
+ [data-theme="green"] input[type="range"].accent-blue-600 { accent-color: #059669; }
123
+
124
+ /* Ring colors */
125
+ [data-theme="green"] .ring-blue-300 { --tw-ring-color: #6ee7b7 !important; }
126
+
127
+ /* Green tint on backgrounds */
128
+ [data-theme="green"] .bg-white { background-color: #f5fef7 !important; }
129
+ [data-theme="green"] .bg-gray-100 { background-color: #dcfce7 !important; }
130
+ [data-theme="green"] .bg-gray-50 { background-color: #ecfdf5 !important; }
131
+ [data-theme="green"] .bg-gray-200 { background-color: #bbf7d0 !important; }
132
+
133
+ /* Green tint on borders — kept light to distinguish from accent */
134
+ [data-theme="green"] .border-gray-200 { border-color: #dcfce7 !important; }
135
+ [data-theme="green"] .border-gray-300 { border-color: #bbf7d0 !important; }
136
+ [data-theme="green"] .border-gray-100 { border-color: #ecfdf5 !important; }
137
+ [data-theme="green"] .divide-gray-200 > :not(:last-child) { border-color: #dcfce7 !important; }
138
+ [data-theme="green"] .divide-gray-100 > :not(:last-child) { border-color: #ecfdf5 !important; }
139
+
140
+ /* Green hover states */
141
+ [data-theme="green"] .hover\:bg-gray-50:hover { background-color: #ecfdf5 !important; }
142
+ [data-theme="green"] .hover\:bg-gray-100:hover { background-color: #dcfce7 !important; }
143
+ [data-theme="green"] .hover\:bg-gray-200:hover { background-color: #bbf7d0 !important; }
144
+
145
+
146
+ /* ═══════════════════════════════════════════════════
147
+ Theme: Grey
148
+ A darker, more contrasty neutral theme
149
+ ═══════════════════════════════════════════════════ */
150
+
151
+ /* Grey tint on backgrounds */
152
+ [data-theme="grey"] .bg-white { background-color: #f3f4f6 !important; }
153
+ [data-theme="grey"] .bg-gray-100 { background-color: #e5e7eb !important; }
154
+ [data-theme="grey"] .bg-gray-50 { background-color: #f3f4f6 !important; }
155
+ [data-theme="grey"] .bg-gray-200 { background-color: #d1d5db !important; }
156
+
157
+ /* Grey tint on borders */
158
+ [data-theme="grey"] .border-gray-200 { border-color: #d1d5db !important; }
159
+ [data-theme="grey"] .border-gray-300 { border-color: #9ca3af !important; }
160
+ [data-theme="grey"] .border-gray-100 { border-color: #e5e7eb !important; }
161
+ [data-theme="grey"] .divide-gray-200 > :not(:last-child) { border-color: #d1d5db !important; }
162
+ [data-theme="grey"] .divide-gray-100 > :not(:last-child) { border-color: #e5e7eb !important; }
163
+
164
+ /* Grey hover states */
165
+ [data-theme="grey"] .hover\:bg-gray-50:hover { background-color: #e5e7eb !important; }
166
+ [data-theme="grey"] .hover\:bg-gray-100:hover { background-color: #d1d5db !important; }
167
+ [data-theme="grey"] .hover\:bg-gray-200:hover { background-color: #9ca3af !important; }
168
+
169
+ /* Grey accent — dark gray buttons */
170
+ [data-theme="grey"] .bg-blue-600 { background-color: #374151 !important; }
171
+ [data-theme="grey"] .bg-blue-700 { background-color: #1f2937 !important; }
172
+ [data-theme="grey"] .bg-blue-500 { background-color: #4b5563 !important; }
173
+ [data-theme="grey"] .bg-blue-100 { background-color: #e5e7eb !important; }
174
+ [data-theme="grey"] .bg-blue-50 { background-color: #f3f4f6 !important; }
175
+ [data-theme="grey"] .text-blue-600 { color: #374151 !important; }
176
+ [data-theme="grey"] .text-blue-700 { color: #1f2937 !important; }
177
+ [data-theme="grey"] .text-blue-800 { color: #111827 !important; }
178
+ [data-theme="grey"] .text-blue-500 { color: #4b5563 !important; }
179
+ [data-theme="grey"] .border-blue-600 { border-color: #374151 !important; }
180
+ [data-theme="grey"] .border-blue-500 { border-color: #4b5563 !important; }
181
+ [data-theme="grey"] .border-blue-400 { border-color: #6b7280 !important; }
182
+ [data-theme="grey"] .border-blue-300 { border-color: #9ca3af !important; }
183
+ [data-theme="grey"] .border-blue-200 { border-color: #d1d5db !important; }
184
+ [data-theme="grey"] .hover\:bg-blue-700:hover { background-color: #1f2937 !important; }
185
+ [data-theme="grey"] .hover\:bg-blue-100:hover { background-color: #e5e7eb !important; }
186
+ [data-theme="grey"] .hover\:bg-blue-50:hover { background-color: #f3f4f6 !important; }
187
+ [data-theme="grey"] .focus\:border-blue-500:focus { border-color: #4b5563 !important; }
188
+ [data-theme="grey"] .focus\:ring-blue-500:focus { --tw-ring-color: #4b5563 !important; }
189
+ [data-theme="grey"] input[type="checkbox"].text-blue-600 { accent-color: #374151; }
190
+ [data-theme="grey"] input[type="range"].accent-blue-600 { accent-color: #374151; }
191
+ [data-theme="grey"] .ring-blue-300 { --tw-ring-color: #9ca3af !important; }
192
+
193
+
194
+ /* ═══════════════════════════════════════════════════
195
+ Theme: Blue
196
+ Swaps the blue accent to a deeper blue, tints UI blue
197
+ ═══════════════════════════════════════════════════ */
198
+
199
+ /* Blue tint on backgrounds */
200
+ [data-theme="blue"] .bg-white { background-color: #f0f6ff !important; }
201
+ [data-theme="blue"] .bg-gray-100 { background-color: #dbeafe !important; }
202
+ [data-theme="blue"] .bg-gray-50 { background-color: #eff6ff !important; }
203
+ [data-theme="blue"] .bg-gray-200 { background-color: #bfdbfe !important; }
204
+
205
+ /* Blue tint on borders — kept light to distinguish from accent */
206
+ [data-theme="blue"] .border-gray-200 { border-color: #dbeafe !important; }
207
+ [data-theme="blue"] .border-gray-300 { border-color: #bfdbfe !important; }
208
+ [data-theme="blue"] .border-gray-100 { border-color: #eff6ff !important; }
209
+ [data-theme="blue"] .divide-gray-200 > :not(:last-child) { border-color: #dbeafe !important; }
210
+ [data-theme="blue"] .divide-gray-100 > :not(:last-child) { border-color: #eff6ff !important; }
211
+
212
+ /* Blue hover states */
213
+ [data-theme="blue"] .hover\:bg-gray-50:hover { background-color: #eff6ff !important; }
214
+ [data-theme="blue"] .hover\:bg-gray-100:hover { background-color: #dbeafe !important; }
215
+ [data-theme="blue"] .hover\:bg-gray-200:hover { background-color: #bfdbfe !important; }
216
+
217
+
218
+ /* ═══════════════════════════════════════════════════
219
+ Custom Accent Color
220
+ Overrides the blue accent when user picks a custom color.
221
+ useTheme() sets data-custom-accent + the --accent-* scale.
222
+ ═══════════════════════════════════════════════════ */
223
+ [data-custom-accent] .bg-blue-600 { background-color: var(--accent-600) !important; }
224
+ [data-custom-accent] .bg-blue-700 { background-color: var(--accent-700) !important; }
225
+ [data-custom-accent] .bg-blue-500 { background-color: var(--accent-500) !important; }
226
+ [data-custom-accent] .bg-blue-100 { background-color: var(--accent-100) !important; }
227
+ [data-custom-accent] .bg-blue-50 { background-color: var(--accent-50) !important; }
228
+ [data-custom-accent] .text-blue-600 { color: var(--accent-600) !important; }
229
+ [data-custom-accent] .text-blue-700 { color: var(--accent-700) !important; }
230
+ [data-custom-accent] .text-blue-800 { color: var(--accent-700) !important; }
231
+ [data-custom-accent] .text-blue-500 { color: var(--accent-500) !important; }
232
+ [data-custom-accent] .border-blue-600 { border-color: var(--accent-600) !important; }
233
+ [data-custom-accent] .border-blue-500 { border-color: var(--accent-500) !important; }
234
+ [data-custom-accent] .border-blue-400 { border-color: var(--accent-400) !important; }
235
+ [data-custom-accent] .border-blue-300 { border-color: var(--accent-300) !important; }
236
+ [data-custom-accent] .border-blue-200 { border-color: var(--accent-200) !important; }
237
+ [data-custom-accent] .hover\:bg-blue-700:hover { background-color: var(--accent-700) !important; }
238
+ [data-custom-accent] .hover\:bg-blue-100:hover { background-color: var(--accent-100) !important; }
239
+ [data-custom-accent] .hover\:bg-blue-50:hover { background-color: var(--accent-50) !important; }
240
+ [data-custom-accent] .focus\:border-blue-500:focus { border-color: var(--accent-500) !important; }
241
+ [data-custom-accent] .focus\:ring-blue-500:focus { --tw-ring-color: var(--accent-500) !important; }
242
+ [data-custom-accent] input[type="checkbox"].text-blue-600 { accent-color: var(--accent-600); }
243
+ [data-custom-accent] input[type="range"].accent-blue-600 { accent-color: var(--accent-600); }
244
+ [data-custom-accent] .ring-blue-300 { --tw-ring-color: var(--accent-300) !important; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-os-shell",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "Desktop-style React UI shell — windows, taskbar, start menu, sticky notes, frosted glass theming, and bundled apps.",
5
5
  "license": "MIT",
6
6
  "author": "Victor Y. Mau",
@@ -28,7 +28,8 @@
28
28
  "types": "./dist/apps/index.d.ts",
29
29
  "import": "./dist/apps/index.js"
30
30
  },
31
- "./styles.css": "./dist/styles.css"
31
+ "./styles.css": "./dist/styles.css",
32
+ "./themes.css": "./dist/themes.css"
32
33
  },
33
34
  "files": [
34
35
  "dist"
@@ -65,7 +66,7 @@
65
66
  "xlsx": "^0.18.5"
66
67
  },
67
68
  "scripts": {
68
- "build": "tsup && cp src/styles.css dist/styles.css",
69
+ "build": "tsup && cp src/styles.css src/themes.css dist/",
69
70
  "dev": "tsup --watch",
70
71
  "typecheck": "tsc --noEmit",
71
72
  "screenshot": "node scripts/screenshot.mjs",
@@ -1,9 +0,0 @@
1
- export { Preview as default, setPdfPreview } from './chunk-UATWDGLV.js';
2
- import './chunk-KUIPWCTJ.js';
3
- import './chunk-WIJ45SYD.js';
4
- import './chunk-MJIMKMSJ.js';
5
- import './chunk-JNF5VRPB.js';
6
- import './chunk-UBN4IUDE.js';
7
- import './chunk-ZF6AYO4G.js';
8
- //# sourceMappingURL=Preview-5SOLJFFK.js.map
9
- //# sourceMappingURL=Preview-5SOLJFFK.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/shell/Sidebar.tsx"],"names":["navSections","navIcons","sectionIcons"],"mappings":"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","file":"Sidebar-BW7SYNBA.js","sourcesContent":["/**\n * Sidebar — persistent left strip used when `prefs.layout_mode === 'sidebar'`.\n *\n * Same configuration surface as <StartMenu> (navSections, navIcons,\n * sectionIcons, categories) but rendered inline:\n * - No flyouts. Sections expand/collapse accordion-style below their\n * header, indented one step.\n * - No taskbar-anchored positioning — fixed full-height left strip,\n * width pulled from `--sidebar-width`.\n * - Right edge `rounded-r-2xl` so it matches windowed cards on the\n * right (which use `rounded-2xl`).\n *\n * Designed for small-screen layouts where flyouts would clip and where\n * keeping the menu always-visible saves a tap to switch apps.\n */\n\nimport { useEffect, useMemo, useRef, useState, isValidElement, cloneElement, type ReactElement, type ReactNode } from 'react';\nimport {\n navSections as defaultNavSections,\n navIcons as defaultNavIcons,\n sectionIcons as defaultSectionIcons,\n startMenuCategories as defaultCategories,\n isSection,\n type NavSection,\n type NavItem,\n type StartMenuCategories,\n type VirtualSection,\n} from '../shell-config/nav';\nimport { useAuth } from '../contexts/AuthContext';\nimport { glassStyle, GLASS_INPUT_BG } from '../utils/glass';\n\ninterface SidebarProps {\n width: number;\n openPage: (path: string) => void;\n profile: any;\n user: any;\n onLogout: () => void;\n onNavigate: (path: string) => void;\n navSections?: (NavSection | NavItem)[];\n navIcons?: Record<string, ReactNode>;\n sectionIcons?: Record<string, ReactNode>;\n categories?: StartMenuCategories;\n productName?: string;\n productIcon?: string;\n}\n\nexport default function Sidebar({\n width,\n openPage,\n profile,\n user,\n onLogout,\n onNavigate,\n navSections = defaultNavSections,\n navIcons = defaultNavIcons,\n sectionIcons = defaultSectionIcons,\n categories = defaultCategories,\n productName,\n productIcon,\n}: SidebarProps) {\n const { hasAnyPerm } = useAuth();\n const erpLabels = new Set(categories.erp);\n const systemLabels = new Set(categories.system);\n const footerLabels = new Set(categories.footer ?? []);\n // Flat rows pinned to the footer (next to the profile) — rendered inline,\n // not as an accordion section. Mirrors StartMenu's `footerItems`.\n const footerItems = (categories.footerItems ?? []).filter(it => !it.perms || hasAnyPerm(it.perms));\n const virtualSections = categories.virtual ?? [];\n\n const [search, setSearch] = useState('');\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n const searchRef = useRef<HTMLInputElement>(null);\n\n const toggleExpanded = (label: string) => {\n setExpanded(prev => {\n const next = new Set(prev);\n if (next.has(label)) next.delete(label);\n else next.add(label);\n return next;\n });\n };\n\n // Top-level items vs sections, mirroring StartMenu's split.\n const topItems = navSections.filter(item => !isSection(item)) as NavItem[];\n const erpSections = navSections.filter(item => isSection(item) && erpLabels.has((item as NavSection).label)) as NavSection[];\n const systemSections = navSections.filter(item => isSection(item) && systemLabels.has((item as NavSection).label)) as NavSection[];\n const footerSections = navSections.filter(item => isSection(item) && footerLabels.has((item as NavSection).label)) as NavSection[];\n\n const getVisibleItems = (section: { items: NavItem[]; perms?: string[] }) => {\n if (section.perms && !hasAnyPerm(section.perms)) return [];\n return section.items.filter(it => !it.perms || hasAnyPerm(it.perms));\n };\n\n // Search across all items + sections (same flat list StartMenu uses).\n // Walks 3rd-level children too so nested entries are still discoverable.\n const matchTree = (it: NavItem, q: string): NavItem[] => {\n if (it.perms && !hasAnyPerm(it.perms)) return [];\n const hits: NavItem[] = [];\n if (it.label.toLowerCase().includes(q)) hits.push(it);\n if (it.children) {\n for (const c of it.children) hits.push(...matchTree(c, q));\n }\n return hits;\n };\n const searchResults = useMemo(() => {\n if (search.length < 2) return [] as NavItem[];\n const q = search.toLowerCase();\n return [\n ...navSections.flatMap((entry) => {\n if (isSection(entry)) {\n return getVisibleItems(entry).flatMap(it => matchTree(it, q));\n }\n return matchTree(entry as NavItem, q);\n }),\n ...footerItems.flatMap(it => matchTree(it, q)),\n ];\n }, [search, navSections, footerItems, hasAnyPerm]);\n\n // Esc collapses any expanded section + clears search; '/' focuses search.\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setExpanded(new Set());\n setSearch('');\n } else if (e.key === '/' && document.activeElement?.tagName !== 'INPUT' && document.activeElement?.tagName !== 'TEXTAREA') {\n e.preventDefault();\n searchRef.current?.focus();\n }\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, []);\n\n const handleClick = (path: string) => {\n onNavigate(path);\n onPageOpenedReset();\n };\n\n // Reset search after navigating so the next visit starts clean.\n const onPageOpenedReset = () => {\n setSearch('');\n };\n\n const itemCls = 'w-full flex items-center gap-2 rounded-lg px-3 py-2 text-sm';\n const menuGlass = glassStyle();\n\n // Helper that returns the (possibly recolored) per-route icon.\n const iconEl = (to: string) => {\n const icon = navIcons[to];\n if (icon && isValidElement(icon)) {\n return cloneElement(icon as ReactElement<{ className?: string }>, {\n className: 'h-4 w-4 shrink-0 text-gray-500',\n });\n }\n return <span className=\"h-4 w-4 shrink-0\" />;\n };\n\n const secIcon = (label: string) => {\n const icon = sectionIcons[label];\n if (icon && isValidElement(icon)) {\n return cloneElement(icon as ReactElement<{ className?: string }>, {\n className: 'h-4 w-4 shrink-0 text-gray-500',\n });\n }\n return <span className=\"h-4 w-4 shrink-0\" />;\n };\n\n const renderItem = (item: NavItem) => (\n <div key={item.to}>\n <button\n onClick={() => handleClick(item.to)}\n className={`${itemCls} text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition-colors`}\n >\n {iconEl(item.to)}\n <span className=\"truncate\">{item.label}</span>\n </button>\n {item.dividerAfter && <div className=\"border-t border-white/20 my-1.5 mx-2\" />}\n </div>\n );\n\n // 3rd-level: when a NavItem inside an accordion has children, render the\n // parent as its own mini-accordion (further indented). Expansion key is\n // `child:<to>` so it doesn't clash with the section labels in `expanded`.\n const renderNestedItem = (item: NavItem) => {\n const kids = (item.children ?? []).filter(c => !c.perms || hasAnyPerm(c.perms));\n if (kids.length === 0) return renderItem(item);\n const key = `child:${item.to}`;\n const isOpen = expanded.has(key);\n return (\n <div key={item.to}>\n <button\n onClick={() => toggleExpanded(key)}\n aria-expanded={isOpen}\n className={`${itemCls} text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition-colors`}\n >\n {iconEl(item.to)}\n <span className=\"truncate\">{item.label}</span>\n <svg\n className={`h-3.5 w-3.5 ml-auto text-gray-500 transition-transform ${isOpen ? 'rotate-90' : ''}`}\n fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.25 4.5l7.5 7.5-7.5 7.5\" />\n </svg>\n </button>\n {isOpen && (\n <div className=\"pl-4 mt-0.5 mb-1 space-y-0.5\">\n {kids.map(c => (\n <button\n key={c.to}\n onClick={() => handleClick(c.to)}\n className={`${itemCls} text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition-colors`}\n >\n {iconEl(c.to)}\n <span className=\"truncate\">{c.label}</span>\n </button>\n ))}\n </div>\n )}\n {item.dividerAfter && <div className=\"border-t border-white/20 my-1.5 mx-2\" />}\n </div>\n );\n };\n\n const renderSectionAccordion = (section: NavSection | VirtualSection, isErp: boolean) => {\n const items = 'perms' in section\n ? getVisibleItems(section as NavSection)\n : (section as VirtualSection).items;\n if (items.length === 0) return null;\n const isOpen = expanded.has(section.label);\n return (\n <div key={section.label}>\n <button\n onClick={() => toggleExpanded(section.label)}\n aria-expanded={isOpen}\n className={`${itemCls} text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition-colors`}\n >\n {'icon' in section && section.icon\n ? section.icon\n : secIcon(section.label)}\n <span className={`truncate ${isErp ? 'font-medium' : ''}`}>{section.label}</span>\n <svg\n className={`h-3.5 w-3.5 ml-auto text-gray-500 transition-transform ${isOpen ? 'rotate-90' : ''}`}\n fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8.25 4.5l7.5 7.5-7.5 7.5\" />\n </svg>\n </button>\n {isOpen && (\n <div className=\"pl-4 mt-0.5 mb-1 space-y-0.5\">\n {items.map(it => renderNestedItem(it))}\n </div>\n )}\n </div>\n );\n };\n\n return (\n <div\n className=\"fixed top-0 left-0 bottom-0 z-[260] flex flex-col rounded-r-2xl overflow-hidden\"\n style={{ width, ...menuGlass }}\n >\n {/* Brand */}\n <div className=\"flex items-center gap-2 px-4 py-3 border-b border-white/15 shrink-0\">\n {productIcon && <img src={productIcon} alt=\"\" className=\"h-5 w-5 shrink-0 opacity-80\" />}\n <span className=\"text-sm font-semibold text-gray-800 truncate\">{productName ?? 'Apps'}</span>\n </div>\n\n {/* Search */}\n <div className=\"px-3 pt-3 pb-2 shrink-0\">\n <div className={`flex items-center gap-2 ${GLASS_INPUT_BG} rounded-lg px-2.5 py-1.5`}>\n <svg className=\"h-3.5 w-3.5 text-gray-400 shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z\" />\n </svg>\n <input\n ref={searchRef}\n value={search}\n onChange={e => setSearch(e.target.value)}\n placeholder=\"Search...\"\n className=\"flex-1 bg-transparent text-xs outline-none placeholder-gray-400\"\n />\n {search && (\n <button onClick={() => setSearch('')} className=\"text-gray-400 hover:text-gray-600 text-xs\">×</button>\n )}\n </div>\n </div>\n\n {/* Body */}\n <div className=\"flex-1 overflow-y-auto px-1 pb-1\">\n {search.length >= 2 ? (\n // Search results take over the body.\n <div>\n {searchResults.length === 0 ? (\n <div className=\"px-3 py-6 text-center text-xs text-gray-400\">No matches</div>\n ) : (\n searchResults.map(r => (\n <button\n key={r.to}\n onClick={() => handleClick(r.to)}\n className={`${itemCls} text-gray-700 hover:bg-blue-50 hover:text-blue-700 transition-colors`}\n >\n {iconEl(r.to)}\n <span className=\"truncate\">{r.label}</span>\n </button>\n ))\n )}\n </div>\n ) : (\n <>\n {/* Top-level apps */}\n {topItems.map(renderItem)}\n\n <div className=\"border-t border-white/15 my-1.5 mx-2\" />\n\n {/* ERP sections then system sections — same order as StartMenu's vertical layout. */}\n {erpSections.map(s => renderSectionAccordion(s, true))}\n {systemSections.map(s => renderSectionAccordion(s, false))}\n {virtualSections.map(v => renderSectionAccordion(v, false))}\n {/* Footer items + sections: pinned just above the profile, divided from the rest. */}\n {(footerSections.length > 0 || footerItems.length > 0) && <div className=\"border-t border-white/15 my-1.5 mx-2\" />}\n {footerSections.map(s => renderSectionAccordion(s, false))}\n {footerItems.map(renderItem)}\n </>\n )}\n </div>\n\n {/* Profile + Sign out at the bottom — mirrors StartMenu's user row. */}\n <div className=\"border-t border-white/15 p-1 shrink-0\">\n <div\n onClick={() => handleClick('/profile')}\n className=\"rounded-lg px-2 py-1.5 flex items-center gap-2.5 hover:bg-blue-50 hover:text-blue-700 transition-colors cursor-pointer\"\n >\n {profile?.avatar_url ? (\n <img src={profile.avatar_url} alt=\"\" className=\"h-8 w-8 rounded-full object-cover border border-white/20 shrink-0\" />\n ) : (\n <div className=\"h-8 w-8 rounded-full bg-blue-100 flex items-center justify-center text-sm font-bold text-blue-700 shrink-0\">\n {(profile?.first_name?.charAt(0) || user?.email?.charAt(0) || '?').toUpperCase()}\n </div>\n )}\n <p className=\"flex-1 min-w-0 text-sm font-medium text-gray-900 truncate\">\n {profile?.first_name ? `${profile.first_name} ${profile.last_name || ''}`.trim() : user?.email}\n </p>\n <button\n onClick={e => { e.stopPropagation(); onLogout(); }}\n title=\"Sign Out\"\n className=\"shrink-0 p-1.5 rounded-md text-gray-500 hover:text-red-600 hover:bg-red-50 transition-colors\"\n >\n <svg className=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9\" />\n </svg>\n </button>\n </div>\n </div>\n </div>\n );\n}\n"]}