mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-17 06:30:50 +01:00
added settings page, cleanup
This commit is contained in:
@ -1,16 +1,10 @@
|
||||
<template>
|
||||
<div class="browser">
|
||||
<div class="browser-controls">
|
||||
<button
|
||||
@click="$emit('goBack', activeTabId)"
|
||||
:disabled="!activeTabId"
|
||||
>
|
||||
<button @click="$emit('goBack', activeTabId)" :disabled="!activeTabId">
|
||||
←
|
||||
</button>
|
||||
<button
|
||||
@click="$emit('goForward', activeTabId)"
|
||||
:disabled="!activeTabId"
|
||||
>
|
||||
<button @click="$emit('goForward', activeTabId)" :disabled="!activeTabId">
|
||||
→
|
||||
</button>
|
||||
<button @click="$emit('createTab')">+</button>
|
||||
@ -29,15 +23,9 @@
|
||||
@activateTab="$emit('activateTab', $event)"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="browser-content"
|
||||
ref="contentRef"
|
||||
>
|
||||
<div class="browser-content" ref="contentRef">
|
||||
<!-- Die eigentlichen Webview-Inhalte werden von Tauri verwaltet -->
|
||||
<div
|
||||
v-if="!activeTabId"
|
||||
class="empty-state"
|
||||
>
|
||||
<div v-if="!activeTabId" class="empty-state">
|
||||
<p>
|
||||
Kein Tab geöffnet. Erstellen Sie einen neuen Tab mit dem + Button.
|
||||
</p>
|
||||
@ -47,9 +35,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { Window } from '@tauri-apps/api/window';
|
||||
import { getCurrentWebview, Webview } from '@tauri-apps/api/webview';
|
||||
import { Webview } from '@tauri-apps/api/webview'
|
||||
import { Window } from '@tauri-apps/api/window'
|
||||
/* const appWindow = new Window('uniqueLabel');
|
||||
const webview = new Webview(appWindow, 'theUniqueLabel', {
|
||||
url: 'https://www.google.de',
|
||||
@ -64,46 +51,46 @@ webview.once('tauri://created', function () {
|
||||
}); */
|
||||
|
||||
interface Tab {
|
||||
id: string;
|
||||
title: string;
|
||||
url: string;
|
||||
isLoading: boolean;
|
||||
isActive: boolean;
|
||||
window_label: string;
|
||||
id: string
|
||||
title: string
|
||||
url: string
|
||||
isLoading: boolean
|
||||
isActive: boolean
|
||||
window_label: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
tabs: Tab[];
|
||||
activeTabId: string | null;
|
||||
tabs: Tab[]
|
||||
activeTabId: string | null
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'createTab'): void;
|
||||
(e: 'closeTab', tabId: string): void;
|
||||
(e: 'navigate', tabId: string, url: string): void;
|
||||
(e: 'goBack', tabId: string | null): void;
|
||||
(e: 'goForward', tabId: string | null): void;
|
||||
(e: 'activateTab', tabId: string | null): void;
|
||||
}>();
|
||||
(e: 'createTab'): void
|
||||
(e: 'closeTab', tabId: string): void
|
||||
(e: 'navigate', tabId: string, url: string): void
|
||||
(e: 'goBack', tabId: string | null): void
|
||||
(e: 'goForward', tabId: string | null): void
|
||||
(e: 'activateTab', tabId: string | null): void
|
||||
}>()
|
||||
|
||||
const { initializeAsync, processNavigation, injectContentScripts } =
|
||||
useBrowserExtensionStore();
|
||||
const contentRef = ref<HTMLDivElement | null>(null);
|
||||
useBrowserExtensionStore()
|
||||
const contentRef = ref<HTMLDivElement | null>(null)
|
||||
//const extensionManager = ref<ExtensionManager>(new ExtensionManager());
|
||||
|
||||
const activeTab = computed(() =>
|
||||
props.tabs?.find((tab) => tab.id === props.activeTabId)
|
||||
);
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
// Initialisiere das Erweiterungssystem
|
||||
await initializeAsync();
|
||||
await initializeAsync()
|
||||
// Aktualisiere die Webview-Größe
|
||||
await updateWebviewBoundsAsync();
|
||||
await updateWebviewBoundsAsync()
|
||||
//window.addEventListener('resize', updateWebviewBounds);
|
||||
});
|
||||
})
|
||||
|
||||
// Wenn ein neuer Tab aktiviert wird, injiziere Content-Scripts
|
||||
/* watch(
|
||||
@ -124,32 +111,46 @@ onMounted(async () => {
|
||||
}
|
||||
); */
|
||||
|
||||
const createNewTabAsync = async () => {
|
||||
const appWindow = new Window(crypto.randomUUID())
|
||||
appWindow.setAlwaysOnTop(true)
|
||||
appWindow.setDecorations(false)
|
||||
const webview = new Webview(appWindow, 'theUniqueLabel', {
|
||||
url: 'https://www.google.de',
|
||||
x: 0,
|
||||
y: 0,
|
||||
height: 1000,
|
||||
width: 1000,
|
||||
})
|
||||
}
|
||||
|
||||
const handleUrlSubmit = (url: string) => {
|
||||
createNewTabAsync()
|
||||
if (props.activeTabId) {
|
||||
// Prüfe URL mit Erweiterungen vor der Navigation
|
||||
if (processNavigation(url)) {
|
||||
emit('navigate', props.activeTabId, url);
|
||||
/* if (processNavigation(url)) {
|
||||
//emit('navigate', props.activeTabId, url);
|
||||
} else {
|
||||
console.log('Navigation blockiert durch Erweiterung');
|
||||
console.log('Navigation blockiert durch Erweiterung')
|
||||
// Hier könnten Sie eine Benachrichtigung anzeigen
|
||||
}
|
||||
} */
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const updateWebviewBoundsAsync = async () => {
|
||||
if (!contentRef.value) return;
|
||||
if (!contentRef.value) return
|
||||
|
||||
const rect = contentRef.value.getBoundingClientRect();
|
||||
const rect = contentRef.value.getBoundingClientRect()
|
||||
const bounds = {
|
||||
x: rect.left,
|
||||
y: rect.top,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
};
|
||||
}
|
||||
|
||||
/* await invoke('update_window_bounds', {
|
||||
contentBounds: { x: bounds.x, y: bounds.y },
|
||||
contentSize: { width: bounds.width, height: bounds.height },
|
||||
}); */
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -10,10 +10,7 @@
|
||||
<span class="tab-title">
|
||||
{{ tab.title || 'Neuer Tab' }}
|
||||
</span>
|
||||
<button
|
||||
class="tab-close"
|
||||
@click.stop="$emit('closeTab', tab.id)"
|
||||
>
|
||||
<button class="tab-close" @click.stop="$emit('closeTab', tab.id)">
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
@ -22,22 +19,22 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
interface Tab {
|
||||
id: string;
|
||||
title: string;
|
||||
url: string;
|
||||
isLoading: boolean;
|
||||
isActive: boolean;
|
||||
id: string
|
||||
title: string
|
||||
url: string
|
||||
isLoading: boolean
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
interface Props {
|
||||
tabs: Tab[];
|
||||
activeTabId: string | null;
|
||||
tabs: Tab[]
|
||||
activeTabId: string | null
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
defineProps<Props>()
|
||||
|
||||
defineEmits<{
|
||||
(e: 'closeTab', tabId: string): void;
|
||||
(e: 'activateTab', tabId: string): void;
|
||||
}>();
|
||||
(e: 'closeTab', tabId: string): void
|
||||
(e: 'activateTab', tabId: string): void
|
||||
}>()
|
||||
</script>
|
||||
|
||||
@ -1,24 +1,8 @@
|
||||
<template>
|
||||
<form
|
||||
class="url-bar"
|
||||
@submit.prevent="handleSubmit"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
v-model="inputValue"
|
||||
placeholder="URL eingeben"
|
||||
/>
|
||||
<span
|
||||
v-if="isLoading"
|
||||
class="loading-indicator"
|
||||
>Laden...</span
|
||||
>
|
||||
<button
|
||||
v-else
|
||||
type="submit"
|
||||
>
|
||||
Go
|
||||
</button>
|
||||
<form class="url-bar" @submit.prevent="handleSubmit">
|
||||
<input type="text" v-model="inputValue" placeholder="URL eingeben" />
|
||||
<span v-if="isLoading" class="loading-indicator">Laden...</span>
|
||||
<button v-else type="submit">Go</button>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
@ -32,26 +16,26 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
const emit = defineEmits(['submit']);
|
||||
const emit = defineEmits(['submit'])
|
||||
|
||||
const inputValue = ref(props.url);
|
||||
const inputValue = ref(props.url)
|
||||
|
||||
watch(
|
||||
() => props.url,
|
||||
(newUrl) => {
|
||||
inputValue.value = newUrl;
|
||||
inputValue.value = newUrl
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
const handleSubmit = () => {
|
||||
// URL validieren und ggf. Protokoll hinzufügen
|
||||
let processedUrl = inputValue.value.trim();
|
||||
let processedUrl = inputValue.value.trim()
|
||||
if (processedUrl && !processedUrl.match(/^[a-zA-Z]+:\/\//)) {
|
||||
processedUrl = 'https://' + processedUrl;
|
||||
processedUrl = 'https://' + processedUrl
|
||||
}
|
||||
|
||||
emit('submit', processedUrl);
|
||||
};
|
||||
emit('submit', processedUrl)
|
||||
}
|
||||
</script>
|
||||
|
||||
59
src/components/haex/menu/main.vue
Normal file
59
src/components/haex/menu/main.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<UiDropdown activator-class="btn btn-text btn-circle">
|
||||
<template #activator>
|
||||
<div
|
||||
class="size-9.5 rounded-full items-center justify-center text-base-content text-base"
|
||||
>
|
||||
<Icon name="mdi:format-list-bulleted" class="size-full p-2" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #items>
|
||||
<ul
|
||||
class="dropdown-menu dropdown-open:opacity-100 hidden min-w-60"
|
||||
role="menu"
|
||||
aria-orientation="vertical"
|
||||
aria-labelledby="dropdown-avatar"
|
||||
>
|
||||
<li>
|
||||
<NuxtLinkLocale class="dropdown-item" :to="{ name: 'haexSettings' }">
|
||||
<span class="icon-[tabler--settings]"></span>
|
||||
{{ t('settings') }}
|
||||
</NuxtLinkLocale>
|
||||
</li>
|
||||
|
||||
<li class="dropdown-footer gap-2">
|
||||
<button
|
||||
class="btn btn-error btn-soft btn-block"
|
||||
@click="onVaultCloseAsync"
|
||||
>
|
||||
<span class="icon-[tabler--logout]"></span>
|
||||
{{ t('vault.close') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</UiDropdown>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { t } = useI18n()
|
||||
const { closeAsync } = useVaultStore()
|
||||
|
||||
const onVaultCloseAsync = async () => {
|
||||
await closeAsync()
|
||||
await navigateTo(useLocalePath()({ name: 'vaultOpen' }))
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n lang="yaml">
|
||||
de:
|
||||
settings: 'Einstellungen'
|
||||
vault:
|
||||
close: 'Vault schließen'
|
||||
|
||||
en:
|
||||
settings: 'Settings'
|
||||
vault:
|
||||
close: 'Close Vault'
|
||||
</i18n>
|
||||
54
src/components/ui/dropdown/index.vue
Normal file
54
src/components/ui/dropdown/index.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="dropdown relative inline-flex">
|
||||
<button
|
||||
:id
|
||||
class="dropdown-toggle"
|
||||
:class="activatorClass"
|
||||
aria-haspopup="menu"
|
||||
aria-expanded="false"
|
||||
:aria-label="label"
|
||||
>
|
||||
<slot name="activator">
|
||||
<slot name="label">
|
||||
{{ label }}
|
||||
</slot>
|
||||
<span
|
||||
class="icon-[tabler--chevron-down] dropdown-open:rotate-180 size-4"
|
||||
>
|
||||
</span>
|
||||
</slot>
|
||||
</button>
|
||||
|
||||
<slot name="items" :items>
|
||||
<ul
|
||||
class="dropdown-menu dropdown-open:opacity-100 hidden min-w-28"
|
||||
role="menu"
|
||||
aria-orientation="vertical"
|
||||
:aria-labelledby="id"
|
||||
>
|
||||
<component
|
||||
:is="itemIs"
|
||||
class="dropdown-item"
|
||||
v-for="item in items"
|
||||
@click="$emit('select', item)"
|
||||
>
|
||||
<slot name="item" :item>
|
||||
{{ item }}
|
||||
</slot>
|
||||
</component>
|
||||
</ul>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" generic="T">
|
||||
const { itemIs = 'li' } = defineProps<{
|
||||
label?: string
|
||||
items?: T[]
|
||||
itemIs?: string
|
||||
activatorClass?: string
|
||||
}>()
|
||||
|
||||
defineEmits<{ select: [T] }>()
|
||||
const id = useId()
|
||||
</script>
|
||||
33
src/components/ui/dropdown/locale.vue
Normal file
33
src/components/ui/dropdown/locale.vue
Normal file
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<UiDropdown
|
||||
:items="availableLocales"
|
||||
@select="(locale) => $emit('select', locale)"
|
||||
activator-class="btn btn-primary"
|
||||
>
|
||||
<template #label>
|
||||
<Icon :name="flags[locale]" />
|
||||
</template>
|
||||
|
||||
<template #item="{ item }">
|
||||
<div class="flex gap-2 justify-center">
|
||||
<Icon :name="flags[item]" class="my-auto" />
|
||||
<p>
|
||||
{{ item }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</UiDropdown>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { type Locale } from 'vue-i18n'
|
||||
|
||||
const flags = {
|
||||
de: 'emojione:flag-for-germany',
|
||||
en: 'emojione:flag-for-united-kingdom',
|
||||
}
|
||||
|
||||
const { availableLocales, locale } = useI18n()
|
||||
|
||||
defineEmits<{ select: [Locale] }>()
|
||||
</script>
|
||||
26
src/components/ui/dropdown/theme.vue
Normal file
26
src/components/ui/dropdown/theme.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<UiDropdown
|
||||
:items="availableThemes"
|
||||
@select="(theme) => $emit('select', theme)"
|
||||
activator-class="btn btn-primary"
|
||||
>
|
||||
<template #label>
|
||||
<Icon :name="currentTheme.icon" />
|
||||
</template>
|
||||
|
||||
<template #item="{ item }">
|
||||
<div class="flex gap-2 justify-center">
|
||||
<Icon :name="item.icon" class="my-auto" />
|
||||
<p>
|
||||
{{ item.name }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</UiDropdown>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { availableThemes, currentTheme } = storeToRefs(useUiStore())
|
||||
|
||||
defineEmits<{ select: [ITheme] }>()
|
||||
</script>
|
||||
@ -1,78 +1,10 @@
|
||||
<template>
|
||||
<span>
|
||||
<!-- <fieldset class="join w-full">
|
||||
<slot name="prepend" />
|
||||
|
||||
<span class="input-group join-item">
|
||||
<span
|
||||
v-if="prependIcon || prependLabel"
|
||||
class="input-group-text"
|
||||
>
|
||||
<label v-if="prependLabel">
|
||||
{{ prependLabel }}
|
||||
</label>
|
||||
<Icon :name="prependIcon" />
|
||||
</span>
|
||||
|
||||
<div class="relative w-full">
|
||||
<input
|
||||
:id
|
||||
:name="name ?? id"
|
||||
:placeholder="placeholder || label"
|
||||
:type
|
||||
:autofocus
|
||||
class="input input-floating peer join-item"
|
||||
:class="{
|
||||
'input-sm':
|
||||
currentScreenSize === 'sm' ||
|
||||
currentScreenSize === '' ||
|
||||
currentScreenSize === 'xs',
|
||||
}"
|
||||
v-bind="$attrs"
|
||||
v-model="input"
|
||||
ref="inputRef"
|
||||
:readonly="read_only"
|
||||
/>
|
||||
|
||||
<label
|
||||
v-if="label"
|
||||
:for="id"
|
||||
class="input-floating-label"
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<span
|
||||
v-if="appendIcon || appendLabel"
|
||||
class="input-group-text"
|
||||
>
|
||||
<label
|
||||
v-if="appendLabel"
|
||||
class=""
|
||||
>
|
||||
{{ appendLabel }}
|
||||
</label>
|
||||
<Icon :name="appendIcon" />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<slot name="append" />
|
||||
|
||||
<UiButton
|
||||
v-if="withCopyButton"
|
||||
class="btn-outline btn-accent h-auto"
|
||||
@click="copy(`${input}`)"
|
||||
>
|
||||
<Icon :name="copied ? 'mdi:check' : 'mdi:content-copy'" />
|
||||
</UiButton>
|
||||
|
||||
</fieldset> -->
|
||||
<fieldset class="join w-full p-1">
|
||||
<div>
|
||||
<fieldset class="join w-full">
|
||||
<slot name="prepend" />
|
||||
|
||||
<div class="input join-item">
|
||||
<Icon :name="prependIcon" class="my-auto shrink-0" />
|
||||
<Icon v-if="prependIcon" :name="prependIcon" class="my-auto shrink-0" />
|
||||
|
||||
<div class="input-floating grow">
|
||||
<input
|
||||
@ -90,12 +22,13 @@
|
||||
<label class="input-floating-label" :for="id">{{ label }}</label>
|
||||
</div>
|
||||
|
||||
<Icon :name="appendIcon" class="my-auto shrink-0" />
|
||||
<Icon v-if="appendIcon" :name="appendIcon" class="my-auto shrink-0" />
|
||||
</div>
|
||||
|
||||
<slot name="append" class="h-auto" />
|
||||
|
||||
<UiButton
|
||||
v-if="withCopyButton"
|
||||
class="btn-outline btn-accent btn-square join-item h-auto"
|
||||
@click="copy(`${input}`)"
|
||||
>
|
||||
@ -108,61 +41,61 @@
|
||||
{{ error }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { type ZodSchema } from "zod";
|
||||
import { type ZodSchema } from 'zod'
|
||||
|
||||
const inputRef = useTemplateRef("inputRef");
|
||||
defineExpose({ inputRef });
|
||||
const inputRef = useTemplateRef('inputRef')
|
||||
defineExpose({ inputRef })
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<
|
||||
| "button"
|
||||
| "checkbox"
|
||||
| "color"
|
||||
| "date"
|
||||
| "datetime-local"
|
||||
| "email"
|
||||
| "file"
|
||||
| "hidden"
|
||||
| "image"
|
||||
| "month"
|
||||
| "number"
|
||||
| "password"
|
||||
| "radio"
|
||||
| "range"
|
||||
| "reset"
|
||||
| "search"
|
||||
| "submit"
|
||||
| "tel"
|
||||
| "text"
|
||||
| "time"
|
||||
| "url"
|
||||
| "week"
|
||||
| 'button'
|
||||
| 'checkbox'
|
||||
| 'color'
|
||||
| 'date'
|
||||
| 'datetime-local'
|
||||
| 'email'
|
||||
| 'file'
|
||||
| 'hidden'
|
||||
| 'image'
|
||||
| 'month'
|
||||
| 'number'
|
||||
| 'password'
|
||||
| 'radio'
|
||||
| 'range'
|
||||
| 'reset'
|
||||
| 'search'
|
||||
| 'submit'
|
||||
| 'tel'
|
||||
| 'text'
|
||||
| 'time'
|
||||
| 'url'
|
||||
| 'week'
|
||||
>,
|
||||
default: "text",
|
||||
default: 'text',
|
||||
},
|
||||
label: String,
|
||||
name: String,
|
||||
prependIcon: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
prependLabel: String,
|
||||
appendIcon: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
appendLabel: String,
|
||||
rules: Object as PropType<ZodSchema>,
|
||||
@ -170,45 +103,45 @@ const props = defineProps({
|
||||
withCopyButton: Boolean,
|
||||
autofocus: Boolean,
|
||||
read_only: Boolean,
|
||||
});
|
||||
})
|
||||
|
||||
const input = defineModel<string | number | undefined | null>({
|
||||
default: "",
|
||||
default: '',
|
||||
required: true,
|
||||
});
|
||||
})
|
||||
|
||||
const { currentScreenSize } = storeToRefs(useUiStore());
|
||||
const { currentScreenSize } = storeToRefs(useUiStore())
|
||||
onMounted(() => {
|
||||
if (props.autofocus && inputRef.value) inputRef.value.focus();
|
||||
});
|
||||
if (props.autofocus && inputRef.value) inputRef.value.focus()
|
||||
})
|
||||
|
||||
const errors = defineModel<string[] | undefined>("errors");
|
||||
const errors = defineModel<string[] | undefined>('errors')
|
||||
|
||||
const id = useId();
|
||||
const id = useId()
|
||||
|
||||
watch(input, () => checkInput());
|
||||
watch(input, () => checkInput())
|
||||
|
||||
watch(
|
||||
() => props.checkInput,
|
||||
() => {
|
||||
checkInput();
|
||||
checkInput()
|
||||
}
|
||||
);
|
||||
)
|
||||
|
||||
const emit = defineEmits(["error"]);
|
||||
const emit = defineEmits(['error'])
|
||||
|
||||
const checkInput = () => {
|
||||
if (props.rules) {
|
||||
const result = props.rules.safeParse(input.value);
|
||||
const result = props.rules.safeParse(input.value)
|
||||
//console.log('check result', result.error, props.rules);
|
||||
if (!result.success) {
|
||||
errors.value = result.error.errors.map((error) => error.message);
|
||||
emit("error", errors.value);
|
||||
errors.value = result.error.errors.map((error) => error.message)
|
||||
emit('error', errors.value)
|
||||
} else {
|
||||
errors.value = [];
|
||||
errors.value = []
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const { copy, copied } = useClipboard();
|
||||
const { copy, copied } = useClipboard()
|
||||
</script>
|
||||
|
||||
@ -9,20 +9,22 @@
|
||||
v-model="value"
|
||||
>
|
||||
<template #append>
|
||||
<UiButton class="btn-outline btn-accent btn-square h-auto" @click="tooglePasswordType">
|
||||
<Icon :name="type === 'password' ? 'mdi:eye' : 'mdi:eye-off'" />
|
||||
<UiButton
|
||||
class="btn-outline btn-accent btn-square h-auto"
|
||||
@click="tooglePasswordType"
|
||||
>
|
||||
<Icon :name="type === 'password' ? 'mdi:eye-off' : 'mdi:eye'" />
|
||||
</UiButton>
|
||||
</template>
|
||||
</UiInput>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { ZodSchema } from "zod";
|
||||
import type { ZodSchema } from 'zod'
|
||||
|
||||
const { t } = useI18n();
|
||||
const { currentScreenSize } = storeToRefs(useUiStore());
|
||||
const { t } = useI18n()
|
||||
|
||||
const value = defineModel<string | number | null | undefined>();
|
||||
const value = defineModel<string | number | null | undefined>()
|
||||
|
||||
defineProps({
|
||||
label: String,
|
||||
@ -30,13 +32,13 @@ defineProps({
|
||||
checkInput: Boolean,
|
||||
rules: Object as PropType<ZodSchema>,
|
||||
autofocus: Boolean,
|
||||
});
|
||||
})
|
||||
|
||||
const type = ref<"password" | "text">("password");
|
||||
const type = ref<'password' | 'text'>('password')
|
||||
|
||||
const tooglePasswordType = () => {
|
||||
type.value = type.value === "password" ? "text" : "password";
|
||||
};
|
||||
type.value = type.value === 'password' ? 'text' : 'password'
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n lang="json">
|
||||
|
||||
@ -6,12 +6,11 @@
|
||||
@click="open = true"
|
||||
>
|
||||
<Icon name="mdi:plus" />
|
||||
{{ t("database.create") }}
|
||||
{{ t('database.create') }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<form class="flex flex-col gap-4" @submit="onCreateAsync">
|
||||
<!-- @keyup.enter="onCreateAsync" -->
|
||||
<UiInput
|
||||
:check-input="check"
|
||||
:label="t('database.label')"
|
||||
@ -32,98 +31,116 @@
|
||||
|
||||
<template #buttons>
|
||||
<UiButton class="btn-error" @click="onClose">
|
||||
{{ t("abort") }}
|
||||
{{ t('abort') }}
|
||||
</UiButton>
|
||||
|
||||
<UiButton class="btn-primary" @click="onCreateAsync">
|
||||
{{ t("create") }}
|
||||
{{ t('create') }}
|
||||
</UiButton>
|
||||
</template>
|
||||
</UiDialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { save } from "@tauri-apps/plugin-dialog";
|
||||
import { useVaultStore } from "~/stores/vault";
|
||||
import { vaultDatabaseSchema } from "./schema";
|
||||
import { save } from '@tauri-apps/plugin-dialog'
|
||||
import { useVaultStore } from '~/stores/vault'
|
||||
import { vaultDatabaseSchema } from './schema'
|
||||
import { onKeyStroke } from '@vueuse/core'
|
||||
|
||||
const check = ref(false);
|
||||
const open = ref();
|
||||
onKeyStroke('Enter', (e) => {
|
||||
e.preventDefault()
|
||||
onCreateAsync()
|
||||
})
|
||||
|
||||
const { t } = useI18n();
|
||||
const check = ref(false)
|
||||
const open = ref()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const database = reactive<{
|
||||
name: string;
|
||||
password: string;
|
||||
path: string | null;
|
||||
type: "password" | "text";
|
||||
name: string
|
||||
password: string
|
||||
path: string | null
|
||||
type: 'password' | 'text'
|
||||
}>({
|
||||
name: "",
|
||||
password: "",
|
||||
path: "",
|
||||
type: "password",
|
||||
});
|
||||
name: '',
|
||||
password: '',
|
||||
path: '',
|
||||
type: 'password',
|
||||
})
|
||||
|
||||
const initDatabase = () => {
|
||||
database.name = t("database.name");
|
||||
database.password = "";
|
||||
database.path = "";
|
||||
database.type = "password";
|
||||
};
|
||||
database.name = t('database.name')
|
||||
database.password = ''
|
||||
database.path = ''
|
||||
database.type = 'password'
|
||||
}
|
||||
|
||||
initDatabase();
|
||||
initDatabase()
|
||||
|
||||
const { add } = useSnackbar();
|
||||
const { createAsync } = useVaultStore();
|
||||
const { add } = useSnackbar()
|
||||
const { createAsync } = useVaultStore()
|
||||
|
||||
const onCreateAsync = async () => {
|
||||
check.value = true;
|
||||
check.value = true
|
||||
|
||||
const nameCheck = vaultDatabaseSchema.name.safeParse(database.name);
|
||||
const passwordCheck = vaultDatabaseSchema.password.safeParse(database.password);
|
||||
const nameCheck = vaultDatabaseSchema.name.safeParse(database.name)
|
||||
const passwordCheck = vaultDatabaseSchema.password.safeParse(
|
||||
database.password
|
||||
)
|
||||
|
||||
console.log("checks", database.name, nameCheck, database.password, passwordCheck);
|
||||
if (!nameCheck.success || !passwordCheck.success) return;
|
||||
console.log(
|
||||
'checks',
|
||||
database.name,
|
||||
nameCheck,
|
||||
database.password,
|
||||
passwordCheck
|
||||
)
|
||||
if (!nameCheck.success || !passwordCheck.success) return
|
||||
|
||||
open.value = false;
|
||||
open.value = false
|
||||
try {
|
||||
database.path = await save({
|
||||
defaultPath: database.name.endsWith(".db") ? database.name : `${database.name}.db`,
|
||||
});
|
||||
defaultPath: database.name.endsWith('.db')
|
||||
? database.name
|
||||
: `${database.name}.db`,
|
||||
})
|
||||
|
||||
console.log("data", database);
|
||||
console.log('data', database)
|
||||
|
||||
if (database.path && database.password) {
|
||||
const vaultId = await createAsync({
|
||||
path: database.path,
|
||||
password: database.password,
|
||||
});
|
||||
})
|
||||
|
||||
console.log("vaultId", vaultId);
|
||||
console.log('vaultId', vaultId)
|
||||
if (vaultId) {
|
||||
await navigateTo(useLocaleRoute()({ name: "vaultOverview", params: { vaultId } }));
|
||||
await navigateTo(
|
||||
useLocaleRoute()({ name: 'vaultOverview', params: { vaultId } })
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
add({ type: "error", text: JSON.stringify(error) });
|
||||
console.error(error)
|
||||
add({ type: 'error', text: JSON.stringify(error) })
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
open.value = false;
|
||||
initDatabase();
|
||||
};
|
||||
open.value = false
|
||||
initDatabase()
|
||||
}
|
||||
</script>
|
||||
|
||||
<i18n lang="json">
|
||||
{
|
||||
"de": {
|
||||
"database": {
|
||||
"label": "Datenbankname",
|
||||
"placeholder": "Passwörter",
|
||||
"label": "Vaultname",
|
||||
"placeholder": "Vaultname",
|
||||
"create": "Neue Vault anlegen",
|
||||
"name": "Passwörter"
|
||||
"name": "HaexVault"
|
||||
},
|
||||
"title": "Neue Datenbank anlegen",
|
||||
"create": "Erstellen",
|
||||
@ -133,10 +150,10 @@ const onClose = () => {
|
||||
|
||||
"en": {
|
||||
"database": {
|
||||
"label": "Databasename",
|
||||
"placeholder": "Databasename",
|
||||
"label": "Vaultname",
|
||||
"placeholder": "Vaultname",
|
||||
"create": "Create new Vault",
|
||||
"name": "Passwords"
|
||||
"name": "HaexVault"
|
||||
},
|
||||
"title": "Create New Database",
|
||||
"create": "Create",
|
||||
|
||||
1
src/components/vault/dialog/host/firstTime.vue
Normal file
1
src/components/vault/dialog/host/firstTime.vue
Normal file
@ -0,0 +1 @@
|
||||
<template><div>first time</div></template>
|
||||
Reference in New Issue
Block a user