Files
inkwell/frontend/src/views/ForgotPasswordView.vue
T
bvandeusenandClaude Opus 5.5 b481e6857c DRY pass #2, batch 5, F14: the web's repeated class lists become component classes (#5372)
style.css gains the classes the views spelled out in full: .section-label
(17 sites), .hint (20), .form-error (13), .alert-error (5), .row-card (5),
.list-empty (5), .field (5), .page-shell (3), and the small row action
.btn-sm (4) / .btn-sm-danger (3). Only exact runs moved, so nothing renders
differently; spacing a site adds beyond a run stays a utility beside it.

Kept: the Reminders and Timeline small buttons. They carry no text colour
and inherit it, so putting them on .btn-sm would recolour them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:41:34 -04:00

85 lines
2.5 KiB
Vue

<script setup lang="ts">
import { ref } from "vue";
import { useRoute } from "vue-router";
import { api } from "../api/client";
import { errorMessage } from "../api/errors";
import { useConfigStore } from "../stores/config";
import BaseInput from "../components/BaseInput.vue";
import BaseButton from "../components/BaseButton.vue";
// Ask for a password reset link by email (#5266). The server answers the same way
// whether or not the address has an account, so this page does too.
const config = useConfigStore();
const route = useRoute();
const email = ref(typeof route.query.email === "string" ? route.query.email : "");
const sent = ref("");
const error = ref("");
const loading = ref(false);
async function submit() {
error.value = "";
loading.value = true;
try {
const res = await api.post<{ message: string }>("/api/auth/forgot-password", { email: email.value });
sent.value = res.message;
} catch (e) {
error.value = errorMessage(e, "Couldn't send a reset link.");
} finally {
loading.value = false;
}
}
</script>
<template>
<main class="flex min-h-full items-center justify-center px-4 py-12">
<div class="w-full max-w-sm">
<div class="mb-8 text-center">
<img
src="/icon.svg"
:alt="config.siteName"
class="mx-auto mb-3 h-12 w-12 rounded-xl"
width="48"
height="48"
/>
<h1 class="text-2xl font-bold tracking-tight">Forgot your password?</h1>
<p class="mt-1 hint">We'll email you a link to choose a new one.</p>
</div>
<p
v-if="sent"
role="status"
class="rounded-lg bg-green-50 px-3 py-2 text-sm text-green-800 dark:bg-green-950/50 dark:text-green-300"
>
{{ sent }}
</p>
<form v-else class="flex flex-col gap-4" novalidate @submit.prevent="submit">
<BaseInput
id="email"
v-model="email"
label="Email"
type="email"
autocomplete="email"
placeholder="you@example.com"
required
/>
<p
v-if="error"
role="alert"
class="alert-error"
>
{{ error }}
</p>
<BaseButton type="submit" :loading="loading">Send reset link</BaseButton>
</form>
<p class="mt-6 text-center hint">
<RouterLink to="/login" class="font-semibold text-brand-700 hover:underline dark:text-brand"
>Back to sign in</RouterLink
>
</p>
</div>
</main>
</template>