@vettvangur/design-system 0.0.1

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 (37) hide show
  1. package/LICENSE +11 -0
  2. package/README.md +18 -0
  3. package/dist/generate-astro-AcegHzWG.js +476 -0
  4. package/dist/generate-astro-B225JTMY.js +534 -0
  5. package/dist/generate-astro-Btr2jiyr.js +389 -0
  6. package/dist/generate-astro-CpNCOn_3.js +475 -0
  7. package/dist/generate-astro-CqXZcTfi.js +820 -0
  8. package/dist/generate-astro-D-FcwrAx.js +819 -0
  9. package/dist/generate-astro-DfaWTEF_.js +539 -0
  10. package/dist/generate-astro-DwBkft4p.js +820 -0
  11. package/dist/generate-razor--hJCWG13.js +454 -0
  12. package/dist/generate-razor-B0Pid10L.js +441 -0
  13. package/dist/generate-razor-B0n9FUR8.js +441 -0
  14. package/dist/generate-razor-B3a_-uDf.js +441 -0
  15. package/dist/generate-razor-BLNML3CC.js +441 -0
  16. package/dist/generate-razor-CABSDQok.js +454 -0
  17. package/dist/generate-razor-CGhqwpRL.js +413 -0
  18. package/dist/generate-razor-DcAkNKya.js +9 -0
  19. package/dist/generate-razor-DwXDvSTP.js +332 -0
  20. package/dist/generate-razor-IGs8o9fx.js +441 -0
  21. package/dist/generate-razor-nGTa0EVW.js +335 -0
  22. package/dist/generate-tailwind-16Mayr2z.js +1050 -0
  23. package/dist/generate-tailwind-BR1-fpNI.js +1056 -0
  24. package/dist/generate-tailwind-BVpI-hUx.js +1057 -0
  25. package/dist/generate-tailwind-Bd3ltCQR.js +1084 -0
  26. package/dist/generate-tailwind-BljcUYMa.js +1051 -0
  27. package/dist/generate-tailwind-BqZCEvj5.js +1049 -0
  28. package/dist/generate-tailwind-CGwQarzK.js +1059 -0
  29. package/dist/generate-tailwind-Cpb8YNNz.js +1050 -0
  30. package/dist/generate-tailwind-CtUsHnBd.js +1060 -0
  31. package/dist/generate-tailwind-DL0GEqR6.js +1050 -0
  32. package/dist/generate-tailwind-Dr3KLBMD.js +1045 -0
  33. package/dist/generate-tailwind-KzRHwyMG.js +1049 -0
  34. package/dist/generate-tailwind-VnkcDTZP.js +1049 -0
  35. package/dist/index.esm.js +58 -0
  36. package/dist/inputs-CQVgm9Do.js +439 -0
  37. package/package.json +35 -0
