@kennofizet/apphub-frontend 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 (90) hide show
  1. package/README.md +84 -0
  2. package/package.json +31 -0
  3. package/src/api/coreApi.js +25 -0
  4. package/src/api/index.js +80 -0
  5. package/src/composables/createZoneContext.js +156 -0
  6. package/src/composables/useAppHubHostApi.js +24 -0
  7. package/src/composables/useAppHubZoneContext.js +11 -0
  8. package/src/composables/useDevOriginToggle.js +40 -0
  9. package/src/i18n/index.js +16 -0
  10. package/src/i18n/resolveLang.js +6 -0
  11. package/src/i18n/resolveTheme.js +30 -0
  12. package/src/i18n/translations/en.js +303 -0
  13. package/src/i18n/translations/vi.js +302 -0
  14. package/src/index.js +427 -0
  15. package/src/moduleStore.js +10 -0
  16. package/src/modules/app-store/components/AppHubAppStoreApp.vue +210 -0
  17. package/src/modules/app-store/components/AppHubAppStoreCard.vue +88 -0
  18. package/src/modules/app-store/components/AppHubAppStoreSettingsPanel.vue +266 -0
  19. package/src/modules/app-store/components/AppHubAppVersionHistory.vue +77 -0
  20. package/src/modules/app-store/components/AppHubDevReviewPanel.vue +206 -0
  21. package/src/modules/app-store/components/AppHubDraftStoreApp.vue +184 -0
  22. package/src/modules/app-store/components/AppHubDraftStoreCard.vue +116 -0
  23. package/src/modules/app-store/composables/useAppStore.js +206 -0
  24. package/src/modules/app-store/composables/useCatalogInfiniteScroll.js +47 -0
  25. package/src/modules/app-store/constants/catalogModes.js +2 -0
  26. package/src/modules/app-store/data/defaultCatalog.js +19 -0
  27. package/src/modules/app-store/index.js +9 -0
  28. package/src/modules/app-store/utils/normalizeCatalogApp.js +37 -0
  29. package/src/modules/desktop/components/AppHubDesktop.vue +1510 -0
  30. package/src/modules/desktop/components/AppHubDesktopDevOriginBar.vue +57 -0
  31. package/src/modules/desktop/components/AppHubDesktopDropLayer.vue +15 -0
  32. package/src/modules/desktop/components/AppHubDesktopDropTarget.vue +32 -0
  33. package/src/modules/desktop/components/AppHubDesktopIconContextMenu.vue +74 -0
  34. package/src/modules/desktop/components/AppHubDesktopIconFolder.vue +60 -0
  35. package/src/modules/desktop/components/AppHubDesktopIconGroup.vue +58 -0
  36. package/src/modules/desktop/components/AppHubDesktopIconInfoDialog.vue +33 -0
  37. package/src/modules/desktop/components/AppHubDesktopIconRenameDialog.vue +62 -0
  38. package/src/modules/desktop/components/AppHubDesktopSettings.vue +28 -0
  39. package/src/modules/desktop/components/AppHubDropInstallBadge.vue +65 -0
  40. package/src/modules/desktop/components/AppHubDuplicateAppDialog.vue +38 -0
  41. package/src/modules/desktop/components/AppHubGuideApp.vue +278 -0
  42. package/src/modules/desktop/components/AppHubOriginBlockScreen.vue +105 -0
  43. package/src/modules/desktop/components/AppHubOriginLoadingScreen.vue +23 -0
  44. package/src/modules/desktop/components/AppHubPlaceholderApp.vue +14 -0
  45. package/src/modules/desktop/components/AppHubSettingsApp.vue +319 -0
  46. package/src/modules/desktop/components/AppHubStartButton.vue +24 -0
  47. package/src/modules/desktop/components/AppHubStartMenu.vue +182 -0
  48. package/src/modules/desktop/components/AppHubTaskbarPins.vue +23 -0
  49. package/src/modules/desktop/components/settings/AppHubSettingsKeyboardPanel.vue +82 -0
  50. package/src/modules/desktop/components/settings/AppHubSettingsScreenPanel.vue +41 -0
  51. package/src/modules/desktop/components/settings/AppHubSettingsStartMenuPanel.vue +95 -0
  52. package/src/modules/desktop/composables/simulateInstallProgress.js +15 -0
  53. package/src/modules/desktop/composables/useDesktopDropInstall.js +272 -0
  54. package/src/modules/desktop/composables/useDesktopHubSettings.js +51 -0
  55. package/src/modules/desktop/composables/useDesktopIconDrag.js +207 -0
  56. package/src/modules/desktop/composables/useDesktopShell.js +335 -0
  57. package/src/modules/desktop/data/builtinApps.js +77 -0
  58. package/src/modules/desktop/index.js +12 -0
  59. package/src/modules/desktop/styles/desktop.css +3104 -0
  60. package/src/modules/desktop/styles/theme.css +616 -0
  61. package/src/modules/desktop/utils/desktopGrid.js +43 -0
  62. package/src/modules/desktop/utils/desktopIconGroups.js +103 -0
  63. package/src/modules/desktop/utils/desktopSession.js +40 -0
  64. package/src/modules/desktop/utils/desktopSettings.js +37 -0
  65. package/src/modules/desktop/utils/dropPackageParser.js +140 -0
  66. package/src/modules/desktop/utils/duplicateAppUtils.js +28 -0
  67. package/src/modules/desktop/utils/hubKeyboardSettings.js +63 -0
  68. package/src/modules/desktop/utils/recentApps.js +148 -0
  69. package/src/modules/desktop/utils/startMenuFavorites.js +100 -0
  70. package/src/modules/desktop/utils/startMenuPins.js +90 -0
  71. package/src/modules/notifications/components/AppHubDesktopNotifications.vue +54 -0
  72. package/src/modules/notifications/composables/createDesktopNotifications.js +86 -0
  73. package/src/modules/notifications/index.js +9 -0
  74. package/src/modules/notifications/styles/notifications.css +118 -0
  75. package/src/modules/notifications/utils/parseApiError.js +29 -0
  76. package/src/modules/runner/components/AppHubRunner.vue +292 -0
  77. package/src/modules/runner/index.js +1 -0
  78. package/src/modules/window-manager/components/AppHubWindowFrame.vue +224 -0
  79. package/src/modules/window-manager/composables/useWindowManager.js +652 -0
  80. package/src/modules/window-manager/index.js +7 -0
  81. package/src/modules/window-manager/utils/sessionLayout.js +28 -0
  82. package/src/modules/window-manager/utils/windowLayout.js +236 -0
  83. package/src/modules/window-manager/utils/windowSnap.js +146 -0
  84. package/src/utils/bootstrapCache.js +47 -0
  85. package/src/utils/devOriginSettings.js +22 -0
  86. package/src/utils/launchUrl.js +111 -0
  87. package/src/utils/originSafety.js +267 -0
  88. package/src/utils/safeStorage.js +191 -0
  89. package/src/utils/semver.js +30 -0
  90. package/src/utils/zoneContext.js +38 -0
