react-os-shell 2.6.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 (62) hide show
  1. package/dist/Browser-LVWMQSR3.js +7 -0
  2. package/dist/{Browser-H55YZJT5.js.map → Browser-LVWMQSR3.js.map} +1 -1
  3. package/dist/{Calculator-H7HMALL3.js → Calculator-LF2IH7NZ.js} +4 -4
  4. package/dist/{Calculator-H7HMALL3.js.map → Calculator-LF2IH7NZ.js.map} +1 -1
  5. package/dist/{CurrencyConverter-576WXG7B.js → CurrencyConverter-AZ5RBU7E.js} +4 -4
  6. package/dist/{CurrencyConverter-576WXG7B.js.map → CurrencyConverter-AZ5RBU7E.js.map} +1 -1
  7. package/dist/{Documents-XBOFBIIZ.js → Documents-AEZKXAW3.js} +4 -4
  8. package/dist/{Documents-XBOFBIIZ.js.map → Documents-AEZKXAW3.js.map} +1 -1
  9. package/dist/Files-3WHYRZI6.js +13 -0
  10. package/dist/{Files-KX3OMH6V.js.map → Files-3WHYRZI6.js.map} +1 -1
  11. package/dist/{Notepad-PWLIOQR5.js → Notepad-R2OY27CY.js} +4 -5
  12. package/dist/Notepad-R2OY27CY.js.map +1 -0
  13. package/dist/{PomodoroTimer-PQ7FXSKY.js → PomodoroTimer-M7MDQTVN.js} +5 -6
  14. package/dist/PomodoroTimer-M7MDQTVN.js.map +1 -0
  15. package/dist/Preview-F75CICNY.js +9 -0
  16. package/dist/{Preview-YOTSKJNV.js.map → Preview-F75CICNY.js.map} +1 -1
  17. package/dist/{Sidebar-BW7SYNBA.js → Sidebar-PY762ANK.js} +3 -3
  18. package/dist/Sidebar-PY762ANK.js.map +1 -0
  19. package/dist/Spreadsheet-P4MBJWSH.js +7 -0
  20. package/dist/{Spreadsheet-LQOJPR4G.js.map → Spreadsheet-P4MBJWSH.js.map} +1 -1
  21. package/dist/{Stock-NQFKY52J.js → Stock-7JFY7KUK.js} +4 -4
  22. package/dist/{Stock-NQFKY52J.js.map → Stock-7JFY7KUK.js.map} +1 -1
  23. package/dist/{Weather-KH5A7AZ3.js → Weather-B55N3VEX.js} +4 -5
  24. package/dist/Weather-B55N3VEX.js.map +1 -0
  25. package/dist/{WorldClock-VUMFYV5V.js → WorldClock-SARH4X3Y.js} +4 -5
  26. package/dist/WorldClock-SARH4X3Y.js.map +1 -0
  27. package/dist/apps/index.js +19 -19
  28. package/dist/{chunk-7CT2Y2MB.js → chunk-4YBNDCJV.js} +4 -4
  29. package/dist/{chunk-7CT2Y2MB.js.map → chunk-4YBNDCJV.js.map} +1 -1
  30. package/dist/{chunk-BE53IFLK.js → chunk-BLYEAKGC.js} +4 -4
  31. package/dist/{chunk-BE53IFLK.js.map → chunk-BLYEAKGC.js.map} +1 -1
  32. package/dist/{chunk-YVIW5GPB.js → chunk-IQTT4ZBV.js} +3 -3
  33. package/dist/{chunk-YVIW5GPB.js.map → chunk-IQTT4ZBV.js.map} +1 -1
  34. package/dist/{chunk-TJ6N7SI5.js → chunk-JNF5VRPB.js} +75 -35
  35. package/dist/chunk-JNF5VRPB.js.map +1 -0
  36. package/dist/{chunk-QOH6MNLW.js → chunk-KQBZLA6K.js} +4 -4
  37. package/dist/{chunk-QOH6MNLW.js.map → chunk-KQBZLA6K.js.map} +1 -1
  38. package/dist/{chunk-5X5LQNOX.js → chunk-P75EON66.js} +3 -3
  39. package/dist/{chunk-5X5LQNOX.js.map → chunk-P75EON66.js.map} +1 -1
  40. package/dist/{chunk-2NHG2V2R.js → chunk-SAKVRVNB.js} +5 -5
  41. package/dist/{chunk-2NHG2V2R.js.map → chunk-SAKVRVNB.js.map} +1 -1
  42. package/dist/{chunk-FIOHSNGM.js → chunk-XGWARUR7.js} +4 -4
  43. package/dist/{chunk-FIOHSNGM.js.map → chunk-XGWARUR7.js.map} +1 -1
  44. package/dist/{chunk-R3CZB3O2.js → chunk-ZW2JB5CK.js} +4 -4
  45. package/dist/{chunk-R3CZB3O2.js.map → chunk-ZW2JB5CK.js.map} +1 -1
  46. package/dist/index.js +90 -14
  47. package/dist/index.js.map +1 -1
  48. package/dist/styles.css +187 -2
  49. package/dist/themes.css +244 -0
  50. package/package.json +4 -3
  51. package/dist/Browser-H55YZJT5.js +0 -7
  52. package/dist/Files-KX3OMH6V.js +0 -13
  53. package/dist/Notepad-PWLIOQR5.js.map +0 -1
  54. package/dist/PomodoroTimer-PQ7FXSKY.js.map +0 -1
  55. package/dist/Preview-YOTSKJNV.js +0 -9
  56. package/dist/Sidebar-BW7SYNBA.js.map +0 -1
  57. package/dist/Spreadsheet-LQOJPR4G.js +0 -7
  58. package/dist/Weather-KH5A7AZ3.js.map +0 -1
  59. package/dist/WorldClock-VUMFYV5V.js.map +0 -1
  60. package/dist/chunk-36VM54SC.js +0 -42
  61. package/dist/chunk-36VM54SC.js.map +0 -1
  62. package/dist/chunk-TJ6N7SI5.js.map +0 -1
