refactor: improve code consistency and formatting across components
CI / changes (push) Successful in 7s
CI / openapi (push) Has been skipped
CI / web (push) Successful in 29s
CI / go (push) Has been skipped
CI / docker-web (push) Successful in 1m22s
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Has been skipped
CI / docker-go (push) Has been skipped

- Standardized formatting in various Svelte components for better readability.
- Updated README.md and .prettierrc for consistent styling and improved documentation.
- Refactored class attributes in UI components to enhance clarity and maintainability.
- Adjusted layout files to ensure proper alignment and spacing in the application interface.
This commit is contained in:
Denozordec
2026-05-20 00:37:00 +07:00
parent 6bee5adc34
commit c263fd5c7e
173 changed files with 1608 additions and 1015 deletions
+1 -4
View File
@@ -3,10 +3,7 @@
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": [
"prettier-plugin-svelte",
"prettier-plugin-tailwindcss"
],
"plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
"tailwindStylesheet": "./src/routes/layout.css",
"overrides": [
{
+1 -5
View File
@@ -1,7 +1,3 @@
{
"recommendations": [
"svelte.svelte-vscode",
"bradlc.vscode-tailwindcss",
"esbenp.prettier-vscode"
]
"recommendations": ["svelte.svelte-vscode", "bradlc.vscode-tailwindcss", "esbenp.prettier-vscode"]
}
+6 -6
View File
@@ -6,12 +6,12 @@ SvelteKit-приложение панели управления EvoBGP. Зап
## UI-архитектура
| Путь | Назначение |
|------|------------|
| `src/lib/ui/core/` | shadcn-svelte (только через `npx shadcn-svelte@latest add … -y -o`) |
| `src/lib/ui/app/` | Layout, PageHeader, toast (`notify`) |
| `src/lib/ui/patterns/` | FormField, AppDataTable, ConfirmDialog, EmptyState |
| `src/lib/components/ui/` | Re-export на `ui/core` (совместимость) |
| Путь | Назначение |
| ------------------------ | ------------------------------------------------------------------- |
| `src/lib/ui/core/` | shadcn-svelte (только через `npx shadcn-svelte@latest add … -y -o`) |
| `src/lib/ui/app/` | Layout, PageHeader, toast (`notify`) |
| `src/lib/ui/patterns/` | FormField, AppDataTable, ConfirmDialog, EmptyState |
| `src/lib/components/ui/` | Re-export на `ui/core` (совместимость) |
Токены темы: `src/routes/layout.css`. Справочник: `src/lib/ui/app/tokens.md`.
@@ -1,7 +1,13 @@
<script lang="ts">
import type { RevisionDiff, RevisionPrefix, RevisionRow } from '$lib/api/types.js';
import { Button } from '$lib/components/ui/button/index.js';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '$lib/components/ui/card/index.js';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle
} from '$lib/components/ui/card/index.js';
import { sortRevisionDiffItems } from '$lib/sort-prefixes.js';
type Props = {
@@ -79,7 +85,7 @@
<select
value={diffRevA}
onchange={(e) => onDiffRevAChange((e.currentTarget as HTMLSelectElement).value)}
class="border-border bg-background h-8 min-w-0 flex-1 rounded-md border px-2 text-sm"
class="h-8 min-w-0 flex-1 rounded-md border border-border bg-background px-2 text-sm"
>
<option value="">Ревизия A</option>
{#each revisions as rev (rev.id)}
@@ -89,51 +95,58 @@
<select
value={diffRevB}
onchange={(e) => onDiffRevBChange((e.currentTarget as HTMLSelectElement).value)}
class="border-border bg-background h-8 min-w-0 flex-1 rounded-md border px-2 text-sm"
class="h-8 min-w-0 flex-1 rounded-md border border-border bg-background px-2 text-sm"
>
<option value="">Ревизия B</option>
{#each revisions as rev (rev.id)}
<option value={rev.id}>{rev.id.slice(0, 8)} ({formatDate(rev.created_at)})</option>
{/each}
</select>
<Button size="sm" class="shrink-0 self-start sm:self-auto" onclick={onLoadDiff} disabled={diffLoading}>
<Button
size="sm"
class="shrink-0 self-start sm:self-auto"
onclick={onLoadDiff}
disabled={diffLoading}
>
{diffLoading ? 'Загрузка…' : 'Сравнить'}
</Button>
</div>
{#if diffData}
<div
class="border-border grid min-h-0 grid-cols-1 overflow-hidden rounded-md border sm:grid-cols-2"
class="grid min-h-0 grid-cols-1 overflow-hidden rounded-md border border-border sm:grid-cols-2"
style="scrollbar-gutter: stable;"
>
<!-- + Добавлено -->
<div class="border-border flex min-h-0 min-w-0 flex-col border-b sm:border-r sm:border-b-0">
<div class="flex min-h-0 min-w-0 flex-col border-b border-border sm:border-r sm:border-b-0">
<div
class="border-border bg-muted/60 flex shrink-0 items-center border-b px-3 py-2 font-mono text-xs font-semibold text-green-600 dark:text-green-400"
class="flex shrink-0 items-center border-b border-border bg-muted/60 px-3 py-2 font-mono text-xs font-semibold text-green-600 dark:text-green-400"
>
<span class="text-muted-foreground mr-2 w-10 shrink-0 select-none text-right">+</span>
<span class="mr-2 w-10 shrink-0 text-right text-muted-foreground select-none">+</span>
<span>Добавлено ({addedSorted.length})</span>
</div>
<div
bind:this={scrollAddedEl}
class="bg-background/50 max-h-[min(28rem,70vh)] min-h-0 overflow-x-auto overflow-y-scroll overscroll-contain"
class="max-h-[min(28rem,70vh)] min-h-0 overflow-x-auto overflow-y-scroll overscroll-contain bg-background/50"
onscroll={syncFromAdded}
>
{#if addedSorted.length === 0}
<p class="text-muted-foreground p-3 font-mono text-xs">Нет изменений</p>
<p class="p-3 font-mono text-xs text-muted-foreground">Нет изменений</p>
{:else}
<table class="w-full border-collapse font-mono text-xs">
<tbody>
{#each addedSorted as line, i (`a-${i}-${line}`)}
<tr
class="border-border/50 hover:bg-muted/30 border-b border-l-2 border-l-green-500/80 bg-green-500/[0.08] dark:bg-green-500/15"
class="border-b border-l-2 border-border/50 border-l-green-500/80 bg-green-500/[0.08] hover:bg-muted/30 dark:bg-green-500/15"
>
<td
class="text-muted-foreground w-10 shrink-0 border-r border-transparent py-0.5 pr-1 pl-2 text-right align-top text-[11px] tabular-nums select-none"
class="w-10 shrink-0 border-r border-transparent py-0.5 pr-1 pl-2 text-right align-top text-[11px] text-muted-foreground tabular-nums select-none"
>
{i + 1}
</td>
<td class="text-foreground max-w-0 break-all py-0.5 pr-3 pl-1 whitespace-pre-wrap">
<td
class="max-w-0 py-0.5 pr-3 pl-1 break-all whitespace-pre-wrap text-foreground"
>
{line}
</td>
</tr>
@@ -147,31 +160,33 @@
<!-- Удалено -->
<div class="flex min-h-0 min-w-0 flex-col">
<div
class="border-border bg-muted/60 flex shrink-0 items-center border-b px-3 py-2 font-mono text-xs font-semibold text-red-600 dark:text-red-400"
class="flex shrink-0 items-center border-b border-border bg-muted/60 px-3 py-2 font-mono text-xs font-semibold text-red-600 dark:text-red-400"
>
<span class="text-muted-foreground mr-2 w-10 shrink-0 select-none text-right"></span>
<span class="mr-2 w-10 shrink-0 text-right text-muted-foreground select-none"></span>
<span>Удалено ({removedSorted.length})</span>
</div>
<div
bind:this={scrollRemovedEl}
class="bg-background/50 max-h-[min(28rem,70vh)] min-h-0 overflow-x-auto overflow-y-scroll overscroll-contain"
class="max-h-[min(28rem,70vh)] min-h-0 overflow-x-auto overflow-y-scroll overscroll-contain bg-background/50"
onscroll={syncFromRemoved}
>
{#if removedSorted.length === 0}
<p class="text-muted-foreground p-3 font-mono text-xs">Нет изменений</p>
<p class="p-3 font-mono text-xs text-muted-foreground">Нет изменений</p>
{:else}
<table class="w-full border-collapse font-mono text-xs">
<tbody>
{#each removedSorted as line, i (`r-${i}-${line}`)}
<tr
class="border-border/50 hover:bg-muted/30 border-b border-l-2 border-l-red-500/80 bg-red-500/[0.08] dark:bg-red-500/15"
class="border-b border-l-2 border-border/50 border-l-red-500/80 bg-red-500/[0.08] hover:bg-muted/30 dark:bg-red-500/15"
>
<td
class="text-muted-foreground w-10 shrink-0 border-r border-transparent py-0.5 pr-1 pl-2 text-right align-top text-[11px] tabular-nums select-none"
class="w-10 shrink-0 border-r border-transparent py-0.5 pr-1 pl-2 text-right align-top text-[11px] text-muted-foreground tabular-nums select-none"
>
{i + 1}
</td>
<td class="text-foreground max-w-0 break-all py-0.5 pr-3 pl-1 whitespace-pre-wrap">
<td
class="max-w-0 py-0.5 pr-3 pl-1 break-all whitespace-pre-wrap text-foreground"
>
{line}
</td>
</tr>
@@ -61,7 +61,7 @@
<div class="space-y-3 rounded-lg border border-border/80 bg-muted/15 p-3">
<div class="flex flex-wrap items-center gap-2">
<Filter class="text-muted-foreground size-4 shrink-0" aria-hidden="true" />
<Filter class="size-4 shrink-0 text-muted-foreground" aria-hidden="true" />
<span class="text-sm font-medium">Фильтры задач</span>
<div class="ml-auto flex flex-wrap gap-1.5">
<Button
@@ -84,7 +84,14 @@
>
В работе
</Button>
<Button type="button" variant="ghost" size="sm" class="h-7 text-xs" {disabled} onclick={onResetFilters}>
<Button
type="button"
variant="ghost"
size="sm"
class="h-7 text-xs"
{disabled}
onclick={onResetFilters}
>
<X class="size-3.5" aria-hidden="true" />
Сброс
</Button>
@@ -93,7 +100,7 @@
<div class="relative">
<Search
class="text-muted-foreground pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2"
class="pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground"
aria-hidden="true"
/>
<Input
@@ -113,7 +120,7 @@
<Label for="job-filter-status" class="text-xs">Статус</Label>
<select
id="job-filter-status"
class="border-border bg-background h-9 w-full rounded-md border px-2 text-sm"
class="h-9 w-full rounded-md border border-border bg-background px-2 text-sm"
value={filterStatus}
onchange={(e) => onFilterStatusChange((e.currentTarget as HTMLSelectElement).value)}
{disabled}
@@ -127,7 +134,7 @@
<Label for="job-filter-kind" class="text-xs">Тип задачи</Label>
<select
id="job-filter-kind"
class="border-border bg-background h-9 w-full rounded-md border px-2 text-sm"
class="h-9 w-full rounded-md border border-border bg-background px-2 text-sm"
value={filterKind}
onchange={(e) => onFilterKindChange((e.currentTarget as HTMLSelectElement).value)}
{disabled}
@@ -141,7 +148,7 @@
<Label for="job-filter-module" class="text-xs">Модуль (локально)</Label>
<select
id="job-filter-module"
class="border-border bg-background h-9 w-full rounded-md border px-2 text-sm"
class="h-9 w-full rounded-md border border-border bg-background px-2 text-sm"
value={filterModuleId}
onchange={(e) => onFilterModuleIdChange((e.currentTarget as HTMLSelectElement).value)}
{disabled}
@@ -87,7 +87,7 @@
<CardDescription class="flex flex-wrap items-center gap-x-2 gap-y-1">
<span>Фоновые задачи (ingest, применение, обновление)</span>
{#if jobsFetchedTotal !== undefined}
<span class="text-muted-foreground font-normal tabular-nums">
<span class="font-normal text-muted-foreground tabular-nums">
· Показано {jobs.length} из {jobsFetchedTotal}
</span>
{/if}
@@ -163,20 +163,18 @@
<div
class="rounded-md border border-chart-1/25 bg-chart-1/5 px-2.5 py-2 dark:bg-chart-1/10"
>
<p
class="text-chart-1 flex items-center gap-1 text-[11px] font-medium uppercase"
>
<p class="flex items-center gap-1 text-[11px] font-medium text-chart-1 uppercase">
<CircleDot class="size-3.5 shrink-0" aria-hidden="true" />
Статус
</p>
<Badge class="mt-1" variant={jobStatusVariant(job.status)}>{jobStatusRu(job.status)}</Badge>
<Badge class="mt-1" variant={jobStatusVariant(job.status)}
>{jobStatusRu(job.status)}</Badge
>
</div>
<div
class="rounded-md border border-chart-2/25 bg-chart-2/5 px-2.5 py-2 dark:bg-chart-2/10"
>
<p
class="text-chart-2 flex items-center gap-1 text-[11px] font-medium uppercase"
>
<p class="flex items-center gap-1 text-[11px] font-medium text-chart-2 uppercase">
<CalendarClock class="size-3.5 shrink-0" aria-hidden="true" />
Создана
</p>
@@ -185,9 +183,7 @@
<div
class="rounded-md border border-chart-3/25 bg-chart-3/5 px-2.5 py-2 dark:bg-chart-3/10"
>
<p
class="text-chart-3 flex items-center gap-1 text-[11px] font-medium uppercase"
>
<p class="flex items-center gap-1 text-[11px] font-medium text-chart-3 uppercase">
<PlayCircle class="size-3.5 shrink-0" aria-hidden="true" />
Запущена
</p>
@@ -196,9 +192,7 @@
<div
class="rounded-md border border-chart-4/25 bg-chart-4/5 px-2.5 py-2 dark:bg-chart-4/10"
>
<p
class="text-chart-4 flex items-center gap-1 text-[11px] font-medium uppercase"
>
<p class="flex items-center gap-1 text-[11px] font-medium text-chart-4 uppercase">
<Flag class="size-3.5 shrink-0" aria-hidden="true" />
Завершена
</p>
@@ -343,7 +337,7 @@
class="min-w-0 overflow-hidden rounded-md border border-chart-1/30 bg-chart-1/5 p-2.5 dark:bg-chart-1/10"
>
<p
class="text-chart-1 flex items-center gap-1 text-[11px] font-medium uppercase"
class="flex items-center gap-1 text-[11px] font-medium text-chart-1 uppercase"
>
<Layers class="size-3.5 shrink-0" aria-hidden="true" />
Агрегация
@@ -354,7 +348,7 @@
class="min-w-0 overflow-hidden rounded-md border border-chart-2/30 bg-chart-2/5 p-2.5 dark:bg-chart-2/10"
>
<p
class="text-chart-2 flex items-center gap-1 text-[11px] font-medium uppercase"
class="flex items-center gap-1 text-[11px] font-medium text-chart-2 uppercase"
>
<Globe class="size-3.5 shrink-0" aria-hidden="true" />
Домены
@@ -365,7 +359,7 @@
class="min-w-0 overflow-hidden rounded-md border border-chart-3/30 bg-chart-3/5 p-2.5 dark:bg-chart-3/10"
>
<p
class="text-chart-3 flex items-center gap-1 text-[11px] font-medium uppercase"
class="flex items-center gap-1 text-[11px] font-medium text-chart-3 uppercase"
>
<Binary class="size-3.5 shrink-0" aria-hidden="true" />
ASN
@@ -376,7 +370,7 @@
class="min-w-0 overflow-hidden rounded-md border border-chart-4/30 bg-chart-4/5 p-2.5 dark:bg-chart-4/10"
>
<p
class="text-chart-4 flex items-center gap-1 text-[11px] font-medium uppercase"
class="flex items-center gap-1 text-[11px] font-medium text-chart-4 uppercase"
>
<Link2 class="size-3.5 shrink-0" aria-hidden="true" />
CDN / IP-диапазоны
@@ -427,7 +421,9 @@
/>
</div>
<div class="min-w-0 space-y-1.5 rounded-lg border p-3">
<p class="text-sm font-medium">IP-диапазоны: итог по статическим диапазонам</p>
<p class="text-sm font-medium">
IP-диапазоны: итог по статическим диапазонам
</p>
<JobReportTableBlock
rows={jobReport.ipRanges as RowData[]}
columns={reportCols}
@@ -18,7 +18,9 @@
onReload: () => void;
onRefreshBirdStatus: () => void;
onOpenBirdProtocols: () => void;
birdHealthyBadgeVariant: (h: boolean | null | undefined) => 'default' | 'secondary' | 'outline' | 'destructive';
birdHealthyBadgeVariant: (
h: boolean | null | undefined
) => 'default' | 'secondary' | 'outline' | 'destructive';
birdHealthyShortLabel: (h: boolean | null | undefined) => string;
};
@@ -38,24 +40,28 @@
<div class="grid grid-cols-1 items-stretch gap-3 sm:grid-cols-2 xl:grid-cols-3">
<Card
class={cn(
'min-w-0 overflow-hidden border-l-4 border-l-chart-1 bg-chart-1/5 p-4 shadow-sm'
)}
class={cn('min-w-0 overflow-hidden border-l-4 border-l-chart-1 bg-chart-1/5 p-4 shadow-sm')}
>
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div class="flex min-w-0 flex-1 gap-3">
<div
class="bg-chart-1/20 flex size-11 shrink-0 items-center justify-center rounded-xl"
class="flex size-11 shrink-0 items-center justify-center rounded-xl bg-chart-1/20"
aria-hidden="true"
>
<Play class="text-chart-1 size-5" />
<Play class="size-5 text-chart-1" />
</div>
<div class="min-w-0 flex-1 space-y-1">
<p class="font-semibold">Применить ко всем спикерам</p>
<p class="text-muted-foreground max-w-[42ch] text-sm">Применить текущую конфигурацию на всех BIRD-спикерах</p>
<p class="max-w-[42ch] text-sm text-muted-foreground">
Применить текущую конфигурацию на всех BIRD-спикерах
</p>
</div>
</div>
<Button class="w-full shrink-0 self-start sm:w-auto sm:self-auto" onclick={onApply} disabled={applying}>
<Button
class="w-full shrink-0 self-start sm:w-auto sm:self-auto"
onclick={onApply}
disabled={applying}
>
<Play class="size-4" aria-hidden="true" />
Применить
</Button>
@@ -63,21 +69,21 @@
</Card>
<Card
class={cn(
'min-w-0 overflow-hidden border-l-4 border-l-chart-4 bg-chart-4/5 p-4 shadow-sm'
)}
class={cn('min-w-0 overflow-hidden border-l-4 border-l-chart-4 bg-chart-4/5 p-4 shadow-sm')}
>
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div class="flex min-w-0 flex-1 gap-3">
<div
class="bg-chart-4/20 flex size-11 shrink-0 items-center justify-center rounded-xl"
class="flex size-11 shrink-0 items-center justify-center rounded-xl bg-chart-4/20"
aria-hidden="true"
>
<RotateCcw class="text-chart-4 size-5" />
<RotateCcw class="size-5 text-chart-4" />
</div>
<div class="min-w-0 flex-1 space-y-1">
<p class="font-semibold">Перезагрузка BIRD</p>
<p class="text-muted-foreground max-w-[42ch] text-sm">Перезагрузить конфигурацию BIRD на всех спикерах</p>
<p class="max-w-[42ch] text-sm text-muted-foreground">
Перезагрузить конфигурацию BIRD на всех спикерах
</p>
</div>
</div>
<Button
@@ -101,26 +107,32 @@
<div class="min-w-0 flex-1 space-y-1">
<div class="flex flex-wrap items-center gap-2">
<div
class="bg-info/15 mr-0.5 flex size-9 items-center justify-center rounded-lg"
class="mr-0.5 flex size-9 items-center justify-center rounded-lg bg-info/15"
aria-hidden="true"
>
<Bird class="text-info size-5 shrink-0" />
<Bird class="size-5 shrink-0 text-info" />
</div>
<p class="font-semibold">Состояние BIRD</p>
{#if birdStatus}
<Badge variant={birdHealthyBadgeVariant(birdStatus.healthy)}>{birdHealthyShortLabel(birdStatus.healthy)}</Badge>
<Badge variant={birdHealthyBadgeVariant(birdStatus.healthy)}
>{birdHealthyShortLabel(birdStatus.healthy)}</Badge
>
{/if}
</div>
<p class="text-foreground/80 max-w-[56ch] text-sm">
Локально на хосте API: <code class="bg-muted rounded px-1 text-xs">birdc show protocols</code>. Не заменяет мониторинг спикеров.
<p class="max-w-[56ch] text-sm text-foreground/80">
Локально на хосте API: <code class="rounded bg-muted px-1 text-xs"
>birdc show protocols</code
>. Не заменяет мониторинг спикеров.
</p>
{#if birdLoading}
<p class="text-foreground/80 text-sm">Загрузка…</p>
<p class="text-sm text-foreground/80">Загрузка…</p>
{:else if birdStatus}
{#if !birdStatus.birdc_configured}
<p class="text-foreground/80 text-sm">{birdStatus.message ?? 'birdc не настроен на API.'}</p>
<p class="text-sm text-foreground/80">
{birdStatus.message ?? 'birdc не настроен на API.'}
</p>
{:else if birdStatus.error}
<p class="text-destructive text-sm">{birdStatus.error}</p>
<p class="text-sm text-destructive">{birdStatus.error}</p>
{:else}
<p class="text-sm">
<span class="text-muted-foreground">BGP сессий:</span>
@@ -131,7 +143,7 @@
</p>
{/if}
{:else}
<p class="text-foreground/80 text-sm">Статус не загружен</p>
<p class="text-sm text-foreground/80">Статус не загружен</p>
{/if}
</div>
@@ -1,7 +1,13 @@
<script lang="ts">
import type { RevisionRow } from '$lib/api/types.js';
import { Button } from '$lib/components/ui/button/index.js';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '$lib/components/ui/card/index.js';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle
} from '$lib/components/ui/card/index.js';
import {
Table,
TableBody,
@@ -41,60 +47,69 @@
<div class="min-w-0 flex-1">
<CardTitle class="text-base">История ревизий</CardTitle>
<CardDescription class="max-w-[75ch]">
Создаются задачей module_refresh (CDN / IP / AS и т.д.); в превью есть полный текст BIRD с инклюдами
Создаются задачей module_refresh (CDN / IP / AS и т.д.); в превью есть полный текст BIRD с
инклюдами
</CardDescription>
</div>
<Button variant="outline" size="sm" class="shrink-0 self-start sm:self-auto" onclick={onReload} disabled={revLoading}>
<Button
variant="outline"
size="sm"
class="shrink-0 self-start sm:self-auto"
onclick={onReload}
disabled={revLoading}
>
<RefreshCw class={revLoading ? 'animate-spin' : ''} />
</Button>
</CardHeader>
<CardContent class="min-w-0 p-0">
<div class="max-w-full overflow-x-auto overscroll-x-contain [scrollbar-gutter:stable]">
<Table class="min-w-[44rem]">
<TableHeader>
<TableRow>
<TableHead>ID</TableHead>
<TableHead>Создана</TableHead>
<TableHead>Префиксов</TableHead>
<TableHead>Хэш</TableHead>
<TableHead class="w-32"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{#each revisions as rev (rev.id)}
<Table class="min-w-[44rem]">
<TableHeader>
<TableRow>
<TableCell class="font-mono text-xs">{rev.id.slice(0, 8)}</TableCell>
<TableCell class="text-sm">{formatDate(rev.created_at)}</TableCell>
<TableCell>{rev.materialized_prefix_count}</TableCell>
<TableCell class="font-mono text-xs text-muted-foreground">{rev.content_hash.slice(0, 12)}</TableCell>
<TableCell>
<div class="flex gap-1">
<Button variant="ghost" size="icon-sm" onclick={() => onOpenPreview(rev)}>
<Eye class="size-3.5" />
</Button>
<Button variant="ghost" size="icon-sm" onclick={() => onRollbackRequest(rev)}>
<Undo class="size-3.5" />
</Button>
<Button
variant="ghost"
size="icon-sm"
title="Скачать диагностический лог"
onclick={() => onDownloadDiagnosticLog(rev)}
>
<Download class="size-3.5" />
</Button>
</div>
</TableCell>
<TableHead>ID</TableHead>
<TableHead>Создана</TableHead>
<TableHead>Префиксов</TableHead>
<TableHead>Хэш</TableHead>
<TableHead class="w-32"></TableHead>
</TableRow>
{:else}
<TableRow>
<TableCell colspan={5} class="text-muted-foreground py-8 text-center">
{revLoading ? 'Загрузка…' : 'Нет ревизий'}
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
</TableHeader>
<TableBody>
{#each revisions as rev (rev.id)}
<TableRow>
<TableCell class="font-mono text-xs">{rev.id.slice(0, 8)}</TableCell>
<TableCell class="text-sm">{formatDate(rev.created_at)}</TableCell>
<TableCell>{rev.materialized_prefix_count}</TableCell>
<TableCell class="font-mono text-xs text-muted-foreground"
>{rev.content_hash.slice(0, 12)}</TableCell
>
<TableCell>
<div class="flex gap-1">
<Button variant="ghost" size="icon-sm" onclick={() => onOpenPreview(rev)}>
<Eye class="size-3.5" />
</Button>
<Button variant="ghost" size="icon-sm" onclick={() => onRollbackRequest(rev)}>
<Undo class="size-3.5" />
</Button>
<Button
variant="ghost"
size="icon-sm"
title="Скачать диагностический лог"
onclick={() => onDownloadDiagnosticLog(rev)}
>
<Download class="size-3.5" />
</Button>
</div>
</TableCell>
</TableRow>
{:else}
<TableRow>
<TableCell colspan={5} class="text-muted-foreground py-8 text-center">
{revLoading ? 'Загрузка…' : 'Нет ревизий'}
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
</div>
</CardContent>
</Card>
+4 -1
View File
@@ -53,7 +53,10 @@ function parseIPv6(addrPart: string): { words: number[]; pl: number } | null {
}
const missing = 8 - left.length - right.length;
if (missing < 0) return null;
return { words: [...left.map(parseGroup), ...Array(missing).fill(0), ...right.map(parseGroup)], pl: 128 };
return {
words: [...left.map(parseGroup), ...Array(missing).fill(0), ...right.map(parseGroup)],
pl: 128
};
}
type SortKey =
+2 -2
View File
@@ -18,10 +18,10 @@
</script>
<TooltipProvider delayDuration={0}>
<div class="bg-background flex min-h-screen">
<div class="flex min-h-screen bg-background">
<AppSidebar bind:collapsed bind:theme />
<div class="flex min-w-0 flex-1 flex-col">
<div class="border-border flex items-center gap-2 border-b px-4 py-2 md:hidden">
<div class="flex items-center gap-2 border-b border-border px-4 py-2 md:hidden">
<AppMobileNav bind:open={mobileNavOpen} bind:theme />
<span class="font-semibold tracking-tight">EvoBGP</span>
</div>
@@ -28,12 +28,12 @@
<Menu class="size-5" />
</Button>
</SheetTrigger>
<SheetContent side="left" class="bg-sidebar text-sidebar-foreground flex w-72 flex-col gap-0 p-0">
<SheetHeader class="border-border border-b p-4 text-left">
<SheetContent side="left" class="flex w-72 flex-col gap-0 bg-sidebar p-0 text-sidebar-foreground">
<SheetHeader class="border-b border-border p-4 text-left">
<SheetTitle>
<a href={resolve('/')} class="font-semibold tracking-tight no-underline">EvoBGP</a>
</SheetTitle>
<p class="text-sidebar-foreground/50 text-xs font-normal">Панель управления</p>
<p class="text-xs font-normal text-sidebar-foreground/50">Панель управления</p>
</SheetHeader>
<div class="flex items-center gap-2 px-4 py-2">
<ThemeMenu bind:theme />
@@ -25,8 +25,13 @@
function linkClass(active: boolean, iconOnly: boolean) {
return cn(
buttonVariants({ variant: active ? 'secondary' : 'ghost', size: iconOnly ? 'icon-sm' : 'sm' }),
iconOnly ? 'flex w-full items-center justify-center no-underline' : 'flex w-full items-center justify-start gap-2 no-underline',
buttonVariants({
variant: active ? 'secondary' : 'ghost',
size: iconOnly ? 'icon-sm' : 'sm'
}),
iconOnly
? 'flex w-full items-center justify-center no-underline'
: 'flex w-full items-center justify-start gap-2 no-underline',
active &&
(iconOnly
? 'ring-sidebar-primary/50 bg-sidebar-accent/90 text-sidebar-accent-foreground ring-1'
+6 -5
View File
@@ -20,7 +20,7 @@
<aside
class={cn(
'border-border bg-sidebar sticky top-0 hidden h-screen shrink-0 flex-col overflow-hidden border-r transition-all duration-200 md:flex',
'sticky top-0 hidden h-screen shrink-0 flex-col overflow-hidden border-r border-border bg-sidebar transition-all duration-200 md:flex',
collapsed ? 'w-14' : 'w-56'
)}
aria-label="Основная навигация"
@@ -28,10 +28,11 @@
<div class={cn('flex items-center gap-2 p-3', collapsed && 'justify-center')}>
{#if !collapsed}
<div class="min-w-0 flex-1">
<a href={resolve('/')} class="text-sidebar-foreground block truncate font-semibold tracking-tight"
>EvoBGP</a
<a
href={resolve('/')}
class="block truncate font-semibold tracking-tight text-sidebar-foreground">EvoBGP</a
>
<p class="text-sidebar-foreground/50 truncate text-xs">Панель управления</p>
<p class="truncate text-xs text-sidebar-foreground/50">Панель управления</p>
</div>
{/if}
<ThemeMenu bind:theme />
@@ -40,7 +41,7 @@
onclick={() => (collapsed = !collapsed)}
class={cn(
buttonVariants({ variant: 'ghost', size: 'icon-sm' }),
'text-sidebar-foreground/60 hover:text-sidebar-foreground shrink-0'
'shrink-0 text-sidebar-foreground/60 hover:text-sidebar-foreground'
)}
aria-label={collapsed ? 'Развернуть меню' : 'Свернуть меню'}
>
+2 -2
View File
@@ -15,7 +15,7 @@
<header
class={cn(
'border-border bg-background/95 supports-[backdrop-filter]:bg-background/60 sticky top-0 z-30 flex flex-col gap-3 border-b px-4 py-3 backdrop-blur md:px-6',
'sticky top-0 z-30 flex flex-col gap-3 border-b border-border bg-background/95 px-4 py-3 backdrop-blur supports-[backdrop-filter]:bg-background/60 md:px-6',
className
)}
>
@@ -28,7 +28,7 @@
<h1 class="text-lg font-semibold tracking-tight md:text-xl">{title}</h1>
{/if}
{#if description}
<p class="text-muted-foreground mt-0.5 text-sm">{description}</p>
<p class="mt-0.5 text-sm text-muted-foreground">{description}</p>
{/if}
</div>
{#if actions}
+5 -2
View File
@@ -14,14 +14,17 @@
import Moon from '@lucide/svelte/icons/moon';
import Monitor from '@lucide/svelte/icons/monitor';
let { theme = $bindable<ThemePreference>('system'), class: className }: { theme?: ThemePreference; class?: string } = $props();
let {
theme = $bindable<ThemePreference>('system'),
class: className
}: { theme?: ThemePreference; class?: string } = $props();
</script>
<DropdownMenu>
<DropdownMenuTrigger
class={cn(
buttonVariants({ variant: 'ghost', size: 'icon-sm' }),
'text-sidebar-foreground/60 hover:text-sidebar-foreground shrink-0',
'shrink-0 text-sidebar-foreground/60 hover:text-sidebar-foreground',
className
)}
aria-label="Тема оформления"
@@ -30,7 +30,7 @@
<div class="min-w-0">
<h1 class="text-2xl font-semibold tracking-tight">{title}</h1>
{#if description}
<p class="text-muted-foreground mt-1 text-sm">{description}</p>
<p class="mt-1 text-sm text-muted-foreground">{description}</p>
{/if}
</div>
</div>
+4 -4
View File
@@ -4,10 +4,10 @@
## Layout
| Token | Значение | Tailwind |
|-------|----------|----------|
| `--page-padding` | 1.5rem | `p-page` через `p-[var(--page-padding)]` |
| `--section-gap` | 1.5rem | `gap-section` |
| Token | Значение | Tailwind |
| ---------------- | -------- | ---------------------------------------- |
| `--page-padding` | 1.5rem | `p-page` через `p-[var(--page-padding)]` |
| `--section-gap` | 1.5rem | `gap-section` |
## Радиусы
@@ -1,17 +1,17 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import {
buttonVariants,
type ButtonVariant,
type ButtonSize,
} from "$lib/ui/core/button/index.js";
import { cn } from "$lib/utils.js";
type ButtonSize
} from '$lib/ui/core/button/index.js';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
class: className,
variant = "default",
size = "default",
variant = 'default',
size = 'default',
...restProps
}: AlertDialogPrimitive.ActionProps & {
variant?: ButtonVariant;
@@ -22,6 +22,6 @@
<AlertDialogPrimitive.Action
bind:ref
data-slot="alert-dialog-action"
class={cn(buttonVariants({ variant, size }), "cn-alert-dialog-action", className)}
class={cn(buttonVariants({ variant, size }), 'cn-alert-dialog-action', className)}
{...restProps}
/>
@@ -1,17 +1,17 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import {
buttonVariants,
type ButtonVariant,
type ButtonSize,
} from "$lib/ui/core/button/index.js";
import { cn } from "$lib/utils.js";
type ButtonSize
} from '$lib/ui/core/button/index.js';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
class: className,
variant = "outline",
size = "default",
variant = 'outline',
size = 'default',
...restProps
}: AlertDialogPrimitive.CancelProps & {
variant?: ButtonVariant;
@@ -22,6 +22,6 @@
<AlertDialogPrimitive.Cancel
bind:ref
data-slot="alert-dialog-cancel"
class={cn(buttonVariants({ variant, size }), "cn-alert-dialog-cancel", className)}
class={cn(buttonVariants({ variant, size }), 'cn-alert-dialog-cancel', className)}
{...restProps}
/>
@@ -1,18 +1,18 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import AlertDialogPortal from "./alert-dialog-portal.svelte";
import AlertDialogOverlay from "./alert-dialog-overlay.svelte";
import { cn, type WithoutChild, type WithoutChildrenOrChild } from "$lib/utils.js";
import type { ComponentProps } from "svelte";
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import AlertDialogPortal from './alert-dialog-portal.svelte';
import AlertDialogOverlay from './alert-dialog-overlay.svelte';
import { cn, type WithoutChild, type WithoutChildrenOrChild } from '$lib/utils.js';
import type { ComponentProps } from 'svelte';
let {
ref = $bindable(null),
class: className,
size = "default",
size = 'default',
portalProps,
...restProps
}: WithoutChild<AlertDialogPrimitive.ContentProps> & {
size?: "default" | "sm";
size?: 'default' | 'sm';
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof AlertDialogPortal>>;
} = $props();
</script>
@@ -24,7 +24,7 @@
data-slot="alert-dialog-content"
data-size={size}
class={cn(
"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-popover text-popover-foreground ring-foreground/10 gap-4 rounded-xl p-4 ring-1 duration-100 data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 outline-none",
'group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm',
className
)}
{...restProps}
@@ -1,6 +1,6 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -12,6 +12,9 @@
<AlertDialogPrimitive.Description
bind:ref
data-slot="alert-dialog-description"
class={cn("text-muted-foreground *:[a]:hover:text-foreground text-sm text-balance md:text-pretty *:[a]:underline *:[a]:underline-offset-3", className)}
class={cn(
'text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground',
className
)}
{...restProps}
/>
@@ -1,6 +1,6 @@
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from '$lib/utils.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
@@ -14,7 +14,7 @@
bind:this={ref}
data-slot="alert-dialog-footer"
class={cn(
"bg-muted/50 -mx-4 -mb-4 rounded-b-xl border-t p-4 flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
'-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end',
className
)}
{...restProps}
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,10 @@
<div
bind:this={ref}
data-slot="alert-dialog-header"
class={cn("grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]", className)}
class={cn(
'grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]',
className
)}
{...restProps}
>
{@render children?.()}
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,10 @@
<div
bind:this={ref}
data-slot="alert-dialog-media"
class={cn("bg-muted mb-2 inline-flex size-10 items-center justify-center rounded-md sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6", className)}
class={cn(
"mb-2 inline-flex size-10 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6",
className
)}
{...restProps}
>
{@render children?.()}
@@ -1,6 +1,6 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -12,6 +12,9 @@
<AlertDialogPrimitive.Overlay
bind:ref
data-slot="alert-dialog-overlay"
class={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50", className)}
class={cn(
'fixed inset-0 z-50 bg-black/10 duration-100 data-closed:animate-out data-closed:fade-out-0 data-open:animate-in data-open:fade-in-0 supports-backdrop-filter:backdrop-blur-xs',
className
)}
{...restProps}
/>
@@ -1,5 +1,5 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
let { ...restProps }: AlertDialogPrimitive.PortalProps = $props();
</script>
@@ -1,6 +1,6 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -12,6 +12,9 @@
<AlertDialogPrimitive.Title
bind:ref
data-slot="alert-dialog-title"
class={cn("text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2", className)}
class={cn(
'text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2',
className
)}
{...restProps}
/>
@@ -1,5 +1,5 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
let { ref = $bindable(null), ...restProps }: AlertDialogPrimitive.TriggerProps = $props();
</script>
@@ -1,5 +1,5 @@
<script lang="ts">
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
import { AlertDialog as AlertDialogPrimitive } from 'bits-ui';
let { open = $bindable(false), ...restProps }: AlertDialogPrimitive.RootProps = $props();
</script>
+13 -13
View File
@@ -1,15 +1,15 @@
import Root from "./alert-dialog.svelte";
import Portal from "./alert-dialog-portal.svelte";
import Trigger from "./alert-dialog-trigger.svelte";
import Title from "./alert-dialog-title.svelte";
import Action from "./alert-dialog-action.svelte";
import Cancel from "./alert-dialog-cancel.svelte";
import Footer from "./alert-dialog-footer.svelte";
import Header from "./alert-dialog-header.svelte";
import Overlay from "./alert-dialog-overlay.svelte";
import Content from "./alert-dialog-content.svelte";
import Description from "./alert-dialog-description.svelte";
import Media from "./alert-dialog-media.svelte";
import Root from './alert-dialog.svelte';
import Portal from './alert-dialog-portal.svelte';
import Trigger from './alert-dialog-trigger.svelte';
import Title from './alert-dialog-title.svelte';
import Action from './alert-dialog-action.svelte';
import Cancel from './alert-dialog-cancel.svelte';
import Footer from './alert-dialog-footer.svelte';
import Header from './alert-dialog-header.svelte';
import Overlay from './alert-dialog-overlay.svelte';
import Content from './alert-dialog-content.svelte';
import Description from './alert-dialog-description.svelte';
import Media from './alert-dialog-media.svelte';
export {
Root,
@@ -36,5 +36,5 @@ export {
Overlay as AlertDialogOverlay,
Content as AlertDialogContent,
Description as AlertDialogDescription,
Media as AlertDialogMedia,
Media as AlertDialogMedia
};
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
<div
bind:this={ref}
data-slot="alert-action"
class={cn("absolute top-2 right-2", className)}
class={cn('absolute top-2 right-2', className)}
{...restProps}
>
{@render children?.()}
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -14,7 +14,7 @@
bind:this={ref}
data-slot="alert-description"
class={cn(
"text-muted-foreground text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3",
'text-sm text-balance text-muted-foreground md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4',
className
)}
{...restProps}
+3 -3
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -14,7 +14,7 @@
bind:this={ref}
data-slot="alert-title"
class={cn(
"font-medium group-has-[>svg]/alert:col-start-2 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3",
'font-medium group-has-[>svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground',
className
)}
{...restProps}
+11 -10
View File
@@ -1,30 +1,31 @@
<script lang="ts" module>
import { type VariantProps, tv } from "tailwind-variants";
import { type VariantProps, tv } from 'tailwind-variants';
export const alertVariants = tv({
base: "grid gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4 group/alert relative w-full",
variants: {
variant: {
default: "bg-card text-card-foreground",
destructive: "text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current",
},
default: 'bg-card text-card-foreground',
destructive:
'text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current'
}
},
defaultVariants: {
variant: "default",
},
variant: 'default'
}
});
export type AlertVariant = VariantProps<typeof alertVariants>["variant"];
export type AlertVariant = VariantProps<typeof alertVariants>['variant'];
</script>
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
class: className,
variant = "default",
variant = 'default',
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
+6 -6
View File
@@ -1,8 +1,8 @@
import Root from "./alert.svelte";
import Description from "./alert-description.svelte";
import Title from "./alert-title.svelte";
import Action from "./alert-action.svelte";
export { alertVariants, type AlertVariant } from "./alert.svelte";
import Root from './alert.svelte';
import Description from './alert-description.svelte';
import Title from './alert-title.svelte';
import Action from './alert-action.svelte';
export { alertVariants, type AlertVariant } from './alert.svelte';
export {
Root,
@@ -13,5 +13,5 @@ export {
Root as Alert,
Description as AlertDescription,
Title as AlertTitle,
Action as AlertAction,
Action as AlertAction
};
+17 -16
View File
@@ -1,35 +1,36 @@
<script lang="ts" module>
import { type VariantProps, tv } from "tailwind-variants";
import { type VariantProps, tv } from 'tailwind-variants';
export const badgeVariants = tv({
base: "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive group/badge inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap transition-colors focus-visible:ring-[3px] [&>svg]:pointer-events-none",
base: 'h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive group/badge inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap transition-colors focus-visible:ring-[3px] [&>svg]:pointer-events-none',
variants: {
variant: {
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
link: "text-primary underline-offset-4 hover:underline",
},
default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',
secondary: 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80',
destructive:
'bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20',
outline: 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground',
ghost: 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50',
link: 'text-primary underline-offset-4 hover:underline'
}
},
defaultVariants: {
variant: "default",
},
variant: 'default'
}
});
export type BadgeVariant = VariantProps<typeof badgeVariants>["variant"];
export type BadgeVariant = VariantProps<typeof badgeVariants>['variant'];
</script>
<script lang="ts">
import type { HTMLAnchorAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAnchorAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
href,
class: className,
variant = "default",
variant = 'default',
children,
...restProps
}: WithElementRef<HTMLAnchorAttributes> & {
@@ -38,7 +39,7 @@
</script>
<svelte:element
this={href ? "a" : "span"}
this={href ? 'a' : 'span'}
bind:this={ref}
data-slot="badge"
{href}
+2 -2
View File
@@ -1,2 +1,2 @@
export { default as Badge } from "./badge.svelte";
export { badgeVariants, type BadgeVariant } from "./badge.svelte";
export { default as Badge } from './badge.svelte';
export { badgeVariants, type BadgeVariant } from './badge.svelte';
+32 -25
View File
@@ -1,38 +1,45 @@
<script lang="ts" module>
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from "svelte/elements";
import { type VariantProps, tv } from "tailwind-variants";
import { cn, type WithElementRef } from '$lib/utils.js';
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
import { type VariantProps, tv } from 'tailwind-variants';
export const buttonVariants = tv({
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-lg border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 active:not-aria-[haspopup]:translate-y-px aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 group/button inline-flex shrink-0 items-center justify-center whitespace-nowrap transition-all outline-none select-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
variants: {
variant: {
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
outline: "border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
destructive: "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
link: "text-primary underline-offset-4 hover:underline",
default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',
outline:
'border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground',
secondary:
'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',
ghost:
'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',
destructive:
'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',
link: 'text-primary underline-offset-4 hover:underline'
},
size: {
default: "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
default:
'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
icon: "size-8",
"icon-xs": "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
"icon-sm": "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
"icon-lg": "size-9",
},
lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
icon: 'size-8',
'icon-xs':
"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
'icon-sm':
'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',
'icon-lg': 'size-9'
}
},
defaultVariants: {
variant: "default",
size: "default",
},
variant: 'default',
size: 'default'
}
});
export type ButtonVariant = VariantProps<typeof buttonVariants>["variant"];
export type ButtonSize = VariantProps<typeof buttonVariants>["size"];
export type ButtonVariant = VariantProps<typeof buttonVariants>['variant'];
export type ButtonSize = VariantProps<typeof buttonVariants>['size'];
export type ButtonProps = WithElementRef<HTMLButtonAttributes> &
WithElementRef<HTMLAnchorAttributes> & {
@@ -44,11 +51,11 @@
<script lang="ts">
let {
class: className,
variant = "default",
size = "default",
variant = 'default',
size = 'default',
ref = $bindable(null),
href = undefined,
type = "button",
type = 'button',
disabled,
children,
...restProps
@@ -62,7 +69,7 @@
class={cn(buttonVariants({ variant, size }), className)}
href={disabled ? undefined : href}
aria-disabled={disabled}
role={disabled ? "link" : undefined}
role={disabled ? 'link' : undefined}
tabindex={disabled ? -1 : undefined}
{...restProps}
>
+3 -3
View File
@@ -2,8 +2,8 @@ import Root, {
type ButtonProps,
type ButtonSize,
type ButtonVariant,
buttonVariants,
} from "./button.svelte";
buttonVariants
} from './button.svelte';
export {
Root,
@@ -13,5 +13,5 @@ export {
buttonVariants,
type ButtonProps,
type ButtonSize,
type ButtonVariant,
type ButtonVariant
};
+3 -3
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from '$lib/utils.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
@@ -14,7 +14,7 @@
bind:this={ref}
data-slot="card-action"
class={cn(
"cn-card-action col-start-2 row-span-2 row-start-1 self-start justify-self-end",
'cn-card-action col-start-2 row-span-2 row-start-1 self-start justify-self-end',
className
)}
{...restProps}
+3 -3
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
<div
bind:this={ref}
data-slot="card-content"
class={cn("px-4 group-data-[size=sm]/card:px-3", className)}
class={cn('px-4 group-data-[size=sm]/card:px-3', className)}
{...restProps}
>
{@render children?.()}
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
<p
bind:this={ref}
data-slot="card-description"
class={cn("text-muted-foreground text-sm", className)}
class={cn('text-sm text-muted-foreground', className)}
{...restProps}
>
{@render children?.()}
+6 -3
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from '$lib/utils.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
@@ -13,7 +13,10 @@
<div
bind:this={ref}
data-slot="card-footer"
class={cn("bg-muted/50 rounded-b-xl border-t p-4 group-data-[size=sm]/card:p-3 flex items-center", className)}
class={cn(
'flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3',
className
)}
{...restProps}
>
{@render children?.()}
+3 -3
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from '$lib/utils.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
@@ -14,7 +14,7 @@
bind:this={ref}
data-slot="card-header"
class={cn(
"gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]",
'group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3',
className
)}
{...restProps}
+3 -3
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
<div
bind:this={ref}
data-slot="card-title"
class={cn("text-base leading-snug font-medium group-data-[size=sm]/card:text-sm", className)}
class={cn('text-base leading-snug font-medium group-data-[size=sm]/card:text-sm', className)}
{...restProps}
>
{@render children?.()}
+8 -5
View File
@@ -1,21 +1,24 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
class: className,
children,
size = "default",
size = 'default',
...restProps
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & { size?: "default" | "sm" } = $props();
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & { size?: 'default' | 'sm' } = $props();
</script>
<div
bind:this={ref}
data-slot="card"
data-size={size}
class={cn("ring-foreground/10 bg-card text-card-foreground gap-4 overflow-hidden rounded-xl py-4 text-sm ring-1 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl group/card flex flex-col", className)}
class={cn(
'group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl',
className
)}
{...restProps}
>
{@render children?.()}
+8 -8
View File
@@ -1,10 +1,10 @@
import Root from "./card.svelte";
import Content from "./card-content.svelte";
import Description from "./card-description.svelte";
import Footer from "./card-footer.svelte";
import Header from "./card-header.svelte";
import Title from "./card-title.svelte";
import Action from "./card-action.svelte";
import Root from './card.svelte';
import Content from './card-content.svelte';
import Description from './card-description.svelte';
import Footer from './card-footer.svelte';
import Header from './card-header.svelte';
import Title from './card-title.svelte';
import Action from './card-action.svelte';
export {
Root,
@@ -21,5 +21,5 @@ export {
Footer as CardFooter,
Header as CardHeader,
Title as CardTitle,
Action as CardAction,
Action as CardAction
};
+6 -6
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { Checkbox as CheckboxPrimitive } from "bits-ui";
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
import { Checkbox as CheckboxPrimitive } from 'bits-ui';
import { cn, type WithoutChildrenOrChild } from '$lib/utils.js';
import CheckIcon from '@lucide/svelte/icons/check';
import MinusIcon from '@lucide/svelte/icons/minus';
@@ -17,7 +17,7 @@
bind:ref
data-slot="checkbox"
class={cn(
"border-input dark:bg-input/30 data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary data-checked:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 flex size-4 items-center justify-center rounded-[4px] border transition-colors group-has-disabled/field:opacity-50 focus-visible:ring-3 aria-invalid:ring-3 peer relative shrink-0 outline-none after:absolute after:-inset-x-3 after:-inset-y-2 disabled:cursor-not-allowed disabled:opacity-50",
'peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 dark:data-checked:bg-primary',
className
)}
bind:checked
@@ -27,12 +27,12 @@
{#snippet children({ checked, indeterminate })}
<div
data-slot="checkbox-indicator"
class="[&>svg]:size-3.5 grid place-content-center text-current transition-none"
class="grid place-content-center text-current transition-none [&>svg]:size-3.5"
>
{#if checked}
<CheckIcon />
<CheckIcon />
{:else if indeterminate}
<MinusIcon />
<MinusIcon />
{/if}
</div>
{/snippet}
+2 -2
View File
@@ -1,6 +1,6 @@
import Root from "./checkbox.svelte";
import Root from './checkbox.svelte';
export {
Root,
//
Root as Checkbox,
Root as Checkbox
};
@@ -4,8 +4,8 @@ import {
type TableOptionsResolved,
type TableState,
type Updater,
createTable,
} from "@tanstack/table-core";
createTable
} from '@tanstack/table-core';
/**
* Creates a reactive TanStack table object for Svelte.
@@ -44,7 +44,7 @@ export function createSvelteTable<TData extends RowData>(options: TableOptions<T
options: Partial<TableOptions<TData>>
) => {
return mergeObjects(defaultOptions, options);
},
}
},
options
);
@@ -62,7 +62,7 @@ export function createSvelteTable<TData extends RowData>(options: TableOptions<T
else state = mergeObjects(state, updater);
options.onStateChange?.(updater);
},
}
});
});
}
@@ -92,7 +92,7 @@ export function mergeObjects<Sources extends readonly MaybeThunk<any>[]>(
...sources: Sources
): Intersection<{ [K in keyof Sources]: Sources[K] }> {
const resolve = <T extends object>(src: MaybeThunk<T>): T | undefined =>
typeof src === "function" ? (src() ?? undefined) : src;
typeof src === 'function' ? (src() ?? undefined) : src;
const findSourceWithKey = (key: PropertyKey) => {
for (let i = sources.length - 1; i >= 0; i--) {
@@ -135,8 +135,8 @@ export function mergeObjects<Sources extends readonly MaybeThunk<any>[]>(
enumerable: true,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value: (src as any)[key],
writable: true,
writable: true
};
},
}
}) as Intersection<{ [K in keyof Sources]: Sources[K] }>;
}
@@ -2,9 +2,9 @@
lang="ts"
generics="TData, TValue, TContext extends HeaderContext<TData, TValue> | CellContext<TData, TValue>"
>
import type { CellContext, ColumnDefTemplate, HeaderContext } from "@tanstack/table-core";
import { RenderComponentConfig, RenderSnippetConfig } from "./render-helpers.js";
import type { Attachment } from "svelte/attachments";
import type { CellContext, ColumnDefTemplate, HeaderContext } from '@tanstack/table-core';
import { RenderComponentConfig, RenderSnippetConfig } from './render-helpers.js';
import type { Attachment } from 'svelte/attachments';
type Props = {
/** The cell or header field of the current cell's column definition. */
content?: TContext extends HeaderContext<TData, TValue>
@@ -22,7 +22,7 @@
let { content, context, attach }: Props = $props();
</script>
{#if typeof content === "string"}
{#if typeof content === 'string'}
{content}
{:else if content instanceof Function}
<!-- It's unlikely that a CellContext will be passed to a Header -->
+3 -3
View File
@@ -1,3 +1,3 @@
export { default as FlexRender } from "./flex-render.svelte";
export { renderComponent, renderSnippet } from "./render-helpers.js";
export { createSvelteTable } from "./data-table.svelte.js";
export { default as FlexRender } from './flex-render.svelte';
export { renderComponent, renderSnippet } from './render-helpers.js';
export { createSvelteTable } from './data-table.svelte.js';
@@ -1,4 +1,4 @@
import type { Component, ComponentProps, Snippet } from "svelte";
import type { Component, ComponentProps, Snippet } from 'svelte';
/**
* A helper class to make it easy to identify Svelte components in
@@ -77,7 +77,7 @@ export class RenderSnippetConfig<TProps> {
export function renderComponent<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends Component<any>,
Props extends ComponentProps<T>,
Props extends ComponentProps<T>
>(component: T, props: Props = {} as Props) {
return new RenderComponentConfig(component, props);
}
@@ -1,9 +1,9 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import { Dialog as DialogPrimitive } from 'bits-ui';
let {
ref = $bindable(null),
type = "button",
type = 'button',
...restProps
}: DialogPrimitive.CloseProps = $props();
</script>
@@ -1,11 +1,11 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import DialogPortal from "./dialog-portal.svelte";
import type { Snippet } from "svelte";
import * as Dialog from "./index.js";
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
import type { ComponentProps } from "svelte";
import { Button } from "$lib/ui/core/button/index.js";
import { Dialog as DialogPrimitive } from 'bits-ui';
import DialogPortal from './dialog-portal.svelte';
import type { Snippet } from 'svelte';
import * as Dialog from './index.js';
import { cn, type WithoutChildrenOrChild } from '$lib/utils.js';
import type { ComponentProps } from 'svelte';
import { Button } from '$lib/ui/core/button/index.js';
import XIcon from '@lucide/svelte/icons/x';
let {
@@ -28,7 +28,7 @@
bind:ref
data-slot="dialog-content"
class={cn(
"bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-sm ring-1 duration-100 sm:max-w-sm fixed top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2 outline-none",
'fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 sm:max-w-sm',
className
)}
{...restProps}
@@ -38,7 +38,7 @@
<DialogPrimitive.Close data-slot="dialog-close">
{#snippet child({ props })}
<Button variant="ghost" class="absolute top-2 right-2" size="icon-sm" {...props}>
<XIcon />
<XIcon />
<span class="sr-only">Close</span>
</Button>
{/snippet}
@@ -1,6 +1,6 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -12,6 +12,9 @@
<DialogPrimitive.Description
bind:ref
data-slot="dialog-description"
class={cn("text-muted-foreground *:[a]:hover:text-foreground text-sm *:[a]:underline *:[a]:underline-offset-3", className)}
class={cn(
'text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground',
className
)}
{...restProps}
/>
@@ -1,8 +1,8 @@
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import { Dialog as DialogPrimitive } from "bits-ui";
import { Button } from "$lib/ui/core/button/index.js";
import { cn, type WithElementRef } from '$lib/utils.js';
import type { HTMLAttributes } from 'svelte/elements';
import { Dialog as DialogPrimitive } from 'bits-ui';
import { Button } from '$lib/ui/core/button/index.js';
let {
ref = $bindable(null),
@@ -18,7 +18,10 @@
<div
bind:this={ref}
data-slot="dialog-footer"
class={cn("bg-muted/50 -mx-4 -mb-4 rounded-b-xl border-t p-4 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
class={cn(
'-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end',
className
)}
{...restProps}
>
{@render children?.()}
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
<div
bind:this={ref}
data-slot="dialog-header"
class={cn("gap-2 flex flex-col", className)}
class={cn('flex flex-col gap-2', className)}
{...restProps}
>
{@render children?.()}
@@ -1,6 +1,6 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -12,6 +12,9 @@
<DialogPrimitive.Overlay
bind:ref
data-slot="dialog-overlay"
class={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50", className)}
class={cn(
'fixed inset-0 isolate z-50 bg-black/10 duration-100 data-closed:animate-out data-closed:fade-out-0 data-open:animate-in data-open:fade-in-0 supports-backdrop-filter:backdrop-blur-xs',
className
)}
{...restProps}
/>
@@ -1,5 +1,5 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import { Dialog as DialogPrimitive } from 'bits-ui';
let { ...restProps }: DialogPrimitive.PortalProps = $props();
</script>
@@ -1,6 +1,6 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
import { Dialog as DialogPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -12,6 +12,6 @@
<DialogPrimitive.Title
bind:ref
data-slot="dialog-title"
class={cn("text-base leading-none font-medium", className)}
class={cn('text-base leading-none font-medium', className)}
{...restProps}
/>
@@ -1,9 +1,9 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import { Dialog as DialogPrimitive } from 'bits-ui';
let {
ref = $bindable(null),
type = "button",
type = 'button',
...restProps
}: DialogPrimitive.TriggerProps = $props();
</script>
+1 -1
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import { Dialog as DialogPrimitive } from 'bits-ui';
let { open = $bindable(false), ...restProps }: DialogPrimitive.RootProps = $props();
</script>
+11 -11
View File
@@ -1,13 +1,13 @@
import Root from "./dialog.svelte";
import Portal from "./dialog-portal.svelte";
import Title from "./dialog-title.svelte";
import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
import Content from "./dialog-content.svelte";
import Description from "./dialog-description.svelte";
import Trigger from "./dialog-trigger.svelte";
import Close from "./dialog-close.svelte";
import Root from './dialog.svelte';
import Portal from './dialog-portal.svelte';
import Title from './dialog-title.svelte';
import Footer from './dialog-footer.svelte';
import Header from './dialog-header.svelte';
import Overlay from './dialog-overlay.svelte';
import Content from './dialog-content.svelte';
import Description from './dialog-description.svelte';
import Trigger from './dialog-trigger.svelte';
import Close from './dialog-close.svelte';
export {
Root,
@@ -30,5 +30,5 @@ export {
Overlay as DialogOverlay,
Content as DialogContent,
Description as DialogDescription,
Close as DialogClose,
Close as DialogClose
};
@@ -1,5 +1,5 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let {
ref = $bindable(null),
@@ -1,9 +1,9 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import MinusIcon from '@lucide/svelte/icons/minus';
import CheckIcon from '@lucide/svelte/icons/check';
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
import type { Snippet } from "svelte";
import { cn, type WithoutChildrenOrChild } from '$lib/utils.js';
import type { Snippet } from 'svelte';
let {
ref = $bindable(null),
@@ -23,20 +23,20 @@
bind:indeterminate
data-slot="dropdown-menu-checkbox-item"
class={cn(
"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...restProps}
>
{#snippet children({ checked, indeterminate })}
<span
class="absolute right-2 flex items-center justify-center pointer-events-none"
class="pointer-events-none absolute right-2 flex items-center justify-center"
data-slot="dropdown-menu-checkbox-item-indicator"
>
{#if indeterminate}
<MinusIcon />
<MinusIcon />
{:else if checked}
<CheckIcon />
<CheckIcon />
{/if}
</span>
{@render childrenProp?.()}
@@ -1,13 +1,13 @@
<script lang="ts">
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
import DropdownMenuPortal from "./dropdown-menu-portal.svelte";
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import type { ComponentProps } from "svelte";
import { cn, type WithoutChildrenOrChild } from '$lib/utils.js';
import DropdownMenuPortal from './dropdown-menu-portal.svelte';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import type { ComponentProps } from 'svelte';
let {
ref = $bindable(null),
sideOffset = 4,
align = "start",
align = 'start',
portalProps,
class: className,
...restProps
@@ -23,7 +23,7 @@
{sideOffset}
{align}
class={cn(
"data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-32 rounded-lg p-1 shadow-md ring-1 duration-100 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 w-(--bits-dropdown-menu-anchor-width) overflow-x-hidden overflow-y-auto outline-none data-closed:overflow-hidden",
'z-50 w-(--bits-dropdown-menu-anchor-width) min-w-32 overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className
)}
{...restProps}
@@ -1,7 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
import type { ComponentProps } from "svelte";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
import type { ComponentProps } from 'svelte';
let {
ref = $bindable(null),
@@ -17,6 +17,6 @@
bind:ref
data-slot="dropdown-menu-group-heading"
data-inset={inset}
class={cn("px-2 py-1.5 text-sm font-semibold data-[inset]:ps-8", className)}
class={cn('px-2 py-1.5 text-sm font-semibold data-[inset]:ps-8', className)}
{...restProps}
/>
@@ -1,5 +1,5 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.GroupProps = $props();
</script>
@@ -1,16 +1,16 @@
<script lang="ts">
import { cn } from "$lib/utils.js";
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from '$lib/utils.js';
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let {
ref = $bindable(null),
class: className,
inset,
variant = "default",
variant = 'default',
...restProps
}: DropdownMenuPrimitive.ItemProps & {
inset?: boolean;
variant?: "default" | "destructive";
variant?: 'default' | 'destructive';
} = $props();
</script>
@@ -20,7 +20,7 @@
data-inset={inset}
data-variant={variant}
class={cn(
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md px-1.5 py-1 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
"group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-7 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
className
)}
{...restProps}
@@ -1,6 +1,6 @@
<script lang="ts">
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from '$lib/utils.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
@@ -17,7 +17,10 @@
bind:this={ref}
data-slot="dropdown-menu-label"
data-inset={inset}
class={cn("text-muted-foreground px-1.5 py-1 text-xs font-medium data-inset:pl-7 data-[inset]:pl-8", className)}
class={cn(
'px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7 data-[inset]:pl-8',
className
)}
{...restProps}
>
{@render children?.()}
@@ -1,5 +1,5 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { ...restProps }: DropdownMenuPrimitive.PortalProps = $props();
</script>
@@ -1,5 +1,5 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let {
ref = $bindable(null),
@@ -1,7 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import CheckIcon from '@lucide/svelte/icons/check';
import { cn, type WithoutChild } from "$lib/utils.js";
import { cn, type WithoutChild } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -15,18 +15,18 @@
bind:ref
data-slot="dropdown-menu-radio-item"
class={cn(
"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...restProps}
>
{#snippet children({ checked })}
<span
class="absolute right-2 flex items-center justify-center pointer-events-none"
class="pointer-events-none absolute right-2 flex items-center justify-center"
data-slot="dropdown-menu-radio-item-indicator"
>
{#if checked}
<CheckIcon />
<CheckIcon />
{/if}
</span>
{@render childrenProp?.({ checked })}
@@ -1,6 +1,6 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -12,6 +12,6 @@
<DropdownMenuPrimitive.Separator
bind:ref
data-slot="dropdown-menu-separator"
class={cn("bg-border -mx-1 my-1 h-px", className)}
class={cn('-mx-1 my-1 h-px bg-border', className)}
{...restProps}
/>
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,10 @@
<span
bind:this={ref}
data-slot="dropdown-menu-shortcut"
class={cn("text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground ml-auto text-xs tracking-widest", className)}
class={cn(
'ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground',
className
)}
{...restProps}
>
{@render children?.()}
@@ -1,6 +1,6 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -12,6 +12,9 @@
<DropdownMenuPrimitive.SubContent
bind:ref
data-slot="dropdown-menu-sub-content"
class={cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-[96px] rounded-lg p-1 shadow-lg ring-1 duration-100 w-auto", className)}
class={cn(
'w-auto min-w-[96px] rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className
)}
{...restProps}
/>
@@ -1,7 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
import ChevronRightIcon from '@lucide/svelte/icons/chevron-right';
import { cn } from "$lib/utils.js";
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -19,7 +19,7 @@
data-slot="dropdown-menu-sub-trigger"
data-inset={inset}
class={cn(
"focus:bg-accent focus:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md px-1.5 py-1 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 flex cursor-default items-center outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
"flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...restProps}
@@ -1,5 +1,5 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { open = $bindable(false), ...restProps }: DropdownMenuPrimitive.SubProps = $props();
</script>
@@ -1,5 +1,5 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { ref = $bindable(null), ...restProps }: DropdownMenuPrimitive.TriggerProps = $props();
</script>
@@ -1,5 +1,5 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import { DropdownMenu as DropdownMenuPrimitive } from 'bits-ui';
let { open = $bindable(false), ...restProps }: DropdownMenuPrimitive.RootProps = $props();
</script>
+18 -18
View File
@@ -1,20 +1,20 @@
import Root from "./dropdown-menu.svelte";
import Sub from "./dropdown-menu-sub.svelte";
import CheckboxGroup from "./dropdown-menu-checkbox-group.svelte";
import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
import Content from "./dropdown-menu-content.svelte";
import Group from "./dropdown-menu-group.svelte";
import Item from "./dropdown-menu-item.svelte";
import Label from "./dropdown-menu-label.svelte";
import RadioGroup from "./dropdown-menu-radio-group.svelte";
import RadioItem from "./dropdown-menu-radio-item.svelte";
import Separator from "./dropdown-menu-separator.svelte";
import Shortcut from "./dropdown-menu-shortcut.svelte";
import Trigger from "./dropdown-menu-trigger.svelte";
import SubContent from "./dropdown-menu-sub-content.svelte";
import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
import GroupHeading from "./dropdown-menu-group-heading.svelte";
import Portal from "./dropdown-menu-portal.svelte";
import Root from './dropdown-menu.svelte';
import Sub from './dropdown-menu-sub.svelte';
import CheckboxGroup from './dropdown-menu-checkbox-group.svelte';
import CheckboxItem from './dropdown-menu-checkbox-item.svelte';
import Content from './dropdown-menu-content.svelte';
import Group from './dropdown-menu-group.svelte';
import Item from './dropdown-menu-item.svelte';
import Label from './dropdown-menu-label.svelte';
import RadioGroup from './dropdown-menu-radio-group.svelte';
import RadioItem from './dropdown-menu-radio-item.svelte';
import Separator from './dropdown-menu-separator.svelte';
import Shortcut from './dropdown-menu-shortcut.svelte';
import Trigger from './dropdown-menu-trigger.svelte';
import SubContent from './dropdown-menu-sub-content.svelte';
import SubTrigger from './dropdown-menu-sub-trigger.svelte';
import GroupHeading from './dropdown-menu-group-heading.svelte';
import Portal from './dropdown-menu-portal.svelte';
export {
CheckboxGroup,
@@ -50,5 +50,5 @@ export {
Sub,
SubContent,
SubTrigger,
Trigger,
Trigger
};
+1 -1
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { Button, type ButtonProps } from "$lib/ui/core/button/index.js";
import { Button, type ButtonProps } from '$lib/ui/core/button/index.js';
let { ref = $bindable(null), ...restProps }: ButtonProps = $props();
</script>
@@ -1,6 +1,6 @@
<script lang="ts">
import * as FormPrimitive from "formsnap";
import { cn, type WithoutChild } from "$lib/utils.js";
import * as FormPrimitive from 'formsnap';
import { cn, type WithoutChild } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -12,6 +12,6 @@
<FormPrimitive.Description
bind:ref
data-slot="form-description"
class={cn("text-muted-foreground text-sm", className)}
class={cn('text-sm text-muted-foreground', className)}
{...restProps}
/>
@@ -1,8 +1,8 @@
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPathLeaves<T>">
import * as FormPrimitive from "formsnap";
import type { FormPathLeaves } from "sveltekit-superforms";
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef, type WithoutChildren } from "$lib/utils.js";
import * as FormPrimitive from 'formsnap';
import type { FormPathLeaves } from 'sveltekit-superforms';
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef, type WithoutChildren } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -17,7 +17,7 @@
<FormPrimitive.ElementField {form} {name}>
{#snippet children({ constraints, errors, tainted, value })}
<div bind:this={ref} class={cn("space-y-2", className)} {...restProps}>
<div bind:this={ref} class={cn('space-y-2', className)} {...restProps}>
{@render childrenProp?.({ constraints, errors, tainted, value: value as T[U] })}
</div>
{/snippet}
@@ -1,6 +1,6 @@
<script lang="ts">
import * as FormPrimitive from "formsnap";
import { cn, type WithoutChild } from "$lib/utils.js";
import * as FormPrimitive from 'formsnap';
import { cn, type WithoutChild } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -15,7 +15,7 @@
<FormPrimitive.FieldErrors
bind:ref
class={cn("text-destructive text-sm font-medium", className)}
class={cn('text-sm font-medium text-destructive', className)}
{...restProps}
>
{#snippet children({ errors, errorProps })}
+5 -10
View File
@@ -1,8 +1,8 @@
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
import * as FormPrimitive from "formsnap";
import type { FormPath } from "sveltekit-superforms";
import { cn, type WithElementRef, type WithoutChildren } from "$lib/utils.js";
import type { HTMLAttributes } from "svelte/elements";
import * as FormPrimitive from 'formsnap';
import type { FormPath } from 'sveltekit-superforms';
import { cn, type WithElementRef, type WithoutChildren } from '$lib/utils.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
@@ -17,12 +17,7 @@
<FormPrimitive.Field {form} {name}>
{#snippet children({ constraints, errors, tainted, value })}
<div
bind:this={ref}
data-slot="form-item"
class={cn("space-y-2", className)}
{...restProps}
>
<div bind:this={ref} data-slot="form-item" class={cn('space-y-2', className)} {...restProps}>
{@render childrenProp?.({ constraints, errors, tainted, value: value as T[U] })}
</div>
{/snippet}
@@ -1,7 +1,7 @@
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
import * as FormPrimitive from "formsnap";
import type { FormPath } from "sveltekit-superforms";
import { cn, type WithoutChild } from "$lib/utils.js";
import * as FormPrimitive from 'formsnap';
import type { FormPath } from 'sveltekit-superforms';
import { cn, type WithoutChild } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -12,4 +12,4 @@
}: WithoutChild<FormPrimitive.FieldsetProps<T, U>> = $props();
</script>
<FormPrimitive.Fieldset bind:ref {form} {name} class={cn("space-y-2", className)} {...restProps} />
<FormPrimitive.Fieldset bind:ref {form} {name} class={cn('space-y-2', className)} {...restProps} />
+4 -4
View File
@@ -1,7 +1,7 @@
<script lang="ts">
import * as FormPrimitive from "formsnap";
import { Label } from "$lib/ui/core/label/index.js";
import { cn, type WithoutChild } from "$lib/utils.js";
import * as FormPrimitive from 'formsnap';
import { Label } from '$lib/ui/core/label/index.js';
import { cn, type WithoutChild } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -16,7 +16,7 @@
<Label
{...props}
data-slot="form-label"
class={cn("data-[fs-error]:text-destructive", className)}
class={cn('data-[fs-error]:text-destructive', className)}
>
{@render children?.()}
</Label>
+3 -3
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import * as FormPrimitive from "formsnap";
import { cn, type WithoutChild } from "$lib/utils.js";
import * as FormPrimitive from 'formsnap';
import { cn, type WithoutChild } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -11,6 +11,6 @@
<FormPrimitive.Legend
bind:ref
class={cn("data-[fs-error]:text-destructive text-sm leading-none font-medium", className)}
class={cn('text-sm leading-none font-medium data-[fs-error]:text-destructive', className)}
{...restProps}
/>
+10 -10
View File
@@ -1,12 +1,12 @@
import * as FormPrimitive from "formsnap";
import Description from "./form-description.svelte";
import Label from "./form-label.svelte";
import FieldErrors from "./form-field-errors.svelte";
import Field from "./form-field.svelte";
import Fieldset from "./form-fieldset.svelte";
import Legend from "./form-legend.svelte";
import ElementField from "./form-element-field.svelte";
import Button from "./form-button.svelte";
import * as FormPrimitive from 'formsnap';
import Description from './form-description.svelte';
import Label from './form-label.svelte';
import FieldErrors from './form-field-errors.svelte';
import Field from './form-field.svelte';
import Fieldset from './form-fieldset.svelte';
import Legend from './form-legend.svelte';
import ElementField from './form-element-field.svelte';
import Button from './form-button.svelte';
const Control = FormPrimitive.Control;
@@ -29,5 +29,5 @@ export {
Fieldset as FormFieldset,
Legend as FormLegend,
ElementField as FormElementField,
Button as FormButton,
Button as FormButton
};
+2 -2
View File
@@ -1,7 +1,7 @@
import Root from "./input.svelte";
import Root from './input.svelte';
export {
Root,
//
Root as Input,
Root as Input
};
+9 -9
View File
@@ -1,12 +1,12 @@
<script lang="ts">
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLInputAttributes, HTMLInputTypeAttribute } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
type InputType = Exclude<HTMLInputTypeAttribute, "file">;
type InputType = Exclude<HTMLInputTypeAttribute, 'file'>;
type Props = WithElementRef<
Omit<HTMLInputAttributes, "type"> &
({ type: "file"; files?: FileList } | { type?: InputType; files?: undefined })
Omit<HTMLInputAttributes, 'type'> &
({ type: 'file'; files?: FileList } | { type?: InputType; files?: undefined })
>;
let {
@@ -15,17 +15,17 @@
type,
files = $bindable(),
class: className,
"data-slot": dataSlot = "input",
'data-slot': dataSlot = 'input',
...restProps
}: Props = $props();
</script>
{#if type === "file"}
{#if type === 'file'}
<input
bind:this={ref}
data-slot={dataSlot}
class={cn(
"dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors file:h-6 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
'h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',
className
)}
type="file"
@@ -38,7 +38,7 @@
bind:this={ref}
data-slot={dataSlot}
class={cn(
"dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 h-8 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors file:h-6 file:text-sm file:font-medium focus-visible:ring-3 aria-invalid:ring-3 md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
'h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',
className
)}
{type}
+2 -2
View File
@@ -1,7 +1,7 @@
import Root from "./label.svelte";
import Root from './label.svelte';
export {
Root,
//
Root as Label,
Root as Label
};
+3 -3
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { Label as LabelPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
import { Label as LabelPrimitive } from 'bits-ui';
import { cn } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
bind:ref
data-slot="label"
class={cn(
"gap-2 text-sm leading-none font-medium group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed",
'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
className
)}
{...restProps}
+9 -9
View File
@@ -1,11 +1,11 @@
import Root from "./popover.svelte";
import Close from "./popover-close.svelte";
import Content from "./popover-content.svelte";
import Description from "./popover-description.svelte";
import Header from "./popover-header.svelte";
import Title from "./popover-title.svelte";
import Trigger from "./popover-trigger.svelte";
import Portal from "./popover-portal.svelte";
import Root from './popover.svelte';
import Close from './popover-close.svelte';
import Content from './popover-content.svelte';
import Description from './popover-description.svelte';
import Header from './popover-header.svelte';
import Title from './popover-title.svelte';
import Trigger from './popover-trigger.svelte';
import Portal from './popover-portal.svelte';
export {
Root,
@@ -24,5 +24,5 @@ export {
Title as PopoverTitle,
Trigger as PopoverTrigger,
Close as PopoverClose,
Portal as PopoverPortal,
Portal as PopoverPortal
};
@@ -1,5 +1,5 @@
<script lang="ts">
import { Popover as PopoverPrimitive } from "bits-ui";
import { Popover as PopoverPrimitive } from 'bits-ui';
let { ref = $bindable(null), ...restProps }: PopoverPrimitive.CloseProps = $props();
</script>
@@ -1,14 +1,14 @@
<script lang="ts">
import { Popover as PopoverPrimitive } from "bits-ui";
import PopoverPortal from "./popover-portal.svelte";
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
import type { ComponentProps } from "svelte";
import { Popover as PopoverPrimitive } from 'bits-ui';
import PopoverPortal from './popover-portal.svelte';
import { cn, type WithoutChildrenOrChild } from '$lib/utils.js';
import type { ComponentProps } from 'svelte';
let {
ref = $bindable(null),
class: className,
sideOffset = 4,
align = "center",
align = 'center',
portalProps,
...restProps
}: PopoverPrimitive.ContentProps & {
@@ -23,7 +23,7 @@
{sideOffset}
{align}
class={cn(
"bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 flex flex-col gap-2.5 rounded-lg p-2.5 text-sm shadow-md ring-1 duration-100 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 w-72 origin-(--transform-origin) outline-hidden",
'z-50 flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className
)}
{...restProps}
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
<div
bind:this={ref}
data-slot="popover-description"
class={cn("text-muted-foreground", className)}
class={cn('text-muted-foreground', className)}
{...restProps}
>
{@render children?.()}
@@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn, type WithElementRef } from "$lib/utils.js";
import type { HTMLAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
@@ -13,7 +13,7 @@
<div
bind:this={ref}
data-slot="popover-header"
class={cn("flex flex-col gap-0.5 text-sm", className)}
class={cn('flex flex-col gap-0.5 text-sm', className)}
{...restProps}
>
{@render children?.()}

Some files were not shown because too many files have changed in this diff Show More