feat(md-deck): support structured data-config with template layers

Allow md-deck layers to render markdown templates via {{var}}
substitution instead of only CSV props. Add config.ts to normalize
a JSON data-config attribute (size, grid, shape, layers) emitted by
the yaml code-block tag, taking precedence over legacy string props.
This commit is contained in:
2026-09-02 18:15:51 +08:00
parent 023d3a0cb9
commit 16dfc8a88c
12 changed files with 450 additions and 41 deletions
+106
View File
@@ -0,0 +1,106 @@
import { layersToConfigs, normalizeDeckConfig } from "./config";
describe("layersToConfigs", () => {
test("parses compact string format (legacy)", () => {
const layers = layersToConfigs("title:1,1-5,1f8 body:1,5-8,8f3");
expect(layers).toHaveLength(2);
expect(layers[0]).toMatchObject({
prop: "title",
visible: true,
x1: 1,
y1: 1,
x2: 5,
y2: 1,
fontSize: 8,
});
expect(layers[1].prop).toBe("body");
});
test("parses structured list with prop layers", () => {
const layers = layersToConfigs([
{ prop: "name", x1: 1, y1: 1, x2: 5, y2: 2, font: 12 },
]);
expect(layers).toHaveLength(1);
expect(layers[0]).toMatchObject({
prop: "name",
template: undefined,
visible: true,
x1: 1,
y1: 1,
x2: 5,
y2: 2,
fontSize: 12,
});
});
test("parses structured list with template layers", () => {
const layers = layersToConfigs([
{ template: "**{{name}}**", x1: 1, y1: 3, x2: 5, y2: 8, align: "l" },
]);
expect(layers).toHaveLength(1);
expect(layers[0]).toMatchObject({
prop: undefined,
template: "**{{name}}**",
visible: true,
x1: 1,
y1: 3,
x2: 5,
y2: 8,
align: "l",
});
});
test("returns [] for absent/empty input", () => {
expect(layersToConfigs()).toEqual([]);
expect(layersToConfigs("")).toEqual([]);
expect(layersToConfigs([])).toEqual([]);
});
});
describe("normalizeDeckConfig", () => {
test("parses string dimensions", () => {
const cfg = normalizeDeckConfig({ size: "54x86", grid: "5x8" });
expect(cfg.sizeW).toBe(54);
expect(cfg.sizeH).toBe(86);
expect(cfg.gridW).toBe(5);
expect(cfg.gridH).toBe(8);
});
test("parses array dimensions", () => {
const cfg = normalizeDeckConfig({ size: [63, 88] });
expect(cfg.sizeW).toBe(63);
expect(cfg.sizeH).toBe(88);
});
test("coerces numeric strings for bleed/padding", () => {
const cfg = normalizeDeckConfig({ bleed: "2", padding: "3" });
expect(cfg.bleed).toBe(2);
expect(cfg.padding).toBe(3);
});
test("normalizes layers and back_layers", () => {
const cfg = normalizeDeckConfig({
layers: [
{ prop: "name", x1: 1, y1: 1, x2: 5, y2: 1 },
{ template: "{{body}}", x1: 1, y1: 2, x2: 5, y2: 8 },
],
back_layers: "logo:1,1-2,2",
});
expect(cfg.frontLayers).toHaveLength(2);
expect(cfg.frontLayers[1].template).toBe("{{body}}");
expect(cfg.backLayers).toHaveLength(1);
expect(cfg.backLayers[0].prop).toBe("logo");
});
test("missing fields stay undefined", () => {
const cfg = normalizeDeckConfig({});
expect(cfg.sizeW).toBeUndefined();
expect(cfg.sizeH).toBeUndefined();
expect(cfg.gridW).toBeUndefined();
expect(cfg.gridH).toBeUndefined();
expect(cfg.bleed).toBeUndefined();
expect(cfg.padding).toBeUndefined();
expect(cfg.frontLayers).toEqual([]);
expect(cfg.backLayers).toEqual([]);
});
});