diff --git a/CONTENT_BRIDGE.md b/CONTENT_BRIDGE.md index d150738..bf89930 100644 --- a/CONTENT_BRIDGE.md +++ b/CONTENT_BRIDGE.md @@ -286,7 +286,8 @@ The data file should contain either a top-level array or an object with an `items` array. The `src` path is resolved relative to the Markdown file. Use `columns` to control the visible columns, `headers` to rename table headers, `link` to choose the column that should link through the row's `link` field, -and `number` to prefix that linked column with a row number such as `slno`. +and `number` to prefix and sort that linked column by a row number such as +`slno`. In Obsidian this remains a readable code fence next to the data file. In Astro it becomes static HTML enhanced with local search and sort. In PDF it becomes a diff --git a/docs/PARSER.md b/docs/PARSER.md index b78ae17..4baef0c 100644 --- a/docs/PARSER.md +++ b/docs/PARSER.md @@ -344,7 +344,7 @@ Attributes: | `headers="key:Label,..."` | Optional | Human-readable labels for selected columns. | | `link="title"` | Optional | Column whose value links through the row's URL field. | | `url="link"` | Optional | URL field used by the linked column; defaults to `link`. | -| `number="slno"` | Optional | Prefix the linked column with a row number field. | +| `number="slno"` | Optional | Prefix and sort the linked column by a row number field. | | `caption="Resources"` | Optional | Visible toolbar title and accessible table caption. | | `search="false"` | Optional | Disable local table search; enabled by default. | | `sort="false"` | Optional | Disable sortable headers; enabled by default. | diff --git a/sites/art/src/remark/semantic-blocks.mjs b/sites/art/src/remark/semantic-blocks.mjs index a8afdbd..23809f1 100644 --- a/sites/art/src/remark/semantic-blocks.mjs +++ b/sites/art/src/remark/semantic-blocks.mjs @@ -220,19 +220,25 @@ function displayValue(value) { return VALUE_LABELS[value] || value; } +function numberLabel(row, field) { + if (!field) return ""; + const value = row[field]; + if (value === undefined || value === null || value === "") return ""; + return String(value).padStart(2, "0"); +} + function renderCell(row, column, options) { const raw = row[column] ?? ""; const display = displayValue(raw); - const sortValue = attribute(sortText(display)); + const numberPrefix = + column === options.linkColumn ? numberLabel(row, options.numberField) : ""; + const sortValue = attribute( + [numberPrefix, sortText(display)].filter(Boolean).join(" "), + ); const cellAttrs = `data-column="${attribute(column)}" data-sort-value="${sortValue}"`; if (column === options.linkColumn && row[options.urlField]) { - const numberValue = row[options.numberField]; - const numberLabel = - numberValue === undefined || numberValue === null || numberValue === "" - ? "" - : String(numberValue).padStart(2, "0"); - const prefix = options.numberField && numberLabel ? `${numberLabel}. ` : ""; + const prefix = numberPrefix ? `${numberPrefix}. ` : ""; return `${escapeHtml(prefix)}${inlineMarkup(display)}`; } diff --git a/sites/poetry/src/remark/semantic-blocks.mjs b/sites/poetry/src/remark/semantic-blocks.mjs index a8afdbd..23809f1 100644 --- a/sites/poetry/src/remark/semantic-blocks.mjs +++ b/sites/poetry/src/remark/semantic-blocks.mjs @@ -220,19 +220,25 @@ function displayValue(value) { return VALUE_LABELS[value] || value; } +function numberLabel(row, field) { + if (!field) return ""; + const value = row[field]; + if (value === undefined || value === null || value === "") return ""; + return String(value).padStart(2, "0"); +} + function renderCell(row, column, options) { const raw = row[column] ?? ""; const display = displayValue(raw); - const sortValue = attribute(sortText(display)); + const numberPrefix = + column === options.linkColumn ? numberLabel(row, options.numberField) : ""; + const sortValue = attribute( + [numberPrefix, sortText(display)].filter(Boolean).join(" "), + ); const cellAttrs = `data-column="${attribute(column)}" data-sort-value="${sortValue}"`; if (column === options.linkColumn && row[options.urlField]) { - const numberValue = row[options.numberField]; - const numberLabel = - numberValue === undefined || numberValue === null || numberValue === "" - ? "" - : String(numberValue).padStart(2, "0"); - const prefix = options.numberField && numberLabel ? `${numberLabel}. ` : ""; + const prefix = numberPrefix ? `${numberPrefix}. ` : ""; return `${escapeHtml(prefix)}${inlineMarkup(display)}`; } diff --git a/sites/puzzles/src/remark/semantic-blocks.mjs b/sites/puzzles/src/remark/semantic-blocks.mjs index a8afdbd..23809f1 100644 --- a/sites/puzzles/src/remark/semantic-blocks.mjs +++ b/sites/puzzles/src/remark/semantic-blocks.mjs @@ -220,19 +220,25 @@ function displayValue(value) { return VALUE_LABELS[value] || value; } +function numberLabel(row, field) { + if (!field) return ""; + const value = row[field]; + if (value === undefined || value === null || value === "") return ""; + return String(value).padStart(2, "0"); +} + function renderCell(row, column, options) { const raw = row[column] ?? ""; const display = displayValue(raw); - const sortValue = attribute(sortText(display)); + const numberPrefix = + column === options.linkColumn ? numberLabel(row, options.numberField) : ""; + const sortValue = attribute( + [numberPrefix, sortText(display)].filter(Boolean).join(" "), + ); const cellAttrs = `data-column="${attribute(column)}" data-sort-value="${sortValue}"`; if (column === options.linkColumn && row[options.urlField]) { - const numberValue = row[options.numberField]; - const numberLabel = - numberValue === undefined || numberValue === null || numberValue === "" - ? "" - : String(numberValue).padStart(2, "0"); - const prefix = options.numberField && numberLabel ? `${numberLabel}. ` : ""; + const prefix = numberPrefix ? `${numberPrefix}. ` : ""; return `${escapeHtml(prefix)}${inlineMarkup(display)}`; } diff --git a/sites/reflections/src/remark/semantic-blocks.mjs b/sites/reflections/src/remark/semantic-blocks.mjs index a8afdbd..23809f1 100644 --- a/sites/reflections/src/remark/semantic-blocks.mjs +++ b/sites/reflections/src/remark/semantic-blocks.mjs @@ -220,19 +220,25 @@ function displayValue(value) { return VALUE_LABELS[value] || value; } +function numberLabel(row, field) { + if (!field) return ""; + const value = row[field]; + if (value === undefined || value === null || value === "") return ""; + return String(value).padStart(2, "0"); +} + function renderCell(row, column, options) { const raw = row[column] ?? ""; const display = displayValue(raw); - const sortValue = attribute(sortText(display)); + const numberPrefix = + column === options.linkColumn ? numberLabel(row, options.numberField) : ""; + const sortValue = attribute( + [numberPrefix, sortText(display)].filter(Boolean).join(" "), + ); const cellAttrs = `data-column="${attribute(column)}" data-sort-value="${sortValue}"`; if (column === options.linkColumn && row[options.urlField]) { - const numberValue = row[options.numberField]; - const numberLabel = - numberValue === undefined || numberValue === null || numberValue === "" - ? "" - : String(numberValue).padStart(2, "0"); - const prefix = options.numberField && numberLabel ? `${numberLabel}. ` : ""; + const prefix = numberPrefix ? `${numberPrefix}. ` : ""; return `${escapeHtml(prefix)}${inlineMarkup(display)}`; } diff --git a/sites/research/src/remark/semantic-blocks.mjs b/sites/research/src/remark/semantic-blocks.mjs index a8afdbd..23809f1 100644 --- a/sites/research/src/remark/semantic-blocks.mjs +++ b/sites/research/src/remark/semantic-blocks.mjs @@ -220,19 +220,25 @@ function displayValue(value) { return VALUE_LABELS[value] || value; } +function numberLabel(row, field) { + if (!field) return ""; + const value = row[field]; + if (value === undefined || value === null || value === "") return ""; + return String(value).padStart(2, "0"); +} + function renderCell(row, column, options) { const raw = row[column] ?? ""; const display = displayValue(raw); - const sortValue = attribute(sortText(display)); + const numberPrefix = + column === options.linkColumn ? numberLabel(row, options.numberField) : ""; + const sortValue = attribute( + [numberPrefix, sortText(display)].filter(Boolean).join(" "), + ); const cellAttrs = `data-column="${attribute(column)}" data-sort-value="${sortValue}"`; if (column === options.linkColumn && row[options.urlField]) { - const numberValue = row[options.numberField]; - const numberLabel = - numberValue === undefined || numberValue === null || numberValue === "" - ? "" - : String(numberValue).padStart(2, "0"); - const prefix = options.numberField && numberLabel ? `${numberLabel}. ` : ""; + const prefix = numberPrefix ? `${numberPrefix}. ` : ""; return `${escapeHtml(prefix)}${inlineMarkup(display)}`; } diff --git a/sites/reviews/src/remark/semantic-blocks.mjs b/sites/reviews/src/remark/semantic-blocks.mjs index a8afdbd..23809f1 100644 --- a/sites/reviews/src/remark/semantic-blocks.mjs +++ b/sites/reviews/src/remark/semantic-blocks.mjs @@ -220,19 +220,25 @@ function displayValue(value) { return VALUE_LABELS[value] || value; } +function numberLabel(row, field) { + if (!field) return ""; + const value = row[field]; + if (value === undefined || value === null || value === "") return ""; + return String(value).padStart(2, "0"); +} + function renderCell(row, column, options) { const raw = row[column] ?? ""; const display = displayValue(raw); - const sortValue = attribute(sortText(display)); + const numberPrefix = + column === options.linkColumn ? numberLabel(row, options.numberField) : ""; + const sortValue = attribute( + [numberPrefix, sortText(display)].filter(Boolean).join(" "), + ); const cellAttrs = `data-column="${attribute(column)}" data-sort-value="${sortValue}"`; if (column === options.linkColumn && row[options.urlField]) { - const numberValue = row[options.numberField]; - const numberLabel = - numberValue === undefined || numberValue === null || numberValue === "" - ? "" - : String(numberValue).padStart(2, "0"); - const prefix = options.numberField && numberLabel ? `${numberLabel}. ` : ""; + const prefix = numberPrefix ? `${numberPrefix}. ` : ""; return `${escapeHtml(prefix)}${inlineMarkup(display)}`; } diff --git a/sites/vibes/src/remark/semantic-blocks.mjs b/sites/vibes/src/remark/semantic-blocks.mjs index a8afdbd..23809f1 100644 --- a/sites/vibes/src/remark/semantic-blocks.mjs +++ b/sites/vibes/src/remark/semantic-blocks.mjs @@ -220,19 +220,25 @@ function displayValue(value) { return VALUE_LABELS[value] || value; } +function numberLabel(row, field) { + if (!field) return ""; + const value = row[field]; + if (value === undefined || value === null || value === "") return ""; + return String(value).padStart(2, "0"); +} + function renderCell(row, column, options) { const raw = row[column] ?? ""; const display = displayValue(raw); - const sortValue = attribute(sortText(display)); + const numberPrefix = + column === options.linkColumn ? numberLabel(row, options.numberField) : ""; + const sortValue = attribute( + [numberPrefix, sortText(display)].filter(Boolean).join(" "), + ); const cellAttrs = `data-column="${attribute(column)}" data-sort-value="${sortValue}"`; if (column === options.linkColumn && row[options.urlField]) { - const numberValue = row[options.numberField]; - const numberLabel = - numberValue === undefined || numberValue === null || numberValue === "" - ? "" - : String(numberValue).padStart(2, "0"); - const prefix = options.numberField && numberLabel ? `${numberLabel}. ` : ""; + const prefix = numberPrefix ? `${numberPrefix}. ` : ""; return `${escapeHtml(prefix)}${inlineMarkup(display)}`; }