pdfn 0.1.0 → 0.2.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,188 @@
1
+ import { Document, Page, Thead, PageNumber, TotalPages } from "@pdfn/react";
2
+
3
+ /**
4
+ * Professional Invoice template using inline styles
5
+ *
6
+ * Demonstrates:
7
+ * - Thead with repeat for multi-page tables
8
+ * - PageNumber and TotalPages in footer
9
+ * - Configurable tax rate
10
+ */
11
+
12
+ interface InvoiceProps {
13
+ number?: string;
14
+ date?: string;
15
+ dueDate?: string;
16
+ customer?: {
17
+ name: string;
18
+ address: string;
19
+ city: string;
20
+ };
21
+ items?: Array<{
22
+ name: string;
23
+ description?: string;
24
+ qty: number;
25
+ price: number;
26
+ }>;
27
+ taxRate?: number;
28
+ notes?: string;
29
+ company?: {
30
+ name: string;
31
+ address: string;
32
+ email: string;
33
+ phone: string;
34
+ };
35
+ }
36
+
37
+ export default function Invoice({
38
+ number = "INV-2025-001",
39
+ date = "January 15, 2025",
40
+ dueDate = "February 14, 2025",
41
+ customer = {
42
+ name: "Acme Corporation",
43
+ address: "456 Enterprise Blvd, Suite 100",
44
+ city: "Austin, TX 78701",
45
+ },
46
+ items = [
47
+ { name: "Web Development", description: "Frontend development with React", qty: 40, price: 150 },
48
+ { name: "API Integration", description: "REST API setup and configuration", qty: 20, price: 175 },
49
+ { name: "UI/UX Design", description: "User interface design", qty: 15, price: 125 },
50
+ ],
51
+ taxRate = 0.1,
52
+ notes = "Payment is due within 30 days. Thank you for your business!",
53
+ company = {
54
+ name: "Your Company",
55
+ address: "123 Business St, San Francisco, CA 94102",
56
+ email: "hello@yourcompany.com",
57
+ phone: "+1 (555) 123-4567",
58
+ },
59
+ }: InvoiceProps) {
60
+ const subtotal = items.reduce((sum, item) => sum + item.qty * item.price, 0);
61
+ const tax = subtotal * taxRate;
62
+ const total = subtotal + tax;
63
+
64
+ const formatCurrency = (amount: number) =>
65
+ "$" + amount.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
66
+
67
+ return (
68
+ <Document title={`Invoice ${number}`}>
69
+ <Page
70
+ size="A4"
71
+ margin="1in"
72
+ footer={
73
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: "10px", color: "#6b7280", borderTop: "1px solid #e5e7eb", paddingTop: "12px" }}>
74
+ <div>
75
+ {company.name} • {company.email} • {company.phone}
76
+ </div>
77
+ <div>
78
+ Page <PageNumber /> of <TotalPages />
79
+ </div>
80
+ </div>
81
+ }
82
+ >
83
+ {/* Header */}
84
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: "32px" }}>
85
+ <div>
86
+ <div style={{ fontSize: "24px", fontWeight: "bold", color: "#111827" }}>{company.name}</div>
87
+ <div style={{ fontSize: "10px", color: "#6b7280", marginTop: "4px" }}>{company.address}</div>
88
+ </div>
89
+ <div style={{ textAlign: "right" }}>
90
+ <div style={{ fontSize: "30px", fontWeight: "bold", color: "#111827", letterSpacing: "-0.025em" }}>INVOICE</div>
91
+ <div style={{ fontSize: "18px", fontWeight: "600", color: "#4b5563", marginTop: "4px" }}>{number}</div>
92
+ </div>
93
+ </div>
94
+
95
+ {/* Invoice Details & Bill To */}
96
+ <div style={{ display: "flex", justifyContent: "space-between", marginBottom: "32px" }}>
97
+ <div>
98
+ <div style={{ fontSize: "10px", fontWeight: "600", color: "#6b7280", textTransform: "uppercase", marginBottom: "8px" }}>Bill To</div>
99
+ <div style={{ fontSize: "14px", fontWeight: "600", color: "#111827" }}>{customer.name}</div>
100
+ <div style={{ fontSize: "14px", color: "#4b5563", marginTop: "2px" }}>{customer.address}</div>
101
+ <div style={{ fontSize: "14px", color: "#4b5563" }}>{customer.city}</div>
102
+ </div>
103
+ <div style={{ textAlign: "right" }}>
104
+ <table style={{ marginLeft: "auto", fontSize: "14px" }}>
105
+ <tbody>
106
+ <tr>
107
+ <td style={{ color: "#6b7280", paddingRight: "16px", paddingTop: "2px", paddingBottom: "2px" }}>Invoice Date:</td>
108
+ <td style={{ color: "#111827", paddingTop: "2px", paddingBottom: "2px" }}>{date}</td>
109
+ </tr>
110
+ <tr>
111
+ <td style={{ color: "#6b7280", paddingRight: "16px", paddingTop: "2px", paddingBottom: "2px" }}>Due Date:</td>
112
+ <td style={{ color: "#111827", paddingTop: "2px", paddingBottom: "2px" }}>{dueDate}</td>
113
+ </tr>
114
+ <tr>
115
+ <td style={{ color: "#6b7280", paddingRight: "16px", paddingTop: "6px", paddingBottom: "6px", fontWeight: "600" }}>Amount Due:</td>
116
+ <td style={{ color: "#111827", paddingTop: "6px", paddingBottom: "6px", fontWeight: "bold", fontSize: "18px" }}>{formatCurrency(total)}</td>
117
+ </tr>
118
+ </tbody>
119
+ </table>
120
+ </div>
121
+ </div>
122
+
123
+ {/* Items Table */}
124
+ <table style={{ width: "100%", marginBottom: "24px", borderCollapse: "collapse" }}>
125
+ <Thead repeat>
126
+ <tr style={{ backgroundColor: "#1f2937", color: "white" }}>
127
+ <th style={{ textAlign: "left", padding: "12px 16px", fontSize: "10px", fontWeight: "600", textTransform: "uppercase" }}>Description</th>
128
+ <th style={{ textAlign: "center", padding: "12px 16px", fontSize: "10px", fontWeight: "600", textTransform: "uppercase", width: "64px" }}>Qty</th>
129
+ <th style={{ textAlign: "right", padding: "12px 16px", fontSize: "10px", fontWeight: "600", textTransform: "uppercase", width: "96px" }}>Rate</th>
130
+ <th style={{ textAlign: "right", padding: "12px 16px", fontSize: "10px", fontWeight: "600", textTransform: "uppercase", width: "112px" }}>Amount</th>
131
+ </tr>
132
+ </Thead>
133
+ <tbody>
134
+ {items.map((item, i) => (
135
+ <tr key={i} style={{ backgroundColor: i % 2 === 0 ? "white" : "#f9fafb" }}>
136
+ <td style={{ padding: "12px 16px", borderBottom: "1px solid #f3f4f6" }}>
137
+ <div style={{ fontWeight: "500", color: "#111827", fontSize: "14px" }}>{item.name}</div>
138
+ {item.description && (
139
+ <div style={{ fontSize: "10px", color: "#6b7280", marginTop: "2px" }}>{item.description}</div>
140
+ )}
141
+ </td>
142
+ <td style={{ textAlign: "center", padding: "12px 16px", color: "#374151", fontSize: "14px", borderBottom: "1px solid #f3f4f6" }}>
143
+ {item.qty}
144
+ </td>
145
+ <td style={{ textAlign: "right", padding: "12px 16px", color: "#374151", fontSize: "14px", borderBottom: "1px solid #f3f4f6" }}>
146
+ {formatCurrency(item.price)}
147
+ </td>
148
+ <td style={{ textAlign: "right", padding: "12px 16px", fontWeight: "500", color: "#111827", fontSize: "14px", borderBottom: "1px solid #f3f4f6" }}>
149
+ {formatCurrency(item.qty * item.price)}
150
+ </td>
151
+ </tr>
152
+ ))}
153
+ </tbody>
154
+ </table>
155
+
156
+ {/* Totals */}
157
+ <div style={{ display: "flex", justifyContent: "flex-end", marginBottom: "32px" }}>
158
+ <table style={{ width: "256px", fontSize: "14px" }}>
159
+ <tbody>
160
+ <tr>
161
+ <td style={{ padding: "8px 0", color: "#4b5563" }}>Subtotal</td>
162
+ <td style={{ padding: "8px 0", textAlign: "right", color: "#111827" }}>{formatCurrency(subtotal)}</td>
163
+ </tr>
164
+ <tr>
165
+ <td style={{ padding: "8px 0", color: "#4b5563" }}>Tax ({(taxRate * 100).toFixed(0)}%)</td>
166
+ <td style={{ padding: "8px 0", textAlign: "right", color: "#111827" }}>{formatCurrency(tax)}</td>
167
+ </tr>
168
+ <tr style={{ borderTop: "2px solid #1f2937" }}>
169
+ <td style={{ paddingTop: "12px", paddingBottom: "8px", fontWeight: "bold", color: "#111827", fontSize: "16px" }}>Total Due</td>
170
+ <td style={{ paddingTop: "12px", paddingBottom: "8px", textAlign: "right", fontWeight: "bold", color: "#111827", fontSize: "18px" }}>
171
+ {formatCurrency(total)}
172
+ </td>
173
+ </tr>
174
+ </tbody>
175
+ </table>
176
+ </div>
177
+
178
+ {/* Notes */}
179
+ {notes && (
180
+ <div style={{ backgroundColor: "#f9fafb", padding: "16px", borderRadius: "8px" }}>
181
+ <div style={{ fontSize: "10px", fontWeight: "600", color: "#374151", textTransform: "uppercase", marginBottom: "4px" }}>Notes</div>
182
+ <div style={{ fontSize: "14px", color: "#4b5563" }}>{notes}</div>
183
+ </div>
184
+ )}
185
+ </Page>
186
+ </Document>
187
+ );
188
+ }
@@ -0,0 +1,129 @@
1
+ import { Document, Page } from "@pdfn/react";
2
+
3
+ /**
4
+ * Business Letter template - US Letter size (inline styles)
5
+ *
6
+ * Demonstrates:
7
+ * - Professional letterhead
8
+ * - Proper business letter format
9
+ * - Single page layout
10
+ */
11
+
12
+ interface LetterProps {
13
+ sender?: {
14
+ name: string;
15
+ title?: string;
16
+ company: string;
17
+ address: string;
18
+ city: string;
19
+ email: string;
20
+ phone: string;
21
+ };
22
+ recipient?: {
23
+ name: string;
24
+ title?: string;
25
+ company: string;
26
+ address: string;
27
+ city: string;
28
+ };
29
+ date?: string;
30
+ subject?: string;
31
+ body?: string[];
32
+ closing?: string;
33
+ signature?: string;
34
+ }
35
+
36
+ export default function Letter({
37
+ sender = {
38
+ name: "Alex Chen",
39
+ title: "Head of Partnerships",
40
+ company: "Your Company",
41
+ address: "123 Business St, Suite 100",
42
+ city: "San Francisco, CA 94102",
43
+ email: "alex@yourcompany.com",
44
+ phone: "+1 (555) 123-4567",
45
+ },
46
+ recipient = {
47
+ name: "Sarah Johnson",
48
+ title: "Chief Technology Officer",
49
+ company: "Acme Corporation",
50
+ address: "456 Enterprise Blvd, Suite 100",
51
+ city: "Austin, TX 78701",
52
+ },
53
+ date = "January 15, 2025",
54
+ subject = "Partnership Proposal",
55
+ body = [
56
+ "I hope this letter finds you well. Following our conversation last month, I wanted to formally present our partnership proposal for your consideration.",
57
+ "Our solution has helped over 500 companies streamline their workflows, reducing development time by an average of 60%. We believe our platform would be an excellent fit for your needs.",
58
+ "I would welcome the opportunity to schedule a technical demo with your team. Please let me know if you would be available for a call next week.",
59
+ ],
60
+ closing = "Best regards",
61
+ signature = "Alex Chen",
62
+ }: LetterProps) {
63
+ return (
64
+ <Document title={`Letter - ${subject}`}>
65
+ <Page size="Letter" margin="1in">
66
+ {/* Letterhead */}
67
+ <div style={{ marginBottom: "24px", paddingBottom: "12px", borderBottom: "2px solid #1f2937" }}>
68
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
69
+ <div>
70
+ <div style={{ fontSize: "20px", fontWeight: "bold", color: "#111827" }}>{sender.company}</div>
71
+ <div style={{ fontSize: "10px", color: "#6b7280", marginTop: "4px" }}>
72
+ {sender.address} • {sender.city}
73
+ </div>
74
+ </div>
75
+ <div style={{ textAlign: "right", fontSize: "10px", color: "#6b7280" }}>
76
+ <div>{sender.email}</div>
77
+ <div>{sender.phone}</div>
78
+ </div>
79
+ </div>
80
+ </div>
81
+
82
+ {/* Date */}
83
+ <div style={{ fontSize: "14px", color: "#374151", marginBottom: "24px" }}>{date}</div>
84
+
85
+ {/* Recipient Info */}
86
+ <div style={{ marginBottom: "24px" }}>
87
+ <div style={{ fontSize: "14px", fontWeight: "600", color: "#111827" }}>{recipient.name}</div>
88
+ {recipient.title && (
89
+ <div style={{ fontSize: "14px", color: "#4b5563" }}>{recipient.title}</div>
90
+ )}
91
+ <div style={{ fontSize: "14px", color: "#4b5563" }}>{recipient.company}</div>
92
+ <div style={{ fontSize: "14px", color: "#6b7280" }}>
93
+ {recipient.address}, {recipient.city}
94
+ </div>
95
+ </div>
96
+
97
+ {/* Subject Line */}
98
+ <div style={{ marginBottom: "16px", padding: "6px 0 6px 12px", borderLeft: "4px solid #1f2937", backgroundColor: "#f9fafb" }}>
99
+ <span style={{ fontSize: "14px", fontWeight: "bold", color: "#111827", textTransform: "uppercase", letterSpacing: "0.05em" }}>Re: </span>
100
+ <span style={{ fontSize: "14px", fontWeight: "500", color: "#1f2937" }}>{subject}</span>
101
+ </div>
102
+
103
+ {/* Salutation */}
104
+ <div style={{ fontSize: "14px", color: "#111827", marginBottom: "12px" }}>Dear {recipient.name},</div>
105
+
106
+ {/* Body */}
107
+ <div style={{ marginBottom: "24px" }}>
108
+ {body.map((paragraph, i) => (
109
+ <p key={i} style={{ fontSize: "14px", color: "#374151", lineHeight: "1.625", marginBottom: "12px" }}>
110
+ {paragraph}
111
+ </p>
112
+ ))}
113
+ </div>
114
+
115
+ {/* Closing & Signature */}
116
+ <div style={{ marginTop: "24px" }}>
117
+ <div style={{ fontSize: "14px", color: "#111827", marginBottom: "24px" }}>{closing},</div>
118
+ <div style={{ borderBottom: "1px solid #d1d5db", width: "160px", marginBottom: "4px" }}></div>
119
+ <div style={{ fontSize: "14px", fontWeight: "bold", color: "#111827" }}>{signature}</div>
120
+ {sender.title && (
121
+ <div style={{ fontSize: "10px", color: "#4b5563" }}>
122
+ {sender.title}, {sender.company}
123
+ </div>
124
+ )}
125
+ </div>
126
+ </Page>
127
+ </Document>
128
+ );
129
+ }
@@ -0,0 +1,128 @@
1
+ import { Document, Page } from "@pdfn/react";
2
+
3
+ /**
4
+ * Event Poster template - Tabloid size, Landscape (inline styles)
5
+ *
6
+ * Demonstrates:
7
+ * - Large format (Tabloid: 17" x 11")
8
+ * - Landscape orientation
9
+ * - Full-bleed design (margin: 0)
10
+ * - Bold typography and visual hierarchy
11
+ */
12
+
13
+ interface PosterProps {
14
+ headline?: string;
15
+ year?: string;
16
+ subheadline?: string;
17
+ date?: string;
18
+ venue?: string;
19
+ highlights?: string[];
20
+ cta?: string;
21
+ website?: string;
22
+ }
23
+
24
+ export default function Poster({
25
+ headline = "Tech Conference",
26
+ year = "2025",
27
+ subheadline = "Innovation Meets Inspiration",
28
+ date = "March 15-17, 2025",
29
+ venue = "Convention Center, San Francisco",
30
+ highlights = ["50+ Speakers", "Workshops", "Networking"],
31
+ cta = "Get Tickets",
32
+ website = "techconf2025.com",
33
+ }: PosterProps) {
34
+ // Tabloid landscape dimensions
35
+ const pageHeight = "792pt"; // 11 inches
36
+
37
+ return (
38
+ <Document title={`Poster - ${headline}`}>
39
+ <Page size="Tabloid" orientation="landscape" margin="0">
40
+ {/* Full bleed dark background */}
41
+ <div
42
+ style={{
43
+ backgroundColor: "#111827",
44
+ color: "white",
45
+ padding: "48px",
46
+ display: "flex",
47
+ flexDirection: "column",
48
+ minHeight: pageHeight,
49
+ height: pageHeight,
50
+ }}
51
+ >
52
+ {/* Top Section: Logo and Accent */}
53
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: "16px" }}>
54
+ <div style={{ fontSize: "24px", fontWeight: "900", color: "white" }}>PDFN</div>
55
+ <div style={{ display: "flex", gap: "8px" }}>
56
+ <div style={{ height: "6px", width: "128px", backgroundColor: "#06b6d4", borderRadius: "9999px" }}></div>
57
+ <div style={{ height: "6px", width: "64px", backgroundColor: "rgba(6, 182, 212, 0.5)", borderRadius: "9999px" }}></div>
58
+ <div style={{ height: "6px", width: "32px", backgroundColor: "rgba(6, 182, 212, 0.25)", borderRadius: "9999px" }}></div>
59
+ </div>
60
+ </div>
61
+
62
+ {/* Main Content - Vertically Centered */}
63
+ <div style={{ flex: 1, display: "flex", flexDirection: "column", justifyContent: "center" }}>
64
+ {/* Headline */}
65
+ <h1 style={{ fontSize: "96px", fontWeight: "900", letterSpacing: "-0.025em", lineHeight: 1, marginBottom: "24px", margin: 0 }}>
66
+ {headline}
67
+ {year && <span style={{ color: "#22d3ee" }}> {year}</span>}
68
+ </h1>
69
+
70
+ {subheadline && (
71
+ <p style={{ fontSize: "30px", color: "#9ca3af", fontWeight: "300", maxWidth: "768px", marginBottom: "48px", marginTop: "24px" }}>
72
+ {subheadline}
73
+ </p>
74
+ )}
75
+
76
+ {/* Event Details */}
77
+ <div style={{ display: "flex", gap: "80px" }}>
78
+ <div>
79
+ <div style={{ fontSize: "14px", color: "#06b6d4", textTransform: "uppercase", letterSpacing: "0.2em", fontWeight: "bold", marginBottom: "8px" }}>
80
+ Date
81
+ </div>
82
+ <div style={{ fontSize: "36px", fontWeight: "bold" }}>{date}</div>
83
+ </div>
84
+ <div>
85
+ <div style={{ fontSize: "14px", color: "#06b6d4", textTransform: "uppercase", letterSpacing: "0.2em", fontWeight: "bold", marginBottom: "8px" }}>
86
+ Venue
87
+ </div>
88
+ <div style={{ fontSize: "36px", fontWeight: "bold" }}>{venue}</div>
89
+ </div>
90
+ </div>
91
+ </div>
92
+
93
+ {/* Bottom Section */}
94
+ <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between" }}>
95
+ {/* Highlights/Tags */}
96
+ <div style={{ display: "flex", gap: "16px" }}>
97
+ {highlights.map((highlight, i) => (
98
+ <div
99
+ key={i}
100
+ style={{ border: "2px solid #4b5563", color: "white", padding: "12px 24px", borderRadius: "9999px", fontSize: "16px", fontWeight: "600" }}
101
+ >
102
+ {highlight}
103
+ </div>
104
+ ))}
105
+ </div>
106
+
107
+ {/* CTA */}
108
+ <div style={{ textAlign: "right" }}>
109
+ <div style={{ display: "inline-block", backgroundColor: "#06b6d4", color: "#111827", fontSize: "24px", fontWeight: "900", padding: "20px 40px", borderRadius: "12px" }}>
110
+ {cta}
111
+ </div>
112
+ <div style={{ fontSize: "16px", color: "#6b7280", marginTop: "16px", fontFamily: "monospace", letterSpacing: "0.05em" }}>
113
+ {website}
114
+ </div>
115
+ </div>
116
+ </div>
117
+
118
+ {/* Bottom Accent */}
119
+ <div style={{ display: "flex", justifyContent: "flex-end", gap: "8px", marginTop: "32px" }}>
120
+ <div style={{ height: "6px", width: "32px", backgroundColor: "rgba(6, 182, 212, 0.25)", borderRadius: "9999px" }}></div>
121
+ <div style={{ height: "6px", width: "64px", backgroundColor: "rgba(6, 182, 212, 0.5)", borderRadius: "9999px" }}></div>
122
+ <div style={{ height: "6px", width: "128px", backgroundColor: "#06b6d4", borderRadius: "9999px" }}></div>
123
+ </div>
124
+ </div>
125
+ </Page>
126
+ </Document>
127
+ );
128
+ }
@@ -0,0 +1,138 @@
1
+ import { Document, Page } from "@pdfn/react";
2
+
3
+ /**
4
+ * Event Ticket template - A5 size (inline styles)
5
+ *
6
+ * Demonstrates:
7
+ * - Compact page size (A5: 148mm x 210mm)
8
+ * - Creative visual design with banner
9
+ * - QR code placeholder
10
+ */
11
+
12
+ interface TicketProps {
13
+ event?: string;
14
+ year?: string;
15
+ tagline?: string;
16
+ date?: string;
17
+ time?: string;
18
+ venue?: string;
19
+ venueAddress?: string;
20
+ attendee?: string;
21
+ ticketType?: string;
22
+ ticketNumber?: string;
23
+ price?: string;
24
+ }
25
+
26
+ export default function Ticket({
27
+ event = "Tech Conference",
28
+ year = "2025",
29
+ tagline = "Innovation Meets Inspiration",
30
+ date = "March 15, 2025",
31
+ time = "9:00 AM - 6:00 PM",
32
+ venue = "Convention Center",
33
+ venueAddress = "123 Main St, San Francisco, CA",
34
+ attendee = "John Smith",
35
+ ticketType = "VIP Access",
36
+ ticketNumber = "TC25-VIP-001234",
37
+ price = "$599.00",
38
+ }: TicketProps) {
39
+ return (
40
+ <Document title={`Ticket - ${event}`}>
41
+ <Page size="A5" margin="0">
42
+ {/* Header Banner */}
43
+ <div style={{ backgroundColor: "#111827", padding: "28px 24px", textAlign: "center" }}>
44
+ <div style={{ fontSize: "30px", fontWeight: "900", color: "white", letterSpacing: "0.05em" }}>
45
+ {event}
46
+ {year && <span style={{ color: "#22d3ee" }}> {year}</span>}
47
+ </div>
48
+ {tagline && (
49
+ <div style={{ fontSize: "14px", color: "#22d3ee", marginTop: "8px", fontWeight: "500", textTransform: "uppercase", letterSpacing: "0.2em" }}>
50
+ {tagline}
51
+ </div>
52
+ )}
53
+ </div>
54
+
55
+ {/* Ticket Content */}
56
+ <div style={{ padding: "20px 24px" }}>
57
+ {/* Ticket Type Badge */}
58
+ <div style={{ display: "flex", justifyContent: "center", marginTop: "-40px", marginBottom: "20px" }}>
59
+ <div style={{ backgroundColor: "#06b6d4", color: "#111827", fontSize: "10px", fontWeight: "bold", textTransform: "uppercase", padding: "8px 20px", borderRadius: "9999px", letterSpacing: "0.2em" }}>
60
+ {ticketType}
61
+ </div>
62
+ </div>
63
+
64
+ {/* Event Details Grid */}
65
+ <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "16px", marginBottom: "20px" }}>
66
+ <div style={{ backgroundColor: "#f9fafb", borderRadius: "8px", padding: "14px", textAlign: "center" }}>
67
+ <div style={{ fontSize: "10px", color: "#6b7280", textTransform: "uppercase", letterSpacing: "0.1em", fontWeight: "500" }}>
68
+ Date
69
+ </div>
70
+ <div style={{ fontSize: "16px", fontWeight: "bold", color: "#111827", marginTop: "4px" }}>{date}</div>
71
+ </div>
72
+ <div style={{ backgroundColor: "#f9fafb", borderRadius: "8px", padding: "14px", textAlign: "center" }}>
73
+ <div style={{ fontSize: "10px", color: "#6b7280", textTransform: "uppercase", letterSpacing: "0.1em", fontWeight: "500" }}>
74
+ Time
75
+ </div>
76
+ <div style={{ fontSize: "16px", fontWeight: "bold", color: "#111827", marginTop: "4px" }}>{time}</div>
77
+ </div>
78
+ </div>
79
+
80
+ {/* Venue */}
81
+ <div style={{ backgroundColor: "#f9fafb", borderRadius: "8px", padding: "14px", textAlign: "center", marginBottom: "20px" }}>
82
+ <div style={{ fontSize: "10px", color: "#6b7280", textTransform: "uppercase", letterSpacing: "0.1em", fontWeight: "500" }}>
83
+ Venue
84
+ </div>
85
+ <div style={{ fontSize: "16px", fontWeight: "bold", color: "#111827", marginTop: "4px" }}>{venue}</div>
86
+ <div style={{ fontSize: "10px", color: "#6b7280", marginTop: "4px" }}>{venueAddress}</div>
87
+ </div>
88
+
89
+ {/* Tear Line */}
90
+ <div style={{ display: "flex", alignItems: "center", gap: "8px", margin: "20px 0" }}>
91
+ <div style={{ flex: 1, borderTop: "2px dashed #d1d5db" }}></div>
92
+ <div style={{ fontSize: "14px", color: "#9ca3af" }}>✂</div>
93
+ <div style={{ flex: 1, borderTop: "2px dashed #d1d5db" }}></div>
94
+ </div>
95
+
96
+ {/* Attendee Section */}
97
+ <div style={{ textAlign: "center", marginBottom: "20px" }}>
98
+ <div style={{ fontSize: "10px", color: "#6b7280", textTransform: "uppercase", letterSpacing: "0.1em", fontWeight: "500", marginBottom: "4px" }}>
99
+ Admit One
100
+ </div>
101
+ <div style={{ fontSize: "36px", fontWeight: "900", color: "#111827" }}>{attendee}</div>
102
+ </div>
103
+
104
+ {/* QR Code Area */}
105
+ <div style={{ display: "flex", justifyContent: "center", marginBottom: "20px" }}>
106
+ <div style={{ width: "144px", height: "144px", backgroundColor: "white", border: "2px solid #111827", borderRadius: "12px", padding: "8px", display: "flex", alignItems: "center", justifyContent: "center" }}>
107
+ {/* Simulated QR pattern */}
108
+ <div style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: "4px", width: "100%", height: "100%" }}>
109
+ {[...Array(25)].map((_, i) => (
110
+ <div
111
+ key={i}
112
+ style={{
113
+ borderRadius: "2px",
114
+ backgroundColor: [0, 1, 2, 4, 5, 6, 10, 12, 14, 18, 19, 20, 22, 23, 24].includes(i)
115
+ ? "#111827"
116
+ : "#f3f4f6"
117
+ }}
118
+ />
119
+ ))}
120
+ </div>
121
+ </div>
122
+ </div>
123
+
124
+ {/* Footer */}
125
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", fontSize: "14px", borderTop: "2px solid #111827", paddingTop: "12px" }}>
126
+ <div style={{ fontFamily: "monospace", fontSize: "10px", color: "#4b5563" }}>{ticketNumber}</div>
127
+ <div style={{ fontWeight: "bold", fontSize: "18px", color: "#111827" }}>{price}</div>
128
+ </div>
129
+
130
+ {/* Terms */}
131
+ <p style={{ textAlign: "center", fontSize: "10px", color: "#9ca3af", marginTop: "12px" }}>
132
+ Non-transferable • Non-refundable • Present at entry
133
+ </p>
134
+ </div>
135
+ </Page>
136
+ </Document>
137
+ );
138
+ }
File without changes
File without changes
File without changes
File without changes