twintrinsic 0.0.1
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/LICENSE +674 -0
- package/README.md +150 -0
- package/dist/App/App.svelte +54 -0
- package/dist/App/App.svelte.d.ts +65 -0
- package/dist/Section.svelte +25 -0
- package/dist/Section.svelte.d.ts +34 -0
- package/dist/actions/clickOutside.d.ts +9 -0
- package/dist/actions/clickOutside.js +19 -0
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/components/Accordion/Accordion.svelte +75 -0
- package/dist/components/Accordion/Accordion.svelte.d.ts +39 -0
- package/dist/components/Accordion/AccordionItem.svelte +150 -0
- package/dist/components/Accordion/AccordionItem.svelte.d.ts +30 -0
- package/dist/components/App/App.story.md +8 -0
- package/dist/components/App/App.story.svelte +170 -0
- package/dist/components/App/App.story.svelte.d.ts +22 -0
- package/dist/components/App/App.svelte +77 -0
- package/dist/components/App/App.svelte.d.ts +66 -0
- package/dist/components/App/Split.svelte +346 -0
- package/dist/components/App/Split.svelte.d.ts +54 -0
- package/dist/components/App/index.d.ts +2 -0
- package/dist/components/App/index.js +3 -0
- package/dist/components/AppHeader/AppHeader.svelte +439 -0
- package/dist/components/AppHeader/AppHeader.svelte.d.ts +24 -0
- package/dist/components/Avatar/Avatar.svelte +300 -0
- package/dist/components/Avatar/Avatar.svelte.d.ts +48 -0
- package/dist/components/Avatar/AvatarGroup.svelte +185 -0
- package/dist/components/Avatar/AvatarGroup.svelte.d.ts +46 -0
- package/dist/components/Badge/Badge.svelte +186 -0
- package/dist/components/Badge/Badge.svelte.d.ts +51 -0
- package/dist/components/BottomBar/BottomBar.svelte +146 -0
- package/dist/components/BottomBar/BottomBar.svelte.d.ts +38 -0
- package/dist/components/Breadcrumb/Breadcrumb.svelte +77 -0
- package/dist/components/Breadcrumb/Breadcrumb.svelte.d.ts +42 -0
- package/dist/components/Breadcrumb/BreadcrumbItem.svelte +171 -0
- package/dist/components/Breadcrumb/BreadcrumbItem.svelte.d.ts +38 -0
- package/dist/components/Button/Button.svelte +252 -0
- package/dist/components/Button/Button.svelte.d.ts +80 -0
- package/dist/components/Button/ButtonGroup.svelte +127 -0
- package/dist/components/Button/ButtonGroup.svelte.d.ts +44 -0
- package/dist/components/Card/Card.svelte +152 -0
- package/dist/components/Card/Card.svelte.d.ts +55 -0
- package/dist/components/Carousel/Carousel.svelte +461 -0
- package/dist/components/Carousel/Carousel.svelte.d.ts +79 -0
- package/dist/components/Carousel/CarouselItem.svelte +149 -0
- package/dist/components/Carousel/CarouselItem.svelte.d.ts +35 -0
- package/dist/components/Chip/Chip.svelte +288 -0
- package/dist/components/Chip/Chip.svelte.d.ts +71 -0
- package/dist/components/Chip/ChipGroup.svelte +190 -0
- package/dist/components/Chip/ChipGroup.svelte.d.ts +71 -0
- package/dist/components/CodeBlock/CodeBlock.svelte +356 -0
- package/dist/components/CodeBlock/CodeBlock.svelte.d.ts +44 -0
- package/dist/components/CodeBlock/index.d.ts +1 -0
- package/dist/components/CodeBlock/index.js +1 -0
- package/dist/components/CodeBlockSpeed/CodeBlockSpeed.svelte +145 -0
- package/dist/components/CodeBlockSpeed/CodeBlockSpeed.svelte.d.ts +44 -0
- package/dist/components/CodeEditor/CodeEditor.svelte +229 -0
- package/dist/components/CodeEditor/CodeEditor.svelte.d.ts +23 -0
- package/dist/components/Combobox/Combobox.svelte +279 -0
- package/dist/components/Combobox/Combobox.svelte.d.ts +34 -0
- package/dist/components/Container/Container.svelte +45 -0
- package/dist/components/Container/Container.svelte.d.ts +36 -0
- package/dist/components/DataTable/DataTable.svelte +879 -0
- package/dist/components/DataTable/DataTable.svelte.d.ts +102 -0
- package/dist/components/Form/AutoComplete.svelte +357 -0
- package/dist/components/Form/AutoComplete.svelte.d.ts +73 -0
- package/dist/components/Form/Calendar.svelte +429 -0
- package/dist/components/Form/Calendar.svelte.d.ts +53 -0
- package/dist/components/Form/Checkbox.svelte +196 -0
- package/dist/components/Form/Checkbox.svelte.d.ts +50 -0
- package/dist/components/Form/ColorPicker.svelte +396 -0
- package/dist/components/Form/ColorPicker.svelte.d.ts +43 -0
- package/dist/components/Form/Combobox.svelte +645 -0
- package/dist/components/Form/Combobox.svelte.d.ts +93 -0
- package/dist/components/Form/Dropdown.svelte +773 -0
- package/dist/components/Form/Dropdown.svelte.d.ts +81 -0
- package/dist/components/Form/FileUpload.svelte +796 -0
- package/dist/components/Form/FileUpload.svelte.d.ts +78 -0
- package/dist/components/Form/FloatLabel.svelte +245 -0
- package/dist/components/Form/FloatLabel.svelte.d.ts +44 -0
- package/dist/components/Form/Form.svelte +281 -0
- package/dist/components/Form/Form.svelte.d.ts +54 -0
- package/dist/components/Form/FormField.svelte +218 -0
- package/dist/components/Form/FormField.svelte.d.ts +47 -0
- package/dist/components/Form/Input.svelte +340 -0
- package/dist/components/Form/Input.svelte.d.ts +79 -0
- package/dist/components/Form/InputSwitch.svelte +189 -0
- package/dist/components/Form/InputSwitch.svelte.d.ts +46 -0
- package/dist/components/Form/InvalidState.svelte +97 -0
- package/dist/components/Form/InvalidState.svelte.d.ts +37 -0
- package/dist/components/Form/Knob.svelte +537 -0
- package/dist/components/Form/Knob.svelte.d.ts +78 -0
- package/dist/components/Form/ListInput.svelte +469 -0
- package/dist/components/Form/ListInput.svelte.d.ts +70 -0
- package/dist/components/Form/Listbox.svelte +513 -0
- package/dist/components/Form/Listbox.svelte.d.ts +74 -0
- package/dist/components/Form/NumberInput.svelte +452 -0
- package/dist/components/Form/NumberInput.svelte.d.ts +82 -0
- package/dist/components/Form/Radio.svelte +192 -0
- package/dist/components/Form/Radio.svelte.d.ts +53 -0
- package/dist/components/Form/RadioGroup.svelte +155 -0
- package/dist/components/Form/RadioGroup.svelte.d.ts +48 -0
- package/dist/components/Form/Rating.svelte +380 -0
- package/dist/components/Form/Rating.svelte.d.ts +64 -0
- package/dist/components/Form/Select.svelte +436 -0
- package/dist/components/Form/Select.svelte.d.ts +49 -0
- package/dist/components/Form/SelectGroup.svelte +34 -0
- package/dist/components/Form/SelectGroup.svelte.d.ts +33 -0
- package/dist/components/Form/Slider.svelte +622 -0
- package/dist/components/Form/Slider.svelte.d.ts +73 -0
- package/dist/components/Form/Switch.svelte +192 -0
- package/dist/components/Form/Switch.svelte.d.ts +46 -0
- package/dist/components/Form/TextInput.svelte +274 -0
- package/dist/components/Form/TextInput.svelte.d.ts +74 -0
- package/dist/components/Form/Textarea.svelte +207 -0
- package/dist/components/Form/Textarea.svelte.d.ts +62 -0
- package/dist/components/Icon/Icon.svelte +140 -0
- package/dist/components/Icon/Icon.svelte.d.ts +25 -0
- package/dist/components/Icon/index.d.ts +1 -0
- package/dist/components/Icon/index.js +1 -0
- package/dist/components/Lazy/Lazy.svelte +158 -0
- package/dist/components/Lazy/Lazy.svelte.d.ts +42 -0
- package/dist/components/Masonry/Masonry.svelte +299 -0
- package/dist/components/Masonry/Masonry.svelte.d.ts +55 -0
- package/dist/components/Menu/Menu/Menu.svelte +65 -0
- package/dist/components/Menu/Menu/Menu.svelte.d.ts +17 -0
- package/dist/components/Menu/Menu/MenuItem.svelte +90 -0
- package/dist/components/Menu/Menu/MenuItem.svelte.d.ts +27 -0
- package/dist/components/Modal/Modal.svelte +334 -0
- package/dist/components/Modal/Modal.svelte.d.ts +55 -0
- package/dist/components/Panel/Card.svelte +141 -0
- package/dist/components/Panel/Card.svelte.d.ts +52 -0
- package/dist/components/Panel/Hero/Hero.story.md +9 -0
- package/dist/components/Panel/Hero/Hero.story.svelte +49 -0
- package/dist/components/Panel/Hero/Hero.story.svelte.d.ts +21 -0
- package/dist/components/Panel/Hero/Hero.svelte +24 -0
- package/dist/components/Panel/Hero/Hero.svelte.d.ts +32 -0
- package/dist/components/Panel/LazyPanel.svelte +110 -0
- package/dist/components/Panel/LazyPanel.svelte.d.ts +46 -0
- package/dist/components/Panel/Panel.svelte +205 -0
- package/dist/components/Panel/Panel.svelte.d.ts +23 -0
- package/dist/components/Progress/Progress.svelte +220 -0
- package/dist/components/Progress/Progress.svelte.d.ts +61 -0
- package/dist/components/Separator/Separator.svelte +109 -0
- package/dist/components/Separator/Separator.svelte.d.ts +35 -0
- package/dist/components/Sidebar/Sidebar.svelte +213 -0
- package/dist/components/Sidebar/Sidebar.svelte.d.ts +60 -0
- package/dist/components/Skeleton/Skeleton.svelte +170 -0
- package/dist/components/Skeleton/Skeleton.svelte.d.ts +48 -0
- package/dist/components/Stepper/Stepper.svelte +111 -0
- package/dist/components/Stepper/Stepper.svelte.d.ts +54 -0
- package/dist/components/Stepper/StepperStep.svelte +369 -0
- package/dist/components/Stepper/StepperStep.svelte.d.ts +63 -0
- package/dist/components/Table/Table.svelte +167 -0
- package/dist/components/Table/Table.svelte.d.ts +56 -0
- package/dist/components/Table/TableBody.svelte +41 -0
- package/dist/components/Table/TableBody.svelte.d.ts +33 -0
- package/dist/components/Table/TableCell.svelte +76 -0
- package/dist/components/Table/TableCell.svelte.d.ts +36 -0
- package/dist/components/Table/TableHead.svelte +41 -0
- package/dist/components/Table/TableHead.svelte.d.ts +32 -0
- package/dist/components/Table/TableHeader.svelte +148 -0
- package/dist/components/Table/TableHeader.svelte.d.ts +42 -0
- package/dist/components/Table/TableRow.svelte +99 -0
- package/dist/components/Table/TableRow.svelte.d.ts +40 -0
- package/dist/components/Tabs/Tab.svelte +145 -0
- package/dist/components/Tabs/Tab.svelte.d.ts +36 -0
- package/dist/components/Tabs/TabList.svelte +60 -0
- package/dist/components/Tabs/TabList.svelte.d.ts +32 -0
- package/dist/components/Tabs/TabPanel.svelte +118 -0
- package/dist/components/Tabs/TabPanel.svelte.d.ts +38 -0
- package/dist/components/Tabs/Tabs.svelte +287 -0
- package/dist/components/Tabs/Tabs.svelte.d.ts +50 -0
- package/dist/components/Tag/Tag.svelte +260 -0
- package/dist/components/Tag/Tag.svelte.d.ts +54 -0
- package/dist/components/Tag/TagGroup.svelte +147 -0
- package/dist/components/Tag/TagGroup.svelte.d.ts +62 -0
- package/dist/components/ThemeToggle/ThemeToggle.svelte +93 -0
- package/dist/components/ThemeToggle/ThemeToggle.svelte.d.ts +12 -0
- package/dist/components/Timeline/Timeline.svelte +144 -0
- package/dist/components/Timeline/Timeline.svelte.d.ts +48 -0
- package/dist/components/Timeline/TimelineItem.svelte +391 -0
- package/dist/components/Timeline/TimelineItem.svelte.d.ts +63 -0
- package/dist/components/Toast/Toast.svelte +313 -0
- package/dist/components/Toast/Toast.svelte.d.ts +44 -0
- package/dist/components/Toast/toastStore.d.ts +40 -0
- package/dist/components/Toast/toastStore.js +293 -0
- package/dist/components/Tooltip/Tooltip.svelte +282 -0
- package/dist/components/Tooltip/Tooltip.svelte.d.ts +55 -0
- package/dist/components/Tree/Tree.svelte +129 -0
- package/dist/components/Tree/Tree.svelte.d.ts +61 -0
- package/dist/components/Tree/TreeNode.svelte +332 -0
- package/dist/components/Tree/TreeNode.svelte.d.ts +55 -0
- package/dist/components/icons/TwintrinsicLogo.svelte +73 -0
- package/dist/components/icons/TwintrinsicLogo.svelte.d.ts +17 -0
- package/dist/components/icons/twintrinsic-source.svg +73 -0
- package/dist/components/icons/twintrinsic.svg +38 -0
- package/dist/docs/EventsTable.svelte +86 -0
- package/dist/docs/EventsTable.svelte.d.ts +27 -0
- package/dist/docs/PropsTable.svelte +103 -0
- package/dist/docs/PropsTable.svelte.d.ts +28 -0
- package/dist/docs/index.d.ts +2 -0
- package/dist/docs/index.js +2 -0
- package/dist/helpers/detectLanguage.d.ts +6 -0
- package/dist/helpers/detectLanguage.js +60 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +1 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +94 -0
- package/dist/twintrinsic.css +347 -0
- package/package.json +98 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export default Split;
|
|
2
|
+
type Split = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Split - A component for creating resizable split panels in an IDE-style layout.
|
|
8
|
+
* Supports horizontal or vertical splitting with draggable dividers and keyboard controls.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```svelte
|
|
12
|
+
* <Split>
|
|
13
|
+
* <div slot="first">First panel content</div>
|
|
14
|
+
* <div slot="second">Second panel content</div>
|
|
15
|
+
* </Split>
|
|
16
|
+
*
|
|
17
|
+
* <Split direction="vertical" initialSize={30} minSize={20} maxSize={80}>
|
|
18
|
+
* <div slot="first">Top panel</div>
|
|
19
|
+
* <div slot="second">Bottom panel</div>
|
|
20
|
+
* </Split>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare const Split: import("svelte").Component<{
|
|
24
|
+
class?: string;
|
|
25
|
+
id?: any;
|
|
26
|
+
direction?: string;
|
|
27
|
+
initialSize?: number;
|
|
28
|
+
minSize?: number;
|
|
29
|
+
maxSize?: number;
|
|
30
|
+
resizable?: boolean;
|
|
31
|
+
collapseFirst?: boolean;
|
|
32
|
+
collapseSecond?: boolean;
|
|
33
|
+
dividerSize?: number;
|
|
34
|
+
dividerAriaLabel: any;
|
|
35
|
+
onresize: any;
|
|
36
|
+
first: any;
|
|
37
|
+
second: any;
|
|
38
|
+
}, {}, "">;
|
|
39
|
+
type $$ComponentProps = {
|
|
40
|
+
class?: string;
|
|
41
|
+
id?: any;
|
|
42
|
+
direction?: string;
|
|
43
|
+
initialSize?: number;
|
|
44
|
+
minSize?: number;
|
|
45
|
+
maxSize?: number;
|
|
46
|
+
resizable?: boolean;
|
|
47
|
+
collapseFirst?: boolean;
|
|
48
|
+
collapseSecond?: boolean;
|
|
49
|
+
dividerSize?: number;
|
|
50
|
+
dividerAriaLabel: any;
|
|
51
|
+
onresize: any;
|
|
52
|
+
first: any;
|
|
53
|
+
second: any;
|
|
54
|
+
};
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
AppHeader - A responsive application header with navigation, actions, and branding.
|
|
4
|
+
Supports mobile menu, search, notifications, and user profile.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
```svelte
|
|
8
|
+
<AppHeader
|
|
9
|
+
brand="My App"
|
|
10
|
+
user={{ name: 'John Doe', avatar: '/avatar.jpg' }}
|
|
11
|
+
/>
|
|
12
|
+
|
|
13
|
+
<AppHeader
|
|
14
|
+
brand={{
|
|
15
|
+
logo: '/logo.svg',
|
|
16
|
+
name: 'My App',
|
|
17
|
+
href: '/'
|
|
18
|
+
}}
|
|
19
|
+
showSearch={true}
|
|
20
|
+
/>
|
|
21
|
+
```
|
|
22
|
+
-->
|
|
23
|
+
<script lang="ts">
|
|
24
|
+
import { slide } from "svelte/transition"
|
|
25
|
+
import ThemeToggle from "../ThemeToggle/ThemeToggle.svelte"
|
|
26
|
+
|
|
27
|
+
type Brand = string | { name: string; logo?: string; href?: string }
|
|
28
|
+
type User = { name: string; avatar?: string; href?: string } | null
|
|
29
|
+
type NavItem = { label: string; href?: string; current?: boolean }
|
|
30
|
+
type AppHeaderProps = {
|
|
31
|
+
brand: Brand
|
|
32
|
+
user?: User
|
|
33
|
+
showSearch?: boolean
|
|
34
|
+
showNotifications?: boolean
|
|
35
|
+
navItems?: NavItem[]
|
|
36
|
+
class?: string
|
|
37
|
+
id?: string
|
|
38
|
+
logo?: () => any
|
|
39
|
+
notifications?: () => any
|
|
40
|
+
userMenu?: () => any
|
|
41
|
+
onsearch?: (payload: { query: string }) => void
|
|
42
|
+
onsignout?: () => void
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const {
|
|
46
|
+
brand,
|
|
47
|
+
user = null,
|
|
48
|
+
showSearch = false,
|
|
49
|
+
showNotifications = false,
|
|
50
|
+
navItems = [],
|
|
51
|
+
class: className = "",
|
|
52
|
+
id = crypto.randomUUID(),
|
|
53
|
+
logo,
|
|
54
|
+
notifications,
|
|
55
|
+
userMenu,
|
|
56
|
+
onsearch,
|
|
57
|
+
onsignout,
|
|
58
|
+
} = $props() satisfies AppHeaderProps
|
|
59
|
+
|
|
60
|
+
let mobileMenuOpen = $state(false)
|
|
61
|
+
let searchQuery = $state("")
|
|
62
|
+
let notificationsOpen = $state(false)
|
|
63
|
+
let userMenuOpen = $state(false)
|
|
64
|
+
let headerElement = $state()
|
|
65
|
+
|
|
66
|
+
// Handle search input
|
|
67
|
+
function handleSearch(event: Event) {
|
|
68
|
+
const target = event.target as HTMLInputElement | null
|
|
69
|
+
if (!target) return
|
|
70
|
+
|
|
71
|
+
searchQuery = target.value
|
|
72
|
+
onsearch?.({ query: searchQuery })
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Handle mobile menu toggle
|
|
76
|
+
function toggleMobileMenu() {
|
|
77
|
+
mobileMenuOpen = !mobileMenuOpen
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Handle notifications toggle
|
|
81
|
+
function toggleNotifications() {
|
|
82
|
+
notificationsOpen = !notificationsOpen
|
|
83
|
+
if (notificationsOpen) userMenuOpen = false
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Handle user menu toggle
|
|
87
|
+
function toggleUserMenu() {
|
|
88
|
+
userMenuOpen = !userMenuOpen
|
|
89
|
+
if (userMenuOpen) notificationsOpen = false
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Handle escape key
|
|
93
|
+
function handleKeydown(event) {
|
|
94
|
+
if (event.key === "Escape") {
|
|
95
|
+
mobileMenuOpen = false
|
|
96
|
+
notificationsOpen = false
|
|
97
|
+
userMenuOpen = false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function handleSignout() {
|
|
102
|
+
onsignout?.()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const brandName = $derived(typeof brand === "string" ? brand : brand.name)
|
|
106
|
+
const brandLogo = $derived(typeof brand === "string" ? null : brand.logo)
|
|
107
|
+
const brandHref = $derived(typeof brand === "string" ? "/" : brand.href || "/")
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<svelte:window onkeydown={handleKeydown} />
|
|
111
|
+
|
|
112
|
+
{#snippet defaultLogo()}
|
|
113
|
+
{#if brandLogo}
|
|
114
|
+
<img
|
|
115
|
+
src={brandLogo}
|
|
116
|
+
alt={brandName}
|
|
117
|
+
class="app-header-logo"
|
|
118
|
+
width="32"
|
|
119
|
+
height="32"
|
|
120
|
+
/>
|
|
121
|
+
{/if}
|
|
122
|
+
<span class="app-header-brand-name">{brandName}</span>
|
|
123
|
+
{/snippet}
|
|
124
|
+
|
|
125
|
+
{#snippet defaultNotifications()}
|
|
126
|
+
<div class="p-4 text-center text-muted">
|
|
127
|
+
No new notifications
|
|
128
|
+
</div>
|
|
129
|
+
{/snippet}
|
|
130
|
+
|
|
131
|
+
{#snippet defaultUserMenu()}
|
|
132
|
+
<div class="app-header-user-menu-header">
|
|
133
|
+
<p class="app-header-user-name">{user.name}</p>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="app-header-user-menu-items">
|
|
136
|
+
<a href="/profile" class="app-header-user-menu-item">Profile</a>
|
|
137
|
+
<a href="/settings" class="app-header-user-menu-item">Settings</a>
|
|
138
|
+
<hr class="app-header-user-menu-separator" />
|
|
139
|
+
<button
|
|
140
|
+
type="button"
|
|
141
|
+
class="app-header-user-menu-item text-error-bold"
|
|
142
|
+
onclick={handleSignout}
|
|
143
|
+
>
|
|
144
|
+
Sign out
|
|
145
|
+
</button>
|
|
146
|
+
</div>
|
|
147
|
+
{/snippet}
|
|
148
|
+
|
|
149
|
+
<header
|
|
150
|
+
class="app-header {className}"
|
|
151
|
+
{id}
|
|
152
|
+
>
|
|
153
|
+
<div class="app-header-container">
|
|
154
|
+
<!-- Brand -->
|
|
155
|
+
<div class="app-header-brand">
|
|
156
|
+
<a href={brandHref} class="app-header-brand-link" aria-label={brandName}>
|
|
157
|
+
{@render (logo ?? defaultLogo)()}
|
|
158
|
+
</a>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<!-- Mobile Menu Button -->
|
|
162
|
+
<button
|
|
163
|
+
type="button"
|
|
164
|
+
class="app-header-mobile-menu"
|
|
165
|
+
aria-expanded={mobileMenuOpen}
|
|
166
|
+
aria-controls="{id}-nav"
|
|
167
|
+
onclick={toggleMobileMenu}
|
|
168
|
+
>
|
|
169
|
+
<span class="sr-only">Open main menu</span>
|
|
170
|
+
<svg class="w-6 h-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
171
|
+
{#if mobileMenuOpen}
|
|
172
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
173
|
+
{:else}
|
|
174
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
|
175
|
+
{/if}
|
|
176
|
+
</svg>
|
|
177
|
+
</button>
|
|
178
|
+
|
|
179
|
+
<!-- Navigation -->
|
|
180
|
+
<nav
|
|
181
|
+
id="{id}-nav"
|
|
182
|
+
class="app-header-nav"
|
|
183
|
+
class:app-header-nav-open={mobileMenuOpen}
|
|
184
|
+
>
|
|
185
|
+
<ul class="app-header-nav-list">
|
|
186
|
+
{#each navItems as item}
|
|
187
|
+
<li>
|
|
188
|
+
<a
|
|
189
|
+
href={item.href || '#'}
|
|
190
|
+
class="app-header-nav-link"
|
|
191
|
+
aria-current={item.current ? 'page' : undefined}
|
|
192
|
+
>
|
|
193
|
+
{item.label}
|
|
194
|
+
</a>
|
|
195
|
+
</li>
|
|
196
|
+
{/each}
|
|
197
|
+
</ul>
|
|
198
|
+
</nav>
|
|
199
|
+
|
|
200
|
+
<!-- Actions -->
|
|
201
|
+
<div class="app-header-actions">
|
|
202
|
+
<ThemeToggle />
|
|
203
|
+
{#if showSearch}
|
|
204
|
+
<div class="app-header-search">
|
|
205
|
+
<label for="{id}-search" class="sr-only">Search</label>
|
|
206
|
+
<div class="app-header-search-input-wrapper">
|
|
207
|
+
<input
|
|
208
|
+
type="search"
|
|
209
|
+
id="{id}-search"
|
|
210
|
+
class="app-header-search-input"
|
|
211
|
+
placeholder="Search..."
|
|
212
|
+
bind:value={searchQuery}
|
|
213
|
+
oninput={handleSearch}
|
|
214
|
+
/>
|
|
215
|
+
<svg class="w-5 h-5 app-header-search-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
216
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
|
217
|
+
</svg>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
{/if}
|
|
221
|
+
|
|
222
|
+
{#if showNotifications}
|
|
223
|
+
<div class="app-header-notifications">
|
|
224
|
+
<button
|
|
225
|
+
type="button"
|
|
226
|
+
class="app-header-notifications-button"
|
|
227
|
+
aria-expanded={notificationsOpen}
|
|
228
|
+
onclick={toggleNotifications}
|
|
229
|
+
>
|
|
230
|
+
<span class="sr-only">View notifications</span>
|
|
231
|
+
<svg class="w-6 h-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
232
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
|
|
233
|
+
</svg>
|
|
234
|
+
</button>
|
|
235
|
+
|
|
236
|
+
{#if notificationsOpen}
|
|
237
|
+
<div
|
|
238
|
+
class="app-header-notifications-panel"
|
|
239
|
+
role="dialog"
|
|
240
|
+
aria-label="Notifications"
|
|
241
|
+
transition:slide={{ duration: 200 }}
|
|
242
|
+
>
|
|
243
|
+
{@render (notifications ?? defaultNotifications)()}
|
|
244
|
+
</div>
|
|
245
|
+
{/if}
|
|
246
|
+
</div>
|
|
247
|
+
{/if}
|
|
248
|
+
|
|
249
|
+
{#if user}
|
|
250
|
+
<div class="app-header-user">
|
|
251
|
+
<button
|
|
252
|
+
type="button"
|
|
253
|
+
class="app-header-user-button"
|
|
254
|
+
aria-expanded={userMenuOpen}
|
|
255
|
+
onclick={toggleUserMenu}
|
|
256
|
+
>
|
|
257
|
+
<span class="sr-only">Open user menu</span>
|
|
258
|
+
{#if user.avatar}
|
|
259
|
+
<img
|
|
260
|
+
src={user.avatar}
|
|
261
|
+
alt=""
|
|
262
|
+
class="app-header-user-avatar"
|
|
263
|
+
width="32"
|
|
264
|
+
height="32"
|
|
265
|
+
/>
|
|
266
|
+
{:else}
|
|
267
|
+
<div class="app-header-user-avatar-placeholder">
|
|
268
|
+
{user.name[0]}
|
|
269
|
+
</div>
|
|
270
|
+
{/if}
|
|
271
|
+
</button>
|
|
272
|
+
|
|
273
|
+
{#if userMenuOpen}
|
|
274
|
+
<div
|
|
275
|
+
class="app-header-user-menu"
|
|
276
|
+
role="dialog"
|
|
277
|
+
aria-label="User menu"
|
|
278
|
+
transition:slide={{ duration: 200 }}
|
|
279
|
+
>
|
|
280
|
+
{@render (userMenu ?? defaultUserMenu)()}
|
|
281
|
+
</div>
|
|
282
|
+
{/if}
|
|
283
|
+
</div>
|
|
284
|
+
{/if}
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
</header>
|
|
288
|
+
|
|
289
|
+
<style>
|
|
290
|
+
@reference "../../twintrinsic.css";
|
|
291
|
+
/* Base header styles */
|
|
292
|
+
.app-header {
|
|
293
|
+
@apply bg-background border-b border-border sticky top-0 z-50;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.app-header-container {
|
|
297
|
+
@apply max-w-7xl mx-auto px-4 px-6 lg:px-8;
|
|
298
|
+
@apply flex items-center justify-between h-16;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/* Brand styles */
|
|
302
|
+
.app-header-brand {
|
|
303
|
+
@apply flex-shrink-0;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.app-header-brand-link {
|
|
307
|
+
@apply flex items-center gap-2;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.app-header-logo {
|
|
311
|
+
@apply h-8 w-auto;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.app-header-brand-name {
|
|
315
|
+
@apply text-lg font-semibold;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/* Mobile menu button */
|
|
319
|
+
.app-header-mobile-menu {
|
|
320
|
+
@apply sm:hidden inline-flex items-center justify-center p-2 rounded-md;
|
|
321
|
+
@apply hover:bg-hover focus:outline-none focus:ring-2 focus:ring-inset focus:ring-primary-500;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* Navigation styles */
|
|
325
|
+
.app-header-nav {
|
|
326
|
+
@apply hidden sm:block;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.app-header-nav-list {
|
|
330
|
+
@apply flex space-x-4;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.app-header-nav-link {
|
|
334
|
+
@apply px-3 py-2 rounded-md text-sm font-medium;
|
|
335
|
+
@apply hover:bg-hover focus:outline-none focus:bg-hover;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.app-header-nav-link[aria-current="page"] {
|
|
339
|
+
@apply bg-primary-500 text-white;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/* Mobile navigation */
|
|
343
|
+
@media (max-width: 640px) {
|
|
344
|
+
.app-header-nav {
|
|
345
|
+
@apply fixed inset-0 bg-background/95 backdrop-blur-sm;
|
|
346
|
+
@apply transform -translate-x-full transition-transform;
|
|
347
|
+
@apply pt-16 px-4;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.app-header-nav-open {
|
|
351
|
+
@apply translate-x-0;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.app-header-nav-list {
|
|
355
|
+
@apply flex-col space-x-0 space-y-2;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.app-header-nav-link {
|
|
359
|
+
@apply block w-full;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* Actions styles */
|
|
364
|
+
.app-header-actions {
|
|
365
|
+
@apply flex items-center gap-4;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* Search styles */
|
|
369
|
+
.app-header-search {
|
|
370
|
+
@apply hidden md:block;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.app-header-search-input-wrapper {
|
|
374
|
+
@apply relative;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.app-header-search-input {
|
|
378
|
+
@apply w-full sm:w-64 pl-10 pr-4 py-2 rounded-md;
|
|
379
|
+
@apply bg-surface border border-border;
|
|
380
|
+
@apply focus:outline-none focus:ring-2 focus:ring-primary-500;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.app-header-search-icon {
|
|
384
|
+
@apply absolute left-3 top-1/2 -translate-y-1/2 text-muted;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/* Notifications styles */
|
|
388
|
+
.app-header-notifications-button {
|
|
389
|
+
@apply p-2 rounded-md;
|
|
390
|
+
@apply hover:bg-hover focus:outline-none focus:ring-2 focus:ring-primary-500;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.app-header-notifications-panel {
|
|
394
|
+
@apply absolute right-0 mt-2 w-80;
|
|
395
|
+
@apply bg-background border border-border rounded-md shadow-lg;
|
|
396
|
+
@apply origin-top-right;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/* User menu styles */
|
|
400
|
+
.app-header-user-button {
|
|
401
|
+
@apply flex rounded-full focus:outline-none focus:ring-2 focus:ring-primary-500;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.app-header-user-avatar {
|
|
405
|
+
@apply h-8 w-8 rounded-full object-cover;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.app-header-user-avatar-placeholder {
|
|
409
|
+
@apply h-8 w-8 rounded-full bg-primary-500 text-white;
|
|
410
|
+
@apply flex items-center justify-center text-sm font-medium;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.app-header-user-menu {
|
|
414
|
+
@apply absolute right-0 mt-2 w-48;
|
|
415
|
+
@apply bg-background border border-border rounded-md shadow-lg;
|
|
416
|
+
@apply origin-top-right;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.app-header-user-menu-header {
|
|
420
|
+
@apply px-4 py-3 border-b border-border;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.app-header-user-name {
|
|
424
|
+
@apply text-sm font-medium;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.app-header-user-menu-items {
|
|
428
|
+
@apply py-1;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.app-header-user-menu-item {
|
|
432
|
+
@apply block px-4 py-2 text-sm w-full text-left;
|
|
433
|
+
@apply hover:bg-hover focus:outline-none focus:bg-hover;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.app-header-user-menu-separator {
|
|
437
|
+
@apply my-1 border-border;
|
|
438
|
+
}
|
|
439
|
+
</style>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppHeader - A responsive application header with navigation, actions, and branding.
|
|
3
|
+
* Supports mobile menu, search, notifications, and user profile.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* ```svelte
|
|
7
|
+
* <AppHeader
|
|
8
|
+
* brand="My App"
|
|
9
|
+
* user={{ name: 'John Doe', avatar: '/avatar.jpg' }}
|
|
10
|
+
* />
|
|
11
|
+
*
|
|
12
|
+
* <AppHeader
|
|
13
|
+
* brand={{
|
|
14
|
+
* logo: '/logo.svg',
|
|
15
|
+
* name: 'My App',
|
|
16
|
+
* href: '/'
|
|
17
|
+
* }}
|
|
18
|
+
* showSearch={true}
|
|
19
|
+
* />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
declare const AppHeader: import("svelte").Component<Record<string, never>, {}, "">;
|
|
23
|
+
type AppHeader = ReturnType<typeof AppHeader>;
|
|
24
|
+
export default AppHeader;
|