Compare commits
11 Commits
499db16fce
...
v0.4.4
| Author | SHA1 | Date | |
|---|---|---|---|
| a2b34572a9 | |||
| b76886e3ec | |||
| 92dd3bcab3 | |||
| f22714c37f | |||
| 5cfbd48282 | |||
| 8425d44658 | |||
| d40a288a4e | |||
| bff9e059d8 | |||
| 5f017d3b22 | |||
| 6386326473 | |||
| 54d4dc9545 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -141,4 +141,7 @@ vite.config.ts.timestamp-*
|
|||||||
.vite/
|
.vite/
|
||||||
|
|
||||||
todo.txt
|
todo.txt
|
||||||
chatgpt_continuation.md5
|
chatgpt_continuation.md5
|
||||||
|
|
||||||
|
# Generated release artifacts
|
||||||
|
release/
|
||||||
|
|||||||
1
.npmrc
Normal file
1
.npmrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@add-ideas:registry=https://git.add-ideas.de/api/packages/lotobo/npm/
|
||||||
61
CHANGELOG.md
61
CHANGELOG.md
@@ -4,6 +4,67 @@ All notable changes to `pdf-tools` are documented here.
|
|||||||
|
|
||||||
The project follows a pragmatic versioning scheme while the app is still below `1.0.0`: minor versions mark coherent user-facing milestones; patch versions mark fixes and small improvements.
|
The project follows a pragmatic versioning scheme while the app is still below `1.0.0`: minor versions mark coherent user-facing milestones; patch versions mark fixes and small improvements.
|
||||||
|
|
||||||
|
## 0.4.4 — LocalToolBox organization migration
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Moved canonical repository, Toolbox schema, corresponding-source, and package-registry URLs from the personal `zemion` namespace to the `lotobo` LocalToolBox organization.
|
||||||
|
- Upgraded the Toolbox contract, React shell, and validation testkit to `0.2.3` from the organization-owned registry.
|
||||||
|
- Bumped the app/package version to `0.4.4`.
|
||||||
|
|
||||||
|
## 0.4.3 — Aligned Toolbox content width
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Expanded the PDF workspace's maximum content width from `900px` to `90rem` so it aligns with the shared Toolbox shell bar and central catalogue.
|
||||||
|
- Bumped the app/package version to `0.4.3`.
|
||||||
|
|
||||||
|
## 0.4.2 — Corrected Toolbox header orientation
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgraded the Toolbox contract, React shell, and validation testkit to `0.2.2`.
|
||||||
|
- Moved the Toolbox icon and `add·ideas Toolbox` label to the fixed far-left block, kept the app title and one tagline centered, and moved the fixed control cluster to the far right in the reverse order: Help, the PDF-specific Gitea source link, Apps, and Personalize.
|
||||||
|
- Bumped the app/package version to `0.4.2`.
|
||||||
|
|
||||||
|
## 0.4.1 — Stable Toolbox header layout
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgraded the Toolbox contract, React shell, and validation testkit to `0.2.1`.
|
||||||
|
- Adopted the stable shared top bar: the fixed left cluster contains Personalize, Apps, the PDF-specific Gitea source link, and Help; the app title and one tagline remain centered; and the fixed far-right block contains the Toolbox icon and `add·ideas Toolbox` label.
|
||||||
|
|
||||||
|
## 0.4.0 — Shared Toolbox header and themes
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added the standard Toolbox header controls for in-app help, the app-specific Gitea source link, appearance personalization, and application switching.
|
||||||
|
- Added explicit light, dark, and system-following themes for the PDF workspace, saved-workspace list, merge queue, dialogs, status messages, and controls.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgraded the Toolbox contract, React shell, and validation testkit to `0.2.0`.
|
||||||
|
- The header now uses the manifest's repository metadata for the source link instead of carrying a release-specific source action.
|
||||||
|
- Replaced application color literals with semantic PDF workspace variables while intentionally keeping rendered PDF pages on a white paper surface.
|
||||||
|
- Scoped application button and card styles to the shell's main content so they cannot override shared header controls.
|
||||||
|
- Bumped the app/package version to `0.4.0`.
|
||||||
|
|
||||||
|
## 0.3.4 — PDF.js compatibility and Toolbox integration
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added a generated Toolbox App Contract manifest and shared Toolbox Shell integration with standalone fallback.
|
||||||
|
- Added deterministic, checksummed release ZIP packaging for artifact-based toolbox assembly.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Centralized PDF.js setup in a shared module so thumbnail rendering and page preview use the same legacy PDF.js build and worker configuration.
|
||||||
|
- Added a local PDF.js worker wrapper that installs a `Uint8Array.prototype.toHex` compatibility shim before PDF.js worker code runs.
|
||||||
|
- Added the same `toHex` compatibility shim in the main app bundle for browsers that do not provide it natively.
|
||||||
|
- Made Vite asset URLs relative so the app can be hosted at arbitrary nested paths.
|
||||||
|
- Corrected the documented licence identifier to `AGPL-3.0-only`.
|
||||||
|
- Bumped the app/package version to `0.3.4`.
|
||||||
|
|
||||||
## 0.3.2 — Multi-file merge queue release
|
## 0.3.2 — Multi-file merge queue release
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
106
README.md
106
README.md
@@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
Current hosted version: <https://pdftools.add-ideas.de>
|
Current hosted version: <https://pdftools.add-ideas.de>
|
||||||
|
|
||||||
Current release: **v0.3.1 — Split ZIP export release**. See [`CHANGELOG.md`](CHANGELOG.md) for release notes and milestone history.
|
Current development release: **v0.4.4 — LocalToolBox organization migration**. See [`CHANGELOG.md`](CHANGELOG.md) for milestone history.
|
||||||
|
|
||||||
|
Active work is tracked in Gitea issues. Durable project context is mirrored into the Gitea wiki from repository docs, including [`ROADMAP.md`](ROADMAP.md).
|
||||||
|
|
||||||
The app is a static React/Vite single-page application. There is no backend service, no server-side queue, and no server-side document storage. When hosted correctly, the server only delivers HTML, JavaScript, CSS, and static assets; PDF processing happens in the user's browser.
|
The app is a static React/Vite single-page application. There is no backend service, no server-side queue, and no server-side document storage. When hosted correctly, the server only delivers HTML, JavaScript, CSS, and static assets; PDF processing happens in the user's browser.
|
||||||
|
|
||||||
@@ -40,6 +42,8 @@ This makes the project especially useful for self-hosted environments, public-se
|
|||||||
- **Thumbnail cache by page and rotation**: Rotated thumbnails are cached and only changed thumbnails need to be regenerated.
|
- **Thumbnail cache by page and rotation**: Rotated thumbnails are cached and only changed thumbnails need to be regenerated.
|
||||||
- **Stable page references**: Duplicated pages and reordered pages are tracked as workspace page references rather than only by original page number.
|
- **Stable page references**: Duplicated pages and reordered pages are tracked as workspace page references rather than only by original page number.
|
||||||
- **Merge choices**: Loading another PDF can replace the current document, append pages, or insert pages at a chosen position.
|
- **Merge choices**: Loading another PDF can replace the current document, append pages, or insert pages at a chosen position.
|
||||||
|
- **PDF.js compatibility setup**: PDF.js is configured through one shared module and a local worker wrapper so the app can polyfill `Uint8Array.prototype.toHex` before PDF.js runs in older browsers.
|
||||||
|
- **Toolbox appearance controls**: The shared header provides light, dark, and system-following themes and keeps the app switcher, help, and source controls in the same place as the Toolbox portal.
|
||||||
- **In-app help**: The app includes a Help/Tutorial dialog with keyboard shortcuts and workflow explanations.
|
- **In-app help**: The app includes a Help/Tutorial dialog with keyboard shortcuts and workflow explanations.
|
||||||
|
|
||||||
## Current features
|
## Current features
|
||||||
@@ -93,7 +97,7 @@ Keyboard shortcuts are ignored while typing in form fields.
|
|||||||
|
|
||||||
## In-app documentation concept
|
## In-app documentation concept
|
||||||
|
|
||||||
The app includes a Help/Tutorial dialog reachable from the header via **Help ?**, `F1`, or `?`.
|
The app includes a Help/Tutorial dialog reachable from the header's **?** control, `F1`, or `?`.
|
||||||
|
|
||||||
Recommended structure for in-app documentation:
|
Recommended structure for in-app documentation:
|
||||||
|
|
||||||
@@ -117,6 +121,18 @@ browser <-- HTTPS --> static web server / reverse proxy --> built app assets
|
|||||||
|
|
||||||
There is no application server to operate. Administrators only need to host the built files from `dist/`.
|
There is no application server to operate. Administrators only need to host the built files from `dist/`.
|
||||||
|
|
||||||
|
The production build is relocatable and can also be assembled into an
|
||||||
|
[Add Ideas Toolbox](https://git.add-ideas.de/lotobo/toolbox-portal) deployment.
|
||||||
|
`toolbox-app.json` describes this app through the framework-independent
|
||||||
|
[Toolbox App Contract](https://git.add-ideas.de/lotobo/toolbox-sdk). The same
|
||||||
|
artifact remains fully usable on its own.
|
||||||
|
|
||||||
|
The shared first-party shell always provides help, source, and appearance
|
||||||
|
controls. When launched with a same-origin catalogue URL, for example
|
||||||
|
`?toolbox=/toolbox.catalog.json`, it also connects the application switcher to
|
||||||
|
the current Toolbox catalogue. Missing, invalid, and cross-origin catalogues
|
||||||
|
are ignored so the app falls back to standalone mode.
|
||||||
|
|
||||||
### Build and test from source
|
### Build and test from source
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -135,6 +151,19 @@ npm run build
|
|||||||
|
|
||||||
The production build is written to `dist/`.
|
The production build is written to `dist/`.
|
||||||
|
|
||||||
|
Create a versioned, checksummed release artifact with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run release:artifact
|
||||||
|
```
|
||||||
|
|
||||||
|
This writes `release/pdf-tools-<version>.zip` and its `.sha256` file. The ZIP
|
||||||
|
contains the static app, its toolbox manifest and changelog, plus the application
|
||||||
|
source-code location, license, and the full license/notice texts found for
|
||||||
|
bundled runtime dependencies under `LICENSES/`. Existing artifacts for the same
|
||||||
|
version are never replaced implicitly; after intentionally reviewing a rebuild, use
|
||||||
|
`npm run release:artifact -- --force`.
|
||||||
|
|
||||||
Useful individual development commands:
|
Useful individual development commands:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -219,7 +248,7 @@ The app expects modern browser APIs, including:
|
|||||||
- Canvas;
|
- Canvas;
|
||||||
- modern JavaScript modules.
|
- modern JavaScript modules.
|
||||||
|
|
||||||
Use current versions of Chromium, Firefox, Safari, or Edge.
|
The app includes a small `Uint8Array.prototype.toHex` compatibility shim for PDF.js fingerprint handling in browsers that do not provide that typed-array helper natively. Use current versions of Chromium, Firefox, Safari, or Edge where possible.
|
||||||
|
|
||||||
## Versioning and release baseline
|
## Versioning and release baseline
|
||||||
|
|
||||||
@@ -228,10 +257,10 @@ The application version shown in the header is defined in `src/version.ts`. The
|
|||||||
The current development baseline is:
|
The current development baseline is:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
v0.3.1 — Split ZIP export release
|
v0.4.4 — LocalToolBox organization migration
|
||||||
```
|
```
|
||||||
|
|
||||||
This release preserves the browser-only workspace baseline and adds split-result ZIP downloads on top of the selection-workspace feature. Workspace state, thumbnail handling, generated download URLs, page-grid components, tests, type-checking, linting, and formatting are separated enough to support additional feature work without turning `App.tsx` back into a monolith.
|
This branch preserves the browser-only workspace baseline and PDF.js compatibility setup while using Toolbox SDK `0.2.3` from the `lotobo` package registry. The displayed app/package version is `0.4.4`; canonical source, schema, and release links use the LocalToolBox organization. The shared header keeps the Toolbox icon and `add·ideas Toolbox` label in a fixed far-left block, the app title and one tagline centered, and Help, the PDF source link, Apps, and Personalize in a fixed far-right cluster. The PDF workspace shares the shell bar's `90rem` maximum width. Workspace state, thumbnail handling, generated download URLs, page-grid components, tests, type-checking, linting, and formatting remain separated enough to support additional feature work without turning `App.tsx` back into a monolith.
|
||||||
|
|
||||||
## Project structure
|
## Project structure
|
||||||
|
|
||||||
@@ -248,6 +277,9 @@ src/
|
|||||||
ReorderPanel.tsx Page grid, selection, drag/drop, copy/delete/rotate
|
ReorderPanel.tsx Page grid, selection, drag/drop, copy/delete/rotate
|
||||||
WorkspacePanel.tsx Workspace save/load/reset and undo/redo history
|
WorkspacePanel.tsx Workspace save/load/reset and undo/redo history
|
||||||
pdf/
|
pdf/
|
||||||
|
pdfJs.ts Shared pdf.js setup and worker configuration
|
||||||
|
pdfjsWorker.ts Local pdf.js worker wrapper with compatibility shim
|
||||||
|
uint8ArrayToHexPolyfill.ts Compatibility shim for PDF.js fingerprint handling
|
||||||
pdfService.ts pdf-lib operations: load, merge, split, export
|
pdfService.ts pdf-lib operations: load, merge, split, export
|
||||||
pdfThumbnailService.ts pdf.js thumbnail rendering
|
pdfThumbnailService.ts pdf.js thumbnail rendering
|
||||||
pdfZipService.ts Browser-side ZIP packaging for split results
|
pdfZipService.ts Browser-side ZIP packaging for split results
|
||||||
@@ -260,68 +292,10 @@ src/
|
|||||||
version.ts App version displayed in the header
|
version.ts App version displayed in the header
|
||||||
```
|
```
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap and backlog
|
||||||
|
|
||||||
### Milestone 1: Fast preview and thumbnails
|
The roadmap and non-goals now live in [`ROADMAP.md`](ROADMAP.md). Open roadmap items are imported into Gitea issues so priorities, status, and implementation notes stay out of the README.
|
||||||
|
|
||||||
- [x] Remove unused legacy page list view.
|
|
||||||
- [x] Bound thumbnail generation by width and height.
|
|
||||||
- [x] Display thumbnails progressively.
|
|
||||||
- [x] Add preview page flipping.
|
|
||||||
- [x] Attach preview controls to the modal container.
|
|
||||||
- [x] Add first keyboard shortcuts.
|
|
||||||
- [x] Cache thumbnails by page and rotation.
|
|
||||||
- [x] Regenerate only changed rotated thumbnails.
|
|
||||||
- [x] Show software version number.
|
|
||||||
|
|
||||||
### Milestone 2: Real page workspace
|
|
||||||
|
|
||||||
- [x] Introduce stable page references instead of only original page indices.
|
|
||||||
- [x] Support duplicate selected pages.
|
|
||||||
- [x] Save and reload the last state from browser storage.
|
|
||||||
- [x] Support named workspaces.
|
|
||||||
- [x] Store PDF binaries directly in IndexedDB.
|
|
||||||
- [x] Reset workspace.
|
|
||||||
- [x] Add command history as a foundation for undo/redo.
|
|
||||||
- [x] Add undo/redo.
|
|
||||||
- [x] Display undo/redo history with redo entries visually separated.
|
|
||||||
- [x] Extract selection as a new active workspace.
|
|
||||||
- [ ] Reduce undo/redo storage footprint if large documents make snapshots too heavy.
|
|
||||||
- [ ] Add grid/list view toggle.
|
|
||||||
|
|
||||||
### Milestone 3: Better merge and mobile handling
|
|
||||||
|
|
||||||
- [ ] Add a full multi-file merge queue.
|
|
||||||
- [ ] Support drag-and-drop of PDFs into the page grid at the hovered position.
|
|
||||||
- [ ] Add custom long-press drag on mobile.
|
|
||||||
- [ ] Consolidate frequently used actions into a toolbar.
|
|
||||||
|
|
||||||
### Milestone 4: Structural PDF editing
|
|
||||||
|
|
||||||
- [ ] Metadata editing.
|
|
||||||
- [ ] Crop pages.
|
|
||||||
- [ ] Add tools directly in the preview overlay.
|
|
||||||
- [ ] Read/fill/flatten forms.
|
|
||||||
- [ ] Read bookmarks, then evaluate bookmark editing.
|
|
||||||
- [ ] Read annotations, then evaluate annotation writing.
|
|
||||||
|
|
||||||
### Milestone 5: Export and power tools
|
|
||||||
|
|
||||||
- [ ] Basic text extraction.
|
|
||||||
- [x] ZIP export for split results.
|
|
||||||
- [ ] Optimize/compress MVP.
|
|
||||||
- [ ] Carefully scoped encrypted PDF handling.
|
|
||||||
|
|
||||||
## Non-goals for now
|
|
||||||
|
|
||||||
- Server-side PDF processing.
|
|
||||||
- Collaborative editing.
|
|
||||||
- User accounts.
|
|
||||||
- OCR.
|
|
||||||
- Full content-stream editing.
|
|
||||||
- Digital signature creation/validation workflows.
|
|
||||||
- DMS replacement functionality.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
GPL-3.0. See `LICENSE`.
|
AGPL-3.0-only. See `LICENSE`.
|
||||||
|
|||||||
63
ROADMAP.md
Normal file
63
ROADMAP.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# pdf-tools Roadmap
|
||||||
|
|
||||||
|
Active roadmap items are tracked as Gitea issues. This file is kept as the source for issue import and wiki sync; completed items remain here as release context.
|
||||||
|
|
||||||
|
## Milestone 1: Fast preview and thumbnails
|
||||||
|
|
||||||
|
- [x] Remove unused legacy page list view.
|
||||||
|
- [x] Bound thumbnail generation by width and height.
|
||||||
|
- [x] Display thumbnails progressively.
|
||||||
|
- [x] Add preview page flipping.
|
||||||
|
- [x] Attach preview controls to the modal container.
|
||||||
|
- [x] Add first keyboard shortcuts.
|
||||||
|
- [x] Cache thumbnails by page and rotation.
|
||||||
|
- [x] Regenerate only changed rotated thumbnails.
|
||||||
|
- [x] Show software version number.
|
||||||
|
|
||||||
|
## Milestone 2: Real page workspace
|
||||||
|
|
||||||
|
- [x] Introduce stable page references instead of only original page indices.
|
||||||
|
- [x] Support duplicate selected pages.
|
||||||
|
- [x] Save and reload the last state from browser storage.
|
||||||
|
- [x] Support named workspaces.
|
||||||
|
- [x] Store PDF binaries directly in IndexedDB.
|
||||||
|
- [x] Reset workspace.
|
||||||
|
- [x] Add command history as a foundation for undo/redo.
|
||||||
|
- [x] Add undo/redo.
|
||||||
|
- [x] Display undo/redo history with redo entries visually separated.
|
||||||
|
- [x] Extract selection as a new active workspace.
|
||||||
|
- [ ] Reduce undo/redo storage footprint if large documents make snapshots too heavy.
|
||||||
|
- [ ] Add grid/list view toggle.
|
||||||
|
|
||||||
|
## Milestone 3: Better merge and mobile handling
|
||||||
|
|
||||||
|
- [x] Add a full multi-file merge queue.
|
||||||
|
- [ ] Support drag-and-drop of PDFs into the page grid at the hovered position.
|
||||||
|
- [ ] Add custom long-press drag on mobile.
|
||||||
|
- [ ] Consolidate frequently used actions into a toolbar.
|
||||||
|
|
||||||
|
## Milestone 4: Structural PDF editing
|
||||||
|
|
||||||
|
- [ ] Metadata editing.
|
||||||
|
- [ ] Crop pages.
|
||||||
|
- [ ] Add tools directly in the preview overlay.
|
||||||
|
- [ ] Read/fill/flatten forms.
|
||||||
|
- [ ] Read bookmarks, then evaluate bookmark editing.
|
||||||
|
- [ ] Read annotations, then evaluate annotation writing.
|
||||||
|
|
||||||
|
## Milestone 5: Export and power tools
|
||||||
|
|
||||||
|
- [ ] Basic text extraction.
|
||||||
|
- [x] ZIP export for split results.
|
||||||
|
- [ ] Optimize/compress MVP.
|
||||||
|
- [ ] Carefully scoped encrypted PDF handling.
|
||||||
|
|
||||||
|
## Non-goals for now
|
||||||
|
|
||||||
|
- Server-side PDF processing.
|
||||||
|
- Collaborative editing.
|
||||||
|
- User accounts.
|
||||||
|
- OCR.
|
||||||
|
- Full content-stream editing.
|
||||||
|
- Digital signature creation/validation workflows.
|
||||||
|
- DMS replacement functionality.
|
||||||
@@ -43,7 +43,7 @@ export default tseslint.config(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ['*.config.{js,ts}', 'eslint.config.js'],
|
files: ['*.config.{js,ts}', 'eslint.config.js', 'scripts/**/*.mjs'],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
globals: {
|
globals: {
|
||||||
...globals.node,
|
...globals.node,
|
||||||
|
|||||||
24
licenses/core-js-3.49.0-LICENSE.txt
Normal file
24
licenses/core-js-3.49.0-LICENSE.txt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
core-js 3.49.0 — MIT License
|
||||||
|
Source: https://github.com/zloirock/core-js/tree/v3.49.0
|
||||||
|
|
||||||
|
Copyright (c) 2013–2025 Denis Pushkarev (zloirock.ru)
|
||||||
|
|
||||||
|
Copyright (c) 2025–2026 CoreJS Company (core-js.io)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
508
package-lock.json
generated
508
package-lock.json
generated
@@ -1,13 +1,16 @@
|
|||||||
{
|
{
|
||||||
"name": "pdf-tools",
|
"name": "pdf-tools",
|
||||||
"version": "0.3.2",
|
"version": "0.4.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "pdf-tools",
|
"name": "pdf-tools",
|
||||||
"version": "0.3.2",
|
"version": "0.4.4",
|
||||||
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@add-ideas/toolbox-contract": "^0.2.3",
|
||||||
|
"@add-ideas/toolbox-shell-react": "^0.2.3",
|
||||||
"fflate": "^0.8.3",
|
"fflate": "^0.8.3",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"pdfjs-dist": "^5.7.284",
|
"pdfjs-dist": "^5.7.284",
|
||||||
@@ -15,6 +18,7 @@
|
|||||||
"react-dom": "^19.2.6"
|
"react-dom": "^19.2.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@add-ideas/toolbox-testkit": "^0.2.3",
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@testing-library/react": "^16.3.2",
|
"@testing-library/react": "^16.3.2",
|
||||||
"@testing-library/user-event": "^14.6.1",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
@@ -35,6 +39,38 @@
|
|||||||
"vitest": "^4.1.6"
|
"vitest": "^4.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@add-ideas/toolbox-contract": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-contract/-/0.2.3/toolbox-contract-0.2.3.tgz",
|
||||||
|
"integrity": "sha512-T0PVSuMT40GjTDfQJhEEY3ZawQq8zz1/ry95JdKI6W39CdLacaRXdGnEpDCMHt+jUbf1Jz7Nat/M5dFCgKVM9A==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/@add-ideas/toolbox-shell-react": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-shell-react/-/0.2.3/toolbox-shell-react-0.2.3.tgz",
|
||||||
|
"integrity": "sha512-DT5lQDH48BFkFcmFLZnQh7+Cm73JzBPcmp5WzUXypfkUXpEyDYHzaXgmW4kZ0edSwh4RK4sPmx+JPtK0X4aKCQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@add-ideas/toolbox-contract": "0.2.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18 <20",
|
||||||
|
"react-dom": ">=18 <20"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@add-ideas/toolbox-testkit": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-testkit/-/0.2.3/toolbox-testkit-0.2.3.tgz",
|
||||||
|
"integrity": "sha512-sq1MwhKWfFKen+N+124hl74qQimRSvmQ9sOU7jdcI+2qCKZ67+2B8rWyezeV80uTFu4Jv6deHksfYQ/tKNV6XQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@add-ideas/toolbox-contract": "0.2.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"toolbox-check": "dist/cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@asamuzakjp/css-color": {
|
"node_modules/@asamuzakjp/css-color": {
|
||||||
"version": "5.1.11",
|
"version": "5.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz",
|
||||||
@@ -87,13 +123,13 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
|
||||||
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
|
"integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.28.5",
|
"@babel/helper-validator-identifier": "^7.29.7",
|
||||||
"js-tokens": "^4.0.0",
|
"js-tokens": "^4.0.0",
|
||||||
"picocolors": "^1.1.1"
|
"picocolors": "^1.1.1"
|
||||||
},
|
},
|
||||||
@@ -102,9 +138,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/compat-data": {
|
"node_modules/@babel/compat-data": {
|
||||||
"version": "7.29.3",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.3.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
|
||||||
"integrity": "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==",
|
"integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -112,21 +148,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/core": {
|
"node_modules/@babel/core": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
|
||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.7",
|
||||||
"@babel/helper-compilation-targets": "^7.28.6",
|
"@babel/helper-compilation-targets": "^7.29.7",
|
||||||
"@babel/helper-module-transforms": "^7.28.6",
|
"@babel/helper-module-transforms": "^7.29.7",
|
||||||
"@babel/helpers": "^7.28.6",
|
"@babel/helpers": "^7.29.7",
|
||||||
"@babel/parser": "^7.29.0",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/template": "^7.28.6",
|
"@babel/template": "^7.29.7",
|
||||||
"@babel/traverse": "^7.29.0",
|
"@babel/traverse": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0",
|
"@babel/types": "^7.29.7",
|
||||||
"@jridgewell/remapping": "^2.3.5",
|
"@jridgewell/remapping": "^2.3.5",
|
||||||
"convert-source-map": "^2.0.0",
|
"convert-source-map": "^2.0.0",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
@@ -143,14 +179,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/generator": {
|
"node_modules/@babel/generator": {
|
||||||
"version": "7.29.1",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
|
||||||
"integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
|
"integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.29.0",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0",
|
"@babel/types": "^7.29.7",
|
||||||
"@jridgewell/gen-mapping": "^0.3.12",
|
"@jridgewell/gen-mapping": "^0.3.12",
|
||||||
"@jridgewell/trace-mapping": "^0.3.28",
|
"@jridgewell/trace-mapping": "^0.3.28",
|
||||||
"jsesc": "^3.0.2"
|
"jsesc": "^3.0.2"
|
||||||
@@ -160,14 +196,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-compilation-targets": {
|
"node_modules/@babel/helper-compilation-targets": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
|
||||||
"integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
|
"integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/compat-data": "^7.28.6",
|
"@babel/compat-data": "^7.29.7",
|
||||||
"@babel/helper-validator-option": "^7.27.1",
|
"@babel/helper-validator-option": "^7.29.7",
|
||||||
"browserslist": "^4.24.0",
|
"browserslist": "^4.24.0",
|
||||||
"lru-cache": "^5.1.1",
|
"lru-cache": "^5.1.1",
|
||||||
"semver": "^6.3.1"
|
"semver": "^6.3.1"
|
||||||
@@ -187,9 +223,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-globals": {
|
"node_modules/@babel/helper-globals": {
|
||||||
"version": "7.28.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
|
||||||
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
|
"integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -197,29 +233,29 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-imports": {
|
"node_modules/@babel/helper-module-imports": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
|
||||||
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
|
"integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/traverse": "^7.28.6",
|
"@babel/traverse": "^7.29.7",
|
||||||
"@babel/types": "^7.28.6"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-transforms": {
|
"node_modules/@babel/helper-module-transforms": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
|
||||||
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
|
"integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-module-imports": "^7.28.6",
|
"@babel/helper-module-imports": "^7.29.7",
|
||||||
"@babel/helper-validator-identifier": "^7.28.5",
|
"@babel/helper-validator-identifier": "^7.29.7",
|
||||||
"@babel/traverse": "^7.28.6"
|
"@babel/traverse": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -229,9 +265,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.27.1",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
|
||||||
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -239,9 +275,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.28.5",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
|
||||||
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
|
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -249,9 +285,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-option": {
|
"node_modules/@babel/helper-validator-option": {
|
||||||
"version": "7.27.1",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
|
||||||
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
|
"integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -259,27 +295,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helpers": {
|
"node_modules/@babel/helpers": {
|
||||||
"version": "7.29.2",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
|
||||||
"integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
|
"integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.28.6",
|
"@babel/template": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.29.3",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
|
||||||
"integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==",
|
"integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.29.0"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
@@ -299,33 +335,33 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
|
||||||
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
|
"integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.28.6",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/parser": "^7.28.6",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/types": "^7.28.6"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/traverse": {
|
"node_modules/@babel/traverse": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
|
||||||
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
|
"integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.7",
|
||||||
"@babel/helper-globals": "^7.28.0",
|
"@babel/helper-globals": "^7.29.7",
|
||||||
"@babel/parser": "^7.29.0",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/template": "^7.28.6",
|
"@babel/template": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0",
|
"@babel/types": "^7.29.7",
|
||||||
"debug": "^4.3.1"
|
"debug": "^4.3.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -333,14 +369,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
|
||||||
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
|
"integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.27.1",
|
"@babel/helper-string-parser": "^7.29.7",
|
||||||
"@babel/helper-validator-identifier": "^7.28.5"
|
"@babel/helper-validator-identifier": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -500,14 +536,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/core": {
|
"node_modules/@emnapi/core": {
|
||||||
"version": "1.10.0",
|
"version": "1.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
|
||||||
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
"integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/wasi-threads": "1.2.1",
|
"@emnapi/wasi-threads": "1.2.2",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -520,9 +556,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/runtime": {
|
"node_modules/@emnapi/runtime": {
|
||||||
"version": "1.10.0",
|
"version": "1.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
|
||||||
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
"integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@@ -539,9 +575,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/wasi-threads": {
|
"node_modules/@emnapi/wasi-threads": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
|
||||||
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
|
"integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@@ -1070,14 +1106,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
|
||||||
"integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
|
"integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tybys/wasm-util": "^0.10.1"
|
"@tybys/wasm-util": "^0.10.3"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -1089,9 +1125,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@oxc-project/types": {
|
"node_modules/@oxc-project/types": {
|
||||||
"version": "0.130.0",
|
"version": "0.139.0",
|
||||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz",
|
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz",
|
||||||
"integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==",
|
"integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
@@ -1117,9 +1153,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-android-arm64": {
|
"node_modules/@rolldown/binding-android-arm64": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz",
|
||||||
"integrity": "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==",
|
"integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1134,9 +1170,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz",
|
||||||
"integrity": "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==",
|
"integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1151,9 +1187,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-x64": {
|
"node_modules/@rolldown/binding-darwin-x64": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz",
|
||||||
"integrity": "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==",
|
"integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1168,9 +1204,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz",
|
||||||
"integrity": "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==",
|
"integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1185,9 +1221,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz",
|
||||||
"integrity": "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==",
|
"integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -1202,13 +1238,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz",
|
||||||
"integrity": "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==",
|
"integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1219,13 +1258,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz",
|
||||||
"integrity": "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==",
|
"integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1236,13 +1278,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz",
|
||||||
"integrity": "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==",
|
"integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1253,13 +1298,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz",
|
||||||
"integrity": "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==",
|
"integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1270,13 +1318,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz",
|
||||||
"integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==",
|
"integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1287,13 +1338,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz",
|
||||||
"integrity": "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==",
|
"integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1304,9 +1358,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz",
|
||||||
"integrity": "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==",
|
"integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1321,9 +1375,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz",
|
||||||
"integrity": "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==",
|
"integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"wasm32"
|
"wasm32"
|
||||||
],
|
],
|
||||||
@@ -1331,18 +1385,18 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/core": "1.10.0",
|
"@emnapi/core": "1.11.1",
|
||||||
"@emnapi/runtime": "1.10.0",
|
"@emnapi/runtime": "1.11.1",
|
||||||
"@napi-rs/wasm-runtime": "^1.1.4"
|
"@napi-rs/wasm-runtime": "^1.1.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz",
|
||||||
"integrity": "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==",
|
"integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -1357,9 +1411,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz",
|
||||||
"integrity": "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==",
|
"integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1373,6 +1427,13 @@
|
|||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@rolldown/pluginutils": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@standard-schema/spec": {
|
"node_modules/@standard-schema/spec": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
||||||
@@ -1444,9 +1505,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tybys/wasm-util": {
|
"node_modules/@tybys/wasm-util": {
|
||||||
"version": "0.10.2",
|
"version": "0.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz",
|
||||||
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
"integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@@ -1808,13 +1869,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitejs/plugin-react/node_modules/@rolldown/pluginutils": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@vitest/expect": {
|
"node_modules/@vitest/expect": {
|
||||||
"version": "4.1.6",
|
"version": "4.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz",
|
||||||
@@ -1998,9 +2052,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/baseline-browser-mapping": {
|
"node_modules/baseline-browser-mapping": {
|
||||||
"version": "2.10.30",
|
"version": "2.10.43",
|
||||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.30.tgz",
|
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz",
|
||||||
"integrity": "sha512-xjOFN16Ha1+Rz4nFYKqHU/LSB+gx/Vi3yQLX7r7sAW+Wa+8hhF2h4pvqTrTMc8+WcDBEunnUurr46Jvv0jk3Vg==",
|
"integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -2034,9 +2088,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.28.2",
|
"version": "4.28.6",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.6.tgz",
|
||||||
"integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
|
"integrity": "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2054,10 +2108,10 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.10.12",
|
"baseline-browser-mapping": "^2.10.42",
|
||||||
"caniuse-lite": "^1.0.30001782",
|
"caniuse-lite": "^1.0.30001803",
|
||||||
"electron-to-chromium": "^1.5.328",
|
"electron-to-chromium": "^1.5.389",
|
||||||
"node-releases": "^2.0.36",
|
"node-releases": "^2.0.51",
|
||||||
"update-browserslist-db": "^1.2.3"
|
"update-browserslist-db": "^1.2.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -2068,9 +2122,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001792",
|
"version": "1.0.30001806",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz",
|
||||||
"integrity": "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==",
|
"integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2217,9 +2271,9 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.357",
|
"version": "1.5.393",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.357.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.393.tgz",
|
||||||
"integrity": "sha512-NHlTIQDK8fmVwHwuIzmXYEJ1Ewq3D9wDNc0cWXxDGysP6Pb21giwGNkxiTifyKy/4SoPuN5l6GLP1W9Sv7zB2g==",
|
"integrity": "sha512-kiDJdIUawuEIcp9XoICKp1iTYDEbgguIPq526N1Q7jIQDeQ3CqoMx71025PI/7E48Ddtw2HuWsVjY7afEgNxmg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
@@ -2525,7 +2579,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/fflate": {
|
"node_modules/fflate": {
|
||||||
"version": "0.8.3",
|
"version": "0.8.3",
|
||||||
"resolved": "https://packages.applied-caas-gateway1.internal.api.openai.org/artifactory/api/npm/npm-public/fflate/-/fflate-0.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz",
|
||||||
"integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==",
|
"integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@@ -3176,9 +3230,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.11",
|
"version": "3.3.16",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
|
||||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
"integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3202,11 +3256,14 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.44",
|
"version": "2.0.51",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz",
|
||||||
"integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==",
|
"integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/obug": {
|
"node_modules/obug": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
@@ -3347,9 +3404,9 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/picomatch": {
|
"node_modules/picomatch": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
|
||||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3360,9 +3417,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.14",
|
"version": "8.5.20",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.20.tgz",
|
||||||
"integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
|
"integrity": "sha512-lW616l85ucIQL+FocMmL7pQFPqBmwejrCMg+iPxyImlrANNJG9NHq/RkyCZopDhd8C3LA03PHRJDjkbGu8vvug==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3380,7 +3437,7 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.16",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"source-map-js": "^1.2.1"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
@@ -3480,13 +3537,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rolldown": {
|
"node_modules/rolldown": {
|
||||||
"version": "1.0.1",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz",
|
||||||
"integrity": "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==",
|
"integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oxc-project/types": "=0.130.0",
|
"@oxc-project/types": "=0.139.0",
|
||||||
"@rolldown/pluginutils": "^1.0.0"
|
"@rolldown/pluginutils": "^1.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -3496,30 +3553,23 @@
|
|||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rolldown/binding-android-arm64": "1.0.1",
|
"@rolldown/binding-android-arm64": "1.1.5",
|
||||||
"@rolldown/binding-darwin-arm64": "1.0.1",
|
"@rolldown/binding-darwin-arm64": "1.1.5",
|
||||||
"@rolldown/binding-darwin-x64": "1.0.1",
|
"@rolldown/binding-darwin-x64": "1.1.5",
|
||||||
"@rolldown/binding-freebsd-x64": "1.0.1",
|
"@rolldown/binding-freebsd-x64": "1.1.5",
|
||||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.1",
|
"@rolldown/binding-linux-arm-gnueabihf": "1.1.5",
|
||||||
"@rolldown/binding-linux-arm64-gnu": "1.0.1",
|
"@rolldown/binding-linux-arm64-gnu": "1.1.5",
|
||||||
"@rolldown/binding-linux-arm64-musl": "1.0.1",
|
"@rolldown/binding-linux-arm64-musl": "1.1.5",
|
||||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.1",
|
"@rolldown/binding-linux-ppc64-gnu": "1.1.5",
|
||||||
"@rolldown/binding-linux-s390x-gnu": "1.0.1",
|
"@rolldown/binding-linux-s390x-gnu": "1.1.5",
|
||||||
"@rolldown/binding-linux-x64-gnu": "1.0.1",
|
"@rolldown/binding-linux-x64-gnu": "1.1.5",
|
||||||
"@rolldown/binding-linux-x64-musl": "1.0.1",
|
"@rolldown/binding-linux-x64-musl": "1.1.5",
|
||||||
"@rolldown/binding-openharmony-arm64": "1.0.1",
|
"@rolldown/binding-openharmony-arm64": "1.1.5",
|
||||||
"@rolldown/binding-wasm32-wasi": "1.0.1",
|
"@rolldown/binding-wasm32-wasi": "1.1.5",
|
||||||
"@rolldown/binding-win32-arm64-msvc": "1.0.1",
|
"@rolldown/binding-win32-arm64-msvc": "1.1.5",
|
||||||
"@rolldown/binding-win32-x64-msvc": "1.0.1"
|
"@rolldown/binding-win32-x64-msvc": "1.1.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rolldown/node_modules/@rolldown/pluginutils": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/saxes": {
|
"node_modules/saxes": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
|
||||||
@@ -3628,9 +3678,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tinyglobby": {
|
"node_modules/tinyglobby": {
|
||||||
"version": "0.2.16",
|
"version": "0.2.17",
|
||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||||
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
|
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -3771,9 +3821,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/undici": {
|
"node_modules/undici": {
|
||||||
"version": "7.25.0",
|
"version": "7.28.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz",
|
||||||
"integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==",
|
"integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3829,17 +3879,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "8.0.13",
|
"version": "8.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz",
|
||||||
"integrity": "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==",
|
"integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lightningcss": "^1.32.0",
|
"lightningcss": "^1.32.0",
|
||||||
"picomatch": "^4.0.4",
|
"picomatch": "^4.0.5",
|
||||||
"postcss": "^8.5.14",
|
"postcss": "^8.5.17",
|
||||||
"rolldown": "1.0.1",
|
"rolldown": "~1.1.5",
|
||||||
"tinyglobby": "^0.2.16"
|
"tinyglobby": "^0.2.17"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
@@ -3855,7 +3905,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/node": "^20.19.0 || >=22.12.0",
|
"@types/node": "^20.19.0 || >=22.12.0",
|
||||||
"@vitejs/devtools": "^0.1.18",
|
"@vitejs/devtools": "^0.3.0",
|
||||||
"esbuild": "^0.27.0 || ^0.28.0",
|
"esbuild": "^0.27.0 || ^0.28.0",
|
||||||
"jiti": ">=1.21.0",
|
"jiti": ">=1.21.0",
|
||||||
"less": "^4.0.0",
|
"less": "^4.0.0",
|
||||||
|
|||||||
24
package.json
24
package.json
@@ -1,10 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "pdf-tools",
|
"name": "pdf-tools",
|
||||||
"version": "0.3.2",
|
"version": "0.4.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"license": "AGPL-3.0-only",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"predev": "npm run manifest:generate",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
"prebuild": "npm run manifest:generate",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
@@ -12,10 +15,16 @@
|
|||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"format:check": "prettier --check .",
|
"format:check": "prettier --check .",
|
||||||
"test": "vitest run --environment jsdom",
|
"test": "vitest run --environment jsdom",
|
||||||
|
"test:toolbox": "toolbox-check dist",
|
||||||
"test:watch": "vitest --environment jsdom",
|
"test:watch": "vitest --environment jsdom",
|
||||||
"check": "npm run typecheck && npm run lint && npm run test && npm run build"
|
"manifest:generate": "node scripts/generate-toolbox-manifest.mjs",
|
||||||
|
"manifest:check": "node scripts/generate-toolbox-manifest.mjs --check",
|
||||||
|
"release:artifact": "npm run check && node scripts/package-release.mjs",
|
||||||
|
"check": "npm run manifest:check && npm run typecheck && npm run lint && npm run test && npm run build && npm run test:toolbox"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@add-ideas/toolbox-contract": "^0.2.3",
|
||||||
|
"@add-ideas/toolbox-shell-react": "^0.2.3",
|
||||||
"fflate": "^0.8.3",
|
"fflate": "^0.8.3",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"pdfjs-dist": "^5.7.284",
|
"pdfjs-dist": "^5.7.284",
|
||||||
@@ -23,6 +32,7 @@
|
|||||||
"react-dom": "^19.2.6"
|
"react-dom": "^19.2.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@add-ideas/toolbox-testkit": "^0.2.3",
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@testing-library/react": "^16.3.2",
|
"@testing-library/react": "^16.3.2",
|
||||||
"@testing-library/user-event": "^14.6.1",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
@@ -42,5 +52,13 @@
|
|||||||
"vite": "^8.0.13",
|
"vite": "^8.0.13",
|
||||||
"vitest": "^4.1.6"
|
"vitest": "^4.1.6"
|
||||||
},
|
},
|
||||||
"description": "Browser-only, self-hostable PDF workbench for page-level PDF operations."
|
"description": "Browser-only, self-hostable PDF workbench for page-level PDF operations.",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://git.add-ideas.de/lotobo/pdf-tools.git"
|
||||||
|
},
|
||||||
|
"homepage": "https://git.add-ideas.de/lotobo/pdf-tools",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://git.add-ideas.de/lotobo/pdf-tools/issues"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
"short_name": "PDFTools",
|
"short_name": "PDFTools",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "/web-app-manifest-192x192.png",
|
"src": "./web-app-manifest-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "maskable"
|
"purpose": "maskable"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/web-app-manifest-512x512.png",
|
"src": "./web-app-manifest-512x512.png",
|
||||||
"sizes": "512x512",
|
"sizes": "512x512",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "maskable"
|
"purpose": "maskable"
|
||||||
@@ -18,4 +18,4 @@
|
|||||||
"theme_color": "#ffffff",
|
"theme_color": "#ffffff",
|
||||||
"background_color": "#ffffff",
|
"background_color": "#ffffff",
|
||||||
"display": "standalone"
|
"display": "standalone"
|
||||||
}
|
}
|
||||||
|
|||||||
32
public/toolbox-app.json
Normal file
32
public/toolbox-app.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://git.add-ideas.de/lotobo/toolbox-sdk/raw/branch/main/schemas/toolbox-app.v1.schema.json",
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "de.add-ideas.pdf-tools",
|
||||||
|
"name": "PDF Workbench",
|
||||||
|
"description": "Page-level PDF operations performed locally in the browser.",
|
||||||
|
"entry": "./",
|
||||||
|
"icon": "./favicon.svg",
|
||||||
|
"categories": ["documents", "pdf"],
|
||||||
|
"tags": ["merge", "split", "rotate", "reorder"],
|
||||||
|
"integration": {
|
||||||
|
"contextVersion": 1,
|
||||||
|
"launchModes": ["navigate", "new-tab"],
|
||||||
|
"embedding": "unsupported"
|
||||||
|
},
|
||||||
|
"requirements": {
|
||||||
|
"secureContext": true,
|
||||||
|
"workers": true,
|
||||||
|
"indexedDb": true,
|
||||||
|
"crossOriginIsolated": false
|
||||||
|
},
|
||||||
|
"privacy": {
|
||||||
|
"processing": "local",
|
||||||
|
"fileUploads": false,
|
||||||
|
"telemetry": false
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"repository": "https://git.add-ideas.de/lotobo/pdf-tools",
|
||||||
|
"license": "AGPL-3.0-only"
|
||||||
|
},
|
||||||
|
"version": "0.4.4"
|
||||||
|
}
|
||||||
64
scripts/generate-toolbox-manifest.mjs
Normal file
64
scripts/generate-toolbox-manifest.mjs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { readFile, writeFile } from 'node:fs/promises';
|
||||||
|
import path from 'node:path';
|
||||||
|
import process from 'node:process';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { parseToolboxApp } from '@add-ideas/toolbox-contract';
|
||||||
|
import { format } from 'prettier';
|
||||||
|
|
||||||
|
const projectRoot = path.resolve(
|
||||||
|
path.dirname(fileURLToPath(import.meta.url)),
|
||||||
|
'..'
|
||||||
|
);
|
||||||
|
const packageJsonPath = path.join(projectRoot, 'package.json');
|
||||||
|
const definitionPath = path.join(
|
||||||
|
projectRoot,
|
||||||
|
'src',
|
||||||
|
'toolboxApp.definition.json'
|
||||||
|
);
|
||||||
|
const versionSourcePath = path.join(projectRoot, 'src', 'version.ts');
|
||||||
|
const manifestPath = path.join(projectRoot, 'public', 'toolbox-app.json');
|
||||||
|
|
||||||
|
const [packageJson, definition, versionSource] = await Promise.all([
|
||||||
|
readJson(packageJsonPath),
|
||||||
|
readJson(definitionPath),
|
||||||
|
readFile(versionSourcePath, 'utf8'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const sourceVersion = versionSource.match(
|
||||||
|
/APP_VERSION\s*=\s*['"]([^'"]+)['"]/
|
||||||
|
)?.[1];
|
||||||
|
|
||||||
|
if (!sourceVersion) {
|
||||||
|
throw new Error('Could not read APP_VERSION from src/version.ts.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceVersion !== packageJson.version) {
|
||||||
|
throw new Error(
|
||||||
|
`Version mismatch: package.json is ${packageJson.version}, while src/version.ts is ${sourceVersion}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const manifest = {
|
||||||
|
$schema:
|
||||||
|
'https://git.add-ideas.de/lotobo/toolbox-sdk/raw/branch/main/schemas/toolbox-app.v1.schema.json',
|
||||||
|
schemaVersion: 1,
|
||||||
|
...definition,
|
||||||
|
version: packageJson.version,
|
||||||
|
};
|
||||||
|
parseToolboxApp(manifest);
|
||||||
|
const output = await format(JSON.stringify(manifest), { parser: 'json' });
|
||||||
|
|
||||||
|
if (process.argv.includes('--check')) {
|
||||||
|
const existing = await readFile(manifestPath, 'utf8').catch(() => '');
|
||||||
|
if (existing !== output) {
|
||||||
|
throw new Error(
|
||||||
|
'public/toolbox-app.json is out of date. Run npm run manifest:generate.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await writeFile(manifestPath, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readJson(filePath) {
|
||||||
|
return JSON.parse(await readFile(filePath, 'utf8'));
|
||||||
|
}
|
||||||
100
scripts/package-release.mjs
Normal file
100
scripts/package-release.mjs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import { createHash } from 'node:crypto';
|
||||||
|
import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import {
|
||||||
|
collectDirectoryFiles,
|
||||||
|
createDeterministicZip,
|
||||||
|
createThirdPartyLicenseBundle,
|
||||||
|
} from './release-archive.mjs';
|
||||||
|
|
||||||
|
const projectRoot = path.resolve(
|
||||||
|
path.dirname(fileURLToPath(import.meta.url)),
|
||||||
|
'..'
|
||||||
|
);
|
||||||
|
const packageJson = JSON.parse(
|
||||||
|
await readFile(path.join(projectRoot, 'package.json'), 'utf8')
|
||||||
|
);
|
||||||
|
const releaseDirectory = path.join(projectRoot, 'release');
|
||||||
|
const archiveName = `pdf-tools-${packageJson.version}.zip`;
|
||||||
|
const archivePath = path.join(releaseDirectory, archiveName);
|
||||||
|
const checksumPath = path.join(
|
||||||
|
releaseDirectory,
|
||||||
|
`pdf-tools-${packageJson.version}.sha256`
|
||||||
|
);
|
||||||
|
const force = process.argv.slice(2).includes('--force');
|
||||||
|
const unknownArguments = process.argv
|
||||||
|
.slice(2)
|
||||||
|
.filter((argument) => argument !== '--force');
|
||||||
|
if (unknownArguments.length > 0) {
|
||||||
|
throw new Error(`Unknown release argument: ${unknownArguments.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await mkdir(releaseDirectory, { recursive: true });
|
||||||
|
if (!force) {
|
||||||
|
await assertDoesNotExist(archivePath);
|
||||||
|
await assertDoesNotExist(checksumPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = await collectDirectoryFiles(path.join(projectRoot, 'dist'));
|
||||||
|
|
||||||
|
files['CHANGELOG.md'] = await readFile(path.join(projectRoot, 'CHANGELOG.md'));
|
||||||
|
files['SOURCE.md'] = Buffer.from(
|
||||||
|
[
|
||||||
|
'# Corresponding source',
|
||||||
|
'',
|
||||||
|
`The source code corresponding to PDF Tools ${packageJson.version} is available at:`,
|
||||||
|
'',
|
||||||
|
`https://git.add-ideas.de/lotobo/pdf-tools/src/tag/v${packageJson.version}`,
|
||||||
|
'',
|
||||||
|
'Third-party components remain available under the separate terms reproduced in LICENSES/.',
|
||||||
|
'',
|
||||||
|
].join('\n'),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
files['LICENSES/pdf-tools-LICENSE.txt'] = await readFile(
|
||||||
|
path.join(projectRoot, 'LICENSE')
|
||||||
|
);
|
||||||
|
files['LICENSES/core-js-3.49.0-LICENSE.txt'] = await readFile(
|
||||||
|
path.join(projectRoot, 'licenses', 'core-js-3.49.0-LICENSE.txt')
|
||||||
|
);
|
||||||
|
files['LICENSES/THIRD-PARTY-LICENSES.txt'] =
|
||||||
|
await createThirdPartyLicenseBundle(projectRoot, [
|
||||||
|
'@add-ideas/toolbox-contract',
|
||||||
|
'@add-ideas/toolbox-shell-react',
|
||||||
|
'@pdf-lib/standard-fonts',
|
||||||
|
'@pdf-lib/upng',
|
||||||
|
'fflate',
|
||||||
|
'pako',
|
||||||
|
'pdf-lib',
|
||||||
|
'pdfjs-dist',
|
||||||
|
'react',
|
||||||
|
'react-dom',
|
||||||
|
'scheduler',
|
||||||
|
'tslib',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const archive = createDeterministicZip(files);
|
||||||
|
const checksum = createHash('sha256').update(archive).digest('hex');
|
||||||
|
|
||||||
|
const writeFlag = force ? 'w' : 'wx';
|
||||||
|
await writeFile(archivePath, archive, { flag: writeFlag });
|
||||||
|
await writeFile(checksumPath, `${checksum} ${archiveName}\n`, {
|
||||||
|
encoding: 'utf8',
|
||||||
|
flag: writeFlag,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Created release/${archiveName}`);
|
||||||
|
console.log(`SHA-256 ${checksum}`);
|
||||||
|
|
||||||
|
async function assertDoesNotExist(outputPath) {
|
||||||
|
try {
|
||||||
|
await access(outputPath);
|
||||||
|
} catch (error) {
|
||||||
|
if (error && typeof error === 'object' && error.code === 'ENOENT') return;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
throw new Error(
|
||||||
|
`${path.relative(projectRoot, outputPath)} already exists; pass --force to replace this exact version.`
|
||||||
|
);
|
||||||
|
}
|
||||||
12
scripts/release-archive.d.ts
vendored
Normal file
12
scripts/release-archive.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export function compareCodePoints(left: string, right: string): number;
|
||||||
|
export function createDeterministicZip(
|
||||||
|
files: Record<string, Uint8Array>
|
||||||
|
): Uint8Array;
|
||||||
|
export function collectDirectoryFiles(
|
||||||
|
directory: string,
|
||||||
|
prefix?: string
|
||||||
|
): Promise<Record<string, Buffer>>;
|
||||||
|
export function createThirdPartyLicenseBundle(
|
||||||
|
projectRoot: string,
|
||||||
|
packageNames: string[]
|
||||||
|
): Promise<Buffer>;
|
||||||
123
scripts/release-archive.mjs
Normal file
123
scripts/release-archive.mjs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import { readFile, readdir } from 'node:fs/promises';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { zipSync } from 'fflate';
|
||||||
|
|
||||||
|
const LICENSE_FILE = /^(?:licen[cs]e|copying|notice)(?:[._-].*)?$/iu;
|
||||||
|
|
||||||
|
export function compareCodePoints(left, right) {
|
||||||
|
return left < right ? -1 : left > right ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createDeterministicZip(files) {
|
||||||
|
const orderedFiles = Object.fromEntries(
|
||||||
|
Object.entries(files).sort(([left], [right]) =>
|
||||||
|
compareCodePoints(left, right)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return zipSync(orderedFiles, {
|
||||||
|
level: 9,
|
||||||
|
// ZIP stores a wall-clock DOS timestamp. Constructing the epoch in local
|
||||||
|
// time keeps its encoded bytes stable in every process timezone.
|
||||||
|
mtime: new Date(1980, 0, 1, 0, 0, 0),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function collectDirectoryFiles(directory, prefix = '') {
|
||||||
|
const result = {};
|
||||||
|
const entries = await readdir(directory, { withFileTypes: true });
|
||||||
|
entries.sort((left, right) => compareCodePoints(left.name, right.name));
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const absolutePath = path.join(directory, entry.name);
|
||||||
|
const relativePath = path.posix.join(prefix, entry.name);
|
||||||
|
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
Object.assign(
|
||||||
|
result,
|
||||||
|
await collectDirectoryFiles(absolutePath, relativePath)
|
||||||
|
);
|
||||||
|
} else if (entry.isFile()) {
|
||||||
|
result[relativePath] = await readFile(absolutePath);
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Unsupported filesystem entry in release input: ${relativePath}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createThirdPartyLicenseBundle(projectRoot, packageNames) {
|
||||||
|
const sections = [];
|
||||||
|
|
||||||
|
for (const packageName of [...new Set(packageNames)].sort(
|
||||||
|
compareCodePoints
|
||||||
|
)) {
|
||||||
|
const packageDirectory = path.join(
|
||||||
|
projectRoot,
|
||||||
|
'node_modules',
|
||||||
|
...packageName.split('/')
|
||||||
|
);
|
||||||
|
const packageJson = JSON.parse(
|
||||||
|
await readFile(path.join(packageDirectory, 'package.json'), 'utf8')
|
||||||
|
);
|
||||||
|
const licenseFiles = await collectLicenseFiles(packageDirectory);
|
||||||
|
if (licenseFiles.length === 0) {
|
||||||
|
throw new Error(`No license text found for ${packageName}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const contents = [];
|
||||||
|
for (const licenseFile of licenseFiles) {
|
||||||
|
const text = await readFile(
|
||||||
|
path.join(packageDirectory, ...licenseFile.split('/')),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
contents.push(
|
||||||
|
`--- ${licenseFile} ---\n${text.replaceAll('\r\n', '\n').trim()}\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
sections.push(
|
||||||
|
[
|
||||||
|
`================================================================================`,
|
||||||
|
`${packageJson.name ?? packageName}@${packageJson.version ?? 'unknown'}`,
|
||||||
|
`Declared license: ${String(packageJson.license ?? 'unspecified')}`,
|
||||||
|
`================================================================================`,
|
||||||
|
...contents,
|
||||||
|
].join('\n')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Buffer.from(
|
||||||
|
[
|
||||||
|
'Third-party software license texts bundled with PDF Tools',
|
||||||
|
'Generated deterministically from the installed production packages.',
|
||||||
|
'',
|
||||||
|
...sections,
|
||||||
|
'',
|
||||||
|
].join('\n'),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function collectLicenseFiles(directory, prefix = '') {
|
||||||
|
const matches = [];
|
||||||
|
const entries = await readdir(directory, { withFileTypes: true });
|
||||||
|
entries.sort((left, right) => compareCodePoints(left.name, right.name));
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.name === 'node_modules') continue;
|
||||||
|
const relativePath = path.posix.join(prefix, entry.name);
|
||||||
|
const absolutePath = path.join(directory, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
matches.push(...(await collectLicenseFiles(absolutePath, relativePath)));
|
||||||
|
} else if (entry.isFile() && LICENSE_FILE.test(entry.name)) {
|
||||||
|
matches.push(relativePath);
|
||||||
|
} else if (!entry.isFile()) {
|
||||||
|
throw new Error(
|
||||||
|
`Unsupported filesystem entry in license input: ${relativePath}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
20
src/App.tsx
20
src/App.tsx
@@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import Layout from './components/Layout';
|
import { AppShell } from '@add-ideas/toolbox-shell-react';
|
||||||
import FileLoader from './components/FileLoader';
|
import FileLoader from './components/FileLoader';
|
||||||
import ReorderPanel from './components/ReorderPanel';
|
import ReorderPanel from './components/ReorderPanel';
|
||||||
import ActionsPanel from './components/ActionsPanel';
|
import ActionsPanel from './components/ActionsPanel';
|
||||||
@@ -43,6 +43,7 @@ import {
|
|||||||
createSplitResultsZip,
|
createSplitResultsZip,
|
||||||
createSplitZipFilename,
|
createSplitZipFilename,
|
||||||
} from './pdf/pdfZipService';
|
} from './pdf/pdfZipService';
|
||||||
|
import { toolboxApp } from './toolboxApp';
|
||||||
import {
|
import {
|
||||||
createSelectionPdfName,
|
createSelectionPdfName,
|
||||||
createSelectionWorkspaceName,
|
createSelectionWorkspaceName,
|
||||||
@@ -1139,7 +1140,14 @@ const App: React.FC = () => {
|
|||||||
previewVisualIndex >= 0 && previewVisualIndex < pages.length - 1;
|
previewVisualIndex >= 0 && previewVisualIndex < pages.length - 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout onOpenHelp={() => setHelpOpen(true)}>
|
<AppShell
|
||||||
|
app={toolboxApp}
|
||||||
|
className="pdf-toolbox-shell"
|
||||||
|
helpAction={{
|
||||||
|
onClick: () => setHelpOpen(true),
|
||||||
|
title: 'Open help and keyboard shortcuts (F1 or ?)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<FileLoader pdf={pdf} onFilesLoaded={handleFilesLoaded} />
|
<FileLoader pdf={pdf} onFilesLoaded={handleFilesLoaded} />
|
||||||
|
|
||||||
{mergeQueueOpen && mergeQueueItems.length > 0 && (
|
{mergeQueueOpen && mergeQueueItems.length > 0 && (
|
||||||
@@ -1222,7 +1230,11 @@ const App: React.FC = () => {
|
|||||||
{error && (
|
{error && (
|
||||||
<div
|
<div
|
||||||
className="card"
|
className="card"
|
||||||
style={{ border: '1px solid #fecaca', background: '#fef2f2' }}
|
style={{
|
||||||
|
border: '1px solid var(--pdf-danger-border)',
|
||||||
|
background: 'var(--pdf-danger-surface)',
|
||||||
|
color: 'var(--pdf-danger-text)',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<strong>Error:</strong> {error}
|
<strong>Error:</strong> {error}
|
||||||
</div>
|
</div>
|
||||||
@@ -1252,7 +1264,7 @@ const App: React.FC = () => {
|
|||||||
</ActionDialog>
|
</ActionDialog>
|
||||||
|
|
||||||
<HelpDialog open={helpOpen} onClose={() => setHelpOpen(false)} />
|
<HelpDialog open={helpOpen} onClose={() => setHelpOpen(false)} />
|
||||||
</Layout>
|
</AppShell>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,18 +21,18 @@ const backgroundByVariant: Record<
|
|||||||
NonNullable<ActionDialogAction['variant']>,
|
NonNullable<ActionDialogAction['variant']>,
|
||||||
string
|
string
|
||||||
> = {
|
> = {
|
||||||
primary: '#2563eb',
|
primary: 'var(--pdf-primary)',
|
||||||
secondary: '#e5e7eb',
|
secondary: 'var(--pdf-control)',
|
||||||
danger: '#dc2626',
|
danger: 'var(--pdf-danger-text)',
|
||||||
};
|
};
|
||||||
|
|
||||||
const colorByVariant: Record<
|
const colorByVariant: Record<
|
||||||
NonNullable<ActionDialogAction['variant']>,
|
NonNullable<ActionDialogAction['variant']>,
|
||||||
string
|
string
|
||||||
> = {
|
> = {
|
||||||
primary: 'white',
|
primary: 'var(--pdf-on-primary)',
|
||||||
secondary: '#111827',
|
secondary: 'var(--pdf-control-text)',
|
||||||
danger: 'white',
|
danger: 'var(--pdf-on-primary)',
|
||||||
};
|
};
|
||||||
|
|
||||||
const ActionDialog: React.FC<ActionDialogProps> = ({
|
const ActionDialog: React.FC<ActionDialogProps> = ({
|
||||||
@@ -75,7 +75,7 @@ const ActionDialog: React.FC<ActionDialogProps> = ({
|
|||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
inset: 0,
|
inset: 0,
|
||||||
zIndex: 70,
|
zIndex: 70,
|
||||||
background: 'rgba(15, 23, 42, 0.55)',
|
background: 'var(--pdf-overlay)',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
@@ -86,9 +86,10 @@ const ActionDialog: React.FC<ActionDialogProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
maxWidth: '440px',
|
maxWidth: '440px',
|
||||||
background: 'white',
|
background: 'var(--pdf-surface-raised)',
|
||||||
|
color: 'var(--pdf-text)',
|
||||||
borderRadius: '0.75rem',
|
borderRadius: '0.75rem',
|
||||||
boxShadow: '0 20px 40px rgba(15, 23, 42, 0.35)',
|
boxShadow: 'var(--pdf-dialog-shadow)',
|
||||||
padding: '1rem',
|
padding: '1rem',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@@ -121,8 +122,8 @@ const ActionDialog: React.FC<ActionDialogProps> = ({
|
|||||||
borderRadius: '999px',
|
borderRadius: '999px',
|
||||||
width: '1.8rem',
|
width: '1.8rem',
|
||||||
height: '1.8rem',
|
height: '1.8rem',
|
||||||
background: '#e5e7eb',
|
background: 'var(--pdf-control)',
|
||||||
color: '#111827',
|
color: 'var(--pdf-control-text)',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
fontSize: '1.1rem',
|
fontSize: '1.1rem',
|
||||||
lineHeight: 1,
|
lineHeight: 1,
|
||||||
@@ -139,7 +140,7 @@ const ActionDialog: React.FC<ActionDialogProps> = ({
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: '0.9rem',
|
fontSize: '0.9rem',
|
||||||
color: '#4b5563',
|
color: 'var(--pdf-muted)',
|
||||||
lineHeight: 1.45,
|
lineHeight: 1.45,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -173,9 +174,11 @@ const ActionDialog: React.FC<ActionDialogProps> = ({
|
|||||||
borderRadius: '0.5rem',
|
borderRadius: '0.5rem',
|
||||||
padding: '0.45rem 0.8rem',
|
padding: '0.45rem 0.8rem',
|
||||||
background: action.disabled
|
background: action.disabled
|
||||||
? '#e5e7eb'
|
? 'var(--pdf-control)'
|
||||||
: backgroundByVariant[variant],
|
: backgroundByVariant[variant],
|
||||||
color: action.disabled ? '#6b7280' : colorByVariant[variant],
|
color: action.disabled
|
||||||
|
? 'var(--pdf-muted-soft)'
|
||||||
|
: colorByVariant[variant],
|
||||||
cursor: action.disabled ? 'default' : 'pointer',
|
cursor: action.disabled ? 'default' : 'pointer',
|
||||||
fontSize: '0.9rem',
|
fontSize: '0.9rem',
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const ActionsPanel: React.FC<ActionsPanelProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<h2>Tools</h2>
|
<h2>Tools</h2>
|
||||||
<p style={{ fontSize: '0.85rem', color: '#6b7280' }}>
|
<p style={{ fontSize: '0.85rem', color: 'var(--pdf-muted-soft)' }}>
|
||||||
Use these tools on the current in-memory document (reordered, rotated,
|
Use these tools on the current in-memory document (reordered, rotated,
|
||||||
with deletions). Nothing is uploaded to a server.
|
with deletions). Nothing is uploaded to a server.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -30,7 +30,13 @@ const FileLoader: React.FC<FileLoaderProps> = ({ pdf, onFilesLoaded }) => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{pdf && (
|
{pdf && (
|
||||||
<div style={{ marginTop: '0.75rem', fontSize: '0.9rem' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
marginTop: '0.75rem',
|
||||||
|
fontSize: '0.9rem',
|
||||||
|
color: 'var(--pdf-muted)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<strong>Loaded:</strong> {pdf.name}
|
<strong>Loaded:</strong> {pdf.name}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { APP_VERSION } from '../version';
|
|
||||||
|
|
||||||
interface LayoutProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
onOpenHelp?: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Layout: React.FC<LayoutProps> = ({ children, onOpenHelp }) => {
|
|
||||||
return (
|
|
||||||
<div className="app-root">
|
|
||||||
<header className="app-header">
|
|
||||||
<div className="app-header-content">
|
|
||||||
<div className="app-header-title">
|
|
||||||
<span className="app-logo">📄</span>
|
|
||||||
<div>
|
|
||||||
<h1>PDF Workbench</h1>
|
|
||||||
<small>All in your browser</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="app-header-actions">
|
|
||||||
{onOpenHelp && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="app-help-button"
|
|
||||||
onClick={onOpenHelp}
|
|
||||||
aria-haspopup="dialog"
|
|
||||||
title="Open help and keyboard shortcuts (F1 or ?)"
|
|
||||||
>
|
|
||||||
Help <span aria-hidden="true">?</span>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="app-version" title={`Version ${APP_VERSION}`}>
|
|
||||||
v{APP_VERSION}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main className="app-main">{children}</main>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Layout;
|
|
||||||
@@ -54,22 +54,25 @@ const MergeQueuePanel: React.FC<MergeQueuePanelProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="card merge-queue-card"
|
className="card merge-queue-card"
|
||||||
style={{ border: '1px solid #bfdbfe', background: '#eff6ff' }}
|
style={{
|
||||||
|
border: '1px solid var(--pdf-info-border)',
|
||||||
|
background: 'var(--pdf-info-surface)',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<h2>Merge PDF queue</h2>
|
<h2>Merge PDF queue</h2>
|
||||||
<p style={{ fontSize: '0.85rem', color: '#374151' }}>
|
<p style={{ fontSize: '0.85rem', color: 'var(--pdf-info-text)' }}>
|
||||||
Add several PDFs, reorder the queue, then merge them into a new unsaved
|
Add several PDFs, reorder the queue, then merge them into a new unsaved
|
||||||
workspace. Processing still happens entirely in your browser.
|
workspace. Processing still happens entirely in your browser.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{hasCurrentPdf ? (
|
{hasCurrentPdf ? (
|
||||||
<p style={{ fontSize: '0.85rem', color: '#374151' }}>
|
<p style={{ fontSize: '0.85rem', color: 'var(--pdf-info-text)' }}>
|
||||||
Current workspace:{' '}
|
Current workspace:{' '}
|
||||||
<strong>{currentPdfName ?? 'Untitled document'}</strong> with{' '}
|
<strong>{currentPdfName ?? 'Untitled document'}</strong> with{' '}
|
||||||
{currentPageCount} {currentPageCount === 1 ? 'page' : 'pages'}.
|
{currentPageCount} {currentPageCount === 1 ? 'page' : 'pages'}.
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p style={{ fontSize: '0.85rem', color: '#374151' }}>
|
<p style={{ fontSize: '0.85rem', color: 'var(--pdf-info-text)' }}>
|
||||||
No current workspace is open. The queue will become a new workspace.
|
No current workspace is open. The queue will become a new workspace.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -122,7 +125,7 @@ const MergeQueuePanel: React.FC<MergeQueuePanelProps> = ({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p style={{ fontSize: '0.85rem', color: '#374151' }}>
|
<p style={{ fontSize: '0.85rem', color: 'var(--pdf-info-text)' }}>
|
||||||
Queue total:{' '}
|
Queue total:{' '}
|
||||||
<strong>
|
<strong>
|
||||||
{items.length} {items.length === 1 ? 'PDF' : 'PDFs'}
|
{items.length} {items.length === 1 ? 'PDF' : 'PDFs'}
|
||||||
@@ -186,7 +189,7 @@ const MergeQueuePanel: React.FC<MergeQueuePanelProps> = ({
|
|||||||
fontSize: '0.85rem',
|
fontSize: '0.85rem',
|
||||||
}}
|
}}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
<span style={{ color: '#6b7280' }}>
|
<span style={{ color: 'var(--pdf-muted-soft)' }}>
|
||||||
(1 = before first page, {currentPageCount + 1} = after last page)
|
(1 = before first page, {currentPageCount + 1} = after last page)
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import type { PdfFile } from '../pdf/pdfTypes';
|
import type { PdfFile } from '../pdf/pdfTypes';
|
||||||
import * as pdfjsLib from 'pdfjs-dist';
|
import { pdfjsLib } from '../pdf/pdfJs';
|
||||||
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker?worker&url';
|
|
||||||
|
|
||||||
// pdf.js worker setup
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
(pdfjsLib as any).GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
|
||||||
|
|
||||||
interface PagePreviewModalProps {
|
interface PagePreviewModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const CopyPagesDialog: React.FC<CopyPagesDialogProps> = ({
|
|||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
inset: 0,
|
inset: 0,
|
||||||
zIndex: 60,
|
zIndex: 60,
|
||||||
background: 'rgba(15, 23, 42, 0.55)',
|
background: 'var(--pdf-overlay)',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
@@ -60,9 +60,10 @@ const CopyPagesDialog: React.FC<CopyPagesDialogProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
maxWidth: '420px',
|
maxWidth: '420px',
|
||||||
background: 'white',
|
background: 'var(--pdf-surface-raised)',
|
||||||
|
color: 'var(--pdf-text)',
|
||||||
borderRadius: '0.75rem',
|
borderRadius: '0.75rem',
|
||||||
boxShadow: '0 20px 40px rgba(15, 23, 42, 0.35)',
|
boxShadow: 'var(--pdf-dialog-shadow)',
|
||||||
padding: '1rem',
|
padding: '1rem',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@@ -95,8 +96,8 @@ const CopyPagesDialog: React.FC<CopyPagesDialogProps> = ({
|
|||||||
borderRadius: '999px',
|
borderRadius: '999px',
|
||||||
width: '1.8rem',
|
width: '1.8rem',
|
||||||
height: '1.8rem',
|
height: '1.8rem',
|
||||||
background: '#e5e7eb',
|
background: 'var(--pdf-control)',
|
||||||
color: '#111827',
|
color: 'var(--pdf-control-text)',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
fontSize: '1.1rem',
|
fontSize: '1.1rem',
|
||||||
lineHeight: 1,
|
lineHeight: 1,
|
||||||
@@ -114,7 +115,7 @@ const CopyPagesDialog: React.FC<CopyPagesDialogProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
margin: 0,
|
margin: 0,
|
||||||
fontSize: '0.9rem',
|
fontSize: '0.9rem',
|
||||||
color: '#4b5563',
|
color: 'var(--pdf-muted)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Copy{' '}
|
Copy{' '}
|
||||||
@@ -145,7 +146,7 @@ const CopyPagesDialog: React.FC<CopyPagesDialogProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
padding: '0.45rem 0.55rem',
|
padding: '0.45rem 0.55rem',
|
||||||
borderRadius: '0.5rem',
|
borderRadius: '0.5rem',
|
||||||
border: '1px solid #d1d5db',
|
border: '1px solid var(--pdf-border-strong)',
|
||||||
fontSize: '0.95rem',
|
fontSize: '0.95rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -154,7 +155,7 @@ const CopyPagesDialog: React.FC<CopyPagesDialogProps> = ({
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: '0.8rem',
|
fontSize: '0.8rem',
|
||||||
color: '#6b7280',
|
color: 'var(--pdf-muted-soft)',
|
||||||
lineHeight: 1.4,
|
lineHeight: 1.4,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -166,9 +167,9 @@ const CopyPagesDialog: React.FC<CopyPagesDialogProps> = ({
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
borderRadius: '0.5rem',
|
borderRadius: '0.5rem',
|
||||||
background: '#fef2f2',
|
background: 'var(--pdf-danger-surface)',
|
||||||
border: '1px solid #fecaca',
|
border: '1px solid var(--pdf-danger-border)',
|
||||||
color: '#b91c1c',
|
color: 'var(--pdf-danger-text)',
|
||||||
padding: '0.5rem',
|
padding: '0.5rem',
|
||||||
fontSize: '0.85rem',
|
fontSize: '0.85rem',
|
||||||
}}
|
}}
|
||||||
@@ -192,8 +193,8 @@ const CopyPagesDialog: React.FC<CopyPagesDialogProps> = ({
|
|||||||
border: 'none',
|
border: 'none',
|
||||||
borderRadius: '0.5rem',
|
borderRadius: '0.5rem',
|
||||||
padding: '0.45rem 0.8rem',
|
padding: '0.45rem 0.8rem',
|
||||||
background: '#e5e7eb',
|
background: 'var(--pdf-control)',
|
||||||
color: '#111827',
|
color: 'var(--pdf-control-text)',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
fontSize: '0.9rem',
|
fontSize: '0.9rem',
|
||||||
}}
|
}}
|
||||||
@@ -207,8 +208,8 @@ const CopyPagesDialog: React.FC<CopyPagesDialogProps> = ({
|
|||||||
border: 'none',
|
border: 'none',
|
||||||
borderRadius: '0.5rem',
|
borderRadius: '0.5rem',
|
||||||
padding: '0.45rem 0.8rem',
|
padding: '0.45rem 0.8rem',
|
||||||
background: '#16a34a',
|
background: 'var(--pdf-success-text)',
|
||||||
color: 'white',
|
color: 'var(--pdf-on-primary)',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
fontSize: '0.9rem',
|
fontSize: '0.9rem',
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -53,11 +53,11 @@ const PageCard: React.FC<PageCardProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const background = isDraggingCard
|
const background = isDraggingCard
|
||||||
? isCopyDragging
|
? isCopyDragging
|
||||||
? '#dcfce7'
|
? 'var(--pdf-success-soft)'
|
||||||
: '#dbeafe'
|
: 'var(--pdf-info-surface)'
|
||||||
: selected
|
: selected
|
||||||
? '#eff6ff'
|
? 'var(--pdf-info-surface)'
|
||||||
: '#f9fafb';
|
: 'var(--pdf-surface-soft)';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -71,7 +71,7 @@ const PageCard: React.FC<PageCardProps> = ({
|
|||||||
width: '162px',
|
width: '162px',
|
||||||
padding: '0.4rem',
|
padding: '0.4rem',
|
||||||
borderRadius: '0.5rem',
|
borderRadius: '0.5rem',
|
||||||
border: '1px solid #e5e7eb',
|
border: '1px solid var(--pdf-border)',
|
||||||
background,
|
background,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@@ -91,9 +91,11 @@ const PageCard: React.FC<PageCardProps> = ({
|
|||||||
width: '20px',
|
width: '20px',
|
||||||
height: '20px',
|
height: '20px',
|
||||||
borderRadius: '0.4rem',
|
borderRadius: '0.4rem',
|
||||||
border: '1px solid #9ca3af',
|
border: '1px solid var(--pdf-border-strong)',
|
||||||
background: selected ? '#2563eb' : 'rgba(255,255,255,0.9)',
|
background: selected
|
||||||
color: selected ? 'white' : 'transparent',
|
? 'var(--pdf-primary)'
|
||||||
|
: 'color-mix(in srgb, var(--pdf-surface) 92%, transparent)',
|
||||||
|
color: selected ? 'var(--pdf-on-primary)' : 'transparent',
|
||||||
fontSize: '0.8rem',
|
fontSize: '0.8rem',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -131,8 +133,8 @@ const PageCard: React.FC<PageCardProps> = ({
|
|||||||
height: 'auto',
|
height: 'auto',
|
||||||
objectFit: 'contain',
|
objectFit: 'contain',
|
||||||
borderRadius: '0.25rem',
|
borderRadius: '0.25rem',
|
||||||
border: '1px solid #e5e7eb',
|
border: '1px solid var(--pdf-paper-border)',
|
||||||
background: 'white',
|
background: 'var(--pdf-paper)',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -141,8 +143,8 @@ const PageCard: React.FC<PageCardProps> = ({
|
|||||||
width: '60px',
|
width: '60px',
|
||||||
height: '80px',
|
height: '80px',
|
||||||
borderRadius: '0.25rem',
|
borderRadius: '0.25rem',
|
||||||
border: '1px dashed #d1d5db',
|
border: '1px dashed var(--pdf-paper-border)',
|
||||||
background: '#f3f4f6',
|
background: 'var(--pdf-paper-placeholder)',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -151,7 +153,7 @@ const PageCard: React.FC<PageCardProps> = ({
|
|||||||
<span style={{ fontSize: '0.8rem' }}>
|
<span style={{ fontSize: '0.8rem' }}>
|
||||||
Page {page.sourcePageIndex + 1}
|
Page {page.sourcePageIndex + 1}
|
||||||
</span>
|
</span>
|
||||||
<span style={{ fontSize: '0.7rem', color: '#6b7280' }}>
|
<span style={{ fontSize: '0.7rem', color: 'var(--pdf-muted-soft)' }}>
|
||||||
Pos {visualIndex + 1} · Rot {page.rotation}°
|
Pos {visualIndex + 1} · Rot {page.rotation}°
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -170,7 +172,8 @@ const PageCard: React.FC<PageCardProps> = ({
|
|||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
...pageActionButtonStyle,
|
...pageActionButtonStyle,
|
||||||
background: '#e5e7eb',
|
background: 'var(--pdf-control)',
|
||||||
|
color: 'var(--pdf-control-text)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
↻ 90°
|
↻ 90°
|
||||||
@@ -184,7 +187,8 @@ const PageCard: React.FC<PageCardProps> = ({
|
|||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
...pageActionButtonStyle,
|
...pageActionButtonStyle,
|
||||||
background: '#e5e7eb',
|
background: 'var(--pdf-control)',
|
||||||
|
color: 'var(--pdf-control-text)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
↺ 90°
|
↺ 90°
|
||||||
@@ -198,8 +202,8 @@ const PageCard: React.FC<PageCardProps> = ({
|
|||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
...pageActionButtonStyle,
|
...pageActionButtonStyle,
|
||||||
background: '#fecaca',
|
background: 'var(--pdf-danger-soft)',
|
||||||
color: '#b91c1c',
|
color: 'var(--pdf-danger-text)',
|
||||||
}}
|
}}
|
||||||
title="Remove this page from the exported PDF"
|
title="Remove this page from the exported PDF"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ const PageSelectionToolbar: React.FC<PageSelectionToolbarProps> = ({
|
|||||||
disabled={!hasSelection}
|
disabled={!hasSelection}
|
||||||
style={{
|
style={{
|
||||||
...pillButtonStyle,
|
...pillButtonStyle,
|
||||||
background: '#dcfce7',
|
background: 'var(--pdf-success-soft)',
|
||||||
color: '#166534',
|
color: 'var(--pdf-success-text)',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
}}
|
}}
|
||||||
title="Copy selected pages to another position"
|
title="Copy selected pages to another position"
|
||||||
@@ -69,8 +69,8 @@ const PageSelectionToolbar: React.FC<PageSelectionToolbarProps> = ({
|
|||||||
onClick={onDeleteSelected}
|
onClick={onDeleteSelected}
|
||||||
style={{
|
style={{
|
||||||
...pillButtonStyle,
|
...pillButtonStyle,
|
||||||
background: '#fee2e2',
|
background: 'var(--pdf-danger-soft)',
|
||||||
color: '#b91c1c',
|
color: 'var(--pdf-danger-text)',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -83,8 +83,8 @@ const PageSelectionToolbar: React.FC<PageSelectionToolbarProps> = ({
|
|||||||
onClick={onSelectAll}
|
onClick={onSelectAll}
|
||||||
style={{
|
style={{
|
||||||
...pillButtonStyle,
|
...pillButtonStyle,
|
||||||
background: '#8dcd8d',
|
background: 'var(--pdf-success-border)',
|
||||||
color: '#111827',
|
color: 'var(--pdf-control-text)',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -97,8 +97,10 @@ const PageSelectionToolbar: React.FC<PageSelectionToolbarProps> = ({
|
|||||||
disabled={!hasSelection}
|
disabled={!hasSelection}
|
||||||
style={{
|
style={{
|
||||||
...pillButtonStyle,
|
...pillButtonStyle,
|
||||||
background: '#e5e7eb',
|
background: 'var(--pdf-control)',
|
||||||
color: hasSelection ? '#111827' : '#6b7280',
|
color: hasSelection
|
||||||
|
? 'var(--pdf-control-text)'
|
||||||
|
: 'var(--pdf-muted-soft)',
|
||||||
cursor: hasSelection ? 'pointer' : 'default',
|
cursor: hasSelection ? 'pointer' : 'default',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -279,13 +279,15 @@ const ReorderPanel: React.FC<ReorderPanelProps> = ({
|
|||||||
draggingPage != null &&
|
draggingPage != null &&
|
||||||
selectedPageIds.length > 0 &&
|
selectedPageIds.length > 0 &&
|
||||||
selectedPageIds.includes(draggingPage.id);
|
selectedPageIds.includes(draggingPage.id);
|
||||||
const dropIndicatorColor = isCopyDragging ? '#16a34a' : '#2563eb';
|
const dropIndicatorColor = isCopyDragging
|
||||||
|
? 'var(--pdf-success-text)'
|
||||||
|
: 'var(--pdf-primary)';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<h2>Pages</h2>
|
<h2>Pages</h2>
|
||||||
<p style={{ fontSize: '0.85rem', color: '#6b7280' }}>
|
<p style={{ fontSize: '0.85rem', color: 'var(--pdf-muted-soft)' }}>
|
||||||
Tap/click a page to preview it. Use the checkbox to select pages
|
Tap/click a page to preview it. Use the checkbox to select pages
|
||||||
(Shift for ranges). Drag to reorder; dragging a selected page moves
|
(Shift for ranges). Drag to reorder; dragging a selected page moves
|
||||||
the whole selection. Hold Ctrl/⌘ while dropping to copy instead of
|
the whole selection. Hold Ctrl/⌘ while dropping to copy instead of
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
<div className="card">
|
<div className="card">
|
||||||
<h2>Workspace</h2>
|
<h2>Workspace</h2>
|
||||||
|
|
||||||
<p style={{ fontSize: '0.85rem', color: '#6b7280' }}>
|
<p style={{ fontSize: '0.85rem', color: 'var(--pdf-muted-soft)' }}>
|
||||||
Save named workspaces in this browser. PDF binaries are stored in
|
Save named workspaces in this browser. PDF binaries are stored in
|
||||||
IndexedDB; nothing is uploaded.
|
IndexedDB; nothing is uploaded.
|
||||||
</p>
|
</p>
|
||||||
@@ -78,7 +78,7 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
padding: '0.45rem 0.55rem',
|
padding: '0.45rem 0.55rem',
|
||||||
borderRadius: '0.5rem',
|
borderRadius: '0.5rem',
|
||||||
border: '1px solid #d1d5db',
|
border: '1px solid var(--pdf-border-strong)',
|
||||||
fontSize: '0.9rem',
|
fontSize: '0.9rem',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -140,7 +140,7 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
marginTop: '0.5rem',
|
marginTop: '0.5rem',
|
||||||
fontSize: '0.8rem',
|
fontSize: '0.8rem',
|
||||||
color: '#92400e',
|
color: 'var(--pdf-warning-text)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Unsaved workspace changes.
|
Unsaved workspace changes.
|
||||||
@@ -152,7 +152,7 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
marginTop: '0.5rem',
|
marginTop: '0.5rem',
|
||||||
fontSize: '0.85rem',
|
fontSize: '0.85rem',
|
||||||
color: '#166534',
|
color: 'var(--pdf-success-text)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{workspaceMessage}
|
{workspaceMessage}
|
||||||
@@ -178,10 +178,12 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
<div
|
<div
|
||||||
key={workspace.id}
|
key={workspace.id}
|
||||||
style={{
|
style={{
|
||||||
border: '1px solid #e5e7eb',
|
border: '1px solid var(--pdf-border)',
|
||||||
borderRadius: '0.5rem',
|
borderRadius: '0.5rem',
|
||||||
padding: '0.5rem',
|
padding: '0.5rem',
|
||||||
background: active ? '#eff6ff' : '#f9fafb',
|
background: active
|
||||||
|
? 'var(--pdf-info-surface)'
|
||||||
|
: 'var(--pdf-surface-soft)',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
gap: '0.75rem',
|
gap: '0.75rem',
|
||||||
@@ -193,11 +195,19 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
<div style={{ fontSize: '0.9rem' }}>
|
<div style={{ fontSize: '0.9rem' }}>
|
||||||
<strong>{workspace.name}</strong>
|
<strong>{workspace.name}</strong>
|
||||||
{active && (
|
{active && (
|
||||||
<span style={{ color: '#2563eb' }}> · active</span>
|
<span style={{ color: 'var(--pdf-primary)' }}>
|
||||||
|
{' '}
|
||||||
|
· active
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ fontSize: '0.75rem', color: '#6b7280' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
color: 'var(--pdf-muted-soft)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
{workspace.pdfName} · source pages:{' '}
|
{workspace.pdfName} · source pages:{' '}
|
||||||
{workspace.sourcePageCount} · workspace pages:{' '}
|
{workspace.sourcePageCount} · workspace pages:{' '}
|
||||||
{workspace.workspacePageCount} · undo:{' '}
|
{workspace.workspacePageCount} · undo:{' '}
|
||||||
@@ -228,8 +238,8 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
disabled={isBusy}
|
disabled={isBusy}
|
||||||
onClick={() => onDeleteWorkspace(workspace.id)}
|
onClick={() => onDeleteWorkspace(workspace.id)}
|
||||||
style={{
|
style={{
|
||||||
background: '#fee2e2',
|
background: 'var(--pdf-danger-soft)',
|
||||||
color: '#991b1b',
|
color: 'var(--pdf-danger-text)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
@@ -261,8 +271,8 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
key={entry.id}
|
key={entry.id}
|
||||||
style={{
|
style={{
|
||||||
fontSize: '0.8rem',
|
fontSize: '0.8rem',
|
||||||
color: '#374151',
|
color: 'var(--pdf-muted)',
|
||||||
borderLeft: '3px solid #2563eb',
|
borderLeft: '3px solid var(--pdf-primary)',
|
||||||
paddingLeft: '0.45rem',
|
paddingLeft: '0.45rem',
|
||||||
paddingTop: '0.2rem',
|
paddingTop: '0.2rem',
|
||||||
paddingBottom: '0.2rem',
|
paddingBottom: '0.2rem',
|
||||||
@@ -272,7 +282,7 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
Undo {history.length - index}. {entry.label}
|
Undo {history.length - index}. {entry.label}
|
||||||
</strong>
|
</strong>
|
||||||
<br />
|
<br />
|
||||||
<span style={{ color: '#6b7280' }}>
|
<span style={{ color: 'var(--pdf-muted-soft)' }}>
|
||||||
{new Date(entry.timestamp).toLocaleString()}
|
{new Date(entry.timestamp).toLocaleString()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -282,12 +292,12 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
style={{
|
style={{
|
||||||
margin: '0.25rem 0',
|
margin: '0.25rem 0',
|
||||||
borderRadius: '999px',
|
borderRadius: '999px',
|
||||||
background: '#ecfdf5',
|
background: 'var(--pdf-success-surface)',
|
||||||
color: '#166534',
|
color: 'var(--pdf-success-text)',
|
||||||
fontSize: '0.8rem',
|
fontSize: '0.8rem',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
alignSelf: 'flex-start',
|
alignSelf: 'flex-start',
|
||||||
border: '2px solid #166534',
|
border: '2px solid var(--pdf-success-text)',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
@@ -300,8 +310,8 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
key={entry.id}
|
key={entry.id}
|
||||||
style={{
|
style={{
|
||||||
fontSize: '0.8rem',
|
fontSize: '0.8rem',
|
||||||
color: '#9ca3af',
|
color: 'var(--pdf-muted-faint)',
|
||||||
borderLeft: '3px solid #d1d5db',
|
borderLeft: '3px solid var(--pdf-border-strong)',
|
||||||
paddingLeft: '0.45rem',
|
paddingLeft: '0.45rem',
|
||||||
paddingTop: '0.2rem',
|
paddingTop: '0.2rem',
|
||||||
paddingBottom: '0.2rem',
|
paddingBottom: '0.2rem',
|
||||||
@@ -312,7 +322,7 @@ const WorkspacePanel: React.FC<WorkspacePanelProps> = ({
|
|||||||
Redo {index + 1}. {entry.label}
|
Redo {index + 1}. {entry.label}
|
||||||
</strong>
|
</strong>
|
||||||
<br />
|
<br />
|
||||||
<span style={{ color: '#9ca3af' }}>
|
<span style={{ color: 'var(--pdf-muted-faint)' }}>
|
||||||
{new Date(entry.timestamp).toLocaleString()}
|
{new Date(entry.timestamp).toLocaleString()}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
import '@add-ideas/toolbox-shell-react/styles.css';
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||||
|
|||||||
9
src/pdf/pdfJs.ts
Normal file
9
src/pdf/pdfJs.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import './uint8ArrayToHexPolyfill';
|
||||||
|
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.mjs';
|
||||||
|
import pdfjsWorker from './pdfjsWorker?worker&url';
|
||||||
|
|
||||||
|
// pdf.js worker setup for Vite.
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
(pdfjsLib as any).GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
||||||
|
|
||||||
|
export { pdfjsLib };
|
||||||
@@ -1,9 +1,4 @@
|
|||||||
import * as pdfjsLib from 'pdfjs-dist';
|
import { pdfjsLib } from './pdfJs';
|
||||||
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker?worker&url';
|
|
||||||
|
|
||||||
// pdf.js worker setup for Vite
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
(pdfjsLib as any).GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
|
||||||
|
|
||||||
type RotationsMap = Record<number, number>; // key: 0-based page index, value: degrees
|
type RotationsMap = Record<number, number>; // key: 0-based page index, value: degrees
|
||||||
|
|
||||||
|
|||||||
2
src/pdf/pdfjsWorker.ts
Normal file
2
src/pdf/pdfjsWorker.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import './uint8ArrayToHexPolyfill';
|
||||||
|
import 'pdfjs-dist/legacy/build/pdf.worker.mjs';
|
||||||
22
src/pdf/uint8ArrayToHexPolyfill.ts
Normal file
22
src/pdf/uint8ArrayToHexPolyfill.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
type Uint8ArrayWithToHex = Uint8Array & {
|
||||||
|
toHex?: () => string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8ArrayPrototype = Uint8Array.prototype as Uint8ArrayWithToHex;
|
||||||
|
|
||||||
|
if (typeof uint8ArrayPrototype.toHex !== 'function') {
|
||||||
|
Object.defineProperty(Uint8Array.prototype, 'toHex', {
|
||||||
|
value: function toHex(this: Uint8Array): string {
|
||||||
|
const hex = new Array<string>(this.length);
|
||||||
|
|
||||||
|
for (let index = 0; index < this.length; index += 1) {
|
||||||
|
const value = this[index].toString(16);
|
||||||
|
hex[index] = value.length === 1 ? `0${value}` : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex.join('');
|
||||||
|
},
|
||||||
|
writable: true,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
365
src/styles.css
365
src/styles.css
@@ -12,89 +12,30 @@ body {
|
|||||||
BlinkMacSystemFont,
|
BlinkMacSystemFont,
|
||||||
'Segoe UI',
|
'Segoe UI',
|
||||||
sans-serif;
|
sans-serif;
|
||||||
background-color: #f3f4f6;
|
background-color: var(--toolbox-background);
|
||||||
color: #111827;
|
color: var(--toolbox-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
#root {
|
#root {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-shell {
|
.pdf-toolbox-shell .toolbox-shell__main .card {
|
||||||
display: flex;
|
border: 1px solid var(--pdf-border);
|
||||||
min-height: 100vh;
|
background: var(--pdf-surface);
|
||||||
}
|
|
||||||
|
|
||||||
.app-sidebar {
|
|
||||||
width: 260px;
|
|
||||||
background: #111827;
|
|
||||||
color: #e5e7eb;
|
|
||||||
padding: 1rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-sidebar h1 {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-sidebar small {
|
|
||||||
color: #9ca3af;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-nav {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-nav button {
|
|
||||||
width: 100%;
|
|
||||||
text-align: left;
|
|
||||||
padding: 0.4rem 0.6rem;
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
color: #d1d5db;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-nav button.active {
|
|
||||||
background: #374151;
|
|
||||||
color: #f9fafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-nav button:disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-main {
|
|
||||||
flex: 1;
|
|
||||||
padding: 1rem 1.5rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
background: white;
|
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.12);
|
box-shadow: var(--pdf-card-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card h2 {
|
.pdf-toolbox-shell .toolbox-shell__main .card h2 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.primary {
|
.pdf-toolbox-shell .toolbox-shell__main button.primary {
|
||||||
background: #2563eb;
|
background: var(--pdf-primary);
|
||||||
color: white;
|
color: var(--pdf-on-primary);
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 0.45rem 0.9rem;
|
padding: 0.45rem 0.9rem;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -102,14 +43,14 @@ button.primary {
|
|||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.primary:disabled {
|
.pdf-toolbox-shell .toolbox-shell__main button.primary:disabled {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.secondary {
|
.pdf-toolbox-shell .toolbox-shell__main button.secondary {
|
||||||
background: #e5e7eb;
|
background: var(--pdf-control);
|
||||||
color: #111827;
|
color: var(--pdf-control-text);
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 0.45rem 0.9rem;
|
padding: 0.45rem 0.9rem;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -117,121 +58,175 @@ button.secondary {
|
|||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-row {
|
.pdf-toolbox-shell .toolbox-shell__main .button-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-root {
|
.pdf-toolbox-shell {
|
||||||
min-height: 100vh;
|
--pdf-surface: var(--toolbox-surface);
|
||||||
background-color: #f3f4f6;
|
--pdf-surface-soft: #f9fafb;
|
||||||
|
--pdf-surface-raised: #ffffff;
|
||||||
|
--pdf-text: var(--toolbox-text);
|
||||||
|
--pdf-muted: #4b5563;
|
||||||
|
--pdf-muted-soft: #6b7280;
|
||||||
|
--pdf-muted-faint: #9ca3af;
|
||||||
|
--pdf-border: #e5e7eb;
|
||||||
|
--pdf-border-strong: #d1d5db;
|
||||||
|
--pdf-primary: #2563eb;
|
||||||
|
--pdf-on-primary: #ffffff;
|
||||||
|
--pdf-control: #e5e7eb;
|
||||||
|
--pdf-control-text: #111827;
|
||||||
|
--pdf-info-surface: #eff6ff;
|
||||||
|
--pdf-info-border: #bfdbfe;
|
||||||
|
--pdf-info-text: #1e3a8a;
|
||||||
|
--pdf-success-surface: #ecfdf5;
|
||||||
|
--pdf-success-soft: #dcfce7;
|
||||||
|
--pdf-success-border: #86efac;
|
||||||
|
--pdf-success-text: #166534;
|
||||||
|
--pdf-warning-surface: #fff7ed;
|
||||||
|
--pdf-warning-border: #fed7aa;
|
||||||
|
--pdf-warning-text: #9a3412;
|
||||||
|
--pdf-danger-surface: #fef2f2;
|
||||||
|
--pdf-danger-soft: #fee2e2;
|
||||||
|
--pdf-danger-border: #fecaca;
|
||||||
|
--pdf-danger-text: #b91c1c;
|
||||||
|
--pdf-overlay: rgba(15, 23, 42, 0.62);
|
||||||
|
--pdf-dialog-shadow: 0 20px 40px rgba(15, 23, 42, 0.35);
|
||||||
|
--pdf-card-shadow: 0 1px 3px rgba(15, 23, 42, 0.12);
|
||||||
|
--pdf-paper: #ffffff;
|
||||||
|
--pdf-paper-placeholder: #f3f4f6;
|
||||||
|
--pdf-paper-border: #d1d5db;
|
||||||
|
--pdf-paper-text: #111827;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header {
|
.pdf-toolbox-shell[data-toolbox-theme='dark'] {
|
||||||
position: sticky;
|
--pdf-surface-soft: #20283a;
|
||||||
top: 0;
|
--pdf-surface-raised: #1b2334;
|
||||||
z-index: 10;
|
--pdf-muted: #b6bfd2;
|
||||||
background: #111827;
|
--pdf-muted-soft: #a9b3ca;
|
||||||
color: #e5e7eb;
|
--pdf-muted-faint: #8792aa;
|
||||||
padding: 0.6rem 1rem;
|
--pdf-border: #303a50;
|
||||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.4);
|
--pdf-border-strong: #465169;
|
||||||
|
--pdf-primary: #8798f5;
|
||||||
|
--pdf-on-primary: #101728;
|
||||||
|
--pdf-control: #293247;
|
||||||
|
--pdf-control-text: #edf1fb;
|
||||||
|
--pdf-info-surface: #182946;
|
||||||
|
--pdf-info-border: #345a8c;
|
||||||
|
--pdf-info-text: #c6dcff;
|
||||||
|
--pdf-success-surface: #12382e;
|
||||||
|
--pdf-success-soft: #174436;
|
||||||
|
--pdf-success-border: #33765d;
|
||||||
|
--pdf-success-text: #a7e8cf;
|
||||||
|
--pdf-warning-surface: #402814;
|
||||||
|
--pdf-warning-border: #80522d;
|
||||||
|
--pdf-warning-text: #ffd2a6;
|
||||||
|
--pdf-danger-surface: #421f29;
|
||||||
|
--pdf-danger-soft: #4f2530;
|
||||||
|
--pdf-danger-border: #81394b;
|
||||||
|
--pdf-danger-text: #ffc0cc;
|
||||||
|
--pdf-overlay: rgba(2, 6, 16, 0.76);
|
||||||
|
--pdf-dialog-shadow: 0 24px 52px rgba(0, 0, 0, 0.5);
|
||||||
|
--pdf-card-shadow: 0 2px 7px rgba(0, 0, 0, 0.26);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header-title {
|
@media (prefers-color-scheme: dark) {
|
||||||
display: flex;
|
.pdf-toolbox-shell[data-toolbox-theme='system'] {
|
||||||
align-items: center;
|
--pdf-surface-soft: #20283a;
|
||||||
gap: 0.6rem;
|
--pdf-surface-raised: #1b2334;
|
||||||
|
--pdf-muted: #b6bfd2;
|
||||||
|
--pdf-muted-soft: #a9b3ca;
|
||||||
|
--pdf-muted-faint: #8792aa;
|
||||||
|
--pdf-border: #303a50;
|
||||||
|
--pdf-border-strong: #465169;
|
||||||
|
--pdf-primary: #8798f5;
|
||||||
|
--pdf-on-primary: #101728;
|
||||||
|
--pdf-control: #293247;
|
||||||
|
--pdf-control-text: #edf1fb;
|
||||||
|
--pdf-info-surface: #182946;
|
||||||
|
--pdf-info-border: #345a8c;
|
||||||
|
--pdf-info-text: #c6dcff;
|
||||||
|
--pdf-success-surface: #12382e;
|
||||||
|
--pdf-success-soft: #174436;
|
||||||
|
--pdf-success-border: #33765d;
|
||||||
|
--pdf-success-text: #a7e8cf;
|
||||||
|
--pdf-warning-surface: #402814;
|
||||||
|
--pdf-warning-border: #80522d;
|
||||||
|
--pdf-warning-text: #ffd2a6;
|
||||||
|
--pdf-danger-surface: #421f29;
|
||||||
|
--pdf-danger-soft: #4f2530;
|
||||||
|
--pdf-danger-border: #81394b;
|
||||||
|
--pdf-danger-text: #ffc0cc;
|
||||||
|
--pdf-overlay: rgba(2, 6, 16, 0.76);
|
||||||
|
--pdf-dialog-shadow: 0 24px 52px rgba(0, 0, 0, 0.5);
|
||||||
|
--pdf-card-shadow: 0 2px 7px rgba(0, 0, 0, 0.26);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header h1 {
|
.pdf-toolbox-shell .toolbox-shell__main {
|
||||||
font-size: 1rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-header small {
|
|
||||||
color: #9ca3af;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-logo {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-main {
|
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
max-width: 900px;
|
max-width: 90rem;
|
||||||
margin: 0 auto;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make cards full-width on mobile */
|
.pdf-toolbox-shell .toolbox-shell__main input,
|
||||||
.card {
|
.pdf-toolbox-shell .toolbox-shell__main select,
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main textarea {
|
||||||
|
border-color: var(--pdf-border-strong);
|
||||||
|
background: var(--pdf-surface);
|
||||||
|
color: var(--pdf-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main input::placeholder,
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main textarea::placeholder {
|
||||||
|
color: var(--pdf-muted-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main a {
|
||||||
|
color: var(--toolbox-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main a:hover {
|
||||||
|
color: var(--toolbox-accent-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main button:disabled {
|
||||||
|
opacity: 0.58;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main button:focus-visible,
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main a:focus-visible,
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main input:focus-visible,
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main select:focus-visible {
|
||||||
|
outline: 3px solid color-mix(in srgb, var(--toolbox-focus) 72%, transparent);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pdf-toolbox-shell .toolbox-shell__main .card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.download-link {
|
.pdf-toolbox-shell .toolbox-shell__main .download-link {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0.15rem 0;
|
margin: 0.15rem 0;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card hr {
|
.pdf-toolbox-shell .toolbox-shell__main .card hr {
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid #e5e7eb;
|
border-top: 1px solid var(--pdf-border);
|
||||||
}
|
|
||||||
|
|
||||||
.app-header-content {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-version {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
border-radius: 999px;
|
|
||||||
background: #374151;
|
|
||||||
color: #d1d5db;
|
|
||||||
padding: 0.4rem 0.7rem;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-header-actions {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-help-button {
|
|
||||||
border: 1px solid #4b5563;
|
|
||||||
border-radius: 999px;
|
|
||||||
background: transparent;
|
|
||||||
color: #e5e7eb;
|
|
||||||
padding: 0.35rem 0.65rem;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-help-button:hover,
|
|
||||||
.app-help-button:focus-visible {
|
|
||||||
background: #374151;
|
|
||||||
outline: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-dialog-backdrop {
|
.help-dialog-backdrop {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
z-index: 80;
|
z-index: 80;
|
||||||
background: rgba(15, 23, 42, 0.65);
|
background: var(--pdf-overlay);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -242,9 +237,9 @@ button.secondary {
|
|||||||
width: min(920px, 100%);
|
width: min(920px, 100%);
|
||||||
max-height: min(88vh, 760px);
|
max-height: min(88vh, 760px);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
background: #ffffff;
|
background: var(--pdf-surface-raised);
|
||||||
border-radius: 0.9rem;
|
border-radius: 0.9rem;
|
||||||
box-shadow: 0 24px 60px rgba(15, 23, 42, 0.4);
|
box-shadow: var(--pdf-dialog-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-dialog-header {
|
.help-dialog-header {
|
||||||
@@ -256,8 +251,8 @@ button.secondary {
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background: #ffffff;
|
background: var(--pdf-surface-raised);
|
||||||
border-bottom: 1px solid #e5e7eb;
|
border-bottom: 1px solid var(--pdf-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-dialog-header h2 {
|
.help-dialog-header h2 {
|
||||||
@@ -267,7 +262,7 @@ button.secondary {
|
|||||||
|
|
||||||
.help-dialog-header p {
|
.help-dialog-header p {
|
||||||
margin: 0.35rem 0 0;
|
margin: 0.35rem 0 0;
|
||||||
color: #4b5563;
|
color: var(--pdf-muted);
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
}
|
}
|
||||||
@@ -278,8 +273,8 @@ button.secondary {
|
|||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
background: #e5e7eb;
|
background: var(--pdf-control);
|
||||||
color: #111827;
|
color: var(--pdf-control-text);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@@ -293,10 +288,10 @@ button.secondary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.help-section {
|
.help-section {
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid var(--pdf-border);
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
padding: 0.9rem;
|
padding: 0.9rem;
|
||||||
background: #f9fafb;
|
background: var(--pdf-surface-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-section h3 {
|
.help-section h3 {
|
||||||
@@ -312,8 +307,8 @@ button.secondary {
|
|||||||
|
|
||||||
.help-step {
|
.help-step {
|
||||||
border-radius: 0.65rem;
|
border-radius: 0.65rem;
|
||||||
background: #ffffff;
|
background: var(--pdf-surface);
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid var(--pdf-border);
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +320,7 @@ button.secondary {
|
|||||||
.help-step p,
|
.help-step p,
|
||||||
.help-note {
|
.help-note {
|
||||||
margin: 0.35rem 0 0;
|
margin: 0.35rem 0 0;
|
||||||
color: #4b5563;
|
color: var(--pdf-muted);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
}
|
}
|
||||||
@@ -341,18 +336,18 @@ button.secondary {
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: 0.4rem;
|
border-radius: 0.4rem;
|
||||||
border: 1px solid #d1d5db;
|
border: 1px solid var(--pdf-border-strong);
|
||||||
background: #ffffff;
|
background: var(--pdf-surface);
|
||||||
padding: 0.2rem 0.45rem;
|
padding: 0.2rem 0.45rem;
|
||||||
font-size: 0.78rem;
|
font-size: 0.78rem;
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||||
color: #111827;
|
color: var(--pdf-text);
|
||||||
box-shadow: inset 0 -1px 0 #d1d5db;
|
box-shadow: inset 0 -1px 0 var(--pdf-border-strong);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcut-grid span {
|
.shortcut-grid span {
|
||||||
color: #4b5563;
|
color: var(--pdf-muted);
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
}
|
}
|
||||||
@@ -369,8 +364,8 @@ button.secondary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.help-concepts dl > div {
|
.help-concepts dl > div {
|
||||||
background: #ffffff;
|
background: var(--pdf-surface);
|
||||||
border: 1px solid #e5e7eb;
|
border: 1px solid var(--pdf-border);
|
||||||
border-radius: 0.65rem;
|
border-radius: 0.65rem;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
}
|
}
|
||||||
@@ -383,7 +378,7 @@ button.secondary {
|
|||||||
|
|
||||||
.help-concepts dd {
|
.help-concepts dd {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #4b5563;
|
color: var(--pdf-muted);
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
@@ -393,10 +388,6 @@ button.secondary {
|
|||||||
.help-concepts dl {
|
.help-concepts dl {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-header-content {
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.merge-queue-list {
|
.merge-queue-list {
|
||||||
@@ -411,16 +402,16 @@ button.secondary {
|
|||||||
grid-template-columns: auto 1fr auto;
|
grid-template-columns: auto 1fr auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
border: 1px solid #bfdbfe;
|
border: 1px solid var(--pdf-info-border);
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
background: rgba(255, 255, 255, 0.8);
|
background: color-mix(in srgb, var(--pdf-surface) 86%, transparent);
|
||||||
padding: 0.6rem;
|
padding: 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.merge-queue-order {
|
.merge-queue-order {
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
background: #dbeafe;
|
background: var(--pdf-info-surface);
|
||||||
color: #1e3a8a;
|
color: var(--pdf-info-text);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
padding: 0.2rem 0.5rem;
|
padding: 0.2rem 0.5rem;
|
||||||
@@ -439,7 +430,7 @@ button.secondary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.merge-queue-details span {
|
.merge-queue-details span {
|
||||||
color: #4b5563;
|
color: var(--pdf-muted);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,10 +462,10 @@ button.secondary {
|
|||||||
|
|
||||||
.merge-warning {
|
.merge-warning {
|
||||||
margin: 0.75rem 0 0;
|
margin: 0.75rem 0 0;
|
||||||
border: 1px solid #fed7aa;
|
border: 1px solid var(--pdf-warning-border);
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
background: #fff7ed;
|
background: var(--pdf-warning-surface);
|
||||||
color: #9a3412;
|
color: var(--pdf-warning-text);
|
||||||
padding: 0.55rem 0.65rem;
|
padding: 0.55rem 0.65rem;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/toolboxApp.definition.json
Normal file
29
src/toolboxApp.definition.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"id": "de.add-ideas.pdf-tools",
|
||||||
|
"name": "PDF Workbench",
|
||||||
|
"description": "Page-level PDF operations performed locally in the browser.",
|
||||||
|
"entry": "./",
|
||||||
|
"icon": "./favicon.svg",
|
||||||
|
"categories": ["documents", "pdf"],
|
||||||
|
"tags": ["merge", "split", "rotate", "reorder"],
|
||||||
|
"integration": {
|
||||||
|
"contextVersion": 1,
|
||||||
|
"launchModes": ["navigate", "new-tab"],
|
||||||
|
"embedding": "unsupported"
|
||||||
|
},
|
||||||
|
"requirements": {
|
||||||
|
"secureContext": true,
|
||||||
|
"workers": true,
|
||||||
|
"indexedDb": true,
|
||||||
|
"crossOriginIsolated": false
|
||||||
|
},
|
||||||
|
"privacy": {
|
||||||
|
"processing": "local",
|
||||||
|
"fileUploads": false,
|
||||||
|
"telemetry": false
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"repository": "https://git.add-ideas.de/lotobo/pdf-tools",
|
||||||
|
"license": "AGPL-3.0-only"
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/toolboxApp.test.ts
Normal file
17
src/toolboxApp.test.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { parseToolboxApp } from '@add-ideas/toolbox-contract';
|
||||||
|
import generatedManifest from '../public/toolbox-app.json';
|
||||||
|
import { toolboxApp } from './toolboxApp';
|
||||||
|
|
||||||
|
describe('toolbox app definition', () => {
|
||||||
|
it('matches the generated public manifest', () => {
|
||||||
|
expect(toolboxApp).toEqual(parseToolboxApp(generatedManifest));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses repository metadata for the shared source control', () => {
|
||||||
|
expect(toolboxApp.source?.repository).toBe(
|
||||||
|
'https://git.add-ideas.de/lotobo/pdf-tools'
|
||||||
|
);
|
||||||
|
expect(toolboxApp.actions).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
9
src/toolboxApp.ts
Normal file
9
src/toolboxApp.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { parseToolboxApp } from '@add-ideas/toolbox-contract';
|
||||||
|
import definition from './toolboxApp.definition.json';
|
||||||
|
import { APP_VERSION } from './version';
|
||||||
|
|
||||||
|
export const toolboxApp = parseToolboxApp({
|
||||||
|
schemaVersion: 1,
|
||||||
|
...definition,
|
||||||
|
version: APP_VERSION,
|
||||||
|
});
|
||||||
@@ -1 +1 @@
|
|||||||
export const APP_VERSION = '0.3.2';
|
export const APP_VERSION = '0.4.4';
|
||||||
|
|||||||
13
tests/layoutStyles.test.ts
Normal file
13
tests/layoutStyles.test.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
describe('Toolbox layout styles', () => {
|
||||||
|
it('keeps the PDF workspace aligned to the 90rem shell width', async () => {
|
||||||
|
const stylesheet = await readFile('src/styles.css', 'utf8');
|
||||||
|
const mainRule = stylesheet.match(
|
||||||
|
/\.pdf-toolbox-shell \.toolbox-shell__main\s*\{(?<body>[^}]*)\}/u
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(mainRule?.groups?.body).toMatch(/\bmax-width:\s*90rem\s*;/u);
|
||||||
|
});
|
||||||
|
});
|
||||||
96
tests/releaseArchive.test.ts
Normal file
96
tests/releaseArchive.test.ts
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import { createHash } from 'node:crypto';
|
||||||
|
import { spawnSync } from 'node:child_process';
|
||||||
|
import {
|
||||||
|
mkdir,
|
||||||
|
mkdtemp,
|
||||||
|
readFile,
|
||||||
|
rm,
|
||||||
|
symlink,
|
||||||
|
writeFile,
|
||||||
|
} from 'node:fs/promises';
|
||||||
|
import os from 'node:os';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import {
|
||||||
|
compareCodePoints,
|
||||||
|
collectDirectoryFiles,
|
||||||
|
createThirdPartyLicenseBundle,
|
||||||
|
} from '../scripts/release-archive.mjs';
|
||||||
|
|
||||||
|
describe('release archive helpers', () => {
|
||||||
|
it('sorts archive paths by code point', () => {
|
||||||
|
expect(['z', 'a', 'ä'].sort(compareCodePoints)).toEqual(['a', 'z', 'ä']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates identical ZIP bytes in different process timezones', () => {
|
||||||
|
const hashes = ['UTC', 'Europe/Berlin', 'America/New_York'].map(
|
||||||
|
(timezone) => {
|
||||||
|
const script = `
|
||||||
|
import { createHash } from 'node:crypto';
|
||||||
|
import { createDeterministicZip } from './scripts/release-archive.mjs';
|
||||||
|
const archive = createDeterministicZip({
|
||||||
|
'z.txt': Buffer.from('last'),
|
||||||
|
'a.txt': Buffer.from('first'),
|
||||||
|
});
|
||||||
|
process.stdout.write(createHash('sha256').update(archive).digest('hex'));
|
||||||
|
`;
|
||||||
|
const result = spawnSync(
|
||||||
|
process.execPath,
|
||||||
|
['--input-type=module', '--eval', script],
|
||||||
|
{
|
||||||
|
cwd: process.cwd(),
|
||||||
|
encoding: 'utf8',
|
||||||
|
env: { ...process.env, TZ: timezone },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(result.status, result.stderr).toBe(0);
|
||||||
|
return result.stdout;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(new Set(hashes)).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('collects installed runtime license and notice texts', async () => {
|
||||||
|
const bundle = await createThirdPartyLicenseBundle(process.cwd(), [
|
||||||
|
'react',
|
||||||
|
'pdfjs-dist',
|
||||||
|
'@add-ideas/toolbox-contract',
|
||||||
|
]);
|
||||||
|
const text = bundle.toString('utf8');
|
||||||
|
expect(text).toContain('react@');
|
||||||
|
expect(text).toContain('pdfjs-dist@');
|
||||||
|
expect(text).toContain('@add-ideas/toolbox-contract@');
|
||||||
|
expect(createHash('sha256').update(bundle).digest('hex')).toMatch(
|
||||||
|
/^[a-f0-9]{64}$/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects symbolic links in release input', async () => {
|
||||||
|
const temporaryDirectory = await mkdtemp(
|
||||||
|
path.join(os.tmpdir(), 'pdf-tools-release-')
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
const outsideFile = path.join(temporaryDirectory, 'outside.txt');
|
||||||
|
const inputDirectory = path.join(temporaryDirectory, 'input');
|
||||||
|
await writeFile(outsideFile, 'private');
|
||||||
|
await mkdir(inputDirectory);
|
||||||
|
await symlink(outsideFile, path.join(inputDirectory, 'linked.txt'));
|
||||||
|
|
||||||
|
await expect(collectDirectoryFiles(inputDirectory)).rejects.toThrow(
|
||||||
|
'Unsupported filesystem entry in release input: linked.txt'
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
await rm(temporaryDirectory, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('carries the embedded core-js license used by the PDF.js legacy build', async () => {
|
||||||
|
const license = await readFile(
|
||||||
|
'licenses/core-js-3.49.0-LICENSE.txt',
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
expect(license).toContain('core-js 3.49.0');
|
||||||
|
expect(license).toContain('CoreJS Company');
|
||||||
|
expect(license).toContain('Permission is hereby granted');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,9 +2,10 @@ import { defineConfig } from 'vite';
|
|||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
base: './',
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
host: true,
|
host: true,
|
||||||
allowedHosts: ['pdftools.add-ideas.de'], // ← ADD THIS
|
allowedHosts: ['pdftools.add-ideas.de'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user