@sankhyatronics/sankhya-cms 0.0.0-stage → 0.0.9

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 (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -3
  3. package/custom-elements.json +4008 -0
  4. package/dist/bento-grid/index.d.ts +27 -0
  5. package/dist/bento-grid/index.js +10 -0
  6. package/dist/bento-grid/index.js.map +1 -0
  7. package/dist/card/index.d.ts +20 -0
  8. package/dist/card/index.js +9 -0
  9. package/dist/card/index.js.map +1 -0
  10. package/dist/carousel/index.d.ts +44 -0
  11. package/dist/carousel/index.js +10 -0
  12. package/dist/carousel/index.js.map +1 -0
  13. package/dist/chunk-23IHTBAB.js +557 -0
  14. package/dist/chunk-23IHTBAB.js.map +1 -0
  15. package/dist/chunk-2VZFHTBC.js +203 -0
  16. package/dist/chunk-2VZFHTBC.js.map +1 -0
  17. package/dist/chunk-3ERKQNZT.js +155 -0
  18. package/dist/chunk-3ERKQNZT.js.map +1 -0
  19. package/dist/chunk-3JU3R22O.js +193 -0
  20. package/dist/chunk-3JU3R22O.js.map +1 -0
  21. package/dist/chunk-3TCP25JG.js +347 -0
  22. package/dist/chunk-3TCP25JG.js.map +1 -0
  23. package/dist/chunk-3VE6VFJ4.js +87 -0
  24. package/dist/chunk-3VE6VFJ4.js.map +1 -0
  25. package/dist/chunk-4HKSA5UT.js +312 -0
  26. package/dist/chunk-4HKSA5UT.js.map +1 -0
  27. package/dist/chunk-5REZSZCK.js +266 -0
  28. package/dist/chunk-5REZSZCK.js.map +1 -0
  29. package/dist/chunk-5UFRGZWG.js +268 -0
  30. package/dist/chunk-5UFRGZWG.js.map +1 -0
  31. package/dist/chunk-74MILER4.js +215 -0
  32. package/dist/chunk-74MILER4.js.map +1 -0
  33. package/dist/chunk-7PSYCTEN.js +118 -0
  34. package/dist/chunk-7PSYCTEN.js.map +1 -0
  35. package/dist/chunk-E52WO7R7.js +279 -0
  36. package/dist/chunk-E52WO7R7.js.map +1 -0
  37. package/dist/chunk-EUXUH3YW.js +15 -0
  38. package/dist/chunk-EUXUH3YW.js.map +1 -0
  39. package/dist/chunk-IMACP7HN.js +156 -0
  40. package/dist/chunk-IMACP7HN.js.map +1 -0
  41. package/dist/chunk-LHU23TF6.js +273 -0
  42. package/dist/chunk-LHU23TF6.js.map +1 -0
  43. package/dist/chunk-OEX5FDMR.js +250 -0
  44. package/dist/chunk-OEX5FDMR.js.map +1 -0
  45. package/dist/chunk-RHAOQ6K4.js +138 -0
  46. package/dist/chunk-RHAOQ6K4.js.map +1 -0
  47. package/dist/chunk-RMIJVTFS.js +397 -0
  48. package/dist/chunk-RMIJVTFS.js.map +1 -0
  49. package/dist/chunk-TIU73O7I.js +221 -0
  50. package/dist/chunk-TIU73O7I.js.map +1 -0
  51. package/dist/chunk-USNFT4DU.js +125 -0
  52. package/dist/chunk-USNFT4DU.js.map +1 -0
  53. package/dist/chunk-VYON56QO.js +90 -0
  54. package/dist/chunk-VYON56QO.js.map +1 -0
  55. package/dist/chunk-WCO7JAIK.js +195 -0
  56. package/dist/chunk-WCO7JAIK.js.map +1 -0
  57. package/dist/chunk-XHBC23TV.js +254 -0
  58. package/dist/chunk-XHBC23TV.js.map +1 -0
  59. package/dist/chunk-XXPBFHWR.js +70 -0
  60. package/dist/chunk-XXPBFHWR.js.map +1 -0
  61. package/dist/chunk-YYK4GQUW.js +299 -0
  62. package/dist/chunk-YYK4GQUW.js.map +1 -0
  63. package/dist/cms-theme.css +15 -0
  64. package/dist/content-block/index.d.ts +25 -0
  65. package/dist/content-block/index.js +11 -0
  66. package/dist/content-block/index.js.map +1 -0
  67. package/dist/cookie-consent/index.d.ts +33 -0
  68. package/dist/cookie-consent/index.js +9 -0
  69. package/dist/cookie-consent/index.js.map +1 -0
  70. package/dist/dropdown/index.d.ts +89 -0
  71. package/dist/dropdown/index.js +9 -0
  72. package/dist/dropdown/index.js.map +1 -0
  73. package/dist/feature-split/index.d.ts +38 -0
  74. package/dist/feature-split/index.js +11 -0
  75. package/dist/feature-split/index.js.map +1 -0
  76. package/dist/features-section/index.d.ts +50 -0
  77. package/dist/features-section/index.js +14 -0
  78. package/dist/features-section/index.js.map +1 -0
  79. package/dist/footer/index.d.ts +64 -0
  80. package/dist/footer/index.js +9 -0
  81. package/dist/footer/index.js.map +1 -0
  82. package/dist/header/index.d.ts +112 -0
  83. package/dist/header/index.js +10 -0
  84. package/dist/header/index.js.map +1 -0
  85. package/dist/hero/index.d.ts +32 -0
  86. package/dist/hero/index.js +10 -0
  87. package/dist/hero/index.js.map +1 -0
  88. package/dist/icon-button/index.d.ts +23 -0
  89. package/dist/icon-button/index.js +9 -0
  90. package/dist/icon-button/index.js.map +1 -0
  91. package/dist/index.d.ts +22 -0
  92. package/dist/index.js +93 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/items-accordion/index.d.ts +31 -0
  95. package/dist/items-accordion/index.js +10 -0
  96. package/dist/items-accordion/index.js.map +1 -0
  97. package/dist/markdown/index.d.ts +33 -0
  98. package/dist/markdown/index.js +9 -0
  99. package/dist/markdown/index.js.map +1 -0
  100. package/dist/menu-grid/index.d.ts +21 -0
  101. package/dist/menu-grid/index.js +9 -0
  102. package/dist/menu-grid/index.js.map +1 -0
  103. package/dist/menu-grid-item/index.d.ts +53 -0
  104. package/dist/menu-grid-item/index.js +9 -0
  105. package/dist/menu-grid-item/index.js.map +1 -0
  106. package/dist/menu-item/index.d.ts +50 -0
  107. package/dist/menu-item/index.js +9 -0
  108. package/dist/menu-item/index.js.map +1 -0
  109. package/dist/promo-banner/index.d.ts +22 -0
  110. package/dist/promo-banner/index.js +10 -0
  111. package/dist/promo-banner/index.js.map +1 -0
  112. package/dist/schema/index.d.ts +72 -0
  113. package/dist/schema/index.js +75 -0
  114. package/dist/schema/index.js.map +1 -0
  115. package/dist/select/index.d.ts +77 -0
  116. package/dist/select/index.js +10 -0
  117. package/dist/select/index.js.map +1 -0
  118. package/dist/shared/icons.d.ts +77 -0
  119. package/dist/shared/icons.js +64 -0
  120. package/dist/shared/icons.js.map +1 -0
  121. package/dist/shared/styles.d.ts +90 -0
  122. package/dist/shared/styles.js +48 -0
  123. package/dist/shared/styles.js.map +1 -0
  124. package/dist/stats/index.d.ts +17 -0
  125. package/dist/stats/index.js +9 -0
  126. package/dist/stats/index.js.map +1 -0
  127. package/dist/testimonials/index.d.ts +25 -0
  128. package/dist/testimonials/index.js +10 -0
  129. package/dist/testimonials/index.js.map +1 -0
  130. package/dist/theme.css +292 -0
  131. package/dist/themes.css +65 -0
  132. package/dist/theming/index.d.ts +28 -0
  133. package/dist/theming/index.js +53 -0
  134. package/dist/theming/index.js.map +1 -0
  135. package/package.json +160 -3
@@ -0,0 +1,254 @@
1
+ import {
2
+ reducedMotionStyles
3
+ } from "./chunk-3VE6VFJ4.js";
4
+ import {
5
+ buttonResetStyles,
6
+ controlBaseStyles
7
+ } from "./chunk-RHAOQ6K4.js";
8
+ import {
9
+ __decorateClass
10
+ } from "./chunk-EUXUH3YW.js";
11
+
12
+ // src/carousel/Carousel.ts
13
+ import { LitElement, css, html, nothing } from "lit";
14
+ import { customElement, property, state } from "lit/decorators.js";
15
+ var Carousel = class extends LitElement {
16
+ constructor() {
17
+ super(...arguments);
18
+ this.autoPlay = true;
19
+ this.interval = 5e3;
20
+ this.showArrows = true;
21
+ this.showIndicators = true;
22
+ this.index = 0;
23
+ this.count = 0;
24
+ this.paused = false;
25
+ this.pause = () => {
26
+ this.paused = true;
27
+ };
28
+ this.resume = () => {
29
+ this.paused = false;
30
+ };
31
+ }
32
+ connectedCallback() {
33
+ super.connectedCallback();
34
+ this.addEventListener("mouseenter", this.pause);
35
+ this.addEventListener("mouseleave", this.resume);
36
+ this.addEventListener("focusin", this.pause);
37
+ this.addEventListener("focusout", this.resume);
38
+ }
39
+ disconnectedCallback() {
40
+ this.stopTimer();
41
+ this.removeEventListener("mouseenter", this.pause);
42
+ this.removeEventListener("mouseleave", this.resume);
43
+ this.removeEventListener("focusin", this.pause);
44
+ this.removeEventListener("focusout", this.resume);
45
+ super.disconnectedCallback();
46
+ }
47
+ updated(changed) {
48
+ if (changed.has("index") || changed.has("count")) this.syncSlides();
49
+ if (changed.has("autoPlay") || changed.has("interval") || changed.has("count")) this.restartTimer();
50
+ }
51
+ get slides() {
52
+ return this.shadowRoot?.querySelector("slot")?.assignedElements({ flatten: true }) ?? [];
53
+ }
54
+ syncSlides() {
55
+ this.slides.forEach((el, i) => el.toggleAttribute("data-st-active", i === this.index));
56
+ }
57
+ onSlotChange() {
58
+ this.count = this.slides.length;
59
+ if (this.index >= this.count) this.index = 0;
60
+ this.syncSlides();
61
+ }
62
+ stopTimer() {
63
+ if (this.timer !== void 0) clearInterval(this.timer);
64
+ this.timer = void 0;
65
+ }
66
+ restartTimer() {
67
+ this.stopTimer();
68
+ if (!this.autoPlay || this.count < 2) return;
69
+ this.timer = setInterval(() => {
70
+ if (!this.paused) this.go(this.index + 1, "next");
71
+ }, this.interval);
72
+ }
73
+ go(target, direction) {
74
+ if (this.count === 0) return;
75
+ this.setAttribute("data-direction", direction);
76
+ this.index = (target + this.count) % this.count;
77
+ this.dispatchEvent(
78
+ new CustomEvent("carousel-change", {
79
+ detail: { index: this.index },
80
+ bubbles: true,
81
+ composed: true
82
+ })
83
+ );
84
+ this.restartTimer();
85
+ }
86
+ render() {
87
+ const multiple = this.count > 1;
88
+ return html`
89
+ <slot @slotchange=${this.onSlotChange}></slot>
90
+ ${this.showArrows && multiple ? html`
91
+ <button part="nav-button prev" class="nav prev" aria-label="Previous Slide" @click=${() => this.go(this.index - 1, "prev")}>&#10094;</button>
92
+ <button part="nav-button next" class="nav next" aria-label="Next Slide" @click=${() => this.go(this.index + 1, "next")}>&#10095;</button>
93
+ ` : nothing}
94
+ ${this.showIndicators && multiple ? html`<div class="indicators" part="indicators">
95
+ ${Array.from(
96
+ { length: this.count },
97
+ (_, i) => html`
98
+ <button
99
+ part="dot"
100
+ class="dot ${i === this.index ? "active" : ""}"
101
+ aria-label="Go to slide ${i + 1}"
102
+ aria-current=${i === this.index ? "true" : "false"}
103
+ @click=${() => this.go(i, i > this.index ? "next" : "prev")}
104
+ ></button>
105
+ `
106
+ )}
107
+ </div>` : nothing}
108
+ `;
109
+ }
110
+ };
111
+ Carousel.styles = css`
112
+ ${controlBaseStyles}
113
+
114
+ :host {
115
+ display: block;
116
+ position: relative;
117
+ width: 100%;
118
+ overflow: hidden;
119
+ }
120
+
121
+ ::slotted(*) {
122
+ display: none !important;
123
+ }
124
+
125
+ ::slotted([data-st-active]) {
126
+ display: block !important;
127
+ animation: st-carousel-in-next 0.4s ease both;
128
+ }
129
+
130
+ :host([data-direction='prev']) ::slotted([data-st-active]) {
131
+ animation-name: st-carousel-in-prev;
132
+ }
133
+
134
+ @keyframes st-carousel-in-next {
135
+ from {
136
+ transform: translateX(10%);
137
+ opacity: 0;
138
+ }
139
+ to {
140
+ transform: none;
141
+ opacity: 1;
142
+ }
143
+ }
144
+
145
+ @keyframes st-carousel-in-prev {
146
+ from {
147
+ transform: translateX(-10%);
148
+ opacity: 0;
149
+ }
150
+ to {
151
+ transform: none;
152
+ opacity: 1;
153
+ }
154
+ }
155
+
156
+ .nav {
157
+ ${buttonResetStyles}
158
+ position: absolute;
159
+ top: 50%;
160
+ transform: translateY(-50%);
161
+ z-index: 10;
162
+ display: flex;
163
+ align-items: center;
164
+ justify-content: center;
165
+ width: var(--st-size-38);
166
+ height: var(--st-size-38);
167
+ border-radius: var(--st-radius-circle);
168
+ border: 1px solid var(--st-color-border);
169
+ background: var(--st-color-surface);
170
+ color: var(--st-color-text-strong);
171
+ font-size: var(--st-text-xl);
172
+ opacity: 0.8;
173
+ transition:
174
+ opacity 0.3s ease,
175
+ transform 0.3s ease;
176
+ }
177
+
178
+ .nav:hover {
179
+ opacity: 1;
180
+ transform: translateY(-50%) scale(1.1);
181
+ }
182
+
183
+ .prev {
184
+ left: var(--st-space-12);
185
+ }
186
+
187
+ .next {
188
+ right: var(--st-space-12);
189
+ }
190
+
191
+ .indicators {
192
+ position: absolute;
193
+ bottom: var(--st-space-24);
194
+ left: 50%;
195
+ transform: translateX(-50%);
196
+ z-index: 10;
197
+ display: flex;
198
+ gap: var(--st-space-12);
199
+ }
200
+
201
+ .dot {
202
+ ${buttonResetStyles}
203
+ width: var(--st-space-12);
204
+ height: var(--st-space-12);
205
+ padding: 0;
206
+ border-radius: var(--st-radius-circle);
207
+ background: var(--st-color-border-strong);
208
+ transition:
209
+ background 0.3s ease,
210
+ transform 0.3s ease;
211
+ }
212
+
213
+ .dot:hover {
214
+ background: var(--st-color-text-muted);
215
+ }
216
+
217
+ .dot.active {
218
+ background: var(--st-color-text-strong);
219
+ transform: scale(1.2);
220
+ }
221
+
222
+ ${reducedMotionStyles}
223
+ @media (prefers-reduced-motion: reduce) {
224
+ ::slotted([data-st-active]) {
225
+ animation: none;
226
+ }
227
+ }
228
+ `;
229
+ __decorateClass([
230
+ property({ type: Boolean, attribute: "auto-play" })
231
+ ], Carousel.prototype, "autoPlay", 2);
232
+ __decorateClass([
233
+ property({ type: Number })
234
+ ], Carousel.prototype, "interval", 2);
235
+ __decorateClass([
236
+ property({ type: Boolean, attribute: "show-arrows" })
237
+ ], Carousel.prototype, "showArrows", 2);
238
+ __decorateClass([
239
+ property({ type: Boolean, attribute: "show-indicators" })
240
+ ], Carousel.prototype, "showIndicators", 2);
241
+ __decorateClass([
242
+ state()
243
+ ], Carousel.prototype, "index", 2);
244
+ __decorateClass([
245
+ state()
246
+ ], Carousel.prototype, "count", 2);
247
+ Carousel = __decorateClass([
248
+ customElement("st-carousel")
249
+ ], Carousel);
250
+
251
+ export {
252
+ Carousel
253
+ };
254
+ //# sourceMappingURL=chunk-XHBC23TV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/carousel/Carousel.ts"],"sourcesContent":["import { LitElement, css, html, nothing } from 'lit';\r\nimport { customElement, property, state } from 'lit/decorators.js';\r\n\r\nimport { buttonResetStyles, controlBaseStyles } from '../shared/styles';\r\nimport { reducedMotionStyles } from '../shared/section-styles';\r\nimport type { CarouselChangeEventDetail } from './CarouselEvents';\r\n\r\n/**\r\n * Cycles through its slotted children, one visible at a time, with optional autoplay, arrows and\r\n * dot indicators. The incoming slide slides in from the travel direction (CSS keyframes in place\r\n * of the source's framer-motion spring). Autoplay pauses while hovered or focused and stops when\r\n * the element is disconnected.\r\n */\r\n@customElement('st-carousel')\r\nexport class Carousel extends LitElement {\r\n static styles = css`\r\n ${controlBaseStyles}\r\n\r\n :host {\r\n display: block;\r\n position: relative;\r\n width: 100%;\r\n overflow: hidden;\r\n }\r\n\r\n ::slotted(*) {\r\n display: none !important;\r\n }\r\n\r\n ::slotted([data-st-active]) {\r\n display: block !important;\r\n animation: st-carousel-in-next 0.4s ease both;\r\n }\r\n\r\n :host([data-direction='prev']) ::slotted([data-st-active]) {\r\n animation-name: st-carousel-in-prev;\r\n }\r\n\r\n @keyframes st-carousel-in-next {\r\n from {\r\n transform: translateX(10%);\r\n opacity: 0;\r\n }\r\n to {\r\n transform: none;\r\n opacity: 1;\r\n }\r\n }\r\n\r\n @keyframes st-carousel-in-prev {\r\n from {\r\n transform: translateX(-10%);\r\n opacity: 0;\r\n }\r\n to {\r\n transform: none;\r\n opacity: 1;\r\n }\r\n }\r\n\r\n .nav {\r\n ${buttonResetStyles}\r\n position: absolute;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n z-index: 10;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: var(--st-size-38);\r\n height: var(--st-size-38);\r\n border-radius: var(--st-radius-circle);\r\n border: 1px solid var(--st-color-border);\r\n background: var(--st-color-surface);\r\n color: var(--st-color-text-strong);\r\n font-size: var(--st-text-xl);\r\n opacity: 0.8;\r\n transition:\r\n opacity 0.3s ease,\r\n transform 0.3s ease;\r\n }\r\n\r\n .nav:hover {\r\n opacity: 1;\r\n transform: translateY(-50%) scale(1.1);\r\n }\r\n\r\n .prev {\r\n left: var(--st-space-12);\r\n }\r\n\r\n .next {\r\n right: var(--st-space-12);\r\n }\r\n\r\n .indicators {\r\n position: absolute;\r\n bottom: var(--st-space-24);\r\n left: 50%;\r\n transform: translateX(-50%);\r\n z-index: 10;\r\n display: flex;\r\n gap: var(--st-space-12);\r\n }\r\n\r\n .dot {\r\n ${buttonResetStyles}\r\n width: var(--st-space-12);\r\n height: var(--st-space-12);\r\n padding: 0;\r\n border-radius: var(--st-radius-circle);\r\n background: var(--st-color-border-strong);\r\n transition:\r\n background 0.3s ease,\r\n transform 0.3s ease;\r\n }\r\n\r\n .dot:hover {\r\n background: var(--st-color-text-muted);\r\n }\r\n\r\n .dot.active {\r\n background: var(--st-color-text-strong);\r\n transform: scale(1.2);\r\n }\r\n\r\n ${reducedMotionStyles}\r\n @media (prefers-reduced-motion: reduce) {\r\n ::slotted([data-st-active]) {\r\n animation: none;\r\n }\r\n }\r\n `;\r\n\r\n @property({ type: Boolean, attribute: 'auto-play' })\r\n autoPlay = true;\r\n\r\n /** Autoplay delay in milliseconds. */\r\n @property({ type: Number })\r\n interval = 5000;\r\n\r\n @property({ type: Boolean, attribute: 'show-arrows' })\r\n showArrows = true;\r\n\r\n @property({ type: Boolean, attribute: 'show-indicators' })\r\n showIndicators = true;\r\n\r\n @state() private index = 0;\r\n @state() private count = 0;\r\n private paused = false;\r\n private timer?: ReturnType<typeof setInterval>;\r\n\r\n connectedCallback() {\r\n super.connectedCallback();\r\n this.addEventListener('mouseenter', this.pause);\r\n this.addEventListener('mouseleave', this.resume);\r\n this.addEventListener('focusin', this.pause);\r\n this.addEventListener('focusout', this.resume);\r\n }\r\n\r\n disconnectedCallback() {\r\n this.stopTimer();\r\n this.removeEventListener('mouseenter', this.pause);\r\n this.removeEventListener('mouseleave', this.resume);\r\n this.removeEventListener('focusin', this.pause);\r\n this.removeEventListener('focusout', this.resume);\r\n super.disconnectedCallback();\r\n }\r\n\r\n protected updated(changed: Map<string, unknown>) {\r\n if (changed.has('index') || changed.has('count')) this.syncSlides();\r\n if (changed.has('autoPlay') || changed.has('interval') || changed.has('count')) this.restartTimer();\r\n }\r\n\r\n private pause = () => {\r\n this.paused = true;\r\n };\r\n\r\n private resume = () => {\r\n this.paused = false;\r\n };\r\n\r\n private get slides(): Element[] {\r\n return this.shadowRoot?.querySelector('slot')?.assignedElements({ flatten: true }) ?? [];\r\n }\r\n\r\n private syncSlides() {\r\n this.slides.forEach((el, i) => el.toggleAttribute('data-st-active', i === this.index));\r\n }\r\n\r\n private onSlotChange() {\r\n this.count = this.slides.length;\r\n if (this.index >= this.count) this.index = 0;\r\n this.syncSlides();\r\n }\r\n\r\n private stopTimer() {\r\n if (this.timer !== undefined) clearInterval(this.timer);\r\n this.timer = undefined;\r\n }\r\n\r\n private restartTimer() {\r\n this.stopTimer();\r\n if (!this.autoPlay || this.count < 2) return;\r\n this.timer = setInterval(() => {\r\n if (!this.paused) this.go(this.index + 1, 'next');\r\n }, this.interval);\r\n }\r\n\r\n private go(target: number, direction: 'next' | 'prev') {\r\n if (this.count === 0) return;\r\n this.setAttribute('data-direction', direction);\r\n this.index = (target + this.count) % this.count;\r\n this.dispatchEvent(\r\n new CustomEvent<CarouselChangeEventDetail>('carousel-change', {\r\n detail: { index: this.index },\r\n bubbles: true,\r\n composed: true,\r\n }),\r\n );\r\n this.restartTimer();\r\n }\r\n\r\n render() {\r\n const multiple = this.count > 1;\r\n return html`\r\n <slot @slotchange=${this.onSlotChange}></slot>\r\n ${this.showArrows && multiple\r\n ? html`\r\n <button part=\"nav-button prev\" class=\"nav prev\" aria-label=\"Previous Slide\" @click=${() => this.go(this.index - 1, 'prev')}>&#10094;</button>\r\n <button part=\"nav-button next\" class=\"nav next\" aria-label=\"Next Slide\" @click=${() => this.go(this.index + 1, 'next')}>&#10095;</button>\r\n `\r\n : nothing}\r\n ${this.showIndicators && multiple\r\n ? html`<div class=\"indicators\" part=\"indicators\">\r\n ${Array.from(\r\n { length: this.count },\r\n (_, i) => html`\r\n <button\r\n part=\"dot\"\r\n class=\"dot ${i === this.index ? 'active' : ''}\"\r\n aria-label=\"Go to slide ${i + 1}\"\r\n aria-current=${i === this.index ? 'true' : 'false'}\r\n @click=${() => this.go(i, i > this.index ? 'next' : 'prev')}\r\n ></button>\r\n `,\r\n )}\r\n </div>`\r\n : nothing}\r\n `;\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
@@ -0,0 +1,70 @@
1
+ import {
2
+ buttonResetStyles,
3
+ controlBaseStyles,
4
+ rootFontFamilyStyles
5
+ } from "./chunk-RHAOQ6K4.js";
6
+ import {
7
+ __decorateClass
8
+ } from "./chunk-EUXUH3YW.js";
9
+
10
+ // src/icon-button/IconButton.ts
11
+ import { LitElement, css, html } from "lit";
12
+ import { customElement, property } from "lit/decorators.js";
13
+ var IconButton = class extends LitElement {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.label = "";
17
+ this.disabled = false;
18
+ }
19
+ render() {
20
+ return html`
21
+ <button part="button" type="button" aria-label=${this.label} title=${this.label} ?disabled=${this.disabled}>
22
+ <slot></slot>
23
+ </button>
24
+ `;
25
+ }
26
+ };
27
+ IconButton.styles = css`
28
+ ${controlBaseStyles}
29
+
30
+ :host {
31
+ display: inline-flex;
32
+ ${rootFontFamilyStyles}
33
+ }
34
+
35
+ button {
36
+ ${buttonResetStyles}
37
+ display: inline-flex;
38
+ align-items: center;
39
+ justify-content: center;
40
+ width: var(--st-size-32);
41
+ height: var(--st-size-32);
42
+ border-radius: var(--st-radius-sm);
43
+ color: var(--st-color-text-muted);
44
+ }
45
+
46
+ button:hover {
47
+ background: var(--st-color-hover);
48
+ color: var(--st-color-text-strong);
49
+ }
50
+
51
+ :host([disabled]) button {
52
+ color: var(--st-color-text-muted);
53
+ cursor: not-allowed;
54
+ pointer-events: none;
55
+ }
56
+ `;
57
+ __decorateClass([
58
+ property({ type: String })
59
+ ], IconButton.prototype, "label", 2);
60
+ __decorateClass([
61
+ property({ type: Boolean, reflect: true })
62
+ ], IconButton.prototype, "disabled", 2);
63
+ IconButton = __decorateClass([
64
+ customElement("st-icon-button")
65
+ ], IconButton);
66
+
67
+ export {
68
+ IconButton
69
+ };
70
+ //# sourceMappingURL=chunk-XXPBFHWR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/icon-button/IconButton.ts"],"sourcesContent":["import { LitElement, css, html } from 'lit';\r\nimport { customElement, property } from 'lit/decorators.js';\r\n\r\nimport { buttonResetStyles, controlBaseStyles, rootFontFamilyStyles } from '../shared/styles';\r\n\r\n/**\r\n * A small, icon-only action button — ported from `SankhyaUI`'s React `IconButton` (a separate,\r\n * unrelated marketing-site project; that source takes an iconify string `icon` prop, this package\r\n * has no iconify dependency, so the icon is default-slotted content instead, same convention as\r\n * `st-dropdown`/`st-menu-grid-item`'s `slot=\"icon\"`).\r\n *\r\n * Fires a plain native `click` — no custom event, since a caller just wants an ordinary button.\r\n */\r\n@customElement('st-icon-button')\r\nexport class IconButton extends LitElement {\r\n static styles = css`\r\n ${controlBaseStyles}\r\n\r\n :host {\r\n display: inline-flex;\r\n ${rootFontFamilyStyles}\r\n }\r\n\r\n button {\r\n ${buttonResetStyles}\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: var(--st-size-32);\r\n height: var(--st-size-32);\r\n border-radius: var(--st-radius-sm);\r\n color: var(--st-color-text-muted);\r\n }\r\n\r\n button:hover {\r\n background: var(--st-color-hover);\r\n color: var(--st-color-text-strong);\r\n }\r\n\r\n :host([disabled]) button {\r\n color: var(--st-color-text-muted);\r\n cursor: not-allowed;\r\n pointer-events: none;\r\n }\r\n `;\r\n\r\n /** Accessible name and tooltip — matches the source component's `ariaLabel` (renamed: modern\r\n * browsers already expose a native `ariaLabel` reflected property on every `Element`, so reusing\r\n * that exact name as a Lit reactive property would shadow it). Required for a control with no\r\n * visible text. */\r\n @property({ type: String })\r\n label = '';\r\n\r\n @property({ type: Boolean, reflect: true })\r\n disabled = false;\r\n\r\n render() {\r\n return html`\r\n <button part=\"button\" type=\"button\" aria-label=${this.label} title=${this.label} ?disabled=${this.disabled}>\r\n <slot></slot>\r\n </button>\r\n `;\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;AAAA,SAAS,YAAY,KAAK,YAAY;AACtC,SAAS,eAAe,gBAAgB;AAajC,IAAM,aAAN,cAAyB,WAAW;AAAA,EAApC;AAAA;AAqCL,iBAAQ;AAGR,oBAAW;AAAA;AAAA,EAEX,SAAS;AACP,WAAO;AAAA,uDAC4C,KAAK,KAAK,UAAU,KAAK,KAAK,cAAc,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA,EAI9G;AACF;AAjDa,WACJ,SAAS;AAAA,MACZ,iBAAiB;AAAA;AAAA;AAAA;AAAA,QAIf,oBAAoB;AAAA;AAAA;AAAA;AAAA,QAIpB,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BvB;AAAA,EADC,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GApCf,WAqCX;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,GAvC/B,WAwCX;AAxCW,aAAN;AAAA,EADN,cAAc,gBAAgB;AAAA,GAClB;","names":[]}
@@ -0,0 +1,299 @@
1
+ import {
2
+ controlBaseStyles,
3
+ rootFontFamilyStyles
4
+ } from "./chunk-RHAOQ6K4.js";
5
+ import {
6
+ __decorateClass
7
+ } from "./chunk-EUXUH3YW.js";
8
+
9
+ // src/footer/Footer.ts
10
+ import { LitElement, css, html, nothing } from "lit";
11
+ import { customElement, property } from "lit/decorators.js";
12
+ import "iconify-icon";
13
+ var Footer = class extends LitElement {
14
+ constructor() {
15
+ super(...arguments);
16
+ this.inverted = false;
17
+ this.companyName = "";
18
+ this.copyright = "";
19
+ this.poweredBy = "";
20
+ this.poweredByLink = "";
21
+ this.version = "";
22
+ this.imageSrc = "";
23
+ this.description = "";
24
+ this.columns = [];
25
+ this.socialLinks = [];
26
+ }
27
+ get isSite() {
28
+ return !!(this.columns.length || this.socialLinks.length || this.description || this.imageSrc);
29
+ }
30
+ get resolvedCopyright() {
31
+ if (this.copyright) return this.copyright;
32
+ if (this.companyName) return `\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${this.companyName}`;
33
+ return `\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()}`;
34
+ }
35
+ willUpdate(changed) {
36
+ if (changed.size) this.toggleAttribute("site", this.isSite);
37
+ }
38
+ onLinkClick(event, href) {
39
+ const select = new CustomEvent("footer-link", {
40
+ detail: { href },
41
+ bubbles: true,
42
+ composed: true,
43
+ cancelable: true
44
+ });
45
+ this.dispatchEvent(select);
46
+ if (select.defaultPrevented) event.preventDefault();
47
+ }
48
+ renderLink(link) {
49
+ return /^https?:/i.test(link.href) ? html`<a part="link" class="link" href=${link.href} target="_blank" rel="noopener noreferrer">${link.label}</a>` : html`<a part="link" class="link" href=${link.href} @click=${(event) => this.onLinkClick(event, link.href)}>${link.label}</a>`;
50
+ }
51
+ renderPoweredBy() {
52
+ return this.poweredBy ? html`
53
+ <a part="powered-by" class="powered-by" href=${this.poweredByLink || "#"} target="_blank" rel="noopener noreferrer">
54
+ ${this.poweredBy}
55
+ </a>
56
+ ` : nothing;
57
+ }
58
+ renderSite() {
59
+ return html`
60
+ <div class="site" part="site">
61
+ <div class="grid">
62
+ <div class="brand" part="brand">
63
+ ${this.imageSrc || this.companyName ? html`<div class="logo">
64
+ ${this.imageSrc ? html`<img class="logo-img" src=${this.imageSrc} alt=${this.companyName || "Logo"} />` : nothing}
65
+ ${this.companyName ? html`<span>${this.companyName}</span>` : nothing}
66
+ </div>` : nothing}
67
+ ${this.description ? html`<p class="description">${this.description}</p>` : nothing}
68
+ ${this.socialLinks.length ? html`<div class="social">
69
+ ${this.socialLinks.map(
70
+ (social) => html`<a part="social" class="social-link" href=${social.href} target="_blank" rel="noopener noreferrer" aria-label=${social.icon}>
71
+ <iconify-icon icon=${social.icon} width="24" height="24"></iconify-icon>
72
+ </a>`
73
+ )}
74
+ </div>` : nothing}
75
+ </div>
76
+ ${this.columns.map(
77
+ (column) => html`<div class="column" part="column">
78
+ <h4 class="column-title">${column.title}</h4>
79
+ <div class="links">${column.links.map((link) => this.renderLink(link))}</div>
80
+ </div>`
81
+ )}
82
+ </div>
83
+ <div class="bottom" part="bottom">
84
+ <div class="bottom-text">
85
+ <span part="copyright">${this.resolvedCopyright}</span>
86
+ ${this.version ? html`<span part="version">v${this.version}</span>` : nothing} ${this.renderPoweredBy()}
87
+ </div>
88
+ </div>
89
+ </div>
90
+ `;
91
+ }
92
+ render() {
93
+ if (this.isSite) return this.renderSite();
94
+ return html`
95
+ <span part="copyright">${this.resolvedCopyright}</span>
96
+ ${this.version ? html`<span part="version">v${this.version}</span>` : nothing} ${this.renderPoweredBy()}
97
+ `;
98
+ }
99
+ };
100
+ Footer.styles = css`
101
+ ${controlBaseStyles}
102
+
103
+ :host {
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: space-between;
107
+ gap: var(--st-space-16);
108
+ flex-wrap: wrap;
109
+ /* !important on padding/border-top only: a shadow host's own :host rule always loses to ANY
110
+ * rule the consuming page has for the same property on that element, regardless of
111
+ * specificity — so a page that resets margin/padding/border on every element (e.g. Tailwind
112
+ * Preflight, which every app but Template Hub loads) silently zeroes this footer's padding
113
+ * and top border unless these two win the conflict outright via !important. */
114
+ padding: var(--st-space-16) var(--st-space-28) !important;
115
+ border-top: 1px solid var(--st-color-border) !important;
116
+ color: var(--st-color-text-muted);
117
+ font-size: var(--st-text-xs);
118
+ ${rootFontFamilyStyles}
119
+ }
120
+
121
+ .powered-by {
122
+ color: inherit;
123
+ text-decoration: none;
124
+ font-weight: var(--st-font-weight-semibold);
125
+ }
126
+
127
+ .powered-by:hover {
128
+ color: var(--st-color-text-strong);
129
+ }
130
+
131
+ :host([inverted]) {
132
+ background: var(--st-color-text-strong);
133
+ color: var(--st-color-on-solid);
134
+ border-top-color: transparent !important;
135
+ }
136
+
137
+ /* Site layout */
138
+ :host([site]) {
139
+ display: block;
140
+ padding: 64px var(--st-space-28) 32px !important;
141
+ font-size: var(--st-text-sm);
142
+ }
143
+
144
+ .site {
145
+ max-width: 1200px;
146
+ margin: 0 auto;
147
+ }
148
+
149
+ .grid {
150
+ display: grid;
151
+ grid-template-columns: 2fr repeat(3, 1fr);
152
+ gap: 64px;
153
+ margin-bottom: 64px;
154
+ }
155
+
156
+ .brand {
157
+ display: flex;
158
+ flex-direction: column;
159
+ gap: 16px;
160
+ }
161
+
162
+ .logo {
163
+ display: flex;
164
+ align-items: center;
165
+ gap: 8px;
166
+ font-size: 1.25rem;
167
+ font-weight: 700;
168
+ color: var(--st-color-text-strong);
169
+ }
170
+
171
+ .logo-img {
172
+ height: 32px;
173
+ width: auto;
174
+ }
175
+
176
+ .description {
177
+ margin: 0;
178
+ max-width: 300px;
179
+ line-height: 1.6;
180
+ }
181
+
182
+ .social {
183
+ display: flex;
184
+ gap: 16px;
185
+ margin-top: 16px;
186
+ }
187
+
188
+ .social-link,
189
+ .link {
190
+ color: inherit;
191
+ text-decoration: none;
192
+ transition: color 0.2s ease;
193
+ }
194
+
195
+ .social-link:hover,
196
+ .link:hover {
197
+ color: var(--st-color-text-strong);
198
+ }
199
+
200
+ .column-title {
201
+ margin: 0 0 24px;
202
+ font-size: var(--st-text-xs);
203
+ font-weight: var(--st-font-weight-semibold);
204
+ color: var(--st-color-text-strong);
205
+ text-transform: uppercase;
206
+ letter-spacing: 0.05em;
207
+ }
208
+
209
+ .links {
210
+ display: flex;
211
+ flex-direction: column;
212
+ gap: 16px;
213
+ }
214
+
215
+ .bottom {
216
+ padding-top: 32px;
217
+ border-top: 1px solid var(--st-color-border);
218
+ font-size: var(--st-text-xs);
219
+ }
220
+
221
+ .bottom-text {
222
+ display: flex;
223
+ flex-direction: column;
224
+ gap: 4px;
225
+ }
226
+
227
+ .bottom-text .powered-by {
228
+ font-size: 0.85em;
229
+ font-weight: inherit;
230
+ opacity: 0.8;
231
+ }
232
+
233
+ @media (max-width: 1024px) {
234
+ .grid {
235
+ grid-template-columns: repeat(3, 1fr);
236
+ gap: 48px;
237
+ }
238
+ }
239
+
240
+ @media (max-width: 768px) {
241
+ .grid {
242
+ grid-template-columns: 1fr;
243
+ gap: 40px;
244
+ }
245
+
246
+ .bottom {
247
+ text-align: center;
248
+ }
249
+ }
250
+
251
+ :host([site][inverted]) .logo,
252
+ :host([site][inverted]) .column-title,
253
+ :host([site][inverted]) .social-link:hover,
254
+ :host([site][inverted]) .link:hover {
255
+ color: var(--st-color-on-solid);
256
+ }
257
+
258
+ :host([site][inverted]) .bottom {
259
+ border-top-color: color-mix(in oklch, var(--st-color-on-solid) 20%, var(--st-color-text-strong));
260
+ }
261
+ `;
262
+ __decorateClass([
263
+ property({ type: Boolean, reflect: true })
264
+ ], Footer.prototype, "inverted", 2);
265
+ __decorateClass([
266
+ property({ type: String, attribute: "company-name" })
267
+ ], Footer.prototype, "companyName", 2);
268
+ __decorateClass([
269
+ property({ type: String })
270
+ ], Footer.prototype, "copyright", 2);
271
+ __decorateClass([
272
+ property({ type: String, attribute: "powered-by" })
273
+ ], Footer.prototype, "poweredBy", 2);
274
+ __decorateClass([
275
+ property({ type: String, attribute: "powered-by-link" })
276
+ ], Footer.prototype, "poweredByLink", 2);
277
+ __decorateClass([
278
+ property({ type: String })
279
+ ], Footer.prototype, "version", 2);
280
+ __decorateClass([
281
+ property({ type: String, attribute: "image-src" })
282
+ ], Footer.prototype, "imageSrc", 2);
283
+ __decorateClass([
284
+ property({ type: String })
285
+ ], Footer.prototype, "description", 2);
286
+ __decorateClass([
287
+ property({ attribute: false })
288
+ ], Footer.prototype, "columns", 2);
289
+ __decorateClass([
290
+ property({ attribute: false })
291
+ ], Footer.prototype, "socialLinks", 2);
292
+ Footer = __decorateClass([
293
+ customElement("st-footer")
294
+ ], Footer);
295
+
296
+ export {
297
+ Footer
298
+ };
299
+ //# sourceMappingURL=chunk-YYK4GQUW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/footer/Footer.ts"],"sourcesContent":["import { LitElement, PropertyValues, css, html, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport 'iconify-icon';\n\nimport { controlBaseStyles, rootFontFamilyStyles } from '../shared/styles';\n\nexport interface FooterLink {\n label: string;\n href: string;\n}\n\nexport interface FooterColumn {\n title: string;\n links: FooterLink[];\n}\n\nexport interface FooterSocialLink {\n /** Iconify icon name, e.g. `mdi:github`. */\n icon: string;\n href: string;\n}\n\n/** Fired when an internal footer link is activated — cancelable, so an SPA can `preventDefault()` and route instead. */\nexport interface FooterLinkEventDetail {\n href: string;\n}\n\n/**\n * The footer, in two layouts:\n *\n * - **Bar** (default): a copyright line plus an optional \"powered by\" link — what the suite's\n * authenticated apps use.\n * - **Site**: when `columns`, `socialLinks`, `description` or `imageSrc` is set, the footer becomes a\n * marketing-site footer — brand (logo/company name, description, social icons), link columns and a\n * bottom bar with the copyright and \"powered by\".\n *\n * Fires a cancelable `footer-link` event (detail `{ href }`) when an internal link is clicked.\n */\n@customElement('st-footer')\nexport class Footer extends LitElement {\n static styles = css`\n ${controlBaseStyles}\n\n :host {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--st-space-16);\n flex-wrap: wrap;\n /* !important on padding/border-top only: a shadow host's own :host rule always loses to ANY\n * rule the consuming page has for the same property on that element, regardless of\n * specificity — so a page that resets margin/padding/border on every element (e.g. Tailwind\n * Preflight, which every app but Template Hub loads) silently zeroes this footer's padding\n * and top border unless these two win the conflict outright via !important. */\n padding: var(--st-space-16) var(--st-space-28) !important;\n border-top: 1px solid var(--st-color-border) !important;\n color: var(--st-color-text-muted);\n font-size: var(--st-text-xs);\n ${rootFontFamilyStyles}\n }\n\n .powered-by {\n color: inherit;\n text-decoration: none;\n font-weight: var(--st-font-weight-semibold);\n }\n\n .powered-by:hover {\n color: var(--st-color-text-strong);\n }\n\n :host([inverted]) {\n background: var(--st-color-text-strong);\n color: var(--st-color-on-solid);\n border-top-color: transparent !important;\n }\n\n /* Site layout */\n :host([site]) {\n display: block;\n padding: 64px var(--st-space-28) 32px !important;\n font-size: var(--st-text-sm);\n }\n\n .site {\n max-width: 1200px;\n margin: 0 auto;\n }\n\n .grid {\n display: grid;\n grid-template-columns: 2fr repeat(3, 1fr);\n gap: 64px;\n margin-bottom: 64px;\n }\n\n .brand {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n\n .logo {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 1.25rem;\n font-weight: 700;\n color: var(--st-color-text-strong);\n }\n\n .logo-img {\n height: 32px;\n width: auto;\n }\n\n .description {\n margin: 0;\n max-width: 300px;\n line-height: 1.6;\n }\n\n .social {\n display: flex;\n gap: 16px;\n margin-top: 16px;\n }\n\n .social-link,\n .link {\n color: inherit;\n text-decoration: none;\n transition: color 0.2s ease;\n }\n\n .social-link:hover,\n .link:hover {\n color: var(--st-color-text-strong);\n }\n\n .column-title {\n margin: 0 0 24px;\n font-size: var(--st-text-xs);\n font-weight: var(--st-font-weight-semibold);\n color: var(--st-color-text-strong);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n .links {\n display: flex;\n flex-direction: column;\n gap: 16px;\n }\n\n .bottom {\n padding-top: 32px;\n border-top: 1px solid var(--st-color-border);\n font-size: var(--st-text-xs);\n }\n\n .bottom-text {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .bottom-text .powered-by {\n font-size: 0.85em;\n font-weight: inherit;\n opacity: 0.8;\n }\n\n @media (max-width: 1024px) {\n .grid {\n grid-template-columns: repeat(3, 1fr);\n gap: 48px;\n }\n }\n\n @media (max-width: 768px) {\n .grid {\n grid-template-columns: 1fr;\n gap: 40px;\n }\n\n .bottom {\n text-align: center;\n }\n }\n\n :host([site][inverted]) .logo,\n :host([site][inverted]) .column-title,\n :host([site][inverted]) .social-link:hover,\n :host([site][inverted]) .link:hover {\n color: var(--st-color-on-solid);\n }\n\n :host([site][inverted]) .bottom {\n border-top-color: color-mix(in oklch, var(--st-color-on-solid) 20%, var(--st-color-text-strong));\n }\n `;\n\n /** Inverts the footer's color roles (light-on-dark instead of dark-on-light) — matches the\n * source component's `inverted` (from its shared `BaseProps`), same as `st-header`'s. */\n @property({ type: Boolean, reflect: true })\n inverted = false;\n\n /** Used to build the default `copyright` line (`© {year} {companyName}`) when `copyright` isn't set explicitly. */\n @property({ type: String, attribute: 'company-name' })\n companyName = '';\n\n /** Overrides the default computed copyright line entirely. */\n @property({ type: String })\n copyright = '';\n\n @property({ type: String, attribute: 'powered-by' })\n poweredBy = '';\n\n @property({ type: String, attribute: 'powered-by-link' })\n poweredByLink = '';\n\n /** App version, rendered as `v{version}` after the copyright line — for apps that show their own\n * version in the footer rather than the header title. */\n @property({ type: String })\n version = '';\n\n /** Logo shown in the brand block (site layout). */\n @property({ type: String, attribute: 'image-src' })\n imageSrc = '';\n\n /** Short blurb under the logo (site layout). */\n @property({ type: String })\n description = '';\n\n /** Link columns (site layout). */\n @property({ attribute: false })\n columns: FooterColumn[] = [];\n\n /** Social icon links under the description (site layout). */\n @property({ attribute: false })\n socialLinks: FooterSocialLink[] = [];\n\n private get isSite(): boolean {\n return !!(this.columns.length || this.socialLinks.length || this.description || this.imageSrc);\n }\n\n private get resolvedCopyright(): string {\n if (this.copyright) return this.copyright;\n if (this.companyName) return `© ${new Date().getFullYear()} ${this.companyName}`;\n return `© ${new Date().getFullYear()}`;\n }\n\n protected willUpdate(changed: PropertyValues): void {\n if (changed.size) this.toggleAttribute('site', this.isSite);\n }\n\n private onLinkClick(event: MouseEvent, href: string): void {\n const select = new CustomEvent<FooterLinkEventDetail>('footer-link', {\n detail: { href },\n bubbles: true,\n composed: true,\n cancelable: true\n });\n this.dispatchEvent(select);\n if (select.defaultPrevented) event.preventDefault();\n }\n\n private renderLink(link: FooterLink) {\n return /^https?:/i.test(link.href)\n ? html`<a part=\"link\" class=\"link\" href=${link.href} target=\"_blank\" rel=\"noopener noreferrer\">${link.label}</a>`\n : html`<a part=\"link\" class=\"link\" href=${link.href} @click=${(event: MouseEvent) => this.onLinkClick(event, link.href)}>${link.label}</a>`;\n }\n\n private renderPoweredBy() {\n return this.poweredBy\n ? html`\n <a part=\"powered-by\" class=\"powered-by\" href=${this.poweredByLink || '#'} target=\"_blank\" rel=\"noopener noreferrer\">\n ${this.poweredBy}\n </a>\n `\n : nothing;\n }\n\n private renderSite() {\n return html`\n <div class=\"site\" part=\"site\">\n <div class=\"grid\">\n <div class=\"brand\" part=\"brand\">\n ${this.imageSrc || this.companyName\n ? html`<div class=\"logo\">\n ${this.imageSrc ? html`<img class=\"logo-img\" src=${this.imageSrc} alt=${this.companyName || 'Logo'} />` : nothing}\n ${this.companyName ? html`<span>${this.companyName}</span>` : nothing}\n </div>`\n : nothing}\n ${this.description ? html`<p class=\"description\">${this.description}</p>` : nothing}\n ${this.socialLinks.length\n ? html`<div class=\"social\">\n ${this.socialLinks.map(\n social => html`<a part=\"social\" class=\"social-link\" href=${social.href} target=\"_blank\" rel=\"noopener noreferrer\" aria-label=${social.icon}>\n <iconify-icon icon=${social.icon} width=\"24\" height=\"24\"></iconify-icon>\n </a>`\n )}\n </div>`\n : nothing}\n </div>\n ${this.columns.map(\n column => html`<div class=\"column\" part=\"column\">\n <h4 class=\"column-title\">${column.title}</h4>\n <div class=\"links\">${column.links.map(link => this.renderLink(link))}</div>\n </div>`\n )}\n </div>\n <div class=\"bottom\" part=\"bottom\">\n <div class=\"bottom-text\">\n <span part=\"copyright\">${this.resolvedCopyright}</span>\n ${this.version ? html`<span part=\"version\">v${this.version}</span>` : nothing} ${this.renderPoweredBy()}\n </div>\n </div>\n </div>\n `;\n }\n\n render() {\n if (this.isSite) return this.renderSite();\n return html`\n <span part=\"copyright\">${this.resolvedCopyright}</span>\n ${this.version ? html`<span part=\"version\">v${this.version}</span>` : nothing} ${this.renderPoweredBy()}\n `;\n }\n}\n"],"mappings":"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","names":[]}