@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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react-pdf/bookend-header.tsx","../src/react-pdf/bookend-footer.tsx","../src/react-pdf/line-card-header.tsx","../src/brand.ts","../src/react-pdf/theme.ts"],"sourcesContent":["import * as React from \"react\";\nimport { Image, StyleSheet, Text, View } from \"@react-pdf/renderer\";\n\nimport type { BookendTheme } from \"./theme\";\n\nexport interface BookendHeaderProps {\n theme: BookendTheme;\n logoUrl: string | null;\n agencyName: string;\n /** Doc label like \"Quotation\" or \"Purchase Order\" */\n docLabel: string;\n /** Doc number like \"#Q-2026-1234\" */\n docNumber: string;\n /** Formatted date string */\n docDate: string;\n /** Optional second line below date (e.g. \"Expires ...\") */\n docExtra?: string;\n logoWidth?: number;\n logoHeight?: number;\n}\n\nconst styles = StyleSheet.create({\n bandRow: {\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n alignItems: \"flex-start\",\n paddingHorizontal: 40,\n paddingVertical: 22,\n },\n logoAndName: {\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 12,\n },\n agencyName: {\n fontSize: 18,\n fontFamily: \"Helvetica-Bold\",\n letterSpacing: 0.5,\n },\n agencyTagline: {\n fontSize: 7.5,\n marginTop: 4,\n letterSpacing: 0.5,\n },\n metaBox: { alignItems: \"flex-end\" },\n metaLabel: {\n fontSize: 7,\n letterSpacing: 2,\n textTransform: \"uppercase\",\n marginBottom: 3,\n },\n metaNum: {\n fontSize: 20,\n fontFamily: \"Courier-Bold\",\n marginTop: 2,\n },\n metaDate: {\n fontSize: 8,\n marginTop: 5,\n },\n accentStripe: {\n height: 3,\n },\n});\n\n/**\n * Dark-or-light branded header band with logo + agency name on the left,\n * doc label/number/date on the right, accent stripe underneath.\n *\n * Renders on every page (uses React-PDF's `fixed` flag).\n */\nexport function BookendHeader({\n theme,\n logoUrl,\n agencyName,\n docLabel,\n docNumber,\n docDate,\n docExtra,\n logoWidth = 80,\n logoHeight = 48,\n}: BookendHeaderProps): React.ReactElement {\n const { bandColor, accentColor, bandTextColor } = theme;\n const mutedText = theme.themeMode === \"dark\" ? \"#8a9aaa\" : \"#666666\";\n\n return (\n <View fixed>\n <View style={[styles.bandRow, { backgroundColor: bandColor }]}>\n <View style={styles.logoAndName}>\n {logoUrl && <Image src={logoUrl} style={{ width: logoWidth, height: logoHeight, objectFit: \"contain\" }} />}\n <View>\n <Text style={[styles.agencyName, { color: bandTextColor }]}>{agencyName}</Text>\n </View>\n </View>\n <View style={styles.metaBox}>\n <Text style={[styles.metaLabel, { color: mutedText }]}>{docLabel}</Text>\n <Text style={[styles.metaNum, { color: bandTextColor }]}>{docNumber}</Text>\n <Text style={[styles.metaDate, { color: mutedText }]}>{docDate}</Text>\n {docExtra && <Text style={[styles.metaDate, { color: mutedText }]}>{docExtra}</Text>}\n </View>\n </View>\n <View style={[styles.accentStripe, { backgroundColor: accentColor }]} />\n </View>\n );\n}\n","import * as React from \"react\";\nimport { StyleSheet, Text, View } from \"@react-pdf/renderer\";\n\nimport type { BookendTheme } from \"./theme\";\n\nexport interface BookendFooterProps {\n theme: BookendTheme;\n agencyName: string;\n agencyPhone?: string | null;\n agencyEmail?: string | null;\n dateStamp?: string | null;\n}\n\nconst styles = StyleSheet.create({\n footer: {\n position: \"absolute\",\n bottom: 20,\n left: 40,\n right: 40,\n flexDirection: \"row\",\n justifyContent: \"space-between\",\n borderTopWidth: 1,\n paddingTop: 8,\n },\n footerLeft: { flexDirection: \"column\" },\n footerText: { fontSize: 6.5 },\n footerRight: { alignItems: \"flex-end\" },\n});\n\n/**\n * Fixed bottom footer with agency name + contact left, date + page numbers right.\n * Renders on every page via React-PDF's `fixed` flag.\n */\nexport function BookendFooter({\n theme,\n agencyName,\n agencyPhone,\n agencyEmail,\n dateStamp,\n}: BookendFooterProps): React.ReactElement {\n const { accentColor } = theme;\n const muted = \"#666666\";\n\n const contactParts: string[] = [];\n if (agencyPhone) contactParts.push(agencyPhone);\n if (agencyEmail) contactParts.push(agencyEmail);\n\n return (\n <View style={[styles.footer, { borderTopColor: accentColor }]} fixed>\n <View style={styles.footerLeft}>\n <Text style={[styles.footerText, { color: muted }]}>{agencyName}</Text>\n {contactParts.length > 0 && (\n <Text style={[styles.footerText, { color: muted }]}>{contactParts.join(\" · \")}</Text>\n )}\n </View>\n <View style={styles.footerRight}>\n {dateStamp && <Text style={[styles.footerText, { color: muted }]}>{dateStamp}</Text>}\n <Text\n style={[styles.footerText, { color: muted }]}\n render={({ pageNumber, totalPages }) => `Page ${pageNumber} of ${totalPages}`}\n fixed\n />\n </View>\n </View>\n );\n}\n","import * as React from \"react\";\nimport { Image, StyleSheet, Text, View } from \"@react-pdf/renderer\";\n\nimport type { BookendTheme } from \"./theme\";\n\nexport interface LineCardHeaderProps {\n theme: BookendTheme;\n logoUrl: string | null;\n agencyName: string;\n agencyPhone?: string | null;\n agencyEmail?: string | null;\n agencyWebsite?: string | null;\n}\n\nconst styles = StyleSheet.create({\n row: {\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n paddingHorizontal: 44,\n paddingTop: 22,\n paddingBottom: 16,\n },\n logo: { height: 64, width: 180, objectFit: \"contain\" },\n fallbackName: { fontSize: 20, fontFamily: \"Helvetica-Bold\", letterSpacing: 0.3 },\n contactBlock: { alignItems: \"flex-end\" },\n contactLine: { fontSize: 8.5, lineHeight: 1.4 },\n contactPhone: { fontSize: 9.5, fontFamily: \"Helvetica-Bold\", marginTop: 2 },\n stripe: { height: 3, marginHorizontal: 44 },\n});\n\n/**\n * Variant header for line-card style documents: logo dominant on the left,\n * contact stack on the right, accent stripe underneath. Lower-weight than the\n * standard BookendHeader (no doc number).\n */\nexport function LineCardHeader({\n theme,\n logoUrl,\n agencyName,\n agencyPhone,\n agencyEmail,\n agencyWebsite,\n}: LineCardHeaderProps): React.ReactElement {\n const { accentColor, bandColor, bandTextColor } = theme;\n\n return (\n <>\n <View style={[styles.row, { backgroundColor: bandColor }]}>\n {logoUrl ? (\n <Image src={logoUrl} style={styles.logo} />\n ) : (\n <Text style={[styles.fallbackName, { color: bandTextColor }]}>{agencyName}</Text>\n )}\n <View style={styles.contactBlock}>\n <Text style={[styles.contactLine, { color: bandTextColor, opacity: 0.8 }]}>{agencyName}</Text>\n {agencyPhone && <Text style={[styles.contactPhone, { color: bandTextColor }]}>{agencyPhone}</Text>}\n {agencyEmail && <Text style={[styles.contactLine, { color: bandTextColor, opacity: 0.7 }]}>{agencyEmail}</Text>}\n {agencyWebsite && (\n <Text style={[styles.contactLine, { color: bandTextColor, opacity: 0.7 }]}>{agencyWebsite}</Text>\n )}\n </View>\n </View>\n <View style={[styles.stripe, { backgroundColor: accentColor }]} />\n </>\n );\n}\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 { BrandInput } from \"../types\";\nimport { darkenHex, resolveBandThemeMode } from \"../brand\";\n\n/**\n * Theme derived from a BrandInput for use in React-PDF bookend components.\n * Mirrors the resolution logic of pdf-lib branded-bookend.ts so the two\n * rendering layers produce identical visual output.\n */\nexport interface BookendTheme {\n bandColor: string;\n accentColor: string;\n creamColor: string;\n bandTextColor: string;\n themeMode: \"dark\" | \"light\";\n}\n\nexport function resolveBookendTheme(brand: BrandInput): BookendTheme {\n const themeVars = brand.themeVars ?? {};\n const themeMode = resolveBandThemeMode(brand);\n\n let bandColor: string;\n if (themeMode === \"dark\") {\n bandColor =\n themeVars[\"--sidebar-bg\"] ??\n themeVars[\"--header-bg\"] ??\n (brand.primaryColor ? darkenHex(brand.primaryColor, 0.45) : \"#1e3a5f\");\n } else {\n bandColor = \"#fbfaf6\";\n }\n\n const accentColor = brand.primaryColor ?? themeVars[\"--accent\"] ?? \"#1e3a5f\";\n const creamColor = \"#faf9f4\";\n const bandTextColor = themeMode === \"dark\" ? \"#ffffff\" : \"#111111\";\n\n return { bandColor, accentColor, creamColor, bandTextColor, themeMode };\n}\n"],"mappings":"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","names":["StyleSheet","Text","View","jsx","jsxs","styles","Image","StyleSheet","Text","View","jsx","jsxs","styles"]}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Brand-agnostic input for all PDF rendering primitives.
3
+ *
4
+ * Both RepFirm tenants and dygarn-dashboard prospects map to this shape via the
5
+ * adapter helpers in src/brand.ts. Keeping the rendering layer keyed off this
6
+ * shared type means a tenant-branded RepFirm quote and a prospect-branded
7
+ * dygarn outreach kit both compose the same way.
8
+ */
9
+ interface BrandInput {
10
+ /** Display name (agency, tenant, prospect — whatever appears in the header) */
11
+ agencyName: string;
12
+ /** Brand primary color, hex like "#1a73e8" */
13
+ primaryColor: string;
14
+ /** Optional company / legal name shown smaller below agencyName */
15
+ legalName?: string | null;
16
+ /** Optional logo URL (https or local public path) */
17
+ logoUrl?: string | null;
18
+ /** Optional dark-variant logo (used when header band is dark) */
19
+ logoDarkUrl?: string | null;
20
+ /** Optional light-variant logo (used when header band is light) */
21
+ logoLightUrl?: string | null;
22
+ /** Optional wordmark / mark fallback logos */
23
+ logoWordmarkUrl?: string | null;
24
+ logoMarkUrl?: string | null;
25
+ /** Optional header theme override. 'auto' picks based on logo variants. */
26
+ pdfHeaderTheme?: "dark" | "light" | "auto";
27
+ /** Optional theme vars dictionary (used by RepFirm tenant theme system) */
28
+ themeVars?: Record<string, string>;
29
+ /** Optional contact + identity fields shown in footer/info section */
30
+ tagline?: string | null;
31
+ address?: string | null;
32
+ phone?: string | null;
33
+ email?: string | null;
34
+ website?: string | null;
35
+ }
36
+
37
+ export type { BrandInput as B };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Brand-agnostic input for all PDF rendering primitives.
3
+ *
4
+ * Both RepFirm tenants and dygarn-dashboard prospects map to this shape via the
5
+ * adapter helpers in src/brand.ts. Keeping the rendering layer keyed off this
6
+ * shared type means a tenant-branded RepFirm quote and a prospect-branded
7
+ * dygarn outreach kit both compose the same way.
8
+ */
9
+ interface BrandInput {
10
+ /** Display name (agency, tenant, prospect — whatever appears in the header) */
11
+ agencyName: string;
12
+ /** Brand primary color, hex like "#1a73e8" */
13
+ primaryColor: string;
14
+ /** Optional company / legal name shown smaller below agencyName */
15
+ legalName?: string | null;
16
+ /** Optional logo URL (https or local public path) */
17
+ logoUrl?: string | null;
18
+ /** Optional dark-variant logo (used when header band is dark) */
19
+ logoDarkUrl?: string | null;
20
+ /** Optional light-variant logo (used when header band is light) */
21
+ logoLightUrl?: string | null;
22
+ /** Optional wordmark / mark fallback logos */
23
+ logoWordmarkUrl?: string | null;
24
+ logoMarkUrl?: string | null;
25
+ /** Optional header theme override. 'auto' picks based on logo variants. */
26
+ pdfHeaderTheme?: "dark" | "light" | "auto";
27
+ /** Optional theme vars dictionary (used by RepFirm tenant theme system) */
28
+ themeVars?: Record<string, string>;
29
+ /** Optional contact + identity fields shown in footer/info section */
30
+ tagline?: string | null;
31
+ address?: string | null;
32
+ phone?: string | null;
33
+ email?: string | null;
34
+ website?: string | null;
35
+ }
36
+
37
+ export type { BrandInput as B };
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@gmoney2000/dygarn-pdf-kit",
3
+ "version": "0.1.0",
4
+ "description": "Branded PDF design system for DyGarn ecosystem apps (RepFirm, dygarn-dashboard). Shared visual primitives + style themes for quote, submittal, PO, and outreach kits.",
5
+ "license": "UNLICENSED",
6
+ "private": false,
7
+ "author": "Greg Drysdale <greg@dygarn.com>",
8
+ "type": "module",
9
+ "main": "./dist/index.cjs",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.cjs"
17
+ },
18
+ "./react-pdf": {
19
+ "types": "./dist/react-pdf.d.ts",
20
+ "import": "./dist/react-pdf.js",
21
+ "require": "./dist/react-pdf.cjs"
22
+ },
23
+ "./pdf-lib": {
24
+ "types": "./dist/pdf-lib.d.ts",
25
+ "import": "./dist/pdf-lib.js",
26
+ "require": "./dist/pdf-lib.cjs"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "README.md"
32
+ ],
33
+ "scripts": {
34
+ "build": "tsup",
35
+ "dev": "tsup --watch",
36
+ "typecheck": "tsc --noEmit",
37
+ "clean": "rimraf dist"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public",
41
+ "registry": "https://registry.npmjs.org"
42
+ },
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/gmoney2000/dygarn-pdf-kit.git"
46
+ },
47
+ "peerDependencies": {
48
+ "@react-pdf/renderer": ">=3.0.0",
49
+ "pdf-lib": ">=1.17.0",
50
+ "react": ">=18.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@react-pdf/renderer": "^4.0.0",
54
+ "@types/react": "^19.0.0",
55
+ "pdf-lib": "^1.17.1",
56
+ "react": "^19.0.0",
57
+ "rimraf": "^6.0.0",
58
+ "tsup": "^8.3.0",
59
+ "typescript": "^5.5.0"
60
+ }
61
+ }