@tabelhadev/tabelhawebui 0.28.4

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.
Files changed (175) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +222 -0
  3. package/README.pt-BR.md +217 -0
  4. package/dist/actions/click-outside.d.ts +3 -0
  5. package/dist/actions/click-outside.js +12 -0
  6. package/dist/actions/combobox-keyboard-nav.d.ts +9 -0
  7. package/dist/actions/combobox-keyboard-nav.js +28 -0
  8. package/dist/actions/focus-trap.d.ts +1 -0
  9. package/dist/actions/focus-trap.js +34 -0
  10. package/dist/actions/scroll-lock.d.ts +1 -0
  11. package/dist/actions/scroll-lock.js +17 -0
  12. package/dist/components/actions/Button.svelte +169 -0
  13. package/dist/components/actions/Button.svelte.d.ts +19 -0
  14. package/dist/components/appshell/AppShell.svelte +50 -0
  15. package/dist/components/appshell/AppShell.svelte.d.ts +19 -0
  16. package/dist/components/appshell/AppShellBottomNav.svelte +67 -0
  17. package/dist/components/appshell/AppShellBottomNav.svelte.d.ts +9 -0
  18. package/dist/components/appshell/AppShellContent.svelte +38 -0
  19. package/dist/components/appshell/AppShellContent.svelte.d.ts +10 -0
  20. package/dist/components/appshell/AppShellSidebar.svelte +196 -0
  21. package/dist/components/appshell/AppShellSidebar.svelte.d.ts +15 -0
  22. package/dist/components/appshell/types.d.ts +6 -0
  23. package/dist/components/appshell/types.js +1 -0
  24. package/dist/components/appshell/utils.d.ts +1 -0
  25. package/dist/components/appshell/utils.js +3 -0
  26. package/dist/components/card/Card.svelte +31 -0
  27. package/dist/components/card/Card.svelte.d.ts +9 -0
  28. package/dist/components/card/CardAction.svelte +57 -0
  29. package/dist/components/card/CardAction.svelte.d.ts +10 -0
  30. package/dist/components/card/CardContent.svelte +25 -0
  31. package/dist/components/card/CardContent.svelte.d.ts +8 -0
  32. package/dist/components/card/CardDescription.svelte +24 -0
  33. package/dist/components/card/CardDescription.svelte.d.ts +8 -0
  34. package/dist/components/card/CardFooter.svelte +25 -0
  35. package/dist/components/card/CardFooter.svelte.d.ts +8 -0
  36. package/dist/components/card/CardHeader.svelte +54 -0
  37. package/dist/components/card/CardHeader.svelte.d.ts +10 -0
  38. package/dist/components/card/CardTitle.svelte +25 -0
  39. package/dist/components/card/CardTitle.svelte.d.ts +8 -0
  40. package/dist/components/chat/ChatMessage.svelte +104 -0
  41. package/dist/components/chat/ChatMessage.svelte.d.ts +10 -0
  42. package/dist/components/choice/Listbox.svelte +183 -0
  43. package/dist/components/choice/Listbox.svelte.d.ts +15 -0
  44. package/dist/components/choice/MultiSelect.svelte +278 -0
  45. package/dist/components/choice/MultiSelect.svelte.d.ts +18 -0
  46. package/dist/components/choice/Rating.svelte +91 -0
  47. package/dist/components/choice/Rating.svelte.d.ts +12 -0
  48. package/dist/components/choice/Toggle.svelte +112 -0
  49. package/dist/components/choice/Toggle.svelte.d.ts +12 -0
  50. package/dist/components/feedback/Badge.svelte +66 -0
  51. package/dist/components/feedback/Badge.svelte.d.ts +9 -0
  52. package/dist/components/feedback/ErrorPage.svelte +99 -0
  53. package/dist/components/feedback/ErrorPage.svelte.d.ts +13 -0
  54. package/dist/components/feedback/Message.svelte +130 -0
  55. package/dist/components/feedback/Message.svelte.d.ts +14 -0
  56. package/dist/components/feedback/ProgressBar.svelte +69 -0
  57. package/dist/components/feedback/ProgressBar.svelte.d.ts +8 -0
  58. package/dist/components/feedback/Skeleton.svelte +47 -0
  59. package/dist/components/feedback/Skeleton.svelte.d.ts +9 -0
  60. package/dist/components/feedback/Status.svelte +75 -0
  61. package/dist/components/feedback/Status.svelte.d.ts +10 -0
  62. package/dist/components/feedback/StatusPill.svelte +94 -0
  63. package/dist/components/feedback/StatusPill.svelte.d.ts +13 -0
  64. package/dist/components/feedback/Toaster.svelte +122 -0
  65. package/dist/components/feedback/Toaster.svelte.d.ts +7 -0
  66. package/dist/components/feedback/Tooltip.svelte +126 -0
  67. package/dist/components/feedback/Tooltip.svelte.d.ts +10 -0
  68. package/dist/components/feedback/toast.svelte.d.ts +27 -0
  69. package/dist/components/feedback/toast.svelte.js +23 -0
  70. package/dist/components/forms/Checkbox.svelte +96 -0
  71. package/dist/components/forms/Checkbox.svelte.d.ts +11 -0
  72. package/dist/components/forms/DatePicker.svelte +372 -0
  73. package/dist/components/forms/DatePicker.svelte.d.ts +21 -0
  74. package/dist/components/forms/Field.svelte +47 -0
  75. package/dist/components/forms/Field.svelte.d.ts +11 -0
  76. package/dist/components/forms/FileUpload.svelte +504 -0
  77. package/dist/components/forms/FileUpload.svelte.d.ts +43 -0
  78. package/dist/components/forms/Input.svelte +93 -0
  79. package/dist/components/forms/Input.svelte.d.ts +9 -0
  80. package/dist/components/forms/Label.svelte +30 -0
  81. package/dist/components/forms/Label.svelte.d.ts +10 -0
  82. package/dist/components/forms/Radio.svelte +80 -0
  83. package/dist/components/forms/Radio.svelte.d.ts +11 -0
  84. package/dist/components/forms/Select.svelte +322 -0
  85. package/dist/components/forms/Select.svelte.d.ts +22 -0
  86. package/dist/components/forms/TagInput.svelte +336 -0
  87. package/dist/components/forms/TagInput.svelte.d.ts +16 -0
  88. package/dist/components/forms/Textarea.svelte +64 -0
  89. package/dist/components/forms/Textarea.svelte.d.ts +9 -0
  90. package/dist/components/landing/Landing.svelte +47 -0
  91. package/dist/components/landing/Landing.svelte.d.ts +8 -0
  92. package/dist/components/landing/LandingFeatures.svelte +92 -0
  93. package/dist/components/landing/LandingFeatures.svelte.d.ts +15 -0
  94. package/dist/components/landing/LandingHero.svelte +92 -0
  95. package/dist/components/landing/LandingHero.svelte.d.ts +13 -0
  96. package/dist/components/landing/LandingRoadmap.svelte +42 -0
  97. package/dist/components/landing/LandingRoadmap.svelte.d.ts +11 -0
  98. package/dist/components/landing/LandingSection.svelte +25 -0
  99. package/dist/components/landing/LandingSection.svelte.d.ts +9 -0
  100. package/dist/components/landing/LandingSectionHeading.svelte +19 -0
  101. package/dist/components/landing/LandingSectionHeading.svelte.d.ts +10 -0
  102. package/dist/components/landing/LandingSteps.svelte +100 -0
  103. package/dist/components/landing/LandingSteps.svelte.d.ts +13 -0
  104. package/dist/components/layout/BracketLink.svelte +41 -0
  105. package/dist/components/layout/BracketLink.svelte.d.ts +9 -0
  106. package/dist/components/layout/Divider.svelte +70 -0
  107. package/dist/components/layout/Divider.svelte.d.ts +9 -0
  108. package/dist/components/layout/Eyebrow.svelte +24 -0
  109. package/dist/components/layout/Eyebrow.svelte.d.ts +8 -0
  110. package/dist/components/layout/PageHeader.svelte +106 -0
  111. package/dist/components/layout/PageHeader.svelte.d.ts +15 -0
  112. package/dist/components/layout/PageSeo.svelte +34 -0
  113. package/dist/components/layout/PageSeo.svelte.d.ts +10 -0
  114. package/dist/components/layout/PageShell.svelte +25 -0
  115. package/dist/components/layout/PageShell.svelte.d.ts +8 -0
  116. package/dist/components/layout/Panel.svelte +105 -0
  117. package/dist/components/layout/Panel.svelte.d.ts +12 -0
  118. package/dist/components/layout/Prose.svelte +101 -0
  119. package/dist/components/layout/Prose.svelte.d.ts +7 -0
  120. package/dist/components/layout/RuleCard.svelte +63 -0
  121. package/dist/components/layout/RuleCard.svelte.d.ts +13 -0
  122. package/dist/components/layout/SectionHeading.svelte +57 -0
  123. package/dist/components/layout/SectionHeading.svelte.d.ts +10 -0
  124. package/dist/components/layout/StatTile.svelte +76 -0
  125. package/dist/components/layout/StatTile.svelte.d.ts +12 -0
  126. package/dist/components/layout/TerminalWindow.svelte +81 -0
  127. package/dist/components/layout/TerminalWindow.svelte.d.ts +9 -0
  128. package/dist/components/layout/Wordmark.svelte +26 -0
  129. package/dist/components/layout/Wordmark.svelte.d.ts +8 -0
  130. package/dist/components/list/List.svelte +40 -0
  131. package/dist/components/list/List.svelte.d.ts +13 -0
  132. package/dist/components/list/ListItem.svelte +81 -0
  133. package/dist/components/list/ListItem.svelte.d.ts +13 -0
  134. package/dist/components/marketing/MarketingShell.svelte +170 -0
  135. package/dist/components/marketing/MarketingShell.svelte.d.ts +23 -0
  136. package/dist/components/marketing/MarketingShellFooter.svelte +92 -0
  137. package/dist/components/marketing/MarketingShellFooter.svelte.d.ts +14 -0
  138. package/dist/components/navigation/Accordion.svelte +110 -0
  139. package/dist/components/navigation/Accordion.svelte.d.ts +15 -0
  140. package/dist/components/navigation/Carousel.svelte +115 -0
  141. package/dist/components/navigation/Carousel.svelte.d.ts +12 -0
  142. package/dist/components/navigation/InstructionStep.svelte +115 -0
  143. package/dist/components/navigation/InstructionStep.svelte.d.ts +10 -0
  144. package/dist/components/navigation/InstructionSteps.svelte +39 -0
  145. package/dist/components/navigation/InstructionSteps.svelte.d.ts +8 -0
  146. package/dist/components/navigation/Nav.svelte +102 -0
  147. package/dist/components/navigation/Nav.svelte.d.ts +14 -0
  148. package/dist/components/navigation/Stepper.svelte +112 -0
  149. package/dist/components/navigation/Stepper.svelte.d.ts +12 -0
  150. package/dist/components/navigation/TabCard.svelte +62 -0
  151. package/dist/components/navigation/TabCard.svelte.d.ts +10 -0
  152. package/dist/components/navigation/Tabs.svelte +83 -0
  153. package/dist/components/navigation/Tabs.svelte.d.ts +12 -0
  154. package/dist/components/navigation/ThemeToggle.svelte +118 -0
  155. package/dist/components/navigation/ThemeToggle.svelte.d.ts +20 -0
  156. package/dist/components/overlay/Dialog.svelte +200 -0
  157. package/dist/components/overlay/Dialog.svelte.d.ts +19 -0
  158. package/dist/components/overlay/DialogActions.svelte +50 -0
  159. package/dist/components/overlay/DialogActions.svelte.d.ts +9 -0
  160. package/dist/components/overlay/Dropdown.svelte +110 -0
  161. package/dist/components/overlay/Dropdown.svelte.d.ts +10 -0
  162. package/dist/components/overlay/FloatingActionPill.svelte +96 -0
  163. package/dist/components/overlay/FloatingActionPill.svelte.d.ts +14 -0
  164. package/dist/components/overlay/Sidebar.svelte +258 -0
  165. package/dist/components/overlay/Sidebar.svelte.d.ts +18 -0
  166. package/dist/components/table/Table.svelte +550 -0
  167. package/dist/components/table/Table.svelte.d.ts +42 -0
  168. package/dist/components/timeline/Timeline.svelte +25 -0
  169. package/dist/components/timeline/Timeline.svelte.d.ts +8 -0
  170. package/dist/components/timeline/TimelineItem.svelte +220 -0
  171. package/dist/components/timeline/TimelineItem.svelte.d.ts +18 -0
  172. package/dist/index.d.ts +156 -0
  173. package/dist/index.js +149 -0
  174. package/dist/theme/theme.css +348 -0
  175. package/package.json +52 -0
