Skip to content

Commit f6d5fe4

Browse files
authored
Merge pull request #177 from DemchaAV/feat/feature-catalog-v18-blocks
docs(examples): Feature Catalog blocks for the v1.8 surface (paths, SVG beta, debug overlay)
2 parents c0c59df + b2333c4 commit f6d5fe4

2 files changed

Lines changed: 136 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,12 @@ Entries land here as they merge.
200200
a code panel shows the exact API call, and the live result renders right
201201
under it — rich text, sparklines, nested lists, timelines, tables, every
202202
chart kind, images (COVER vs CONTAIN fit), gradients, translucency,
203-
polygons, shape basics (dividers, ellipses, soft cards), clipped
204-
containers, canvas, transforms, barcodes, and the document's own chrome —
205-
19 blocks across 6 pages. Blocks use `keepTogether()`, so a snippet is
206-
never orphaned from its result.
203+
polygons, vector paths (solid and dashed native Béziers), SVG path import
204+
and a beta `SvgIcon` tile row, shape basics (dividers, ellipses, soft
205+
cards), clipped containers, canvas, transforms, barcodes, the
206+
debug-overlay switch, and the document's own chrome — 23 blocks across
207+
7 pages. Blocks use `keepTogether()`, so a snippet is never orphaned
208+
from its result.
207209
- **Recipe coverage is complete.** Nine new cookbook pages close every gap the
208210
recipe index tracked: rich text, lists, timelines, barcodes, images,
209211
PDF chrome (metadata / watermark / running header-footer / protection /

examples/src/main/java/com/demcha/examples/flagships/FeatureCatalogExample.java

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import com.demcha.compose.document.style.DocumentTextStyle;
2828
import com.demcha.compose.document.style.DocumentTransform;
2929
import com.demcha.compose.document.style.ShapePoint;
30+
import com.demcha.compose.document.svg.SvgIcon;
31+
import com.demcha.compose.document.svg.SvgPath;
3032
import com.demcha.compose.document.theme.BusinessTheme;
3133
import com.demcha.compose.font.FontName;
3234
import com.demcha.examples.support.ExampleOutputPaths;
@@ -57,6 +59,21 @@ public final class FeatureCatalogExample {
5759
private static final DocumentColor CODE_BG = DocumentColor.rgb(244, 245, 248);
5860
private static final DocumentColor CODE_INK = DocumentColor.rgb(52, 74, 94);
5961

62+
/** Material Icons "favorite" path data (Apache 2.0), viewBox 0 0 24 24. */
63+
private static final String MATERIAL_HEART_D =
64+
"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3"
65+
+ "c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5"
66+
+ "c0 3.78-3.4 6.86-8.55 11.54L12 21.35z";
67+
68+
/** The svgrepo.com icons shown on the beta SvgIcon card row: file → label. */
69+
private static final List<String[]> CATALOG_ICONS = List.of(
70+
new String[] {"apple", "APPLE"},
71+
new String[] {"headphones-music", "HEADPHONES"},
72+
new String[] {"shopping-cart", "CART"},
73+
new String[] {"camera-take-pictures", "CAMERA"},
74+
new String[] {"starfish", "STARFISH"},
75+
new String[] {"toolbox", "TOOLBOX"});
76+
6077
private FeatureCatalogExample() {
6178
}
6279

@@ -300,6 +317,47 @@ public static Path generate() throws Exception {
300317
TEAL, DocumentStroke.of(GOLD, 1.2),
301318
DocumentInsets.zero(), DocumentInsets.zero())));
302319

