fix(design-preview): переключатели вида и периода на компоненте Tabs
Кнопки с aria-pressed выглядели криво в тёмной теме; заменены на общий Segmented. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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 { Button } from '@authportal/ui/components/button'
|
||||||
import { Input } from '@authportal/ui/components/input'
|
import { Input } from '@authportal/ui/components/input'
|
||||||
import { Label } from '@authportal/ui/components/label'
|
import { Label } from '@authportal/ui/components/label'
|
||||||
|
import { Tabs, TabsList, TabsTrigger } from '@authportal/ui/components/tabs'
|
||||||
import {
|
import {
|
||||||
Sheet,
|
Sheet,
|
||||||
SheetClose,
|
SheetClose,
|
||||||
@@ -367,3 +368,28 @@ export function CodeBlock({ label, children }: { label: string; children: string
|
|||||||
</div>
|
</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 { KpiStatGrid } from '@/components/reui-kit/kpi-stat-grid'
|
||||||
import { Button } from '@authportal/ui/components/button'
|
import { Button } from '@authportal/ui/components/button'
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@authportal/ui/components/tabs'
|
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 { MOCK_AUDIT, APP_SHORT, type Tone } from '../mock'
|
||||||
import { PreviewSectionGrid, TwoLineCell, type GridColumn } from '../section-grid'
|
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">
|
<Segmented label="Период" options={['24 ч', '7 д', '30 д', '90 д', 'Весь период']} value={period} onChange={setPeriod} />
|
||||||
{['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>
|
|
||||||
<KpiStatGrid
|
<KpiStatGrid
|
||||||
aria-label="Показатели"
|
aria-label="Показатели"
|
||||||
items={[
|
items={[
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { toast } from 'sonner'
|
|||||||
import { KpiStatGrid } from '@/components/reui-kit/kpi-stat-grid'
|
import { KpiStatGrid } from '@/components/reui-kit/kpi-stat-grid'
|
||||||
import { Button } from '@authportal/ui/components/button'
|
import { Button } from '@authportal/ui/components/button'
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@authportal/ui/components/tabs'
|
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 { MOCK_LOGINS, MOCK_SESSIONS, type LoginRow, type SessionRow } from '../mock'
|
||||||
import { PreviewSectionGrid, TwoLineCell, type GridColumn } from '../section-grid'
|
import { PreviewSectionGrid, TwoLineCell, type GridColumn } from '../section-grid'
|
||||||
|
|
||||||
@@ -83,21 +83,7 @@ export function LoginsPage() {
|
|||||||
>
|
>
|
||||||
6 неудачных входов с 203.0.113.58 за 10 минут. При необходимости отключите учётную запись в разделе «Пользователи».
|
6 неудачных входов с 203.0.113.58 за 10 минут. При необходимости отключите учётную запись в разделе «Пользователи».
|
||||||
</SignalAlert>
|
</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">
|
<Segmented label="Период" options={PERIODS} value={period} onChange={setPeriod} />
|
||||||
{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>
|
|
||||||
<KpiStatGrid
|
<KpiStatGrid
|
||||||
aria-label="Показатели"
|
aria-label="Показатели"
|
||||||
items={[
|
items={[
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { Button } from '@authportal/ui/components/button'
|
|||||||
import { Separator } from '@authportal/ui/components/separator'
|
import { Separator } from '@authportal/ui/components/separator'
|
||||||
import { InputGroup, InputGroupAddon, InputGroupInput } from '@authportal/ui/components/input-group'
|
import { InputGroup, InputGroupAddon, InputGroupInput } from '@authportal/ui/components/input-group'
|
||||||
import { cn } from '@authportal/ui/lib/utils'
|
import { cn } from '@authportal/ui/lib/utils'
|
||||||
|
import { Segmented } from './bits'
|
||||||
|
|
||||||
export type GridColumn<T> = {
|
export type GridColumn<T> = {
|
||||||
id: string
|
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 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">
|
<div className="flex min-w-0 flex-wrap items-center gap-2">
|
||||||
{views ? (
|
{views ? (
|
||||||
<div role="group" aria-label="Вид" className="bg-muted/60 inline-flex flex-wrap gap-0.5 rounded-lg p-0.5">
|
<Segmented
|
||||||
{views.map((v, i) => (
|
label="Вид"
|
||||||
<Button
|
options={views.map((v) => v.label)}
|
||||||
key={v.label}
|
value={view}
|
||||||
type="button"
|
onChange={(i) => {
|
||||||
size="xs"
|
setView(i)
|
||||||
variant="ghost"
|
setPagination((p) => ({ ...p, pageIndex: 0 }))
|
||||||
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>
|
|
||||||
) : null}
|
) : null}
|
||||||
{searchText ? (
|
{searchText ? (
|
||||||
<InputGroup className="w-56 max-w-full">
|
<InputGroup className="w-56 max-w-full">
|
||||||
|
|||||||
Reference in new issue
Block a user