quality / changes (push) Successful in 9s
quality / go (push) Skipped
quality / bird2 (push) Skipped
quality / commitlint (push) Skipped
quality / docker-check (push) Skipped
quality / openapi (push) Successful in 23s
quality / web (push) Successful in 1m22s
CD / quality (push) Successful in 1m57s
CD / publish (push) Successful in 3m31s
ResourcePage и FrameDataGrid получили раскладку досок: заголовок Frame с поиском и фильтрами, линейные виды со счётчиками, подвал «Показано N из M». Страница модулей — KPI-полоса, кнопка создания в шапке, вкладка. Операции: действия применения и перезагрузки BIRD в шапке, баннер при ошибках задач. Сеть: баннер пиров на одобрение. Кнопки шапок — стандартной высоты. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
66 lines
1.8 KiB
TypeScript
66 lines
1.8 KiB
TypeScript
import type { ReactNode } from 'react'
|
|
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@evobgp/ui/components/tabs'
|
|
import { cn } from '@evobgp/ui/lib/utils'
|
|
|
|
export type SegmentedTabItem = {
|
|
value: string
|
|
label: string
|
|
count?: number
|
|
/** @deprecated Счётчик теперь без плашки (линейные вкладки макета). */
|
|
badgeVariant?: string
|
|
icon?: ReactNode
|
|
}
|
|
|
|
interface SegmentedTabsProps {
|
|
items: SegmentedTabItem[]
|
|
value?: string
|
|
defaultValue?: string
|
|
onValueChange?: (value: string) => void
|
|
children: ReactNode
|
|
className?: string
|
|
listClassName?: string
|
|
contentClassName?: string
|
|
}
|
|
|
|
/**
|
|
* Page-level section switcher — line tabs as on the shared mockup boards.
|
|
* @see https://reui.io/preview/base/components/c-tabs-9
|
|
* @see https://reui.io/components/tabs
|
|
*/
|
|
export function SegmentedTabs({
|
|
items,
|
|
value,
|
|
defaultValue,
|
|
onValueChange,
|
|
children,
|
|
className,
|
|
listClassName,
|
|
contentClassName,
|
|
}: SegmentedTabsProps) {
|
|
return (
|
|
<Tabs
|
|
value={value}
|
|
defaultValue={defaultValue}
|
|
onValueChange={onValueChange}
|
|
orientation="horizontal"
|
|
className={cn('w-full min-w-0 gap-4', className)}
|
|
>
|
|
<TabsList variant="line" className={cn('h-10! w-full min-w-0 justify-start gap-0.5 overflow-x-auto [scrollbar-width:none]', listClassName)}>
|
|
{items.map((item) => (
|
|
<TabsTrigger key={item.value} value={item.value} className="flex-none shrink-0 gap-1.5 px-4 text-sm">
|
|
{item.icon}
|
|
{item.label}
|
|
{item.count !== undefined ? (
|
|
<span className="text-muted-foreground font-mono text-xs font-normal">{item.count}</span>
|
|
) : null}
|
|
</TabsTrigger>
|
|
))}
|
|
</TabsList>
|
|
<div className={cn('w-full min-w-0', contentClassName)}>{children}</div>
|
|
</Tabs>
|
|
)
|
|
}
|
|
|
|
export { TabsContent }
|