Skip to content

Commit db0336a

Browse files
committed
Add URL API docs to README and GitHub link to header
Document the ?data= URL parameter for programmatic invoice generation with a collapsible example in the README. Add a "Self-host this" link with GitHub icon to the app header bar.
1 parent f47315b commit db0336a

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,61 @@ Inspired by [easy-invoice-pdf](https://github.com/VladSez/easy-invoice-pdf).
2121
- Cyrillic/Unicode support (embedded Open Sans fonts)
2222
- 60 e2e tests
2323

24+
<details>
25+
<summary><strong>URL API — generate invoice links programmatically</strong></summary>
26+
27+
The app accepts a `?data=` URL parameter containing a compressed invoice. You can generate these links from any language to create pre-filled invoices — useful for billing systems, CRMs, or automated workflows.
28+
29+
**How it works:** JSON → key compression → lz-string → URL
30+
31+
```js
32+
import LZString from "lz-string";
33+
34+
// Key compression map (same keys the app uses internally)
35+
const KEY_MAP = {
36+
language: "a", currency: "c", seller: "k", buyer: "l",
37+
items: "m", name: "A", address: "B", vatNo: "C",
38+
dateOfIssue: "g", dateOfService: "h", paymentDue: "r",
39+
amount: "N", unit: "P", netPrice: "R", vat: "T",
40+
netAmount: "V", vatAmount: "X", preTaxAmount: "Z",
41+
total: "n", notes: "t",
42+
};
43+
44+
function compressKeys(obj) {
45+
if (Array.isArray(obj)) return obj.map(compressKeys);
46+
if (obj && typeof obj === "object") {
47+
return Object.fromEntries(
48+
Object.entries(obj).map(([k, v]) => [KEY_MAP[k] ?? k, compressKeys(v)])
49+
);
50+
}
51+
return obj;
52+
}
53+
54+
const invoice = {
55+
language: "en",
56+
currency: "USD",
57+
dateOfIssue: "2026-01-15",
58+
dateOfService: "2026-01-15",
59+
paymentDue: "2026-02-15",
60+
seller: { name: "Acme Corp", address: "123 Main St" },
61+
buyer: { name: "Client Inc", address: "456 Oak Ave" },
62+
items: [
63+
{ name: "Consulting", amount: 10, unit: "hours",
64+
netPrice: 150, vat: 0, netAmount: 1500, vatAmount: 0, preTaxAmount: 1500 },
65+
],
66+
total: 1500,
67+
};
68+
69+
const compressed = LZString.compressToEncodedURIComponent(
70+
JSON.stringify(compressKeys(invoice))
71+
);
72+
const url = `https://h1d.github.io/easypdf-lite/?data=${compressed}`;
73+
```
74+
75+
Only include the fields you need — the app fills in defaults for everything else. See [`src/types.ts`](src/types.ts) for the full `InvoiceData` shape.
76+
77+
</details>
78+
2479
## What you don't get
2580
2681
API endpoints, analytics, Sentry, newsletters, about pages, or 200 MB of node_modules.

public/css/style.css

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,33 @@ body::before {
150150

151151
.header-right {
152152
display: flex;
153+
align-items: center;
153154
gap: 8px;
154155
}
155156

157+
.gh-link {
158+
display: inline-flex;
159+
align-items: center;
160+
gap: 6px;
161+
padding: 6px 12px;
162+
font-family: var(--font-body);
163+
font-size: 0.78rem;
164+
font-weight: 500;
165+
color: var(--ink-light);
166+
text-decoration: none;
167+
border: 1px solid var(--border-light);
168+
border-radius: var(--r-md);
169+
letter-spacing: 0.01em;
170+
transition: all 0.2s var(--ease-out);
171+
margin-right: 4px;
172+
}
173+
174+
.gh-link:hover {
175+
color: var(--ink);
176+
border-color: var(--border);
177+
background: var(--accent-soft);
178+
}
179+
156180
/* === Buttons === */
157181
.btn {
158182
display: inline-flex;
@@ -819,6 +843,8 @@ input[type="file"] {
819843
.header-right .btn svg + span,
820844
.header-right .btn:not(:has(svg)) { font-size: 0; }
821845
.header-right .btn { padding: 8px 12px; }
846+
.gh-link span { display: none; }
847+
.gh-link { padding: 6px; margin-right: 0; }
822848

823849
.item-fields { grid-template-columns: 1fr; }
824850
.item-field[data-col="name"] { grid-column: span 1; }

public/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ <h1 class="logo">EasyPDF <span class="logo-lite">Lite</span></h1>
1616
<span class="tagline">Free Invoice Generator</span>
1717
</div>
1818
<div class="header-right">
19+
<a href="https://github.com/h1d/easypdf-lite" target="_blank" rel="noopener" class="gh-link" data-testid="github-link">
20+
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
21+
<span>Self-host this</span>
22+
</a>
1923
<button type="button" id="btn-share" class="btn btn-outline" data-testid="share-invoice-link-button">
2024
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"/><polyline points="16 6 12 2 8 6"/><line x1="12" y1="2" x2="12" y2="15"/></svg>
2125
<span>Share Link</span>

0 commit comments

Comments
 (0)