@svadmin/ui 0.42.3 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.css +462 -825
- package/dist/app.theme.css +462 -825
- package/dist/components/ErrorPage.svelte +4 -56
- package/dist/components/ResourceOperationsPage.svelte +84 -223
- package/dist/components/ResourceOperationsPage.svelte.d.ts +1 -1
- package/dist/components/TwoFactorAuthPage.svelte +44 -232
- package/dist/components/account/CompanyProfilePage.svelte +21 -142
- package/dist/components/account/GetStartedPage.svelte +45 -106
- package/dist/components/account/GetStartedPage.svelte.d.ts +1 -2
- package/dist/components/account/MembersStarterPage.svelte +49 -92
- package/dist/components/account/SecurityLogPage.svelte +16 -131
- package/dist/components/account/SettingsEnterprisePage.svelte +15 -275
- package/dist/components/account/SettingsPlainPage.svelte +10 -175
- package/dist/components/account/SettingsSidebarPage.svelte +11 -304
- package/dist/components/account/TeamMembersPage.svelte +18 -187
- package/dist/components/account/UserProfilePage.svelte +19 -196
- package/dist/components/account/UserProfilePage.svelte.d.ts +1 -2
- package/dist/components/content/ApiKeyList.svelte +13 -0
- package/dist/components/content/ApiKeyList.svelte.d.ts +16 -0
- package/dist/components/content/ContentPageHeader.svelte +31 -0
- package/dist/components/content/ContentPageHeader.svelte.d.ts +12 -0
- package/dist/components/content/ContentPageShell.svelte +39 -0
- package/dist/components/content/ContentPageShell.svelte.d.ts +14 -0
- package/dist/components/content/DataState.svelte +44 -0
- package/dist/components/content/DataState.svelte.d.ts +13 -0
- package/dist/components/content/DescriptionList.svelte +27 -0
- package/dist/components/content/DescriptionList.svelte.d.ts +14 -0
- package/dist/components/content/FileList.svelte +13 -0
- package/dist/components/content/FileList.svelte.d.ts +16 -0
- package/dist/components/content/FilterToolbar.svelte +24 -0
- package/dist/components/content/FilterToolbar.svelte.d.ts +11 -0
- package/dist/components/content/ImportDropzone.svelte +19 -0
- package/dist/components/content/ImportDropzone.svelte.d.ts +10 -0
- package/dist/components/content/IntegrationCard.svelte +16 -0
- package/dist/components/content/IntegrationCard.svelte.d.ts +15 -0
- package/dist/components/content/MemberList.svelte +16 -0
- package/dist/components/content/MemberList.svelte.d.ts +17 -0
- package/dist/components/content/MetricBlock.svelte +27 -0
- package/dist/components/content/MetricBlock.svelte.d.ts +13 -0
- package/dist/components/content/NetworkTable.svelte +18 -0
- package/dist/components/content/NetworkTable.svelte.d.ts +31 -0
- package/dist/components/content/NetworkTable.types.d.ts +4 -0
- package/dist/components/content/NetworkTable.types.js +1 -0
- package/dist/components/content/NetworkUserCard.svelte +17 -0
- package/dist/components/content/NetworkUserCard.svelte.d.ts +17 -0
- package/dist/components/content/OtpInput.svelte +22 -0
- package/dist/components/content/OtpInput.svelte.d.ts +10 -0
- package/dist/components/content/PageToolbar.svelte +18 -0
- package/dist/components/content/PageToolbar.svelte.d.ts +10 -0
- package/dist/components/content/ProjectCard.svelte +39 -0
- package/dist/components/content/ProjectCard.svelte.d.ts +20 -0
- package/dist/components/content/SectionHeader.svelte +18 -0
- package/dist/components/content/SectionHeader.svelte.d.ts +10 -0
- package/dist/components/content/SecurityEventTable.svelte +18 -0
- package/dist/components/content/SecurityEventTable.svelte.d.ts +15 -0
- package/dist/components/content/StatusBadge.svelte +19 -0
- package/dist/components/content/StatusBadge.svelte.d.ts +9 -0
- package/dist/components/content/SystemErrorState.svelte +18 -0
- package/dist/components/content/SystemErrorState.svelte.d.ts +10 -0
- package/dist/components/content/TeamCard.svelte +26 -0
- package/dist/components/content/TeamCard.svelte.d.ts +23 -0
- package/dist/components/content/TwoFactorStepper.svelte +11 -0
- package/dist/components/content/TwoFactorStepper.svelte.d.ts +8 -0
- package/dist/components/content/index.d.ts +32 -0
- package/dist/components/content/index.js +22 -0
- package/dist/components/network/TeamCrewTablePage.svelte +29 -181
- package/dist/components/network/UserCardsNFTPage.svelte +24 -137
- package/dist/components/profile/ActivityTimeline.svelte +17 -91
- package/dist/components/profile/ProfileCard.svelte +4 -4
- package/dist/components/profile/ProjectsGrid.svelte +28 -106
- package/dist/components/profile/ProjectsGrid.svelte.d.ts +2 -12
- package/dist/components/profile/PublicProfilePage.svelte +34 -186
- package/dist/components/profile/TeamsShowcase.svelte +12 -114
- package/dist/components/profile/TeamsShowcase.svelte.d.ts +2 -12
- package/dist/index.d.ts +36 -0
- package/dist/index.js +24 -0
- package/dist/reference-data.d.ts +171 -0
- package/dist/reference-data.js +47 -0
- package/package.json +2 -2
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface MemberSummary {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
role?: string;
|
|
6
|
+
department?: string;
|
|
7
|
+
status?: 'success' | 'warning' | 'danger' | 'info' | 'neutral';
|
|
8
|
+
avatar?: string;
|
|
9
|
+
}
|
|
10
|
+
interface Props {
|
|
11
|
+
members?: MemberSummary[];
|
|
12
|
+
onaction?: (member: MemberSummary) => void;
|
|
13
|
+
class?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const MemberList: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type MemberList = ReturnType<typeof MemberList>;
|
|
17
|
+
export default MemberList;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { Skeleton } from '../ui/skeleton/index.js';
|
|
4
|
+
interface Props {
|
|
5
|
+
label: string;
|
|
6
|
+
value: string | number;
|
|
7
|
+
detail?: string;
|
|
8
|
+
trend?: string;
|
|
9
|
+
icon?: Snippet;
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
let { label, value, detail, trend, icon, loading = false, class: className = '' }: Props = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<div data-svadmin-metric-card class={'min-w-0 rounded-lg border border-border bg-card p-4 shadow-sm ' + className}>
|
|
17
|
+
<div class="flex items-start justify-between gap-3">
|
|
18
|
+
<p class="text-sm text-muted-foreground">{label}</p>
|
|
19
|
+
{#if icon}<span class="text-muted-foreground">{@render icon()}</span>{/if}
|
|
20
|
+
</div>
|
|
21
|
+
{#if loading}
|
|
22
|
+
<Skeleton class="mt-3 h-8 w-24" />
|
|
23
|
+
{:else}
|
|
24
|
+
<p class="mt-2 truncate text-2xl font-semibold tracking-normal text-foreground">{value}</p>
|
|
25
|
+
{#if detail || trend}<div class="mt-2 flex flex-wrap gap-2 text-xs">{#if trend}<span class="font-medium text-success">{trend}</span>{/if}{#if detail}<span class="text-muted-foreground">{detail}</span>{/if}</div>{/if}
|
|
26
|
+
{/if}
|
|
27
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string | number;
|
|
5
|
+
detail?: string;
|
|
6
|
+
trend?: string;
|
|
7
|
+
icon?: Snippet;
|
|
8
|
+
loading?: boolean;
|
|
9
|
+
class?: string;
|
|
10
|
+
}
|
|
11
|
+
declare const MetricBlock: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type MetricBlock = ReturnType<typeof MetricBlock>;
|
|
13
|
+
export default MetricBlock;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts" generics="T extends object">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import * as Table from '../ui/table/index.js';
|
|
4
|
+
import type { NetworkColumn } from './NetworkTable.types.js';
|
|
5
|
+
interface Props { rows?: T[]; columns: NetworkColumn<T>[]; row?: Snippet<[T]>; class?: string; }
|
|
6
|
+
let { rows = [], columns, row, class: className = '' }: Props = $props();
|
|
7
|
+
</script>
|
|
8
|
+
<div class={'overflow-x-auto rounded-lg border border-border bg-card ' + className}>
|
|
9
|
+
<Table.Root data-svadmin-datatable>
|
|
10
|
+
<Table.Header data-svadmin-table-head><Table.Row>{#each columns as column (String(column.key))}<Table.Head>{column.label}</Table.Head>{/each}</Table.Row></Table.Header>
|
|
11
|
+
<Table.Body>
|
|
12
|
+
{#each rows as item, index (String('id' in item ? item.id : index))}
|
|
13
|
+
{#if row}{@render row(item)}{:else}<Table.Row data-svadmin-table-row>{#each columns as column (String(column.key))}<Table.Cell>{String(item[column.key] ?? '')}</Table.Cell>{/each}</Table.Row>{/if}
|
|
14
|
+
{/each}
|
|
15
|
+
</Table.Body>
|
|
16
|
+
</Table.Root>
|
|
17
|
+
{#if rows.length === 0}<div class="p-6 text-center text-sm text-muted-foreground">No records</div>{/if}
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { NetworkColumn } from './NetworkTable.types.js';
|
|
3
|
+
declare function $$render<T extends object>(): {
|
|
4
|
+
props: {
|
|
5
|
+
rows?: T[];
|
|
6
|
+
columns: NetworkColumn<T>[];
|
|
7
|
+
row?: Snippet<[T]>;
|
|
8
|
+
class?: string;
|
|
9
|
+
};
|
|
10
|
+
exports: {};
|
|
11
|
+
bindings: "";
|
|
12
|
+
slots: {};
|
|
13
|
+
events: {};
|
|
14
|
+
};
|
|
15
|
+
declare class __sveltets_Render<T extends object> {
|
|
16
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
17
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
18
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
19
|
+
bindings(): "";
|
|
20
|
+
exports(): {};
|
|
21
|
+
}
|
|
22
|
+
interface $$IsomorphicComponent {
|
|
23
|
+
new <T extends object>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
24
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
25
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
26
|
+
<T extends object>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
27
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
28
|
+
}
|
|
29
|
+
declare const NetworkTable: $$IsomorphicComponent;
|
|
30
|
+
type NetworkTable<T extends object> = InstanceType<typeof NetworkTable<T>>;
|
|
31
|
+
export default NetworkTable;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { MessageSquare, UserPlus } from '@lucide/svelte';
|
|
3
|
+
import { Avatar } from '../ui/avatar/index.js';
|
|
4
|
+
import { Button } from '../ui/button/index.js';
|
|
5
|
+
import * as Card from '../ui/card/index.js';
|
|
6
|
+
export interface NetworkUser { id: string; name: string; handle?: string; role?: string; avatar?: string; summary?: string; }
|
|
7
|
+
interface Props { user: NetworkUser; onconnect?: () => void; onmessage?: () => void; class?: string; }
|
|
8
|
+
let { user, onconnect, onmessage, class: className = '' }: Props = $props();
|
|
9
|
+
const initials = $derived(user.name.split(' ').map((part) => part[0]).join('').slice(0, 2).toUpperCase());
|
|
10
|
+
</script>
|
|
11
|
+
<Card.Card class={className}>
|
|
12
|
+
<Card.CardContent class="flex items-start gap-3 p-4">
|
|
13
|
+
<Avatar src={user.avatar} alt={user.name} fallback={initials} size="lg" />
|
|
14
|
+
<div class="min-w-0 flex-1"><h3 class="truncate text-sm font-semibold text-foreground">{user.name}</h3>{#if user.handle}<p class="truncate text-xs text-muted-foreground">{user.handle}</p>{/if}{#if user.role}<p class="mt-2 text-xs font-medium text-foreground">{user.role}</p>{/if}{#if user.summary}<p class="mt-1 line-clamp-2 text-xs text-muted-foreground">{user.summary}</p>{/if}</div>
|
|
15
|
+
<div class="flex shrink-0 gap-1">{#if onmessage}<Button variant="ghost" size="icon-sm" aria-label={'Message ' + user.name} onclick={onmessage}><MessageSquare class="size-4" /></Button>{/if}{#if onconnect}<Button variant="outline" size="icon-sm" aria-label={'Connect with ' + user.name} onclick={onconnect}><UserPlus class="size-4" /></Button>{/if}</div>
|
|
16
|
+
</Card.CardContent>
|
|
17
|
+
</Card.Card>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface NetworkUser {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
handle?: string;
|
|
5
|
+
role?: string;
|
|
6
|
+
avatar?: string;
|
|
7
|
+
summary?: string;
|
|
8
|
+
}
|
|
9
|
+
interface Props {
|
|
10
|
+
user: NetworkUser;
|
|
11
|
+
onconnect?: () => void;
|
|
12
|
+
onmessage?: () => void;
|
|
13
|
+
class?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const NetworkUserCard: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type NetworkUserCard = ReturnType<typeof NetworkUserCard>;
|
|
17
|
+
export default NetworkUserCard;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Input } from '../ui/input/index.js';
|
|
3
|
+
interface Props { value?: string[]; length?: number; disabled?: boolean; 'aria-label'?: string; class?: string; }
|
|
4
|
+
let { value = $bindable<string[]>([]), length = 6, disabled = false, 'aria-label': ariaLabel = 'One-time password', class: className = '' }: Props = $props();
|
|
5
|
+
const slots = $derived(Array.from({ length }, (_, index) => index));
|
|
6
|
+
function updateDigit(event: Event, index: number) {
|
|
7
|
+
const input = event.currentTarget as HTMLInputElement;
|
|
8
|
+
const digit = input.value.replace(/\D/g, '').slice(-1);
|
|
9
|
+
const next = [...value];
|
|
10
|
+
next[index] = digit;
|
|
11
|
+
value = next;
|
|
12
|
+
if (digit && index < length - 1) {
|
|
13
|
+
const sibling = input.parentElement?.querySelectorAll('input')[index + 1] as HTMLInputElement | undefined;
|
|
14
|
+
sibling?.focus();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
<div class={'flex justify-center gap-2 ' + className} role="group" aria-label={ariaLabel}>
|
|
19
|
+
{#each slots as index (index)}
|
|
20
|
+
<Input class="size-12 text-center text-lg font-semibold" value={value[index] ?? ''} maxlength={1} inputmode="numeric" pattern="[0-9]*" aria-label={ariaLabel + ' digit ' + (index + 1)} {disabled} oninput={(event) => updateDigit(event, index)} />
|
|
21
|
+
{/each}
|
|
22
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
value?: string[];
|
|
3
|
+
length?: number;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
'aria-label'?: string;
|
|
6
|
+
class?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const OtpInput: import("svelte").Component<Props, {}, "value">;
|
|
9
|
+
type OtpInput = ReturnType<typeof OtpInput>;
|
|
10
|
+
export default OtpInput;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
interface Props {
|
|
4
|
+
leading?: Snippet;
|
|
5
|
+
trailing?: Snippet;
|
|
6
|
+
children?: Snippet;
|
|
7
|
+
class?: string;
|
|
8
|
+
}
|
|
9
|
+
let { leading, trailing, children, class: className = '' }: Props = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<div data-svadmin-table-toolbar class={'flex flex-col gap-3 rounded-lg border border-border bg-card p-3 shadow-sm sm:flex-row sm:items-center sm:justify-between ' + className}>
|
|
13
|
+
<div class="flex min-w-0 flex-1 flex-wrap items-center gap-2">
|
|
14
|
+
{#if leading}{@render leading()}{/if}
|
|
15
|
+
{#if children}{@render children()}{/if}
|
|
16
|
+
</div>
|
|
17
|
+
{#if trailing}<div class="flex shrink-0 flex-wrap items-center gap-2">{@render trailing()}</div>{/if}
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
leading?: Snippet;
|
|
4
|
+
trailing?: Snippet;
|
|
5
|
+
children?: Snippet;
|
|
6
|
+
class?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const PageToolbar: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type PageToolbar = ReturnType<typeof PageToolbar>;
|
|
10
|
+
export default PageToolbar;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ArrowRight, CheckCircle2, FolderKanban, Users } from '@lucide/svelte';
|
|
3
|
+
import { Button } from '../ui/button/index.js';
|
|
4
|
+
import * as Card from '../ui/card/index.js';
|
|
5
|
+
import { Badge } from '../ui/badge/index.js';
|
|
6
|
+
import Progress from '../ui/progress/progress.svelte';
|
|
7
|
+
import StatusBadge from './StatusBadge.svelte';
|
|
8
|
+
export type ProjectStatus = 'active' | 'completed' | 'on-hold' | 'draft';
|
|
9
|
+
export interface ProjectSummary {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
status: ProjectStatus;
|
|
14
|
+
members?: number;
|
|
15
|
+
tasks?: number;
|
|
16
|
+
progress?: number;
|
|
17
|
+
tags?: string[];
|
|
18
|
+
image?: string;
|
|
19
|
+
}
|
|
20
|
+
interface Props { project: ProjectSummary; onclick?: () => void; class?: string; }
|
|
21
|
+
let { project, onclick, class: className = '' }: Props = $props();
|
|
22
|
+
const progress = $derived(project.progress ?? (project.status === 'completed' ? 100 : project.status === 'active' ? 72 : 0));
|
|
23
|
+
</script>
|
|
24
|
+
<Card.Card data-interactive={onclick ? 'true' : undefined} class={'h-full ' + className}>
|
|
25
|
+
{#if project.image}<img src={project.image} alt={project.name} class="h-32 w-full object-cover" />{/if}
|
|
26
|
+
<Card.CardContent class="flex h-full flex-col gap-4 p-4">
|
|
27
|
+
<div class="flex items-start justify-between gap-3">
|
|
28
|
+
<div class="flex min-w-0 items-center gap-3"><span class="flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-muted/50 text-muted-foreground"><FolderKanban class="size-4" /></span><h3 class="truncate text-sm font-semibold text-foreground">{project.name}</h3></div>
|
|
29
|
+
<StatusBadge status={project.status === 'active' ? 'success' : project.status === 'completed' ? 'info' : project.status === 'on-hold' ? 'warning' : 'neutral'} label={project.status} />
|
|
30
|
+
</div>
|
|
31
|
+
{#if project.description}<p class="line-clamp-2 text-sm text-muted-foreground">{project.description}</p>{/if}
|
|
32
|
+
{#if project.tags?.length}<div class="flex flex-wrap gap-1.5">{#each project.tags as tag (tag)}<Badge variant="outline">{tag}</Badge>{/each}</div>{/if}
|
|
33
|
+
<div class="mt-auto space-y-2">
|
|
34
|
+
<div class="flex items-center justify-between text-xs text-muted-foreground"><span>Progress</span><span class="font-medium text-foreground">{progress}%</span></div>
|
|
35
|
+
<Progress value={progress} class="h-1.5" />
|
|
36
|
+
<div class="flex items-center justify-between border-t border-border pt-3 text-xs text-muted-foreground"><span class="flex items-center gap-1"><Users class="size-3.5" />{project.members ?? 0}</span><span class="flex items-center gap-1"><CheckCircle2 class="size-3.5" />{project.tasks ?? 0}</span>{#if onclick}<Button variant="ghost" size="icon-sm" aria-label={project.name} onclick={onclick}><ArrowRight class="size-3.5" /></Button>{/if}</div>
|
|
37
|
+
</div>
|
|
38
|
+
</Card.CardContent>
|
|
39
|
+
</Card.Card>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type ProjectStatus = 'active' | 'completed' | 'on-hold' | 'draft';
|
|
2
|
+
export interface ProjectSummary {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
status: ProjectStatus;
|
|
7
|
+
members?: number;
|
|
8
|
+
tasks?: number;
|
|
9
|
+
progress?: number;
|
|
10
|
+
tags?: string[];
|
|
11
|
+
image?: string;
|
|
12
|
+
}
|
|
13
|
+
interface Props {
|
|
14
|
+
project: ProjectSummary;
|
|
15
|
+
onclick?: () => void;
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
declare const ProjectCard: import("svelte").Component<Props, {}, "">;
|
|
19
|
+
type ProjectCard = ReturnType<typeof ProjectCard>;
|
|
20
|
+
export default ProjectCard;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
interface Props {
|
|
4
|
+
title: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
actions?: Snippet;
|
|
7
|
+
class?: string;
|
|
8
|
+
}
|
|
9
|
+
let { title, description, actions, class: className = '' }: Props = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<div class={'flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between ' + className}>
|
|
13
|
+
<div class="min-w-0 space-y-1">
|
|
14
|
+
<h2 class="text-base font-semibold text-foreground">{title}</h2>
|
|
15
|
+
{#if description}<p class="text-sm text-muted-foreground">{description}</p>{/if}
|
|
16
|
+
</div>
|
|
17
|
+
{#if actions}<div class="flex shrink-0 flex-wrap items-center gap-2">{@render actions()}</div>{/if}
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
title: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
actions?: Snippet;
|
|
6
|
+
class?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const SectionHeader: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type SectionHeader = ReturnType<typeof SectionHeader>;
|
|
10
|
+
export default SectionHeader;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import * as Table from '../ui/table/index.js';
|
|
3
|
+
import StatusBadge from './StatusBadge.svelte';
|
|
4
|
+
export interface SecurityEvent { id: string; event: string; actor?: string; location?: string; createdAt: string; severity: 'info' | 'warning' | 'danger'; }
|
|
5
|
+
interface Props { events?: SecurityEvent[]; class?: string; }
|
|
6
|
+
let { events = [], class: className = '' }: Props = $props();
|
|
7
|
+
</script>
|
|
8
|
+
<div class={'overflow-x-auto rounded-lg border border-border bg-card ' + className}>
|
|
9
|
+
<Table.Root data-svadmin-datatable>
|
|
10
|
+
<Table.Header data-svadmin-table-head><Table.Row><Table.Head>Event</Table.Head><Table.Head>Actor</Table.Head><Table.Head>Location</Table.Head><Table.Head>Time</Table.Head><Table.Head>Risk</Table.Head></Table.Row></Table.Header>
|
|
11
|
+
<Table.Body>
|
|
12
|
+
{#each events as event (event.id)}
|
|
13
|
+
<Table.Row data-svadmin-table-row><Table.Cell class="font-medium">{event.event}</Table.Cell><Table.Cell>{event.actor ?? 'System'}</Table.Cell><Table.Cell>{event.location ?? 'Unknown'}</Table.Cell><Table.Cell class="whitespace-nowrap">{event.createdAt}</Table.Cell><Table.Cell><StatusBadge status={event.severity} label={event.severity} /></Table.Cell></Table.Row>
|
|
14
|
+
{/each}
|
|
15
|
+
</Table.Body>
|
|
16
|
+
</Table.Root>
|
|
17
|
+
{#if events.length === 0}<div class="p-6 text-center text-sm text-muted-foreground">No security events</div>{/if}
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface SecurityEvent {
|
|
2
|
+
id: string;
|
|
3
|
+
event: string;
|
|
4
|
+
actor?: string;
|
|
5
|
+
location?: string;
|
|
6
|
+
createdAt: string;
|
|
7
|
+
severity: 'info' | 'warning' | 'danger';
|
|
8
|
+
}
|
|
9
|
+
interface Props {
|
|
10
|
+
events?: SecurityEvent[];
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
declare const SecurityEventTable: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type SecurityEventTable = ReturnType<typeof SecurityEventTable>;
|
|
15
|
+
export default SecurityEventTable;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Badge } from '../ui/badge/index.js';
|
|
3
|
+
export type Status = 'success' | 'warning' | 'danger' | 'info' | 'neutral';
|
|
4
|
+
interface Props {
|
|
5
|
+
status: Status;
|
|
6
|
+
label?: string;
|
|
7
|
+
class?: string;
|
|
8
|
+
}
|
|
9
|
+
let { status, label = status, class: className = '' }: Props = $props();
|
|
10
|
+
const toneClass: Record<Status, string> = {
|
|
11
|
+
success: 'border-success/30 bg-success/10 text-success',
|
|
12
|
+
warning: 'border-warning/30 bg-warning/10 text-warning-foreground',
|
|
13
|
+
danger: 'border-destructive/30 bg-destructive/10 text-destructive',
|
|
14
|
+
info: 'border-primary/30 bg-primary/10 text-primary',
|
|
15
|
+
neutral: 'border-border bg-muted text-muted-foreground',
|
|
16
|
+
};
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<Badge variant="outline" class={'font-medium ' + toneClass[status] + ' ' + className}>{label}</Badge>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type Status = 'success' | 'warning' | 'danger' | 'info' | 'neutral';
|
|
2
|
+
interface Props {
|
|
3
|
+
status: Status;
|
|
4
|
+
label?: string;
|
|
5
|
+
class?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const StatusBadge: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type StatusBadge = ReturnType<typeof StatusBadge>;
|
|
9
|
+
export default StatusBadge;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { AlertTriangle, ArrowLeft, FileQuestion, Home } from '@lucide/svelte';
|
|
4
|
+
import { captureAdminContext } from '@svadmin/core';
|
|
5
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
6
|
+
import { Button } from '../ui/button/index.js';
|
|
7
|
+
import * as Card from '../ui/card/index.js';
|
|
8
|
+
interface Props { status?: '404' | '500'; title?: string; description?: string; action?: Snippet; }
|
|
9
|
+
let { status = '404', title, description, action }: Props = $props();
|
|
10
|
+
const adminContext = captureAdminContext();
|
|
11
|
+
const i18n = useTranslation();
|
|
12
|
+
const isNotFound = $derived(status === '404');
|
|
13
|
+
const resolvedTitle = $derived(title ?? (isNotFound ? i18n.t('common.pageNotFound') : i18n.t('common.error')));
|
|
14
|
+
const resolvedDescription = $derived(description ?? (isNotFound ? i18n.t('error.pageNotFoundDescription') : i18n.t('error.internalServerErrorDescription')));
|
|
15
|
+
</script>
|
|
16
|
+
<div class="flex min-h-[24rem] items-center justify-center p-4" data-svadmin-system-error>
|
|
17
|
+
<Card.Card class="w-full max-w-md"><Card.CardContent class="space-y-5 p-8 text-center"><div class="mx-auto flex size-14 items-center justify-center rounded-lg bg-muted text-muted-foreground">{#if isNotFound}<FileQuestion class="size-7" />{:else}<AlertTriangle class="size-7 text-destructive" />{/if}</div><div class="space-y-2"><p class="text-xs font-medium text-muted-foreground">{status}</p><h2 class="text-xl font-semibold text-foreground">{resolvedTitle}</h2><p class="text-sm leading-6 text-muted-foreground">{resolvedDescription}</p></div>{#if action}<div>{@render action()}</div>{/if}<div class="flex flex-wrap justify-center gap-2"><Button variant="outline" onclick={() => adminContext.back()}><ArrowLeft class="size-4" />{i18n.t('common.back')}</Button><Button onclick={() => adminContext.navigate('/')}><Home class="size-4" />{i18n.t('common.returnHome')}</Button></div></Card.CardContent></Card.Card>
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
status?: '404' | '500';
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
action?: Snippet;
|
|
7
|
+
}
|
|
8
|
+
declare const SystemErrorState: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type SystemErrorState = ReturnType<typeof SystemErrorState>;
|
|
10
|
+
export default SystemErrorState;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ArrowRight, Users } from '@lucide/svelte';
|
|
3
|
+
import { Avatar } from '../ui/avatar/index.js';
|
|
4
|
+
import { Button } from '../ui/button/index.js';
|
|
5
|
+
import * as Card from '../ui/card/index.js';
|
|
6
|
+
export interface TeamSummary {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
totalMembers?: number;
|
|
11
|
+
members?: Array<{ id?: string; name: string; avatar?: string; role?: string }>;
|
|
12
|
+
color?: string;
|
|
13
|
+
rating?: number;
|
|
14
|
+
}
|
|
15
|
+
interface Props { team: TeamSummary; onjoin?: () => void; onclick?: () => void; class?: string; }
|
|
16
|
+
let { team, onjoin, onclick, class: className = '' }: Props = $props();
|
|
17
|
+
const initials = (name: string) => name.split(' ').map((part) => part[0]).join('').slice(0, 2).toUpperCase();
|
|
18
|
+
</script>
|
|
19
|
+
<Card.Card data-interactive={onclick ? 'true' : undefined} class={'h-full ' + className}>
|
|
20
|
+
<Card.CardContent class="flex h-full flex-col gap-3 p-4">
|
|
21
|
+
<div class="flex items-start gap-3"><span class="flex size-9 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary" style:background-color={team.color ? `${team.color}20` : undefined}><Users class="size-4" style={team.color ? `color: ${team.color}` : undefined} /></span><div class="min-w-0 flex-1"><h3 class="truncate text-sm font-semibold text-foreground">{team.name}</h3><p class="text-xs text-muted-foreground">{team.totalMembers ?? team.members?.length ?? 0} members</p></div>{#if team.rating}<span class="text-xs font-semibold text-warning">{team.rating}</span>{/if}</div>
|
|
22
|
+
{#if team.description}<p class="line-clamp-2 text-sm text-muted-foreground">{team.description}</p>{/if}
|
|
23
|
+
<div class="flex items-center gap-1">{#each (team.members ?? []).slice(0, 5) as member, index (member.id ?? member.name + '-' + index)}<Avatar src={member.avatar} alt={member.name} fallback={initials(member.name)} size="sm" class="-mr-1 ring-2 ring-card" />{/each}</div>
|
|
24
|
+
<div class="mt-auto flex gap-2 border-t border-border pt-3">{#if onjoin}<Button variant="outline" size="sm" class="flex-1" onclick={onjoin}>Join</Button>{/if}{#if onclick}<Button variant="ghost" size="sm" class="flex-1" onclick={onclick}>View <ArrowRight class="size-3.5" /></Button>{/if}</div>
|
|
25
|
+
</Card.CardContent>
|
|
26
|
+
</Card.Card>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface TeamSummary {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
totalMembers?: number;
|
|
6
|
+
members?: Array<{
|
|
7
|
+
id?: string;
|
|
8
|
+
name: string;
|
|
9
|
+
avatar?: string;
|
|
10
|
+
role?: string;
|
|
11
|
+
}>;
|
|
12
|
+
color?: string;
|
|
13
|
+
rating?: number;
|
|
14
|
+
}
|
|
15
|
+
interface Props {
|
|
16
|
+
team: TeamSummary;
|
|
17
|
+
onjoin?: () => void;
|
|
18
|
+
onclick?: () => void;
|
|
19
|
+
class?: string;
|
|
20
|
+
}
|
|
21
|
+
declare const TeamCard: import("svelte").Component<Props, {}, "">;
|
|
22
|
+
type TeamCard = ReturnType<typeof TeamCard>;
|
|
23
|
+
export default TeamCard;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props { current: number; steps?: string[]; class?: string; }
|
|
3
|
+
let { current, steps = ['Setup', 'Verify', 'Recovery'], class: className = '' }: Props = $props();
|
|
4
|
+
</script>
|
|
5
|
+
<ol class={'grid gap-2 sm:grid-cols-3 ' + className} aria-label="Progress">
|
|
6
|
+
{#each steps as step, index (step)}
|
|
7
|
+
<li class={'flex items-center gap-2 rounded-md border px-3 py-2 text-xs ' + (index < current ? 'border-success/30 bg-success/10 text-success' : index === current ? 'border-primary/30 bg-primary/10 font-medium text-primary' : 'border-border text-muted-foreground')}>
|
|
8
|
+
<span class="flex size-5 shrink-0 items-center justify-center rounded-full border text-[11px]">{index + 1}</span><span class="truncate">{step}</span>
|
|
9
|
+
</li>
|
|
10
|
+
{/each}
|
|
11
|
+
</ol>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export { default as ContentPageShell } from './ContentPageShell.svelte';
|
|
2
|
+
export { default as ContentPageHeader } from './ContentPageHeader.svelte';
|
|
3
|
+
export { default as SectionHeader } from './SectionHeader.svelte';
|
|
4
|
+
export { default as PageToolbar } from './PageToolbar.svelte';
|
|
5
|
+
export { default as MetricBlock } from './MetricBlock.svelte';
|
|
6
|
+
export { default as DescriptionList } from './DescriptionList.svelte';
|
|
7
|
+
export { default as StatusBadge } from './StatusBadge.svelte';
|
|
8
|
+
export { default as FilterToolbar } from './FilterToolbar.svelte';
|
|
9
|
+
export { default as DataState } from './DataState.svelte';
|
|
10
|
+
export type { DataStateKind } from './DataState.svelte';
|
|
11
|
+
export { default as ProjectCard } from './ProjectCard.svelte';
|
|
12
|
+
export type { ProjectSummary, ProjectStatus } from './ProjectCard.svelte';
|
|
13
|
+
export { default as TeamCard } from './TeamCard.svelte';
|
|
14
|
+
export type { TeamSummary } from './TeamCard.svelte';
|
|
15
|
+
export { default as FileList } from './FileList.svelte';
|
|
16
|
+
export type { FileItem } from './FileList.svelte';
|
|
17
|
+
export { default as IntegrationCard } from './IntegrationCard.svelte';
|
|
18
|
+
export type { IntegrationSummary } from './IntegrationCard.svelte';
|
|
19
|
+
export { default as ApiKeyList } from './ApiKeyList.svelte';
|
|
20
|
+
export type { ApiKeySummary } from './ApiKeyList.svelte';
|
|
21
|
+
export { default as SecurityEventTable } from './SecurityEventTable.svelte';
|
|
22
|
+
export type { SecurityEvent } from './SecurityEventTable.svelte';
|
|
23
|
+
export { default as MemberList } from './MemberList.svelte';
|
|
24
|
+
export type { MemberSummary } from './MemberList.svelte';
|
|
25
|
+
export { default as ImportDropzone } from './ImportDropzone.svelte';
|
|
26
|
+
export { default as NetworkUserCard } from './NetworkUserCard.svelte';
|
|
27
|
+
export type { NetworkUser } from './NetworkUserCard.svelte';
|
|
28
|
+
export { default as NetworkTable } from './NetworkTable.svelte';
|
|
29
|
+
export type { NetworkColumn } from './NetworkTable.types.js';
|
|
30
|
+
export { default as OtpInput } from './OtpInput.svelte';
|
|
31
|
+
export { default as TwoFactorStepper } from './TwoFactorStepper.svelte';
|
|
32
|
+
export { default as SystemErrorState } from './SystemErrorState.svelte';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export { default as ContentPageShell } from './ContentPageShell.svelte';
|
|
2
|
+
export { default as ContentPageHeader } from './ContentPageHeader.svelte';
|
|
3
|
+
export { default as SectionHeader } from './SectionHeader.svelte';
|
|
4
|
+
export { default as PageToolbar } from './PageToolbar.svelte';
|
|
5
|
+
export { default as MetricBlock } from './MetricBlock.svelte';
|
|
6
|
+
export { default as DescriptionList } from './DescriptionList.svelte';
|
|
7
|
+
export { default as StatusBadge } from './StatusBadge.svelte';
|
|
8
|
+
export { default as FilterToolbar } from './FilterToolbar.svelte';
|
|
9
|
+
export { default as DataState } from './DataState.svelte';
|
|
10
|
+
export { default as ProjectCard } from './ProjectCard.svelte';
|
|
11
|
+
export { default as TeamCard } from './TeamCard.svelte';
|
|
12
|
+
export { default as FileList } from './FileList.svelte';
|
|
13
|
+
export { default as IntegrationCard } from './IntegrationCard.svelte';
|
|
14
|
+
export { default as ApiKeyList } from './ApiKeyList.svelte';
|
|
15
|
+
export { default as SecurityEventTable } from './SecurityEventTable.svelte';
|
|
16
|
+
export { default as MemberList } from './MemberList.svelte';
|
|
17
|
+
export { default as ImportDropzone } from './ImportDropzone.svelte';
|
|
18
|
+
export { default as NetworkUserCard } from './NetworkUserCard.svelte';
|
|
19
|
+
export { default as NetworkTable } from './NetworkTable.svelte';
|
|
20
|
+
export { default as OtpInput } from './OtpInput.svelte';
|
|
21
|
+
export { default as TwoFactorStepper } from './TwoFactorStepper.svelte';
|
|
22
|
+
export { default as SystemErrorState } from './SystemErrorState.svelte';
|