Enhance frontend documentation and UI components; update frontend-shadcn.mdc to include UI patterns reference; improve navigation structure in AppSidebar by categorizing items; refactor DataTableCard to support empty states with EmptyState component; implement ConfirmDialog for delete actions in DnsRecordsTable and GroupsPage; add search functionality in CertificatesPage and GroupsPage for better user experience; update ServiceEditSheet to utilize tabs for organization.
Build, Test, and Push CFDM Docker Image / test (push) Has been cancelled
Build, Test, and Push CFDM Docker Image / build-and-push (push) Has been cancelled
Build, Test, and Push CFDM Docker Image / create-release (push) Has been cancelled
Build, Test, and Push CFDM Docker Image / update-wiki (push) Has been cancelled
Build, Test, and Push CFDM Docker Image / test (push) Has been cancelled
Build, Test, and Push CFDM Docker Image / build-and-push (push) Has been cancelled
Build, Test, and Push CFDM Docker Image / create-release (push) Has been cancelled
Build, Test, and Push CFDM Docker Image / update-wiki (push) Has been cancelled
This commit is contained in:
1 parent
d11414666f
commit
4a70cf5854
32 files changed
+1546
-435
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { Link, useRouterState } from '@tanstack/react-router'
|
||||
import { Link, useMatches, useRouterState } from '@tanstack/react-router'
|
||||
import { useMemo } from 'react'
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
@@ -10,31 +11,39 @@ import {
|
||||
import { Separator } from '@cfdm/ui/components/separator'
|
||||
import { SidebarTrigger } from '@cfdm/ui/components/sidebar'
|
||||
|
||||
export interface RouteBreadcrumbLoaderData {
|
||||
breadcrumb?: string
|
||||
}
|
||||
|
||||
const routeTitles: Record<string, string> = {
|
||||
'/': 'Панель управления',
|
||||
'/domains': 'Домены',
|
||||
'/groups': 'Группы',
|
||||
'/groups': 'Группы доменов',
|
||||
'/services': 'Сервисы',
|
||||
'/certificates': 'Сертификаты',
|
||||
}
|
||||
|
||||
function getBreadcrumbs(pathname: string) {
|
||||
function getBreadcrumbs(
|
||||
pathname: string,
|
||||
dynamicLabels: Record<string, string>,
|
||||
) {
|
||||
if (pathname === '/') {
|
||||
return [{ label: 'Панель управления', href: '/' }]
|
||||
}
|
||||
|
||||
if (pathname.match(/^\/groups\/\d+$/)) {
|
||||
return [
|
||||
{ label: 'Группы', href: '/groups' },
|
||||
{ label: 'Группа', href: pathname },
|
||||
{ label: 'Группы доменов', href: '/groups' },
|
||||
{ label: dynamicLabels[pathname] ?? 'Группа', href: pathname },
|
||||
]
|
||||
}
|
||||
|
||||
if (pathname.match(/^\/domains\/\d+\/dns$/)) {
|
||||
const domainId = pathname.split('/')[2]
|
||||
const domainPath = `/domains/${domainId}`
|
||||
return [
|
||||
{ label: 'Домены', href: '/domains' },
|
||||
{ label: 'Домен', href: `/domains/${domainId}` },
|
||||
{ label: dynamicLabels[domainPath] ?? 'Домен', href: domainPath },
|
||||
{ label: 'DNS', href: pathname },
|
||||
]
|
||||
}
|
||||
@@ -42,7 +51,7 @@ function getBreadcrumbs(pathname: string) {
|
||||
if (pathname.match(/^\/domains\/\d+$/)) {
|
||||
return [
|
||||
{ label: 'Домены', href: '/domains' },
|
||||
{ label: 'Обзор домена', href: pathname },
|
||||
{ label: dynamicLabels[pathname] ?? 'Обзор домена', href: pathname },
|
||||
]
|
||||
}
|
||||
|
||||
@@ -54,9 +63,24 @@ function getBreadcrumbs(pathname: string) {
|
||||
return [{ label: 'Панель управления', href: '/' }]
|
||||
}
|
||||
|
||||
function useDynamicBreadcrumbLabels() {
|
||||
const matches = useMatches()
|
||||
return useMemo(() => {
|
||||
const labels: Record<string, string> = {}
|
||||
for (const match of matches) {
|
||||
const data = match.loaderData as RouteBreadcrumbLoaderData | undefined
|
||||
if (data?.breadcrumb && match.pathname) {
|
||||
labels[match.pathname] = data.breadcrumb
|
||||
}
|
||||
}
|
||||
return labels
|
||||
}, [matches])
|
||||
}
|
||||
|
||||
export function SiteHeader() {
|
||||
const pathname = useRouterState({ select: (s) => s.location.pathname })
|
||||
const crumbs = getBreadcrumbs(pathname)
|
||||
const dynamicLabels = useDynamicBreadcrumbLabels()
|
||||
const crumbs = getBreadcrumbs(pathname, dynamicLabels)
|
||||
|
||||
return (
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
|
||||
@@ -72,8 +96,12 @@ export function SiteHeader() {
|
||||
const isLast = index === crumbs.length - 1
|
||||
return (
|
||||
<span key={crumb.href} className="contents">
|
||||
{index > 0 && <BreadcrumbSeparator className="hidden md:block" />}
|
||||
<BreadcrumbItem className={index === 0 ? 'hidden md:block' : undefined}>
|
||||
{index > 0 && (
|
||||
<BreadcrumbSeparator className="hidden md:block" />
|
||||
)}
|
||||
<BreadcrumbItem
|
||||
className={index === 0 ? 'hidden md:block' : undefined}
|
||||
>
|
||||
{isLast ? (
|
||||
<BreadcrumbPage>{crumb.label}</BreadcrumbPage>
|
||||
) : (
|
||||
|
||||
Reference in new issue
Block a user