@farming-labs/svelte 0.2.45 → 0.2.47
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/dist/markdown.js +95 -20
- package/package.json +2 -2
package/dist/markdown.js
CHANGED
|
@@ -316,10 +316,41 @@ const calloutIcons = {
|
|
|
316
316
|
important: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>',
|
|
317
317
|
caution: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>',
|
|
318
318
|
};
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
319
|
+
const calloutTypeAliases = {
|
|
320
|
+
danger: "caution",
|
|
321
|
+
error: "caution",
|
|
322
|
+
info: "note",
|
|
323
|
+
success: "tip",
|
|
324
|
+
warn: "warning",
|
|
325
|
+
};
|
|
326
|
+
const calloutLabels = {
|
|
327
|
+
caution: "Caution",
|
|
328
|
+
important: "Important",
|
|
329
|
+
note: "Note",
|
|
330
|
+
tip: "Tip",
|
|
331
|
+
warning: "Warning",
|
|
332
|
+
};
|
|
333
|
+
function normalizeCalloutType(type) {
|
|
334
|
+
const normalized = type.trim().toLowerCase();
|
|
335
|
+
const aliased = calloutTypeAliases[normalized] ?? normalized;
|
|
336
|
+
return calloutIcons[aliased] ? aliased : "note";
|
|
337
|
+
}
|
|
338
|
+
function renderInlineCalloutContent(content) {
|
|
339
|
+
return content
|
|
340
|
+
.trim()
|
|
341
|
+
.replace(/`([^`]+)`/g, "<code>$1</code>")
|
|
342
|
+
.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>")
|
|
343
|
+
.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>")
|
|
344
|
+
.replace(/\*(.+?)\*/g, "<em>$1</em>")
|
|
345
|
+
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>')
|
|
346
|
+
.replace(/\n+/g, "<br />");
|
|
347
|
+
}
|
|
348
|
+
function renderCallout(type, content, title) {
|
|
349
|
+
const normalizedType = normalizeCalloutType(type);
|
|
350
|
+
const icon = calloutIcons[normalizedType] || calloutIcons.note;
|
|
351
|
+
const label = title?.trim() || calloutLabels[normalizedType] || "Note";
|
|
352
|
+
const renderedContent = renderInlineCalloutContent(content);
|
|
353
|
+
return `<div class="fd-callout fd-callout-${normalizedType}" role="note"><div class="fd-callout-indicator" role="none"></div><div class="fd-callout-icon">${icon}</div><div class="fd-callout-content"><p class="fd-callout-title">${escapeHtml(label)}</p><p>${renderedContent}</p></div></div>`;
|
|
323
354
|
}
|
|
324
355
|
function highlightCode(hl, code, lang) {
|
|
325
356
|
if (lang === "sh" || lang === "shell")
|
|
@@ -347,12 +378,6 @@ function highlightCode(hl, code, lang) {
|
|
|
347
378
|
};
|
|
348
379
|
}
|
|
349
380
|
}
|
|
350
|
-
function parseMeta(meta) {
|
|
351
|
-
const trimmed = meta.trim();
|
|
352
|
-
const lang = (trimmed.split(/\s/)[0] || "text").toLowerCase();
|
|
353
|
-
const titleMatch = trimmed.match(/\b(?:title|filename|file|name|label)=["']([^"']+)["']/);
|
|
354
|
-
return { lang, title: titleMatch ? titleMatch[1] : null };
|
|
355
|
-
}
|
|
356
381
|
const ignoredCodeGroupBareTitleTokens = new Set([
|
|
357
382
|
"copy",
|
|
358
383
|
"no-copy",
|
|
@@ -364,6 +389,25 @@ const ignoredCodeGroupBareTitleTokens = new Set([
|
|
|
364
389
|
"showlinenumbers",
|
|
365
390
|
"wrap",
|
|
366
391
|
]);
|
|
392
|
+
function parseMeta(meta) {
|
|
393
|
+
const trimmed = meta.trim();
|
|
394
|
+
const firstToken = trimmed.split(/\s+/, 1)[0] ?? "";
|
|
395
|
+
const hasLanguage = Boolean(firstToken && !firstToken.includes("=") && !firstToken.startsWith("{"));
|
|
396
|
+
const lang = hasLanguage ? firstToken.toLowerCase() : "text";
|
|
397
|
+
const titleMatch = trimmed.match(/\b(?:title|filename|file|name|label)=["']([^"']+)["']/);
|
|
398
|
+
if (titleMatch)
|
|
399
|
+
return { lang, title: titleMatch[1] };
|
|
400
|
+
const bareTitle = trimmed
|
|
401
|
+
.slice(hasLanguage ? firstToken.length : 0)
|
|
402
|
+
.trim()
|
|
403
|
+
.replace(/\{[^}]*\}/g, " ")
|
|
404
|
+
.split(/\s+/)
|
|
405
|
+
.find((part) => part && !part.includes("=") && !ignoredCodeGroupBareTitleTokens.has(part.toLowerCase()));
|
|
406
|
+
return {
|
|
407
|
+
lang,
|
|
408
|
+
title: bareTitle ? bareTitle.replace(/^["']|["']$/g, "") : null,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
367
411
|
function parseCodeGroupMeta(meta) {
|
|
368
412
|
const parsed = parseMeta(meta);
|
|
369
413
|
if (parsed.title)
|
|
@@ -392,6 +436,25 @@ function createCodeGroupTabValue(label, used) {
|
|
|
392
436
|
used.add(value);
|
|
393
437
|
return value;
|
|
394
438
|
}
|
|
439
|
+
const terminalCodeLanguages = new Set([
|
|
440
|
+
"bash",
|
|
441
|
+
"console",
|
|
442
|
+
"sh",
|
|
443
|
+
"shell",
|
|
444
|
+
"shellscript",
|
|
445
|
+
"terminal",
|
|
446
|
+
]);
|
|
447
|
+
const fileCodeBlockIcon = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/></svg>';
|
|
448
|
+
const terminalCodeBlockIcon = '<svg width="14" height="14" viewBox="0 0 24 24" aria-hidden="true"><path d="m 4,4 a 1,1 0 0 0 -0.7070312,0.2929687 1,1 0 0 0 0,1.4140625 L 8.5859375,11 3.2929688,16.292969 a 1,1 0 0 0 0,1.414062 1,1 0 0 0 1.4140624,0 l 5.9999998,-6 a 1.0001,1.0001 0 0 0 0,-1.414062 L 4.7070312,4.2929687 A 1,1 0 0 0 4,4 Z m 8,14 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 h 8 a 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z" fill="currentColor"/></svg>';
|
|
449
|
+
const copyCodeBlockIcon = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/></svg>';
|
|
450
|
+
function renderCodeBlockTitleIcon(title, language) {
|
|
451
|
+
const normalizedTitle = title?.trim().toLowerCase() ?? "";
|
|
452
|
+
const normalizedLanguage = language?.trim().toLowerCase() ?? "";
|
|
453
|
+
if (normalizedTitle.includes("terminal") || terminalCodeLanguages.has(normalizedLanguage)) {
|
|
454
|
+
return terminalCodeBlockIcon;
|
|
455
|
+
}
|
|
456
|
+
return fileCodeBlockIcon;
|
|
457
|
+
}
|
|
395
458
|
function wrapCodeWithCopy(html, rawCode, title, language) {
|
|
396
459
|
const escapedRaw = rawCode
|
|
397
460
|
.replace(/&/g, "&")
|
|
@@ -399,11 +462,11 @@ function wrapCodeWithCopy(html, rawCode, title, language) {
|
|
|
399
462
|
.replace(/</g, "<")
|
|
400
463
|
.replace(/>/g, ">");
|
|
401
464
|
const dataLang = language ? ` data-language="${escapeHtml(String(language))}"` : "";
|
|
402
|
-
const copyBtn = `<button class="fd-copy-btn" data-code="${escapedRaw}" title="Copy code"
|
|
465
|
+
const copyBtn = `<button type="button" class="fd-copy-btn" data-code="${escapedRaw}" title="Copy code" aria-label="Copy code">${copyCodeBlockIcon}</button>`;
|
|
403
466
|
if (title) {
|
|
404
|
-
return `<
|
|
467
|
+
return `<figure class="fd-codeblock fd-codeblock--titled shiki not-prose" dir="ltr" tabindex="-1"${dataLang}><div class="fd-codeblock-title" data-title>${renderCodeBlockTitleIcon(title, language)}<span class="fd-codeblock-title-text">${escapeHtml(title)}</span><div class="fd-codeblock-actions">${copyBtn}</div></div><div class="fd-codeblock-content fd-scroll-container" role="region" tabindex="0">${html}</div></figure>`;
|
|
405
468
|
}
|
|
406
|
-
return `<
|
|
469
|
+
return `<figure class="fd-codeblock shiki not-prose" dir="ltr" tabindex="-1"${dataLang}><div class="fd-codeblock-actions fd-codeblock-actions-floating">${copyBtn}</div><div class="fd-codeblock-content fd-scroll-container" role="region" tabindex="0">${html}</div></figure>`;
|
|
407
470
|
}
|
|
408
471
|
function dedentCode(raw) {
|
|
409
472
|
const lines = raw.replace(/\n$/, "").split("\n");
|
|
@@ -452,14 +515,16 @@ export async function renderMarkdown(content, options = {}) {
|
|
|
452
515
|
}
|
|
453
516
|
if (panels.length === 0)
|
|
454
517
|
return body;
|
|
455
|
-
let tabsHtml = `<div class="fd-tabs" data-tabs data-code-group${dropdown ? ' data-dropdown="true"' : ""}>`;
|
|
456
|
-
tabsHtml += `<div class="fd-tabs-list" role="tablist">`;
|
|
518
|
+
let tabsHtml = `<div class="fd-tabs fd-code-group" data-tabs data-code-group data-fd-code-group${dropdown ? ' data-dropdown="true"' : ""}>`;
|
|
519
|
+
tabsHtml += `<div class="fd-tabs-list fd-code-group-list" role="tablist">`;
|
|
457
520
|
for (let i = 0; i < panels.length; i++) {
|
|
458
|
-
|
|
521
|
+
const state = i === 0 ? "active" : "inactive";
|
|
522
|
+
tabsHtml += `<button type="button" role="tab" class="fd-tab-trigger${i === 0 ? " fd-tab-active" : ""}" data-tab-value="${escapeHtml(panels[i].value)}" data-state="${state}" aria-selected="${i === 0}" tabindex="${i === 0 ? "0" : "-1"}">${escapeHtml(panels[i].label)}</button>`;
|
|
459
523
|
}
|
|
460
524
|
tabsHtml += `</div>`;
|
|
461
525
|
for (let i = 0; i < panels.length; i++) {
|
|
462
|
-
|
|
526
|
+
const state = i === 0 ? "active" : "inactive";
|
|
527
|
+
tabsHtml += `<div class="fd-tab-panel fd-code-group-panel${i === 0 ? " fd-tab-panel-active" : ""}" data-tab-panel="${escapeHtml(panels[i].value)}" data-state="${state}" role="tabpanel">${panels[i].html}</div>`;
|
|
463
528
|
}
|
|
464
529
|
tabsHtml += `</div>`;
|
|
465
530
|
const placeholder = `%%TABS_${tabsBlocks.length}%%`;
|
|
@@ -489,11 +554,13 @@ export async function renderMarkdown(content, options = {}) {
|
|
|
489
554
|
let tabsHtml = `<div class="fd-tabs" data-tabs>`;
|
|
490
555
|
tabsHtml += `<div class="fd-tabs-list" role="tablist">`;
|
|
491
556
|
for (let i = 0; i < items.length; i++) {
|
|
492
|
-
|
|
557
|
+
const state = i === 0 ? "active" : "inactive";
|
|
558
|
+
tabsHtml += `<button type="button" role="tab" class="fd-tab-trigger${i === 0 ? " fd-tab-active" : ""}" data-tab-value="${escapeHtml(items[i])}" data-state="${state}" aria-selected="${i === 0}" tabindex="${i === 0 ? "0" : "-1"}">${escapeHtml(items[i])}</button>`;
|
|
493
559
|
}
|
|
494
560
|
tabsHtml += `</div>`;
|
|
495
561
|
for (let i = 0; i < panels.length; i++) {
|
|
496
|
-
|
|
562
|
+
const state = i === 0 ? "active" : "inactive";
|
|
563
|
+
tabsHtml += `<div class="fd-tab-panel${i === 0 ? " fd-tab-panel-active" : ""}" data-tab-panel="${escapeHtml(panels[i].value)}" data-state="${state}" role="tabpanel">${panels[i].html}</div>`;
|
|
497
564
|
}
|
|
498
565
|
tabsHtml += `</div>`;
|
|
499
566
|
const placeholder = `%%TABS_${tabsBlocks.length}%%`;
|
|
@@ -521,6 +588,15 @@ export async function renderMarkdown(content, options = {}) {
|
|
|
521
588
|
promptBlocks.push(renderPrompt(attrSource ?? "", children, options));
|
|
522
589
|
return placeholder;
|
|
523
590
|
});
|
|
591
|
+
const calloutBlocks = [];
|
|
592
|
+
result = result.replace(/<Callout(?:\s+([^>]*?))?>([\s\S]*?)<\/Callout>/g, (_, attrSource, children) => {
|
|
593
|
+
const attrs = parseJsxAttributes(attrSource ?? "");
|
|
594
|
+
const type = toStringValue(attrs.type) ?? toStringValue(attrs.kind) ?? "note";
|
|
595
|
+
const title = toStringValue(attrs.title);
|
|
596
|
+
const placeholder = `%%CALLOUT_${calloutBlocks.length}%%`;
|
|
597
|
+
calloutBlocks.push(renderCallout(type, children, title));
|
|
598
|
+
return placeholder;
|
|
599
|
+
});
|
|
524
600
|
// Inline code
|
|
525
601
|
result = result.replace(/`([^`]+)`/g, "<code>$1</code>");
|
|
526
602
|
// Headings (h4 → h1 order to avoid prefix collisions)
|
|
@@ -535,7 +611,6 @@ export async function renderMarkdown(content, options = {}) {
|
|
|
535
611
|
});
|
|
536
612
|
result = result.replace(/^# (.+)$/gm, "<h1>$1</h1>");
|
|
537
613
|
// ── Callouts / blockquotes (before inline formatting) ──
|
|
538
|
-
const calloutBlocks = [];
|
|
539
614
|
result = result.replace(/(?:^>\s*.+\n?)+/gm, (block) => {
|
|
540
615
|
const lines = block.split("\n").filter(Boolean);
|
|
541
616
|
const inner = lines.map((l) => l.replace(/^>\s?/, "")).join("\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farming-labs/svelte",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.47",
|
|
4
4
|
"description": "SvelteKit adapter for @farming-labs/docs — content loading and navigation utilities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docs",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/node": "^22.10.0",
|
|
58
58
|
"typescript": "^5.9.3",
|
|
59
|
-
"@farming-labs/docs": "0.2.
|
|
59
|
+
"@farming-labs/docs": "0.2.47"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"@farming-labs/docs": "*"
|