snice 1.14.3 → 2.1.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.
Files changed (185) hide show
  1. package/bin/templates/base/tsconfig.json +5 -4
  2. package/components/accordion/demo.html +403 -0
  3. package/components/accordion/snice-accordion-item.css +85 -0
  4. package/components/accordion/snice-accordion-item.ts +226 -0
  5. package/components/accordion/snice-accordion.css +31 -0
  6. package/components/accordion/snice-accordion.ts +182 -0
  7. package/components/accordion/snice-accordion.types.ts +32 -0
  8. package/components/alert/demo.html +445 -0
  9. package/components/alert/snice-alert.css +195 -0
  10. package/components/alert/snice-alert.ts +141 -0
  11. package/components/alert/snice-alert.types.ts +12 -0
  12. package/components/avatar/demo.html +598 -0
  13. package/components/avatar/snice-avatar.css +131 -0
  14. package/components/avatar/snice-avatar.ts +136 -0
  15. package/components/avatar/snice-avatar.types.ts +13 -0
  16. package/components/badge/demo.html +523 -0
  17. package/components/badge/snice-badge.css +161 -0
  18. package/components/badge/snice-badge.ts +117 -0
  19. package/components/badge/snice-badge.types.ts +16 -0
  20. package/components/breadcrumbs/demo.html +404 -0
  21. package/components/breadcrumbs/snice-breadcrumbs.css +133 -0
  22. package/components/breadcrumbs/snice-breadcrumbs.ts +191 -0
  23. package/components/breadcrumbs/snice-breadcrumbs.types.ts +26 -0
  24. package/components/breadcrumbs/snice-crumb.ts +26 -0
  25. package/components/button/demo.html +42 -0
  26. package/components/button/snice-button.css +230 -0
  27. package/components/button/snice-button.ts +169 -0
  28. package/components/button/snice-button.types.ts +25 -0
  29. package/components/card/demo.html +525 -0
  30. package/components/card/snice-card.css +140 -0
  31. package/components/card/snice-card.ts +102 -0
  32. package/components/card/snice-card.types.ts +10 -0
  33. package/components/checkbox/demo.html +253 -0
  34. package/components/checkbox/snice-checkbox.css +164 -0
  35. package/components/checkbox/snice-checkbox.ts +223 -0
  36. package/components/checkbox/snice-checkbox.types.ts +22 -0
  37. package/components/chip/demo.html +383 -0
  38. package/components/chip/snice-chip.css +195 -0
  39. package/components/chip/snice-chip.ts +139 -0
  40. package/components/chip/snice-chip.types.ts +15 -0
  41. package/components/date-picker/README.md +233 -0
  42. package/components/date-picker/demo.html +191 -0
  43. package/components/date-picker/snice-date-picker.css +330 -0
  44. package/components/date-picker/snice-date-picker.ts +777 -0
  45. package/components/date-picker/snice-date-picker.types.ts +83 -0
  46. package/components/divider/demo.html +233 -0
  47. package/components/divider/snice-divider.css +155 -0
  48. package/components/divider/snice-divider.ts +69 -0
  49. package/components/divider/snice-divider.types.ts +15 -0
  50. package/components/drawer/demo.html +328 -0
  51. package/components/drawer/snice-drawer.css +476 -0
  52. package/components/drawer/snice-drawer.ts +287 -0
  53. package/components/drawer/snice-drawer.types.ts +17 -0
  54. package/components/global.d.ts +14 -0
  55. package/components/input/demo.html +303 -0
  56. package/components/input/snice-input.css +257 -0
  57. package/components/input/snice-input.ts +442 -0
  58. package/components/input/snice-input.types.ts +59 -0
  59. package/components/input/test.html +77 -0
  60. package/components/layout/README.md +260 -0
  61. package/components/layout/demo.html +538 -0
  62. package/components/layout/snice-layout-blog.css +129 -0
  63. package/components/layout/snice-layout-blog.ts +48 -0
  64. package/components/layout/snice-layout-card.css +104 -0
  65. package/components/layout/snice-layout-card.ts +35 -0
  66. package/components/layout/snice-layout-centered.css +51 -0
  67. package/components/layout/snice-layout-centered.ts +22 -0
  68. package/components/layout/snice-layout-dashboard.css +98 -0
  69. package/components/layout/snice-layout-dashboard.ts +45 -0
  70. package/components/layout/snice-layout-fullscreen.css +72 -0
  71. package/components/layout/snice-layout-fullscreen.ts +34 -0
  72. package/components/layout/snice-layout-landing.css +92 -0
  73. package/components/layout/snice-layout-landing.ts +47 -0
  74. package/components/layout/snice-layout-minimal.css +16 -0
  75. package/components/layout/snice-layout-minimal.ts +19 -0
  76. package/components/layout/snice-layout-sidebar.css +117 -0
  77. package/components/layout/snice-layout-sidebar.ts +48 -0
  78. package/components/layout/snice-layout-split.css +103 -0
  79. package/components/layout/snice-layout-split.ts +29 -0
  80. package/components/layout/snice-layout.css +72 -0
  81. package/components/layout/snice-layout.ts +35 -0
  82. package/components/layout/snice-layout.types.ts +5 -0
  83. package/components/login/demo-auth-controller.ts +185 -0
  84. package/components/login/demo.html +470 -0
  85. package/components/login/snice-login.css +204 -0
  86. package/components/login/snice-login.ts +337 -0
  87. package/components/login/snice-login.types.ts +34 -0
  88. package/components/modal/demo.html +291 -0
  89. package/components/modal/snice-modal.css +203 -0
  90. package/components/modal/snice-modal.ts +233 -0
  91. package/components/modal/snice-modal.types.ts +21 -0
  92. package/components/pagination/demo.html +395 -0
  93. package/components/pagination/snice-pagination.ts +333 -0
  94. package/components/pagination/snice-pagination.types.ts +21 -0
  95. package/components/progress/demo.html +510 -0
  96. package/components/progress/snice-progress.css +267 -0
  97. package/components/progress/snice-progress.ts +247 -0
  98. package/components/progress/snice-progress.types.ts +19 -0
  99. package/components/radio/demo.html +287 -0
  100. package/components/radio/snice-radio.css +171 -0
  101. package/components/radio/snice-radio.ts +218 -0
  102. package/components/radio/snice-radio.types.ts +21 -0
  103. package/components/select/demo.html +511 -0
  104. package/components/select/snice-option.ts +52 -0
  105. package/components/select/snice-option.types.ts +14 -0
  106. package/components/select/snice-select.css +392 -0
  107. package/components/select/snice-select.ts +796 -0
  108. package/components/select/snice-select.types.ts +55 -0
  109. package/components/skeleton/demo.html +514 -0
  110. package/components/skeleton/snice-skeleton.css +109 -0
  111. package/components/skeleton/snice-skeleton.ts +126 -0
  112. package/components/skeleton/snice-skeleton.types.ts +11 -0
  113. package/components/switch/demo.html +284 -0
  114. package/components/switch/snice-switch.css +221 -0
  115. package/components/switch/snice-switch.ts +229 -0
  116. package/components/switch/snice-switch.types.ts +23 -0
  117. package/components/symbols.ts +23 -0
  118. package/components/table/demo-table-controller.ts +100 -0
  119. package/components/table/demo.html +480 -0
  120. package/components/table/snice-cell-boolean.ts +112 -0
  121. package/components/table/snice-cell-date.ts +210 -0
  122. package/components/table/snice-cell-duration.ts +91 -0
  123. package/components/table/snice-cell-filesize.ts +90 -0
  124. package/components/table/snice-cell-number.ts +165 -0
  125. package/components/table/snice-cell-progress.ts +83 -0
  126. package/components/table/snice-cell-rating.ts +82 -0
  127. package/components/table/snice-cell-sparkline.ts +253 -0
  128. package/components/table/snice-cell-text.ts +125 -0
  129. package/components/table/snice-cell.css +296 -0
  130. package/components/table/snice-cell.ts +473 -0
  131. package/components/table/snice-column.ts +353 -0
  132. package/components/table/snice-header.css +243 -0
  133. package/components/table/snice-header.ts +261 -0
  134. package/components/table/snice-progress.ts +66 -0
  135. package/components/table/snice-rating.ts +45 -0
  136. package/components/table/snice-row.css +255 -0
  137. package/components/table/snice-row.ts +331 -0
  138. package/components/table/snice-table.css +241 -0
  139. package/components/table/snice-table.ts +737 -0
  140. package/components/table/snice-table.types.ts +158 -0
  141. package/components/tabs/demo.html +487 -0
  142. package/components/tabs/snice-tab-panel.css +264 -0
  143. package/components/tabs/snice-tab-panel.ts +47 -0
  144. package/components/tabs/snice-tab.css +96 -0
  145. package/components/tabs/snice-tab.ts +65 -0
  146. package/components/tabs/snice-tabs.css +189 -0
  147. package/components/tabs/snice-tabs.ts +332 -0
  148. package/components/tabs/snice-tabs.types.ts +28 -0
  149. package/components/theme/theme.css +234 -0
  150. package/components/toast/demo.html +329 -0
  151. package/components/toast/snice-toast-container.ts +256 -0
  152. package/components/toast/snice-toast.css +213 -0
  153. package/components/toast/snice-toast.ts +276 -0
  154. package/components/toast/snice-toast.types.ts +35 -0
  155. package/components/tooltip/demo.html +350 -0
  156. package/components/tooltip/snice-tooltip-portal.css +79 -0
  157. package/components/tooltip/snice-tooltip.css +117 -0
  158. package/components/tooltip/snice-tooltip.ts +612 -0
  159. package/components/tooltip/snice-tooltip.types.ts +32 -0
  160. package/components/transitions.ts +94 -0
  161. package/components/tsconfig.json +18 -0
  162. package/dist/index.cjs +441 -329
  163. package/dist/index.cjs.map +1 -1
  164. package/dist/index.cjs.min.map +1 -1
  165. package/dist/index.esm.js +441 -329
  166. package/dist/index.esm.js.map +1 -1
  167. package/dist/index.esm.min.js +3 -3
  168. package/dist/index.esm.min.js.map +1 -1
  169. package/dist/index.iife.js +441 -329
  170. package/dist/index.iife.js.map +1 -1
  171. package/dist/index.iife.min.js +3 -3
  172. package/dist/index.iife.min.js.map +1 -1
  173. package/dist/symbols.esm.js +1 -1
  174. package/dist/transitions.esm.js +1 -1
  175. package/dist/types/controller.d.ts +1 -1
  176. package/dist/types/element.d.ts +10 -10
  177. package/dist/types/events.d.ts +2 -2
  178. package/dist/types/index.d.ts +1 -1
  179. package/dist/types/observe.d.ts +1 -1
  180. package/dist/types/request-response.d.ts +2 -3
  181. package/dist/types/router.d.ts +1 -1
  182. package/package.json +9 -3
  183. package/dist/index.cjs.min +0 -15
  184. package/dist/symbols.cjs +0 -103
  185. package/dist/transitions.cjs +0 -219
