@sondor-technology/sondor-components 1.0.0-1165-initial-setup.11

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 (168) hide show
  1. package/README.md +8 -0
  2. package/dist/components/alert/alert.d.ts +13 -0
  3. package/dist/components/alert/alert.d.ts.map +1 -0
  4. package/dist/components/alert/alert.js +105 -0
  5. package/dist/components/badge/badge.d.ts +13 -0
  6. package/dist/components/badge/badge.d.ts.map +1 -0
  7. package/dist/components/badge/badge.js +101 -0
  8. package/dist/components/breadcrumb/breadcrumb.d.ts +19 -0
  9. package/dist/components/breadcrumb/breadcrumb.d.ts.map +1 -0
  10. package/dist/components/breadcrumb/breadcrumb.js +99 -0
  11. package/dist/components/button/button.d.ts +23 -0
  12. package/dist/components/button/button.d.ts.map +1 -0
  13. package/dist/components/button/button.js +304 -0
  14. package/dist/components/button-group/button-group.d.ts +6 -0
  15. package/dist/components/button-group/button-group.d.ts.map +1 -0
  16. package/dist/components/button-group/button-group.js +74 -0
  17. package/dist/components/card/card.d.ts +11 -0
  18. package/dist/components/card/card.d.ts.map +1 -0
  19. package/dist/components/card/card.js +54 -0
  20. package/dist/components/checkbox/checkbox.d.ts +28 -0
  21. package/dist/components/checkbox/checkbox.d.ts.map +1 -0
  22. package/dist/components/checkbox/checkbox.js +247 -0
  23. package/dist/components/code-block/code-block.d.ts +20 -0
  24. package/dist/components/code-block/code-block.d.ts.map +1 -0
  25. package/dist/components/code-block/code-block.js +260 -0
  26. package/dist/components/content-card/content-card.d.ts +13 -0
  27. package/dist/components/content-card/content-card.d.ts.map +1 -0
  28. package/dist/components/content-card/content-card.js +140 -0
  29. package/dist/components/divider/divider.d.ts +16 -0
  30. package/dist/components/divider/divider.d.ts.map +1 -0
  31. package/dist/components/divider/divider.js +82 -0
  32. package/dist/components/drawer/drawer.d.ts +22 -0
  33. package/dist/components/drawer/drawer.d.ts.map +1 -0
  34. package/dist/components/drawer/drawer.js +226 -0
  35. package/dist/components/field/field.d.ts +11 -0
  36. package/dist/components/field/field.d.ts.map +1 -0
  37. package/dist/components/field/field.js +32 -0
  38. package/dist/components/footer/footer.d.ts +6 -0
  39. package/dist/components/footer/footer.d.ts.map +1 -0
  40. package/dist/components/footer/footer.js +65 -0
  41. package/dist/components/form/form-step.d.ts +13 -0
  42. package/dist/components/form/form-step.d.ts.map +1 -0
  43. package/dist/components/form/form-step.js +41 -0
  44. package/dist/components/form/form.d.ts +25 -0
  45. package/dist/components/form/form.d.ts.map +1 -0
  46. package/dist/components/form/form.js +358 -0
  47. package/dist/components/grid/grid-row.d.ts +17 -0
  48. package/dist/components/grid/grid-row.d.ts.map +1 -0
  49. package/dist/components/grid/grid-row.js +92 -0
  50. package/dist/components/grid/grid.d.ts +13 -0
  51. package/dist/components/grid/grid.d.ts.map +1 -0
  52. package/dist/components/grid/grid.js +42 -0
  53. package/dist/components/icon/icon-paths.d.ts +116 -0
  54. package/dist/components/icon/icon-paths.d.ts.map +1 -0
  55. package/dist/components/icon/icon-paths.js +121 -0
  56. package/dist/components/icon/icon.d.ts +16 -0
  57. package/dist/components/icon/icon.d.ts.map +1 -0
  58. package/dist/components/icon/icon.js +95 -0
  59. package/dist/components/input/input.d.ts +31 -0
  60. package/dist/components/input/input.d.ts.map +1 -0
  61. package/dist/components/input/input.js +268 -0
  62. package/dist/components/link/link.d.ts +16 -0
  63. package/dist/components/link/link.d.ts.map +1 -0
  64. package/dist/components/link/link.js +116 -0
  65. package/dist/components/metadata/metadata.d.ts +18 -0
  66. package/dist/components/metadata/metadata.d.ts.map +1 -0
  67. package/dist/components/metadata/metadata.js +71 -0
  68. package/dist/components/modal/modal.d.ts +24 -0
  69. package/dist/components/modal/modal.d.ts.map +1 -0
  70. package/dist/components/modal/modal.js +163 -0
  71. package/dist/components/page-layout/page-layout.d.ts +46 -0
  72. package/dist/components/page-layout/page-layout.d.ts.map +1 -0
  73. package/dist/components/page-layout/page-layout.js +697 -0
  74. package/dist/components/radio/radio.d.ts +16 -0
  75. package/dist/components/radio/radio.d.ts.map +1 -0
  76. package/dist/components/radio/radio.js +152 -0
  77. package/dist/components/radio-group/radio-group.d.ts +27 -0
  78. package/dist/components/radio-group/radio-group.d.ts.map +1 -0
  79. package/dist/components/radio-group/radio-group.js +161 -0
  80. package/dist/components/router/router.d.ts +7 -0
  81. package/dist/components/router/router.d.ts.map +1 -0
  82. package/dist/components/router/router.js +37 -0
  83. package/dist/components/select/select.d.ts +16 -0
  84. package/dist/components/select/select.d.ts.map +1 -0
  85. package/dist/components/select/select.js +172 -0
  86. package/dist/components/skeleton/skeleton.d.ts +17 -0
  87. package/dist/components/skeleton/skeleton.d.ts.map +1 -0
  88. package/dist/components/skeleton/skeleton.js +78 -0
  89. package/dist/components/switch/switch.d.ts +25 -0
  90. package/dist/components/switch/switch.d.ts.map +1 -0
  91. package/dist/components/switch/switch.js +185 -0
  92. package/dist/components/table/data-table.d.ts +72 -0
  93. package/dist/components/table/data-table.d.ts.map +1 -0
  94. package/dist/components/table/data-table.js +551 -0
  95. package/dist/components/table/table.d.ts +22 -0
  96. package/dist/components/table/table.d.ts.map +1 -0
  97. package/dist/components/table/table.js +167 -0
  98. package/dist/components/tabs/tab-panel.d.ts +8 -0
  99. package/dist/components/tabs/tab-panel.d.ts.map +1 -0
  100. package/dist/components/tabs/tab-panel.js +46 -0
  101. package/dist/components/tabs/tab.d.ts +9 -0
  102. package/dist/components/tabs/tab.d.ts.map +1 -0
  103. package/dist/components/tabs/tab.js +91 -0
  104. package/dist/components/tabs/tabs.d.ts +14 -0
  105. package/dist/components/tabs/tabs.d.ts.map +1 -0
  106. package/dist/components/tabs/tabs.js +85 -0
  107. package/dist/components/textarea/textarea.d.ts +36 -0
  108. package/dist/components/textarea/textarea.d.ts.map +1 -0
  109. package/dist/components/textarea/textarea.js +231 -0
  110. package/dist/components/theme-toggle/theme-toggle.d.ts +15 -0
  111. package/dist/components/theme-toggle/theme-toggle.d.ts.map +1 -0
  112. package/dist/components/theme-toggle/theme-toggle.js +130 -0
  113. package/dist/components/vertical-nav/vertical-nav-group.d.ts +9 -0
  114. package/dist/components/vertical-nav/vertical-nav-group.d.ts.map +1 -0
  115. package/dist/components/vertical-nav/vertical-nav-group.js +111 -0
  116. package/dist/components/vertical-nav/vertical-nav-item.d.ts +8 -0
  117. package/dist/components/vertical-nav/vertical-nav-item.d.ts.map +1 -0
  118. package/dist/components/vertical-nav/vertical-nav-item.js +65 -0
  119. package/dist/styles/index.css +171 -0
  120. package/dist/styles/reset.d.ts +2 -0
  121. package/dist/styles/reset.d.ts.map +1 -0
  122. package/dist/styles/reset.js +50 -0
  123. package/package.json +192 -0
  124. package/src/components/alert/alert.ts +101 -0
  125. package/src/components/badge/badge.ts +97 -0
  126. package/src/components/breadcrumb/breadcrumb.ts +99 -0
  127. package/src/components/button/button.ts +281 -0
  128. package/src/components/button-group/button-group.ts +67 -0
  129. package/src/components/card/card.ts +53 -0
  130. package/src/components/checkbox/checkbox.ts +238 -0
  131. package/src/components/code-block/code-block.ts +257 -0
  132. package/src/components/content-card/content-card.ts +134 -0
  133. package/src/components/divider/divider.ts +69 -0
  134. package/src/components/drawer/drawer.ts +218 -0
  135. package/src/components/field/field.ts +31 -0
  136. package/src/components/footer/footer.ts +58 -0
  137. package/src/components/form/form-step.ts +32 -0
  138. package/src/components/form/form.ts +376 -0
  139. package/src/components/grid/grid-row.ts +76 -0
  140. package/src/components/grid/grid.ts +37 -0
  141. package/src/components/icon/icon-paths.ts +124 -0
  142. package/src/components/icon/icon.ts +83 -0
  143. package/src/components/input/input.ts +248 -0
  144. package/src/components/link/link.ts +98 -0
  145. package/src/components/metadata/metadata.ts +67 -0
  146. package/src/components/modal/modal.ts +159 -0
  147. package/src/components/page-layout/page-layout.ts +705 -0
  148. package/src/components/radio/radio.ts +142 -0
  149. package/src/components/radio-group/radio-group.ts +157 -0
  150. package/src/components/router/router.ts +47 -0
  151. package/src/components/select/select.ts +162 -0
  152. package/src/components/skeleton/skeleton.ts +68 -0
  153. package/src/components/switch/switch.ts +181 -0
  154. package/src/components/table/data-table.ts +557 -0
  155. package/src/components/table/table.ts +154 -0
  156. package/src/components/tabs/tab-panel.ts +31 -0
  157. package/src/components/tabs/tab.ts +77 -0
  158. package/src/components/tabs/tabs.ts +88 -0
  159. package/src/components/textarea/textarea.ts +215 -0
  160. package/src/components/theme-toggle/theme-toggle.ts +131 -0
  161. package/src/components/vertical-nav/vertical-nav-group.ts +97 -0
  162. package/src/components/vertical-nav/vertical-nav-item.ts +50 -0
  163. package/src/styles/globals.css +58 -0
  164. package/src/styles/index.css +80 -0
  165. package/src/styles/reset.ts +51 -0
  166. package/src/styles/theme.css +59 -0
  167. package/src/styles/typography.css +26 -0
  168. package/tsconfig.json +16 -0
