Some checks failed
Nouveau composant `components/ui/PasswordInput` : un `<input>` de mot de passe avec un bouton œil (`lucide-react` Eye/EyeOff) qui bascule le `type` entre "password" et "text". Visibilité en état local, toujours masquée au montage, jamais persistée. Bouton `type="button"` (ne soumet pas le formulaire) + `aria-label` traduit (`common.passwordInput.*`) + `aria-pressed`. Branché dans `LoginPage` et `SignupPage` à la place du `<input type="password">` nu. La règle `.auth-card button` de `auth-form.scss` est resserrée sur `button[type="submit"]` pour que le bouton œil n'hérite pas du traitement plein-largeur du bouton de connexion. Tests : `cypress/component/PasswordInput.cy.tsx` (7 cas, composant isolé) + `cypress/e2e/auth-form.cy.ts` (mode layout, l'œil sur /login et /signup). Closes #134 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
117 lines
3.5 KiB
SCSS
117 lines
3.5 KiB
SCSS
// =============================================================================
|
|
// Styles shared by LoginPage and SignupPage — both render the same card/form
|
|
// layout, so this lives in features/auth/ (the concern both pages share)
|
|
// rather than being duplicated in each page's own stylesheet. Imported by
|
|
// both LoginPage.tsx and SignupPage.tsx.
|
|
// =============================================================================
|
|
|
|
// No `@use` of the theme partial needed here: every design token below is a
|
|
// CSS custom property (--color-*, --space-*...) declared once on :root in
|
|
// styles/global.scss and available globally at runtime — not a Sass-level
|
|
// variable/mixin that would require an explicit compile-time import.
|
|
|
|
// Full-viewport centering wrapper for the auth card.
|
|
.auth-page {
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: var(--space-md);
|
|
background: var(--color-background);
|
|
}
|
|
|
|
// The form itself: a vertically-stacked card, capped width so it stays
|
|
// readable on wide screens. Raised on its own surface (rather than sitting
|
|
// directly on the page background) so it reads as one focused task.
|
|
.auth-card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-xs);
|
|
width: 100%;
|
|
max-width: var(--max-width-form);
|
|
padding: var(--space-xl);
|
|
background: var(--color-surface);
|
|
border-radius: var(--radius-md);
|
|
box-shadow: var(--shadow-md);
|
|
|
|
// Card title — smaller than the global page-title size (h1 defaults to
|
|
// --font-size-2xl), since here it's heading a card, not the page.
|
|
h1 {
|
|
font-size: var(--font-size-lg);
|
|
text-align: center;
|
|
margin-bottom: var(--space-sm);
|
|
}
|
|
|
|
// Field labels sit directly above their input, with a little breathing
|
|
// room from the previous field.
|
|
label {
|
|
font-size: var(--font-size-sm);
|
|
font-weight: 600;
|
|
margin-top: var(--space-sm);
|
|
}
|
|
|
|
input {
|
|
padding: var(--space-sm);
|
|
font-family: var(--font-body);
|
|
font-size: var(--font-size-base);
|
|
color: var(--color-text);
|
|
background: var(--color-background);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-base);
|
|
}
|
|
|
|
// Submit button: full-width, visually separated from the fields above it.
|
|
// Scoped to `[type="submit"]` specifically — the card also contains the
|
|
// PasswordInput's `type="button"` eye toggle, which must NOT inherit this
|
|
// full-width primary-coloured treatment (it styles itself in
|
|
// components/ui/password-input.scss).
|
|
button[type="submit"] {
|
|
margin-top: var(--space-md);
|
|
padding: 0.6rem;
|
|
font-family: var(--font-body);
|
|
font-size: var(--font-size-base);
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
border-radius: var(--radius-base);
|
|
border: none;
|
|
background: var(--color-primary);
|
|
color: #fff;
|
|
|
|
&:hover:not(:disabled) {
|
|
background: var(--color-primary-hover);
|
|
}
|
|
|
|
&:disabled {
|
|
opacity: 0.6;
|
|
cursor: not-allowed;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Per-field validation message (client-side, from zod) — sits directly
|
|
// under its input.
|
|
.field-error {
|
|
color: var(--color-error);
|
|
font-size: var(--font-size-xs);
|
|
margin: 0;
|
|
}
|
|
|
|
// Whole-form error message (from the API, e.g. wrong credentials) — sits
|
|
// above the submit button.
|
|
.form-error {
|
|
color: var(--color-error);
|
|
font-size: var(--font-size-sm);
|
|
}
|
|
|
|
// "Already have an account? / No account yet?" link row under the form.
|
|
.auth-switch {
|
|
font-size: var(--font-size-sm);
|
|
color: var(--color-text-muted);
|
|
margin-top: var(--space-md);
|
|
text-align: center;
|
|
|
|
a {
|
|
color: var(--color-primary);
|
|
font-weight: 600;
|
|
}
|
|
}
|