320+
feature(flow, "Vector paths — native Bézier curves, dashed strokes", """
321+
section.addPath(path -> path.size(420, 48) // unit box, y-up; controls may overshoot
322+
.moveTo(0.0, 0.5)
323+
.curveTo(0.25, 1.1, 0.25, -0.1, 0.5, 0.5)
324+
.curveTo(0.75, 1.1, 0.75, -0.1, 1.0, 0.5)
325+
.stroke(DocumentStroke.of(TEAL, 2.2)));
326+
// .dashed(6, 3) turns the same stroke into a dash pattern that follows the curve""",
327+
demo -> demo
328+
.addPath(path -> path.size(420, 48)
329+
.moveTo(0.0, 0.5)
330+
.curveTo(0.25, 1.1, 0.25, -0.1, 0.5, 0.5)
331+
.curveTo(0.75, 1.1, 0.75, -0.1, 1.0, 0.5)
332+
.stroke(DocumentStroke.of(TEAL, 2.2)))
333+
.addPath(path -> path.size(420, 48)
334+
.moveTo(0.0, 0.5)
335+
.curveTo(0.25, 1.1, 0.25, -0.1, 0.5, 0.5)
336+
.curveTo(0.75, 1.1, 0.75, -0.1, 1.0, 0.5)
337+
.stroke(DocumentStroke.of(GOLD, 2.2))
338+
.dashed(6, 3)));
339+
340+
feature(flow, "SVG path import (beta) — any d string as native curves", """
341+
// Material Icons "favorite" (Apache 2.0), viewBox 0 0 24 24
342+
section.addPath(path -> path.size(64, 64)
343+
.svg(SvgPath.parse(HEART_D, 0, 0, 24, 24)) // curves stay native PDF operators
344+
.fillColor(rgb(196, 30, 58)))""",
345+
demo -> demo.addPath(path -> path.size(64, 64)
346+
.svg(SvgPath.parse(MATERIAL_HEART_D, 0, 0, 24, 24))
347+
.fillColor(DocumentColor.rgb(196, 30, 58))));
348+
349+
feature(flow, "SVG icons (beta) — multicolour files centred on tile cards", """
350+
SvgIcon icon = SvgIcon.read(Path.of("icons/apple.svg")); // layers + resolved paints
351+
card.roundedRect(74, 64, 8) // fixed box = the tile
352+
.position(iconNode(icon), 0, -7, LayerAlign.CENTER) // anchor centres the icon's
353+
.bottomCenter(plaque("APPLE")) // own tight box inside the card""",
354+
demo -> demo.addRow(r -> {
355+
r.spacing(8).evenWeights();
356+
for (String[] entry : CATALOG_ICONS) {
357+
r.addSection("Tile" + entry[1], s -> s.add(iconCard(entry[0], entry[1])));
358+
}
359+
}));
360+
303361
feature(flow, "Shape as container — children clipped to the outline", """
304362
section.addCircle(72, TEAL, c -> c
305363
.stroke(DocumentStroke.of(GOLD, 1.2))
@@ -344,6 +402,21 @@ public static Path generate() throws Exception {
344402
.addSection("C128", c -> c.addBarcode(b -> b.code128()
345403
.data("GC-2026-001").size(200, 44)))));
346404

405+
feature(flow, "Debug overlay — corner badges name every box", """
406+
GraphCompose.document(out)
407+
.debug(DocumentDebugOptions.nodeLabels()) // or guidesAndNodeLabels()
408+
.create();
409+
// LabelText.FULL_PATH prints whole layout paths; guides() adds box outlines""",
410+
demo -> demo.addParagraph(p -> p
411+
.text("Re-render any document with nodeLabels() and every placed box "
412+
+ "grows a corner badge with its semantic name (PriceSummaryTitle[0], "
413+
+ "SvgLayer3, …) — a misplaced component traces straight back to the "
414+
+ "builder call that produced it. The full annotated sheet is "
415+
+ "debug-overlay.pdf among the examples.")
416+
.textStyle(THEME.text().body())
417+
.lineSpacing(1.35)
418+
.margin(DocumentInsets.zero())));
419+
347420
feature(flow, "Page chrome — this document's own header, footer, outline", """
348421
document.metadata(DocumentMetadata.builder().title("…").author("…").build());
349422
document.header(DocumentHeaderFooter.builder().zone(HEADER)
@@ -413,6 +486,63 @@ private static com.demcha.compose.document.image.DocumentImageData catalogImage(
413486
}
414487
}
415488

489+
/** Classpath icon for the beta SvgIcon card row (same set as the gallery). */
490+
private static SvgIcon catalogIcon(String name) {
491+
try (java.io.InputStream stream = java.util.Objects.requireNonNull(
492+
FeatureCatalogExample.class.getResourceAsStream("/icons/" + name + ".svg"),
493+
"icon resource missing: " + name)) {
494+
return SvgIcon.parse(new String(stream.readAllBytes(),
495+
java.nio.charset.StandardCharsets.UTF_8));
496+
} catch (java.io.IOException e) {
497+
throw new IllegalStateException("failed to load icon: " + name, e);
498+
}
499+
}
500+
501+
/**
502+
* Mini tile for the icon row: fixed rounded card, the icon centred in the
503+
* body as a tight-box layer stack, a label plaque across the bottom. The
504+
* stack keeps the icon's exact contain-fit size — that is what makes the
505+
* card's CENTER anchor land true.
506+
*/
507+
private static com.demcha.compose.document.node.DocumentNode iconCard(String name, String label) {
508+
SvgIcon icon = catalogIcon(name);
509+
double box = 34;
510+
double width = Math.min(box, box * icon.aspectRatio());
511+
double height = width / icon.aspectRatio();
512+
var stack = new com.demcha.compose.document.dsl.LayerStackBuilder().name("Icon" + label);
513+
for (int i = 0; i < icon.layers().size(); i++) {
514+
SvgIcon.Layer layer = icon.layers().get(i);
515+
stack.layer(new com.demcha.compose.document.dsl.PathBuilder()
516+
.name("SvgLayer" + i)
517+
.size(width, height)
518+
.svg(layer.geometry())
519+
.fillColor(layer.fill())
520+
.stroke(layer.stroke())
521+
.build());
522+
}
523+
double plaqueHeight = 14;
524+
return new com.demcha.compose.document.dsl.ShapeContainerBuilder()
525+
.name("IconCard" + label)
526+
.roundedRect(74, 64, 8)
527+
.fillColor(DocumentColor.rgb(248, 249, 251))
528+
.stroke(DocumentStroke.of(DocumentColor.rgb(228, 231, 236), 0.8))
529+
.position(stack.build(), 0, -plaqueHeight / 2.0,
530+
com.demcha.compose.document.node.LayerAlign.CENTER)
531+
.bottomCenter(new com.demcha.compose.document.dsl.ShapeContainerBuilder()
532+
.name("Plaque" + label)
533+
.rectangle(74, plaqueHeight)
534+
.fillColor(DocumentColor.rgb(235, 238, 243))
535+
.center(new com.demcha.compose.document.dsl.ParagraphBuilder()
536+
.text(label)
537+
.textStyle(DocumentTextStyle.builder()
538+
.fontName(FontName.HELVETICA_BOLD).size(6.2)
539+
.color(DocumentColor.rgb(82, 90, 102)).build())
540+
.align(com.demcha.compose.document.node.TextAlign.CENTER)
541+
.build())
542+
.build())
543+
.build();
544+
}
545+
416546
private static com.demcha.compose.document.node.DocumentNode badge(String text) {
417547
return new com.demcha.compose.document.dsl.ShapeContainerBuilder()
418548
.roundedRect(64, 22, 11)

0 commit comments

Comments
 (0)