@owdproject/core 3.1.4-beta.0 → 3.2.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.
- package/README.md +6 -6
- package/bin/cli.js +395 -0
- package/bin/desktop.js +5 -0
- package/bin/lib/catalog.js +293 -0
- package/bin/lib/config.js +109 -0
- package/bin/lib/desktopConfig.js +56 -0
- package/bin/lib/generateTemplate.js +389 -0
- package/bin/lib/install.js +408 -0
- package/bin/lib/migrateModulePlayground.config.mjs +164 -0
- package/bin/lib/migrateModulePlayground.mjs +313 -0
- package/bin/lib/npmVersions.js +124 -0
- package/bin/lib/playgroundContext.js +188 -0
- package/bin/lib/scaffold.js +197 -0
- package/bin/lib/status.js +289 -0
- package/bin/lib/validateModule.js +683 -0
- package/bin/lib/workspace.js +182 -0
- package/bin/owd.js +2 -25
- package/bin/tui.js +1379 -0
- package/dist/module.d.mts +13 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +219 -0
- package/dist/types.d.mts +7 -0
- package/module.ts +53 -19
- package/package.json +78 -22
- package/runtime/components/Core/Application/CoreApplicationRender.vue +3 -1
- package/runtime/components/Core/Application/CoreApplicationWindowsRender.vue +28 -7
- package/runtime/components/Core/Desktop/CoreDesktop.vue +11 -7
- package/runtime/components/Core/Window/CoreWindow.vue +45 -9
- package/runtime/components/Core/Window/CoreWindowNav.vue +26 -8
- package/runtime/composables/useApplicationEntries.ts +1 -1
- package/runtime/composables/useApplicationManager.ts +282 -4
- package/runtime/composables/useDesktopManager.ts +46 -4
- package/runtime/composables/useOwdDialogs.ts +13 -0
- package/runtime/composables/useTerminalManager.ts +62 -3
- package/runtime/composables/useWorkspaceOverview.ts +41 -0
- package/runtime/core/controllers/ApplicationController.ts +120 -30
- package/runtime/core/controllers/WindowController.ts +5 -10
- package/runtime/dialogs/owdDialogProvider.ts +81 -0
- package/runtime/plugins/01.owd-dialogs-fallback.ts +15 -0
- package/runtime/stores/storeApplicationMeta.ts +56 -12
- package/runtime/stores/storeDesktop.ts +79 -0
- package/runtime/stores/storeDesktopDefaultApps.ts +53 -0
- package/runtime/stores/storeDesktopExplorer.ts +74 -0
- package/runtime/stores/storeDesktopWorkspace.ts +14 -2
- package/runtime/utils/captureElementToCanvas.ts +21 -0
- package/runtime/utils/explorerEntryPath.ts +10 -0
- package/runtime/utils/resolveDesktopConfigPath.ts +52 -0
- package/runtime/utils/validateOwdUserConfig.ts +44 -0
- package/types/index.d.ts +64 -12
- package/CHANGELOG.md +0 -25
- package/project.json +0 -4
- package/runtime/composables/useClipboardFs.ts +0 -25
- package/runtime/core/managers/ApplicationManager.ts +0 -281
- package/runtime/core/managers/DesktopManager.ts +0 -47
- package/runtime/core/managers/TerminalManager.ts +0 -48
- package/runtime/stores/storeApplication.ts +0 -235
- package/test/basic.test.ts +0 -15
- package/test/fixtures/basic/app.vue +0 -5
- package/test/fixtures/basic/nuxt.config.ts +0 -5
- package/test/fixtures/basic/package.json +0 -5
- package/tsconfig.app.json +0 -31
- package/tsconfig.json +0 -12
- package/tsconfig.spec.json +0 -37
- package/vitest.config.ts +0 -24
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, provide } from 'vue'
|
|
3
3
|
import { computed } from '@vue/reactivity'
|
|
4
|
-
import {
|
|
4
|
+
import { useAppConfig } from 'nuxt/app'
|
|
5
5
|
import { handleWindowControllerProps } from '@owdproject/core/runtime/utils/utilWindow'
|
|
6
|
+
import { useDesktopWorkspaceStore } from '../../../stores/storeDesktopWorkspace'
|
|
6
7
|
|
|
7
8
|
const props = defineProps<{
|
|
8
9
|
window?: IWindowController
|
|
9
10
|
content?: WindowContent
|
|
10
11
|
}>()
|
|
11
12
|
|
|
13
|
+
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
14
|
+
|
|
12
15
|
const emit = defineEmits([
|
|
13
16
|
'resize:start',
|
|
14
17
|
'resize:move',
|
|
@@ -27,7 +30,7 @@ const emit = defineEmits([
|
|
|
27
30
|
'toggle-maximize',
|
|
28
31
|
])
|
|
29
32
|
|
|
30
|
-
const
|
|
33
|
+
const appConfig = useAppConfig()
|
|
31
34
|
const windowController: IWindowController = handleWindowControllerProps(
|
|
32
35
|
props.window,
|
|
33
36
|
)
|
|
@@ -115,6 +118,36 @@ const classes = computed(() => {
|
|
|
115
118
|
|
|
116
119
|
return list
|
|
117
120
|
})
|
|
121
|
+
|
|
122
|
+
/** While workspace overview is open, disable vue-resizable chrome drag and use native HTML5 drag to move windows between desktops. */
|
|
123
|
+
const workspaceChromeDragSelector = computed(() => {
|
|
124
|
+
if (desktopWorkspaceStore.overview) {
|
|
125
|
+
return '.owd-window-overview-drag-none'
|
|
126
|
+
}
|
|
127
|
+
return windowController?.isDraggable
|
|
128
|
+
? '.owd-window-nav__draggable'
|
|
129
|
+
: '.owd-window-nav__draggable-none'
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
function onOverviewNativeDragStart(e: DragEvent) {
|
|
133
|
+
if (!desktopWorkspaceStore.overview || !windowController) return
|
|
134
|
+
e.stopPropagation()
|
|
135
|
+
e.dataTransfer?.setData('text/plain', windowController.state.id)
|
|
136
|
+
e.dataTransfer!.effectAllowed = 'move'
|
|
137
|
+
try {
|
|
138
|
+
const img = new Image()
|
|
139
|
+
img.src =
|
|
140
|
+
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
|
|
141
|
+
e.dataTransfer?.setDragImage(img, 0, 0)
|
|
142
|
+
} catch {
|
|
143
|
+
/* noop */
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** `fit-parent` clamps drag/resize to the parent box — wrong for viewport-fixed shells (Win11, GNOME). */
|
|
148
|
+
const shouldFitParent = computed(
|
|
149
|
+
() => appConfig.desktop.windows.position !== 'fixed',
|
|
150
|
+
)
|
|
118
151
|
</script>
|
|
119
152
|
|
|
120
153
|
<template>
|
|
@@ -130,7 +163,7 @@ const classes = computed(() => {
|
|
|
130
163
|
:left="windowController?.position?.x"
|
|
131
164
|
:top="windowController?.position?.y"
|
|
132
165
|
:active="windowController?.isResizable ? undefined : []"
|
|
133
|
-
fit-parent
|
|
166
|
+
:fit-parent="shouldFitParent"
|
|
134
167
|
@drag:start="onWindowDragStart"
|
|
135
168
|
@drag:move="onWindowDragMove"
|
|
136
169
|
@drag:end="onWindowDragEnd"
|
|
@@ -138,20 +171,23 @@ const classes = computed(() => {
|
|
|
138
171
|
@resize:move="onWindowResizeMove"
|
|
139
172
|
@resize:end="onWindowResizeEnd"
|
|
140
173
|
:style="{ zIndex: windowController?.position?.z }"
|
|
141
|
-
:drag-selector="
|
|
142
|
-
|
|
143
|
-
? '.owd-window-nav__draggable'
|
|
144
|
-
: '.owd-window-nav__draggable-none'
|
|
145
|
-
"
|
|
174
|
+
:drag-selector="workspaceChromeDragSelector"
|
|
175
|
+
:draggable="desktopWorkspaceStore.overview"
|
|
146
176
|
@pointerdown="onWindowPointerDown"
|
|
177
|
+
@dragstart="onOverviewNativeDragStart"
|
|
147
178
|
>
|
|
148
179
|
<slot />
|
|
149
180
|
</vue-resizable>
|
|
150
181
|
</template>
|
|
151
182
|
|
|
152
183
|
<style scoped lang="scss">
|
|
184
|
+
/* vue-resizable sets `.resizable-component { position: relative }` — override so desktop geometry stays consistent */
|
|
185
|
+
.owd-window.resizable-component {
|
|
186
|
+
position: v-bind('appConfig.desktop.windows.position') !important;
|
|
187
|
+
}
|
|
188
|
+
|
|
153
189
|
.owd-window {
|
|
154
|
-
position: v-bind('
|
|
190
|
+
position: v-bind('appConfig.desktop.windows.position');
|
|
155
191
|
|
|
156
192
|
&--dragging,
|
|
157
193
|
&--resizing {
|
|
@@ -14,10 +14,7 @@ const classes = computed(() => {
|
|
|
14
14
|
list.push('owd-window-nav--active')
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
if (
|
|
18
|
-
typeof windowController?.state.focused === 'undefined' ||
|
|
19
|
-
!!windowController?.state.focused
|
|
20
|
-
) {
|
|
17
|
+
if (windowController?.state.focused) {
|
|
21
18
|
list.push('owd-window-nav--focused')
|
|
22
19
|
}
|
|
23
20
|
|
|
@@ -34,15 +31,36 @@ const classes = computed(() => {
|
|
|
34
31
|
</template>
|
|
35
32
|
|
|
36
33
|
<style lang="scss">
|
|
34
|
+
/**
|
|
35
|
+
* Title/icon sit above the drag layer in DOM order; use pointer-events so
|
|
36
|
+
* mousedown reaches `.owd-window-nav__draggable` for vue-resizable. Window
|
|
37
|
+
* controls stay clickable.
|
|
38
|
+
*/
|
|
37
39
|
.owd-window-nav {
|
|
38
40
|
position: relative;
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: stretch;
|
|
43
|
+
width: 100%;
|
|
44
|
+
min-height: 0;
|
|
39
45
|
|
|
40
46
|
&__draggable {
|
|
41
47
|
position: absolute;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
inset: 0;
|
|
49
|
+
z-index: 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
> :not(.owd-window-nav__draggable) {
|
|
53
|
+
position: relative;
|
|
54
|
+
z-index: 2;
|
|
55
|
+
pointer-events: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
> .owd-window-nav__btn-group {
|
|
59
|
+
pointer-events: auto;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
> .owd-window-nav__interactive {
|
|
63
|
+
pointer-events: auto;
|
|
46
64
|
}
|
|
47
65
|
}
|
|
48
66
|
</style>
|
|
@@ -21,7 +21,7 @@ export function useApplicationEntries() {
|
|
|
21
21
|
visibility: Visibility = 'primary',
|
|
22
22
|
): Ref<ApplicationEntryWithInherited[]> {
|
|
23
23
|
return computed(() => {
|
|
24
|
-
const currentEntries = [...applicationManager.appsEntries]
|
|
24
|
+
const currentEntries = [...applicationManager.appsEntries.value]
|
|
25
25
|
|
|
26
26
|
// filtering
|
|
27
27
|
const filtered =
|
|
@@ -1,7 +1,285 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { reactive, markRaw, computed } from 'vue'
|
|
2
|
+
import { ApplicationController } from '../core/controllers/ApplicationController'
|
|
3
|
+
import { normalizeApplicationConfig } from '../utils/utilApp'
|
|
4
|
+
import { debugLog } from '../utils/utilDebug'
|
|
5
|
+
import * as shellwords from 'shellwords'
|
|
6
|
+
import getopts from "getopts"
|
|
2
7
|
|
|
3
|
-
const
|
|
8
|
+
const apps = reactive(new Map<string, IApplicationController>())
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Application Manager Composable (Singleton)
|
|
12
|
+
*/
|
|
13
|
+
export function useApplicationManager() {
|
|
14
|
+
/**
|
|
15
|
+
* Define new application
|
|
16
|
+
*
|
|
17
|
+
* @param id
|
|
18
|
+
* @param config
|
|
19
|
+
*/
|
|
20
|
+
async function defineApp(id: string, config: ApplicationConfig) {
|
|
21
|
+
if (isAppDefined(id)) {
|
|
22
|
+
debugLog(`App "${id}" is already defined`)
|
|
23
|
+
return getAppById(id)!
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const normalizedConfig = normalizeApplicationConfig(config)
|
|
27
|
+
const applicationConfig = markRaw(normalizedConfig)
|
|
28
|
+
|
|
29
|
+
const applicationController: IApplicationController = new ApplicationController(id, applicationConfig)
|
|
30
|
+
await applicationController.initApplication()
|
|
31
|
+
|
|
32
|
+
apps.set(id, markRaw(applicationController))
|
|
33
|
+
|
|
34
|
+
return applicationController
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Check if app has been defined
|
|
39
|
+
*
|
|
40
|
+
* @param {string} id
|
|
41
|
+
*/
|
|
42
|
+
function isAppDefined(id: string) {
|
|
43
|
+
return getAppById(id)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Retrieves an app instance by its unique identifier
|
|
48
|
+
*
|
|
49
|
+
* @param {string} id
|
|
50
|
+
*/
|
|
51
|
+
function getAppById(id: string) {
|
|
52
|
+
return apps.get(id)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check if app is running
|
|
57
|
+
*
|
|
58
|
+
* @param {string} id
|
|
59
|
+
*/
|
|
60
|
+
function isAppRunning(id: string) {
|
|
61
|
+
if (!isAppDefined(id)) {
|
|
62
|
+
throw Error(`App "${id}" is not defined`)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const applicationController = getAppById(id)!
|
|
66
|
+
return applicationController.isRunning
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Launch app entry
|
|
71
|
+
*
|
|
72
|
+
* @param id
|
|
73
|
+
* @param entryKey
|
|
74
|
+
* @param argument
|
|
75
|
+
*/
|
|
76
|
+
async function launchAppEntry(
|
|
77
|
+
id: string,
|
|
78
|
+
entryKey: string,
|
|
79
|
+
argument: string = ''
|
|
80
|
+
): Promise<IApplicationController | undefined | void> {
|
|
81
|
+
if (!isAppDefined(id)) {
|
|
82
|
+
throw Error(`App "${id}" is not defined`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const applicationController = getAppById(id)!
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
applicationController.config.entries &&
|
|
89
|
+
!applicationController.config.entries.hasOwnProperty(entryKey)
|
|
90
|
+
) {
|
|
91
|
+
throw Error(`App entry "${entryKey}" is not defined in ${id} application`)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const entry: ApplicationEntry = applicationController.config.entries[entryKey]!
|
|
95
|
+
|
|
96
|
+
if (argument) argument = ` ${argument}`
|
|
97
|
+
|
|
98
|
+
await execAppCommand(applicationController.id, entry.command + argument)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Run app command
|
|
103
|
+
*
|
|
104
|
+
* @param id
|
|
105
|
+
* @param rawCommand
|
|
106
|
+
*/
|
|
107
|
+
async function execAppCommand(
|
|
108
|
+
id: string,
|
|
109
|
+
rawCommand: string,
|
|
110
|
+
): Promise<CommandOutput> {
|
|
111
|
+
if (!isAppDefined(id)) {
|
|
112
|
+
throw Error(`App "${id}" is not defined`)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const applicationController = getAppById(id)!
|
|
116
|
+
|
|
117
|
+
const args = shellwords.split(rawCommand)
|
|
118
|
+
const parsed = getopts(args)
|
|
119
|
+
const command: string = parsed._[0]
|
|
120
|
+
|
|
121
|
+
if (
|
|
122
|
+
applicationController.config.commands &&
|
|
123
|
+
!applicationController.config.commands.hasOwnProperty(command)
|
|
124
|
+
) {
|
|
125
|
+
throw Error(
|
|
126
|
+
`App command "${command}" is not defined in ${id} application`,
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const commandFn: any = applicationController.config.commands![command]
|
|
131
|
+
|
|
132
|
+
const commandOutput = await commandFn(applicationController, parsed)
|
|
133
|
+
|
|
134
|
+
applicationController.setRunning(true)
|
|
135
|
+
|
|
136
|
+
return commandOutput
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Close application
|
|
141
|
+
*
|
|
142
|
+
* @param id
|
|
143
|
+
*/
|
|
144
|
+
function closeApp(id: string) {
|
|
145
|
+
if (!isAppDefined(id)) {
|
|
146
|
+
throw Error(`App "${id}" is not defined`)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const applicationController = getAppById(id)!
|
|
150
|
+
|
|
151
|
+
applicationController.closeAllWindows()
|
|
152
|
+
applicationController.setRunning(false)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Array of available menu entries for system bars, docks
|
|
157
|
+
*/
|
|
158
|
+
const appsEntries = computed(() => {
|
|
159
|
+
const entries: ApplicationEntryWithInherited[] = []
|
|
160
|
+
|
|
161
|
+
for (const applicationController of apps.values()) {
|
|
162
|
+
if (!applicationController.config.entries) {
|
|
163
|
+
continue
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (const entryKey of Object.keys(applicationController.config.entries)) {
|
|
167
|
+
const entry = applicationController.config.entries[entryKey]!
|
|
168
|
+
|
|
169
|
+
entries.push({
|
|
170
|
+
application: applicationController,
|
|
171
|
+
title: entry.title ?? applicationController.config.title,
|
|
172
|
+
icon: entry.icon ?? applicationController.config.icon,
|
|
173
|
+
category: entry.category ?? applicationController.config.category,
|
|
174
|
+
visibility: entry.visibility ?? 'primary',
|
|
175
|
+
command: entry.command,
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return entries
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Array of opened windows for system bars, docks
|
|
185
|
+
*/
|
|
186
|
+
const windowsOpened = computed(() => {
|
|
187
|
+
const windows = new Map<string, IWindowController>()
|
|
188
|
+
|
|
189
|
+
for (const applicationController of apps.values()) {
|
|
190
|
+
if (
|
|
191
|
+
!applicationController.isRunning &&
|
|
192
|
+
applicationController.openWindowCount.value === 0
|
|
193
|
+
) {
|
|
194
|
+
continue
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
for (const [windowId, window] of applicationController.windows) {
|
|
198
|
+
windows.set(windowId, window)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return windows
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Array of running applications
|
|
207
|
+
*/
|
|
208
|
+
const appsRunning = computed(() => {
|
|
209
|
+
const runningApps: IApplicationController[] = []
|
|
210
|
+
|
|
211
|
+
for (const applicationController of apps.values()) {
|
|
212
|
+
const openCount = applicationController.openWindowCount.value
|
|
213
|
+
if (applicationController.isRunning || openCount > 0) {
|
|
214
|
+
runningApps.push(applicationController)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return runningApps
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
function getWindowOpenedId(windowId: string) {
|
|
222
|
+
for (const window of windowsOpened.value.values()) {
|
|
223
|
+
if (window.state.id === windowId) {
|
|
224
|
+
return window
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Gets all unique categories from the installed apps
|
|
231
|
+
*/
|
|
232
|
+
const appCategories = computed(() => {
|
|
233
|
+
const categories = new Set<string>()
|
|
234
|
+
|
|
235
|
+
for (const applicationController of apps.values()) {
|
|
236
|
+
if (applicationController.config.category) {
|
|
237
|
+
categories.add(applicationController.config.category)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return Array.from(categories).sort()
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Gets the apps ordered by category
|
|
246
|
+
*/
|
|
247
|
+
const appsByCategory = computed(() => {
|
|
248
|
+
const categorizedApps: {
|
|
249
|
+
[category: string]: IApplicationController[]
|
|
250
|
+
} = {}
|
|
251
|
+
|
|
252
|
+
for (const applicationController of apps.values()) {
|
|
253
|
+
const category = applicationController.config.category || 'other'
|
|
254
|
+
if (!categorizedApps[category]) {
|
|
255
|
+
categorizedApps[category] = []
|
|
256
|
+
}
|
|
257
|
+
categorizedApps[category].push(applicationController)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
for (const category in categorizedApps) {
|
|
261
|
+
categorizedApps[category].sort((a, b) =>
|
|
262
|
+
a.config.title.localeCompare(b.config.title),
|
|
263
|
+
)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return categorizedApps
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
return {
|
|
270
|
+
defineApp,
|
|
271
|
+
isAppDefined,
|
|
272
|
+
getAppById,
|
|
273
|
+
isAppRunning,
|
|
274
|
+
launchAppEntry,
|
|
275
|
+
execAppCommand,
|
|
276
|
+
closeApp,
|
|
277
|
+
getWindowOpenedId,
|
|
278
|
+
apps,
|
|
279
|
+
appsEntries,
|
|
280
|
+
appsRunning,
|
|
281
|
+
windowsOpened,
|
|
282
|
+
appCategories,
|
|
283
|
+
appsByCategory,
|
|
284
|
+
}
|
|
7
285
|
}
|
|
@@ -1,7 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { computed } from 'vue'
|
|
2
|
+
import { useAppConfig } from 'nuxt/app'
|
|
3
|
+
import { deepMerge } from '../utils/utilCommon'
|
|
4
|
+
import { useDesktopStore } from '../stores/storeDesktop'
|
|
5
|
+
import { useDesktopDefaultAppsStore } from '../stores/storeDesktopDefaultApps'
|
|
4
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Desktop Manager composable (singleton pattern via Pinia + app config).
|
|
9
|
+
* Agnostic of any theme: merges runtime shell config and exposes default-app routing.
|
|
10
|
+
*/
|
|
5
11
|
export function useDesktopManager() {
|
|
6
|
-
|
|
12
|
+
const appConfig = useAppConfig()
|
|
13
|
+
const desktopStore = useDesktopStore()
|
|
14
|
+
const defaultAppsStore = useDesktopDefaultAppsStore()
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Merges and sets the desktop config at runtime (shell geometry, feature flags, etc.).
|
|
18
|
+
*/
|
|
19
|
+
function setConfig(newConfig: DesktopConfig) {
|
|
20
|
+
appConfig.desktop = deepMerge(
|
|
21
|
+
appConfig.desktop,
|
|
22
|
+
newConfig,
|
|
23
|
+
) as DesktopConfig
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Map of feature name → default app handler (e.g. terminal, browser). */
|
|
27
|
+
const defaultApps = computed(
|
|
28
|
+
() => desktopStore.state.defaultApps,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
function getDefaultApp(feature: string) {
|
|
32
|
+
return defaultAppsStore.getDefaultApp(feature)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function setDefaultApp(
|
|
36
|
+
feature: string,
|
|
37
|
+
application: IApplicationController,
|
|
38
|
+
entry: string,
|
|
39
|
+
) {
|
|
40
|
+
defaultAppsStore.setDefaultApp(feature, application, entry)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
setConfig,
|
|
45
|
+
defaultApps,
|
|
46
|
+
getDefaultApp,
|
|
47
|
+
setDefaultApp,
|
|
48
|
+
}
|
|
7
49
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { inject } from 'vue'
|
|
2
|
+
import {
|
|
3
|
+
OWD_DIALOG_PROVIDER_KEY,
|
|
4
|
+
createBrowserFallbackDialogProvider,
|
|
5
|
+
type OwdDialogProvider,
|
|
6
|
+
} from '../dialogs/owdDialogProvider'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns the active desktop dialog provider (theme) or a documented browser fallback.
|
|
10
|
+
*/
|
|
11
|
+
export function useOwdDialogs(): OwdDialogProvider {
|
|
12
|
+
return inject(OWD_DIALOG_PROVIDER_KEY, null) ?? createBrowserFallbackDialogProvider()
|
|
13
|
+
}
|
|
@@ -1,7 +1,66 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useApplicationManager } from './useApplicationManager'
|
|
2
|
+
import { debugLog } from '../utils/utilDebug'
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
+
const commands = new Map<string, TerminalCommand>()
|
|
4
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Terminal Manager Composable (Singleton)
|
|
8
|
+
*/
|
|
5
9
|
export function useTerminalManager() {
|
|
6
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Add a new terminal command
|
|
12
|
+
*
|
|
13
|
+
* @param command
|
|
14
|
+
*/
|
|
15
|
+
const addCommand = (command: TerminalCommand) => {
|
|
16
|
+
for (const existingCommand of commands.keys()) {
|
|
17
|
+
if (
|
|
18
|
+
existingCommand.startsWith(command.name) ||
|
|
19
|
+
command.name.startsWith(existingCommand)
|
|
20
|
+
) {
|
|
21
|
+
throw new Error(`Command prefix conflict with "${existingCommand}"`)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
commands.set(command.name, command)
|
|
26
|
+
debugLog(`Registered terminal command: ${command.name} → ${command.applicationId}`)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* List all registered command names
|
|
31
|
+
*/
|
|
32
|
+
const listCommands = (): string[] => {
|
|
33
|
+
return Array.from(commands.keys())
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Execute a terminal command
|
|
38
|
+
*
|
|
39
|
+
* @param input
|
|
40
|
+
*/
|
|
41
|
+
const execCommand = async (input: string): Promise<CommandOutput | void> => {
|
|
42
|
+
const applicationManager = useApplicationManager()
|
|
43
|
+
|
|
44
|
+
const [name, ...args] = input.trim().split(/\s+/)
|
|
45
|
+
|
|
46
|
+
if (!name) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!commands.has(name)) {
|
|
51
|
+
return {
|
|
52
|
+
message: `Command "${name}" not found`,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const application = commands.get(name)!
|
|
57
|
+
|
|
58
|
+
return applicationManager.execAppCommand(application.applicationId, input)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
addCommand,
|
|
63
|
+
listCommands,
|
|
64
|
+
execCommand,
|
|
65
|
+
}
|
|
7
66
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useEventListener } from '@vueuse/core'
|
|
2
|
+
import { useApplicationManager } from './useApplicationManager'
|
|
3
|
+
import { useDesktopWorkspaceStore } from '../stores/storeDesktopWorkspace'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Keyboard + HTML5 drop handlers for workspace overview (move windows between desktops).
|
|
7
|
+
*/
|
|
8
|
+
export function useWorkspaceOverview() {
|
|
9
|
+
const applicationManager = useApplicationManager()
|
|
10
|
+
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
11
|
+
|
|
12
|
+
useEventListener(window, 'keydown', (e: KeyboardEvent) => {
|
|
13
|
+
if (e.key !== 'Escape') return
|
|
14
|
+
if (!desktopWorkspaceStore.overview) return
|
|
15
|
+
desktopWorkspaceStore.setOverview(false)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
function onWorkspaceDragOver(e: DragEvent) {
|
|
19
|
+
if (!desktopWorkspaceStore.overview) return
|
|
20
|
+
e.preventDefault()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function onWorkspaceDrop(e: DragEvent, workspaceId: string) {
|
|
24
|
+
e.preventDefault()
|
|
25
|
+
if (!desktopWorkspaceStore.overview) return
|
|
26
|
+
|
|
27
|
+
const raw =
|
|
28
|
+
e.dataTransfer?.getData('text/plain') ||
|
|
29
|
+
e.dataTransfer?.getData('text') ||
|
|
30
|
+
''
|
|
31
|
+
if (!raw) return
|
|
32
|
+
|
|
33
|
+
const win = applicationManager.getWindowOpenedId(raw)
|
|
34
|
+
win?.actions.setWorkspace(workspaceId)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
onWorkspaceDragOver,
|
|
39
|
+
onWorkspaceDrop,
|
|
40
|
+
}
|
|
41
|
+
}
|