@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
|
@@ -1,123 +1,45 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useTranslation } from '@svadmin/core/i18n';
|
|
3
|
-
import * as Card from '../ui/card/index.js';
|
|
4
|
-
import { Badge } from '../ui/badge/index.js';
|
|
5
3
|
import { Button } from '../ui/button/index.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import Progress from '../ui/progress/progress.svelte';
|
|
9
|
-
|
|
10
|
-
const i18n = useTranslation();
|
|
11
|
-
|
|
12
|
-
interface Project {
|
|
13
|
-
id: string;
|
|
14
|
-
name: string;
|
|
15
|
-
description: string;
|
|
16
|
-
members: number;
|
|
17
|
-
tasks: number;
|
|
18
|
-
status: 'active' | 'completed' | 'on-hold';
|
|
19
|
-
tags?: string[];
|
|
20
|
-
image?: string;
|
|
21
|
-
progress?: number;
|
|
22
|
-
}
|
|
4
|
+
import { DataState, FilterToolbar, ProjectCard } from '../content/index.js';
|
|
5
|
+
import type { ProjectSummary } from '../content/ProjectCard.svelte';
|
|
23
6
|
|
|
24
7
|
interface Props {
|
|
25
8
|
columns?: 2 | 3;
|
|
26
|
-
projects?:
|
|
9
|
+
projects?: ProjectSummary[];
|
|
27
10
|
}
|
|
28
11
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
const statusConfig = {
|
|
42
|
-
'active': { color: 'bg-green-500/10 text-green-600', label: 'Active' },
|
|
43
|
-
'completed': { color: 'bg-blue-500/10 text-blue-600', label: 'Completed' },
|
|
44
|
-
'on-hold': { color: 'bg-amber-500/10 text-amber-600', label: 'On Hold' },
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const gridCols = $derived(columns === 3 ? 'lg:grid-cols-3' : 'lg:grid-cols-2');
|
|
12
|
+
const i18n = useTranslation();
|
|
13
|
+
let { columns = 2, projects = [] }: Props = $props();
|
|
14
|
+
let query = $state('');
|
|
15
|
+
const filtered = $derived.by(() => {
|
|
16
|
+
const needle = query.trim().toLowerCase();
|
|
17
|
+
if (!needle) return projects;
|
|
18
|
+
return projects.filter((project) => [project.name, project.description, ...(project.tags ?? [])]
|
|
19
|
+
.filter(Boolean)
|
|
20
|
+
.some((value) => String(value).toLowerCase().includes(needle)));
|
|
21
|
+
});
|
|
22
|
+
const gridClass = $derived(columns === 3 ? 'md:grid-cols-2 xl:grid-cols-3' : 'md:grid-cols-2');
|
|
48
23
|
</script>
|
|
49
24
|
|
|
50
|
-
<
|
|
51
|
-
<div class="flex flex-
|
|
52
|
-
<
|
|
53
|
-
{i18n.t('publicProfile.projectsCount', { count: filtered.length })}
|
|
54
|
-
|
|
55
|
-
<div class="flex w-full items-center gap-2 sm:w-auto">
|
|
56
|
-
<div class="relative min-w-0 flex-1 sm:flex-none">
|
|
57
|
-
<Search class="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
|
58
|
-
<Input placeholder={i18n.t('publicProfile.searchProjects')} bind:value={searchQuery} class="w-full pl-9 sm:w-48" />
|
|
59
|
-
</div>
|
|
60
|
-
<Button size="sm"><Plus class="h-3.5 w-3.5 mr-1" />{i18n.t('common.create')}</Button>
|
|
25
|
+
<section class="space-y-4" data-svadmin-profile-projects>
|
|
26
|
+
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
|
27
|
+
<div>
|
|
28
|
+
<h2 class="text-base font-semibold text-foreground">{i18n.t('publicProfile.projectsCount', { count: filtered.length })}</h2>
|
|
29
|
+
<p class="mt-1 text-sm text-muted-foreground">{i18n.t('publicProfile.searchProjects')}</p>
|
|
61
30
|
</div>
|
|
31
|
+
<Button size="sm">{i18n.t('common.create')}</Button>
|
|
62
32
|
</div>
|
|
63
|
-
|
|
64
|
-
{#if
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
33
|
+
<FilterToolbar bind:query placeholder={i18n.t('publicProfile.searchProjects')} />
|
|
34
|
+
{#if projects.length === 0}
|
|
35
|
+
<DataState state="empty" title={i18n.t('publicProfile.noProjects')} />
|
|
36
|
+
{:else if filtered.length === 0}
|
|
37
|
+
<DataState state="empty" title={i18n.t('publicProfile.noProjects')} description={i18n.t('publicProfile.searchProjects')} />
|
|
68
38
|
{:else}
|
|
69
|
-
<div class=
|
|
39
|
+
<div class={'grid gap-4 ' + gridClass}>
|
|
70
40
|
{#each filtered as project (project.id)}
|
|
71
|
-
{
|
|
72
|
-
<Card.Card class="group overflow-hidden border-border/60 hover:border-primary/30 transition-colors">
|
|
73
|
-
{#if project.image}
|
|
74
|
-
<div class="h-32 overflow-hidden">
|
|
75
|
-
<img src={project.image} alt={project.name} class="h-full w-full object-cover group-hover:scale-105 transition-transform duration-300" />
|
|
76
|
-
</div>
|
|
77
|
-
{/if}
|
|
78
|
-
<Card.CardContent class="p-4 space-y-3">
|
|
79
|
-
<div class="flex items-start justify-between gap-2">
|
|
80
|
-
<div class="flex min-w-0 items-center gap-3">
|
|
81
|
-
<span class="flex h-9 w-9 shrink-0 items-center justify-center rounded-md border bg-muted/40 text-muted-foreground">
|
|
82
|
-
<FolderKanban class="h-4 w-4" />
|
|
83
|
-
</span>
|
|
84
|
-
<h4 class="font-semibold text-foreground">{project.name}</h4>
|
|
85
|
-
</div>
|
|
86
|
-
<span class="shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold {statusConfig[project.status].color}">
|
|
87
|
-
{statusConfig[project.status].label}
|
|
88
|
-
</span>
|
|
89
|
-
</div>
|
|
90
|
-
|
|
91
|
-
<p class="text-sm text-muted-foreground line-clamp-2">{project.description}</p>
|
|
92
|
-
|
|
93
|
-
{#if project.tags && project.tags.length > 0}
|
|
94
|
-
<div class="flex flex-wrap gap-1">
|
|
95
|
-
{#each project.tags as tag (tag)}
|
|
96
|
-
<Badge variant="outline" class="text-[10px]">{tag}</Badge>
|
|
97
|
-
{/each}
|
|
98
|
-
</div>
|
|
99
|
-
{/if}
|
|
100
|
-
|
|
101
|
-
<div class="space-y-1.5">
|
|
102
|
-
<div class="flex items-center justify-between text-[11px] text-muted-foreground">
|
|
103
|
-
<span>{i18n.t('common.progress')}</span>
|
|
104
|
-
<span class="font-medium text-foreground">{progress}%</span>
|
|
105
|
-
</div>
|
|
106
|
-
<Progress value={progress} class="h-1.5" />
|
|
107
|
-
</div>
|
|
108
|
-
|
|
109
|
-
<div class="flex items-center justify-between pt-2 border-t">
|
|
110
|
-
<div class="flex items-center gap-3 text-xs text-muted-foreground">
|
|
111
|
-
<span class="flex items-center gap-1"><Users class="h-3 w-3" />{i18n.t('publicProfile.projectMembers', { count: project.members })}</span>
|
|
112
|
-
<span class="flex items-center gap-1"><CheckCircle2 class="h-3 w-3" />{i18n.t('publicProfile.projectTasks', { count: project.tasks })}</span>
|
|
113
|
-
</div>
|
|
114
|
-
<Button variant="ghost" size="icon-sm" aria-label={project.name} title={project.name}>
|
|
115
|
-
<ArrowRight class="h-3.5 w-3.5" />
|
|
116
|
-
</Button>
|
|
117
|
-
</div>
|
|
118
|
-
</Card.CardContent>
|
|
119
|
-
</Card.Card>
|
|
41
|
+
<ProjectCard {project} />
|
|
120
42
|
{/each}
|
|
121
43
|
</div>
|
|
122
44
|
{/if}
|
|
123
|
-
</
|
|
45
|
+
</section>
|
|
@@ -1,17 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
id: string;
|
|
3
|
-
name: string;
|
|
4
|
-
description: string;
|
|
5
|
-
members: number;
|
|
6
|
-
tasks: number;
|
|
7
|
-
status: 'active' | 'completed' | 'on-hold';
|
|
8
|
-
tags?: string[];
|
|
9
|
-
image?: string;
|
|
10
|
-
progress?: number;
|
|
11
|
-
}
|
|
1
|
+
import type { ProjectSummary } from '../content/ProjectCard.svelte';
|
|
12
2
|
interface Props {
|
|
13
3
|
columns?: 2 | 3;
|
|
14
|
-
projects?:
|
|
4
|
+
projects?: ProjectSummary[];
|
|
15
5
|
}
|
|
16
6
|
declare const ProjectsGrid: import("svelte").Component<Props, {}, "">;
|
|
17
7
|
type ProjectsGrid = ReturnType<typeof ProjectsGrid>;
|
|
@@ -1,202 +1,50 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useTranslation } from '@svadmin/core/i18n';
|
|
3
|
-
import * as Card from '../ui/card/index.js';
|
|
4
|
-
import { Button } from '../ui/button/index.js';
|
|
5
3
|
import { Badge } from '../ui/badge/index.js';
|
|
6
|
-
import
|
|
4
|
+
import ProfileCard from './ProfileCard.svelte';
|
|
7
5
|
import ProjectsGrid from './ProjectsGrid.svelte';
|
|
8
6
|
import ActivityTimeline from './ActivityTimeline.svelte';
|
|
9
7
|
import TeamsShowcase from './TeamsShowcase.svelte';
|
|
10
8
|
import ProfileVariantSections from './ProfileVariantSections.svelte';
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
import ContentPageShell from '../content/ContentPageShell.svelte';
|
|
10
|
+
import ContentPageHeader from '../content/ContentPageHeader.svelte';
|
|
11
|
+
import { referenceDemoData } from '../../reference-data.js';
|
|
14
12
|
|
|
15
13
|
type ProfileVariant = 'default' | 'company' | 'gamer';
|
|
16
14
|
type ProfileTab = 'projects' | 'activity' | 'teams';
|
|
17
|
-
|
|
18
|
-
interface Props {
|
|
19
|
-
variant?: ProfileVariant;
|
|
20
|
-
initialTab?: ProfileTab;
|
|
21
|
-
columns?: 2 | 3;
|
|
22
|
-
showSections?: boolean;
|
|
23
|
-
}
|
|
24
|
-
|
|
15
|
+
interface Props { variant?: ProfileVariant; initialTab?: ProfileTab; columns?: 2 | 3; showSections?: boolean; }
|
|
25
16
|
let { variant = 'default', initialTab = 'projects', columns = 2, showSections = false }: Props = $props();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{ label: i18n.t('publicProfile.teams'), value: '12' },
|
|
45
|
-
],
|
|
46
|
-
tags: ['SaaS', 'Enterprise', 'Cloud', 'AI'],
|
|
47
|
-
};
|
|
48
|
-
} else if (variant === 'gamer') {
|
|
49
|
-
return {
|
|
50
|
-
name: 'ShadowFox',
|
|
51
|
-
tagline: 'Pro gamer & content creator',
|
|
52
|
-
gamerTag: 'ShadowFox#7742',
|
|
53
|
-
level: 42,
|
|
54
|
-
rank: 'Diamond II',
|
|
55
|
-
location: 'Seoul, KR',
|
|
56
|
-
followers: 24600,
|
|
57
|
-
following: 180,
|
|
58
|
-
stats: [
|
|
59
|
-
{ label: i18n.t('profile.gamesPlayed'), value: '1,284' },
|
|
60
|
-
{ label: i18n.t('profile.winRate'), value: '68%' },
|
|
61
|
-
{ label: i18n.t('profile.rank'), value: 'Diamond II' },
|
|
62
|
-
],
|
|
63
|
-
tags: ['FPS', 'RPG', 'Streaming', 'Esports'],
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
name: 'Alex Chen',
|
|
68
|
-
tagline: 'Full-stack developer & open source enthusiast',
|
|
69
|
-
location: 'Shanghai, CN',
|
|
70
|
-
website: 'alexchen.dev',
|
|
71
|
-
joinedDate: '2023',
|
|
72
|
-
followers: 1234,
|
|
73
|
-
following: 567,
|
|
74
|
-
stats: [
|
|
75
|
-
{ label: i18n.t('publicProfile.projects'), value: '24' },
|
|
76
|
-
{ label: i18n.t('publicProfile.followers'), value: '1.2K' },
|
|
77
|
-
{ label: i18n.t('publicProfile.following'), value: '567' },
|
|
78
|
-
],
|
|
79
|
-
tags: ['TypeScript', 'Svelte', 'Node.js', 'Open Source'],
|
|
80
|
-
};
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// Demo data
|
|
84
|
-
const demoProjects = [
|
|
85
|
-
{ id: '1', name: 'Dashboard Redesign', description: 'Modern admin dashboard with real-time analytics and customizable widgets.', members: 8, tasks: 34, status: 'active' as const, tags: ['UI', 'Analytics'] },
|
|
86
|
-
{ id: '2', name: 'API Gateway v2', description: 'High-performance API gateway with rate limiting and circuit breaker patterns.', members: 5, tasks: 21, status: 'active' as const, tags: ['Backend', 'Infra'] },
|
|
87
|
-
{ id: '3', name: 'Mobile App', description: 'Cross-platform mobile application built with React Native.', members: 12, tasks: 56, status: 'completed' as const, tags: ['Mobile', 'React'] },
|
|
88
|
-
{ id: '4', name: 'Data Pipeline', description: 'Real-time data processing pipeline for event streaming.', members: 3, tasks: 18, status: 'on-hold' as const, tags: ['Data', 'Streaming'] },
|
|
89
|
-
{ id: '5', name: 'Design System 2.0', description: 'Unified component library with tokens, theming, and accessibility built in.', members: 6, tasks: 42, status: 'active' as const, tags: ['Design', 'UI'] },
|
|
90
|
-
{ id: '6', name: 'Billing Platform', description: 'Subscription billing with usage-based metering and invoicing.', members: 4, tasks: 27, status: 'active' as const, tags: ['Fintech', 'Backend'] },
|
|
91
|
-
{ id: '7', name: 'Search Relevance', description: 'Ranking improvements and vector search for the product catalog.', members: 5, tasks: 19, status: 'on-hold' as const, tags: ['Search', 'ML'] },
|
|
92
|
-
{ id: '8', name: 'Customer Portal', description: 'Self-service portal for account management and support tickets.', members: 9, tasks: 63, status: 'active' as const, tags: ['Web', 'Support'] },
|
|
93
|
-
{ id: '9', name: 'Notification Hub', description: 'Multi-channel notification delivery with user preference controls.', members: 3, tasks: 15, status: 'completed' as const, tags: ['Infra', 'Messaging'] },
|
|
94
|
-
{ id: '10', name: 'Analytics SDK', description: 'Lightweight event tracking SDK for web and mobile clients.', members: 4, tasks: 22, status: 'active' as const, tags: ['Analytics', 'SDK'] },
|
|
95
|
-
{ id: '11', name: 'Docs Revamp', description: 'New documentation site with interactive examples and search.', members: 2, tasks: 31, status: 'completed' as const, tags: ['Docs', 'Content'] },
|
|
96
|
-
{ id: '12', name: 'Edge Cache Layer', description: 'Distributed caching layer to cut origin latency for global users.', members: 5, tasks: 17, status: 'on-hold' as const, tags: ['Infra', 'Performance'] },
|
|
97
|
-
];
|
|
98
|
-
|
|
99
|
-
const demoActivities = [
|
|
100
|
-
{ id: '1', type: 'posted' as const, user: 'Alex Chen', content: 'Just shipped the new dashboard redesign with real-time analytics support.', timestamp: '2 hours ago' },
|
|
101
|
-
{ id: '2', type: 'commented' as const, user: 'Alex Chen', target: 'API Gateway PR #42', content: 'Looks great, just a few minor suggestions on error handling.', timestamp: '5 hours ago' },
|
|
102
|
-
{ id: '3', type: 'created' as const, user: 'Alex Chen', target: 'Mobile App project', timestamp: '1 day ago' },
|
|
103
|
-
{ id: '4', type: 'joined' as const, user: 'Alex Chen', target: 'Design Systems Guild', timestamp: '3 days ago' },
|
|
104
|
-
{ id: '5', type: 'starred' as const, user: 'Alex Chen', target: 'svadmin/svadmin', timestamp: '1 week ago' },
|
|
105
|
-
];
|
|
106
|
-
|
|
107
|
-
const demoTeams = [
|
|
108
|
-
{ id: '1', name: 'Frontend Platform', description: 'Building the core UI component library and design system.', members: [{ name: 'Alice' }, { name: 'Bob' }, { name: 'Carol' }], totalMembers: 8, rating: 4.8, color: '#3b82f6' },
|
|
109
|
-
{ id: '2', name: 'Backend Services', description: 'API development, microservices architecture, and infrastructure.', members: [{ name: 'Dave' }, { name: 'Eve' }], totalMembers: 5, rating: 4.5, color: '#10b981' },
|
|
110
|
-
{ id: '3', name: 'Design', description: 'User experience research and visual design.', members: [{ name: 'Frank' }, { name: 'Grace' }, { name: 'Hank' }, { name: 'Ivy' }], totalMembers: 6, rating: 4.9, color: '#f59e0b' },
|
|
111
|
-
{ id: '4', name: 'DevOps', description: 'CI/CD pipelines, cloud infrastructure, and reliability engineering.', members: [{ name: 'Jack' }, { name: 'Karen' }], totalMembers: 4, rating: 4.3, color: '#8b5cf6' },
|
|
112
|
-
{ id: '5', name: 'Data Engineering', description: 'Data pipelines, warehousing, and analytics infrastructure.', members: [{ name: 'Leo' }, { name: 'Mona' }, { name: 'Nina' }], totalMembers: 7, rating: 4.6, color: '#ec4899' },
|
|
113
|
-
{ id: '6', name: 'Mobile', description: 'iOS and Android apps with shared native modules.', members: [{ name: 'Oscar' }, { name: 'Paula' }], totalMembers: 5, rating: 4.4, color: '#14b8a6' },
|
|
114
|
-
{ id: '7', name: 'QA & Release', description: 'Test automation, release management, and quality gates.', members: [{ name: 'Quinn' }, { name: 'Rosa' }, { name: 'Sam' }], totalMembers: 4, rating: 4.2, color: '#f97316' },
|
|
115
|
-
{ id: '8', name: 'Security', description: 'Application security, compliance, and incident response.', members: [{ name: 'Tina' }, { name: 'Umar' }], totalMembers: 3, rating: 4.7, color: '#ef4444' },
|
|
116
|
-
{ id: '9', name: 'Developer Relations', description: 'Documentation, community programs, and developer outreach.', members: [{ name: 'Vera' }, { name: 'Will' }, { name: 'Xu' }], totalMembers: 6, rating: 4.5, color: '#0ea5e9' },
|
|
117
|
-
];
|
|
17
|
+
const i18n = useTranslation();
|
|
18
|
+
const columnLabel = $derived(i18n.locale === 'zh-CN' ? '栏' : 'columns');
|
|
19
|
+
const pageId = $derived(showSections ? `public-profile-${variant}` : `public-profile-${initialTab}-${initialTab === 'projects' ? columns : 'view'}`);
|
|
20
|
+
|
|
21
|
+
const profileData = $derived.by(() => variant === 'company'
|
|
22
|
+
? { name: 'Acme Corporation', tagline: 'Building the future of enterprise software', industry: 'Technology', employees: 1250, founded: '2015', website: 'acme.com', location: 'San Francisco, CA', followers: 8420, following: 312, tags: ['SaaS', 'Enterprise', 'Cloud'], stats: [{ label: i18n.t('profile.employees'), value: '1,250' }, { label: i18n.t('publicProfile.projects'), value: '48' }, { label: i18n.t('publicProfile.teams'), value: '12' }] }
|
|
23
|
+
: variant === 'gamer'
|
|
24
|
+
? { name: 'ShadowFox', tagline: 'Pro gamer & content creator', gamerTag: 'ShadowFox#7742', level: 42, rank: 'Diamond II', location: 'Seoul, KR', followers: 24600, following: 180, tags: ['FPS', 'RPG', 'Streaming'], stats: [{ label: i18n.t('profile.gamesPlayed'), value: '1,284' }, { label: i18n.t('profile.winRate'), value: '68%' }, { label: i18n.t('profile.rank'), value: 'Diamond II' }] }
|
|
25
|
+
: { name: 'Alex Chen', tagline: 'Full-stack developer & open source enthusiast', location: 'Shanghai, CN', website: 'alexchen.dev', joinedDate: '2023', followers: 1234, following: 567, tags: ['TypeScript', 'Svelte', 'Open Source'], stats: [{ label: i18n.t('publicProfile.projects'), value: '24' }, { label: i18n.t('publicProfile.followers'), value: '1.2K' }, { label: i18n.t('publicProfile.following'), value: '567' }] });
|
|
26
|
+
|
|
27
|
+
const projects = referenceDemoData.projects;
|
|
28
|
+
const visibleProjects = $derived(columns === 2 ? projects.slice(0, 6) : projects);
|
|
29
|
+
const activities = $derived.by(() => [
|
|
30
|
+
{ id: '1', type: 'posted' as const, user: profileData.name, content: 'Shipped the new dashboard redesign with real-time analytics support.', timestamp: '2 hours ago' },
|
|
31
|
+
{ id: '2', type: 'commented' as const, user: profileData.name, target: 'API Gateway PR #42', content: 'Looks great, with a few minor suggestions on error handling.', timestamp: '5 hours ago' },
|
|
32
|
+
{ id: '3', type: 'created' as const, user: profileData.name, target: 'Mobile App project', timestamp: '1 day ago' },
|
|
33
|
+
]);
|
|
34
|
+
const teams = referenceDemoData.teams;
|
|
118
35
|
</script>
|
|
119
36
|
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
<Card.Card class="overflow-hidden border-border/60">
|
|
123
|
-
<div class="h-28 bg-gradient-to-r from-primary/25 via-primary/15 to-accent/20 relative sm:h-40">
|
|
124
|
-
<div class="absolute inset-0 opacity-[0.06]" style="background-image: radial-gradient(circle, currentColor 1px, transparent 1px); background-size: 24px 24px;"></div>
|
|
125
|
-
</div>
|
|
126
|
-
<Card.CardContent class="relative px-6 pb-5">
|
|
127
|
-
<div class="-mt-10 flex flex-col gap-3 sm:-mt-12 sm:flex-row sm:items-end sm:gap-4">
|
|
128
|
-
<div class="ring-4 ring-card rounded-2xl overflow-hidden shrink-0">
|
|
129
|
-
<div class="flex h-20 w-20 items-center justify-center bg-primary/10 text-2xl font-bold text-primary sm:h-24 sm:w-24 sm:text-3xl">
|
|
130
|
-
{profileData.name.split(' ').map(n => n[0]).join('').slice(0, 2)}
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
<div class="flex-1 min-w-0">
|
|
134
|
-
<h2 class="text-xl font-bold text-foreground sm:text-2xl">{profileData.name}</h2>
|
|
135
|
-
{#if profileData.tagline}
|
|
136
|
-
<p class="text-muted-foreground">{profileData.tagline}</p>
|
|
137
|
-
{/if}
|
|
138
|
-
<div class="mt-2 flex flex-wrap gap-3 text-sm text-muted-foreground">
|
|
139
|
-
{#if profileData.location}
|
|
140
|
-
<span class="flex items-center gap-1"><MapPin class="h-3.5 w-3.5" />{profileData.location}</span>
|
|
141
|
-
{/if}
|
|
142
|
-
{#if profileData.website}
|
|
143
|
-
<span class="flex items-center gap-1"><Link class="h-3.5 w-3.5" />{profileData.website}</span>
|
|
144
|
-
{/if}
|
|
145
|
-
{#if 'joinedDate' in profileData && profileData.joinedDate}
|
|
146
|
-
<span class="flex items-center gap-1"><Calendar class="h-3.5 w-3.5" />{i18n.t('publicProfile.joinedDate', { date: profileData.joinedDate })}</span>
|
|
147
|
-
{/if}
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
<div class="flex shrink-0 flex-wrap gap-2">
|
|
151
|
-
<Button size="sm">{i18n.t('publicProfile.editProfile')}</Button>
|
|
152
|
-
<Button size="sm" variant="outline">{i18n.t('publicProfile.sendMessage')}</Button>
|
|
153
|
-
<Button size="sm" variant="ghost"><MoreHorizontal class="h-4 w-4" /></Button>
|
|
154
|
-
</div>
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
<!-- Stats -->
|
|
158
|
-
{#if profileData.stats.length > 0}
|
|
159
|
-
<div class="mt-4 grid grid-cols-3 gap-4 border-t pt-4">
|
|
160
|
-
{#each profileData.stats as stat (stat.label)}
|
|
161
|
-
<div class="text-center">
|
|
162
|
-
<div class="text-xl font-bold text-foreground">{stat.value}</div>
|
|
163
|
-
<div class="text-xs text-muted-foreground">{stat.label}</div>
|
|
164
|
-
</div>
|
|
165
|
-
{/each}
|
|
166
|
-
</div>
|
|
167
|
-
{/if}
|
|
168
|
-
|
|
169
|
-
<!-- Tags -->
|
|
170
|
-
{#if profileData.tags.length > 0}
|
|
171
|
-
<div class="mt-3 flex flex-wrap gap-1.5">
|
|
172
|
-
{#each profileData.tags as tag (tag)}
|
|
173
|
-
<Badge variant="outline" class="text-xs">{tag}</Badge>
|
|
174
|
-
{/each}
|
|
175
|
-
</div>
|
|
176
|
-
{/if}
|
|
177
|
-
</Card.CardContent>
|
|
178
|
-
</Card.Card>
|
|
179
|
-
|
|
180
|
-
<!-- Variant-specific sections (About / Projects table / Jobs / Games ...) -->
|
|
37
|
+
<ContentPageShell {pageId} width="wide">
|
|
38
|
+
<ContentPageHeader title={profileData.name} eyebrow={i18n.t('publicProfile.title')} description={profileData.tagline} />
|
|
181
39
|
{#if showSections}
|
|
182
|
-
<ProfileVariantSections {variant}
|
|
40
|
+
<div class="grid gap-6 xl:grid-cols-[20rem_minmax(0,1fr)]"><ProfileCard {...profileData} {variant} /><ProfileVariantSections {variant} /></div>
|
|
41
|
+
{:else if initialTab === 'projects'}
|
|
42
|
+
<div class="flex flex-wrap items-center justify-between gap-3 border-y border-border py-3"><div class="flex items-center gap-2"><Badge variant="outline">{columns} {columnLabel}</Badge><span class="text-sm text-muted-foreground">{visibleProjects.length} {i18n.t('publicProfile.projects')}</span></div><div class="flex gap-3 text-sm"><a class="text-primary" href="#/public-profile/projects/2-columns">2 {columnLabel}</a><a class="text-primary" href="#/public-profile/projects/3-columns">3 {columnLabel}</a></div></div>
|
|
43
|
+
<div class={columns === 2 ? 'grid gap-6 xl:grid-cols-[20rem_minmax(0,1fr)]' : 'space-y-5'}>{#if columns === 2}<ProfileCard {...profileData} {variant} />{/if}<ProjectsGrid projects={visibleProjects} {columns} /></div>
|
|
44
|
+
{:else if initialTab === 'activity'}
|
|
45
|
+
<div class="grid gap-6 xl:grid-cols-[20rem_minmax(0,1fr)]"><ProfileCard {...profileData} {variant} /><div class="space-y-4"><div class="flex items-center justify-between border-b border-border pb-3"><h2 class="text-base font-semibold text-foreground">{i18n.t('publicProfile.activity')}</h2><Badge variant="outline">{activities.length}</Badge></div><ActivityTimeline activities={activities} /></div></div>
|
|
183
46
|
{:else}
|
|
184
|
-
|
|
185
|
-
<
|
|
186
|
-
<Tabs.List class="w-full justify-start border-b">
|
|
187
|
-
<Tabs.Trigger value="projects" active={activeTab === 'projects'} onclick={() => activeTab = 'projects'} class="gap-1.5">{i18n.t('publicProfile.projects')}</Tabs.Trigger>
|
|
188
|
-
<Tabs.Trigger value="activity" active={activeTab === 'activity'} onclick={() => activeTab = 'activity'} class="gap-1.5">{i18n.t('publicProfile.activity')}</Tabs.Trigger>
|
|
189
|
-
<Tabs.Trigger value="teams" active={activeTab === 'teams'} onclick={() => activeTab = 'teams'} class="gap-1.5">{i18n.t('publicProfile.teams')}</Tabs.Trigger>
|
|
190
|
-
</Tabs.List>
|
|
191
|
-
<Tabs.Content value="projects" active={activeTab === 'projects'} class="mt-4">
|
|
192
|
-
<ProjectsGrid {columns} projects={columns === 3 ? demoProjects : demoProjects.slice(0, 6)} />
|
|
193
|
-
</Tabs.Content>
|
|
194
|
-
<Tabs.Content value="activity" active={activeTab === 'activity'} class="mt-4">
|
|
195
|
-
<ActivityTimeline activities={demoActivities} />
|
|
196
|
-
</Tabs.Content>
|
|
197
|
-
<Tabs.Content value="teams" active={activeTab === 'teams'} class="mt-4">
|
|
198
|
-
<TeamsShowcase teams={demoTeams} />
|
|
199
|
-
</Tabs.Content>
|
|
200
|
-
</Tabs.Root>
|
|
47
|
+
<div class="grid gap-4 sm:grid-cols-3">{#each profileData.stats as stat (stat.label)}<div class="border-l-2 border-primary pl-3"><p class="text-sm text-muted-foreground">{stat.label}</p><p class="mt-1 text-xl font-semibold text-foreground">{stat.value}</p></div>{/each}</div>
|
|
48
|
+
<div class="grid gap-6 xl:grid-cols-[minmax(0,1fr)_20rem]"><TeamsShowcase {teams} /><ProfileCard {...profileData} {variant} /></div>
|
|
201
49
|
{/if}
|
|
202
|
-
</
|
|
50
|
+
</ContentPageShell>
|
|
@@ -1,119 +1,17 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useTranslation } from '@svadmin/core/i18n';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { Users, ArrowRight, Search, Star } from '@lucide/svelte';
|
|
8
|
-
|
|
9
|
-
const i18n = useTranslation();
|
|
10
|
-
|
|
11
|
-
interface TeamMember {
|
|
12
|
-
name: string;
|
|
13
|
-
avatar?: string;
|
|
14
|
-
role?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface Team {
|
|
18
|
-
id: string;
|
|
19
|
-
name: string;
|
|
20
|
-
description: string;
|
|
21
|
-
members: TeamMember[];
|
|
22
|
-
totalMembers: number;
|
|
23
|
-
color?: string;
|
|
24
|
-
rating?: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface Props {
|
|
28
|
-
teams?: Team[];
|
|
29
|
-
}
|
|
30
|
-
|
|
3
|
+
import { DataState, FilterToolbar, TeamCard } from '../content/index.js';
|
|
4
|
+
import type { TeamSummary } from '../content/TeamCard.svelte';
|
|
5
|
+
interface Team extends TeamSummary { description: string; }
|
|
6
|
+
interface Props { teams?: Team[]; }
|
|
31
7
|
let { teams = [] }: Props = $props();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const filtered = $derived(
|
|
35
|
-
searchQuery
|
|
36
|
-
? teams.filter(t => t.name.toLowerCase().includes(searchQuery.toLowerCase()) || t.description.toLowerCase().includes(searchQuery.toLowerCase()))
|
|
37
|
-
: teams
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
const initials = (name: string) => name.split(' ').map(n => n[0]).join('').toUpperCase().slice(0, 2);
|
|
8
|
+
let query = $state('');
|
|
9
|
+
const i18n = useTranslation();
|
|
10
|
+
const filtered = $derived(query ? teams.filter((team) => `${team.name} ${team.description}`.toLowerCase().includes(query.toLowerCase())) : teams);
|
|
41
11
|
</script>
|
|
42
12
|
|
|
43
|
-
<
|
|
44
|
-
<div class="flex flex-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
<Input placeholder={i18n.t('publicProfile.searchTeams')} bind:value={searchQuery} class="w-48 pl-9" />
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
{#if filtered.length === 0}
|
|
53
|
-
<div class="rounded-xl border border-dashed border-border/60 p-8 text-center">
|
|
54
|
-
<p class="text-sm text-muted-foreground">{i18n.t('publicProfile.noTeams')}</p>
|
|
55
|
-
</div>
|
|
56
|
-
{:else}
|
|
57
|
-
<div class="grid gap-4 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
|
|
58
|
-
{#each filtered as team (team.id)}
|
|
59
|
-
<Card.Card class="border-border/60 hover:border-primary/30 transition-colors">
|
|
60
|
-
<Card.CardContent class="p-4 space-y-3">
|
|
61
|
-
<div class="flex items-start justify-between gap-2">
|
|
62
|
-
<div class="flex items-center gap-3">
|
|
63
|
-
{#if team.color}
|
|
64
|
-
<div class="h-8 w-8 rounded-lg" style="background-color: {team.color}20;">
|
|
65
|
-
<Users class="h-4 w-4" style="color: {team.color}" />
|
|
66
|
-
</div>
|
|
67
|
-
{:else}
|
|
68
|
-
<div class="flex h-8 w-8 items-center justify-center rounded-lg bg-primary/10 text-primary">
|
|
69
|
-
<Users class="h-4 w-4" />
|
|
70
|
-
</div>
|
|
71
|
-
{/if}
|
|
72
|
-
<div>
|
|
73
|
-
<h4 class="font-semibold text-foreground">{team.name}</h4>
|
|
74
|
-
<p class="text-xs text-muted-foreground">{i18n.t('publicProfile.projectMembers', { count: team.totalMembers })}</p>
|
|
75
|
-
</div>
|
|
76
|
-
</div>
|
|
77
|
-
{#if team.rating}
|
|
78
|
-
<span class="flex shrink-0 items-center gap-1 text-xs font-semibold text-amber-500">
|
|
79
|
-
<Star class="h-3.5 w-3.5 fill-amber-400 text-amber-400" />{team.rating}
|
|
80
|
-
</span>
|
|
81
|
-
{/if}
|
|
82
|
-
</div>
|
|
83
|
-
|
|
84
|
-
<p class="text-sm text-muted-foreground line-clamp-2">{team.description}</p>
|
|
85
|
-
|
|
86
|
-
<!-- Member avatars -->
|
|
87
|
-
<div class="flex items-center gap-1">
|
|
88
|
-
{#each team.members.slice(0, 5) as member (member.name)}
|
|
89
|
-
{#if member.avatar}
|
|
90
|
-
<Avatar class="h-7 w-7 ring-1 ring-background">
|
|
91
|
-
<img src={member.avatar} alt={member.name} />
|
|
92
|
-
</Avatar>
|
|
93
|
-
{:else}
|
|
94
|
-
<div class="flex h-7 w-7 items-center justify-center rounded-full bg-muted text-[10px] font-semibold text-muted-foreground ring-1 ring-background">
|
|
95
|
-
{initials(member.name)}
|
|
96
|
-
</div>
|
|
97
|
-
{/if}
|
|
98
|
-
{/each}
|
|
99
|
-
{#if team.members.length > 5}
|
|
100
|
-
<div class="flex h-7 w-7 items-center justify-center rounded-full bg-muted text-[10px] font-semibold text-muted-foreground ring-1 ring-background">
|
|
101
|
-
+{team.members.length - 5}
|
|
102
|
-
</div>
|
|
103
|
-
{/if}
|
|
104
|
-
</div>
|
|
105
|
-
|
|
106
|
-
<div class="flex gap-2 pt-2 border-t">
|
|
107
|
-
<Button variant="outline" size="sm" class="flex-1">
|
|
108
|
-
{i18n.t('publicProfile.join')}
|
|
109
|
-
</Button>
|
|
110
|
-
<Button variant="ghost" size="sm" class="flex-1">
|
|
111
|
-
{i18n.t('publicProfile.viewProfile')} <ArrowRight class="h-3.5 w-3.5 ml-1" />
|
|
112
|
-
</Button>
|
|
113
|
-
</div>
|
|
114
|
-
</Card.CardContent>
|
|
115
|
-
</Card.Card>
|
|
116
|
-
{/each}
|
|
117
|
-
</div>
|
|
118
|
-
{/if}
|
|
119
|
-
</div>
|
|
13
|
+
<section class="space-y-4">
|
|
14
|
+
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"><div><h2 class="text-base font-semibold text-foreground">{i18n.t('publicProfile.teamsCount', { count: filtered.length })}</h2><p class="mt-1 text-sm text-muted-foreground">{i18n.t('publicProfile.searchTeams')}</p></div></div>
|
|
15
|
+
<FilterToolbar bind:query placeholder={i18n.t('publicProfile.searchTeams')} />
|
|
16
|
+
{#if filtered.length === 0}<DataState state="empty" title={i18n.t('publicProfile.noTeams')} />{:else}<div class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">{#each filtered as team (team.id)}<TeamCard {team} />{/each}</div>{/if}
|
|
17
|
+
</section>
|
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
avatar?: string;
|
|
4
|
-
role?: string;
|
|
5
|
-
}
|
|
6
|
-
interface Team {
|
|
7
|
-
id: string;
|
|
8
|
-
name: string;
|
|
1
|
+
import type { TeamSummary } from '../content/TeamCard.svelte';
|
|
2
|
+
interface Team extends TeamSummary {
|
|
9
3
|
description: string;
|
|
10
|
-
members: TeamMember[];
|
|
11
|
-
totalMembers: number;
|
|
12
|
-
color?: string;
|
|
13
|
-
rating?: number;
|
|
14
4
|
}
|
|
15
5
|
interface Props {
|
|
16
6
|
teams?: Team[];
|
package/dist/index.d.ts
CHANGED
|
@@ -151,3 +151,39 @@ export { default as TeamMembersPage } from './components/account/TeamMembersPage
|
|
|
151
151
|
export { default as UserCardsNFTPage } from './components/network/UserCardsNFTPage.svelte';
|
|
152
152
|
export { default as TeamCrewTablePage } from './components/network/TeamCrewTablePage.svelte';
|
|
153
153
|
export { default as TwoFactorAuthPage } from './components/TwoFactorAuthPage.svelte';
|
|
154
|
+
export { default as ContentPageShell } from './components/content/ContentPageShell.svelte';
|
|
155
|
+
export { default as ContentPageHeader } from './components/content/ContentPageHeader.svelte';
|
|
156
|
+
export { default as SectionHeader } from './components/content/SectionHeader.svelte';
|
|
157
|
+
export { default as PageToolbar } from './components/content/PageToolbar.svelte';
|
|
158
|
+
export { default as MetricBlock } from './components/content/MetricBlock.svelte';
|
|
159
|
+
export { default as DescriptionList } from './components/content/DescriptionList.svelte';
|
|
160
|
+
export type { DescriptionItem } from './components/content/DescriptionList.svelte';
|
|
161
|
+
export { default as StatusBadge } from './components/content/StatusBadge.svelte';
|
|
162
|
+
export type { Status } from './components/content/StatusBadge.svelte';
|
|
163
|
+
export { default as FilterToolbar } from './components/content/FilterToolbar.svelte';
|
|
164
|
+
export { default as DataState } from './components/content/DataState.svelte';
|
|
165
|
+
export type { DataStateKind } from './components/content/DataState.svelte';
|
|
166
|
+
export { default as ProjectCard } from './components/content/ProjectCard.svelte';
|
|
167
|
+
export type { ProjectSummary, ProjectStatus } from './components/content/ProjectCard.svelte';
|
|
168
|
+
export { default as TeamCard } from './components/content/TeamCard.svelte';
|
|
169
|
+
export type { TeamSummary } from './components/content/TeamCard.svelte';
|
|
170
|
+
export { default as FileList } from './components/content/FileList.svelte';
|
|
171
|
+
export type { FileItem } from './components/content/FileList.svelte';
|
|
172
|
+
export { default as IntegrationCard } from './components/content/IntegrationCard.svelte';
|
|
173
|
+
export type { IntegrationSummary } from './components/content/IntegrationCard.svelte';
|
|
174
|
+
export { default as ApiKeyList } from './components/content/ApiKeyList.svelte';
|
|
175
|
+
export type { ApiKeySummary } from './components/content/ApiKeyList.svelte';
|
|
176
|
+
export { default as SecurityEventTable } from './components/content/SecurityEventTable.svelte';
|
|
177
|
+
export type { SecurityEvent } from './components/content/SecurityEventTable.svelte';
|
|
178
|
+
export { default as MemberList } from './components/content/MemberList.svelte';
|
|
179
|
+
export type { MemberSummary } from './components/content/MemberList.svelte';
|
|
180
|
+
export { default as ImportDropzone } from './components/content/ImportDropzone.svelte';
|
|
181
|
+
export { default as NetworkUserCard } from './components/content/NetworkUserCard.svelte';
|
|
182
|
+
export type { NetworkUser } from './components/content/NetworkUserCard.svelte';
|
|
183
|
+
export { default as NetworkTable } from './components/content/NetworkTable.svelte';
|
|
184
|
+
export type { NetworkColumn } from './components/content/NetworkTable.types.js';
|
|
185
|
+
export { default as OtpInput } from './components/content/OtpInput.svelte';
|
|
186
|
+
export { default as TwoFactorStepper } from './components/content/TwoFactorStepper.svelte';
|
|
187
|
+
export { default as SystemErrorState } from './components/content/SystemErrorState.svelte';
|
|
188
|
+
export { referenceDemoData } from './reference-data.js';
|
|
189
|
+
export type { DemoMember, DemoProject, DemoTeam, DemoIntegration, DemoApiKey, DemoSecurityEvent, DemoNotification } from './reference-data.js';
|