diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..43242d6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +resolver = "2" +members = ["lamassu-next/apps/machine/src-tauri"] diff --git a/lamassu-next/Cargo.toml b/lamassu-next/Cargo.toml new file mode 100644 index 0000000..584dc59 --- /dev/null +++ b/lamassu-next/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +resolver = "2" +members = ["apps/machine/src-tauri"] diff --git a/lamassu-next/apps/machine/components.json b/lamassu-next/apps/machine/components.json new file mode 100644 index 0000000..09b9b8c --- /dev/null +++ b/lamassu-next/apps/machine/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://shadcn-vue.com/schema.json", + "style": "new-york", + "typescript": true, + "tailwind": { + "config": "", + "css": "src/style.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "composables": "@/composables" + }, + "registries": {} +} diff --git a/lamassu-next/apps/machine/index.html b/lamassu-next/apps/machine/index.html new file mode 100644 index 0000000..9d92055 --- /dev/null +++ b/lamassu-next/apps/machine/index.html @@ -0,0 +1,27 @@ + + + + + + + Lamassu ATM + + + +
+ + + diff --git a/lamassu-next/apps/machine/package.json b/lamassu-next/apps/machine/package.json new file mode 100644 index 0000000..f56d5cb --- /dev/null +++ b/lamassu-next/apps/machine/package.json @@ -0,0 +1,43 @@ +{ + "name": "@lamassu/machine", + "version": "0.1.0", + "description": "Tauri 2.x ATM kiosk application with Vue 3 UI", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vue-tsc --noEmit && vite build", + "preview": "vite preview", + "tauri": "tauri", + "tauri:dev": "tauri dev", + "tauri:build": "tauri build", + "typecheck": "vue-tsc --noEmit", + "lint": "eslint src/" + }, + "dependencies": { + "@lamassu/clink": "workspace:*", + "@lamassu/lightning": "workspace:*", + "@lamassu/nostr-client": "workspace:*", + "@lamassu/state-machine": "workspace:*", + "@vueuse/core": "^14.1.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-vue-next": "^0.563.0", + "pinia": "^2.2.0", + "reka-ui": "^2.7.0", + "tailwind-merge": "^3.4.0", + "vue": "^3.5.0", + "vue-router": "^4.4.0" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.0.0", + "@tauri-apps/api": "^2.1.0", + "@tauri-apps/cli": "^2.1.0", + "@types/node": "^22.0.0", + "@vitejs/plugin-vue": "^5.2.0", + "tailwindcss": "^4.0.0", + "tw-animate-css": "^1.4.0", + "typescript": "^5.7.0", + "vite": "^6.0.0", + "vue-tsc": "^2.1.0" + } +} diff --git a/lamassu-next/apps/machine/src-tauri/Cargo.toml b/lamassu-next/apps/machine/src-tauri/Cargo.toml new file mode 100644 index 0000000..fd55b19 --- /dev/null +++ b/lamassu-next/apps/machine/src-tauri/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "lamassu-machine" +version = "0.1.0" +description = "Lamassu ATM Kiosk Application" +authors = ["Lamassu Industries"] +edition = "2021" +rust-version = "1.70" + +[lib] +name = "lamassu_machine_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +tauri = { version = "2", features = [] } +tauri-plugin-shell = "2" +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +[features] +# This feature is used for production builds or when a dev server is not specified +custom-protocol = ["tauri/custom-protocol"] diff --git a/lamassu-next/apps/machine/src-tauri/build.rs b/lamassu-next/apps/machine/src-tauri/build.rs new file mode 100644 index 0000000..d860e1e --- /dev/null +++ b/lamassu-next/apps/machine/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/lamassu-next/apps/machine/src-tauri/src/lib.rs b/lamassu-next/apps/machine/src-tauri/src/lib.rs new file mode 100644 index 0000000..467b260 --- /dev/null +++ b/lamassu-next/apps/machine/src-tauri/src/lib.rs @@ -0,0 +1,35 @@ +//! Lamassu ATM Tauri Application +//! +//! This is the Rust backend for the Lamassu ATM kiosk application. +//! Hardware drivers and native functionality will be implemented here. + +use tauri::Manager; + +/// Greet command for testing Tauri IPC +#[tauri::command] +fn greet(name: &str) -> String { + format!("Hello, {}! Welcome to Lamassu ATM.", name) +} + +/// Get application version +#[tauri::command] +fn get_version() -> String { + env!("CARGO_PKG_VERSION").to_string() +} + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_shell::init()) + .setup(|app| { + #[cfg(debug_assertions)] + { + let window = app.get_webview_window("main").unwrap(); + window.open_devtools(); + } + Ok(()) + }) + .invoke_handler(tauri::generate_handler![greet, get_version]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/lamassu-next/apps/machine/src-tauri/src/main.rs b/lamassu-next/apps/machine/src-tauri/src/main.rs new file mode 100644 index 0000000..d5fb610 --- /dev/null +++ b/lamassu-next/apps/machine/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + lamassu_machine_lib::run() +} diff --git a/lamassu-next/apps/machine/src-tauri/tauri.conf.json b/lamassu-next/apps/machine/src-tauri/tauri.conf.json new file mode 100644 index 0000000..15d6461 --- /dev/null +++ b/lamassu-next/apps/machine/src-tauri/tauri.conf.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "productName": "Lamassu ATM", + "version": "0.1.0", + "identifier": "io.lamassu.atm", + "build": { + "beforeDevCommand": "pnpm dev", + "devUrl": "http://localhost:1420", + "beforeBuildCommand": "pnpm build", + "frontendDist": "../dist" + }, + "app": { + "withGlobalTauri": true, + "windows": [ + { + "title": "Lamassu ATM", + "width": 1080, + "height": 1920, + "resizable": false, + "fullscreen": false, + "decorations": true + } + ], + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + } +} diff --git a/lamassu-next/apps/machine/src/App.vue b/lamassu-next/apps/machine/src/App.vue new file mode 100644 index 0000000..7616400 --- /dev/null +++ b/lamassu-next/apps/machine/src/App.vue @@ -0,0 +1,28 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/alert/Alert.vue b/lamassu-next/apps/machine/src/components/ui/alert/Alert.vue new file mode 100644 index 0000000..4726d7a --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/alert/Alert.vue @@ -0,0 +1,17 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/alert/AlertDescription.vue b/lamassu-next/apps/machine/src/components/ui/alert/AlertDescription.vue new file mode 100644 index 0000000..4b41cf6 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/alert/AlertDescription.vue @@ -0,0 +1,22 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/alert/AlertTitle.vue b/lamassu-next/apps/machine/src/components/ui/alert/AlertTitle.vue new file mode 100644 index 0000000..91a9299 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/alert/AlertTitle.vue @@ -0,0 +1,17 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/alert/index.ts b/lamassu-next/apps/machine/src/components/ui/alert/index.ts new file mode 100644 index 0000000..08c2772 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/alert/index.ts @@ -0,0 +1,24 @@ +import type { VariantProps } from 'class-variance-authority' +import { cva } from 'class-variance-authority' + +export { default as Alert } from './Alert.vue' +export { default as AlertDescription } from './AlertDescription.vue' +export { default as AlertTitle } from './AlertTitle.vue' + +export const alertVariants = cva( + 'relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current', + { + variants: { + variant: { + default: 'bg-card text-card-foreground', + destructive: + 'text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90', + }, + }, + defaultVariants: { + variant: 'default', + }, + } +) + +export type AlertVariants = VariantProps diff --git a/lamassu-next/apps/machine/src/components/ui/badge/Badge.vue b/lamassu-next/apps/machine/src/components/ui/badge/Badge.vue new file mode 100644 index 0000000..3ba2fb7 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/badge/Badge.vue @@ -0,0 +1,28 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/badge/index.ts b/lamassu-next/apps/machine/src/components/ui/badge/index.ts new file mode 100644 index 0000000..661ab05 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/badge/index.ts @@ -0,0 +1,24 @@ +import type { VariantProps } from 'class-variance-authority' +import { cva } from 'class-variance-authority' + +export { default as Badge } from './Badge.vue' + +export const badgeVariants = cva( + 'inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden', + { + variants: { + variant: { + default: 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90', + secondary: + 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90', + destructive: + 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', + outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground', + }, + }, + defaultVariants: { + variant: 'default', + }, + } +) +export type BadgeVariants = VariantProps diff --git a/lamassu-next/apps/machine/src/components/ui/button/Button.vue b/lamassu-next/apps/machine/src/components/ui/button/Button.vue new file mode 100644 index 0000000..47a80b6 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/button/Button.vue @@ -0,0 +1,29 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/button/index.ts b/lamassu-next/apps/machine/src/components/ui/button/index.ts new file mode 100644 index 0000000..4c4bd6f --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/button/index.ts @@ -0,0 +1,35 @@ +import type { VariantProps } from 'class-variance-authority' +import { cva } from 'class-variance-authority' + +export { default as Button } from './Button.vue' + +export const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: + 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', + outline: + 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50', + secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-9 px-4 py-2 has-[>svg]:px-3', + sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5', + lg: 'h-10 rounded-md px-6 has-[>svg]:px-4', + icon: 'size-9', + 'icon-sm': 'size-8', + 'icon-lg': 'size-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + } +) +export type ButtonVariants = VariantProps diff --git a/lamassu-next/apps/machine/src/components/ui/card/Card.vue b/lamassu-next/apps/machine/src/components/ui/card/Card.vue new file mode 100644 index 0000000..42bd9b1 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/card/Card.vue @@ -0,0 +1,22 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/card/CardAction.vue b/lamassu-next/apps/machine/src/components/ui/card/CardAction.vue new file mode 100644 index 0000000..c2beb20 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/card/CardAction.vue @@ -0,0 +1,17 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/card/CardContent.vue b/lamassu-next/apps/machine/src/components/ui/card/CardContent.vue new file mode 100644 index 0000000..6039a5e --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/card/CardContent.vue @@ -0,0 +1,14 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/card/CardDescription.vue b/lamassu-next/apps/machine/src/components/ui/card/CardDescription.vue new file mode 100644 index 0000000..d74841b --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/card/CardDescription.vue @@ -0,0 +1,14 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/card/CardFooter.vue b/lamassu-next/apps/machine/src/components/ui/card/CardFooter.vue new file mode 100644 index 0000000..922f683 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/card/CardFooter.vue @@ -0,0 +1,14 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/card/CardHeader.vue b/lamassu-next/apps/machine/src/components/ui/card/CardHeader.vue new file mode 100644 index 0000000..00e34e7 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/card/CardHeader.vue @@ -0,0 +1,22 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/card/CardTitle.vue b/lamassu-next/apps/machine/src/components/ui/card/CardTitle.vue new file mode 100644 index 0000000..a9e4a45 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/card/CardTitle.vue @@ -0,0 +1,14 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/card/index.ts b/lamassu-next/apps/machine/src/components/ui/card/index.ts new file mode 100644 index 0000000..73d985f --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/card/index.ts @@ -0,0 +1,7 @@ +export { default as Card } from './Card.vue' +export { default as CardAction } from './CardAction.vue' +export { default as CardContent } from './CardContent.vue' +export { default as CardDescription } from './CardDescription.vue' +export { default as CardFooter } from './CardFooter.vue' +export { default as CardHeader } from './CardHeader.vue' +export { default as CardTitle } from './CardTitle.vue' diff --git a/lamassu-next/apps/machine/src/components/ui/skeleton/Skeleton.vue b/lamassu-next/apps/machine/src/components/ui/skeleton/Skeleton.vue new file mode 100644 index 0000000..50f3448 --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/skeleton/Skeleton.vue @@ -0,0 +1,14 @@ + + + diff --git a/lamassu-next/apps/machine/src/components/ui/skeleton/index.ts b/lamassu-next/apps/machine/src/components/ui/skeleton/index.ts new file mode 100644 index 0000000..be21fad --- /dev/null +++ b/lamassu-next/apps/machine/src/components/ui/skeleton/index.ts @@ -0,0 +1 @@ +export { default as Skeleton } from './Skeleton.vue' diff --git a/lamassu-next/apps/machine/src/lib/utils.ts b/lamassu-next/apps/machine/src/lib/utils.ts new file mode 100644 index 0000000..abba253 --- /dev/null +++ b/lamassu-next/apps/machine/src/lib/utils.ts @@ -0,0 +1,7 @@ +import type { ClassValue } from 'clsx' +import { clsx } from 'clsx' +import { twMerge } from 'tailwind-merge' + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/lamassu-next/apps/machine/src/main.ts b/lamassu-next/apps/machine/src/main.ts new file mode 100644 index 0000000..c643306 --- /dev/null +++ b/lamassu-next/apps/machine/src/main.ts @@ -0,0 +1,29 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import { createRouter, createWebHistory } from 'vue-router' +import App from './App.vue' +import './style.css' + +// Import views +import IdleView from './views/IdleView.vue' +import CashOutView from './views/CashOutView.vue' +import CashInView from './views/CashInView.vue' + +// Create router +const router = createRouter({ + history: createWebHistory(), + routes: [ + { path: '/', name: 'idle', component: IdleView }, + { path: '/cash-out', name: 'cash-out', component: CashOutView }, + { path: '/cash-in', name: 'cash-in', component: CashInView }, + ], +}) + +// Create Pinia store +const pinia = createPinia() + +// Create and mount app +const app = createApp(App) +app.use(pinia) +app.use(router) +app.mount('#app') diff --git a/lamassu-next/apps/machine/src/stores/atm.ts b/lamassu-next/apps/machine/src/stores/atm.ts new file mode 100644 index 0000000..652026b --- /dev/null +++ b/lamassu-next/apps/machine/src/stores/atm.ts @@ -0,0 +1,180 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import { + createATMMachine, + createActor, + type ATMContext, + type ATMServices, +} from '@lamassu/state-machine' +import type { Actor, SnapshotFrom } from 'xstate' + +// Service implementations will be injected +// For now, use mock implementations for development +const mockServices: ATMServices = { + generateClinkOffer: async (context) => { + console.log('[Mock] Generating CLINK offer for', context.satsAmount, 'sats') + // Return a fake noffer for development + return `noffer1mock${Date.now().toString(36)}` + }, + + generateInvoice: async (amountMsat) => { + console.log('[Mock] Generating invoice for', amountMsat, 'msats') + // Return a fake invoice for development + return `lnbc${amountMsat}n1mock${Date.now().toString(36)}` + }, + + getExchangeRate: async (currency) => { + console.log('[Mock] Fetching exchange rate for', currency) + // Return mock rate: 2500 sats per USD (40k USD/BTC) + return 2500 + }, + + sendNostrReceipt: async (context) => { + console.log('[Mock] Sending Nostr receipt to', context.userNpub) + return true + }, + + dispenseCash: async (amounts) => { + console.log('[Mock] Dispensing cash:', amounts) + // Simulate dispense delay + await new Promise((resolve) => setTimeout(resolve, 2000)) + return true + }, +} + +export const useAtmStore = defineStore('atm', () => { + // State + const actor = ref> | null>(null) + const snapshot = ref> | null>(null) + const debugMode = ref(import.meta.env.DEV) + + // Computed + const currentState = computed(() => { + if (!snapshot.value) return 'uninitialized' + const value = snapshot.value.value + if (typeof value === 'string') return value + // Handle nested states + return JSON.stringify(value) + }) + + const context = computed((): ATMContext | null => { + return snapshot.value?.context ?? null + }) + + const isIdle = computed(() => currentState.value === 'idle') + + const isCashIn = computed(() => { + const state = snapshot.value?.value + return typeof state === 'object' && 'cashIn' in state + }) + + const isCashOut = computed(() => { + const state = snapshot.value?.value + return typeof state === 'object' && 'cashOut' in state + }) + + // Get the nested state for cashIn or cashOut + const nestedState = computed(() => { + const state = snapshot.value?.value + if (typeof state === 'object') { + if ('cashIn' in state) return state.cashIn as string + if ('cashOut' in state) return state.cashOut as string + } + return null + }) + + // Actions + function initialize(services: ATMServices = mockServices) { + const machine = createATMMachine(services) + actor.value = createActor(machine) + + // Subscribe to state changes + actor.value.subscribe((newSnapshot) => { + snapshot.value = newSnapshot + console.log('[ATM] State:', newSnapshot.value) + }) + + // Start the machine + actor.value.start() + console.log('[ATM] State machine initialized') + } + + function send(event: Parameters['send']>[0]) { + if (!actor.value) { + console.error('[ATM] Cannot send event: machine not initialized') + return + } + console.log('[ATM] Sending event:', event) + actor.value.send(event) + } + + // Convenience methods for common events + function selectCashIn() { + send({ type: 'SELECT_CASH_IN' }) + } + + function selectCashOut() { + send({ type: 'SELECT_CASH_OUT' }) + } + + function cancel() { + send({ type: 'CANCEL' }) + } + + function insertBill(denomination: number) { + send({ type: 'BILL_INSERTED', denomination }) + } + + function finishInserting() { + send({ type: 'FINISH_INSERTING' }) + } + + function selectAmount(amount: number) { + send({ type: 'SELECT_AMOUNT', amount }) + } + + function paymentReceived(preimage: string) { + send({ type: 'PAYMENT_RECEIVED', preimage }) + } + + function skipReceipt() { + send({ type: 'SKIP_RECEIPT' }) + } + + function cashTaken() { + send({ type: 'CASH_DISPENSED' }) + } + + function toggleDebug() { + debugMode.value = !debugMode.value + } + + return { + // State + actor, + snapshot, + debugMode, + + // Computed + currentState, + context, + isIdle, + isCashIn, + isCashOut, + nestedState, + + // Actions + initialize, + send, + selectCashIn, + selectCashOut, + cancel, + insertBill, + finishInserting, + selectAmount, + paymentReceived, + skipReceipt, + cashTaken, + toggleDebug, + } +}) diff --git a/lamassu-next/apps/machine/src/style.css b/lamassu-next/apps/machine/src/style.css new file mode 100644 index 0000000..9e65621 --- /dev/null +++ b/lamassu-next/apps/machine/src/style.css @@ -0,0 +1,112 @@ +@import 'tailwindcss'; +@import 'tw-animate-css'; + +@custom-variant dark (&:is(.dark *)); + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + /* ATM-specific semantic colors */ + --color-success: var(--success); + --color-success-foreground: var(--success-foreground); + --color-warning: var(--warning); + --color-warning-foreground: var(--warning-foreground); + --color-bitcoin: var(--bitcoin); + --color-bitcoin-foreground: var(--bitcoin-foreground); +} + +/* + * Gruvbox Color Palette + * https://github.com/morhetz/gruvbox + */ + +:root { + --radius: 0.625rem; + + /* Gruvbox Light */ + --background: #fbf1c7; /* bg0 hard */ + --foreground: #3c3836; /* fg1 */ + --card: #ebdbb2; /* bg1 */ + --card-foreground: #3c3836; + --popover: #ebdbb2; + --popover-foreground: #3c3836; + --primary: #d65d0e; /* orange */ + --primary-foreground: #fbf1c7; + --secondary: #d5c4a1; /* bg2 */ + --secondary-foreground: #3c3836; + --muted: #d5c4a1; + --muted-foreground: #665c54; /* bg3 */ + --accent: #458588; /* blue */ + --accent-foreground: #fbf1c7; + --destructive: #cc241d; /* red */ + --border: #bdae93; /* fg3 */ + --input: #bdae93; + --ring: #d65d0e; + + /* ATM semantic colors - light */ + --success: #98971a; /* green */ + --success-foreground: #fbf1c7; + --warning: #d79921; /* yellow */ + --warning-foreground: #3c3836; + --bitcoin: #d65d0e; /* orange */ + --bitcoin-foreground: #fbf1c7; +} + +.dark { + /* Gruvbox Dark */ + --background: #282828; /* bg0 */ + --foreground: #ebdbb2; /* fg1 */ + --card: #3c3836; /* bg1 */ + --card-foreground: #ebdbb2; + --popover: #3c3836; + --popover-foreground: #ebdbb2; + --primary: #fe8019; /* bright orange */ + --primary-foreground: #282828; + --secondary: #504945; /* bg2 */ + --secondary-foreground: #ebdbb2; + --muted: #504945; + --muted-foreground: #a89984; /* fg4 */ + --accent: #83a598; /* bright blue */ + --accent-foreground: #282828; + --destructive: #fb4934; /* bright red */ + --border: #504945; + --input: #504945; + --ring: #fe8019; + + /* ATM semantic colors - dark */ + --success: #b8bb26; /* bright green */ + --success-foreground: #282828; + --warning: #fabd2f; /* bright yellow */ + --warning-foreground: #282828; + --bitcoin: #fe8019; /* bright orange */ + --bitcoin-foreground: #282828; +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/lamassu-next/apps/machine/src/views/CashInView.vue b/lamassu-next/apps/machine/src/views/CashInView.vue new file mode 100644 index 0000000..1510ccc --- /dev/null +++ b/lamassu-next/apps/machine/src/views/CashInView.vue @@ -0,0 +1,231 @@ + + + diff --git a/lamassu-next/apps/machine/src/views/CashOutView.vue b/lamassu-next/apps/machine/src/views/CashOutView.vue new file mode 100644 index 0000000..80ee0f9 --- /dev/null +++ b/lamassu-next/apps/machine/src/views/CashOutView.vue @@ -0,0 +1,219 @@ + + + diff --git a/lamassu-next/apps/machine/src/views/IdleView.vue b/lamassu-next/apps/machine/src/views/IdleView.vue new file mode 100644 index 0000000..a37992c --- /dev/null +++ b/lamassu-next/apps/machine/src/views/IdleView.vue @@ -0,0 +1,85 @@ + + + diff --git a/lamassu-next/apps/machine/src/vite-env.d.ts b/lamassu-next/apps/machine/src/vite-env.d.ts new file mode 100644 index 0000000..65c7311 --- /dev/null +++ b/lamassu-next/apps/machine/src/vite-env.d.ts @@ -0,0 +1,7 @@ +/// + +declare module '*.vue' { + import type { DefineComponent } from 'vue' + const component: DefineComponent + export default component +} diff --git a/lamassu-next/apps/machine/tsconfig.json b/lamassu-next/apps/machine/tsconfig.json new file mode 100644 index 0000000..5de7dfa --- /dev/null +++ b/lamassu-next/apps/machine/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + "strict": true, + "strictNullChecks": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "paths": { + "@/*": ["./src/*"] + }, + "baseUrl": "." + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/lamassu-next/apps/machine/tsconfig.node.json b/lamassu-next/apps/machine/tsconfig.node.json new file mode 100644 index 0000000..97ede7e --- /dev/null +++ b/lamassu-next/apps/machine/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true + }, + "include": ["vite.config.ts"] +} diff --git a/lamassu-next/apps/machine/vite.config.ts b/lamassu-next/apps/machine/vite.config.ts new file mode 100644 index 0000000..f331db5 --- /dev/null +++ b/lamassu-next/apps/machine/vite.config.ts @@ -0,0 +1,33 @@ +import path from 'node:path' +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, + // Tauri expects a fixed port during development + server: { + port: 1420, + strictPort: true, + watch: { + ignored: ['**/src-tauri/**'], + }, + }, + // Build configuration for Tauri + build: { + // Tauri uses Chromium on Windows and WebKit on macOS and Linux + target: process.env.TAURI_ENV_PLATFORM === 'windows' ? 'chrome105' : 'safari14', + // Don't minify for debug builds + minify: !process.env.TAURI_ENV_DEBUG ? 'esbuild' : false, + // Produce sourcemaps for debug builds + sourcemap: !!process.env.TAURI_ENV_DEBUG, + }, + // Prevent Vite from clearing the screen + clearScreen: false, +}) diff --git a/lamassu-next/pnpm-lock.yaml b/lamassu-next/pnpm-lock.yaml index 1c78238..efe5f40 100644 --- a/lamassu-next/pnpm-lock.yaml +++ b/lamassu-next/pnpm-lock.yaml @@ -21,6 +21,79 @@ importers: specifier: ^5.7.0 version: 5.9.3 + apps/machine: + dependencies: + '@lamassu/clink': + specifier: workspace:* + version: link:../../packages/clink + '@lamassu/lightning': + specifier: workspace:* + version: link:../../packages/lightning + '@lamassu/nostr-client': + specifier: workspace:* + version: link:../../packages/nostr-client + '@lamassu/state-machine': + specifier: workspace:* + version: link:../../packages/state-machine + '@vueuse/core': + specifier: ^14.1.0 + version: 14.1.0(vue@3.5.27(typescript@5.9.3)) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide-vue-next: + specifier: ^0.563.0 + version: 0.563.0(vue@3.5.27(typescript@5.9.3)) + pinia: + specifier: ^2.2.0 + version: 2.3.1(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)) + reka-ui: + specifier: ^2.7.0 + version: 2.7.0(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)) + tailwind-merge: + specifier: ^3.4.0 + version: 3.4.0 + vue: + specifier: ^3.5.0 + version: 3.5.27(typescript@5.9.3) + vue-router: + specifier: ^4.4.0 + version: 4.6.4(vue@3.5.27(typescript@5.9.3)) + devDependencies: + '@tailwindcss/vite': + specifier: ^4.0.0 + version: 4.1.18(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) + '@tauri-apps/api': + specifier: ^2.1.0 + version: 2.9.1 + '@tauri-apps/cli': + specifier: ^2.1.0 + version: 2.9.6 + '@types/node': + specifier: ^22.0.0 + version: 22.19.7 + '@vitejs/plugin-vue': + specifier: ^5.2.0 + version: 5.2.4(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))(vue@3.5.27(typescript@5.9.3)) + tailwindcss: + specifier: ^4.0.0 + version: 4.1.18 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 + typescript: + specifier: ^5.7.0 + version: 5.9.3 + vite: + specifier: ^6.0.0 + version: 6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) + vue-tsc: + specifier: ^2.1.0 + version: 2.2.12(typescript@5.9.3) + packages/cashu: dependencies: '@cashu/cashu-ts': @@ -35,7 +108,7 @@ importers: version: 5.9.3 vitest: specifier: ^2.1.0 - version: 2.1.9(@types/node@22.19.7) + version: 2.1.9(@types/node@22.19.7)(lightningcss@1.30.2) packages/clink: dependencies: @@ -57,7 +130,7 @@ importers: version: 5.9.3 vitest: specifier: ^2.1.0 - version: 2.1.9(@types/node@22.19.7) + version: 2.1.9(@types/node@22.19.7)(lightningcss@1.30.2) packages/lightning: dependencies: @@ -79,7 +152,7 @@ importers: version: 5.9.3 vitest: specifier: ^2.1.0 - version: 2.1.9(@types/node@22.19.7) + version: 2.1.9(@types/node@22.19.7)(lightningcss@1.30.2) packages/nostr-client: dependencies: @@ -98,7 +171,7 @@ importers: version: 5.9.3 vitest: specifier: ^2.1.0 - version: 2.1.9(@types/node@22.19.7) + version: 2.1.9(@types/node@22.19.7)(lightningcss@1.30.2) packages/state-machine: dependencies: @@ -114,7 +187,7 @@ importers: version: 5.9.3 vitest: specifier: ^2.1.0 - version: 2.1.9(@types/node@22.19.7) + version: 2.1.9(@types/node@22.19.7)(lightningcss@1.30.2) packages/ui-shared: dependencies: @@ -127,16 +200,16 @@ importers: version: 22.19.7 '@vitejs/plugin-vue': specifier: ^5.2.0 - version: 5.2.4(vite@6.4.1(@types/node@22.19.7)(tsx@4.21.0))(vue@3.5.27(typescript@5.9.3)) + version: 5.2.4(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))(vue@3.5.27(typescript@5.9.3)) typescript: specifier: ^5.7.0 version: 5.9.3 vite: specifier: ^6.0.0 - version: 6.4.1(@types/node@22.19.7)(tsx@4.21.0) + version: 6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) vitest: specifier: ^2.1.0 - version: 2.1.9(@types/node@22.19.7) + version: 2.1.9(@types/node@22.19.7)(lightningcss@1.30.2) vue-tsc: specifier: ^2.1.0 version: 2.2.12(typescript@5.9.3) @@ -614,9 +687,40 @@ packages: cpu: [x64] os: [win32] + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@floating-ui/vue@1.1.9': + resolution: {integrity: sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==} + + '@internationalized/date@3.10.1': + resolution: {integrity: sha512-oJrXtQiAXLvT9clCf1K4kxp3eKsQhIaZqxEyowkBcsvZDdZkbWrVmnGknxs5flTD0VGsxrxKgBCZty1EzoiMzA==} + + '@internationalized/number@3.6.5': + resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@noble/ciphers@0.5.3': resolution: {integrity: sha512-B0+6IIHiqEs3BPMT0hcRmHvEj2QHOLu+uwt+tqDDeVd0oyVzh7BPrDcPjRnV1PV/5LaknXJJQvOuRGR0zQJz+w==} @@ -790,12 +894,190 @@ packages: '@scure/bip39@1.2.1': resolution: {integrity: sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==} + '@swc/helpers@0.5.18': + resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} + + '@tailwindcss/node@4.1.18': + resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + + '@tailwindcss/oxide-android-arm64@4.1.18': + resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.18': + resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.18': + resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.18': + resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@tanstack/virtual-core@3.13.18': + resolution: {integrity: sha512-Mx86Hqu1k39icq2Zusq+Ey2J6dDWTjDvEv43PJtRCoEYTLyfaPnxIQ6iy7YAOK0NV/qOEmZQ/uCufrppZxTgcg==} + + '@tanstack/vue-virtual@3.13.18': + resolution: {integrity: sha512-6pT8HdHtTU5Z+t906cGdCroUNA5wHjFXsNss9gwk7QAr1VNZtz9IQCs2Nhx0gABK48c+OocHl2As+TMg8+Hy4A==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + + '@tauri-apps/api@2.9.1': + resolution: {integrity: sha512-IGlhP6EivjXHepbBic618GOmiWe4URJiIeZFlB7x3czM0yDHHYviH1Xvoiv4FefdkQtn6v7TuwWCRfOGdnVUGw==} + + '@tauri-apps/cli-darwin-arm64@2.9.6': + resolution: {integrity: sha512-gf5no6N9FCk1qMrti4lfwP77JHP5haASZgVbBgpZG7BUepB3fhiLCXGUK8LvuOjP36HivXewjg72LTnPDScnQQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tauri-apps/cli-darwin-x64@2.9.6': + resolution: {integrity: sha512-oWh74WmqbERwwrwcueJyY6HYhgCksUc6NT7WKeXyrlY/FPmNgdyQAgcLuTSkhRFuQ6zh4Np1HZpOqCTpeZBDcw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tauri-apps/cli-linux-arm-gnueabihf@2.9.6': + resolution: {integrity: sha512-/zde3bFroFsNXOHN204DC2qUxAcAanUjVXXSdEGmhwMUZeAQalNj5cz2Qli2elsRjKN/hVbZOJj0gQ5zaYUjSg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tauri-apps/cli-linux-arm64-gnu@2.9.6': + resolution: {integrity: sha512-pvbljdhp9VOo4RnID5ywSxgBs7qiylTPlK56cTk7InR3kYSTJKYMqv/4Q/4rGo/mG8cVppesKIeBMH42fw6wjg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tauri-apps/cli-linux-arm64-musl@2.9.6': + resolution: {integrity: sha512-02TKUndpodXBCR0oP//6dZWGYcc22Upf2eP27NvC6z0DIqvkBBFziQUcvi2n6SrwTRL0yGgQjkm9K5NIn8s6jw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tauri-apps/cli-linux-riscv64-gnu@2.9.6': + resolution: {integrity: sha512-fmp1hnulbqzl1GkXl4aTX9fV+ubHw2LqlLH1PE3BxZ11EQk+l/TmiEongjnxF0ie4kV8DQfDNJ1KGiIdWe1GvQ==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + + '@tauri-apps/cli-linux-x64-gnu@2.9.6': + resolution: {integrity: sha512-vY0le8ad2KaV1PJr+jCd8fUF9VOjwwQP/uBuTJvhvKTloEwxYA/kAjKK9OpIslGA9m/zcnSo74czI6bBrm2sYA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tauri-apps/cli-linux-x64-musl@2.9.6': + resolution: {integrity: sha512-TOEuB8YCFZTWVDzsO2yW0+zGcoMiPPwcUgdnW1ODnmgfwccpnihDRoks+ABT1e3fHb1ol8QQWsHSCovb3o2ENQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tauri-apps/cli-win32-arm64-msvc@2.9.6': + resolution: {integrity: sha512-ujmDGMRc4qRLAnj8nNG26Rlz9klJ0I0jmZs2BPpmNNf0gM/rcVHhqbEkAaHPTBVIrtUdf7bGvQAD2pyIiUrBHQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tauri-apps/cli-win32-ia32-msvc@2.9.6': + resolution: {integrity: sha512-S4pT0yAJgFX8QRCyKA1iKjZ9Q/oPjCZf66A/VlG5Yw54Nnr88J1uBpmenINbXxzyhduWrIXBaUbEY1K80ZbpMg==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@tauri-apps/cli-win32-x64-msvc@2.9.6': + resolution: {integrity: sha512-ldWuWSSkWbKOPjQMJoYVj9wLHcOniv7diyI5UAJ4XsBdtaFB0pKHQsqw/ItUma0VXGC7vB4E9fZjivmxur60aw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tauri-apps/cli@2.9.6': + resolution: {integrity: sha512-3xDdXL5omQ3sPfBfdC8fCtDKcnyV7OqyzQgfyT5P3+zY6lcPqIYKQBvUasNvppi21RSdfhy44ttvJmftb0PCDw==} + engines: {node: '>= 10'} + hasBin: true + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/node@22.19.7': resolution: {integrity: sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==} + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@vitejs/plugin-vue@5.2.4': resolution: {integrity: sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -856,6 +1138,9 @@ packages: '@vue/compiler-vue2@2.7.16': resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + '@vue/devtools-api@6.6.4': + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + '@vue/language-core@2.2.12': resolution: {integrity: sha512-IsGljWbKGU1MZpBPN+BvPAdr55YPkj2nB/TBNGNC32Vy2qLG25DYu/NBN2vNtZqdRbTRjaoYrahLrToim2NanA==} peerDependencies: @@ -881,9 +1166,35 @@ packages: '@vue/shared@3.5.27': resolution: {integrity: sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==} + '@vueuse/core@12.8.2': + resolution: {integrity: sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==} + + '@vueuse/core@14.1.0': + resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/metadata@12.8.2': + resolution: {integrity: sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==} + + '@vueuse/metadata@14.1.0': + resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==} + + '@vueuse/shared@12.8.2': + resolution: {integrity: sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==} + + '@vueuse/shared@14.1.0': + resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==} + peerDependencies: + vue: ^3.5.0 + alien-signals@1.0.13: resolution: {integrity: sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -906,6 +1217,13 @@ packages: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -925,6 +1243,17 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + enhanced-resolve@5.18.4: + resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} + engines: {node: '>=10.13.0'} + entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} @@ -974,13 +1303,95 @@ packages: get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lucide-vue-next@0.563.0: + resolution: {integrity: sha512-zsE/lCKtmaa7bGfhSpN84br1K9YoQ5pCN+2oKWjQQG3Lo6ufUUKBuHSjNFI6RvUevxaajNXb8XwFUKeTXG3sIA==} + peerDependencies: + vue: '>=3.0.1' + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -1010,6 +1421,9 @@ packages: nostr-wasm@0.1.0: resolution: {integrity: sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} @@ -1027,6 +1441,15 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pinia@2.3.1: + resolution: {integrity: sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==} + peerDependencies: + typescript: '>=4.4.4' + vue: ^2.7.0 || ^3.5.11 + peerDependenciesMeta: + typescript: + optional: true + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -1036,6 +1459,11 @@ packages: engines: {node: '>=14'} hasBin: true + reka-ui@2.7.0: + resolution: {integrity: sha512-m+XmxQN2xtFzBP3OAdIafKq7C8OETo2fqfxcIIxYmNN2Ch3r5oAf6yEYCIJg5tL/yJU2mHqF70dCCekUkrAnXA==} + peerDependencies: + vue: '>= 3.2.0' + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -1057,6 +1485,16 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + tailwind-merge@3.4.0: + resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + + tailwindcss@4.1.18: + resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -1079,6 +1517,9 @@ packages: resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} engines: {node: '>=14.0.0'} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.21.0: resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} @@ -1118,6 +1559,9 @@ packages: resolution: {integrity: sha512-7Imdmg37joOloTnj+DPrab9hIaQcDdJ5RwSzcauo/wMOSAgO+A/I/8b3hsGGs6PWQz70m/jkPgdqWsfNKtwwDQ==} hasBin: true + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -1230,6 +1674,22 @@ packages: vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + + vue-router@4.6.4: + resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} + peerDependencies: + vue: ^3.5.0 + vue-tsc@2.2.12: resolution: {integrity: sha512-P7OP77b2h/Pmk+lZdJ0YWs+5tJ6J2+uOQPo7tlBnY44QqQSPYvS0qVT4wqDJgwrZaLe47etJLLQRFia71GYITw==} hasBin: true @@ -1498,8 +1958,53 @@ snapshots: '@esbuild/win32-x64@0.27.2': optional: true + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/utils@0.2.10': {} + + '@floating-ui/vue@1.1.9(vue@3.5.27(typescript@5.9.3))': + dependencies: + '@floating-ui/dom': 1.7.4 + '@floating-ui/utils': 0.2.10 + vue-demi: 0.14.10(vue@3.5.27(typescript@5.9.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + + '@internationalized/date@3.10.1': + dependencies: + '@swc/helpers': 0.5.18 + + '@internationalized/number@3.6.5': + dependencies: + '@swc/helpers': 0.5.18 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@noble/ciphers@0.5.3': {} '@noble/curves@1.1.0': @@ -1622,15 +2127,145 @@ snapshots: '@noble/hashes': 1.3.1 '@scure/base': 1.1.1 + '@swc/helpers@0.5.18': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.1.18': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.4 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.18 + + '@tailwindcss/oxide-android-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.18': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.18': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.18': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.18': + optional: true + + '@tailwindcss/oxide@4.1.18': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-arm64': 4.1.18 + '@tailwindcss/oxide-darwin-x64': 4.1.18 + '@tailwindcss/oxide-freebsd-x64': 4.1.18 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 + '@tailwindcss/oxide-linux-x64-musl': 4.1.18 + '@tailwindcss/oxide-wasm32-wasi': 4.1.18 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 + + '@tailwindcss/vite@4.1.18(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))': + dependencies: + '@tailwindcss/node': 4.1.18 + '@tailwindcss/oxide': 4.1.18 + tailwindcss: 4.1.18 + vite: 6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) + + '@tanstack/virtual-core@3.13.18': {} + + '@tanstack/vue-virtual@3.13.18(vue@3.5.27(typescript@5.9.3))': + dependencies: + '@tanstack/virtual-core': 3.13.18 + vue: 3.5.27(typescript@5.9.3) + + '@tauri-apps/api@2.9.1': {} + + '@tauri-apps/cli-darwin-arm64@2.9.6': + optional: true + + '@tauri-apps/cli-darwin-x64@2.9.6': + optional: true + + '@tauri-apps/cli-linux-arm-gnueabihf@2.9.6': + optional: true + + '@tauri-apps/cli-linux-arm64-gnu@2.9.6': + optional: true + + '@tauri-apps/cli-linux-arm64-musl@2.9.6': + optional: true + + '@tauri-apps/cli-linux-riscv64-gnu@2.9.6': + optional: true + + '@tauri-apps/cli-linux-x64-gnu@2.9.6': + optional: true + + '@tauri-apps/cli-linux-x64-musl@2.9.6': + optional: true + + '@tauri-apps/cli-win32-arm64-msvc@2.9.6': + optional: true + + '@tauri-apps/cli-win32-ia32-msvc@2.9.6': + optional: true + + '@tauri-apps/cli-win32-x64-msvc@2.9.6': + optional: true + + '@tauri-apps/cli@2.9.6': + optionalDependencies: + '@tauri-apps/cli-darwin-arm64': 2.9.6 + '@tauri-apps/cli-darwin-x64': 2.9.6 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.9.6 + '@tauri-apps/cli-linux-arm64-gnu': 2.9.6 + '@tauri-apps/cli-linux-arm64-musl': 2.9.6 + '@tauri-apps/cli-linux-riscv64-gnu': 2.9.6 + '@tauri-apps/cli-linux-x64-gnu': 2.9.6 + '@tauri-apps/cli-linux-x64-musl': 2.9.6 + '@tauri-apps/cli-win32-arm64-msvc': 2.9.6 + '@tauri-apps/cli-win32-ia32-msvc': 2.9.6 + '@tauri-apps/cli-win32-x64-msvc': 2.9.6 + '@types/estree@1.0.8': {} '@types/node@22.19.7': dependencies: undici-types: 6.21.0 - '@vitejs/plugin-vue@5.2.4(vite@6.4.1(@types/node@22.19.7)(tsx@4.21.0))(vue@3.5.27(typescript@5.9.3))': + '@types/web-bluetooth@0.0.21': {} + + '@vitejs/plugin-vue@5.2.4(vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))(vue@3.5.27(typescript@5.9.3))': dependencies: - vite: 6.4.1(@types/node@22.19.7)(tsx@4.21.0) + vite: 6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) vue: 3.5.27(typescript@5.9.3) '@vitest/expect@2.1.9': @@ -1640,13 +2275,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@22.19.7))': + '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@22.19.7)(lightningcss@1.30.2))': dependencies: '@vitest/spy': 2.1.9 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 5.4.21(@types/node@22.19.7) + vite: 5.4.21(@types/node@22.19.7)(lightningcss@1.30.2) '@vitest/pretty-format@2.1.9': dependencies: @@ -1720,6 +2355,8 @@ snapshots: de-indent: 1.0.2 he: 1.2.0 + '@vue/devtools-api@6.6.4': {} + '@vue/language-core@2.2.12(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.15 @@ -1757,8 +2394,42 @@ snapshots: '@vue/shared@3.5.27': {} + '@vueuse/core@12.8.2(typescript@5.9.3)': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 12.8.2 + '@vueuse/shared': 12.8.2(typescript@5.9.3) + vue: 3.5.27(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + '@vueuse/core@14.1.0(vue@3.5.27(typescript@5.9.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 14.1.0 + '@vueuse/shared': 14.1.0(vue@3.5.27(typescript@5.9.3)) + vue: 3.5.27(typescript@5.9.3) + + '@vueuse/metadata@12.8.2': {} + + '@vueuse/metadata@14.1.0': {} + + '@vueuse/shared@12.8.2(typescript@5.9.3)': + dependencies: + vue: 3.5.27(typescript@5.9.3) + transitivePeerDependencies: + - typescript + + '@vueuse/shared@14.1.0(vue@3.5.27(typescript@5.9.3))': + dependencies: + vue: 3.5.27(typescript@5.9.3) + alien-signals@1.0.13: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + assertion-error@2.0.1: {} balanced-match@1.0.2: {} @@ -1779,6 +2450,12 @@ snapshots: check-error@2.1.3: {} + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + clsx@2.1.1: {} + csstype@3.2.3: {} de-indent@1.0.2: {} @@ -1789,6 +2466,15 @@ snapshots: deep-eql@5.0.2: {} + defu@6.1.4: {} + + detect-libc@2.1.2: {} + + enhanced-resolve@5.18.4: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + entities@7.0.1: {} es-module-lexer@1.7.0: {} @@ -1896,10 +2582,67 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + graceful-fs@4.2.11: {} + he@1.2.0: {} + jiti@2.6.1: {} + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + loupe@3.2.1: {} + lucide-vue-next@0.563.0(vue@3.5.27(typescript@5.9.3)): + dependencies: + vue: 3.5.27(typescript@5.9.3) + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -1928,6 +2671,8 @@ snapshots: nostr-wasm@0.1.0: {} + ohash@2.0.11: {} + path-browserify@1.0.1: {} pathe@1.1.2: {} @@ -1938,6 +2683,16 @@ snapshots: picomatch@4.0.3: {} + pinia@2.3.1(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.27(typescript@5.9.3) + vue-demi: 0.14.10(vue@3.5.27(typescript@5.9.3)) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@vue/composition-api' + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -1946,6 +2701,23 @@ snapshots: prettier@3.8.1: {} + reka-ui@2.7.0(typescript@5.9.3)(vue@3.5.27(typescript@5.9.3)): + dependencies: + '@floating-ui/dom': 1.7.4 + '@floating-ui/vue': 1.1.9(vue@3.5.27(typescript@5.9.3)) + '@internationalized/date': 3.10.1 + '@internationalized/number': 3.6.5 + '@tanstack/vue-virtual': 3.13.18(vue@3.5.27(typescript@5.9.3)) + '@vueuse/core': 12.8.2(typescript@5.9.3) + '@vueuse/shared': 12.8.2(typescript@5.9.3) + aria-hidden: 1.2.6 + defu: 6.1.4 + ohash: 2.0.11 + vue: 3.5.27(typescript@5.9.3) + transitivePeerDependencies: + - '@vue/composition-api' + - typescript + resolve-pkg-maps@1.0.0: {} rollup@4.56.0: @@ -1987,6 +2759,12 @@ snapshots: std-env@3.10.0: {} + tailwind-merge@3.4.0: {} + + tailwindcss@4.1.18: {} + + tapable@2.3.0: {} + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -2002,6 +2780,8 @@ snapshots: tinyspy@3.0.2: {} + tslib@2.8.1: {} + tsx@4.21.0: dependencies: esbuild: 0.27.2 @@ -2036,17 +2816,19 @@ snapshots: turbo-windows-64: 2.7.5 turbo-windows-arm64: 2.7.5 + tw-animate-css@1.4.0: {} + typescript@5.9.3: {} undici-types@6.21.0: {} - vite-node@2.1.9(@types/node@22.19.7): + vite-node@2.1.9(@types/node@22.19.7)(lightningcss@1.30.2): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 1.1.2 - vite: 5.4.21(@types/node@22.19.7) + vite: 5.4.21(@types/node@22.19.7)(lightningcss@1.30.2) transitivePeerDependencies: - '@types/node' - less @@ -2058,7 +2840,7 @@ snapshots: - supports-color - terser - vite@5.4.21(@types/node@22.19.7): + vite@5.4.21(@types/node@22.19.7)(lightningcss@1.30.2): dependencies: esbuild: 0.21.5 postcss: 8.5.6 @@ -2066,8 +2848,9 @@ snapshots: optionalDependencies: '@types/node': 22.19.7 fsevents: 2.3.3 + lightningcss: 1.30.2 - vite@6.4.1(@types/node@22.19.7)(tsx@4.21.0): + vite@6.4.1(@types/node@22.19.7)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -2078,12 +2861,14 @@ snapshots: optionalDependencies: '@types/node': 22.19.7 fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 tsx: 4.21.0 - vitest@2.1.9(@types/node@22.19.7): + vitest@2.1.9(@types/node@22.19.7)(lightningcss@1.30.2): dependencies: '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@22.19.7)) + '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@22.19.7)(lightningcss@1.30.2)) '@vitest/pretty-format': 2.1.9 '@vitest/runner': 2.1.9 '@vitest/snapshot': 2.1.9 @@ -2099,8 +2884,8 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.1.1 tinyrainbow: 1.2.0 - vite: 5.4.21(@types/node@22.19.7) - vite-node: 2.1.9(@types/node@22.19.7) + vite: 5.4.21(@types/node@22.19.7)(lightningcss@1.30.2) + vite-node: 2.1.9(@types/node@22.19.7)(lightningcss@1.30.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.19.7 @@ -2117,6 +2902,15 @@ snapshots: vscode-uri@3.1.0: {} + vue-demi@0.14.10(vue@3.5.27(typescript@5.9.3)): + dependencies: + vue: 3.5.27(typescript@5.9.3) + + vue-router@4.6.4(vue@3.5.27(typescript@5.9.3)): + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.27(typescript@5.9.3) + vue-tsc@2.2.12(typescript@5.9.3): dependencies: '@volar/typescript': 2.4.15