@@ -0,0 +1,475 @@
1
+ #!/usr/bin/env node
2
+ import { promises } from 'node:fs';
3
+ import path from 'node:path';
4
+ import 'node:url';
5
+ import process from 'node:process';
6
+ import { p as parseColors, a as parseTypography, b as parseButtons, i as inputsSpec } from './inputs-CQVgm9Do.js';
7
+
8
+ // core/astro/generate-astro.mjs
9
+ const CWD = process.cwd();
10
+
11
+ // Generated components
12
+ const OUT_DIR = path.resolve(CWD, 'src/astrobook/components');
13
+ const OUT_PREVIEW = path.join(OUT_DIR, 'Preview.astro');
14
+ const OUT_COLORS = path.join(OUT_DIR, 'Colors.astro');
15
+ const OUT_BODIES = path.join(OUT_DIR, 'Bodies.astro');
16
+ const OUT_HEADLINES = path.join(OUT_DIR, 'Headlines.astro');
17
+ const OUT_BUTTONS = path.join(OUT_DIR, 'Buttons.astro');
18
+ const OUT_INPUTS = path.join(OUT_DIR, 'Inputs.astro');
19
+ const OUT_RICHTEXT = path.join(OUT_DIR, 'Richtext.astro'); // <-- added
20
+
21
+ // Story folders
22
+ const ASTROBOOK_DIR = path.resolve(CWD, 'src/astrobook');
23
+ const OUT_DIR_TYPOGRAPHY = path.join(ASTROBOOK_DIR, 'Typography');
24
+ const OUT_DIR_UI = path.join(ASTROBOOK_DIR, 'UI');
25
+ const OUT_DIR_COLORS = path.join(ASTROBOOK_DIR, 'Colors');
26
+ async function generateAstro() {
27
+ // ensure dirs
28
+ await promises.mkdir(OUT_DIR, {
29
+ recursive: true
30
+ });
31
+ await promises.mkdir(ASTROBOOK_DIR, {
32
+ recursive: true
33
+ });
34
+ await promises.mkdir(OUT_DIR_TYPOGRAPHY, {
35
+ recursive: true
36
+ });
37
+ await promises.mkdir(OUT_DIR_UI, {
38
+ recursive: true
39
+ });
40
+ await promises.mkdir(OUT_DIR_COLORS, {
41
+ recursive: true
42
+ });
43
+
44
+ // write Preview.astro (to a FILE, not the folder)
45
+ await promises.writeFile(OUT_PREVIEW, generatePreview(), 'utf8');
46
+ console.log(`✓ Wrote ${rel(OUT_PREVIEW)} (Preview)`);
47
+
48
+ // write story files
49
+ await renderStoriesAstro();
50
+ const [colors, typography, buttons] = await Promise.all([parseColors(),
51
+ // -> [{ title, color, class }]
52
+ parseTypography(),
53
+ // -> { bodies: [...], headlines: [...] }
54
+ parseButtons() // -> [{ title, class, text }]
55
+ ]);
56
+
57
+ // Colors -> Colors.astro
58
+ if (colors?.length) {
59
+ await promises.writeFile(OUT_COLORS, renderColorsAstro(colors), 'utf8');
60
+ console.log(`✓ Wrote ${rel(OUT_COLORS)} (${colors.length} swatches)`);
61
+ } else {
62
+ console.warn('• No colors parsed — Colors.astro not written');
63
+ }
64
+
65
+ // Bodies -> Bodies.astro
66
+ if (typography?.bodies?.length) {
67
+ await promises.writeFile(OUT_BODIES, renderBodiesAstro(typography.bodies), 'utf8');
68
+ console.log(`✓ Wrote ${rel(OUT_BODIES)} (${typography.bodies.length} bodies)`);
69
+ } else {
70
+ console.warn('• No bodies parsed — Bodies.astro not written');
71
+ }
72
+
73
+ // Headlines -> Headlines.astro
74
+ if (typography?.headlines?.length) {
75
+ await promises.writeFile(OUT_HEADLINES, renderHeadlinesAstro(typography.headlines), 'utf8');
76
+ console.log(`✓ Wrote ${rel(OUT_HEADLINES)} (${typography.headlines.length} headlines)`);
77
+ } else {
78
+ console.warn('• No headlines parsed — Headlines.astro not written');
79
+ }
80
+
81
+ // Buttons -> Buttons.astro
82
+ if (buttons?.length) {
83
+ await promises.writeFile(OUT_BUTTONS, renderButtonsAstro(buttons), 'utf8');
84
+ console.log(`✓ Wrote ${rel(OUT_BUTTONS)} (${buttons.length} buttons)`);
85
+ } else {
86
+ console.warn('• No buttons parsed — Buttons.astro not written');
87
+ }
88
+
89
+ // Inputs -> Inputs.astro
90
+ const hasAnyInputs = Object.values(inputsSpec).some(arr => Array.isArray(arr) && arr.length);
91
+ if (hasAnyInputs) {
92
+ await promises.writeFile(OUT_INPUTS, renderInputsAstro(inputsSpec), 'utf8');
93
+ console.log(`✓ Wrote ${rel(OUT_INPUTS)} (inputs:${inputsSpec.inputs?.length ?? 0} selects:${inputsSpec.selects?.length ?? 0} ` + `checkboxes:${inputsSpec.checkboxes?.length ?? 0} radios:${inputsSpec.radios?.length ?? 0} textareas:${inputsSpec.textareas?.length ?? 0})`);
94
+ } else {
95
+ console.warn('• No input spec items — Inputs.astro not written');
96
+ }
97
+
98
+ // Richtext -> Richtext.astro (always write; it’s a static specimen)
99
+ await promises.writeFile(OUT_RICHTEXT, renderRichtextAstro(), 'utf8');
100
+ console.log(`✓ Wrote ${rel(OUT_RICHTEXT)} (Richtext)`);
101
+ }
102
+
103
+ /* ---------- story writers ---------- */
104
+
105
+ async function renderStoriesAstro() {
106
+ const storyBody = generateStoryBody();
107
+ const storyColors = generateStoryColors();
108
+ const storyHeadline = generateStoryHeadline();
109
+ const storyButton = generateStoryButtons();
110
+ const storyInputs = generateStoryInputs();
111
+ const storyRichtext = generateStoryRichtextAstro(); // <-- added
112
+
113
+ const FILE_BODY = path.join(OUT_DIR_TYPOGRAPHY, 'Body.stories.ts');
114
+ const FILE_HEADLINES = path.join(OUT_DIR_TYPOGRAPHY, 'Headlines.stories.ts');
115
+ const FILE_BUTTONS = path.join(OUT_DIR_UI, 'Buttons.stories.ts');
116
+ const FILE_INPUTS = path.join(OUT_DIR_UI, 'Inputs.stories.ts');
117
+ const FILE_COLORS = path.join(OUT_DIR_COLORS, 'Colors.stories.ts');
118
+ const FILE_RICHTEXT_S = path.join(OUT_DIR_TYPOGRAPHY, 'Richtext.stories.astro'); // <-- added
119
+
120
+ await promises.writeFile(FILE_BODY, storyBody, 'utf8');
121
+ await promises.writeFile(FILE_HEADLINES, storyHeadline, 'utf8');
122
+ await promises.writeFile(FILE_BUTTONS, storyButton, 'utf8');
123
+ await promises.writeFile(FILE_INPUTS, storyInputs, 'utf8');
124
+ await promises.writeFile(FILE_COLORS, storyColors, 'utf8');
125
+ await promises.writeFile(FILE_RICHTEXT_S, storyRichtext, 'utf8'); // <-- added
126
+
127
+ console.log('✓ Wrote story files:');
128
+ console.log(` - ${rel(FILE_BODY)}`);
129
+ console.log(` - ${rel(FILE_HEADLINES)}`);
130
+ console.log(` - ${rel(FILE_BUTTONS)}`);
131
+ console.log(` - ${rel(FILE_INPUTS)}`);
132
+ console.log(` - ${rel(FILE_COLORS)}`);
133
+ console.log(` - ${rel(FILE_RICHTEXT_S)}`);
134
+ }
135
+
136
+ /* ---------- code gens ---------- */
137
+
138
+ function generatePreview() {
139
+ return `
140
+ ---
141
+ /** Auto-generated - do not edit by hand */
142
+ import '@/styles/main.css'
143
+ import Fonts from '@/components/core/utility/Fonts.astro'
144
+ ---
145
+ <Fonts />
146
+ <div class="astrobook-preview bg-background">
147
+ <slot />
148
+ </div>
149
+ `.trimStart();
150
+ }
151
+ function generateStoryBody() {
152
+ return `
153
+ // Auto-generated — do not edit by hand
154
+ import Preview from '@/astrobook/components/Preview.astro'
155
+ import Bodies from '@/astrobook/components/Bodies.astro'
156
+
157
+ export default {
158
+ title: 'Typography/Body',
159
+ component: Bodies,
160
+ }
161
+
162
+ export const Overview = {
163
+ render: () => Preview({ slots: { default: Bodies({}) } }),
164
+ }
165
+ `.trimStart();
166
+ }
167
+ function generateStoryColors() {
168
+ return `
169
+ // Auto-generated — do not edit by hand
170
+ import Preview from '@/astrobook/components/Preview.astro'
171
+ import Colors from '@/astrobook/components/Colors.astro'
172
+
173
+ export default {
174
+ title: 'Colors',
175
+ component: Colors,
176
+ }
177
+
178
+ export const Overview = {
179
+ render: () => Preview({ slots: { default: Colors({}) } }),
180
+ }
181
+ `.trimStart();
182
+ }
183
+ function generateStoryHeadline() {
184
+ return `
185
+ // Auto-generated — do not edit by hand
186
+ import Preview from '@/astrobook/components/Preview.astro'
187
+ import Headlines from '@/astrobook/components/Headlines.astro'
188
+
189
+ export default {
190
+ title: 'Typography/Headlines',
191
+ component: Headlines,
192
+ }
193
+
194
+ export const Overview = {
195
+ render: () => Preview({ slots: { default: Headlines({}) } }),
196
+ }
197
+ `.trimStart();
198
+ }
199
+ function generateStoryButtons() {
200
+ return `
201
+ // Auto-generated — do not edit by hand
202
+ import Preview from '@/astrobook/components/Preview.astro'
203
+ import Buttons from '@/astrobook/components/Buttons.astro'
204
+
205
+ export default {
206
+ title: 'UI/Buttons',
207
+ component: Buttons,
208
+ }
209
+
210
+ export const Overview = {
211
+ render: () => Preview({ slots: { default: Buttons({}) } }),
212
+ }
213
+ `.trimStart();
214
+ }
215
+ function generateStoryInputs() {
216
+ return `
217
+ // Auto-generated — do not edit by hand
218
+ import Preview from '@/astrobook/components/Preview.astro'
219
+ import Inputs from '@/astrobook/components/Inputs.astro'
220
+
221
+ export default {
222
+ title: 'UI/Inputs',
223
+ component: Inputs,
224
+ }
225
+
226
+ export const Overview = {
227
+ render: () => Preview({ slots: { default: Inputs({}) } }),
228
+ }
229
+ `.trimStart();
230
+ }
231
+ function generateStoryRichtextAstro() {
232
+ return `---
233
+ /* Auto-generated — do not edit by hand */
234
+ import Preview from '@/astrobook/components/Preview.astro'
235
+ import Richtext from '@/astrobook/components/Richtext.astro'
236
+ export const title = 'Typography/Richtext'
237
+ export const component = Richtext
238
+ ---
239
+ <Preview>
240
+ <Richtext />
241
+ </Preview>
242
+ `.trimStart();
243
+ }
244
+
245
+ /* ---------- renderers ---------- */
246
+
247
+ function renderColorsAstro(colors) {
248
+ const items = colors.map(({
249
+ title,
250
+ color,
251
+ class: klass
252
+ }) => {
253
+ const style = `background:${color};`;
254
+ return `
255
+ <div class="flex items-center gap-4 p-3 rounded border border-black/10 bg-white/5">
256
+ <div class="size-10 rounded shadow-inner ring-1 ring-black/10" style="${style}"></div>
257
+ <div class="flex flex-col text-sm">
258
+ <span class="font-medium">${e(title)}</span>
259
+ <span class="opacity-70">token: <code>--color-${e(klass.replace(/^x-/, ''))}</code></span>
260
+ <span class="opacity-70">class: <code>${e(klass)}</code></span>
261
+ <span class="opacity-70">value: <code>${e(color)}</code></span>
262
+ </div>
263
+ </div>`.trim();
264
+ });
265
+ return `---
266
+ /* Auto-generated — do not edit by hand */
267
+ ---
268
+ <div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
269
+ ${items.join('\n')}
270
+ </div>
271
+ `;
272
+ }
273
+ function renderBodiesAstro(bodies) {
274
+ const items = bodies.map(b => {
275
+ const meta = metaText(b.size, b.lineheight, b.config);
276
+ return ` <p class="${a(b.class)}">${e(b.title)} ${meta}</p>`;
277
+ });
278
+ return `---
279
+ /* Auto-generated — do not edit by hand */
280
+ ---
281
+ <div class="space-y-4">
282
+ ${items.join('\n')}
283
+ </div>
284
+ `;
285
+ }
286
+ function renderHeadlinesAstro(headlines) {
287
+ const lines = headlines.map(h => {
288
+ const meta = metaText(h.size, h.lineheight, h.config);
289
+ return ` <div class="flex items-baseline gap-2">
290
+ <Headline size="2" text="${a(h.title)}" class="${a(h.class)}" />
291
+ ${meta}
292
+ </div>`;
293
+ });
294
+ return `---
295
+ /* Auto-generated — do not edit by hand */
296
+ import Headline from '@/components/core/Headline.astro'
297
+ ---
298
+ <div class="space-y-4">
299
+ ${lines.join('\n')}
300
+ </div>
301
+ `;
302
+ }
303
+ function renderButtonsAstro(buttons) {
304
+ const lines = buttons.map(b => {
305
+ const klass = b.class.trim(); // variants already @apply button; don't prepend "button"
306
+ return ` <div class="flex items-center gap-3">
307
+ <Button text="${a(b.text)}" modifier="${a(klass)}" />
308
+ <span class="text-sm opacity-70">${e(b.title)} — <code>${e(klass)}</code></span>
309
+ </div>`;
310
+ });
311
+ return `---
312
+ /* Auto-generated — do not edit by hand */
313
+ import Button from '@/components/core/button/Button.astro' /* adjust if path differs */
314
+ ---
315
+ <div class="space-y-3">
316
+ ${lines.join('\n')}
317
+ </div>
318
+ `;
319
+ }
320
+ function renderInputsAstro(spec) {
321
+ const {
322
+ inputs = [],
323
+ selects = [],
324
+ checkboxes = [],
325
+ radios = [],
326
+ textareas = []
327
+ } = spec;
328
+ const renderGroup = (title, componentTag, items) => {
329
+ if (!items?.length) {
330
+ return '';
331
+ }
332
+ const rows = items.map(obj => ` <${componentTag} ${attrs(obj)} />`).join('\n');
333
+ return `
334
+ <section>
335
+ <h3 class="text-sm opacity-70 mb-2">${e(title)}</h3>
336
+ ${rows}
337
+ </section>`;
338
+ };
339
+ return `---
340
+ /* Auto-generated — do not edit by hand */
341
+ import Input from '@/components/core/inputs/Input.astro'
342
+ import Select from '@/components/core/inputs/Select.astro'
343
+ import Selection from '@/components/core/inputs/Selection.astro'
344
+ ---
345
+ <div class="space-y-8">
346
+ ${renderGroup('Inputs', 'Input', inputs)}
347
+ ${renderGroup('Selects', 'Select', selects)}
348
+ ${renderGroup('Checkboxes', 'Selection', checkboxes)}
349
+ ${renderGroup('Radios', 'Selection', radios)}
350
+ ${renderGroup('Textareas', 'Select', textareas)}
351
+ </div>
352
+ `;
353
+ }
354
+ function renderRichtextAstro() {
355
+ return `---
356
+ /* Auto-generated — do not edit by hand */
357
+ import Headline from '@/components/core/Headline.astro'
358
+ ---
359
+ <section class="w-full">
360
+ <Headline
361
+ text="Richtext"
362
+ size="1"
363
+ class="headline-1 mb-[60px]"
364
+ />
365
+
366
+ <div class="richtext">
367
+ <h1>h1</h1>
368
+ <h2>h2</h2>
369
+ <h3>h3</h3>
370
+ <h4>h4</h4>
371
+ <h5>h5</h5>
372
+ <p>
373
+ Ófróðlegt þorviðar <a href="https://www.vettvangur.is/" target="_blank">látist kærðu</a>, allfeginn því að kaupmanni, <strong>hraðasta</strong> ættleri <em>farminum</em> þuríði brústeinunum konungsþræll grænar. Hólmganga hrísflekkur, lifum skalla-grímur tíkr. Meiðinn hatast oddleifsdóttir, dólglegast dyflini, torfafóstri torfunni rak jarðarmenið stirðir. Býsn hvé ölseljunni gerði, jafnvitur lög vaskligr, sám hvortveggja ófrelsi trúfasti hallkelsdóttur sneri mund guðmundarsonum. Sekum meginmerkurinnar, arfsali allmikilli sjaldgæf. Uggasyni sættu konungsþræll gæs, alþýðuskap orðtækið stokkar, orkar mund ormláðs skrumaði hriflusonar virðak. Biðjum meiðinn keppa, taliðr uggasyni, skerðan manngjarnlega hofgyðja vilk allmikilli. Ógott hirðum samdóma, heimamaðr endilangt, erlingur kaldur gjósa seimþollr hallkell landkaupi. Torfunni tungu-oddur þorviðar gufárós, ævifús sekur tröllskessa, umbanda rétttrúaður bráðan svörfuði nýt íþrótt dalalönd halli. Flyðruness haldnar aðsóknar skerðan, auðhnykkjanda mannvandur smálöndum sauðarhöfðinu ferjunni.
374
+ </p>
375
+ <ul>
376
+ <li>List item</li>
377
+ <li>List item</li>
378
+ <li>
379
+ List item
380
+ <ul>
381
+ <li>Nested item</li>
382
+ <li>Nested item</li>
383
+ <li>
384
+ Nested item
385
+ <ul>
386
+ <li>Nested even more item</li>
387
+ <li>Nested even more item</li>
388
+ <li>Nested even more item</li>
389
+ </ul>
390
+ </li>
391
+ </ul>
392
+ </li>
393
+ <li>List item</li>
394
+ </ul>
395
+ <ol>
396
+ <li>List item</li>
397
+ <li>
398
+ List item
399
+ <ol>
400
+ <li>Nested item</li>
401
+ <li>Nested item</li>
402
+ <li>Nested item</li>
403
+ </ol>
404
+ </li>
405
+ <li>List item</li>
406
+ <li>List item</li>
407
+ </ol>
408
+ <p>
409
+ Ófróðlegt þorviðar <a href="https://www.vettvangur.is/" target="_blank">látist kærðu</a>, allfeginn því að kaupmanni, hraðasta ættleri farminum þuríði brústeinunum konungsþræll grænar. Hólmganga hrísflekkur, lifum skalla-grímur tíkr. Meiðinn hatast oddleifsdóttir, dólglegast dyflini, torfafóstri torfunni rak jarðarmenið stirðir. Býsn hvé ölseljunni gerði, jafnvitur lög vaskligr, sám hvortveggja ófrelsi trúfasti hallkelsdóttur sneri mund guðmundarsonum. Sekum meginmerkurinnar, arfsali allmikilli sjaldgæf. Uggasyni sættu konungsþræll gæs, alþýðuskap orðtækið stokkar, orkar mund ormláðs skrumaði hriflusonar virðak. Biðjum meiðinn keppa, taliðr uggasyni, skerðan manngjarnlega hofgyðja vilk allmikilli. Ógott hirðum samdóma, heimamaðr endilangt, erlingur kaldur gjósa seimþollr hallkell landkaupi. Torfunni tungu-oddur þorviðar gufárós, ævifús sekur tröllskessa, umbanda rétttrúaður bráðan svörfuði nýt íþrótt dalalönd halli. Flyðruness haldnar aðsóknar skerðan, auðhnykkjanda mannvandur smálöndum sauðarhöfðinu ferjunni.
410
+ </p>
411
+ </div>
412
+ </section>
413
+ `.trimStart();
414
+ }
415
+
416
+ /* ---------- helpers ---------- */
417
+
418
+ function attrs(obj = {}) {
419
+ const parts = [];
420
+ for (const [key, val] of Object.entries(obj)) {
421
+ if (val === '' || val === null || val === undefined || val === false) {
422
+ continue;
423
+ }
424
+ if (typeof val === 'string') {
425
+ parts.push(`${key}="${a(val)}"`);
426
+ } else if (typeof val === 'number') {
427
+ parts.push(`${key}={${val}}`);
428
+ } else if (typeof val === 'boolean') {
429
+ parts.push(`${key}={true}`);
430
+ } else {
431
+ parts.push(`${key}={${JSON.stringify(val)}}`);
432
+ }
433
+ }
434
+ return parts.join(' ');
435
+ }
436
+ function metaText(size, lineheight, config) {
437
+ const basePair = pair({
438
+ size,
439
+ lineHeight: lineheight
440
+ });
441
+ const parts = [];
442
+ if (config?.desktop && (config.desktop.size || config.desktop.lineHeight)) {
443
+ parts.push(`D: ${pair(config.desktop)}`);
444
+ }
445
+ if (config?.mobile && (config.mobile.size || config.mobile.lineHeight)) {
446
+ parts.push(`M: ${pair(config.mobile)}`);
447
+ }
448
+ const label = parts.length ? parts.join(' • ') : basePair;
449
+ if (!label) {
450
+ return '';
451
+ }
452
+ return `<span class="opacity-60 text-sm">${e(label)}</span>`;
453
+ }
454
+ function pair({
455
+ size,
456
+ lineHeight
457
+ } = {}) {
458
+ const s = size ?? null;
459
+ const l = lineHeight ?? null;
460
+ if (!s && !l) {
461
+ return '';
462
+ }
463
+ return `${s ?? '-'} / ${l ?? '-'}`;
464
+ }
465
+ function e(s = '') {
466
+ return String(s).replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
467
+ }
468
+ function a(s = '') {
469
+ return String(s).replaceAll('"', '&quot;');
470
+ }
471
+ function rel(p) {
472
+ return path.relative(process.cwd(), p);
473
+ }
474
+
475
+ export { generateAstro as default };