Files
shop-server/docs/superpowers/specs/2026-05-22-auth-redesign-design.md
T
2026-05-22 13:18:21 +05:00

226 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Auth Page Redesign — Spec
**Date:** 2026-05-22
**Goal:** Минималистичный редизайн страницы входа с лёгким брендингом (медведь + слоган), pill-кнопками и Paper-карточкой.
**Style:** Минималистичный, чистый. Одна колонка по центру.
---
## 1. Шрифт Outfit
**Проблема:** Outfit указан в MUI-теме, но не загружается. Фактически везде системный Segoe UI.
**Исправление:** Скачать шрифт Outfit (woff2, веса 400/500/600/700) и разместить в `client/public/fonts/`. Добавить `@font-face` в `client/src/app/styles/global.css`:
```css
@font-face {
font-family: 'Outfit';
font-style: normal;
font-weight: 400;
src: url('/fonts/Outfit-Regular.woff2') format('woff2');
}
@font-face {
font-family: 'Outfit';
font-style: normal;
font-weight: 500;
src: url('/fonts/Outfit-Medium.woff2') format('woff2');
}
@font-face {
font-family: 'Outfit';
font-style: normal;
font-weight: 600;
src: url('/fonts/Outfit-SemiBold.woff2') format('woff2');
}
@font-face {
font-family: 'Outfit';
font-style: normal;
font-weight: 700;
src: url('/fonts/Outfit-Bold.woff2') format('woff2');
}
```
Файлы woff2 скачать с Google Fonts или из CDN и положить в `client/public/fonts/`.
---
## 2. Фон страницы
- `background.default` + лёгкий радиальный градиент
- Градиент: от центра к краям, `primary.main` с 3-5% opacity
- Реализация: `sx` prop на корневом `<Box>`: `background: radial-gradient(circle at 50% 30%, ${alpha(theme.palette.primary.main, 0.05)} 0%, transparent 70%)`
---
## 3. Компоновка
```
┌──────────────────────────────────────────┐
│ (воздух) │
│ 🐻 BearLogo 72px │
│ Добро пожаловать в Любимый Креатив │
│ (subtitle, text.secondary) │
│ (воздух) │
│ ┌─────── Paper 440px max-width ──────┐ │
│ │ [Пароль] [Код] [Другой способ] │ │
│ │ │ │
│ │ Вход / Регистрация │ │
│ │ │ │
│ │ Email: __________________ │ │
│ │ Пароль: __________________ │ │
│ │ │ │
│ │ [────────── Войти ──────────] │ │
│ │ │ │
│ └─────────────────────────────────────┘ │
│ (воздух) │
└──────────────────────────────────────────┘
```
Детали:
- Корневой `<Box>`: `display: flex, alignItems: center, justifyContent: center, minHeight: calc(100vh - header)`
- BearLogo: `<Box sx={{ display: 'flex', justifyContent: 'center', mb: 2 }}><BearLogo sx={{ fontSize: 72 }} /></Box>`
- Заголовок: `variant="h5"`, `fontWeight: 700`, `textAlign: center`
- Слоган: `variant="body2"`, `color: text.secondary`, `textAlign: center`, `mb: 3`
- Paper: `maxWidth: 440`, `mx: auto`, `p: 4`, `borderRadius: 3` (12px), `border: 1px solid divider`, мягкая тень
---
## 4. Pill-переключатель методов
Вместо MUI Tabs — три MUI Button в ряд:
```tsx
<Stack direction="row" spacing={1} sx={{ mb: 3 }}>
<Button
variant={tab === 0 ? 'contained' : 'outlined'}
sx={{ borderRadius: '24px', flex: 1, textTransform: 'none' }}
onClick={() => setTab(0)}
>
Пароль
</Button>
<Button
variant={tab === 1 ? 'contained' : 'outlined'}
sx={{ borderRadius: '24px', flex: 1, textTransform: 'none' }}
onClick={() => setTab(1)}
>
Код
</Button>
<Button
variant={tab === 2 ? 'contained' : 'outlined'}
sx={{ borderRadius: '24px', flex: 1, textTransform: 'none' }}
onClick={() => setTab(2)}
>
Другой способ
</Button>
</Stack>
```
---
## 5. Под-переключатель Вход/Регистрация
Только на вкладке «Пароль»:
```tsx
<Stack direction="row" justifyContent="center" spacing={3} sx={{ mb: 2 }}>
<Button
variant="text"
size="small"
sx={{
color: !isRegister ? 'primary.main' : 'text.secondary',
borderBottom: !isRegister ? 2 : 0,
borderColor: 'primary.main',
borderRadius: 0,
pb: 0.5,
}}
onClick={() => setIsRegister(false)}
>
Вход
</Button>
<Button
variant="text"
size="small"
sx={{
color: isRegister ? 'primary.main' : 'text.secondary',
borderBottom: isRegister ? 2 : 0,
borderColor: 'primary.main',
borderRadius: 0,
pb: 0.5,
}}
onClick={() => setIsRegister(true)}
>
Регистрация
</Button>
</Stack>
```
---
## 6. Формы по вкладкам
### Пароль (вход)
- Email TextField
- Пароль TextField
- Button contained fullWidth: «Войти»
### Пароль (регистрация)
- Email TextField
- Имя TextField (опционально, helperText: «Необязательно. Будет использована часть email»)
- Пароль TextField
- Подтверждение пароля TextField (с валидацией совпадения)
- Button contained fullWidth: «Зарегистрироваться»
### Код
- Строка: Email + кнопка «Отправить код»
- Строка: поле Код + кнопка «Войти»
- Alert outlined success после успешной отправки
### Другой способ
- OAuthButtons — стилизовать кнопки как outlined pill (borderRadius 24px, fullWidth)
- Кнопки: «Войти через Яндекс ID», «Войти через VK ID»
---
## 7. Alert'ы
- Все ошибки: `Alert severity="error" variant="outlined"` внутри Paper, над формой
- Успешная отправка кода: `Alert severity="success" variant="outlined"`
- OAuth-ошибки: так же внутри Paper
---
## 8. Иконки в TextField
Добавить `InputAdornment` с иконками для визуального улучшения:
- Email: `<Mail>` иконка (lucide-react)
- Пароль: `<Lock>` иконка
Иконки только если это не перегружает минималистичный стиль. Решение — использовать в полях email и пароля `startAdornment`.
---
## 9. Адаптивность
- `min-height` вместо `height` (использовать `minHeight: calc(100vh - 64px)`)
- Paper: `mx: 2` на мобильных, `mx: auto` на десктопе
- Pill-кнопки остаются в ряд на всех разрешениях (они и так компактные)
- Отправка кода: на мобильных поля в столбец (уже есть `direction={{ xs: 'column', sm: 'row' }}`)
---
## 10. Плавные переходы
- Смена вкладок: контент формы — `opacity` transition 200ms
- Смена Вход/Регистрация: поля появляются с fade-in
---
## 11. Заметки
- BearLogo уже существует (`@/shared/ui/BearLogo`)
- OAuthButtons существует (`@/features/auth-oauth`)
- Менять бизнес-логику (хуки, mutations) не нужно — только вёрстку
- Текущий AuthPage — 232 строки, нужно заменить полностью
- Все цвета брать из темы (`primary.main`, `text.secondary`, `divider`, `background.paper`)
- Для градиента использовать `useTheme` + `alpha` из MUI