pdf-catalog-generator 1.1.0 → 3.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 +423 -34
- package/dist/index.d.mts +262 -0
- package/dist/index.d.ts +262 -4
- package/dist/index.js +1161 -15
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1110 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +50 -8
- package/.claude/settings.local.json +0 -7
- package/dist/generator.d.ts +0 -7
- package/dist/generator.js +0 -130
- package/dist/parser.d.ts +0 -17
- package/dist/parser.js +0 -93
- package/dist/templates/Template1.d.ts +0 -4
- package/dist/templates/Template1.js +0 -86
- package/dist/templates/Template2.d.ts +0 -4
- package/dist/templates/Template2.js +0 -104
- package/dist/templates/Template3.d.ts +0 -4
- package/dist/templates/Template3.js +0 -85
- package/dist/templates/Template4.d.ts +0 -4
- package/dist/templates/Template4.js +0 -126
- package/dist/templates/index.d.ts +0 -4
- package/dist/templates/index.js +0 -14
- package/dist/types.d.ts +0 -16
- package/dist/types.js +0 -2
- package/pdf-catalog-test/README.md +0 -100
- package/pdf-catalog-test/data/products.csv +0 -8
- package/pdf-catalog-test/data/products.json +0 -51
- package/pdf-catalog-test/data/products.xlsx +0 -0
- package/pdf-catalog-test/package-lock.json +0 -260
- package/pdf-catalog-test/package.json +0 -24
package/README.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# PDF Catalog Generator
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/pdf-catalog-generator)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
|
|
7
|
+
Generate beautiful product catalog PDFs from Excel, CSV, or JSON data with multiple professional templates.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- 🎨 **4 Professional Templates** - Choose from multiple layout options
|
|
12
|
+
- 📊 **Multiple Input Formats** - Excel, CSV, and JSON support
|
|
13
|
+
- 🏢 **Customizable Branding** - Add your company logo and name
|
|
14
|
+
- 📦 **Dual Package** - Supports both ESM and CommonJS
|
|
15
|
+
- 🔒 **Type Safe** - Full TypeScript support with type definitions
|
|
16
|
+
- ✅ **Tested** - Comprehensive unit test coverage
|
|
17
|
+
- 📚 **Well Documented** - Interactive Storybook documentation
|
|
4
18
|
|
|
5
19
|
## Installation
|
|
6
20
|
|
|
@@ -8,64 +22,439 @@ Generate beautiful product catalog PDFs from Excel, CSV, or JSON data.
|
|
|
8
22
|
npm install pdf-catalog-generator
|
|
9
23
|
```
|
|
10
24
|
|
|
11
|
-
##
|
|
25
|
+
## Quick Start
|
|
12
26
|
|
|
13
27
|
```typescript
|
|
14
28
|
import { generateProductCatalog } from 'pdf-catalog-generator';
|
|
29
|
+
import fs from 'fs';
|
|
15
30
|
|
|
16
|
-
// From JSON
|
|
17
31
|
const pdfBuffer = await generateProductCatalog({
|
|
18
32
|
products: [
|
|
19
33
|
{
|
|
20
|
-
Title: '
|
|
21
|
-
Description: '
|
|
22
|
-
Image: 'https://example.com/
|
|
23
|
-
Price:
|
|
34
|
+
Title: 'Laptop Pro 15',
|
|
35
|
+
Description: 'High-performance laptop',
|
|
36
|
+
Image: 'https://example.com/laptop.jpg',
|
|
37
|
+
Price: 1299.99,
|
|
24
38
|
Rating: 4.5,
|
|
25
|
-
Link: 'https://example.com/
|
|
39
|
+
Link: 'https://store.example.com/laptop'
|
|
26
40
|
}
|
|
27
41
|
],
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
template: 'template1'
|
|
42
|
+
companyName: 'Tech Store',
|
|
43
|
+
companyLogo: 'https://example.com/logo.png',
|
|
44
|
+
template: 'template1'
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Save to file
|
|
48
|
+
fs.writeFileSync('catalog.pdf', pdfBuffer);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Platform Compatibility
|
|
52
|
+
|
|
53
|
+
This library works seamlessly across different JavaScript environments:
|
|
54
|
+
|
|
55
|
+
- ✅ **Node.js** - Backend servers, build scripts, CLI tools
|
|
56
|
+
- ✅ **Browser/React** - Client-side web applications
|
|
57
|
+
- ✅ **Next.js** - Both server components (SSR) and client components
|
|
58
|
+
|
|
59
|
+
### Browser/React Usage
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import { parseExcelFile, generateProductCatalog } from 'pdf-catalog-generator';
|
|
63
|
+
|
|
64
|
+
async function handleFileUpload(event: React.ChangeEvent<HTMLInputElement>) {
|
|
65
|
+
const file = event.target.files?.[0];
|
|
66
|
+
if (!file) return;
|
|
67
|
+
|
|
68
|
+
// Use browser File API
|
|
69
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
70
|
+
|
|
71
|
+
// Parse with ArrayBuffer (cross-platform compatible)
|
|
72
|
+
const products = parseExcelFile(arrayBuffer);
|
|
73
|
+
|
|
74
|
+
// Generate PDF
|
|
75
|
+
const pdfBuffer = await generateProductCatalog({
|
|
76
|
+
products,
|
|
77
|
+
companyName: 'My Store',
|
|
78
|
+
template: 'template1',
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Download in browser
|
|
82
|
+
const blob = new Blob([pdfBuffer], { type: 'application/pdf' });
|
|
83
|
+
const url = URL.createObjectURL(blob);
|
|
84
|
+
const link = document.createElement('a');
|
|
85
|
+
link.href = url;
|
|
86
|
+
link.download = 'catalog.pdf';
|
|
87
|
+
link.click();
|
|
88
|
+
URL.revokeObjectURL(url);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Next.js Usage
|
|
93
|
+
|
|
94
|
+
**Server Component (App Router):**
|
|
95
|
+
```typescript
|
|
96
|
+
// app/api/generate-catalog/route.ts
|
|
97
|
+
import { parseExcelFile, generateProductCatalog } from 'pdf-catalog-generator';
|
|
98
|
+
|
|
99
|
+
export async function POST(request: Request) {
|
|
100
|
+
const formData = await request.formData();
|
|
101
|
+
const file = formData.get('file') as File;
|
|
102
|
+
|
|
103
|
+
// Convert File to ArrayBuffer
|
|
104
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
105
|
+
|
|
106
|
+
const products = parseExcelFile(arrayBuffer);
|
|
107
|
+
const pdfBuffer = await generateProductCatalog({
|
|
108
|
+
products,
|
|
109
|
+
companyName: 'My Store',
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return new Response(pdfBuffer, {
|
|
113
|
+
headers: {
|
|
114
|
+
'Content-Type': 'application/pdf',
|
|
115
|
+
'Content-Disposition': 'attachment; filename="catalog.pdf"',
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Client Component:**
|
|
122
|
+
```typescript
|
|
123
|
+
'use client';
|
|
124
|
+
|
|
125
|
+
import { useState } from 'react';
|
|
126
|
+
import { parseExcelFile, generateProductCatalog } from 'pdf-catalog-generator';
|
|
127
|
+
|
|
128
|
+
export default function CatalogGenerator() {
|
|
129
|
+
const handleGenerate = async (file: File) => {
|
|
130
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
131
|
+
const products = parseExcelFile(arrayBuffer);
|
|
132
|
+
const pdfBuffer = await generateProductCatalog({
|
|
133
|
+
products,
|
|
134
|
+
companyName: 'My Store',
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Download
|
|
138
|
+
const blob = new Blob([pdfBuffer], { type: 'application/pdf' });
|
|
139
|
+
const url = URL.createObjectURL(blob);
|
|
140
|
+
const link = document.createElement('a');
|
|
141
|
+
link.href = url;
|
|
142
|
+
link.download = 'catalog.pdf';
|
|
143
|
+
link.click();
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<input
|
|
148
|
+
type="file"
|
|
149
|
+
accept=".xlsx,.csv"
|
|
150
|
+
onChange={(e) => e.target.files?.[0] && handleGenerate(e.target.files[0])}
|
|
151
|
+
/>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Input Types
|
|
157
|
+
|
|
158
|
+
The parser functions accept multiple input types for cross-platform compatibility:
|
|
159
|
+
|
|
160
|
+
- **Node.js Buffer** - `fs.readFileSync()` returns Buffer
|
|
161
|
+
- **ArrayBuffer** - Browser `File.arrayBuffer()` returns ArrayBuffer
|
|
162
|
+
- **Uint8Array** - Universal typed array format
|
|
163
|
+
|
|
164
|
+
All input types are automatically detected and handled correctly.
|
|
165
|
+
|
|
166
|
+
## API Reference
|
|
167
|
+
|
|
168
|
+
### `generateProductCatalog(config)`
|
|
169
|
+
|
|
170
|
+
Generates a PDF catalog from the provided configuration.
|
|
171
|
+
|
|
172
|
+
**Parameters:**
|
|
173
|
+
- `config` (CatalogConfig):
|
|
174
|
+
- `products` (ProductData[]): Array of product data
|
|
175
|
+
- `companyName` (string): Your company name
|
|
176
|
+
- `companyLogo` (string | null, optional): Logo URL or base64 string
|
|
177
|
+
- `template` (TemplateType, optional): Template to use (default: 'template1')
|
|
178
|
+
|
|
179
|
+
**Returns:** `Promise<Uint8Array>` - PDF file as Uint8Array (works in both Node.js and browser)
|
|
180
|
+
|
|
181
|
+
### `parseExcelFile(buffer)`
|
|
182
|
+
|
|
183
|
+
Parse Excel file buffer into product data.
|
|
184
|
+
|
|
185
|
+
**Parameters:**
|
|
186
|
+
- `buffer` (Buffer | ArrayBuffer | Uint8Array): Excel file data
|
|
187
|
+
- Node.js: Use `Buffer` from `fs.readFileSync()`
|
|
188
|
+
- Browser: Use `ArrayBuffer` from `file.arrayBuffer()`
|
|
189
|
+
- Universal: `Uint8Array` works everywhere
|
|
190
|
+
|
|
191
|
+
**Returns:** `ProductData[]` - Array of products
|
|
192
|
+
|
|
193
|
+
**Example (Node.js):**
|
|
194
|
+
```typescript
|
|
195
|
+
import { parseExcelFile, generateProductCatalog } from 'pdf-catalog-generator';
|
|
196
|
+
import fs from 'fs';
|
|
197
|
+
|
|
198
|
+
const excelBuffer = fs.readFileSync('products.xlsx');
|
|
199
|
+
const products = parseExcelFile(excelBuffer);
|
|
200
|
+
const pdfBuffer = await generateProductCatalog({
|
|
201
|
+
products,
|
|
202
|
+
companyName: 'My Store'
|
|
31
203
|
});
|
|
204
|
+
```
|
|
32
205
|
|
|
33
|
-
|
|
34
|
-
|
|
206
|
+
**Example (Browser/React):**
|
|
207
|
+
```typescript
|
|
208
|
+
import { parseExcelFile, generateProductCatalog } from 'pdf-catalog-generator';
|
|
35
209
|
|
|
36
|
-
const
|
|
210
|
+
const file = event.target.files[0];
|
|
211
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
212
|
+
const products = parseExcelFile(arrayBuffer);
|
|
37
213
|
const pdfBuffer = await generateProductCatalog({
|
|
38
214
|
products,
|
|
39
|
-
|
|
40
|
-
companyName: 'Your Company',
|
|
41
|
-
template: 'template2'
|
|
215
|
+
companyName: 'My Store'
|
|
42
216
|
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### `parseCSVFile(csvString)`
|
|
220
|
+
|
|
221
|
+
Parse CSV string into product data.
|
|
222
|
+
|
|
223
|
+
**Parameters:**
|
|
224
|
+
- `csvString` (string): CSV content as string
|
|
225
|
+
|
|
226
|
+
**Returns:** `ProductData[]` - Array of products
|
|
227
|
+
|
|
228
|
+
**Example:**
|
|
229
|
+
```typescript
|
|
230
|
+
import { parseCSVFile, generateProductCatalog } from 'pdf-catalog-generator';
|
|
231
|
+
import fs from 'fs';
|
|
232
|
+
|
|
233
|
+
const csvString = fs.readFileSync('products.csv', 'utf-8');
|
|
234
|
+
const products = parseCSVFile(csvString);
|
|
235
|
+
const pdfBuffer = await generateProductCatalog({
|
|
236
|
+
products,
|
|
237
|
+
companyName: 'My Store'
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### `parseCSVBuffer(buffer)`
|
|
242
|
+
|
|
243
|
+
Parse CSV buffer into product data.
|
|
244
|
+
|
|
245
|
+
**Parameters:**
|
|
246
|
+
- `buffer` (Buffer | ArrayBuffer | Uint8Array): CSV file data
|
|
247
|
+
- Node.js: Use `Buffer` from `fs.readFileSync()`
|
|
248
|
+
- Browser: Use `ArrayBuffer` from `file.arrayBuffer()`
|
|
249
|
+
- Universal: `Uint8Array` works everywhere
|
|
250
|
+
|
|
251
|
+
**Returns:** `ProductData[]` - Array of products
|
|
252
|
+
|
|
253
|
+
### `parseJSON(data)`
|
|
43
254
|
|
|
44
|
-
|
|
45
|
-
import { parseCSVFile } from 'pdf-catalog-generator';
|
|
255
|
+
Parse JSON product data. No fields are mandatory - data is passed through as-is.
|
|
46
256
|
|
|
47
|
-
|
|
257
|
+
**Parameters:**
|
|
258
|
+
- `data` (any[]): Array of product objects
|
|
259
|
+
|
|
260
|
+
**Returns:** `ProductData[]` - Products passed through without modification
|
|
261
|
+
|
|
262
|
+
**Note:** parseJSON no longer validates or normalizes data. It simply passes through your data as-is, just like the Excel/CSV parsers.
|
|
263
|
+
|
|
264
|
+
**Example:**
|
|
265
|
+
```typescript
|
|
266
|
+
import { parseJSON, generateProductCatalog } from 'pdf-catalog-generator';
|
|
267
|
+
|
|
268
|
+
const rawData = [
|
|
269
|
+
{ Title: 'Product 1', Link: 'https://example.com/1' },
|
|
270
|
+
{ sku: 'ABC-123', name: 'Custom Product', color: 'Blue' },
|
|
271
|
+
{ designNumber: 'DN-001', fabric: 'Cotton', gsm: 180 }
|
|
272
|
+
];
|
|
273
|
+
|
|
274
|
+
const products = parseJSON(rawData); // All pass through without modification
|
|
48
275
|
const pdfBuffer = await generateProductCatalog({
|
|
49
276
|
products,
|
|
50
|
-
|
|
51
|
-
companyName: 'Your Company',
|
|
52
|
-
template: 'template3'
|
|
277
|
+
companyName: 'My Store'
|
|
53
278
|
});
|
|
54
279
|
```
|
|
55
280
|
|
|
56
|
-
##
|
|
281
|
+
## Data Format
|
|
282
|
+
|
|
283
|
+
### ProductData
|
|
284
|
+
|
|
285
|
+
This library is **completely schema-free** - no fields are mandatory! You can use any data structure you want.
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
interface ProductData {
|
|
289
|
+
[key: string]: string | number | boolean | null | undefined;
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Dynamic Field Rendering:**
|
|
294
|
+
- All templates automatically detect and display whatever fields you provide
|
|
295
|
+
- Common fields (Title, Description, Image, Price, Rating, Link) are displayed prominently if present
|
|
296
|
+
- All other fields are rendered dynamically with auto-formatted labels
|
|
297
|
+
- Missing fields are gracefully handled - nothing breaks!
|
|
57
298
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
299
|
+
**Common Field Names (Optional):**
|
|
300
|
+
Templates intelligently look for these common fields (case-insensitive):
|
|
301
|
+
- **Title/Name/ProductName** - Displayed as main heading
|
|
302
|
+
- **Image/ImageUrl/photo** - Used as product image (fallback image if missing)
|
|
303
|
+
- **Description/Details/Info** - Shown as product description
|
|
304
|
+
- **Price/Cost/Amount** - Displayed prominently (formatted if provided)
|
|
305
|
+
- **Rating/Stars/Score** - Shown with star emoji if present
|
|
306
|
+
- **Link/URL/ProductUrl** - Powers "Buy Now" buttons
|
|
307
|
+
|
|
308
|
+
**Custom Fields:**
|
|
309
|
+
Any other fields are automatically displayed with smart formatting:
|
|
310
|
+
- `designNumber` → "Design Number"
|
|
311
|
+
- `gsm` → "GSM" (uppercase for known acronyms)
|
|
312
|
+
- `fabric_finish` → "Fabric Finish"
|
|
313
|
+
|
|
314
|
+
**Example - Traditional E-commerce:**
|
|
315
|
+
```typescript
|
|
316
|
+
{
|
|
317
|
+
Title: 'Laptop Pro 15',
|
|
318
|
+
Description: 'High-performance laptop',
|
|
319
|
+
Image: 'https://example.com/laptop.jpg',
|
|
320
|
+
Price: 1299.99,
|
|
321
|
+
Rating: 4.5,
|
|
322
|
+
Link: 'https://store.example.com/laptop'
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Example - Custom Textile Catalog:**
|
|
327
|
+
```typescript
|
|
328
|
+
{
|
|
329
|
+
designNumber: 'DN-12345',
|
|
330
|
+
fabric: '100% Cotton',
|
|
331
|
+
gsm: 180,
|
|
332
|
+
finish: 'Mercerized',
|
|
333
|
+
color: 'Navy Blue',
|
|
334
|
+
Image: 'https://example.com/fabric.jpg'
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**Example - Minimal:**
|
|
339
|
+
```typescript
|
|
340
|
+
{
|
|
341
|
+
name: 'Widget',
|
|
342
|
+
sku: 'WDG-001'
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
All of the above work perfectly! Templates adapt to your data structure.
|
|
65
347
|
|
|
66
348
|
## Templates
|
|
67
349
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
350
|
+
All templates are **fully dynamic** and adapt to your data structure. They intelligently detect common fields and display all additional fields automatically.
|
|
351
|
+
|
|
352
|
+
### Template 1: Grid Layout
|
|
353
|
+
2-column grid layout with product cards. Perfect for showcasing multiple products.
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
template: 'template1'
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
**Best for:** Products with mixed field types - automatically displays all fields in a compact grid card.
|
|
360
|
+
|
|
361
|
+
### Template 2: List Layout
|
|
362
|
+
Full-width horizontal layout with image on left, details on right. Great for detailed product information.
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
template: 'template2'
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Best for:** Detailed products - shows all fields with room for descriptions and custom attributes.
|
|
369
|
+
|
|
370
|
+
### Template 3: Full Page Layout
|
|
371
|
+
Full-page product view with image background and overlay details box. One product per page.
|
|
372
|
+
|
|
373
|
+
```typescript
|
|
374
|
+
template: 'template3'
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
**Best for:** Premium catalogs with hero images - displays key fields in an elegant overlay box (shows up to 5 custom fields).
|
|
378
|
+
|
|
379
|
+
### Template 4: One-Per-Page
|
|
380
|
+
Full-page product view with header on each page and all product details listed. One product per page.
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
template: 'template4'
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**Best for:** Maximum detail - displays ALL product fields with formatted labels. Ideal for technical specifications or textile catalogs.
|
|
387
|
+
|
|
388
|
+
## TypeScript Support
|
|
389
|
+
|
|
390
|
+
This package is written in TypeScript and includes type definitions:
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
import type { CatalogConfig, ProductData, TemplateType } from 'pdf-catalog-generator';
|
|
394
|
+
|
|
395
|
+
const config: CatalogConfig = {
|
|
396
|
+
products: [],
|
|
397
|
+
companyName: 'My Company',
|
|
398
|
+
template: 'template1'
|
|
399
|
+
};
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Examples
|
|
403
|
+
|
|
404
|
+
Check the `examples/` directory for complete working examples:
|
|
405
|
+
- Basic usage
|
|
406
|
+
- Excel to PDF
|
|
407
|
+
- CSV to PDF
|
|
408
|
+
- Custom templates
|
|
409
|
+
|
|
410
|
+
## Development
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# Install dependencies
|
|
414
|
+
npm install
|
|
415
|
+
|
|
416
|
+
# Run tests
|
|
417
|
+
npm test
|
|
418
|
+
|
|
419
|
+
# Run tests with coverage
|
|
420
|
+
npm run test:coverage
|
|
421
|
+
|
|
422
|
+
# Build package
|
|
423
|
+
npm run build
|
|
424
|
+
|
|
425
|
+
# Run Storybook
|
|
426
|
+
npm run storybook
|
|
427
|
+
|
|
428
|
+
# Lint code
|
|
429
|
+
npm run lint
|
|
430
|
+
|
|
431
|
+
# Format code
|
|
432
|
+
npm run format
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## Contributing
|
|
436
|
+
|
|
437
|
+
Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
|
|
438
|
+
|
|
439
|
+
## Changelog
|
|
440
|
+
|
|
441
|
+
See [CHANGELOG.md](CHANGELOG.md) for a list of changes.
|
|
442
|
+
|
|
443
|
+
## License
|
|
444
|
+
|
|
445
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
446
|
+
|
|
447
|
+
## Support
|
|
448
|
+
|
|
449
|
+
- 📚 [Documentation](https://github.com/yourusername/pdf-catalog-generator)
|
|
450
|
+
- 🐛 [Issue Tracker](https://github.com/yourusername/pdf-catalog-generator/issues)
|
|
451
|
+
- 💬 [Discussions](https://github.com/yourusername/pdf-catalog-generator/discussions)
|
|
452
|
+
|
|
453
|
+
## Credits
|
|
71
454
|
|
|
455
|
+
Built with:
|
|
456
|
+
- [@react-pdf/renderer](https://github.com/diegomura/react-pdf) - PDF generation
|
|
457
|
+
- [xlsx](https://github.com/SheetJS/sheetjs) - Excel/CSV parsing
|
|
458
|
+
- [TypeScript](https://www.typescriptlang.org/) - Type safety
|
|
459
|
+
- [Vitest](https://vitest.dev/) - Testing
|
|
460
|
+
- [Storybook](https://storybook.js.org/) - Documentation
|