Add the Neutral template family, template picker and text-only logo allowances
Linea (the vendor's original format.pdf design), Monogram and Serenity are rebuilt from the reference PDFs as one parametric family on the engine, with the user's logo in the measured slot, a home for every GST field and A4/Letter support. Adds static Montserrat, Open Sans and Poppins fonts and a generated Ms Madi outline for Serenity's vertical word. Text-only logo placeholders (Monolith, Tangerine) use a doc-derived allowance box. A Carbon TemplatePicker with committed thumbnails opens from the page setup controls.
This commit is contained in:
+30
-11
@@ -3,7 +3,9 @@ import type { ReactNode } from "react";
|
||||
import type { PageFrame } from "./engine/geometry";
|
||||
import { chromeHeight } from "./engine/metrics";
|
||||
import type { RenderModel } from "./model/build";
|
||||
import type { TemplateDefinition } from "./templates/contract";
|
||||
import { AvailableWidthProvider } from "./blocks/AvailableWidth";
|
||||
import type { DecorItem } from "./blocks/FirstPageHeader";
|
||||
import { PageChrome } from "./blocks/PageChrome";
|
||||
|
||||
/** Height the footer strip takes inside the bottom padding: the text line, a 6 pt gap and the rule. */
|
||||
@@ -11,13 +13,10 @@ export const FOOTER_RESERVE = 24;
|
||||
/** Room above the content on pages 2+ for the continuation band, inside the top margin. */
|
||||
export const CONTINUATION_RESERVE = 18;
|
||||
|
||||
const CHROME_INK = "#6f6f6f";
|
||||
const RULE = "#e0e0e0";
|
||||
const FOOTER_LEFT_WIDTH = 170;
|
||||
|
||||
export interface InvoicePageProps {
|
||||
frame: PageFrame;
|
||||
model: RenderModel;
|
||||
template: TemplateDefinition;
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
@@ -26,25 +25,45 @@ export interface InvoicePageProps {
|
||||
* anywhere else), the flow is the template's, and the chrome (footer, continuation band) is added after
|
||||
* it as fixed page-level boxes. No lineHeight here: it would reach the render-prop page-number text.
|
||||
*/
|
||||
export function InvoicePage({ frame, model, children }: InvoicePageProps) {
|
||||
export function InvoicePage({ frame, model, template, children }: InvoicePageProps) {
|
||||
const { pad } = frame;
|
||||
const { chrome, decor } = template;
|
||||
const marginBottom = pad.bottom - frame.footerReserve;
|
||||
const ruleY = frame.page.height - marginBottom - chromeHeight("footer") - 6.6;
|
||||
const ruleY = frame.page.height - marginBottom - chromeHeight(chrome.role ?? "footer") - 6.6;
|
||||
const bandLeft = `${model.docTitle} ${model.meta.number} · ${model.meta.date}`;
|
||||
const items: DecorItem[] = [...(decor.everyPage?.(frame) ?? [])];
|
||||
if (chrome.rule) {
|
||||
items.push({ x: pad.left, y: ruleY, width: frame.contentWidth, height: 0.6, children: <View style={{ height: 0.6, backgroundColor: chrome.rule }} /> });
|
||||
}
|
||||
// The footer sits inside the template's text column, which may be narrower than the page content width.
|
||||
const inset = chrome.inset ?? { left: 0, right: 0 };
|
||||
const chromeFrame: PageFrame = {
|
||||
...frame,
|
||||
pad: { ...pad, left: pad.left + inset.left, right: pad.right + inset.right },
|
||||
contentWidth: frame.contentWidth - inset.left - inset.right,
|
||||
};
|
||||
return (
|
||||
<Page
|
||||
size={frame.page.size}
|
||||
style={{ paddingTop: pad.top, paddingRight: pad.right, paddingBottom: pad.bottom, paddingLeft: pad.left, color: "#161616" }}
|
||||
style={{
|
||||
paddingTop: pad.top,
|
||||
paddingRight: pad.right,
|
||||
paddingBottom: pad.bottom,
|
||||
paddingLeft: pad.left,
|
||||
color: decor.ink,
|
||||
...(decor.background ? { backgroundColor: decor.background } : {}),
|
||||
}}
|
||||
>
|
||||
<AvailableWidthProvider width={frame.contentWidth}>{children}</AvailableWidthProvider>
|
||||
<PageChrome
|
||||
frame={frame}
|
||||
frame={chromeFrame}
|
||||
footerLeft={model.supplier.name}
|
||||
footerLeftWidth={FOOTER_LEFT_WIDTH}
|
||||
footerLeftWidth={chrome.leftWidth}
|
||||
footerCenter={model.footerText}
|
||||
color={CHROME_INK}
|
||||
role={chrome.role}
|
||||
color={chrome.color}
|
||||
band={{ left: bandLeft, right: "continued" }}
|
||||
decor={[{ x: pad.left, y: ruleY, width: frame.contentWidth, height: 0.6, children: <View style={{ height: 0.6, backgroundColor: RULE }} /> }]}
|
||||
decor={items}
|
||||
/>
|
||||
</Page>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user