@@ -0,0 +1,616 @@
1
+ /* App Hub desktop theme tokens (dark default, light via .apphub-desktop--light) */
2
+ .apphub-desktop {
3
+ --ah-text: #f0f4fc;
4
+ --ah-text-secondary: #e2e8f0;
5
+ --ah-text-muted: #94a3b8;
6
+ --ah-border: rgba(255, 255, 255, 0.1);
7
+ --ah-border-subtle: rgba(255, 255, 255, 0.06);
8
+ --ah-hover: rgba(255, 255, 255, 0.08);
9
+ --ah-hover-strong: rgba(255, 255, 255, 0.12);
10
+ --ah-surface: #1e293b;
11
+ --ah-surface-elevated: rgba(32, 32, 32, 0.97);
12
+ --ah-surface-panel: rgba(37, 37, 37, 0.45);
13
+ --ah-surface-input: rgba(255, 255, 255, 0.07);
14
+ --ah-taskbar: rgba(0, 0, 0, 0.82);
15
+ --ah-shadow: rgba(0, 0, 0, 0.45);
16
+ --ah-icon-label-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
17
+ --ah-accent: #60a5fa;
18
+ --ah-titlebar: linear-gradient(180deg, #2d3f5c 0%, #1e2d45 100%);
19
+ --ah-titlebar-text: #fff;
20
+ --ah-overlay: rgba(2, 6, 23, 0.55);
21
+ --ah-draft-accent: #fde68a;
22
+ --ah-draft-accent-strong: #fbbf24;
23
+ --ah-draft-surface: #1e293b;
24
+ --ah-draft-hero-bg: linear-gradient(90deg, rgba(251, 191, 36, 0.1) 0%, transparent 55%);
25
+ --ah-draft-card-bg: var(--ah-hover);
26
+ --ah-draft-card-border: rgba(251, 191, 36, 0.22);
27
+ --ah-draft-icon-bg: var(--ah-surface-input);
28
+ color: var(--ah-text);
29
+ transition: color 0.2s ease;
30
+ }
31
+
32
+ .apphub-desktop--light {
33
+ --ah-text: #1a2332;
34
+ --ah-text-secondary: #3d4f66;
35
+ --ah-text-muted: #5c6b7f;
36
+ --ah-border: rgba(26, 35, 50, 0.14);
37
+ --ah-border-subtle: rgba(26, 35, 50, 0.09);
38
+ --ah-hover: rgba(26, 35, 50, 0.055);
39
+ --ah-hover-strong: rgba(26, 35, 50, 0.09);
40
+ --ah-surface: #eef1f6;
41
+ --ah-surface-elevated: #e4e9f0;
42
+ --ah-surface-panel: #d8dfe9;
43
+ --ah-surface-input: #f4f6fa;
44
+ --ah-taskbar: rgba(220, 227, 236, 0.9);
45
+ --ah-shadow: rgba(26, 35, 50, 0.16);
46
+ --ah-icon-label-shadow: 0 1px 0 rgba(255, 255, 255, 0.75);
47
+ --ah-accent: #1d6fd6;
48
+ --ah-titlebar: linear-gradient(180deg, #f2f5fa 0%, #d4dce8 100%);
49
+ --ah-titlebar-text: #1a2332;
50
+ --ah-overlay: rgba(26, 35, 50, 0.42);
51
+ --ah-draft-accent: #b45309;
52
+ --ah-draft-accent-strong: #d97706;
53
+ --ah-draft-surface: #eef1f6;
54
+ --ah-draft-hero-bg: linear-gradient(90deg, rgba(251, 191, 36, 0.14) 0%, transparent 55%);
55
+ --ah-draft-card-bg: #fff;
56
+ --ah-draft-card-border: rgba(180, 130, 20, 0.28);
57
+ --ah-draft-icon-bg: #f1f5f9;
58
+ }
59
+
60
+ .apphub-desktop--light .apphub-desktop__wallpaper {
61
+ background:
62
+ radial-gradient(ellipse 85% 65% at 18% 15%, rgba(59, 130, 246, 0.38) 0%, transparent 52%),
63
+ radial-gradient(ellipse 65% 55% at 88% 78%, rgba(139, 92, 246, 0.24) 0%, transparent 48%),
64
+ radial-gradient(ellipse 45% 35% at 55% 35%, rgba(14, 165, 233, 0.18) 0%, transparent 42%),
65
+ linear-gradient(155deg, #9eb4cc 0%, #8aa3be 28%, #7a94b0 55%, #6b849f 100%);
66
+ transition: filter 0.25s ease, background 0.35s ease;
67
+ }
68
+
69
+ .apphub-desktop--light .apphub-desktop__wallpaper--drop {
70
+ filter: brightness(1.04) saturate(1.08);
71
+ }
72
+
73
+ .apphub-desktop--light .apphub-desktop__icon-label {
74
+ color: #f8fafc;
75
+ text-shadow:
76
+ 0 1px 2px rgba(15, 23, 42, 0.75),
77
+ 0 0 10px rgba(15, 23, 42, 0.35);
78
+ }
79
+
80
+ .apphub-desktop--light .apphub-desktop__icon:hover {
81
+ background: rgba(255, 255, 255, 0.18);
82
+ border-color: rgba(255, 255, 255, 0.28);
83
+ }
84
+
85
+ .apphub-desktop--light .apphub-desktop__icon-img {
86
+ filter: drop-shadow(0 2px 4px rgba(15, 23, 42, 0.25));
87
+ }
88
+
89
+ .apphub-desktop--light .apphub-desktop__icon--placed.apphub-desktop__icon--dragging {
90
+ background: rgba(255, 255, 255, 0.55);
91
+ border-color: rgba(29, 111, 214, 0.45);
92
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.2);
93
+ }
94
+
95
+ .apphub-desktop__taskbar {
96
+ background: var(--ah-taskbar);
97
+ border-top-color: var(--ah-border);
98
+ }
99
+
100
+ .apphub-desktop--light .apphub-desktop__taskbar {
101
+ backdrop-filter: blur(20px) saturate(1.15);
102
+ box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.5) inset;
103
+ }
104
+
105
+ .apphub-desktop__clock {
106
+ color: var(--ah-text-secondary);
107
+ border-left-color: var(--ah-border-subtle);
108
+ }
109
+
110
+ .apphub-desktop__task {
111
+ color: var(--ah-text-secondary);
112
+ }
113
+
114
+ .apphub-desktop__task:hover {
115
+ background: var(--ah-hover);
116
+ }
117
+
118
+ .apphub-desktop__task.active {
119
+ background: var(--ah-hover);
120
+ }
121
+
122
+ .apphub-desktop__task.active::after {
123
+ background: var(--ah-accent);
124
+ }
125
+
126
+ .apphub-start-btn {
127
+ color: var(--ah-text);
128
+ }
129
+
130
+ .apphub-start-btn:hover,
131
+ .apphub-start-btn--active {
132
+ background: var(--ah-hover);
133
+ }
134
+
135
+ .apphub-start__panel {
136
+ background: var(--ah-surface-elevated);
137
+ border-color: var(--ah-border);
138
+ box-shadow: 0 -4px 32px var(--ah-shadow);
139
+ }
140
+
141
+ .apphub-start__left {
142
+ background: var(--ah-surface-elevated);
143
+ border-right-color: var(--ah-border-subtle);
144
+ }
145
+
146
+ .apphub-start__right {
147
+ background: var(--ah-surface-panel);
148
+ }
149
+
150
+ .apphub-start__search {
151
+ border-color: var(--ah-border);
152
+ background: var(--ah-surface-input);
153
+ color: var(--ah-text);
154
+ }
155
+
156
+ .apphub-start__search::placeholder {
157
+ color: var(--ah-text-muted);
158
+ }
159
+
160
+ .apphub-start__section-label {
161
+ color: var(--ah-text-muted);
162
+ }
163
+
164
+ .apphub-start__list-item {
165
+ color: var(--ah-text);
166
+ }
167
+
168
+ .apphub-start__list-item:hover {
169
+ background: var(--ah-hover);
170
+ }
171
+
172
+ .apphub-start__list-icon-wrap {
173
+ background: var(--ah-hover);
174
+ border-color: var(--ah-border-subtle);
175
+ }
176
+
177
+ .apphub-start__empty {
178
+ color: var(--ah-text-muted);
179
+ }
180
+
181
+ .apphub-start__footer {
182
+ border-top-color: var(--ah-border-subtle);
183
+ }
184
+
185
+ .apphub-start__hero {
186
+ border-color: rgba(37, 99, 235, 0.25);
187
+ background: linear-gradient(135deg, rgba(59, 130, 246, 0.15) 0%, rgba(37, 99, 235, 0.08) 100%);
188
+ color: var(--ah-text);
189
+ }
190
+
191
+ .apphub-desktop--light .apphub-start__hero {
192
+ background: linear-gradient(135deg, rgba(191, 219, 254, 0.85) 0%, rgba(147, 197, 253, 0.55) 100%);
193
+ border-color: rgba(29, 111, 214, 0.35);
194
+ }
195
+
196
+ .apphub-start__hero--guide {
197
+ margin-bottom: 12px;
198
+ background: linear-gradient(135deg, rgba(16, 185, 129, 0.18) 0%, rgba(5, 150, 105, 0.1) 100%);
199
+ border-color: rgba(16, 185, 129, 0.3);
200
+ }
201
+
202
+ .apphub-start__hero--guide:hover {
203
+ background: linear-gradient(135deg, rgba(16, 185, 129, 0.28) 0%, rgba(5, 150, 105, 0.18) 100%);
204
+ border-color: rgba(16, 185, 129, 0.45);
205
+ }
206
+
207
+ .apphub-desktop--light .apphub-start__hero--guide {
208
+ background: linear-gradient(135deg, rgba(167, 243, 208, 0.85) 0%, rgba(110, 231, 183, 0.5) 100%);
209
+ border-color: rgba(5, 150, 105, 0.35);
210
+ }
211
+
212
+ .apphub-desktop--light .apphub-start__hero-icon {
213
+ background: rgba(255, 255, 255, 0.45);
214
+ }
215
+
216
+ .apphub-desktop--light .apphub-start__app-tile {
217
+ background: rgba(255, 255, 255, 0.35);
218
+ border-color: rgba(26, 35, 50, 0.1);
219
+ }
220
+
221
+ .apphub-desktop--light .apphub-start__app-tile:hover {
222
+ background: rgba(255, 255, 255, 0.55);
223
+ border-color: rgba(26, 35, 50, 0.14);
224
+ }
225
+
226
+ .apphub-desktop--light .apphub-start__app-tile-icon {
227
+ background: rgba(255, 255, 255, 0.5);
228
+ }
229
+
230
+ .apphub-desktop--light .apphub-start__search:focus {
231
+ border-color: rgba(29, 111, 214, 0.55);
232
+ box-shadow: 0 0 0 2px rgba(29, 111, 214, 0.15);
233
+ }
234
+
235
+ .apphub-start__hero-hint {
236
+ color: var(--ah-text-muted);
237
+ }
238
+
239
+ .apphub-start__app-tile {
240
+ border-color: var(--ah-border);
241
+ background: var(--ah-hover);
242
+ color: var(--ah-text);
243
+ }
244
+
245
+ .apphub-start__app-tile:hover {
246
+ background: var(--ah-hover-strong);
247
+ border-color: var(--ah-border);
248
+ box-shadow: 0 6px 16px var(--ah-shadow);
249
+ }
250
+
251
+ .apphub-start__app-tile-icon {
252
+ background: var(--ah-hover-strong);
253
+ }
254
+
255
+ .apphub-win {
256
+ border-color: var(--ah-border);
257
+ box-shadow: 0 12px 40px var(--ah-shadow);
258
+ }
259
+
260
+ .apphub-win__titlebar {
261
+ background: var(--ah-titlebar);
262
+ color: var(--ah-titlebar-text);
263
+ }
264
+
265
+ .apphub-win__btn {
266
+ color: var(--ah-titlebar-text);
267
+ }
268
+
269
+ .apphub-win__btn:hover {
270
+ background: var(--ah-hover);
271
+ }
272
+
273
+ .apphub-win__body {
274
+ background: var(--ah-surface);
275
+ color: var(--ah-text);
276
+ }
277
+
278
+ .apphub-store {
279
+ color: var(--ah-text-secondary);
280
+ background: var(--ah-surface);
281
+ }
282
+
283
+ .apphub-store__search {
284
+ border-color: var(--ah-border);
285
+ background: var(--ah-surface-input);
286
+ color: var(--ah-text);
287
+ }
288
+
289
+ .apphub-store__card {
290
+ background: var(--ah-hover);
291
+ border-color: var(--ah-border);
292
+ }
293
+
294
+ .apphub-desktop--light .apphub-store__card {
295
+ background: #f7f9fc;
296
+ border-color: rgba(26, 35, 50, 0.12);
297
+ box-shadow: 0 1px 2px rgba(26, 35, 50, 0.06);
298
+ }
299
+
300
+ .apphub-desktop--light .apphub-store__btn {
301
+ background: #1d6fd6;
302
+ }
303
+
304
+ .apphub-desktop--light .apphub-win {
305
+ box-shadow:
306
+ 0 8px 32px rgba(26, 35, 50, 0.14),
307
+ 0 0 0 1px rgba(26, 35, 50, 0.06);
308
+ }
309
+
310
+ .apphub-desktop--light .apphub-win--active {
311
+ border-color: rgba(29, 111, 214, 0.55);
312
+ box-shadow:
313
+ 0 8px 32px rgba(26, 35, 50, 0.16),
314
+ 0 0 0 1px rgba(29, 111, 214, 0.35);
315
+ }
316
+
317
+ .apphub-desktop--light .apphub-win__btn:hover {
318
+ background: rgba(26, 35, 50, 0.08);
319
+ }
320
+
321
+ .apphub-store__meta p,
322
+ .apphub-store__empty {
323
+ color: var(--ah-text-muted);
324
+ }
325
+
326
+ .apphub-draft-store {
327
+ color: var(--ah-text-secondary);
328
+ background: var(--ah-draft-surface);
329
+ }
330
+
331
+ .apphub-draft-store__hero {
332
+ border-bottom-color: var(--ah-border);
333
+ background: var(--ah-draft-hero-bg);
334
+ }
335
+
336
+ .apphub-draft-store__hero-icon {
337
+ background: var(--ah-draft-icon-bg);
338
+ border-color: var(--ah-draft-card-border);
339
+ }
340
+
341
+ .apphub-draft-store__title {
342
+ color: var(--ah-draft-accent);
343
+ }
344
+
345
+ .apphub-draft-store__intro,
346
+ .apphub-draft-store__msg,
347
+ .apphub-draft-card__desc {
348
+ color: var(--ah-text-muted);
349
+ }
350
+
351
+ .apphub-draft-store__search {
352
+ border-color: var(--ah-border);
353
+ background: var(--ah-surface-input);
354
+ color: var(--ah-text);
355
+ }
356
+
357
+ .apphub-draft-store__empty {
358
+ color: var(--ah-text-muted);
359
+ }
360
+
361
+ .apphub-publish {
362
+ border-color: var(--ah-draft-card-border);
363
+ background: var(--ah-draft-card-bg);
364
+ }
365
+
366
+ .apphub-publish__title {
367
+ color: var(--ah-draft-accent);
368
+ }
369
+
370
+ .apphub-publish__intro {
371
+ color: var(--ah-text-muted);
372
+ }
373
+
374
+ .apphub-publish__tab {
375
+ border-color: var(--ah-border);
376
+ color: var(--ah-text-secondary);
377
+ }
378
+
379
+ .apphub-publish__tab--active {
380
+ background: var(--ah-hover);
381
+ border-color: var(--ah-draft-card-border);
382
+ color: var(--ah-draft-accent);
383
+ }
384
+
385
+ .apphub-publish__input,
386
+ .apphub-publish__file {
387
+ border-color: var(--ah-border);
388
+ background: var(--ah-surface-input);
389
+ color: var(--ah-text);
390
+ }
391
+
392
+ .apphub-publish__submit {
393
+ background: var(--ah-draft-accent);
394
+ color: #fff;
395
+ }
396
+
397
+ .apphub-draft-card {
398
+ background: var(--ah-draft-card-bg);
399
+ border-color: var(--ah-draft-card-border);
400
+ }
401
+
402
+ .apphub-desktop--light .apphub-draft-card {
403
+ box-shadow: 0 2px 10px rgba(26, 35, 50, 0.08);
404
+ }
405
+
406
+ .apphub-draft-card__icon {
407
+ background: var(--ah-draft-icon-bg);
408
+ border-color: var(--ah-border-subtle);
409
+ }
410
+
411
+ .apphub-draft-card__name {
412
+ color: var(--ah-text);
413
+ }
414
+
415
+ .apphub-draft-card__slug {
416
+ color: var(--ah-text-muted);
417
+ }
418
+
419
+ .apphub-draft-card__actions {
420
+ border-top-color: var(--ah-border-subtle);
421
+ }
422
+
423
+ .apphub-draft-card__btn--secondary {
424
+ border-color: var(--ah-border);
425
+ background: var(--ah-surface-input);
426
+ color: var(--ah-text-secondary);
427
+ }
428
+
429
+ .apphub-draft-card__btn--secondary:hover:not(:disabled) {
430
+ border-color: var(--ah-draft-card-border);
431
+ color: var(--ah-draft-accent);
432
+ background: var(--ah-hover);
433
+ }
434
+
435
+ .apphub-desktop--light .apphub-draft-card__btn--primary {
436
+ background: linear-gradient(180deg, #1d6fd6 0%, #1558b0 100%);
437
+ }
438
+
439
+ .apphub-desktop--light .apphub-desktop__taskbar-draft-store {
440
+ color: var(--ah-draft-accent-strong);
441
+ border-color: rgba(180, 130, 20, 0.45);
442
+ background: linear-gradient(180deg, rgba(251, 191, 36, 0.2) 0%, rgba(251, 191, 36, 0.1) 100%);
443
+ }
444
+
445
+ .apphub-runner {
446
+ background: var(--ah-surface);
447
+ }
448
+
449
+ .apphub-runner__msg {
450
+ color: var(--ah-text-muted);
451
+ }
452
+
453
+ .apphub-runner__preflight-title {
454
+ color: var(--ah-text);
455
+ }
456
+
457
+ .apphub-runner__preflight-icon {
458
+ background: var(--ah-surface-elevated);
459
+ }
460
+
461
+ .apphub-runner__preflight-dl {
462
+ background: var(--ah-surface-elevated);
463
+ border-color: var(--ah-border);
464
+ }
465
+
466
+ .apphub-runner__preflight-row dt {
467
+ color: var(--ah-text-muted);
468
+ }
469
+
470
+ .apphub-runner__preflight-row dd {
471
+ color: var(--ah-text);
472
+ }
473
+
474
+ .apphub-runner__btn {
475
+ border-color: var(--ah-border);
476
+ background: var(--ah-surface-elevated);
477
+ color: var(--ah-text);
478
+ }
479
+
480
+ .apphub-runner__btn--primary {
481
+ background: var(--ah-accent);
482
+ border-color: var(--ah-accent);
483
+ color: #fff;
484
+ }
485
+
486
+ .apphub-placeholder {
487
+ color: var(--ah-text);
488
+ }
489
+
490
+ .apphub-placeholder__hint {
491
+ color: var(--ah-text-muted);
492
+ }
493
+
494
+ .apphub-icon-menu {
495
+ border-color: var(--ah-border);
496
+ background: var(--ah-surface-elevated);
497
+ box-shadow: 0 8px 28px var(--ah-shadow);
498
+ }
499
+
500
+ .apphub-icon-menu__item {
501
+ color: var(--ah-text);
502
+ }
503
+
504
+ .apphub-icon-menu__item:hover {
505
+ background: rgba(96, 165, 250, 0.25);
506
+ }
507
+
508
+ .apphub-desktop--light .apphub-icon-menu__item:hover {
509
+ background: rgba(37, 99, 235, 0.12);
510
+ }
511
+
512
+ .apphub-icon-menu__sep {
513
+ background: var(--ah-border-subtle);
514
+ }
515
+
516
+ .apphub-dup-dialog,
517
+ .apphub-icon-info,
518
+ .apphub-icon-rename {
519
+ background: var(--ah-overlay);
520
+ }
521
+
522
+ .apphub-dup-dialog__panel,
523
+ .apphub-icon-info__panel,
524
+ .apphub-icon-rename__panel {
525
+ background: var(--ah-surface);
526
+ border-color: var(--ah-border);
527
+ color: var(--ah-text);
528
+ }
529
+
530
+ .apphub-dup-dialog__title,
531
+ .apphub-icon-info__title,
532
+ .apphub-icon-rename__title {
533
+ color: var(--ah-text);
534
+ }
535
+
536
+ .apphub-dup-dialog__message,
537
+ .apphub-icon-info__row dd {
538
+ color: var(--ah-text-secondary);
539
+ }
540
+
541
+ .apphub-dup-dialog__hint,
542
+ .apphub-icon-info__row dt,
543
+ .apphub-icon-rename__label {
544
+ color: var(--ah-text-muted);
545
+ }
546
+
547
+ .apphub-dup-dialog__btn,
548
+ .apphub-icon-info__btn,
549
+ .apphub-icon-rename__btn {
550
+ border-color: var(--ah-border);
551
+ background: var(--ah-hover);
552
+ color: var(--ah-text);
553
+ }
554
+
555
+ .apphub-icon-rename__input {
556
+ border-color: var(--ah-border);
557
+ background: var(--ah-surface-input);
558
+ color: var(--ah-text);
559
+ }
560
+
561
+ .apphub-icon-info__header {
562
+ background: var(--ah-hover);
563
+ border-bottom-color: var(--ah-border-subtle);
564
+ }
565
+
566
+ .apphub-icon-info__row {
567
+ border-bottom-color: var(--ah-border-subtle);
568
+ }
569
+
570
+ .apphub-desktop-settings__row {
571
+ color: var(--ah-text-secondary);
572
+ }
573
+
574
+ .apphub-desktop-settings__row:hover {
575
+ background: var(--ah-hover);
576
+ }
577
+
578
+ .apphub-desktop--light .apphub-dup-dialog__panel,
579
+ .apphub-desktop--light .apphub-icon-info__panel,
580
+ .apphub-desktop--light .apphub-icon-rename__panel {
581
+ background: #e8ecf2;
582
+ box-shadow: 0 16px 48px rgba(26, 35, 50, 0.2);
583
+ }
584
+
585
+ .apphub-desktop--light .apphub-icon-info__header {
586
+ background: rgba(255, 255, 255, 0.35);
587
+ }
588
+
589
+ .apphub-desktop--light .apphub-dup-dialog__btn--primary,
590
+ .apphub-desktop--light .apphub-icon-rename__btn--primary {
591
+ background: #1d6fd6;
592
+ border-color: #2563eb;
593
+ color: #fff;
594
+ }
595
+
596
+ .apphub-desktop--light .apphub-drop-badge__label {
597
+ color: #f8fafc;
598
+ text-shadow: 0 1px 2px rgba(15, 23, 42, 0.75);
599
+ }
600
+
601
+ .apphub-desktop--light .apphub-drop-layer__hint {
602
+ background: rgba(232, 236, 242, 0.95);
603
+ border-color: rgba(29, 111, 214, 0.4);
604
+ color: #1a2332;
605
+ box-shadow: 0 8px 24px rgba(26, 35, 50, 0.15);
606
+ }
607
+
608
+ .apphub-desktop--light .apphub-drop-layer__glow {
609
+ border-color: rgba(29, 111, 214, 0.45);
610
+ background: rgba(59, 130, 246, 0.08);
611
+ }
612
+
613
+ .apphub-desktop--light .apphub-icon-menu {
614
+ background: #e8ecf2;
615
+ border-color: rgba(26, 35, 50, 0.12);
616
+ }
@@ -0,0 +1,43 @@
1
+ export const ICON_GRID = {
2
+ cellW: 96,
3
+ cellH: 96,
4
+ paddingX: 16,
5
+ paddingY: 16,
6
+ }
7
+
8
+ export function snapPoint(x, y, enabled = true) {
9
+ if (!enabled) return { x: Math.round(x), y: Math.round(y) }
10
+ const { cellW, cellH, paddingX, paddingY } = ICON_GRID
11
+ const col = Math.max(0, Math.round((x - paddingX) / cellW))
12
+ const row = Math.max(0, Math.round((y - paddingY) / cellH))
13
+ return {
14
+ x: paddingX + col * cellW,
15
+ y: paddingY + row * cellH,
16
+ }
17
+ }
18
+
19
+ export function clampPointToLayer(x, y, layerWidth, layerHeight) {
20
+ return {
21
+ x: Math.max(8, Math.min(x, Math.max(8, layerWidth - 96))),
22
+ y: Math.max(8, Math.min(y, Math.max(8, layerHeight - 96))),
23
+ }
24
+ }
25
+
26
+ /** Next free grid cell for a new desktop icon. */
27
+ export function nextIconGridSlot(occupied, layerWidth, layerHeight) {
28
+ const { cellW, cellH, paddingX, paddingY } = ICON_GRID
29
+ const cols = Math.max(1, Math.floor((layerWidth - paddingX) / cellW))
30
+ const maxRows = Math.max(1, Math.floor((layerHeight - paddingY) / cellH))
31
+ const taken = new Set((occupied ?? []).map((p) => `${p.x},${p.y}`))
32
+
33
+ for (let row = 0; row < maxRows; row += 1) {
34
+ for (let col = 0; col < cols; col += 1) {
35
+ const x = paddingX + col * cellW
36
+ const y = paddingY + row * cellH
37
+ if (!taken.has(`${x},${y}`)) return { x, y }
38
+ }
39
+ }
40
+
41
+ const n = occupied?.length ?? 0
42
+ return snapPoint(paddingX + (n % cols) * cellW, paddingY + Math.floor(n / cols) * cellH, true)
43
+ }