Enhance DataTableCard component with accent and icon support
- Added accent and icon properties to the DataTableCard component for improved visual distinction and context. - Updated multiple pages to utilize the new accent feature, enhancing the user interface with color-coded cards. - Incorporated icons in DataTableCard instances across various routes for better representation of content.
This commit is contained in:
@@ -1,31 +1,57 @@
|
||||
<script lang="ts">
|
||||
import * as Card from '$lib/components/ui/card/index.js';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import { kpiAccent, type KpiAccentKey } from '$lib/kpi-accents.js';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
let {
|
||||
title,
|
||||
description,
|
||||
accent,
|
||||
icon,
|
||||
class: className,
|
||||
toolbar,
|
||||
children
|
||||
}: {
|
||||
/** Без title — как в shadcn dashboard-01: сразу toolbar и таблица */
|
||||
title?: string;
|
||||
description?: string;
|
||||
accent?: KpiAccentKey;
|
||||
icon?: Snippet;
|
||||
toolbar?: Snippet;
|
||||
children: Snippet;
|
||||
class?: string;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<Card.Root density="compact" class={cn('overflow-hidden rounded-lg border border-border shadow-sm', className)}>
|
||||
<Card.Root
|
||||
density="compact"
|
||||
class={cn(
|
||||
'overflow-hidden rounded-lg border border-border shadow-sm',
|
||||
accent && 'border-l-4',
|
||||
accent && kpiAccent[accent].border,
|
||||
className
|
||||
)}
|
||||
>
|
||||
{#if title}
|
||||
<Card.Header class="border-b border-border bg-muted/30 px-4 py-3.5">
|
||||
<Card.Title class="text-base font-semibold">{title}</Card.Title>
|
||||
{#if description}
|
||||
<Card.Description class="text-xs sm:text-sm">{description}</Card.Description>
|
||||
{/if}
|
||||
<div class="flex gap-3">
|
||||
{#if icon && accent}
|
||||
<div
|
||||
class={cn(
|
||||
'flex size-10 shrink-0 items-center justify-center rounded-lg',
|
||||
kpiAccent[accent].iconWrap
|
||||
)}
|
||||
>
|
||||
{@render icon()}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="min-w-0 flex-1 space-y-0.5">
|
||||
<Card.Title class="text-base font-semibold">{title}</Card.Title>
|
||||
{#if description}
|
||||
<Card.Description class="text-xs sm:text-sm">{description}</Card.Description>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</Card.Header>
|
||||
{/if}
|
||||
{#if toolbar}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
import GlobeIcon from '@lucide/svelte/icons/globe';
|
||||
import CloudUploadIcon from '@lucide/svelte/icons/cloud-upload';
|
||||
import LockIcon from '@lucide/svelte/icons/lock';
|
||||
import UsersIcon from '@lucide/svelte/icons/users';
|
||||
import { nextSortDir, compareStrings, compareNum, type SortDir } from '$lib/table-sort.js';
|
||||
|
||||
let loading = $state(true);
|
||||
@@ -619,7 +620,9 @@ async function handleAliasFilterChange(nextAlias: string) {
|
||||
class="mb-6"
|
||||
title="Активные IP (агрегат)"
|
||||
description="С GeoIP при включённой базе на шлюзе"
|
||||
accent="teal"
|
||||
>
|
||||
{#snippet icon()}<GlobeIcon class="size-5" aria-hidden="true" />{/snippet}
|
||||
{#snippet toolbar()}
|
||||
<DataTableToolbar>
|
||||
<div class="relative max-w-xs flex-1">
|
||||
@@ -751,7 +754,9 @@ async function handleAliasFilterChange(nextAlias: string) {
|
||||
class="mb-6"
|
||||
title="По нодам"
|
||||
description="Health, версия, аптайм, bad connections"
|
||||
accent="violet"
|
||||
>
|
||||
{#snippet icon()}<ServerIcon class="size-5" aria-hidden="true" />{/snippet}
|
||||
{#snippet toolbar()}
|
||||
<DataTableToolbar>
|
||||
<div class="relative max-w-xs flex-1">
|
||||
@@ -910,7 +915,9 @@ async function handleAliasFilterChange(nextAlias: string) {
|
||||
class="mt-6"
|
||||
title="Топ пользователей по трафику"
|
||||
description="До 10 записей из summary"
|
||||
accent="info"
|
||||
>
|
||||
{#snippet icon()}<UsersIcon class="size-5" aria-hidden="true" />{/snippet}
|
||||
{#snippet toolbar()}
|
||||
<DataTableToolbar>
|
||||
<div class="relative max-w-xs flex-1">
|
||||
|
||||
@@ -346,7 +346,8 @@
|
||||
</KpiStatCard>
|
||||
</div>
|
||||
|
||||
<DataTableCard title="Инциденты" description="Список и разбор">
|
||||
<DataTableCard title="Инциденты" description="Список и разбор" accent="danger">
|
||||
{#snippet icon()}<SirenIcon class="size-5" aria-hidden="true" />{/snippet}
|
||||
{#snippet toolbar()}
|
||||
<DataTableToolbar>
|
||||
<div class="relative max-w-md flex-1">
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import SearchIcon from '@lucide/svelte/icons/search';
|
||||
import { nextSortDir, compareStrings, type SortDir } from '$lib/table-sort.js';
|
||||
import MapIcon from '@lucide/svelte/icons/map';
|
||||
import GlobeIcon from '@lucide/svelte/icons/globe';
|
||||
import { Alert, AlertDescription, AlertTitle } from '$lib/components/ui/alert/index.js';
|
||||
import { Button } from '$lib/components/ui/button/index.js';
|
||||
import { Badge } from '$lib/components/ui/badge/index.js';
|
||||
@@ -617,7 +618,8 @@ $effect(() => {
|
||||
</Alert>
|
||||
{/if}
|
||||
|
||||
<DataTableCard title="Уникальные IP" description="Снимок шлюза: активные и недавние списки">
|
||||
<DataTableCard title="Уникальные IP" description="Снимок шлюза: активные и недавние списки" accent="teal">
|
||||
{#snippet icon()}<GlobeIcon class="size-5" aria-hidden="true" />{/snippet}
|
||||
{#snippet toolbar()}
|
||||
<DataTableToolbar>
|
||||
<div class="relative max-w-md flex-1">
|
||||
|
||||
@@ -391,7 +391,9 @@
|
||||
<DataTableCard
|
||||
title="Последние инциденты из снимка"
|
||||
description="Всего: {snapshot?.counts?.total ?? snapshot?.incidents?.length ?? 0}"
|
||||
accent="warning"
|
||||
>
|
||||
{#snippet icon()}<ActivityIcon class="size-5" aria-hidden="true" />{/snippet}
|
||||
{#snippet toolbar()}
|
||||
<DataTableToolbar>
|
||||
<div class="relative max-w-md flex-1">
|
||||
|
||||
@@ -260,7 +260,9 @@
|
||||
<DataTableCard
|
||||
title="Ноды"
|
||||
description="Контроллер и метрики. Ниже — компактные группы прокси (автозагрузка). «Детально» — обзор с графиками."
|
||||
accent="violet"
|
||||
>
|
||||
{#snippet icon()}<ServerIcon class="size-5" aria-hidden="true" />{/snippet}
|
||||
<ScrollArea class="w-full" orientation="both">
|
||||
<Table.Root>
|
||||
<Table.Header class="sticky top-0 z-10 bg-muted">
|
||||
|
||||
@@ -440,7 +440,8 @@ let sumActiveIps = $derived.by(() =>
|
||||
</KpiStatCard>
|
||||
</div>
|
||||
|
||||
<DataTableCard>
|
||||
<DataTableCard title="Пользователи" description="Слияние по имени между серверами" accent="violet">
|
||||
{#snippet icon()}<UsersIcon class="size-5" aria-hidden="true" />{/snippet}
|
||||
{#snippet toolbar()}
|
||||
<div class="border-b border-border">
|
||||
<div class="flex flex-wrap items-center justify-between gap-2 px-3 py-2.5">
|
||||
|
||||
Reference in New Issue
Block a user