simple-magazine-flip-book 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Davis Media
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,231 @@
1
+ # SimpleMagazineFlipBook
2
+
3
+ npm package: [`simple-magazine-flip-book`](https://www.npmjs.com/package/simple-magazine-flip-book)
4
+
5
+ Magazine-style flip book viewer for publication archives. Converts a PDF URL to JPEG pages in the browser, opens as soon as the initial spread is ready, and renders (or loads from cache) the rest in the background.
6
+
7
+ ## Features
8
+
9
+ - Themed header, body, and footer (background + text colors)
10
+ - Header logo, optional Media Kit link, share current URL
11
+ - PDF URL as the primary prop (always a string)
12
+ - Cover shown alone; inner pages as two-page spreads on desktop
13
+ - Single-page view on viewports ≤ 768px
14
+ - Thumbnail grid ("Pages" in the header)
15
+ - Deep linking via `?page=N` (shareable URLs, browser back/forward)
16
+ - Invisible click hotspots for links detected in PDF annotations, text URLs, and QR codes
17
+ - **IndexedDB page cache** — after the first visit, repeat loads reuse rendered JPEGs (no full re-processing on refresh)
18
+ - Works in Next.js App Router and Pages Router (client-only)
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ npm install simple-magazine-flip-book pdfjs-dist
24
+ ```
25
+
26
+ `pdfjs-dist` is a direct dependency of this package but must be resolvable in your app (hoisted). With **pnpm**, add to `.npmrc`:
27
+
28
+ ```
29
+ public-hoist-pattern[]=pdfjs-dist
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ### App Router (Next.js 13+)
35
+
36
+ ```tsx
37
+ // app/magazine/page.tsx
38
+ import { FlipBook } from "simple-magazine-flip-book";
39
+ import "simple-magazine-flip-book/styles.css";
40
+
41
+ export default function MagazinePage() {
42
+ return (
43
+ <FlipBook
44
+ pdfUrl="https://cdn.example.com/archive/spring-2024.pdf"
45
+ headerBackgroundColor="#1a1a2e"
46
+ bodyBackgroundColor="#eaeaea"
47
+ footerBackgroundColor="#1a1a2e"
48
+ headerTextColor="#ffffff"
49
+ footerTextColor="#cccccc"
50
+ headerLogo={<img src="/logo.svg" alt="Publication" />}
51
+ footerCopyrightText="© 2024 Davis Media. All rights reserved."
52
+ mediaKitUrl="https://example.com/media-kit"
53
+ />
54
+ );
55
+ }
56
+ ```
57
+
58
+ `FlipBook` is a Client Component (`"use client"`). Import it from a Server Component page as above, or from your own client wrapper.
59
+
60
+ ### Pages Router
61
+
62
+ Disable SSR so PDF.js only runs in the browser:
63
+
64
+ ```tsx
65
+ // pages/magazine/[slug].tsx
66
+ import dynamic from "next/dynamic";
67
+ import "simple-magazine-flip-book/styles.css";
68
+
69
+ const FlipBook = dynamic(
70
+ () => import("simple-magazine-flip-book").then((m) => m.FlipBook),
71
+ { ssr: false }
72
+ );
73
+
74
+ export default function MagazinePage() {
75
+ return (
76
+ <FlipBook
77
+ pdfUrl="/editions/spring-2024.pdf"
78
+ headerBackgroundColor="#1a1a2e"
79
+ bodyBackgroundColor="#eaeaea"
80
+ footerBackgroundColor="#1a1a2e"
81
+ headerTextColor="#ffffff"
82
+ footerTextColor="#cccccc"
83
+ headerLogo={<img src="/logo.svg" alt="" />}
84
+ footerCopyrightText="© 2024 Davis Media"
85
+ />
86
+ );
87
+ }
88
+ ```
89
+
90
+ ### PDF.js worker (recommended for production)
91
+
92
+ By default the legacy worker loads from unpkg. For CSP or offline builds, copy the worker to `public/` and pass `pdfWorkerSrc`:
93
+
94
+ ```bash
95
+ cp node_modules/pdfjs-dist/legacy/build/pdf.worker.min.mjs public/pdf.worker.min.mjs
96
+ ```
97
+
98
+ ```tsx
99
+ <FlipBook
100
+ pdfWorkerSrc="/pdf.worker.min.mjs"
101
+ pdfUrl="..."
102
+ {/* ...other props */}
103
+ />
104
+ ```
105
+
106
+ ### `next.config` (optional)
107
+
108
+ If you see build errors related to canvas:
109
+
110
+ ```js
111
+ /** @type {import('next').NextConfig} */
112
+ const nextConfig = {
113
+ webpack: (config) => {
114
+ config.resolve.alias.canvas = false;
115
+ return config;
116
+ },
117
+ };
118
+ module.exports = nextConfig;
119
+ ```
120
+
121
+ ## Props
122
+
123
+ | Prop | Type | Required | Description |
124
+ |------|------|----------|-------------|
125
+ | `pdfUrl` | `string` | yes | URL to the magazine PDF |
126
+ | `headerBackgroundColor` | `string` | yes | Header bar background |
127
+ | `bodyBackgroundColor` | `string` | yes | Main reading area background |
128
+ | `footerBackgroundColor` | `string` | yes | Footer background |
129
+ | `headerTextColor` | `string` | yes | Header text and button borders |
130
+ | `footerTextColor` | `string` | yes | Footer text |
131
+ | `headerLogo` | `ReactNode` | yes | Logo or branding in the header |
132
+ | `footerCopyrightText` | `string` | yes | Copyright line in the footer |
133
+ | `mediaKitUrl` | `string` | no | Opens as "Media Kit" in the header |
134
+ | `pdfWorkerSrc` | `string` | no | Custom PDF.js worker URL |
135
+ | `pageQuality` | `number` | no | JPEG quality 0–1 (default `0.92`) |
136
+ | `initialView` | `"reader" \| "thumbnails"` | no | Starting view (default `"reader"`) |
137
+ | `enableDeepLinking` | `boolean` | no | Sync page to URL query (default `true`) |
138
+ | `deepLinkParam` | `string` | no | Query param name (default `"page"`) |
139
+ | `enablePageCache` | `boolean` | no | Store rendered pages in IndexedDB (default `true`) |
140
+ | `className` | `string` | no | Root wrapper class |
141
+
142
+ ## Deep linking
143
+
144
+ The current page is synced to the query string (default `?page=3`). This works in both App Router and Pages Router without Next-specific APIs.
145
+
146
+ ```
147
+ https://yoursite.com/magazine/spring-2024?page=12
148
+ ```
149
+
150
+ - Opening a URL with `?page=N` jumps to that page after the PDF loads
151
+ - Prev/next navigation updates the URL (`history.replaceState`)
152
+ - **Share** copies/opens a URL that includes the current page
153
+ - Disable with `enableDeepLinking={false}` or customize with `deepLinkParam="p"`
154
+
155
+ ## Clickable links on pages
156
+
157
+ While each page is rendered to JPEG, the library also:
158
+
159
+ 1. **PDF link annotations** — native PDF hyperlinks
160
+ 2. **Text URLs** — `https://`, `www.`, and common domain patterns in text layers
161
+ 3. **QR codes** — decoded from the rendered page image
162
+
163
+ Matching regions get invisible `<a>` overlays (open in a new tab). Hotspots use normalized coordinates so they stay aligned when the page image scales.
164
+
165
+ ## Spread layout
166
+
167
+ | Step | Desktop view |
168
+ |------|----------------|
169
+ | 0 | Page 1 (cover), centered |
170
+ | 1 | Pages 2–3 |
171
+ | 2 | Pages 4–5 |
172
+ | … | Pairs until the last page; odd final page shows alone on the left |
173
+
174
+ Mobile always shows one PDF page per step.
175
+
176
+ ## Page cache
177
+
178
+ Rendered full pages and thumbnails are stored in **IndexedDB** (JPEG `Blob`s plus link metadata for full pages). On reload:
179
+
180
+ 1. Only the **initial spread** is loaded from cache first (near-instant when cached).
181
+ 2. The PDF is still opened once to confirm page count; remaining pages hydrate from cache or render in the background.
182
+
183
+ Cache entries are keyed by PDF URL, render settings, and a **HEAD-request fingerprint** (ETag / `Content-Length` / `Last-Modified` when CORS allows) so replacing the file at the same URL invalidates stale data.
184
+
185
+ Disable with `enablePageCache={false}`. Check support at runtime with `isPageCacheAvailable()` from the package.
186
+
187
+ ## Browser support
188
+
189
+ Tested targets: **Chrome**, **Firefox**, **Edge**, and **Safari** (macOS and iOS), current versions.
190
+
191
+ | Capability | Notes |
192
+ |------------|--------|
193
+ | PDF.js + Web Worker | Required; host `pdf.worker` for strict CSP |
194
+ | Canvas → JPEG (`toBlob` / `toDataURL`) | Safari supported; falls back to `data:` URLs if `toBlob` fails |
195
+ | `blob:` image URLs | Used for cached images (Safari 6+) |
196
+ | IndexedDB | Used for the page cache; unavailable in some private browsing modes → cache is skipped, viewer still works |
197
+ | `fetch` HEAD | Optional cache busting when the PDF CDN sends CORS headers for HEAD |
198
+ | `crypto.subtle` (SHA-256) | Used for cache keys when available; non-secure contexts use a fallback hash |
199
+ | Deep linking (`history.replaceState`) | Supported in all modern browsers |
200
+ | Fullscreen API | Used for the fullscreen toolbar button where available |
201
+
202
+ Safari-specific: keep the worker on the same origin as the app; very large editions may hit memory limits on older iOS devices (same as any canvas-heavy viewer).
203
+
204
+ ## CORS
205
+
206
+ The PDF URL must be reachable from the user's browser. Cross-origin PDFs need appropriate `Access-Control-Allow-Origin` headers (or serve the PDF from the same origin). For cache invalidation, HEAD responses should include `ETag` or `Last-Modified` when possible.
207
+
208
+ ## Demo (Next.js App Router)
209
+
210
+ ```bash
211
+ npm run build
212
+ cd demo
213
+ npm install
214
+ npm run setup # copies PDF from Downloads + logo + pdf.worker
215
+ npm run dev
216
+ ```
217
+
218
+ Open the URL shown in the terminal (default [http://localhost:3000](http://localhost:3000)). See `demo/README.md` for large-PDF notes.
219
+
220
+ From the repo root you can also run `npm run demo` after setup.
221
+
222
+ ## Development
223
+
224
+ ```bash
225
+ npm install
226
+ npm run build
227
+ ```
228
+
229
+ ## License
230
+
231
+ MIT