@dogsbay/format-astro 0.2.0-beta.159 → 0.2.0-beta.160
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/serialize.js +26 -14
- package/dist/theme-css.js +1 -1
- package/package.json +8 -8
package/dist/serialize.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { walkInline, applyTextFlags, renderLeaf, indent, isSafeHref, apiPageLayout, apiSymbolLevels, renderAroundGroup, isDetailsSheet, stepLead, stepTitle, } from "@dogsbay/serialize-core";
|
|
1
|
+
import { walkInline, applyTextFlags, renderLeaf, indent, isSafeHref, apiPageLayout, apiSymbolLevels, renderAroundGroup, isDetailsSheet, isEmptyTableHead, cardBodyHasLink, stepLead, stepTitle, } from "@dogsbay/serialize-core";
|
|
2
2
|
import { parseInline } from "@dogsbay/format-dogsbay-md";
|
|
3
3
|
import { decorateDiff, hasDiffMarks } from "./diff-decoration.js";
|
|
4
4
|
import { TAB_GLYPH, tabDiffSignal } from "@dogsbay/render-html/diff";
|
|
@@ -310,6 +310,9 @@ function nodeToAstroBase(node, ctx) {
|
|
|
310
310
|
case "table":
|
|
311
311
|
return tableToAstro(node, ctx);
|
|
312
312
|
case "thead":
|
|
313
|
+
// a header row with no text (`| | |`, a headerless table) is no header (as render-html)
|
|
314
|
+
if (isEmptyTableHead(node))
|
|
315
|
+
return "";
|
|
313
316
|
ctx.imports.add("table");
|
|
314
317
|
return `<TableHeader>\n${childrenToAstro(node, ctx)}\n</TableHeader>`;
|
|
315
318
|
case "tbody":
|
|
@@ -656,9 +659,12 @@ function proseToAstro(node, ctx) {
|
|
|
656
659
|
}
|
|
657
660
|
/** TableHead's classes, for a header row's empty cell written as a plain `td`. */
|
|
658
661
|
const EMPTY_HEADER_CELL_CLASS = "px-2 py-2 text-left align-bottom font-semibold text-muted-foreground";
|
|
659
|
-
/**
|
|
660
|
-
|
|
661
|
-
|
|
662
|
+
/**
|
|
663
|
+
* A card's title is text styled as one, not a heading (as render-html): a grid of cards is not a
|
|
664
|
+
* section of the page, and as headings its titles filled the outline and a reader's heading list.
|
|
665
|
+
*/
|
|
666
|
+
function cardTitleTag(_ctx) {
|
|
667
|
+
return "div";
|
|
662
668
|
}
|
|
663
669
|
function headingToAstro(node, ctx) {
|
|
664
670
|
const level = node.props?.level ?? 1;
|
|
@@ -1528,6 +1534,8 @@ function wholeCardLink(yes, fn) {
|
|
|
1528
1534
|
}
|
|
1529
1535
|
/** A card's title: not-prose, or docs.css's h3 rule (1.25rem, 2rem above) applies inside the card. */
|
|
1530
1536
|
const CARD_TITLE_CLASS = "not-prose m-0 border-0 p-0 text-base font-semibold";
|
|
1537
|
+
/** Marks a card title for styles and tests (it is a div, not a heading). */
|
|
1538
|
+
const CARD_TITLE_ATTR = "data-card-title";
|
|
1531
1539
|
/**
|
|
1532
1540
|
* A card group's columns, responsive as render-html draws them (its GRID_COLS): one column on a
|
|
1533
1541
|
* phone, then up to `cols` (1–6) by Grid's breakpoints (0, 640, 768, 1024). Default 2. A list
|
|
@@ -1562,10 +1570,12 @@ function cardsToAstro(node, ctx) {
|
|
|
1562
1570
|
const before = ctx.lastHeading;
|
|
1563
1571
|
// Description sources: inline content, children, or props.description.
|
|
1564
1572
|
// Child blocks carry their own <p>, so they get a <div>: <p><p>…</p></p> is invalid HTML.
|
|
1565
|
-
|
|
1573
|
+
// A body with links of its own: the title links, not the whole card (cardBodyHasLink)
|
|
1574
|
+
const whole = !!href && (!title || !cardBodyHasLink([card.children, card.inline]));
|
|
1575
|
+
const blocks = wholeCardLink(whole, () => childrenToAstro(card, ctx));
|
|
1566
1576
|
ctx.lastHeading = before;
|
|
1567
1577
|
const inner = blocks
|
|
1568
|
-
|| (card.inline ? wholeCardLink(
|
|
1578
|
+
|| (card.inline ? wholeCardLink(whole, () => inlineToTemplate(card.inline)) : "")
|
|
1569
1579
|
|| (description ? escapeTemplate(description) : "");
|
|
1570
1580
|
const descTag = blocks ? "div" : "p";
|
|
1571
1581
|
// Icon renders inline before the title — picks up Lucide
|
|
@@ -1577,7 +1587,8 @@ function cardsToAstro(node, ctx) {
|
|
|
1577
1587
|
if (icon) {
|
|
1578
1588
|
iconHtml = cardIconHtml(icon, title, ctx);
|
|
1579
1589
|
}
|
|
1580
|
-
const
|
|
1590
|
+
const titleText = href && !whole ? `<a href="${escapeAttr(href)}">${escapeTemplate(title)}</a>` : escapeTemplate(title);
|
|
1591
|
+
const titleHtml = title ? `<${tag} class="${CARD_TITLE_CLASS}" ${CARD_TITLE_ATTR}>${titleText}</${tag}>` : "";
|
|
1581
1592
|
// A description and a body are both shown (the description used to be dropped when a body existed).
|
|
1582
1593
|
const lead = blocks && description
|
|
1583
1594
|
? `<p class="text-sm text-muted-foreground mt-1 [text-decoration:none]">${escapeTemplate(description)}</p>`
|
|
@@ -1588,14 +1599,14 @@ function cardsToAstro(node, ctx) {
|
|
|
1588
1599
|
// A tone (TONES; the card's own, else the group's) sets the card's
|
|
1589
1600
|
// border and tint: Card's tailwind-variants merge replaces bg-card
|
|
1590
1601
|
const toned = lookup(CARD_TONE_CLASSES, card.props?.tone ?? node.props?.tone);
|
|
1591
|
-
const cardDefaultClass =
|
|
1602
|
+
const cardDefaultClass = whole
|
|
1592
1603
|
? toned ? `p-4 ${toned} hover:shadow-md transition-colors` : "p-4 hover:border-foreground/20 transition-colors"
|
|
1593
1604
|
: toned ? `p-4 ${toned}` : "p-4";
|
|
1594
1605
|
const cardClassAttr = mergeClassAttr(cardDefaultClass, card.props?.class);
|
|
1595
1606
|
const cardPass = renderPassthroughAttrs(card.props, [
|
|
1596
1607
|
"title", "href", "description", "icon", "variant", "class", "tone",
|
|
1597
1608
|
]);
|
|
1598
|
-
if (
|
|
1609
|
+
if (whole) {
|
|
1599
1610
|
return `<Card${cardClassAttr}${cardPass}>\n<CardContent class="p-0">\n<a href="${escapeAttr(href)}" data-variant="card" class="[text-decoration:none] text-foreground">\n${iconHtml}\n${titleHtml}\n${desc}\n</a>\n</CardContent>\n</Card>`;
|
|
1600
1611
|
}
|
|
1601
1612
|
return `<Card${cardClassAttr}${cardPass}>\n<CardContent class="p-0">\n${iconHtml}\n${titleHtml}\n${desc}\n</CardContent>\n</Card>`;
|
|
@@ -1632,16 +1643,17 @@ function standaloneCardToAstro(node, ctx) {
|
|
|
1632
1643
|
const tag = cardTitleTag(ctx);
|
|
1633
1644
|
const before = ctx.lastHeading;
|
|
1634
1645
|
// Child blocks carry their own <p>, so they get a <div>: <p><p>…</p></p> is invalid HTML.
|
|
1635
|
-
const
|
|
1646
|
+
const whole = !!href && (!title || !cardBodyHasLink([node.children, node.inline]));
|
|
1647
|
+
const blocks = wholeCardLink(whole, () => childrenToAstro(node, ctx));
|
|
1636
1648
|
ctx.lastHeading = before;
|
|
1637
1649
|
const inner = blocks
|
|
1638
|
-
|| (node.inline ? wholeCardLink(
|
|
1650
|
+
|| (node.inline ? wholeCardLink(whole, () => inlineToTemplate(node.inline)) : "")
|
|
1639
1651
|
|| (description ? escapeTemplate(description) : "");
|
|
1640
1652
|
const descTag = blocks ? "div" : "p";
|
|
1641
1653
|
// Icon renders inline before the title, a name or an image path, as in a card group
|
|
1642
1654
|
const iconHtml = icon ? cardIconHtml(icon, title, ctx) : "";
|
|
1643
1655
|
const titleHtml = title
|
|
1644
|
-
? `<${tag} class="${CARD_TITLE_CLASS}">${escapeTemplate(title)}</${tag}>`
|
|
1656
|
+
? `<${tag} class="${CARD_TITLE_CLASS}" ${CARD_TITLE_ATTR}>${href && !whole ? `<a href="${escapeAttr(href)}">${escapeTemplate(title)}</a>` : escapeTemplate(title)}</${tag}>`
|
|
1645
1657
|
: "";
|
|
1646
1658
|
// A description and a body are both shown (the description used to be dropped when a body existed).
|
|
1647
1659
|
const lead = blocks && description
|
|
@@ -1652,14 +1664,14 @@ function standaloneCardToAstro(node, ctx) {
|
|
|
1652
1664
|
: "");
|
|
1653
1665
|
// A tone (TONES), as on a card in a group (cardsToAstro)
|
|
1654
1666
|
const toned = lookup(CARD_TONE_CLASSES, node.props?.tone);
|
|
1655
|
-
const cardDefaultClass =
|
|
1667
|
+
const cardDefaultClass = whole
|
|
1656
1668
|
? toned ? `p-4 ${toned} hover:shadow-md transition-colors` : "p-4 hover:border-foreground/20 transition-colors"
|
|
1657
1669
|
: toned ? `p-4 ${toned}` : "p-4";
|
|
1658
1670
|
const classAttr = mergeClassAttr(cardDefaultClass, node.props?.class);
|
|
1659
1671
|
const passthrough = renderPassthroughAttrs(node.props, [
|
|
1660
1672
|
"title", "href", "description", "icon", "variant", "class", "tone",
|
|
1661
1673
|
]);
|
|
1662
|
-
if (
|
|
1674
|
+
if (whole) {
|
|
1663
1675
|
return `<Card${classAttr}${passthrough}>\n<CardContent class="p-0">\n<a href="${escapeAttr(href)}" data-variant="card" class="[text-decoration:none] text-foreground">\n${iconHtml}\n${titleHtml}\n${desc}\n</a>\n</CardContent>\n</Card>`;
|
|
1664
1676
|
}
|
|
1665
1677
|
return `<Card${classAttr}${passthrough}>\n<CardContent class="p-0">\n${iconHtml}\n${titleHtml}\n${desc}\n</CardContent>\n</Card>`;
|
package/dist/theme-css.js
CHANGED
|
@@ -104,7 +104,7 @@ export function generateGlobalCss() {
|
|
|
104
104
|
.docs-prose {
|
|
105
105
|
line-height: 1.7;
|
|
106
106
|
|
|
107
|
-
/* A heading
|
|
107
|
+
/* A heading inside a component (.not-prose) keeps the component look */
|
|
108
108
|
& h1:not(.dba-api *, .not-prose, .not-prose *) { font-family: var(--font-heading); font-size: 2rem; font-weight: 700; margin-top: 0; margin-bottom: 1rem; line-height: 1.2; letter-spacing: -0.025em; }
|
|
109
109
|
& h2:not(.dba-api *, .not-prose, .not-prose *) { font-family: var(--font-heading); font-size: 1.5rem; font-weight: 600; margin-top: 2.5rem; margin-bottom: 0.75rem; line-height: 1.3; border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; letter-spacing: -0.015em; }
|
|
110
110
|
& h3:not(.dba-api *, .not-prose, .not-prose *) { font-family: var(--font-heading); font-size: 1.25rem; font-weight: 600; margin-top: 2rem; margin-bottom: 0.5rem; line-height: 1.4; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/format-astro",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.160",
|
|
4
4
|
"description": "Astro format plugin for Dogsbay — export TreeNode[] to Astro component markup",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -32,13 +32,13 @@
|
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"markdown-it": "^14.3.0",
|
|
35
|
-
"@dogsbay/format-dogsbay-md": "0.2.0-beta.
|
|
36
|
-
"@dogsbay/render-html": "0.2.0-beta.
|
|
37
|
-
"@dogsbay/
|
|
38
|
-
"@dogsbay/
|
|
39
|
-
"@dogsbay/
|
|
40
|
-
"@dogsbay/types": "0.2.0-beta.
|
|
41
|
-
"@dogsbay/ui": "0.2.0-beta.
|
|
35
|
+
"@dogsbay/format-dogsbay-md": "0.2.0-beta.160",
|
|
36
|
+
"@dogsbay/render-html": "0.2.0-beta.160",
|
|
37
|
+
"@dogsbay/serialize-core": "0.2.0-beta.160",
|
|
38
|
+
"@dogsbay/site-files": "0.2.0-beta.160",
|
|
39
|
+
"@dogsbay/icons": "0.2.0-beta.160",
|
|
40
|
+
"@dogsbay/types": "0.2.0-beta.160",
|
|
41
|
+
"@dogsbay/ui": "0.2.0-beta.160"
|
|
42
42
|
},
|
|
43
43
|
"repository": {
|
|
44
44
|
"type": "git",
|