feat: Улучшение компонентов Dashboard, EmptyState, ErrorAlert и Pagination. Добавлены новые функции, такие как индикаторы тренда, возможность перехода на страницу и улучшенные действия с ошибками. Обновлены стили для повышения удобства использования и доступности.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m54s

This commit is contained in:
2025-10-03 19:11:10 +07:00
parent 72fbb7bde5
commit 18f3a5312a
16 changed files with 2697 additions and 96 deletions
+554
View File
@@ -0,0 +1,554 @@
# 🎨 UX/UI Улучшения - Документация
Этот документ описывает все внедренные UX/UI улучшения в проект S3 Lists Manager.
## 📋 Содержание
1. [CSS Улучшения](#css-улучшения)
2. [Новые Компоненты](#новые-компоненты)
3. [Улучшенные Компоненты](#улучшенные-компоненты)
4. [Примеры Использования](#примеры-использования)
---
## CSS Улучшения
### Semantic Colors
Добавлена система семантических цветов для статусов и акцентов:
```css
--status-online: #2fb344;
--status-offline: #d63939;
--status-warning: #f59f00;
--status-unknown: #868e96;
--accent-primary: #206bc4;
--accent-danger: #d63939;
--accent-success: #2fb344;
```
### Улучшенная Типографика
- Увеличенный размер заголовков с лучшей читаемостью
- Оптимизированная межстрочная высота
- Letter-spacing для заголовков
### Enhanced Spacing
- Единая система отступов через CSS переменные
- Увеличенные padding в таблицах для лучшей читаемости
- Consistent spacing между карточками
### Интерактивные Элементы
- **Hover states**: кнопки поднимаются на 1px с тенью
- **Active states**: визуальный feedback при нажатии
- **Focus states**: улучшенные для accessibility
- **Touch targets**: минимум 44x44px на мобильных
---
## Новые Компоненты
### 1. Tooltip
Компонент для отображения подсказок с поддержкой keyboard shortcuts.
**Использование:**
```jsx
import Tooltip from './components/Tooltip.jsx'
<Tooltip content="Сохранить изменения" shortcut="Ctrl+S" position="top">
<button className="btn btn-primary">
<IconDeviceFloppy /> Сохранить
</button>
</Tooltip>
```
**Props:**
- `content` (string) - текст подсказки
- `shortcut` (string) - keyboard shortcut для отображения
- `position` (string) - позиция: 'top', 'bottom', 'left', 'right'
- `delay` (number) - задержка перед показом (ms)
---
### 2. TrendIndicator
Компонент для отображения изменения метрик со стрелками вверх/вниз.
**Использование:**
```jsx
import TrendIndicator from './components/TrendIndicator.jsx'
<TrendIndicator
value={1250}
previousValue={1180}
format="number" // или "percent"
inverse={false} // true если рост = плохо
/>
```
**Props:**
- `value` (number) - текущее значение
- `previousValue` (number) - предыдущее значение
- `format` ('number' | 'percent') - формат отображения
- `inverse` (boolean) - инвертировать цвета (рост = красный)
---
### 3. LastSaved
Компонент для отображения времени последнего сохранения с автообновлением.
**Использование:**
```jsx
import LastSaved from './components/LastSaved.jsx'
<LastSaved
timestamp="2025-01-15T10:30:00Z"
variant="compact" // 'default', 'badge', 'compact'
/>
```
**Варианты:**
- `default` - полный вид с иконкой
- `badge` - зеленый badge "Сохранено X мин назад"
- `compact` - компактный вид для toolbar
---
### 4. ContextMenu
Компонент контекстного меню для действий с поддержкой правого клика.
**Использование:**
```jsx
import ContextMenu from './components/ContextMenu.jsx'
import { IconEdit, IconTrash, IconCopy } from '@tabler/icons-react'
<ContextMenu
items={[
{ label: 'Редактировать', icon: IconEdit, onClick: handleEdit },
{ label: 'Копировать', icon: IconCopy, onClick: handleCopy },
{ divider: true },
{ label: 'Удалить', icon: IconTrash, onClick: handleDelete, variant: 'danger' }
]}
align="right"
>
{/* Trigger element или оставить пустым для кнопки с тремя точками */}
</ContextMenu>
```
---
### 5. ValidatedInput
Input с real-time валидацией и визуальным feedback.
**Использование:**
```jsx
import ValidatedInput from './components/ValidatedInput.jsx'
const validateDomain = (value) => {
const valid = /^([a-z0-9-]+\.)+[a-z]{2,}$/i.test(value)
return {
valid,
message: valid ? 'Домен валиден' : 'Введите корректный домен (example.com)'
}
}
<ValidatedInput
value={domain}
onChange={(e) => setDomain(e.target.value)}
validate={validateDomain}
label="Домен"
placeholder="example.com"
hint="Введите доменное имя без http://"
required
debounce={300}
/>
```
**Props:**
- `validate` (function) - функция валидации
- `debounce` (number) - задержка перед валидацией
- `showValidIcon` (boolean) - показывать иконку валидации
- `validateOnChange` (boolean) - валидировать при вводе или только при blur
---
### 6. ProgressBar & MultiStepProgress
Компоненты для отображения прогресса операций.
**ProgressBar:**
```jsx
import ProgressBar from './components/ProgressBar.jsx'
<ProgressBar
progress={65}
status="Загрузка данных..."
estimatedTime={45} // секунды
variant="primary"
striped
animated
/>
```
**MultiStepProgress:**
```jsx
import { MultiStepProgress } from './components/ProgressBar.jsx'
<MultiStepProgress
steps={['Валидация', 'Обработка', 'Сохранение', 'Завершение']}
currentStep={1} // текущий шаг (0-indexed)
variant="success"
/>
```
---
### 7. MobileCardView
Компонент для отображения таблиц в виде карточек на мобильных с swipe gestures.
**Использование:**
```jsx
import MobileCardView from './components/MobileCardView.jsx'
<MobileCardView
items={domains}
onItemClick={(item) => console.log('Clicked:', item)}
renderContent={(item) => (
<div>
<div className="fw-bold">{item.domain}</div>
<div className="text-muted small">{item.community}</div>
</div>
)}
actions={[
{ label: 'Редактировать', icon: IconEdit, onClick: handleEdit },
{ label: 'Удалить', icon: IconTrash, onClick: handleDelete, variant: 'danger' }
]}
/>
```
---
### 8. KeyboardShortcutHint
Компонент для отображения горячих клавиш.
**Использование:**
```jsx
import KeyboardShortcutHint, { ShortcutsList } from './components/KeyboardShortcutHint.jsx'
// Внутри кнопки:
<button className="btn btn-primary">
Сохранить
<KeyboardShortcutHint shortcut="Ctrl + S" />
</button>
// Список горячих клавиш:
<ShortcutsList
shortcuts={[
{ description: 'Сохранить изменения', keys: 'Ctrl + S' },
{ description: 'Отменить', keys: 'Ctrl + Z' },
{ description: 'Поиск', keys: 'Ctrl + F' }
]}
/>
```
---
## Улучшенные Компоненты
### ErrorAlert
Добавлены новые возможности:
- Кнопка "Копировать ошибку" для bug reports
- Кнопка "Повторить" для retry операций
- Раскрывающиеся детали ошибки
- Отображение кода ошибки
**Новое использование:**
```jsx
<ErrorAlert
message="Не удалось загрузить данные"
error={{ code: 'E_NETWORK', details: errorDetails }}
onRetry={fetchData}
onClose={() => setError(null)}
showDetails={true}
/>
```
---
### EmptyState
Добавлены:
- Поддержка иллюстраций
- Различные размеры (small, default, large)
- Варианты цветов (success, info, warning)
- Анимация иллюстраций
**Новое использование:**
```jsx
<EmptyState
icon={IconDatabase}
title="Нет доменов"
description="Начните с добавления первого домена"
size="large"
variant="info"
illustration="/illustrations/empty-state.svg"
action={<button className="btn btn-primary">Добавить домен</button>}
/>
```
---
### Pagination
Улучшения:
- Jump to Page для быстрого перехода (показывается при > 10 страниц)
- Иконки вместо текста для навигации
- Улучшенная accessibility
- Адаптивность для мобильных
**Автоматически используется везде, где был старый Pagination**
---
### Dashboard
Улучшения:
- StatCard теперь поддерживает trends
- Добавлен LastSaved в header
- Hover эффекты на карточках (card-hover)
- Tooltips на кнопках
**Изменения в коде:**
```jsx
<StatCard
icon={IconWorld}
value={stats.domainsCount}
title="Доменов"
to="/domains"
trend={true}
previousValue={previousStats?.domainsCount}
/>
```
---
## Примеры Использования
### Пример 1: Форма с валидацией
```jsx
function AddDomainForm() {
const [domain, setDomain] = useState('')
const [community, setCommunity] = useState('')
const validateDomain = (value) => ({
valid: /^([a-z0-9-]+\.)+[a-z]{2,}$/i.test(value),
message: 'Введите корректный домен'
})
const validateCommunity = (value) => ({
valid: /^\d+$/.test(value),
message: 'Введите числовой community'
})
return (
<form>
<ValidatedInput
value={domain}
onChange={(e) => setDomain(e.target.value)}
validate={validateDomain}
label="Домен"
placeholder="example.com"
required
/>
<ValidatedInput
value={community}
onChange={(e) => setCommunity(e.target.value)}
validate={validateCommunity}
label="Community"
placeholder="65000"
required
/>
<button type="submit" className="btn btn-primary">
Добавить
<KeyboardShortcutHint shortcut="Ctrl + Enter" />
</button>
</form>
)
}
```
### Пример 2: Таблица с ContextMenu и MobileCardView
```jsx
function DomainsTable({ domains, onEdit, onDelete }) {
return (
<>
{/* Desktop view */}
<div className="table-responsive d-none d-md-block">
<table className="table">
<tbody>
{domains.map(domain => (
<tr key={domain.id}>
<td>{domain.name}</td>
<td>{domain.community}</td>
<td>
<ContextMenu
items={[
{ label: 'Редактировать', icon: IconEdit, onClick: () => onEdit(domain) },
{ label: 'Удалить', icon: IconTrash, onClick: () => onDelete(domain), variant: 'danger' }
]}
/>
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* Mobile view */}
<MobileCardView
items={domains}
renderContent={(domain) => (
<div>
<div className="fw-bold">{domain.name}</div>
<div className="text-muted small">{domain.community}</div>
</div>
)}
actions={[
{ label: 'Редактировать', icon: IconEdit, onClick: onEdit },
{ label: 'Удалить', icon: IconTrash, onClick: onDelete, variant: 'danger' }
]}
/>
</>
)
}
```
### Пример 3: Dashboard с трендами
```jsx
function Dashboard() {
const [stats, setStats] = useState({})
const [previousStats, setPreviousStats] = useState(null)
const [lastFetchTime, setLastFetchTime] = useState(null)
return (
<div>
<PageHeader
title="Панель"
actions={
<div className="d-flex gap-3">
<LastSaved timestamp={lastFetchTime} variant="compact" />
<Tooltip content="Обновить данные" shortcut="F5">
<button className="btn btn-outline-primary">
<IconRefresh /> Обновить
</button>
</Tooltip>
</div>
}
/>
<div className="row g-3">
<div className="col-md-3">
<StatCard
icon={IconWorld}
value={stats.domains}
title="Доменов"
trend={true}
previousValue={previousStats?.domains}
/>
</div>
</div>
</div>
)
}
```
---
## Best Practices
### 1. Accessibility
- Всегда добавляйте `aria-label` для иконочных кнопок
- Используйте semantic HTML
- Обеспечьте минимум 44x44px для touch targets на мобильных
- Добавляйте keyboard shortcuts для частых действий
### 2. Performance
- Используйте `useMemo` для тяжелых вычислений
- Debounce для валидации форм
- Lazy loading для больших списков
- Virtualization для таблиц > 1000 записей
### 3. User Experience
- Показывайте loading states для всех async операций
- Предоставляйте clear error messages с действиями
- Используйте optimistic updates где возможно
- Сохраняйте состояние форм при навигации
### 4. Mobile First
- Используйте MobileCardView для таблиц
- Убедитесь что все элементы кликабельны на touch screens
- Тестируйте swipe gestures
- Адаптируйте модальные окна для мобильных
---
## Roadmap
Планируемые улучшения:
- [ ] Виртуальный скроллинг для больших таблиц
- [ ] Drag & Drop для изменения порядка
- [ ] Сохранение пользовательских настроек
- [ ] Dark mode improvements
- [ ] Анимированные transitions между страницами
- [ ] PWA support
- [ ] Offline mode
---
## Вклад
При добавлении новых компонентов:
1. Следуйте существующим паттернам
2. Добавляйте JSDoc комментарии
3. Обеспечьте accessibility
4. Тестируйте на мобильных
5. Обновляйте эту документацию
---
**Версия:** 1.0.0
**Последнее обновление:** 2025-01-15