Style guide improvement
This commit is contained in:
@@ -11,6 +11,7 @@
|
|||||||
Spinner,
|
Spinner,
|
||||||
Toggle,
|
Toggle,
|
||||||
Toast,
|
Toast,
|
||||||
|
ToastContainer,
|
||||||
Chip,
|
Chip,
|
||||||
ListItem,
|
ListItem,
|
||||||
OrgHeader,
|
OrgHeader,
|
||||||
@@ -27,6 +28,22 @@
|
|||||||
StatCard,
|
StatCard,
|
||||||
StatusBadge,
|
StatusBadge,
|
||||||
TabBar,
|
TabBar,
|
||||||
|
Icon,
|
||||||
|
ContextMenu,
|
||||||
|
KanbanColumn,
|
||||||
|
AssigneePicker,
|
||||||
|
MemberList,
|
||||||
|
ActivityFeed,
|
||||||
|
EventCard,
|
||||||
|
ModuleCard,
|
||||||
|
QuickLinkGrid,
|
||||||
|
PageSkeleton,
|
||||||
|
ContentSkeleton,
|
||||||
|
Twemoji,
|
||||||
|
EmojiPicker,
|
||||||
|
ImagePreviewModal,
|
||||||
|
VirtualList,
|
||||||
|
PersonContactModal,
|
||||||
} from "$lib/components/ui";
|
} from "$lib/components/ui";
|
||||||
|
|
||||||
let inputValue = $state("");
|
let inputValue = $state("");
|
||||||
@@ -34,9 +51,96 @@
|
|||||||
let selectValue = $state("");
|
let selectValue = $state("");
|
||||||
let toggleChecked = $state(false);
|
let toggleChecked = $state(false);
|
||||||
let modalOpen = $state(false);
|
let modalOpen = $state(false);
|
||||||
|
let imagePreviewOpen = $state(false);
|
||||||
|
let emojiPickerOpen = $state(false);
|
||||||
|
let personModalProfile = $state<any>(null);
|
||||||
|
let assigneeValue = $state<string | null>(null);
|
||||||
let activeTab = $state("tab1");
|
let activeTab = $state("tab1");
|
||||||
let searchFilter = $state("");
|
let searchFilter = $state("");
|
||||||
|
|
||||||
|
const demoMembers = [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
user_id: "u1",
|
||||||
|
role: "owner",
|
||||||
|
profiles: {
|
||||||
|
id: "u1",
|
||||||
|
email: "alice@example.com",
|
||||||
|
full_name: "Alice Johnson",
|
||||||
|
avatar_url: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
user_id: "u2",
|
||||||
|
role: "admin",
|
||||||
|
profiles: {
|
||||||
|
id: "u2",
|
||||||
|
email: "bob@example.com",
|
||||||
|
full_name: "Bob Smith",
|
||||||
|
avatar_url: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "3",
|
||||||
|
user_id: "u3",
|
||||||
|
role: "member",
|
||||||
|
profiles: {
|
||||||
|
id: "u3",
|
||||||
|
email: "charlie@example.com",
|
||||||
|
full_name: "Charlie Brown",
|
||||||
|
avatar_url: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "4",
|
||||||
|
user_id: "u4",
|
||||||
|
role: "member",
|
||||||
|
profiles: {
|
||||||
|
id: "u4",
|
||||||
|
email: "diana@example.com",
|
||||||
|
full_name: "Diana Prince",
|
||||||
|
avatar_url: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const demoActivity = [
|
||||||
|
{
|
||||||
|
id: "a1",
|
||||||
|
action: "create",
|
||||||
|
entity_type: "document",
|
||||||
|
entity_id: "d1",
|
||||||
|
entity_name: "Project Brief",
|
||||||
|
created_at: new Date(Date.now() - 300000).toISOString(),
|
||||||
|
profiles: {
|
||||||
|
full_name: "Alice Johnson",
|
||||||
|
email: "alice@example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "a2",
|
||||||
|
action: "update",
|
||||||
|
entity_type: "kanban_card",
|
||||||
|
entity_id: "k1",
|
||||||
|
entity_name: "Design Review",
|
||||||
|
created_at: new Date(Date.now() - 3600000).toISOString(),
|
||||||
|
profiles: { full_name: "Bob Smith", email: "bob@example.com" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "a3",
|
||||||
|
action: "delete",
|
||||||
|
entity_type: "folder",
|
||||||
|
entity_id: "f1",
|
||||||
|
entity_name: "Old Files",
|
||||||
|
created_at: new Date(Date.now() - 86400000).toISOString(),
|
||||||
|
profiles: {
|
||||||
|
full_name: "Charlie Brown",
|
||||||
|
email: "charlie@example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const selectOptions = [
|
const selectOptions = [
|
||||||
{ value: "option1", label: "Option 1" },
|
{ value: "option1", label: "Option 1" },
|
||||||
{ value: "option2", label: "Option 2" },
|
{ value: "option2", label: "Option 2" },
|
||||||
@@ -47,7 +151,7 @@
|
|||||||
// Component Registry - add new components here and they render automatically
|
// Component Registry - add new components here and they render automatically
|
||||||
// Each entry: { name, description, sections: [{ label, ... }] }
|
// Each entry: { name, description, sections: [{ label, ... }] }
|
||||||
// ============================================================
|
// ============================================================
|
||||||
const componentCount = 25;
|
const componentCount = 42;
|
||||||
|
|
||||||
const colors = [
|
const colors = [
|
||||||
{
|
{
|
||||||
@@ -97,9 +201,13 @@
|
|||||||
"Colors",
|
"Colors",
|
||||||
"Typography",
|
"Typography",
|
||||||
"Button",
|
"Button",
|
||||||
|
"Icon",
|
||||||
|
"IconButton",
|
||||||
"Input",
|
"Input",
|
||||||
"Textarea",
|
"Textarea",
|
||||||
"Select",
|
"Select",
|
||||||
|
"Toggle",
|
||||||
|
"AssigneePicker",
|
||||||
"Avatar",
|
"Avatar",
|
||||||
"Badge",
|
"Badge",
|
||||||
"Chip",
|
"Chip",
|
||||||
@@ -107,21 +215,33 @@
|
|||||||
"Card",
|
"Card",
|
||||||
"SectionCard",
|
"SectionCard",
|
||||||
"StatCard",
|
"StatCard",
|
||||||
"Toggle",
|
"ModuleCard",
|
||||||
|
"EventCard",
|
||||||
|
"KanbanColumn",
|
||||||
|
"ListItem",
|
||||||
|
"MemberList",
|
||||||
|
"ActivityFeed",
|
||||||
|
"QuickLinkGrid",
|
||||||
|
"Modal",
|
||||||
|
"ImagePreviewModal",
|
||||||
|
"PersonContactModal",
|
||||||
|
"ContextMenu",
|
||||||
|
"Dropdown",
|
||||||
|
"Toast",
|
||||||
"Spinner",
|
"Spinner",
|
||||||
"Skeleton",
|
"Skeleton",
|
||||||
"Modal",
|
"PageSkeleton",
|
||||||
"Toast",
|
"ContentSkeleton",
|
||||||
"Logo",
|
"Logo",
|
||||||
"ListItem",
|
|
||||||
"OrgHeader",
|
"OrgHeader",
|
||||||
"IconButton",
|
|
||||||
"ContentHeader",
|
"ContentHeader",
|
||||||
"PageHeader",
|
"PageHeader",
|
||||||
"CalendarDay",
|
"CalendarDay",
|
||||||
"TabBar",
|
"TabBar",
|
||||||
"EmptyState",
|
"EmptyState",
|
||||||
"Dropdown",
|
"Twemoji",
|
||||||
|
"EmojiPicker",
|
||||||
|
"VirtualList",
|
||||||
];
|
];
|
||||||
|
|
||||||
const filteredSections = $derived(
|
const filteredSections = $derived(
|
||||||
@@ -339,6 +459,54 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Icon -->
|
||||||
|
<section id="icon" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
Icon
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
Sizes
|
||||||
|
</h3>
|
||||||
|
<div class="flex items-end gap-4">
|
||||||
|
{#each [16, 20, 24, 32, 48] as size}
|
||||||
|
<div class="flex flex-col items-center gap-1">
|
||||||
|
<Icon name="star" {size} />
|
||||||
|
<span class="text-[10px] text-light/30"
|
||||||
|
>{size}px</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
Various Icons
|
||||||
|
</h3>
|
||||||
|
<div class="flex flex-wrap gap-4">
|
||||||
|
{#each ["home", "settings", "search", "notifications", "person", "edit", "delete", "add", "check_circle", "error", "info", "warning", "folder", "description", "calendar_today", "group"] as name}
|
||||||
|
<div
|
||||||
|
class="flex flex-col items-center gap-1 w-14"
|
||||||
|
>
|
||||||
|
<Icon {name} size={24} />
|
||||||
|
<span
|
||||||
|
class="text-[9px] text-light/30 truncate w-full text-center"
|
||||||
|
>{name}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Input -->
|
<!-- Input -->
|
||||||
<section id="input" class="space-y-4">
|
<section id="input" class="space-y-4">
|
||||||
<h2
|
<h2
|
||||||
@@ -976,6 +1144,578 @@
|
|||||||
</Dropdown>
|
</Dropdown>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- AssigneePicker -->
|
||||||
|
<section id="assigneepicker" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
AssigneePicker
|
||||||
|
</h2>
|
||||||
|
<div class="max-w-sm">
|
||||||
|
<AssigneePicker
|
||||||
|
value={assigneeValue}
|
||||||
|
members={demoMembers}
|
||||||
|
label="Assigned to"
|
||||||
|
onchange={(v) => (assigneeValue = v)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p class="text-body-sm text-light/40">
|
||||||
|
Selected: {assigneeValue ?? "none"}
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ContextMenu -->
|
||||||
|
<section id="contextmenu" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
ContextMenu
|
||||||
|
</h2>
|
||||||
|
<p class="text-body-sm text-light/40">
|
||||||
|
A three-dot menu that opens a dropdown with actions. Click
|
||||||
|
the icon to toggle.
|
||||||
|
</p>
|
||||||
|
<div class="flex items-center gap-6">
|
||||||
|
<div class="flex flex-col items-center gap-1">
|
||||||
|
<ContextMenu
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
label: "Edit",
|
||||||
|
icon: "edit",
|
||||||
|
onclick: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Duplicate",
|
||||||
|
icon: "content_copy",
|
||||||
|
onclick: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "",
|
||||||
|
icon: "",
|
||||||
|
onclick: () => {},
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Delete",
|
||||||
|
icon: "delete",
|
||||||
|
onclick: () => {},
|
||||||
|
danger: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<span class="text-[10px] text-light/30">right</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center gap-1">
|
||||||
|
<ContextMenu
|
||||||
|
align="left"
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
label: "Share",
|
||||||
|
icon: "share",
|
||||||
|
onclick: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Export",
|
||||||
|
icon: "download",
|
||||||
|
onclick: () => {},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<span class="text-[10px] text-light/30">left</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- KanbanColumn -->
|
||||||
|
<section id="kanbancolumn" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
KanbanColumn
|
||||||
|
</h2>
|
||||||
|
<div
|
||||||
|
class="flex gap-3 overflow-x-auto pb-2"
|
||||||
|
style="height: 320px"
|
||||||
|
>
|
||||||
|
<KanbanColumn title="To Do" count={2} onAddCard={() => {}}>
|
||||||
|
<div
|
||||||
|
class="bg-surface border border-light/5 rounded-xl p-3"
|
||||||
|
>
|
||||||
|
<p class="text-body-sm text-white">
|
||||||
|
Design mockups
|
||||||
|
</p>
|
||||||
|
<p class="text-[11px] text-light/40 mt-1">
|
||||||
|
Due tomorrow
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-surface border border-light/5 rounded-xl p-3"
|
||||||
|
>
|
||||||
|
<p class="text-body-sm text-white">Write specs</p>
|
||||||
|
</div>
|
||||||
|
</KanbanColumn>
|
||||||
|
<KanbanColumn
|
||||||
|
title="In Progress"
|
||||||
|
count={1}
|
||||||
|
onAddCard={() => {}}
|
||||||
|
onMore={() => {}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="bg-surface border border-light/5 rounded-xl p-3"
|
||||||
|
>
|
||||||
|
<p class="text-body-sm text-white">
|
||||||
|
API integration
|
||||||
|
</p>
|
||||||
|
<p class="text-[11px] text-light/40 mt-1">
|
||||||
|
Started 2h ago
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</KanbanColumn>
|
||||||
|
<KanbanColumn title="Done" count={0} onAddCard={() => {}} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- MemberList -->
|
||||||
|
<section id="memberlist" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
MemberList
|
||||||
|
</h2>
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div
|
||||||
|
class="bg-dark/30 border border-light/5 p-4 rounded-xl"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
With Members
|
||||||
|
</h3>
|
||||||
|
<MemberList
|
||||||
|
members={demoMembers}
|
||||||
|
max={3}
|
||||||
|
moreHref="#"
|
||||||
|
moreLabel="+1 more"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-dark/30 border border-light/5 p-4 rounded-xl"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
Empty
|
||||||
|
</h3>
|
||||||
|
<MemberList members={[]} emptyLabel="No members yet" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ActivityFeed -->
|
||||||
|
<section id="activityfeed" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
ActivityFeed
|
||||||
|
</h2>
|
||||||
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
|
<div
|
||||||
|
class="bg-dark/30 border border-light/5 p-4 rounded-xl"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
With Entries
|
||||||
|
</h3>
|
||||||
|
<ActivityFeed entries={demoActivity} />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bg-dark/30 border border-light/5 p-4 rounded-xl"
|
||||||
|
>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
Empty
|
||||||
|
</h3>
|
||||||
|
<ActivityFeed entries={[]} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- EventCard -->
|
||||||
|
<section id="eventcard" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
EventCard
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
Full Card
|
||||||
|
</h3>
|
||||||
|
<div class="grid md:grid-cols-2 gap-4">
|
||||||
|
<EventCard
|
||||||
|
name="Summer Hackathon"
|
||||||
|
slug="summer-hackathon"
|
||||||
|
status="active"
|
||||||
|
startDate="2026-06-15"
|
||||||
|
endDate="2026-06-17"
|
||||||
|
color="#33b679"
|
||||||
|
venueName="Tech Hub"
|
||||||
|
href="#"
|
||||||
|
/>
|
||||||
|
<EventCard
|
||||||
|
name="Design Sprint"
|
||||||
|
slug="design-sprint"
|
||||||
|
status="planning"
|
||||||
|
startDate="2026-07-01"
|
||||||
|
endDate={null}
|
||||||
|
color="#7986cb"
|
||||||
|
venueName={null}
|
||||||
|
href="#"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
Compact
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
class="max-w-md bg-dark/30 border border-light/5 rounded-xl overflow-hidden"
|
||||||
|
>
|
||||||
|
<EventCard
|
||||||
|
name="Team Retreat"
|
||||||
|
slug="team-retreat"
|
||||||
|
status="completed"
|
||||||
|
startDate="2026-03-10"
|
||||||
|
endDate="2026-03-12"
|
||||||
|
color="#e67c73"
|
||||||
|
venueName="Mountain Lodge"
|
||||||
|
href="#"
|
||||||
|
compact
|
||||||
|
/>
|
||||||
|
<EventCard
|
||||||
|
name="Q2 Planning"
|
||||||
|
slug="q2-planning"
|
||||||
|
status="draft"
|
||||||
|
startDate="2026-04-01"
|
||||||
|
endDate={null}
|
||||||
|
color="#f6bf26"
|
||||||
|
venueName={null}
|
||||||
|
href="#"
|
||||||
|
compact
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ModuleCard -->
|
||||||
|
<section id="modulecard" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
ModuleCard
|
||||||
|
</h2>
|
||||||
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||||
|
<ModuleCard
|
||||||
|
label="Documents"
|
||||||
|
description="Shared files and folders"
|
||||||
|
icon="description"
|
||||||
|
href="#"
|
||||||
|
/>
|
||||||
|
<ModuleCard
|
||||||
|
label="Calendar"
|
||||||
|
description="Events and scheduling"
|
||||||
|
icon="calendar_today"
|
||||||
|
href="#"
|
||||||
|
color="text-success"
|
||||||
|
bg="bg-success/10"
|
||||||
|
/>
|
||||||
|
<ModuleCard
|
||||||
|
label="Kanban"
|
||||||
|
description="Task boards"
|
||||||
|
icon="view_kanban"
|
||||||
|
href="#"
|
||||||
|
color="text-warning"
|
||||||
|
bg="bg-warning/10"
|
||||||
|
/>
|
||||||
|
<ModuleCard
|
||||||
|
label="Finances"
|
||||||
|
description="Budget tracking"
|
||||||
|
icon="payments"
|
||||||
|
href="#"
|
||||||
|
color="text-error"
|
||||||
|
bg="bg-error/10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- QuickLinkGrid -->
|
||||||
|
<section id="quicklinkgrid" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
QuickLinkGrid
|
||||||
|
</h2>
|
||||||
|
<div class="max-w-xs">
|
||||||
|
<QuickLinkGrid
|
||||||
|
links={[
|
||||||
|
{
|
||||||
|
label: "Documents",
|
||||||
|
icon: "description",
|
||||||
|
href: "#",
|
||||||
|
color: "text-primary",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Calendar",
|
||||||
|
icon: "calendar_today",
|
||||||
|
href: "#",
|
||||||
|
color: "text-success",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Team",
|
||||||
|
icon: "group",
|
||||||
|
href: "#",
|
||||||
|
color: "text-warning",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Settings",
|
||||||
|
icon: "settings",
|
||||||
|
href: "#",
|
||||||
|
color: "text-light/50",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ImagePreviewModal -->
|
||||||
|
<section id="imagepreviewmodal" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
ImagePreviewModal
|
||||||
|
</h2>
|
||||||
|
<Button onclick={() => (imagePreviewOpen = true)}
|
||||||
|
>Open Image Preview</Button
|
||||||
|
>
|
||||||
|
</section>
|
||||||
|
{#if imagePreviewOpen}
|
||||||
|
<ImagePreviewModal
|
||||||
|
src="https://placehold.co/800x600/0F1B2E/00A3E0?text=Preview"
|
||||||
|
alt="Demo image"
|
||||||
|
onClose={() => (imagePreviewOpen = false)}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- PersonContactModal -->
|
||||||
|
<section id="personcontactmodal" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
PersonContactModal
|
||||||
|
</h2>
|
||||||
|
<Button
|
||||||
|
onclick={() =>
|
||||||
|
(personModalProfile = {
|
||||||
|
id: "demo-1",
|
||||||
|
full_name: "Alice Johnson",
|
||||||
|
email: "alice@example.com",
|
||||||
|
phone: "+1 555-0123",
|
||||||
|
avatar_url: null,
|
||||||
|
discord_handle: "alice#1234",
|
||||||
|
shirt_size: "M",
|
||||||
|
hoodie_size: "M",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
Open Person Modal
|
||||||
|
</Button>
|
||||||
|
</section>
|
||||||
|
<PersonContactModal
|
||||||
|
profile={personModalProfile}
|
||||||
|
role="admin"
|
||||||
|
roleName="Admin"
|
||||||
|
isOpen={personModalProfile !== null}
|
||||||
|
onClose={() => (personModalProfile = null)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- PageSkeleton -->
|
||||||
|
<section id="pageskeleton" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
PageSkeleton
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-6">
|
||||||
|
{#each ["default", "kanban", "files", "calendar", "settings"] as variant}
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
{variant}
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
class="bg-dark/30 border border-light/5 rounded-xl overflow-hidden h-[200px]"
|
||||||
|
>
|
||||||
|
<PageSkeleton
|
||||||
|
variant={variant as
|
||||||
|
| "default"
|
||||||
|
| "kanban"
|
||||||
|
| "files"
|
||||||
|
| "calendar"
|
||||||
|
| "settings"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ContentSkeleton -->
|
||||||
|
<section id="contentskeleton" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
ContentSkeleton
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-6">
|
||||||
|
{#each ["default", "kanban", "files", "list", "detail"] as variant}
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
{variant}
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
class="bg-dark/30 border border-light/5 rounded-xl overflow-hidden h-[200px]"
|
||||||
|
>
|
||||||
|
<ContentSkeleton
|
||||||
|
variant={variant as
|
||||||
|
| "default"
|
||||||
|
| "kanban"
|
||||||
|
| "files"
|
||||||
|
| "list"
|
||||||
|
| "detail"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Twemoji -->
|
||||||
|
<section id="twemoji" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
Twemoji
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
Sizes
|
||||||
|
</h3>
|
||||||
|
<div class="flex items-end gap-4">
|
||||||
|
{#each [16, 24, 32, 48] as size}
|
||||||
|
<div class="flex flex-col items-center gap-1">
|
||||||
|
<Twemoji emoji="🚀" {size} />
|
||||||
|
<span class="text-[10px] text-light/30"
|
||||||
|
>{size}px</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3
|
||||||
|
class="text-body-sm font-heading text-light/60 mb-2"
|
||||||
|
>
|
||||||
|
Various Emojis
|
||||||
|
</h3>
|
||||||
|
<div class="flex flex-wrap gap-3">
|
||||||
|
{#each ["😀", "🎉", "🔥", "💡", "⭐", "🎯", "📦", "🛠️", "✅", "❌", "🌍", "🎨"] as emoji}
|
||||||
|
<Twemoji {emoji} size={32} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- EmojiPicker -->
|
||||||
|
<section id="emojipicker" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
EmojiPicker
|
||||||
|
</h2>
|
||||||
|
<p class="text-body-sm text-light/40">
|
||||||
|
A full emoji picker with category tabs and search. Click to
|
||||||
|
open.
|
||||||
|
</p>
|
||||||
|
<div class="relative">
|
||||||
|
<Button onclick={() => (emojiPickerOpen = !emojiPickerOpen)}
|
||||||
|
>{emojiPickerOpen
|
||||||
|
? "Close Picker"
|
||||||
|
: "Open Emoji Picker"}</Button
|
||||||
|
>
|
||||||
|
{#if emojiPickerOpen}
|
||||||
|
<div class="absolute top-12 left-0 z-50">
|
||||||
|
<EmojiPicker
|
||||||
|
onSelect={(emoji) => {
|
||||||
|
emojiPickerOpen = false;
|
||||||
|
}}
|
||||||
|
onClose={() => (emojiPickerOpen = false)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- VirtualList -->
|
||||||
|
<section id="virtuallist" class="space-y-4">
|
||||||
|
<h2
|
||||||
|
class="font-heading text-body text-white border-b border-light/5 pb-2"
|
||||||
|
>
|
||||||
|
VirtualList
|
||||||
|
</h2>
|
||||||
|
<p class="text-body-sm text-light/40">
|
||||||
|
Renders only visible items for large lists. Scroll to see
|
||||||
|
virtualization in action.
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
class="bg-dark/30 border border-light/5 rounded-xl overflow-hidden"
|
||||||
|
style="height: 240px"
|
||||||
|
>
|
||||||
|
<VirtualList
|
||||||
|
items={Array.from({ length: 1000 }, (_, i) => ({
|
||||||
|
id: i,
|
||||||
|
label: `Item ${i + 1}`,
|
||||||
|
}))}
|
||||||
|
itemHeight={40}
|
||||||
|
getKey={(item) => String(item.id)}
|
||||||
|
>
|
||||||
|
{#snippet children(
|
||||||
|
item: { id: number; label: string },
|
||||||
|
_index: number,
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
class="flex items-center px-4 h-[40px] border-b border-light/5 text-body-sm text-light/70"
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</div>
|
||||||
|
{/snippet}
|
||||||
|
</VirtualList>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<footer class="text-center py-8 border-t border-light/5">
|
<footer class="text-center py-8 border-t border-light/5">
|
||||||
<p class="text-[11px] text-light/30 font-body">
|
<p class="text-[11px] text-light/30 font-body">
|
||||||
|
|||||||
Reference in New Issue
Block a user