zwischenstand

This commit is contained in:
2025-05-28 11:35:02 +02:00
parent 07ff15aba0
commit 4774d3fdc1
105 changed files with 4129 additions and 1438 deletions

View File

@ -1,28 +1,48 @@
<template>
<UiDialog :title="t('title')" v-model:open="open"
class="btn btn-primary btn-outline shadow-md md:btn-lg shrink-0 flex-1 whitespace-nowrap flex-nowrap">
<UiDialog
v-model:open="open"
:title="t('title')"
class="btn btn-primary btn-outline shadow-md md:btn-lg shrink-0 flex-1 whitespace-nowrap flex-nowrap"
>
<template #trigger>
<Icon name="mdi:plus" />
{{ t('database.create') }}
</template>
<form class="flex flex-col gap-4" @submit="onCreateAsync">
<UiInput :check-input="check" :label="t('database.label')" :placeholder="t('database.placeholder')"
:rules="vaultDatabaseSchema.name" autofocus prepend-icon="mdi:safe" v-model="database.name" />
<form
class="flex flex-col gap-4"
@submit="onCreateAsync"
>
<UiInput
v-model="database.name"
:check-input="check"
:label="t('database.label')"
:placeholder="t('database.placeholder')"
:rules="vaultDatabaseSchema.name"
autofocus
prepend-icon="mdi:safe"
/>
<UiInputPassword :check-input="check" :rules="vaultDatabaseSchema.password" prepend-icon="mdi:key-outline"
v-model="database.password" />
<UiInputPassword
v-model="database.password"
:check-input="check"
:rules="vaultDatabaseSchema.password"
prepend-icon="mdi:key-outline"
/>
</form>
<template #buttons>
<UiButton class="btn-error" @click="onClose">
<UiButton
class="btn-error"
@click="onClose"
>
{{ t('abort') }}
</UiButton>
<UiButton class="btn-primary" @click="onCreateAsync">
<UiButton
class="btn-primary"
@click="onCreateAsync"
>
{{ t('create') }}
</UiButton>
</template>
@ -74,7 +94,7 @@ const onCreateAsync = async () => {
const nameCheck = vaultDatabaseSchema.name.safeParse(database.name)
const passwordCheck = vaultDatabaseSchema.password.safeParse(
database.password
database.password,
)
console.log(
@ -82,7 +102,7 @@ const onCreateAsync = async () => {
database.name,
nameCheck,
database.password,
passwordCheck
passwordCheck,
)
if (!nameCheck.success || !passwordCheck.success) return
@ -105,7 +125,7 @@ const onCreateAsync = async () => {
console.log('vaultId', vaultId)
if (vaultId) {
await navigateTo(
useLocaleRoute()({ name: 'vaultOverview', params: { vaultId } })
useLocaleRoute()({ name: 'vaultOverview', params: { vaultId } }),
)
}
}
@ -121,7 +141,8 @@ const onClose = () => {
}
</script>
<i18n lang="json">{
<i18n lang="json">
{
"de": {
"database": {
"label": "Vaultname",
@ -146,4 +167,5 @@ const onClose = () => {
"abort": "Abort",
"description": "Haex Vault for your most secret secrets"
}
}</i18n>
}
</i18n>

View File

@ -1,40 +1,52 @@
<template>
<UiDialog v-model:open="isOpen" class="btn btn-primary btn-outline shadow-md md:btn-lg shrink-0 flex-1 "
@open="onLoadDatabase">
<UiDialogConfirm
v-model:open="open"
class="btn btn-primary btn-outline shadow-md md:btn-lg shrink-0 flex-1"
:confirm-label="t('open')"
:abort-label="t('abort')"
@open="onLoadDatabase"
@abort="onAbort"
>
<template #title>
<i18n-t
keypath="title"
tag="p"
class="flex gap-2"
>
<template #haexvault>
<UiTextGradient>HaexVault</UiTextGradient>
</template>
</i18n-t>
<p class="text-sm">{{ path }}</p>
</template>
<template #trigger>
<Icon name="mdi:folder-open-outline" />
{{ t('database.open') }}
</template>
<UiInputPassword :check-input="check" :rules="vaultDatabaseSchema.password" @keyup.enter="onOpenDatabase" autofocus
prepend-icon="mdi:key-outline" v-model="database.password" />
<template #buttons>
<UiButton class="btn-error" @click="onClose">
{{ t('abort') }}
</UiButton>
<UiButton type="submit" class="btn-primary" @click="onOpenDatabase">
{{ t('open') }}
</UiButton>
</template>
</UiDialog>
<UiInputPassword
v-model="database.password"
:check-input="check"
:rules="vaultDatabaseSchema.password"
autofocus
prepend-icon="mdi:key-outline"
@keyup.enter="onOpenDatabase"
/>
</UiDialogConfirm>
</template>
<script setup lang="ts">
import { open } from '@tauri-apps/plugin-dialog'
import { open as openVault } from '@tauri-apps/plugin-dialog'
import { vaultDatabaseSchema } from './schema'
const { t } = useI18n()
const isOpen = defineModel('isOpen', { type: Boolean })
const open = defineModel('open', { type: Boolean })
const props = defineProps({
path: String,
})
const props = defineProps<{
path: string
}>()
const check = ref(false)
@ -62,7 +74,7 @@ initDatabase()
const { add } = useSnackbar()
const handleError = (error: unknown) => {
isOpen.value = false
open.value = false
console.error('handleError', error, typeof error)
add({ type: 'error', text: 'Passwort falsch' })
}
@ -71,7 +83,7 @@ const { openAsync } = useVaultStore()
const onLoadDatabase = async () => {
try {
database.path = await open({
database.path = await openVault({
multiple: false,
directory: false,
filters: [
@ -82,10 +94,9 @@ const onLoadDatabase = async () => {
],
})
console.log("database.path", database.path)
if (!database.path) return
isOpen.value = true
open.value = true
} catch (error) {
handleError(error)
}
@ -100,7 +111,7 @@ const onOpenDatabase = async () => {
const path = database.path || props.path
const pathCheck = vaultDatabaseSchema.path.safeParse(path)
const passwordCheck = vaultDatabaseSchema.password.safeParse(
database.password
database.password,
)
if (!pathCheck.success || !passwordCheck.success || !path) {
@ -124,7 +135,7 @@ const onOpenDatabase = async () => {
return
}
onClose()
onAbort()
await navigateTo(
localePath({
@ -132,7 +143,7 @@ const onOpenDatabase = async () => {
params: {
vaultId,
},
})
}),
)
await Promise.allSettled([
syncLocaleAsync(),
@ -144,25 +155,24 @@ const onOpenDatabase = async () => {
}
}
const onClose = () => {
const onAbort = () => {
initDatabase()
isOpen.value = false
open.value = false
}
</script>
<i18n lang="json">{
"de": {
"open": "Öffnen",
"abort": "Abbrechen",
"database": {
"open": "Vault öffnen"
}
},
"en": {
"open": "Open",
"abort": "Abort",
"database": {
"open": "Open Vault"
}
}
}</i18n>
<i18n lang="yaml">
de:
open: Öffnen
abort: Abbrechen
title: '{haexvault} entsperren'
database:
open: Vault öffnen
en:
open: Open
abort: Abort
title: Unlock {haexvault}
database:
open: Open Vault
</i18n>

View File

@ -66,7 +66,6 @@
<div
class="flex flex-col items-center w-full min-h-14 gap-2 py-1"
:class="{ '-ml-6': !show }"
:style="{ color }"
>
<Icon
@ -91,10 +90,7 @@
v-show="!read_only"
class="fixed bottom-2 left-0 w-full flex items-center justify-between px-4 md:hidden"
>
<div
class="transition-all duration-500"
:class="{ 'pl-96': show }"
>
<div class="transition-all duration-500">
<button
class="btn btn-square btn-error btn-outline"
@click="onClose"
@ -112,7 +108,7 @@
<span class="hidden"> {{ t('create') }} </span>
</button>
</div>
<div></div>
<div />
</div>
<!-- <UiButtonAction
class=""
@ -129,89 +125,86 @@
</template>
<script setup lang="ts">
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router';
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router'
const { t } = useI18n();
const { t } = useI18n()
const { show } = storeToRefs(useSidebarStore());
const read_only = defineModel<boolean>('read_only', { default: false })
const read_only = defineModel<boolean>('read_only', { default: false });
const props = defineProps({
color: String,
hasChanges: Boolean,
icon: String,
title: String,
});
const props = defineProps<{
color: string
hasChanges: boolean
icon: string
title: string
}>()
const emit = defineEmits<{
back: [void];
close: [void];
reject: [to?: RouteLocationNormalizedLoadedGeneric];
submit: [to?: RouteLocationNormalizedLoadedGeneric];
}>();
back: [void]
close: [void]
reject: [to?: RouteLocationNormalizedLoadedGeneric]
submit: [to?: RouteLocationNormalizedLoadedGeneric]
}>()
const showConfirmation = ref(false);
const showConfirmation = ref(false)
const to = ref<RouteLocationNormalizedLoadedGeneric>();
const to = ref<RouteLocationNormalizedLoadedGeneric>()
const isApprovedForLeave = ref(false);
const isApprovedForLeave = ref(false)
const wantToGoBack = ref(false);
const wantToGoBack = ref(false)
const onSubmit = () => {
showConfirmation.value = false;
isApprovedForLeave.value = true;
showConfirmation.value = false
isApprovedForLeave.value = true
if (wantToGoBack.value) {
wantToGoBack.value = false;
read_only.value = true;
emit('submit');
wantToGoBack.value = false
read_only.value = true
emit('submit')
} else {
emit('submit', to.value);
emit('submit', to.value)
}
};
}
const onReject = () => {
showConfirmation.value = false;
isApprovedForLeave.value = true;
read_only.value = true;
showConfirmation.value = false
isApprovedForLeave.value = true
read_only.value = true
if (wantToGoBack.value) {
wantToGoBack.value = false;
emit('back');
} else emit('reject', to.value);
};
wantToGoBack.value = false
emit('back')
} else emit('reject', to.value)
}
const onBack = () => {
if (props.hasChanges) {
wantToGoBack.value = true;
showConfirmation.value = true;
wantToGoBack.value = true
showConfirmation.value = true
} else {
emit('back');
emit('back')
}
};
}
const onClose = () => {
if (props.hasChanges) {
showConfirmation.value = true;
showConfirmation.value = true
} else {
emit('close'); //read_only.value = true;
emit('close') //read_only.value = true;
}
};
}
const onDelete = () => {};
onBeforeRouteLeave((_to, _from, next) => {
//console.log('check before leave', _to, _from);
to.value = _to;
to.value = _to
if (isApprovedForLeave.value) {
isApprovedForLeave.value = false;
next();
isApprovedForLeave.value = false
next()
} else if (props.hasChanges) {
showConfirmation.value = true;
showConfirmation.value = true
} else {
next();
next()
}
});
})
</script>
<i18n lang="json">

View File

@ -4,7 +4,7 @@
<div class="card-header">
<div v-if="$slots.title || title">
<Icon :name="icon" />
<Icon v-if="icon" :name="icon" />
<h5 v-if="title" class="card-title mb-0">
{{ title }}
</h5>
@ -16,7 +16,7 @@
<div class="card-body">
<slot />
aaaaaaaaa
<div class="card-actions" v-if="$slots.action">
<div v-if="$slots.action" class="card-actions">
<slot name="action" />
</div>
</div>

View File

@ -1,6 +1,7 @@
<template>
<VaultCardEdit
v-if="vaultGroup"
v-model:read_only="read_only"
:color="vaultGroup.color ?? 'text-base-content'"
:has-changes="hasChanges"
:icon="vaultGroup.icon ?? 'mdi:folder-outline'"
@ -9,42 +10,41 @@
@close="$emit('close')"
@reject="(to) => $emit('reject', to)"
@submit="(to) => $emit('submit', to)"
v-model:read_only="read_only"
>
<div class="flex flex-col gap-4 w-full p-4">
<UiInput
v-show="!read_only"
v-model.trim="vaultGroup.name"
:label="t('vaultGroup.name')"
:placeholder="t('vaultGroup.name')"
:rules="vaultGroupSchema.name"
:with-copy-button="read_only"
:read_only
autofocus
v-model.trim="vaultGroup.name"
/>
<UiInput
v-show="!read_only || vaultGroup.description?.length"
v-model.trim="vaultGroup.description"
:read_only
:label="t('vaultGroup.description')"
:placeholder="t('vaultGroup.description')"
:rules="vaultGroupSchema.description"
:with-copy-button="read_only"
v-model.trim="vaultGroup.description"
/>
<UiColorPicker
v-model="vaultGroup.color"
:read_only
:label="t('vaultGroup.color')"
:placeholder="t('vaultGroup.color')"
v-model="vaultGroup.color"
/>
<UiIconPicker
v-model="vaultGroup.icon"
:read_only
:label="t('vaultGroup.icon')"
:placeholder="t('vaultGroup.icon')"
v-model="vaultGroup.icon"
/>
</div>
</VaultCardEdit>

View File

@ -1,42 +0,0 @@
<template>
<UiListButton
v-if="entry"
:key="entry.id"
@click="navigateToEntryAsync(entry.id)"
class="text-base-content"
>
<div class="flex items-center gap-3">
<div class="w-8">
<Icon
v-if="entry.icon || groupIcon"
:name="entry.icon || groupIcon!"
/>
</div>
<div class="flex flex-col items-start">
<div v-if="!entry.title && !entry.username && !entry.url">
{{ entry.id }}
</div>
<div class="font-semibold">
{{ entry.title }}
</div>
<span class="text-sm">
{{ entry.username }}
</span>
<span class="text-sm">
{{ entry.url }}
</span>
</div>
</div>
</UiListButton>
</template>
<script setup lang="ts">
import type { SelectVaultEntry } from '~/database/schemas/vault';
defineProps({
entry: Object as PropType<SelectVaultEntry>,
groupIcon: [String, null],
});
const { navigateToEntryAsync } = useVaultEntryStore();
</script>

View File

@ -16,9 +16,9 @@
</span>
</UiButton>
<UiButton
ref="abortButtonRef"
class="btn-outline focus:bg-primary"
tabindex="11"
ref="abortButtonRef"
@click="showConfirmation = false"
>
<Icon name="mdi:close" />
@ -41,17 +41,16 @@
</template>
<script setup lang="ts">
const showConfirmation = defineModel<boolean>();
const abortButtonRef = useTemplateRef('abortButtonRef');
const showConfirmation = defineModel<boolean>()
const abortButtonRef = useTemplateRef('abortButtonRef')
const { t } = useI18n();
const { currentScreenSize } = storeToRefs(useUiStore());
const { t } = useI18n()
onUpdated(() => {
abortButtonRef.value?.$el.focus();
});
abortButtonRef.value?.$el.focus()
})
defineEmits(['submit', 'reject']);
defineEmits(['submit', 'reject'])
</script>
<i18n lang="json">