Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.demcha.examples.templates.cv.v2;

import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentPageSize;
import com.demcha.compose.document.api.DocumentSession;
import com.demcha.compose.document.templates.api.DocumentTemplate;
import com.demcha.compose.document.templates.cv.v2.data.CvDocument;
import com.demcha.compose.document.templates.cv.v2.presets.EngineeringResume;
import com.demcha.examples.support.ExampleDataFactory;
import com.demcha.examples.support.ExampleOutputPaths;

import java.nio.file.Path;

/**
* Renders the v2 Engineering Resume CV preset against the shared
* grouped skills sample data — full-width navy command header with
* UPPERCASE Barlow name, right-aligned contact stack with cyan-green
* underlined links, dark navy skill rail (Core Stack / Learning /
* Details) and white evidence cards for Leadership Experience and
* Technical Evidence on the right.
*
* <p>Output:
* {@code examples/target/generated-pdfs/templates/cv/cv-engineering-resume-v2.pdf}.</p>
*/
public final class CvEngineeringResumeExample {

private CvEngineeringResumeExample() {
}

public static Path generate() throws Exception {
Path outputFile = ExampleOutputPaths.prepare(
"templates/cv", "cv-engineering-resume-v2.pdf");
CvDocument doc = ExampleDataFactory.sampleCvDocumentV2();
DocumentTemplate<CvDocument> template = EngineeringResume.create();

float m = (float) EngineeringResume.RECOMMENDED_MARGIN;
try (DocumentSession document = GraphCompose.document(outputFile)
.pageSize(DocumentPageSize.A4)
.margin(m, m, m, m)
.create()) {
template.compose(document, doc);
document.buildPdf();
}
return outputFile;
}

public static void main(String[] args) throws Exception {
System.out.println("Generated: " + generate());
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -509,18 +509,18 @@ private static List<String> sectionLines(CvSection section) {
line.append(header);
}
if (!subtitle.isBlank()) {
if (line.length() > 0) {
if (!line.isEmpty()) {
line.append(" | ");
}
line.append(subtitle);
}
if (!dates.isBlank()) {
if (line.length() > 0) {
if (!line.isEmpty()) {
line.append(" - ");
}
line.append(dates);
}
if (line.length() > 0) {
if (!line.isEmpty()) {
lines.add(line.toString());
}
if (!body.isBlank()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,23 @@ public static CvPalette editorialBlue() {
DocumentColor.rgb(193, 201, 211));
}

/**
* Engineering Resume palette ported from the v1
* {@code TechLeadCvTemplateComposer}: body-slate ink, muted slate
* for subtitles, pale teal-green rule that matches the white
* evidence cards, and the soft pale-green profile band fill. Deep
* navy header, brighter green accent, navy-rail variants and the
* cyan-green contact link colour stay preset-local as they are the
* fifth+ tokens — no other v2 preset shares them today.
*/
public static CvPalette engineeringResume() {
return new CvPalette(
DocumentColor.rgb(32, 42, 55), // ink — V1 INK body slate
DocumentColor.rgb(91, 105, 119), // muted — V1 MUTED subtitles
DocumentColor.rgb(190, 212, 204), // rule — V1 RULE pale teal-green
DocumentColor.rgb(232, 246, 239)); // banner — V1 GREEN_SOFT profile fill
}

/**
* Timeline Minimal palette: an all-grey scale ported from the v1
* {@code TimelineMinimalCvTemplateComposer} — medium-grey ink,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,30 @@ public static CvSpacing editorialBlue() {
3.0); // entrySeparation
}

/**
* Spacing for the Engineering Resume preset: navy command header
* + 2-column body (navy skill rail / white evidence cards), with
* a 2.5pt accent rule under the header and tight 1pt paragraph
* top so the dense rail + card content reads as a single page.
*/
public static CvSpacing engineeringResume() {
return new CvSpacing(
8, // pageFlowSpacing
4, // sectionBodySpacing
DocumentInsets.zero(), // sectionBodyPadding
DocumentInsets.zero(), // headlinePadding
DocumentInsets.zero(), // contactPadding
4.0, // bannerCornerRadius (card top/bottom radius)
10.0, // bannerInnerPadding (card padding token)
DocumentInsets.zero(), // bannerMargin
2.5, // accentRuleWidth (header bottom accent strip)
1.0, // paragraphMarginTop
8.0, // entryHeaderRowSpacing
1.0, // entryTitleWeight
0.45, // entryDateWeight
2.0); // entrySeparation
}

/**
* Spacing for the Timeline Minimal preset: tight 3-column layout
* with a fixed-width axis between the sidebar and main column.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,22 @@ public static CvTheme editorialBlue() {
CvDecoration.classic());
}

/**
* The "Engineering Resume" look — Barlow display + Lato body, deep
* navy command header with cyan-green contact links, dark navy
* skill rail with green accent labels, and white evidence cards
* for Leadership Experience + Technical Evidence on the right.
* Visual signature ported from the v1
* {@code TechLeadCvTemplateComposer}.
*/
public static CvTheme engineeringResume() {
return new CvTheme(
CvPalette.engineeringResume(),
CvTypography.engineeringResume(),
CvSpacing.engineeringResume(),
CvDecoration.classic());
}

/**
* The "Timeline Minimal" look — Barlow Condensed display + Lato
* body, all-grey palette, spaced uppercase name, right-aligned
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,25 @@ public static CvTypography editorialBlue() {
1.45); // line spacing
}

/**
* Barlow headline + Lato body scale ported from the v1
* {@code TechLeadCvTemplateComposer}: 24.5pt UPPERCASE masthead,
* 7.8pt main section headings, 7.25pt body, and a 1.08 line
* spacing tuned for dense engineering-resume cards.
*/
public static CvTypography engineeringResume() {
return new CvTypography(
FontName.BARLOW, FontName.LATO,
24.5, // headline (UPPERCASE name in navy header)
7.2, // contact (right-aligned navy header stack)
7.8, // banner / main section heading
8.0, // entry title (role title in experience cards)
7.1, // entry date
7.0, // entry subtitle (employer)
7.25, // body
1.08); // line spacing
}

/**
* Barlow Condensed headline + Lato body scale ported from the v1
* {@code TimelineMinimalCvTemplateComposer}: 28pt spaced-caps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,10 @@ private static Stream<Arguments> presets() {
(Supplier<DocumentTemplate<CvDocument>>) Panel::create),
Arguments.of("timeline_minimal",
TimelineMinimal.RECOMMENDED_MARGIN,
(Supplier<DocumentTemplate<CvDocument>>) TimelineMinimal::create));
(Supplier<DocumentTemplate<CvDocument>>) TimelineMinimal::create),
Arguments.of("engineering_resume",
EngineeringResume.RECOMMENDED_MARGIN,
(Supplier<DocumentTemplate<CvDocument>>) EngineeringResume::create));
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.demcha.compose.document.templates.cv.v2.presets;

import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentSession;
import com.demcha.compose.document.style.DocumentInsets;
import com.demcha.compose.document.templates.api.DocumentTemplate;
import com.demcha.compose.document.templates.cv.v2.data.CvDocument;
import com.demcha.compose.document.templates.cv.v2.data.CvIdentity;
import com.demcha.compose.document.templates.cv.v2.data.EntriesSection;
import com.demcha.compose.document.templates.cv.v2.data.ParagraphSection;
import com.demcha.compose.document.templates.cv.v2.data.RowStyle;
import com.demcha.compose.document.templates.cv.v2.data.RowsSection;
import com.demcha.compose.document.templates.cv.v2.data.SkillsSection;
import com.demcha.compose.document.templates.cv.v2.theme.CvTheme;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Smoke test for the v2 Engineering Resume preset. Covers the navy
* command header with subtitle + contact stack, plus the 2-column
* rail / main-card composition fed through
* {@link com.demcha.compose.document.templates.cv.v2.components.SectionLookup}.
*/
class EngineeringResumeSmokeTest {

@Test
void exposes_stable_identity() {
DocumentTemplate<CvDocument> template = EngineeringResume.create();
assertThat(template.id()).isEqualTo("engineering-resume");
assertThat(template.displayName()).isEqualTo("Engineering Resume");
}

@Test
void default_factory_renders_full_document() throws Exception {
renderAndAssertNonEmpty(EngineeringResume.create(), fullDocument());
}

@Test
void custom_theme_factory_renders() throws Exception {
renderAndAssertNonEmpty(EngineeringResume.create(CvTheme.engineeringResume()),
fullDocument());
}

private static void renderAndAssertNonEmpty(
DocumentTemplate<CvDocument> template,
CvDocument doc) throws Exception {
try (DocumentSession session = GraphCompose.document()
.pageSize(420, 595)
.margin(DocumentInsets.of(20))
.create()) {
template.compose(session, doc);
assertThat(session.roots()).isNotEmpty();
}
}

private static CvDocument fullDocument() {
return CvDocument.builder()
.identity(CvIdentity.builder()
.name("Jane", "Doe")
.jobTitle("Senior Platform Engineer")
.contact("+44 0", "j@d.com", "London")
.link("LinkedIn", "https://linkedin.com/in/jane-doe")
.link("GitHub", "https://github.com/jane")
.build())
.sections(
new ParagraphSection("Professional Summary",
"Builds **reliable** document pipelines."),
SkillsSection.builder("Technical Skills")
.group("Languages", "Java 21", "Kotlin")
.group("Testing", "JUnit 5", "AssertJ")
.build(),
EntriesSection.builder("Education & Certifications")
.entry("MSc Computer Science",
"University of Manchester",
"2019-2021",
"Distinction.")
.build(),
RowsSection.builder("Projects", RowStyle.BULLETED_STACKED)
.row("GraphCompose (Java, PDFBox)",
"Declarative PDF layout engine.")
.build(),
EntriesSection.builder("Professional Experience")
.entry("Senior Platform Engineer", "Acme",
"2021-2024",
"Built rendering services.")
.build(),
RowsSection.builder("Additional Information", RowStyle.PLAIN)
.row("Languages", "English, German")
.build())
.build();
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.