Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Has been cancelled
Go + Wails v3 + Vue 3 + SQLite + FreeRDP3 (purego) 183 tests, 76 source files, 9,910 lines of code Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
123 lines
4.1 KiB
Vue
123 lines
4.1 KiB
Vue
<template>
|
|
<div class="h-screen w-screen flex items-center justify-center bg-[var(--wraith-bg-primary)]">
|
|
<div class="w-full max-w-sm px-6">
|
|
<!-- Branding -->
|
|
<div class="text-center mb-8">
|
|
<h1 class="text-4xl font-bold tracking-widest text-[var(--wraith-accent-blue)]">
|
|
WRAITH
|
|
</h1>
|
|
<p class="text-[var(--wraith-text-secondary)] mt-2 text-sm">
|
|
{{ appStore.isFirstRun ? "Create a master password" : "Enter your master password" }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Card -->
|
|
<form
|
|
class="bg-[var(--wraith-bg-secondary)] border border-[var(--wraith-border)] rounded-lg p-6 space-y-4"
|
|
@submit.prevent="handleSubmit"
|
|
>
|
|
<!-- Error -->
|
|
<div
|
|
v-if="appStore.error"
|
|
class="text-sm text-[var(--wraith-accent-red)] bg-[var(--wraith-accent-red)]/10 border border-[var(--wraith-accent-red)]/20 rounded px-3 py-2"
|
|
>
|
|
{{ appStore.error }}
|
|
</div>
|
|
|
|
<!-- Password -->
|
|
<div>
|
|
<label class="block text-xs text-[var(--wraith-text-secondary)] mb-1.5">
|
|
Master Password
|
|
</label>
|
|
<input
|
|
ref="passwordInput"
|
|
v-model="password"
|
|
type="password"
|
|
autocomplete="current-password"
|
|
placeholder="Enter password..."
|
|
class="w-full px-3 py-2 text-sm rounded bg-[var(--wraith-bg-tertiary)] border border-[var(--wraith-border)] text-[var(--wraith-text-primary)] placeholder-[var(--wraith-text-muted)] outline-none focus:border-[var(--wraith-accent-blue)] transition-colors"
|
|
@input="appStore.clearError()"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Confirm password (first run only) -->
|
|
<div v-if="appStore.isFirstRun">
|
|
<label class="block text-xs text-[var(--wraith-text-secondary)] mb-1.5">
|
|
Confirm Password
|
|
</label>
|
|
<input
|
|
v-model="confirmPassword"
|
|
type="password"
|
|
autocomplete="new-password"
|
|
placeholder="Confirm password..."
|
|
class="w-full px-3 py-2 text-sm rounded bg-[var(--wraith-bg-tertiary)] border border-[var(--wraith-border)] text-[var(--wraith-text-primary)] placeholder-[var(--wraith-text-muted)] outline-none focus:border-[var(--wraith-accent-blue)] transition-colors"
|
|
@input="appStore.clearError()"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Submit -->
|
|
<button
|
|
type="submit"
|
|
:disabled="submitting"
|
|
class="w-full py-2 text-sm font-medium rounded bg-[var(--wraith-accent-blue)] text-white hover:opacity-90 disabled:opacity-50 transition-opacity cursor-pointer disabled:cursor-not-allowed"
|
|
>
|
|
<span v-if="submitting">{{ appStore.isFirstRun ? "Creating..." : "Unlocking..." }}</span>
|
|
<span v-else>{{ appStore.isFirstRun ? "Create Vault" : "Unlock" }}</span>
|
|
</button>
|
|
</form>
|
|
|
|
<!-- Version -->
|
|
<p class="text-center text-xs text-[var(--wraith-text-muted)] mt-4">
|
|
v1.0.0-alpha
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted } from "vue";
|
|
import { useAppStore } from "@/stores/app.store";
|
|
|
|
const appStore = useAppStore();
|
|
|
|
const password = ref("");
|
|
const confirmPassword = ref("");
|
|
const submitting = ref(false);
|
|
const passwordInput = ref<HTMLInputElement | null>(null);
|
|
|
|
onMounted(() => {
|
|
passwordInput.value?.focus();
|
|
});
|
|
|
|
async function handleSubmit(): Promise<void> {
|
|
if (!password.value) {
|
|
appStore.error = "Password is required";
|
|
return;
|
|
}
|
|
|
|
if (appStore.isFirstRun) {
|
|
if (password.value.length < 8) {
|
|
appStore.error = "Password must be at least 8 characters";
|
|
return;
|
|
}
|
|
if (password.value !== confirmPassword.value) {
|
|
appStore.error = "Passwords do not match";
|
|
return;
|
|
}
|
|
}
|
|
|
|
submitting.value = true;
|
|
try {
|
|
if (appStore.isFirstRun) {
|
|
await appStore.createVault(password.value);
|
|
} else {
|
|
await appStore.unlock(password.value);
|
|
}
|
|
} catch {
|
|
// Error is set in the store
|
|
} finally {
|
|
submitting.value = false;
|
|
}
|
|
}
|
|
</script>
|