mirror of
https://github.com/haexhub/haex-hub.git
synced 2025-12-16 22:20:51 +01:00
added settings page, cleanup
This commit is contained in:
@ -22,11 +22,11 @@ export default defineNuxtConfig({
|
|||||||
provider: 'server',
|
provider: 'server',
|
||||||
mode: "svg",
|
mode: "svg",
|
||||||
clientBundle: {
|
clientBundle: {
|
||||||
icons: ["solar:global-outline", "gg:extension"],
|
icons: ["solar:global-outline", "gg:extension", "hugeicons:corporate"],
|
||||||
scan: true,
|
scan: true,
|
||||||
includeCustomCollections: true,
|
includeCustomCollections: true,
|
||||||
},
|
},
|
||||||
serverBundle: { collections: ["mdi", "line-md", "solar", "gg"] }
|
serverBundle: { collections: ["mdi", "line-md", "solar", "gg", "emojione"] }
|
||||||
//collections: ["mdi", "line-md"]
|
//collections: ["mdi", "line-md"]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
"opener:allow-open-url",
|
"opener:allow-open-url",
|
||||||
"opener:default",
|
"opener:default",
|
||||||
"os:default",
|
"os:default",
|
||||||
|
"os:allow-hostname",
|
||||||
"store:default"
|
"store:default"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE `haex_settings` RENAME COLUMN "value_text" TO "value";--> statement-breakpoint
|
||||||
|
DROP TABLE `testTable`;--> statement-breakpoint
|
||||||
|
ALTER TABLE `haex_settings` DROP COLUMN `value_json`;--> statement-breakpoint
|
||||||
|
ALTER TABLE `haex_settings` DROP COLUMN `value_number`;
|
||||||
180
src-tauri/database/migrations/meta/0002_snapshot.json
Normal file
180
src-tauri/database/migrations/meta/0002_snapshot.json
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
{
|
||||||
|
"version": "6",
|
||||||
|
"dialect": "sqlite",
|
||||||
|
"id": "ea3507ca-77bc-4f3c-a605-8426614f5803",
|
||||||
|
"prevId": "6fb5396b-9f87-4fb5-87a2-22d4eecaa11e",
|
||||||
|
"tables": {
|
||||||
|
"haex_extensions": {
|
||||||
|
"name": "haex_extensions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"name": "author",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"name": "enabled",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"name": "icon",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"name": "url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"name": "version",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_extensions_permissions": {
|
||||||
|
"name": "haex_extensions_permissions",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"extension_id": {
|
||||||
|
"name": "extension_id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"resource": {
|
||||||
|
"name": "resource",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"operation": {
|
||||||
|
"name": "operation",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"name": "path",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"haex_extensions_permissions_extension_id_resource_operation_path_unique": {
|
||||||
|
"name": "haex_extensions_permissions_extension_id_resource_operation_path_unique",
|
||||||
|
"columns": [
|
||||||
|
"extension_id",
|
||||||
|
"resource",
|
||||||
|
"operation",
|
||||||
|
"path"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"haex_extensions_permissions_extension_id_haex_extensions_id_fk": {
|
||||||
|
"name": "haex_extensions_permissions_extension_id_haex_extensions_id_fk",
|
||||||
|
"tableFrom": "haex_extensions_permissions",
|
||||||
|
"tableTo": "haex_extensions",
|
||||||
|
"columnsFrom": [
|
||||||
|
"extension_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
},
|
||||||
|
"haex_settings": {
|
||||||
|
"name": "haex_settings",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"name": "key",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"name": "value",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"views": {},
|
||||||
|
"enums": {},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {
|
||||||
|
"\"haex_settings\".\"value_text\"": "\"haex_settings\".\"value\""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"indexes": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,6 +15,13 @@
|
|||||||
"when": 1746281577722,
|
"when": 1746281577722,
|
||||||
"tag": "0001_wealthy_thaddeus_ross",
|
"tag": "0001_wealthy_thaddeus_ross",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 2,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1747583956679,
|
||||||
|
"tag": "0002_married_bushwacker",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -1,18 +1,15 @@
|
|||||||
import {
|
import {
|
||||||
integer,
|
integer,
|
||||||
numeric,
|
|
||||||
sqliteTable,
|
sqliteTable,
|
||||||
text,
|
text,
|
||||||
type AnySQLiteColumn,
|
|
||||||
unique,
|
unique,
|
||||||
|
type AnySQLiteColumn
|
||||||
} from "drizzle-orm/sqlite-core";
|
} from "drizzle-orm/sqlite-core";
|
||||||
|
|
||||||
export const haexSettings = sqliteTable("haex_settings", {
|
export const haexSettings = sqliteTable("haex_settings", {
|
||||||
id: text().primaryKey(),
|
id: text().primaryKey(),
|
||||||
key: text(),
|
key: text(),
|
||||||
value_text: text(),
|
value: text(),
|
||||||
value_json: text({ mode: "json" }),
|
|
||||||
value_number: numeric(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const haexExtensions = sqliteTable("haex_extensions", {
|
export const haexExtensions = sqliteTable("haex_extensions", {
|
||||||
@ -25,18 +22,13 @@ export const haexExtensions = sqliteTable("haex_extensions", {
|
|||||||
version: text(),
|
version: text(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const testTable = sqliteTable("testTable", {
|
|
||||||
id: text().primaryKey(),
|
|
||||||
author: text(),
|
|
||||||
test: text(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const haexExtensionsPermissions = sqliteTable(
|
export const haexExtensionsPermissions = sqliteTable(
|
||||||
"haex_extensions_permissions",
|
"haex_extensions_permissions",
|
||||||
{
|
{
|
||||||
id: text().primaryKey(),
|
id: text().primaryKey(),
|
||||||
extensionId: text("extension_id").references((): AnySQLiteColumn => haexExtensions.id),
|
extensionId: text("extension_id").references((): AnySQLiteColumn => haexExtensions.id),
|
||||||
resource: text({ enum: ["fs", "http", "database"] }),
|
resource: text({ enum: ["fs", "http", "db", "shell"] }),
|
||||||
operation: text({ enum: ["read", "write", "create"] }),
|
operation: text({ enum: ["read", "write", "create"] }),
|
||||||
path: text(),
|
path: text(),
|
||||||
},
|
},
|
||||||
|
|||||||
Binary file not shown.
@ -41,7 +41,6 @@ pub fn run() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//extension::core::extension_protocol_handler(&context, &request)
|
|
||||||
})
|
})
|
||||||
.plugin(tauri_plugin_http::init())
|
.plugin(tauri_plugin_http::init())
|
||||||
.manage(DbConnection(Mutex::new(None)))
|
.manage(DbConnection(Mutex::new(None)))
|
||||||
|
|||||||
@ -19,7 +19,7 @@
|
|||||||
],
|
],
|
||||||
"security": {
|
"security": {
|
||||||
"csp": {
|
"csp": {
|
||||||
"default-src": ["'self'", "haex-extension: data: blob: asset:"],
|
"default-src": "'self' ipc: http://ipc.localhost; img-src 'self' asset: http://asset.localhost; default-src 'self' asset: http://asset.localhost",
|
||||||
"script-src": ["'self'", "haex-extension:"],
|
"script-src": ["'self'", "haex-extension:"],
|
||||||
"style-src": ["'self'", "haex-extension:"],
|
"style-src": ["'self'", "haex-extension:"],
|
||||||
"connect-src": ["'self'", "haex-extension:"],
|
"connect-src": ["'self'", "haex-extension:"],
|
||||||
@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"assetProtocol": {
|
"assetProtocol": {
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"scope": ["$RESOURCE/extensions/**"]
|
"scope": ["$RESOURCE/**", "$APPDATA/**"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<NuxtLayout :data-theme="currentTheme">
|
<NuxtLayout :data-theme="currentTheme.value">
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
<NuxtSnackbar />
|
<NuxtSnackbar />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
@ -8,7 +8,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { currentTheme } = storeToRefs(useUiStore());
|
const { currentTheme } = storeToRefs(useUiStore())
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@ -1,16 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="browser">
|
<div class="browser">
|
||||||
<div class="browser-controls">
|
<div class="browser-controls">
|
||||||
<button
|
<button @click="$emit('goBack', activeTabId)" :disabled="!activeTabId">
|
||||||
@click="$emit('goBack', activeTabId)"
|
|
||||||
:disabled="!activeTabId"
|
|
||||||
>
|
|
||||||
←
|
←
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button @click="$emit('goForward', activeTabId)" :disabled="!activeTabId">
|
||||||
@click="$emit('goForward', activeTabId)"
|
|
||||||
:disabled="!activeTabId"
|
|
||||||
>
|
|
||||||
→
|
→
|
||||||
</button>
|
</button>
|
||||||
<button @click="$emit('createTab')">+</button>
|
<button @click="$emit('createTab')">+</button>
|
||||||
@ -29,15 +23,9 @@
|
|||||||
@activateTab="$emit('activateTab', $event)"
|
@activateTab="$emit('activateTab', $event)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div class="browser-content" ref="contentRef">
|
||||||
class="browser-content"
|
|
||||||
ref="contentRef"
|
|
||||||
>
|
|
||||||
<!-- Die eigentlichen Webview-Inhalte werden von Tauri verwaltet -->
|
<!-- Die eigentlichen Webview-Inhalte werden von Tauri verwaltet -->
|
||||||
<div
|
<div v-if="!activeTabId" class="empty-state">
|
||||||
v-if="!activeTabId"
|
|
||||||
class="empty-state"
|
|
||||||
>
|
|
||||||
<p>
|
<p>
|
||||||
Kein Tab geöffnet. Erstellen Sie einen neuen Tab mit dem + Button.
|
Kein Tab geöffnet. Erstellen Sie einen neuen Tab mit dem + Button.
|
||||||
</p>
|
</p>
|
||||||
@ -47,9 +35,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { invoke } from '@tauri-apps/api/core';
|
import { Webview } from '@tauri-apps/api/webview'
|
||||||
import { Window } from '@tauri-apps/api/window';
|
import { Window } from '@tauri-apps/api/window'
|
||||||
import { getCurrentWebview, Webview } from '@tauri-apps/api/webview';
|
|
||||||
/* const appWindow = new Window('uniqueLabel');
|
/* const appWindow = new Window('uniqueLabel');
|
||||||
const webview = new Webview(appWindow, 'theUniqueLabel', {
|
const webview = new Webview(appWindow, 'theUniqueLabel', {
|
||||||
url: 'https://www.google.de',
|
url: 'https://www.google.de',
|
||||||
@ -64,46 +51,46 @@ webview.once('tauri://created', function () {
|
|||||||
}); */
|
}); */
|
||||||
|
|
||||||
interface Tab {
|
interface Tab {
|
||||||
id: string;
|
id: string
|
||||||
title: string;
|
title: string
|
||||||
url: string;
|
url: string
|
||||||
isLoading: boolean;
|
isLoading: boolean
|
||||||
isActive: boolean;
|
isActive: boolean
|
||||||
window_label: string;
|
window_label: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
tabs: Tab[];
|
tabs: Tab[]
|
||||||
activeTabId: string | null;
|
activeTabId: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'createTab'): void;
|
(e: 'createTab'): void
|
||||||
(e: 'closeTab', tabId: string): void;
|
(e: 'closeTab', tabId: string): void
|
||||||
(e: 'navigate', tabId: string, url: string): void;
|
(e: 'navigate', tabId: string, url: string): void
|
||||||
(e: 'goBack', tabId: string | null): void;
|
(e: 'goBack', tabId: string | null): void
|
||||||
(e: 'goForward', tabId: string | null): void;
|
(e: 'goForward', tabId: string | null): void
|
||||||
(e: 'activateTab', tabId: string | null): void;
|
(e: 'activateTab', tabId: string | null): void
|
||||||
}>();
|
}>()
|
||||||
|
|
||||||
const { initializeAsync, processNavigation, injectContentScripts } =
|
const { initializeAsync, processNavigation, injectContentScripts } =
|
||||||
useBrowserExtensionStore();
|
useBrowserExtensionStore()
|
||||||
const contentRef = ref<HTMLDivElement | null>(null);
|
const contentRef = ref<HTMLDivElement | null>(null)
|
||||||
//const extensionManager = ref<ExtensionManager>(new ExtensionManager());
|
//const extensionManager = ref<ExtensionManager>(new ExtensionManager());
|
||||||
|
|
||||||
const activeTab = computed(() =>
|
const activeTab = computed(() =>
|
||||||
props.tabs?.find((tab) => tab.id === props.activeTabId)
|
props.tabs?.find((tab) => tab.id === props.activeTabId)
|
||||||
);
|
)
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// Initialisiere das Erweiterungssystem
|
// Initialisiere das Erweiterungssystem
|
||||||
await initializeAsync();
|
await initializeAsync()
|
||||||
// Aktualisiere die Webview-Größe
|
// Aktualisiere die Webview-Größe
|
||||||
await updateWebviewBoundsAsync();
|
await updateWebviewBoundsAsync()
|
||||||
//window.addEventListener('resize', updateWebviewBounds);
|
//window.addEventListener('resize', updateWebviewBounds);
|
||||||
});
|
})
|
||||||
|
|
||||||
// Wenn ein neuer Tab aktiviert wird, injiziere Content-Scripts
|
// Wenn ein neuer Tab aktiviert wird, injiziere Content-Scripts
|
||||||
/* watch(
|
/* 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) => {
|
const handleUrlSubmit = (url: string) => {
|
||||||
|
createNewTabAsync()
|
||||||
if (props.activeTabId) {
|
if (props.activeTabId) {
|
||||||
// Prüfe URL mit Erweiterungen vor der Navigation
|
// Prüfe URL mit Erweiterungen vor der Navigation
|
||||||
if (processNavigation(url)) {
|
/* if (processNavigation(url)) {
|
||||||
emit('navigate', props.activeTabId, url);
|
//emit('navigate', props.activeTabId, url);
|
||||||
} else {
|
} else {
|
||||||
console.log('Navigation blockiert durch Erweiterung');
|
console.log('Navigation blockiert durch Erweiterung')
|
||||||
// Hier könnten Sie eine Benachrichtigung anzeigen
|
// Hier könnten Sie eine Benachrichtigung anzeigen
|
||||||
}
|
} */
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const updateWebviewBoundsAsync = async () => {
|
const updateWebviewBoundsAsync = async () => {
|
||||||
if (!contentRef.value) return;
|
if (!contentRef.value) return
|
||||||
|
|
||||||
const rect = contentRef.value.getBoundingClientRect();
|
const rect = contentRef.value.getBoundingClientRect()
|
||||||
const bounds = {
|
const bounds = {
|
||||||
x: rect.left,
|
x: rect.left,
|
||||||
y: rect.top,
|
y: rect.top,
|
||||||
width: rect.width,
|
width: rect.width,
|
||||||
height: rect.height,
|
height: rect.height,
|
||||||
};
|
}
|
||||||
|
|
||||||
/* await invoke('update_window_bounds', {
|
/* await invoke('update_window_bounds', {
|
||||||
contentBounds: { x: bounds.x, y: bounds.y },
|
contentBounds: { x: bounds.x, y: bounds.y },
|
||||||
contentSize: { width: bounds.width, height: bounds.height },
|
contentSize: { width: bounds.width, height: bounds.height },
|
||||||
}); */
|
}); */
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -10,10 +10,7 @@
|
|||||||
<span class="tab-title">
|
<span class="tab-title">
|
||||||
{{ tab.title || 'Neuer Tab' }}
|
{{ tab.title || 'Neuer Tab' }}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button class="tab-close" @click.stop="$emit('closeTab', tab.id)">
|
||||||
class="tab-close"
|
|
||||||
@click.stop="$emit('closeTab', tab.id)"
|
|
||||||
>
|
|
||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -22,22 +19,22 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
interface Tab {
|
interface Tab {
|
||||||
id: string;
|
id: string
|
||||||
title: string;
|
title: string
|
||||||
url: string;
|
url: string
|
||||||
isLoading: boolean;
|
isLoading: boolean
|
||||||
isActive: boolean;
|
isActive: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
tabs: Tab[];
|
tabs: Tab[]
|
||||||
activeTabId: string | null;
|
activeTabId: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>();
|
defineProps<Props>()
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
(e: 'closeTab', tabId: string): void;
|
(e: 'closeTab', tabId: string): void
|
||||||
(e: 'activateTab', tabId: string): void;
|
(e: 'activateTab', tabId: string): void
|
||||||
}>();
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,24 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<form
|
<form class="url-bar" @submit.prevent="handleSubmit">
|
||||||
class="url-bar"
|
<input type="text" v-model="inputValue" placeholder="URL eingeben" />
|
||||||
@submit.prevent="handleSubmit"
|
<span v-if="isLoading" class="loading-indicator">Laden...</span>
|
||||||
>
|
<button v-else type="submit">Go</button>
|
||||||
<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>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -32,26 +16,26 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['submit']);
|
const emit = defineEmits(['submit'])
|
||||||
|
|
||||||
const inputValue = ref(props.url);
|
const inputValue = ref(props.url)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.url,
|
() => props.url,
|
||||||
(newUrl) => {
|
(newUrl) => {
|
||||||
inputValue.value = newUrl;
|
inputValue.value = newUrl
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
// URL validieren und ggf. Protokoll hinzufügen
|
// URL validieren und ggf. Protokoll hinzufügen
|
||||||
let processedUrl = inputValue.value.trim();
|
let processedUrl = inputValue.value.trim()
|
||||||
if (processedUrl && !processedUrl.match(/^[a-zA-Z]+:\/\//)) {
|
if (processedUrl && !processedUrl.match(/^[a-zA-Z]+:\/\//)) {
|
||||||
processedUrl = 'https://' + processedUrl;
|
processedUrl = 'https://' + processedUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
emit('submit', processedUrl);
|
emit('submit', processedUrl)
|
||||||
};
|
}
|
||||||
</script>
|
</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>
|
<template>
|
||||||
<span>
|
<div>
|
||||||
<!-- <fieldset class="join w-full">
|
<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">
|
|
||||||
<slot name="prepend" />
|
<slot name="prepend" />
|
||||||
|
|
||||||
<div class="input join-item">
|
<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">
|
<div class="input-floating grow">
|
||||||
<input
|
<input
|
||||||
@ -90,12 +22,13 @@
|
|||||||
<label class="input-floating-label" :for="id">{{ label }}</label>
|
<label class="input-floating-label" :for="id">{{ label }}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Icon :name="appendIcon" class="my-auto shrink-0" />
|
<Icon v-if="appendIcon" :name="appendIcon" class="my-auto shrink-0" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<slot name="append" class="h-auto" />
|
<slot name="append" class="h-auto" />
|
||||||
|
|
||||||
<UiButton
|
<UiButton
|
||||||
|
v-if="withCopyButton"
|
||||||
class="btn-outline btn-accent btn-square join-item h-auto"
|
class="btn-outline btn-accent btn-square join-item h-auto"
|
||||||
@click="copy(`${input}`)"
|
@click="copy(`${input}`)"
|
||||||
>
|
>
|
||||||
@ -108,61 +41,61 @@
|
|||||||
{{ error }}
|
{{ error }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { type ZodSchema } from "zod";
|
import { type ZodSchema } from 'zod'
|
||||||
|
|
||||||
const inputRef = useTemplateRef("inputRef");
|
const inputRef = useTemplateRef('inputRef')
|
||||||
defineExpose({ inputRef });
|
defineExpose({ inputRef })
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
});
|
})
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: '',
|
||||||
},
|
},
|
||||||
type: {
|
type: {
|
||||||
type: String as PropType<
|
type: String as PropType<
|
||||||
| "button"
|
| 'button'
|
||||||
| "checkbox"
|
| 'checkbox'
|
||||||
| "color"
|
| 'color'
|
||||||
| "date"
|
| 'date'
|
||||||
| "datetime-local"
|
| 'datetime-local'
|
||||||
| "email"
|
| 'email'
|
||||||
| "file"
|
| 'file'
|
||||||
| "hidden"
|
| 'hidden'
|
||||||
| "image"
|
| 'image'
|
||||||
| "month"
|
| 'month'
|
||||||
| "number"
|
| 'number'
|
||||||
| "password"
|
| 'password'
|
||||||
| "radio"
|
| 'radio'
|
||||||
| "range"
|
| 'range'
|
||||||
| "reset"
|
| 'reset'
|
||||||
| "search"
|
| 'search'
|
||||||
| "submit"
|
| 'submit'
|
||||||
| "tel"
|
| 'tel'
|
||||||
| "text"
|
| 'text'
|
||||||
| "time"
|
| 'time'
|
||||||
| "url"
|
| 'url'
|
||||||
| "week"
|
| 'week'
|
||||||
>,
|
>,
|
||||||
default: "text",
|
default: 'text',
|
||||||
},
|
},
|
||||||
label: String,
|
label: String,
|
||||||
name: String,
|
name: String,
|
||||||
prependIcon: {
|
prependIcon: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: '',
|
||||||
},
|
},
|
||||||
prependLabel: String,
|
prependLabel: String,
|
||||||
appendIcon: {
|
appendIcon: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: '',
|
||||||
},
|
},
|
||||||
appendLabel: String,
|
appendLabel: String,
|
||||||
rules: Object as PropType<ZodSchema>,
|
rules: Object as PropType<ZodSchema>,
|
||||||
@ -170,45 +103,45 @@ const props = defineProps({
|
|||||||
withCopyButton: Boolean,
|
withCopyButton: Boolean,
|
||||||
autofocus: Boolean,
|
autofocus: Boolean,
|
||||||
read_only: Boolean,
|
read_only: Boolean,
|
||||||
});
|
})
|
||||||
|
|
||||||
const input = defineModel<string | number | undefined | null>({
|
const input = defineModel<string | number | undefined | null>({
|
||||||
default: "",
|
default: '',
|
||||||
required: true,
|
required: true,
|
||||||
});
|
})
|
||||||
|
|
||||||
const { currentScreenSize } = storeToRefs(useUiStore());
|
const { currentScreenSize } = storeToRefs(useUiStore())
|
||||||
onMounted(() => {
|
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(
|
watch(
|
||||||
() => props.checkInput,
|
() => props.checkInput,
|
||||||
() => {
|
() => {
|
||||||
checkInput();
|
checkInput()
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
const emit = defineEmits(["error"]);
|
const emit = defineEmits(['error'])
|
||||||
|
|
||||||
const checkInput = () => {
|
const checkInput = () => {
|
||||||
if (props.rules) {
|
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);
|
//console.log('check result', result.error, props.rules);
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
errors.value = result.error.errors.map((error) => error.message);
|
errors.value = result.error.errors.map((error) => error.message)
|
||||||
emit("error", errors.value);
|
emit('error', errors.value)
|
||||||
} else {
|
} else {
|
||||||
errors.value = [];
|
errors.value = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const { copy, copied } = useClipboard();
|
const { copy, copied } = useClipboard()
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -9,20 +9,22 @@
|
|||||||
v-model="value"
|
v-model="value"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<UiButton class="btn-outline btn-accent btn-square h-auto" @click="tooglePasswordType">
|
<UiButton
|
||||||
<Icon :name="type === 'password' ? 'mdi:eye' : 'mdi:eye-off'" />
|
class="btn-outline btn-accent btn-square h-auto"
|
||||||
|
@click="tooglePasswordType"
|
||||||
|
>
|
||||||
|
<Icon :name="type === 'password' ? 'mdi:eye-off' : 'mdi:eye'" />
|
||||||
</UiButton>
|
</UiButton>
|
||||||
</template>
|
</template>
|
||||||
</UiInput>
|
</UiInput>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ZodSchema } from "zod";
|
import type { ZodSchema } from 'zod'
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n()
|
||||||
const { currentScreenSize } = storeToRefs(useUiStore());
|
|
||||||
|
|
||||||
const value = defineModel<string | number | null | undefined>();
|
const value = defineModel<string | number | null | undefined>()
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
label: String,
|
label: String,
|
||||||
@ -30,13 +32,13 @@ defineProps({
|
|||||||
checkInput: Boolean,
|
checkInput: Boolean,
|
||||||
rules: Object as PropType<ZodSchema>,
|
rules: Object as PropType<ZodSchema>,
|
||||||
autofocus: Boolean,
|
autofocus: Boolean,
|
||||||
});
|
})
|
||||||
|
|
||||||
const type = ref<"password" | "text">("password");
|
const type = ref<'password' | 'text'>('password')
|
||||||
|
|
||||||
const tooglePasswordType = () => {
|
const tooglePasswordType = () => {
|
||||||
type.value = type.value === "password" ? "text" : "password";
|
type.value = type.value === 'password' ? 'text' : 'password'
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="json">
|
<i18n lang="json">
|
||||||
|
|||||||
@ -6,12 +6,11 @@
|
|||||||
@click="open = true"
|
@click="open = true"
|
||||||
>
|
>
|
||||||
<Icon name="mdi:plus" />
|
<Icon name="mdi:plus" />
|
||||||
{{ t("database.create") }}
|
{{ t('database.create') }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<form class="flex flex-col gap-4" @submit="onCreateAsync">
|
<form class="flex flex-col gap-4" @submit="onCreateAsync">
|
||||||
<!-- @keyup.enter="onCreateAsync" -->
|
|
||||||
<UiInput
|
<UiInput
|
||||||
:check-input="check"
|
:check-input="check"
|
||||||
:label="t('database.label')"
|
:label="t('database.label')"
|
||||||
@ -32,98 +31,116 @@
|
|||||||
|
|
||||||
<template #buttons>
|
<template #buttons>
|
||||||
<UiButton class="btn-error" @click="onClose">
|
<UiButton class="btn-error" @click="onClose">
|
||||||
{{ t("abort") }}
|
{{ t('abort') }}
|
||||||
</UiButton>
|
</UiButton>
|
||||||
|
|
||||||
<UiButton class="btn-primary" @click="onCreateAsync">
|
<UiButton class="btn-primary" @click="onCreateAsync">
|
||||||
{{ t("create") }}
|
{{ t('create') }}
|
||||||
</UiButton>
|
</UiButton>
|
||||||
</template>
|
</template>
|
||||||
</UiDialog>
|
</UiDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { save } from "@tauri-apps/plugin-dialog";
|
import { save } from '@tauri-apps/plugin-dialog'
|
||||||
import { useVaultStore } from "~/stores/vault";
|
import { useVaultStore } from '~/stores/vault'
|
||||||
import { vaultDatabaseSchema } from "./schema";
|
import { vaultDatabaseSchema } from './schema'
|
||||||
|
import { onKeyStroke } from '@vueuse/core'
|
||||||
|
|
||||||
const check = ref(false);
|
onKeyStroke('Enter', (e) => {
|
||||||
const open = ref();
|
e.preventDefault()
|
||||||
|
onCreateAsync()
|
||||||
|
})
|
||||||
|
|
||||||
const { t } = useI18n();
|
const check = ref(false)
|
||||||
|
const open = ref()
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const database = reactive<{
|
const database = reactive<{
|
||||||
name: string;
|
name: string
|
||||||
password: string;
|
password: string
|
||||||
path: string | null;
|
path: string | null
|
||||||
type: "password" | "text";
|
type: 'password' | 'text'
|
||||||
}>({
|
}>({
|
||||||
name: "",
|
name: '',
|
||||||
password: "",
|
password: '',
|
||||||
path: "",
|
path: '',
|
||||||
type: "password",
|
type: 'password',
|
||||||
});
|
})
|
||||||
|
|
||||||
const initDatabase = () => {
|
const initDatabase = () => {
|
||||||
database.name = t("database.name");
|
database.name = t('database.name')
|
||||||
database.password = "";
|
database.password = ''
|
||||||
database.path = "";
|
database.path = ''
|
||||||
database.type = "password";
|
database.type = 'password'
|
||||||
};
|
}
|
||||||
|
|
||||||
initDatabase();
|
initDatabase()
|
||||||
|
|
||||||
const { add } = useSnackbar();
|
const { add } = useSnackbar()
|
||||||
const { createAsync } = useVaultStore();
|
const { createAsync } = useVaultStore()
|
||||||
|
|
||||||
const onCreateAsync = async () => {
|
const onCreateAsync = async () => {
|
||||||
check.value = true;
|
check.value = true
|
||||||
|
|
||||||
const nameCheck = vaultDatabaseSchema.name.safeParse(database.name);
|
const nameCheck = vaultDatabaseSchema.name.safeParse(database.name)
|
||||||
const passwordCheck = vaultDatabaseSchema.password.safeParse(database.password);
|
const passwordCheck = vaultDatabaseSchema.password.safeParse(
|
||||||
|
database.password
|
||||||
|
)
|
||||||
|
|
||||||
console.log("checks", database.name, nameCheck, database.password, passwordCheck);
|
console.log(
|
||||||
if (!nameCheck.success || !passwordCheck.success) return;
|
'checks',
|
||||||
|
database.name,
|
||||||
|
nameCheck,
|
||||||
|
database.password,
|
||||||
|
passwordCheck
|
||||||
|
)
|
||||||
|
if (!nameCheck.success || !passwordCheck.success) return
|
||||||
|
|
||||||
open.value = false;
|
open.value = false
|
||||||
try {
|
try {
|
||||||
database.path = await save({
|
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) {
|
if (database.path && database.password) {
|
||||||
const vaultId = await createAsync({
|
const vaultId = await createAsync({
|
||||||
path: database.path,
|
path: database.path,
|
||||||
password: database.password,
|
password: database.password,
|
||||||
});
|
})
|
||||||
|
|
||||||
console.log("vaultId", vaultId);
|
console.log('vaultId', vaultId)
|
||||||
if (vaultId) {
|
if (vaultId) {
|
||||||
await navigateTo(useLocaleRoute()({ name: "vaultOverview", params: { vaultId } }));
|
await navigateTo(
|
||||||
|
useLocaleRoute()({ name: 'vaultOverview', params: { vaultId } })
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error)
|
||||||
add({ type: "error", text: JSON.stringify(error) });
|
add({ type: 'error', text: JSON.stringify(error) })
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
open.value = false;
|
open.value = false
|
||||||
initDatabase();
|
initDatabase()
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="json">
|
<i18n lang="json">
|
||||||
{
|
{
|
||||||
"de": {
|
"de": {
|
||||||
"database": {
|
"database": {
|
||||||
"label": "Datenbankname",
|
"label": "Vaultname",
|
||||||
"placeholder": "Passwörter",
|
"placeholder": "Vaultname",
|
||||||
"create": "Neue Vault anlegen",
|
"create": "Neue Vault anlegen",
|
||||||
"name": "Passwörter"
|
"name": "HaexVault"
|
||||||
},
|
},
|
||||||
"title": "Neue Datenbank anlegen",
|
"title": "Neue Datenbank anlegen",
|
||||||
"create": "Erstellen",
|
"create": "Erstellen",
|
||||||
@ -133,10 +150,10 @@ const onClose = () => {
|
|||||||
|
|
||||||
"en": {
|
"en": {
|
||||||
"database": {
|
"database": {
|
||||||
"label": "Databasename",
|
"label": "Vaultname",
|
||||||
"placeholder": "Databasename",
|
"placeholder": "Vaultname",
|
||||||
"create": "Create new Vault",
|
"create": "Create new Vault",
|
||||||
"name": "Passwords"
|
"name": "HaexVault"
|
||||||
},
|
},
|
||||||
"title": "Create New Database",
|
"title": "Create New Database",
|
||||||
"create": "Create",
|
"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>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-full h-full flex flex-col min-w-min">
|
<div class="w-full h-full flex flex-col min-w-min relative overflow-hidden">
|
||||||
<nav
|
<nav
|
||||||
class="navbar bg-base-100 rounded-b max-sm:shadow border-b border-base-content/25 sm:z-20 relative px-2"
|
class="navbar bg-base-100 rounded-b max-sm:shadow border-b border-base-content/25 sm:z-20 relative px-2"
|
||||||
>
|
>
|
||||||
@ -14,7 +14,11 @@
|
|||||||
ref="sidebarToogleRef"
|
ref="sidebarToogleRef"
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
:name="isVisible ? 'tabler:layout-sidebar' : 'tabler:layout-sidebar-filled'"
|
:name="
|
||||||
|
isVisible
|
||||||
|
? 'tabler:layout-sidebar-filled'
|
||||||
|
: 'tabler:layout-sidebar'
|
||||||
|
"
|
||||||
size="28"
|
size="28"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
@ -25,9 +29,12 @@
|
|||||||
class="link text-base-content link-neutral text-xl font-semibold no-underline"
|
class="link text-base-content link-neutral text-xl font-semibold no-underline"
|
||||||
:to="{ name: 'vaultOverview' }"
|
:to="{ name: 'vaultOverview' }"
|
||||||
>
|
>
|
||||||
<UiTextGradient class="text-nowrap">Haex Hub</UiTextGradient>
|
<UiTextGradient class="text-nowrap">{{
|
||||||
|
currentVaultName
|
||||||
|
}}</UiTextGradient>
|
||||||
</NuxtLinkLocale>
|
</NuxtLinkLocale>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="navbar-end flex items-center gap-4 me-4">
|
<div class="navbar-end flex items-center gap-4 me-4">
|
||||||
<div
|
<div
|
||||||
class="dropdown relative inline-flex [--auto-close:inside] [--offset:8] [--placement:bottom-end]"
|
class="dropdown relative inline-flex [--auto-close:inside] [--offset:8] [--placement:bottom-end]"
|
||||||
@ -45,7 +52,9 @@
|
|||||||
v-show="notifications.length"
|
v-show="notifications.length"
|
||||||
class="indicator-item bg-error size-2 rounded-full text-sm"
|
class="indicator-item bg-error size-2 rounded-full text-sm"
|
||||||
></span>
|
></span>
|
||||||
<span class="icon-[tabler--bell] text-base-content size-[1.375rem]"></span>
|
<span
|
||||||
|
class="icon-[tabler--bell] text-base-content size-[1.375rem]"
|
||||||
|
></span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
@ -56,7 +65,7 @@
|
|||||||
>
|
>
|
||||||
<div class="dropdown-header justify-center">
|
<div class="dropdown-header justify-center">
|
||||||
<h6 class="text-base-content text-base">
|
<h6 class="text-base-content text-base">
|
||||||
{{ t("notifications.label") }}
|
{{ t('notifications.label') }}
|
||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -70,7 +79,10 @@
|
|||||||
:src="notification.image"
|
:src="notification.image"
|
||||||
:alt="notification.alt ?? 'notification avatar'"
|
:alt="notification.alt ?? 'notification avatar'"
|
||||||
/>
|
/>
|
||||||
<Icon v-else-if="notification.icon" :name="notification.icon" />
|
<Icon
|
||||||
|
v-else-if="notification.icon"
|
||||||
|
:name="notification.icon"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-60">
|
<div class="w-60">
|
||||||
@ -85,80 +97,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<a href="#" class="dropdown-footer justify-center gap-1">
|
<a href="#" class="dropdown-footer justify-center gap-1">
|
||||||
<span class="icon-[tabler--eye] size-4"></span>
|
<span class="icon-[tabler--eye] size-4"></span>
|
||||||
{{ t("notifications.view_all") }}
|
{{ t('notifications.view_all') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
class="dropdown relative inline-flex [--auto-close:inside] [--offset:8] [--placement:bottom-end]"
|
<HaexMenuMain />
|
||||||
>
|
|
||||||
<button
|
|
||||||
id="dropdown-scrollable"
|
|
||||||
type="button"
|
|
||||||
class="dropdown-toggle flex items-center"
|
|
||||||
aria-haspopup="menu"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="Dropdown"
|
|
||||||
>
|
|
||||||
<div class="avatar">
|
|
||||||
<div class="size-9.5 rounded-full">
|
|
||||||
<img src="https://cdn.flyonui.com/fy-assets/avatar/avatar-1.png" alt="avatar 1" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<ul
|
|
||||||
class="dropdown-menu dropdown-open:opacity-100 hidden min-w-60"
|
|
||||||
role="menu"
|
|
||||||
aria-orientation="vertical"
|
|
||||||
aria-labelledby="dropdown-avatar"
|
|
||||||
>
|
|
||||||
<li class="dropdown-header gap-2">
|
|
||||||
<div class="avatar">
|
|
||||||
<div class="w-10 rounded-full">
|
|
||||||
<img src="https://cdn.flyonui.com/fy-assets/avatar/avatar-1.png" alt="avatar" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h6 class="text-base-content text-base font-semibold">John Doe</h6>
|
|
||||||
<small class="text-base-content/50">Admin</small>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="#">
|
|
||||||
<span class="icon-[tabler--user]"></span>
|
|
||||||
My Profile
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="#">
|
|
||||||
<span class="icon-[tabler--settings]"></span>
|
|
||||||
Settings
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="#">
|
|
||||||
<span class="icon-[tabler--receipt-rupee]"></span>
|
|
||||||
Billing
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item" href="#">
|
|
||||||
<span class="icon-[tabler--help-triangle]"></span>
|
|
||||||
FAQs
|
|
||||||
</a>
|
|
||||||
</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>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="flex h-full">
|
<div class="flex h-full overflow-hidden">
|
||||||
<aside
|
<aside
|
||||||
id="sidebar"
|
id="sidebar"
|
||||||
class="sm:shadow-none transition-all h-full overflow-hidden border-r border-base-300"
|
class="sm:shadow-none transition-all h-full overflow-hidden border-r border-base-300"
|
||||||
@ -179,7 +127,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<main class="w-full">
|
<main class="w-full h-full overflow-scroll">
|
||||||
<NuxtPage :transition="{ name: 'fade' }" />
|
<NuxtPage :transition="{ name: 'fade' }" />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
@ -187,32 +135,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NuxtLinkLocale } from "#components";
|
const { t } = useI18n()
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { currentVaultName } = storeToRefs(useVaultStore())
|
||||||
const { menu, isVisible } = storeToRefs(useSidebarStore());
|
|
||||||
const sidebarToogleRef = useTemplateRef("sidebarToogleRef");
|
|
||||||
|
|
||||||
/* onClickOutside(sidebarToogleRef, () => {
|
const { menu, isVisible } = storeToRefs(useSidebarStore())
|
||||||
if (currentScreenSize.value === "xs") {
|
|
||||||
isVisible.value = false;
|
const { notifications } = storeToRefs(useNotificationStore())
|
||||||
}
|
|
||||||
}); */
|
const { extensionLinks } = storeToRefs(useExtensionsStore())
|
||||||
const { notifications } = storeToRefs(useNotificationStore());
|
|
||||||
|
|
||||||
const { isActive } = useExtensionsStore();
|
|
||||||
const { closeAsync } = useVaultStore();
|
|
||||||
const { currentScreenSize } = storeToRefs(useUiStore());
|
|
||||||
const onExtensionSelectAsync = async (id: string) => {};
|
|
||||||
const { extensionLinks } = storeToRefs(useExtensionsStore());
|
|
||||||
const toogleSidebar = () => {
|
const toogleSidebar = () => {
|
||||||
isVisible.value = !isVisible.value;
|
isVisible.value = !isVisible.value
|
||||||
};
|
}
|
||||||
|
|
||||||
const onVaultCloseAsync = async () => {
|
|
||||||
await closeAsync();
|
|
||||||
await navigateTo(useLocalePath()({ name: "vaultOpen" }));
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="yaml">
|
<i18n lang="yaml">
|
||||||
@ -223,7 +158,7 @@ de:
|
|||||||
vault:
|
vault:
|
||||||
close: Vault schließen
|
close: Vault schließen
|
||||||
sidebar:
|
sidebar:
|
||||||
close: Sidebar schließen
|
close: Sidebar ausblenden
|
||||||
show: Sidebar anzeigen
|
show: Sidebar anzeigen
|
||||||
en:
|
en:
|
||||||
notifications:
|
notifications:
|
||||||
|
|||||||
@ -1,11 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="items-center justify-center min-h-full flex w-full">
|
<div class="items-center justify-center min-h-full flex w-full relative">
|
||||||
|
<div class="fixed top-2 right-2">
|
||||||
|
<UiDropdownLocale @select="setLocale" />
|
||||||
|
</div>
|
||||||
<div class="flex flex-col justify-center items-center gap-5 max-w-3xl">
|
<div class="flex flex-col justify-center items-center gap-5 max-w-3xl">
|
||||||
<img src="/logo.svg" class="bg-primary p-3 size-16 rounded-full" alt="HaexVault Logo" />
|
<img
|
||||||
|
src="/logo.svg"
|
||||||
|
class="bg-primary p-3 size-16 rounded-full"
|
||||||
|
alt="HaexVault Logo"
|
||||||
|
/>
|
||||||
|
|
||||||
<span class="flex flex-wrap font-bold text-pretty text-xl gap-2 justify-center">
|
<span
|
||||||
|
class="flex flex-wrap font-bold text-pretty text-xl gap-2 justify-center"
|
||||||
|
>
|
||||||
<p class="whitespace-nowrap">
|
<p class="whitespace-nowrap">
|
||||||
{{ t("welcome") }}
|
{{ t('welcome') }}
|
||||||
</p>
|
</p>
|
||||||
<UiTextGradient>Haex Hub</UiTextGradient>
|
<UiTextGradient>Haex Hub</UiTextGradient>
|
||||||
</span>
|
</span>
|
||||||
@ -13,34 +22,15 @@
|
|||||||
<div class="flex flex-col md:flex-row gap-4 w-full h-24 md:h-auto">
|
<div class="flex flex-col md:flex-row gap-4 w-full h-24 md:h-auto">
|
||||||
<VaultButtonCreate />
|
<VaultButtonCreate />
|
||||||
|
|
||||||
<VaultButtonOpen v-model:isOpen="passwordPromptOpen" :path="vaultPath" />
|
<VaultButtonOpen
|
||||||
<!-- <NuxtLinkLocale
|
v-model:isOpen="passwordPromptOpen"
|
||||||
:to="{
|
:path="vaultPath"
|
||||||
name: 'haexBrowser',
|
|
||||||
params: { vaultId: 'test' },
|
|
||||||
}"
|
|
||||||
>test link</NuxtLinkLocale
|
|
||||||
> -->
|
|
||||||
<!-- <button @click="test">test</button>
|
|
||||||
<NuxtLinkLocale
|
|
||||||
:to="{ name: 'vaultGroup', params: { vaultId: 'test' } }"
|
|
||||||
>test link</NuxtLinkLocale
|
|
||||||
> -->
|
|
||||||
|
|
||||||
<!-- <UiTreeFolder
|
|
||||||
@edit="test"
|
|
||||||
:value="tests"
|
|
||||||
v-for="tests in [1, 2, 3]"
|
|
||||||
/>
|
/>
|
||||||
<UiTreeFolder
|
|
||||||
@edit="test"
|
|
||||||
value="test123"
|
|
||||||
/> -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-show="lastVaults.length" class="w-full">
|
<div v-show="lastVaults.length" class="w-full">
|
||||||
<div class="font-thin text-sm justify-start px-2 pb-1">
|
<div class="font-thin text-sm justify-start px-2 pb-1">
|
||||||
{{ t("lastUsed") }}
|
{{ t('lastUsed') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@ -53,10 +43,7 @@
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="link link-accent flex items-center no-underline justify-between text-nowrap text-sm md:text-base shrink w-full py-2 px-4"
|
class="link link-accent flex items-center no-underline justify-between text-nowrap text-sm md:text-base shrink w-full py-2 px-4"
|
||||||
@click="
|
@click=";(passwordPromptOpen = true), (vaultPath = vault.path)"
|
||||||
passwordPromptOpen = true;
|
|
||||||
vaultPath = vault.path;
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<span class="block md:hidden">
|
<span class="block md:hidden">
|
||||||
{{ vault.name }}
|
{{ vault.name }}
|
||||||
@ -68,14 +55,17 @@
|
|||||||
<button
|
<button
|
||||||
class="absolute right-2 btn btn-square btn-error btn-xs hidden group-hover:flex min-w-6"
|
class="absolute right-2 btn btn-square btn-error btn-xs hidden group-hover:flex min-w-6"
|
||||||
>
|
>
|
||||||
<Icon name="mdi:trash-can-outline" @click="removeVaultAsync(vault.path)" />
|
<Icon
|
||||||
|
name="mdi:trash-can-outline"
|
||||||
|
@click="removeVaultAsync(vault.path)"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col items-center gap-2">
|
<div class="flex flex-col items-center gap-2">
|
||||||
<h4>{{ t("sponsors") }}</h4>
|
<h4>{{ t('sponsors') }}</h4>
|
||||||
<div>
|
<div>
|
||||||
<button @click="openUrl('https://itemis.com')">
|
<button @click="openUrl('https://itemis.com')">
|
||||||
<UiLogoItemis class="text-[#00457C]" />
|
<UiLogoItemis class="text-[#00457C]" />
|
||||||
@ -87,41 +77,21 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { openUrl } from "@tauri-apps/plugin-opener";
|
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||||
|
|
||||||
const passwordPromptOpen = ref(false);
|
|
||||||
const vaultPath = ref("");
|
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
name: "vaultOpen",
|
name: 'vaultOpen',
|
||||||
});
|
})
|
||||||
|
|
||||||
const { t } = useI18n();
|
const passwordPromptOpen = ref(false)
|
||||||
|
const vaultPath = ref('')
|
||||||
|
|
||||||
const { syncLastVaultsAsync, removeVaultAsync } = useLastVaultStore();
|
const { t, setLocale } = useI18n()
|
||||||
const { lastVaults } = storeToRefs(useLastVaultStore());
|
|
||||||
|
|
||||||
await syncLastVaultsAsync();
|
const { syncLastVaultsAsync, removeVaultAsync } = useLastVaultStore()
|
||||||
|
const { lastVaults } = storeToRefs(useLastVaultStore())
|
||||||
|
|
||||||
/* const { $pluginManager } = useNuxtApp();
|
await syncLastVaultsAsync()
|
||||||
|
|
||||||
console.log('$pluginManager', $pluginManager);
|
|
||||||
async function loadModule() {
|
|
||||||
try {
|
|
||||||
// Dynamisches Laden des Moduls
|
|
||||||
const file = await open({
|
|
||||||
multiple: false,
|
|
||||||
directory: false,
|
|
||||||
});
|
|
||||||
const moduleUrl =
|
|
||||||
'/home/haex/Projekte/haex-vault-2/haex-vault/src/extensions/test/testPlugin.ts'; // Pfad relativ zum Server-Root
|
|
||||||
await $pluginManager.loadDynamicModule(file);
|
|
||||||
console.log('Modul erfolgreich geladen');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Fehler beim Laden des Moduls:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//await loadModule(); */
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="json">
|
<i18n lang="json">
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="text-white h-full">
|
<div class="w-full h-full">
|
||||||
<NuxtLayout name="app">
|
<NuxtLayout name="app">
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
@ -8,6 +8,6 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: "database",
|
middleware: 'database',
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
{{ iframeSrc }}
|
{{ iframeSrc }}
|
||||||
</div> -->
|
</div> -->
|
||||||
<iframe
|
<iframe
|
||||||
v-if="iframeSrc"
|
v-if="iframeIndex"
|
||||||
class="w-full h-full"
|
class="w-full h-full"
|
||||||
@load=""
|
@load=""
|
||||||
ref="iFrameRef"
|
ref="iFrameRef"
|
||||||
@ -13,14 +13,25 @@
|
|||||||
allow="autoplay; speaker-selection; encrypted-media;"
|
allow="autoplay; speaker-selection; encrypted-media;"
|
||||||
>
|
>
|
||||||
</iframe>
|
</iframe>
|
||||||
|
|
||||||
|
<UiButton @click="go = true">Go</UiButton>
|
||||||
<!-- <p v-else>{{ t("loading") }}</p> -->
|
<!-- <p v-else>{{ t("loading") }}</p> -->
|
||||||
<audio controls :src="audioTest">
|
{{ audioTest }}
|
||||||
|
<audio v-if="go" controls :src="audioTest">
|
||||||
Dein Browser unterstützt das Audio-Element nicht.
|
Dein Browser unterstützt das Audio-Element nicht.
|
||||||
</audio>
|
</audio>
|
||||||
|
|
||||||
|
<video v-if="go" controls width="600" :src="demoVideo"></video>
|
||||||
|
<div v-if="audioError">
|
||||||
|
Fehler beim Laden der Audio-Datei: {{ audioError }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||||
|
import { appDataDir, join, resourceDir } from '@tauri-apps/api/path'
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
name: 'haexExtension',
|
name: 'haexExtension',
|
||||||
})
|
})
|
||||||
@ -30,25 +41,34 @@ const iframeRef = useTemplateRef('iFrameRef')
|
|||||||
const { extensionEntry: iframeSrc, currentExtension } = storeToRefs(
|
const { extensionEntry: iframeSrc, currentExtension } = storeToRefs(
|
||||||
useExtensionsStore()
|
useExtensionsStore()
|
||||||
)
|
)
|
||||||
const audioTest = computed(() => `${iframeSrc.value}/sounds/music/demo.mp3`)
|
const audioAssetUrl = ref('')
|
||||||
watch(audioTest, () => console.log('audioTest', audioTest.value), {
|
const audioError = ref('')
|
||||||
immediate: true,
|
const audioTest = convertFileSrc(
|
||||||
})
|
await join(await appDataDir(), 'resources/demo.mp3')
|
||||||
|
)
|
||||||
|
|
||||||
|
//computed(() => `${iframeSrc.value}/sounds/music/demo.mp3`)
|
||||||
|
|
||||||
|
const go = ref(false)
|
||||||
const iframeIndex = computed(() => `${iframeSrc.value}/index.html`)
|
const iframeIndex = computed(() => `${iframeSrc.value}/index.html`)
|
||||||
|
const demoVideo = computed(() => `${iframeSrc.value}/sounds/music/demo.mp3`)
|
||||||
|
|
||||||
const extensionStore = useExtensionsStore()
|
const extensionStore = useExtensionsStore()
|
||||||
|
|
||||||
watch(iframeSrc, () => console.log('iframeSrc', iframeSrc.value), {
|
watch(
|
||||||
immediate: true,
|
demoVideo,
|
||||||
})
|
async () => {
|
||||||
|
const res = await fetch(
|
||||||
|
'/home/haex/.local/share/space.haex.hub/extensions/pokedemo/1.0/sounds/music/demo.mp3'
|
||||||
|
)
|
||||||
|
console.log('respo', res)
|
||||||
|
|
||||||
onMounted(async () => {
|
console.log('iframeSrc', iframeSrc.value)
|
||||||
/* const minfest = await extensionStore.readManifestFileAsync(
|
},
|
||||||
currentExtension.value!.id,
|
{
|
||||||
currentExtension.value!.version
|
immediate: true,
|
||||||
);
|
}
|
||||||
console.log("manifest", minfest, extensionStore.extensionEntry); */
|
)
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="yaml">
|
<i18n lang="yaml">
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-full"></div>
|
<div class="h-full text-base-content"></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
name: "vaultOverview",
|
name: 'vaultOverview',
|
||||||
});
|
})
|
||||||
|
|
||||||
const extensionStore = useExtensionsStore();
|
const extensionStore = useExtensionsStore()
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await extensionStore.loadExtensionsAsync();
|
await extensionStore.loadExtensionsAsync()
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
77
src/pages/vault/[vaultId]/settings.vue
Normal file
77
src/pages/vault/[vaultId]/settings.vue
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="grid grid-rows-2 sm:grid-cols-2 sm:gap-2 p-2 max-w-2xl w-full h-fit"
|
||||||
|
>
|
||||||
|
<div class="p-2">{{ t('language') }}</div>
|
||||||
|
<div><UiDropdownLocale @select="onSelectLocaleAsync" /></div>
|
||||||
|
|
||||||
|
<div class="p-2">{{ t('design') }}</div>
|
||||||
|
<div><UiDropdownTheme @select="onSelectThemeAsync" /></div>
|
||||||
|
|
||||||
|
<div class="p-2">{{ t('vaultName') }}</div>
|
||||||
|
<div>
|
||||||
|
<UiInput v-model="currentVaultName" :placeholder="t('vaultName')">
|
||||||
|
<template #append>
|
||||||
|
<UiTooltip :tooltip="t('save')">
|
||||||
|
<UiButton class="btn-primary" @click="onSetVaultNameAsync">
|
||||||
|
<Icon name="mdi:content-save-outline" />
|
||||||
|
</UiButton>
|
||||||
|
</UiTooltip>
|
||||||
|
</template>
|
||||||
|
</UiInput>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { eq } from 'drizzle-orm'
|
||||||
|
import { type Locale } from 'vue-i18n'
|
||||||
|
import { haexSettings } from '~~/src-tauri/database/schemas/vault'
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
name: 'haexSettings',
|
||||||
|
})
|
||||||
|
|
||||||
|
const { t, setLocale } = useI18n()
|
||||||
|
|
||||||
|
const { currentVault, currentVaultName } = storeToRefs(useVaultStore())
|
||||||
|
const { updateVaultNameAsync } = useVaultStore()
|
||||||
|
|
||||||
|
const onSelectLocaleAsync = async (locale: Locale) => {
|
||||||
|
console.log('onSelectLocaleAsync', locale)
|
||||||
|
const update = await currentVault.value?.drizzle
|
||||||
|
.update(haexSettings)
|
||||||
|
.set({ key: 'locale', value: locale })
|
||||||
|
.where(eq(haexSettings.key, 'locale'))
|
||||||
|
await setLocale(locale)
|
||||||
|
console.log('update locale', update)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { currentTheme } = storeToRefs(useUiStore())
|
||||||
|
|
||||||
|
const onSelectThemeAsync = async (theme: ITheme) => {
|
||||||
|
const update = await currentVault.value?.drizzle
|
||||||
|
.update(haexSettings)
|
||||||
|
.set({ key: 'theme', value: theme.name })
|
||||||
|
.where(eq(haexSettings.key, 'theme'))
|
||||||
|
currentTheme.value = theme
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSetVaultNameAsync = async (vaultName: string) => {
|
||||||
|
updateVaultNameAsync(vaultName)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<i18n lang="yaml">
|
||||||
|
de:
|
||||||
|
language: Sprache
|
||||||
|
design: Design
|
||||||
|
vaultName: Vaultname
|
||||||
|
save: Änderung speichern
|
||||||
|
|
||||||
|
en:
|
||||||
|
language: Language
|
||||||
|
design: Design
|
||||||
|
vaultName: Vault Name
|
||||||
|
save: save changes
|
||||||
|
</i18n>
|
||||||
@ -46,6 +46,7 @@ export const useBrowserExtensionStore = defineStore(
|
|||||||
|
|
||||||
const initializeAsync = async () => {
|
const initializeAsync = async () => {
|
||||||
const { isInitialized } = storeToRefs(useBrowserExtensionStore());
|
const { isInitialized } = storeToRefs(useBrowserExtensionStore());
|
||||||
|
return
|
||||||
if (isInitialized.value) return;
|
if (isInitialized.value) return;
|
||||||
|
|
||||||
// Lade Erweiterungen aus dem Erweiterungsverzeichnis
|
// Lade Erweiterungen aus dem Erweiterungsverzeichnis
|
||||||
@ -87,4 +88,4 @@ const processNavigation = (url: string) => {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const injectContentScripts = (t: string) => {};
|
const injectContentScripts = (t: string) => { };
|
||||||
|
|||||||
@ -285,12 +285,12 @@ export const useExtensionsStore = defineStore("extensionsStore", () => {
|
|||||||
const extensionEntry = computedAsync(
|
const extensionEntry = computedAsync(
|
||||||
async () => {
|
async () => {
|
||||||
try {
|
try {
|
||||||
console.log("extensionEntry start", currentExtension.value);
|
/* console.log("extensionEntry start", currentExtension.value);
|
||||||
const regex = /((href|src)=["'])([^"']+)(["'])/g;
|
const regex = /((href|src)=["'])([^"']+)(["'])/g; */
|
||||||
|
|
||||||
if (!currentExtension.value?.id || !currentExtension.value.version) {
|
if (!currentExtension.value?.id || !currentExtension.value.version) {
|
||||||
console.log("extension id or entry missing", currentExtension.value);
|
console.log("extension id or entry missing", currentExtension.value);
|
||||||
return "no mani: " + currentExtension.value;
|
return ""// "no mani: " + currentExtension.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const extensionPath = await getExtensionPathAsync(
|
const extensionPath = await getExtensionPathAsync(
|
||||||
@ -304,7 +304,7 @@ export const useExtensionsStore = defineStore("extensionsStore", () => {
|
|||||||
currentExtension.value.version
|
currentExtension.value.version
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!manifest) return "no manifest readable";
|
if (!manifest) return ""//"no manifest readable";
|
||||||
|
|
||||||
const entryPath = await join(extensionPath, manifest.entry);
|
const entryPath = await join(extensionPath, manifest.entry);
|
||||||
|
|
||||||
@ -322,12 +322,12 @@ export const useExtensionsStore = defineStore("extensionsStore", () => {
|
|||||||
console.log("entryHtml", entryHtml);
|
console.log("entryHtml", entryHtml);
|
||||||
const replacements = [];
|
const replacements = [];
|
||||||
let match;
|
let match;
|
||||||
while ((match = regex.exec(entryHtml)) !== null) {
|
/* while ((match = regex.exec(entryHtml)) !== null) {
|
||||||
const [fullMatch, prefix, attr, resource, suffix] = match;
|
const [fullMatch, prefix, attr, resource, suffix] = match;
|
||||||
if (!resource.startsWith("http")) {
|
if (!resource.startsWith("http")) {
|
||||||
replacements.push({ match: fullMatch, resource, prefix, suffix });
|
replacements.push({ match: fullMatch, resource, prefix, suffix });
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
|
|
||||||
for (const { match, resource, prefix, suffix } of replacements) {
|
for (const { match, resource, prefix, suffix } of replacements) {
|
||||||
const srcFile = convertFileSrc(await join(extensionPath, resource));
|
const srcFile = convertFileSrc(await join(extensionPath, resource));
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"light": "Hell",
|
"light": "Hell",
|
||||||
"dark": "Dunkel",
|
"dark": "Dunkel",
|
||||||
"soft": "Soft"
|
"soft": "Soft",
|
||||||
|
"corporate": "Corporate"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"light": "Light",
|
"light": "Light",
|
||||||
"dark": "Dark",
|
"dark": "Dark",
|
||||||
"soft": "Soft"
|
"soft": "Soft",
|
||||||
|
"corporate": "Corporate"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,12 @@ import { breakpointsTailwind, useBreakpoints } from '@vueuse/core';
|
|||||||
import de from './de.json';
|
import de from './de.json';
|
||||||
import en from './en.json';
|
import en from './en.json';
|
||||||
|
|
||||||
|
export interface ITheme {
|
||||||
|
value: string,
|
||||||
|
name: string,
|
||||||
|
icon: string
|
||||||
|
}
|
||||||
|
|
||||||
export const useUiStore = defineStore('uiStore', () => {
|
export const useUiStore = defineStore('uiStore', () => {
|
||||||
const breakpoints = useBreakpoints(breakpointsTailwind);
|
const breakpoints = useBreakpoints(breakpointsTailwind);
|
||||||
|
|
||||||
@ -28,14 +34,22 @@ export const useUiStore = defineStore('uiStore', () => {
|
|||||||
icon: 'line-md:moon-to-sunny-outline-loop-transition',
|
icon: 'line-md:moon-to-sunny-outline-loop-transition',
|
||||||
},
|
},
|
||||||
{ value: 'soft', name: t('ui.soft'), icon: 'line-md:paint-drop' },
|
{ value: 'soft', name: t('ui.soft'), icon: 'line-md:paint-drop' },
|
||||||
|
{
|
||||||
|
value: 'corporate',
|
||||||
|
name: t('ui.corporate'),
|
||||||
|
icon: 'hugeicons:corporate',
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const currentTheme = ref(availableThemes.value[0].value);
|
const defaultTheme = ref(availableThemes.value[0])
|
||||||
|
|
||||||
|
const currentTheme = ref(defaultTheme);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
availableThemes,
|
||||||
breakpoints,
|
breakpoints,
|
||||||
currentScreenSize,
|
currentScreenSize,
|
||||||
currentTheme,
|
currentTheme,
|
||||||
availableThemes,
|
defaultTheme,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,13 +13,6 @@ export const useSidebarStore = defineStore("sidebarStore", () => {
|
|||||||
const isVisible = ref(true);
|
const isVisible = ref(true);
|
||||||
|
|
||||||
const menu = ref<ISidebarItem[]>([
|
const menu = ref<ISidebarItem[]>([
|
||||||
{
|
|
||||||
id: "haex-browser",
|
|
||||||
name: "Haex Browser",
|
|
||||||
icon: "solar:global-outline",
|
|
||||||
to: { name: "haexBrowser" },
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
id: "haex-extensions-add",
|
id: "haex-extensions-add",
|
||||||
name: "Haex Extensions",
|
name: "Haex Extensions",
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
//import Database from '@tauri-apps/plugin-sql';
|
|
||||||
import { drizzle, SqliteRemoteDatabase } from "drizzle-orm/sqlite-proxy";
|
|
||||||
//import Database from "tauri-plugin-sql-api";
|
|
||||||
import * as schema from "@/../src-tauri/database/schemas/vault";
|
|
||||||
|
|
||||||
|
import * as schema from "@/../src-tauri/database/schemas/vault";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { and, count, eq } from "drizzle-orm";
|
import { hostname, platform, type, version } from "@tauri-apps/plugin-os";
|
||||||
import { platform } from "@tauri-apps/plugin-os";
|
import { eq } from "drizzle-orm";
|
||||||
|
import { drizzle, SqliteRemoteDatabase } from "drizzle-orm/sqlite-proxy";
|
||||||
|
|
||||||
interface IVault {
|
interface IVault {
|
||||||
name: string;
|
name: string;
|
||||||
@ -16,6 +14,7 @@ interface IOpenVaults {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useVaultStore = defineStore("vaultStore", () => {
|
export const useVaultStore = defineStore("vaultStore", () => {
|
||||||
|
|
||||||
const currentVaultId = computed<string | undefined>({
|
const currentVaultId = computed<string | undefined>({
|
||||||
get: () => getSingleRouteParam(useRouter().currentRoute.value.params.vaultId),
|
get: () => getSingleRouteParam(useRouter().currentRoute.value.params.vaultId),
|
||||||
set: (newVaultId) => {
|
set: (newVaultId) => {
|
||||||
@ -23,6 +22,9 @@ export const useVaultStore = defineStore("vaultStore", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const defaultVaultName = ref("HaexHub")
|
||||||
|
const currentVaultName = ref(defaultVaultName.value)
|
||||||
|
|
||||||
const read_only = computed<boolean>({
|
const read_only = computed<boolean>({
|
||||||
get: () => {
|
get: () => {
|
||||||
console.log("query showSidebar", useRouter().currentRoute.value.query.readonly);
|
console.log("query showSidebar", useRouter().currentRoute.value.query.readonly);
|
||||||
@ -53,6 +55,8 @@ export const useVaultStore = defineStore("vaultStore", () => {
|
|||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hostKey = computedAsync(async () => "".concat(type(), version(), await hostname() ?? ""))
|
||||||
|
|
||||||
const openAsync = async ({ path = "", password }: { path: string; password: string }) => {
|
const openAsync = async ({ path = "", password }: { path: string; password: string }) => {
|
||||||
try {
|
try {
|
||||||
const result = await invoke<string>("open_encrypted_database", {
|
const result = await invoke<string>("open_encrypted_database", {
|
||||||
@ -102,7 +106,11 @@ export const useVaultStore = defineStore("vaultStore", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const { addVaultAsync } = useLastVaultStore();
|
const { addVaultAsync } = useLastVaultStore();
|
||||||
await addVaultAsync({ path });
|
addVaultAsync({ path });
|
||||||
|
|
||||||
|
syncLocaleAsync()
|
||||||
|
syncThemeAsync()
|
||||||
|
syncVaultNameAsync()
|
||||||
|
|
||||||
return vaultId;
|
return vaultId;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -147,15 +155,86 @@ export const useVaultStore = defineStore("vaultStore", () => {
|
|||||||
delete openVaults.value?.[currentVaultId.value];
|
delete openVaults.value?.[currentVaultId.value];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const syncLocaleAsync = async () => {
|
||||||
|
try {
|
||||||
|
const app = useNuxtApp()
|
||||||
|
app.$i18n.availableLocales
|
||||||
|
//const { availableLocales, defaultLocale, setLocale, locale } = useI18n()
|
||||||
|
|
||||||
|
const currentLocaleRow = await currentVault.value?.drizzle
|
||||||
|
.select()
|
||||||
|
.from(schema.haexSettings)
|
||||||
|
.where(eq(schema.haexSettings.key, 'locale'))
|
||||||
|
|
||||||
|
if (currentLocaleRow?.[0]?.value) {
|
||||||
|
const currentLocale = app.$i18n.availableLocales.find(
|
||||||
|
(locale) => locale === currentLocaleRow[0].value
|
||||||
|
)
|
||||||
|
await app.$i18n.setLocale(currentLocale ?? app.$i18n.defaultLocale)
|
||||||
|
} else {
|
||||||
|
await currentVault.value?.drizzle
|
||||||
|
.insert(schema.haexSettings)
|
||||||
|
.values({ id: crypto.randomUUID(), key: 'locale', value: app.$i18n.locale.value })
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("ERROR syncLocaleAsync", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const syncThemeAsync = async () => {
|
||||||
|
const { availableThemes, defaultTheme, currentTheme } = storeToRefs(useUiStore())
|
||||||
|
const currentThemeRow = await currentVault.value?.drizzle
|
||||||
|
.select()
|
||||||
|
.from(schema.haexSettings)
|
||||||
|
.where(eq(schema.haexSettings.key, 'theme'))
|
||||||
|
|
||||||
|
if (currentThemeRow?.[0]?.value) {
|
||||||
|
const theme = availableThemes.value.find(
|
||||||
|
(theme) => theme.name === currentThemeRow[0].value
|
||||||
|
)
|
||||||
|
currentTheme.value = theme ?? defaultTheme.value
|
||||||
|
} else {
|
||||||
|
await currentVault.value?.drizzle.insert(schema.haexSettings).values({
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
key: 'theme',
|
||||||
|
value: currentTheme.value.name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const syncVaultNameAsync = async () => {
|
||||||
|
const currentVaultNameRow = await currentVault.value?.drizzle
|
||||||
|
.select()
|
||||||
|
.from(schema.haexSettings)
|
||||||
|
.where(eq(schema.haexSettings.key, 'vaultName'))
|
||||||
|
|
||||||
|
if (currentVaultNameRow?.[0]?.value) {
|
||||||
|
currentVaultName.value = currentVaultNameRow.at(0)?.value ?? defaultVaultName.value
|
||||||
|
} else {
|
||||||
|
await currentVault.value?.drizzle.insert(schema.haexSettings).values({
|
||||||
|
id: crypto.randomUUID(),
|
||||||
|
key: 'vaultName',
|
||||||
|
value: currentVaultName.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateVaultNameAsync = async (newVaultName?: string | null) => {
|
||||||
|
return currentVault.value?.drizzle.update(schema.haexSettings).set({ value: newVaultName ?? defaultVaultName.value }).where(eq(schema.haexSettings.key, "vaultName"))
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
closeAsync,
|
closeAsync,
|
||||||
createAsync,
|
createAsync,
|
||||||
currentVault,
|
currentVault,
|
||||||
currentVaultId,
|
currentVaultId,
|
||||||
|
currentVaultName,
|
||||||
|
hostKey,
|
||||||
openAsync,
|
openAsync,
|
||||||
openVaults,
|
openVaults,
|
||||||
refreshDatabaseAsync,
|
|
||||||
read_only,
|
read_only,
|
||||||
|
refreshDatabaseAsync,
|
||||||
|
updateVaultNameAsync,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -174,3 +253,6 @@ const isSelectQuery = (sql: string) => {
|
|||||||
const selectRegex = /^\s*SELECT\b/i;
|
const selectRegex = /^\s*SELECT\b/i;
|
||||||
return selectRegex.test(sql);
|
return selectRegex.test(sql);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,148 +0,0 @@
|
|||||||
import { defineConfig } from '@nuxtjs/tailwindcss/config';
|
|
||||||
//import { iconsPlugin, dynamicIconsPlugin } from '@egoist/tailwindcss-icons';
|
|
||||||
//import colors from 'tailwindcss/colors';
|
|
||||||
import themes from 'flyonui/src/theming/themes';
|
|
||||||
//import * as tailwindMotion from 'tailwindcss-motion';
|
|
||||||
import { addDynamicIconSelectors } from '@iconify/tailwind';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
content: ['./src/**/*.{vue,ts,svg}', './node_modules/flyonui/dist/js/*.js'],
|
|
||||||
darkMode: 'selector',
|
|
||||||
plugins: [
|
|
||||||
/* iconsPlugin(),
|
|
||||||
dynamicIconsPlugin(), */
|
|
||||||
addDynamicIconSelectors(),
|
|
||||||
require('flyonui'),
|
|
||||||
require('flyonui/plugin'),
|
|
||||||
//tailwindMotion,
|
|
||||||
],
|
|
||||||
|
|
||||||
flyonui: {
|
|
||||||
themes: [
|
|
||||||
{
|
|
||||||
light: {
|
|
||||||
...themes.light,
|
|
||||||
/* primary: colors.teal[500],
|
|
||||||
secondary: colors.purple[500], */
|
|
||||||
},
|
|
||||||
soft: {
|
|
||||||
...themes.soft,
|
|
||||||
/* primary: colors.teal[500],
|
|
||||||
secondary: colors.purple[500], */
|
|
||||||
},
|
|
||||||
dark: {
|
|
||||||
...themes.dark,
|
|
||||||
/* primary: colors.cyan[700], //colors.teal[600],
|
|
||||||
secondary: colors.purple[500], */
|
|
||||||
/* 'primary-content': '#000516',
|
|
||||||
'secondary': '#008f9c',
|
|
||||||
'secondary-content': '#000709',
|
|
||||||
'accent': '#007f7a',
|
|
||||||
'accent-content': '#d3e5e3',
|
|
||||||
'neutral': '#321a15',
|
|
||||||
'neutral-content': '#d3ccca',
|
|
||||||
'base-100': '#002732',
|
|
||||||
'base-200': '#00202a',
|
|
||||||
'base-300': '#001a22',
|
|
||||||
'base-content': '#c8cfd2',
|
|
||||||
'info': '#0086b2',
|
|
||||||
'info-content': '#00060c',
|
|
||||||
'success': '#a5da00',
|
|
||||||
'success-content': '#0a1100',
|
|
||||||
'warning': '#ff8d00',
|
|
||||||
'warning-content': '#160700',
|
|
||||||
'error': '#c83849',
|
|
||||||
'error-content': '#f9d9d9', */
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
/* themes: [
|
|
||||||
{
|
|
||||||
dark: {
|
|
||||||
'primary': colors.teal[500],
|
|
||||||
'primary-content': '#010811',
|
|
||||||
'secondary': colors.purple[500],
|
|
||||||
'secondary-content': '#130201',
|
|
||||||
'accent': '#9b59b6',
|
|
||||||
'accent-content': '#ebddf1',
|
|
||||||
'neutral': '#95a5a6',
|
|
||||||
'neutral-content': '#080a0a',
|
|
||||||
'base-100': colors.slate[100],
|
|
||||||
'base-200': colors.slate[400],
|
|
||||||
'base-300': colors.slate[900],
|
|
||||||
'base-content': colors.slate[800],
|
|
||||||
'info': '#1abc9c',
|
|
||||||
'info-content': '#000d09',
|
|
||||||
'success': '#2ecc71',
|
|
||||||
'success-content': '#010f04',
|
|
||||||
'warning': '#f1c40f',
|
|
||||||
'warning-content': '#140e00',
|
|
||||||
'error': '#e74c3c',
|
|
||||||
'error-content': '#130201',
|
|
||||||
},
|
|
||||||
|
|
||||||
light: {
|
|
||||||
'primary': colors.teal[500],
|
|
||||||
'primary-content': '#010811',
|
|
||||||
'secondary': colors.purple[500],
|
|
||||||
'secondary-content': '#130201',
|
|
||||||
'accent': '#9b59b6',
|
|
||||||
'accent-content': '#ebddf1',
|
|
||||||
'neutral': '#95a5a6',
|
|
||||||
'neutral-content': '#080a0a',
|
|
||||||
'base-100': '#ecf0f1',
|
|
||||||
'base-200': '#cdd1d2',
|
|
||||||
'base-300': '#afb2b3',
|
|
||||||
'base-content': '#131414',
|
|
||||||
'info': '#1abc9c',
|
|
||||||
'info-content': '#000d09',
|
|
||||||
'success': '#2ecc71',
|
|
||||||
'success-content': '#010f04',
|
|
||||||
'warning': '#f1c40f',
|
|
||||||
'warning-content': '#140e00',
|
|
||||||
'error': '#e74c3c',
|
|
||||||
'error-content': '#130201',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
], */
|
|
||||||
},
|
|
||||||
|
|
||||||
/* theme: {
|
|
||||||
extend: {
|
|
||||||
colors: {
|
|
||||||
'primary-active': colors.teal[600],
|
|
||||||
'primary-focus': colors.teal[400],
|
|
||||||
'primary-hover': colors.teal[400],
|
|
||||||
'primary': colors.teal[500],
|
|
||||||
|
|
||||||
'dark': {
|
|
||||||
'primary-active': colors.teal[700],
|
|
||||||
'primary-focus': colors.teal[600],
|
|
||||||
'primary-hover': colors.teal[600],
|
|
||||||
'primary': colors.teal[500],
|
|
||||||
},
|
|
||||||
'secondary': colors.sky[500],
|
|
||||||
},
|
|
||||||
|
|
||||||
fontFamily: {
|
|
||||||
sans: [
|
|
||||||
'Adelle',
|
|
||||||
'Roboto Slab',
|
|
||||||
'DejaVu Serif',
|
|
||||||
'Georgia',
|
|
||||||
'Graphik',
|
|
||||||
'sans-serif',
|
|
||||||
],
|
|
||||||
serif: ['Merriweather', 'serif'],
|
|
||||||
},
|
|
||||||
|
|
||||||
screens: {
|
|
||||||
xs: '360px',
|
|
||||||
},
|
|
||||||
|
|
||||||
transitionProperty: {
|
|
||||||
height: 'height',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, */
|
|
||||||
}); // satisfies Config;
|
|
||||||
Reference in New Issue
Block a user