wraith/frontend/pages/login.vue
Vantz Stockwell 826ca1c0c7 feat: replace WRAITH text with ghost logo in nav bar and login
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 09:16:21 -04:00

76 lines
2.8 KiB
Vue

<script setup lang="ts">
definePageMeta({ layout: 'auth' })
const auth = useAuthStore()
const email = ref('')
const password = ref('')
const totpCode = ref('')
const error = ref('')
const loading = ref(false)
const requiresTotp = ref(false)
async function handleLogin() {
error.value = ''
loading.value = true
try {
const res = await auth.login(
email.value,
password.value,
requiresTotp.value ? totpCode.value : undefined,
)
if (res.requires_totp) {
requiresTotp.value = true
loading.value = false
return
}
navigateTo('/')
} catch (e: any) {
error.value = e.data?.message || 'Login failed'
} finally {
loading.value = false
}
}
</script>
<template>
<div class="w-full max-w-sm">
<div class="text-center mb-8">
<img src="/wraith-logo.png" alt="Wraith" class="h-20 mx-auto" />
</div>
<form @submit.prevent="handleLogin" class="space-y-4 bg-gray-900 p-6 rounded-lg border border-gray-800">
<template v-if="!requiresTotp">
<div>
<label class="block text-sm text-gray-400 mb-1">Email</label>
<input v-model="email" type="email" required autofocus
class="w-full px-3 py-2 bg-gray-800 border border-gray-700 rounded text-white focus:border-wraith-500 focus:outline-none" />
</div>
<div>
<label class="block text-sm text-gray-400 mb-1">Password</label>
<input v-model="password" type="password" required
class="w-full px-3 py-2 bg-gray-800 border border-gray-700 rounded text-white focus:border-wraith-500 focus:outline-none" />
</div>
</template>
<template v-else>
<div class="text-center mb-2">
<p class="text-sm text-gray-400">Enter your authenticator code</p>
</div>
<div>
<label class="block text-sm text-gray-400 mb-1">TOTP Code</label>
<input v-model="totpCode" type="text" inputmode="numeric" pattern="[0-9]*" maxlength="6"
required autofocus autocomplete="one-time-code" placeholder="000000"
class="w-full px-3 py-2 bg-gray-800 border border-gray-700 rounded text-white text-center text-lg tracking-widest focus:border-wraith-500 focus:outline-none" />
</div>
</template>
<p v-if="error" class="text-red-400 text-sm">{{ error }}</p>
<button type="submit" :disabled="loading"
class="w-full py-2 bg-wraith-600 hover:bg-wraith-700 text-white rounded font-medium disabled:opacity-50">
{{ loading ? 'Verifying...' : requiresTotp ? 'Verify' : 'Sign In' }}
</button>
<button v-if="requiresTotp" type="button" @click="requiresTotp = false; totpCode = ''; error = ''"
class="w-full py-2 text-sm text-gray-500 hover:text-gray-300">
Back to login
</button>
</form>
</div>
</template>