@soloworks/smking-next 0.12.2 → 0.14.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.
- package/CHANGELOG.md +40 -0
- package/package.json +1 -1
- package/src/components/smking-cms.tsx +607 -28
- package/src/lib/smking-cms-styles.ts +569 -0
- package/src/lib/smking-elements-iife.ts +46 -0
- package/src/types.ts +73 -0
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUTO-GENERATED - do not edit by hand.
|
|
3
|
+
* Source: packages/shared/src/styles/cms-styles.css
|
|
4
|
+
* Sync: pnpm sync:cms-styles
|
|
5
|
+
* Hash: bf93aa1f4b52
|
|
6
|
+
*
|
|
7
|
+
* Inlined by <SmkingCms> (smking-cms.tsx) inside a
|
|
8
|
+
* <style data-smking="cms-styles"> ... </style>
|
|
9
|
+
* tag exactly once per page render. Mode A only; Mode B
|
|
10
|
+
* ("tailwind-prose") skips this entirely.
|
|
11
|
+
*/
|
|
12
|
+
export const SMKING_CMS_STYLES = `/*
|
|
13
|
+
* smking CMS — canonical block styles (Mode A "css")
|
|
14
|
+
*
|
|
15
|
+
* Single source of truth for all customer-facing CMS render styling.
|
|
16
|
+
* Consumed at build time by \`scripts/sync-cms-styles.mjs\` which emits:
|
|
17
|
+
* - packages/smking-next/src/lib/smking-cms-styles.ts (TS const)
|
|
18
|
+
* - packages/smking-laravel/resources/views/cms-styles.blade.php (Blade)
|
|
19
|
+
*
|
|
20
|
+
* The dashboard imports the same file directly via Next.js workspace
|
|
21
|
+
* alias so what the editor preview shows = what the customer site renders
|
|
22
|
+
* (WYSIWYG strict per boss original spec).
|
|
23
|
+
*
|
|
24
|
+
* Mode B (\`tailwind-prose\`) customers do NOT load this file — their
|
|
25
|
+
* Tailwind + @tailwindcss/typography plugin replaces all styles below.
|
|
26
|
+
*
|
|
27
|
+
* Namespacing rules (cross-platform parity):
|
|
28
|
+
* - All selectors are scoped to \`.smk-cms\` or \`.smk-block--*\` — no
|
|
29
|
+
* global element rules (\`h1 {}\` \`p {}\`) so SDK styles never leak
|
|
30
|
+
* into customer's other page sections.
|
|
31
|
+
* - Wrapped in \`@layer smking-cms\` so customer CSS authoring with
|
|
32
|
+
* Tailwind \`@layer base|components|utilities\` has predictable order.
|
|
33
|
+
* - Tokens on \`.smk-cms\` (CSS variables) — customer overrides via
|
|
34
|
+
* \`:root { --smk-accent: …; }\` or per-instance.
|
|
35
|
+
*
|
|
36
|
+
* Edit invariants:
|
|
37
|
+
* 1. Never write a global element selector.
|
|
38
|
+
* 2. Always declare variants via \`[data-*]\` attribute selectors — the
|
|
39
|
+
* SDK markup emits the attributes; CSS reads them. No hard-coded
|
|
40
|
+
* ratios / layouts / colors.
|
|
41
|
+
* 3. Test against Mode A's class hooks: smk-cms / smk-block--{type} /
|
|
42
|
+
* smk-hero / smk-nav / smk-nav-search / smk-carousel.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
@layer smking-cms {
|
|
46
|
+
/* ============================================================
|
|
47
|
+
Design tokens — customer overrides on :root or .smk-cms
|
|
48
|
+
============================================================ */
|
|
49
|
+
.smk-cms {
|
|
50
|
+
--smk-fg: #0a0a0a;
|
|
51
|
+
--smk-fg-muted: #525252;
|
|
52
|
+
--smk-fg-subtle: #a3a3a3;
|
|
53
|
+
--smk-bg: #fff;
|
|
54
|
+
--smk-bg-soft: #fafafa;
|
|
55
|
+
--smk-border: #e5e5e5;
|
|
56
|
+
--smk-border-strong: #d4d4d4;
|
|
57
|
+
--smk-accent: #0a0a0a;
|
|
58
|
+
--smk-accent-fg: #fff;
|
|
59
|
+
--smk-radius-sm: 6px;
|
|
60
|
+
--smk-radius-md: 10px;
|
|
61
|
+
--smk-radius-lg: 16px;
|
|
62
|
+
--smk-section-gap: 4rem;
|
|
63
|
+
--smk-font-serif: ui-serif, Georgia, "Iowan Old Style", "Apple Garamond",
|
|
64
|
+
"Times New Roman", serif;
|
|
65
|
+
--smk-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI",
|
|
66
|
+
"PingFang TC", "Noto Sans CJK TC", "Microsoft JhengHei", sans-serif;
|
|
67
|
+
}
|
|
68
|
+
@media (prefers-color-scheme: dark) {
|
|
69
|
+
.smk-cms {
|
|
70
|
+
--smk-fg: #f5f5f5;
|
|
71
|
+
--smk-fg-muted: #a3a3a3;
|
|
72
|
+
--smk-fg-subtle: #525252;
|
|
73
|
+
--smk-bg: #0a0a0a;
|
|
74
|
+
--smk-bg-soft: #171717;
|
|
75
|
+
--smk-border: #262626;
|
|
76
|
+
--smk-border-strong: #404040;
|
|
77
|
+
--smk-accent: #f5f5f5;
|
|
78
|
+
--smk-accent-fg: #0a0a0a;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* ============================================================
|
|
83
|
+
Article wrapper
|
|
84
|
+
============================================================ */
|
|
85
|
+
.smk-cms {
|
|
86
|
+
color: var(--smk-fg);
|
|
87
|
+
font-family: var(--smk-font-sans);
|
|
88
|
+
line-height: 1.7;
|
|
89
|
+
font-size: 17px;
|
|
90
|
+
max-width: 42rem;
|
|
91
|
+
margin: 0 auto;
|
|
92
|
+
padding: 3rem 1.5rem;
|
|
93
|
+
}
|
|
94
|
+
.smk-cms__title {
|
|
95
|
+
font-family: var(--smk-font-serif);
|
|
96
|
+
font-size: clamp(2rem, 5vw, 3rem);
|
|
97
|
+
font-weight: 700;
|
|
98
|
+
line-height: 1.1;
|
|
99
|
+
letter-spacing: -0.02em;
|
|
100
|
+
margin: 0 0 3rem;
|
|
101
|
+
}
|
|
102
|
+
.smk-cms > .smk-block + .smk-block {
|
|
103
|
+
margin-top: 2.5rem;
|
|
104
|
+
}
|
|
105
|
+
/* Hero edges out to wrapper bounds; other blocks stay readable column. */
|
|
106
|
+
.smk-cms > .smk-block--hero {
|
|
107
|
+
margin-left: -1.5rem;
|
|
108
|
+
margin-right: -1.5rem;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ============================================================
|
|
112
|
+
Article — Plate-rendered HTML
|
|
113
|
+
SDK emits: \`<div class="smk-block smk-block--article">{html}</div>\`
|
|
114
|
+
The inner HTML comes from Plate's serializeHtml on the SaaS side,
|
|
115
|
+
so customer SDK ships zero editor deps. Below selectors style the
|
|
116
|
+
emitted h1/h2/p/ul/blockquote etc inside the article wrapper.
|
|
117
|
+
============================================================ */
|
|
118
|
+
.smk-block--article p {
|
|
119
|
+
margin: 0 0 1.25em;
|
|
120
|
+
}
|
|
121
|
+
.smk-block--article p:last-child {
|
|
122
|
+
margin-bottom: 0;
|
|
123
|
+
}
|
|
124
|
+
.smk-block--article h1,
|
|
125
|
+
.smk-block--article h2,
|
|
126
|
+
.smk-block--article h3 {
|
|
127
|
+
font-family: var(--smk-font-serif);
|
|
128
|
+
font-weight: 700;
|
|
129
|
+
letter-spacing: -0.015em;
|
|
130
|
+
line-height: 1.2;
|
|
131
|
+
}
|
|
132
|
+
.smk-block--article h1 {
|
|
133
|
+
font-size: 2rem;
|
|
134
|
+
margin: 2em 0 0.5em;
|
|
135
|
+
}
|
|
136
|
+
.smk-block--article h2 {
|
|
137
|
+
font-size: 1.6rem;
|
|
138
|
+
margin: 1.8em 0 0.5em;
|
|
139
|
+
}
|
|
140
|
+
.smk-block--article h3 {
|
|
141
|
+
font-size: 1.25rem;
|
|
142
|
+
margin: 1.5em 0 0.5em;
|
|
143
|
+
}
|
|
144
|
+
.smk-block--article h1:first-child,
|
|
145
|
+
.smk-block--article h2:first-child,
|
|
146
|
+
.smk-block--article h3:first-child {
|
|
147
|
+
margin-top: 0;
|
|
148
|
+
}
|
|
149
|
+
.smk-block--article ul,
|
|
150
|
+
.smk-block--article ol {
|
|
151
|
+
margin: 0 0 1.25em;
|
|
152
|
+
padding-left: 1.75em;
|
|
153
|
+
}
|
|
154
|
+
.smk-block--article li {
|
|
155
|
+
margin: 0.4em 0;
|
|
156
|
+
}
|
|
157
|
+
.smk-block--article li::marker {
|
|
158
|
+
color: var(--smk-fg-subtle);
|
|
159
|
+
}
|
|
160
|
+
.smk-block--article a {
|
|
161
|
+
color: inherit;
|
|
162
|
+
text-decoration: underline;
|
|
163
|
+
text-decoration-color: var(--smk-border-strong);
|
|
164
|
+
text-underline-offset: 3px;
|
|
165
|
+
transition: text-decoration-color 0.15s;
|
|
166
|
+
}
|
|
167
|
+
.smk-block--article a:hover {
|
|
168
|
+
text-decoration-color: currentColor;
|
|
169
|
+
}
|
|
170
|
+
.smk-block--article blockquote {
|
|
171
|
+
margin: 1.5em 0;
|
|
172
|
+
padding: 0.25em 0 0.25em 1.25rem;
|
|
173
|
+
border-left: 3px solid var(--smk-border-strong);
|
|
174
|
+
color: var(--smk-fg-muted);
|
|
175
|
+
font-style: italic;
|
|
176
|
+
}
|
|
177
|
+
.smk-block--article code {
|
|
178
|
+
background: var(--smk-bg-soft);
|
|
179
|
+
padding: 0.15em 0.4em;
|
|
180
|
+
border-radius: 4px;
|
|
181
|
+
font-size: 0.9em;
|
|
182
|
+
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
183
|
+
}
|
|
184
|
+
.smk-block--article pre {
|
|
185
|
+
background: var(--smk-bg-soft);
|
|
186
|
+
padding: 1rem;
|
|
187
|
+
border-radius: var(--smk-radius-sm);
|
|
188
|
+
overflow-x: auto;
|
|
189
|
+
margin: 1.5em 0;
|
|
190
|
+
}
|
|
191
|
+
.smk-block--article pre code {
|
|
192
|
+
background: transparent;
|
|
193
|
+
padding: 0;
|
|
194
|
+
}
|
|
195
|
+
.smk-block--article img {
|
|
196
|
+
max-width: 100%;
|
|
197
|
+
height: auto;
|
|
198
|
+
border-radius: var(--smk-radius-sm);
|
|
199
|
+
margin: 1.5em 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* ============================================================
|
|
203
|
+
Hero — magazine cover banner
|
|
204
|
+
SDK emits: \`<section class="smk-block smk-block--hero smk-hero">\`
|
|
205
|
+
============================================================ */
|
|
206
|
+
.smk-hero {
|
|
207
|
+
text-align: center;
|
|
208
|
+
padding: 5rem 1.5rem 4rem;
|
|
209
|
+
background: var(--smk-bg-soft);
|
|
210
|
+
border-radius: 0;
|
|
211
|
+
margin-bottom: 3rem;
|
|
212
|
+
position: relative;
|
|
213
|
+
}
|
|
214
|
+
.smk-hero__image {
|
|
215
|
+
max-width: 100%;
|
|
216
|
+
height: auto;
|
|
217
|
+
margin: 0 auto 2rem;
|
|
218
|
+
border-radius: var(--smk-radius-md);
|
|
219
|
+
display: block;
|
|
220
|
+
}
|
|
221
|
+
.smk-hero__title {
|
|
222
|
+
font-family: var(--smk-font-serif);
|
|
223
|
+
font-size: clamp(2.25rem, 6vw, 4rem);
|
|
224
|
+
font-weight: 800;
|
|
225
|
+
line-height: 1.05;
|
|
226
|
+
letter-spacing: -0.025em;
|
|
227
|
+
margin: 0 0 1rem;
|
|
228
|
+
color: var(--smk-fg);
|
|
229
|
+
max-width: 32rem;
|
|
230
|
+
margin-inline: auto;
|
|
231
|
+
}
|
|
232
|
+
.smk-hero__subtitle {
|
|
233
|
+
color: var(--smk-fg-muted);
|
|
234
|
+
font-size: 0.95rem;
|
|
235
|
+
margin: 1.5rem auto 0;
|
|
236
|
+
max-width: 28rem;
|
|
237
|
+
letter-spacing: 0.02em;
|
|
238
|
+
}
|
|
239
|
+
.smk-hero__cta {
|
|
240
|
+
display: inline-block;
|
|
241
|
+
padding: 0.75rem 1.5rem;
|
|
242
|
+
margin-top: 2rem;
|
|
243
|
+
background: var(--smk-accent);
|
|
244
|
+
color: var(--smk-accent-fg);
|
|
245
|
+
border-radius: var(--smk-radius-sm);
|
|
246
|
+
text-decoration: none;
|
|
247
|
+
font-weight: 500;
|
|
248
|
+
font-size: 0.95rem;
|
|
249
|
+
transition: opacity 0.15s;
|
|
250
|
+
}
|
|
251
|
+
.smk-hero__cta:hover {
|
|
252
|
+
opacity: 0.85;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* ============================================================
|
|
256
|
+
Nav — recent-posts / taxonomy-list
|
|
257
|
+
SDK emits: \`<section class="smk-block smk-block--nav-{type} smk-nav {sub-class}" data-layout="list|grid|carousel">\`
|
|
258
|
+
============================================================ */
|
|
259
|
+
.smk-nav {
|
|
260
|
+
padding: 2.5rem 0;
|
|
261
|
+
border-top: 1px solid var(--smk-border);
|
|
262
|
+
}
|
|
263
|
+
.smk-nav__heading {
|
|
264
|
+
font-size: 0.75rem;
|
|
265
|
+
font-weight: 700;
|
|
266
|
+
text-transform: uppercase;
|
|
267
|
+
letter-spacing: 0.12em;
|
|
268
|
+
color: var(--smk-fg-muted);
|
|
269
|
+
margin: 0 0 1.5rem;
|
|
270
|
+
}
|
|
271
|
+
.smk-nav__list {
|
|
272
|
+
list-style: none;
|
|
273
|
+
padding: 0;
|
|
274
|
+
margin: 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/* List layout (data-layout="list") */
|
|
278
|
+
.smk-nav[data-layout="list"] .smk-nav__list {
|
|
279
|
+
display: flex;
|
|
280
|
+
flex-direction: column;
|
|
281
|
+
}
|
|
282
|
+
.smk-nav[data-layout="list"] .smk-nav__item + .smk-nav__item {
|
|
283
|
+
border-top: 1px solid var(--smk-border);
|
|
284
|
+
}
|
|
285
|
+
.smk-nav[data-layout="list"] .smk-nav__link {
|
|
286
|
+
display: flex;
|
|
287
|
+
gap: 1.25rem;
|
|
288
|
+
align-items: center;
|
|
289
|
+
padding: 1.25rem 0;
|
|
290
|
+
color: inherit;
|
|
291
|
+
text-decoration: none;
|
|
292
|
+
transition: opacity 0.15s;
|
|
293
|
+
}
|
|
294
|
+
.smk-nav[data-layout="list"] .smk-nav__thumb {
|
|
295
|
+
width: 6rem;
|
|
296
|
+
height: 6rem;
|
|
297
|
+
object-fit: cover;
|
|
298
|
+
border-radius: var(--smk-radius-sm);
|
|
299
|
+
flex-shrink: 0;
|
|
300
|
+
background: var(--smk-bg-soft);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/* Grid layout (data-layout="grid") */
|
|
304
|
+
.smk-nav[data-layout="grid"] .smk-nav__list {
|
|
305
|
+
display: grid;
|
|
306
|
+
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
307
|
+
gap: 1.25rem;
|
|
308
|
+
}
|
|
309
|
+
.smk-nav[data-layout="grid"] .smk-nav__link {
|
|
310
|
+
display: flex;
|
|
311
|
+
flex-direction: column;
|
|
312
|
+
color: inherit;
|
|
313
|
+
text-decoration: none;
|
|
314
|
+
background: var(--smk-bg);
|
|
315
|
+
border: 1px solid var(--smk-border);
|
|
316
|
+
border-radius: var(--smk-radius-md);
|
|
317
|
+
overflow: hidden;
|
|
318
|
+
transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;
|
|
319
|
+
}
|
|
320
|
+
.smk-nav[data-layout="grid"] .smk-nav__link:hover {
|
|
321
|
+
transform: translateY(-2px);
|
|
322
|
+
border-color: var(--smk-border-strong);
|
|
323
|
+
box-shadow: 0 8px 24px -8px rgb(0 0 0 / 0.12);
|
|
324
|
+
}
|
|
325
|
+
.smk-nav[data-layout="grid"] .smk-nav__thumb {
|
|
326
|
+
width: 100%;
|
|
327
|
+
aspect-ratio: 16 / 10;
|
|
328
|
+
object-fit: cover;
|
|
329
|
+
background: var(--smk-bg-soft);
|
|
330
|
+
}
|
|
331
|
+
.smk-nav[data-layout="grid"] .smk-nav__meta {
|
|
332
|
+
padding: 1rem;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/* Carousel layout (data-layout="carousel") — horizontal scroll-snap */
|
|
336
|
+
.smk-nav[data-layout="carousel"] .smk-nav__list {
|
|
337
|
+
display: grid;
|
|
338
|
+
grid-auto-flow: column;
|
|
339
|
+
grid-auto-columns: 70%;
|
|
340
|
+
gap: 1rem;
|
|
341
|
+
overflow-x: auto;
|
|
342
|
+
scroll-snap-type: x mandatory;
|
|
343
|
+
padding-bottom: 0.5rem;
|
|
344
|
+
}
|
|
345
|
+
@media (min-width: 640px) {
|
|
346
|
+
.smk-nav[data-layout="carousel"] .smk-nav__list {
|
|
347
|
+
grid-auto-columns: 40%;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
.smk-nav[data-layout="carousel"] .smk-nav__item {
|
|
351
|
+
scroll-snap-align: start;
|
|
352
|
+
background: var(--smk-bg);
|
|
353
|
+
border: 1px solid var(--smk-border);
|
|
354
|
+
border-radius: var(--smk-radius-md);
|
|
355
|
+
overflow: hidden;
|
|
356
|
+
}
|
|
357
|
+
.smk-nav[data-layout="carousel"] .smk-nav__link {
|
|
358
|
+
display: flex;
|
|
359
|
+
flex-direction: column;
|
|
360
|
+
color: inherit;
|
|
361
|
+
text-decoration: none;
|
|
362
|
+
}
|
|
363
|
+
.smk-nav[data-layout="carousel"] .smk-nav__thumb {
|
|
364
|
+
width: 100%;
|
|
365
|
+
aspect-ratio: 16 / 10;
|
|
366
|
+
object-fit: cover;
|
|
367
|
+
background: var(--smk-bg-soft);
|
|
368
|
+
}
|
|
369
|
+
.smk-nav[data-layout="carousel"] .smk-nav__meta {
|
|
370
|
+
padding: 1rem;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* Shared internals */
|
|
374
|
+
.smk-nav__link:hover {
|
|
375
|
+
opacity: 0.85;
|
|
376
|
+
}
|
|
377
|
+
.smk-nav[data-layout="grid"] .smk-nav__link:hover,
|
|
378
|
+
.smk-nav[data-layout="carousel"] .smk-nav__link:hover {
|
|
379
|
+
opacity: 1;
|
|
380
|
+
}
|
|
381
|
+
.smk-nav__meta {
|
|
382
|
+
flex: 1;
|
|
383
|
+
min-width: 0;
|
|
384
|
+
}
|
|
385
|
+
.smk-nav__title {
|
|
386
|
+
font-family: var(--smk-font-serif);
|
|
387
|
+
font-size: 1.15rem;
|
|
388
|
+
font-weight: 700;
|
|
389
|
+
line-height: 1.3;
|
|
390
|
+
margin: 0 0 0.5rem;
|
|
391
|
+
letter-spacing: -0.01em;
|
|
392
|
+
}
|
|
393
|
+
.smk-nav__excerpt {
|
|
394
|
+
font-size: 0.9rem;
|
|
395
|
+
color: var(--smk-fg-muted);
|
|
396
|
+
margin: 0;
|
|
397
|
+
line-height: 1.55;
|
|
398
|
+
display: -webkit-box;
|
|
399
|
+
-webkit-line-clamp: 2;
|
|
400
|
+
-webkit-box-orient: vertical;
|
|
401
|
+
overflow: hidden;
|
|
402
|
+
}
|
|
403
|
+
.smk-nav__date {
|
|
404
|
+
display: block;
|
|
405
|
+
font-size: 0.75rem;
|
|
406
|
+
color: var(--smk-fg-subtle);
|
|
407
|
+
margin-top: 0.6rem;
|
|
408
|
+
letter-spacing: 0.04em;
|
|
409
|
+
text-transform: uppercase;
|
|
410
|
+
}
|
|
411
|
+
.smk-nav__empty {
|
|
412
|
+
color: var(--smk-fg-subtle);
|
|
413
|
+
font-style: italic;
|
|
414
|
+
padding: 1rem 0;
|
|
415
|
+
}
|
|
416
|
+
.smk-nav__view-all {
|
|
417
|
+
display: inline-flex;
|
|
418
|
+
align-items: center;
|
|
419
|
+
gap: 0.4rem;
|
|
420
|
+
margin-top: 1.5rem;
|
|
421
|
+
color: var(--smk-accent);
|
|
422
|
+
font-size: 0.875rem;
|
|
423
|
+
font-weight: 600;
|
|
424
|
+
text-decoration: none;
|
|
425
|
+
}
|
|
426
|
+
.smk-nav__view-all::after {
|
|
427
|
+
content: "→";
|
|
428
|
+
transition: transform 0.15s;
|
|
429
|
+
}
|
|
430
|
+
.smk-nav__view-all:hover::after {
|
|
431
|
+
transform: translateX(3px);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/* ============================================================
|
|
435
|
+
Nav-search — inline filter input
|
|
436
|
+
SDK emits: \`<section class="smk-block smk-block--nav-search smk-nav-search">\`
|
|
437
|
+
with \`data-smk-search-input\` / \`data-smk-search-results\` /
|
|
438
|
+
\`data-smk-search-empty\` attributes the IIFE wires up.
|
|
439
|
+
============================================================ */
|
|
440
|
+
.smk-nav-search {
|
|
441
|
+
padding: 2rem 0;
|
|
442
|
+
border-top: 1px solid var(--smk-border);
|
|
443
|
+
}
|
|
444
|
+
.smk-nav-search__shell {
|
|
445
|
+
position: relative;
|
|
446
|
+
}
|
|
447
|
+
.smk-nav-search__input {
|
|
448
|
+
width: 100%;
|
|
449
|
+
padding: 0.875rem 1.125rem;
|
|
450
|
+
border: 1px solid var(--smk-border);
|
|
451
|
+
border-radius: var(--smk-radius-md);
|
|
452
|
+
background: var(--smk-bg);
|
|
453
|
+
color: var(--smk-fg);
|
|
454
|
+
font-size: 1rem;
|
|
455
|
+
font-family: inherit;
|
|
456
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
457
|
+
}
|
|
458
|
+
.smk-nav-search__input::placeholder {
|
|
459
|
+
color: var(--smk-fg-subtle);
|
|
460
|
+
}
|
|
461
|
+
.smk-nav-search__input:focus {
|
|
462
|
+
outline: none;
|
|
463
|
+
border-color: var(--smk-fg);
|
|
464
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, var(--smk-fg) 8%, transparent);
|
|
465
|
+
}
|
|
466
|
+
.smk-nav-search__list {
|
|
467
|
+
list-style: none;
|
|
468
|
+
padding: 0;
|
|
469
|
+
margin: 0.75rem 0 0;
|
|
470
|
+
border: 1px solid var(--smk-border);
|
|
471
|
+
border-radius: var(--smk-radius-md);
|
|
472
|
+
background: var(--smk-bg);
|
|
473
|
+
overflow: hidden;
|
|
474
|
+
box-shadow: 0 4px 12px -4px rgb(0 0 0 / 0.1);
|
|
475
|
+
}
|
|
476
|
+
.smk-nav-search__result + .smk-nav-search__result {
|
|
477
|
+
border-top: 1px solid var(--smk-border);
|
|
478
|
+
}
|
|
479
|
+
.smk-nav-search__result a {
|
|
480
|
+
display: block;
|
|
481
|
+
padding: 0.875rem 1.125rem;
|
|
482
|
+
color: var(--smk-fg);
|
|
483
|
+
text-decoration: none;
|
|
484
|
+
transition: background 0.1s;
|
|
485
|
+
}
|
|
486
|
+
.smk-nav-search__result a:hover {
|
|
487
|
+
background: var(--smk-bg-soft);
|
|
488
|
+
}
|
|
489
|
+
.smk-nav-search__empty {
|
|
490
|
+
color: var(--smk-fg-subtle);
|
|
491
|
+
padding: 1rem 0 0;
|
|
492
|
+
font-size: 0.9rem;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* ============================================================
|
|
496
|
+
Carousel — \`data-aspect\` token-driven aspect-ratio
|
|
497
|
+
SDK emits: \`<section class="smk-block smk-block--carousel smk-carousel"
|
|
498
|
+
data-aspect="16:9|4:3|1:1|3:4|9:16">\`
|
|
499
|
+
5 aspect ratio variants — picked by the editor's settings popover,
|
|
500
|
+
written into props.aspectRatio, surfaced as data-aspect attr by
|
|
501
|
+
SDK render. All variant CSS lives below — image / slide both consume
|
|
502
|
+
the same --smk-carousel-aspect token.
|
|
503
|
+
============================================================ */
|
|
504
|
+
.smk-carousel {
|
|
505
|
+
margin: 2.5rem 0;
|
|
506
|
+
--smk-carousel-aspect: 16 / 9;
|
|
507
|
+
}
|
|
508
|
+
.smk-carousel[data-aspect="4:3"] {
|
|
509
|
+
--smk-carousel-aspect: 4 / 3;
|
|
510
|
+
}
|
|
511
|
+
.smk-carousel[data-aspect="1:1"] {
|
|
512
|
+
--smk-carousel-aspect: 1 / 1;
|
|
513
|
+
}
|
|
514
|
+
.smk-carousel[data-aspect="3:4"] {
|
|
515
|
+
--smk-carousel-aspect: 3 / 4;
|
|
516
|
+
}
|
|
517
|
+
.smk-carousel[data-aspect="9:16"] {
|
|
518
|
+
--smk-carousel-aspect: 9 / 16;
|
|
519
|
+
}
|
|
520
|
+
.smk-carousel__viewport {
|
|
521
|
+
display: grid;
|
|
522
|
+
grid-auto-flow: column;
|
|
523
|
+
grid-auto-columns: 80%;
|
|
524
|
+
gap: 1rem;
|
|
525
|
+
overflow-x: auto;
|
|
526
|
+
scroll-snap-type: x mandatory;
|
|
527
|
+
-webkit-overflow-scrolling: touch;
|
|
528
|
+
padding-bottom: 0.5rem;
|
|
529
|
+
margin-inline: -1.5rem;
|
|
530
|
+
padding-inline: 1.5rem;
|
|
531
|
+
}
|
|
532
|
+
@media (min-width: 640px) {
|
|
533
|
+
.smk-carousel__viewport {
|
|
534
|
+
grid-auto-columns: 60%;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
.smk-carousel__viewport::-webkit-scrollbar {
|
|
538
|
+
height: 6px;
|
|
539
|
+
}
|
|
540
|
+
.smk-carousel__viewport::-webkit-scrollbar-thumb {
|
|
541
|
+
background: var(--smk-border-strong);
|
|
542
|
+
border-radius: 3px;
|
|
543
|
+
}
|
|
544
|
+
.smk-carousel__slide {
|
|
545
|
+
scroll-snap-align: start;
|
|
546
|
+
background: var(--smk-bg-soft);
|
|
547
|
+
border-radius: var(--smk-radius-md);
|
|
548
|
+
overflow: hidden;
|
|
549
|
+
}
|
|
550
|
+
.smk-carousel__image {
|
|
551
|
+
width: 100%;
|
|
552
|
+
aspect-ratio: var(--smk-carousel-aspect);
|
|
553
|
+
object-fit: cover;
|
|
554
|
+
display: block;
|
|
555
|
+
}
|
|
556
|
+
.smk-carousel__caption {
|
|
557
|
+
padding: 0.75rem 1rem;
|
|
558
|
+
font-size: 0.875rem;
|
|
559
|
+
color: var(--smk-fg-muted);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/* ============================================================
|
|
563
|
+
Unknown block — forward-compat fallback
|
|
564
|
+
============================================================ */
|
|
565
|
+
.smk-block--unknown {
|
|
566
|
+
display: none;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
`;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IIFE source for `<smking-carousel>` + `<smking-slide>` Web Component
|
|
3
|
+
* registration. The Next.js SDK inlines this as a `<script>` tag once
|
|
4
|
+
* per page so customer sites get the carousel interactivity without
|
|
5
|
+
* adding a `<script src>` to their layout.
|
|
6
|
+
*
|
|
7
|
+
* Idempotent: the IIFE guards each `customElements.define` call with a
|
|
8
|
+
* `customElements.get(...)` check, so multiple emits per page are
|
|
9
|
+
* harmless.
|
|
10
|
+
*
|
|
11
|
+
* Keep this string in sync with
|
|
12
|
+
* `apps/web/src/features/cms/sdk/smking-elements.ts` — the SaaS-side
|
|
13
|
+
* Plate editor imports the TS module directly, so both paths register
|
|
14
|
+
* the same runtime.
|
|
15
|
+
*/
|
|
16
|
+
export const SMKING_ELEMENTS_IIFE = `(function(){if(typeof window==="undefined"||typeof customElements==="undefined")return;
|
|
17
|
+
var C="smking-carousel",S="smking-slide";
|
|
18
|
+
if(customElements.get(C))return;
|
|
19
|
+
function nextFrame(cb){if(typeof requestAnimationFrame!=="undefined")return requestAnimationFrame(cb);return setTimeout(cb,16);}
|
|
20
|
+
function cancelFrame(id){if(typeof cancelAnimationFrame!=="undefined")return cancelAnimationFrame(id);return clearTimeout(id);}
|
|
21
|
+
function CarouselEl(){return Reflect.construct(HTMLElement,[],CarouselEl);}
|
|
22
|
+
CarouselEl.prototype=Object.create(HTMLElement.prototype);
|
|
23
|
+
CarouselEl.prototype.constructor=CarouselEl;
|
|
24
|
+
CarouselEl.prototype.connectedCallback=function(){var self=this;
|
|
25
|
+
var viewport=self.querySelector(".smk-carousel__viewport");
|
|
26
|
+
if(!viewport)return;
|
|
27
|
+
var dotsContainer=self.querySelector(".smk-carousel__dots");
|
|
28
|
+
var prevBtn=self.querySelector(".smk-carousel__nav-prev");
|
|
29
|
+
var nextBtn=self.querySelector(".smk-carousel__nav-next");
|
|
30
|
+
var slides=Array.prototype.slice.call(viewport.querySelectorAll(":scope > "+S));
|
|
31
|
+
if(dotsContainer){var dotEls=slides.map(function(_,i){var d=document.createElement("button");d.type="button";d.className="smk-carousel__dot";d.dataset.index=String(i);d.setAttribute("aria-label","Go to slide "+(i+1));if(i===0)d.setAttribute("aria-current","true");d.addEventListener("click",function(e){e.preventDefault();viewport.scrollTo({left:i*viewport.clientWidth,behavior:"smooth"});});return d;});dotsContainer.replaceChildren.apply(dotsContainer,dotEls);}
|
|
32
|
+
function onPrev(e){e.preventDefault();viewport.scrollBy({left:-viewport.clientWidth,behavior:"smooth"});}
|
|
33
|
+
function onNext(e){e.preventDefault();viewport.scrollBy({left:viewport.clientWidth,behavior:"smooth"});}
|
|
34
|
+
if(prevBtn)prevBtn.addEventListener("click",onPrev);
|
|
35
|
+
if(nextBtn)nextBtn.addEventListener("click",onNext);
|
|
36
|
+
var raf=0;
|
|
37
|
+
function onScroll(){if(raf)return;raf=nextFrame(function(){raf=0;var ai=Math.round(viewport.scrollLeft/Math.max(1,viewport.clientWidth));if(!dotsContainer)return;var dots=dotsContainer.querySelectorAll(".smk-carousel__dot");dots.forEach(function(d,i){if(i===ai)d.setAttribute("aria-current","true");else d.removeAttribute("aria-current");});});}
|
|
38
|
+
viewport.addEventListener("scroll",onScroll,{passive:true});
|
|
39
|
+
self._smkCleanup=function(){if(prevBtn)prevBtn.removeEventListener("click",onPrev);if(nextBtn)nextBtn.removeEventListener("click",onNext);viewport.removeEventListener("scroll",onScroll);if(raf)cancelFrame(raf);};};
|
|
40
|
+
CarouselEl.prototype.disconnectedCallback=function(){if(this._smkCleanup)this._smkCleanup();};
|
|
41
|
+
function SlideEl(){return Reflect.construct(HTMLElement,[],SlideEl);}
|
|
42
|
+
SlideEl.prototype=Object.create(HTMLElement.prototype);
|
|
43
|
+
SlideEl.prototype.constructor=SlideEl;
|
|
44
|
+
customElements.define(C,CarouselEl);
|
|
45
|
+
customElements.define(S,SlideEl);
|
|
46
|
+
})();`;
|