switch to nuxt ui
3
.gitignore
vendored
@ -22,6 +22,5 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
.nuxt
|
.nuxt
|
||||||
.output
|
src-tauri/target
|
||||||
@ -1,6 +1,4 @@
|
|||||||
// @ts-check
|
|
||||||
import withNuxt from './.nuxt/eslint.config.mjs'
|
import withNuxt from './.nuxt/eslint.config.mjs'
|
||||||
|
|
||||||
export default withNuxt(
|
export default withNuxt()
|
||||||
// Your custom configs here
|
// Your custom configs here
|
||||||
)
|
|
||||||
|
|||||||
@ -1,25 +1,30 @@
|
|||||||
import tailwindcss from '@tailwindcss/vite'
|
import tailwindcss from '@tailwindcss/vite'
|
||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
|
||||||
|
|
||||||
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
|
compatibilityDate: '2025-07-15',
|
||||||
|
devtools: { enabled: true },
|
||||||
|
|
||||||
|
srcDir: './src',
|
||||||
|
|
||||||
app: {
|
app: {
|
||||||
pageTransition: {
|
pageTransition: {
|
||||||
name: 'fade',
|
name: 'fade',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
modules: [
|
modules: [
|
||||||
'nuxt-zod-i18n',
|
'nuxt-zod-i18n',
|
||||||
'@nuxtjs/i18n',
|
'@nuxtjs/i18n',
|
||||||
'@pinia/nuxt',
|
'@pinia/nuxt',
|
||||||
'@vueuse/nuxt',
|
'@vueuse/nuxt',
|
||||||
'@nuxt/icon',
|
'@nuxt/icon',
|
||||||
'nuxt-snackbar',
|
|
||||||
'@nuxt/eslint',
|
'@nuxt/eslint',
|
||||||
'@nuxt/image',
|
//"@nuxt/image",
|
||||||
|
'@nuxt/fonts',
|
||||||
|
'@nuxt/ui',
|
||||||
],
|
],
|
||||||
|
|
||||||
compatibilityDate: '2024-11-01',
|
|
||||||
|
|
||||||
imports: {
|
imports: {
|
||||||
dirs: [
|
dirs: [
|
||||||
'composables/**',
|
'composables/**',
|
||||||
@ -30,7 +35,7 @@ export default defineNuxtConfig({
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
css: ['./assets/css/tailwind.css'],
|
css: ['./assets/css/main.css'],
|
||||||
|
|
||||||
icon: {
|
icon: {
|
||||||
provider: 'server',
|
provider: 'server',
|
||||||
@ -55,7 +60,6 @@ export default defineNuxtConfig({
|
|||||||
i18n: {
|
i18n: {
|
||||||
strategy: 'prefix_and_default',
|
strategy: 'prefix_and_default',
|
||||||
defaultLocale: 'de',
|
defaultLocale: 'de',
|
||||||
vueI18n: '~/i18n/i18n.config.ts',
|
|
||||||
|
|
||||||
locales: [
|
locales: [
|
||||||
{ code: 'de', language: 'de-DE', isCatchallLocale: true },
|
{ code: 'de', language: 'de-DE', isCatchallLocale: true },
|
||||||
@ -68,9 +72,6 @@ export default defineNuxtConfig({
|
|||||||
redirectOn: 'root', // recommended
|
redirectOn: 'root', // recommended
|
||||||
},
|
},
|
||||||
types: 'composition',
|
types: 'composition',
|
||||||
bundle: {
|
|
||||||
optimizeTranslationDirective: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
zodI18n: {
|
zodI18n: {
|
||||||
@ -90,14 +91,10 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
devtools: { enabled: true },
|
|
||||||
|
|
||||||
srcDir: './src',
|
|
||||||
// Enable SSG
|
|
||||||
ssr: false,
|
ssr: false,
|
||||||
// Enables the development server to be discoverable by other devices when running on iOS physical devices
|
// Enables the development server to be discoverable by other devices when running on iOS physical devices
|
||||||
devServer: {
|
devServer: {
|
||||||
host: process.env.TAURI_DEV_HOST || 'localhost',
|
host: '0',
|
||||||
port: 3003,
|
port: 3003,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -114,4 +111,5 @@ export default defineNuxtConfig({
|
|||||||
strictPort: true,
|
strictPort: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ignore: ['**/src-tauri/**'],
|
||||||
})
|
})
|
||||||
|
|||||||
55
package.json
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "haex-hub",
|
"name": "tauri-app",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@ -16,57 +16,48 @@
|
|||||||
"eslint:fix": "eslint --fix"
|
"eslint:fix": "eslint --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@libsql/client": "^0.15.9",
|
"@nuxt/eslint": "1.9.0",
|
||||||
"@nuxt/eslint": "1.4.1",
|
"@nuxt/fonts": "0.11.4",
|
||||||
"@nuxt/icon": "^1.14.0",
|
"@nuxt/icon": "2.0.0",
|
||||||
"@nuxt/image": "1.10.0",
|
"@nuxt/ui": "^3.3.2",
|
||||||
"@nuxtjs/i18n": "^9.5.5",
|
"@nuxtjs/i18n": "10.0.6",
|
||||||
"@pinia/nuxt": "^0.11.1",
|
"@pinia/nuxt": "^0.11.1",
|
||||||
"@tailwindcss/vite": "^4.1.10",
|
"@tailwindcss/vite": "^4.1.10",
|
||||||
"@tauri-apps/api": "^2.5.0",
|
"@tauri-apps/api": "^2.5.0",
|
||||||
"@tauri-apps/plugin-dialog": "^2.2.2",
|
"@tauri-apps/plugin-dialog": "^2.2.2",
|
||||||
"@tauri-apps/plugin-fs": "^2.3.0",
|
"@tauri-apps/plugin-fs": "^2.3.0",
|
||||||
"@tauri-apps/plugin-http": "~2.4.4",
|
"@tauri-apps/plugin-http": "2.5.2",
|
||||||
"@tauri-apps/plugin-notification": "~2.2.3",
|
"@tauri-apps/plugin-notification": "2.3.1",
|
||||||
"@tauri-apps/plugin-opener": "^2.3.0",
|
"@tauri-apps/plugin-opener": "^2.3.0",
|
||||||
"@tauri-apps/plugin-os": "^2.2.2",
|
"@tauri-apps/plugin-os": "^2.2.2",
|
||||||
"@tauri-apps/plugin-sql": "~2.2.1",
|
"@tauri-apps/plugin-sql": "2.3.0",
|
||||||
"@tauri-apps/plugin-store": "^2.2.1",
|
"@tauri-apps/plugin-store": "^2.2.1",
|
||||||
"@vlcn.io/crsqlite": "^0.16.3",
|
"@vueuse/components": "^13.9.0",
|
||||||
"@vueuse/components": "^13.4.0",
|
|
||||||
"@vueuse/core": "^13.4.0",
|
"@vueuse/core": "^13.4.0",
|
||||||
"@vueuse/nuxt": "^13.4.0",
|
"@vueuse/nuxt": "^13.4.0",
|
||||||
"drizzle-orm": "^0.44.2",
|
"drizzle-orm": "^0.44.2",
|
||||||
"eslint": "^9.29.0",
|
"eslint": "^9.34.0",
|
||||||
"flyonui": "^2.2.0",
|
|
||||||
"fuse.js": "^7.1.0",
|
"fuse.js": "^7.1.0",
|
||||||
"nuxt": "^3.17.5",
|
"nuxt": "^4.0.3",
|
||||||
"nuxt-snackbar": "1.3.0",
|
|
||||||
"nuxt-zod-i18n": "^1.12.0",
|
"nuxt-zod-i18n": "^1.12.0",
|
||||||
"tailwindcss": "^4.1.10",
|
"tailwindcss": "^4.1.10",
|
||||||
"tailwindcss-intersect": "^2.2.0",
|
"vue": "^3.5.20",
|
||||||
"tailwindcss-motion": "^1.1.1",
|
"vue-router": "^4.5.1",
|
||||||
"vue": "^3.5.17",
|
"zod": "4.1.5"
|
||||||
"zod": "^3.25.67"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify-json/proicons": "^1.2.17",
|
|
||||||
"@iconify/json": "^2.2.351",
|
"@iconify/json": "^2.2.351",
|
||||||
"@iconify/tailwind4": "^1.0.6",
|
"@iconify/tailwind4": "^1.0.6",
|
||||||
"@tauri-apps/cli": "^2.5.0",
|
"@tauri-apps/cli": "^2.5.0",
|
||||||
|
"@vitejs/plugin-vue": "6.0.1",
|
||||||
"@vue/compiler-sfc": "^3.5.17",
|
"@vue/compiler-sfc": "^3.5.17",
|
||||||
"drizzle-kit": "^0.31.2",
|
"drizzle-kit": "^0.31.2",
|
||||||
"globals": "^16.2.0",
|
"globals": "^16.2.0",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.6.2",
|
||||||
"typescript": "^5.8.3"
|
"tw-animate-css": "^1.3.8",
|
||||||
},
|
"typescript": "^5.8.3",
|
||||||
"packageManager": "pnpm@10.12.2",
|
"vite": "7.1.3",
|
||||||
"pnpm": {
|
"vue-tsc": "3.0.6"
|
||||||
"ignoredBuiltDependencies": [
|
|
||||||
"@parcel/watcher",
|
|
||||||
"esbuild",
|
|
||||||
"vue-demi"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"trailingComma": "all",
|
"trailingComma": "all",
|
||||||
@ -74,5 +65,11 @@
|
|||||||
"semi": false,
|
"semi": false,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"singleAttributePerLine": true
|
"singleAttributePerLine": true
|
||||||
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"overrides": {
|
||||||
|
"zod": "^3.22.4"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.15.1+sha512.34e538c329b5553014ca8e8f4535997f96180a1d0f614339357449935350d924e22f8614682191264ec33d1462ac21561aff97f6bb18065351c162c7e8f6de67"
|
||||||
}
|
}
|
||||||
|
|||||||
7492
pnpm-lock.yaml
generated
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
7
src-tauri/.gitignore
vendored
@ -1,7 +0,0 @@
|
|||||||
# Generated by Cargo
|
|
||||||
# will have compiled files and executables
|
|
||||||
/target/
|
|
||||||
|
|
||||||
# Generated by Tauri
|
|
||||||
# will have schema files for capabilities auto-completion
|
|
||||||
/gen/schemas
|
|
||||||
363
src-tauri/Cargo.lock
generated
@ -117,17 +117,6 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-fs"
|
|
||||||
version = "2.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a"
|
|
||||||
dependencies = [
|
|
||||||
"async-lock",
|
|
||||||
"blocking",
|
|
||||||
"futures-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-io"
|
name = "async-io"
|
||||||
version = "2.4.0"
|
version = "2.4.0"
|
||||||
@ -451,7 +440,7 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -461,7 +450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257"
|
checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"toml",
|
"toml 0.8.20",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -801,7 +790,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"option-ext",
|
"option-ext",
|
||||||
"redox_users",
|
"redox_users",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -835,9 +824,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dlopen2"
|
name = "dlopen2"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6"
|
checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dlopen2_derive",
|
"dlopen2_derive",
|
||||||
"libc",
|
"libc",
|
||||||
@ -910,7 +899,7 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
"memchr",
|
"memchr",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"toml",
|
"toml 0.8.20",
|
||||||
"vswhom",
|
"vswhom",
|
||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
@ -1563,7 +1552,7 @@ dependencies = [
|
|||||||
"tauri-plugin-os",
|
"tauri-plugin-os",
|
||||||
"tauri-plugin-persisted-scope",
|
"tauri-plugin-persisted-scope",
|
||||||
"tauri-plugin-store",
|
"tauri-plugin-store",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"tokio",
|
"tokio",
|
||||||
"ts-rs",
|
"ts-rs",
|
||||||
"uhlc",
|
"uhlc",
|
||||||
@ -1733,7 +1722,7 @@ dependencies = [
|
|||||||
"http-body",
|
"http-body",
|
||||||
"hyper",
|
"hyper",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -2122,9 +2111,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.171"
|
version = "0.2.175"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
@ -2316,7 +2305,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"png",
|
"png",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2358,9 +2347,9 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.29.0"
|
version = "0.30.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@ -2611,6 +2600,17 @@ dependencies = [
|
|||||||
"objc2-foundation 0.3.0",
|
"objc2-foundation 0.3.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-security"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3126341c65c5d5728423ae95d788e1b660756486ad0592307ab87ba02d9a7268"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.0",
|
||||||
|
"objc2 0.6.0",
|
||||||
|
"objc2-core-foundation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-ui-kit"
|
name = "objc2-ui-kit"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -2635,6 +2635,7 @@ dependencies = [
|
|||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation 0.3.0",
|
"objc2-foundation 0.3.0",
|
||||||
|
"objc2-security",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3127,8 +3128,8 @@ dependencies = [
|
|||||||
"quinn-udp",
|
"quinn-udp",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustls",
|
"rustls",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"web-time",
|
"web-time",
|
||||||
@ -3148,7 +3149,7 @@ dependencies = [
|
|||||||
"rustls",
|
"rustls",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"slab",
|
"slab",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
"tracing",
|
"tracing",
|
||||||
"web-time",
|
"web-time",
|
||||||
@ -3163,7 +3164,7 @@ dependencies = [
|
|||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
@ -3337,7 +3338,7 @@ checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.15",
|
||||||
"libredox",
|
"libredox",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3687,9 +3688,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.140"
|
version = "1.0.143"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -3717,6 +3718,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@ -3761,9 +3771,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serialize-to-javascript"
|
name = "serialize-to-javascript"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb"
|
checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -3772,13 +3782,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serialize-to-javascript-impl"
|
name = "serialize-to-javascript-impl"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763"
|
checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 2.0.100",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3860,6 +3870,16 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "softbuffer"
|
name = "softbuffer"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@ -3916,9 +3936,9 @@ checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlparser"
|
name = "sqlparser"
|
||||||
version = "0.57.0"
|
version = "0.58.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07c5f081b292a3d19637f0b32a79e28ff14a9fd23ef47bd7fce08ff5de221eca"
|
checksum = "ec4b661c54b1e4b603b37873a18c59920e4c51ea8ea2cf527d925424dbd4437c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"recursive",
|
"recursive",
|
||||||
@ -4090,17 +4110,18 @@ dependencies = [
|
|||||||
"cfg-expr",
|
"cfg-expr",
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"toml",
|
"toml 0.8.20",
|
||||||
"version-compare",
|
"version-compare",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tao"
|
name = "tao"
|
||||||
version = "0.34.0"
|
version = "0.34.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49c380ca75a231b87b6c9dd86948f035012e7171d1a7c40a9c2890489a7ffd8a"
|
checksum = "959469667dbcea91e5485fc48ba7dd6023face91bb0f1a14681a70f99847c3f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
|
"block2 0.6.0",
|
||||||
"core-foundation 0.10.0",
|
"core-foundation 0.10.0",
|
||||||
"core-graphics",
|
"core-graphics",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
@ -4152,12 +4173,13 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri"
|
name = "tauri"
|
||||||
version = "2.6.2"
|
version = "2.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "124e129c9c0faa6bec792c5948c89e86c90094133b0b9044df0ce5f0a8efaa0d"
|
checksum = "d4d1d3b3dc4c101ac989fd7db77e045cc6d91a25349cd410455cb5c57d510c1c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"cookie",
|
||||||
"dirs",
|
"dirs",
|
||||||
"dunce",
|
"dunce",
|
||||||
"embed_plist",
|
"embed_plist",
|
||||||
@ -4176,6 +4198,7 @@ dependencies = [
|
|||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation 0.3.0",
|
"objc2-foundation 0.3.0",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
|
"objc2-web-kit",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"plist",
|
"plist",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
@ -4190,7 +4213,7 @@ dependencies = [
|
|||||||
"tauri-runtime",
|
"tauri-runtime",
|
||||||
"tauri-runtime-wry",
|
"tauri-runtime-wry",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tray-icon",
|
"tray-icon",
|
||||||
"url",
|
"url",
|
||||||
@ -4203,9 +4226,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-build"
|
name = "tauri-build"
|
||||||
version = "2.3.0"
|
version = "2.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "12f025c389d3adb83114bec704da973142e82fc6ec799c7c750c5e21cefaec83"
|
checksum = "9c432ccc9ff661803dab74c6cd78de11026a578a9307610bbc39d3c55be7943f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cargo_toml",
|
"cargo_toml",
|
||||||
@ -4219,15 +4242,15 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"tauri-winres",
|
"tauri-winres",
|
||||||
"toml",
|
"toml 0.9.5",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-codegen"
|
name = "tauri-codegen"
|
||||||
version = "2.3.0"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f5df493a1075a241065bc865ed5ef8d0fbc1e76c7afdc0bf0eccfaa7d4f0e406"
|
checksum = "1ab3a62cf2e6253936a8b267c2e95839674e7439f104fa96ad0025e149d54d8a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"brotli",
|
"brotli",
|
||||||
@ -4243,7 +4266,7 @@ dependencies = [
|
|||||||
"sha2",
|
"sha2",
|
||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"time",
|
"time",
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
@ -4252,9 +4275,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-macros"
|
name = "tauri-macros"
|
||||||
version = "2.3.1"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f237fbea5866fa5f2a60a21bea807a2d6e0379db070d89c3a10ac0f2d4649bbc"
|
checksum = "4368ea8094e7045217edb690f493b55b30caf9f3e61f79b4c24b6db91f07995e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -4266,9 +4289,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin"
|
name = "tauri-plugin"
|
||||||
version = "2.3.0"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d9a0bd00bf1930ad1a604d08b0eb6b2a9c1822686d65d7f4731a7723b8901d3"
|
checksum = "9946a3cede302eac0c6eb6c6070ac47b1768e326092d32efbb91f21ed58d978f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"glob",
|
"glob",
|
||||||
@ -4277,15 +4300,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"toml",
|
"toml 0.9.5",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-android-fs"
|
name = "tauri-plugin-android-fs"
|
||||||
version = "9.5.0"
|
version = "12.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70913be3272e29ada966e8158ffb4f1b3985041635bf4563baade6178309231a"
|
checksum = "1387b55109ae9b8ad0521ac11f8ce827740f53c0e0ce74648d1cb2efe0fd9c09"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"serde",
|
"serde",
|
||||||
@ -4293,14 +4316,14 @@ dependencies = [
|
|||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"tauri-plugin-fs",
|
"tauri-plugin-fs",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-dialog"
|
name = "tauri-plugin-dialog"
|
||||||
version = "2.3.0"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1aefb14219b492afb30b12647b5b1247cadd2c0603467310c36e0f7ae1698c28"
|
checksum = "0beee42a4002bc695550599b011728d9dfabf82f767f134754ed6655e434824e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
@ -4310,15 +4333,15 @@ dependencies = [
|
|||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"tauri-plugin-fs",
|
"tauri-plugin-fs",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-fs"
|
name = "tauri-plugin-fs"
|
||||||
version = "2.4.0"
|
version = "2.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c341290d31991dbca38b31d412c73dfbdb070bb11536784f19dd2211d13b778f"
|
checksum = "315784ec4be45e90a987687bae7235e6be3d6e9e350d2b75c16b8a4bf22c1db7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"dunce",
|
"dunce",
|
||||||
@ -4331,16 +4354,16 @@ dependencies = [
|
|||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"toml",
|
"toml 0.9.5",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-http"
|
name = "tauri-plugin-http"
|
||||||
version = "2.5.0"
|
version = "2.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0c1a38da944b357ffa23bafd563b1579f18e6fbd118fcd84769406d35dcc5c7"
|
checksum = "938a3d7051c9a82b431e3a0f3468f85715b3442b3c3a3913095e9fa509e2652c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"cookie_store",
|
"cookie_store",
|
||||||
@ -4354,7 +4377,7 @@ dependencies = [
|
|||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"tauri-plugin-fs",
|
"tauri-plugin-fs",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
"urlpattern",
|
"urlpattern",
|
||||||
@ -4362,28 +4385,28 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-notification"
|
name = "tauri-plugin-notification"
|
||||||
version = "2.3.0"
|
version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cfe06ed89cff6d0ec06ff4f544fb961e4718348a33309f56ccb2086e77bc9116"
|
checksum = "d2fbc86b929b5376ab84b25c060f966d146b2fbd59b6af8264027b343c82c219"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"notify-rust",
|
"notify-rust",
|
||||||
"rand 0.8.5",
|
"rand 0.9.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"time",
|
"time",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-opener"
|
name = "tauri-plugin-opener"
|
||||||
version = "2.4.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ecee219f11cdac713ab32959db5d0cceec4810ba4f4458da992292ecf9660321"
|
checksum = "786156aa8e89e03d271fbd3fe642207da8e65f3c961baa9e2930f332bf80a1f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"dunce",
|
||||||
"glob",
|
"glob",
|
||||||
@ -4395,7 +4418,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"url",
|
"url",
|
||||||
"windows",
|
"windows",
|
||||||
"zbus",
|
"zbus",
|
||||||
@ -4403,9 +4426,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-os"
|
name = "tauri-plugin-os"
|
||||||
version = "2.3.0"
|
version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "05bccb4c6de4299beec5a9b070878a01bce9e2c945aa7a75bcea38bcba4c675d"
|
checksum = "77a1c77ebf6f20417ab2a74e8c310820ba52151406d0c80fbcea7df232e3f6ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gethostname",
|
"gethostname",
|
||||||
"log",
|
"log",
|
||||||
@ -4416,14 +4439,14 @@ dependencies = [
|
|||||||
"sys-locale",
|
"sys-locale",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-persisted-scope"
|
name = "tauri-plugin-persisted-scope"
|
||||||
version = "2.3.0"
|
version = "2.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7380eff2525adcf7f6b1cf3de191ccd3fdbe2a42281e4659604a26749c77bfbd"
|
checksum = "41f1fed7dc3c24a4bdb183ce7c18490466985e5b3aaef05825bd62588c507ae2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"bincode",
|
"bincode",
|
||||||
@ -4432,30 +4455,30 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin-fs",
|
"tauri-plugin-fs",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-store"
|
name = "tauri-plugin-store"
|
||||||
version = "2.3.0"
|
version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5916c609664a56c82aeaefffca9851fd072d4d41f73d63f22ee3ee451508194f"
|
checksum = "d85dd80d60a76ee2c2fdce09e9ef30877b239c2a6bb76e6d7d03708aa5f13a19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"dunce",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime"
|
name = "tauri-runtime"
|
||||||
version = "2.7.0"
|
version = "2.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e7bb73d1bceac06c20b3f755b2c8a2cb13b20b50083084a8cf3700daf397ba4"
|
checksum = "d4cfc9ad45b487d3fded5a4731a567872a4812e9552e3964161b08edabf93846"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cookie",
|
"cookie",
|
||||||
"dpi",
|
"dpi",
|
||||||
@ -4464,20 +4487,23 @@ dependencies = [
|
|||||||
"jni",
|
"jni",
|
||||||
"objc2 0.6.0",
|
"objc2 0.6.0",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
|
"objc2-web-kit",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"url",
|
"url",
|
||||||
|
"webkit2gtk",
|
||||||
|
"webview2-com",
|
||||||
"windows",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime-wry"
|
name = "tauri-runtime-wry"
|
||||||
version = "2.7.1"
|
version = "2.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "902b5aa9035e16f342eb64f8bf06ccdc2808e411a2525ed1d07672fa4e780bad"
|
checksum = "c1fe9d48bd122ff002064e88cfcd7027090d789c4302714e68fcccba0f4b7807"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
@ -4502,9 +4528,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-utils"
|
name = "tauri-utils"
|
||||||
version = "2.5.0"
|
version = "2.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41743bbbeb96c3a100d234e5a0b60a46d5aa068f266160862c7afdbf828ca02e"
|
checksum = "41a3852fdf9a4f8fbeaa63dc3e9a85284dd6ef7200751f0bd66ceee30c93f212"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"brotli",
|
"brotli",
|
||||||
@ -4530,8 +4556,8 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"swift-rs",
|
"swift-rs",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"toml",
|
"toml 0.9.5",
|
||||||
"url",
|
"url",
|
||||||
"urlpattern",
|
"urlpattern",
|
||||||
"uuid",
|
"uuid",
|
||||||
@ -4545,7 +4571,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "56eaa45f707bedf34d19312c26d350bc0f3c59a47e58e8adbeecdc850d2c13a0"
|
checksum = "56eaa45f707bedf34d19312c26d350bc0f3c59a47e58e8adbeecdc850d2c13a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"embed-resource",
|
"embed-resource",
|
||||||
"toml",
|
"toml 0.8.20",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4555,7 +4581,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9"
|
checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quick-xml 0.37.5",
|
"quick-xml 0.37.5",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"windows",
|
"windows",
|
||||||
"windows-version",
|
"windows-version",
|
||||||
]
|
]
|
||||||
@ -4604,11 +4630,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.12"
|
version = "2.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl 2.0.12",
|
"thiserror-impl 2.0.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4624,9 +4650,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "2.0.12"
|
version = "2.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -4691,9 +4717,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.46.1"
|
version = "1.47.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
|
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -4703,10 +4729,10 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"slab",
|
"slab",
|
||||||
"socket2",
|
"socket2 0.6.0",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4750,11 +4776,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
|
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned 0.6.8",
|
||||||
"toml_datetime",
|
"toml_datetime 0.6.8",
|
||||||
"toml_edit 0.22.24",
|
"toml_edit 0.22.24",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap 2.8.0",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned 1.0.0",
|
||||||
|
"toml_datetime 0.7.0",
|
||||||
|
"toml_parser",
|
||||||
|
"toml_writer",
|
||||||
|
"winnow 0.7.13",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.8"
|
version = "0.6.8"
|
||||||
@ -4764,6 +4805,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.19.15"
|
version = "0.19.15"
|
||||||
@ -4771,7 +4821,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.8.0",
|
||||||
"toml_datetime",
|
"toml_datetime 0.6.8",
|
||||||
"winnow 0.5.40",
|
"winnow 0.5.40",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4782,7 +4832,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
|
checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.8.0",
|
||||||
"toml_datetime",
|
"toml_datetime 0.6.8",
|
||||||
"winnow 0.5.40",
|
"winnow 0.5.40",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4794,11 +4844,26 @@ checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.8.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned 0.6.8",
|
||||||
"toml_datetime",
|
"toml_datetime 0.6.8",
|
||||||
"winnow 0.7.4",
|
"winnow 0.7.13",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_parser"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10"
|
||||||
|
dependencies = [
|
||||||
|
"winnow 0.7.13",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_writer"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@ -4875,7 +4940,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"png",
|
"png",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4891,7 +4956,7 @@ version = "11.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ef1b7a6d914a34127ed8e1fa927eb7088903787bcded4fa3eef8f85ee1568be"
|
checksum = "6ef1b7a6d914a34127ed8e1fa927eb7088903787bcded4fa3eef8f85ee1568be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"ts-rs-macros",
|
"ts-rs-macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -5053,9 +5118,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.17.0"
|
version = "1.18.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.3.2",
|
"getrandom 0.3.2",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@ -5329,7 +5394,7 @@ version = "0.38.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c"
|
checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"windows",
|
"windows",
|
||||||
"windows-core 0.61.0",
|
"windows-core 0.61.0",
|
||||||
]
|
]
|
||||||
@ -5480,7 +5545,7 @@ checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-result",
|
"windows-result",
|
||||||
"windows-strings 0.3.1",
|
"windows-strings 0.3.1",
|
||||||
"windows-targets 0.53.0",
|
"windows-targets 0.53.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5546,6 +5611,15 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.60.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.53.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@ -5594,9 +5668,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.53.0"
|
version = "0.53.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
|
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm 0.53.0",
|
"windows_aarch64_gnullvm 0.53.0",
|
||||||
"windows_aarch64_msvc 0.53.0",
|
"windows_aarch64_msvc 0.53.0",
|
||||||
@ -5808,9 +5882,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.4"
|
version = "0.7.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@ -5848,14 +5922,15 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wry"
|
name = "wry"
|
||||||
version = "0.52.1"
|
version = "0.53.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "12a714d9ba7075aae04a6e50229d6109e3d584774b99a6a8c60de1698ca111b9"
|
checksum = "31f0e9642a0d061f6236c54ccae64c2722a7879ad4ec7dff59bd376d446d8e90"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"block2 0.6.0",
|
"block2 0.6.0",
|
||||||
"cookie",
|
"cookie",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
"dirs",
|
||||||
"dpi",
|
"dpi",
|
||||||
"dunce",
|
"dunce",
|
||||||
"gdkx11",
|
"gdkx11",
|
||||||
@ -5879,7 +5954,7 @@ dependencies = [
|
|||||||
"sha2",
|
"sha2",
|
||||||
"soup3",
|
"soup3",
|
||||||
"tao-macros",
|
"tao-macros",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.16",
|
||||||
"url",
|
"url",
|
||||||
"webkit2gtk",
|
"webkit2gtk",
|
||||||
"webkit2gtk-sys",
|
"webkit2gtk-sys",
|
||||||
@ -5911,16 +5986,6 @@ dependencies = [
|
|||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xdg-home"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.7.5"
|
version = "0.7.5"
|
||||||
@ -5947,13 +6012,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zbus"
|
name = "zbus"
|
||||||
version = "5.5.0"
|
version = "5.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "59c333f648ea1b647bc95dc1d34807c8e25ed7a6feff3394034dc4776054b236"
|
checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-broadcast",
|
"async-broadcast",
|
||||||
"async-executor",
|
"async-executor",
|
||||||
"async-fs",
|
|
||||||
"async-io",
|
"async-io",
|
||||||
"async-lock",
|
"async-lock",
|
||||||
"async-process",
|
"async-process",
|
||||||
@ -5970,13 +6034,11 @@ dependencies = [
|
|||||||
"ordered-stream",
|
"ordered-stream",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"static_assertions",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"uds_windows",
|
"uds_windows",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.60.2",
|
||||||
"winnow 0.7.4",
|
"winnow 0.7.13",
|
||||||
"xdg-home",
|
|
||||||
"zbus_macros",
|
"zbus_macros",
|
||||||
"zbus_names",
|
"zbus_names",
|
||||||
"zvariant",
|
"zvariant",
|
||||||
@ -5984,9 +6046,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zbus_macros"
|
name = "zbus_macros"
|
||||||
version = "5.5.0"
|
version = "5.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f325ad10eb0d0a3eb060203494c3b7ec3162a01a59db75d2deee100339709fc0"
|
checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 3.3.0",
|
"proc-macro-crate 3.3.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -6005,7 +6067,7 @@ checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"winnow 0.7.4",
|
"winnow 0.7.13",
|
||||||
"zvariant",
|
"zvariant",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -6080,25 +6142,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zvariant"
|
name = "zvariant"
|
||||||
version = "5.4.0"
|
version = "5.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2df9ee044893fcffbdc25de30546edef3e32341466811ca18421e3cd6c5a3ac"
|
checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"endi",
|
"endi",
|
||||||
"enumflags2",
|
"enumflags2",
|
||||||
"serde",
|
"serde",
|
||||||
"static_assertions",
|
|
||||||
"url",
|
"url",
|
||||||
"winnow 0.7.4",
|
"winnow 0.7.13",
|
||||||
"zvariant_derive",
|
"zvariant_derive",
|
||||||
"zvariant_utils",
|
"zvariant_utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zvariant_derive"
|
name = "zvariant_derive"
|
||||||
version = "5.4.0"
|
version = "5.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74170caa85b8b84cc4935f2d56a57c7a15ea6185ccdd7eadb57e6edd90f94b2f"
|
checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 3.3.0",
|
"proc-macro-crate 3.3.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@ -6118,5 +6179,5 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
"winnow 0.7.4",
|
"winnow 0.7.13",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -25,28 +25,28 @@ rusqlite = { version = "0.37.0", features = [
|
|||||||
] }
|
] }
|
||||||
#libsqlite3-sys = { version = "0.31", features = ["bundled-sqlcipher"] }
|
#libsqlite3-sys = { version = "0.31", features = ["bundled-sqlcipher"] }
|
||||||
#sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite"] }
|
#sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite"] }
|
||||||
tokio = { version = "1.46", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
serde_json = "1"
|
serde_json = "1.0.143"
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
mime_guess = "2.0"
|
mime_guess = "2.0"
|
||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
fs_extra = "1.3.0"
|
fs_extra = "1.3.0"
|
||||||
sqlparser = { version = "0.57.0", features = ["visitor"] }
|
sqlparser = { version = "0.58.0", features = ["visitor"] }
|
||||||
uhlc = "0.8"
|
uhlc = "0.8"
|
||||||
tauri = { version = "2.6.2", features = ["protocol-asset", "devtools"] }
|
tauri = { version = "2.8.5", features = ["protocol-asset", "devtools"] }
|
||||||
tauri-plugin-dialog = "2.3"
|
tauri-plugin-dialog = "2.4.0"
|
||||||
tauri-plugin-fs = "2.4.0"
|
tauri-plugin-fs = "2.4.0"
|
||||||
tauri-plugin-opener = "2.4.0"
|
tauri-plugin-opener = "2.5.0"
|
||||||
tauri-plugin-os = "2.3"
|
tauri-plugin-os = "2.3"
|
||||||
tauri-plugin-store = "2.3"
|
tauri-plugin-store = "2.4.0"
|
||||||
tauri-plugin-http = "2.5"
|
tauri-plugin-http = "2.5.2"
|
||||||
tauri-plugin-notification = "2.3"
|
tauri-plugin-notification = "2.3.1"
|
||||||
tauri-plugin-persisted-scope = "2.0.0"
|
tauri-plugin-persisted-scope = "2.3.2"
|
||||||
tauri-plugin-android-fs = "9.5.0"
|
tauri-plugin-android-fs = "12.0.1"
|
||||||
uuid = { version = "1.17.0", features = ["v4"] }
|
uuid = { version = "1.18.1", features = ["v4"] }
|
||||||
ts-rs = "11.0.1"
|
ts-rs = "11.0.1"
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.16"
|
||||||
|
|
||||||
#tauri-plugin-sql = { version = "2", features = ["sqlite"] }
|
#tauri-plugin-sql = { version = "2", features = ["sqlite"] }
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>AvailableLibraries</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>LibraryIdentifier</key>
|
|
||||||
<string>ios-arm64</string>
|
|
||||||
<key>LibraryPath</key>
|
|
||||||
<string>crsqlite.framework</string>
|
|
||||||
<key>SupportedArchitectures</key>
|
|
||||||
<array>
|
|
||||||
<string>arm64</string>
|
|
||||||
</array>
|
|
||||||
<key>SupportedPlatform</key>
|
|
||||||
<string>ios</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>LibraryIdentifier</key>
|
|
||||||
<string>ios-arm64_x86_64-simulator</string>
|
|
||||||
<key>LibraryPath</key>
|
|
||||||
<string>crsqlite.framework</string>
|
|
||||||
<key>SupportedArchitectures</key>
|
|
||||||
<array>
|
|
||||||
<string>arm64</string>
|
|
||||||
<string>x86_64</string>
|
|
||||||
</array>
|
|
||||||
<key>SupportedPlatform</key>
|
|
||||||
<string>ios</string>
|
|
||||||
<key>SupportedPlatformVariant</key>
|
|
||||||
<string>simulator</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>XFWK</string>
|
|
||||||
<key>XCFrameworkFormatVersion</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>en</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>crsqlite</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>io.vlcn.crsqlite</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>FMWK</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>en</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>crsqlite</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>io.vlcn.crsqlite</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>FMWK</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@ -1,23 +1,23 @@
|
|||||||
import { drizzle } from "drizzle-orm/sqlite-proxy"; // Adapter für Query Building ohne direkte Verbindung
|
import { drizzle } from 'drizzle-orm/sqlite-proxy' // Adapter für Query Building ohne direkte Verbindung
|
||||||
import * as schema from "./schemas/vault"; // Importiere alles aus deiner Schema-Datei
|
import * as schema from './schemas/vault' // Importiere alles aus deiner Schema-Datei
|
||||||
|
|
||||||
// sqlite-proxy benötigt eine (dummy) Ausführungsfunktion als Argument.
|
// sqlite-proxy benötigt eine (dummy) Ausführungsfunktion als Argument.
|
||||||
// Diese wird in unserem Tauri-Workflow nie aufgerufen, da wir nur .toSQL() verwenden.
|
// Diese wird in unserem Tauri-Workflow nie aufgerufen, da wir nur .toSQL() verwenden.
|
||||||
// Sie muss aber vorhanden sein, um drizzle() aufrufen zu können.
|
// Sie muss aber vorhanden sein, um drizzle() aufrufen zu können.
|
||||||
const dummyExecutor = async (
|
const dummyExecutor = async (
|
||||||
sql: string,
|
sql: string,
|
||||||
params: any[],
|
params: unknown[],
|
||||||
method: "all" | "run" | "get" | "values"
|
method: 'all' | 'run' | 'get' | 'values',
|
||||||
) => {
|
) => {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Frontend Drizzle Executor wurde aufgerufen (Methode: ${method}). Das sollte im Tauri-Invoke-Workflow nicht passieren!`
|
`Frontend Drizzle Executor wurde aufgerufen (Methode: ${method}). Das sollte im Tauri-Invoke-Workflow nicht passieren!`,
|
||||||
);
|
)
|
||||||
// Wir geben leere Ergebnisse zurück, um die Typen zufriedenzustellen, falls es doch aufgerufen wird.
|
// Wir geben leere Ergebnisse zurück, um die Typen zufriedenzustellen, falls es doch aufgerufen wird.
|
||||||
return { rows: [] }; // Für 'run' (z.B. bei INSERT/UPDATE)
|
return { rows: [] } // Für 'run' (z.B. bei INSERT/UPDATE)
|
||||||
};
|
}
|
||||||
|
|
||||||
// Erstelle die Drizzle-Instanz für den SQLite-Dialekt
|
// Erstelle die Drizzle-Instanz für den SQLite-Dialekt
|
||||||
// Übergib den dummyExecutor und das importierte Schema
|
// Übergib den dummyExecutor und das importierte Schema
|
||||||
export const db = drizzle(dummyExecutor, { schema });
|
export const db = drizzle(dummyExecutor, { schema })
|
||||||
|
|
||||||
// Exportiere auch alle Schema-Definitionen weiter, damit man alles aus einer Datei importieren kann
|
// Exportiere auch alle Schema-Definitionen weiter, damit man alles aus einer Datei importieren kann
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { blob, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'
|
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'
|
||||||
|
|
||||||
export const haexCrdtLogs = sqliteTable('haex_crdt_logs', {
|
export const haexCrdtLogs = sqliteTable('haex_crdt_logs', {
|
||||||
hlc_timestamp: text().primaryKey(),
|
hlc_timestamp: text().primaryKey(),
|
||||||
|
|||||||
@ -14,13 +14,13 @@ val tauriProperties = Properties().apply {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk = 34
|
compileSdk = 36
|
||||||
namespace = "space.haex.hub"
|
namespace = "space.haex.hub"
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
||||||
applicationId = "space.haex.hub"
|
applicationId = "space.haex.hub"
|
||||||
minSdk = 30
|
minSdk = 24
|
||||||
targetSdk = 34
|
targetSdk = 36
|
||||||
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
||||||
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
||||||
}
|
}
|
||||||
@ -58,9 +58,10 @@ rust {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("androidx.webkit:webkit:1.6.1")
|
implementation("androidx.webkit:webkit:1.14.0")
|
||||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
implementation("androidx.appcompat:appcompat:1.7.1")
|
||||||
implementation("com.google.android.material:material:1.8.0")
|
implementation("androidx.activity:activity-ktx:1.10.1")
|
||||||
|
implementation("com.google.android.material:material:1.12.0")
|
||||||
testImplementation("junit:junit:4.13.2")
|
testImplementation("junit:junit:4.13.2")
|
||||||
androidTestImplementation("androidx.test.ext:junit:1.1.4")
|
androidTestImplementation("androidx.test.ext:junit:1.1.4")
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
|
||||||
<!-- AndroidTV support -->
|
<!-- AndroidTV support -->
|
||||||
<uses-feature android:name="android.software.leanback" android:required="false" />
|
<uses-feature android:name="android.software.leanback" android:required="false" />
|
||||||
|
|
||||||
@ -11,8 +9,7 @@
|
|||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.haex_hub"
|
android:theme="@style/Theme.haex_hub"
|
||||||
android:usesCleartextTraffic="${usesCleartextTraffic}"
|
android:usesCleartextTraffic="${usesCleartextTraffic}">
|
||||||
android:requestLegacyExternalStorage="true">
|
|
||||||
<activity
|
<activity
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
|
|||||||
@ -1,20 +1,11 @@
|
|||||||
package space.haex.hub
|
package space.haex.hub
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.content.Context
|
import androidx.activity.enableEdgeToEdge
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
|
||||||
import android.provider.Settings
|
|
||||||
|
|
||||||
class MainActivity : TauriActivity(){
|
class MainActivity : TauriActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
/* override fun onCreate(savedInstanceState: Bundle?) {
|
enableEdgeToEdge()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
startActivity(
|
}
|
||||||
Intent(
|
|
||||||
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
|
|
||||||
Uri.parse("package:${BuildConfig.APPLICATION_ID}")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
@ -1,17 +0,0 @@
|
|||||||
package space.haex.hub
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
|
||||||
import android.provider.Settings
|
|
||||||
|
|
||||||
class SettingsOpener {
|
|
||||||
companion object {
|
|
||||||
@JvmStatic
|
|
||||||
fun openManageAllFilesAccessSettings(context: Context) {
|
|
||||||
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
|
|
||||||
intent.data = Uri.parse("package:" + context.packageName)
|
|
||||||
context.startActivity(intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -4,7 +4,7 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("com.android.tools.build:gradle:8.5.1")
|
classpath("com.android.tools.build:gradle:8.11.0")
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,6 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly(gradleApi())
|
compileOnly(gradleApi())
|
||||||
implementation("com.android.tools.build:gradle:8.5.1")
|
implementation("com.android.tools.build:gradle:8.11.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#Tue May 10 19:22:52 CST 2022
|
#Tue May 10 19:22:52 CST 2022
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
1
src-tauri/gen/schemas/acl-manifests.json
Normal file
1
src-tauri/gen/schemas/capabilities.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main"],"permissions":["core:default","core:webview:allow-create-webview-window","core:webview:allow-create-webview","core:webview:allow-webview-show","core:webview:default","core:window:allow-create","core:window:allow-get-all-windows","core:window:allow-show","core:window:default","dialog:default","fs:allow-appconfig-read-recursive","fs:allow-appconfig-write-recursive","fs:allow-appdata-read-recursive","fs:allow-appdata-write-recursive","fs:allow-read-file","fs:allow-read-dir","fs:allow-resource-read-recursive","fs:allow-resource-write-recursive","fs:allow-download-read-recursive","fs:allow-download-write-recursive","fs:default","android-fs:default",{"identifier":"fs:scope","allow":[{"path":"**"}]},"http:allow-fetch-send","http:allow-fetch","http:default","notification:allow-create-channel","notification:allow-list-channels","notification:allow-notify","notification:default","opener:allow-open-url","opener:default","os:allow-hostname","os:default","store:default"]}}
|
||||||
6707
src-tauri/gen/schemas/desktop-schema.json
Normal file
6707
src-tauri/gen/schemas/linux-schema.json
Normal file
32
src-tauri/src/binss/setup-triggers.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use crdt::trigger::TriggerManager;
|
||||||
|
use rusqlite::{Connection, Result};
|
||||||
|
// anpassen an dein Crate-Modul
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
// Vault-Datenbank öffnen
|
||||||
|
let conn = Connection::open("vault.db")?;
|
||||||
|
|
||||||
|
println!("🔄 Setup CRDT triggers...");
|
||||||
|
|
||||||
|
// Tabellen aus der DB holen
|
||||||
|
let mut stmt =
|
||||||
|
conn.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'haex_%' AND NOT LIKE 'haex_crdt_%';")?;
|
||||||
|
let table_iter = stmt.query_map([], |row| row.get::<_, String>(0))?;
|
||||||
|
|
||||||
|
for table_name in table_iter {
|
||||||
|
let table_name = table_name?;
|
||||||
|
println!("➡️ Processing table: {}", table_name);
|
||||||
|
|
||||||
|
// Trigger für die Tabelle neu anlegen
|
||||||
|
match TriggerManager::setup_triggers_for_table(&conn, &table_name) {
|
||||||
|
Ok(_) => println!(" ✅ Triggers created for {}", table_name),
|
||||||
|
Err(e) => println!(
|
||||||
|
" ⚠️ Could not create triggers for {}: {:?}",
|
||||||
|
table_name, e
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("✨ Done setting up CRDT triggers.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@ -195,7 +195,7 @@ impl SqlProxy {
|
|||||||
} */
|
} */
|
||||||
Statement::Update {
|
Statement::Update {
|
||||||
table,
|
table,
|
||||||
assignments: assignments,
|
assignments,
|
||||||
from,
|
from,
|
||||||
selection,
|
selection,
|
||||||
returning,
|
returning,
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
use crate::crdt::hlc;
|
|
||||||
use rusqlite::{Connection, Result, Row};
|
use rusqlite::{Connection, Result, Row};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
@ -76,6 +75,7 @@ impl TriggerManager {
|
|||||||
|
|
||||||
let insert_trigger_sql = self.generate_insert_trigger_sql(table_name, &pks, &cols_to_track);
|
let insert_trigger_sql = self.generate_insert_trigger_sql(table_name, &pks, &cols_to_track);
|
||||||
let update_trigger_sql = self.generate_update_trigger_sql(table_name, &pks, &cols_to_track);
|
let update_trigger_sql = self.generate_update_trigger_sql(table_name, &pks, &cols_to_track);
|
||||||
|
let drop_insert_trigger_sql = self.drop_trigger_sql(table_name, "insert");
|
||||||
|
|
||||||
let tx = conn.transaction()?;
|
let tx = conn.transaction()?;
|
||||||
tx.execute_batch(&format!("{}\n{}", insert_trigger_sql, update_trigger_sql))?;
|
tx.execute_batch(&format!("{}\n{}", insert_trigger_sql, update_trigger_sql))?;
|
||||||
@ -127,6 +127,10 @@ impl TriggerManager {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn drop_trigger_sql(&self, table: &str, action: &str) -> String {
|
||||||
|
format!("DROP TRIGGER IF EXISTS z_crdt_{table}_{action};")
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_update_trigger_sql(
|
fn generate_update_trigger_sql(
|
||||||
&self,
|
&self,
|
||||||
table_name: &str,
|
table_name: &str,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//mod browser;
|
//mod browser;
|
||||||
mod android_storage;
|
mod android_storage;
|
||||||
mod crdt;
|
pub mod crdt;
|
||||||
mod database;
|
mod database;
|
||||||
mod extension;
|
mod extension;
|
||||||
mod models;
|
mod models;
|
||||||
|
|||||||
8
src/app.config.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export default defineAppConfig({
|
||||||
|
ui: {
|
||||||
|
colors: {
|
||||||
|
primary: 'sky',
|
||||||
|
secondary: 'purple',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
14
src/app.vue
@ -1,20 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<UApp :locale="locales[locale]">
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
<NuxtSnackbar />
|
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</div>
|
</UApp>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { currentThemeValue } = storeToRefs(useUiStore())
|
import * as locales from '@nuxt/ui/locale'
|
||||||
|
const { locale } = useI18n()
|
||||||
useHead({
|
|
||||||
htmlAttrs: {
|
|
||||||
'data-theme': currentThemeValue,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
20
src/assets/css/main.css
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
@import 'tailwindcss';
|
||||||
|
@import '@nuxt/ui';
|
||||||
|
@import 'tw-animate-css';
|
||||||
|
|
||||||
|
/* Custom Colors */
|
||||||
|
@layer base {
|
||||||
|
button,
|
||||||
|
[role='button'] {
|
||||||
|
@apply cursor-pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
:disabled,
|
||||||
|
[disabled] {
|
||||||
|
@apply cursor-not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--ui-header-height: 48px; /* oder was auch immer deine Header-Höhe ist */
|
||||||
|
}
|
||||||
@ -1,11 +0,0 @@
|
|||||||
@import 'tailwindcss';
|
|
||||||
@import 'flyonui/variants.css';
|
|
||||||
@import 'tailwindcss-intersect';
|
|
||||||
|
|
||||||
@plugin "tailwindcss-motion";
|
|
||||||
@plugin "@iconify/tailwind4";
|
|
||||||
@plugin "flyonui" {
|
|
||||||
themes: all;
|
|
||||||
}
|
|
||||||
|
|
||||||
@source "../../../node_modules/flyonui/flyonui.js";
|
|
||||||
|
Before Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 1.4 MiB |
@ -1,156 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="browser">
|
|
||||||
<div class="browser-controls">
|
|
||||||
<button :disabled="!activeTabId" @click="$emit('goBack', activeTabId)">
|
|
||||||
←
|
|
||||||
</button>
|
|
||||||
<button :disabled="!activeTabId" @click="$emit('goForward', activeTabId)">
|
|
||||||
→
|
|
||||||
</button>
|
|
||||||
<button @click="$emit('createTab')">+</button>
|
|
||||||
|
|
||||||
<HaexBrowserUrlBar
|
|
||||||
:url="activeTab?.url || ''"
|
|
||||||
:is-loading="activeTab?.isLoading || false"
|
|
||||||
@submit="handleUrlSubmit"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<HaexBrowserTabBar
|
|
||||||
:tabs="tabs"
|
|
||||||
:active-tab-id="activeTabId"
|
|
||||||
@close-tab="$emit('closeTab', $event)"
|
|
||||||
@activate-tab="$emit('activateTab', $event)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div ref="contentRef" class="browser-content">
|
|
||||||
<!-- Die eigentlichen Webview-Inhalte werden von Tauri verwaltet -->
|
|
||||||
<div v-if="!activeTabId" class="empty-state">
|
|
||||||
<p>
|
|
||||||
Kein Tab geöffnet. Erstellen Sie einen neuen Tab mit dem + Button.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
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',
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
height: 1000,
|
|
||||||
width: 1000,
|
|
||||||
});
|
|
||||||
|
|
||||||
webview.once('tauri://created', function () {
|
|
||||||
console.log('create new webview');
|
|
||||||
}); */
|
|
||||||
|
|
||||||
interface Tab {
|
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
url: string
|
|
||||||
isLoading: boolean
|
|
||||||
isActive: boolean
|
|
||||||
window_label: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
tabs: Tab[]
|
|
||||||
activeTabId: string | null
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const { initializeAsync, processNavigation, injectContentScripts } =
|
|
||||||
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()
|
|
||||||
// Aktualisiere die Webview-Größe
|
|
||||||
await updateWebviewBoundsAsync()
|
|
||||||
//window.addEventListener('resize', updateWebviewBounds);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Wenn ein neuer Tab aktiviert wird, injiziere Content-Scripts
|
|
||||||
/* watch(
|
|
||||||
() => props.activeTabId,
|
|
||||||
async (newTabId) => {
|
|
||||||
if (newTabId && props.tabs.length > 0) {
|
|
||||||
const activeTab = props.tabs.find((tab) => tab.id === newTabId);
|
|
||||||
if (activeTab) {
|
|
||||||
// Warte kurz, bis die Seite geladen ist
|
|
||||||
setTimeout(() => {
|
|
||||||
injectContentScripts(activeTab.window_label);
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
// Aktualisiere die Webview-Größe
|
|
||||||
updateWebviewBounds();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
); */
|
|
||||||
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
console.log('Navigation blockiert durch Erweiterung')
|
|
||||||
// Hier könnten Sie eine Benachrichtigung anzeigen
|
|
||||||
} */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateWebviewBoundsAsync = async () => {
|
|
||||||
if (!contentRef.value) return
|
|
||||||
|
|
||||||
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>
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="tab-bar">
|
|
||||||
<div
|
|
||||||
v-for="tab in tabs"
|
|
||||||
:key="tab.id"
|
|
||||||
class="tab"
|
|
||||||
:class="{ active: tab.id === activeTabId }"
|
|
||||||
@click="$emit('activateTab', tab.id)"
|
|
||||||
>
|
|
||||||
<span class="tab-title">
|
|
||||||
{{ tab.title || 'Neuer Tab' }}
|
|
||||||
</span>
|
|
||||||
<button class="tab-close" @click.stop="$emit('closeTab', tab.id)">
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
interface Tab {
|
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
url: string
|
|
||||||
isLoading: boolean
|
|
||||||
isActive: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
tabs: Tab[]
|
|
||||||
activeTabId: string | null
|
|
||||||
}
|
|
||||||
|
|
||||||
defineProps<Props>()
|
|
||||||
|
|
||||||
defineEmits<{
|
|
||||||
(e: 'closeTab', tabId: string): void
|
|
||||||
(e: 'activateTab', tabId: string): void
|
|
||||||
}>()
|
|
||||||
</script>
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
<template>
|
|
||||||
<form class="url-bar" @submit.prevent="handleSubmit">
|
|
||||||
<input v-model="inputValue" type="text" placeholder="URL eingeben" >
|
|
||||||
<span v-if="isLoading" class="loading-indicator">Laden...</span>
|
|
||||||
<button v-else type="submit">Go</button>
|
|
||||||
</form>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
const props = defineProps({
|
|
||||||
url: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
isLoading: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['submit'])
|
|
||||||
|
|
||||||
const inputValue = ref(props.url)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.url,
|
|
||||||
(newUrl) => {
|
|
||||||
inputValue.value = newUrl
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const handleSubmit = () => {
|
|
||||||
// URL validieren und ggf. Protokoll hinzufügen
|
|
||||||
let processedUrl = inputValue.value.trim()
|
|
||||||
if (processedUrl && !processedUrl.match(/^[a-zA-Z]+:\/\//)) {
|
|
||||||
processedUrl = 'https://' + processedUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
emit('submit', processedUrl)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button class="btn join-item" :type>
|
|
||||||
<slot />
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
defineProps({
|
|
||||||
type: {
|
|
||||||
type: String as PropType<"reset" | "submit" | "button">,
|
|
||||||
default: "button",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button
|
|
||||||
:class="cn(
|
|
||||||
`relative flex items-center justify-center min-w-28 min-h-10 overflow-hidden outline-2 outline-offset-2 rounded cursor-pointer`, className
|
|
||||||
)
|
|
||||||
">
|
|
||||||
<span class="btn-content inline-flex size-full items-center justify-center px-4 py-2 gap-2">
|
|
||||||
<slot />
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
const { className = "primary" } = defineProps<{ className?: string }>()
|
|
||||||
</script>
|
|
||||||
@ -1,7 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="card border-4 shadow-md shadow-accent h-48 w-48 overflow-hidden hover:shadow-xl transition-shadow "
|
class="card border-4 shadow-md shadow-accent h-48 w-48 overflow-hidden hover:shadow-xl transition-shadow"
|
||||||
v-bind="$attrs">
|
v-bind="$attrs"
|
||||||
|
>
|
||||||
<div class="absolute top-2 right-2">
|
<div class="absolute top-2 right-2">
|
||||||
<UiDropdown class="btn btn-sm btn-text btn-circle">
|
<UiDropdown class="btn btn-sm btn-text btn-circle">
|
||||||
<template #activator>
|
<template #activator>
|
||||||
@ -9,27 +10,44 @@ class="card border-4 shadow-md shadow-accent h-48 w-48 overflow-hidden hover:s
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #items>
|
<template #items>
|
||||||
<UiButton class="btn-error btn-outline btn-sm " @click="showRemoveDialog = true">
|
<UiButton
|
||||||
<Icon name="mdi:trash" /> {{ t("remove") }}
|
class="btn-error btn-outline btn-sm"
|
||||||
|
@click="showRemoveDialog = true"
|
||||||
|
>
|
||||||
|
<Icon name="mdi:trash" /> {{ t('remove') }}
|
||||||
</UiButton>
|
</UiButton>
|
||||||
</template>
|
</template>
|
||||||
</UiDropdown>
|
</UiDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h5 v-if="name" class="card-title">
|
<h5
|
||||||
|
v-if="name"
|
||||||
|
class="card-title"
|
||||||
|
>
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</h5>
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="card-body relative cursor-pointer"
|
class="card-body relative cursor-pointer"
|
||||||
@click="navigateTo(useLocalePath()({ name: 'haexExtension', params: { extensionId: id } }))">
|
@click="
|
||||||
|
navigateTo(
|
||||||
|
useLocalePath()({
|
||||||
|
name: 'haexExtension',
|
||||||
|
params: { extensionId: id },
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
<!-- <slot />
|
<!-- <slot />
|
||||||
<div class="card-actions" v-if="$slots.action">
|
<div class="card-actions" v-if="$slots.action">
|
||||||
<slot name="action" />
|
<slot name="action" />
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="size-20 absolute bottom-2 right-2" v-html="icon" />
|
<div
|
||||||
|
class="size-20 absolute bottom-2 right-2"
|
||||||
|
v-html="icon"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="card-footer">
|
<!-- <div class="card-footer">
|
||||||
@ -37,63 +55,69 @@ class="card-body relative cursor-pointer"
|
|||||||
</div> -->
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<HaexExtensionDialogRemove v-model:open="showRemoveDialog" :extension @confirm="removeExtensionAsync" />
|
<HaexExtensionDialogRemove
|
||||||
|
v-model:open="showRemoveDialog"
|
||||||
|
:extension
|
||||||
|
@confirm="removeExtensionAsync"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { IHaexHubExtension } from "~/types/haexhub";
|
import type { IHaexHubExtension } from '~/types/haexhub'
|
||||||
const emit = defineEmits(["close", "submit", "remove"]);
|
const emit = defineEmits(['close', 'submit', 'remove'])
|
||||||
|
|
||||||
const extension = defineProps<IHaexHubExtension>();
|
const extension = defineProps<IHaexHubExtension>()
|
||||||
|
|
||||||
const { escape, enter } = useMagicKeys();
|
const { escape, enter } = useMagicKeys()
|
||||||
|
|
||||||
watchEffect(async () => {
|
watchEffect(async () => {
|
||||||
if (escape.value) {
|
if (escape?.value) {
|
||||||
await nextTick();
|
await nextTick()
|
||||||
emit("close");
|
emit('close')
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
watchEffect(async () => {
|
watchEffect(async () => {
|
||||||
if (enter.value) {
|
if (enter?.value) {
|
||||||
await nextTick();
|
await nextTick()
|
||||||
emit("submit");
|
emit('submit')
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
const showRemoveDialog = ref(false)
|
const showRemoveDialog = ref(false)
|
||||||
const { add } = useSnackbar()
|
const { add } = useToast()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const extensionStore = useExtensionsStore()
|
const extensionStore = useExtensionsStore()
|
||||||
|
|
||||||
const removeExtensionAsync = async () => {
|
const removeExtensionAsync = async () => {
|
||||||
if (!extension?.id || !extension?.version) {
|
if (!extension?.id || !extension?.version) {
|
||||||
add({ type: 'error', text: 'Erweiterung kann nicht gelöscht werden' })
|
add({
|
||||||
|
color: 'error',
|
||||||
|
description: 'Erweiterung kann nicht gelöscht werden',
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await extensionStore.removeExtensionAsync(
|
await extensionStore.removeExtensionAsync(extension.id, extension.version)
|
||||||
extension.id,
|
|
||||||
extension.version
|
|
||||||
)
|
|
||||||
await extensionStore.loadExtensionsAsync()
|
await extensionStore.loadExtensionsAsync()
|
||||||
|
|
||||||
add({
|
add({
|
||||||
type: 'success',
|
color: 'success',
|
||||||
title: t('extension.remove.success.title', {
|
title: t('extension.remove.success.title', {
|
||||||
extensionName: extension.name,
|
extensionName: extension.name,
|
||||||
}),
|
}),
|
||||||
text: t('extension.remove.success.text', {
|
description: t('extension.remove.success.text', {
|
||||||
extensionName: extension.name,
|
extensionName: extension.name,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
add({
|
add({
|
||||||
type: 'error',
|
color: 'error',
|
||||||
title: t('extension.remove.error.title'),
|
title: t('extension.remove.error.title'),
|
||||||
text: t('extension.remove.error.text', { error: JSON.stringify(error) }),
|
description: t('extension.remove.error.text', {
|
||||||
|
error: JSON.stringify(error),
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,7 +135,6 @@ de:
|
|||||||
text: "Erweiterung {extensionName} konnte nicht entfernt werden. \n {error}"
|
text: "Erweiterung {extensionName} konnte nicht entfernt werden. \n {error}"
|
||||||
title: 'Fehler beim Entfernen von {extensionName}'
|
title: 'Fehler beim Entfernen von {extensionName}'
|
||||||
|
|
||||||
|
|
||||||
en:
|
en:
|
||||||
remove: Remove
|
remove: Remove
|
||||||
extension:
|
extension:
|
||||||
@ -122,6 +145,4 @@ en:
|
|||||||
error:
|
error:
|
||||||
text: "Extension {extensionName} couldn't be removed. \n {error}"
|
text: "Extension {extensionName} couldn't be removed. \n {error}"
|
||||||
title: 'Exception during uninstall {extensionName}'
|
title: 'Exception during uninstall {extensionName}'
|
||||||
|
|
||||||
|
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|||||||
@ -1,7 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiDialogConfirm v-model:open="open" @abort="onDeny" @confirm="onConfirm">
|
<UiDialogConfirm
|
||||||
|
v-model:open="open"
|
||||||
|
@abort="onDeny"
|
||||||
|
@confirm="onConfirm"
|
||||||
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<i18n-t keypath="question" tag="p">
|
<i18n-t
|
||||||
|
keypath="question"
|
||||||
|
tag="p"
|
||||||
|
>
|
||||||
<template #extension>
|
<template #extension>
|
||||||
<span class="font-bold text-primary">{{ manifest?.name }}</span>
|
<span class="font-bold text-primary">{{ manifest?.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
@ -9,94 +16,138 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<nav class="tabs tabs-bordered" aria-label="Tabs" role="tablist" aria-orientation="horizontal">
|
<nav
|
||||||
|
class="tabs tabs-bordered"
|
||||||
|
aria-label="Tabs"
|
||||||
|
role="tablist"
|
||||||
|
aria-orientation="horizontal"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
v-show="manifest?.permissions?.database" id="tabs-basic-item-1" type="button"
|
v-show="manifest?.permissions?.database"
|
||||||
class="tab active-tab:tab-active active" data-tab="#tabs-basic-1" aria-controls="tabs-basic-1" role="tab" aria-selected="true">
|
id="tabs-basic-item-1"
|
||||||
{{ t("database") }}
|
type="button"
|
||||||
|
class="tab active-tab:tab-active active"
|
||||||
|
data-tab="#tabs-basic-1"
|
||||||
|
aria-controls="tabs-basic-1"
|
||||||
|
role="tab"
|
||||||
|
aria-selected="true"
|
||||||
|
>
|
||||||
|
{{ t('database') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-show="manifest?.permissions?.filesystem" id="tabs-basic-item-2" type="button"
|
v-show="manifest?.permissions?.filesystem"
|
||||||
class="tab active-tab:tab-active" data-tab="#tabs-basic-2" aria-controls="tabs-basic-2" role="tab" aria-selected="false">
|
id="tabs-basic-item-2"
|
||||||
{{ t("filesystem") }}
|
type="button"
|
||||||
|
class="tab active-tab:tab-active"
|
||||||
|
data-tab="#tabs-basic-2"
|
||||||
|
aria-controls="tabs-basic-2"
|
||||||
|
role="tab"
|
||||||
|
aria-selected="false"
|
||||||
|
>
|
||||||
|
{{ t('filesystem') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-show="manifest?.permissions?.http" id="tabs-basic-item-3" type="button"
|
v-show="manifest?.permissions?.http"
|
||||||
class="tab active-tab:tab-active" data-tab="#tabs-basic-3" aria-controls="tabs-basic-3" role="tab" aria-selected="false">
|
id="tabs-basic-item-3"
|
||||||
{{ t("http") }}
|
type="button"
|
||||||
|
class="tab active-tab:tab-active"
|
||||||
|
data-tab="#tabs-basic-3"
|
||||||
|
aria-controls="tabs-basic-3"
|
||||||
|
role="tab"
|
||||||
|
aria-selected="false"
|
||||||
|
>
|
||||||
|
{{ t('http') }}
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="mt-3 min-h-40">
|
<div class="mt-3 min-h-40">
|
||||||
<div id="tabs-basic-1" role="tabpanel" aria-labelledby="tabs-basic-item-1">
|
<div
|
||||||
<HaexExtensionManifestPermissionsDatabase :database="permissions?.database" />
|
id="tabs-basic-1"
|
||||||
|
role="tabpanel"
|
||||||
|
aria-labelledby="tabs-basic-item-1"
|
||||||
|
>
|
||||||
|
<HaexExtensionManifestPermissionsDatabase
|
||||||
|
:database="permissions?.database"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div id="tabs-basic-2" class="hidden" role="tabpanel" aria-labelledby="tabs-basic-item-2">
|
<div
|
||||||
<HaexExtensionManifestPermissionsFilesystem :filesystem="permissions?.filesystem" />
|
id="tabs-basic-2"
|
||||||
|
class="hidden"
|
||||||
|
role="tabpanel"
|
||||||
|
aria-labelledby="tabs-basic-item-2"
|
||||||
|
>
|
||||||
|
<HaexExtensionManifestPermissionsFilesystem
|
||||||
|
:filesystem="permissions?.filesystem"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div id="tabs-basic-3" class="hidden" role="tabpanel" aria-labelledby="tabs-basic-item-3">
|
<div
|
||||||
|
id="tabs-basic-3"
|
||||||
|
class="hidden"
|
||||||
|
role="tabpanel"
|
||||||
|
aria-labelledby="tabs-basic-item-3"
|
||||||
|
>
|
||||||
<HaexExtensionManifestPermissionsHttp :http="permissions?.http" />
|
<HaexExtensionManifestPermissionsHttp :http="permissions?.http" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</UiDialogConfirm>
|
</UiDialogConfirm>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { IHaexHubExtensionManifest } from "~/types/haexhub";
|
import type { IHaexHubExtensionManifest } from '~/types/haexhub'
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n()
|
||||||
|
|
||||||
const open = defineModel<boolean>("open", { default: false });
|
const open = defineModel<boolean>('open', { default: false })
|
||||||
const { manifest } = defineProps<{ manifest?: IHaexHubExtensionManifest | null }>();
|
const { manifest } = defineProps<{
|
||||||
|
manifest?: IHaexHubExtensionManifest | null
|
||||||
|
}>()
|
||||||
|
|
||||||
const permissions = computed(() => ({
|
const permissions = computed(() => ({
|
||||||
|
|
||||||
database: {
|
database: {
|
||||||
read: manifest?.permissions.database?.read?.map(read => ({
|
read: manifest?.permissions.database?.read?.map((read) => ({
|
||||||
[read]: true
|
[read]: true,
|
||||||
})),
|
})),
|
||||||
write: manifest?.permissions.database?.read?.map(write => ({
|
write: manifest?.permissions.database?.read?.map((write) => ({
|
||||||
[write]: true
|
[write]: true,
|
||||||
})),
|
})),
|
||||||
create: manifest?.permissions.database?.read?.map(create => ({
|
create: manifest?.permissions.database?.read?.map((create) => ({
|
||||||
[create]: true
|
[create]: true,
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
|
|
||||||
filesystem: {
|
filesystem: {
|
||||||
read: manifest?.permissions.filesystem?.read?.map(read => ({
|
read: manifest?.permissions.filesystem?.read?.map((read) => ({
|
||||||
[read]: true
|
[read]: true,
|
||||||
})),
|
})),
|
||||||
write: manifest?.permissions.filesystem?.write?.map(write => ({
|
write: manifest?.permissions.filesystem?.write?.map((write) => ({
|
||||||
[write]: true
|
[write]: true,
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
|
|
||||||
http: manifest?.permissions.http?.map(http => ({
|
http: manifest?.permissions.http?.map((http) => ({
|
||||||
[http]: true
|
[http]: true,
|
||||||
})),
|
})),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
watch(permissions, () => console.log("permissions", permissions.value))
|
watch(permissions, () => console.log('permissions', permissions.value))
|
||||||
const emit = defineEmits(["deny", "confirm"]);
|
const emit = defineEmits(['deny', 'confirm'])
|
||||||
|
|
||||||
const onDeny = () => {
|
const onDeny = () => {
|
||||||
open.value = false;
|
open.value = false
|
||||||
console.log("onDeny open", open.value);
|
console.log('onDeny open', open.value)
|
||||||
emit("deny");
|
emit('deny')
|
||||||
};
|
}
|
||||||
|
|
||||||
const onConfirm = () => {
|
const onConfirm = () => {
|
||||||
open.value = false;
|
open.value = false
|
||||||
console.log("onConfirm open", open.value);
|
console.log('onConfirm open', open.value)
|
||||||
emit("confirm");
|
emit('confirm')
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="json">{
|
<i18n lang="json">
|
||||||
|
{
|
||||||
"de": {
|
"de": {
|
||||||
"title": "Erweiterung hinzufügen",
|
"title": "Erweiterung hinzufügen",
|
||||||
"question": "Erweiterung {extension} hinzufügen?",
|
"question": "Erweiterung {extension} hinzufügen?",
|
||||||
@ -115,4 +166,5 @@ const onConfirm = () => {
|
|||||||
"http": "Internet",
|
"http": "Internet",
|
||||||
"filesystem": "Filesystem"
|
"filesystem": "Filesystem"
|
||||||
}
|
}
|
||||||
}</i18n>
|
}
|
||||||
|
</i18n>
|
||||||
|
|||||||
56
src/components/haex/menu/applications.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<UPopover v-model:open="open">
|
||||||
|
<UButton
|
||||||
|
icon="material-symbols:apps"
|
||||||
|
color="neutral"
|
||||||
|
variant="outline"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<template #content>
|
||||||
|
<ul
|
||||||
|
class="p-4 max-h-96 grid grid-cols-3 gap-2 overflow-scroll"
|
||||||
|
@click="open = false"
|
||||||
|
>
|
||||||
|
<UiButton
|
||||||
|
v-for="item in menu"
|
||||||
|
:key="item.id"
|
||||||
|
square
|
||||||
|
size="xl"
|
||||||
|
variant="ghost"
|
||||||
|
:ui="{
|
||||||
|
base: 'size-24 flex flex-wrap text-sm items-center justify-center overflow-visible',
|
||||||
|
leadingIcon: 'size-10',
|
||||||
|
label: 'w-full',
|
||||||
|
}"
|
||||||
|
:icon="item.icon"
|
||||||
|
:label="item.name"
|
||||||
|
:tooltip="item.name"
|
||||||
|
@click="item.onSelect"
|
||||||
|
/>
|
||||||
|
<!-- <UiButton
|
||||||
|
v-for="item in extensionLinks"
|
||||||
|
:key="item.id"
|
||||||
|
v-bind="item"
|
||||||
|
icon-type="svg"
|
||||||
|
/> -->
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
</UPopover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
//const { extensionLinks } = storeToRefs(useExtensionsStore())
|
||||||
|
const { menu } = storeToRefs(useSidebarStore())
|
||||||
|
|
||||||
|
const open = ref(false)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<i18n lang="yaml">
|
||||||
|
de:
|
||||||
|
settings: 'Einstellungen'
|
||||||
|
close: 'Vault schließen'
|
||||||
|
|
||||||
|
en:
|
||||||
|
settings: 'Settings'
|
||||||
|
close: 'Close Vault'
|
||||||
|
</i18n>
|
||||||
@ -1,63 +0,0 @@
|
|||||||
<template>
|
|
||||||
<UiDropdown offset="[--offset:20]">
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<!-- <ul class="dropdown-menu dropdown-open:opacity-100 hidden min-w-60" role="menu" aria-orientation="vertical"
|
|
||||||
aria-labelledby="dropdown-avatar"> -->
|
|
||||||
|
|
||||||
<template #items>
|
|
||||||
<li>
|
|
||||||
<NuxtLinkLocale
|
|
||||||
class="dropdown-item"
|
|
||||||
:to="{ name: 'settings' }"
|
|
||||||
>
|
|
||||||
<span class="icon-[tabler--settings]" />
|
|
||||||
{{ 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]" />
|
|
||||||
{{ t('vault.close') }}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</template>
|
|
||||||
<!--
|
|
||||||
</ul> -->
|
|
||||||
</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>
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
class="dropdown relative inline-flex [--auto-close:inside] [--offset:18] [--placement:bottom]"
|
|
||||||
>
|
|
||||||
<UiTooltip :tooltip="t('notifications.label')">
|
|
||||||
<button
|
|
||||||
id="dropdown-scrollable"
|
|
||||||
type="button"
|
|
||||||
class="dropdown-toggle btn btn-text btn-circle dropdown-open:bg-base-content/10"
|
|
||||||
aria-haspopup="menu"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="Dropdown"
|
|
||||||
>
|
|
||||||
<div class="indicator">
|
|
||||||
<span
|
|
||||||
v-show="notifications.length"
|
|
||||||
class="indicator-item bg-error size-2 rounded-full text-sm"
|
|
||||||
/>
|
|
||||||
<span class="icon-[tabler--bell] text-base-content size-[1.375rem]" />
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</UiTooltip>
|
|
||||||
<div
|
|
||||||
class="dropdown-menu dropdown-open:opacity-100 hidden w-full max-w-96 shadow"
|
|
||||||
role="menu"
|
|
||||||
aria-orientation="vertical"
|
|
||||||
aria-labelledby="dropdown-scrollable"
|
|
||||||
>
|
|
||||||
<div class="dropdown-header justify-center">
|
|
||||||
<h6 class="text-base-content text-base">
|
|
||||||
{{ t('notifications.label') }}
|
|
||||||
</h6>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="vertical-scrollbar horizontal-scrollbar rounded-scrollbar text-base-content/80 max-h-56 overflow-auto"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="notification in notifications"
|
|
||||||
:key="notification.id"
|
|
||||||
class="dropdown-item"
|
|
||||||
>
|
|
||||||
<div class="avatar">
|
|
||||||
<div class="w-10 rounded-full">
|
|
||||||
<img
|
|
||||||
v-if="notification.image"
|
|
||||||
:src="notification.image"
|
|
||||||
:alt="notification.alt ?? 'notification avatar'"
|
|
||||||
/>
|
|
||||||
<Icon
|
|
||||||
v-else-if="notification.icon"
|
|
||||||
:name="notification.icon"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="w-60">
|
|
||||||
<h6 class="truncate text-base">
|
|
||||||
{{ notification.title }}
|
|
||||||
</h6>
|
|
||||||
<small class="text-base-content/50 truncate">
|
|
||||||
{{ notification.text }}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<NuxtLinkLocale
|
|
||||||
:to="{ name: 'notifications' }"
|
|
||||||
class="dropdown-footer justify-center gap-1 hover:bg-base-content/10"
|
|
||||||
>
|
|
||||||
<span class="icon-[tabler--eye] size-4" />
|
|
||||||
{{ t('notifications.view_all') }}
|
|
||||||
</NuxtLinkLocale>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
const { t } = useI18n()
|
|
||||||
const { notifications } = storeToRefs(useNotificationStore())
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<i18n lang="yaml">
|
|
||||||
de:
|
|
||||||
notifications:
|
|
||||||
label: Benachrichtigungen
|
|
||||||
view_all: Alle ansehen
|
|
||||||
en:
|
|
||||||
notifications:
|
|
||||||
label: Notifications
|
|
||||||
view_all: View all
|
|
||||||
</i18n>
|
|
||||||
@ -6,9 +6,11 @@
|
|||||||
@abort="$emit('abort')"
|
@abort="$emit('abort')"
|
||||||
@confirm="$emit('confirm')"
|
@confirm="$emit('confirm')"
|
||||||
>
|
>
|
||||||
|
<template #body>
|
||||||
{{
|
{{
|
||||||
final ? t('final.question', { itemName }) : t('question', { itemName })
|
final ? t('final.question', { itemName }) : t('question', { itemName })
|
||||||
}}
|
}}
|
||||||
|
</template>
|
||||||
</UiDialogConfirm>
|
</UiDialogConfirm>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiDialogConfirm
|
<UiDialogConfirm
|
||||||
|
v-model:open="showUnsavedChangesDialog"
|
||||||
:confirm-label="t('label')"
|
:confirm-label="t('label')"
|
||||||
:title="t('title')"
|
:title="t('title')"
|
||||||
@abort="$emit('abort')"
|
@abort="$emit('abort')"
|
||||||
@confirm="onConfirm"
|
@confirm="onConfirm"
|
||||||
v-model:open="showUnsavedChangesDialog"
|
|
||||||
>
|
>
|
||||||
|
<template #body>
|
||||||
|
<div class="flex items-center h-full">
|
||||||
{{ t('question') }}
|
{{ t('question') }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</UiDialogConfirm>
|
</UiDialogConfirm>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -43,5 +47,5 @@ de:
|
|||||||
en:
|
en:
|
||||||
title: Unsaved changes
|
title: Unsaved changes
|
||||||
question: Should the changes be discarded?
|
question: Should the changes be discarded?
|
||||||
label: discard
|
label: Discard
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="breadcrumbs">
|
<ul class="flex items-center gap-2 p-2">
|
||||||
<ul>
|
|
||||||
<li>
|
<li>
|
||||||
<NuxtLinkLocale :to="{ name: 'passwordGroupItems' }">
|
<NuxtLinkLocale :to="{ name: 'passwordGroupItems' }">
|
||||||
<Icon
|
<Icon
|
||||||
@ -9,24 +8,25 @@
|
|||||||
/>
|
/>
|
||||||
</NuxtLinkLocale>
|
</NuxtLinkLocale>
|
||||||
</li>
|
</li>
|
||||||
<template v-for="item in items">
|
|
||||||
<li class="breadcrumbs-separator rtl:rotate-180">
|
|
||||||
<Icon name="tabler:chevron-right" />
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
<li
|
||||||
|
v-for="item in items"
|
||||||
|
:key="item.id"
|
||||||
|
class="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name="tabler:chevron-right"
|
||||||
|
class="rtl:rotate-180"
|
||||||
|
/>
|
||||||
<NuxtLinkLocale
|
<NuxtLinkLocale
|
||||||
:to="{ name: 'passwordGroupItems', params: { groupId: item.id } }"
|
:to="{ name: 'passwordGroupItems', params: { groupId: item.id } }"
|
||||||
>
|
>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</NuxtLinkLocale>
|
</NuxtLinkLocale>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
|
||||||
<li class="ml-2">
|
<li class="ml-2">
|
||||||
<UiTooltip
|
<UTooltip :text="t('edit')">
|
||||||
:tooltip="t('edit')"
|
|
||||||
class="[--placement:bottom]"
|
|
||||||
>
|
|
||||||
<NuxtLinkLocale
|
<NuxtLinkLocale
|
||||||
:to="{
|
:to="{
|
||||||
name: 'passwordGroupEdit',
|
name: 'passwordGroupEdit',
|
||||||
@ -35,14 +35,12 @@
|
|||||||
>
|
>
|
||||||
<Icon name="mdi:pencil" />
|
<Icon name="mdi:pencil" />
|
||||||
</NuxtLinkLocale>
|
</NuxtLinkLocale>
|
||||||
</UiTooltip>
|
</UTooltip>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { UiTooltip } from '#components'
|
|
||||||
import type { SelectHaexPasswordsGroups } from '~~/src-tauri/database/schemas/vault'
|
import type { SelectHaexPasswordsGroups } from '~~/src-tauri/database/schemas/vault'
|
||||||
|
|
||||||
const groups = defineProps<{ items: SelectHaexPasswordsGroups[] }>()
|
const groups = defineProps<{ items: SelectHaexPasswordsGroups[] }>()
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
import type { SelectHaexPasswordsGroups } from '~~/src-tauri/database/schemas/vault'
|
|
||||||
|
|
||||||
export const usePasswordGroup = () => {
|
export const usePasswordGroup = () => {
|
||||||
const areItemsEqual = (
|
const areItemsEqual = (
|
||||||
groupA: unknown | unknown[] | null,
|
groupA: unknown | unknown[] | null,
|
||||||
groupB: unknown | unknown[] | null,
|
groupB: unknown | unknown[] | null,
|
||||||
) => {
|
) => {
|
||||||
if (groupA === null && groupB === null) return true
|
console.log('compare values', groupA, groupB)
|
||||||
|
if (groupA === groupB) return true
|
||||||
|
|
||||||
if (Array.isArray(groupA) && Array.isArray(groupB)) {
|
if (Array.isArray(groupA) && Array.isArray(groupB)) {
|
||||||
console.log('compare object arrays', groupA, groupB)
|
console.log('compare object arrays', groupA, groupB)
|
||||||
@ -18,7 +17,55 @@ export const usePasswordGroup = () => {
|
|||||||
return areObjectsEqual(groupA, groupB)
|
return areObjectsEqual(groupA, groupB)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deepEqual = (obj1: unknown, obj2: unknown) => {
|
||||||
|
console.log('compare values', obj1, obj2)
|
||||||
|
if (obj1 === obj2) return true
|
||||||
|
|
||||||
|
// Null/undefined Check
|
||||||
|
if (obj1 == null || obj2 == null) return obj1 === obj2
|
||||||
|
|
||||||
|
// Typ-Check
|
||||||
|
if (typeof obj1 !== typeof obj2) return false
|
||||||
|
|
||||||
|
// Primitive Typen
|
||||||
|
if (typeof obj1 !== 'object') return obj1 === obj2
|
||||||
|
|
||||||
|
// Arrays
|
||||||
|
if (Array.isArray(obj1) !== Array.isArray(obj2)) return false
|
||||||
|
|
||||||
|
if (Array.isArray(obj1)) {
|
||||||
|
if (obj1.length !== obj2.length) return false
|
||||||
|
for (let i = 0; i < obj1.length; i++) {
|
||||||
|
if (!deepEqual(obj1[i], obj2[i])) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date Objekte
|
||||||
|
if (obj1 instanceof Date && obj2 instanceof Date) {
|
||||||
|
return obj1.getTime() === obj2.getTime()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegExp Objekte
|
||||||
|
if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
|
||||||
|
return obj1.toString() === obj2.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Objekte
|
||||||
|
const keys1 = Object.keys(obj1)
|
||||||
|
const keys2 = Object.keys(obj2)
|
||||||
|
|
||||||
|
if (keys1.length !== keys2.length) return false
|
||||||
|
|
||||||
|
for (const key of keys1) {
|
||||||
|
if (!keys2.includes(key)) return false
|
||||||
|
if (!deepEqual(obj1[key], obj2[key])) return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
areItemsEqual,
|
areItemsEqual,
|
||||||
|
deepEqual,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-1">
|
<UCard v-if="group">
|
||||||
<UiCard
|
<template #header>
|
||||||
v-if="group"
|
<div class="flex items-center gap-2">
|
||||||
:title="mode === 'edit' ? t('title.edit') : t('title.create')"
|
<Icon
|
||||||
icon="mdi:folder-plus-outline"
|
:name="
|
||||||
@close="$emit('close')"
|
mode === 'edit'
|
||||||
body-class="px-0"
|
? 'mdi:folder-edit-outline'
|
||||||
>
|
: 'mdi:folder-plus-outline'
|
||||||
<form
|
"
|
||||||
class="flex flex-col gap-4 w-full p-4"
|
size="24"
|
||||||
@submit.prevent="$emit('submit')"
|
/>
|
||||||
>
|
<span>{{ mode === 'edit' ? t('title.edit') : t('title.create') }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<form class="flex flex-col gap-4 w-full p-4">
|
||||||
<UiInput
|
<UiInput
|
||||||
|
ref="nameRef"
|
||||||
|
v-model="group.name"
|
||||||
:label="t('name')"
|
:label="t('name')"
|
||||||
:placeholder="t('name')"
|
:placeholder="t('name')"
|
||||||
:read_only
|
:read-only
|
||||||
autofocus
|
autofocus
|
||||||
v-model="group.name"
|
|
||||||
ref="nameRef"
|
|
||||||
@keyup.enter="$emit('submit')"
|
@keyup.enter="$emit('submit')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -25,60 +29,50 @@
|
|||||||
v-model="group.description"
|
v-model="group.description"
|
||||||
:label="t('description')"
|
:label="t('description')"
|
||||||
:placeholder="t('description')"
|
:placeholder="t('description')"
|
||||||
:read_only
|
:read-only
|
||||||
@keyup.enter="$emit('submit')"
|
@keyup.enter="$emit('submit')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="flex flex-wrap gap-4">
|
<div class="flex flex-wrap gap-4">
|
||||||
<UiSelectIcon
|
<!-- <UiSelectIcon
|
||||||
v-model="group.icon"
|
v-model="group.icon"
|
||||||
default-icon="mdi:folder-outline"
|
default-icon="mdi:folder-outline"
|
||||||
:read_only
|
:readOnly
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UiSelectColor
|
<UiSelectColor
|
||||||
v-model="group.color"
|
v-model="group.color"
|
||||||
:read_only
|
:readOnly
|
||||||
/>
|
/> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="flex flex-wrap justify-end gap-4">
|
|
||||||
<UiButton
|
|
||||||
class="btn-error btn-outline flex-1"
|
|
||||||
@click="$emit('close')"
|
|
||||||
>
|
|
||||||
{{ t('abort') }}
|
|
||||||
<Icon name="mdi:close" />
|
|
||||||
</UiButton>
|
|
||||||
|
|
||||||
<UiButton
|
|
||||||
class="btn-primary flex-1"
|
|
||||||
@click="$emit('submit')"
|
|
||||||
>
|
|
||||||
{{ mode === 'create' ? t('create') : t('save') }}
|
|
||||||
<Icon name="mdi:check" />
|
|
||||||
</UiButton>
|
|
||||||
</div> -->
|
|
||||||
</form>
|
</form>
|
||||||
</UiCard>
|
</UCard>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SelectHaexPasswordsGroups } from '~~/src-tauri/database/schemas/vault'
|
import type { SelectHaexPasswordsGroups } from '~~/src-tauri/database/schemas/vault'
|
||||||
|
|
||||||
const group = defineModel<SelectHaexPasswordsGroups | null>()
|
const group = defineModel<SelectHaexPasswordsGroups | null>()
|
||||||
const { read_only = false } = defineProps<{
|
const { readOnly = false } = defineProps<{
|
||||||
read_only?: boolean
|
readOnly?: boolean
|
||||||
mode: 'create' | 'edit'
|
mode: 'create' | 'edit'
|
||||||
}>()
|
}>()
|
||||||
defineEmits(['close', 'submit'])
|
const emit = defineEmits(['close', 'submit'])
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const nameRef = useTemplateRef('nameRef')
|
const nameRef = useTemplateRef('nameRef')
|
||||||
onStartTyping(() => {
|
onStartTyping(() => {
|
||||||
nameRef.value?.inputRef?.focus()
|
nameRef.value?.$el.focus()
|
||||||
|
})
|
||||||
|
|
||||||
|
const { escape } = useMagicKeys()
|
||||||
|
|
||||||
|
watchEffect(async () => {
|
||||||
|
if (escape?.value) {
|
||||||
|
await nextTick()
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -5,73 +5,73 @@
|
|||||||
@submit.prevent="$emit('submit')"
|
@submit.prevent="$emit('submit')"
|
||||||
>
|
>
|
||||||
<UiInput
|
<UiInput
|
||||||
v-show="!read_only || itemDetails.title"
|
v-show="!readOnly || itemDetails.title"
|
||||||
|
ref="titleRef"
|
||||||
|
v-model.trim="itemDetails.title"
|
||||||
:check-input="check"
|
:check-input="check"
|
||||||
:label="t('item.title')"
|
:label="t('item.title')"
|
||||||
:placeholder="t('item.title')"
|
:placeholder="t('item.title')"
|
||||||
:read_only
|
:read-only
|
||||||
:with-copy-button
|
:with-copy-button
|
||||||
autofocus
|
autofocus
|
||||||
ref="titleRef"
|
|
||||||
v-model.trim="itemDetails.title"
|
|
||||||
@keyup.enter="$emit('submit')"
|
@keyup.enter="$emit('submit')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UiInput
|
<UiInput
|
||||||
v-show="!read_only || itemDetails.username"
|
v-show="!readOnly || itemDetails.username"
|
||||||
|
v-model.trim="itemDetails.username"
|
||||||
:check-input="check"
|
:check-input="check"
|
||||||
:label="t('item.username')"
|
:label="t('item.username')"
|
||||||
:placeholder="t('item.username')"
|
:placeholder="t('item.username')"
|
||||||
:with-copy-button
|
:with-copy-button
|
||||||
:read_only
|
:read-only
|
||||||
v-model.trim="itemDetails.username"
|
|
||||||
@keyup.enter="$emit('submit')"
|
@keyup.enter="$emit('submit')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UiInputPassword
|
<UiInputPassword
|
||||||
v-show="!read_only || itemDetails.password"
|
v-show="!readOnly || itemDetails.password"
|
||||||
:check-input="check"
|
|
||||||
:read_only
|
|
||||||
:with-copy-button
|
|
||||||
v-model.trim="itemDetails.password"
|
v-model.trim="itemDetails.password"
|
||||||
|
:check-input="check"
|
||||||
|
:read-only
|
||||||
|
:with-copy-button
|
||||||
@keyup.enter="$emit('submit')"
|
@keyup.enter="$emit('submit')"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<UiDialogPasswordGenerator
|
<!-- <UiDialogPasswordGenerator
|
||||||
v-if="!read_only"
|
v-if="!readOnly"
|
||||||
class="join-item"
|
class="join-item"
|
||||||
:password="itemDetails.password"
|
:password="itemDetails.password"
|
||||||
v-model="preventClose"
|
v-model="preventClose"
|
||||||
/>
|
/> -->
|
||||||
</template>
|
</template>
|
||||||
</UiInputPassword>
|
</UiInputPassword>
|
||||||
|
|
||||||
<UiInputUrl
|
<UiInputUrl
|
||||||
v-show="!read_only || itemDetails.url"
|
v-show="!readOnly || itemDetails.url"
|
||||||
|
v-model="itemDetails.url"
|
||||||
:label="t('item.url')"
|
:label="t('item.url')"
|
||||||
:placeholder="t('item.url')"
|
:placeholder="t('item.url')"
|
||||||
:read_only
|
:read-only
|
||||||
:with-copy-button
|
:with-copy-button
|
||||||
v-model="itemDetails.url"
|
|
||||||
@keyup.enter="$emit('submit')"
|
@keyup.enter="$emit('submit')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UiSelectIcon
|
<!-- <UiSelectIcon
|
||||||
v-show="!read_only"
|
v-show="!readOnly"
|
||||||
:default-icon="defaultIcon || 'mdi:key-outline'"
|
:default-icon="defaultIcon || 'mdi:key-outline'"
|
||||||
:read_only
|
:readOnly
|
||||||
v-model="itemDetails.icon"
|
v-model="itemDetails.icon"
|
||||||
/>
|
/> -->
|
||||||
|
|
||||||
<UiTextarea
|
<UiTextarea
|
||||||
v-show="!read_only || itemDetails.note"
|
v-show="!readOnly || itemDetails.note"
|
||||||
v-model="itemDetails.note"
|
v-model="itemDetails.note"
|
||||||
:label="t('item.note')"
|
:label="t('item.note')"
|
||||||
:placeholder="t('item.note')"
|
:placeholder="t('item.note')"
|
||||||
:read_only
|
:readOnly
|
||||||
:with-copy-button
|
:with-copy-button
|
||||||
@keyup.enter.stop
|
@keyup.enter.stop
|
||||||
class="h-52"
|
color="error"
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -82,7 +82,7 @@ import type { SelectHaexPasswordsItemDetails } from '~~/src-tauri/database/schem
|
|||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
defaultIcon?: string | null
|
defaultIcon?: string | null
|
||||||
read_only?: boolean
|
readOnly?: boolean
|
||||||
withCopyButton?: boolean
|
withCopyButton?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ const itemDetails = defineModel<SelectHaexPasswordsItemDetails>({
|
|||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const preventClose = defineModel<boolean>('preventClose')
|
//const preventClose = defineModel<boolean>('preventClose')
|
||||||
|
|
||||||
const check = defineModel<boolean>('check-input', { default: false })
|
const check = defineModel<boolean>('check-input', { default: false })
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ const check = defineModel<boolean>('check-input', { default: false })
|
|||||||
|
|
||||||
const titleRef = useTemplateRef('titleRef')
|
const titleRef = useTemplateRef('titleRef')
|
||||||
onStartTyping(() => {
|
onStartTyping(() => {
|
||||||
titleRef.value?.inputRef?.focus()
|
titleRef.value?.$el?.focus()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -1,70 +1,41 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-1">
|
<div class="p-1">
|
||||||
<UiCard
|
<UCard
|
||||||
body-class="rounded overflow-auto p-0 h-full"
|
class="rounded overflow-auto p-0 h-full"
|
||||||
@close="onClose"
|
@close="onClose"
|
||||||
>
|
>
|
||||||
<div class="">
|
<div class="">
|
||||||
<nav
|
<UTabs
|
||||||
aria-label="Tabs Password Item"
|
:items="tabs"
|
||||||
aria-orientation="horizontal"
|
variant="link"
|
||||||
class="tabs tabs-bordered w-full transition-all duration-700 sticky top-0 z-10"
|
:ui="{ trigger: 'grow' }"
|
||||||
role="tablist"
|
class="gap-4 w-full"
|
||||||
>
|
>
|
||||||
<button
|
<template #details>
|
||||||
:id="id.details"
|
<HaexPassItemDetails
|
||||||
aria-controls="vaultDetailsId"
|
v-if="details"
|
||||||
aria-selected="true"
|
v-model="details"
|
||||||
class="tab active-tab:tab-active active w-full"
|
with-copy-button
|
||||||
data-tab="#vaultDetailsId"
|
:read-only
|
||||||
role="tab"
|
:defaultIcon
|
||||||
type="button"
|
v-model:prevent-close="preventClose"
|
||||||
>
|
@submit="$emit('submit')"
|
||||||
<Icon
|
|
||||||
name="material-symbols:key-outline"
|
|
||||||
class="me-2"
|
|
||||||
/>
|
/>
|
||||||
<span class="hidden sm:block">
|
</template>
|
||||||
{{ t('tab.details') }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
:id="id.keyValue"
|
|
||||||
aria-controls="tabs-basic-2"
|
|
||||||
aria-selected="false"
|
|
||||||
class="tab active-tab:tab-active w-full"
|
|
||||||
data-tab="#tabs-basic-2"
|
|
||||||
role="tab"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name="fluent:group-list-20-filled"
|
|
||||||
class="me-2"
|
|
||||||
/>
|
|
||||||
<span class="hidden sm:block">
|
|
||||||
{{ t('tab.keyValue') }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
:id="id.history"
|
|
||||||
aria-controls="tabs-basic-3"
|
|
||||||
aria-selected="false"
|
|
||||||
class="tab active-tab:tab-active w-full"
|
|
||||||
data-tab="#tabs-basic-3"
|
|
||||||
role="tab"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name="material-symbols:history"
|
|
||||||
class="me-2"
|
|
||||||
/>
|
|
||||||
<span class="hidden sm:block">
|
|
||||||
{{ t('tab.history') }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="h-full pb-8">
|
<template #keyValue>
|
||||||
|
<HaexPassItemKeyValue
|
||||||
|
v-if="keyValues"
|
||||||
|
v-model="keyValues"
|
||||||
|
v-model:items-to-add="keyValuesAdd"
|
||||||
|
v-model:items-to-delete="keyValuesDelete"
|
||||||
|
:read-only
|
||||||
|
:item-id="details!.id"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</UTabs>
|
||||||
|
|
||||||
|
<!-- <div class="h-full pb-8">
|
||||||
<div
|
<div
|
||||||
id="vaultDetailsId"
|
id="vaultDetailsId"
|
||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
@ -104,15 +75,16 @@
|
|||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
:aria-labelledby="id.history"
|
:aria-labelledby="id.history"
|
||||||
>
|
>
|
||||||
<!-- <HaexPassItemHistory v-model="itemHistory" /> -->
|
<HaexPassItemHistory />
|
||||||
</div>
|
</div>
|
||||||
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</UCard>
|
||||||
</UiCard>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { TabsItem } from '@nuxt/ui'
|
||||||
import type {
|
import type {
|
||||||
SelectHaexPasswordsItemDetails,
|
SelectHaexPasswordsItemDetails,
|
||||||
SelectHaexPasswordsItemHistory,
|
SelectHaexPasswordsItemHistory,
|
||||||
@ -125,13 +97,13 @@ defineProps<{
|
|||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
close: [void]
|
close: []
|
||||||
addKeyValue: [void]
|
addKeyValue: []
|
||||||
removeKeyValue: [string]
|
removeKeyValue: [string]
|
||||||
submit: [void]
|
submit: []
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const read_only = defineModel<boolean>('read_only', { default: false })
|
const readOnly = defineModel<boolean>('readOnly', { default: false })
|
||||||
|
|
||||||
const details = defineModel<SelectHaexPasswordsItemDetails | null>('details', {
|
const details = defineModel<SelectHaexPasswordsItemDetails | null>('details', {
|
||||||
required: true,
|
required: true,
|
||||||
@ -152,12 +124,12 @@ const keyValuesDelete = defineModel<SelectHaexPasswordsItemKeyValues[]>(
|
|||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const id = reactive({
|
/* const id = reactive({
|
||||||
details: useId(),
|
details: useId(),
|
||||||
keyValue: useId(),
|
keyValue: useId(),
|
||||||
history: useId(),
|
history: useId(),
|
||||||
content: {},
|
content: {},
|
||||||
})
|
}) */
|
||||||
|
|
||||||
const preventClose = ref(false)
|
const preventClose = ref(false)
|
||||||
|
|
||||||
@ -166,6 +138,24 @@ const onClose = () => {
|
|||||||
|
|
||||||
emit('close')
|
emit('close')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tabs = ref<TabsItem[]>([
|
||||||
|
{
|
||||||
|
label: t('tab.details'),
|
||||||
|
icon: 'material-symbols:key-outline',
|
||||||
|
slot: 'details' as const,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('tab.keyValue'),
|
||||||
|
icon: 'fluent:group-list-20-filled',
|
||||||
|
slot: 'keyValue' as const,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('tab.history'),
|
||||||
|
icon: 'material-symbols:history',
|
||||||
|
slot: 'history' as const,
|
||||||
|
},
|
||||||
|
])
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="json">
|
<i18n lang="json">
|
||||||
|
|||||||
@ -12,47 +12,44 @@
|
|||||||
class="flex gap-2 hover:bg-primary/20 px-4 items-center"
|
class="flex gap-2 hover:bg-primary/20 px-4 items-center"
|
||||||
@click="currentSelected = item"
|
@click="currentSelected = item"
|
||||||
>
|
>
|
||||||
<button class="link flex items-center no-underline w-full py-2">
|
<button class="flex items-center no-underline w-full py-2">
|
||||||
<input
|
<input
|
||||||
v-model="item.key"
|
v-model="item.key"
|
||||||
:readonly="currentSelected !== item || read_only"
|
:readonly="currentSelected !== item || readOnly"
|
||||||
class="flex-1 cursor-pointer"
|
class="flex-1 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<UiButton
|
<UiButton
|
||||||
v-if="!read_only"
|
v-if="!readOnly"
|
||||||
:class="[currentSelected === item ? 'visible' : 'invisible']"
|
:class="[currentSelected === item ? 'visible' : 'invisible']"
|
||||||
class="inline-flex btn-square btn-error btn-outline"
|
variant="outline"
|
||||||
|
color="error"
|
||||||
|
icon="mdi:trash-outline"
|
||||||
@click="deleteItem(item.id)"
|
@click="deleteItem(item.id)"
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name="mdi:trash-outline"
|
|
||||||
class="size-5"
|
|
||||||
/>
|
/>
|
||||||
</UiButton>
|
|
||||||
</li>
|
</li>
|
||||||
</UiList>
|
</UiList>
|
||||||
|
|
||||||
<UiTextarea
|
<UTextarea
|
||||||
v-if="items.length || itemsToAdd.length"
|
v-if="items.length || itemsToAdd.length"
|
||||||
:read_only="read_only || !currentSelected"
|
:readOnly="readOnly || !currentSelected"
|
||||||
class="flex-1 min-w-52 border-base-content/25"
|
class="flex-1 min-w-52 border-base-content/25"
|
||||||
rows="6"
|
|
||||||
v-model="currentValue"
|
v-model="currentValue"
|
||||||
with-copy-button
|
with-copy-button
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="!read_only"
|
v-show="!readOnly"
|
||||||
class="flex py-4 gap-2 justify-center items-end flex-wrap"
|
class="flex py-4 gap-2 justify-center items-end flex-wrap"
|
||||||
>
|
>
|
||||||
<UiButton
|
<UiButton
|
||||||
@click="addItem"
|
@click="addItem"
|
||||||
class="btn-primary btn-outline flex-1-1 min-w-40"
|
class="btn-primary btn-outline flex-1-1 min-w-40"
|
||||||
|
icon="mdi:plus"
|
||||||
>
|
>
|
||||||
<Icon name="mdi:plus" />
|
<!-- <Icon name="mdi:plus" />
|
||||||
<p class="hidden sm:inline-block">{{ t('add') }}</p>
|
<p class="hidden sm:inline-block">{{ t('add') }}</p> -->
|
||||||
</UiButton>
|
</UiButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -61,7 +58,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SelectHaexPasswordsItemKeyValues } from '~~/src-tauri/database/schemas/vault'
|
import type { SelectHaexPasswordsItemKeyValues } from '~~/src-tauri/database/schemas/vault'
|
||||||
|
|
||||||
const { itemId } = defineProps<{ read_only?: boolean; itemId: string }>()
|
const { itemId } = defineProps<{ readOnly?: boolean; itemId: string }>()
|
||||||
|
|
||||||
const items = defineModel<SelectHaexPasswordsItemKeyValues[]>({ default: [] })
|
const items = defineModel<SelectHaexPasswordsItemKeyValues[]>({ default: [] })
|
||||||
|
|
||||||
@ -74,9 +71,9 @@ const itemsToAdd = defineModel<SelectHaexPasswordsItemKeyValues[]>(
|
|||||||
{ default: [] },
|
{ default: [] },
|
||||||
)
|
)
|
||||||
|
|
||||||
defineEmits<{ add: [void]; remove: [string] }>()
|
defineEmits<{ add: []; remove: [string] }>()
|
||||||
|
|
||||||
const { t } = useI18n()
|
//const { t } = useI18n()
|
||||||
|
|
||||||
const currentSelected = ref<SelectHaexPasswordsItemKeyValues | undefined>(
|
const currentSelected = ref<SelectHaexPasswordsItemKeyValues | undefined>(
|
||||||
items.value?.at(0),
|
items.value?.at(0),
|
||||||
@ -101,6 +98,7 @@ const addItem = () => {
|
|||||||
key: '',
|
key: '',
|
||||||
value: '',
|
value: '',
|
||||||
updateAt: null,
|
updateAt: null,
|
||||||
|
haex_tombstone: null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,70 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="fixed bottom-4 flex justify-between transition-all pointer-events-none right-0 sm:items-center items-end"
|
class="fixed bottom-4 flex justify-between transition-all pointer-events-none right-0 sm:items-center items-end h-12"
|
||||||
:class="[isVisible ? 'left-15 ' : 'left-0']"
|
:class="[isVisible ? 'left-16' : 'left-0']"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-center flex-1">
|
<div class="flex items-center justify-center flex-1">
|
||||||
<UiButton
|
<UiButton
|
||||||
v-show="showCloseButton"
|
v-show="showCloseButton"
|
||||||
:tooltip="t('abort')"
|
:tooltip="t('abort')"
|
||||||
|
icon="mdi:close"
|
||||||
|
color="error"
|
||||||
|
variant="ghost"
|
||||||
|
class="pointer-events-auto"
|
||||||
@click="$emit('close')"
|
@click="$emit('close')"
|
||||||
class="btn-accent btn-square"
|
/>
|
||||||
>
|
|
||||||
<Icon name="mdi:close" />
|
|
||||||
</UiButton>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<UiButton
|
<UiButton
|
||||||
v-show="showEditButton"
|
v-show="showEditButton"
|
||||||
|
icon="mdi:pencil-outline"
|
||||||
|
class="pointer-events-auto"
|
||||||
|
size="xl"
|
||||||
:tooltip="t('edit')"
|
:tooltip="t('edit')"
|
||||||
@click="$emit('edit')"
|
@click="$emit('edit')"
|
||||||
class="btn-xl btn-square btn-primary"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name="mdi:pencil-outline"
|
|
||||||
class="size-11 shrink-0"
|
|
||||||
/>
|
/>
|
||||||
</UiButton>
|
|
||||||
|
|
||||||
<UiButton
|
<UiButton
|
||||||
v-show="showReadonlyButton"
|
v-show="showReadonlyButton"
|
||||||
|
icon="mdi:pencil-off-outline"
|
||||||
|
class="pointer-events-auto"
|
||||||
|
size="xl"
|
||||||
:tooltip="t('readonly')"
|
:tooltip="t('readonly')"
|
||||||
class="btn-xl btn-square btn-primary"
|
|
||||||
@click="$emit('readonly')"
|
@click="$emit('readonly')"
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name="mdi:pencil-off-outline"
|
|
||||||
class="size-11 shrink-0"
|
|
||||||
/>
|
/>
|
||||||
</UiButton>
|
|
||||||
|
|
||||||
<UiButton
|
<UiButton
|
||||||
v-show="showSaveButton"
|
v-show="showSaveButton"
|
||||||
|
icon="mdi:content-save-outline"
|
||||||
|
size="xl"
|
||||||
|
class="pointer-events-auto"
|
||||||
|
:class="{ 'animate-pulse': hasChanges }"
|
||||||
:tooltip="t('save')"
|
:tooltip="t('save')"
|
||||||
class="btn-xl btn-square btn-primary motion-duration-2000"
|
|
||||||
:class="{ 'motion-preset-pulse-sm': hasChanges }"
|
|
||||||
@click="$emit('save')"
|
@click="$emit('save')"
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name="mdi:content-save-outline"
|
|
||||||
class="size-11 shrink-0"
|
|
||||||
/>
|
/>
|
||||||
</UiButton>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-center flex-1">
|
<div class="flex items-center justify-center flex-1">
|
||||||
<UiButton
|
<UiButton
|
||||||
v-show="showDeleteButton"
|
v-show="showDeleteButton"
|
||||||
|
color="error"
|
||||||
|
icon="mdi:trash-outline"
|
||||||
|
class="pointer-events-auto"
|
||||||
|
variant="ghost"
|
||||||
:tooltip="t('delete')"
|
:tooltip="t('delete')"
|
||||||
class="btn-square btn-error"
|
|
||||||
@click="$emit('delete')"
|
@click="$emit('delete')"
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name="mdi:trash-outline"
|
|
||||||
class="shrink-0"
|
|
||||||
/>
|
/>
|
||||||
</UiButton>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -74,12 +64,12 @@ const { isVisible } = storeToRefs(useSidebarStore())
|
|||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
hasChanges?: boolean
|
||||||
showCloseButton?: boolean
|
showCloseButton?: boolean
|
||||||
showDeleteButton?: boolean
|
showDeleteButton?: boolean
|
||||||
showEditButton?: boolean
|
showEditButton?: boolean
|
||||||
showReadonlyButton?: boolean
|
showReadonlyButton?: boolean
|
||||||
showSaveButton?: boolean
|
showSaveButton?: boolean
|
||||||
hasChanges?: boolean
|
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
defineEmits(['close', 'edit', 'readonly', 'save', 'delete'])
|
defineEmits(['close', 'edit', 'readonly', 'save', 'delete'])
|
||||||
|
|||||||
@ -4,15 +4,21 @@
|
|||||||
class="flex-1"
|
class="flex-1"
|
||||||
>
|
>
|
||||||
<ul
|
<ul
|
||||||
class="flex flex-col w-full h-full gap-y-2 first:rounded-t-md last:rounded-b-md p-1"
|
|
||||||
ref="listRef"
|
ref="listRef"
|
||||||
|
class="flex flex-col w-full h-full gap-y-2 first:rounded-t-md last:rounded-b-md p-1"
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
v-for="(item, index) in menuItems"
|
v-for="(item, index) in menuItems"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
class="bg-base-100 rounded-lg hover:bg-base-content/20 origin-to intersect:motion-preset-slide-down intersect:motion-ease-spring-bouncier intersect:motion-delay ease-in-out shadow"
|
v-on-long-press="[
|
||||||
|
onLongPressCallbackHook,
|
||||||
|
{
|
||||||
|
delay: 1000,
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
class="bg-accented rounded-lg hover:bg-base-content/20 origin-to intersect:motion-preset-slide-down intersect:motion-ease-spring-bouncier intersect:motion-delay ease-in-out shadow"
|
||||||
:class="{
|
:class="{
|
||||||
'bg-base-content/30 outline outline-accent hover:bg-base-content/20':
|
'bg-elevated/30 outline outline-accent hover:bg-base-content/20':
|
||||||
selectedItems.has(item) ||
|
selectedItems.has(item) ||
|
||||||
(currentSelectedItem?.id === item.id &&
|
(currentSelectedItem?.id === item.id &&
|
||||||
longPressedHook &&
|
longPressedHook &&
|
||||||
@ -22,12 +28,6 @@
|
|||||||
),
|
),
|
||||||
}"
|
}"
|
||||||
:style="{ '--motion-delay': `${50 * index}ms` }"
|
:style="{ '--motion-delay': `${50 * index}ms` }"
|
||||||
v-on-long-press="[
|
|
||||||
onLongPressCallbackHook,
|
|
||||||
{
|
|
||||||
delay: 1000,
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
@mousedown="
|
@mousedown="
|
||||||
longPressedHook
|
longPressedHook
|
||||||
? (currentSelectedItem = null)
|
? (currentSelectedItem = null)
|
||||||
@ -85,7 +85,7 @@ const { search } = storeToRefs(useSearchStore())
|
|||||||
const onClickItemAsync = async (item: IPasswordMenuItem) => {
|
const onClickItemAsync = async (item: IPasswordMenuItem) => {
|
||||||
currentSelectedItem.value = null
|
currentSelectedItem.value = null
|
||||||
|
|
||||||
if (longPressedHook.value || selectedItems.value.size || ctrl.value) {
|
if (longPressedHook.value || selectedItems.value.size || ctrl?.value) {
|
||||||
if (selectedItems.value?.has(item)) {
|
if (selectedItems.value?.has(item)) {
|
||||||
selectedItems.value.delete(item)
|
selectedItems.value.delete(item)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,188 +0,0 @@
|
|||||||
<template>
|
|
||||||
<aside
|
|
||||||
:id
|
|
||||||
ref="sidebarRef"
|
|
||||||
class="flex sm:shadow-none w-full md:max-w-64"
|
|
||||||
tabindex="-1"
|
|
||||||
>
|
|
||||||
<div class="drawer-body w-full">
|
|
||||||
<ul class="menu space-y-0.5 p-0 rounded-none md:rounded">
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--home] size-5" />
|
|
||||||
Home
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="space-y-0.5">
|
|
||||||
<a
|
|
||||||
id="menu-app"
|
|
||||||
class="collapse-toggle collapse-open:bg-base-content/10"
|
|
||||||
data-collapse="#menu-app-collapse"
|
|
||||||
>
|
|
||||||
<span class="icon-[tabler--apps] size-5" />
|
|
||||||
Apps
|
|
||||||
<span
|
|
||||||
class="icon-[tabler--chevron-down] collapse-open:rotate-180 size-4 transition-all duration-300"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<ul
|
|
||||||
id="menu-app-collapse"
|
|
||||||
class="collapse hidden w-auto space-y-0.5 overflow-hidden transition-[height] duration-300"
|
|
||||||
aria-labelledby="menu-app"
|
|
||||||
>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--message] size-5" />
|
|
||||||
Chat
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--calendar] size-5" />
|
|
||||||
Calendar
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="space-y-0.5">
|
|
||||||
<a
|
|
||||||
id="sub-menu-academy"
|
|
||||||
class="collapse-toggle collapse-open:bg-base-content/10"
|
|
||||||
data-collapse="#sub-menu-academy-collapse"
|
|
||||||
>
|
|
||||||
<span class="icon-[tabler--book] size-5" />
|
|
||||||
Academy
|
|
||||||
<span
|
|
||||||
class="icon-[tabler--chevron-down] collapse-open:rotate-180 size-4"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<ul
|
|
||||||
id="sub-menu-academy-collapse"
|
|
||||||
class="collapse hidden w-auto space-y-0.5 overflow-hidden transition-[height] duration-300"
|
|
||||||
aria-labelledby="sub-menu-academy"
|
|
||||||
>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--books] size-5" />
|
|
||||||
Courses
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--list-details] size-5" />
|
|
||||||
Course details
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="space-y-0.5">
|
|
||||||
<a
|
|
||||||
id="sub-menu-academy-stats"
|
|
||||||
class="collapse-toggle collapse-open:bg-base-content/10"
|
|
||||||
data-collapse="#sub-menu-academy-stats-collapse"
|
|
||||||
>
|
|
||||||
<span class="icon-[tabler--chart-bar] size-5" />
|
|
||||||
Stats
|
|
||||||
<span
|
|
||||||
class="icon-[tabler--chevron-down] collapse-open:rotate-180 size-4"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<ul
|
|
||||||
id="sub-menu-academy-stats-collapse"
|
|
||||||
class="collapse hidden w-auto space-y-0.5 overflow-hidden transition-[height] duration-300"
|
|
||||||
aria-labelledby="sub-menu-academy-stats"
|
|
||||||
>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--chart-donut] size-5" />
|
|
||||||
Goals
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--settings] size-5" />
|
|
||||||
Settings
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<div class="divider text-base-content/50 py-6 after:border-0">
|
|
||||||
Account
|
|
||||||
</div>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--login] size-5" />
|
|
||||||
Sign In
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--logout-2] size-5" />
|
|
||||||
Sign Out
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<div class="divider text-base-content/50 py-6 after:border-0">
|
|
||||||
Miscellaneous
|
|
||||||
</div>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--users-group] size-5" />
|
|
||||||
Support
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
<span class="icon-[tabler--files] size-5" />
|
|
||||||
Documentation
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import type { HSOverlay } from 'flyonui/flyonui'
|
|
||||||
|
|
||||||
defineProps<{ title?: string; label?: string }>()
|
|
||||||
|
|
||||||
defineEmits(['open', 'close'])
|
|
||||||
|
|
||||||
const id = useId()
|
|
||||||
|
|
||||||
const open = defineModel<boolean>('open', { default: true })
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const sidebarRef = useTemplateRef('sidebarRef')
|
|
||||||
|
|
||||||
const modal = ref<HSOverlay>()
|
|
||||||
|
|
||||||
watch(open, async () => {
|
|
||||||
if (open.value) {
|
|
||||||
await modal.value?.open()
|
|
||||||
} else {
|
|
||||||
await modal.value?.close(true)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
if (!sidebarRef.value) return
|
|
||||||
|
|
||||||
modal.value = new window.HSOverlay(sidebarRef.value, {
|
|
||||||
isClosePrev: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
modal.value.on('close', () => {
|
|
||||||
open.value = false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<i18n lang="yaml">
|
|
||||||
de:
|
|
||||||
close: Schließen
|
|
||||||
|
|
||||||
en:
|
|
||||||
close: Close
|
|
||||||
</i18n>
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
const onClick = () => {
|
|
||||||
console.log("click")
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Dialog>
|
|
||||||
<DialogTrigger as-child>
|
|
||||||
<Button variant="outline" @click="onClick">
|
|
||||||
Edit Profile
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent class="sm:max-w-[425px]">
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Edit profile</DialogTitle>
|
|
||||||
<DialogDescription>
|
|
||||||
Make changes to your profile here. Click save when you're done.
|
|
||||||
</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
<div class="grid gap-4 py-4">
|
|
||||||
<div class="grid grid-cols-4 items-center gap-4">
|
|
||||||
<Label for="name" class="text-right">
|
|
||||||
Name
|
|
||||||
</Label>
|
|
||||||
<Input id="name" default-value="Pedro Duarte" class="col-span-3" />
|
|
||||||
</div>
|
|
||||||
<div class="grid grid-cols-4 items-center gap-4">
|
|
||||||
<Label for="username" class="text-right">
|
|
||||||
Username
|
|
||||||
</Label>
|
|
||||||
<Input id="username" default-value="@peduarte" class="col-span-3" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<DialogFooter>
|
|
||||||
<Button type="submit">
|
|
||||||
Save changes
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</template>
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
class="accordion divide-neutral/20 divide-y accordion-shadow *:accordion-item-active:shadow-md"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
:id="itemId"
|
|
||||||
ref="accordionRef"
|
|
||||||
class="accordion-item active"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="accordion-toggle inline-flex items-center gap-x-4 text-start"
|
|
||||||
:aria-controls="collapseId"
|
|
||||||
aria-expanded="true"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="icon-[tabler--chevron-right] accordion-item-active:rotate-90 size-5 shrink-0 transition-transform duration-300 rtl:rotate-180"
|
|
||||||
/>
|
|
||||||
<slot name="title" />
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
:id="collapseId"
|
|
||||||
class="accordion-content w-full overflow-hidden transition-[height] duration-300"
|
|
||||||
:aria-labelledby="itemId"
|
|
||||||
role="region"
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import type { HSAccordion } from 'flyonui/flyonui'
|
|
||||||
|
|
||||||
const itemId = useId()
|
|
||||||
const collapseId = useId()
|
|
||||||
|
|
||||||
const accordionRef = useTemplateRef('accordionRef')
|
|
||||||
const accordion = ref<HSAccordion>()
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (accordionRef.value) {
|
|
||||||
accordion.value = new window.HSAccordion(accordionRef.value)
|
|
||||||
accordion.value.hide()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@ -1,107 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="z-10 pointer-events-auto">
|
|
||||||
<div
|
|
||||||
class="dropdown relative inline-flex [--placement:top] [--strategy:absolute]"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
:id
|
|
||||||
class="dropdown-toggle btn btn-primary btn-xl btn-square dropdown-open:rotate-45 transition-transform"
|
|
||||||
aria-haspopup="menu"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="Menu"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
:name="icon"
|
|
||||||
class="size-11 shrink-0"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<ul
|
|
||||||
class="dropdown-menu dropdown-open:opacity-100 hidden min-w-60 bg-transparent shadow-none"
|
|
||||||
data-dropdown-transition
|
|
||||||
role="menu"
|
|
||||||
aria-orientation="vertical"
|
|
||||||
:aria-labelledby="id"
|
|
||||||
>
|
|
||||||
<li
|
|
||||||
v-for="link in menu"
|
|
||||||
class="dropdown-item hover:bg-transparent px-0 py-1"
|
|
||||||
>
|
|
||||||
<NuxtLinkLocale
|
|
||||||
v-if="link.to"
|
|
||||||
:to="link.to"
|
|
||||||
class="btn btn-primary flex items-center no-underline rounded-lg flex-nowrap w-full"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
v-if="link.icon"
|
|
||||||
:name="link.icon"
|
|
||||||
class="me-3"
|
|
||||||
/>
|
|
||||||
{{ te(link.label) ? t(link.label) : link.label }}
|
|
||||||
</NuxtLinkLocale>
|
|
||||||
|
|
||||||
<button
|
|
||||||
v-else
|
|
||||||
@click="link.action"
|
|
||||||
class="link hover:link-primary flex items-center no-underline w-full"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
v-if="link.icon"
|
|
||||||
:name="link.icon"
|
|
||||||
class="me-3"
|
|
||||||
/>
|
|
||||||
{{ link.label }}
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import type { IActionMenuItem } from './types'
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
menu: {
|
|
||||||
type: Array as PropType<IActionMenuItem[]>,
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
type: String,
|
|
||||||
default: 'mdi:plus',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const id = useId()
|
|
||||||
|
|
||||||
const { t, te } = useI18n()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="css" scoped>
|
|
||||||
@keyframes fadeInStagger {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(15px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 2. Die Listenelemente sind standardmäßig unsichtbar, damit sie nicht aufblitzen */
|
|
||||||
.stagger-menu li {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 3. Wenn das Menü geöffnet wird, weise die Animation zu */
|
|
||||||
:global(.dropdown-open) .stagger-menu li {
|
|
||||||
animation-name: fadeInStagger;
|
|
||||||
animation-duration: 0.4s;
|
|
||||||
animation-timing-function: ease-out;
|
|
||||||
|
|
||||||
/* SEHR WICHTIG: Sorgt dafür, dass die Elemente nach der Animation sichtbar bleiben (den Zustand von 'to' beibehalten) */
|
|
||||||
animation-fill-mode: forwards;
|
|
||||||
|
|
||||||
/* Die individuelle animation-delay wird per :style im Template gesetzt. */
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,22 +1,31 @@
|
|||||||
<template>
|
<template>
|
||||||
<button
|
<div>
|
||||||
class="btn join-item pointer-events-auto"
|
<UTooltip :text="buttonProps?.tooltip">
|
||||||
:type
|
<UButton
|
||||||
|
class="pointer-events-auto"
|
||||||
|
v-bind="{ ...buttonProps, ...$attrs }"
|
||||||
|
@click="(e) => $emit('click', e)"
|
||||||
>
|
>
|
||||||
<UiTooltip
|
<template
|
||||||
:tooltip
|
v-for="(_, slotName) in $slots"
|
||||||
v-if="tooltip"
|
#[slotName]="slotProps"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot
|
||||||
</UiTooltip>
|
:name="slotName"
|
||||||
|
v-bind="slotProps"
|
||||||
<slot v-else />
|
/>
|
||||||
</button>
|
</template>
|
||||||
|
</UButton>
|
||||||
|
</UTooltip>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { type = 'button' } = defineProps<{
|
import type { ButtonProps } from '@nuxt/ui'
|
||||||
type?: 'reset' | 'submit' | 'button'
|
|
||||||
|
interface IButtonProps extends /* @vue-ignore */ ButtonProps {
|
||||||
tooltip?: string
|
tooltip?: string
|
||||||
}>()
|
}
|
||||||
|
const buttonProps = defineProps<IButtonProps>()
|
||||||
|
defineEmits<{ click: [Event] }>()
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
8
src/components/ui/button/types.d.ts
vendored
@ -1,8 +0,0 @@
|
|||||||
import type { RouteLocationRaw } from 'vue-router'
|
|
||||||
|
|
||||||
export interface IActionMenuItem {
|
|
||||||
label: string
|
|
||||||
icon?: string
|
|
||||||
action?: () => Promise<unknown>
|
|
||||||
to?: RouteLocationRaw
|
|
||||||
}
|
|
||||||
@ -1,81 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="card min-w-56">
|
|
||||||
<slot name="image" />
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="card-header"
|
|
||||||
v-if="$slots.title || title"
|
|
||||||
>
|
|
||||||
<slot name="header">
|
|
||||||
<div
|
|
||||||
v-if="$slots.title || title"
|
|
||||||
class="flex items-center gap-2"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
v-if="icon"
|
|
||||||
:name="icon"
|
|
||||||
size="28"
|
|
||||||
/>
|
|
||||||
<h5
|
|
||||||
v-if="title"
|
|
||||||
class="card-title mb-0"
|
|
||||||
>
|
|
||||||
{{ title }}
|
|
||||||
</h5>
|
|
||||||
<slot
|
|
||||||
v-else
|
|
||||||
name="title"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="text-base-content/45">{{ subtitle }}</div>
|
|
||||||
</slot>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="card-body"
|
|
||||||
:class="bodyClass"
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
<div
|
|
||||||
v-if="$slots.action"
|
|
||||||
class="card-actions"
|
|
||||||
>
|
|
||||||
<slot name="action" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="$slots.footer"
|
|
||||||
class="card-footer"
|
|
||||||
>
|
|
||||||
<slot name="footer" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
const emit = defineEmits(['close', 'submit'])
|
|
||||||
|
|
||||||
defineProps<{
|
|
||||||
title?: string
|
|
||||||
subtitle?: string
|
|
||||||
icon?: string
|
|
||||||
bodyClass?: string
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const { escape, enter } = useMagicKeys()
|
|
||||||
|
|
||||||
watchEffect(async () => {
|
|
||||||
if (escape.value) {
|
|
||||||
await nextTick()
|
|
||||||
emit('close')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
watchEffect(async () => {
|
|
||||||
if (enter.value) {
|
|
||||||
await nextTick()
|
|
||||||
emit('submit')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@ -1,61 +1,73 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiDialog
|
<UModal
|
||||||
:title
|
|
||||||
@close="onAbort"
|
|
||||||
v-model:open="open"
|
v-model:open="open"
|
||||||
|
:title
|
||||||
|
:description
|
||||||
|
:fullscreen="isSmallScreen"
|
||||||
>
|
>
|
||||||
<template #trigger>
|
<slot>
|
||||||
<slot name="trigger" />
|
<!-- <UiButton
|
||||||
</template>
|
color="primary"
|
||||||
|
variant="outline"
|
||||||
|
icon="mdi:menu"
|
||||||
|
:ui="{
|
||||||
|
base: '',
|
||||||
|
}"
|
||||||
|
/> -->
|
||||||
|
</slot>
|
||||||
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<slot name="title" />
|
<slot name="title" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<slot />
|
<template #body>
|
||||||
|
<slot name="body" />
|
||||||
<template #buttons>
|
|
||||||
<slot name="buttons">
|
|
||||||
<UiButton
|
|
||||||
class="btn-error btn-outline w-full sm:w-auto"
|
|
||||||
@click="onAbort"
|
|
||||||
>
|
|
||||||
<Icon :name="abortIcon || 'mdi:close'" />
|
|
||||||
{{ abortLabel ?? t('abort') }}
|
|
||||||
</UiButton>
|
|
||||||
<UiButton
|
|
||||||
class="btn-primary w-full sm:w-auto"
|
|
||||||
@click="onConfirm"
|
|
||||||
>
|
|
||||||
<Icon :name="confirmIcon || 'mdi:check'" />
|
|
||||||
{{ confirmLabel ?? t('confirm') }}
|
|
||||||
</UiButton>
|
|
||||||
</slot>
|
|
||||||
</template>
|
</template>
|
||||||
</UiDialog>
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="flex flex-col sm:flex-row gap-4 justify-end w-full">
|
||||||
|
<UiButton
|
||||||
|
:icon="abortIcon || 'mdi:close'"
|
||||||
|
:label="abortLabel || t('abort')"
|
||||||
|
block
|
||||||
|
color="error"
|
||||||
|
variant="outline"
|
||||||
|
@click="open = false"
|
||||||
|
/>
|
||||||
|
<UiButton
|
||||||
|
:icon="confirmIcon || 'mdi:check'"
|
||||||
|
:label="confirmLabel || t('confirm')"
|
||||||
|
block
|
||||||
|
color="primary"
|
||||||
|
varaint="solid"
|
||||||
|
@click="$emit('confirm')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
confirmLabel?: string
|
|
||||||
abortLabel?: string
|
|
||||||
title?: string
|
|
||||||
abortIcon?: string
|
abortIcon?: string
|
||||||
|
abortLabel?: string
|
||||||
confirmIcon?: string
|
confirmIcon?: string
|
||||||
|
confirmLabel?: string
|
||||||
|
description?: string
|
||||||
|
title?: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const open = defineModel<boolean>('open', { default: false })
|
const open = defineModel<boolean>('open', { default: false })
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const emit = defineEmits(['confirm', 'abort'])
|
defineEmits(['confirm'])
|
||||||
|
|
||||||
const onAbort = () => {
|
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||||
emit('abort')
|
|
||||||
}
|
|
||||||
|
|
||||||
const onConfirm = () => {
|
// "smAndDown" gilt für sm, xs usw.
|
||||||
emit('confirm')
|
const isSmallScreen = breakpoints.smaller('sm')
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="yaml">
|
<i18n lang="yaml">
|
||||||
|
|||||||
@ -1,116 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button
|
|
||||||
v-if="$slots.trigger || label"
|
|
||||||
v-bind="$attrs"
|
|
||||||
type="button"
|
|
||||||
aria-haspopup="dialog"
|
|
||||||
aria-expanded="false"
|
|
||||||
:aria-label="label"
|
|
||||||
@click="$emit('open')"
|
|
||||||
>
|
|
||||||
<slot name="trigger">
|
|
||||||
{{ label }}
|
|
||||||
</slot>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="hidden">
|
|
||||||
<Teleport to="body">
|
|
||||||
<div
|
|
||||||
:id
|
|
||||||
ref="modalRef"
|
|
||||||
class="overlay modal overlay-open:opacity-100 overlay-open:duration-300 hidden modal-middle p-0 xs:p-2 --prevent-on-load-init pointer-events-auto max-w-none"
|
|
||||||
role="dialog"
|
|
||||||
tabindex="-1"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="overlay-animation-target overlay-open:duration-300 overlay-open:opacity-100 transition-all ease-out modal-dialog"
|
|
||||||
>
|
|
||||||
<div class="modal-content justify-between">
|
|
||||||
<div class="modal-header py-0 sm:py-4">
|
|
||||||
<div
|
|
||||||
v-if="title || $slots.title"
|
|
||||||
class="modal-title py-4 break-all"
|
|
||||||
>
|
|
||||||
<slot name="title">
|
|
||||||
{{ title }}
|
|
||||||
</slot>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-text btn-circle btn-sm absolute end-3 top-3"
|
|
||||||
:aria-label="t('close')"
|
|
||||||
tabindex="1"
|
|
||||||
@click="open = false"
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name="mdi:close"
|
|
||||||
size="18"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body text-sm sm:text-base grow mt-0 pt-0">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer flex-col sm:flex-row">
|
|
||||||
<slot name="buttons" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Teleport>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import type { HSOverlay } from 'flyonui/flyonui'
|
|
||||||
const { currentTheme } = storeToRefs(useUiStore())
|
|
||||||
|
|
||||||
defineProps<{ title?: string; label?: string }>()
|
|
||||||
|
|
||||||
const emit = defineEmits(['open', 'close'])
|
|
||||||
|
|
||||||
const id = useId()
|
|
||||||
|
|
||||||
const open = defineModel<boolean>('open', { default: false })
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const modalRef = useTemplateRef('modalRef')
|
|
||||||
|
|
||||||
defineExpose({ modalRef })
|
|
||||||
|
|
||||||
const modal = ref<HSOverlay>()
|
|
||||||
|
|
||||||
watch(open, async () => {
|
|
||||||
if (!modal.value) return
|
|
||||||
|
|
||||||
if (open.value) {
|
|
||||||
await modal.value.open()
|
|
||||||
} else {
|
|
||||||
await modal.value.close(true)
|
|
||||||
emit('close')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
if (!modalRef.value) return
|
|
||||||
|
|
||||||
modal.value = new window.HSOverlay(modalRef.value)
|
|
||||||
|
|
||||||
modal.value.isLayoutAffect = true
|
|
||||||
modal.value.on('close', () => {
|
|
||||||
open.value = false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<i18n lang="yaml">
|
|
||||||
de:
|
|
||||||
close: Schließen
|
|
||||||
|
|
||||||
en:
|
|
||||||
close: Close
|
|
||||||
</i18n>
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
<template>
|
|
||||||
<UiDialogConfirm
|
|
||||||
:confirm-label="t('apply')"
|
|
||||||
:title="t('title')"
|
|
||||||
@abort="open = false"
|
|
||||||
@click="open = true"
|
|
||||||
class="btn btn-square btn-accent btn-outline"
|
|
||||||
v-model:open="open"
|
|
||||||
>
|
|
||||||
<template #trigger>
|
|
||||||
<Icon name="mdi:dice" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<form class="flex flex-col gap-4">
|
|
||||||
<UiInputPassword
|
|
||||||
v-model="newPassword"
|
|
||||||
prepend-icon="mdi:key-outline"
|
|
||||||
with-copy-button
|
|
||||||
>
|
|
||||||
<template #append>
|
|
||||||
<UiButton class="btn-square btn-accent btn-outline">
|
|
||||||
<Icon name="mdi:refresh" />
|
|
||||||
</UiButton>
|
|
||||||
</template>
|
|
||||||
</UiInputPassword>
|
|
||||||
</form>
|
|
||||||
</UiDialogConfirm>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
const open = defineModel<boolean>()
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const { password } = defineProps<{
|
|
||||||
autofocus?: boolean
|
|
||||||
checkInput?: boolean
|
|
||||||
label?: string
|
|
||||||
placeholder?: string
|
|
||||||
withCopyButton?: boolean
|
|
||||||
password: string | null
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const newPassword = computed(() => password)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<i18n lang="yaml">
|
|
||||||
de:
|
|
||||||
title: Passwortgenerator
|
|
||||||
apply: Übernehmen
|
|
||||||
|
|
||||||
en:
|
|
||||||
title: Passwordgenerator
|
|
||||||
apply: Apply
|
|
||||||
</i18n>
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
:class="offset"
|
|
||||||
class="dropdown relative inline-flex"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
:aria-label="label"
|
|
||||||
:id
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-haspopup="menu"
|
|
||||||
class="dropdown-toggle"
|
|
||||||
type="button"
|
|
||||||
v-bind="$attrs"
|
|
||||||
>
|
|
||||||
<slot name="activator">
|
|
||||||
{{ label }}
|
|
||||||
<span
|
|
||||||
class="icon-[tabler--chevron-down] dropdown-open:rotate-180 size-4"
|
|
||||||
/>
|
|
||||||
</slot>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<ul
|
|
||||||
:aria-labelledby="id"
|
|
||||||
aria-orientation="vertical"
|
|
||||||
class="dropdown-menu dropdown-open:opacity-100 hidden min-w-28 z-20 shadow shadow-primary"
|
|
||||||
role="menu"
|
|
||||||
>
|
|
||||||
<slot
|
|
||||||
name="items"
|
|
||||||
:items
|
|
||||||
>
|
|
||||||
<li
|
|
||||||
:is="itemIs"
|
|
||||||
@click="read_only ? '' : $emit('select', item)"
|
|
||||||
class="dropdown-item"
|
|
||||||
v-for="item in items"
|
|
||||||
>
|
|
||||||
<slot
|
|
||||||
:item
|
|
||||||
name="item"
|
|
||||||
>
|
|
||||||
{{ item }}
|
|
||||||
</slot>
|
|
||||||
</li>
|
|
||||||
</slot>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts" generic="T">
|
|
||||||
defineOptions({
|
|
||||||
inheritAttrs: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
const { itemIs = 'li', offset = '[--offset:0]' } = defineProps<{
|
|
||||||
label?: string
|
|
||||||
items?: T[]
|
|
||||||
itemIs?: string
|
|
||||||
activatorClass?: string
|
|
||||||
offset?: string
|
|
||||||
read_only?: boolean
|
|
||||||
}>()
|
|
||||||
|
|
||||||
defineEmits<{ select: [T] }>()
|
|
||||||
|
|
||||||
const id = useId()
|
|
||||||
|
|
||||||
//const offset = '[--offset:30]'
|
|
||||||
</script>
|
|
||||||
@ -1,40 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiDropdown
|
<UDropdownMenu
|
||||||
:items="availableLocales"
|
arrow
|
||||||
class="btn btn-primary btn-outline"
|
:items
|
||||||
@select="(locale) => $emit('select', locale)"
|
:ui="{}"
|
||||||
>
|
>
|
||||||
<template #activator>
|
<UButton
|
||||||
<Icon :name="flags[locale]" />
|
:icon="items.find((item) => item.label === locale)?.icon"
|
||||||
<Icon
|
:label="locale"
|
||||||
name="tabler:chevron-down"
|
color="neutral"
|
||||||
class="dropdown-open:rotate-180 size-4"
|
variant="outline"
|
||||||
/>
|
/>
|
||||||
</template>
|
</UDropdownMenu>
|
||||||
|
|
||||||
<template #item="{ item }">
|
|
||||||
<div class="flex gap-2 justify-center">
|
|
||||||
<Icon
|
|
||||||
:name="flags[item]"
|
|
||||||
class="my-auto"
|
|
||||||
/>
|
|
||||||
<p>
|
|
||||||
{{ item }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</UiDropdown>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||||
import type { Locale } from 'vue-i18n'
|
import type { Locale } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { locales, locale } = useI18n()
|
||||||
|
|
||||||
const flags = {
|
const flags = {
|
||||||
de: 'emojione:flag-for-germany',
|
de: 'circle-flags:de',
|
||||||
en: 'emojione:flag-for-united-kingdom',
|
en: 'circle-flags:uk',
|
||||||
}
|
}
|
||||||
|
|
||||||
const { availableLocales, locale } = useI18n()
|
const emit = defineEmits<{ select: [Locale] }>()
|
||||||
|
|
||||||
defineEmits<{ select: [Locale] }>()
|
const items = computed<DropdownMenuItem[]>(() =>
|
||||||
|
locales.value.map((locale) => ({
|
||||||
|
label: locale.code,
|
||||||
|
icon: flags[locale.code],
|
||||||
|
onSelect() {
|
||||||
|
emit('select', locale.code)
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,22 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiDropdown :items="availableThemes" class="btn btn-primary btn-outline" @select="(theme) => $emit('select', theme)">
|
<UDropdownMenu :items>
|
||||||
<template #activator>
|
<UButton :icon="currentTheme?.icon" />
|
||||||
<Icon :name="currentTheme.icon" />
|
</UDropdownMenu>
|
||||||
</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>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||||
|
|
||||||
const { availableThemes, currentTheme } = storeToRefs(useUiStore())
|
const { availableThemes, currentTheme } = storeToRefs(useUiStore())
|
||||||
|
|
||||||
defineEmits<{ select: [ITheme] }>()
|
const emit = defineEmits<{ select: [string] }>()
|
||||||
|
|
||||||
|
watchImmediate(availableThemes, () =>
|
||||||
|
console.log('availableThemes', availableThemes),
|
||||||
|
)
|
||||||
|
|
||||||
|
const items = computed<DropdownMenuItem[]>(() =>
|
||||||
|
availableThemes?.value.map((theme) => ({
|
||||||
|
...theme,
|
||||||
|
onSelect: () => emit('select', theme.value),
|
||||||
|
})),
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
45
src/components/ui/dropdown/vault.vue
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<UDropdownMenu :items>
|
||||||
|
<UButton
|
||||||
|
icon="mdi:menu"
|
||||||
|
color="neutral"
|
||||||
|
variant="outline"
|
||||||
|
/>
|
||||||
|
</UDropdownMenu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { DropdownMenuItem } from '@nuxt/ui'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const { closeAsync } = useVaultStore()
|
||||||
|
|
||||||
|
const onVaultCloseAsync = async () => {
|
||||||
|
await closeAsync()
|
||||||
|
await navigateTo(useLocalePath()({ name: 'vaultOpen' }))
|
||||||
|
}
|
||||||
|
|
||||||
|
const items: DropdownMenuItem[] = [
|
||||||
|
{
|
||||||
|
icon: 'tabler:settings',
|
||||||
|
label: t('settings'),
|
||||||
|
to: useLocalePath()({ name: 'settings' }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'tabler:logout',
|
||||||
|
label: t('close'),
|
||||||
|
onSelect: () => onVaultCloseAsync(),
|
||||||
|
color: 'error',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<i18n lang="yaml">
|
||||||
|
de:
|
||||||
|
settings: 'Einstellungen'
|
||||||
|
close: 'Vault schließen'
|
||||||
|
|
||||||
|
en:
|
||||||
|
settings: 'Settings'
|
||||||
|
close: 'Close Vault'
|
||||||
|
</i18n>
|
||||||
@ -1,181 +1,88 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<UInput
|
||||||
<fieldset
|
v-model="value"
|
||||||
class="join w-full"
|
:placeholder="props.placeholder || ' '"
|
||||||
:class="{ 'pt-1.5': label }"
|
:readonly="props.readOnly"
|
||||||
v-bind="$attrs"
|
:leading-icon="props.leadingIcon"
|
||||||
|
:ui="{ base: 'peer' }"
|
||||||
|
@change="(e) => $emit('change', e)"
|
||||||
|
@blur="(e) => $emit('blur', e)"
|
||||||
|
@keyup="(e: KeyboardEvent) => $emit('keyup', e)"
|
||||||
|
@keydown="(e: KeyboardEvent) => $emit('keydown', e)"
|
||||||
>
|
>
|
||||||
<slot name="prepend" />
|
|
||||||
|
|
||||||
<div class="input join-item">
|
|
||||||
<Icon
|
|
||||||
v-if="prependIcon"
|
|
||||||
:name="prependIcon"
|
|
||||||
class="my-auto shrink-0"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="input-floating grow">
|
|
||||||
<input
|
|
||||||
:autofocus
|
|
||||||
:id
|
|
||||||
:name="name ?? id"
|
|
||||||
:placeholder="placeholder || label"
|
|
||||||
:readonly="read_only"
|
|
||||||
:type
|
|
||||||
class="ps-2"
|
|
||||||
ref="inputRef"
|
|
||||||
v-model="input"
|
|
||||||
@keyup="(e:KeyboardEvent) => $emit('keyup', e)"
|
|
||||||
/>
|
|
||||||
<label
|
<label
|
||||||
:for="id"
|
class="absolute pointer-events-none -top-2.5 left-0 text-highlighted text-xs font-medium px-1.5 transition-all peer-focus:-top-2.5 peer-focus:text-highlighted peer-focus:text-xs peer-focus:font-medium peer-placeholder-shown:text-sm peer-placeholder-shown:text-dimmed peer-placeholder-shown:top-1.5 peer-placeholder-shown:font-normal"
|
||||||
class="input-floating-label"
|
|
||||||
>
|
>
|
||||||
{{ label }}
|
<span
|
||||||
|
class="inline-flex bg-default px-1"
|
||||||
|
:class="props?.leadingIcon ? 'mx-6' : 'mx-0'"
|
||||||
|
>
|
||||||
|
{{ props?.label }}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
|
||||||
|
|
||||||
<Icon
|
<template #trailing>
|
||||||
v-if="appendIcon"
|
<slot name="trailing" />
|
||||||
:name="appendIcon"
|
|
||||||
class="my-auto shrink-0"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<UiButton
|
<UiButton
|
||||||
v-if="withClearButton"
|
v-show="props.withCopyButton"
|
||||||
class="btn-outline btn-square"
|
:color="copied ? 'success' : 'neutral'"
|
||||||
@click="input = ''"
|
|
||||||
>
|
|
||||||
<Icon name="mdi:close" />
|
|
||||||
</UiButton>
|
|
||||||
|
|
||||||
<slot name="append" />
|
|
||||||
|
|
||||||
<UiButton
|
|
||||||
v-if="withCopyButton"
|
|
||||||
:tooltip="t('copy')"
|
:tooltip="t('copy')"
|
||||||
class="btn-outline btn-accent btn-square"
|
:icon="copied ? 'mdi:check' : 'mdi:content-copy'"
|
||||||
@click="copy(`${input}`)"
|
size="sm"
|
||||||
>
|
variant="link"
|
||||||
<Icon :name="copied ? 'mdi:check' : 'mdi:content-copy'" />
|
@click="copy(`${value}`)"
|
||||||
</UiButton>
|
/>
|
||||||
</fieldset>
|
</template>
|
||||||
|
|
||||||
<span
|
<template
|
||||||
v-show="errors"
|
v-for="(_, slotName) in filteredSlots"
|
||||||
class="flex flex-col px-2 pt-0.5"
|
#[slotName]="slotProps"
|
||||||
>
|
>
|
||||||
<span
|
<slot
|
||||||
v-for="error in errors"
|
:name="slotName"
|
||||||
class="label-text-alt text-error"
|
v-bind="slotProps"
|
||||||
>
|
/>
|
||||||
{{ error }}
|
</template>
|
||||||
</span>
|
</UInput>
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ZodSchema } from 'zod'
|
import type { AcceptableValue, InputProps } from '@nuxt/ui'
|
||||||
|
|
||||||
const input = defineModel<string | number | undefined | null>({
|
const value = defineModel<AcceptableValue | undefined>()
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
const inputRef = useTemplateRef('inputRef')
|
interface IInputProps extends /* @vue-ignore */ InputProps {
|
||||||
defineExpose({ inputRef })
|
tooltip?: string
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
error: [string[]]
|
|
||||||
keyup: [KeyboardEvent]
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
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'
|
|
||||||
>,
|
|
||||||
default: 'text',
|
|
||||||
},
|
|
||||||
label: String,
|
|
||||||
name: String,
|
|
||||||
prependIcon: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
prependLabel: String,
|
|
||||||
appendIcon: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
appendLabel: String,
|
|
||||||
rules: Object as PropType<ZodSchema>,
|
|
||||||
checkInput: Boolean,
|
|
||||||
withCopyButton: Boolean,
|
|
||||||
withClearButton: Boolean,
|
|
||||||
autofocus: Boolean,
|
|
||||||
read_only: Boolean,
|
|
||||||
})
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (props.autofocus && inputRef.value) inputRef.value.focus()
|
|
||||||
})
|
|
||||||
|
|
||||||
const errors = defineModel<string[] | undefined>('errors')
|
|
||||||
|
|
||||||
const id = useId()
|
|
||||||
|
|
||||||
watch(input, () => checkInput())
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.checkInput,
|
|
||||||
() => {
|
|
||||||
checkInput()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
const checkInput = () => {
|
|
||||||
if (props.rules) {
|
|
||||||
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)
|
|
||||||
} else {
|
|
||||||
errors.value = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const props = defineProps<
|
||||||
|
IInputProps & {
|
||||||
|
withCopyButton?: boolean
|
||||||
|
readOnly?: boolean
|
||||||
|
label?: string
|
||||||
|
leadingIcon?: string
|
||||||
|
}
|
||||||
|
>()
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
change: [Event]
|
||||||
|
blur: [Event]
|
||||||
|
keyup: [KeyboardEvent]
|
||||||
|
keydown: [KeyboardEvent]
|
||||||
|
}>()
|
||||||
|
|
||||||
const { copy, copied } = useClipboard()
|
const { copy, copied } = useClipboard()
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const filteredSlots = computed(() => {
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(useSlots()).filter(([name]) => name !== 'trailing'),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
watchImmediate(props, () => console.log('props', props))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="yaml">
|
<i18n lang="yaml">
|
||||||
|
|||||||
@ -1,62 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiInput
|
<UiInput
|
||||||
v-model="value"
|
v-model="value"
|
||||||
:autofocus
|
:label="t('label')"
|
||||||
:check-input
|
:leading-icon
|
||||||
:label="label || t('password')"
|
:placeholder="placeholder || ' '"
|
||||||
:placeholder="placeholder || t('password')"
|
:read-only
|
||||||
:rules
|
:type="show ? 'text' : 'password'"
|
||||||
:type="type"
|
|
||||||
:with-copy-button
|
:with-copy-button
|
||||||
@keyup="(e) => $emit('keyup', e)"
|
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #trailing>
|
||||||
<slot name="append" />
|
|
||||||
|
|
||||||
<UiButton
|
<UiButton
|
||||||
class="btn-outline btn-accent btn-square join-item"
|
aria-controls="password"
|
||||||
@click="tooglePasswordType"
|
color="neutral"
|
||||||
>
|
variant="link"
|
||||||
<Icon :name="type === 'password' ? 'mdi:eye-off' : 'mdi:eye'" />
|
:aria-label="show ? t('hide') : t('show')"
|
||||||
</UiButton>
|
:aria-pressed="show"
|
||||||
|
:icon="show ? 'i-lucide-eye-off' : 'i-lucide-eye'"
|
||||||
|
:tooltip="show ? t('hide') : t('show')"
|
||||||
|
size="sm"
|
||||||
|
@click="show = !show"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</UiInput>
|
</UiInput>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ZodSchema } from 'zod'
|
import type { AcceptableValue } from '@nuxt/ui'
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const value = defineModel<string | number | null | undefined>()
|
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
autofocus?: boolean
|
|
||||||
checkInput?: boolean
|
|
||||||
label?: string
|
label?: string
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
rules?: ZodSchema
|
leadingIcon?: string
|
||||||
withCopyButton?: boolean
|
withCopyButton?: boolean
|
||||||
|
readOnly?: boolean
|
||||||
}>()
|
}>()
|
||||||
|
const value = defineModel<AcceptableValue | undefined>()
|
||||||
|
|
||||||
defineEmits<{
|
const show = ref(false)
|
||||||
keyup: [KeyboardEvent]
|
const { t } = useI18n()
|
||||||
}>()
|
|
||||||
|
|
||||||
const type = ref<'password' | 'text'>('password')
|
|
||||||
|
|
||||||
const tooglePasswordType = () => {
|
|
||||||
type.value = type.value === 'password' ? 'text' : 'password'
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="json">
|
<i18n lang="yaml">
|
||||||
{
|
de:
|
||||||
"de": {
|
show: Passwort ansehen
|
||||||
"password": "Passwort"
|
hide: Passwort verstecken
|
||||||
},
|
label: Passwort
|
||||||
"en": {
|
|
||||||
"password": "Password"
|
en:
|
||||||
}
|
show: Show password
|
||||||
}
|
hide: Hide password
|
||||||
|
label: Password
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiInput
|
<UiInput
|
||||||
|
v-model.trim="value"
|
||||||
:autofocus
|
:autofocus
|
||||||
:check-input="checkInput"
|
:check-input="checkInput"
|
||||||
:label="label || t('url')"
|
:label="label || t('url')"
|
||||||
@ -7,17 +8,18 @@
|
|||||||
:read_only
|
:read_only
|
||||||
:rules
|
:rules
|
||||||
:with-copy-button
|
:with-copy-button
|
||||||
v-model.trim="value"
|
|
||||||
@keyup="(e) => $emit('keyup', e)"
|
@keyup="(e) => $emit('keyup', e)"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #trailing>
|
||||||
<UiButton
|
<UiButton
|
||||||
|
color="neutral"
|
||||||
|
variant="link"
|
||||||
|
size="sm"
|
||||||
|
icon="streamline:web"
|
||||||
:disabled="!value?.length"
|
:disabled="!value?.length"
|
||||||
|
:tooltip="t('browse')"
|
||||||
@click="openUrl(`${value}`)"
|
@click="openUrl(`${value}`)"
|
||||||
class="btn-outline btn-accent btn-square"
|
/>
|
||||||
>
|
|
||||||
<Icon name="streamline:web" />
|
|
||||||
</UiButton>
|
|
||||||
</template>
|
</template>
|
||||||
</UiInput>
|
</UiInput>
|
||||||
</template>
|
</template>
|
||||||
@ -45,13 +47,12 @@ defineEmits<{
|
|||||||
}>()
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i18n lang="json">
|
<i18n lang="yaml">
|
||||||
{
|
de:
|
||||||
"de": {
|
url: Url
|
||||||
"url": "Url"
|
browse: Url öffnen
|
||||||
},
|
|
||||||
"en": {
|
en:
|
||||||
"url": "Url"
|
url: Url
|
||||||
}
|
browse: Open url
|
||||||
}
|
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col h-fit border border-base-content/25 divide-base-content/25 divide-y rounded-md first:rounded-t-md last:rounded-b-md"
|
class="flex flex-col h-fit border border-default/25 divide-default/25 divide-y rounded-md first:rounded-t-md last:rounded-b-md"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
<svg
|
<svg
|
||||||
viewBox="122 107 263 292"
|
viewBox="122 107 263 292"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
style="max-height: 500px"
|
|
||||||
>
|
>
|
||||||
<g
|
<g
|
||||||
stroke-width="0.3"
|
stroke-width="0.3"
|
||||||
|
|||||||
@ -10,24 +10,23 @@
|
|||||||
|
|
||||||
<input
|
<input
|
||||||
:id
|
:id
|
||||||
:readonly="read_only"
|
ref="colorRef"
|
||||||
:disabled="read_only"
|
v-model="model"
|
||||||
|
:readonly="readOnly"
|
||||||
|
:disabled="readOnly"
|
||||||
:title="t('pick')"
|
:title="t('pick')"
|
||||||
class="top-0 left-0 absolute size-0"
|
class="top-0 left-0 absolute size-0"
|
||||||
type="color"
|
type="color"
|
||||||
v-model="model"
|
|
||||||
ref="colorRef"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UiTooltip :tooltip="t('reset')">
|
<UiTooltip :tooltip="t('reset')">
|
||||||
<button
|
<UiButton
|
||||||
|
color="error"
|
||||||
|
:class="{ 'btn-disabled': readOnly }"
|
||||||
|
icon="mdi:refresh"
|
||||||
|
:disabled="readOnly"
|
||||||
@click="model = ''"
|
@click="model = ''"
|
||||||
class="btn btn-sm text-sm btn-outline btn-error"
|
/>
|
||||||
:class="{ 'btn-disabled': read_only }"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<Icon name="mdi:refresh" />
|
|
||||||
</button>
|
|
||||||
</UiTooltip>
|
</UiTooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -39,12 +38,12 @@ const { t } = useI18n()
|
|||||||
const model = defineModel<string | null>()
|
const model = defineModel<string | null>()
|
||||||
const colorRef = useTemplateRef('colorRef')
|
const colorRef = useTemplateRef('colorRef')
|
||||||
defineProps({
|
defineProps({
|
||||||
read_only: Boolean,
|
readOnly: Boolean,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { currentTheme } = storeToRefs(useUiStore())
|
const { currentTheme } = storeToRefs(useUiStore())
|
||||||
const textColorClass = computed(() => {
|
const textColorClass = computed(() => {
|
||||||
if (!model.value)
|
if (!model.value && currentTheme.value)
|
||||||
return currentTheme.value.value === 'dark' ? 'text-black' : 'text-white'
|
return currentTheme.value.value === 'dark' ? 'text-black' : 'text-white'
|
||||||
|
|
||||||
const color = getContrastingTextColor(model.value)
|
const color = getContrastingTextColor(model.value)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<UiDropdown
|
<UDropdownMenu
|
||||||
:items="icons"
|
:items="icons"
|
||||||
class="btn"
|
class="btn"
|
||||||
@select="(newIcon) => (iconName = newIcon)"
|
@select="(newIcon) => (iconName = newIcon)"
|
||||||
@ -23,7 +23,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</UiDropdown>
|
</UDropdownMenu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
60
src/components/ui/sidebar/link.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<li
|
||||||
|
class="rounded hover:bg-elevated py-2 cursor-pointer"
|
||||||
|
:class="{
|
||||||
|
['bg-base-content/20 ']: isActive,
|
||||||
|
}"
|
||||||
|
@click="triggerNavigate"
|
||||||
|
>
|
||||||
|
<UTooltip :tooltip="tooltip ?? name">
|
||||||
|
<NuxtLinkLocale
|
||||||
|
ref="linkRef"
|
||||||
|
:to
|
||||||
|
class="flex items-center justify-center cursor-pointer tooltip-toogle"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="iconType === 'svg'"
|
||||||
|
class="shrink-0 size-5"
|
||||||
|
v-html="icon"
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
v-else
|
||||||
|
:name="icon"
|
||||||
|
size="1.5em"
|
||||||
|
/>
|
||||||
|
</NuxtLinkLocale>
|
||||||
|
</UTooltip>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { ISidebarItem } from '#imports'
|
||||||
|
|
||||||
|
const props = defineProps<ISidebarItem>()
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
console.log('to', props.to)
|
||||||
|
const isActive = computed(() => {
|
||||||
|
if (props.to?.name === 'haexExtension') {
|
||||||
|
return (
|
||||||
|
getSingleRouteParam(router.currentRoute.value.params.extensionId) ===
|
||||||
|
props.id
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
props.to?.name === router.currentRoute.value.meta.name ||
|
||||||
|
router
|
||||||
|
.getRoutes()
|
||||||
|
.find((route) => route.meta.name === props.to?.name)
|
||||||
|
?.children.some(
|
||||||
|
(route) => route.meta?.name === router.currentRoute.value.meta.name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const linkRef = useTemplateRef('linkRef')
|
||||||
|
|
||||||
|
const triggerNavigate = () => linkRef.value?.$el.click()
|
||||||
|
</script>
|
||||||
@ -1,7 +0,0 @@
|
|||||||
<template>
|
|
||||||
<input v-model="value" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
const value = defineModel()
|
|
||||||
</script>
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<p
|
<p
|
||||||
class="bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent font-black"
|
class="bg-gradient-to-r from-primary to-secondary bg-clip-text text-transparent font-black"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@ -1,41 +1,54 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative">
|
<div>
|
||||||
<UiButton
|
<UTextarea
|
||||||
v-if="withCopyButton"
|
|
||||||
:tooltip="t('copy')"
|
|
||||||
class="btn-square btn-outline btn-accent absolute z-10 top-2 right-2"
|
|
||||||
@click="copy(`${value}`)"
|
|
||||||
>
|
|
||||||
<Icon :name="copied ? 'mdi:check' : 'mdi:content-copy'" />
|
|
||||||
</UiButton>
|
|
||||||
|
|
||||||
<div class="textarea-floating">
|
|
||||||
<textarea
|
|
||||||
:class="{ 'pr-10': withCopyButton }"
|
|
||||||
:id
|
:id
|
||||||
:placeholder
|
|
||||||
:readonly="read_only"
|
|
||||||
class="textarea"
|
|
||||||
v-bind="$attrs"
|
|
||||||
v-model="value"
|
v-model="value"
|
||||||
></textarea>
|
:ui="{ base: 'peer' }"
|
||||||
<label
|
:readonly="readOnly"
|
||||||
class="textarea-floating-label"
|
class="w-full"
|
||||||
:for="id"
|
v-bind="$attrs"
|
||||||
>
|
>
|
||||||
{{ label }}
|
<label
|
||||||
|
class="absolute pointer-events-none -top-2.5 left-0 text-highlighted text-xs font-medium px-1.5 transition-all peer-focus:-top-2.5 peer-focus:text-highlighted peer-focus:text-xs peer-focus:font-medium peer-placeholder-shown:text-sm peer-placeholder-shown:text-dimmed peer-placeholder-shown:top-1.5 peer-placeholder-shown:font-normal"
|
||||||
|
>
|
||||||
|
<span class="inline-flex bg-default px-1">
|
||||||
|
{{ props.label }}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
|
||||||
|
<template #trailing>
|
||||||
|
<UiButton
|
||||||
|
v-show="withCopyButton"
|
||||||
|
:color="copied ? 'success' : 'neutral'"
|
||||||
|
:tooltip="t('copy')"
|
||||||
|
:icon="copied ? 'mdi:check' : 'mdi:content-copy'"
|
||||||
|
size="sm"
|
||||||
|
variant="link"
|
||||||
|
@click="copy(`${value}`)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</UTextarea>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps<{
|
import type { TextareaProps } from '@nuxt/ui'
|
||||||
|
|
||||||
|
interface ITextareaProps extends /* @vue-ignore */ TextareaProps {
|
||||||
|
tooltip?: string
|
||||||
|
withCopyButton?: boolean
|
||||||
|
readOnly?: boolean
|
||||||
|
label?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<ITextareaProps>()
|
||||||
|
|
||||||
|
/* defineProps<{
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
label?: string
|
label?: string
|
||||||
read_only?: boolean
|
readOnly?: boolean
|
||||||
withCopyButton?: boolean
|
withCopyButton?: boolean
|
||||||
}>()
|
}>() */
|
||||||
|
|
||||||
const id = useId()
|
const id = useId()
|
||||||
|
|
||||||
|
|||||||
@ -1,57 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="tooltip [--prevent-popper:false]">
|
|
||||||
<div
|
|
||||||
class="tooltip-toggle"
|
|
||||||
:aria-label="tooltip"
|
|
||||||
>
|
|
||||||
<slot>
|
|
||||||
<button class="btn btn-square">
|
|
||||||
<Icon name="mdi:chevron-up-box-outline" />
|
|
||||||
</button>
|
|
||||||
</slot>
|
|
||||||
|
|
||||||
<span
|
|
||||||
class="tooltip-content tooltip-shown:opacity-100 tooltip-shown:visible pointer-events-none z-50"
|
|
||||||
role="tooltip"
|
|
||||||
>
|
|
||||||
<span class="tooltip-body">
|
|
||||||
{{ tooltip }}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import type { PropType } from 'vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
direction: {
|
|
||||||
type: String as PropType<
|
|
||||||
| 'top'
|
|
||||||
| 'top-start'
|
|
||||||
| 'top-end'
|
|
||||||
| 'bottom'
|
|
||||||
| 'bottom-start'
|
|
||||||
| 'bottom-end'
|
|
||||||
| 'right'
|
|
||||||
| 'right-start'
|
|
||||||
| 'right-end'
|
|
||||||
| 'left'
|
|
||||||
| 'left-start'
|
|
||||||
| 'left-end'
|
|
||||||
>,
|
|
||||||
default: 'top',
|
|
||||||
},
|
|
||||||
|
|
||||||
tooltip: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
|
|
||||||
trigger: {
|
|
||||||
type: String as PropType<'focus' | 'hover' | 'click'>,
|
|
||||||
default: 'hover',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
class="tree-view-selected:bg-base-200/60 dragged:bg-primary/20 dragged:rounded nested-4 cursor-pointer rounded-md px-2"
|
|
||||||
role="treeitem" :data-tree-view-item="JSON.stringify({
|
|
||||||
value,
|
|
||||||
isDir: false,
|
|
||||||
})
|
|
||||||
">
|
|
||||||
<div class="flex items-center gap-x-3">
|
|
||||||
<span class="icon-[tabler--file] text-base-content size-4 flex-shrink-0"/>
|
|
||||||
<div class="grow">
|
|
||||||
<span class="text-base-content">{{ value }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
defineProps({
|
|
||||||
value: String,
|
|
||||||
});
|
|
||||||
|
|
||||||
const id = useId();
|
|
||||||
const controlId = useId();
|
|
||||||
const isActive = ref(false);
|
|
||||||
</script>
|
|
||||||
@ -1,204 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :id ref="folderRef" data-nested-draggable="" :value class="">
|
|
||||||
<div
|
|
||||||
isDir :data-tree-view-item="JSON.stringify({ value })"
|
|
||||||
class="accordion-item active motion-preset-slide-left motion-ease-spring-bouncier" :class="{
|
|
||||||
'selected': isActive?.value,
|
|
||||||
'text-base-content': !color,
|
|
||||||
}" role="treeitem" :style="{ color: color || '' }">
|
|
||||||
<div
|
|
||||||
class="accordion-heading tree-view-selected:bg-primary/80 flex items-center gap-x-0.5 rounded-md hover:bg-primary/20 group">
|
|
||||||
<button class="accordion-toggle btn btn-sm btn-circle btn-text shrink-0" :aria-controls="controlId">
|
|
||||||
<Icon name="tabler:plus" class="accordion-item-active:rotate-45 size-4 transition-all duration-300" />
|
|
||||||
</button>
|
|
||||||
<button class="cursor-pointer rounded-md px-1.5 w-full" @click.stop="$emit('click', value)">
|
|
||||||
<div class="flex items-center gap-x-3">
|
|
||||||
<Icon v-if="icon" :name="icon || 'mdi:folder-outline'" class="shrink-0" />
|
|
||||||
|
|
||||||
<div class="flex whitespace-nowrap">
|
|
||||||
{{ value }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="sticky right-2 btn btn-sm btn-circle btn-text shrink-0 group-hover:flex hidden ml-auto"
|
|
||||||
@click.stop="$emit('edit', value)">
|
|
||||||
<Icon name="mdi:pencil-outline" class="size-4 transition-all duration-300" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
:id="controlId" class="accordion-content w-full transition-[height] duration-300" role="group"
|
|
||||||
:aria-labelledby="id">
|
|
||||||
<div ref="childRef" class="tree-view-space min-h-1" data-nested-draggable="">
|
|
||||||
<slot>
|
|
||||||
<template
|
|
||||||
v-for="(item, index) in children?.sort(
|
|
||||||
(a, b) => a.order ?? 0 - (b.order ?? 0)
|
|
||||||
)" :key="item.id!" :data-tree-view-item="JSON.stringify({ value: item.value })">
|
|
||||||
<UiTreeFolder
|
|
||||||
v-if="item.type === 'folder'" :icon="item.icon || 'tabler:folder'"
|
|
||||||
v-bind="item" @click="(value) => $emit('click', value)" @edit="(value) => $emit('edit', value)" />
|
|
||||||
|
|
||||||
<UiTreeFile v-if="item.type === 'file'" v-bind="item" />
|
|
||||||
</template>
|
|
||||||
</slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { HSAccordion } from 'flyonui/flyonui';
|
|
||||||
import Sortable from 'sortablejs';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
value: String,
|
|
||||||
icon: {
|
|
||||||
type: [String, null],
|
|
||||||
default: 'tabler:folder',
|
|
||||||
},
|
|
||||||
children: {
|
|
||||||
type: Array as PropType<ITreeItem[] | null>,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
name: String,
|
|
||||||
color: [String, null],
|
|
||||||
isActive: Object as PropType<ComputedRef<boolean>>,
|
|
||||||
});
|
|
||||||
|
|
||||||
const id = useId();
|
|
||||||
const controlId = useId();
|
|
||||||
const folderRef = ref<HTMLElement>();
|
|
||||||
const childRef = ref<HTMLElement>();
|
|
||||||
|
|
||||||
defineEmits<{
|
|
||||||
click: [value: string | undefined];
|
|
||||||
edit: [value: string | undefined];
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const { groups } = storeToRefs(useVaultGroupStore());
|
|
||||||
const sorty = ref([]);
|
|
||||||
onMounted(() => {
|
|
||||||
if (folderRef.value && childRef.value)
|
|
||||||
[folderRef.value, childRef.value].forEach((element) => {
|
|
||||||
const create = Sortable.create(element, {
|
|
||||||
animation: 150,
|
|
||||||
ghostClass: 'bg-opacity-20',
|
|
||||||
group: 'vault',
|
|
||||||
swapThreshold: 0.65,
|
|
||||||
fallbackOnBody: true,
|
|
||||||
fallbackTolerance: 3,
|
|
||||||
|
|
||||||
onEnd: (evt) => {
|
|
||||||
const { item } = evt;
|
|
||||||
|
|
||||||
/* if (item.classList.contains('accordion')) {
|
|
||||||
let existingInstance = HSAccordion.getInstance(item, true);
|
|
||||||
let updatedInstance;
|
|
||||||
|
|
||||||
existingInstance.element.update();
|
|
||||||
updatedInstance = HSAccordion.getInstance(item, true);
|
|
||||||
window.$hsAccordionCollection.map((el) => {
|
|
||||||
if (
|
|
||||||
el.element.el !== existingInstance.element.el &&
|
|
||||||
el.element.group === existingInstance.element.group &&
|
|
||||||
el.element.el.closest('.accordion') &&
|
|
||||||
el.element.el.classList.contains('active') &&
|
|
||||||
existingInstance.element.el.classList.contains('active')
|
|
||||||
)
|
|
||||||
el.element.hide();
|
|
||||||
|
|
||||||
return el;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!!item.hasAttribute('data-tree-view-item')) {
|
|
||||||
const treeViewItem = HSTreeView.getInstance(
|
|
||||||
item.closest('[data-tree-view]'),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
treeViewItem.element.update();
|
|
||||||
} */
|
|
||||||
},
|
|
||||||
onUpdate: (evt) => {
|
|
||||||
console.log('update', evt.item, props.value, sorty.value);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
/* const sortable = new Sortable(element, {
|
|
||||||
animation: 150,
|
|
||||||
ghostClass: 'bg-opacity-20',
|
|
||||||
group: 'vault',
|
|
||||||
swapThreshold: 0.65,
|
|
||||||
fallbackOnBody: true,
|
|
||||||
fallbackTolerance: 3,
|
|
||||||
|
|
||||||
onEnd: (evt) => {
|
|
||||||
console.log(
|
|
||||||
'end',
|
|
||||||
evt.item,
|
|
||||||
props.value,
|
|
||||||
sorty.value.at(0).toArray(),
|
|
||||||
sorty.value.at(1).toArray()
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onUpdate: (evt) => {
|
|
||||||
console.log('update', evt.item, props.value, sorty.value);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
sorty.value.push(sortable); */
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
const draggable = document.querySelectorAll('[data-nested-draggable]');
|
|
||||||
|
|
||||||
draggable.forEach((el) => {
|
|
||||||
const options = {
|
|
||||||
group: 'nested',
|
|
||||||
animation: 150,
|
|
||||||
fallbackOnBody: true,
|
|
||||||
swapThreshold: 0.65,
|
|
||||||
ghostClass: 'dragged',
|
|
||||||
onEnd: (evt) => {
|
|
||||||
const { item, items } = evt;
|
|
||||||
console.log('standard', item, evt);
|
|
||||||
if (item.classList.contains('accordion')) {
|
|
||||||
const existingInstance = HSAccordion.getInstance(item, true);
|
|
||||||
let updatedInstance;
|
|
||||||
|
|
||||||
existingInstance.element.update();
|
|
||||||
updatedInstance = HSAccordion.getInstance(item, true);
|
|
||||||
window.$hsAccordionCollection.map((el) => {
|
|
||||||
if (
|
|
||||||
el.element.el !== existingInstance.element.el &&
|
|
||||||
el.element.group === existingInstance.element.group &&
|
|
||||||
el.element.el.closest('.accordion') &&
|
|
||||||
el.element.el.classList.contains('active') &&
|
|
||||||
existingInstance.element.el.classList.contains('active')
|
|
||||||
)
|
|
||||||
el.element.hide();
|
|
||||||
|
|
||||||
return el;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.hasAttribute('data-tree-view-item')) {
|
|
||||||
const treeViewItem = HSTreeView.getInstance(
|
|
||||||
item.closest('[data-tree-view]'),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
treeViewItem.element.update();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const data = el.getAttribute('data-nested-draggable');
|
|
||||||
const dataOptions = data ? JSON.parse(data) : {};
|
|
||||||
const sortable = new Sortable(el, options);
|
|
||||||
console.log('stand', sortable.toArray());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div data-tree-view role="tree" aria-orientation="vertical" class="rounded min-w-fit w-full">
|
|
||||||
<slot/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||