@@ -0,0 +1,117 @@
1
+ import { element, property, watch, query, ready, part } from 'snice';
2
+ import css from './snice-badge.css?inline';
3
+ import type { BadgeVariant, BadgePosition, BadgeSize, SniceBadgeElement } from './snice-badge.types';
4
+
5
+ @element('snice-badge')
6
+ export class SniceBadge extends HTMLElement implements SniceBadgeElement {
7
+ @property({ reflect: true })
8
+ content = '';
9
+
10
+ @property({ type: Number, reflect: true })
11
+ count = 0;
12
+
13
+ @property({ type: Number, reflect: true })
14
+ max = 99;
15
+
16
+ @property({ type: Boolean, reflect: true })
17
+ dot = false;
18
+
19
+ @property({ reflect: true })
20
+ variant: BadgeVariant = 'default';
21
+
22
+ @property({ reflect: true })
23
+ position: BadgePosition = 'top-right';
24
+
25
+ @property({ type: Boolean, reflect: true })
26
+ inline = false;
27
+
28
+ @property({ reflect: true })
29
+ size: BadgeSize = 'medium';
30
+
31
+ @property({ type: Boolean, reflect: true })
32
+ pulse = false;
33
+
34
+ @property({ type: Number, reflect: true })
35
+ offset = 0;
36
+
37
+ @query('.badge')
38
+ badgeElement?: HTMLElement;
39
+
40
+ html() {
41
+ return /*html*/`
42
+ <div class="badge-wrapper">
43
+ <slot></slot>
44
+ <div part="badge-section"></div>
45
+ </div>
46
+ `;
47
+ }
48
+
49
+ @watch('content', 'count', 'max', 'dot', 'pulse')
50
+ @part('badge-section')
51
+ renderBadgeSection() {
52
+ const displayContent = this.getDisplayContent();
53
+ const showBadge = this.shouldShowBadge();
54
+
55
+ if (!showBadge) return '';
56
+
57
+ return /*html*/`
58
+ <span class="badge ${this.dot ? 'badge--dot' : ''} ${this.pulse ? 'badge--pulse' : ''}"
59
+ aria-label="${displayContent}"
60
+ role="status">
61
+ ${!this.dot ? displayContent : ''}
62
+ </span>
63
+ `;
64
+ }
65
+
66
+ css() {
67
+ return css;
68
+ }
69
+
70
+ private getDisplayContent(): string {
71
+ if (this.dot) return 'notification';
72
+ if (this.content) return this.content;
73
+ if (this.count > 0) {
74
+ return this.count > this.max ? `${this.max}+` : String(this.count);
75
+ }
76
+ return '';
77
+ }
78
+
79
+ private shouldShowBadge(): boolean {
80
+ return this.dot || this.content !== '' || this.count > 0;
81
+ }
82
+
83
+ @ready()
84
+ init() {
85
+ this.updateOffset();
86
+ }
87
+
88
+
89
+ @watch('offset')
90
+ updateOffset() {
91
+ this.style.setProperty('--badge-offset', `${this.offset}px`);
92
+ }
93
+
94
+ setBadgeContent(content: string) {
95
+ this.content = content;
96
+ this.count = 0;
97
+ this.dot = false;
98
+ }
99
+
100
+ setBadgeCount(count: number) {
101
+ this.count = count;
102
+ this.content = '';
103
+ this.dot = false;
104
+ }
105
+
106
+ showDot() {
107
+ this.dot = true;
108
+ this.content = '';
109
+ this.count = 0;
110
+ }
111
+
112
+ hide() {
113
+ this.dot = false;
114
+ this.content = '';
115
+ this.count = 0;
116
+ }
117
+ }
@@ -0,0 +1,16 @@
1
+ export type BadgeVariant = 'default' | 'primary' | 'success' | 'warning' | 'error' | 'info';
2
+ export type BadgePosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
3
+ export type BadgeSize = 'small' | 'medium' | 'large';
4
+
5
+ export interface SniceBadgeElement extends HTMLElement {
6
+ content: string;
7
+ count: number;
8
+ max: number;
9
+ dot: boolean;
10
+ variant: BadgeVariant;
11
+ position: BadgePosition;
12
+ inline: boolean;
13
+ size: BadgeSize;
14
+ pulse: boolean;
15
+ offset: number;
16
+ }
@@ -0,0 +1,404 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Snice Breadcrumb Demo</title>
7
+ <link rel="stylesheet" href="../theme/theme.css">
8
+ <style>
9
+ body {
10
+ font-family: system-ui, -apple-system, sans-serif;
11
+ padding: 40px;
12
+ line-height: 1.6;
13
+ background: #f5f5f5;
14
+ }
15
+
16
+ .container {
17
+ max-width: 900px;
18
+ margin: 0 auto;
19
+ background: white;
20
+ padding: 40px;
21
+ border-radius: 8px;
22
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
23
+ }
24
+
25
+ h1 {
26
+ color: #333;
27
+ border-bottom: 2px solid #e0e0e0;
28
+ padding-bottom: 10px;
29
+ }
30
+
31
+ h2 {
32
+ color: #555;
33
+ margin-top: 30px;
34
+ }
35
+
36
+ .demo-section {
37
+ margin: 30px 0;
38
+ padding: 20px;
39
+ background: #fafafa;
40
+ border-radius: 4px;
41
+ }
42
+
43
+ .demo-label {
44
+ display: block;
45
+ margin-bottom: 12px;
46
+ font-weight: 500;
47
+ color: #666;
48
+ font-size: 14px;
49
+ }
50
+
51
+ .breadcrumb-demo {
52
+ margin: 16px 0;
53
+ padding: 16px;
54
+ background: white;
55
+ border: 1px solid #e0e0e0;
56
+ border-radius: 4px;
57
+ }
58
+
59
+ .controls {
60
+ display: flex;
61
+ gap: 10px;
62
+ margin: 20px 0;
63
+ flex-wrap: wrap;
64
+ align-items: center;
65
+ }
66
+
67
+ button {
68
+ padding: 8px 16px;
69
+ background: #3b82f6;
70
+ color: white;
71
+ border: none;
72
+ border-radius: 4px;
73
+ cursor: pointer;
74
+ font-size: 14px;
75
+ transition: background 0.2s;
76
+ }
77
+
78
+ button:hover {
79
+ background: #2563eb;
80
+ }
81
+
82
+ select, input {
83
+ padding: 8px 12px;
84
+ border: 1px solid #d1d5db;
85
+ border-radius: 4px;
86
+ font-size: 14px;
87
+ }
88
+
89
+ code {
90
+ background: #f0f0f0;
91
+ padding: 2px 6px;
92
+ border-radius: 3px;
93
+ font-size: 0.9em;
94
+ }
95
+
96
+ .event-log {
97
+ margin-top: 16px;
98
+ padding: 12px;
99
+ background: #f0f9ff;
100
+ border: 1px solid #0ea5e9;
101
+ border-radius: 4px;
102
+ font-family: monospace;
103
+ font-size: 13px;
104
+ max-height: 150px;
105
+ overflow-y: auto;
106
+ }
107
+ </style>
108
+ </head>
109
+ <body>
110
+ <div class="container">
111
+ <h1>Snice Breadcrumb Component Demo</h1>
112
+
113
+ <div class="demo-section">
114
+ <h2>Basic Breadcrumb</h2>
115
+
116
+ <span class="demo-label">Using items property</span>
117
+ <div class="breadcrumb-demo">
118
+ <snice-breadcrumbs id="basic-breadcrumb"></snice-breadcrumbs>
119
+ </div>
120
+
121
+ <span class="demo-label">Using slot with snice-crumb elements (with icons)</span>
122
+ <div class="breadcrumb-demo">
123
+ <snice-breadcrumbs separator=">">
124
+ <snice-crumb href="/" label="Home" icon="🏠"></snice-crumb>
125
+ <snice-crumb href="/docs" label="Documentation" icon="📚"></snice-crumb>
126
+ <snice-crumb href="/docs/components" label="Components" icon="🧩"></snice-crumb>
127
+ <snice-crumb label="Breadcrumbs" active></snice-crumb>
128
+ </snice-breadcrumbs>
129
+ </div>
130
+
131
+ <span class="demo-label">With active last item</span>
132
+ <div class="breadcrumb-demo">
133
+ <snice-breadcrumbs id="active-breadcrumb"></snice-breadcrumbs>
134
+ </div>
135
+ </div>
136
+
137
+ <div class="demo-section">
138
+ <h2>Separators</h2>
139
+
140
+ <div class="breadcrumb-demo">
141
+ <span class="demo-label">Slash (default)</span>
142
+ <snice-breadcrumbs id="slash-breadcrumb" separator="/"></snice-breadcrumbs>
143
+ </div>
144
+
145
+ <div class="breadcrumb-demo">
146
+ <span class="demo-label">Chevron</span>
147
+ <snice-breadcrumbs id="chevron-breadcrumb" separator=">"></snice-breadcrumbs>
148
+ </div>
149
+
150
+ <div class="breadcrumb-demo">
151
+ <span class="demo-label">Double Chevron</span>
152
+ <snice-breadcrumbs id="double-chevron-breadcrumb" separator="»"></snice-breadcrumbs>
153
+ </div>
154
+
155
+ <div class="breadcrumb-demo">
156
+ <span class="demo-label">Dot</span>
157
+ <snice-breadcrumbs id="dot-breadcrumb" separator="•"></snice-breadcrumbs>
158
+ </div>
159
+
160
+ <div class="breadcrumb-demo">
161
+ <span class="demo-label">Pipe</span>
162
+ <snice-breadcrumbs id="pipe-breadcrumb" separator="|"></snice-breadcrumbs>
163
+ </div>
164
+ </div>
165
+
166
+ <div class="demo-section">
167
+ <h2>Sizes</h2>
168
+
169
+ <div class="breadcrumb-demo">
170
+ <span class="demo-label">Small</span>
171
+ <snice-breadcrumbs id="small-breadcrumb" size="small"></snice-breadcrumbs>
172
+ </div>
173
+
174
+ <div class="breadcrumb-demo">
175
+ <span class="demo-label">Medium (default)</span>
176
+ <snice-breadcrumbs id="medium-breadcrumb" size="medium"></snice-breadcrumbs>
177
+ </div>
178
+
179
+ <div class="breadcrumb-demo">
180
+ <span class="demo-label">Large</span>
181
+ <snice-breadcrumbs id="large-breadcrumb" size="large"></snice-breadcrumbs>
182
+ </div>
183
+ </div>
184
+
185
+ <div class="demo-section">
186
+ <h2>Collapsed Breadcrumbs</h2>
187
+
188
+ <span class="demo-label">Long path with max-items="3" (click ••• to expand)</span>
189
+ <div class="breadcrumb-demo">
190
+ <snice-breadcrumbs id="collapsed-breadcrumb" max-items="3"></snice-breadcrumbs>
191
+ </div>
192
+
193
+ <span class="demo-label">Using slots with max-items="2" and external icon images</span>
194
+ <div class="breadcrumb-demo">
195
+ <snice-breadcrumbs max-items="2" separator="»">
196
+ <snice-crumb href="/" label="Root" icon-image="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%234f46e5'%3E%3Cpath d='M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'/%3E%3C/svg%3E"></snice-crumb>
197
+ <snice-crumb href="/home" label="Home"></snice-crumb>
198
+ <snice-crumb href="/home/user" label="User"></snice-crumb>
199
+ <snice-crumb href="/home/user/docs" label="Documents" icon="📁"></snice-crumb>
200
+ <snice-crumb href="/home/user/docs/projects" label="Projects"></snice-crumb>
201
+ <snice-crumb label="Current File" icon="📄"></snice-crumb>
202
+ </snice-breadcrumbs>
203
+ </div>
204
+
205
+ <span class="demo-label">Max 2 items</span>
206
+ <div class="breadcrumb-demo">
207
+ <snice-breadcrumbs id="collapsed-2-breadcrumb" max-items="2"></snice-breadcrumbs>
208
+ </div>
209
+ </div>
210
+
211
+ <div class="demo-section">
212
+ <h2>Interactive Demo</h2>
213
+
214
+ <div class="controls">
215
+ <select id="separator-select">
216
+ <option value="/">Slash (/)</option>
217
+ <option value=">">Chevron (>)</option>
218
+ <option value="»">Double Chevron (»)</option>
219
+ <option value="•">Dot (•)</option>
220
+ <option value="|">Pipe (|)</option>
221
+ </select>
222
+
223
+ <select id="size-select">
224
+ <option value="small">Small</option>
225
+ <option value="medium" selected>Medium</option>
226
+ <option value="large">Large</option>
227
+ </select>
228
+
229
+ <input type="number" id="max-items" placeholder="Max items" min="0" max="10" value="0">
230
+
231
+ <button onclick="addItem()">Add Item</button>
232
+ <button onclick="removeItem()">Remove Item</button>
233
+ <button onclick="updateBreadcrumb()">Update</button>
234
+ </div>
235
+
236
+ <div class="breadcrumb-demo">
237
+ <snice-breadcrumbs id="interactive-breadcrumb"></snice-breadcrumbs>
238
+ </div>
239
+
240
+ <div class="event-log" id="event-log">
241
+ Event log will appear here...
242
+ </div>
243
+ </div>
244
+
245
+ <div class="demo-section">
246
+ <h2>Real-world Examples</h2>
247
+
248
+ <span class="demo-label">E-commerce Category</span>
249
+ <div class="breadcrumb-demo">
250
+ <snice-breadcrumbs id="ecommerce-breadcrumb"></snice-breadcrumbs>
251
+ </div>
252
+
253
+ <span class="demo-label">Documentation</span>
254
+ <div class="breadcrumb-demo">
255
+ <snice-breadcrumbs id="docs-breadcrumb" separator="»"></snice-breadcrumbs>
256
+ </div>
257
+
258
+ <span class="demo-label">File System</span>
259
+ <div class="breadcrumb-demo">
260
+ <snice-breadcrumbs id="filesystem-breadcrumb" max-items="4"></snice-breadcrumbs>
261
+ </div>
262
+
263
+ <span class="demo-label">Admin Dashboard</span>
264
+ <div class="breadcrumb-demo">
265
+ <snice-breadcrumbs id="admin-breadcrumb"></snice-breadcrumbs>
266
+ </div>
267
+ </div>
268
+ </div>
269
+
270
+ <script type="module">
271
+ import './snice-breadcrumbs.ts';
272
+ import './snice-crumb.ts';
273
+
274
+ // Basic breadcrumb
275
+ document.getElementById('basic-breadcrumb').items = [
276
+ { label: 'Home', href: '/' },
277
+ { label: 'Products', href: '/products' },
278
+ { label: 'Electronics', href: '/products/electronics' },
279
+ { label: 'Laptops', href: '/products/electronics/laptops' }
280
+ ];
281
+
282
+ // Active breadcrumb
283
+ document.getElementById('active-breadcrumb').items = [
284
+ { label: 'Home', href: '/' },
285
+ { label: 'Blog', href: '/blog' },
286
+ { label: 'Tech', href: '/blog/tech' },
287
+ { label: 'Latest Post', active: true }
288
+ ];
289
+
290
+ // Separator examples
291
+ const separatorItems = [
292
+ { label: 'Home', href: '/' },
293
+ { label: 'Category', href: '/category' },
294
+ { label: 'Subcategory', href: '/category/sub' },
295
+ { label: 'Item' }
296
+ ];
297
+
298
+ document.getElementById('slash-breadcrumb').items = separatorItems;
299
+ document.getElementById('chevron-breadcrumb').items = separatorItems;
300
+ document.getElementById('double-chevron-breadcrumb').items = separatorItems;
301
+ document.getElementById('dot-breadcrumb').items = separatorItems;
302
+ document.getElementById('pipe-breadcrumb').items = separatorItems;
303
+
304
+ // Size examples
305
+ const sizeItems = [
306
+ { label: 'Dashboard', href: '/' },
307
+ { label: 'Analytics', href: '/analytics' },
308
+ { label: 'Reports', href: '/analytics/reports' }
309
+ ];
310
+
311
+ document.getElementById('small-breadcrumb').items = sizeItems;
312
+ document.getElementById('medium-breadcrumb').items = sizeItems;
313
+ document.getElementById('large-breadcrumb').items = sizeItems;
314
+
315
+ // Collapsed examples
316
+ const longPath = [
317
+ { label: 'Home', href: '/' },
318
+ { label: 'Documents', href: '/docs' },
319
+ { label: 'Projects', href: '/docs/projects' },
320
+ { label: '2024', href: '/docs/projects/2024' },
321
+ { label: 'Q1', href: '/docs/projects/2024/q1' },
322
+ { label: 'Reports', href: '/docs/projects/2024/q1/reports' },
323
+ { label: 'Final Report' }
324
+ ];
325
+
326
+ document.getElementById('collapsed-breadcrumb').items = longPath;
327
+ document.getElementById('collapsed-2-breadcrumb').items = longPath;
328
+
329
+ // Interactive demo
330
+ let interactiveItems = [
331
+ { label: 'Home', href: '/' },
332
+ { label: 'Page 1', href: '/page1' },
333
+ { label: 'Page 2', href: '/page2' },
334
+ { label: 'Current Page' }
335
+ ];
336
+
337
+ const interactiveBreadcrumb = document.getElementById('interactive-breadcrumb');
338
+ interactiveBreadcrumb.items = interactiveItems;
339
+
340
+ window.addItem = function() {
341
+ const num = interactiveItems.length;
342
+ interactiveItems.splice(-1, 0, {
343
+ label: `Page ${num}`,
344
+ href: `/page${num}`
345
+ });
346
+ interactiveBreadcrumb.items = [...interactiveItems];
347
+ };
348
+
349
+ window.removeItem = function() {
350
+ if (interactiveItems.length > 2) {
351
+ interactiveItems.splice(-2, 1);
352
+ interactiveBreadcrumb.items = [...interactiveItems];
353
+ }
354
+ };
355
+
356
+ window.updateBreadcrumb = function() {
357
+ interactiveBreadcrumb.separator = document.getElementById('separator-select').value;
358
+ interactiveBreadcrumb.size = document.getElementById('size-select').value;
359
+ interactiveBreadcrumb.maxItems = parseInt(document.getElementById('max-items').value) || 0;
360
+ };
361
+
362
+ // Event logging
363
+ interactiveBreadcrumb.addEventListener('breadcrumb-click', (e) => {
364
+ const log = document.getElementById('event-log');
365
+ const time = new Date().toLocaleTimeString();
366
+ log.innerHTML = `[${time}] Clicked: "${e.detail.label}" (index: ${e.detail.index}, href: ${e.detail.href})<br>` + log.innerHTML;
367
+ });
368
+
369
+ // Real-world examples
370
+ document.getElementById('ecommerce-breadcrumb').items = [
371
+ { label: 'Store', href: '/', icon: '🏪' },
372
+ { label: 'Women', href: '/women' },
373
+ { label: 'Clothing', href: '/women/clothing' },
374
+ { label: 'Dresses', href: '/women/clothing/dresses' },
375
+ { label: 'Summer Collection' }
376
+ ];
377
+
378
+ document.getElementById('docs-breadcrumb').items = [
379
+ { label: 'Docs', href: '/docs' },
380
+ { label: 'Components', href: '/docs/components' },
381
+ { label: 'Navigation', href: '/docs/components/navigation' },
382
+ { label: 'Breadcrumb' }
383
+ ];
384
+
385
+ document.getElementById('filesystem-breadcrumb').items = [
386
+ { label: 'root', href: '/' },
387
+ { label: 'home', href: '/home' },
388
+ { label: 'user', href: '/home/user' },
389
+ { label: 'documents', href: '/home/user/documents' },
390
+ { label: 'projects', href: '/home/user/documents/projects' },
391
+ { label: 'snice', href: '/home/user/documents/projects/snice' },
392
+ { label: 'components', href: '/home/user/documents/projects/snice/components' },
393
+ { label: 'breadcrumb.ts' }
394
+ ];
395
+
396
+ document.getElementById('admin-breadcrumb').items = [
397
+ { label: 'Admin', href: '/admin' },
398
+ { label: 'Users', href: '/admin/users' },
399
+ { label: 'Roles', href: '/admin/users/roles' },
400
+ { label: 'Edit Role' }
401
+ ];
402
+ </script>
403
+ </body>
404
+ </html>
@@ -0,0 +1,133 @@
1
+ :host {
2
+ display: block;
3
+ --breadcrumb-font-size: 0.875rem; /* 14px */
4
+ --breadcrumb-spacing: 0.5rem; /* 8px */
5
+ --breadcrumb-color: rgb(var(--snice-color-gray-600, 82 82 82));
6
+ --breadcrumb-hover-color: rgb(var(--snice-color-blue-600, 37 99 235));
7
+ --breadcrumb-active-color: rgb(var(--snice-color-gray-900, 23 23 23));
8
+ --breadcrumb-separator-color: rgb(var(--snice-color-gray-400, 163 163 163));
9
+ }
10
+
11
+ .breadcrumb {
12
+ display: flex;
13
+ align-items: center;
14
+ flex-wrap: wrap;
15
+ list-style: none;
16
+ margin: 0;
17
+ padding: 0;
18
+ font-size: var(--breadcrumb-font-size);
19
+ line-height: 1.5;
20
+ }
21
+
22
+ .breadcrumb-item {
23
+ display: flex;
24
+ align-items: center;
25
+ color: var(--breadcrumb-color);
26
+ }
27
+
28
+ .breadcrumb-link {
29
+ color: inherit;
30
+ text-decoration: none;
31
+ transition: color 0.2s ease;
32
+ cursor: pointer;
33
+ outline: none;
34
+ border-radius: 2px;
35
+ padding: 0.125rem 0.25rem; /* 2px 4px */
36
+ margin: -0.125rem -0.25rem; /* -2px -4px */
37
+ display: inline-flex;
38
+ align-items: center;
39
+ gap: 0.375rem; /* 6px */
40
+ }
41
+
42
+ .breadcrumb-link:hover {
43
+ color: var(--breadcrumb-hover-color);
44
+ text-decoration: underline;
45
+ }
46
+
47
+ .breadcrumb-link:focus-visible {
48
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.4);
49
+ }
50
+
51
+ .breadcrumb-text {
52
+ padding: 2px 4px;
53
+ margin: -2px -4px;
54
+ display: inline-flex;
55
+ align-items: center;
56
+ gap: 0.375rem; /* 6px */
57
+ }
58
+
59
+ .breadcrumb-icon {
60
+ display: inline-flex;
61
+ align-items: center;
62
+ font-size: 1.1em;
63
+ }
64
+
65
+ .breadcrumb-icon-image {
66
+ width: 1.2em;
67
+ height: 1.2em;
68
+ object-fit: contain;
69
+ vertical-align: middle;
70
+ }
71
+
72
+ [hidden] {
73
+ display: none !important;
74
+ }
75
+
76
+ .breadcrumb-item--active {
77
+ color: var(--breadcrumb-active-color);
78
+ font-weight: 500;
79
+ }
80
+
81
+ .breadcrumb-item--active .breadcrumb-link {
82
+ cursor: default;
83
+ pointer-events: none;
84
+ }
85
+
86
+ .breadcrumb-separator {
87
+ margin: 0 var(--breadcrumb-spacing);
88
+ color: var(--breadcrumb-separator-color);
89
+ user-select: none;
90
+ }
91
+
92
+ .breadcrumb-ellipsis {
93
+ display: flex;
94
+ align-items: center;
95
+ padding: 2px 4px;
96
+ margin: -2px -4px;
97
+ cursor: pointer;
98
+ color: var(--breadcrumb-color);
99
+ border-radius: 2px;
100
+ transition: background 0.2s ease;
101
+ }
102
+
103
+ .breadcrumb-ellipsis:hover {
104
+ background: rgba(0, 0, 0, 0.05);
105
+ }
106
+
107
+ .breadcrumb-ellipsis:focus-visible {
108
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.4);
109
+ outline: none;
110
+ }
111
+
112
+ /* Sizes */
113
+ :host([size="small"]) {
114
+ --breadcrumb-font-size: 12px;
115
+ --breadcrumb-spacing: 6px;
116
+ }
117
+
118
+ :host([size="large"]) {
119
+ --breadcrumb-font-size: 16px;
120
+ --breadcrumb-spacing: 10px;
121
+ }
122
+
123
+ /* Collapsed state */
124
+ .breadcrumb--collapsed .breadcrumb-item--hidden {
125
+ display: none;
126
+ }
127
+
128
+ /* Mobile responsive */
129
+ @media (max-width: 640px) {
130
+ .breadcrumb {
131
+ font-size: calc(var(--breadcrumb-font-size) * 0.9);
132
+ }
133
+ }