package/dist/styles.css CHANGED
@@ -18,11 +18,15 @@
18
18
  * - Status-badge tone-downs (matches the 8 semantic groups in StatusBadge)
19
19
  * - Scrollbar styling for editable grids and dark-mode containers
20
20
  *
21
- * Per-theme variants (pink / green / grey / blue) ship as extension
22
- * stylesheets the consumer can opt into separately not included here.
21
+ * Per-theme accent variants (pink / green / grey / blue + custom accent)
22
+ * live in themes.css, imported below so every consumer gets the full set —
23
+ * useTheme() offers all of them in every portal, so the remaps must exist
24
+ * wherever styles.css is loaded. themes.css is also exported standalone
25
+ * ("react-os-shell/themes.css") for consumers that import granularly.
23
26
  */
24
27
 
25
28
  @import "tailwindcss";
29
+ @import "./themes.css";
26
30
 
27
31
  /* Tailwind v4 doesn't scan node_modules by default — tell it to scan this
28
32
  package's compiled JS so utility classes used in shell components get
@@ -212,6 +216,7 @@
212
216
  [data-theme="dark"] [data-sticky-id] .text-black\/70 { color: rgba(230, 233, 245, 0.92) !important; }
213
217
  [data-theme="dark"] [data-sticky-id] .text-black\/30 { color: rgba(230, 233, 245, 0.45) !important; }
214
218
  [data-theme="dark"] [data-sticky-id] .text-black\/20 { color: rgba(230, 233, 245, 0.42) !important; }
219
+ [data-theme="dark"] [data-sticky-id] .text-black\/15 { color: rgba(230, 233, 245, 0.35) !important; }
215
220
  [data-theme="dark"] [data-sticky-id] .hover\:text-black\/50:hover { color: rgba(230, 233, 245, 0.70) !important; }
216
221
  [data-theme="dark"] [data-sticky-id] .placeholder\:text-black\/30::placeholder { color: rgba(230, 233, 245, 0.45) !important; }
217
222
  [data-theme="dark"] [data-sticky-id] .bg-black\/10 { background-color: rgba(230, 233, 245, 0.16) !important; }
@@ -262,6 +267,186 @@
262
267
  [data-theme="dark"] .bg-orange-100.text-orange-800 { background-color: rgba(249, 115, 22, 0.18) !important; color: #fdba74 !important; }
263
268
  [data-theme="dark"] .bg-red-100.text-red-800 { background-color: rgba(239, 68, 68, 0.18) !important; color: #fca5a5 !important; }
264
269
 
270
+ /* ── Extended dark-mode tint families ────────────────────────────────
271
+ Upstreamed 2026-06-13 from the admin portal's 2026-06-10 audit so all
272
+ consumers share one source of truth. Every hue used by chips/badges
273
+ (tag colors, group colors, status accents, deal stages), notice
274
+ banners, verdict panels, row tints and danger buttons gets the same
275
+ scale as the families above: -50 → 10% tint, -100 → 18%, -200 → ~30%,
276
+ borders -200 → 32% / -300 → 45%, and dark inks flip to the
277
+ -400/-300/-200 light end of their scale.
278
+ Deliberately NOT remapped: game surfaces that read as intentionally
279
+ light (Calculator LCD bg-slate-200/text-slate-600/800, 2048/Chess
280
+ tiles, weather gradients), the Customization theme-preview swatches
281
+ (bg-pink-50/90, bg-green-50/90, bg-blue-50/90, bg-gray-200/90,
282
+ bg-pink-200, bg-green-200 — they must show each theme's real colors),
283
+ and low white/black alphas used as glass highlights on wallpaper. */
284
+
285
+ /* Red */
286
+ [data-theme="dark"] .bg-red-50 { background-color: rgba(239, 68, 68, 0.10) !important; }
287
+ [data-theme="dark"] .hover\:bg-red-50:hover { background-color: rgba(239, 68, 68, 0.16) !important; }
288
+ [data-theme="dark"] .active\:bg-red-50:active { background-color: rgba(239, 68, 68, 0.16) !important; }
289
+ [data-theme="dark"] .bg-red-50\/30 { background-color: rgba(239, 68, 68, 0.06) !important; }
290
+ [data-theme="dark"] .bg-red-50\/50 { background-color: rgba(239, 68, 68, 0.08) !important; }
291
+ [data-theme="dark"] .hover\:bg-red-100:hover { background-color: rgba(239, 68, 68, 0.22) !important; }
292
+ [data-theme="dark"] .border-red-200 { border-color: rgba(239, 68, 68, 0.35) !important; }
293
+ [data-theme="dark"] .border-red-300,
294
+ [data-theme="dark"] .hover\:border-red-300:hover { border-color: rgba(239, 68, 68, 0.45) !important; }
295
+ [data-theme="dark"] .text-red-600,
296
+ [data-theme="dark"] .hover\:text-red-600:hover { color: #f87171 !important; }
297
+ [data-theme="dark"] .hover\:text-red-700:hover { color: #fca5a5 !important; }
298
+ [data-theme="dark"] .text-red-800,
299
+ [data-theme="dark"] .hover\:text-red-800:hover { color: #fecaca !important; }
300
+ [data-theme="dark"] .text-red-900 { color: #fecaca !important; }
301
+
302
+ /* Amber */
303
+ [data-theme="dark"] .bg-amber-50 { background-color: rgba(245, 158, 11, 0.10) !important; }
304
+ [data-theme="dark"] .hover\:bg-amber-50:hover { background-color: rgba(245, 158, 11, 0.14) !important; }
305
+ [data-theme="dark"] .bg-amber-50\/30 { background-color: rgba(245, 158, 11, 0.06) !important; }
306
+ [data-theme="dark"] .bg-amber-50\/40 { background-color: rgba(245, 158, 11, 0.07) !important; }
307
+ [data-theme="dark"] .bg-amber-50\/50 { background-color: rgba(245, 158, 11, 0.08) !important; }
308
+ [data-theme="dark"] .hover\:bg-amber-100:hover { background-color: rgba(245, 158, 11, 0.24) !important; }
309
+ [data-theme="dark"] .bg-amber-200 { background-color: rgba(245, 158, 11, 0.28) !important; }
310
+ [data-theme="dark"] .border-amber-200 { border-color: rgba(245, 158, 11, 0.35) !important; }
311
+ [data-theme="dark"] .border-amber-300,
312
+ [data-theme="dark"] .hover\:border-amber-300:hover { border-color: rgba(245, 158, 11, 0.45) !important; }
313
+ [data-theme="dark"] .text-amber-600,
314
+ [data-theme="dark"] .hover\:text-amber-600:hover { color: #fbbf24 !important; }
315
+ [data-theme="dark"] .text-amber-800 { color: #fde68a !important; }
316
+ [data-theme="dark"] .text-amber-900 { color: #fde68a !important; }
317
+
318
+ /* Yellow */
319
+ [data-theme="dark"] .bg-yellow-50 { background-color: rgba(234, 179, 8, 0.10) !important; }
320
+ [data-theme="dark"] .bg-yellow-50\/50 { background-color: rgba(234, 179, 8, 0.08) !important; }
321
+ [data-theme="dark"] .border-yellow-200 { border-color: rgba(234, 179, 8, 0.35) !important; }
322
+ [data-theme="dark"] .border-yellow-300 { border-color: rgba(234, 179, 8, 0.45) !important; }
323
+ [data-theme="dark"] .text-yellow-600,
324
+ [data-theme="dark"] .hover\:text-yellow-600:hover { color: #facc15 !important; }
325
+ [data-theme="dark"] .text-yellow-900 { color: #fef08a !important; }
326
+
327
+ /* Green / emerald */
328
+ [data-theme="dark"] .bg-green-50 { background-color: rgba(34, 197, 94, 0.10) !important; }
329
+ [data-theme="dark"] .hover\:bg-green-50:hover { background-color: rgba(34, 197, 94, 0.14) !important; }
330
+ [data-theme="dark"] .bg-green-50\/40 { background-color: rgba(34, 197, 94, 0.06) !important; }
331
+ [data-theme="dark"] .border-green-200 { border-color: rgba(34, 197, 94, 0.32) !important; }
332
+ [data-theme="dark"] .border-green-300,
333
+ [data-theme="dark"] .hover\:border-green-300:hover { border-color: rgba(34, 197, 94, 0.45) !important; }
334
+ [data-theme="dark"] .text-green-600,
335
+ [data-theme="dark"] .hover\:text-green-600:hover { color: #4ade80 !important; }
336
+ [data-theme="dark"] .text-green-900,
337
+ [data-theme="dark"] .hover\:text-green-800:hover { color: #bbf7d0 !important; }
338
+ [data-theme="dark"] .bg-emerald-50 { background-color: rgba(16, 185, 129, 0.10) !important; }
339
+ [data-theme="dark"] .hover\:bg-emerald-100:hover { background-color: rgba(16, 185, 129, 0.24) !important; }
340
+ [data-theme="dark"] .border-emerald-200 { border-color: rgba(16, 185, 129, 0.32) !important; }
341
+ [data-theme="dark"] .border-emerald-300 { border-color: rgba(16, 185, 129, 0.45) !important; }
342
+ [data-theme="dark"] .text-emerald-600 { color: #34d399 !important; }
343
+ [data-theme="dark"] .text-emerald-800 { color: #a7f3d0 !important; }
344
+
345
+ /* Orange */
346
+ [data-theme="dark"] .bg-orange-50 { background-color: rgba(249, 115, 22, 0.10) !important; }
347
+ [data-theme="dark"] .hover\:bg-orange-50:hover { background-color: rgba(249, 115, 22, 0.14) !important; }
348
+ [data-theme="dark"] .hover\:bg-orange-200:hover { background-color: rgba(249, 115, 22, 0.30) !important; }
349
+ [data-theme="dark"] .border-orange-200 { border-color: rgba(249, 115, 22, 0.32) !important; }
350
+ [data-theme="dark"] .border-orange-300,
351
+ [data-theme="dark"] .hover\:border-orange-300:hover { border-color: rgba(249, 115, 22, 0.45) !important; }
352
+ [data-theme="dark"] .text-orange-600 { color: #fb923c !important; }
353
+ [data-theme="dark"] .text-orange-900 { color: #fed7aa !important; }
354
+
355
+ /* Sky / teal / cyan */
356
+ [data-theme="dark"] .bg-sky-50 { background-color: rgba(14, 165, 233, 0.10) !important; }
357
+ [data-theme="dark"] .border-sky-300 { border-color: rgba(14, 165, 233, 0.45) !important; }
358
+ [data-theme="dark"] .bg-teal-50 { background-color: rgba(20, 184, 166, 0.10) !important; }
359
+ [data-theme="dark"] .bg-teal-100 { background-color: rgba(20, 184, 166, 0.18) !important; }
360
+ [data-theme="dark"] .text-teal-600 { color: #2dd4bf !important; }
361
+ [data-theme="dark"] .text-teal-700 { color: #5eead4 !important; }
362
+ [data-theme="dark"] .text-teal-800 { color: #99f6e4 !important; }
363
+ [data-theme="dark"] .text-cyan-600 { color: #22d3ee !important; }
364
+
365
+ /* Purple / violet */
366
+ [data-theme="dark"] .bg-purple-50 { background-color: rgba(168, 85, 247, 0.10) !important; }
367
+ [data-theme="dark"] .hover\:bg-purple-50:hover { background-color: rgba(168, 85, 247, 0.14) !important; }
368
+ [data-theme="dark"] .border-purple-200 { border-color: rgba(168, 85, 247, 0.32) !important; }
369
+ [data-theme="dark"] .border-purple-300,
370
+ [data-theme="dark"] .hover\:border-purple-300:hover { border-color: rgba(168, 85, 247, 0.45) !important; }
371
+ [data-theme="dark"] .text-purple-600 { color: #c084fc !important; }
372
+ [data-theme="dark"] .text-purple-800,
373
+ [data-theme="dark"] .text-purple-900 { color: #e9d5ff !important; }
374
+ [data-theme="dark"] .bg-violet-100 { background-color: rgba(139, 92, 246, 0.18) !important; }
375
+ [data-theme="dark"] .border-violet-300 { border-color: rgba(139, 92, 246, 0.45) !important; }
376
+ [data-theme="dark"] .text-violet-800 { color: #ddd6fe !important; }
377
+
378
+ /* Pink / rose */
379
+ [data-theme="dark"] .bg-pink-100 { background-color: rgba(236, 72, 153, 0.18) !important; }
380
+ [data-theme="dark"] .border-pink-200 { border-color: rgba(236, 72, 153, 0.32) !important; }
381
+ [data-theme="dark"] .border-pink-300 { border-color: rgba(236, 72, 153, 0.45) !important; }
382
+ [data-theme="dark"] .text-pink-600 { color: #f472b6 !important; }
383
+ [data-theme="dark"] .text-pink-800,
384
+ [data-theme="dark"] .text-pink-900 { color: #fbcfe8 !important; }
385
+ [data-theme="dark"] .bg-rose-100 { background-color: rgba(244, 63, 94, 0.18) !important; }
386
+ [data-theme="dark"] .text-rose-700 { color: #fda4af !important; }
387
+ [data-theme="dark"] .text-rose-800 { color: #fecdd3 !important; }
388
+
389
+ /* Indigo / slate */
390
+ [data-theme="dark"] .bg-indigo-50 { background-color: rgba(99, 102, 241, 0.15) !important; }
391
+ [data-theme="dark"] .hover\:bg-indigo-100:hover { background-color: rgba(99, 102, 241, 0.25) !important; }
392
+ [data-theme="dark"] .text-indigo-600 { color: #a5b4fc !important; }
393
+ [data-theme="dark"] .border-indigo-300 { border-color: rgba(99, 102, 241, 0.45) !important; }
394
+ [data-theme="dark"] .text-slate-700 { color: #cbd5e1 !important; } /* slate-600/800 left for the Calculator LCD */
395
+ [data-theme="dark"] .border-slate-300 { border-color: rgba(148, 163, 184, 0.35) !important; }
396
+
397
+ /* Blue — gaps beyond the accent remaps above. Hover/active steps sit one
398
+ ladder step above their resting tint (base .26 → active .30; the /30../50
399
+ alpha ladder steps 0.10/0.12/0.15 → hovers 0.12/0.15/0.18). */
400
+ [data-theme="dark"] .bg-blue-200 { background-color: rgba(59, 130, 246, 0.35) !important; }
401
+ [data-theme="dark"] .active\:bg-blue-200:active { background-color: rgba(59, 130, 246, 0.40) !important; }
402
+ [data-theme="dark"] .bg-blue-200\/60 { background-color: rgba(59, 130, 246, 0.20) !important; }
403
+ [data-theme="dark"] .hover\:bg-blue-100:hover { background-color: rgba(59, 130, 246, 0.26) !important; }
404
+ [data-theme="dark"] .active\:bg-blue-50:active { background-color: rgba(59, 130, 246, 0.30) !important; }
405
+ [data-theme="dark"] .hover\:bg-blue-50\/30:hover { background-color: rgba(59, 130, 246, 0.12) !important; }
406
+ [data-theme="dark"] .hover\:bg-blue-50\/40:hover { background-color: rgba(59, 130, 246, 0.15) !important; }
407
+ [data-theme="dark"] .hover\:bg-blue-50\/50:hover { background-color: rgba(59, 130, 246, 0.18) !important; }
408
+ [data-theme="dark"] .border-blue-100 { border-color: rgba(59, 130, 246, 0.22) !important; }
409
+ [data-theme="dark"] .border-blue-200,
410
+ [data-theme="dark"] .hover\:border-blue-200:hover { border-color: rgba(59, 130, 246, 0.32) !important; }
411
+ [data-theme="dark"] .border-blue-300,
412
+ [data-theme="dark"] .hover\:border-blue-300:hover { border-color: rgba(59, 130, 246, 0.45) !important; }
413
+ [data-theme="dark"] .border-blue-300\/50 { border-color: rgba(59, 130, 246, 0.25) !important; }
414
+ [data-theme="dark"] .text-blue-900 { color: #bfdbfe !important; }
415
+ [data-theme="dark"] .hover\:text-blue-600:hover { color: #93c5fd !important; }
416
+ [data-theme="dark"] .hover\:text-blue-800:hover { color: #bfdbfe !important; }
417
+ /* File-input buttons (file: compiles to ::file-selector-button) */
418
+ [data-theme="dark"] .file\:bg-blue-50::file-selector-button { background-color: rgba(59, 130, 246, 0.26) !important; }
419
+ [data-theme="dark"] .file\:text-blue-700::file-selector-button { color: #bfdbfe !important; }
420
+ [data-theme="dark"] .hover\:file\:bg-blue-100:hover::file-selector-button { background-color: rgba(59, 130, 246, 0.26) !important; }
421
+
422
+ /* Gray interaction-state variants (separate class names from the bare remaps) */
423
+ [data-theme="dark"] .hover\:text-gray-600:hover,
424
+ [data-theme="dark"] .hover\:text-gray-700:hover { color: #a6adc8 !important; }
425
+ [data-theme="dark"] .hover\:text-gray-800:hover { color: #bac2de !important; }
426
+ [data-theme="dark"] .hover\:text-gray-900:hover,
427
+ [data-theme="dark"] .active\:text-gray-900:active { color: #cdd6f4 !important; }
428
+ [data-theme="dark"] .active\:bg-gray-100:active { background-color: #313244 !important; }
429
+ [data-theme="dark"] .active\:bg-gray-200:active { background-color: #45475a !important; }
430
+ [data-theme="dark"] .active\:bg-gray-300:active,
431
+ [data-theme="dark"] .hover\:bg-gray-300:hover { background-color: #585b70 !important; }
432
+ [data-theme="dark"] .disabled\:bg-gray-100:disabled { background-color: #1e1e2e !important; }
433
+ [data-theme="dark"] .disabled\:bg-gray-200:disabled { background-color: #313244 !important; }
434
+ [data-theme="dark"] .hover\:bg-gray-200\/50:hover { background-color: rgba(69, 71, 90, 0.5) !important; }
435
+ [data-theme="dark"] .even\:bg-gray-50\/50:nth-child(even) { background-color: rgba(24, 24, 37, 0.5) !important; }
436
+ [data-theme="dark"] .border-gray-50,
437
+ [data-theme="dark"] .divide-gray-50 > :not(:last-child) { border-color: #2a2a3c !important; }
438
+ [data-theme="dark"] .border-gray-200\/50 { border-color: rgba(49, 50, 68, 0.6) !important; }
439
+ [data-theme="dark"] .hover\:border-gray-200:hover { border-color: #313244 !important; }
440
+ [data-theme="dark"] .hover\:border-gray-300:hover { border-color: #45475a !important; }
441
+
442
+ /* White panel surfaces / solid black ink. hover-to-white means "emphasize",
443
+ which on dark glass means a solid panel tint; hover-to-black ink flips to
444
+ brighter, not darker (e.g. the taskbar bell). */
445
+ [data-theme="dark"] .bg-white\/85 { background-color: rgba(30, 30, 46, 0.85) !important; }
446
+ [data-theme="dark"] .hover\:bg-white:hover { background-color: #1e1e2e !important; }
447
+ [data-theme="dark"] .text-black { color: #cdd6f4 !important; }
448
+ [data-theme="dark"] .hover\:text-black:hover { color: #ffffff !important; }
449
+
265
450
  /* Scrollbar */
266
451
  /* Force visible scrollbars on editable grids (macOS hides them by default) */
267
452
  .grid-scroll::-webkit-scrollbar { width: 10px; height: 10px; }
@@ -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.6.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,7 +0,0 @@
1
- export { Browser as default, setBrowserStartUrl } from './chunk-R3CZB3O2.js';
2
- import './chunk-FIOHSNGM.js';
3
- import './chunk-TJ6N7SI5.js';
4
- import './chunk-UBN4IUDE.js';
5
- import './chunk-ZF6AYO4G.js';
6
- //# sourceMappingURL=Browser-H55YZJT5.js.map
7
- //# sourceMappingURL=Browser-H55YZJT5.js.map
@@ -1,13 +0,0 @@
1
- export { Files as default, openFilesInTrashMode, setFilesDemoTree } from './chunk-2NHG2V2R.js';
2
- import './chunk-BE53IFLK.js';
3
- import './chunk-VGTEM5RZ.js';
4
- import './chunk-7CT2Y2MB.js';
5
- import './chunk-KUIPWCTJ.js';
6
- import './chunk-WIJ45SYD.js';
7
- import './chunk-QOH6MNLW.js';
8
- import './chunk-FIOHSNGM.js';
9
- import './chunk-TJ6N7SI5.js';
10
- import './chunk-UBN4IUDE.js';
11
- import './chunk-ZF6AYO4G.js';
12
- //# sourceMappingURL=Files-KX3OMH6V.js.map
13
- //# sourceMappingURL=Files-KX3OMH6V.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/auth.ts","../src/apps/Notepad.tsx"],"names":[],"mappings":"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","file":"Notepad-PWLIOQR5.js","sourcesContent":["/** User-profile API — calls below proxy to the consumer-supplied apiClient\n * via setShellApiClient(). Prefs reads/writes go through <ShellPrefsProvider>. */\nimport apiClient from './client';\nexport const getMe = () => apiClient.get('/auth/me/').then((r: any) => r.data);\nexport const updateMe = (patch: any) => apiClient.patch('/auth/me/', patch).then((r: any) => r.data);\nexport const getNumberingConfigs = () => apiClient.get('/auth/numbering-configs/').then((r: any) => r.data?.results ?? r.data ?? []);\n","import { useState, useEffect, useRef, useCallback, type ReactNode } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { getNumberingConfigs } from '../api/auth';\nimport apiClient from '../api/client';\nimport toast from '../shell/toast';\nimport { useWindowManager } from '../shell/WindowManager';\nimport { useShellPrefs } from '../shell/ShellPrefs';\nimport SidebarLayout from '../shell/SidebarLayout';\nimport AboutApp from './_about';\n\ninterface Note {\n id: string;\n title: string;\n content: string;\n color: string;\n sticky: boolean; // pinned to desktop\n updated_at: string;\n}\n\nconst COLORS = [\n { key: 'yellow', bg: 'bg-yellow-100', border: 'border-yellow-300', text: 'text-yellow-900', dot: 'bg-yellow-400' },\n { key: 'blue', bg: 'bg-blue-100', border: 'border-blue-300', text: 'text-blue-900', dot: 'bg-blue-400' },\n { key: 'green', bg: 'bg-green-100', border: 'border-green-300', text: 'text-green-900', dot: 'bg-green-400' },\n { key: 'pink', bg: 'bg-pink-100', border: 'border-pink-300', text: 'text-pink-900', dot: 'bg-pink-400' },\n { key: 'purple', bg: 'bg-purple-100', border: 'border-purple-300', text: 'text-purple-900', dot: 'bg-purple-400' },\n { key: 'orange', bg: 'bg-orange-100', border: 'border-orange-300', text: 'text-orange-900', dot: 'bg-orange-400' },\n { key: 'white', bg: 'bg-white', border: 'border-gray-300', text: 'text-gray-900', dot: 'bg-gray-300' },\n];\n\nfunction getColor(key: string) {\n return COLORS.find(c => c.key === key) || COLORS[0];\n}\n\nfunction newNote(): Note {\n return {\n id: `note-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n title: '',\n content: '',\n color: 'yellow',\n sticky: false,\n updated_at: new Date().toISOString(),\n };\n}\n\n// ── Entity reference mapping ──\n// Maps entity_type from NumberingConfig to modal registry entityType and search endpoint\nconst ENTITY_TYPE_MAP: Record<string, { entityType: string; endpoint: string }> = {\n sales_order: { entityType: 'order', endpoint: '/orders/sales-orders/' },\n purchase_order: { entityType: 'purchase_order', endpoint: '/purchase-orders/' },\n invoice: { entityType: 'invoice', endpoint: '/invoicing/invoices/' },\n vendor_invoice: { entityType: 'vendor_invoice', endpoint: '/invoicing/vendor-invoices/' },\n shipment: { entityType: 'shipment', endpoint: '/shipments/delivery-notes/' },\n receipt: { entityType: 'payment', endpoint: '/invoicing/payments/' },\n vendor_payment: { entityType: 'vendor_payment', endpoint: '/invoicing/vendor-payments/' },\n vendor_price_sheet: { entityType: 'vendor_price_sheet', endpoint: '/pricing/manufacturer-price-sheets/' },\n client_price_sheet: { entityType: 'price_sheet', endpoint: '/pricing/price-sheets/' },\n qc_report: { entityType: 'qc_report', endpoint: '/qc-reports/' },\n warranty_claim: { entityType: 'warranty_claim', endpoint: '/warranty-claims/claims/' },\n vendor_shipment: { entityType: 'vendor_shipment', endpoint: '/shipments/goods-receipts/' },\n};\n\n// Match checkboxes: [] or [x] or [X]\nconst CHECKBOX_REGEX = /\\[([ xX]?)\\]/g;\n\nexport default function Notepad() {\n const { openEntity } = useWindowManager();\n const { prefs, save } = useShellPrefs();\n\n // Fetch numbering configs to build dynamic prefix map (optional — only used\n // for entity-reference autolinking; safe to fail when no apiClient is wired).\n const { data: numberingConfigs } = useQuery({\n queryKey: ['numbering-configs'],\n queryFn: () => getNumberingConfigs(),\n retry: false,\n });\n\n // Build prefix → { entityType, endpoint } map from DB configs\n const prefixMap = useRef<Record<string, { entityType: string; endpoint: string; prefix: string }>>({});\n useEffect(() => {\n if (!numberingConfigs) return;\n const map: Record<string, { entityType: string; endpoint: string; prefix: string }> = {};\n for (const cfg of numberingConfigs) {\n const mapping = ENTITY_TYPE_MAP[cfg.entity_type];\n if (!mapping) continue;\n // prefix from DB is like \"SO#\" — strip the # to get \"SO\"\n const rawPrefix = (cfg.prefix || '').replace('#', '').toUpperCase();\n if (rawPrefix) {\n map[rawPrefix] = { ...mapping, prefix: cfg.prefix };\n }\n // Also register alt_prefix if set\n if (cfg.alt_prefix) {\n const altRaw = cfg.alt_prefix.replace('#', '').toUpperCase();\n if (altRaw) map[altRaw] = { ...mapping, prefix: cfg.alt_prefix };\n }\n }\n prefixMap.current = map;\n }, [numberingConfigs]);\n\n const notes: Note[] = prefs.notepad_notes || [];\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [editTitle, setEditTitle] = useState('');\n const [editContent, setEditContent] = useState('');\n const [editColor, setEditColor] = useState('yellow');\n const [dirty, setDirty] = useState(false);\n const [editing, setEditing] = useState(false);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const saveTimerRef = useRef<ReturnType<typeof setTimeout>>();\n\n const selected = notes.find(n => n.id === selectedId);\n\n // Select first note on load\n useEffect(() => {\n if (!selectedId && notes.length > 0) {\n const n = notes[0];\n setSelectedId(n.id);\n setEditTitle(n.title);\n setEditContent(n.content);\n setEditColor(n.color);\n }\n }, [notes.length]);\n\n const saveNotes = useCallback((updated: Note[]) => {\n save({ notepad_notes: updated });\n }, [save]);\n\n const autoSave = useCallback(() => {\n if (!selectedId || !dirty) return;\n const updated = notes.map(n =>\n n.id === selectedId ? { ...n, title: editTitle, content: editContent, color: editColor, updated_at: new Date().toISOString() } : n\n );\n saveNotes(updated);\n setDirty(false);\n }, [selectedId, dirty, editTitle, editContent, editColor, notes, saveNotes]);\n\n // Debounced auto-save\n useEffect(() => {\n if (!dirty) return;\n if (saveTimerRef.current) clearTimeout(saveTimerRef.current);\n saveTimerRef.current = setTimeout(autoSave, 800);\n return () => { if (saveTimerRef.current) clearTimeout(saveTimerRef.current); };\n }, [dirty, autoSave]);\n\n // Save on unmount\n useEffect(() => () => { if (dirty) autoSave(); }, []);\n\n const selectNote = (n: Note) => {\n if (dirty) autoSave();\n setSelectedId(n.id);\n setEditTitle(n.title);\n setEditContent(n.content);\n setEditColor(n.color);\n setDirty(false);\n setEditing(false);\n };\n\n const createNote = () => {\n if (dirty) autoSave();\n const n = newNote();\n const updated = [n, ...notes];\n saveNotes(updated);\n setSelectedId(n.id);\n setEditTitle('');\n setEditContent('');\n setEditColor('yellow');\n setDirty(false);\n setEditing(true);\n setTimeout(() => textareaRef.current?.focus(), 50);\n };\n\n const deleteNote = (id: string) => {\n const updated = notes.filter(n => n.id !== id);\n saveNotes(updated);\n if (selectedId === id) {\n const next = updated[0];\n if (next) selectNote(next);\n else { setSelectedId(null); setEditTitle(''); setEditContent(''); }\n }\n };\n\n const toggleSticky = (id: string) => {\n const updated = notes.map(n =>\n n.id === id ? { ...n, sticky: !n.sticky } : n\n );\n saveNotes(updated);\n const note = updated.find(n => n.id === id);\n toast.success(note?.sticky ? 'Pinned to desktop' : 'Removed from desktop');\n };\n\n const timeAgo = (iso: string) => {\n const diff = Date.now() - new Date(iso).getTime();\n const mins = Math.floor(diff / 60000);\n if (mins < 1) return 'just now';\n if (mins < 60) return `${mins}m ago`;\n const hrs = Math.floor(mins / 60);\n if (hrs < 24) return `${hrs}h ago`;\n const days = Math.floor(hrs / 24);\n return `${days}d ago`;\n };\n\n // ── Toggle checkbox in content ──\n const toggleCheckbox = (charIndex: number) => {\n const before = editContent.slice(0, charIndex);\n const match = editContent.slice(charIndex).match(/^\\[([ xX]?)\\]/);\n if (!match) return;\n const isChecked = match[1] === 'x' || match[1] === 'X';\n const replacement = isChecked ? '[ ]' : '[x]';\n const after = editContent.slice(charIndex + match[0].length);\n setEditContent(before + replacement + after);\n setDirty(true);\n };\n\n // ── Open entity reference ──\n const openRef = async (prefix: string, number: string) => {\n const mapping = prefixMap.current[prefix];\n if (!mapping) return;\n const refNum = `${prefix}#${number}`;\n try {\n const { data } = await apiClient.get(mapping.endpoint, { params: { search: refNum, page_size: 1 } });\n const results = data?.results ?? data ?? [];\n const entity = results[0];\n if (entity) {\n openEntity(mapping.entityType, entity.id, entity, refNum);\n } else {\n toast.error(`${refNum} not found`);\n }\n } catch {\n toast.error(`Failed to look up ${refNum}`);\n }\n };\n\n // ── Render content with links and checkboxes ──\n const renderContent = (text: string): ReactNode[] => {\n if (!text) return [];\n const lines = text.split('\\n');\n return lines.map((line, li) => {\n const parts: ReactNode[] = [];\n let lastIdx = 0;\n // Find all special tokens in the line\n const tokens: { idx: number; len: number; render: () => ReactNode }[] = [];\n\n // Entity references — match XX#NNNNN (2+ letters + # + 4-6 digits)\n const refRegex = /([A-Z]{2,4})#(\\d{4,6})/g;\n let m: RegExpExecArray | null;\n while ((m = refRegex.exec(line)) !== null) {\n const prefix = m[1];\n const num = m[2];\n if (prefixMap.current[prefix]) {\n const startIdx = m.index;\n const matchText = m[0];\n tokens.push({\n idx: startIdx,\n len: matchText.length,\n render: () => (\n <button key={`ref-${li}-${startIdx}`} onClick={() => openRef(prefix, num)}\n className=\"text-blue-600 hover:text-blue-800 hover:underline font-medium cursor-pointer\">\n {matchText}\n </button>\n ),\n });\n }\n }\n\n // Checkboxes\n CHECKBOX_REGEX.lastIndex = 0;\n // Calculate the character offset in the full content for this line\n let lineStartInContent = 0;\n for (let i = 0; i < li; i++) lineStartInContent += lines[i].length + 1;\n while ((m = CHECKBOX_REGEX.exec(line)) !== null) {\n const isChecked = m[1] === 'x' || m[1] === 'X';\n const startIdx = m.index;\n const contentCharIdx = lineStartInContent + startIdx;\n tokens.push({\n idx: startIdx,\n len: m[0].length,\n render: () => (\n <button key={`cb-${li}-${startIdx}`} onClick={() => toggleCheckbox(contentCharIdx)}\n className={`inline-flex items-center justify-center w-4 h-4 rounded border ${isChecked ? 'bg-blue-500 border-blue-500 text-white' : 'border-gray-400 bg-white hover:border-blue-400'} cursor-pointer align-text-bottom mr-0.5`}>\n {isChecked && <svg className=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\" /></svg>}\n </button>\n ),\n });\n }\n\n // Sort tokens by position\n tokens.sort((a, b) => a.idx - b.idx);\n\n // Build line with tokens interspersed\n for (const token of tokens) {\n if (token.idx > lastIdx) {\n // Check if text after a checked checkbox should be struck through\n parts.push(<span key={`t-${li}-${lastIdx}`}>{line.slice(lastIdx, token.idx)}</span>);\n }\n parts.push(token.render());\n lastIdx = token.idx + token.len;\n }\n if (lastIdx < line.length) {\n parts.push(<span key={`t-${li}-${lastIdx}`}>{line.slice(lastIdx)}</span>);\n }\n if (parts.length === 0) parts.push(<span key={`empty-${li}`}>{'\\u200B'}</span>); // zero-width space for empty lines\n\n // Check if line starts with a checked checkbox → strikethrough the rest\n const lineHasChecked = /^\\[x\\]/i.test(line.trimStart());\n return (\n <div key={li} className={lineHasChecked ? 'line-through text-gray-400' : ''}>\n {parts}\n </div>\n );\n });\n };\n\n const startEditing = () => {\n setEditing(true);\n setTimeout(() => textareaRef.current?.focus(), 50);\n };\n\n const stopEditing = () => {\n setEditing(false);\n if (dirty) autoSave();\n };\n\n const PLACEHOLDER_HINT = `Start writing...\n\nTips:\n [] Type [] for a checkbox, click to toggle\n SO#35001 Type XX#NNNNN to link entities (SO, PO, CI, VI, PL, etc.)`;\n\n const sidebar = (\n <>\n <div className=\"p-2 border-b border-gray-200\">\n <button onClick={createNote}\n className=\"w-full flex items-center justify-center gap-1.5 rounded-lg bg-blue-600 text-white px-3 py-1.5 text-sm font-medium hover:bg-blue-700 transition-colors\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 4.5v15m7.5-7.5h-15\" /></svg>\n New Note\n </button>\n </div>\n <div className=\"flex-1 overflow-y-auto\">\n {notes.length === 0 ? (\n <p className=\"text-sm text-gray-400 text-center py-8 px-4\">No notes yet. Create one to get started.</p>\n ) : (\n notes.map(n => {\n const c = getColor(n.color);\n return (\n <button key={n.id} onClick={() => selectNote(n)}\n className={`w-full text-left px-3 py-2.5 border-b border-gray-100 transition-colors ${selectedId === n.id ? 'bg-blue-50' : 'hover:bg-gray-50'}`}>\n <div className=\"flex items-center gap-2\">\n <div className={`w-2.5 h-2.5 rounded-full shrink-0 ${c.dot}`} />\n <span className=\"text-sm font-medium text-gray-900 truncate flex-1\">\n {n.title || 'Untitled'}\n </span>\n {n.sticky && (\n <svg className=\"h-3 w-3 text-amber-500 shrink-0\" fill=\"currentColor\" viewBox=\"0 0 24 24\"><path d=\"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z\" /></svg>\n )}\n </div>\n <p className=\"text-xs text-gray-400 mt-0.5 truncate ml-4.5\">{n.content.replace(/\\[[ xX]?\\]/g, '').slice(0, 60) || 'Empty note'}</p>\n <p className=\"text-[10px] text-gray-300 mt-0.5 ml-4.5\">{timeAgo(n.updated_at)}</p>\n </button>\n );\n })\n )}\n </div>\n </>\n );\n\n return (\n <div className=\"h-full\">\n <AboutApp app=\"notepad\" />\n <SidebarLayout\n sidebar={sidebar}\n storageKey=\"notepad.sidebarWidth\"\n defaultWidth={224}\n minWidth={180}\n maxWidth={360}\n >\n {/* Editor */}\n {selectedId ? (\n <div className=\"flex-1 flex flex-col min-w-0\">\n {/* Title */}\n <div className=\"flex items-center gap-2 px-4 py-2 border-b border-gray-200\">\n <input\n value={editTitle}\n onChange={e => { setEditTitle(e.target.value); setDirty(true); }}\n placeholder=\"Note title...\"\n className=\"flex-1 text-lg font-semibold text-gray-900 outline-none bg-transparent placeholder:text-gray-300\"\n />\n {/* Color picker */}\n <div className=\"flex gap-1\">\n {COLORS.map(c => (\n <button key={c.key} onClick={() => { setEditColor(c.key); setDirty(true); }}\n className={`w-5 h-5 rounded-full border-2 transition-all ${c.dot} ${editColor === c.key ? 'border-gray-600 scale-110' : 'border-transparent hover:border-gray-400'}`}\n title={c.key} />\n ))}\n </div>\n {/* Sticky toggle */}\n <button onClick={() => toggleSticky(selectedId)} title={selected?.sticky ? 'Remove from desktop' : 'Pin to desktop'}\n className={`p-1 rounded transition-colors ${selected?.sticky ? 'text-amber-500 hover:text-amber-600' : 'text-gray-300 hover:text-amber-400'}`}>\n <svg className=\"h-4 w-4\" fill={selected?.sticky ? 'currentColor' : 'none'} viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z\" /></svg>\n </button>\n {/* Delete */}\n <button onClick={() => deleteNote(selectedId)} title=\"Delete note\"\n className=\"p-1 rounded text-gray-300 hover:text-red-500 transition-colors\">\n <svg className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0\" /></svg>\n </button>\n </div>\n {/* Content — toggle between textarea (edit) and rendered view */}\n {editing ? (\n <textarea\n ref={textareaRef}\n value={editContent}\n onChange={e => { setEditContent(e.target.value); setDirty(true); }}\n onBlur={stopEditing}\n placeholder={PLACEHOLDER_HINT}\n className=\"flex-1 p-4 text-sm text-gray-700 outline-none resize-none bg-transparent leading-relaxed placeholder:text-gray-300 font-mono\"\n />\n ) : (\n <div\n onClick={startEditing}\n className=\"flex-1 p-4 text-sm text-gray-700 overflow-y-auto leading-relaxed cursor-text\"\n >\n {editContent ? renderContent(editContent) : (\n <p className=\"text-gray-300 whitespace-pre-line\">{PLACEHOLDER_HINT}</p>\n )}\n </div>\n )}\n {/* Bottom hint bar */}\n <div className=\"px-4 py-1.5 border-t border-gray-100 flex items-center gap-4 text-[10px] text-gray-400\">\n <span>[] checkbox</span>\n <span>SO#35001 entity link</span>\n <span className=\"ml-auto\">{editing ? 'Editing' : 'Click to edit'}</span>\n </div>\n </div>\n ) : (\n <div className=\"flex-1 flex items-center justify-center\">\n <div className=\"text-center text-gray-400\">\n <svg className=\"h-12 w-12 mx-auto mb-3 text-gray-300\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z\" /></svg>\n <p className=\"text-sm\">Select a note or create a new one</p>\n </div>\n </div>\n )}\n </SidebarLayout>\n </div>\n );\n}\n"]}