@@ -0,0 +1,169 @@
1
+ <script module lang="ts">
2
+ export type ButtonVariant = 'primary' | 'ghost' | 'danger' | 'outline';
3
+ export type ButtonSize = 'sm' | 'md' | 'lg' | 'icon-sm';
4
+
5
+ // Variant class helper for use where a real <Button> doesn't fit (e.g. decorative <span>).
6
+ export function buttonVariants(
7
+ opts: { variant?: ButtonVariant; size?: ButtonSize } = {}
8
+ ): string {
9
+ const { variant = 'primary', size = 'md' } = opts;
10
+ return `twui-button twui-button-${variant} twui-button-${size}`;
11
+ }
12
+ </script>
13
+
14
+ <script lang="ts">
15
+ import type { Snippet } from 'svelte';
16
+ import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
17
+
18
+ let {
19
+ variant = 'primary',
20
+ size = 'md',
21
+ href,
22
+ loading = false,
23
+ children,
24
+ class: className = '',
25
+ ...rest
26
+ }: {
27
+ variant?: ButtonVariant;
28
+ size?: ButtonSize;
29
+ href?: string;
30
+ loading?: boolean;
31
+ children: Snippet;
32
+ class?: string;
33
+ } & HTMLButtonAttributes & HTMLAnchorAttributes = $props();
34
+ </script>
35
+
36
+ {#if href}
37
+ <a
38
+ href={href}
39
+ class="twui-button twui-button-{variant} twui-button-{size} {loading ? 'twui-button-loading' : ''} {className}"
40
+ aria-busy={loading}
41
+ {...rest}
42
+ >
43
+ {#if loading}
44
+ <span class="twui-button-spinner" aria-hidden="true"></span>
45
+ {/if}
46
+ {@render children()}
47
+ </a>
48
+ {:else}
49
+ <button
50
+ class="twui-button twui-button-{variant} twui-button-{size} {loading ? 'twui-button-loading' : ''} {className}"
51
+ disabled={rest.disabled || loading}
52
+ aria-busy={loading}
53
+ {...rest}
54
+ >
55
+ {#if loading}
56
+ <span class="twui-button-spinner" aria-hidden="true"></span>
57
+ {/if}
58
+ {@render children()}
59
+ </button>
60
+ {/if}
61
+
62
+ <style>
63
+ .twui-button {
64
+ display: inline-flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+ gap: 6px;
68
+ border: 1px solid transparent;
69
+ background: transparent;
70
+ font-family: var(--twui-font-mono, 'JetBrains Mono', monospace);
71
+ font-size: 14px;
72
+ font-weight: 500;
73
+ white-space: nowrap;
74
+ cursor: pointer;
75
+ text-decoration: none;
76
+ transition:
77
+ background-color 0.15s ease,
78
+ color 0.15s ease,
79
+ border-color 0.15s ease;
80
+ }
81
+
82
+ .twui-button:disabled {
83
+ opacity: 0.5;
84
+ cursor: not-allowed;
85
+ }
86
+
87
+ .twui-button-spinner {
88
+ width: 12px;
89
+ height: 12px;
90
+ flex-shrink: 0;
91
+ border: 2px solid currentColor;
92
+ border-right-color: transparent;
93
+ border-radius: 9999px;
94
+ animation: twui-button-spin 0.7s linear infinite;
95
+ }
96
+
97
+ @keyframes twui-button-spin {
98
+ to {
99
+ transform: rotate(360deg);
100
+ }
101
+ }
102
+
103
+ .twui-button-sm {
104
+ padding: 4px 12px;
105
+ font-size: 13px;
106
+ }
107
+
108
+ .twui-button-md {
109
+ padding: 6px 16px;
110
+ font-size: 14px;
111
+ }
112
+
113
+ .twui-button-lg {
114
+ padding: 8px 24px;
115
+ font-size: 14px;
116
+ }
117
+
118
+ .twui-button-icon-sm {
119
+ width: 28px;
120
+ height: 28px;
121
+ padding: 0;
122
+ }
123
+
124
+ .twui-button-primary {
125
+ background: color-mix(in oklab, var(--twui-accent) 12%, transparent);
126
+ border-color: var(--twui-accent);
127
+ color: var(--twui-accent);
128
+ }
129
+
130
+ .twui-button-primary:hover:not(:disabled) {
131
+ background: color-mix(in oklab, var(--twui-accent) 25%, transparent);
132
+ border-color: var(--twui-accent);
133
+ color: var(--twui-accent);
134
+ }
135
+
136
+ .twui-button-ghost {
137
+ background: transparent;
138
+ border-color: transparent;
139
+ color: var(--twui-ink-soft);
140
+ }
141
+
142
+ .twui-button-ghost:hover:not(:disabled) {
143
+ background: color-mix(in oklab, var(--twui-ink-soft) 10%, transparent);
144
+ color: var(--twui-ink);
145
+ }
146
+
147
+ .twui-button-danger {
148
+ background: transparent;
149
+ border-color: var(--twui-danger);
150
+ color: var(--twui-danger);
151
+ }
152
+
153
+ .twui-button-danger:hover:not(:disabled) {
154
+ background: color-mix(in oklab, var(--twui-danger) 15%, transparent);
155
+ color: var(--twui-danger);
156
+ }
157
+
158
+ .twui-button-outline {
159
+ background: transparent;
160
+ border-color: var(--twui-ink-soft);
161
+ color: var(--twui-ink);
162
+ }
163
+
164
+ .twui-button-outline:hover:not(:disabled) {
165
+ background: var(--twui-accent-soft);
166
+ border-color: var(--twui-accent);
167
+ color: var(--twui-accent);
168
+ }
169
+ </style>
@@ -0,0 +1,19 @@
1
+ export type ButtonVariant = 'primary' | 'ghost' | 'danger' | 'outline';
2
+ export type ButtonSize = 'sm' | 'md' | 'lg' | 'icon-sm';
3
+ export declare function buttonVariants(opts?: {
4
+ variant?: ButtonVariant;
5
+ size?: ButtonSize;
6
+ }): string;
7
+ import type { Snippet } from 'svelte';
8
+ import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
9
+ type $$ComponentProps = {
10
+ variant?: ButtonVariant;
11
+ size?: ButtonSize;
12
+ href?: string;
13
+ loading?: boolean;
14
+ children: Snippet;
15
+ class?: string;
16
+ } & HTMLButtonAttributes & HTMLAnchorAttributes;
17
+ declare const Button: import("svelte").Component<$$ComponentProps, {}, "">;
18
+ type Button = ReturnType<typeof Button>;
19
+ export default Button;
@@ -0,0 +1,50 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import AppShellSidebar from './AppShellSidebar.svelte';
4
+ import AppShellBottomNav from './AppShellBottomNav.svelte';
5
+ import AppShellContent from './AppShellContent.svelte';
6
+ import type { AppShellNavItem } from './types';
7
+
8
+ let {
9
+ brand = { prefix: 'TAbelha', suffix: '' },
10
+ navItems = [],
11
+ currentPath = '',
12
+ logoutAction = '',
13
+ profile,
14
+ children,
15
+ pad = true,
16
+ class: className = ''
17
+ }: {
18
+ brand?: { prefix?: string; suffix?: string };
19
+ navItems?: AppShellNavItem[];
20
+ currentPath?: string;
21
+ logoutAction?: string;
22
+ profile?: AppShellNavItem;
23
+ children: Snippet;
24
+ /** When false, the content area skips its built-in padding. */
25
+ pad?: boolean;
26
+ class?: string;
27
+ } = $props();
28
+ </script>
29
+
30
+ <div class="twui-appshell {className}">
31
+ <AppShellSidebar {brand} {navItems} {currentPath} {logoutAction} {profile} />
32
+ <div class="twui-appshell-body">
33
+ <AppShellContent {pad}>{@render children()}</AppShellContent>
34
+ </div>
35
+ <AppShellBottomNav {navItems} {currentPath} />
36
+ </div>
37
+
38
+ <style>
39
+ .twui-appshell {
40
+ display: flex;
41
+ min-height: 100svh;
42
+ }
43
+
44
+ .twui-appshell-body {
45
+ display: flex;
46
+ flex: 1;
47
+ min-width: 0;
48
+ flex-direction: column;
49
+ }
50
+ </style>
@@ -0,0 +1,19 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { AppShellNavItem } from './types';
3
+ type $$ComponentProps = {
4
+ brand?: {
5
+ prefix?: string;
6
+ suffix?: string;
7
+ };
8
+ navItems?: AppShellNavItem[];
9
+ currentPath?: string;
10
+ logoutAction?: string;
11
+ profile?: AppShellNavItem;
12
+ children: Snippet;
13
+ /** When false, the content area skips its built-in padding. */
14
+ pad?: boolean;
15
+ class?: string;
16
+ };
17
+ declare const AppShell: import("svelte").Component<$$ComponentProps, {}, "">;
18
+ type AppShell = ReturnType<typeof AppShell>;
19
+ export default AppShell;
@@ -0,0 +1,67 @@
1
+ <script lang="ts">
2
+ import { isPathActive } from './utils';
3
+ import type { AppShellNavItem } from './types';
4
+
5
+ let {
6
+ navItems = [],
7
+ currentPath = '',
8
+ class: className = ''
9
+ }: {
10
+ navItems?: AppShellNavItem[];
11
+ currentPath?: string;
12
+ class?: string;
13
+ } = $props();
14
+ </script>
15
+
16
+ <nav class="twui-appshell-bottomnav {className}" aria-label="Navegação principal">
17
+ {#each navItems as item (item.href)}
18
+ {@const active = isPathActive(currentPath, item.href)}
19
+ <a
20
+ href={item.href}
21
+ class="twui-appshell-bottomnav-item {active ? 'twui-appshell-bottomnav-item-active' : ''}"
22
+ aria-current={active ? 'page' : undefined}
23
+ >
24
+ {#if item.icon}{@render item.icon()}{/if}
25
+ <span>{item.label}</span>
26
+ </a>
27
+ {/each}
28
+ </nav>
29
+
30
+ <style>
31
+ .twui-appshell-bottomnav {
32
+ position: fixed;
33
+ inset-inline: 0;
34
+ bottom: 0;
35
+ z-index: 50;
36
+ display: flex;
37
+ align-items: center;
38
+ justify-content: space-around;
39
+ padding: 8px 0;
40
+ border-top: 1px solid var(--twui-rule);
41
+ background: var(--twui-paper-raised);
42
+ }
43
+
44
+ @media (min-width: 1024px) {
45
+ .twui-appshell-bottomnav {
46
+ display: none;
47
+ }
48
+ }
49
+
50
+ .twui-appshell-bottomnav-item {
51
+ display: flex;
52
+ flex-direction: column;
53
+ align-items: center;
54
+ gap: 2px;
55
+ padding: 4px 16px;
56
+ font-family: var(--twui-font-mono);
57
+ font-size: 12px;
58
+ line-height: 1.2;
59
+ color: var(--twui-ink-soft);
60
+ text-decoration: none;
61
+ transition: color 0.15s ease;
62
+ }
63
+
64
+ .twui-appshell-bottomnav-item-active {
65
+ color: var(--twui-accent);
66
+ }
67
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { AppShellNavItem } from './types';
2
+ type $$ComponentProps = {
3
+ navItems?: AppShellNavItem[];
4
+ currentPath?: string;
5
+ class?: string;
6
+ };
7
+ declare const AppShellBottomNav: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type AppShellBottomNav = ReturnType<typeof AppShellBottomNav>;
9
+ export default AppShellBottomNav;
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ let {
5
+ children,
6
+ pad = true,
7
+ class: className = ''
8
+ }: {
9
+ children: Snippet;
10
+ /** When false, skip the built-in padding so a child `Page.Shell` owns spacing. */
11
+ pad?: boolean;
12
+ class?: string;
13
+ } = $props();
14
+ </script>
15
+
16
+ <main class="twui-appshell-content {className}" class:twui-appshell-content-nopad={!pad}>
17
+ {@render children()}
18
+ </main>
19
+
20
+ <style>
21
+ .twui-appshell-content {
22
+ margin-inline: auto;
23
+ width: 100%;
24
+ max-width: 72rem;
25
+ flex: 1;
26
+ padding: 1rem 1rem 6rem;
27
+ }
28
+
29
+ @media (min-width: 1024px) {
30
+ .twui-appshell-content {
31
+ padding: 2rem;
32
+ }
33
+ }
34
+
35
+ .twui-appshell-content-nopad {
36
+ padding: 0;
37
+ }
38
+ </style>
@@ -0,0 +1,10 @@
1
+ import type { Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ children: Snippet;
4
+ /** When false, skip the built-in padding so a child `Page.Shell` owns spacing. */
5
+ pad?: boolean;
6
+ class?: string;
7
+ };
8
+ declare const AppShellContent: import("svelte").Component<$$ComponentProps, {}, "">;
9
+ type AppShellContent = ReturnType<typeof AppShellContent>;
10
+ export default AppShellContent;
@@ -0,0 +1,196 @@
1
+ <script lang="ts">
2
+ import Wordmark from '../layout/Wordmark.svelte';
3
+ import ThemeToggle from '../navigation/ThemeToggle.svelte';
4
+ import { isPathActive } from './utils';
5
+ import type { AppShellNavItem } from './types';
6
+
7
+ let {
8
+ brand = { prefix: 'TAbelha', suffix: '' },
9
+ navItems = [],
10
+ currentPath = '',
11
+ logoutAction = '',
12
+ profile,
13
+ class: className = ''
14
+ }: {
15
+ brand?: { prefix?: string; suffix?: string };
16
+ navItems?: AppShellNavItem[];
17
+ currentPath?: string;
18
+ logoutAction?: string;
19
+ profile?: AppShellNavItem;
20
+ class?: string;
21
+ } = $props();
22
+ </script>
23
+
24
+ <aside class="twui-appshell-sidebar {className}">
25
+ <div class="twui-appshell-sidebar-brand">
26
+ <a href="/" class="twui-appshell-sidebar-brand-link" aria-label="Ir para o início">
27
+ <Wordmark prefix={brand.prefix} suffix={brand.suffix} />
28
+ </a>
29
+ </div>
30
+ <div class="twui-appshell-sidebar-sep" role="presentation"></div>
31
+ <nav class="twui-appshell-sidebar-nav" aria-label="Navegação principal">
32
+ {#each navItems as item (item.href)}
33
+ {@const active = isPathActive(currentPath, item.href)}
34
+ <a
35
+ href={item.href}
36
+ class="twui-appshell-nav-item {active ? 'twui-appshell-nav-item-active' : ''}"
37
+ aria-current={active ? 'page' : undefined}
38
+ >
39
+ {#if item.icon}{@render item.icon()}{/if}
40
+ <span>{item.label}</span>
41
+ </a>
42
+ {/each}
43
+ </nav>
44
+ <div class="twui-appshell-sidebar-sep" role="presentation"></div>
45
+ <div class="twui-appshell-sidebar-footer">
46
+ {#if profile}
47
+ {@const active = isPathActive(currentPath, profile.href)}
48
+ <a
49
+ href={profile.href}
50
+ class="twui-appshell-nav-item twui-appshell-sidebar-profile {active
51
+ ? 'twui-appshell-nav-item-active'
52
+ : ''}"
53
+ aria-current={active ? 'page' : undefined}
54
+ >
55
+ {#if profile.icon}{@render profile.icon()}{/if}
56
+ <span>{profile.label}</span>
57
+ </a>
58
+ {/if}
59
+ <ThemeToggle showLabel class="twui-appshell-sidebar-theme" />
60
+ {#if logoutAction}
61
+ <form method="POST" action={logoutAction} class="twui-appshell-sidebar-logout-form">
62
+ <button type="submit" class="twui-appshell-sidebar-logout">
63
+ <svg
64
+ width="16"
65
+ height="16"
66
+ viewBox="0 0 24 24"
67
+ fill="none"
68
+ stroke="currentColor"
69
+ stroke-width="2"
70
+ stroke-linecap="round"
71
+ stroke-linejoin="round"
72
+ aria-hidden="true"
73
+ >
74
+ <path d="M12 2v10" />
75
+ <path d="M18.4 6.6a9 9 0 1 1-12.77.04" />
76
+ </svg>
77
+ <span>Sair</span>
78
+ </button>
79
+ </form>
80
+ {/if}
81
+ </div>
82
+ </aside>
83
+
84
+ <style>
85
+ .twui-appshell-sidebar {
86
+ display: none;
87
+ flex-direction: column;
88
+ position: sticky;
89
+ top: 0;
90
+ height: 100svh;
91
+ width: 15rem;
92
+ flex-shrink: 0;
93
+ border-right: 1px solid var(--twui-rule);
94
+ background: var(--twui-paper-raised);
95
+ }
96
+
97
+ @media (min-width: 1024px) {
98
+ .twui-appshell-sidebar {
99
+ display: flex;
100
+ }
101
+ }
102
+
103
+ .twui-appshell-sidebar-brand {
104
+ padding: 20px 20px 16px;
105
+ }
106
+
107
+ .twui-appshell-sidebar-brand-link {
108
+ text-decoration: none;
109
+ }
110
+
111
+ .twui-appshell-sidebar-sep {
112
+ border-top: 1px solid var(--twui-rule);
113
+ }
114
+
115
+ .twui-appshell-sidebar-nav {
116
+ display: flex;
117
+ flex: 1;
118
+ flex-direction: column;
119
+ gap: 4px;
120
+ padding: 16px 12px;
121
+ overflow-y: auto;
122
+ }
123
+
124
+ .twui-appshell-nav-item {
125
+ display: flex;
126
+ align-items: center;
127
+ gap: 12px;
128
+ padding: 6px 8px;
129
+ border-left: 2px solid transparent;
130
+ font-family: var(--twui-font-mono);
131
+ font-size: 14px;
132
+ line-height: 1.4;
133
+ color: var(--twui-ink-soft);
134
+ text-decoration: none;
135
+ transition: color 0.15s ease;
136
+ }
137
+
138
+ .twui-appshell-nav-item:hover {
139
+ color: var(--twui-ink);
140
+ }
141
+
142
+ .twui-appshell-nav-item-active {
143
+ border-left-color: var(--twui-accent);
144
+ color: var(--twui-accent);
145
+ font-weight: 500;
146
+ }
147
+
148
+ .twui-appshell-nav-item-active:hover {
149
+ color: var(--twui-accent);
150
+ }
151
+
152
+ .twui-appshell-sidebar-footer {
153
+ display: flex;
154
+ flex-direction: column;
155
+ gap: 4px;
156
+ padding: 16px 12px;
157
+ }
158
+
159
+ .twui-appshell-sidebar-profile {
160
+ display: flex;
161
+ }
162
+
163
+ .twui-appshell-sidebar-logout-form {
164
+ margin: 0;
165
+ }
166
+
167
+ .twui-appshell-sidebar-logout {
168
+ display: flex;
169
+ align-items: center;
170
+ gap: 12px;
171
+ width: 100%;
172
+ padding: 6px 8px;
173
+ border: none;
174
+ border-left: 2px solid transparent;
175
+ background: transparent;
176
+ font-family: var(--twui-font-mono);
177
+ font-size: 14px;
178
+ line-height: 1.4;
179
+ color: var(--twui-danger);
180
+ text-align: left;
181
+ cursor: pointer;
182
+ transition: color 0.15s ease;
183
+ }
184
+
185
+ .twui-appshell-sidebar-logout:hover {
186
+ color: var(--twui-ink);
187
+ }
188
+
189
+ :global(.twui-appshell-sidebar .twui-appshell-sidebar-footer .twui-appshell-sidebar-theme) {
190
+ width: 100%;
191
+ justify-content: flex-start;
192
+ gap: 12px;
193
+ padding: 6px 8px;
194
+ border-left: 2px solid transparent;
195
+ }
196
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { AppShellNavItem } from './types';
2
+ type $$ComponentProps = {
3
+ brand?: {
4
+ prefix?: string;
5
+ suffix?: string;
6
+ };
7
+ navItems?: AppShellNavItem[];
8
+ currentPath?: string;
9
+ logoutAction?: string;
10
+ profile?: AppShellNavItem;
11
+ class?: string;
12
+ };
13
+ declare const AppShellSidebar: import("svelte").Component<$$ComponentProps, {}, "">;
14
+ type AppShellSidebar = ReturnType<typeof AppShellSidebar>;
15
+ export default AppShellSidebar;
@@ -0,0 +1,6 @@
1
+ import type { Snippet } from "svelte";
2
+ export interface AppShellNavItem {
3
+ href: string;
4
+ label: string;
5
+ icon?: Snippet;
6
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export declare function isPathActive(currentPath: string, href: string): boolean;
@@ -0,0 +1,3 @@
1
+ export function isPathActive(currentPath, href) {
2
+ return currentPath === href || currentPath.startsWith(href + "/");
3
+ }
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ let {
5
+ variant = 'base',
6
+ children,
7
+ class: className = ''
8
+ }: {
9
+ variant?: 'base' | 'danger';
10
+ children: Snippet;
11
+ class?: string;
12
+ } = $props();
13
+ </script>
14
+
15
+ <section class="twui-card twui-card-{variant} {className}">
16
+ {@render children()}
17
+ </section>
18
+
19
+ <style>
20
+ .twui-card {
21
+ display: flex;
22
+ flex-direction: column;
23
+ border: 1px solid var(--twui-rule);
24
+ background: var(--twui-paper-raised);
25
+ }
26
+
27
+ .twui-card-danger {
28
+ border-color: var(--twui-danger);
29
+ background: color-mix(in oklab, var(--twui-danger) 8%, var(--twui-paper-raised));
30
+ }
31
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ variant?: 'base' | 'danger';
4
+ children: Snippet;
5
+ class?: string;
6
+ };
7
+ declare const Card: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type Card = ReturnType<typeof Card>;
9
+ export default Card;