@owdproject/core
Version:
Nuxt Desktop module for browser desktop experiences (windows, shell, apps)
177 lines (143 loc) • 4.82 kB
text/typescript
import type { IWindowController } from '@owdproject/core'
import { computed, ref } from 'vue'
import { useDesktopWorkspaceStore } from '../stores/storeDesktopWorkspace'
import { WORKSPACE_EDGE_DROP_PX } from '../constants/shellLayout'
const edgeHint = ref<'left' | 'right' | null>(null)
const isWindowDragActive = ref(false)
let draggingWindowId: string | null = null
function adjacentWorkspaceId(side: 'left' | 'right'): string | null {
const desktopWorkspaceStore = useDesktopWorkspaceStore()
if (desktopWorkspaceStore.overview) return null
const list = desktopWorkspaceStore.list
if (list.length < 2) return null
const index = desktopWorkspaceStore.workspaceActiveIndex
if (index < 0) return null
if (side === 'left' && index > 0) {
return list[index - 1] ?? null
}
if (side === 'right' && index < list.length - 1) {
return list[index + 1] ?? null
}
return null
}
function updateEdgeHintFromClientX(clientX: number) {
const desktopWorkspaceStore = useDesktopWorkspaceStore()
if (!isWindowDragActive.value || desktopWorkspaceStore.overview) {
edgeHint.value = null
return
}
const viewportWidth =
typeof globalThis !== 'undefined' ? globalThis.innerWidth : 0
if (clientX <= WORKSPACE_EDGE_DROP_PX && adjacentWorkspaceId('left')) {
edgeHint.value = 'left'
return
}
if (
clientX >= viewportWidth - WORKSPACE_EDGE_DROP_PX &&
adjacentWorkspaceId('right')
) {
edgeHint.value = 'right'
return
}
edgeHint.value = null
}
function onDocumentPointerMove(e: PointerEvent) {
updateEdgeHintFromClientX(e.clientX)
}
function stopPointerTracking() {
document.removeEventListener('pointermove', onDocumentPointerMove)
}
/**
* While dragging a window (normal desktop, not overview), highlight left/right
* screen edges when an adjacent workspace exists so the user can drop there.
*/
export function useWorkspaceEdgeDrop() {
const desktopWorkspaceStore = useDesktopWorkspaceStore()
function beginWindowDrag(windowId: string) {
if (desktopWorkspaceStore.overview) return
if (desktopWorkspaceStore.list.length < 2) return
draggingWindowId = windowId
isWindowDragActive.value = true
edgeHint.value = null
document.addEventListener('pointermove', onDocumentPointerMove, {
passive: true,
})
}
function commitEdgeDrop(win: IWindowController) {
const side = edgeHint.value
if (!side || !draggingWindowId) return false
const targetWorkspaceId = adjacentWorkspaceId(side)
if (!targetWorkspaceId) return false
win.actions.setWorkspace(targetWorkspaceId)
desktopWorkspaceStore.setWorkspace(targetWorkspaceId)
const inset = WORKSPACE_EDGE_DROP_PX + 24
const pos = win.position
if (pos && typeof pos.y === 'number') {
const viewportWidth =
typeof globalThis !== 'undefined' ? globalThis.innerWidth : 1920
const rawWidth = win.size?.width ?? 400
const width =
typeof rawWidth === 'number'
? rawWidth
: Number.parseFloat(String(rawWidth)) || 400
const x =
side === 'left'
? inset
: Math.max(inset, viewportWidth - width - inset)
win.actions.setPosition({ x, y: pos.y })
}
return true
}
function endWindowDrag(win?: IWindowController): boolean {
stopPointerTracking()
let moved = false
if (win && edgeHint.value) {
moved = commitEdgeDrop(win)
}
isWindowDragActive.value = false
draggingWindowId = null
edgeHint.value = null
return moved
}
const edgeTargetDesktopIndex = computed(() => {
const side = edgeHint.value
if (!side) return null
const targetId = adjacentWorkspaceId(side)
if (!targetId) return null
const index = desktopWorkspaceStore.list.indexOf(targetId)
return index >= 0 ? index + 1 : null
})
return {
edgeHint,
edgeTargetDesktopIndex,
isWindowDragActive,
beginWindowDrag,
endWindowDrag,
adjacentWorkspaceId,
}
}
/**
* Wire {@link useWorkspaceEdgeDrop} to DesktopWindow drag events (theme Window wrapper).
*/
export function useWorkspaceEdgeDropWindowHandlers(
getWindow: () => IWindowController | undefined,
) {
const desktopWorkspaceStore = useDesktopWorkspaceStore()
const { beginWindowDrag, endWindowDrag } = useWorkspaceEdgeDrop()
function onDragStart() {
const win = getWindow()
if (!win?.state?.id || desktopWorkspaceStore.overview) return
beginWindowDrag(win.state.id)
}
function onDragEnd(data: { left: number; top: number }) {
const win = getWindow()
const moved =
Boolean(win) &&
!desktopWorkspaceStore.overview &&
endWindowDrag(win)
if (!moved && win) {
win.actions.setPosition({ x: data.left, y: data.top })
}
}
return { onDragStart, onDragEnd }
}