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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/workflows/build_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ jobs:
matrix:
include:
- os: macos-latest
app: src-tauri/target/release/opendocument-desktop
- os: windows-latest
app: src-tauri/target/release/opendocument-desktop.exe
- os: ubuntu-24.04
app: src-tauri/target/release/opendocument-desktop
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
Expand All @@ -26,7 +29,7 @@ jobs:
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libxdo-dev
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libxdo-dev xvfb

- uses: actions/setup-node@v5
with:
Expand All @@ -43,6 +46,14 @@ jobs:
- run: npm run check
- run: npx tauri build

# Opens every file in test/documents in the built app, and saves a copy.
- name: Smoke test
if: runner.os != 'Linux'
run: node test/smoke.mjs ${{ matrix.app }}
- name: Smoke test
if: runner.os == 'Linux'
run: xvfb-run -a node test/smoke.mjs ${{ matrix.app }}

- uses: actions/upload-artifact@v5
with:
name: bundle-${{ matrix.os }}
Expand Down
44 changes: 44 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,50 @@ The frontend owns the user interface, and it runs the core.
The renderer is [OpenDocument.core](https://github.com/opendocument-app/OpenDocument.core).
Unsupported formats and rendering bugs belong there, not here.

## Architecture

```
src/core/backend.ts the Backend interface: the only way to the core
src/core/wasm-*.ts the Backend over the WebAssembly core, in a Web Worker
src/viewer/viewer.ts one window: open, render, tabs, search, zoom, edit, save, print
src/viewer/frame-bridge.js runs inside the rendered document, talks over postMessage
src/platform.ts files, dialogs, menus, recents: everything from Tauri
src-tauri/src/lib.rs file access, window routing, print windows, smoke mode
src-tauri/src/menu.rs the menu bar; a click is a `menu` event to the focused window
```

- **The engine is behind `Backend`.** The viewer calls nothing else of the
core. A native backend, for example the core's HTTP server as a sidecar, can
replace the WebAssembly one without a change to the viewer.
- **The viewer comes from the website.** `viewer.ts` and `frame-bridge.js` are
ports of `src/scripts/` in OpenDocument.web. A fix in one is usually a fix in
the other. The rendered document runs in a `sandbox="allow-scripts"` frame
with an opaque origin, so it cannot reach Tauri.
- **One document per window.** A file that arrives while a window holds a
document opens a new window. On macOS the system sends files with
`RunEvent::Opened`, on Windows and Linux a second launch hands its arguments
to the first through the single-instance plugin.
- **A save writes a temporary file beside the target and renames it over the
target**, so a failed save never leaves half a document.
- **Print renders the view again** with every part laid out, and a `print-*`
window shows it as a top-level page. On macOS, Tauri prints only a top-level
page, not a frame. The print windows get no file access.
- **The CSP keeps `'unsafe-inline'`**, because the srcdoc frame takes the
policy of its parent and the renderer writes inline scripts and styles.
`dangerousDisableAssetCspModification` stops Tauri from adding hashes, which
would switch `'unsafe-inline'` off.
- **No Undo item in the menu.** The page owns its edit log and takes the undo
chord itself.
- **No edition gate, no ads, no store.** How the desktop app earns money is
not decided yet.

## Checks

- `npm run check` type-checks the frontend.
- `node test/smoke.mjs <app binary>` opens every file in `test/documents/` in
the built app and saves a copy. CI runs it on all three systems. A file named
`*-<password>.<ext>` opens with that password.

## Rules

- The app compiles no C++. It uses the WebAssembly build of the core from npm,
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ Before a release, a pull request changes that heading to the version.

## Unreleased

- The first version of OpenDocument Reader for Windows, macOS and Linux.
- The first version of OpenDocument Reader for Windows, macOS and Linux. It opens
OpenDocument, Word, Excel, PowerPoint, PDF, Pages, Numbers, Keynote and more,
also with a password.
- Edit and save text documents, spreadsheets and presentations, and mark up PDFs.
- Search, zoom, print, a tab for each sheet, recent documents, and new empty
documents.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ npm run tauri dev # starts the app with hot reload
npm run tauri build # writes the installers to src-tauri/target/release/bundle/
```

`npm run check` type-checks the frontend.
`npm run check` type-checks the frontend. After a build,
`node test/smoke.mjs src-tauri/target/release/opendocument-desktop` opens each
document in `test/documents/` in the app and saves a copy.

## Layout

Expand All @@ -29,6 +31,7 @@ npm run tauri build # writes the installers to src-tauri/target/release/bundle
| `src/` | the frontend: TypeScript, Vite and Tailwind |
| `src-tauri/` | the Rust shell: windows, menus, file access, bundling |
| `scripts/sync-odr.mjs` | copies the core from `node_modules` into `public/odr/` |
| `test/` | the smoke test and its documents |

[`AGENTS.md`](AGENTS.md) describes the architecture and the rules.

Expand Down
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>OpenDocument Reader</title>
<link rel="stylesheet" href="/src/styles.css" />
</head>
<body class="overflow-hidden">
<div id="app" class="flex h-screen flex-col"></div>
Expand Down
12 changes: 11 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"dependencies": {
"@opendocument/odr-core": "^7.7.0",
"@tauri-apps/api": "^2.12.4",
"@tauri-apps/plugin-dialog": "^2.8.4"
"@tauri-apps/plugin-dialog": "^2.8.4",
"@tauri-apps/plugin-opener": "^2.7.2"
},
"devDependencies": {
"@tailwindcss/vite": "^4.3.3",
Expand Down
10 changes: 10 additions & 0 deletions print.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Print</title>
</head>
<body>
<script type="module" src="/src/print.ts"></script>
</body>
</html>
Loading
Loading