@gmoney2000/dygarn-pdf-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +155 -0
- package/dist/index.cjs +332 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +142 -0
- package/dist/index.d.ts +142 -0
- package/dist/index.js +292 -0
- package/dist/index.js.map +1 -0
- package/dist/pdf-lib.cjs +474 -0
- package/dist/pdf-lib.cjs.map +1 -0
- package/dist/pdf-lib.d.cts +119 -0
- package/dist/pdf-lib.d.ts +119 -0
- package/dist/pdf-lib.js +440 -0
- package/dist/pdf-lib.js.map +1 -0
- package/dist/react-pdf.cjs +241 -0
- package/dist/react-pdf.cjs.map +1 -0
- package/dist/react-pdf.d.cts +69 -0
- package/dist/react-pdf.d.ts +69 -0
- package/dist/react-pdf.js +211 -0
- package/dist/react-pdf.js.map +1 -0
- package/dist/types-CHgvU4U1.d.cts +37 -0
- package/dist/types-CHgvU4U1.d.ts +37 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# @gmoney2000/dygarn-pdf-kit
|
|
2
|
+
|
|
3
|
+
Branded PDF design system for the DyGarn ecosystem (RepFirm, dygarn-dashboard, future apps).
|
|
4
|
+
|
|
5
|
+
Shared visual primitives + style themes so quote, submittal, PO, and outreach kit PDFs across all DyGarn apps look like they came from the same shop.
|
|
6
|
+
|
|
7
|
+
## Why it exists
|
|
8
|
+
|
|
9
|
+
Each app (RepFirm, dygarn-dashboard) had its own PDF generation code with similar-but-drifting visual layouts. This package extracts the visual primitives so:
|
|
10
|
+
|
|
11
|
+
- **One source of truth** for the bookend header band, accent stripe, info section, line items table, totals box, footer
|
|
12
|
+
- **Same look** across all DyGarn ecosystem outputs no matter which app produced them
|
|
13
|
+
- **Composable** — each app picks the primitives it needs and supplies its own data + business logic
|
|
14
|
+
- **Brand-agnostic** — primitives take a generic `BrandInput` shape, so they work for both tenant-style branding (RepFirm) and prospect-style branding (dygarn-dashboard outreach)
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @gmoney2000/dygarn-pdf-kit
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Requires peer deps:
|
|
23
|
+
```bash
|
|
24
|
+
npm install @react-pdf/renderer pdf-lib react
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This is a public npm package. No auth needed.
|
|
28
|
+
|
|
29
|
+
## Exports
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// Core types + brand resolution + style themes
|
|
33
|
+
import { BrandInput, PdfStyle, resolvePdfStyle, resolveBrandTheme } from "@gmoney2000/dygarn-pdf-kit";
|
|
34
|
+
|
|
35
|
+
// React-PDF primitives (for @react-pdf/renderer-based docs)
|
|
36
|
+
import {
|
|
37
|
+
BookendHeader,
|
|
38
|
+
BookendFooter,
|
|
39
|
+
InfoSection,
|
|
40
|
+
LineItemsTable,
|
|
41
|
+
TotalsBox,
|
|
42
|
+
TermsBlock,
|
|
43
|
+
} from "@gmoney2000/dygarn-pdf-kit/react-pdf";
|
|
44
|
+
|
|
45
|
+
// pdf-lib primitives (for pdf-lib-based docs like submittal page assembly)
|
|
46
|
+
import {
|
|
47
|
+
drawBookendCover,
|
|
48
|
+
drawBookendHeader,
|
|
49
|
+
drawBookendFooter,
|
|
50
|
+
loadBookendFonts,
|
|
51
|
+
BOOKEND_HEADER_HEIGHT,
|
|
52
|
+
BOOKEND_FOOTER_HEIGHT,
|
|
53
|
+
} from "@gmoney2000/dygarn-pdf-kit/pdf-lib";
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
### Compose a simple quote (React-PDF)
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { Document, Page } from "@react-pdf/renderer";
|
|
62
|
+
import {
|
|
63
|
+
BookendHeader,
|
|
64
|
+
BookendFooter,
|
|
65
|
+
InfoSection,
|
|
66
|
+
LineItemsTable,
|
|
67
|
+
TotalsBox,
|
|
68
|
+
TermsBlock,
|
|
69
|
+
} from "@gmoney2000/dygarn-pdf-kit/react-pdf";
|
|
70
|
+
import { resolvePdfStyle, resolveBrandTheme } from "@gmoney2000/dygarn-pdf-kit";
|
|
71
|
+
|
|
72
|
+
const brand = {
|
|
73
|
+
agencyName: "EFC Sales",
|
|
74
|
+
logoUrl: "https://...",
|
|
75
|
+
primaryColor: "#0a2540",
|
|
76
|
+
// ... other BrandInput fields
|
|
77
|
+
};
|
|
78
|
+
const style = resolvePdfStyle("branded-bookend");
|
|
79
|
+
const theme = resolveBrandTheme(brand);
|
|
80
|
+
|
|
81
|
+
<Document>
|
|
82
|
+
<Page size="LETTER">
|
|
83
|
+
<BookendHeader theme={theme} brand={brand} docLabel="Quotation" docNumber="#Q-2026-1234" docDate="June 1, 2026" />
|
|
84
|
+
<InfoSection style={style} blocks={[{label: "Project", value: "Downtown Tower"}]} />
|
|
85
|
+
<LineItemsTable style={style} lines={lines} mode="standard" />
|
|
86
|
+
<TotalsBox style={style} subtotal={1234.56} total={1234.56} />
|
|
87
|
+
<TermsBlock style={style} terms="Standard terms..." />
|
|
88
|
+
<BookendFooter theme={theme} brand={brand} docDate="June 1, 2026" />
|
|
89
|
+
</Page>
|
|
90
|
+
</Document>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Submittal page assembly (pdf-lib)
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { PDFDocument } from "pdf-lib";
|
|
97
|
+
import { drawBookendCover, drawBookendHeader, drawBookendFooter, loadBookendFonts } from "@gmoney2000/dygarn-pdf-kit/pdf-lib";
|
|
98
|
+
|
|
99
|
+
const pdf = await PDFDocument.create();
|
|
100
|
+
const fonts = await loadBookendFonts(pdf);
|
|
101
|
+
await drawBookendCover(pdf, { brand, fonts, title: "Submittal Package", projectName: "..." });
|
|
102
|
+
// concat external spec sheets ...
|
|
103
|
+
// drawBookendHeader / drawBookendFooter on each generated page
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Brand input
|
|
107
|
+
|
|
108
|
+
The package is brand-agnostic. Adapter functions live in `src/brand.ts`:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
// RepFirm
|
|
112
|
+
import { brandFromTenantBranding } from "@gmoney2000/dygarn-pdf-kit";
|
|
113
|
+
const brand = brandFromTenantBranding(tenantBranding);
|
|
114
|
+
|
|
115
|
+
// dygarn-dashboard
|
|
116
|
+
import { brandFromProspectBrand } from "@gmoney2000/dygarn-pdf-kit";
|
|
117
|
+
const brand = brandFromProspectBrand(prospectBrand);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Both produce the same `BrandInput` shape that all primitives consume.
|
|
121
|
+
|
|
122
|
+
## Style themes
|
|
123
|
+
|
|
124
|
+
Five visual styles ported from RepFirm:
|
|
125
|
+
|
|
126
|
+
- `branded-bookend` (default) — dark band + accent stripe + cream info strip
|
|
127
|
+
- `bold` — heavy color blocks
|
|
128
|
+
- `classic` — traditional rep-agency look
|
|
129
|
+
- `minimal` — clean white space
|
|
130
|
+
- `modern` — geometric / contemporary
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
const style = resolvePdfStyle("branded-bookend"); // returns full PdfStyle contract
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npm install
|
|
140
|
+
npm run build # produces dist/
|
|
141
|
+
npm run dev # watch mode
|
|
142
|
+
npm run typecheck
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Publishing
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npm version patch # or minor / major
|
|
149
|
+
npm publish # publishes to GitHub Packages (private)
|
|
150
|
+
git push --follow-tags
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
Proprietary. © DyGarn Technical Solutions.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
DEFAULT_PDF_STYLE_ID: () => DEFAULT_PDF_STYLE_ID,
|
|
24
|
+
PDF_STYLES: () => PDF_STYLES,
|
|
25
|
+
PDF_STYLE_LIST: () => PDF_STYLE_LIST,
|
|
26
|
+
boldStyle: () => boldStyle,
|
|
27
|
+
brandFromProspectBrand: () => brandFromProspectBrand,
|
|
28
|
+
brandFromTenantBranding: () => brandFromTenantBranding,
|
|
29
|
+
classicStyle: () => classicStyle,
|
|
30
|
+
darkenHex: () => darkenHex,
|
|
31
|
+
hexToRgb01: () => hexToRgb01,
|
|
32
|
+
minimalStyle: () => minimalStyle,
|
|
33
|
+
modernStyle: () => modernStyle,
|
|
34
|
+
resolveBandThemeMode: () => resolveBandThemeMode,
|
|
35
|
+
resolveBestLogoUrl: () => resolveBestLogoUrl,
|
|
36
|
+
resolvePdfStyle: () => resolvePdfStyle
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(src_exports);
|
|
39
|
+
|
|
40
|
+
// src/brand.ts
|
|
41
|
+
function brandFromTenantBranding(tenantName, branding, fallbackPrimary = "#1e3a5f") {
|
|
42
|
+
const b = branding ?? {};
|
|
43
|
+
return {
|
|
44
|
+
agencyName: tenantName,
|
|
45
|
+
primaryColor: b.primary_color ?? fallbackPrimary,
|
|
46
|
+
logoUrl: b.logo_url ?? null,
|
|
47
|
+
logoDarkUrl: b.logo_dark_url ?? null,
|
|
48
|
+
logoLightUrl: b.logo_light_url ?? null,
|
|
49
|
+
logoWordmarkUrl: b.logo_wordmark_url ?? null,
|
|
50
|
+
logoMarkUrl: b.logo_mark_url ?? null,
|
|
51
|
+
pdfHeaderTheme: b.pdf_header_theme ?? "auto",
|
|
52
|
+
themeVars: b.theme_vars ?? {},
|
|
53
|
+
tagline: b.tagline ?? null,
|
|
54
|
+
address: b.company_address ?? null,
|
|
55
|
+
phone: b.company_phone ?? null,
|
|
56
|
+
email: b.company_email ?? null
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function brandFromProspectBrand(p) {
|
|
60
|
+
const agency = p.agencyName ?? p.agency_name ?? "Agency";
|
|
61
|
+
return {
|
|
62
|
+
agencyName: agency,
|
|
63
|
+
legalName: p.legalName ?? p.legal_name ?? null,
|
|
64
|
+
logoUrl: p.logoUrl ?? p.logo_url ?? null,
|
|
65
|
+
primaryColor: p.primaryColor ?? p.primary_color ?? "#1a73e8",
|
|
66
|
+
address: p.address ?? null,
|
|
67
|
+
phone: p.phone ?? null,
|
|
68
|
+
website: p.website ?? null,
|
|
69
|
+
pdfHeaderTheme: "auto"
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function resolveBandThemeMode(brand) {
|
|
73
|
+
if (brand.pdfHeaderTheme === "dark") return "dark";
|
|
74
|
+
if (brand.pdfHeaderTheme === "light") return "light";
|
|
75
|
+
if (brand.logoDarkUrl) return "dark";
|
|
76
|
+
const candidate = (brand.logoWordmarkUrl ?? brand.logoUrl ?? brand.logoMarkUrl ?? "").toLowerCase();
|
|
77
|
+
if (candidate.includes("white") || candidate.includes("-on-dark") || candidate.includes("_dark")) return "dark";
|
|
78
|
+
return "light";
|
|
79
|
+
}
|
|
80
|
+
function resolveBestLogoUrl(brand, mode) {
|
|
81
|
+
if (mode === "dark") {
|
|
82
|
+
return brand.logoDarkUrl ?? brand.logoUrl ?? brand.logoWordmarkUrl ?? brand.logoMarkUrl ?? null;
|
|
83
|
+
}
|
|
84
|
+
return brand.logoLightUrl ?? brand.logoUrl ?? brand.logoWordmarkUrl ?? brand.logoMarkUrl ?? brand.logoDarkUrl ?? null;
|
|
85
|
+
}
|
|
86
|
+
function darkenHex(hex, amount) {
|
|
87
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(hex);
|
|
88
|
+
if (!m) return hex;
|
|
89
|
+
const n = Number.parseInt(m[1], 16);
|
|
90
|
+
let r = n >> 16 & 255;
|
|
91
|
+
let g = n >> 8 & 255;
|
|
92
|
+
let b = n & 255;
|
|
93
|
+
r = Math.max(0, Math.round(r * (1 - amount)));
|
|
94
|
+
g = Math.max(0, Math.round(g * (1 - amount)));
|
|
95
|
+
b = Math.max(0, Math.round(b * (1 - amount)));
|
|
96
|
+
return `#${[r, g, b].map((c) => c.toString(16).padStart(2, "0")).join("")}`;
|
|
97
|
+
}
|
|
98
|
+
function hexToRgb01(hex) {
|
|
99
|
+
const h = hex.replace("#", "").trim();
|
|
100
|
+
const r = Number.parseInt(h.slice(0, 2), 16) / 255;
|
|
101
|
+
const g = Number.parseInt(h.slice(2, 4), 16) / 255;
|
|
102
|
+
const b = Number.parseInt(h.slice(4, 6), 16) / 255;
|
|
103
|
+
return [Number.isFinite(r) ? r : 0.12, Number.isFinite(g) ? g : 0.23, Number.isFinite(b) ? b : 0.37];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/styles/bold.ts
|
|
107
|
+
var boldStyle = {
|
|
108
|
+
id: "bold",
|
|
109
|
+
label: "Bold",
|
|
110
|
+
description: "Heavy colored header and big typography. Brand-forward look.",
|
|
111
|
+
colors: {
|
|
112
|
+
text: "#0f1420",
|
|
113
|
+
textMuted: "#5a6378",
|
|
114
|
+
textInverse: "#ffffff",
|
|
115
|
+
accent: "#d97706",
|
|
116
|
+
accentLight: "#fff4e6",
|
|
117
|
+
border: "#e5d4bd",
|
|
118
|
+
rowAlt: "#fffaf2",
|
|
119
|
+
headerBg: "#0f1420",
|
|
120
|
+
headerText: "#ffffff",
|
|
121
|
+
tableHeaderBg: "#d97706",
|
|
122
|
+
tableHeaderText: "#ffffff",
|
|
123
|
+
surface: "#ffffff"
|
|
124
|
+
},
|
|
125
|
+
fonts: {
|
|
126
|
+
body: "Helvetica",
|
|
127
|
+
heading: "Helvetica-Bold",
|
|
128
|
+
mono: "Helvetica-Bold",
|
|
129
|
+
sizeBase: 9,
|
|
130
|
+
sizeLabel: 7,
|
|
131
|
+
sizeHeading: 14,
|
|
132
|
+
sizeHuge: 28,
|
|
133
|
+
letterSpacingHeading: 1
|
|
134
|
+
},
|
|
135
|
+
layout: {
|
|
136
|
+
pagePaddingBottom: 50,
|
|
137
|
+
sectionPaddingHorizontal: 40,
|
|
138
|
+
headerPaddingVertical: 36,
|
|
139
|
+
accentBarHeight: 6,
|
|
140
|
+
tableRadius: 2,
|
|
141
|
+
zebra: true,
|
|
142
|
+
showInfoSection: true,
|
|
143
|
+
infoSectionBg: "accent"
|
|
144
|
+
},
|
|
145
|
+
header: {
|
|
146
|
+
variant: "bold-block",
|
|
147
|
+
logoWidth: 90,
|
|
148
|
+
logoHeight: 54,
|
|
149
|
+
agencyNameSize: 24,
|
|
150
|
+
titleSize: 8,
|
|
151
|
+
numberSize: 32
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// src/styles/classic.ts
|
|
156
|
+
var classicStyle = {
|
|
157
|
+
id: "classic",
|
|
158
|
+
label: "Classic",
|
|
159
|
+
description: "Dark navy header band with steel-blue accent. Professional and traditional.",
|
|
160
|
+
colors: {
|
|
161
|
+
text: "#1a2535",
|
|
162
|
+
textMuted: "#6b7a8a",
|
|
163
|
+
textInverse: "#ffffff",
|
|
164
|
+
accent: "#4a7aa0",
|
|
165
|
+
accentLight: "#e8f2ed",
|
|
166
|
+
border: "#d4dbe3",
|
|
167
|
+
rowAlt: "#f7f9f8",
|
|
168
|
+
headerBg: "#2c3e50",
|
|
169
|
+
headerText: "#ffffff",
|
|
170
|
+
tableHeaderBg: "#2c3e50",
|
|
171
|
+
tableHeaderText: "#a0b4c0",
|
|
172
|
+
surface: "#ffffff"
|
|
173
|
+
},
|
|
174
|
+
fonts: {
|
|
175
|
+
body: "Helvetica",
|
|
176
|
+
heading: "Helvetica-Bold",
|
|
177
|
+
mono: "Courier-Bold",
|
|
178
|
+
sizeBase: 9,
|
|
179
|
+
sizeLabel: 7,
|
|
180
|
+
sizeHeading: 12,
|
|
181
|
+
sizeHuge: 20,
|
|
182
|
+
letterSpacingHeading: 0.5
|
|
183
|
+
},
|
|
184
|
+
layout: {
|
|
185
|
+
pagePaddingBottom: 50,
|
|
186
|
+
sectionPaddingHorizontal: 40,
|
|
187
|
+
headerPaddingVertical: 28,
|
|
188
|
+
accentBarHeight: 3,
|
|
189
|
+
tableRadius: 4,
|
|
190
|
+
zebra: true,
|
|
191
|
+
showInfoSection: true,
|
|
192
|
+
infoSectionBg: "accent"
|
|
193
|
+
},
|
|
194
|
+
header: {
|
|
195
|
+
variant: "band",
|
|
196
|
+
logoWidth: 80,
|
|
197
|
+
logoHeight: 48,
|
|
198
|
+
agencyNameSize: 18,
|
|
199
|
+
titleSize: 7,
|
|
200
|
+
numberSize: 20
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// src/styles/minimal.ts
|
|
205
|
+
var minimalStyle = {
|
|
206
|
+
id: "minimal",
|
|
207
|
+
label: "Minimal",
|
|
208
|
+
description: "Monochrome and typographic. Hairline rules, no color blocks.",
|
|
209
|
+
colors: {
|
|
210
|
+
text: "#111111",
|
|
211
|
+
textMuted: "#6b6b6b",
|
|
212
|
+
textInverse: "#ffffff",
|
|
213
|
+
accent: "#111111",
|
|
214
|
+
accentLight: "#f5f5f5",
|
|
215
|
+
border: "#d4d4d4",
|
|
216
|
+
rowAlt: "#fafafa",
|
|
217
|
+
headerBg: "#ffffff",
|
|
218
|
+
headerText: "#111111",
|
|
219
|
+
tableHeaderBg: "#ffffff",
|
|
220
|
+
tableHeaderText: "#6b6b6b",
|
|
221
|
+
surface: "#ffffff"
|
|
222
|
+
},
|
|
223
|
+
fonts: {
|
|
224
|
+
body: "Helvetica",
|
|
225
|
+
heading: "Helvetica-Bold",
|
|
226
|
+
mono: "Courier",
|
|
227
|
+
sizeBase: 9,
|
|
228
|
+
sizeLabel: 6.5,
|
|
229
|
+
sizeHeading: 11,
|
|
230
|
+
sizeHuge: 18,
|
|
231
|
+
letterSpacingHeading: 2
|
|
232
|
+
},
|
|
233
|
+
layout: {
|
|
234
|
+
pagePaddingBottom: 55,
|
|
235
|
+
sectionPaddingHorizontal: 54,
|
|
236
|
+
headerPaddingVertical: 36,
|
|
237
|
+
accentBarHeight: 1,
|
|
238
|
+
tableRadius: 2,
|
|
239
|
+
zebra: false,
|
|
240
|
+
showInfoSection: true,
|
|
241
|
+
infoSectionBg: "none"
|
|
242
|
+
},
|
|
243
|
+
header: {
|
|
244
|
+
variant: "minimal",
|
|
245
|
+
logoWidth: 70,
|
|
246
|
+
logoHeight: 42,
|
|
247
|
+
agencyNameSize: 16,
|
|
248
|
+
titleSize: 7,
|
|
249
|
+
numberSize: 16
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// src/styles/modern.ts
|
|
254
|
+
var modernStyle = {
|
|
255
|
+
id: "modern",
|
|
256
|
+
label: "Modern",
|
|
257
|
+
description: "Light and airy with generous whitespace. Contemporary look.",
|
|
258
|
+
colors: {
|
|
259
|
+
text: "#18243a",
|
|
260
|
+
textMuted: "#5e7290",
|
|
261
|
+
textInverse: "#ffffff",
|
|
262
|
+
accent: "#5590b8",
|
|
263
|
+
accentLight: "#f4f8fb",
|
|
264
|
+
border: "#e5ecf3",
|
|
265
|
+
rowAlt: "#fafbfd",
|
|
266
|
+
headerBg: "#ffffff",
|
|
267
|
+
headerText: "#18243a",
|
|
268
|
+
tableHeaderBg: "#f4f8fb",
|
|
269
|
+
tableHeaderText: "#5e7290",
|
|
270
|
+
surface: "#ffffff"
|
|
271
|
+
},
|
|
272
|
+
fonts: {
|
|
273
|
+
body: "Helvetica",
|
|
274
|
+
heading: "Helvetica-Bold",
|
|
275
|
+
mono: "Courier-Bold",
|
|
276
|
+
sizeBase: 9.5,
|
|
277
|
+
sizeLabel: 7,
|
|
278
|
+
sizeHeading: 13,
|
|
279
|
+
sizeHuge: 22,
|
|
280
|
+
letterSpacingHeading: -0.3
|
|
281
|
+
},
|
|
282
|
+
layout: {
|
|
283
|
+
pagePaddingBottom: 60,
|
|
284
|
+
sectionPaddingHorizontal: 48,
|
|
285
|
+
headerPaddingVertical: 32,
|
|
286
|
+
accentBarHeight: 2,
|
|
287
|
+
tableRadius: 8,
|
|
288
|
+
zebra: true,
|
|
289
|
+
showInfoSection: true,
|
|
290
|
+
infoSectionBg: "surface"
|
|
291
|
+
},
|
|
292
|
+
header: {
|
|
293
|
+
variant: "hairline",
|
|
294
|
+
logoWidth: 90,
|
|
295
|
+
logoHeight: 54,
|
|
296
|
+
agencyNameSize: 22,
|
|
297
|
+
titleSize: 6.5,
|
|
298
|
+
numberSize: 24
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// src/styles/index.ts
|
|
303
|
+
var PDF_STYLES = {
|
|
304
|
+
classic: classicStyle,
|
|
305
|
+
modern: modernStyle,
|
|
306
|
+
minimal: minimalStyle,
|
|
307
|
+
bold: boldStyle
|
|
308
|
+
};
|
|
309
|
+
var PDF_STYLE_LIST = [classicStyle, modernStyle, minimalStyle, boldStyle];
|
|
310
|
+
var DEFAULT_PDF_STYLE_ID = "classic";
|
|
311
|
+
function resolvePdfStyle(id) {
|
|
312
|
+
if (id && id in PDF_STYLES) return PDF_STYLES[id];
|
|
313
|
+
return PDF_STYLES[DEFAULT_PDF_STYLE_ID];
|
|
314
|
+
}
|
|
315
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
316
|
+
0 && (module.exports = {
|
|
317
|
+
DEFAULT_PDF_STYLE_ID,
|
|
318
|
+
PDF_STYLES,
|
|
319
|
+
PDF_STYLE_LIST,
|
|
320
|
+
boldStyle,
|
|
321
|
+
brandFromProspectBrand,
|
|
322
|
+
brandFromTenantBranding,
|
|
323
|
+
classicStyle,
|
|
324
|
+
darkenHex,
|
|
325
|
+
hexToRgb01,
|
|
326
|
+
minimalStyle,
|
|
327
|
+
modernStyle,
|
|
328
|
+
resolveBandThemeMode,
|
|
329
|
+
resolveBestLogoUrl,
|
|
330
|
+
resolvePdfStyle
|
|
331
|
+
});
|
|
332
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/brand.ts","../src/styles/bold.ts","../src/styles/classic.ts","../src/styles/minimal.ts","../src/styles/modern.ts","../src/styles/index.ts"],"sourcesContent":["// Brand + brand adapters\nexport type { BrandInput } from \"./types\";\nexport {\n brandFromProspectBrand,\n brandFromTenantBranding,\n darkenHex,\n hexToRgb01,\n resolveBandThemeMode,\n resolveBestLogoUrl,\n} from \"./brand\";\nexport type { ProspectBrandShape, TenantBrandingShape } from \"./brand\";\n\n// Style contract + 4 themes\nexport {\n boldStyle,\n classicStyle,\n DEFAULT_PDF_STYLE_ID,\n minimalStyle,\n modernStyle,\n PDF_STYLE_LIST,\n PDF_STYLES,\n resolvePdfStyle,\n} from \"./styles\";\nexport type { PdfStyle, PdfStyleId } from \"./styles/types\";\n","import type { BrandInput } from \"./types\";\n\n/**\n * Adapter: RepFirm TenantBranding shape -> BrandInput.\n *\n * RepFirm tenants store branding on the `tenants.branding` JSONB column with\n * keys like primary_color, logo_url, logo_dark_url, etc. (snake_case). Pair\n * with the tenant name from the parent row when calling.\n */\nexport interface TenantBrandingShape {\n primary_color?: string;\n logo_url?: string | null;\n logo_wordmark_url?: string | null;\n logo_mark_url?: string | null;\n logo_dark_url?: string | null;\n logo_light_url?: string | null;\n pdf_header_theme?: \"dark\" | \"light\" | \"auto\";\n theme_vars?: Record<string, string>;\n tagline?: string | null;\n company_address?: string | null;\n company_phone?: string | null;\n company_email?: string | null;\n}\n\nexport function brandFromTenantBranding(\n tenantName: string,\n branding: TenantBrandingShape | null | undefined,\n fallbackPrimary = \"#1e3a5f\",\n): BrandInput {\n const b = branding ?? {};\n return {\n agencyName: tenantName,\n primaryColor: b.primary_color ?? fallbackPrimary,\n logoUrl: b.logo_url ?? null,\n logoDarkUrl: b.logo_dark_url ?? null,\n logoLightUrl: b.logo_light_url ?? null,\n logoWordmarkUrl: b.logo_wordmark_url ?? null,\n logoMarkUrl: b.logo_mark_url ?? null,\n pdfHeaderTheme: b.pdf_header_theme ?? \"auto\",\n themeVars: b.theme_vars ?? {},\n tagline: b.tagline ?? null,\n address: b.company_address ?? null,\n phone: b.company_phone ?? null,\n email: b.company_email ?? null,\n };\n}\n\n/**\n * Adapter: dygarn-dashboard prospect brand shape -> BrandInput.\n *\n * Dygarn-dashboard stores per-prospect brand kits in outreach_prospect_brands\n * with simpler shape (camelCase or snake — be liberal in what we accept).\n */\nexport interface ProspectBrandShape {\n agency_name?: string;\n agencyName?: string;\n legal_name?: string | null;\n legalName?: string | null;\n logo_url?: string | null;\n logoUrl?: string | null;\n primary_color?: string;\n primaryColor?: string;\n secondary_color?: string;\n secondaryColor?: string;\n address?: string | null;\n phone?: string | null;\n website?: string | null;\n}\n\nexport function brandFromProspectBrand(p: ProspectBrandShape): BrandInput {\n const agency = p.agencyName ?? p.agency_name ?? \"Agency\";\n return {\n agencyName: agency,\n legalName: p.legalName ?? p.legal_name ?? null,\n logoUrl: p.logoUrl ?? p.logo_url ?? null,\n primaryColor: p.primaryColor ?? p.primary_color ?? \"#1a73e8\",\n address: p.address ?? null,\n phone: p.phone ?? null,\n website: p.website ?? null,\n pdfHeaderTheme: \"auto\",\n };\n}\n\n/**\n * Determine whether to use a dark or light header band for this brand.\n *\n * - Explicit override: respect pdfHeaderTheme if set to 'dark' or 'light'.\n * - Auto (default): use dark theme only when a logoDarkUrl (white-on-dark\n * variant) is available, OR when the logo filename hints at a white/dark\n * variant. Otherwise default to LIGHT (safe for multi-color logos).\n */\nexport function resolveBandThemeMode(brand: BrandInput): \"dark\" | \"light\" {\n if (brand.pdfHeaderTheme === \"dark\") return \"dark\";\n if (brand.pdfHeaderTheme === \"light\") return \"light\";\n if (brand.logoDarkUrl) return \"dark\";\n const candidate = (brand.logoWordmarkUrl ?? brand.logoUrl ?? brand.logoMarkUrl ?? \"\").toLowerCase();\n if (candidate.includes(\"white\") || candidate.includes(\"-on-dark\") || candidate.includes(\"_dark\")) return \"dark\";\n return \"light\";\n}\n\n/**\n * Pick the best logo URL for the resolved theme mode.\n * Returns null if no logo available.\n */\nexport function resolveBestLogoUrl(brand: BrandInput, mode: \"dark\" | \"light\"): string | null {\n if (mode === \"dark\") {\n return brand.logoDarkUrl ?? brand.logoUrl ?? brand.logoWordmarkUrl ?? brand.logoMarkUrl ?? null;\n }\n return (\n brand.logoLightUrl ?? brand.logoUrl ?? brand.logoWordmarkUrl ?? brand.logoMarkUrl ?? brand.logoDarkUrl ?? null\n );\n}\n\n/**\n * Darken a hex color by a 0-1 amount. Used to derive a dark band color from\n * a brand primary when no explicit dark variant exists.\n */\nexport function darkenHex(hex: string, amount: number): string {\n const m = /^#?([0-9a-f]{6})$/i.exec(hex);\n if (!m) return hex;\n const n = Number.parseInt(m[1], 16);\n let r = (n >> 16) & 0xff;\n let g = (n >> 8) & 0xff;\n let b = n & 0xff;\n r = Math.max(0, Math.round(r * (1 - amount)));\n g = Math.max(0, Math.round(g * (1 - amount)));\n b = Math.max(0, Math.round(b * (1 - amount)));\n return `#${[r, g, b].map((c) => c.toString(16).padStart(2, \"0\")).join(\"\")}`;\n}\n\n/**\n * Convert hex to {r,g,b} normalized 0-1. Used by both React-PDF (color objects)\n * and pdf-lib (rgb() arguments).\n */\nexport function hexToRgb01(hex: string): [number, number, number] {\n const h = hex.replace(\"#\", \"\").trim();\n const r = Number.parseInt(h.slice(0, 2), 16) / 255;\n const g = Number.parseInt(h.slice(2, 4), 16) / 255;\n const b = Number.parseInt(h.slice(4, 6), 16) / 255;\n return [Number.isFinite(r) ? r : 0.12, Number.isFinite(g) ? g : 0.23, Number.isFinite(b) ? b : 0.37];\n}\n","import type { PdfStyle } from \"./types\";\n\nexport const boldStyle: PdfStyle = {\n id: \"bold\",\n label: \"Bold\",\n description: \"Heavy colored header and big typography. Brand-forward look.\",\n\n colors: {\n text: \"#0f1420\",\n textMuted: \"#5a6378\",\n textInverse: \"#ffffff\",\n accent: \"#d97706\",\n accentLight: \"#fff4e6\",\n border: \"#e5d4bd\",\n rowAlt: \"#fffaf2\",\n headerBg: \"#0f1420\",\n headerText: \"#ffffff\",\n tableHeaderBg: \"#d97706\",\n tableHeaderText: \"#ffffff\",\n surface: \"#ffffff\",\n },\n\n fonts: {\n body: \"Helvetica\",\n heading: \"Helvetica-Bold\",\n mono: \"Helvetica-Bold\",\n sizeBase: 9,\n sizeLabel: 7,\n sizeHeading: 14,\n sizeHuge: 28,\n letterSpacingHeading: 1,\n },\n\n layout: {\n pagePaddingBottom: 50,\n sectionPaddingHorizontal: 40,\n headerPaddingVertical: 36,\n accentBarHeight: 6,\n tableRadius: 2,\n zebra: true,\n showInfoSection: true,\n infoSectionBg: \"accent\",\n },\n\n header: {\n variant: \"bold-block\",\n logoWidth: 90,\n logoHeight: 54,\n agencyNameSize: 24,\n titleSize: 8,\n numberSize: 32,\n },\n};\n","import type { PdfStyle } from \"./types\";\n\nexport const classicStyle: PdfStyle = {\n id: \"classic\",\n label: \"Classic\",\n description: \"Dark navy header band with steel-blue accent. Professional and traditional.\",\n\n colors: {\n text: \"#1a2535\",\n textMuted: \"#6b7a8a\",\n textInverse: \"#ffffff\",\n accent: \"#4a7aa0\",\n accentLight: \"#e8f2ed\",\n border: \"#d4dbe3\",\n rowAlt: \"#f7f9f8\",\n headerBg: \"#2c3e50\",\n headerText: \"#ffffff\",\n tableHeaderBg: \"#2c3e50\",\n tableHeaderText: \"#a0b4c0\",\n surface: \"#ffffff\",\n },\n\n fonts: {\n body: \"Helvetica\",\n heading: \"Helvetica-Bold\",\n mono: \"Courier-Bold\",\n sizeBase: 9,\n sizeLabel: 7,\n sizeHeading: 12,\n sizeHuge: 20,\n letterSpacingHeading: 0.5,\n },\n\n layout: {\n pagePaddingBottom: 50,\n sectionPaddingHorizontal: 40,\n headerPaddingVertical: 28,\n accentBarHeight: 3,\n tableRadius: 4,\n zebra: true,\n showInfoSection: true,\n infoSectionBg: \"accent\",\n },\n\n header: {\n variant: \"band\",\n logoWidth: 80,\n logoHeight: 48,\n agencyNameSize: 18,\n titleSize: 7,\n numberSize: 20,\n },\n};\n","import type { PdfStyle } from \"./types\";\n\nexport const minimalStyle: PdfStyle = {\n id: \"minimal\",\n label: \"Minimal\",\n description: \"Monochrome and typographic. Hairline rules, no color blocks.\",\n\n colors: {\n text: \"#111111\",\n textMuted: \"#6b6b6b\",\n textInverse: \"#ffffff\",\n accent: \"#111111\",\n accentLight: \"#f5f5f5\",\n border: \"#d4d4d4\",\n rowAlt: \"#fafafa\",\n headerBg: \"#ffffff\",\n headerText: \"#111111\",\n tableHeaderBg: \"#ffffff\",\n tableHeaderText: \"#6b6b6b\",\n surface: \"#ffffff\",\n },\n\n fonts: {\n body: \"Helvetica\",\n heading: \"Helvetica-Bold\",\n mono: \"Courier\",\n sizeBase: 9,\n sizeLabel: 6.5,\n sizeHeading: 11,\n sizeHuge: 18,\n letterSpacingHeading: 2,\n },\n\n layout: {\n pagePaddingBottom: 55,\n sectionPaddingHorizontal: 54,\n headerPaddingVertical: 36,\n accentBarHeight: 1,\n tableRadius: 2,\n zebra: false,\n showInfoSection: true,\n infoSectionBg: \"none\",\n },\n\n header: {\n variant: \"minimal\",\n logoWidth: 70,\n logoHeight: 42,\n agencyNameSize: 16,\n titleSize: 7,\n numberSize: 16,\n },\n};\n","import type { PdfStyle } from \"./types\";\n\nexport const modernStyle: PdfStyle = {\n id: \"modern\",\n label: \"Modern\",\n description: \"Light and airy with generous whitespace. Contemporary look.\",\n\n colors: {\n text: \"#18243a\",\n textMuted: \"#5e7290\",\n textInverse: \"#ffffff\",\n accent: \"#5590b8\",\n accentLight: \"#f4f8fb\",\n border: \"#e5ecf3\",\n rowAlt: \"#fafbfd\",\n headerBg: \"#ffffff\",\n headerText: \"#18243a\",\n tableHeaderBg: \"#f4f8fb\",\n tableHeaderText: \"#5e7290\",\n surface: \"#ffffff\",\n },\n\n fonts: {\n body: \"Helvetica\",\n heading: \"Helvetica-Bold\",\n mono: \"Courier-Bold\",\n sizeBase: 9.5,\n sizeLabel: 7,\n sizeHeading: 13,\n sizeHuge: 22,\n letterSpacingHeading: -0.3,\n },\n\n layout: {\n pagePaddingBottom: 60,\n sectionPaddingHorizontal: 48,\n headerPaddingVertical: 32,\n accentBarHeight: 2,\n tableRadius: 8,\n zebra: true,\n showInfoSection: true,\n infoSectionBg: \"surface\",\n },\n\n header: {\n variant: \"hairline\",\n logoWidth: 90,\n logoHeight: 54,\n agencyNameSize: 22,\n titleSize: 6.5,\n numberSize: 24,\n },\n};\n","import { boldStyle } from \"./bold\";\nimport { classicStyle } from \"./classic\";\nimport { minimalStyle } from \"./minimal\";\nimport { modernStyle } from \"./modern\";\nimport type { PdfStyle, PdfStyleId } from \"./types\";\n\nexport const PDF_STYLES: Record<PdfStyleId, PdfStyle> = {\n classic: classicStyle,\n modern: modernStyle,\n minimal: minimalStyle,\n bold: boldStyle,\n};\n\nexport const PDF_STYLE_LIST: PdfStyle[] = [classicStyle, modernStyle, minimalStyle, boldStyle];\n\nexport const DEFAULT_PDF_STYLE_ID: PdfStyleId = \"classic\";\n\nexport function resolvePdfStyle(id: string | null | undefined): PdfStyle {\n if (id && id in PDF_STYLES) return PDF_STYLES[id as PdfStyleId];\n return PDF_STYLES[DEFAULT_PDF_STYLE_ID];\n}\n\nexport { boldStyle, classicStyle, minimalStyle, modernStyle };\nexport type { PdfStyle, PdfStyleId } from \"./types\";\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { B as BrandInput } from './types-CHgvU4U1.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Adapter: RepFirm TenantBranding shape -> BrandInput.
|
|
5
|
+
*
|
|
6
|
+
* RepFirm tenants store branding on the `tenants.branding` JSONB column with
|
|
7
|
+
* keys like primary_color, logo_url, logo_dark_url, etc. (snake_case). Pair
|
|
8
|
+
* with the tenant name from the parent row when calling.
|
|
9
|
+
*/
|
|
10
|
+
interface TenantBrandingShape {
|
|
11
|
+
primary_color?: string;
|
|
12
|
+
logo_url?: string | null;
|
|
13
|
+
logo_wordmark_url?: string | null;
|
|
14
|
+
logo_mark_url?: string | null;
|
|
15
|
+
logo_dark_url?: string | null;
|
|
16
|
+
logo_light_url?: string | null;
|
|
17
|
+
pdf_header_theme?: "dark" | "light" | "auto";
|
|
18
|
+
theme_vars?: Record<string, string>;
|
|
19
|
+
tagline?: string | null;
|
|
20
|
+
company_address?: string | null;
|
|
21
|
+
company_phone?: string | null;
|
|
22
|
+
company_email?: string | null;
|
|
23
|
+
}
|
|
24
|
+
declare function brandFromTenantBranding(tenantName: string, branding: TenantBrandingShape | null | undefined, fallbackPrimary?: string): BrandInput;
|
|
25
|
+
/**
|
|
26
|
+
* Adapter: dygarn-dashboard prospect brand shape -> BrandInput.
|
|
27
|
+
*
|
|
28
|
+
* Dygarn-dashboard stores per-prospect brand kits in outreach_prospect_brands
|
|
29
|
+
* with simpler shape (camelCase or snake — be liberal in what we accept).
|
|
30
|
+
*/
|
|
31
|
+
interface ProspectBrandShape {
|
|
32
|
+
agency_name?: string;
|
|
33
|
+
agencyName?: string;
|
|
34
|
+
legal_name?: string | null;
|
|
35
|
+
legalName?: string | null;
|
|
36
|
+
logo_url?: string | null;
|
|
37
|
+
logoUrl?: string | null;
|
|
38
|
+
primary_color?: string;
|
|
39
|
+
primaryColor?: string;
|
|
40
|
+
secondary_color?: string;
|
|
41
|
+
secondaryColor?: string;
|
|
42
|
+
address?: string | null;
|
|
43
|
+
phone?: string | null;
|
|
44
|
+
website?: string | null;
|
|
45
|
+
}
|
|
46
|
+
declare function brandFromProspectBrand(p: ProspectBrandShape): BrandInput;
|
|
47
|
+
/**
|
|
48
|
+
* Determine whether to use a dark or light header band for this brand.
|
|
49
|
+
*
|
|
50
|
+
* - Explicit override: respect pdfHeaderTheme if set to 'dark' or 'light'.
|
|
51
|
+
* - Auto (default): use dark theme only when a logoDarkUrl (white-on-dark
|
|
52
|
+
* variant) is available, OR when the logo filename hints at a white/dark
|
|
53
|
+
* variant. Otherwise default to LIGHT (safe for multi-color logos).
|
|
54
|
+
*/
|
|
55
|
+
declare function resolveBandThemeMode(brand: BrandInput): "dark" | "light";
|
|
56
|
+
/**
|
|
57
|
+
* Pick the best logo URL for the resolved theme mode.
|
|
58
|
+
* Returns null if no logo available.
|
|
59
|
+
*/
|
|
60
|
+
declare function resolveBestLogoUrl(brand: BrandInput, mode: "dark" | "light"): string | null;
|
|
61
|
+
/**
|
|
62
|
+
* Darken a hex color by a 0-1 amount. Used to derive a dark band color from
|
|
63
|
+
* a brand primary when no explicit dark variant exists.
|
|
64
|
+
*/
|
|
65
|
+
declare function darkenHex(hex: string, amount: number): string;
|
|
66
|
+
/**
|
|
67
|
+
* Convert hex to {r,g,b} normalized 0-1. Used by both React-PDF (color objects)
|
|
68
|
+
* and pdf-lib (rgb() arguments).
|
|
69
|
+
*/
|
|
70
|
+
declare function hexToRgb01(hex: string): [number, number, number];
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* PDF style contract. All branded paperwork (quotes, POs, packing slips,
|
|
74
|
+
* invoices) consumes a PdfStyle to render. Switching a tenant's style changes
|
|
75
|
+
* every PDF at once.
|
|
76
|
+
*
|
|
77
|
+
* Structure stays identical across styles - only colors, fonts, spacing, and
|
|
78
|
+
* visual accents vary.
|
|
79
|
+
*/
|
|
80
|
+
type PdfStyleId = "classic" | "modern" | "minimal" | "bold";
|
|
81
|
+
interface PdfStyle {
|
|
82
|
+
id: PdfStyleId;
|
|
83
|
+
label: string;
|
|
84
|
+
description: string;
|
|
85
|
+
colors: {
|
|
86
|
+
text: string;
|
|
87
|
+
textMuted: string;
|
|
88
|
+
textInverse: string;
|
|
89
|
+
accent: string;
|
|
90
|
+
accentLight: string;
|
|
91
|
+
border: string;
|
|
92
|
+
rowAlt: string;
|
|
93
|
+
headerBg: string;
|
|
94
|
+
headerText: string;
|
|
95
|
+
tableHeaderBg: string;
|
|
96
|
+
tableHeaderText: string;
|
|
97
|
+
surface: string;
|
|
98
|
+
};
|
|
99
|
+
fonts: {
|
|
100
|
+
body: string;
|
|
101
|
+
heading: string;
|
|
102
|
+
mono: string;
|
|
103
|
+
sizeBase: number;
|
|
104
|
+
sizeLabel: number;
|
|
105
|
+
sizeHeading: number;
|
|
106
|
+
sizeHuge: number;
|
|
107
|
+
letterSpacingHeading: number;
|
|
108
|
+
};
|
|
109
|
+
layout: {
|
|
110
|
+
pagePaddingBottom: number;
|
|
111
|
+
sectionPaddingHorizontal: number;
|
|
112
|
+
headerPaddingVertical: number;
|
|
113
|
+
accentBarHeight: number;
|
|
114
|
+
tableRadius: number;
|
|
115
|
+
zebra: boolean;
|
|
116
|
+
showInfoSection: boolean;
|
|
117
|
+
infoSectionBg: "accent" | "surface" | "none";
|
|
118
|
+
};
|
|
119
|
+
header: {
|
|
120
|
+
variant: "band" | "hairline" | "minimal" | "bold-block";
|
|
121
|
+
logoWidth: number;
|
|
122
|
+
logoHeight: number;
|
|
123
|
+
agencyNameSize: number;
|
|
124
|
+
titleSize: number;
|
|
125
|
+
numberSize: number;
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
declare const boldStyle: PdfStyle;
|
|
130
|
+
|
|
131
|
+
declare const classicStyle: PdfStyle;
|
|
132
|
+
|
|
133
|
+
declare const minimalStyle: PdfStyle;
|
|
134
|
+
|
|
135
|
+
declare const modernStyle: PdfStyle;
|
|
136
|
+
|
|
137
|
+
declare const PDF_STYLES: Record<PdfStyleId, PdfStyle>;
|
|
138
|
+
declare const PDF_STYLE_LIST: PdfStyle[];
|
|
139
|
+
declare const DEFAULT_PDF_STYLE_ID: PdfStyleId;
|
|
140
|
+
declare function resolvePdfStyle(id: string | null | undefined): PdfStyle;
|
|
141
|
+
|
|
142
|
+
export { BrandInput, DEFAULT_PDF_STYLE_ID, PDF_STYLES, PDF_STYLE_LIST, type PdfStyle, type PdfStyleId, type ProspectBrandShape, type TenantBrandingShape, boldStyle, brandFromProspectBrand, brandFromTenantBranding, classicStyle, darkenHex, hexToRgb01, minimalStyle, modernStyle, resolveBandThemeMode, resolveBestLogoUrl, resolvePdfStyle };
|