@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,224 @@
1
+ <template>
2
+ <div
3
+ class="apphub-win"
4
+ :class="{
5
+ 'apphub-win--active': active,
6
+ 'apphub-win--fullscreen': window.display === 'fullscreen',
7
+ 'apphub-win--resizable': window.display !== 'fullscreen',
8
+ }"
9
+ :style="frameStyle"
10
+ @mousedown="onFocus"
11
+ >
12
+ <header
13
+ class="apphub-win__titlebar"
14
+ @mousedown.stop="onDragStart"
15
+ @dblclick.stop="onTitlebarDblClick"
16
+ >
17
+ <span class="apphub-win__icon">{{ window.icon }}</span>
18
+ <span class="apphub-win__title">{{ window.title }}</span>
19
+ <div class="apphub-win__controls" @mousedown.stop @dblclick.stop>
20
+ <button
21
+ type="button"
22
+ class="apphub-win__btn"
23
+ :title="window.display === 'fullscreen' ? labels.window_restore : labels.window_fullscreen"
24
+ @mousedown.stop
25
+ @click.stop="onToggleDisplay"
26
+ >
27
+ {{ window.display === 'fullscreen' ? '⤢' : '⛶' }}
28
+ </button>
29
+ <button type="button" class="apphub-win__btn" :title="labels.window_minimize" @mousedown.stop @click.stop="onMinimize">—</button>
30
+ <button type="button" class="apphub-win__btn apphub-win__btn--close" :title="labels.window_close" @mousedown.stop @click.stop="onClose">×</button>
31
+ </div>
32
+ </header>
33
+ <section class="apphub-win__body">
34
+ <component :is="window.component" v-bind="window.props" />
35
+ </section>
36
+
37
+ <template v-if="window.display !== 'fullscreen'">
38
+ <div
39
+ v-for="edge in resizeEdges"
40
+ :key="edge"
41
+ class="apphub-win__resize"
42
+ :class="`apphub-win__resize--${edge}`"
43
+ @mousedown.stop="onResizeStart(edge, $event)"
44
+ />
45
+ </template>
46
+ </div>
47
+ </template>
48
+
49
+ <script setup>
50
+ import { computed, inject, onBeforeUnmount, ref } from 'vue'
51
+ import { resolveLang } from '../../../i18n/resolveLang.js'
52
+ import { t } from '../../../i18n/index.js'
53
+ import { useWindowManager } from '../composables/useWindowManager.js'
54
+ import { applyWindowResize, clampWindowToWorkArea } from '../utils/windowLayout.js'
55
+
56
+ const DESKTOP_HOST_KEY = 'apphubDesktopHost'
57
+ const resizeEdges = ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw']
58
+
59
+ const props = defineProps({
60
+ window: { type: Object, required: true },
61
+ active: { type: Boolean, default: false },
62
+ })
63
+
64
+ const emit = defineEmits(['session-change'])
65
+
66
+ const lang = computed(() => resolveLang(inject('apphubOptions', {})?.language, 'vi'))
67
+ const workAreaRef = inject(DESKTOP_HOST_KEY, null)
68
+
69
+ const labels = computed(() => ({
70
+ window_close: t('window_close', lang.value),
71
+ window_minimize: t('window_minimize', lang.value),
72
+ window_fullscreen: t('window_fullscreen', lang.value),
73
+ window_restore: t('window_restore', lang.value),
74
+ }))
75
+
76
+ const wm = useWindowManager()
77
+ const drag = ref(null)
78
+ const resize = ref(null)
79
+
80
+ const frameStyle = computed(() => ({
81
+ width: `${props.window.width}px`,
82
+ height: `${props.window.height}px`,
83
+ left: `${props.window.x}px`,
84
+ top: `${props.window.y}px`,
85
+ zIndex: String(props.window.zIndex),
86
+ }))
87
+
88
+ function getPointerInWorkArea(clientX, clientY) {
89
+ const el = workAreaRef?.value
90
+ if (!el) return { x: clientX, y: clientY }
91
+ const rect = el.getBoundingClientRect()
92
+ return { x: clientX - rect.left, y: clientY - rect.top }
93
+ }
94
+
95
+ function onFocus() {
96
+ wm?.focusWindow(props.window.id)
97
+ }
98
+
99
+ function notifySession() {
100
+ emit('session-change')
101
+ }
102
+
103
+ function onClose() {
104
+ wm?.closeWindow(props.window.id)
105
+ notifySession()
106
+ }
107
+
108
+ function onMinimize() {
109
+ wm?.minimizeWindow(props.window.id)
110
+ notifySession()
111
+ }
112
+
113
+ function onToggleDisplay() {
114
+ wm?.toggleWindowDisplay(props.window.id)
115
+ notifySession()
116
+ }
117
+
118
+ function onTitlebarDblClick(event) {
119
+ if (event.target.closest('button, .apphub-win__controls')) return
120
+ cleanupPointerHandlers()
121
+ wm?.toggleWindowDisplay(props.window.id)
122
+ notifySession()
123
+ }
124
+
125
+ function onDragStart(event) {
126
+ if (!wm) return
127
+ if (event.target.closest('button, .apphub-win__controls')) return
128
+
129
+ const win = wm.state.windows.find((w) => w.id === props.window.id)
130
+ if (!win) return
131
+
132
+ if (win.display === 'fullscreen') {
133
+ const pointer = getPointerInWorkArea(event.clientX, event.clientY)
134
+ wm.restoreWindowFromFullscreen(props.window.id, {
135
+ pointerX: pointer.x,
136
+ pointerY: pointer.y,
137
+ offsetX: event.offsetX,
138
+ offsetY: event.offsetY,
139
+ })
140
+ }
141
+
142
+ const current = wm.state.windows.find((w) => w.id === props.window.id)
143
+ if (!current || current.display === 'fullscreen') return
144
+
145
+ drag.value = {
146
+ id: props.window.id,
147
+ startX: event.clientX,
148
+ startY: event.clientY,
149
+ origX: current.x,
150
+ origY: current.y,
151
+ }
152
+ window.addEventListener('mousemove', onDragMove)
153
+ window.addEventListener('mouseup', onDragEnd)
154
+ }
155
+
156
+ function onDragMove(event) {
157
+ if (!drag.value) return
158
+ const win = wm.state.windows.find((w) => w.id === drag.value.id)
159
+ if (!win) return
160
+ win.x = drag.value.origX + (event.clientX - drag.value.startX)
161
+ win.y = drag.value.origY + (event.clientY - drag.value.startY)
162
+ clampWindowToWorkArea(win)
163
+ }
164
+
165
+ function onDragEnd() {
166
+ window.removeEventListener('mousemove', onDragMove)
167
+ window.removeEventListener('mouseup', onDragEnd)
168
+ if (drag.value) {
169
+ const win = wm.state.windows.find((w) => w.id === drag.value.id)
170
+ if (win) {
171
+ clampWindowToWorkArea(win)
172
+ wm?.clearSnap(props.window.id)
173
+ }
174
+ wm?.saveWindowLayoutState(props.window.id)
175
+ notifySession()
176
+ }
177
+ drag.value = null
178
+ }
179
+
180
+ function onResizeStart(edge, event) {
181
+ if (!wm || event.button !== 0) return
182
+ const win = wm.state.windows.find((w) => w.id === props.window.id)
183
+ if (!win || win.display === 'fullscreen') return
184
+
185
+ wm.focusWindow(props.window.id)
186
+ wm.clearSnap(props.window.id)
187
+ resize.value = {
188
+ id: props.window.id,
189
+ edge,
190
+ startX: event.clientX,
191
+ startY: event.clientY,
192
+ }
193
+ window.addEventListener('mousemove', onResizeMove)
194
+ window.addEventListener('mouseup', onResizeEnd)
195
+ }
196
+
197
+ function onResizeMove(event) {
198
+ if (!resize.value) return
199
+ const win = wm.state.windows.find((w) => w.id === resize.value.id)
200
+ if (!win) return
201
+ const dx = event.clientX - resize.value.startX
202
+ const dy = event.clientY - resize.value.startY
203
+ applyWindowResize(win, resize.value.edge, dx, dy)
204
+ resize.value.startX = event.clientX
205
+ resize.value.startY = event.clientY
206
+ }
207
+
208
+ function onResizeEnd() {
209
+ window.removeEventListener('mousemove', onResizeMove)
210
+ window.removeEventListener('mouseup', onResizeEnd)
211
+ if (resize.value) {
212
+ wm?.saveWindowLayoutState(props.window.id)
213
+ notifySession()
214
+ }
215
+ resize.value = null
216
+ }
217
+
218
+ function cleanupPointerHandlers() {
219
+ onDragEnd()
220
+ onResizeEnd()
221
+ }
222
+
223
+ onBeforeUnmount(cleanupPointerHandlers)
224
+ </script>