@@ -0,0 +1,705 @@
1
+ import { LitElement, html, css, PropertyValues } from 'lit';
2
+ import { customElement, property, state } from 'lit/decorators.js';
3
+ import { resetStyles } from '../../styles/reset.js';
4
+
5
+ export type LayoutVariant = 'app-shell' | 'content-sidebar' | 'single-column' | 'three-column';
6
+
7
+ @customElement('st-page-layout')
8
+ export class StPageLayout extends LitElement {
9
+ /**
10
+ * Defines the structural layout variant to render.
11
+ */
12
+ @property({ type: String, reflect: true })
13
+ variant: LayoutVariant = 'single-column';
14
+
15
+ /**
16
+ * Maximum width for the left sidebar section (e.g., '20rem', '300px').
17
+ */
18
+ @property({ type: String, attribute: 'sidebar-width' })
19
+ sidebarWidth = '';
20
+
21
+ /**
22
+ * Maximum width for the right sidebar section (e.g., '16rem', '250px').
23
+ */
24
+ @property({ type: String, attribute: 'right-sidebar-width' })
25
+ rightSidebarWidth = '';
26
+
27
+ /**
28
+ * Optional maximum width for the main content area (e.g., '48rem', '800px').
29
+ */
30
+ @property({ type: String, attribute: 'main-max-width' })
31
+ mainMaxWidth = '';
32
+
33
+ /**
34
+ * When true, expands the main content area to fill 100% of the available width between sidebars.
35
+ */
36
+ @property({ type: Boolean, attribute: 'fill-main', reflect: true })
37
+ fillMain = false;
38
+
39
+ @state()
40
+ private _mobileMenuOpen = false;
41
+
42
+ private _touchStartX = 0;
43
+ private _currentTranslateX = 0;
44
+ private _isDragging = false;
45
+
46
+ override updated(changedProperties: PropertyValues<this>) {
47
+ super.updated(changedProperties);
48
+
49
+ if (changedProperties.has('sidebarWidth')) {
50
+ if (this.sidebarWidth) {
51
+ this.style.setProperty('--layout-sidebar-width', this.sidebarWidth);
52
+ } else {
53
+ this.style.removeProperty('--layout-sidebar-width');
54
+ }
55
+ }
56
+
57
+ if (changedProperties.has('rightSidebarWidth')) {
58
+ if (this.rightSidebarWidth) {
59
+ this.style.setProperty('--layout-right-sidebar-width', this.rightSidebarWidth);
60
+ } else {
61
+ this.style.removeProperty('--layout-right-sidebar-width');
62
+ }
63
+ }
64
+
65
+ if (changedProperties.has('mainMaxWidth')) {
66
+ if (this.mainMaxWidth) {
67
+ this.style.setProperty('--layout-main-max-width', this.mainMaxWidth);
68
+ } else {
69
+ this.style.removeProperty('--layout-main-max-width');
70
+ }
71
+ }
72
+ }
73
+
74
+ private _toggleMobileMenu = () => {
75
+ this._mobileMenuOpen = !this._mobileMenuOpen;
76
+ };
77
+
78
+ private _closeMobileMenu = () => {
79
+ this._mobileMenuOpen = false;
80
+ };
81
+
82
+ // Only close if an actual navigation link/item was clicked
83
+ private _handleNavClick = (e: MouseEvent) => {
84
+ const path = e.composedPath();
85
+ const clickedLink = path.some(node => {
86
+ const el = node as HTMLElement;
87
+ return el.tagName === 'A' || el.tagName === 'ST-VERTICAL-NAV-ITEM';
88
+ });
89
+
90
+ if (clickedLink) {
91
+ this._closeMobileMenu();
92
+ }
93
+ };
94
+
95
+ private _handleTouchStart = (e: TouchEvent) => {
96
+ if (window.innerWidth >= 768) return;
97
+ this._touchStartX = e.touches[0].clientX;
98
+ this._isDragging = true;
99
+ const sidebar = e.currentTarget as HTMLElement;
100
+ sidebar.style.transition = 'none';
101
+ };
102
+
103
+ private _handleTouchMove = (e: TouchEvent) => {
104
+ if (!this._isDragging || window.innerWidth >= 768) return;
105
+ const currentX = e.touches[0].clientX;
106
+ const diff = currentX - this._touchStartX;
107
+ const sidebar = e.currentTarget as HTMLElement;
108
+
109
+ if (diff < 0) {
110
+ this._currentTranslateX = diff;
111
+ sidebar.style.transform = `translateX(${diff}px)`;
112
+ }
113
+ };
114
+
115
+ private _handleTouchEnd = (e: TouchEvent) => {
116
+ if (!this._isDragging || window.innerWidth >= 768) return;
117
+ this._isDragging = false;
118
+ const sidebar = e.currentTarget as HTMLElement;
119
+ sidebar.style.transition = '';
120
+
121
+ if (this._currentTranslateX < -70) {
122
+ this._closeMobileMenu();
123
+ sidebar.style.transform = '';
124
+ } else {
125
+ sidebar.style.transform = '';
126
+ }
127
+ this._currentTranslateX = 0;
128
+ };
129
+
130
+ private _resizeListener = () => {
131
+ if (window.innerWidth >= 768 && this._mobileMenuOpen) {
132
+ this._mobileMenuOpen = false;
133
+ }
134
+ };
135
+
136
+ connectedCallback() {
137
+ super.connectedCallback();
138
+ window.addEventListener('resize', this._resizeListener);
139
+ }
140
+
141
+ disconnectedCallback() {
142
+ super.disconnectedCallback();
143
+ window.removeEventListener('resize', this._resizeListener);
144
+ }
145
+
146
+ static styles = [
147
+ resetStyles,
148
+ css`
149
+ :host {
150
+ display: block;
151
+ box-sizing: border-box;
152
+ --layout-bg-color: var(--st-color-bg, #ffffff);
153
+ --layout-surface-color: var(--st-color-surface, #f8fafc);
154
+ --layout-border-color: var(--st-color-border, #e2e8f0);
155
+ --layout-sidebar-width: 16rem;
156
+ --layout-right-sidebar-width: 14rem;
157
+ --layout-main-max-width: none;
158
+ --layout-nav-height: 4rem;
159
+ }
160
+
161
+ *, *::before, *::after {
162
+ box-sizing: inherit;
163
+ }
164
+
165
+ /* ==========================================================
166
+ Mobile Hamburger Toggle Button Styles
167
+ ========================================================== */
168
+ .mobile-menu-btn {
169
+ display: flex;
170
+ align-items: center;
171
+ justify-content: center;
172
+ background: transparent;
173
+ border: 1px solid var(--layout-border-color);
174
+ border-radius: var(--st-radius-sm, 0.375rem);
175
+ width: 2.25rem;
176
+ height: 2.25rem;
177
+ cursor: pointer;
178
+ color: var(--st-color-text);
179
+ margin-right: var(--st-spacing-sm);
180
+ flex-shrink: 0;
181
+ }
182
+
183
+ .mobile-menu-btn svg {
184
+ width: 1.25rem;
185
+ height: 1.25rem;
186
+ stroke: currentColor;
187
+ stroke-width: 2;
188
+ stroke-linecap: round;
189
+ stroke-linejoin: round;
190
+ fill: none;
191
+ }
192
+
193
+ @media (min-width: 768px) {
194
+ .mobile-menu-btn {
195
+ display: none;
196
+ }
197
+ }
198
+
199
+ /* ==========================================================
200
+ Mobile Backdrop Overlay
201
+ ========================================================== */
202
+ .mobile-backdrop {
203
+ position: fixed;
204
+ top: 0;
205
+ left: 0;
206
+ width: 100vw;
207
+ height: 100vh;
208
+ background-color: rgba(0, 0, 0, 0.5);
209
+ backdrop-filter: blur(2px);
210
+ z-index: 1000;
211
+ display: none;
212
+ }
213
+
214
+ .mobile-backdrop.open {
215
+ display: block;
216
+ }
217
+
218
+ @media (min-width: 768px) {
219
+ .mobile-backdrop {
220
+ display: none !important;
221
+ }
222
+ }
223
+
224
+ /* ==========================================================
225
+ Mobile Drawer Header (Only visible < 768px)
226
+ ========================================================== */
227
+ .mobile-drawer-header {
228
+ display: flex;
229
+ align-items: center;
230
+ justify-content: space-between;
231
+ padding: var(--st-spacing-md) var(--st-spacing-lg);
232
+ border-bottom: 1px solid var(--layout-border-color);
233
+ flex-shrink: 0;
234
+ }
235
+
236
+ .mobile-drawer-title {
237
+ font-weight: var(--st-font-weight-bold);
238
+ font-size: var(--st-font-size-sm);
239
+ color: var(--st-color-text);
240
+ text-transform: uppercase;
241
+ letter-spacing: 0.05em;
242
+ }
243
+
244
+ .mobile-close-btn {
245
+ background: transparent;
246
+ border: none;
247
+ cursor: pointer;
248
+ color: var(--st-color-text-muted);
249
+ padding: 0.25rem;
250
+ display: flex;
251
+ align-items: center;
252
+ justify-content: center;
253
+ border-radius: var(--st-radius-sm, 0.375rem);
254
+ }
255
+
256
+ .mobile-close-btn:hover {
257
+ color: var(--st-color-text);
258
+ background-color: var(--st-color-surface-muted, #f1f5f9);
259
+ }
260
+
261
+ .mobile-close-btn svg {
262
+ width: 1.25rem;
263
+ height: 1.25rem;
264
+ stroke: currentColor;
265
+ stroke-width: 2;
266
+ stroke-linecap: round;
267
+ stroke-linejoin: round;
268
+ fill: none;
269
+ }
270
+
271
+ @media (min-width: 768px) {
272
+ .mobile-drawer-header {
273
+ display: none !important;
274
+ }
275
+ }
276
+
277
+ /* ==========================================================
278
+ 1. App Shell Layout
279
+ ========================================================== */
280
+ .layout-app-shell {
281
+ display: flex;
282
+ height: 100vh;
283
+ overflow: hidden;
284
+ background-color: var(--layout-surface-color);
285
+ }
286
+
287
+ .app-shell-sidebar {
288
+ display: none;
289
+ border-right: 1px solid var(--layout-border-color);
290
+ background: var(--layout-bg-color);
291
+ }
292
+
293
+ .app-shell-sidebar-inner {
294
+ flex: 1;
295
+ overflow-y: auto;
296
+ }
297
+
298
+ .app-shell-content {
299
+ display: flex;
300
+ flex-direction: column;
301
+ flex: 1;
302
+ width: 100%;
303
+ }
304
+
305
+ .app-shell-nav {
306
+ height: var(--layout-nav-height);
307
+ border-bottom: 1px solid var(--layout-border-color);
308
+ background: var(--layout-bg-color);
309
+ display: flex;
310
+ align-items: center;
311
+ padding: 0 var(--st-spacing-md);
312
+ }
313
+
314
+ .app-shell-main {
315
+ flex: 1;
316
+ overflow-y: auto;
317
+ padding: var(--st-spacing-lg);
318
+ }
319
+
320
+ .app-shell-footer {
321
+ background: var(--layout-bg-color);
322
+ border-top: 1px solid var(--layout-border-color);
323
+ padding: var(--st-spacing-md);
324
+ }
325
+
326
+ @media (min-width: 768px) {
327
+ .app-shell-sidebar {
328
+ display: flex;
329
+ flex-direction: column;
330
+ width: 100%;
331
+ max-width: var(--layout-sidebar-width);
332
+ flex-shrink: 0;
333
+ }
334
+ }
335
+
336
+ /* ==========================================================
337
+ 2. Content Sidebar Layout
338
+ ========================================================== */
339
+ .layout-content-sidebar {
340
+ min-height: 100vh;
341
+ display: flex;
342
+ flex-direction: column;
343
+ background: var(--layout-bg-color);
344
+ }
345
+
346
+ .content-sidebar-nav {
347
+ border-bottom: 1px solid var(--layout-border-color);
348
+ background: var(--layout-bg-color);
349
+ }
350
+
351
+ .content-sidebar-container {
352
+ flex: 1;
353
+ width: 100%;
354
+ max-width: 72rem;
355
+ margin: 0 auto;
356
+ padding: var(--st-spacing-xl) var(--st-spacing-md);
357
+ display: flex;
358
+ flex-direction: column;
359
+ gap: var(--st-spacing-xl);
360
+ }
361
+
362
+ .content-sidebar-main {
363
+ flex: 1;
364
+ max-width: 48rem;
365
+ }
366
+
367
+ .content-sidebar-aside {
368
+ width: 100%;
369
+ flex-shrink: 0;
370
+ }
371
+
372
+ .content-sidebar-footer {
373
+ margin-top: auto;
374
+ border-top: 1px solid var(--layout-border-color);
375
+ background: var(--layout-surface-color);
376
+ }
377
+
378
+ @media (min-width: 1024px) {
379
+ .content-sidebar-container {
380
+ flex-direction: row;
381
+ gap: 3rem;
382
+ }
383
+ .content-sidebar-aside {
384
+ width: 100%;
385
+ max-width: var(--layout-sidebar-width);
386
+ }
387
+ .content-sidebar-aside-inner {
388
+ position: sticky;
389
+ top: var(--st-spacing-lg);
390
+ }
391
+ }
392
+
393
+ /* ==========================================================
394
+ 3. Single Column Layout
395
+ ========================================================== */
396
+ .layout-single-column {
397
+ min-height: 100vh;
398
+ display: flex;
399
+ flex-direction: column;
400
+ background: var(--layout-bg-color);
401
+ }
402
+
403
+ .single-column-nav {
404
+ position: sticky;
405
+ top: 0;
406
+ z-index: 50;
407
+ width: 100%;
408
+ background: var(--layout-bg-color);
409
+ border-bottom: 1px solid var(--layout-border-color);
410
+ }
411
+
412
+ .single-column-main {
413
+ flex: 1;
414
+ display: flex;
415
+ flex-direction: column;
416
+ }
417
+
418
+ .single-column-footer {
419
+ margin-top: auto;
420
+ }
421
+
422
+ /* ==========================================================
423
+ 4. Three-Column Layout (Docs Shell)
424
+ ========================================================== */
425
+ .layout-three-column {
426
+ min-height: 100vh;
427
+ display: flex;
428
+ flex-direction: column;
429
+ background: var(--layout-bg-color);
430
+ }
431
+
432
+ .three-column-nav {
433
+ position: sticky;
434
+ top: 0;
435
+ z-index: 50;
436
+ height: var(--layout-nav-height);
437
+ border-bottom: 1px solid var(--layout-border-color);
438
+ background: var(--layout-bg-color);
439
+ display: flex;
440
+ align-items: center;
441
+ padding: 0 var(--st-spacing-md);
442
+ }
443
+
444
+ .three-column-body {
445
+ flex: 1;
446
+ width: 100%;
447
+ max-width: 96rem;
448
+ margin: 0 auto;
449
+ display: flex;
450
+ }
451
+
452
+ :host([fill-main]) .three-column-body {
453
+ max-width: 100%;
454
+ }
455
+
456
+ .three-column-sidebar-left {
457
+ display: none;
458
+ width: 100%;
459
+ max-width: var(--layout-sidebar-width);
460
+ flex-shrink: 0;
461
+ border-right: 1px solid var(--layout-border-color);
462
+ background: var(--layout-bg-color);
463
+ }
464
+
465
+ .three-column-sidebar-left-inner {
466
+ position: sticky;
467
+ top: calc(var(--layout-nav-height) + 1rem);
468
+ height: calc(100vh - var(--layout-nav-height) - 2rem);
469
+ overflow-y: auto;
470
+ padding: var(--st-spacing-md) 0;
471
+ }
472
+
473
+ .three-column-main {
474
+ flex: 1;
475
+ min-width: 0;
476
+ padding: var(--st-spacing-xl) var(--st-spacing-lg);
477
+ max-width: var(--layout-main-max-width);
478
+ margin-left: auto;
479
+ margin-right: auto;
480
+ }
481
+
482
+ .three-column-sidebar-right {
483
+ display: none;
484
+ width: 100%;
485
+ max-width: var(--layout-right-sidebar-width);
486
+ flex-shrink: 0;
487
+ border-left: 1px solid var(--layout-border-color);
488
+ background: var(--layout-bg-color);
489
+ }
490
+
491
+ .three-column-sidebar-right-inner {
492
+ position: sticky;
493
+ top: calc(var(--layout-nav-height) + 1rem);
494
+ height: calc(100vh - var(--layout-nav-height) - 2rem);
495
+ overflow-y: auto;
496
+ padding: var(--st-spacing-md) var(--st-spacing-sm);
497
+ }
498
+
499
+ .three-column-footer {
500
+ border-top: 1px solid var(--layout-border-color);
501
+ background: var(--layout-surface-color);
502
+ padding: var(--st-spacing-lg);
503
+ }
504
+
505
+ @media (min-width: 768px) {
506
+ .three-column-sidebar-left {
507
+ display: block;
508
+ }
509
+ }
510
+
511
+ @media (min-width: 1280px) {
512
+ .three-column-sidebar-right {
513
+ display: block;
514
+ }
515
+ }
516
+
517
+ /* ==========================================================
518
+ Mobile Drawer Transformation & Touch Support (< 768px)
519
+ ========================================================== */
520
+ @media (max-width: 767px) {
521
+ .three-column-sidebar-left,
522
+ .app-shell-sidebar {
523
+ position: fixed;
524
+ top: 0;
525
+ left: 0;
526
+ width: 100%;
527
+ max-width: var(--layout-sidebar-width);
528
+ height: 100vh;
529
+ background: var(--layout-bg-color);
530
+ z-index: 1001;
531
+ box-shadow: 4px 0 24px rgba(0, 0, 0, 0.15);
532
+ transform: translateX(-100%);
533
+ transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
534
+ display: flex !important;
535
+ flex-direction: column;
536
+ touch-action: pan-y;
537
+ }
538
+
539
+ .three-column-sidebar-left.open,
540
+ .app-shell-sidebar.open {
541
+ transform: translateX(0);
542
+ }
543
+
544
+ .three-column-sidebar-left-inner {
545
+ position: static;
546
+ height: auto;
547
+ flex: 1;
548
+ overflow-y: auto;
549
+ }
550
+ }
551
+ `
552
+ ];
553
+
554
+ render() {
555
+ const backdrop = html`
556
+ <div
557
+ class="mobile-backdrop ${this._mobileMenuOpen ? 'open' : ''}"
558
+ @click=${this._closeMobileMenu}
559
+ ></div>
560
+ `;
561
+
562
+ const hamburgerBtn = html`
563
+ <button class="mobile-menu-btn" @click=${this._toggleMobileMenu} aria-label="Open Navigation Menu">
564
+ <svg viewBox="0 0 24 24"><path d="M3 12h18M3 6h18M3 18h18"></path></svg>
565
+ </button>
566
+ `;
567
+
568
+ const drawerHeader = html`
569
+ <div class="mobile-drawer-header">
570
+ <span class="mobile-drawer-title">Menu</span>
571
+ <button class="mobile-close-btn" @click=${this._closeMobileMenu} aria-label="Close Navigation Menu">
572
+ <svg viewBox="0 0 24 24"><path d="M18 6L6 18M6 6l12 12"></path></svg>
573
+ </button>
574
+ </div>
575
+ `;
576
+
577
+ if (this.variant === 'app-shell') {
578
+ return html`
579
+ ${backdrop}
580
+ <div class="layout-app-shell">
581
+ <aside
582
+ class="app-shell-sidebar ${this._mobileMenuOpen ? 'open' : ''}"
583
+ @click=${this._handleNavClick}
584
+ @touchstart=${this._handleTouchStart}
585
+ @touchmove=${this._handleTouchMove}
586
+ @touchend=${this._handleTouchEnd}
587
+ >
588
+ ${drawerHeader}
589
+ <div class="app-shell-sidebar-inner">
590
+ <slot name="sidebar"></slot>
591
+ </div>
592
+ </aside>
593
+
594
+ <div class="app-shell-content">
595
+ <header class="app-shell-nav">
596
+ ${hamburgerBtn}
597
+ <slot name="nav"></slot>
598
+ </header>
599
+
600
+ <main class="app-shell-main">
601
+ <slot></slot>
602
+ </main>
603
+
604
+ <footer class="app-shell-footer">
605
+ <slot name="footer"></slot>
606
+ </footer>
607
+ </div>
608
+ </div>
609
+ `;
610
+ }
611
+
612
+ if (this.variant === 'content-sidebar') {
613
+ return html`
614
+ <div class="layout-content-sidebar">
615
+ <header class="content-sidebar-nav">
616
+ <div style="display: flex; align-items: center; padding: 0 var(--st-spacing-md); height: var(--layout-nav-height);">
617
+ <slot name="nav"></slot>
618
+ </div>
619
+ </header>
620
+
621
+ <div class="content-sidebar-container">
622
+ <main class="content-sidebar-main">
623
+ <slot></slot>
624
+ </main>
625
+
626
+ <aside class="content-sidebar-aside">
627
+ <div class="content-sidebar-aside-inner">
628
+ <slot name="aside"></slot>
629
+ </div>
630
+ </aside>
631
+ </div>
632
+
633
+ <footer class="content-sidebar-footer">
634
+ <slot name="footer"></slot>
635
+ </footer>
636
+ </div>
637
+ `;
638
+ }
639
+
640
+ if (this.variant === 'three-column') {
641
+ return html`
642
+ ${backdrop}
643
+ <div class="layout-three-column">
644
+ <header class="three-column-nav">
645
+ ${hamburgerBtn}
646
+ <slot name="nav"></slot>
647
+ </header>
648
+
649
+ <div class="three-column-body">
650
+ <aside
651
+ class="three-column-sidebar-left ${this._mobileMenuOpen ? 'open' : ''}"
652
+ @click=${this._handleNavClick}
653
+ @touchstart=${this._handleTouchStart}
654
+ @touchmove=${this._handleTouchMove}
655
+ @touchend=${this._handleTouchEnd}
656
+ >
657
+ ${drawerHeader}
658
+ <div class="three-column-sidebar-left-inner">
659
+ <slot name="sidebar-left"></slot>
660
+ </div>
661
+ </aside>
662
+
663
+ <main class="three-column-main">
664
+ <slot></slot>
665
+ </main>
666
+
667
+ <aside class="three-column-sidebar-right">
668
+ <div class="three-column-sidebar-right-inner">
669
+ <slot name="sidebar-right"></slot>
670
+ </div>
671
+ </aside>
672
+ </div>
673
+
674
+ <footer class="three-column-footer">
675
+ <slot name="footer"></slot>
676
+ </footer>
677
+ </div>
678
+ `;
679
+ }
680
+
681
+ return html`
682
+ <div class="layout-single-column">
683
+ <header class="single-column-nav">
684
+ <div style="display: flex; align-items: center; padding: 0 var(--st-spacing-md); height: var(--layout-nav-height);">
685
+ <slot name="nav"></slot>
686
+ </div>
687
+ </header>
688
+
689
+ <main class="single-column-main">
690
+ <slot></slot>
691
+ </main>
692
+
693
+ <footer class="single-column-footer">
694
+ <slot name="footer"></slot>
695
+ </footer>
696
+ </div>
697
+ `;
698
+ }
699
+ }
700
+
701
+ declare global {
702
+ interface HTMLElementTagNameMap {
703
+ 'st-page-layout': StPageLayout;
704
+ }
705
+ }