feat: Добавить новые компоненты и улучшения UX/UI, включая Breadcrumbs с динамическими фильтрами, ToastContainer для уведомлений и CommandPalette для глобального поиска. Обновить TableSkeleton с анимацией и добавить новые skeleton компоненты для карточек, списков и форм. Обновить документацию по новым компонентам и улучшениям.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m38s

This commit is contained in:
2025-10-02 18:02:22 +07:00
parent 495063a510
commit 339144fb11
12 changed files with 1950 additions and 24 deletions
+72 -17
View File
@@ -1,25 +1,80 @@
import React from 'react'
import { Link } from 'react-router-dom'
import { Link, useNavigate } from 'react-router-dom'
import { IconArrowLeft, IconFilter } from '@tabler/icons-react'
function Breadcrumbs({ items = [] }) {
/**
* Улучшенный компонент Breadcrumbs с поддержкой:
* - Динамических фильтров
* - Счетчиков результатов
* - Кнопки "Назад" с сохранением состояния
*/
function Breadcrumbs({ items = [], showBack = false, filterInfo = null, count = null }) {
const navigate = useNavigate()
if (!Array.isArray(items) || items.length === 0) return null
const handleBack = () => {
navigate(-1)
}
return (
<nav aria-label="breadcrumb">
<ol className="breadcrumb">
{items.map((it, idx) => (
<li key={idx} className={`breadcrumb-item${idx === items.length - 1 ? ' active' : ''}`} aria-current={idx === items.length - 1 ? 'page' : undefined}>
{it.to && idx !== items.length - 1 ? (
<Link to={it.to}>{it.label}</Link>
) : (
<span>{it.label}</span>
)}
</li>
))}
</ol>
</nav>
<div className="d-flex align-items-center gap-2 flex-wrap">
{/* Кнопка "Назад" */}
{showBack && (
<button
className="btn btn-ghost-secondary btn-sm btn-icon"
onClick={handleBack}
title="Назад"
aria-label="Назад"
>
<IconArrowLeft size={18} />
</button>
)}
{/* Breadcrumbs */}
<nav aria-label="breadcrumb">
<ol className="breadcrumb mb-0">
{items.map((it, idx) => {
const isLast = idx === items.length - 1
return (
<li key={idx} className={`breadcrumb-item${isLast ? ' active' : ''}`} aria-current={isLast ? 'page' : undefined}>
{it.to && !isLast ? (
<Link to={it.to} className="text-decoration-none">
{it.label}
{it.count !== undefined && (
<span className="badge bg-blue-lt text-blue ms-1">{it.count}</span>
)}
</Link>
) : (
<span>
{it.label}
{it.count !== undefined && (
<span className="badge bg-blue-lt text-blue ms-1">{it.count}</span>
)}
</span>
)}
</li>
)
})}
</ol>
</nav>
{/* Информация о фильтрах */}
{filterInfo && (
<span className="badge bg-azure-lt text-azure d-inline-flex align-items-center">
<IconFilter size={14} className="me-1" />
{filterInfo}
</span>
)}
{/* Общий счетчик */}
{count !== null && count !== undefined && (
<span className="text-muted small">
({count} {count === 1 ? 'запись' : count < 5 ? 'записи' : 'записей'})
</span>
)}
</div>
)
}
export default Breadcrumbs