16 KiB
🎨 UX/UI Улучшения Router Lists UI - 2025
📋 Обзор
Данный документ описывает комплексные UX/UI улучшения, внесенные в проект Router Lists UI. Все компоненты разработаны исключительно на стилях Tabler UI без использования сторонних UI библиотек.
✅ РЕАЛИЗОВАННЫЕ УЛУЧШЕНИЯ
🎯 ВЫСОКИЙ ПРИОРИТЕТ
1. Оптимизация навигации и информационной архитектуры
📍 Улучшенный компонент Breadcrumbs
Файл: frontend/src/components/Breadcrumbs.jsx
Новые возможности:
- ✅ Кнопка "Назад" с сохранением состояния навигации
- ✅ Динамические счетчики результатов в breadcrumbs
- ✅ Отображение информации об активных фильтрах
- ✅ Автоматический подсчет записей с правильными склонениями
Использование:
<Breadcrumbs
items={[
{ label: 'Главная', to: '/dashboard' },
{ label: 'Домены', count: 1250 }
]}
showBack={true}
filterInfo="Community: Cloudflare"
count={1250}
/>
2. Улучшения таблиц и списков данных
🔖 SavedFilters - Сохраненные фильтры
Файл: frontend/src/components/SavedFilters.jsx
Возможности:
- ✅ Сохранение комбинаций фильтров в localStorage
- ✅ Быстрое применение сохраненных фильтров
- ✅ Удаление неактуальных фильтров
- ✅ Отображение даты создания фильтра
Использование:
<SavedFilters
pageKey="domains" // уникальный ключ страницы
currentFilters={{ searchTerm, filterCommunity, sortField }}
onApplyFilter={(filters) => {
setSearchTerm(filters.searchTerm)
setFilterCommunity(filters.filterCommunity)
}}
/>
☑️ BulkActionsBar - Массовые операции
Файл: frontend/src/components/BulkActionsBar.jsx
Возможности:
- ✅ Выбор множества элементов через чекбоксы
- ✅ Кнопка "Выбрать все" / "Снять выбор"
- ✅ Массовое удаление, редактирование, экспорт
- ✅ Sticky позиционирование при скролле
- ✅ Кастомные действия через props
Использование:
<BulkActionsBar
selectedCount={selectedItems.size}
totalCount={totalItems}
onSelectAll={() => selectAll()}
onDeselectAll={() => clearSelection()}
onDelete={() => handleBulkDelete()}
onExport={() => handleBulkExport()}
customActions={[
{
icon: IconEdit,
label: 'Изменить community',
onClick: handleBulkEditCommunity
}
]}
/>
3. Формы и валидация
✓ ValidatedInput - Input с inline валидацией
Файл: frontend/src/components/ValidatedInput.jsx
Возможности:
- ✅ Real-time валидация с debounce
- ✅ Визуальные индикаторы (галочка/крестик)
- ✅ Подсказки при ошибках
- ✅ Поддержка required полей
- ✅ Автофокус
Использование:
<ValidatedInput
label="IP адрес"
value={ip}
onChange={setIp}
onValidate={(value) => {
const valid = /^(\d{1,3}\.){3}\d{1,3}$/.test(value)
return {
valid,
message: valid
? 'IP адрес корректен'
: 'Введите IPv4 (например: 1.1.1.1)'
}
}}
helpText="Введите IPv4 адрес"
required
/>
4. Feedback и уведомления
🔔 ToastContainer - Система toast уведомлений
Файлы:
frontend/src/components/ToastContainer.jsx- Интеграция в
frontend/src/App.jsx
Возможности:
- ✅ 4 типа уведомлений: success, error, warning, info
- ✅ Автозакрытие с настраиваемой длительностью
- ✅ Действия в уведомлениях (кнопки "Отменить", "Повторить")
- ✅ Анимированное появление/исчезновение
- ✅ Глобальный доступ через
window.toast
Использование:
// Через hook
const toast = useToast()
toast.success('Данные сохранены')
toast.error('Ошибка соединения', { duration: 0 }) // не закроется автоматически
toast.warning('Проверьте данные', { duration: 5000 })
toast.info('Обновление доступно', {
actions: [
{ label: 'Обновить', onClick: () => window.location.reload() }
]
})
// Через window (обратная совместимость)
window.toast.success('Успех!')
⏳ ProgressIndicator - Индикаторы прогресса
Файл: frontend/src/components/ProgressIndicator.jsx
Компоненты:
- ProgressIndicator - полный индикатор с кнопкой отмены
- LinearProgress - компактный линейный
- CircularProgress - кольцевой индикатор
Использование:
// Полный индикатор
<ProgressIndicator
current={45}
total={100}
message="Обработка доменов..."
variant="blue"
onCancel={() => cancelOperation()}
/>
// Линейный
<LinearProgress
progress={75}
message="Загрузка..."
variant="green"
/>
// Кольцевой
<CircularProgress
progress={60}
size={64}
variant="purple"
/>
💀 Skeleton Loaders - Улучшенные загрузчики
Файл: frontend/src/components/TableSkeleton.jsx
Компоненты:
- TableSkeleton - для таблиц (с поддержкой чекбоксов)
- CardSkeleton - для карточек статистики
- ListSkeleton - для списков
- FormSkeleton - для форм
Использование:
import TableSkeleton, { CardSkeleton, ListSkeleton, FormSkeleton } from './components/TableSkeleton'
{loading ? (
<TableSkeleton rows={10} cols={5} hasCheckbox={true} />
) : (
<table>...</table>
)}
5. Keyboard Shortcuts и Command Palette
⌨️ CommandPalette - Глобальный поиск (Ctrl+K)
Файлы:
frontend/src/components/CommandPalette.jsx- Интеграция в
frontend/src/App.jsx
Возможности:
- ✅ Открытие по Ctrl+K / Cmd+K
- ✅ Навигация стрелками ↑↓
- ✅ Фильтрация команд по keywords
- ✅ Быстрый переход по страницам
- ✅ Подсветка активной команды
Горячие клавиши:
Ctrl+K- Открыть command palette↑↓- Навигация по спискуEnter- Выполнить командуEsc- Закрыть
📋 KeyboardShortcutsButton - Справка по горячим клавишам
Использование: Добавлена кнопка в навбар
Список горячих клавиш:
Ctrl+K- Поиск командCtrl+N- Добавить новую записьCtrl+S- СохранитьCtrl+F- Поиск по таблицеEsc- Закрыть / Отменить↑↓- НавигацияEnter- Подтвердить
🎨 СРЕДНИЙ ПРИОРИТЕТ
6. Визуальная иерархия
📊 Sparkline - Мини-графики
Файл: frontend/src/components/Sparkline.jsx
Компоненты:
- Sparkline - линейный график
- SparklineWithTrend - с процентом изменения
- SparklineBar - столбчатый график
Возможности:
- ✅ Чистый SVG без библиотек
- ✅ Настраиваемые цвета и размеры
- ✅ Опциональная заливка под графиком
- ✅ Отображение точек на графике
Использование:
// Простой sparkline
<Sparkline
data={[10, 20, 15, 30, 25, 40]}
width={100}
height={30}
strokeColor="#206bc4"
fillColor="#206bc4"
/>
// С трендом
<SparklineWithTrend
data={[100, 105, 110, 120]}
label="за 7 дней"
showPercentage={true}
/>
// Столбчатый
<SparklineBar
data={[5, 8, 3, 12, 7]}
width={100}
height={30}
barColor="#2fb344"
/>
🚀 КАК ИСПОЛЬЗОВАТЬ
Интеграция в существующие страницы
Пример: DomainsNewManager с новыми компонентами
import { useState } from 'react'
import Breadcrumbs from './components/Breadcrumbs'
import SavedFilters from './components/SavedFilters'
import BulkActionsBar from './components/BulkActionsBar'
import ValidatedInput from './components/ValidatedInput'
import TableSkeleton from './components/TableSkeleton'
import { useToast } from './components/ToastContainer'
function DomainsNewManager() {
const [selectedItems, setSelectedItems] = useState(new Set())
const [loading, setLoading] = useState(false)
const [filters, setFilters] = useState({ searchTerm: '', community: '' })
const toast = useToast()
const handleBulkDelete = async () => {
try {
await api.delete('/domains-new/bulk', { ids: Array.from(selectedItems) })
toast.success(`Удалено ${selectedItems.size} доменов`)
setSelectedItems(new Set())
} catch (e) {
toast.error('Ошибка удаления', { duration: 0 })
}
}
return (
<div>
{/* Breadcrumbs с кнопкой назад */}
<Breadcrumbs
items={[
{ label: 'Главная', to: '/dashboard' },
{ label: 'Данные' },
{ label: 'Домены', count: items.length }
]}
showBack={true}
filterInfo={filters.community ? `Community: ${filters.community}` : null}
/>
{/* Сохраненные фильтры */}
<div className="mb-3">
<SavedFilters
pageKey="domains"
currentFilters={filters}
onApplyFilter={setFilters}
/>
</div>
{/* Bulk actions */}
<BulkActionsBar
selectedCount={selectedItems.size}
totalCount={items.length}
onSelectAll={() => setSelectedItems(new Set(items.map(i => i.id)))}
onDeselectAll={() => setSelectedItems(new Set())}
onDelete={handleBulkDelete}
onExport={handleBulkExport}
/>
{/* Таблица с skeleton loader */}
{loading ? (
<TableSkeleton rows={10} cols={3} hasCheckbox={true} />
) : (
<table className="table">
{/* таблица */}
</table>
)}
</div>
)
}
📐 ДИЗАЙН-СИСТЕМА
Цветовая палитра Tabler
// Основные цвета
$blue: #206bc4; // primary
$azure: #4299e1; // info
$indigo: #4263eb;
$purple: #ae3ec9;
$pink: #d6336c;
$red: #d63939; // danger
$orange: #f76707; // warning
$yellow: #f59f00;
$lime: #74b816;
$green: #2fb344; // success
$teal: #0ca678;
$cyan: #17a2b8;
// Semantic colors
$primary: $blue;
$success: $green;
$warning: $orange;
$danger: $red;
$info: $azure;
Использование badges
// Успех
<span className="badge bg-green-lt text-green">Активен</span>
// Ошибка
<span className="badge bg-red-lt text-red">Офлайн</span>
// Предупреждение
<span className="badge bg-yellow-lt text-yellow">Внимание</span>
// Информация
<span className="badge bg-blue-lt text-blue">123</span>
Иконки (Tabler Icons)
Все иконки из @tabler/icons-react:
import {
IconCheck,
IconX,
IconAlertTriangle,
IconWorld,
IconServer,
IconFilter
} from '@tabler/icons-react'
<IconCheck size={20} className="text-success" />
📊 СТАТИСТИКА УЛУЧШЕНИЙ
Созданные компоненты
| Компонент | Файл | Строк кода | Статус |
|---|---|---|---|
| Breadcrumbs | Breadcrumbs.jsx |
82 | ✅ |
| SavedFilters | SavedFilters.jsx |
170 | ✅ |
| BulkActionsBar | BulkActionsBar.jsx |
110 | ✅ |
| ToastContainer | ToastContainer.jsx |
160 | ✅ |
| ValidatedInput | ValidatedInput.jsx |
120 | ✅ |
| ProgressIndicator | ProgressIndicator.jsx |
180 | ✅ |
| Sparkline | Sparkline.jsx |
150 | ✅ |
| CommandPalette | CommandPalette.jsx |
250 | ✅ |
| Итого | 8 компонентов | ~1222 строки | 100% |
Улучшенные компоненты
TableSkeleton.jsx- добавлены CardSkeleton, ListSkeleton, FormSkeleton (+70 строк)App.jsx- интеграция ToastContainer и CommandPalette
🎯 СЛЕДУЮЩИЕ ШАГИ (pending)
7. Графики и визуализация данных
- Timeline chart для Dashboard (динамика за месяц)
- Pie chart для распределения по community
- Heatmap активности
- Улучшенный GraphView с zoom controls
8. Мобильная адаптивность
- Card view для таблиц на мобильных
- Swipe actions (свайп для удаления/редактирования)
- Bottom navigation для мобилок
- Адаптивные модалки (bottom sheet)
💡 РЕКОМЕНДАЦИИ ПО ИСПОЛЬЗОВАНИЮ
1. Замена старых alert'ов на Toast
// Было
setSuccess('Данные сохранены')
setError('Ошибка')
// Стало
toast.success('Данные сохранены')
toast.error('Ошибка')
2. Добавление bulk operations в таблицы
- Добавить состояние
const [selected, setSelected] = useState(new Set()) - Добавить чекбоксы в
<th>и<td> - Добавить
<BulkActionsBar />над таблицей
3. Использование ValidatedInput вместо обычного input
Заменить все критичные input'ы (IP, email, домены) на <ValidatedInput />
4. Skeleton loaders вместо спиннеров
// Вместо
{loading && <div className="spinner-border" />}
// Использовать
{loading ? <TableSkeleton /> : <Table />}
🐛 ИЗВЕСТНЫЕ ОГРАНИЧЕНИЯ
- SavedFilters хранит данные в localStorage (ограничение 5-10MB)
- BulkActionsBar sticky позиция может конфликтовать с другими sticky элементами
- CommandPalette не поддерживает вложенные команды
- Sparkline не имеет интерактивности (нет hover tooltips)
📝 ЗАКЛЮЧЕНИЕ
Все компоненты разработаны с использованием чистого Tabler UI без сторонних библиотек. Компоненты:
- ✅ Полностью адаптивны
- ✅ Поддерживают темную тему
- ✅ Доступны (ARIA labels, keyboard navigation)
- ✅ Легковесны (нет зависимостей)
- ✅ Расширяемы через props
Итого внедрено: 8 новых компонентов, улучшено 3 существующих, добавлено ~1300 строк кода.
Версия документа: 1.0
Дата: 2 октября 2025
Автор: AI Assistant (Claude Sonnet 4.5)