fix window overview

This commit is contained in:
2025-10-24 14:33:56 +02:00
parent 252b8711de
commit 8f8bbb5558
5 changed files with 70 additions and 51 deletions

View File

@ -90,7 +90,8 @@
<!-- Window with dynamic teleport --> <!-- Window with dynamic teleport -->
<Teleport <Teleport
:to=" :to="
windowManager.showWindowOverview windowManager.showWindowOverview &&
overviewWindowState.has(window.id)
? `#window-preview-${window.id}` ? `#window-preview-${window.id}`
: `#desktop-container-${window.id}` : `#desktop-container-${window.id}`
" "
@ -98,15 +99,15 @@
<template <template
v-if=" v-if="
windowManager.showWindowOverview && windowManager.showWindowOverview &&
overviewWindowState[window.id] overviewWindowState.has(window.id)
" "
> >
<div <div
class="absolute origin-top-left" class="absolute origin-top-left"
:style="{ :style="{
transform: `scale(${overviewWindowState[window.id]!.scale})`, transform: `scale(${overviewWindowState.get(window.id)!.scale})`,
width: `${overviewWindowState[window.id]!.width}px`, width: `${overviewWindowState.get(window.id)!.width}px`,
height: `${overviewWindowState[window.id]!.height}px`, height: `${overviewWindowState.get(window.id)!.height}px`,
}" }"
> >
<HaexWindow <HaexWindow
@ -116,10 +117,10 @@
:id="window.id" :id="window.id"
:title="window.title" :title="window.title"
:icon="window.icon" :icon="window.icon"
v-model:x="overviewWindowState[window.id]!.x" v-model:x="overviewWindowState.get(window.id)!.x"
v-model:y="overviewWindowState[window.id]!.y" v-model:y="overviewWindowState.get(window.id)!.y"
v-model:width="overviewWindowState[window.id]!.width" v-model:width="overviewWindowState.get(window.id)!.width"
v-model:height="overviewWindowState[window.id]!.height" v-model:height="overviewWindowState.get(window.id)!.height"
:is-active="windowManager.isWindowActive(window.id)" :is-active="windowManager.isWindowActive(window.id)"
:source-x="window.sourceX" :source-x="window.sourceX"
:source-y="window.sourceY" :source-y="window.sourceY"
@ -567,47 +568,48 @@ const MIN_PREVIEW_HEIGHT = 225 // 50% increase from 150
const MAX_PREVIEW_HEIGHT = 450 // 50% increase from 300 const MAX_PREVIEW_HEIGHT = 450 // 50% increase from 300
// Store window state for overview (position only, size stays original) // Store window state for overview (position only, size stays original)
const overviewWindowState = reactive< const overviewWindowState = ref(
Record< new Map<string, { x: number; y: number; width: number; height: number; scale: number }>(),
string, )
{ x: number; y: number; width: number; height: number; scale: number }
>
>({})
// Calculate scale and card dimensions for each window // Calculate scale and card dimensions for each window
watch( watch(
() => windowManager.showWindowOverview, () => windowManager.showWindowOverview,
(isOpen) => { (isOpen) => {
if (isOpen) { if (isOpen) {
// Calculate scale for each window // Wait for the Overview modal to mount and create the teleport targets
windowManager.windows.forEach((window) => { nextTick(() => {
const scaleX = MAX_PREVIEW_WIDTH / window.width windowManager.windows.forEach((window) => {
const scaleY = MAX_PREVIEW_HEIGHT / window.height const scaleX = MAX_PREVIEW_WIDTH / window.width
const scale = Math.min(scaleX, scaleY, 1) // Never scale up, only down const scaleY = MAX_PREVIEW_HEIGHT / window.height
const scale = Math.min(scaleX, scaleY, 1)
// Ensure minimum card size // Ensure minimum card size
const scaledWidth = window.width * scale const scaledWidth = window.width * scale
const scaledHeight = window.height * scale const scaledHeight = window.height * scale
let finalScale = scale let finalScale = scale
if (scaledWidth < MIN_PREVIEW_WIDTH) { if (scaledWidth < MIN_PREVIEW_WIDTH) {
finalScale = MIN_PREVIEW_WIDTH / window.width finalScale = MIN_PREVIEW_WIDTH / window.width
} }
if (scaledHeight < MIN_PREVIEW_HEIGHT) { if (scaledHeight < MIN_PREVIEW_HEIGHT) {
finalScale = Math.max(finalScale, MIN_PREVIEW_HEIGHT / window.height) finalScale = Math.max(finalScale, MIN_PREVIEW_HEIGHT / window.height)
} }
overviewWindowState[window.id] = { overviewWindowState.value.set(window.id, {
x: 0, x: 0,
y: 0, y: 0,
width: window.width, // Keep original width width: window.width,
height: window.height, // Keep original height height: window.height,
scale: finalScale, // Store the scale factor scale: finalScale,
} })
})
}) })
} else {
// Clear state when overview is closed
overviewWindowState.value.clear()
} }
}, },
{ immediate: true },
) )
// Disable Swiper in overview mode // Disable Swiper in overview mode

