From f38cecc84b82b69afd945a19ae506fc67d53cbd9 Mon Sep 17 00:00:00 2001 From: haex Date: Mon, 3 Nov 2025 01:29:08 +0100 Subject: [PATCH] Add workspace background customization and fix launcher drawer drag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add workspace background image support with file-based storage - Store background images in $APPLOCALDATA/files directory - Save file paths in database (text column in haex_workspaces) - Use convertFileSrc for secure asset:// URL conversion - Add context menu to workspaces with "Hintergrund ändern" option - Implement background management in settings - File selection dialog for PNG, JPG, JPEG, WebP images - Copy selected images to app data directory - Remove background with file cleanup - Multilingual UI (German/English) - Fix launcher drawer drag interference - Add :handle-only="true" to UDrawer to restrict drag to handle - Simplify drag handlers (removed complex state tracking) - Items can now be dragged to desktop without drawer interference - Extend Tauri asset protocol scope to include $APPLOCALDATA/** for background image loading --- src-tauri/tauri.conf.json | 2 +- src/components/haex/desktop/index.vue | 363 +++++++++++---------- src/components/haex/extension/launcher.vue | 9 +- src/components/haex/system/settings.vue | 107 ++++++ src/database/schemas/haex.ts | 3 +- src/stores/desktop/workspace.ts | 76 +++++ 6 files changed, 376 insertions(+), 184 deletions(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index d4da637..d6eafae 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -64,7 +64,7 @@ }, "assetProtocol": { "enable": true, - "scope": ["$APPDATA", "$RESOURCE"] + "scope": ["$APPDATA", "$RESOURCE", "$APPLOCALDATA/**"] } } }, diff --git a/src/components/haex/desktop/index.vue b/src/components/haex/desktop/index.vue index e63d624..68dbe8f 100644 --- a/src/components/haex/desktop/index.vue +++ b/src/components/haex/desktop/index.vue @@ -23,191 +23,198 @@ :key="workspace.id" class="w-full h-full" > -
- +
- - - -
- -
- - -
- - - - - - +
+ @@ -239,6 +246,8 @@ const { allowSwipe, isOverviewMode, } = storeToRefs(workspaceStore) +const { getWorkspaceBackgroundStyle, getWorkspaceContextMenuItems } = + workspaceStore const { x: mouseX } = useMouse() diff --git a/src/components/haex/extension/launcher.vue b/src/components/haex/extension/launcher.vue index 9c7407f..f7b4cb5 100644 --- a/src/components/haex/extension/launcher.vue +++ b/src/components/haex/extension/launcher.vue @@ -4,6 +4,9 @@ direction="right" :title="t('launcher.title')" :description="t('launcher.description')" + :overlay="false" + :modal="false" + :handle-only="true" :ui="{ content: 'w-dvw max-w-md sm:max-w-fit', }" @@ -30,7 +33,7 @@ size="lg" variant="ghost" :ui="{ - base: 'size-24 flex flex-wrap text-sm items-center justify-center overflow-visible cursor-grab active:cursor-grabbing', + base: 'size-24 flex flex-wrap text-sm items-center justify-center overflow-visible cursor-grab', leadingIcon: 'size-10', label: 'w-full', }" @@ -241,10 +244,6 @@ const handleDragStart = (event: DragEvent, item: LauncherItem) => { event.dataTransfer.setDragImage(dragImage, 20, 20) } } - -const handleDragEnd = () => { - // Cleanup if needed -} diff --git a/src/components/haex/system/settings.vue b/src/components/haex/system/settings.vue index 8ebece3..fb1b050 100644 --- a/src/components/haex/system/settings.vue +++ b/src/components/haex/system/settings.vue @@ -33,6 +33,20 @@ />
+
{{ t('workspaceBackground.label') }}
+
+ + +
+
@@ -40,6 +54,9 @@ @@ -112,6 +199,16 @@ de: update: success: Gerätename wurde erfolgreich aktualisiert error: Gerätename konnte nich aktualisiert werden + workspaceBackground: + label: Workspace-Hintergrund + choose: Bild auswählen + update: + success: Hintergrund erfolgreich aktualisiert + error: Fehler beim Aktualisieren des Hintergrunds + remove: + label: Hintergrund entfernen + success: Hintergrund erfolgreich entfernt + error: Fehler beim Entfernen des Hintergrunds en: language: Language design: Design @@ -129,4 +226,14 @@ en: update: success: Device name has been successfully updated error: Device name could not be updated + workspaceBackground: + label: Workspace Background + choose: Choose Image + update: + success: Background successfully updated + error: Error updating background + remove: + label: Remove Background + success: Background successfully removed + error: Error removing background diff --git a/src/database/schemas/haex.ts b/src/database/schemas/haex.ts index 0497a00..e6bb163 100644 --- a/src/database/schemas/haex.ts +++ b/src/database/schemas/haex.ts @@ -8,7 +8,7 @@ import { type AnySQLiteColumn, type SQLiteColumnBuilderBase, } from 'drizzle-orm/sqlite-core' -import tableNames from '~/database/tableNames.json' +import tableNames from '@/database/tableNames.json' const crdtColumnNames = { haexTimestamp: 'haex_timestamp', @@ -137,6 +137,7 @@ export const haexWorkspaces = sqliteTable( position: integer(tableNames.haex.workspaces.columns.position) .notNull() .default(0), + background: text(), }), (table) => [unique().on(table.position)], ) diff --git a/src/stores/desktop/workspace.ts b/src/stores/desktop/workspace.ts index 47d334e..03d3c9f 100644 --- a/src/stores/desktop/workspace.ts +++ b/src/stores/desktop/workspace.ts @@ -4,6 +4,7 @@ import { type SelectHaexWorkspaces, } from '~/database/schemas' import type { Swiper } from 'swiper/types' +import { convertFileSrc } from '@tauri-apps/api/core' export type IWorkspace = SelectHaexWorkspaces @@ -203,12 +204,86 @@ export const useWorkspaceStore = defineStore('workspaceStore', () => { isOverviewMode.value = false } + const updateWorkspaceBackgroundAsync = async ( + workspaceId: string, + base64Image: string | null, + ) => { + if (!currentVault.value?.drizzle) { + throw new Error('Kein Vault geöffnet') + } + + try { + const result = await currentVault.value.drizzle + .update(haexWorkspaces) + .set({ background: base64Image }) + .where(eq(haexWorkspaces.id, workspaceId)) + .returning() + + if (result.length > 0 && result[0]) { + const index = workspaces.value.findIndex((ws) => ws.id === workspaceId) + if (index !== -1) { + workspaces.value[index] = result[0] + } + } + } catch (error) { + console.error('Fehler beim Aktualisieren des Workspace-Hintergrunds:', error) + throw error + } + } + + const getWorkspaceBackgroundStyle = (workspace: IWorkspace) => { + if (!workspace.background) return {} + + // The background field contains the absolute file path + // Convert it to an asset URL + const assetUrl = convertFileSrc(workspace.background) + + return { + backgroundImage: `url(${assetUrl})`, + backgroundSize: 'cover', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + } + } + + const getWorkspaceContextMenuItems = (workspaceId: string) => { + const windowManager = useWindowManagerStore() + + return [[ + { + label: 'Hintergrund ändern', + icon: 'i-mdi-image', + onSelect: async () => { + // Store the workspace ID for settings to use + currentWorkspaceIndex.value = workspaces.value.findIndex( + (ws) => ws.id === workspaceId, + ) + // Get settings window info + const settingsWindow = windowManager.getAllSystemWindows() + .find((win) => win.id === 'settings') + + if (settingsWindow) { + await windowManager.openWindowAsync({ + type: 'system', + sourceId: settingsWindow.id, + title: settingsWindow.name, + icon: settingsWindow.icon || undefined, + workspaceId, + }) + } + }, + }, + ]] + } + return { addWorkspaceAsync, allowSwipe, closeWorkspaceAsync, currentWorkspace, currentWorkspaceIndex, + getWorkspaceBackgroundStyle, + getWorkspaceContextMenuItems, isOverviewMode, slideToWorkspace, loadWorkspacesAsync, @@ -218,6 +293,7 @@ export const useWorkspaceStore = defineStore('workspaceStore', () => { switchToNext, switchToPrevious, switchToWorkspace, + updateWorkspaceBackgroundAsync, workspaces, } })