Skip to content
Merged
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
61 changes: 61 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
lint:
name: Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run lint

build:
name: Build
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: npm run build
- name: Verify dist output
run: |
test -f dist/index.js
test -f dist/index.cjs
test -f dist/index.d.ts
test -f dist/react.js
test -f dist/react.cjs
test -f dist/react.d.ts

test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: npm test
31 changes: 31 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Release

on:
push:
tags:
- 'v*'

permissions:
contents: read

jobs:
publish:
name: Publish to npm
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
registry-url: https://registry.npmjs.org
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
179 changes: 155 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,187 @@
# @readmigo/reader-engine

A CSS column-based pagination engine for rendering book chapter HTML in web environments.
[![CI](https://github.com/readmigo/reader-engine/actions/workflows/ci.yml/badge.svg)](https://github.com/readmigo/reader-engine/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue.svg)](https://www.typescriptlang.org/)
[![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green.svg)](https://nodejs.org/)

A CSS column-based pagination engine for rendering book chapter HTML in web environments. Built with TypeScript, ships as ESM and CJS with full type declarations.

---

## Features

- **HTML Pagination** - CSS column layout engine that splits chapter HTML into discrete pages
- **Scroll Mode** - Alternative continuous scroll reading mode with progress tracking
- **Typography Settings** - Configurable font size, family, line height, letter spacing, word spacing, paragraph spacing, text alignment, and hyphenation
- **Theme System** - Four built-in themes: Light, Sepia, Dark, and Ultra Dark
- **Chapter Navigation** - Chapter manager with ordered traversal, jump-to-chapter, and boundary detection
- **Reading Progress** - Combined chapter + page progress calculation (0 to 1)
- **Content Security** - DOMPurify-based HTML sanitization before rendering
- **React Wrapper** - Provider, View component, and hooks for React integration
- **Dual Format** - Ships as ESM and CJS with full TypeScript declarations
| Feature | Description |
|---------|-------------|
| 📖 **HTML Pagination** | CSS column layout engine that splits chapter HTML into discrete pages |
| 📜 **Scroll Mode** | Alternative continuous scroll reading mode with progress tracking |
| 🔤 **Typography Settings** | Configurable font size, family, line height, letter/word spacing, paragraph spacing, text alignment, and hyphenation |
| 🎨 **Theme System** | Four built-in themes — Light, Sepia, Dark, and Ultra Dark |
| 🧭 **Chapter Navigation** | Chapter manager with ordered traversal, jump-to-chapter, and boundary detection |
| 📊 **Reading Progress** | Combined chapter + page progress calculation (0 to 1) |
| 🔒 **Content Security** | DOMPurify-based HTML sanitization before rendering |
| ⚛️ **React Wrapper** | Provider, View component, and hooks for React integration |
| 📦 **Dual Format** | Ships as ESM and CJS with full TypeScript declarations |

## Installation

```
```bash
npm install @readmigo/reader-engine
```

## Architecture
For React integration:

```bash
npm install @readmigo/reader-engine react react-dom
```

## Quick Start

See [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) for module diagrams and data flow.
### Vanilla TypeScript

## Design Document
```typescript
import { ReaderEngine } from '@readmigo/reader-engine';

See [docs/DESIGN.md](./docs/DESIGN.md) for detailed design documentation covering architecture decisions, core mechanisms, data flow, security, and extensibility.
const engine = new ReaderEngine({
apiBaseUrl: 'https://api.readmigo.com',
settings: { theme: 'sepia', fontSize: 20 },
});

## API Reference
// Mount to a DOM container
engine.mount(document.getElementById('reader')!);

See [docs/API.md](./docs/API.md) for complete type and method documentation.
// Load a book and its first chapter
const book = await engine.loadBook('book-123');
await engine.loadChapter(0);

## Getting Started
// Navigate pages
engine.nextPage();
engine.prevPage();

See [docs/GETTING-STARTED.md](./docs/GETTING-STARTED.md) for setup and integration guides.
// Listen for state changes
engine.callbacks.onStateChange = (state) => {
console.log(`Page ${state.currentPage + 1}/${state.totalPages}`);
};
```

### React

```tsx
import React, { useEffect } from 'react';
import { ReaderProvider, ReaderView, useReader } from '@readmigo/reader-engine/react';

function App() {
return (
<ReaderProvider apiBaseUrl="https://api.readmigo.com">
<ReaderPage bookId="book-123" />
</ReaderProvider>
);
}

function ReaderPage({ bookId }: { bookId: string }) {
const { state, loadBook, loadChapter, nextPage, prevPage } = useReader();

useEffect(() => {
loadBook(bookId).then(() => loadChapter(0));
}, [bookId, loadBook, loadChapter]);

return (
<div>
<ReaderView style={{ height: '80vh' }} />
<p>Progress: {(state.overallProgress * 100).toFixed(1)}%</p>
</div>
);
}
```

## Architecture

```
@readmigo/reader-engine
├── types/ # Data models, settings, themes
├── api/ # HTTP client + content loader
├── renderer/ # CSS generation + DOMPurify HTML rendering
├── core/ # Paginator (CSS columns) + scroll mode
├── navigation/ # Chapter traversal + progress calculation
├── engine.ts # ReaderEngine facade
└── react/ # Provider, View component, hooks
```

## Usage Examples
The engine uses CSS multi-column layout to split content into pages, then translates the content horizontally to display one page at a time. See [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) for detailed module diagrams and data flow.

- `examples/basic-usage.ts` - Vanilla TypeScript usage
- `examples/react-usage.tsx` - React component usage
### Theme Color Palette

| Theme | Background | Text | Best For |
|-------|-----------|------|----------|
| Light | `#FFFFFF` | `#1A1A1A` | Daytime reading |
| Sepia | `#F4ECD8` | `#5B4636` | Reduced eye strain |
| Dark | `#1C1C1E` | `#E5E5E7` | Low-light environments |
| Ultra Dark | `#000000` | `#E5E5E7` | OLED screens / night |

## Documentation

| Document | Description |
|----------|-------------|
| [Architecture](./docs/ARCHITECTURE.md) | Module diagrams, data flow, CSS column pagination |
| [Design](./docs/DESIGN.md) | Architecture decisions, core mechanisms, data flow, security, and extensibility |
| [API Reference](./docs/API.md) | Complete type and method documentation |
| [Getting Started](./docs/GETTING-STARTED.md) | Setup, integration guides, and customization |

## Examples

| Example | Description |
|---------|-------------|
| [`examples/basic-usage.ts`](./examples/basic-usage.ts) | Vanilla TypeScript — engine lifecycle, navigation, settings |
| [`examples/react-usage.tsx`](./examples/react-usage.tsx) | React — provider, view, hooks, theme switcher |

## Development

### Prerequisites

- Node.js ≥ 18
- npm ≥ 9

### Commands

| Command | Description |
|---------|-------------|
| `npm install` | Install dependencies |
| `npm run build` | Build with tsup (ESM + CJS + DTS) |
| `npm run dev` | Watch mode build |
| `npm test` | Run tests with Vitest |
| `npm run test:watch` | Watch mode tests |
| `npm run lint` | Type check with tsc |
| `npm run lint` | Type check with `tsc --noEmit` |

### Project Structure

```
reader-engine/
├── src/
│ ├── types/ # Book, Chapter, Settings, Theme types
│ ├── api/ # ApiClient, ContentLoader
│ ├── renderer/ # ChapterRenderer, generateReaderCSS
│ ├── core/ # Paginator, ScrollMode
│ ├── navigation/ # ChapterManager, calculateOverallProgress
│ ├── react/ # ReaderProvider, ReaderView, hooks
│ ├── engine.ts # ReaderEngine facade
│ └── index.ts # Public exports
├── docs/ # Architecture, API, Getting Started
├── examples/ # Usage examples
├── tsconfig.json # TypeScript config
├── tsup.config.ts # Build config (ESM + CJS + DTS)
└── vitest.config.ts # Test config (happy-dom)
```

## Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/my-feature`)
3. Make your changes and add tests
4. Ensure all checks pass: `npm run lint && npm run build && npm test`
5. Commit your changes (`git commit -m 'feat: add my feature'`)
6. Push to the branch (`git push origin feature/my-feature`)
7. Open a Pull Request

## License

MIT
[MIT](./LICENSE)
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
"require": "./dist/index.cjs"
},
"./react": {
"types": "./dist/react.d.ts",
"import": "./dist/react.js",
"require": "./dist/react.cjs",
"types": "./dist/react.d.ts"
"require": "./dist/react.cjs"
}
},
"files": [
Expand Down
Loading