View File

@ -3,7 +3,7 @@
ref="windowEl" ref="windowEl"
:style="windowStyle" :style="windowStyle"
:class="[ :class="[
'absolute bg-default/80 backdrop-blur-xl rounded-xl shadow-2xl overflow-hidden isolate', 'absolute bg-default/80 backdrop-blur-xl rounded-lg shadow-xl overflow-hidden isolate',
'border border-gray-200 dark:border-gray-700 transition-all ease-out duration-600 ', 'border border-gray-200 dark:border-gray-700 transition-all ease-out duration-600 ',
'flex flex-col @container', 'flex flex-col @container',
{ 'select-none': isResizingOrDragging }, { 'select-none': isResizingOrDragging },

View File

@ -1,20 +1,20 @@
<template> <template>
<UModal <UModal
v-model:open="localShowWindowOverview" v-model:open="localShowWindowOverview"
title="" :title="t('modal.title')"
:description="t('modal.description')"
fullscreen fullscreen
> >
<template #content> <template #content>
<div class="flex flex-col h-full"> <div class="flex flex-col h-full">
<!-- Header --> <!-- Header -->
<div <div
class="flex items-center justify-between p-6 border-b border-gray-200 dark:border-gray-700" class="flex items-center justify-end border-b p-2 border-gray-200 dark:border-gray-700"
> >
<h3 class="text-2xl font-bold">Window Overview</h3>
<UButton <UButton
icon="i-heroicons-x-mark" icon="i-heroicons-x-mark"
color="neutral" color="error"
variant="ghost" variant="soft"
@click="localShowWindowOverview = false" @click="localShowWindowOverview = false"
/> />
</div> </div>
@ -48,15 +48,15 @@
v-if="window.isMinimized" v-if="window.isMinimized"
color="info" color="info"
size="xs" size="xs"
:title="t('minimized')"
> >
Minimized
</UBadge> </UBadge>
</div> </div>
<!-- Scaled Window Preview Container / Teleport Target --> <!-- Scaled Window Preview Container / Teleport Target -->
<div <div
:id="`window-preview-${window.id}`" :id="`window-preview-${window.id}`"
class="relative bg-gray-100 dark:bg-gray-900 rounded-lg overflow-hidden border-2 border-gray-200 dark:border-gray-700 group-hover:border-primary-500 transition-all shadow-lg" class="relative bg-gray-100 dark:bg-gray-900 rounded-xl overflow-hidden border-2 border-gray-200 dark:border-gray-700 group-hover:border-primary-500 transition-all shadow-lg"
:style="getCardStyle(window)" :style="getCardStyle(window)"
@click="handleRestoreAndActivateWindow(window.id)" @click="handleRestoreAndActivateWindow(window.id)"
> >
@ -75,7 +75,7 @@
> >
<UIcon <UIcon
name="i-heroicons-window" name="i-heroicons-window"
class="size-16 mb-4" class="size-16 mb-4 shrink-0"
/> />
<p class="text-lg font-medium">No windows open</p> <p class="text-lg font-medium">No windows open</p>
<p class="text-sm"> <p class="text-sm">
@ -89,6 +89,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const { t } = useI18n()
const windowManager = useWindowManagerStore() const windowManager = useWindowManagerStore()
const workspaceStore = useWorkspaceStore() const workspaceStore = useWorkspaceStore()
@ -217,3 +219,19 @@ watch(
}, },
) )
</script> </script>
<i18n lang="yaml">
de:
modal:
title: Fensterübersicht
description: Übersicht aller offenen Fenster auf allen Workspaces
minimized: Minimiert
en:
modal:
title: Window Overview
description: Overview of all open windows on all workspaces
minimized: Minimized
</i18n>

View File

@ -1,7 +1,7 @@
<template> <template>
<UCard <UCard
ref="cardEl" ref="cardEl"
class="cursor-pointer transition-all h-32 w-72 shrink-0 group duration-500" class="cursor-pointer transition-all h-32 w-72 shrink-0 group duration-500 rounded-lg"
:class="[ :class="[
workspace.id === currentWorkspace?.id workspace.id === currentWorkspace?.id
? 'ring-2 ring-secondary bg-secondary/10' ? 'ring-2 ring-secondary bg-secondary/10'

View File

@ -178,11 +178,10 @@ const drizzleCallback = (async (
} }
console.log('drizzleCallback', method, sql, params) console.log('drizzleCallback', method, sql, params)
console.log('drizzleCallback rows', rows) console.log('drizzleCallback rows', rows, rows.slice(0, 1))
if (method === 'get') { if (method === 'get') {
return { rows: rows.slice(0, 1) } return rows.length > 0 ? { rows: rows.at(0) } : { rows }
//return rows.length > 0 ? { rows: rows[0] } : { rows }
} }
return { rows } return { rows }
}) satisfies AsyncRemoteCallback }) satisfies AsyncRemoteCallback