226 lines
8.2 KiB
Markdown
226 lines
8.2 KiB
Markdown
# 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
|