Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ coverage
.next/
out/
build
dist
# dist - Allow prebuilt packages for quick startup
packages/*/dist/
!packages/react/dist/
!packages/render/dist/
!packages/htmldocs/dist/

# Playwright
**/playwright-report
Expand Down
135 changes: 135 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ htmldocs is a local document editor and preview server to help you _create_ PDFs
- 🔗 Full TypeScript support for type safety
- ⚡ Dynamic data integration through props and APIs
- 📊 Real-time preview server with hot reloading
- 🚀 **Zero-build development** - modify templates and see changes instantly
- 🏗️ **Monorepo architecture** with pnpm workspaces and Turbo
- 🔄 **Workspace dependencies** - automatic linking between packages

## Example

Expand Down Expand Up @@ -60,6 +63,76 @@ npx htmldocs@latest init

For further instructions or to integrate htmldocs into your existing project, refer to the [Getting Started](https://docs.htmldocs.com/getting-started) guide.

## Development Workflow

htmldocs supports a **zero-build development experience** for rapid template iteration. You can modify template files and see changes instantly without any build step.

### One-Click Development

For the fastest setup, use our development script:

```bash
# Start zero-build development (from project root)
./dev.sh

# Or using npm/pnpm script
pnpm dev:zero-build
```

This script will:
- ✅ Install tsx if needed
- ✅ Build core dependencies (one-time)
- ✅ Start development server with hot reload
- ✅ Open examples at http://localhost:3000

### Manual Setup

```bash
# 1. Install dependencies
pnpm install

# 2. Build core dependencies (one-time only)
cd packages/react && pnpm build
cd ../render && pnpm build

# 3. Install TypeScript runner
npm install -g tsx

# 4. Start zero-build development
cd packages/htmldocs
tsx src/cli/index.ts dev --dir ../../apps/examples/documents
```

### What You Can Edit Without Building

- ✅ **Template files** (`*.tsx` documents) - hot reload enabled
- ✅ **Next.js app** (`packages/htmldocs/src/app/*`) - hot reload enabled
- ✅ **CLI logic** (`packages/htmldocs/src/cli/*`) - restart to see changes
- ✅ **Styles** (CSS, Tailwind) - hot reload enabled

### What Requires Building

- ⚠️ **React components** (`packages/react/`) - run `pnpm build` after changes
- ⚠️ **Render engine** (`packages/render/`) - run `pnpm build` after changes

### Development Commands

```bash
# Start development with hot reload
tsx src/cli/index.ts dev --dir ../../apps/examples/documents

# Build core packages when needed
pnpm build

# Run tests
pnpm test

# Format code
pnpm format
```

This workflow enables you to modify templates and see changes instantly in your browser, providing a smooth development experience similar to modern web frameworks.

## Components

htmldocs comes with a standard set of components to help you layout and style your documents.
Expand Down Expand Up @@ -99,6 +172,68 @@ htmldocs also uses the [Paged.js library](https://pagedjs.org/) under the hood.
|--------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
| Next.js | TypeScript | Turborepo | pnpm |

## Monorepo Architecture

This project uses a monorepo structure with pnpm workspaces and Turbo for efficient development:

```
├── packages/
│ ├── htmldocs/ # Main CLI and Next.js app
│ ├── react/ # React components (@htmldocs/react)
│ ├── render/ # PDF rendering engine (@htmldocs/render)
│ ├── eslint-config/ # Shared ESLint configuration
│ └── typescript-config/ # Shared TypeScript configuration
├── apps/
│ ├── examples/ # Example templates and documents
│ └── docs/ # Documentation site
```

### Package Dependencies

- `htmldocs` → depends on `@htmldocs/render`
- `examples` → depends on `htmldocs`, `@htmldocs/react`, `@htmldocs/render`
- All packages → share `@htmldocs/eslint-config` and `@htmldocs/typescript-config`

The monorepo uses `workspace:*` protocol for internal dependencies, enabling seamless development across packages with automatic linking.

## Contributing

We welcome contributions! Here's how to get started:

### Development Environment

1. **Clone and setup**:
```bash
git clone https://github.com/htmldocs-js/htmldocs.git
cd htmldocs
pnpm install
```

2. **Start development**:
```bash
./dev.sh
```

3. **Make changes** to templates in `apps/examples/documents/templates/`

4. **See changes instantly** in your browser with hot reload

### Common Tasks

- **Add new templates**: Create `.tsx` files in `apps/examples/documents/templates/`
- **Modify components**: Edit `packages/react/components/` (requires `pnpm build`)
- **Update CLI**: Edit `packages/htmldocs/src/cli/` (restart dev server)
- **Fix rendering**: Edit `packages/render/src/` (requires `pnpm build`)

### Testing

```bash
pnpm test # Run all tests
pnpm test:coverage # Run tests with coverage
pnpm lint # Check code style
pnpm format # Format code
```

## License

MIT License
10 changes: 10 additions & 0 deletions apps/examples/dist/Book/Book.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/ComponentProps",
"definitions": {
"ComponentProps": {
"type": "object",
"additionalProperties": false
}
}
}
201 changes: 201 additions & 0 deletions apps/examples/documents/templates/Index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// Import all available components from the htmldocs library
import { Document, Head, Page, Footer, MarginBox, Spacer } from '@htmldocs/react';
import * as React from 'react';
// Import CSS for Tailwind support
import "~/index.css";

// Main template component showcasing all htmldocs features
export default function Index() {

return (
<Document size="A4" orientation="portrait" margin="0.75in">
<Head>
<title>Document Template</title>
{/*
IMPORTANT FOR AI:
- Do NOT add Google Fonts links (may be blocked/slow loading)
- Do NOT add local font files that don't exist
- Use only system fonts and Tailwind defaults
- Keep Head section minimal for fast rendering
*/}
</Head>

{/* Page header in margin - shows on all pages */}
<MarginBox
position="top-right"
runningName="header-info"
className="text-xs text-gray-500"
>
Doc-001 | 2025
</MarginBox>

{/* Page footer with numbering */}
<Footer className="text-xs text-gray-500 text-center">
{({ currentPage, totalPages }) => (
<span>Page {currentPage} of {totalPages}</span>
)}
</Footer>

<Page className="text-gray-900">
{/* Clean document header */}
<div className="text-center mb-12">
<h1 className="text-4xl font-bold mb-2">Document Title</h1>
<p className="text-gray-600 text-lg">Professional Document Template</p>
<div className="w-24 h-1 bg-blue-500 mx-auto mt-4"></div>
</div>

{/* Essential info section */}
<div className="bg-gray-50 rounded-lg p-6 mb-8">
<div className="grid grid-cols-2 gap-8">
<div>
<h3 className="font-semibold text-gray-700 mb-3">Document Details</h3>
<div className="space-y-2 text-sm">
<div>Date: September 26, 2025</div>
<div>Reference: DOC-001</div>
<div>Status: Draft</div>
</div>
</div>
<div>
<h3 className="font-semibold text-gray-700 mb-3">Contact Information</h3>
<div className="space-y-2 text-sm">
<div>Company Name</div>
<div>contact@company.com</div>
<div>(555) 123-4567</div>
</div>
</div>
</div>
</div>

{/* Main content area */}
<div className="mb-8">
<h2 className="text-2xl font-semibold mb-4">Executive Summary</h2>
<p className="text-gray-700 leading-relaxed mb-6">
This document template demonstrates clean, professional formatting with essential
components. It includes headers, footers, spacing controls, and multi-page support
while maintaining fast loading times and visual clarity.
</p>

<h2 className="text-2xl font-semibold mb-4">Key Features</h2>

{/* Feature highlights in clean boxes */}
<div className="grid grid-cols-2 gap-4 mb-8">
<div className="border border-gray-200 rounded p-4">
<h4 className="font-semibold text-blue-600 mb-2">Layout Control</h4>
<ul className="text-sm text-gray-600 space-y-1">
<li>• A4 page sizing</li>
<li>• Automatic page breaks</li>
<li>• Margin management</li>
</ul>
</div>
<div className="border border-gray-200 rounded p-4">
<h4 className="font-semibold text-green-600 mb-2">Content Features</h4>
<ul className="text-sm text-gray-600 space-y-1">
<li>• Headers and footers</li>
<li>• Page numbering</li>
<li>• Spacing control</li>
</ul>
</div>
</div>

<Spacer height={24} />

{/* Data presentation example */}
<h2 className="text-2xl font-semibold mb-4">Sample Data Table</h2>
<div className="overflow-x-auto mb-8">
<table className="w-full border-collapse">
<thead>
<tr className="bg-gray-100">
<th className="border border-gray-300 px-4 py-2 text-left">Item</th>
<th className="border border-gray-300 px-4 py-2 text-left">Description</th>
<th className="border border-gray-300 px-4 py-2 text-right">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td className="border border-gray-300 px-4 py-2">Component A</td>
<td className="border border-gray-300 px-4 py-2">Essential feature</td>
<td className="border border-gray-300 px-4 py-2 text-right">100%</td>
</tr>
<tr className="bg-gray-50">
<td className="border border-gray-300 px-4 py-2">Component B</td>
<td className="border border-gray-300 px-4 py-2">Optional feature</td>
<td className="border border-gray-300 px-4 py-2 text-right">85%</td>
</tr>
</tbody>
</table>
</div>
</div>

{/* Clean conclusion */}
<div className="border-t border-gray-200 pt-6">
<h2 className="text-xl font-semibold mb-3">Summary</h2>
<p className="text-gray-700 text-sm leading-relaxed">
This template provides a solid foundation for professional documents with
clean formatting, essential features, and fast rendering. All components
use reliable system fonts and minimal external dependencies.
</p>
</div>
</Page>

{/* Second page example */}
<Page className="text-gray-900">
<div className="mb-8">
<h1 className="text-3xl font-bold mb-6">Additional Content</h1>

<div className="bg-blue-50 border-l-4 border-blue-400 p-4 mb-6">
<h3 className="font-semibold text-blue-800 mb-2">Multi-page Support</h3>
<p className="text-sm text-blue-700">
Content automatically flows to new pages. Headers and footers
appear consistently across all pages.
</p>
</div>

{/* Content sections */}
<div className="space-y-6">
<div>
<h3 className="text-xl font-semibold mb-3">Section One</h3>
<p className="text-gray-700 mb-4">
Content for the first major section goes here. This demonstrates
how text flows naturally within the document structure.
</p>
</div>

<div>
<h3 className="text-xl font-semibold mb-3">Section Two</h3>
<p className="text-gray-700 mb-4">
Additional content sections can be added as needed. The template
maintains consistent formatting throughout.
</p>
</div>

<Spacer height={32} />

<div>
<h3 className="text-xl font-semibold mb-3">Lists and Formatting</h3>
<div className="grid grid-cols-2 gap-6">
<div>
<h4 className="font-medium mb-2">Ordered List:</h4>
<ol className="list-decimal list-inside text-sm space-y-1">
<li>First item</li>
<li>Second item</li>
<li>Third item</li>
</ol>
</div>
<div>
<h4 className="font-medium mb-2">Bullet List:</h4>
<ul className="list-disc list-inside text-sm space-y-1">
<li>Key point one</li>
<li>Key point two</li>
<li>Key point three</li>
</ul>
</div>
</div>
</div>
</div>

<Spacer height={40} />
</div>
</Page>
</Document>
);
}
2 changes: 1 addition & 1 deletion apps/examples/documents/templates/Invoice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function Invoice({ billedTo, yourCompany, services }: InvoiceProps) {
className="flex flex-row items-center justify-between"
>
<div id="header_left" className="flex flex-col">
<div className="uppercase text-4xl font-medium mb-1">Invoice</div>
<div className="uppercase text-4xl font-medium mb-1 text-blue-600">🚀 开发中 Invoice</div>
<p className="text-gray-500">#AB2324-01</p>
</div>
<div id="header_right">
Expand Down
Loading