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
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ follow semantic versioning; release dates are ISO 8601.

### Templates

- **A second structured proposal preset: `EditorialProposal`.** The same document the
`NorthlineProposal` preset renders, in a different hand: an orange accent, section
headings set in the display serif over short accent rules instead of in the body sans
inside icon badges, a brand mark drawn from vector paths instead of a monogram letter,
an untitled fact card, a scope ordinal set in plain accent text, and a hairline page
foot. Moving a document between the two presets is a one-line change plus two data
checks — the badge and goal icon tokens are preset-scoped (the four `fact-*` tokens
are not), and headings are drawn as authored, so the sibling's tracked capitals stay
capitals here. Ships as
`proposal.presets.EditorialProposal` on the structured proposal model, porting the
rendered layout of the published standalone `northline-proposal-orange` template,
with its SVG icon set packaged in the artifact. Guarded by a smoke test (including
the empty document, both data contracts, and the proof that one document renders
through both proposal presets), an exact two-page layout snapshot, and a
pixel-parity gate; the examples showcase gains `proposal-editorial-v2`.

- **A professional-services invoice preset: `ConsultingInvoice`.** A corporate masthead
— brand lockup and contact channels beside the document title and its metadata —
over priced service lines that carry a service period and a unit per line, closing
Expand Down
Binary file added assets/readme/examples/proposal-editorial-v2.pdf
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import com.demcha.examples.templates.invoice.InvoiceCinematicFileExample;
import com.demcha.examples.templates.invoice.ModernInvoiceV2Example;
import com.demcha.examples.templates.proposal.CinematicProposalFileExample;
import com.demcha.examples.templates.proposal.EditorialProposalV2Example;
import com.demcha.examples.templates.proposal.NorthlineProposalV2Example;
import com.demcha.examples.templates.proposal.ProposalCinematicFileExample;
import com.demcha.examples.templates.proposal.ModernProposalV2Example;
Expand Down Expand Up @@ -172,6 +173,7 @@ public static void main(String[] args) throws Exception {
System.out.println("Generated: " + ProposalCinematicFileExample.generate());
System.out.println("Generated: " + ModernProposalV2Example.generate());
System.out.println("Generated: " + NorthlineProposalV2Example.generate());
System.out.println("Generated: " + EditorialProposalV2Example.generate());
System.out.println("Generated: " + CinematicProposalFileExample.generate());

// Schedule
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package com.demcha.examples.support;

import com.demcha.compose.document.templates.data.proposal.ProposalAcceptance;
import com.demcha.compose.document.templates.data.proposal.ProposalBrand;
import com.demcha.compose.document.templates.data.proposal.ProposalDeliverables;
import com.demcha.compose.document.templates.data.proposal.ProposalGlance;
import com.demcha.compose.document.templates.data.proposal.ProposalGoals;
import com.demcha.compose.document.templates.data.proposal.ProposalInvestment;
import com.demcha.compose.document.templates.data.proposal.ProposalMetaLine;
import com.demcha.compose.document.templates.data.proposal.ProposalPhaseGrid;
import com.demcha.compose.document.templates.data.proposal.ProposalScope;
import com.demcha.compose.document.templates.data.proposal.ProposalSummaryBlock;
import com.demcha.compose.document.templates.data.proposal.ProposalTermsBlock;
import com.demcha.compose.document.templates.data.proposal.ProposalTitleLines;
import com.demcha.compose.document.templates.data.proposal.StructuredProposalData;
import com.demcha.compose.document.templates.data.proposal.StructuredProposalDocumentSpec;

import java.util.List;

/**
* Shared sample data for the Editorial proposal example.
*
* <p>Kept in lockstep with the qa module's
* {@code EditorialProposalFixtures} — the two modules cannot share a source
* file, so a content change here belongs there too.</p>
*
* <p>The sample is the preset's reference content: a two-page
* brand-refresh proposal exercising every band — all four glance facts
* (one with the optional note), four goal cells, five scope rows, both
* deliverable columns, the four-phase grid, an investment table with
* ordinary, subtotal and optional rows plus the total band, four terms,
* and the three-field signing card.</p>
*
*/
public final class EditorialProposalSampleData {

private EditorialProposalSampleData() {
}

public static StructuredProposalDocumentSpec sample() {
return StructuredProposalDocumentSpec.from(StructuredProposalData.builder()
.brand(new ProposalBrand("N", "NORTHLINE", "STUDIO", "PROPOSAL",
"northlinestudio.com", "NORTHLINE STUDIO"))
.title(new ProposalTitleLines("Proposal —", "Brand Refresh &",
"Website Redesign"))
.meta(new ProposalMetaLine("PREPARED FOR ASTERA HEALTH CO.",
"PREPARED BY NORTHLINE STUDIO", "25 AUGUST 2026"))
.executiveSummary(new ProposalSummaryBlock("Executive Summary", "", List.of(
"Thank you for the opportunity to partner with Astera Health Co. "
+ "on your next chapter. This proposal outlines our approach to "
+ "refreshing your brand identity and redesigning your website to "
+ "better reflect your mission, elevate credibility, and deliver a "
+ "seamless experience for the people you serve.",
"Our process blends strategic thinking with thoughtful design to "
+ "create a cohesive brand system and a modern, conversion-focused "
+ "website. The outcome will be a clear, confident presence that "
+ "strengthens trust, improves engagement, and supports your "
+ "growth goals.")))
.glance(new ProposalGlance("", List.of(
new ProposalGlance.Fact("fact-duration", "PROJECT DURATION",
"6 weeks", null),
new ProposalGlance.Fact("fact-start", "START WINDOW",
"September 2026", null),
new ProposalGlance.Fact("fact-contact", "PRIMARY CONTACT",
"Project Lead", null),
new ProposalGlance.Fact("fact-validity", "PROPOSAL VALIDITY",
"14 days", "(until 8 September 2026)"))))
.goals(new ProposalGoals("Project Goals", "goal-check", List.of(
new ProposalGoals.Goal("",
"Strengthen brand credibility and visual consistency."),
new ProposalGoals.Goal("",
"Improve website usability and drive meaningful action."),
new ProposalGoals.Goal("",
"Communicate your value clearly across all touchpoints."),
new ProposalGoals.Goal("",
"Build a scalable digital foundation for future growth."))))
.scope(new ProposalScope("Scope of Work", "", List.of(
new ProposalScope.Item("01", "Discovery & Research",
"Stakeholder interviews, brand audit, competitor review, and "
+ "audience insights to inform strategy."),
new ProposalScope.Item("02", "Visual Identity Refinement",
"Refine logo system, color palette, typography, and visual "
+ "guidelines for a cohesive, modern identity."),
new ProposalScope.Item("03", "Website UX/UI Design",
"Design a responsive, accessibility-minded website with "
+ "intuitive navigation and clear conversion pathways."),
new ProposalScope.Item("04", "Content Structure & Messaging",
"Define site architecture, key messaging, and content "
+ "hierarchy to communicate value and build trust."),
new ProposalScope.Item("05", "Launch Support",
"Developer handoff, QA support, training, and go-live "
+ "assistance to ensure a smooth launch."))))
.deliverables(new ProposalDeliverables("Deliverables", "",
List.of("Brand strategy summary",
"Refined logo suite & brand guidelines",
"Color, typography & design system",
"Website UX wireframes",
"High-fidelity website designs"),
List.of("Responsive design for desktop, tablet & mobile",
"Content strategy & page templates",
"Developer-ready assets & specifications",
"Launch checklist & training session")))
.timeline(new ProposalPhaseGrid("Timeline", "",
List.of("PHASE", "FOCUS", "DURATION", "OUTPUT"), List.of(
new ProposalPhaseGrid.Phase("01", "Discover",
"Research, audit, insights, and strategy", "1 week",
"Discovery report & creative direction"),
new ProposalPhaseGrid.Phase("02", "Design",
"Brand refinement and website UX/UI design", "2 weeks",
"Design system & high-fidelity designs"),
new ProposalPhaseGrid.Phase("03", "Develop Prep",
"Content structure, developer handoff & asset preparation",
"1 week", "Specs, assets & content framework"),
new ProposalPhaseGrid.Phase("04", "Launch Support",
"QA, training & go-live assistance", "2 weeks",
"QA sign-off & successful launch"))))
.investment(new ProposalInvestment("Investment", "",
"ITEM", "AMOUNT (GBP)", List.of(
new ProposalInvestment.Row("Discovery & Strategy", "£2,500",
ProposalInvestment.Role.NONE),
new ProposalInvestment.Row("Brand Identity Refinement", "£4,500",
ProposalInvestment.Role.NONE),
new ProposalInvestment.Row("Website UX/UI Design", "£7,000",
ProposalInvestment.Role.NONE),
new ProposalInvestment.Row("Content Structure & Messaging", "£2,000",
ProposalInvestment.Role.NONE),
new ProposalInvestment.Row("Launch Support", "£1,500",
ProposalInvestment.Role.NONE),
new ProposalInvestment.Row("Subtotal", "£17,500",
ProposalInvestment.Role.SUBTOTAL),
new ProposalInvestment.Row("Optional: 3 Months Post-Launch Support",
"£1,750", ProposalInvestment.Role.OPTIONAL)),
"TOTAL INVESTMENT", "£19,250"))
.terms(new ProposalTermsBlock("Terms", "", List.of(
"50% deposit is required to secure the project and schedule the "
+ "kick-off.",
"Includes two rounds of revisions per major deliverable.",
"Final files and handoff delivered upon final payment.",
"Ownership of all final deliverables transfers to Astera Health Co. "
+ "after full payment is received.")))
.acceptance(new ProposalAcceptance("Acceptance", "",
"By signing below, you agree to the scope, timeline, investment, "
+ "and terms outlined in this proposal.",
List.of("Accepted by:", "Signature:", "Date:")))
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ record Entry(String title, String description, List<String> tags, String codeUrl
proposal("proposal-cinematic", "ProposalCinematicFileExample", "Cinematic Proposal", "Layered ModernProposal layout with cover panel, hero spread, and rich typography.", "proposal", "cinematic");
proposal("project-proposal-cinematic", "CinematicProposalFileExample", "Project Proposal (cinematic)", "End-to-end project proposal with mountain hero, scope panels, and pricing summary.", "proposal", "cinematic");
proposal("proposal-modern-v2", "v2/ModernProposalV2Example", "Modern Proposal", "The ModernProposal preset composed straight from its document spec — cover, scope sections and pricing table themed through BrandTheme.", "proposal");
proposal("proposal-editorial-v2", "v2/EditorialProposalV2Example", "Editorial Proposal", "The EditorialProposal preset — the same structured proposal document as Northline, set in a serif display face with an orange accent, a drawn brand mark and headings over accent rules.", "proposal");
proposal("proposal-northline-v2", "v2/NorthlineProposalV2Example", "Northline Proposal", "The NorthlineProposal preset on the structured proposal model — brand header, stacked title, glance card, goal cells, numbered scope, phase grid, investment table and signing card across two pages.", "proposal");

// ===== Templates / Schedule =====
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.demcha.examples.templates.proposal;

import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentSession;
import com.demcha.compose.document.templates.api.DocumentTemplate;
import com.demcha.compose.document.templates.data.proposal.StructuredProposalDocumentSpec;
import com.demcha.compose.document.templates.proposal.presets.EditorialProposal;
import com.demcha.examples.support.EditorialProposalSampleData;
import com.demcha.examples.support.ExampleOutputPaths;

import java.nio.file.Path;

/**
* Renders the layered {@code proposal.v2} Editorial Proposal preset against
* the structured proposal sample data.
*
* <p>Output:
* {@code examples/target/generated-pdfs/templates/proposal/proposal-editorial-v2.pdf}.</p>
*
* <p>The same document shape the Northline example renders, in the serif
* editorial look: the preset owns its page geometry, so the session starts
* unconfigured.</p>
*/
public final class EditorialProposalV2Example {

private EditorialProposalV2Example() {
}

/**
* @return absolute path of the rendered PDF
* @throws Exception if rendering fails
*/
public static Path generate() throws Exception {
Path outputFile = ExampleOutputPaths.prepare(
"templates/proposal", "proposal-editorial-v2.pdf");
StructuredProposalDocumentSpec spec = EditorialProposalSampleData.sample();
DocumentTemplate<StructuredProposalDocumentSpec> template = EditorialProposal.create();

try (DocumentSession document = GraphCompose.document(outputFile).create()) {
template.compose(document, spec);
document.buildPdf();
}
return outputFile;
}

/**
* @param args ignored
* @throws Exception if rendering fails
*/
public static void main(String[] args) throws Exception {
System.out.println("Generated: " + generate());
}
}
Loading
Loading