@owdproject/core 3.3.0 → 3.4.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/CHANGELOG.md +98 -0
- package/DESKTOP_KERNEL.md +232 -0
- package/MIGRATION_3.3.2.md +23 -0
- package/MIGRATION_3.4.md +126 -0
- package/PLAYGROUND.md +91 -0
- package/README.md +13 -80
- package/dist/module.d.mts +2 -2
- package/dist/module.json +3 -3
- package/dist/module.mjs +86 -99
- package/index.ts +6 -3
- package/kit/authoring.ts +340 -0
- package/kit/defineDesktopApp.ts +56 -0
- package/module.ts +76 -108
- package/package.json +70 -40
- package/runtime/components/{Desktop/Application/DesktopApplicationRender.vue → Application/DesktopCoreApplicationRender.vue} +2 -2
- package/runtime/components/{Desktop/Application/DesktopApplicationWindowsRender.vue → Application/DesktopCoreApplicationWindowsRender.vue} +1 -1
- package/runtime/components/core/DesktopCore.vue +43 -0
- package/runtime/components/{Desktop/Window/DesktopWindow.vue → window/DesktopCoreWindow.vue} +17 -6
- package/runtime/components/window/DesktopCoreWindowSnapHintsBase.vue +74 -0
- package/runtime/components/workspace/DesktopCoreWorkspaceEdgeHintsBase.vue +84 -0
- package/runtime/composables/useBlockNonInputContextMenu.ts +30 -0
- package/runtime/composables/useDesktopConfig.ts +8 -0
- package/runtime/composables/useDesktopDialogs.ts +16 -0
- package/runtime/composables/useDesktopExtension.ts +8 -0
- package/runtime/composables/useDesktopManager.ts +2 -0
- package/runtime/composables/useDesktopManifest.ts +17 -0
- package/runtime/composables/useDesktopSession.ts +27 -0
- package/runtime/composables/useDesktopShellIdentity.ts +99 -0
- package/runtime/composables/useDesktopShellOptions.ts +36 -0
- package/runtime/composables/useDesktopShellReady.ts +7 -0
- package/runtime/composables/useDesktopWorkArea.ts +93 -0
- package/runtime/composables/useTerminalManager.ts +102 -9
- package/runtime/composables/useToggleWindowMaximize.ts +35 -0
- package/runtime/composables/useWindowDragHandlers.ts +47 -0
- package/runtime/composables/useWindowSnapDrop.ts +112 -0
- package/runtime/composables/useWorkspaceEdgeDrop.ts +176 -0
- package/runtime/composables/useWorkspaceManager.ts +26 -0
- package/runtime/composables/useWorkspaceOverviewCapture.ts +92 -0
- package/runtime/composables/useWorkspaceOverviewLiveScale.ts +151 -0
- package/runtime/constants/desktopShellKeys.ts +12 -0
- package/runtime/constants/shellLayout.ts +5 -0
- package/runtime/dialogs/desktopDialogProvider.ts +73 -0
- package/runtime/internal/controllers/ApplicationController.ts +8 -2
- package/runtime/internal/controllers/WindowController.ts +93 -8
- package/runtime/plugins/01.desktop-shell-init.client.ts +28 -0
- package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +2 -6
- package/runtime/stores/storeApplicationMeta.ts +2 -1
- package/runtime/stores/storeApplicationWindows.ts +2 -1
- package/runtime/stores/storeDesktop.ts +17 -57
- package/runtime/stores/storeDesktopDefaultApps.ts +2 -1
- package/runtime/stores/storeDesktopVolume.ts +2 -1
- package/runtime/stores/storeDesktopWindow.ts +20 -2
- package/runtime/stores/storeDesktopWorkspace.ts +31 -1
- package/runtime/stores/storeIds.ts +35 -0
- package/runtime/types/desktopMenu.ts +10 -0
- package/runtime/utils/initDesktopShell.ts +80 -0
- package/runtime/utils/migratePersistedStoreIds.ts +57 -0
- package/runtime/utils/utilApp.ts +0 -12
- package/runtime/utils/{captureElementToCanvas.ts → utilCaptureElementToCanvas.ts} +1 -1
- package/runtime/utils/utilDetectSnapZone.ts +57 -0
- package/runtime/utils/utilWindowLayout.ts +82 -0
- package/runtime/utils/utilWindowMaximizeLayout.ts +44 -0
- package/runtime/utils/utilWorkspaceWindows.ts +33 -0
- package/types/index.d.ts +125 -14
- package/bin/cli.js +0 -395
- package/bin/desktop.js +0 -5
- package/bin/lib/catalog.js +0 -293
- package/bin/lib/config.js +0 -109
- package/bin/lib/desktopConfig.js +0 -56
- package/bin/lib/generateTemplate.js +0 -389
- package/bin/lib/install.js +0 -408
- package/bin/lib/migrateModulePlayground.config.mjs +0 -164
- package/bin/lib/migrateModulePlayground.mjs +0 -313
- package/bin/lib/npmVersions.js +0 -124
- package/bin/lib/playgroundContext.js +0 -188
- package/bin/lib/scaffold.js +0 -197
- package/bin/lib/status.js +0 -289
- package/bin/lib/validateModule.js +0 -697
- package/bin/lib/workspace.js +0 -182
- package/bin/owd.js +0 -5
- package/bin/tui.js +0 -1379
- package/runtime/components/Desktop/Core/DesktopCore.vue +0 -90
- package/runtime/utils/explorerEntryPath.ts +0 -10
- package/runtime/utils/resolveDesktopConfigPath.ts +0 -52
- package/runtime/utils/splitDesktopUserConfig.ts +0 -85
- package/runtime/utils/utilDesktop.ts +0 -35
- package/runtime/utils/validateDesktopUserConfig.ts +0 -44
- /package/runtime/components/{Desktop/Background/DesktopBackground.vue → background/DesktopCoreBackground.vue} +0 -0
- /package/runtime/components/{Desktop/Time/DesktopTime.vue → time/DesktopCoreTime.vue} +0 -0
- /package/runtime/components/{Desktop/Window/DesktopWindowContent.vue → window/DesktopCoreWindowContent.vue} +0 -0
- /package/runtime/components/{Desktop/Window/DesktopWindowNav.vue → window/DesktopCoreWindowNav.vue} +0 -0
- /package/runtime/utils/{utilWindow.ts → utilWindowControllerAdapter.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owdproject/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "Nuxt Desktop module for browser desktop experiences (windows, shell, apps)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nuxt",
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
"owd",
|
|
13
13
|
"open-web-desktop"
|
|
14
14
|
],
|
|
15
|
-
"homepage": "https://github.com/owdproject/
|
|
15
|
+
"homepage": "https://github.com/owdproject/core#readme",
|
|
16
16
|
"bugs": {
|
|
17
|
-
"url": "https://github.com/owdproject/
|
|
17
|
+
"url": "https://github.com/owdproject/core/issues"
|
|
18
18
|
},
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
|
-
"url": "git+https://github.com/owdproject/
|
|
21
|
+
"url": "git+https://github.com/owdproject/core.git"
|
|
22
22
|
},
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"author": {
|
|
@@ -28,23 +28,20 @@
|
|
|
28
28
|
"type": "module",
|
|
29
29
|
"types": "types/index.d.ts",
|
|
30
30
|
"files": [
|
|
31
|
-
"bin",
|
|
32
31
|
"dist",
|
|
32
|
+
"kit",
|
|
33
33
|
"runtime",
|
|
34
34
|
"types",
|
|
35
35
|
"index.ts",
|
|
36
36
|
"module.ts",
|
|
37
37
|
"package.json",
|
|
38
|
-
"README.md"
|
|
38
|
+
"README.md",
|
|
39
|
+
"DESKTOP_KERNEL.md",
|
|
40
|
+
"CHANGELOG.md",
|
|
41
|
+
"MIGRATION_3.3.2.md",
|
|
42
|
+
"MIGRATION_3.4.md",
|
|
43
|
+
"PLAYGROUND.md"
|
|
39
44
|
],
|
|
40
|
-
"scripts": {
|
|
41
|
-
"dev": "pnpm run dev:prepare",
|
|
42
|
-
"dev:prepare": "nuxt-module-build build --stub",
|
|
43
|
-
"build:module": "nuxt-module-build build",
|
|
44
|
-
"prepack": "nuxt-module-build build",
|
|
45
|
-
"test": "vitest run",
|
|
46
|
-
"test:watch": "vitest"
|
|
47
|
-
},
|
|
48
45
|
"exports": {
|
|
49
46
|
".": {
|
|
50
47
|
"types": "./types/index.d.ts",
|
|
@@ -63,50 +60,83 @@
|
|
|
63
60
|
"default": "./module.ts"
|
|
64
61
|
},
|
|
65
62
|
"./package.json": "./package.json",
|
|
66
|
-
"./
|
|
67
|
-
"types": "./
|
|
68
|
-
"development": "./
|
|
69
|
-
"import": "./
|
|
70
|
-
"default": "./
|
|
63
|
+
"./kit/*": {
|
|
64
|
+
"types": "./types/index.d.ts",
|
|
65
|
+
"development": "./kit/*",
|
|
66
|
+
"import": "./kit/*",
|
|
67
|
+
"default": "./kit/*"
|
|
68
|
+
},
|
|
69
|
+
"./runtime/composables/*": {
|
|
70
|
+
"types": "./runtime/composables/*",
|
|
71
|
+
"development": "./runtime/composables/*",
|
|
72
|
+
"import": "./runtime/composables/*",
|
|
73
|
+
"default": "./runtime/composables/*"
|
|
74
|
+
},
|
|
75
|
+
"./runtime/constants/*": {
|
|
76
|
+
"types": "./runtime/constants/*",
|
|
77
|
+
"development": "./runtime/constants/*",
|
|
78
|
+
"import": "./runtime/constants/*",
|
|
79
|
+
"default": "./runtime/constants/*"
|
|
80
|
+
},
|
|
81
|
+
"./runtime/dialogs/*": {
|
|
82
|
+
"types": "./runtime/dialogs/*",
|
|
83
|
+
"development": "./runtime/dialogs/*",
|
|
84
|
+
"import": "./runtime/dialogs/*",
|
|
85
|
+
"default": "./runtime/dialogs/*"
|
|
86
|
+
},
|
|
87
|
+
"./runtime/utils/*": {
|
|
88
|
+
"types": "./runtime/utils/*",
|
|
89
|
+
"development": "./runtime/utils/*",
|
|
90
|
+
"import": "./runtime/utils/*",
|
|
91
|
+
"default": "./runtime/utils/*"
|
|
92
|
+
},
|
|
93
|
+
"./runtime/stores/*": {
|
|
94
|
+
"types": "./runtime/stores/*",
|
|
95
|
+
"development": "./runtime/stores/*",
|
|
96
|
+
"import": "./runtime/stores/*",
|
|
97
|
+
"default": "./runtime/stores/*"
|
|
98
|
+
},
|
|
99
|
+
"./runtime/components/*": {
|
|
100
|
+
"types": "./runtime/components/*",
|
|
101
|
+
"development": "./runtime/components/*",
|
|
102
|
+
"import": "./runtime/components/*",
|
|
103
|
+
"default": "./runtime/components/*"
|
|
104
|
+
},
|
|
105
|
+
"./runtime/types/*": {
|
|
106
|
+
"types": "./runtime/types/*",
|
|
107
|
+
"development": "./runtime/types/*",
|
|
108
|
+
"import": "./runtime/types/*",
|
|
109
|
+
"default": "./runtime/types/*"
|
|
71
110
|
}
|
|
72
111
|
},
|
|
73
|
-
"bin": {
|
|
74
|
-
"desktop": "bin/desktop.js",
|
|
75
|
-
"owd": "bin/owd.js"
|
|
76
|
-
},
|
|
77
112
|
"dependencies": {
|
|
78
113
|
"@nuxt/fonts": "^0.14.0",
|
|
79
114
|
"@nuxt/icon": "^2.2.1",
|
|
80
115
|
"@nuxt/kit": "^4.4.4",
|
|
81
116
|
"@nuxtjs/i18n": "^10.3.0",
|
|
82
|
-
"@nuxtjs/tailwindcss": "^6.14.0",
|
|
83
117
|
"@pinia/nuxt": "^0.11.3",
|
|
84
|
-
"@primeuix/themes": "^2.0.3",
|
|
85
|
-
"@primevue/forms": "^4.5.5",
|
|
86
|
-
"@primevue/nuxt-module": "^4.5.5",
|
|
87
118
|
"@vueuse/components": "^14.3.0",
|
|
88
119
|
"@vueuse/core": "^14.3.0",
|
|
89
120
|
"@vueuse/nuxt": "^14.3.0",
|
|
121
|
+
"defu": "^6.1.4",
|
|
90
122
|
"mitt": "^3.0.1",
|
|
91
123
|
"nanoid": "^5.1.11",
|
|
92
124
|
"nuxt": "^4.4.4",
|
|
93
125
|
"pinia": "^3.0.4",
|
|
94
126
|
"sanitize.css": "^13.0.0",
|
|
95
127
|
"sass": "^1.99.0",
|
|
96
|
-
"
|
|
97
|
-
"vue-resizable": "^2.1.7",
|
|
98
|
-
"getopts": "^2.3.0",
|
|
99
|
-
"defu": "^6.1.4",
|
|
100
|
-
"neo-blessed": "^0.2.0"
|
|
101
|
-
},
|
|
102
|
-
"optionalDependencies": {
|
|
103
|
-
"html2canvas": "^1.4.1"
|
|
128
|
+
"vue-resizable": "^2.1.7"
|
|
104
129
|
},
|
|
105
130
|
"devDependencies": {
|
|
106
|
-
"@nuxt/devtools": "^3.2.4",
|
|
107
131
|
"@nuxt/module-builder": "^1.0.2",
|
|
108
|
-
"
|
|
109
|
-
|
|
110
|
-
|
|
132
|
+
"typescript": "~6.0.3"
|
|
133
|
+
},
|
|
134
|
+
"scripts": {
|
|
135
|
+
"dev": "pnpm run dev:prepare",
|
|
136
|
+
"dev:prepare": "nuxt-module-build build --stub",
|
|
137
|
+
"build:module": "nuxt-module-build build",
|
|
138
|
+
"test": "vitest run",
|
|
139
|
+
"test:watch": "vitest",
|
|
140
|
+
"test:coverage": "vitest run --coverage"
|
|
111
141
|
}
|
|
112
|
-
}
|
|
142
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { useApplicationManager } from '
|
|
2
|
+
import { useApplicationManager } from '../../composables/useApplicationManager'
|
|
3
3
|
|
|
4
4
|
defineProps<{
|
|
5
5
|
workspaceFilter?: string
|
|
@@ -10,7 +10,7 @@ const runningApps = applicationManager.appsRunning
|
|
|
10
10
|
</script>
|
|
11
11
|
|
|
12
12
|
<template>
|
|
13
|
-
<
|
|
13
|
+
<DesktopCoreApplicationWindowsRender
|
|
14
14
|
v-for="app of runningApps"
|
|
15
15
|
:key="app.id"
|
|
16
16
|
:workspace-filter="workspaceFilter"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from 'vue'
|
|
3
|
-
import { useDesktopWorkspaceStore } from '
|
|
3
|
+
import { useDesktopWorkspaceStore } from '../../stores/storeDesktopWorkspace'
|
|
4
4
|
|
|
5
5
|
const props = defineProps<{
|
|
6
6
|
workspaceFilter?: string
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useAttrs, computed } from 'vue'
|
|
3
|
+
import { useAppConfig } from 'nuxt/app'
|
|
4
|
+
|
|
5
|
+
defineOptions({ inheritAttrs: false })
|
|
6
|
+
|
|
7
|
+
defineProps<{
|
|
8
|
+
windows?: DesktopWindowsConfig
|
|
9
|
+
systemBar?: DesktopSystemBarConfig
|
|
10
|
+
dockBar?: DesktopDockBarConfig
|
|
11
|
+
workspaces?: DesktopWorkspacesConfig
|
|
12
|
+
}>()
|
|
13
|
+
|
|
14
|
+
const appConfig = useAppConfig()
|
|
15
|
+
const attrs = useAttrs()
|
|
16
|
+
|
|
17
|
+
const classes = computed(() => {
|
|
18
|
+
const list = ['owd-desktop']
|
|
19
|
+
|
|
20
|
+
if (appConfig.desktop?.name) {
|
|
21
|
+
list.push(`owd-desktop--${appConfig.desktop.name}`)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return list
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const rootClass = computed(() => [classes.value, attrs.class])
|
|
28
|
+
const rootStyle = computed(() => attrs.style)
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div :class="rootClass" :style="rootStyle">
|
|
33
|
+
<slot />
|
|
34
|
+
</div>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<style scoped lang="scss">
|
|
38
|
+
.owd-desktop {
|
|
39
|
+
width: 100vw;
|
|
40
|
+
height: 100dvh;
|
|
41
|
+
user-select: none;
|
|
42
|
+
}
|
|
43
|
+
</style>
|
package/runtime/components/{Desktop/Window/DesktopWindow.vue → window/DesktopCoreWindow.vue}
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, provide } from 'vue'
|
|
2
|
+
import { ref, provide, onMounted } from 'vue'
|
|
3
3
|
import { computed } from '@vue/reactivity'
|
|
4
4
|
import { useAppConfig } from 'nuxt/app'
|
|
5
|
-
import { handleWindowControllerProps } from '
|
|
6
|
-
import { useDesktopWorkspaceStore } from '
|
|
5
|
+
import { handleWindowControllerProps } from '../../utils/utilWindowControllerAdapter'
|
|
6
|
+
import { useDesktopWorkspaceStore } from '../../stores/storeDesktopWorkspace'
|
|
7
7
|
|
|
8
8
|
const props = defineProps<{
|
|
9
9
|
window?: IWindowController
|
|
@@ -41,6 +41,12 @@ provide<WindowContent>('windowContent', props.content ?? {})
|
|
|
41
41
|
const isDragging = ref(false)
|
|
42
42
|
const isResizing = ref(false)
|
|
43
43
|
|
|
44
|
+
onMounted(() => {
|
|
45
|
+
if (windowController?.state?.focused) {
|
|
46
|
+
windowController.actions.bringToFront()
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
44
50
|
function onWindowPointerDown() {
|
|
45
51
|
windowController?.actions?.setActive(true)
|
|
46
52
|
windowController?.actions?.bringToFront()
|
|
@@ -144,9 +150,13 @@ function onOverviewNativeDragStart(e: DragEvent) {
|
|
|
144
150
|
}
|
|
145
151
|
}
|
|
146
152
|
|
|
153
|
+
const windowPositionMode = computed(
|
|
154
|
+
() => appConfig.desktop?.windows?.position ?? 'fixed',
|
|
155
|
+
)
|
|
156
|
+
|
|
147
157
|
/** `fit-parent` clamps drag/resize to the parent box — wrong for viewport-fixed shells (Win11, GNOME). */
|
|
148
158
|
const shouldFitParent = computed(
|
|
149
|
-
() =>
|
|
159
|
+
() => windowPositionMode.value !== 'fixed',
|
|
150
160
|
)
|
|
151
161
|
</script>
|
|
152
162
|
|
|
@@ -183,11 +193,11 @@ const shouldFitParent = computed(
|
|
|
183
193
|
<style scoped lang="scss">
|
|
184
194
|
/* vue-resizable sets `.resizable-component { position: relative }` — override so desktop geometry stays consistent */
|
|
185
195
|
.owd-window.resizable-component {
|
|
186
|
-
position: v-bind('
|
|
196
|
+
position: v-bind('windowPositionMode') !important;
|
|
187
197
|
}
|
|
188
198
|
|
|
189
199
|
.owd-window {
|
|
190
|
-
position: v-bind('
|
|
200
|
+
position: v-bind('windowPositionMode');
|
|
191
201
|
|
|
192
202
|
&--dragging,
|
|
193
203
|
&--resizing {
|
|
@@ -199,6 +209,7 @@ const shouldFitParent = computed(
|
|
|
199
209
|
:deep(.owd-window__content) {
|
|
200
210
|
overflow-y: auto;
|
|
201
211
|
height: 100%;
|
|
212
|
+
min-height: 0;
|
|
202
213
|
}
|
|
203
214
|
}
|
|
204
215
|
</style>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { useDesktopWorkspaceStore } from '@owdproject/core/runtime/stores/storeDesktopWorkspace'
|
|
4
|
+
import { useWindowSnapDrop } from '@owdproject/core/runtime/composables/useWindowSnapDrop'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
enabled?: boolean
|
|
8
|
+
}>()
|
|
9
|
+
|
|
10
|
+
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
11
|
+
const { snapHint, snapHintRect, isSnapDragActive } = useWindowSnapDrop()
|
|
12
|
+
|
|
13
|
+
const visible = computed(
|
|
14
|
+
() =>
|
|
15
|
+
props.enabled !== false &&
|
|
16
|
+
!desktopWorkspaceStore.overview &&
|
|
17
|
+
isSnapDragActive.value &&
|
|
18
|
+
snapHint.value !== null &&
|
|
19
|
+
snapHintRect.value !== null,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const hintStyle = computed(() => {
|
|
23
|
+
const rect = snapHintRect.value
|
|
24
|
+
if (!rect) return undefined
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
left: `${rect.x}px`,
|
|
28
|
+
top: `${rect.y}px`,
|
|
29
|
+
width: `${rect.width}px`,
|
|
30
|
+
height: `${rect.height}px`,
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<div
|
|
37
|
+
v-if="visible"
|
|
38
|
+
class="owd-window-snap-hints"
|
|
39
|
+
aria-hidden="true"
|
|
40
|
+
>
|
|
41
|
+
<div
|
|
42
|
+
class="owd-window-snap-hints__zone"
|
|
43
|
+
:class="`owd-window-snap-hints__zone--${snapHint}`"
|
|
44
|
+
:style="hintStyle"
|
|
45
|
+
>
|
|
46
|
+
<slot
|
|
47
|
+
:zone="snapHint"
|
|
48
|
+
:rect="snapHintRect"
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<style scoped>
|
|
55
|
+
.owd-window-snap-hints {
|
|
56
|
+
position: fixed;
|
|
57
|
+
inset: 0;
|
|
58
|
+
pointer-events: none;
|
|
59
|
+
z-index: 999998;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.owd-window-snap-hints__zone {
|
|
63
|
+
position: fixed;
|
|
64
|
+
box-sizing: border-box;
|
|
65
|
+
border: 2px solid rgba(96, 165, 250, 0.85);
|
|
66
|
+
background: rgba(96, 165, 250, 0.18);
|
|
67
|
+
border-radius: 4px;
|
|
68
|
+
transition:
|
|
69
|
+
left 80ms ease,
|
|
70
|
+
top 80ms ease,
|
|
71
|
+
width 80ms ease,
|
|
72
|
+
height 80ms ease;
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { useWorkspaceEdgeDrop } from '@owdproject/core/runtime/composables/useWorkspaceEdgeDrop'
|
|
4
|
+
import { useDesktopWorkspaceStore } from '@owdproject/core/runtime/stores/storeDesktopWorkspace'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
enabled?: boolean
|
|
8
|
+
}>()
|
|
9
|
+
|
|
10
|
+
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
11
|
+
const { edgeHint, edgeTargetDesktopIndex } = useWorkspaceEdgeDrop()
|
|
12
|
+
|
|
13
|
+
const visible = computed(
|
|
14
|
+
() =>
|
|
15
|
+
props.enabled !== false &&
|
|
16
|
+
!desktopWorkspaceStore.overview &&
|
|
17
|
+
desktopWorkspaceStore.list.length > 1 &&
|
|
18
|
+
edgeHint.value !== null &&
|
|
19
|
+
edgeTargetDesktopIndex.value !== null,
|
|
20
|
+
)
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<div
|
|
25
|
+
v-if="visible"
|
|
26
|
+
class="owd-workspace-edge-hints"
|
|
27
|
+
aria-hidden="true"
|
|
28
|
+
>
|
|
29
|
+
<div
|
|
30
|
+
class="owd-workspace-edge-hints__zone owd-workspace-edge-hints__zone--left"
|
|
31
|
+
:class="{
|
|
32
|
+
'owd-workspace-edge-hints__zone--active': edgeHint === 'left',
|
|
33
|
+
}"
|
|
34
|
+
>
|
|
35
|
+
<slot
|
|
36
|
+
name="left"
|
|
37
|
+
:desktop-index="edgeTargetDesktopIndex"
|
|
38
|
+
:side="'left' as const"
|
|
39
|
+
/>
|
|
40
|
+
</div>
|
|
41
|
+
<div
|
|
42
|
+
class="owd-workspace-edge-hints__zone owd-workspace-edge-hints__zone--right"
|
|
43
|
+
:class="{
|
|
44
|
+
'owd-workspace-edge-hints__zone--active': edgeHint === 'right',
|
|
45
|
+
}"
|
|
46
|
+
>
|
|
47
|
+
<slot
|
|
48
|
+
name="right"
|
|
49
|
+
:desktop-index="edgeTargetDesktopIndex"
|
|
50
|
+
:side="'right' as const"
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<style scoped>
|
|
57
|
+
.owd-workspace-edge-hints {
|
|
58
|
+
position: fixed;
|
|
59
|
+
inset: 0;
|
|
60
|
+
pointer-events: none;
|
|
61
|
+
z-index: 999998;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.owd-workspace-edge-hints__zone {
|
|
65
|
+
position: fixed;
|
|
66
|
+
top: 0;
|
|
67
|
+
bottom: 0;
|
|
68
|
+
width: 72px;
|
|
69
|
+
opacity: 0;
|
|
70
|
+
transition: opacity 120ms ease;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.owd-workspace-edge-hints__zone--left {
|
|
74
|
+
left: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.owd-workspace-edge-hints__zone--right {
|
|
78
|
+
right: 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.owd-workspace-edge-hints__zone--active {
|
|
82
|
+
opacity: 1;
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useEventListener } from '@vueuse/core'
|
|
2
|
+
import { isDebugMode } from '../utils/utilDebug'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Blocks the browser context menu on non-input elements (typical desktop shell behaviour).
|
|
6
|
+
* Debug builds skip blocking so DevTools stay usable when {@link isDebugMode} is true.
|
|
7
|
+
*/
|
|
8
|
+
export function useBlockNonInputContextMenu() {
|
|
9
|
+
useEventListener(
|
|
10
|
+
document,
|
|
11
|
+
'contextmenu',
|
|
12
|
+
(event: MouseEvent) => {
|
|
13
|
+
if (isDebugMode()) return
|
|
14
|
+
|
|
15
|
+
const target = event.target as HTMLElement | null
|
|
16
|
+
if (!target) return
|
|
17
|
+
|
|
18
|
+
const tag = target.tagName?.toLowerCase()
|
|
19
|
+
const isInput =
|
|
20
|
+
tag === 'input' ||
|
|
21
|
+
tag === 'textarea' ||
|
|
22
|
+
Boolean(target.isContentEditable)
|
|
23
|
+
|
|
24
|
+
if (!isInput) {
|
|
25
|
+
event.preventDefault()
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{ passive: false },
|
|
29
|
+
)
|
|
30
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useRuntimeConfig } from 'nuxt/app'
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
|
|
4
|
+
/** Reactive view of `runtimeConfig.public.desktop` (full desktop.config merge + coreVersion). */
|
|
5
|
+
export function useDesktopConfig() {
|
|
6
|
+
const runtimeConfig = useRuntimeConfig()
|
|
7
|
+
return computed(() => runtimeConfig.public.desktop)
|
|
8
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { inject } from 'vue'
|
|
2
|
+
import { DESKTOP_DIALOG_PROVIDER_KEY } from '../constants/desktopShellKeys'
|
|
3
|
+
import {
|
|
4
|
+
createBrowserFallbackDialogProvider,
|
|
5
|
+
type DesktopDialogProvider,
|
|
6
|
+
} from '../dialogs/desktopDialogProvider'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns the active desktop dialog provider (theme) or a browser fallback.
|
|
10
|
+
*/
|
|
11
|
+
export function useDesktopDialogs(): DesktopDialogProvider {
|
|
12
|
+
return (
|
|
13
|
+
inject(DESKTOP_DIALOG_PROVIDER_KEY, null) ??
|
|
14
|
+
createBrowserFallbackDialogProvider()
|
|
15
|
+
)
|
|
16
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { computed } from 'vue'
|
|
2
|
+
import { useDesktopConfig } from './useDesktopConfig'
|
|
3
|
+
|
|
4
|
+
/** Readonly slice for an extension namespace (`fs`, `terminal`, or custom `configKey`). */
|
|
5
|
+
export function useDesktopExtension<K extends string>(key: K) {
|
|
6
|
+
const desktop = useDesktopConfig()
|
|
7
|
+
return computed(() => desktop.value?.[key as keyof typeof desktop.value])
|
|
8
|
+
}
|
|
@@ -17,6 +17,8 @@ export function useDesktopManager() {
|
|
|
17
17
|
* Merges and sets the desktop config at runtime (shell geometry, feature flags, etc.).
|
|
18
18
|
*/
|
|
19
19
|
function setConfig(newConfig: DesktopConfig) {
|
|
20
|
+
if (!appConfig) return
|
|
21
|
+
|
|
20
22
|
appConfig.desktop = defu(
|
|
21
23
|
newConfig,
|
|
22
24
|
(appConfig.desktop ?? {}) as DesktopConfig,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { computed } from 'vue'
|
|
2
|
+
import { useDesktopConfig } from './useDesktopConfig'
|
|
3
|
+
|
|
4
|
+
export function hasDesktopModule(pkg: string) {
|
|
5
|
+
const desktop = useDesktopConfig()
|
|
6
|
+
return computed(() => desktop.value?.modules?.includes(pkg) ?? false)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function hasDesktopApp(pkg: string) {
|
|
10
|
+
const desktop = useDesktopConfig()
|
|
11
|
+
return computed(() => desktop.value?.apps?.includes(pkg) ?? false)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function hasDesktopExtension(key: string) {
|
|
15
|
+
const desktop = useDesktopConfig()
|
|
16
|
+
return computed(() => Boolean(desktop.value?.[key as keyof typeof desktop.value]))
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useRouter } from 'nuxt/app'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Neutral API for “leave the desktop shell” flows (shutdown animation → start route).
|
|
6
|
+
* Themes keep their own `/start` / `/boot` pages and styling.
|
|
7
|
+
*/
|
|
8
|
+
const shuttingDown = ref(false)
|
|
9
|
+
|
|
10
|
+
export function useDesktopSession() {
|
|
11
|
+
const initiateShutdownToStart = () => {
|
|
12
|
+
shuttingDown.value = true
|
|
13
|
+
|
|
14
|
+
setTimeout(() => {
|
|
15
|
+
useRouter()
|
|
16
|
+
.push('/start')
|
|
17
|
+
.then(() => {
|
|
18
|
+
shuttingDown.value = false
|
|
19
|
+
})
|
|
20
|
+
}, 2000)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
shuttingDown,
|
|
25
|
+
initiateShutdownToStart,
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { computed, ref } from 'vue'
|
|
2
|
+
import { useRuntimeConfig } from 'nuxt/app'
|
|
3
|
+
|
|
4
|
+
export type ShellIdentity = {
|
|
5
|
+
userId: string
|
|
6
|
+
displayName: string
|
|
7
|
+
avatarUrl: string | null
|
|
8
|
+
userHome: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const GUEST_USER_ID = 'guest'
|
|
12
|
+
|
|
13
|
+
const identity = ref<ShellIdentity | null>(null)
|
|
14
|
+
|
|
15
|
+
export function sanitizeUserHomeSegment(input: string): string {
|
|
16
|
+
const cleaned = input
|
|
17
|
+
.trim()
|
|
18
|
+
.replace(/^@/, '')
|
|
19
|
+
.replace(/[^\w.\-]/g, '_')
|
|
20
|
+
.slice(0, 64)
|
|
21
|
+
return cleaned || 'user'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Build a VFS home path from an auth handle (e.g. Bluesky `@alice.bsky.social`). */
|
|
25
|
+
export function userHomeFromHandle(handle: string, base = '/home'): string {
|
|
26
|
+
const baseNorm = base.endsWith('/') ? base.slice(0, -1) : base
|
|
27
|
+
return `${baseNorm}/${sanitizeUserHomeSegment(handle)}`
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function resolveDefaultHome(): string {
|
|
31
|
+
try {
|
|
32
|
+
const config = useRuntimeConfig()
|
|
33
|
+
const desktop = config.public.desktop as {
|
|
34
|
+
fs?: { defaultUserHome?: string }
|
|
35
|
+
}
|
|
36
|
+
const home = desktop.fs?.defaultUserHome?.trim()
|
|
37
|
+
if (home) return home.startsWith('/') ? home : `/${home}`
|
|
38
|
+
} catch {
|
|
39
|
+
/* outside Nuxt setup */
|
|
40
|
+
}
|
|
41
|
+
return '/home/Guest'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function guestIdentity(defaultHome: string): ShellIdentity {
|
|
45
|
+
return {
|
|
46
|
+
userId: GUEST_USER_ID,
|
|
47
|
+
displayName: 'Guest',
|
|
48
|
+
avatarUrl: null,
|
|
49
|
+
userHome: defaultHome,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Shell session identity (display + VFS home). Auth modules call {@link setShellIdentity}
|
|
55
|
+
* after login; defaults to Guest.
|
|
56
|
+
*/
|
|
57
|
+
export function useDesktopShellIdentity() {
|
|
58
|
+
function ensureIdentity(): ShellIdentity {
|
|
59
|
+
if (!identity.value) {
|
|
60
|
+
identity.value = guestIdentity(resolveDefaultHome())
|
|
61
|
+
}
|
|
62
|
+
return identity.value
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const userId = computed(() => ensureIdentity().userId)
|
|
66
|
+
const displayName = computed(() => ensureIdentity().displayName)
|
|
67
|
+
const avatarUrl = computed(() => ensureIdentity().avatarUrl)
|
|
68
|
+
const userHome = computed(() => ensureIdentity().userHome)
|
|
69
|
+
const isGuest = computed(() => userId.value === GUEST_USER_ID)
|
|
70
|
+
|
|
71
|
+
function setShellIdentity(partial: Partial<ShellIdentity>) {
|
|
72
|
+
const current = ensureIdentity()
|
|
73
|
+
identity.value = {
|
|
74
|
+
...current,
|
|
75
|
+
...partial,
|
|
76
|
+
userId: partial.userId?.trim() || current.userId,
|
|
77
|
+
displayName: partial.displayName?.trim() || current.displayName,
|
|
78
|
+
userHome: partial.userHome?.trim()
|
|
79
|
+
? partial.userHome.startsWith('/')
|
|
80
|
+
? partial.userHome
|
|
81
|
+
: `/${partial.userHome}`
|
|
82
|
+
: current.userHome,
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function clearShellIdentity() {
|
|
87
|
+
identity.value = guestIdentity(resolveDefaultHome())
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
userId,
|
|
92
|
+
displayName,
|
|
93
|
+
avatarUrl,
|
|
94
|
+
userHome,
|
|
95
|
+
isGuest,
|
|
96
|
+
setShellIdentity,
|
|
97
|
+
clearShellIdentity,
|
|
98
|
+
}
|
|
99
|
+
}
|