@owdproject/core 3.4.0 → 4.0.0-alpha.4
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 +112 -13
- package/dist/dom/index.d.mts +65 -0
- package/dist/dom/index.d.ts +65 -0
- package/dist/dom/index.mjs +224 -0
- package/dist/events/index.d.mts +70 -0
- package/dist/events/index.d.ts +70 -0
- package/dist/events/index.mjs +3 -0
- package/dist/index.d.mts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.mjs +115 -0
- package/dist/layout/index.d.mts +41 -0
- package/dist/layout/index.d.ts +41 -0
- package/dist/layout/index.mjs +64 -0
- package/dist/machines/index.d.mts +31 -0
- package/dist/machines/index.d.ts +31 -0
- package/dist/machines/index.mjs +2 -0
- package/dist/managers/index.d.mts +118 -0
- package/dist/managers/index.d.ts +118 -0
- package/dist/managers/index.mjs +6 -0
- package/dist/session/index.d.mts +57 -0
- package/dist/session/index.d.ts +57 -0
- package/dist/session/index.mjs +65 -0
- package/dist/shared/core.B1XxB289.mjs +239 -0
- package/dist/shared/core.B3mp7ztE.mjs +237 -0
- package/dist/shared/core.BOvFdEVQ.d.ts +114 -0
- package/dist/shared/core.CsDFgGnX.mjs +40 -0
- package/dist/shared/core.Di1eFcr_.d.mts +114 -0
- package/dist/shared/core.Pd_Ogt4g.mjs +101 -0
- package/dist/shared/core.b3Xldzyu.mjs +29 -0
- package/dist/shared/core.d_A3q1kZ.mjs +869 -0
- package/dist/types/index.d.mts +266 -0
- package/dist/types/index.d.ts +266 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +56 -112
- package/CHANGELOG.md +0 -98
- package/DESKTOP_KERNEL.md +0 -232
- package/MIGRATION_3.3.2.md +0 -23
- package/MIGRATION_3.4.md +0 -126
- package/PLAYGROUND.md +0 -91
- package/dist/module.d.mts +0 -13
- package/dist/module.json +0 -9
- package/dist/module.mjs +0 -254
- package/dist/types.d.mts +0 -7
- package/index.ts +0 -8
- package/kit/authoring.ts +0 -340
- package/kit/defineDesktopApp.ts +0 -56
- package/module.ts +0 -203
- package/runtime/components/Application/DesktopCoreApplicationRender.vue +0 -20
- package/runtime/components/Application/DesktopCoreApplicationWindowsRender.vue +0 -38
- package/runtime/components/background/DesktopCoreBackground.vue +0 -16
- package/runtime/components/core/DesktopCore.vue +0 -43
- package/runtime/components/time/DesktopCoreTime.vue +0 -56
- package/runtime/components/window/DesktopCoreWindow.vue +0 -215
- package/runtime/components/window/DesktopCoreWindowContent.vue +0 -28
- package/runtime/components/window/DesktopCoreWindowNav.vue +0 -66
- package/runtime/components/window/DesktopCoreWindowSnapHintsBase.vue +0 -74
- package/runtime/components/workspace/DesktopCoreWorkspaceEdgeHintsBase.vue +0 -84
- package/runtime/composables/useApplicationEntries.ts +0 -51
- package/runtime/composables/useApplicationManager.ts +0 -285
- package/runtime/composables/useBlockNonInputContextMenu.ts +0 -30
- package/runtime/composables/useDesktopConfig.ts +0 -8
- package/runtime/composables/useDesktopDialogs.ts +0 -16
- package/runtime/composables/useDesktopExtension.ts +0 -8
- package/runtime/composables/useDesktopManager.ts +0 -51
- package/runtime/composables/useDesktopManifest.ts +0 -17
- package/runtime/composables/useDesktopSession.ts +0 -27
- package/runtime/composables/useDesktopShellIdentity.ts +0 -99
- package/runtime/composables/useDesktopShellOptions.ts +0 -36
- package/runtime/composables/useDesktopShellReady.ts +0 -7
- package/runtime/composables/useDesktopWorkArea.ts +0 -93
- package/runtime/composables/useTerminalManager.ts +0 -159
- package/runtime/composables/useToggleWindowMaximize.ts +0 -35
- package/runtime/composables/useWindowDragHandlers.ts +0 -47
- package/runtime/composables/useWindowSnapDrop.ts +0 -112
- package/runtime/composables/useWorkspaceEdgeDrop.ts +0 -176
- package/runtime/composables/useWorkspaceManager.ts +0 -67
- package/runtime/composables/useWorkspaceOverviewCapture.ts +0 -92
- package/runtime/composables/useWorkspaceOverviewLiveScale.ts +0 -151
- package/runtime/constants/desktopShellKeys.ts +0 -12
- package/runtime/constants/shellLayout.ts +0 -5
- package/runtime/dialogs/desktopDialogProvider.ts +0 -73
- package/runtime/internal/controllers/ApplicationController.ts +0 -351
- package/runtime/internal/controllers/WindowController.ts +0 -547
- package/runtime/plugins/01.desktop-shell-init.client.ts +0 -28
- package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +0 -13
- package/runtime/plugins/resize.client.ts +0 -6
- package/runtime/stores/storeApplicationMeta.ts +0 -60
- package/runtime/stores/storeApplicationWindows.ts +0 -21
- package/runtime/stores/storeDesktop.ts +0 -71
- package/runtime/stores/storeDesktopDefaultApps.ts +0 -54
- package/runtime/stores/storeDesktopVolume.ts +0 -19
- package/runtime/stores/storeDesktopWindow.ts +0 -38
- package/runtime/stores/storeDesktopWorkspace.ts +0 -105
- package/runtime/stores/storeIds.ts +0 -35
- package/runtime/types/desktopMenu.ts +0 -10
- package/runtime/utils/initDesktopShell.ts +0 -80
- package/runtime/utils/migratePersistedStoreIds.ts +0 -57
- package/runtime/utils/utilApp.ts +0 -25
- package/runtime/utils/utilCaptureElementToCanvas.ts +0 -21
- package/runtime/utils/utilCommon.ts +0 -26
- package/runtime/utils/utilDebug.ts +0 -30
- package/runtime/utils/utilDetectSnapZone.ts +0 -57
- package/runtime/utils/utilTerminal.ts +0 -6
- package/runtime/utils/utilWindowControllerAdapter.ts +0 -15
- package/runtime/utils/utilWindowLayout.ts +0 -82
- package/runtime/utils/utilWindowMaximizeLayout.ts +0 -44
- package/runtime/utils/utilWorkspaceWindows.ts +0 -33
- package/types/index.d.ts +0 -531
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { useApplicationManager } from './useApplicationManager'
|
|
2
|
-
import { debugLog } from '../utils/utilDebug'
|
|
3
|
-
|
|
4
|
-
const commands = new Map<string, TerminalCommand>()
|
|
5
|
-
|
|
6
|
-
// ─── formatting helpers ──────────────────────────────────────────────────────
|
|
7
|
-
|
|
8
|
-
function padEnd(str: string, len: number): string {
|
|
9
|
-
return str.length >= len ? str : str + ' '.repeat(len - str.length)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function buildHelpList(): string {
|
|
13
|
-
const sorted = Array.from(commands.values()).sort((a, b) =>
|
|
14
|
-
a.name.localeCompare(b.name),
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
const colWidth = Math.max(...sorted.map((c) => c.name.length)) + 4
|
|
18
|
-
|
|
19
|
-
const rows = sorted
|
|
20
|
-
.map((cmd) => ` ${padEnd(cmd.name, colWidth)}${cmd.description ?? ''}`)
|
|
21
|
-
.join('\n')
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
`Available commands:\n\n` +
|
|
25
|
-
rows +
|
|
26
|
-
`\n\nType 'help <command>' for more details.`
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function buildHelpDetail(cmd: TerminalCommand): string {
|
|
31
|
-
const lines: string[] = []
|
|
32
|
-
|
|
33
|
-
lines.push(` ${cmd.name}${cmd.description ? ` — ${cmd.description}` : ''}`)
|
|
34
|
-
lines.push('')
|
|
35
|
-
|
|
36
|
-
if (cmd.usage) {
|
|
37
|
-
lines.push(` Usage: ${cmd.usage}`)
|
|
38
|
-
lines.push('')
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (cmd.args && cmd.args.length > 0) {
|
|
42
|
-
lines.push(' Arguments:')
|
|
43
|
-
const argColW = Math.max(...cmd.args.map((a) => a.name.length)) + 4
|
|
44
|
-
for (const arg of cmd.args) {
|
|
45
|
-
const required = arg.required ? '' : ' (optional)'
|
|
46
|
-
lines.push(
|
|
47
|
-
` ${padEnd(arg.name, argColW)}${arg.description ?? ''}${required}`,
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
lines.push('')
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (cmd.options && cmd.options.length > 0) {
|
|
54
|
-
lines.push(' Options:')
|
|
55
|
-
const optColW = Math.max(...cmd.options.map((o) => o.flag.length)) + 4
|
|
56
|
-
for (const opt of cmd.options) {
|
|
57
|
-
lines.push(` ${padEnd(opt.flag, optColW)}${opt.description ?? ''}`)
|
|
58
|
-
}
|
|
59
|
-
lines.push('')
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return lines.join('\n').trimEnd()
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ─── composable ─────────────────────────────────────────────────────────────
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Terminal Manager Composable (Singleton)
|
|
69
|
-
*/
|
|
70
|
-
export function useTerminalManager(): ITerminalManager {
|
|
71
|
-
/**
|
|
72
|
-
* Add a new terminal command
|
|
73
|
-
*/
|
|
74
|
-
const addCommand = (command: TerminalCommand) => {
|
|
75
|
-
for (const existingCommand of commands.keys()) {
|
|
76
|
-
if (
|
|
77
|
-
existingCommand.startsWith(command.name) ||
|
|
78
|
-
command.name.startsWith(existingCommand)
|
|
79
|
-
) {
|
|
80
|
-
throw new Error(`Command prefix conflict with "${existingCommand}"`)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
commands.set(command.name, command)
|
|
85
|
-
debugLog(`Registered terminal command: ${command.name} → ${command.applicationId}`)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* List all registered command names
|
|
90
|
-
*/
|
|
91
|
-
const listCommands = (): string[] => {
|
|
92
|
-
return Array.from(commands.keys())
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Get a single command by name
|
|
97
|
-
*/
|
|
98
|
-
const getCommand = (name: string): TerminalCommand | undefined => {
|
|
99
|
-
return commands.get(name)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Get all registered commands with metadata
|
|
104
|
-
*/
|
|
105
|
-
const getAllCommands = (): TerminalCommand[] => {
|
|
106
|
-
return Array.from(commands.values())
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Execute a terminal command
|
|
111
|
-
*/
|
|
112
|
-
const execCommand = async (input: string): Promise<CommandOutput | void> => {
|
|
113
|
-
const applicationManager = useApplicationManager()
|
|
114
|
-
|
|
115
|
-
const trimmed = input.trim()
|
|
116
|
-
const [name, ...rest] = trimmed.split(/\s+/)
|
|
117
|
-
|
|
118
|
-
if (!name) return
|
|
119
|
-
|
|
120
|
-
// ── built-in: help ────────────────────────────────────────────────────────
|
|
121
|
-
if (name === 'help') {
|
|
122
|
-
const target = rest[0]
|
|
123
|
-
|
|
124
|
-
if (!target) {
|
|
125
|
-
return { message: buildHelpList() }
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const cmd = commands.get(target)
|
|
129
|
-
if (!cmd) {
|
|
130
|
-
return {
|
|
131
|
-
message: `help: command not found: '${target}'\nType 'help' to list available commands.`,
|
|
132
|
-
isError: true,
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return { message: buildHelpDetail(cmd) }
|
|
137
|
-
}
|
|
138
|
-
// ─────────────────────────────────────────────────────────────────────────
|
|
139
|
-
|
|
140
|
-
if (!commands.has(name)) {
|
|
141
|
-
return {
|
|
142
|
-
message: `Command not found: '${name}'\nType 'help' to list available commands.`,
|
|
143
|
-
isError: true,
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const application = commands.get(name)!
|
|
148
|
-
|
|
149
|
-
return applicationManager.execAppCommand(application.applicationId, input)
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
addCommand,
|
|
154
|
-
listCommands,
|
|
155
|
-
getCommand,
|
|
156
|
-
getAllCommands,
|
|
157
|
-
execCommand,
|
|
158
|
-
}
|
|
159
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { inject } from 'vue'
|
|
2
|
-
import {
|
|
3
|
-
useDesktopWindowStore,
|
|
4
|
-
} from '../stores/storeDesktopWindow'
|
|
5
|
-
import { toggleWindowMaximizeLayout } from '../utils/utilWindowMaximizeLayout'
|
|
6
|
-
import {
|
|
7
|
-
DESKTOP_TOGGLE_WINDOW_MAXIMIZE_KEY,
|
|
8
|
-
type DesktopToggleWindowMaximizeFn,
|
|
9
|
-
} from '../constants/desktopShellKeys'
|
|
10
|
-
|
|
11
|
-
export type { DesktopToggleWindowMaximizeFn }
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Maximize / restore a window. Themes may override via
|
|
15
|
-
* {@link DESKTOP_TOGGLE_WINDOW_MAXIMIZE_KEY}; otherwise uses
|
|
16
|
-
* {@link useDesktopWindowStore.workArea} (when measured) or
|
|
17
|
-
* {@link IWindowController.actions.toggleMaximize}.
|
|
18
|
-
*/
|
|
19
|
-
export function useToggleWindowMaximize(): DesktopToggleWindowMaximizeFn {
|
|
20
|
-
const override = inject(DESKTOP_TOGGLE_WINDOW_MAXIMIZE_KEY, null)
|
|
21
|
-
if (override) return override
|
|
22
|
-
|
|
23
|
-
const desktopWindowStore = useDesktopWindowStore()
|
|
24
|
-
|
|
25
|
-
return function toggle(win: IWindowController | undefined) {
|
|
26
|
-
if (!win?.instanced) return false
|
|
27
|
-
|
|
28
|
-
const workArea = desktopWindowStore.workArea
|
|
29
|
-
if (workArea.width > 0 && workArea.height > 0) {
|
|
30
|
-
return toggleWindowMaximizeLayout(win, workArea)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return win.actions.toggleMaximize()
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { IWindowController } from '@owdproject/core'
|
|
2
|
-
import { useDesktopWindowStore } from '../stores/storeDesktopWindow'
|
|
3
|
-
import { useDesktopWorkspaceStore } from '../stores/storeDesktopWorkspace'
|
|
4
|
-
import { useWorkspaceEdgeDrop } from './useWorkspaceEdgeDrop'
|
|
5
|
-
import { useWindowSnapDrop } from './useWindowSnapDrop'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Wire workspace edge drop and window snap to theme `Window.vue` drag events.
|
|
9
|
-
*/
|
|
10
|
-
export function useWindowDragHandlers(
|
|
11
|
-
getWindow: () => IWindowController | undefined,
|
|
12
|
-
) {
|
|
13
|
-
const desktopWindowStore = useDesktopWindowStore()
|
|
14
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
15
|
-
const { beginWindowDrag, endWindowDrag } = useWorkspaceEdgeDrop()
|
|
16
|
-
const { beginWindowSnapDrag, endWindowSnapDrag } = useWindowSnapDrop()
|
|
17
|
-
|
|
18
|
-
function onDragStart() {
|
|
19
|
-
const win = getWindow()
|
|
20
|
-
if (!win?.state?.id || desktopWorkspaceStore.overview) return
|
|
21
|
-
|
|
22
|
-
beginWindowDrag(win.state.id)
|
|
23
|
-
beginWindowSnapDrag(
|
|
24
|
-
win.state.id,
|
|
25
|
-
desktopWindowStore.workArea,
|
|
26
|
-
win.isMaximizable,
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function onDragEnd(data: { left: number; top: number }) {
|
|
31
|
-
const win = getWindow()
|
|
32
|
-
if (!win || desktopWorkspaceStore.overview) return
|
|
33
|
-
|
|
34
|
-
const snapped = endWindowSnapDrag(win)
|
|
35
|
-
if (snapped) return
|
|
36
|
-
|
|
37
|
-
const moved = endWindowDrag(win)
|
|
38
|
-
if (!moved) {
|
|
39
|
-
win.actions.setPosition({ x: data.left, y: data.top })
|
|
40
|
-
if (win.state.layout && win.state.layout !== 'normal') {
|
|
41
|
-
win.actions.clearLayout()
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return { onDragStart, onDragEnd }
|
|
47
|
-
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import type { DesktopWorkAreaRect, IWindowController } from '@owdproject/core'
|
|
2
|
-
import type { Ref } from 'vue'
|
|
3
|
-
import { computed, ref } from 'vue'
|
|
4
|
-
import { useDesktopWorkspaceStore } from '../stores/storeDesktopWorkspace'
|
|
5
|
-
import {
|
|
6
|
-
detectSnapZone,
|
|
7
|
-
type SnapZoneHint,
|
|
8
|
-
} from '../utils/utilDetectSnapZone'
|
|
9
|
-
import { applySnapToWindow, computeSnapRect } from '../utils/utilWindowLayout'
|
|
10
|
-
import { useWorkspaceEdgeDrop } from './useWorkspaceEdgeDrop'
|
|
11
|
-
|
|
12
|
-
const snapHint = ref<SnapZoneHint | null>(null)
|
|
13
|
-
const isSnapDragActive = ref(false)
|
|
14
|
-
let snapDraggingWindowId: string | null = null
|
|
15
|
-
let activeWorkArea: DesktopWorkAreaRect = { x: 0, y: 0, width: 0, height: 0 }
|
|
16
|
-
|
|
17
|
-
function onDocumentPointerMove(e: PointerEvent) {
|
|
18
|
-
updateSnapHintFromPointer(e.clientX, e.clientY)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function onDocumentMouseMove(e: MouseEvent) {
|
|
22
|
-
updateSnapHintFromPointer(e.clientX, e.clientY)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function stopSnapPointerTracking() {
|
|
26
|
-
document.removeEventListener('pointermove', onDocumentPointerMove)
|
|
27
|
-
document.removeEventListener('mousemove', onDocumentMouseMove)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function updateSnapHintFromPointer(clientX: number, clientY: number) {
|
|
31
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
32
|
-
|
|
33
|
-
if (!isSnapDragActive.value || desktopWorkspaceStore.overview) {
|
|
34
|
-
snapHint.value = null
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const deferSide =
|
|
39
|
-
desktopWorkspaceStore.list.length > 1 &&
|
|
40
|
-
!desktopWorkspaceStore.overview
|
|
41
|
-
|
|
42
|
-
snapHint.value = detectSnapZone(clientX, clientY, activeWorkArea, {
|
|
43
|
-
deferSideSnapForWorkspaceEdge: deferSide,
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* While dragging a maximizable window, highlight snap zones in the shell work area.
|
|
49
|
-
*/
|
|
50
|
-
export function useWindowSnapDrop() {
|
|
51
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
52
|
-
|
|
53
|
-
function beginWindowSnapDrag(
|
|
54
|
-
windowId: string,
|
|
55
|
-
workArea: DesktopWorkAreaRect,
|
|
56
|
-
maximizable: boolean,
|
|
57
|
-
) {
|
|
58
|
-
if (desktopWorkspaceStore.overview) return
|
|
59
|
-
if (!maximizable) return
|
|
60
|
-
if (workArea.width <= 0 || workArea.height <= 0) return
|
|
61
|
-
|
|
62
|
-
snapDraggingWindowId = windowId
|
|
63
|
-
isSnapDragActive.value = true
|
|
64
|
-
activeWorkArea = { ...workArea }
|
|
65
|
-
snapHint.value = null
|
|
66
|
-
|
|
67
|
-
document.addEventListener('pointermove', onDocumentPointerMove, {
|
|
68
|
-
passive: true,
|
|
69
|
-
})
|
|
70
|
-
document.addEventListener('mousemove', onDocumentMouseMove, {
|
|
71
|
-
passive: true,
|
|
72
|
-
})
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function commitSnapDrop(win: IWindowController): boolean {
|
|
76
|
-
const zone = snapHint.value
|
|
77
|
-
if (!zone || !snapDraggingWindowId) return false
|
|
78
|
-
|
|
79
|
-
return applySnapToWindow(win, zone, activeWorkArea)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function endWindowSnapDrag(win?: IWindowController): boolean {
|
|
83
|
-
stopSnapPointerTracking()
|
|
84
|
-
|
|
85
|
-
let snapped = false
|
|
86
|
-
if (win && snapHint.value) {
|
|
87
|
-
snapped = commitSnapDrop(win)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
isSnapDragActive.value = false
|
|
91
|
-
snapDraggingWindowId = null
|
|
92
|
-
snapHint.value = null
|
|
93
|
-
|
|
94
|
-
return snapped
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const snapHintRect = computed(() => {
|
|
98
|
-
const zone = snapHint.value
|
|
99
|
-
if (!zone || activeWorkArea.width <= 0) return null
|
|
100
|
-
|
|
101
|
-
return computeSnapRect(zone, activeWorkArea)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
return {
|
|
105
|
-
snapHint,
|
|
106
|
-
snapHintRect,
|
|
107
|
-
isSnapDragActive,
|
|
108
|
-
beginWindowSnapDrag,
|
|
109
|
-
endWindowSnapDrag,
|
|
110
|
-
activeWorkArea: () => activeWorkArea,
|
|
111
|
-
}
|
|
112
|
-
}
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import type { IWindowController } from '@owdproject/core'
|
|
2
|
-
import { computed, ref } from 'vue'
|
|
3
|
-
import { useDesktopWorkspaceStore } from '../stores/storeDesktopWorkspace'
|
|
4
|
-
import { WORKSPACE_EDGE_DROP_PX } from '../constants/shellLayout'
|
|
5
|
-
|
|
6
|
-
const edgeHint = ref<'left' | 'right' | null>(null)
|
|
7
|
-
const isWindowDragActive = ref(false)
|
|
8
|
-
let draggingWindowId: string | null = null
|
|
9
|
-
|
|
10
|
-
function adjacentWorkspaceId(side: 'left' | 'right'): string | null {
|
|
11
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
12
|
-
if (desktopWorkspaceStore.overview) return null
|
|
13
|
-
const list = desktopWorkspaceStore.list
|
|
14
|
-
if (list.length < 2) return null
|
|
15
|
-
|
|
16
|
-
const index = desktopWorkspaceStore.workspaceActiveIndex
|
|
17
|
-
if (index < 0) return null
|
|
18
|
-
|
|
19
|
-
if (side === 'left' && index > 0) {
|
|
20
|
-
return list[index - 1] ?? null
|
|
21
|
-
}
|
|
22
|
-
if (side === 'right' && index < list.length - 1) {
|
|
23
|
-
return list[index + 1] ?? null
|
|
24
|
-
}
|
|
25
|
-
return null
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function updateEdgeHintFromClientX(clientX: number) {
|
|
29
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
30
|
-
if (!isWindowDragActive.value || desktopWorkspaceStore.overview) {
|
|
31
|
-
edgeHint.value = null
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const viewportWidth =
|
|
36
|
-
typeof globalThis !== 'undefined' ? globalThis.innerWidth : 0
|
|
37
|
-
|
|
38
|
-
if (clientX <= WORKSPACE_EDGE_DROP_PX && adjacentWorkspaceId('left')) {
|
|
39
|
-
edgeHint.value = 'left'
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
clientX >= viewportWidth - WORKSPACE_EDGE_DROP_PX &&
|
|
45
|
-
adjacentWorkspaceId('right')
|
|
46
|
-
) {
|
|
47
|
-
edgeHint.value = 'right'
|
|
48
|
-
return
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
edgeHint.value = null
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function onDocumentPointerMove(e: PointerEvent) {
|
|
55
|
-
updateEdgeHintFromClientX(e.clientX)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function stopPointerTracking() {
|
|
59
|
-
document.removeEventListener('pointermove', onDocumentPointerMove)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* While dragging a window (normal desktop, not overview), highlight left/right
|
|
64
|
-
* screen edges when an adjacent workspace exists so the user can drop there.
|
|
65
|
-
*/
|
|
66
|
-
export function useWorkspaceEdgeDrop() {
|
|
67
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
68
|
-
|
|
69
|
-
function beginWindowDrag(windowId: string) {
|
|
70
|
-
if (desktopWorkspaceStore.overview) return
|
|
71
|
-
if (desktopWorkspaceStore.list.length < 2) return
|
|
72
|
-
|
|
73
|
-
draggingWindowId = windowId
|
|
74
|
-
isWindowDragActive.value = true
|
|
75
|
-
edgeHint.value = null
|
|
76
|
-
|
|
77
|
-
document.addEventListener('pointermove', onDocumentPointerMove, {
|
|
78
|
-
passive: true,
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function commitEdgeDrop(win: IWindowController) {
|
|
83
|
-
const side = edgeHint.value
|
|
84
|
-
if (!side || !draggingWindowId) return false
|
|
85
|
-
|
|
86
|
-
const targetWorkspaceId = adjacentWorkspaceId(side)
|
|
87
|
-
if (!targetWorkspaceId) return false
|
|
88
|
-
|
|
89
|
-
win.actions.setWorkspace(targetWorkspaceId)
|
|
90
|
-
desktopWorkspaceStore.setWorkspace(targetWorkspaceId)
|
|
91
|
-
|
|
92
|
-
const inset = WORKSPACE_EDGE_DROP_PX + 24
|
|
93
|
-
const pos = win.position
|
|
94
|
-
if (pos && typeof pos.y === 'number') {
|
|
95
|
-
const viewportWidth =
|
|
96
|
-
typeof globalThis !== 'undefined' ? globalThis.innerWidth : 1920
|
|
97
|
-
const rawWidth = win.size?.width ?? 400
|
|
98
|
-
const width =
|
|
99
|
-
typeof rawWidth === 'number'
|
|
100
|
-
? rawWidth
|
|
101
|
-
: Number.parseFloat(String(rawWidth)) || 400
|
|
102
|
-
const x =
|
|
103
|
-
side === 'left'
|
|
104
|
-
? inset
|
|
105
|
-
: Math.max(inset, viewportWidth - width - inset)
|
|
106
|
-
win.actions.setPosition({ x, y: pos.y })
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return true
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function endWindowDrag(win?: IWindowController): boolean {
|
|
113
|
-
stopPointerTracking()
|
|
114
|
-
|
|
115
|
-
let moved = false
|
|
116
|
-
if (win && edgeHint.value) {
|
|
117
|
-
moved = commitEdgeDrop(win)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
isWindowDragActive.value = false
|
|
121
|
-
draggingWindowId = null
|
|
122
|
-
edgeHint.value = null
|
|
123
|
-
|
|
124
|
-
return moved
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const edgeTargetDesktopIndex = computed(() => {
|
|
128
|
-
const side = edgeHint.value
|
|
129
|
-
if (!side) return null
|
|
130
|
-
|
|
131
|
-
const targetId = adjacentWorkspaceId(side)
|
|
132
|
-
if (!targetId) return null
|
|
133
|
-
|
|
134
|
-
const index = desktopWorkspaceStore.list.indexOf(targetId)
|
|
135
|
-
return index >= 0 ? index + 1 : null
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
edgeHint,
|
|
140
|
-
edgeTargetDesktopIndex,
|
|
141
|
-
isWindowDragActive,
|
|
142
|
-
beginWindowDrag,
|
|
143
|
-
endWindowDrag,
|
|
144
|
-
adjacentWorkspaceId,
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Wire {@link useWorkspaceEdgeDrop} to DesktopWindow drag events (theme Window wrapper).
|
|
150
|
-
*/
|
|
151
|
-
export function useWorkspaceEdgeDropWindowHandlers(
|
|
152
|
-
getWindow: () => IWindowController | undefined,
|
|
153
|
-
) {
|
|
154
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
155
|
-
const { beginWindowDrag, endWindowDrag } = useWorkspaceEdgeDrop()
|
|
156
|
-
|
|
157
|
-
function onDragStart() {
|
|
158
|
-
const win = getWindow()
|
|
159
|
-
if (!win?.state?.id || desktopWorkspaceStore.overview) return
|
|
160
|
-
beginWindowDrag(win.state.id)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function onDragEnd(data: { left: number; top: number }) {
|
|
164
|
-
const win = getWindow()
|
|
165
|
-
const moved =
|
|
166
|
-
Boolean(win) &&
|
|
167
|
-
!desktopWorkspaceStore.overview &&
|
|
168
|
-
endWindowDrag(win)
|
|
169
|
-
|
|
170
|
-
if (!moved && win) {
|
|
171
|
-
win.actions.setPosition({ x: data.left, y: data.top })
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return { onDragStart, onDragEnd }
|
|
176
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { useEventListener } from '@vueuse/core'
|
|
2
|
-
import { useApplicationManager } from './useApplicationManager'
|
|
3
|
-
import { useDesktopWorkspaceStore } from '../stores/storeDesktopWorkspace'
|
|
4
|
-
import { collectWindowsOnWorkspace } from '../utils/utilWorkspaceWindows'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Keyboard + HTML5 drop handlers for workspace management (move windows between desktops).
|
|
8
|
-
*/
|
|
9
|
-
export function useWorkspaceManager() {
|
|
10
|
-
const applicationManager = useApplicationManager()
|
|
11
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
12
|
-
|
|
13
|
-
useEventListener(window, 'keydown', (e: KeyboardEvent) => {
|
|
14
|
-
if (e.key !== 'Escape') return
|
|
15
|
-
if (!desktopWorkspaceStore.overview) return
|
|
16
|
-
desktopWorkspaceStore.setOverview(false)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
function onWorkspaceDragOver(e: DragEvent) {
|
|
20
|
-
if (!desktopWorkspaceStore.overview) return
|
|
21
|
-
e.preventDefault()
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function onWorkspaceDrop(e: DragEvent, workspaceId: string) {
|
|
25
|
-
e.preventDefault()
|
|
26
|
-
if (!desktopWorkspaceStore.overview) return
|
|
27
|
-
|
|
28
|
-
const raw =
|
|
29
|
-
e.dataTransfer?.getData('text/plain') ||
|
|
30
|
-
e.dataTransfer?.getData('text') ||
|
|
31
|
-
''
|
|
32
|
-
if (!raw) return
|
|
33
|
-
|
|
34
|
-
const win = applicationManager.getWindowOpenedId(raw)
|
|
35
|
-
win?.actions.setWorkspace(workspaceId)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Remove a virtual desktop: migrate its windows to the last remaining workspace
|
|
40
|
-
* (excluding the removed id), then drop the workspace from the list.
|
|
41
|
-
*/
|
|
42
|
-
function removeWorkspace(workspaceId: string): boolean {
|
|
43
|
-
if (desktopWorkspaceStore.list.length <= 2) return false
|
|
44
|
-
|
|
45
|
-
const fallbackId = desktopWorkspaceStore.resolveWorkspaceFallback(workspaceId)
|
|
46
|
-
if (!fallbackId) return false
|
|
47
|
-
|
|
48
|
-
const activeId = desktopWorkspaceStore.active
|
|
49
|
-
const windows = collectWindowsOnWorkspace(
|
|
50
|
-
applicationManager.apps.values(),
|
|
51
|
-
workspaceId,
|
|
52
|
-
activeId,
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
for (const win of windows) {
|
|
56
|
-
win.actions.setWorkspace(fallbackId)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return desktopWorkspaceStore.removeWorkspace(workspaceId)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
onWorkspaceDragOver,
|
|
64
|
-
onWorkspaceDrop,
|
|
65
|
-
removeWorkspace,
|
|
66
|
-
}
|
|
67
|
-
}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { useDebounceFn } from '@vueuse/core'
|
|
2
|
-
import { nextTick, ref, shallowRef, watch } from 'vue'
|
|
3
|
-
import { useDesktopWorkspaceStore } from '@owdproject/core/runtime/stores/storeDesktopWorkspace'
|
|
4
|
-
import { captureElementToCanvas } from '../utils/utilCaptureElementToCanvas'
|
|
5
|
-
|
|
6
|
-
export type WorkspaceRootResolver = (
|
|
7
|
-
workspaceId: string,
|
|
8
|
-
) => HTMLElement | null | undefined
|
|
9
|
-
|
|
10
|
-
export type UseWorkspaceOverviewCaptureOptions = {
|
|
11
|
-
/** Delay before capturing after overview opens (ms). Default 150. */
|
|
12
|
-
debounceMs?: number
|
|
13
|
-
/** JPEG quality for thumbnail data URLs (0–1). Default 0.7. */
|
|
14
|
-
jpegQuality?: number
|
|
15
|
-
/** Passed through to html2canvas. */
|
|
16
|
-
captureOptions?: Record<string, unknown>
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Captures workspace desktop roots as JPEG data URLs while workspace overview is open.
|
|
21
|
-
* Themes supply a resolver that maps each workspace id to its DOM root (e.g. a layer wrapping
|
|
22
|
-
* {@link DesktopApplicationRender} with `workspace-filter`).
|
|
23
|
-
*/
|
|
24
|
-
export function useWorkspaceOverviewCapture(
|
|
25
|
-
resolveWorkspaceRoot: WorkspaceRootResolver,
|
|
26
|
-
options: UseWorkspaceOverviewCaptureOptions = {},
|
|
27
|
-
) {
|
|
28
|
-
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
29
|
-
const thumbnails = shallowRef(new Map<string, string>())
|
|
30
|
-
const isCapturing = ref(false)
|
|
31
|
-
|
|
32
|
-
const debounceMs = options.debounceMs ?? 150
|
|
33
|
-
const jpegQuality = options.jpegQuality ?? 0.7
|
|
34
|
-
|
|
35
|
-
async function captureWorkspace(workspaceId: string): Promise<string | null> {
|
|
36
|
-
const element = resolveWorkspaceRoot(workspaceId)
|
|
37
|
-
const canvas = await captureElementToCanvas(element, options.captureOptions)
|
|
38
|
-
if (!canvas) return null
|
|
39
|
-
return canvas.toDataURL('image/jpeg', jpegQuality)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async function refreshThumbnails() {
|
|
43
|
-
if (!desktopWorkspaceStore.overview) return
|
|
44
|
-
|
|
45
|
-
isCapturing.value = true
|
|
46
|
-
const next = new Map<string, string>()
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
await nextTick()
|
|
50
|
-
const ids = [...desktopWorkspaceStore.list]
|
|
51
|
-
await Promise.all(
|
|
52
|
-
ids.map(async (id) => {
|
|
53
|
-
const dataUrl = await captureWorkspace(id)
|
|
54
|
-
if (dataUrl) next.set(id, dataUrl)
|
|
55
|
-
}),
|
|
56
|
-
)
|
|
57
|
-
thumbnails.value = next
|
|
58
|
-
} finally {
|
|
59
|
-
isCapturing.value = false
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const scheduleRefresh = useDebounceFn(() => {
|
|
64
|
-
void refreshThumbnails()
|
|
65
|
-
}, debounceMs)
|
|
66
|
-
|
|
67
|
-
watch(
|
|
68
|
-
() => desktopWorkspaceStore.overview,
|
|
69
|
-
(open) => {
|
|
70
|
-
if (open) scheduleRefresh()
|
|
71
|
-
else thumbnails.value = new Map()
|
|
72
|
-
},
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
watch(
|
|
76
|
-
() => desktopWorkspaceStore.list.join('\0'),
|
|
77
|
-
() => {
|
|
78
|
-
if (desktopWorkspaceStore.overview) scheduleRefresh()
|
|
79
|
-
},
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
function thumbnailFor(workspaceId: string): string | undefined {
|
|
83
|
-
return thumbnails.value.get(workspaceId)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
thumbnails,
|
|
88
|
-
isCapturing,
|
|
89
|
-
refreshThumbnails,
|
|
90
|
-
thumbnailFor,
|
|
91
|
-
}
|
|
92
|
-
}
|