mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-17 14:30:52 +01:00
switch to nuxt ui
This commit is contained in:
@ -1,127 +1,101 @@
|
||||
<template>
|
||||
<UiDialogConfirm
|
||||
v-model:open="open"
|
||||
class="btn btn-primary btn-outline shadow-md btn-lg"
|
||||
@click="open = true"
|
||||
@abort="open = false"
|
||||
@confirm="onCreateAsync"
|
||||
:confirm-label="t('create')"
|
||||
@confirm="onCreateAsync"
|
||||
>
|
||||
<template #trigger>
|
||||
<Icon name="mdi:plus" />
|
||||
{{ t('database.create') }}
|
||||
</template>
|
||||
<UiButton
|
||||
:label="t('vault.create')"
|
||||
:ui="{
|
||||
base: 'px-3 py-2',
|
||||
}"
|
||||
icon="mdi:plus"
|
||||
size="xl"
|
||||
variant="outline"
|
||||
block
|
||||
/>
|
||||
|
||||
<template #title>
|
||||
<div class="flex gap-x-2 items-center">
|
||||
<Icon
|
||||
name="mdi:safe"
|
||||
class="text-primary"
|
||||
/>
|
||||
<p>
|
||||
{{ t('title') }}
|
||||
</p>
|
||||
</div>
|
||||
<i18n-t
|
||||
keypath="title"
|
||||
tag="p"
|
||||
class="flex gap-x-2 flex-wrap"
|
||||
>
|
||||
<template #haexvault>
|
||||
<UiTextGradient>HaexVault</UiTextGradient>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</template>
|
||||
<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
|
||||
v-model="database.password"
|
||||
:check-input="check"
|
||||
:rules="vaultDatabaseSchema.password"
|
||||
prepend-icon="mdi:key-outline"
|
||||
/>
|
||||
</form>
|
||||
|
||||
<!-- <template #buttons>
|
||||
<UiButton
|
||||
class="btn-error btn-outline w-full sm:w-auto"
|
||||
@click="onClose"
|
||||
<template #body>
|
||||
<UForm
|
||||
:state="vault"
|
||||
class="flex flex-col gap-4 w-full h-full justify-center"
|
||||
>
|
||||
<Icon name="mdi:x" />
|
||||
{{ t('abort') }}
|
||||
</UiButton>
|
||||
<UiInput
|
||||
v-model="vault.name"
|
||||
leading-icon="mdi:safe"
|
||||
:label="t('vault.label')"
|
||||
:placeholder="t('vault.placeholder')"
|
||||
/>
|
||||
<UiInputPassword
|
||||
v-model="vault.password"
|
||||
leading-icon="mdi:key-outline"
|
||||
/>
|
||||
|
||||
<UiButton
|
||||
class="btn-primary w-full sm:w-auto"
|
||||
@click="onCreateAsync"
|
||||
>
|
||||
{{ t('create') }}
|
||||
</UiButton>
|
||||
</template> -->
|
||||
<UButton
|
||||
hidden
|
||||
type="submit"
|
||||
@click="onCreateAsync"
|
||||
/>
|
||||
</UForm>
|
||||
</template>
|
||||
</UiDialogConfirm>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { save } from '@tauri-apps/plugin-dialog'
|
||||
import { onKeyStroke } from '@vueuse/core'
|
||||
import { useVaultStore } from '~/stores/vault'
|
||||
import { vaultDatabaseSchema } from './schema'
|
||||
import { BaseDirectory, readFile, writeFile } from '@tauri-apps/plugin-fs'
|
||||
import { resolveResource } from '@tauri-apps/api/path'
|
||||
//import { convertFileSrc } from "@tauri-apps/api/tauri";
|
||||
|
||||
onKeyStroke('Enter', (e) => {
|
||||
e.preventDefault()
|
||||
onCreateAsync()
|
||||
})
|
||||
|
||||
const check = ref(false)
|
||||
const open = ref()
|
||||
import { vaultSchema } from './schema'
|
||||
//import type { FormSubmitEvent } from '@nuxt/ui'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const database = reactive<{
|
||||
//type Schema = z.output<typeof vaultSchema>
|
||||
|
||||
const vault = reactive<{
|
||||
name: string
|
||||
password: string
|
||||
path: string | null
|
||||
type: 'password' | 'text'
|
||||
}>({
|
||||
name: '',
|
||||
name: 'HaexVault',
|
||||
password: '',
|
||||
path: '',
|
||||
type: 'password',
|
||||
})
|
||||
|
||||
const initDatabase = () => {
|
||||
database.name = t('database.name')
|
||||
database.password = ''
|
||||
database.path = ''
|
||||
database.type = 'password'
|
||||
const initVault = () => {
|
||||
vault.name = 'HaexVault'
|
||||
vault.password = ''
|
||||
vault.path = ''
|
||||
vault.type = 'password'
|
||||
}
|
||||
|
||||
initDatabase()
|
||||
|
||||
const { add } = useSnackbar()
|
||||
const { createAsync } = useVaultStore()
|
||||
const { add } = useToast()
|
||||
|
||||
const check = ref(false)
|
||||
const open = ref()
|
||||
|
||||
const onCreateAsync = async () => {
|
||||
check.value = true
|
||||
|
||||
const nameCheck = vaultDatabaseSchema.name.safeParse(database.name)
|
||||
const passwordCheck = vaultDatabaseSchema.password.safeParse(
|
||||
database.password,
|
||||
)
|
||||
const nameCheck = vaultSchema.name.safeParse(vault.name)
|
||||
const passwordCheck = vaultSchema.password.safeParse(vault.password)
|
||||
|
||||
console.log(
|
||||
'checks',
|
||||
database.name,
|
||||
nameCheck,
|
||||
database.password,
|
||||
passwordCheck,
|
||||
)
|
||||
console.log('checks', vault.name, nameCheck, vault.password, passwordCheck)
|
||||
if (!nameCheck.success || !passwordCheck.success) return
|
||||
|
||||
open.value = false
|
||||
@ -130,28 +104,27 @@ const onCreateAsync = async () => {
|
||||
|
||||
const template_vault = await readFile(template_vault_path)
|
||||
|
||||
database.path = await save({
|
||||
defaultPath: database.name.endsWith('.db')
|
||||
? database.name
|
||||
: `${database.name}.db`,
|
||||
vault.path = await save({
|
||||
defaultPath: vault.name.endsWith('.db') ? vault.name : `${vault.name}.db`,
|
||||
})
|
||||
|
||||
if (!database.path) return
|
||||
if (!vault.path) return
|
||||
|
||||
await writeFile('temp_vault.db', template_vault, {
|
||||
baseDir: BaseDirectory.AppLocalData,
|
||||
})
|
||||
|
||||
console.log('data', database)
|
||||
console.log('data', vault)
|
||||
|
||||
if (database.path && database.password) {
|
||||
if (vault.path && vault.password) {
|
||||
const vaultId = await createAsync({
|
||||
path: database.path,
|
||||
password: database.password,
|
||||
path: vault.path,
|
||||
password: vault.password,
|
||||
})
|
||||
|
||||
console.log('vaultId', vaultId)
|
||||
if (vaultId) {
|
||||
initVault()
|
||||
await navigateTo(
|
||||
useLocaleRoute()({ name: 'vaultOverview', params: { vaultId } }),
|
||||
)
|
||||
@ -159,41 +132,27 @@ const onCreateAsync = async () => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
add({ type: 'error', text: `${error}` })
|
||||
add({ color: 'error', description: `${error}` })
|
||||
}
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
open.value = false
|
||||
initDatabase()
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n lang="json">
|
||||
{
|
||||
"de": {
|
||||
"database": {
|
||||
"label": "Vaultname",
|
||||
"placeholder": "Vaultname",
|
||||
"create": "Neue Vault anlegen",
|
||||
"name": "HaexVault"
|
||||
},
|
||||
"title": "Neue Vault anlegen",
|
||||
"create": "Erstellen",
|
||||
"abort": "Abbrechen",
|
||||
"description": "Haex Vault für deine geheimsten Geheimnisse"
|
||||
},
|
||||
"en": {
|
||||
"database": {
|
||||
"label": "Vaultname",
|
||||
"placeholder": "Vaultname",
|
||||
"create": "Create new Vault",
|
||||
"name": "HaexVault"
|
||||
},
|
||||
"title": "Create New Vault",
|
||||
"create": "Create",
|
||||
"abort": "Abort",
|
||||
"description": "Haex Vault for your most secret secrets"
|
||||
}
|
||||
}
|
||||
<i18n lang="yaml">
|
||||
de:
|
||||
vault:
|
||||
create: Neue Vault erstellen
|
||||
label: Vaultname
|
||||
placeholder: Vaultname
|
||||
name: HaexVault
|
||||
title: Neue {haexvault} erstellen
|
||||
create: Erstellen
|
||||
|
||||
en:
|
||||
vault:
|
||||
create: Create new vault
|
||||
label: Vaultname
|
||||
placeholder: Vaultname
|
||||
name: HaexVault
|
||||
title: Create new {haexvault}
|
||||
create: Create
|
||||
</i18n>
|
||||
|
||||
@ -1,67 +1,62 @@
|
||||
<template>
|
||||
<UiDialogConfirm
|
||||
v-model:open="open"
|
||||
class="btn btn-primary btn-outline shadow-md btn-lg"
|
||||
:confirm-label="t('open')"
|
||||
:abort-label="t('abort')"
|
||||
@abort="onAbort"
|
||||
:description="vault.path || path"
|
||||
@confirm="onOpenDatabase"
|
||||
@open="onLoadDatabase"
|
||||
>
|
||||
<UiButton
|
||||
:label="t('vault.open')"
|
||||
:ui="{
|
||||
base: 'px-3 py-2',
|
||||
}"
|
||||
icon="mdi:folder-open-outline"
|
||||
size="xl"
|
||||
variant="outline"
|
||||
block
|
||||
@click.stop="onLoadDatabase"
|
||||
/>
|
||||
|
||||
<template #title>
|
||||
<i18n-t
|
||||
keypath="title"
|
||||
tag="p"
|
||||
class="flex gap-x-2 flex-wrap"
|
||||
class="flex gap-x-2 text-wrap"
|
||||
>
|
||||
<template #haexvault>
|
||||
<UiTextGradient>HaexVault</UiTextGradient>
|
||||
</template>
|
||||
</i18n-t>
|
||||
Path1: {{ test }}
|
||||
<div class="text-sm">{{ props.path ?? database.path }}</div>
|
||||
</template>
|
||||
|
||||
<template #trigger>
|
||||
<Icon name="mdi:folder-open-outline" />
|
||||
{{ t('database.open') }}
|
||||
</template>
|
||||
<template #body>
|
||||
<UForm
|
||||
:state="vault"
|
||||
class="flex flex-col gap-4 w-full h-full justify-center"
|
||||
>
|
||||
<UiInputPassword
|
||||
v-model="vault.password"
|
||||
class="w-full"
|
||||
autofocus
|
||||
/>
|
||||
|
||||
<UiInputPassword
|
||||
:check-input="check"
|
||||
:rules="vaultDatabaseSchema.password"
|
||||
@keyup.enter="onOpenDatabase"
|
||||
autofocus
|
||||
prepend-icon="mdi:key-outline"
|
||||
v-model="database.password"
|
||||
/>
|
||||
<UButton
|
||||
hidden
|
||||
type="submit"
|
||||
@click="onOpenDatabase"
|
||||
/>
|
||||
</UForm>
|
||||
</template>
|
||||
</UiDialogConfirm>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { open as openVault } from '@tauri-apps/plugin-dialog'
|
||||
import { vaultDatabaseSchema } from './schema'
|
||||
import {
|
||||
BaseDirectory,
|
||||
copyFile,
|
||||
mkdir,
|
||||
exists,
|
||||
readFile,
|
||||
writeFile,
|
||||
stat,
|
||||
} from '@tauri-apps/plugin-fs'
|
||||
import { vaultSchema } from './schema'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const open = defineModel('open', { type: Boolean })
|
||||
|
||||
const props = defineProps<{
|
||||
path: string
|
||||
}>()
|
||||
|
||||
const check = ref(false)
|
||||
|
||||
const database = reactive<{
|
||||
const vault = reactive<{
|
||||
name: string
|
||||
password: string
|
||||
path: string | null
|
||||
@ -73,28 +68,13 @@ const database = reactive<{
|
||||
type: 'password',
|
||||
})
|
||||
|
||||
const initDatabase = () => {
|
||||
database.name = ''
|
||||
database.password = ''
|
||||
database.path = ''
|
||||
database.type = 'password'
|
||||
}
|
||||
const open = defineModel('open', { type: Boolean })
|
||||
|
||||
initDatabase()
|
||||
|
||||
const { add } = useSnackbar()
|
||||
|
||||
const handleError = (error: unknown) => {
|
||||
open.value = false
|
||||
console.error('handleError', error, typeof error)
|
||||
add({ type: 'error', text: `${error}` })
|
||||
}
|
||||
|
||||
const { openAsync } = useVaultStore()
|
||||
const { add } = useToast()
|
||||
|
||||
const onLoadDatabase = async () => {
|
||||
try {
|
||||
database.path = await openVault({
|
||||
vault.path = await openVault({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
filters: [
|
||||
@ -105,50 +85,62 @@ const onLoadDatabase = async () => {
|
||||
],
|
||||
})
|
||||
|
||||
console.log('onLoadDatabase', database.path)
|
||||
if (!database.path) return
|
||||
console.log('onLoadDatabase', vault.path)
|
||||
if (!vault.path) {
|
||||
open.value = false
|
||||
return
|
||||
}
|
||||
|
||||
open.value = true
|
||||
} catch (error) {
|
||||
handleError(error)
|
||||
open.value = false
|
||||
console.error('handleError', error, typeof error)
|
||||
add({ color: 'error', description: `${error}` })
|
||||
}
|
||||
}
|
||||
|
||||
const localePath = useLocalePath()
|
||||
|
||||
const { syncLocaleAsync, syncThemeAsync, syncVaultNameAsync } =
|
||||
useVaultSettingsStore()
|
||||
|
||||
const props = defineProps<{
|
||||
path: string
|
||||
}>()
|
||||
|
||||
const check = ref(false)
|
||||
|
||||
const initVault = () => {
|
||||
vault.name = ''
|
||||
vault.password = ''
|
||||
vault.path = ''
|
||||
vault.type = 'password'
|
||||
}
|
||||
|
||||
const onAbort = () => {
|
||||
initVault()
|
||||
open.value = false
|
||||
}
|
||||
|
||||
const onOpenDatabase = async () => {
|
||||
try {
|
||||
const { openAsync } = useVaultStore()
|
||||
const localePath = useLocalePath()
|
||||
|
||||
check.value = true
|
||||
const path = database.path || props.path
|
||||
const pathCheck = vaultDatabaseSchema.path.safeParse(path)
|
||||
const passwordCheck = vaultDatabaseSchema.password.safeParse(
|
||||
database.password,
|
||||
)
|
||||
const path = vault.path || props.path
|
||||
const pathCheck = vaultSchema.path.safeParse(path)
|
||||
const passwordCheck = vaultSchema.password.safeParse(vault.password)
|
||||
|
||||
/* if (!pathCheck.success || !passwordCheck.success || !path) {
|
||||
add({
|
||||
type: 'error',
|
||||
text: `Params falsch. Path: ${pathCheck.error} | Password: ${passwordCheck.error}`,
|
||||
})
|
||||
return
|
||||
} */
|
||||
|
||||
//const vaultName = await copyDatabaseInAppDirectoryAsync(path)
|
||||
|
||||
//if (!vaultName) return
|
||||
if (pathCheck.error || passwordCheck.error) return
|
||||
|
||||
const vaultId = await openAsync({
|
||||
path,
|
||||
password: database.password,
|
||||
password: vault.password,
|
||||
})
|
||||
|
||||
if (!vaultId) {
|
||||
add({
|
||||
type: 'error',
|
||||
text: 'Vault konnte nicht geöffnet werden. \n Vermutlich ist das Passwort falsch',
|
||||
color: 'error',
|
||||
description: t('error.open'),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -169,53 +161,31 @@ const onOpenDatabase = async () => {
|
||||
syncVaultNameAsync(),
|
||||
])
|
||||
} catch (error) {
|
||||
handleError(error)
|
||||
open.value = false
|
||||
console.error('handleError', error, typeof error)
|
||||
add({ color: 'error', description: `${error}` })
|
||||
}
|
||||
}
|
||||
|
||||
const test = ref()
|
||||
const copyDatabaseInAppDirectoryAsync = async (source: string) => {
|
||||
const vaultName = getFileName(source)
|
||||
const vaultsDirExists = await exists('vaults', {
|
||||
baseDir: BaseDirectory.AppLocalData,
|
||||
})
|
||||
//convertFileSrc
|
||||
if (!vaultsDirExists) {
|
||||
await mkdir('vaults', {
|
||||
baseDir: BaseDirectory.AppLocalData,
|
||||
})
|
||||
}
|
||||
|
||||
test.value = `source: ${source} - target: vaults/${vaultName}`
|
||||
console.log('copyDatabaseInAppDirectoryAsync', `vaults/${vaultName}`)
|
||||
|
||||
const sourceFile = await readFile(source)
|
||||
await writeFile(`vaults/HaexVault.db`, sourceFile, {
|
||||
baseDir: BaseDirectory.AppLocalData,
|
||||
})
|
||||
/* await copyFile(source, `vaults/HaexVault.db`, {
|
||||
toPathBaseDir: BaseDirectory.AppLocalData,
|
||||
}) */
|
||||
return vaultName
|
||||
}
|
||||
const onAbort = () => {
|
||||
initDatabase()
|
||||
open.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n lang="yaml">
|
||||
de:
|
||||
open: Öffnen
|
||||
abort: Abbrechen
|
||||
open: Entsperren
|
||||
title: '{haexvault} entsperren'
|
||||
database:
|
||||
password: Passwort
|
||||
vault:
|
||||
open: Vault öffnen
|
||||
description: Öffne eine vorhandene Vault
|
||||
error:
|
||||
open: Vault konnte nicht geöffnet werden. \n Vermutlich ist das Passwort falsch
|
||||
|
||||
en:
|
||||
open: Open
|
||||
abort: Abort
|
||||
open: Unlock
|
||||
title: Unlock {haexvault}
|
||||
database:
|
||||
password: Passwort
|
||||
description: Open your existing vault
|
||||
vault:
|
||||
open: Open Vault
|
||||
error:
|
||||
open: Vault couldn't be opened. \n The password is probably wrong
|
||||
</i18n>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { z } from 'zod';
|
||||
import { z } from 'zod'
|
||||
|
||||
export const vaultDatabaseSchema = {
|
||||
export const vaultSchema = {
|
||||
password: z.string().min(6).max(255),
|
||||
name: z.string().min(1).max(255),
|
||||
path: z.string().min(4).endsWith('.db'),
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,244 +0,0 @@
|
||||
<template>
|
||||
<VaultCard
|
||||
@close="onClose"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex flex-wrap items-center justify-between w-full px-2 py-3">
|
||||
<div class="w-full flex gap-2 justify-between items-center">
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
class="btn btn-square btn-primary btn-outline"
|
||||
@click="onBack"
|
||||
>
|
||||
<Icon
|
||||
name="mdi:chevron-left"
|
||||
size="32"
|
||||
/>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-square btn-error btn-outline"
|
||||
@click="onBack"
|
||||
>
|
||||
<Icon
|
||||
name="mdi:trash-can-outline"
|
||||
size="28"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<slot name="buttons">
|
||||
<div
|
||||
v-if="read_only"
|
||||
class="h-full"
|
||||
>
|
||||
<button
|
||||
class="btn btn-square btn-primary btn-outline"
|
||||
@click="read_only = false"
|
||||
>
|
||||
<Icon
|
||||
name="mdi:pencil-outline"
|
||||
size="24"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="gap-2 h-full hidden md:flex"
|
||||
>
|
||||
<button
|
||||
class="btn btn-square btn-error btn-outline"
|
||||
@click="onClose"
|
||||
>
|
||||
<Icon name="mdi:close" />
|
||||
<span class="hidden"> {{ t('abort') }} </span>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-square btn-success btn-outline"
|
||||
@click="onSubmit"
|
||||
>
|
||||
<Icon name="mdi:check" />
|
||||
<span class="hidden"> {{ t('create') }} </span>
|
||||
</button>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex items-center w-full min-h-14 gap-2 py-1"
|
||||
:style="{ color }"
|
||||
>
|
||||
<Icon
|
||||
v-if="icon"
|
||||
:name="icon"
|
||||
size="28"
|
||||
/>
|
||||
|
||||
<h5
|
||||
v-show="read_only"
|
||||
class="overflow-hidden whitespace-nowrap"
|
||||
>
|
||||
a{{ title }}
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="h-full">
|
||||
<slot />
|
||||
<div
|
||||
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">
|
||||
aa
|
||||
<button
|
||||
class="btn btn-square btn-error btn-outline"
|
||||
@click="onClose"
|
||||
>
|
||||
<Icon name="mdi:close" />
|
||||
<span class="hidden"> {{ t('abort') }} </span>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-square btn-success"
|
||||
@click="onSubmit"
|
||||
>
|
||||
<Icon name="mdi:check" />
|
||||
<span class="hidden"> {{ t('create') }} </span>
|
||||
</button>
|
||||
</div>
|
||||
<div />
|
||||
</div>
|
||||
<!-- <UiButtonAction
|
||||
class=""
|
||||
icon="mdi:content-save-outline"
|
||||
><Icon name="mdi:content-save-outline" />
|
||||
</UiButtonAction> -->
|
||||
</div>
|
||||
</VaultCard>
|
||||
<VaultModalSaveChanges
|
||||
v-model="showConfirmation"
|
||||
@reject="onReject"
|
||||
@submit="onSubmit"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const read_only = defineModel<boolean>('read_only', { default: false })
|
||||
|
||||
const props = defineProps<{
|
||||
color: string
|
||||
hasChanges: boolean
|
||||
icon: string
|
||||
title: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
back: [void]
|
||||
close: [void]
|
||||
reject: [to?: RouteLocationNormalizedLoadedGeneric]
|
||||
submit: [to?: RouteLocationNormalizedLoadedGeneric]
|
||||
}>()
|
||||
|
||||
const showConfirmation = ref(false)
|
||||
|
||||
const to = ref<RouteLocationNormalizedLoadedGeneric>()
|
||||
|
||||
const isApprovedForLeave = ref(false)
|
||||
|
||||
const wantToGoBack = ref(false)
|
||||
|
||||
const onSubmit = () => {
|
||||
showConfirmation.value = false
|
||||
isApprovedForLeave.value = true
|
||||
if (wantToGoBack.value) {
|
||||
wantToGoBack.value = false
|
||||
read_only.value = true
|
||||
emit('submit')
|
||||
} else {
|
||||
emit('submit', to.value)
|
||||
}
|
||||
}
|
||||
|
||||
const onReject = () => {
|
||||
showConfirmation.value = false
|
||||
isApprovedForLeave.value = true
|
||||
read_only.value = true
|
||||
|
||||
if (wantToGoBack.value) {
|
||||
wantToGoBack.value = false
|
||||
emit('back')
|
||||
} else emit('reject', to.value)
|
||||
}
|
||||
|
||||
const onBack = () => {
|
||||
if (props.hasChanges) {
|
||||
wantToGoBack.value = true
|
||||
showConfirmation.value = true
|
||||
} else {
|
||||
emit('back')
|
||||
}
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
if (props.hasChanges) {
|
||||
showConfirmation.value = true
|
||||
} else {
|
||||
emit('close') //read_only.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeRouteLeave((_to, _from, next) => {
|
||||
//console.log('check before leave', _to, _from);
|
||||
to.value = _to
|
||||
if (isApprovedForLeave.value) {
|
||||
isApprovedForLeave.value = false
|
||||
next()
|
||||
} else if (props.hasChanges) {
|
||||
showConfirmation.value = true
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<i18n lang="json">
|
||||
{
|
||||
"de": {
|
||||
"create": "Anlegen",
|
||||
"abort": "Abbrechen",
|
||||
"entry": {
|
||||
"title": "Titel",
|
||||
"username": "Nutzername",
|
||||
"password": "Passwort",
|
||||
"url": "Url"
|
||||
},
|
||||
"tab": {
|
||||
"details": "Details",
|
||||
"keyValue": "Extra",
|
||||
"history": "Verlauf"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"create": "Create",
|
||||
"abort": "Abort",
|
||||
"entry": {
|
||||
"title": "Title",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"url": "Url"
|
||||
},
|
||||
"tab": {
|
||||
"details": "Details",
|
||||
"keyValue": "Extra",
|
||||
"history": "History"
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<slot name="image" />
|
||||
|
||||
<div class="card-header">
|
||||
<slot name="header">
|
||||
<div
|
||||
v-if="$slots.title || title"
|
||||
class="flex items-center gap-2"
|
||||
>
|
||||
<Icon
|
||||
v-if="icon"
|
||||
:name="icon"
|
||||
size="28"
|
||||
/>
|
||||
<h5
|
||||
v-if="title"
|
||||
class="card-title mb-0"
|
||||
>
|
||||
{{ title }}
|
||||
</h5>
|
||||
<slot
|
||||
v-else
|
||||
name="title"
|
||||
/>
|
||||
</div>
|
||||
<div class="text-base-content/50">{{ subtitle }}</div>
|
||||
</slot>
|
||||
</div>
|
||||
|
||||
<div class="card-body px-2 sm:px-6">
|
||||
<slot />
|
||||
<div
|
||||
v-if="$slots.action"
|
||||
class="card-actions"
|
||||
>
|
||||
<slot name="action" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const emit = defineEmits(['close', 'submit'])
|
||||
|
||||
defineProps<{ title?: string; subtitle?: string; icon?: string }>()
|
||||
|
||||
const { escape, enter } = useMagicKeys()
|
||||
|
||||
watchEffect(async () => {
|
||||
if (escape.value) {
|
||||
await nextTick()
|
||||
emit('close')
|
||||
}
|
||||
})
|
||||
|
||||
watchEffect(async () => {
|
||||
if (enter.value) {
|
||||
await nextTick()
|
||||
emit('submit')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@ -1 +0,0 @@
|
||||
<template><div>first time</div></template>
|
||||
@ -1,32 +0,0 @@
|
||||
<template>
|
||||
<UiDialog :title="t('title')">
|
||||
<form class="flex flex-col">
|
||||
<UiInput v-model="vaultItem.title" />
|
||||
<UiInput v-model="vaultItem.username" />
|
||||
<UiInput v-model="vaultItem.password" />
|
||||
<UiInput v-model="vaultItem.note" />
|
||||
</form>
|
||||
</UiDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { t } = useI18n();
|
||||
|
||||
const vaultItem = reactive({
|
||||
title: '',
|
||||
username: '',
|
||||
password: '',
|
||||
note: '',
|
||||
});
|
||||
</script>
|
||||
|
||||
<i18n lang="json">
|
||||
{
|
||||
"de": {
|
||||
"title": "Eintrag erstellen"
|
||||
},
|
||||
"en": {
|
||||
"title": "Create Entry"
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@ -1,112 +0,0 @@
|
||||
<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'"
|
||||
:title="vaultGroup.name ?? ''"
|
||||
@back="$emit('back')"
|
||||
@close="$emit('close')"
|
||||
@reject="(to) => $emit('reject', to)"
|
||||
@submit="(to) => $emit('submit', to)"
|
||||
>
|
||||
<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')"
|
||||
:with-copy-button="read_only"
|
||||
:read_only
|
||||
autofocus
|
||||
/>
|
||||
|
||||
<UiInput
|
||||
v-show="!read_only || vaultGroup.description?.length"
|
||||
v-model.trim="vaultGroup.description"
|
||||
:read_only
|
||||
:label="t('vaultGroup.description')"
|
||||
:placeholder="t('vaultGroup.description')"
|
||||
:with-copy-button="read_only"
|
||||
/>
|
||||
|
||||
<UiSelectColor
|
||||
v-model="vaultGroup.color"
|
||||
:read_only
|
||||
:label="t('vaultGroup.color')"
|
||||
:placeholder="t('vaultGroup.color')"
|
||||
/>
|
||||
|
||||
<UiSelectIcon
|
||||
v-model="vaultGroup.icon"
|
||||
:read_only
|
||||
:label="t('vaultGroup.icon')"
|
||||
:placeholder="t('vaultGroup.icon')"
|
||||
/>
|
||||
</div>
|
||||
</VaultCardEdit>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router'
|
||||
import type { SelectHaexPasswordsGroups } from '~~/src-tauri/database/schemas/vault'
|
||||
|
||||
const { t } = useI18n()
|
||||
const showConfirmation = ref(false)
|
||||
const vaultGroup = defineModel<SelectHaexPasswordsGroups>({ required: true })
|
||||
const read_only = defineModel<boolean>('read_only')
|
||||
const props = defineProps({
|
||||
originally: Object as PropType<SelectHaexPasswordsGroups>,
|
||||
})
|
||||
|
||||
defineEmits<{
|
||||
submit: [to?: RouteLocationNormalizedLoadedGeneric]
|
||||
close: [void]
|
||||
back: [void]
|
||||
reject: [to?: RouteLocationNormalizedLoadedGeneric]
|
||||
}>()
|
||||
|
||||
const hasChanges = computed(() => {
|
||||
console.log('group has changes', props.originally, vaultGroup.value)
|
||||
if (!props.originally) {
|
||||
if (
|
||||
vaultGroup.value.color?.length ||
|
||||
vaultGroup.value.description?.length ||
|
||||
vaultGroup.value.icon?.length ||
|
||||
vaultGroup.value.name?.length
|
||||
) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return JSON.stringify(props.originally) !== JSON.stringify(vaultGroup.value)
|
||||
})
|
||||
|
||||
/* const onClose = () => {
|
||||
if (props.originally) vaultGroup.value = { ...props.originally };
|
||||
emit('close');
|
||||
}; */
|
||||
</script>
|
||||
|
||||
<i18n lang="json">
|
||||
{
|
||||
"de": {
|
||||
"vaultGroup": {
|
||||
"name": "Name",
|
||||
"description": "Beschreibung",
|
||||
"icon": "Icon",
|
||||
"color": "Farbe"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"vaultGroup": {
|
||||
"name": "Name",
|
||||
"description": "Description",
|
||||
"icon": "Icon",
|
||||
"color": "Color"
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
@ -1,7 +0,0 @@
|
||||
<template>
|
||||
<UiList>
|
||||
<slot />
|
||||
</UiList>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
@ -1,77 +0,0 @@
|
||||
<template>
|
||||
<UiDialog
|
||||
v-model:open="showConfirmation"
|
||||
:title="t('dialog.title')"
|
||||
>
|
||||
{{ t('dialog.question') }}
|
||||
<template #buttons>
|
||||
<UiButton
|
||||
class="btn-outline btn-error focus:bg-primary"
|
||||
tabindex="10"
|
||||
@click="$emit('reject')"
|
||||
>
|
||||
<Icon name="mdi:cancel" />
|
||||
<span class="hidden sm:block">
|
||||
{{ t('dialog.reject') }}
|
||||
</span>
|
||||
</UiButton>
|
||||
<UiButton
|
||||
ref="abortButtonRef"
|
||||
class="btn-outline focus:bg-primary"
|
||||
tabindex="11"
|
||||
@click="showConfirmation = false"
|
||||
>
|
||||
<Icon name="mdi:close" />
|
||||
<span class="hidden sm:block">
|
||||
{{ t('dialog.abort') }}
|
||||
</span>
|
||||
</UiButton>
|
||||
<UiButton
|
||||
class="btn-outline btn-success"
|
||||
tabindex="12"
|
||||
@click="$emit('submit')"
|
||||
>
|
||||
<Icon name="mdi:check" />
|
||||
<span class="hidden sm:block">
|
||||
{{ t('dialog.save') }}
|
||||
</span>
|
||||
</UiButton>
|
||||
</template>
|
||||
</UiDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const showConfirmation = defineModel<boolean>()
|
||||
const abortButtonRef = useTemplateRef('abortButtonRef')
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
onUpdated(() => {
|
||||
abortButtonRef.value?.$el.focus()
|
||||
})
|
||||
|
||||
defineEmits(['submit', 'reject'])
|
||||
</script>
|
||||
|
||||
<i18n lang="json">
|
||||
{
|
||||
"de": {
|
||||
"dialog": {
|
||||
"title": "Ungespeicherte Änderungen",
|
||||
"question": "Möchten Sie die Änderungen speichern?",
|
||||
"reject": "Verwerfen",
|
||||
"abort": "Abbrechen",
|
||||
"save": "Speichern"
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"dialog": {
|
||||
"title": "Unsaved Changes",
|
||||
"question": "Would you like to save the changes?",
|
||||
"reject": "Reject",
|
||||
"abort": "Abort",
|
||||
"save": "Save"
|
||||
}
|
||||
}
|
||||
}
|
||||
</i18n>
|
||||
Reference in New Issue
Block a user