react-os-shell 0.1.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 (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +242 -0
  3. package/dist/Calculator-BNBRNV4P.js +184 -0
  4. package/dist/Calculator-BNBRNV4P.js.map +1 -0
  5. package/dist/Calendar-5EYUVGUU.js +423 -0
  6. package/dist/Calendar-5EYUVGUU.js.map +1 -0
  7. package/dist/Checkers-MIAHIKJH.js +214 -0
  8. package/dist/Checkers-MIAHIKJH.js.map +1 -0
  9. package/dist/Chess-C5BY45NA.js +190 -0
  10. package/dist/Chess-C5BY45NA.js.map +1 -0
  11. package/dist/ConfirmDialog-ZP4AHVUD.js +3 -0
  12. package/dist/ConfirmDialog-ZP4AHVUD.js.map +1 -0
  13. package/dist/CurrencyConverter-TYPU2IRF.js +223 -0
  14. package/dist/CurrencyConverter-TYPU2IRF.js.map +1 -0
  15. package/dist/Email-JEYYJ3YV.js +1835 -0
  16. package/dist/Email-JEYYJ3YV.js.map +1 -0
  17. package/dist/Game2048-3RH3ELRD.js +191 -0
  18. package/dist/Game2048-3RH3ELRD.js.map +1 -0
  19. package/dist/GeminiChat-BXLBJFT4.js +184 -0
  20. package/dist/GeminiChat-BXLBJFT4.js.map +1 -0
  21. package/dist/Minesweeper-VQGLAZON.js +270 -0
  22. package/dist/Minesweeper-VQGLAZON.js.map +1 -0
  23. package/dist/Notepad-YTZRCAXX.js +389 -0
  24. package/dist/Notepad-YTZRCAXX.js.map +1 -0
  25. package/dist/PomodoroTimer-HARIJN4S.js +196 -0
  26. package/dist/PomodoroTimer-HARIJN4S.js.map +1 -0
  27. package/dist/Spreadsheet-IOKEDNS6.js +446 -0
  28. package/dist/Spreadsheet-IOKEDNS6.js.map +1 -0
  29. package/dist/Sudoku-XHLYCEVT.js +197 -0
  30. package/dist/Sudoku-XHLYCEVT.js.map +1 -0
  31. package/dist/Tetris-ZHCZYL24.js +243 -0
  32. package/dist/Tetris-ZHCZYL24.js.map +1 -0
  33. package/dist/Weather-ROZ7TRNW.js +310 -0
  34. package/dist/Weather-ROZ7TRNW.js.map +1 -0
  35. package/dist/apps/index.d.ts +55 -0
  36. package/dist/apps/index.js +48 -0
  37. package/dist/apps/index.js.map +1 -0
  38. package/dist/chunk-5O2KEISQ.js +155 -0
  39. package/dist/chunk-5O2KEISQ.js.map +1 -0
  40. package/dist/chunk-D7PYW2QS.js +265 -0
  41. package/dist/chunk-D7PYW2QS.js.map +1 -0
  42. package/dist/chunk-GP4Y3VCB.js +806 -0
  43. package/dist/chunk-GP4Y3VCB.js.map +1 -0
  44. package/dist/chunk-NSU7OHPC.js +39 -0
  45. package/dist/chunk-NSU7OHPC.js.map +1 -0
  46. package/dist/chunk-PDFQNHW7.js +24 -0
  47. package/dist/chunk-PDFQNHW7.js.map +1 -0
  48. package/dist/chunk-RFTLYCSF.js +144 -0
  49. package/dist/chunk-RFTLYCSF.js.map +1 -0
  50. package/dist/chunk-SVBID2P6.js +142 -0
  51. package/dist/chunk-SVBID2P6.js.map +1 -0
  52. package/dist/chunk-TFGOLXGD.js +41 -0
  53. package/dist/chunk-TFGOLXGD.js.map +1 -0
  54. package/dist/chunk-WIJ45SYD.js +120 -0
  55. package/dist/chunk-WIJ45SYD.js.map +1 -0
  56. package/dist/chunk-WQIS72NL.js +1470 -0
  57. package/dist/chunk-WQIS72NL.js.map +1 -0
  58. package/dist/index.d.ts +642 -0
  59. package/dist/index.js +3443 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/sounds-NT4DEZGD.js +3 -0
  62. package/dist/sounds-NT4DEZGD.js.map +1 -0
  63. package/dist/styles.css +174 -0
  64. package/dist/types-CFIZ1_xt.d.ts +67 -0
  65. package/package.json +76 -0
@@ -0,0 +1,3 @@
1
+ export { SOUND_PACKS, SOUND_PACK_KEYS, SOUND_TYPES, SOUND_TYPE_LABELS, getSoundConfig, playClick, playError, playLogout, playNotification, playStartup, playSuccess, playTimerDone, previewSound, setAllSounds, setSoundForType, soundsEnabled, toggleSounds } from './chunk-D7PYW2QS.js';
2
+ //# sourceMappingURL=sounds-NT4DEZGD.js.map
3
+ //# sourceMappingURL=sounds-NT4DEZGD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"sounds-NT4DEZGD.js"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * react-os-shell base styles — Tailwind v4 @theme + dark-mode tone-down rules.
3
+ *
4
+ * Consumers import this once near their app entry:
5
+ *
6
+ * import 'react-os-shell/styles.css';
7
+ *
8
+ * The CSS custom properties are namespaced `--window-*` / `--taskbar-*` /
9
+ * `--menu-*` so they don't collide with consumer styles. Dark mode is
10
+ * activated by setting `data-theme="dark"` on the document element; the
11
+ * package's `useTheme()` hook handles this.
12
+ *
13
+ * Scope:
14
+ * - :root variables for window header/footer/content tints
15
+ * - [data-theme="dark"] overrides for bg-/text-/border-/shadow-/divide-
16
+ * Tailwind utility classes so the desktop, modals, and start menu
17
+ * all stay readable on dark glass
18
+ * - Status-badge tone-downs (matches the 8 semantic groups in StatusBadge)
19
+ * - Scrollbar styling for editable grids and dark-mode containers
20
+ *
21
+ * Per-theme variants (pink / green / grey / blue) ship as extension
22
+ * stylesheets the consumer can opt into separately — not included here.
23
+ */
24
+
25
+ @import "tailwindcss";
26
+
27
+ /* Tailwind v4 doesn't scan node_modules by default — tell it to scan this
28
+ package's compiled JS so utility classes used in shell components get
29
+ generated when consumers import react-os-shell/styles.css. */
30
+ @source "./**/*.js";
31
+
32
+ /* Base theme colors for transparent windows */
33
+ :root {
34
+ --window-header-rgb: 243 244 246;
35
+ --window-footer-rgb: 249 250 251;
36
+ --window-content-rgb: 255 255 255;
37
+ }
38
+ [data-theme="pink"] {
39
+ --window-header-rgb: 252 231 243;
40
+ --window-footer-rgb: 253 242 248;
41
+ --window-content-rgb: 255 245 249;
42
+ }
43
+ [data-theme="green"] {
44
+ --window-header-rgb: 220 252 231;
45
+ --window-footer-rgb: 236 253 245;
46
+ --window-content-rgb: 245 254 247;
47
+ }
48
+ [data-theme="grey"] {
49
+ --window-header-rgb: 229 231 235;
50
+ --window-footer-rgb: 243 244 246;
51
+ --window-content-rgb: 249 250 251;
52
+ }
53
+ [data-theme="blue"] {
54
+ --window-header-rgb: 219 234 254;
55
+ --window-footer-rgb: 239 246 255;
56
+ --window-content-rgb: 245 249 255;
57
+ }
58
+ [data-theme="dark"] {
59
+ --window-header-rgb: 49 50 68;
60
+ --window-footer-rgb: 24 24 37;
61
+ --window-content-rgb: 30 30 46;
62
+ }
63
+
64
+ /* ═══════════════════════════════════════════════════
65
+ Theme: Dark
66
+ ═══════════════════════════════════════════════════ */
67
+ [data-theme="dark"] {
68
+ color-scheme: dark;
69
+ }
70
+
71
+ /* Backgrounds */
72
+ [data-theme="dark"] .bg-white { background-color: #1e1e2e !important; }
73
+ [data-theme="dark"] .bg-gray-50 { background-color: #181825 !important; }
74
+ [data-theme="dark"] .bg-gray-100 { background-color: #1e1e2e !important; }
75
+ [data-theme="dark"] .bg-gray-200 { background-color: #313244 !important; }
76
+
77
+ /* Text */
78
+ [data-theme="dark"] .text-gray-900 { color: #cdd6f4 !important; }
79
+ [data-theme="dark"] .text-gray-800 { color: #bac2de !important; }
80
+ [data-theme="dark"] .text-gray-700 { color: #a6adc8 !important; }
81
+ [data-theme="dark"] .text-gray-600 { color: #9399b2 !important; }
82
+ [data-theme="dark"] .text-gray-500 { color: #7f849c !important; }
83
+ [data-theme="dark"] .text-gray-400 { color: #6c7086 !important; }
84
+
85
+ /* Borders */
86
+ [data-theme="dark"] .border-gray-200 { border-color: #313244 !important; }
87
+ [data-theme="dark"] .border-gray-300 { border-color: #45475a !important; }
88
+ [data-theme="dark"] .border-gray-100 { border-color: #2a2a3c !important; }
89
+
90
+ /* Cards, shadows, tables */
91
+ [data-theme="dark"] .shadow { --tw-shadow-color: rgba(0,0,0,0.4) !important; }
92
+ [data-theme="dark"] .shadow-lg { --tw-shadow-color: rgba(0,0,0,0.5) !important; }
93
+ [data-theme="dark"] .shadow-xl { --tw-shadow-color: rgba(0,0,0,0.5) !important; }
94
+ [data-theme="dark"] .shadow-2xl { --tw-shadow-color: rgba(0,0,0,0.6) !important; }
95
+ [data-theme="dark"] .divide-gray-200 > :not(:last-child) { border-color: #313244 !important; }
96
+ [data-theme="dark"] .divide-gray-100 > :not(:last-child) { border-color: #2a2a3c !important; }
97
+
98
+ /* Hover states */
99
+ [data-theme="dark"] .hover\:bg-gray-50:hover { background-color: #2a2a3c !important; }
100
+ [data-theme="dark"] .hover\:bg-gray-100:hover { background-color: #313244 !important; }
101
+ [data-theme="dark"] .hover\:bg-gray-200:hover { background-color: #45475a !important; }
102
+
103
+ /* Blue hover states — used by menu items, profile row, etc.
104
+ In dark mode swap the near-white bg for a dark blue tint and the dark
105
+ blue text for a light shade so highlighted items stay readable. */
106
+ [data-theme="dark"] .bg-blue-50,
107
+ [data-theme="dark"] .hover\:bg-blue-50:hover { background-color: rgba(59, 130, 246, 0.18) !important; }
108
+ [data-theme="dark"] .text-blue-700,
109
+ [data-theme="dark"] .hover\:text-blue-700:hover { color: #93c5fd !important; }
110
+ [data-theme="dark"] .text-blue-600 { color: #93c5fd !important; }
111
+ [data-theme="dark"] .text-blue-800 { color: #bfdbfe !important; }
112
+
113
+ /* Brighten taskbar button text so it stays readable on dark glass.
114
+ The default override (#9399b2) is too dim for short button labels. */
115
+ [data-theme="dark"] .text-gray-600 { color: #a6adc8 !important; }
116
+
117
+ /* Translucent button backgrounds — Tailwind generates separate classes for the
118
+ /40 /60 alpha variants (bg-gray-50\/40 etc.) so the bare .bg-gray-50 override
119
+ doesn't match. Override them explicitly with dark equivalents so taskbar
120
+ tabs and the start-menu button don't look too bright in Dark mode. */
121
+ [data-theme="dark"] .bg-gray-50\/40 { background-color: rgba(24, 24, 37, 0.4) !important; }
122
+ [data-theme="dark"] .bg-gray-100\/40 { background-color: rgba(30, 30, 46, 0.4) !important; }
123
+ [data-theme="dark"] .bg-gray-100\/60 { background-color: rgba(30, 30, 46, 0.6) !important; }
124
+ [data-theme="dark"] .bg-gray-200\/40 { background-color: rgba(49, 50, 68, 0.4) !important; }
125
+ [data-theme="dark"] .bg-gray-200\/50 { background-color: rgba(49, 50, 68, 0.5) !important; }
126
+ [data-theme="dark"] .bg-blue-100\/60 { background-color: rgba(59, 130, 246, 0.22) !important; }
127
+ [data-theme="dark"] .border-gray-200\/40 { border-color: rgba(69, 71, 90, 0.4) !important; }
128
+ [data-theme="dark"] .border-gray-300\/40 { border-color: rgba(88, 91, 112, 0.4) !important; }
129
+ [data-theme="dark"] .border-blue-400\/60 { border-color: rgba(96, 165, 250, 0.45) !important; }
130
+ [data-theme="dark"] .hover\:bg-gray-200\/40:hover { background-color: rgba(49, 50, 68, 0.4) !important; }
131
+
132
+ /* Inputs */
133
+ [data-theme="dark"] input:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]),
134
+ [data-theme="dark"] select,
135
+ [data-theme="dark"] textarea {
136
+ background-color: #181825 !important;
137
+ border-color: #45475a !important;
138
+ color: #cdd6f4 !important;
139
+ }
140
+
141
+ /* Window title colors — read by Modal.tsx */
142
+ [data-theme="dark"] {
143
+ --window-title-active: #cdd6f4;
144
+ --window-title-inactive: #6c7086;
145
+ --taskbar-bg-rgb: 24 24 37; /* Catppuccin mantle */
146
+ --taskbar-border-color: #313244;
147
+ }
148
+
149
+ /* Status badges — tone down brightness in dark mode (matches StatusBadge.tsx semantic groups) */
150
+ [data-theme="dark"] .bg-gray-100.text-gray-800 { background-color: #313244 !important; color: #a6adc8 !important; }
151
+ [data-theme="dark"] .bg-gray-300.text-gray-800 { background-color: #45475a !important; color: #cdd6f4 !important; }
152
+ [data-theme="dark"] .bg-green-100.text-green-800 { background-color: rgba(34, 197, 94, 0.18) !important; color: #86efac !important; }
153
+ [data-theme="dark"] .bg-blue-100.text-blue-800 { background-color: rgba(59, 130, 246, 0.18) !important; color: #93c5fd !important; }
154
+ [data-theme="dark"] .bg-indigo-100.text-indigo-800 { background-color: rgba(99, 102, 241, 0.18) !important; color: #a5b4fc !important; }
155
+ [data-theme="dark"] .bg-sky-100.text-sky-800 { background-color: rgba(14, 165, 233, 0.18) !important; color: #7dd3fc !important; }
156
+ [data-theme="dark"] .bg-yellow-100.text-yellow-800 { background-color: rgba(234, 179, 8, 0.18) !important; color: #fde68a !important; }
157
+ [data-theme="dark"] .bg-orange-100.text-orange-800 { background-color: rgba(249, 115, 22, 0.18) !important; color: #fdba74 !important; }
158
+ [data-theme="dark"] .bg-red-100.text-red-800 { background-color: rgba(239, 68, 68, 0.18) !important; color: #fca5a5 !important; }
159
+
160
+ /* Scrollbar */
161
+ /* Force visible scrollbars on editable grids (macOS hides them by default) */
162
+ .grid-scroll::-webkit-scrollbar { width: 10px; height: 10px; }
163
+ .grid-scroll::-webkit-scrollbar-track { background: #f1f5f9; }
164
+ .grid-scroll::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 5px; border: 2px solid #f1f5f9; }
165
+ .grid-scroll::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
166
+ .grid-scroll::-webkit-scrollbar-corner { background: #f1f5f9; }
167
+
168
+ [data-theme="dark"] ::-webkit-scrollbar { width: 8px; height: 8px; }
169
+ [data-theme="dark"] ::-webkit-scrollbar-track { background: #181825; }
170
+ [data-theme="dark"] ::-webkit-scrollbar-thumb { background: #45475a; border-radius: 4px; }
171
+ [data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: #585b70; }
172
+
173
+
174
+ /* ═══════════════════════════════════════════════════
@@ -0,0 +1,67 @@
1
+ import { ReactNode, LazyExoticComponent } from 'react';
2
+
3
+ /**
4
+ * Window registry types — generic shell concepts (no consumer-specific data).
5
+ *
6
+ * Two kinds of entries can be registered:
7
+ * - PageRegistryEntry: a lazy-loaded React component rendered as a windowed
8
+ * page (Calculator, Notepad, Sales Order list, etc.).
9
+ * - ModalRegistryEntry: a detail-modal definition that fetches an entity
10
+ * from a REST endpoint and hands it to a render function (Sales Order
11
+ * detail, Bug Report detail, etc.).
12
+ *
13
+ * Consumers compose their full registry by passing entries to
14
+ * `createWindowRegistry()` (see ./createWindowRegistry).
15
+ */
16
+
17
+ /** Page window entry — renders a lazy-loaded page component. */
18
+ interface PageRegistryEntry {
19
+ component: LazyExoticComponent<any>;
20
+ label: string;
21
+ size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';
22
+ allowPinOnTop?: boolean;
23
+ /** Utility apps don't show as taskbar window tabs. */
24
+ utility?: boolean;
25
+ /** Initial position hint. */
26
+ initialPosition?: 'top-right' | 'top-left';
27
+ /** Widget mode: no title bar, drag via body, right-click context menu. */
28
+ widget?: boolean;
29
+ /** Compact title bar: smaller header with title + close only, no footer. */
30
+ compact?: boolean;
31
+ /** Custom window dimensions [width, height] in pixels. */
32
+ dimensions?: [number, number];
33
+ /** Auto-size height based on content (widget only). */
34
+ autoHeight?: boolean;
35
+ /** navIcon route key for window title icon (e.g. '/orders'). */
36
+ icon?: string;
37
+ }
38
+ /** Entity window entry — renders a detail modal with API data. */
39
+ interface ModalRegistryEntry {
40
+ /** API endpoint prefix — entity fetched via GET {endpoint}{id}/. */
41
+ endpoint: string;
42
+ /** How to render the detail content. */
43
+ render: (entity: any, onClose: () => void, entityId?: string, editing?: boolean, setEditing?: (v: boolean) => void) => ReactNode;
44
+ /** Generate modal title from entity data. Editing state passed for Edit button. */
45
+ title: (entity: any, editing?: boolean, setEditing?: (v: boolean) => void) => ReactNode;
46
+ /** Generate modal footer from entity data. */
47
+ footer?: (entity: any) => ReactNode;
48
+ /** Modal size. */
49
+ size?: string;
50
+ /** If true, the component fetches its own data — pass ID, not entity. */
51
+ selfFetching?: boolean;
52
+ /** If true, the component renders its own Modal — skip outer Modal wrapper. */
53
+ rendersOwnModal?: boolean;
54
+ /** Query key prefix for React Query — must match what detail components invalidate. */
55
+ queryKey?: string;
56
+ /** navIcon route key for window title icon (e.g. '/orders'). */
57
+ icon?: string;
58
+ }
59
+ type WindowRegistryEntry = PageRegistryEntry | ModalRegistryEntry;
60
+ type WindowRegistry = Record<string, WindowRegistryEntry>;
61
+ /** Type guard: true if entry is a page window (has `component`). */
62
+ declare function isPageEntry(entry: WindowRegistryEntry): entry is PageRegistryEntry;
63
+ /** Type guard: true if entry is an entity window (has `endpoint`). */
64
+ declare function isEntityEntry(entry: WindowRegistryEntry): entry is ModalRegistryEntry;
65
+ declare function setShellWindowRegistry(registry: WindowRegistry): void;
66
+
67
+ export { type ModalRegistryEntry as M, type PageRegistryEntry as P, type WindowRegistry as W, type WindowRegistryEntry as a, isPageEntry as b, isEntityEntry as i, setShellWindowRegistry as s };
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "react-os-shell",
3
+ "version": "0.1.0",
4
+ "description": "Desktop-style React UI shell — windows, taskbar, start menu, sticky notes, frosted glass theming, plus 16 bundled apps (utilities, games, Google integrations).",
5
+ "license": "MIT",
6
+ "author": "Victor Y. Mau",
7
+ "type": "module",
8
+ "sideEffects": [
9
+ "**/*.css"
10
+ ],
11
+ "main": "./dist/index.js",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ },
19
+ "./apps": {
20
+ "types": "./dist/apps/index.d.ts",
21
+ "import": "./dist/apps/index.js"
22
+ },
23
+ "./styles.css": "./dist/styles.css"
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "peerDependencies": {
29
+ "@headlessui/react": ">=2",
30
+ "@heroicons/react": ">=2",
31
+ "@tanstack/react-query": ">=5",
32
+ "react": ">=18",
33
+ "react-dom": ">=18",
34
+ "react-hook-form": ">=7",
35
+ "react-router-dom": ">=6",
36
+ "tailwindcss": ">=4",
37
+ "xlsx": "*"
38
+ },
39
+ "dependencies": {
40
+ "axios": "^1.6.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/react": "^18.2.0",
44
+ "@types/react-dom": "^18.2.0",
45
+ "playwright": "^1.48.0",
46
+ "react": "^18.2.0",
47
+ "react-dom": "^18.2.0",
48
+ "tsup": "^8.0.0",
49
+ "typescript": "^5.3.0",
50
+ "xlsx": "^0.18.5"
51
+ },
52
+ "scripts": {
53
+ "build": "tsup && cp src/styles.css dist/styles.css",
54
+ "dev": "tsup --watch",
55
+ "typecheck": "tsc --noEmit",
56
+ "screenshot": "node scripts/screenshot.mjs",
57
+ "clean": "rm -rf dist"
58
+ },
59
+ "keywords": [
60
+ "react",
61
+ "desktop",
62
+ "ui-shell",
63
+ "window-manager",
64
+ "tailwind",
65
+ "macos",
66
+ "frosted-glass"
67
+ ],
68
+ "engines": {
69
+ "node": ">=20"
70
+ },
71
+ "peerDependenciesMeta": {
72
+ "xlsx": {
73
+ "optional": true
74
+ }
75
+ }
76
+ }