fix(design-preview): переключатели вида и периода на компоненте Tabs
Кнопки с aria-pressed выглядели криво в тёмной теме; заменены на общий Segmented. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
157396613d
commit
0be272f917
4 files changed
+40
-54
No files matched your search
@@ -22,6 +22,7 @@ import {
|
||||
import { Button } from '@authportal/ui/components/button'
|
||||
import { Input } from '@authportal/ui/components/input'
|
||||
import { Label } from '@authportal/ui/components/label'
|
||||
import { Tabs, TabsList, TabsTrigger } from '@authportal/ui/components/tabs'
|
||||
import {
|
||||
Sheet,
|
||||
SheetClose,
|
||||
@@ -367,3 +368,28 @@ export function CodeBlock({ label, children }: { label: string; children: string
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/** Сегментированный переключатель на Tabs (вид таблицы, период). */
|
||||
export function Segmented({
|
||||
label,
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
}: {
|
||||
label: string
|
||||
options: string[]
|
||||
value: number
|
||||
onChange: (index: number) => void
|
||||
}) {
|
||||
return (
|
||||
<Tabs value={String(value)} onValueChange={(v) => onChange(Number(v))} aria-label={label} className="max-w-full">
|
||||
<TabsList className="max-w-full justify-start overflow-x-auto">
|
||||
{options.map((o, i) => (
|
||||
<TabsTrigger key={o} value={String(i)}>
|
||||
{o}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
)
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { AuditRetentionPanel } from '@/components/reui-kit/audit-retention-panel
|
||||
import { KpiStatGrid } from '@/components/reui-kit/kpi-stat-grid'
|
||||
import { Button } from '@authportal/ui/components/button'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@authportal/ui/components/tabs'
|
||||
import { CodeBlock, KvList, PageHead, PreviewSheet, StatesFrame, StatusBadge, TypedConfirm } from '../bits'
|
||||
import { Segmented, CodeBlock, KvList, PageHead, PreviewSheet, StatesFrame, StatusBadge, TypedConfirm } from '../bits'
|
||||
import { MOCK_AUDIT, APP_SHORT, type Tone } from '../mock'
|
||||
import { PreviewSectionGrid, TwoLineCell, type GridColumn } from '../section-grid'
|
||||
|
||||
@@ -85,21 +85,7 @@ export function AuditPage() {
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<div role="group" aria-label="Период" className="bg-muted/60 flex w-fit max-w-full flex-wrap gap-0.5 rounded-lg p-0.5">
|
||||
{['24 ч', '7 д', '30 д', '90 д', 'Весь период'].map((p, i) => (
|
||||
<Button
|
||||
key={p}
|
||||
type="button"
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
aria-pressed={i === period}
|
||||
onClick={() => setPeriod(i)}
|
||||
className={i === period ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}
|
||||
>
|
||||
{p}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<Segmented label="Период" options={['24 ч', '7 д', '30 д', '90 д', 'Весь период']} value={period} onChange={setPeriod} />
|
||||
<KpiStatGrid
|
||||
aria-label="Показатели"
|
||||
items={[
|
||||
|
||||
@@ -5,7 +5,7 @@ import { toast } from 'sonner'
|
||||
import { KpiStatGrid } from '@/components/reui-kit/kpi-stat-grid'
|
||||
import { Button } from '@authportal/ui/components/button'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@authportal/ui/components/tabs'
|
||||
import { CodeBlock, KvList, PageHead, PreviewSheet, SignalAlert, StatesFrame, StatusBadge } from '../bits'
|
||||
import { Segmented, CodeBlock, KvList, PageHead, PreviewSheet, SignalAlert, StatesFrame, StatusBadge } from '../bits'
|
||||
import { MOCK_LOGINS, MOCK_SESSIONS, type LoginRow, type SessionRow } from '../mock'
|
||||
import { PreviewSectionGrid, TwoLineCell, type GridColumn } from '../section-grid'
|
||||
|
||||
@@ -83,21 +83,7 @@ export function LoginsPage() {
|
||||
>
|
||||
6 неудачных входов с 203.0.113.58 за 10 минут. При необходимости отключите учётную запись в разделе «Пользователи».
|
||||
</SignalAlert>
|
||||
<div role="group" aria-label="Период" className="bg-muted/60 flex w-fit max-w-full flex-wrap gap-0.5 rounded-lg p-0.5">
|
||||
{PERIODS.map((p, i) => (
|
||||
<Button
|
||||
key={p}
|
||||
type="button"
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
aria-pressed={i === period}
|
||||
onClick={() => setPeriod(i)}
|
||||
className={i === period ? 'bg-background text-foreground shadow-sm' : 'text-muted-foreground hover:text-foreground'}
|
||||
>
|
||||
{p}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<Segmented label="Период" options={PERIODS} value={period} onChange={setPeriod} />
|
||||
<KpiStatGrid
|
||||
aria-label="Показатели"
|
||||
items={[
|
||||
|
||||
@@ -30,6 +30,7 @@ import { Button } from '@authportal/ui/components/button'
|
||||
import { Separator } from '@authportal/ui/components/separator'
|
||||
import { InputGroup, InputGroupAddon, InputGroupInput } from '@authportal/ui/components/input-group'
|
||||
import { cn } from '@authportal/ui/lib/utils'
|
||||
import { Segmented } from './bits'
|
||||
|
||||
export type GridColumn<T> = {
|
||||
id: string
|
||||
@@ -167,28 +168,15 @@ export function PreviewSectionGrid<T extends object>({
|
||||
<div className="flex flex-wrap items-center justify-between gap-2 px-(--frame-panel-header-px) py-(--frame-panel-header-py)">
|
||||
<div className="flex min-w-0 flex-wrap items-center gap-2">
|
||||
{views ? (
|
||||
<div role="group" aria-label="Вид" className="bg-muted/60 inline-flex flex-wrap gap-0.5 rounded-lg p-0.5">
|
||||
{views.map((v, i) => (
|
||||
<Button
|
||||
key={v.label}
|
||||
type="button"
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
aria-pressed={i === view}
|
||||
onClick={() => {
|
||||
setView(i)
|
||||
setPagination((p) => ({ ...p, pageIndex: 0 }))
|
||||
}}
|
||||
className={cn(
|
||||
i === view
|
||||
? 'bg-background text-foreground shadow-sm'
|
||||
: 'text-muted-foreground hover:text-foreground',
|
||||
)}
|
||||
>
|
||||
{v.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<Segmented
|
||||
label="Вид"
|
||||
options={views.map((v) => v.label)}
|
||||
value={view}
|
||||
onChange={(i) => {
|
||||
setView(i)
|
||||
setPagination((p) => ({ ...p, pageIndex: 0 }))
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{searchText ? (
|
||||
<InputGroup className="w-56 max-w-full">
|
||||
|
||||
Reference in new issue
Block a user