mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-17 06:30:50 +01:00
refactored design
This commit is contained in:
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<UApp :locale="locales[locale]">
|
||||
<div data-vaul-drawer-wrapper>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
<NuxtPage />
|
||||
</div>
|
||||
</UApp>
|
||||
</template>
|
||||
|
||||
@ -13,6 +13,20 @@
|
||||
[disabled] {
|
||||
@apply cursor-not-allowed;
|
||||
}
|
||||
|
||||
#__nuxt {
|
||||
/* Stellt sicher, dass die App immer die volle Höhe hat */
|
||||
min-height: 100vh;
|
||||
|
||||
/* Sorgt dafür, dass Padding die Höhe nicht sprengt */
|
||||
@apply box-border;
|
||||
|
||||
/* Die Safe-Area Paddings */
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
}
|
||||
}
|
||||
|
||||
@theme {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
ref="desktopEl"
|
||||
class="w-full h-full relative overflow-hidden isolate"
|
||||
class="w-full h-full relative overflow-hidden"
|
||||
>
|
||||
<Swiper
|
||||
:modules="[SwiperNavigation]"
|
||||
@ -24,7 +24,7 @@
|
||||
class="w-full h-full"
|
||||
>
|
||||
<div
|
||||
class="w-full h-full relative isolate"
|
||||
class="w-full h-full relative"
|
||||
@click.self.stop="handleDesktopClick"
|
||||
@mousedown.left.self="handleAreaSelectStart"
|
||||
@dragover.prevent="handleDragOver"
|
||||
@ -51,7 +51,6 @@
|
||||
class="absolute right-0 top-0 bottom-0 border-blue-500 pointer-events-none backdrop-blur-sm z-50 transition-all duration-500 ease-in-out"
|
||||
:class="showRightSnapZone ? 'w-1/2 bg-blue-500/20 border-2' : 'w-0'"
|
||||
/>
|
||||
<!-- </Transition> -->
|
||||
|
||||
<!-- Area Selection Box -->
|
||||
<div
|
||||
@ -199,52 +198,6 @@
|
||||
|
||||
<!-- Window Overview Modal -->
|
||||
<HaexWindowOverview />
|
||||
|
||||
<!-- Workspace Drawer -->
|
||||
<UDrawer
|
||||
v-model:open="isOverviewMode"
|
||||
direction="left"
|
||||
:dismissible="false"
|
||||
:overlay="false"
|
||||
:modal="false"
|
||||
title="Workspaces"
|
||||
description="Workspaces"
|
||||
>
|
||||
<template #content>
|
||||
<div class="p-6 h-full overflow-y-auto">
|
||||
<UButton
|
||||
block
|
||||
trailing-icon="mdi-close"
|
||||
class="text-2xl font-bold ext-gray-900 dark:text-white mb-4"
|
||||
@click="isOverviewMode = false"
|
||||
>
|
||||
Workspaces
|
||||
</UButton>
|
||||
|
||||
<!-- Workspace Cards -->
|
||||
<div class="flex flex-col gap-3">
|
||||
<HaexWorkspaceCard
|
||||
v-for="workspace in workspaces"
|
||||
:key="workspace.id"
|
||||
:workspace
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Add New Workspace Button -->
|
||||
<UButton
|
||||
block
|
||||
variant="outline"
|
||||
class="mt-6"
|
||||
@click="handleAddWorkspace"
|
||||
>
|
||||
<template #leading>
|
||||
<UIcon name="i-heroicons-plus" />
|
||||
</template>
|
||||
New Workspace
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UDrawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -600,17 +553,6 @@ const onSlideChange = (swiper: SwiperType) => {
|
||||
)
|
||||
}
|
||||
|
||||
// Workspace control handlers
|
||||
const handleAddWorkspace = async () => {
|
||||
await workspaceStore.addWorkspaceAsync()
|
||||
// Swiper will auto-slide to new workspace because we switch in addWorkspaceAsync
|
||||
nextTick(() => {
|
||||
if (swiperInstance.value) {
|
||||
swiperInstance.value.slideTo(workspaces.value.length - 1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* const handleRemoveWorkspace = async () => {
|
||||
if (!currentWorkspace.value || workspaces.value.length <= 1) return
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
:description="vault.path || path"
|
||||
@confirm="onOpenDatabase"
|
||||
>
|
||||
<!-- <UiButton
|
||||
<UiButton
|
||||
:label="t('vault.open')"
|
||||
:ui="{
|
||||
base: 'px-3 py-2',
|
||||
@ -14,8 +14,7 @@
|
||||
size="xl"
|
||||
variant="outline"
|
||||
block
|
||||
@click.stop="onLoadDatabase"
|
||||
/> -->
|
||||
/>
|
||||
|
||||
<template #title>
|
||||
<i18n-t
|
||||
|
||||
83
src/components/haex/window/button.vue
Normal file
83
src/components/haex/window/button.vue
Normal file
@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<UTooltip :text="tooltip">
|
||||
<button
|
||||
class="size-8 shrink-0 rounded-lg flex justify-center transition-colors group"
|
||||
:class="variantClasses.buttonClass"
|
||||
@click="(e) => $emit('click', e)"
|
||||
>
|
||||
<UIcon
|
||||
:name="icon"
|
||||
class="size-4 text-gray-600 dark:text-gray-400"
|
||||
:class="variantClasses.iconClass"
|
||||
/>
|
||||
</button>
|
||||
</UTooltip>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
variant: 'close' | 'maximize' | 'minimize'
|
||||
isMaximized?: boolean
|
||||
}>()
|
||||
|
||||
defineEmits(['click'])
|
||||
|
||||
const icon = computed(() => {
|
||||
switch (props.variant) {
|
||||
case 'close':
|
||||
return 'i-heroicons-x-mark'
|
||||
case 'maximize':
|
||||
return props.isMaximized
|
||||
? 'i-heroicons-arrows-pointing-in'
|
||||
: 'i-heroicons-arrows-pointing-out'
|
||||
default:
|
||||
return 'i-heroicons-minus'
|
||||
}
|
||||
})
|
||||
|
||||
const variantClasses = computed(() => {
|
||||
if (props.variant === 'close') {
|
||||
return {
|
||||
iconClass: 'group-hover:text-error',
|
||||
buttonClass: 'hover:bg-error/30 items-center',
|
||||
}
|
||||
} else if (props.variant === 'maximize') {
|
||||
return {
|
||||
iconClass: 'group-hover:text-warning',
|
||||
buttonClass: 'hover:bg-warning/30 items-center',
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
iconClass: 'group-hover:text-success',
|
||||
buttonClass: 'hover:bg-success/30 items-end pb-1',
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const tooltip = computed(() => {
|
||||
switch (props.variant) {
|
||||
case 'close':
|
||||
return t('close')
|
||||
case 'maximize':
|
||||
return props.isMaximized ? t('shrink') : t('maximize')
|
||||
default:
|
||||
return t('minimize')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<i18n lang="yaml">
|
||||
de:
|
||||
close: Schließen
|
||||
maximize: Maximieren
|
||||
shrink: Verkleinern
|
||||
minimize: Minimieren
|
||||
|
||||
en:
|
||||
close: Close
|
||||
maximize: Maximize
|
||||
shrink: Shrink
|
||||
minimize: Minimize
|
||||
</i18n>
|
||||
@ -38,37 +38,21 @@
|
||||
|
||||
<!-- Right: Window Controls -->
|
||||
<div class="flex items-center gap-1 justify-end">
|
||||
<button
|
||||
class="w-8 h-8 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 flex items-center justify-center transition-colors"
|
||||
<HaexWindowButton
|
||||
variant="minimize"
|
||||
@click.stop="handleMinimize"
|
||||
>
|
||||
<UIcon
|
||||
name="i-heroicons-minus"
|
||||
class="w-4 h-4 text-gray-600 dark:text-gray-400"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="w-8 h-8 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 flex items-center justify-center transition-colors"
|
||||
/>
|
||||
|
||||
<HaexWindowButton
|
||||
:is-maximized
|
||||
variant="maximize"
|
||||
@click.stop="handleMaximize"
|
||||
>
|
||||
<UIcon
|
||||
:name="
|
||||
isMaximized
|
||||
? 'i-heroicons-arrows-pointing-in'
|
||||
: 'i-heroicons-arrows-pointing-out'
|
||||
"
|
||||
class="w-4 h-4 text-gray-600 dark:text-gray-400"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="w-8 h-8 rounded-lg hover:bg-red-100 dark:hover:bg-red-900/30 flex items-center justify-center transition-colors group"
|
||||
/>
|
||||
|
||||
<HaexWindowButton
|
||||
variant="close"
|
||||
@click.stop="handleClose"
|
||||
>
|
||||
<UIcon
|
||||
name="i-heroicons-x-mark"
|
||||
class="w-4 h-4 text-gray-600 dark:text-gray-400 group-hover:text-red-600 dark:group-hover:text-red-400"
|
||||
/>
|
||||
</button>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,98 +0,0 @@
|
||||
<template>
|
||||
<div class="flex flex-col w-full h-full overflow-hidden">
|
||||
<div ref="headerRef">
|
||||
<UPageHeader
|
||||
as="header"
|
||||
:ui="{
|
||||
root: [
|
||||
'bg-default border-b border-accented sticky top-0 z-50 pt-2 px-8 h-header',
|
||||
],
|
||||
wrapper: [
|
||||
'flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4',
|
||||
],
|
||||
}"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<UiLogoHaexhub class="size-12 shrink-0" />
|
||||
|
||||
<NuxtLinkLocale
|
||||
class="link text-base-content link-neutral text-xl font-semibold no-underline flex items-center"
|
||||
:to="{ name: 'desktop' }"
|
||||
>
|
||||
<UiTextGradient class="text-nowrap">
|
||||
{{ currentVaultName }}
|
||||
</UiTextGradient>
|
||||
</NuxtLinkLocale>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #links>
|
||||
<UButton
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
:block="isSmallScreen"
|
||||
icon="i-bi-person-workspace"
|
||||
size="lg"
|
||||
@click="isOverviewMode = !isOverviewMode"
|
||||
/>
|
||||
<UButton
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
:block="isSmallScreen"
|
||||
icon="i-heroicons-squares-2x2"
|
||||
size="lg"
|
||||
@click="showWindowOverview = !showWindowOverview"
|
||||
>
|
||||
<template v-if="openWindowsCount > 0" #trailing>
|
||||
<UBadge
|
||||
:label="openWindowsCount.toString()"
|
||||
color="primary"
|
||||
size="xs"
|
||||
/>
|
||||
</template>
|
||||
</UButton>
|
||||
<HaexExtensionLauncher :block="isSmallScreen" />
|
||||
</template>
|
||||
</UPageHeader>
|
||||
</div>
|
||||
|
||||
<main class="flex-1 overflow-hidden bg-elevated">
|
||||
<NuxtPage />
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { currentVaultName } = storeToRefs(useVaultStore())
|
||||
|
||||
const { isSmallScreen } = storeToRefs(useUiStore())
|
||||
|
||||
const { isOverviewMode } = storeToRefs(useWorkspaceStore())
|
||||
|
||||
const { showWindowOverview, openWindowsCount } = storeToRefs(
|
||||
useWindowManagerStore(),
|
||||
)
|
||||
</script>
|
||||
|
||||
<i18n lang="yaml">
|
||||
de:
|
||||
vault:
|
||||
close: Vault schließen
|
||||
|
||||
sidebar:
|
||||
close: Sidebar ausblenden
|
||||
show: Sidebar anzeigen
|
||||
|
||||
search:
|
||||
label: Suche
|
||||
en:
|
||||
vault:
|
||||
close: Close vault
|
||||
sidebar:
|
||||
close: close sidebar
|
||||
show: show sidebar
|
||||
|
||||
search:
|
||||
label: Search
|
||||
</i18n>
|
||||
@ -1,5 +1,145 @@
|
||||
<template>
|
||||
<div class="bg-default isolate w-dvw h-dvh flex flex-col">
|
||||
<slot />
|
||||
<div class="w-dvw h-dvh flex flex-col">
|
||||
<UPageHeader
|
||||
as="header"
|
||||
:ui="{
|
||||
root: ['px-8 py-0'],
|
||||
wrapper: ['flex flex-row items-center justify-between gap-4'],
|
||||
}"
|
||||
>
|
||||
<template #default>
|
||||
<div class="flex justify-between items-center py-1">
|
||||
<div>
|
||||
<!-- <NuxtLinkLocale
|
||||
class="link text-base-content link-neutral text-xl font-semibold no-underline flex items-center"
|
||||
:to="{ name: 'desktop' }"
|
||||
>
|
||||
<UiTextGradient class="text-nowrap">
|
||||
{{ currentVaultName }}
|
||||
</UiTextGradient>
|
||||
</NuxtLinkLocale> -->
|
||||
<UiButton
|
||||
v-if="currentVaultId"
|
||||
color="neutral"
|
||||
variant="outline"
|
||||
icon="i-bi-person-workspace"
|
||||
size="lg"
|
||||
:tooltip="t('header.workspaces')"
|
||||
@click="isOverviewMode = !isOverviewMode"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div v-if="!currentVaultId">
|
||||
<UiDropdownLocale @select="onSelectLocale" />
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="flex flex-row gap-2"
|
||||
>
|
||||
<UButton
|
||||
v-if="openWindowsCount > 0"
|
||||
color="primary"
|
||||
variant="outline"
|
||||
size="lg"
|
||||
@click="showWindowOverview = !showWindowOverview"
|
||||
>
|
||||
{{ openWindowsCount }}
|
||||
</UButton>
|
||||
<HaexExtensionLauncher />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</UPageHeader>
|
||||
|
||||
<main class="flex-1 overflow-hidden bg-elevated flex flex-col">
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<!-- Workspace Drawer -->
|
||||
<UDrawer
|
||||
v-model:open="isOverviewMode"
|
||||
direction="left"
|
||||
:dismissible="false"
|
||||
:overlay="false"
|
||||
:modal="false"
|
||||
title="Workspaces"
|
||||
description="Workspaces"
|
||||
>
|
||||
<template #content>
|
||||
<div class="p-6 h-full overflow-y-auto">
|
||||
<UButton
|
||||
block
|
||||
trailing-icon="mdi-close"
|
||||
class="text-2xl font-bold ext-gray-900 dark:text-white mb-4"
|
||||
@click="isOverviewMode = false"
|
||||
>
|
||||
Workspaces
|
||||
</UButton>
|
||||
|
||||
<!-- Workspace Cards -->
|
||||
<div class="flex flex-col gap-3">
|
||||
<HaexWorkspaceCard
|
||||
v-for="workspace in workspaces"
|
||||
:key="workspace.id"
|
||||
:workspace
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Add New Workspace Button -->
|
||||
<UButton
|
||||
block
|
||||
variant="outline"
|
||||
class="mt-6"
|
||||
@click="handleAddWorkspace"
|
||||
>
|
||||
<template #leading>
|
||||
<UIcon name="i-heroicons-plus" />
|
||||
</template>
|
||||
New Workspace
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UDrawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Locale } from 'vue-i18n'
|
||||
|
||||
const { t, setLocale } = useI18n()
|
||||
const onSelectLocale = async (locale: Locale) => {
|
||||
await setLocale(locale)
|
||||
}
|
||||
|
||||
const { currentVaultId } = storeToRefs(useVaultStore())
|
||||
const { showWindowOverview, openWindowsCount } = storeToRefs(
|
||||
useWindowManagerStore(),
|
||||
)
|
||||
|
||||
const workspaceStore = useWorkspaceStore()
|
||||
const { workspaces, isOverviewMode } = storeToRefs(workspaceStore)
|
||||
|
||||
const handleAddWorkspace = async () => {
|
||||
const workspace = await workspaceStore.addWorkspaceAsync()
|
||||
nextTick(() => {
|
||||
workspaceStore.slideToWorkspace(workspace?.id)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n lang="yaml">
|
||||
de:
|
||||
search:
|
||||
label: Suche
|
||||
|
||||
header:
|
||||
workspaces: Workspaces
|
||||
en:
|
||||
search:
|
||||
label: Search
|
||||
|
||||
header:
|
||||
workspaces: Workspaces
|
||||
</i18n>
|
||||
|
||||
@ -1,111 +1,132 @@
|
||||
<template>
|
||||
<div class="items-center justify-center flex w-full h-full relative">
|
||||
<div class="absolute top-8 right-8 sm:top-4 sm:right-4">
|
||||
<UiDropdownLocale @select="onSelectLocale" />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col justify-center items-center gap-5 max-w-3xl">
|
||||
<UiLogoHaexhub class="bg-primary p-3 size-16 rounded-full shrink-0" />
|
||||
<span
|
||||
class="flex flex-wrap font-bold text-pretty text-xl gap-2 justify-center"
|
||||
<div>
|
||||
<NuxtLayout>
|
||||
<UDashboardPanel
|
||||
id="inbox-1"
|
||||
resizable
|
||||
class=""
|
||||
>
|
||||
<p class="whitespace-nowrap">
|
||||
{{ t('welcome') }}
|
||||
</p>
|
||||
<UiTextGradient>Haex Hub</UiTextGradient>
|
||||
</span>
|
||||
<template #body>
|
||||
<div class="items-center justify-center flex relative flex-1">
|
||||
<!-- <div class="absolute top-0 right-0">
|
||||
<UiDropdownLocale @select="onSelectLocale" />
|
||||
</div> -->
|
||||
|
||||
<div class="flex flex-col md:flex-row gap-4 w-full h-24 md:h-auto">
|
||||
<HaexVaultCreate />
|
||||
|
||||
<HaexVaultOpen
|
||||
v-model:open="passwordPromptOpen"
|
||||
:path="selectedVault?.path"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-show="lastVaults.length"
|
||||
class="w-full"
|
||||
>
|
||||
<div class="font-thin text-sm justify-start px-2 pb-1">
|
||||
{{ t('lastUsed') }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="relative border-base-content/25 divide-base-content/25 flex w-full flex-col divide-y rounded-md border overflow-scroll"
|
||||
>
|
||||
<div
|
||||
v-for="vault in lastVaults"
|
||||
:key="vault.name"
|
||||
class="flex items-center justify-between group overflow-x-scroll"
|
||||
>
|
||||
<UButton
|
||||
variant="ghost"
|
||||
color="neutral"
|
||||
class="flex items-center no-underline justify-between text-nowrap text-sm md:text-base shrink w-full px-3"
|
||||
@click="
|
||||
() => {
|
||||
passwordPromptOpen = true
|
||||
selectedVault = vault
|
||||
}
|
||||
"
|
||||
<div
|
||||
class="flex flex-col justify-center items-center gap-5 max-w-3xl"
|
||||
>
|
||||
<span class="block">
|
||||
{{ vault.name }}
|
||||
</span>
|
||||
</UButton>
|
||||
<UButton
|
||||
color="error"
|
||||
square
|
||||
class="absolute right-2 hidden group-hover:flex min-w-6"
|
||||
>
|
||||
<Icon
|
||||
name="mdi:trash-can-outline"
|
||||
@click="prepareRemoveVault(vault.name)"
|
||||
<UiLogoHaexhub
|
||||
class="bg-primary p-3 size-16 rounded-full shrink-0"
|
||||
/>
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="flex flex-wrap font-bold text-pretty text-xl gap-2 justify-center"
|
||||
>
|
||||
<p class="whitespace-nowrap">
|
||||
{{ t('welcome') }}
|
||||
</p>
|
||||
<UiTextGradient>Haex Hub</UiTextGradient>
|
||||
</span>
|
||||
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<h4>{{ t('sponsors') }}</h4>
|
||||
<div>
|
||||
<UButton
|
||||
variant="link"
|
||||
@click="openUrl('https://itemis.com')"
|
||||
>
|
||||
<UiLogoItemis class="text-[#00457C]" />
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<UiDialogConfirm
|
||||
v-model:open="showRemoveDialog"
|
||||
:title="t('remove.title')"
|
||||
:description="t('remove.description', { vaultName: vaultToBeRemoved })"
|
||||
@confirm="onConfirmRemoveAsync"
|
||||
/>
|
||||
<div
|
||||
class="flex flex-col md:flex-row gap-4 w-full h-24 md:h-auto"
|
||||
>
|
||||
<HaexVaultCreate />
|
||||
|
||||
<HaexVaultOpen
|
||||
v-model:open="passwordPromptOpen"
|
||||
:path="selectedVault?.path"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-show="lastVaults.length"
|
||||
class="w-full"
|
||||
>
|
||||
<div class="font-thin text-sm justify-start px-2 pb-1">
|
||||
{{ t('lastUsed') }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="relative border-base-content/25 divide-base-content/25 flex w-full flex-col divide-y rounded-md border overflow-scroll"
|
||||
>
|
||||
<div
|
||||
v-for="vault in lastVaults"
|
||||
:key="vault.name"
|
||||
class="flex items-center justify-between group overflow-x-scroll"
|
||||
>
|
||||
<UButton
|
||||
variant="ghost"
|
||||
color="neutral"
|
||||
class="flex items-center no-underline justify-between text-nowrap text-sm md:text-base shrink w-full px-3"
|
||||
@click="
|
||||
() => {
|
||||
passwordPromptOpen = true
|
||||
selectedVault = vault
|
||||
}
|
||||
"
|
||||
>
|
||||
<span class="block">
|
||||
{{ vault.name }}
|
||||
</span>
|
||||
</UButton>
|
||||
<UButton
|
||||
color="error"
|
||||
square
|
||||
class="absolute right-2 hidden group-hover:flex min-w-6"
|
||||
>
|
||||
<Icon
|
||||
name="mdi:trash-can-outline"
|
||||
@click="prepareRemoveVault(vault.name)"
|
||||
/>
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<h4>{{ t('sponsors') }}</h4>
|
||||
<div>
|
||||
<UButton
|
||||
variant="link"
|
||||
@click="openUrl('https://itemis.com')"
|
||||
>
|
||||
<UiLogoItemis class="text-[#00457C]" />
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<UiDialogConfirm
|
||||
v-model:open="showRemoveDialog"
|
||||
:title="t('remove.title')"
|
||||
:description="
|
||||
t('remove.description', { vaultName: vaultToBeRemoved })
|
||||
"
|
||||
@confirm="onConfirmRemoveAsync"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</UDashboardPanel>
|
||||
</NuxtLayout>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import type { Locale } from 'vue-i18n'
|
||||
|
||||
import type { VaultInfo } from '@bindings/VaultInfo'
|
||||
|
||||
definePageMeta({
|
||||
name: 'vaultOpen',
|
||||
})
|
||||
|
||||
const { t, setLocale } = useI18n()
|
||||
const { t } = useI18n()
|
||||
|
||||
const passwordPromptOpen = ref(false)
|
||||
const selectedVault = ref<VaultInfo>()
|
||||
|
||||
const showRemoveDialog = ref(false)
|
||||
const { syncLastVaultsAsync, removeVaultAsync } = useLastVaultStore()
|
||||
|
||||
const { lastVaults } = storeToRefs(useLastVaultStore())
|
||||
|
||||
const vaultToBeRemoved = ref('')
|
||||
@ -127,17 +148,18 @@ const onConfirmRemoveAsync = async () => {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const { syncLastVaultsAsync, removeVaultAsync } = useLastVaultStore()
|
||||
const { syncDeviceIdAsync } = useDeviceStore()
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
await syncLastVaultsAsync()
|
||||
await syncDeviceIdAsync()
|
||||
} catch (error) {
|
||||
console.error('ERROR: ', error)
|
||||
}
|
||||
})
|
||||
|
||||
const onSelectLocale = async (locale: Locale) => {
|
||||
await setLocale(locale)
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n lang="yaml">
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="w-full h-full overflow-y-auto">
|
||||
<NuxtLayout name="app">
|
||||
<div>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
|
||||
@ -48,7 +48,7 @@ const newDeviceName = ref<string>('unknown')
|
||||
const { readNotificationsAsync } = useNotificationStore()
|
||||
const { isKnownDeviceAsync } = useDeviceStore()
|
||||
const { loadExtensionsAsync } = useExtensionsStore()
|
||||
const { setDeviceIdIfNotExistsAsync, addDeviceNameAsync } = useDeviceStore()
|
||||
const { addDeviceNameAsync } = useDeviceStore()
|
||||
const { deviceId } = storeToRefs(useDeviceStore())
|
||||
const { syncLocaleAsync, syncThemeAsync, syncVaultNameAsync } =
|
||||
useVaultSettingsStore()
|
||||
@ -56,11 +56,11 @@ const { syncLocaleAsync, syncThemeAsync, syncVaultNameAsync } =
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// Sync settings first before other initialization
|
||||
|
||||
await Promise.allSettled([
|
||||
syncLocaleAsync(),
|
||||
syncThemeAsync(),
|
||||
syncVaultNameAsync(),
|
||||
setDeviceIdIfNotExistsAsync(),
|
||||
loadExtensionsAsync(),
|
||||
readNotificationsAsync(),
|
||||
])
|
||||
|
||||
@ -10,6 +10,7 @@ export type IWorkspace = SelectHaexWorkspaces
|
||||
export const useWorkspaceStore = defineStore('workspaceStore', () => {
|
||||
const vaultStore = useVaultStore()
|
||||
const windowStore = useWindowManagerStore()
|
||||
const { deviceId } = storeToRefs(useDeviceStore())
|
||||
|
||||
const { currentVault } = storeToRefs(vaultStore)
|
||||
|
||||
@ -31,10 +32,16 @@ export const useWorkspaceStore = defineStore('workspaceStore', () => {
|
||||
return
|
||||
}
|
||||
|
||||
if (!deviceId.value) {
|
||||
console.error('Keine DeviceId vergeben')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const items = await currentVault.value.drizzle
|
||||
.select()
|
||||
.from(haexWorkspaces)
|
||||
.where(eq(haexWorkspaces.deviceId, deviceId.value))
|
||||
.orderBy(asc(haexWorkspaces.position))
|
||||
|
||||
workspaces.value = items
|
||||
@ -58,11 +65,16 @@ export const useWorkspaceStore = defineStore('workspaceStore', () => {
|
||||
throw new Error('Kein Vault geöffnet')
|
||||
}
|
||||
|
||||
if (!deviceId.value) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const newIndex = workspaces.value.length + 1
|
||||
const newWorkspace = {
|
||||
name: name || `Workspace ${newIndex}`,
|
||||
position: workspaces.value.length,
|
||||
deviceId: deviceId.value,
|
||||
}
|
||||
|
||||
const result = await currentVault.value.drizzle
|
||||
|
||||
@ -4,8 +4,18 @@ import {
|
||||
platform as tauriPlatform,
|
||||
} from '@tauri-apps/plugin-os'
|
||||
|
||||
export const useDeviceStore = defineStore('vaultInstanceStore', () => {
|
||||
const deviceId = ref<string>()
|
||||
const deviceIdKey = 'deviceId'
|
||||
const defaultDeviceFileName = 'device.json'
|
||||
|
||||
export const useDeviceStore = defineStore('vaultDeviceStore', () => {
|
||||
const deviceId = ref<string | undefined>('')
|
||||
|
||||
const syncDeviceIdAsync = async () => {
|
||||
deviceId.value = await getDeviceIdAsync()
|
||||
if (deviceId.value) return deviceId.value
|
||||
|
||||
deviceId.value = await setDeviceIdAsync()
|
||||
}
|
||||
|
||||
const platform = computedAsync(() => tauriPlatform())
|
||||
|
||||
@ -15,7 +25,7 @@ export const useDeviceStore = defineStore('vaultInstanceStore', () => {
|
||||
|
||||
const getDeviceIdAsync = async () => {
|
||||
const store = await getStoreAsync()
|
||||
return store.get<string>('id')
|
||||
return await store.get<string>(deviceIdKey)
|
||||
}
|
||||
|
||||
const getStoreAsync = async () => {
|
||||
@ -23,30 +33,19 @@ export const useDeviceStore = defineStore('vaultInstanceStore', () => {
|
||||
public: { haexVault },
|
||||
} = useRuntimeConfig()
|
||||
|
||||
return await load(haexVault.instanceFileName || 'instance.json')
|
||||
return await load(haexVault.deviceFileName || defaultDeviceFileName)
|
||||
}
|
||||
|
||||
const setDeviceIdAsync = async (id?: string) => {
|
||||
const store = await getStoreAsync()
|
||||
const _id = id || crypto.randomUUID()
|
||||
await store.set('id', _id)
|
||||
deviceId.value = _id
|
||||
await store.set(deviceIdKey, _id)
|
||||
return _id
|
||||
}
|
||||
|
||||
const setDeviceIdIfNotExistsAsync = async () => {
|
||||
const _deviceId = await getDeviceIdAsync()
|
||||
if (_deviceId) {
|
||||
deviceId.value = _deviceId
|
||||
return deviceId.value
|
||||
}
|
||||
return await setDeviceIdAsync()
|
||||
}
|
||||
|
||||
const isKnownDeviceAsync = async () => {
|
||||
const { readDeviceNameAsync } = useVaultSettingsStore()
|
||||
const deviceId = await getDeviceIdAsync()
|
||||
return deviceId ? (await readDeviceNameAsync(deviceId)) || false : false
|
||||
return !!(await readDeviceNameAsync(deviceId.value))
|
||||
}
|
||||
|
||||
const readDeviceNameAsync = async (id?: string) => {
|
||||
@ -99,12 +98,13 @@ export const useDeviceStore = defineStore('vaultInstanceStore', () => {
|
||||
addDeviceNameAsync,
|
||||
deviceId,
|
||||
deviceName,
|
||||
getDeviceIdAsync,
|
||||
hostname,
|
||||
isKnownDeviceAsync,
|
||||
platform,
|
||||
readDeviceNameAsync,
|
||||
setDeviceIdAsync,
|
||||
setDeviceIdIfNotExistsAsync,
|
||||
syncDeviceIdAsync,
|
||||
updateDeviceNameAsync,
|
||||
}
|
||||
})
|
||||
|
||||
@ -118,9 +118,11 @@ export const useVaultSettingsStore = defineStore('vaultSettingsStore', () => {
|
||||
.where(eq(schema.haexSettings.key, 'vaultName'))
|
||||
}
|
||||
|
||||
const readDeviceNameAsync = async (id: string) => {
|
||||
const readDeviceNameAsync = async (id?: string) => {
|
||||
const { currentVault } = useVaultStore()
|
||||
|
||||
if (!id) return undefined
|
||||
|
||||
const deviceName =
|
||||
await currentVault?.drizzle?.query.haexSettings.findFirst({
|
||||
where: and(
|
||||
|
||||
Reference in New Issue
Block a user