weasyprint-tsx 0.0.1 → 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 CHANGED
@@ -1 +1,99 @@
1
-
1
+ # weasyprint-tsx
2
+
3
+ Write PDFs in TSX. Uses [Bun](https://bun.sh) to bundle your Preact components into HTML, then [WeasyPrint](https://weasyprint.org) to render them as PDF.
4
+
5
+ ## Requirements
6
+
7
+ - [Bun](https://bun.sh) ≥ 1.0
8
+ - [WeasyPrint](https://weasyprint.org) — `pip install weasyprint`
9
+
10
+ ## Quick start
11
+
12
+ ```bash
13
+ bunx create-weasyprint-tsx my-doc
14
+ cd my-doc
15
+ bun install
16
+ bun run dev
17
+ ```
18
+
19
+ Open `http://localhost:3000` to preview the document live. The PDF is written to `output.pdf` on every save.
20
+
21
+ ## Scripts
22
+
23
+ | Script | Effect |
24
+ |--------|--------|
25
+ | `bun run dev` | Watch `src/`, rebuild HTML + PDF on change, serve preview at port 3000 |
26
+ | `bun run build` | Build once and write `output.pdf` |
27
+
28
+ ## Project structure
29
+
30
+ ```
31
+ my-doc/
32
+ ├── src/
33
+ │ ├── index.tsx # Document root — must export a default Preact component
34
+ │ └── index.css # Styles — must begin with @import "tailwindcss"
35
+ ├── weasyprint-tsx.config.ts
36
+ └── package.json
37
+ ```
38
+
39
+ `src/index.tsx` must export a default component that renders a **complete HTML document** (`<html>`, `<head>`, `<body>`). WeasyPrint receives the full HTML string.
40
+
41
+ ## Configuration
42
+
43
+ Create or edit `weasyprint-tsx.config.ts` at the project root:
44
+
45
+ ```ts
46
+ import type { Config } from "@weasyprint-tsx/build";
47
+
48
+ const config: Config = {
49
+ io: { output: "report.pdf" },
50
+ weasyprint: { path: "weasyprint", optimize_images: true },
51
+ };
52
+
53
+ export default config;
54
+ ```
55
+
56
+ ### `io`
57
+
58
+ | Field | Default | Description |
59
+ |-------|---------|-------------|
60
+ | `input` | `"src/index.tsx"` | Entry point |
61
+ | `output` | `"output.pdf"` | Output PDF path |
62
+ | `buildDir` | `".build"` | Intermediate HTML directory |
63
+ | `media_type` | `"print"` | CSS media type passed to WeasyPrint |
64
+
65
+ ### `weasyprint`
66
+
67
+ | Field | Default | Description |
68
+ |-------|---------|-------------|
69
+ | `path` | `"weasyprint"` | Path to the WeasyPrint binary |
70
+ | `verbose` | `false` | Print WeasyPrint stdout |
71
+ | `dpi` | — | Output resolution |
72
+ | `optimize_images` | — | Compress images in output |
73
+ | `pdf_forms` | — | Enable PDF form fields |
74
+ | `pdf_variant` | — | `"pdf/a-1b"`, `"pdf/a-2b"`, `"pdf/a-3b"`, `"pdf/a-4b"`, `"pdf/ua-1"` |
75
+ | `cache` | — | WeasyPrint font/image cache folder |
76
+ | `full_fonts` | — | Embed full font files (not just subsets) |
77
+ | `srgb` | — | Force sRGB color profile |
78
+ | `jpeg_quality` | — | JPEG compression quality (0–95) |
79
+
80
+ ### `dev`
81
+
82
+ | Field | Default | Description |
83
+ |-------|---------|-------------|
84
+ | `port` | `3000` | Dev server port |
85
+ | `watch` | `"src"` | Directory to watch for changes |
86
+
87
+ ### `pdf`
88
+
89
+ | Field | Default | Description |
90
+ |-------|---------|-------------|
91
+ | `stylesheets` | `[]` | Additional CSS files passed to WeasyPrint via `--stylesheet` |
92
+
93
+ ## UI components
94
+
95
+ `@weasyprint-tsx/ui` provides print-optimized Preact components. See [`packages/ui/README.md`](packages/ui/README.md) for the full API.
96
+
97
+ ```tsx
98
+ import { H1, H2, Page, UL, LI, Table, Entry } from "@weasyprint-tsx/ui";
99
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weasyprint-tsx",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "scripts": {
5
5
  "dev": "bun packages/build/src/cli.ts --watch",
6
6
  "init" : "bun packages/create/cli.ts"
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@weasyprint-tsx/build",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
+ "main": "./src/index.ts",
5
+ "exports": { ".": "./src/index.ts" },
6
+ "types": "./src/index.ts",
4
7
  "bin": {
5
8
  "weasyprint-tsx": "./src/cli.ts"
6
9
  },
7
- "workspaces": [
8
- "packages/*"
9
- ],
10
10
  "devDependencies": {
11
11
  "bun-types": "latest"
12
12
  },
@@ -89,7 +89,7 @@ export async function buildPDF(cfg: DConfig): Promise<void> {
89
89
  const t0 = performance.now();
90
90
  const proc = Bun.spawn(args, {
91
91
  cwd: process.cwd(),
92
- stderr: "inherit",
92
+ stderr: cfg.weasyprint.verbose ? "inherit" : "ignore",
93
93
  stdout: cfg.weasyprint.verbose ? "inherit" : "ignore",
94
94
  });
95
95
  const code = await proc.exited;
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env bun
1
2
  import { devMode, buildOnce } from "./orchestrator";
2
3
 
3
4
 
@@ -80,11 +80,12 @@ export async function loadConfig(): Promise<DConfig> {
80
80
  const configPath = resolve(process.cwd(), "weasyprint-tsx.config.ts");
81
81
  let config = defaultConfig;
82
82
  try {
83
- const {default : userConfig} = await import(`${configPath}`);
83
+ const { default: userConfig } = await import(`${configPath}`);
84
84
  config = mergeDeep(config, userConfig) as unknown as DConfig;
85
- console.log(config , userConfig)
86
85
  } catch (e) {
87
- process.stdout.write(`No config file at ${configPath} found, using default.`);
86
+ process.stdout.write(
87
+ `No config file at ${configPath} found, using default.`,
88
+ );
88
89
  }
89
90
  return config;
90
91
  }
@@ -0,0 +1 @@
1
+ export type { Config, DConfig } from "./config";
@@ -1,11 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { cpSync, existsSync, readFileSync, writeFileSync } from "fs";
4
- import { join } from "path";
4
+ import { join,dirname } from "path";
5
+ import { fileURLToPath } from "url";
5
6
 
6
7
  const name = process.argv[2] ?? "my-doc";
7
8
  const dest = join(process.cwd(), name);
8
- const templateDir = join(import.meta.dir, "template");
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+
13
+ const templateDir = join(__dirname, "template");
9
14
 
10
15
  if (existsSync(dest)) {
11
16
  process.stderr.write(`Error: directory '${name}' already exists\n`);
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@weasyprint-tsx/create",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "bin": {
5
- "create-weasyprint-tsx": "src/cli.ts"
5
+ "create-weasyprint-tsx": "cli.js"
6
6
  },
7
- "workspaces": [
8
- "packages/*"
7
+ "files": [
8
+ "cli.js",
9
+ "template"
9
10
  ]
10
11
  }
@@ -0,0 +1,119 @@
1
+ # weasyprint-tsx Project — LLM Context
2
+
3
+ This is a **weasyprint-tsx** document project. The output is a PDF file generated from Preact/TSX source.
4
+
5
+ ## Pipeline
6
+
7
+ ```
8
+ src/index.tsx → Bun.build() → .build/index.html → WeasyPrint → output.pdf
9
+ ```
10
+
11
+ - **Bun** bundles the TSX entry point (and its imports) into a static HTML file
12
+ - **WeasyPrint** converts that HTML into a PDF using CSS print rules
13
+ - The dev server (`port 3000`) serves the HTML with live reload injected
14
+
15
+ ## Commands
16
+
17
+ ```bash
18
+ bun run dev # watch src/, rebuild on change, serve preview at localhost:3000
19
+ bun run build # build once, write output.pdf
20
+ ```
21
+
22
+ ## Entry point (`src/index.tsx`)
23
+
24
+ Must export a **default Preact component** that returns a **complete HTML document**:
25
+
26
+ ```tsx
27
+ import { H1, Page } from "@weasyprint-tsx/ui";
28
+ import "./index.css";
29
+
30
+ export default function Document() {
31
+ return (
32
+ <html>
33
+ <head>
34
+ <meta charset="UTF-8" />
35
+ <title>My Document</title>
36
+ <link rel="stylesheet" href="index.css" />
37
+ </head>
38
+ <body>
39
+ <Page>
40
+ <H1>My Document</H1>
41
+ </Page>
42
+ </body>
43
+ </html>
44
+ );
45
+ }
46
+ ```
47
+
48
+ The component must render `<html>`, `<head>`, and `<body>` — WeasyPrint receives the full HTML string.
49
+
50
+ ## Stylesheet (`src/index.css`)
51
+
52
+ Must start with `@import "tailwindcss"`. Page size and margins are set via `@page`:
53
+
54
+ ```css
55
+ @import "tailwindcss";
56
+
57
+ @page {
58
+ size: A4;
59
+ margin: 2cm 1.5cm;
60
+ }
61
+ ```
62
+
63
+ CSS `@page` rules control paper size, margins, and page headers/footers. Do **not** use `html { width: 21cm }` — let WeasyPrint handle page geometry via `@page`.
64
+
65
+ ## Configuration (`weasyprint-tsx.config.ts`)
66
+
67
+ ```ts
68
+ import type { Config } from "@weasyprint-tsx/build";
69
+
70
+ const config: Config = {
71
+ io: {
72
+ output: "output.pdf", // output path
73
+ input: "src/index.tsx", // entry point
74
+ },
75
+ weasyprint: {
76
+ path: "weasyprint", // path to weasyprint binary
77
+ },
78
+ };
79
+
80
+ export default config;
81
+ ```
82
+
83
+ ## UI Components (`@weasyprint-tsx/ui`)
84
+
85
+ All components are Preact components (not React). Import from `@weasyprint-tsx/ui`:
86
+
87
+ ```ts
88
+ import {
89
+ // Layout
90
+ Page, PageBreak,
91
+ BlockBox, Block,
92
+ // Headings
93
+ H1, H2, H3, H4, H5, H6, Title, ResetCounter,
94
+ // Lists
95
+ UL, OL, LI,
96
+ // Table
97
+ Table, Entry,
98
+ // Inline
99
+ DotLine, CodeBlock, Equation,
100
+ } from "@weasyprint-tsx/ui";
101
+ ```
102
+
103
+ See the full API: https://github.com/weasyprint-tsx/weasyprint-tsx/blob/main/packages/ui/README.md
104
+
105
+ ## CSS References
106
+
107
+ - **WeasyPrint CSS support**: https://doc.courtbouillon.org/weasyprint/stable/first_steps.html
108
+ - **Tailwind CSS v4 docs**: https://tailwindcss.com/docs
109
+
110
+ ## Constraints for LLMs
111
+
112
+ - **No `position: fixed` or `position: sticky`** — these do not work in print media
113
+ - **No `vh` / `vw` units** — viewport units are meaningless in print context
114
+ - **No `@media screen`** — the document is rendered in print media; use `@media print` or no media query
115
+ - **Page geometry** belongs in `@page` rules, not on `html` or `body`
116
+ - **All layout** should use CSS that WeasyPrint supports. Flexbox and CSS Grid have partial support — prefer block layout or the `BlockBox`/`Block` components for multi-column content
117
+ - **Components are Preact**, not React — use `class` not `className` for raw HTML elements (Preact accepts both, but prefer `class`)
118
+ - **Images** must be embedded as base64 data URIs or served by the dev server; external URLs may not resolve during build
119
+ - **Fonts** must be declared in CSS with `@font-face` or imported via Tailwind; Google Fonts CDN links work at build time
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "name": "my-doc",
3
- "private": true,
4
3
  "scripts": {
5
4
  "build": "weasyprint-tsx",
6
5
  "dev": "weasyprint-tsx --watch",
@@ -1,17 +1,5 @@
1
1
  import type { Config } from "@weasyprint-tsx/build";
2
2
 
3
- const config: Config = {
4
- io: {
5
- engine: "weasyprint",
6
- output: "output.pdf",
7
- },
8
- weasyprint: {
9
- pdf_forms: true,
10
- },
11
- watchdog: {
12
- path: "./src",
13
- debounce: 500,
14
- },
15
- };
3
+ const config: Config = {};
16
4
 
17
5
  export default config;
@@ -0,0 +1,278 @@
1
+ # @weasyprint-tsx/ui
2
+
3
+ Print-optimized Preact components for [weasyprint-tsx](../../README.md) documents.
4
+
5
+ ```ts
6
+ import { H1, H2, Page, UL, LI, Table, Entry, BlockBox, Block } from "@weasyprint-tsx/ui";
7
+ ```
8
+
9
+ ---
10
+
11
+ ## Page layout
12
+
13
+ ### `Page`
14
+
15
+ Wraps a page section. Maps to a `<section>` element.
16
+
17
+ ```tsx
18
+ <Page page="cover">
19
+ <H1>My Document</H1>
20
+ </Page>
21
+ ```
22
+
23
+ | Prop | Type | Description |
24
+ |------|------|-------------|
25
+ | `page` | `string` | Value for the CSS `page` property (named page rule) |
26
+
27
+ ---
28
+
29
+ ### `PageBreak`
30
+
31
+ Forces a page break at the current position.
32
+
33
+ ```tsx
34
+ <PageBreak />
35
+ ```
36
+
37
+ No props.
38
+
39
+ ---
40
+
41
+ ## Headings
42
+
43
+ ### `H1` – `H6`
44
+
45
+ Render `<h1>`–`<h6>` with optional marker and color overrides. Headings participate in CSS counters for automatic numbering if you set them up in your stylesheet.
46
+
47
+ ```tsx
48
+ <H1>Title</H1>
49
+ <H2 color="#1e40af" fontSize="14pt">Section</H2>
50
+ <H3 marker="§">Subsection</H3>
51
+ ```
52
+
53
+ | Prop | Type | Description |
54
+ |------|------|-------------|
55
+ | `marker` | `string` | Sets `data-marker` attribute (used by CSS `::before` counter content) |
56
+ | `color` | `string` | Inline text color |
57
+ | `fontSize` | `string` | Inline font size |
58
+ | `...rest` | `ComponentProps<"h1">` etc. | All standard HTML heading attributes |
59
+
60
+ ---
61
+
62
+ ### `Title`
63
+
64
+ Generic heading that accepts a `type` prop.
65
+
66
+ ```tsx
67
+ <Title type="h2" color="red">Dynamic heading</Title>
68
+ ```
69
+
70
+ | Prop | Type | Description |
71
+ |------|------|-------------|
72
+ | `type` | `"h1"` \| `"h2"` \| … \| `"h6"` | Which heading element to render |
73
+
74
+ ---
75
+
76
+ ### `ResetCounter`
77
+
78
+ Renders a hidden `<div>` that resets CSS counters. Use at the start of a section when you want numbered headings to restart.
79
+
80
+ ```tsx
81
+ <ResetCounter />
82
+ ```
83
+
84
+ No props.
85
+
86
+ ---
87
+
88
+ ## Lists
89
+
90
+ ### `UL`
91
+
92
+ Unordered list. Children should be `<LI>` elements.
93
+
94
+ ```tsx
95
+ <UL marker="→">
96
+ <LI>Item one</LI>
97
+ <LI>Item two</LI>
98
+ </UL>
99
+ ```
100
+
101
+ | Prop | Type | Default | Description |
102
+ |------|------|---------|-------------|
103
+ | `marker` | `string` | `"•"` | Bullet character |
104
+ | `gap` | `string \| number` | — | Gap between items |
105
+ | `pre` | `ComponentChildren` | — | Content rendered before the list (e.g. a label) |
106
+
107
+ ---
108
+
109
+ ### `OL`
110
+
111
+ Ordered list. Children should be `<LI>` elements.
112
+
113
+ ```tsx
114
+ <OL counterType="lower-roman" markerPost=".">
115
+ <LI>First</LI>
116
+ <LI>Second</LI>
117
+ </OL>
118
+ ```
119
+
120
+ | Prop | Type | Default | Description |
121
+ |------|------|---------|-------------|
122
+ | `start` | `number` | `1` | Starting counter value |
123
+ | `counterType` | `"decimal"` \| `"lower-alpha"` \| `"upper-alpha"` \| `"lower-roman"` \| `"upper-roman"` | `"decimal"` | Counter style |
124
+ | `markerPre` | `string` | — | String prepended to the counter (e.g. `"("`) |
125
+ | `markerPost` | `string` | `"."` | String appended to the counter |
126
+ | `gap` | `string \| number` | — | Gap between items |
127
+ | `pre` | `ComponentChildren` | — | Content rendered before the list |
128
+
129
+ ---
130
+
131
+ ### `LI`
132
+
133
+ List item, used inside `UL` or `OL`.
134
+
135
+ ```tsx
136
+ <LI>Plain item</LI>
137
+ <LI marker="★">Custom marker</LI>
138
+ ```
139
+
140
+ | Prop | Type | Description |
141
+ |------|------|-------------|
142
+ | `marker` | `string` | Override the list's default marker for this item |
143
+ | `count` | `number` | Override the displayed counter value (OL only) |
144
+
145
+ ---
146
+
147
+ ## Table
148
+
149
+ ### `Table`
150
+
151
+ Renders an HTML table. Children must be `<Entry>` components.
152
+
153
+ ```tsx
154
+ <Table orientation="col" headerBg="#1e40af" borderColor="#cbd5e1">
155
+ <Entry content={["Alice", "Engineer", "Berlin"]} />
156
+ <Entry content={["Bob", "Designer", "Paris"]} />
157
+ </Table>
158
+ ```
159
+
160
+ | Prop | Type | Default | Description |
161
+ |------|------|---------|-------------|
162
+ | `orientation` | `"col"` \| `"row"` | `"col"` | `"col"`: first Entry is the header row. `"row"`: first cell of each Entry is the row header. |
163
+ | `headerBg` | `string` | — | Background color for header cells |
164
+ | `cellBg` | `string` | — | Background color for data cells |
165
+ | `headerFontSize` | `string` | — | Font size for header cells |
166
+ | `cellFontSize` | `string` | — | Font size for data cells |
167
+ | `borderWidth` | `string` | `"1px"` | Border width |
168
+ | `borderColor` | `string` | `"#000"` | Border color |
169
+ | `contentClass` | `string` | — | Extra class applied to all data cells |
170
+ | `headerClass` | `string` | — | Extra class applied to all header cells |
171
+
172
+ ---
173
+
174
+ ### `Entry`
175
+
176
+ Data row or column for `Table`. Renders `null` — `Table` reads its props directly.
177
+
178
+ ```tsx
179
+ <Entry content={["Name", "Role", "Location"]} headerBg="#e2e8f0" />
180
+ ```
181
+
182
+ | Prop | Type | Description |
183
+ |------|------|-------------|
184
+ | `content` | `ComponentChild[]` | Array of cell values |
185
+ | `contentClass` | `string` | Extra class for this Entry's data cells |
186
+ | `headerBg` | `string` | Override header background for this Entry |
187
+ | `cellBg` | `string` | Override cell background for this Entry |
188
+ | `headerFontSize` | `string` | Override header font size |
189
+ | `cellFontSize` | `string` | Override cell font size |
190
+
191
+ ---
192
+
193
+ ## BlockBox / Block
194
+
195
+ Two-component system for multi-column / ratio-based layouts.
196
+
197
+ ### `BlockBox`
198
+
199
+ Container. Lays out `<Block>` children side by side.
200
+
201
+ ```tsx
202
+ <BlockBox gap="1cm" basis={50}>
203
+ <Block ratio={2}>Wide column</Block>
204
+ <Block ratio={1}>Narrow column</Block>
205
+ </BlockBox>
206
+ ```
207
+
208
+ | Prop | Type | Default | Description |
209
+ |------|------|---------|-------------|
210
+ | `gap` | `string` | `"0"` | Gap between blocks |
211
+ | `basis` | `number` | `100` | Flex basis percentage for equal-width fallback |
212
+ | `centered` | `boolean` | `false` | Center block contents horizontally |
213
+ | `align` | `"top"` \| `"middle"` \| `"bottom"` | `"top"` | Vertical alignment of blocks |
214
+
215
+ ### `Block`
216
+
217
+ A single column inside `BlockBox`.
218
+
219
+ | Prop | Type | Description |
220
+ |------|------|-------------|
221
+ | `ratio` | `number` | Relative width ratio compared to siblings |
222
+ | `centered` | `boolean` | Center this block's content |
223
+ | `align` | `"top"` \| `"middle"` \| `"bottom"` | Vertical alignment override |
224
+
225
+ ---
226
+
227
+ ## DotLine
228
+
229
+ A repeating dot pattern, useful for fill lines in tables of contents or forms.
230
+
231
+ ```tsx
232
+ <DotLine width="100%" />
233
+ <DotLine inline num={3} color="#94a3b8" />
234
+ ```
235
+
236
+ | Prop | Type | Default | Description |
237
+ |------|------|---------|-------------|
238
+ | `num` | `number` | `1` | Number of dot-line rows |
239
+ | `width` | `number \| string` | `"100%"` | Width of the dot line |
240
+ | `inline` | `boolean` | `false` | Render as inline element |
241
+ | `color` | `string` | — | Dot color |
242
+ | `lineHeight` | `string` | — | Line height of each dot row |
243
+
244
+ ---
245
+
246
+ ## CodeBlock
247
+
248
+ Syntax-highlighted code block using highlight.js.
249
+
250
+ ```tsx
251
+ <CodeBlock language="typescript" code={`const x: number = 42;`} />
252
+ ```
253
+
254
+ | Prop | Type | Description |
255
+ |------|------|-------------|
256
+ | `language` | `string` | highlight.js language identifier (e.g. `"typescript"`, `"python"`, `"bash"`) |
257
+ | `code` | `string` | Source code string |
258
+
259
+ Renders with `break-inside: avoid` to prevent page breaks mid-block.
260
+
261
+ ---
262
+
263
+ ## Equation
264
+
265
+ LaTeX equation rendering via KaTeX.
266
+
267
+ ```tsx
268
+ <Equation tex="E = mc^2" displayMode />
269
+ <Equation tex="\ce{H2O}" chemical />
270
+ <Equation tex="x &= a + b \\ y &= c + d" aligned displayMode />
271
+ ```
272
+
273
+ | Prop | Type | Default | Description |
274
+ |------|------|---------|-------------|
275
+ | `tex` | `string` | — | LaTeX source |
276
+ | `displayMode` | `boolean` | `false` | Render as block-level equation |
277
+ | `aligned` | `boolean` | `false` | Wrap in `\begin{aligned}…\end{aligned}` |
278
+ | `chemical` | `boolean` | `false` | Wrap in `\ce{…}` for chemical notation |
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@weasyprint-tsx/ui",
3
- "version" : "0.0.1",
4
- "private": true,
5
- "workspaces": [
6
- "packages/*"
7
- ]
3
+ "version": "0.1.0",
4
+ "exports": {
5
+ ".": "./src/index.ts"
6
+ },
7
+ "types": "./src/index.ts"
8
8
  }
package/src/index.css CHANGED
@@ -0,0 +1,39 @@
1
+ @import "tailwindcss";
2
+
3
+ @page {
4
+ size: A4;
5
+ margin: 2.5cm 2cm;
6
+
7
+ @bottom-center {
8
+ content: counter(page) " / " counter(pages);
9
+ font-size: 8pt;
10
+ color: #94a3b8;
11
+ }
12
+ }
13
+
14
+ html,
15
+ body {
16
+ color: #0f172a;
17
+ margin: 0;
18
+ padding: 0;
19
+ font-size: 10pt;
20
+ line-height: 1.75;
21
+ font-family: system-ui, sans-serif;
22
+ }
23
+
24
+ h1, h2, h3 {
25
+ line-height: 1.2;
26
+ }
27
+
28
+ code {
29
+ font-family: ui-monospace, monospace;
30
+ font-size: 0.88em;
31
+ background: #f1f5f9;
32
+ padding: 0.1em 0.3em;
33
+ border-radius: 3px;
34
+ }
35
+
36
+ pre code {
37
+ background: none;
38
+ padding: 0;
39
+ }
package/src/index.tsx CHANGED
@@ -1,15 +1,203 @@
1
- import { H1 } from "@weasyprint-tsx/ui";
1
+ import {
2
+ H1, H2, H3,
3
+ Page, PageBreak,
4
+ UL, OL, LI,
5
+ Table, Entry,
6
+ BlockBox, Block,
7
+ CodeBlock,
8
+ DotLine,
9
+ } from "@weasyprint-tsx/ui";
2
10
  import "./index.css";
3
11
 
12
+ const configCode = `import type { Config } from "@weasyprint-tsx/build";
13
+
14
+ const config: Config = {
15
+ io: { output: "report.pdf" },
16
+ weasyprint: {
17
+ path: "weasyprint",
18
+ optimize_images: true,
19
+ dpi: 150,
20
+ },
21
+ dev: { port: 3000 },
22
+ };
23
+
24
+ export default config;`;
25
+
26
+ const indexCode = `import { H1, H2, Page, UL, LI } from "@weasyprint-tsx/ui";
27
+ import "./index.css";
28
+
29
+ export default function Document() {
30
+ return (
31
+ <html>
32
+ <head>
33
+ <title>My Report</title>
34
+ <link rel="stylesheet" href="index.css" />
35
+ </head>
36
+ <body>
37
+ <Page>
38
+ <H1>My Report</H1>
39
+ <H2>Introduction</H2>
40
+ <UL>
41
+ <LI>Authored in TSX</LI>
42
+ <LI>Rendered by WeasyPrint</LI>
43
+ </UL>
44
+ </Page>
45
+ </body>
46
+ </html>
47
+ );
48
+ }`;
49
+
4
50
  export default function Document() {
5
51
  return (
6
52
  <html>
7
53
  <head>
8
- <title>Weasyprint-tsx - ReadMe</title>
54
+ <meta charset="UTF-8" />
55
+ <title>weasyprint-tsx</title>
9
56
  <link rel="stylesheet" href="index.css" />
10
57
  </head>
11
58
  <body>
12
- <H1>HEHE</H1>
59
+
60
+ {/* ── Cover ── */}
61
+ <Page>
62
+ <div style={{ marginBottom: "1.5cm" }}>
63
+ <H1 fontSize="28pt" color="#1e40af">weasyprint-tsx</H1>
64
+ <p style={{ fontSize: "13pt", color: "#475569", marginTop: "0.3cm" }}>
65
+ Write PDFs in TSX — Bun bundles your Preact components into HTML,
66
+ WeasyPrint renders them as PDF.
67
+ </p>
68
+ <DotLine width="100%" color="#cbd5e1" />
69
+ </div>
70
+
71
+ <BlockBox gap="1cm">
72
+ <Block ratio={1}>
73
+ <H3 color="#1e40af">Requirements</H3>
74
+ <UL>
75
+ <LI>Bun ≥ 1.0</LI>
76
+ <LI>WeasyPrint (pip install weasyprint)</LI>
77
+ </UL>
78
+ </Block>
79
+ <Block ratio={1}>
80
+ <H3 color="#1e40af">Quick start</H3>
81
+ <OL>
82
+ <LI>bunx create-weasyprint-tsx my-doc</LI>
83
+ <LI>cd my-doc &amp;&amp; bun install</LI>
84
+ <LI>bun run dev</LI>
85
+ </OL>
86
+ </Block>
87
+ </BlockBox>
88
+ </Page>
89
+
90
+ <PageBreak />
91
+
92
+ {/* ── Getting Started ── */}
93
+ <Page>
94
+ <H2 color="#1e40af">Getting Started</H2>
95
+
96
+ <p>
97
+ The <code>create-weasyprint-tsx</code> scaffolder generates a ready-to-use
98
+ project. After installation, two scripts are available:
99
+ </p>
100
+
101
+ <Table orientation="col" headerBg="#1e40af" headerFontSize="9pt" cellFontSize="9pt" borderColor="#e2e8f0">
102
+ <Entry content={["Script", "Effect"]} />
103
+ <Entry content={["bun run dev", "Watch src/, rebuild on change, serve preview at localhost:3000"]} />
104
+ <Entry content={["bun run build", "Build once, write output.pdf"]} />
105
+ </Table>
106
+
107
+ <H3>Project structure</H3>
108
+ <CodeBlock language="plaintext" code={`my-doc/
109
+ ├── src/
110
+ │ ├── index.tsx # Document root — export a default Preact component
111
+ │ └── index.css # Styles — must start with @import "tailwindcss"
112
+ ├── weasyprint-tsx.config.ts
113
+ └── package.json`} />
114
+
115
+ <H3>Entry point</H3>
116
+ <p>
117
+ <code>src/index.tsx</code> must export a default component that renders a
118
+ complete HTML document. WeasyPrint receives the full HTML string.
119
+ </p>
120
+ <CodeBlock language="tsx" code={indexCode} />
121
+ </Page>
122
+
123
+ <PageBreak />
124
+
125
+ {/* ── Configuration ── */}
126
+ <Page>
127
+ <H2 color="#1e40af">Configuration</H2>
128
+ <p>
129
+ Create <code>weasyprint-tsx.config.ts</code> at the project root to
130
+ override any default:
131
+ </p>
132
+ <CodeBlock language="typescript" code={configCode} />
133
+
134
+ <H3>All config fields</H3>
135
+
136
+ <Table orientation="col" headerBg="#334155" headerFontSize="8.5pt" cellFontSize="8.5pt" borderColor="#e2e8f0">
137
+ <Entry content={["Field", "Default", "Description"]} />
138
+ <Entry content={["io.input", "src/index.tsx", "TSX entry point"]} />
139
+ <Entry content={["io.output", "output.pdf", "Output PDF path"]} />
140
+ <Entry content={["io.buildDir", ".build", "Intermediate HTML directory"]} />
141
+ <Entry content={["io.media_type", "print", "CSS media type"]} />
142
+ <Entry content={["weasyprint.path", "weasyprint", "Path to WeasyPrint binary"]} />
143
+ <Entry content={["weasyprint.dpi", "—", "Output resolution"]} />
144
+ <Entry content={["weasyprint.optimize_images", "—", "Compress images in output"]} />
145
+ <Entry content={["weasyprint.pdf_forms", "—", "Enable PDF form fields"]} />
146
+ <Entry content={["weasyprint.pdf_variant", "—", "pdf/a-1b, pdf/ua-1, …"]} />
147
+ <Entry content={["weasyprint.full_fonts", "—", "Embed full font files"]} />
148
+ <Entry content={["weasyprint.cache", "—", "Font/image cache folder"]} />
149
+ <Entry content={["dev.port", "3000", "Dev server port"]} />
150
+ <Entry content={["dev.watch", "src", "Directory to watch"]} />
151
+ <Entry content={["pdf.stylesheets", "[]", "Extra CSS files via --stylesheet"]} />
152
+ </Table>
153
+ </Page>
154
+
155
+ <PageBreak />
156
+
157
+ {/* ── UI Components ── */}
158
+ <Page>
159
+ <H2 color="#1e40af">UI Components</H2>
160
+ <p>
161
+ <code>@weasyprint-tsx/ui</code> provides print-optimized Preact components.
162
+ Import everything from the package root:
163
+ </p>
164
+ <CodeBlock language="ts" code={`import { H1, H2, Page, PageBreak, UL, OL, LI, Table, Entry, BlockBox, Block, DotLine, CodeBlock, Equation } from "@weasyprint-tsx/ui";`} />
165
+
166
+ <H3>Page &amp; Layout</H3>
167
+ <Table orientation="row" headerBg="#f1f5f9" borderColor="#e2e8f0" headerFontSize="8.5pt" cellFontSize="8.5pt">
168
+ <Entry content={["Page", "Wraps a page section (<section>). Accepts page?: string for named page rules."]} />
169
+ <Entry content={["PageBreak", "Inserts a CSS page break. No props."]} />
170
+ <Entry content={["BlockBox", "Multi-column flex container. Props: gap, basis, centered, align."]} />
171
+ <Entry content={["Block", "Column inside BlockBox. Props: ratio, centered, align."]} />
172
+ </Table>
173
+
174
+ <H3>Headings</H3>
175
+ <Table orientation="row" headerBg="#f1f5f9" borderColor="#e2e8f0" headerFontSize="8.5pt" cellFontSize="8.5pt">
176
+ <Entry content={["H1 – H6", "Render h1–h6. Props: marker (data-marker for CSS counters), color, fontSize."]} />
177
+ <Entry content={["ResetCounter", "Hidden div that resets CSS counters. Use at the top of numbered sections."]} />
178
+ </Table>
179
+
180
+ <H3>Lists</H3>
181
+ <Table orientation="row" headerBg="#f1f5f9" borderColor="#e2e8f0" headerFontSize="8.5pt" cellFontSize="8.5pt">
182
+ <Entry content={["UL", "Unordered list. Props: marker (bullet char), gap, pre."]} />
183
+ <Entry content={["OL", "Ordered list. Props: start, counterType (decimal/lower-alpha/upper-roman/…), markerPre, markerPost, gap, pre."]} />
184
+ <Entry content={["LI", "List item. Props: marker (override bullet), count (override counter)."]} />
185
+ </Table>
186
+
187
+ <H3>Table</H3>
188
+ <Table orientation="row" headerBg="#f1f5f9" borderColor="#e2e8f0" headerFontSize="8.5pt" cellFontSize="8.5pt">
189
+ <Entry content={["Table", `orientation "col" (default): first Entry is the header row. orientation "row": first cell of each Entry is the row header. Also: headerBg, cellBg, borderWidth, borderColor, headerFontSize, cellFontSize.`]} />
190
+ <Entry content={["Entry", "Data row/column. content: ComponentChild[] holds cell values. Accepts per-entry overrides: headerBg, cellBg."]} />
191
+ </Table>
192
+
193
+ <H3>Inline elements</H3>
194
+ <Table orientation="row" headerBg="#f1f5f9" borderColor="#e2e8f0" headerFontSize="8.5pt" cellFontSize="8.5pt">
195
+ <Entry content={["DotLine", "Repeating dot fill line. Props: num, width, inline, color, lineHeight."]} />
196
+ <Entry content={["CodeBlock", "Syntax-highlighted code (highlight.js). Props: language, code."]} />
197
+ <Entry content={["Equation", "LaTeX via KaTeX. Props: tex, displayMode, aligned, chemical."]} />
198
+ </Table>
199
+ </Page>
200
+
13
201
  </body>
14
202
  </html>
15
203
  );