Skip to content

Tauri desktop shell (spike) and remove Electron - #143

Closed
rdrake wants to merge 8 commits into
evilnet:developfrom
rdrake:feat/desktop-shells
Closed

rdrake wants to merge 8 commits into
evilnet:developfrom
rdrake:feat/desktop-shells

Conversation

@rdrake

@rdrake rdrake commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

Adds a Tauri v2 desktop shell for Windows, macOS and Linux, and removes the unused Electron wrapper. The plan is docs/projects/desktop-shells.md.

What's in it

  1. Plan (docs/projects/desktop-shells.md): Tauri v2 on all three, each OS's own web view (WebView2, WKWebView, WebKitGTK), macOS-only plugins in Swift. Linux steps down where WebKitGTK can't carry a feature. Closing the window follows each platform. Signed direct downloads, no app stores.
  2. Remove the Electron shell. Nothing in the client read its bridge, and nothing is carried over. Docs that named it now say "app shell" or Tauri, and initial_conversion.md E.4a is open again.
  3. Connect form fix. Connect read its query only once, when it first appeared. A link arriving while the form was open changed the route but left the old values, and Cancel on a link dialog stayed on the dialog. The installed PWA's warm launches hit this too. The Connect route is now keyed on its full path; no other route changes. link-approval.mjs raced (it treated the autojoin placeholder row as proof the socket was open) and now waits for the socket itself.
  4. One bridge for every shell. helpers/capacitor.ts becomes helpers/shell.ts:
    • A desktop shell provides window.seanceShell ({platform, version, call, listen}); window.Capacitor is adapted to the same contract.
    • isShell / isMobileShell / isDesktopShell sit beside the iOS and Android checks.
    • Haptics, the status bar, the splash, the system text size and the back button are phone-only; links and the badge are every shell's.
    • A desktop shell sets data-shell="desktop" (never native) and registers no service worker.
    • In a desktop shell, the system's light/dark mode is followed by default; text size isn't.
  5. Tauri shell, a spike (shells/tauri):
    • public/ is compiled in and served as the app's own origin, with a strict CSP; the page can't navigate outside the app.
    • Window state is remembered, only one instance runs, and web+irc: links arrive through deep-link or a second launch's argv, with no reload.
    • One seance_call command answers App and Badge; no Tauri plugin API is exposed to the page.
    • Closing the window: the app stays in the Dock on macOS and in the notification area on Windows; Linux quits.
  6. CLAUDE.md gets a shells/ entry naming the bridge.

Testing

  • Lint, tsc and mocha (3,556 passing) on develop c1f633f, plus 12 new tests for the bridge and platform defaults (test/helpers/shell.ts).
  • On macOS 27 and Linux (Debian bookworm, WebKitGTK 4.1, Docker + Xvfb):
    • corepack yarn smoke checks the bridge, a missing plugin answering unimplemented, data-shell, no service worker, and a warm web+irc: link with no reload.
    • tools/shots-macos.sh / tools/shots-linux.sh walk through, against the dev ircd: connect, join, send, Settings, and a second launch's link. Both pass.
  • Origin is tauri://localhost on both. A release .app is 10 MB.
  • link-approval.mjs passes 4/4, at desktop and phone size.
  • An iPhone build of the bridge (on the phone branch) is installed but not yet exercised by hand.

Not done

  • Windows has never been run.
  • No desktop notifications yet. WKWebView has no Notification API, so they need the LocalNotifications plugin (gate 4).
  • Web push still prompts in a desktop shell, and subscribing fails there.
  • The connect form's "Browser notifications" label is wrong in a shell.
  • Signing, the updater and installers aren't done.
  • Debug and installed builds keep localStorage in different places, so they don't share data.
  • Behaviour change: a desktop shell follows the system's light/dark mode by default.

One shell on the major three, the system web view on each, macOS plugins in
Swift called from Rust. Linux steps down where WebKitGTK cannot carry a
feature; closing the window follows each platform; signed direct downloads.
Step 1 is a shell-neutral bridge, so every shell answers the same contract.
It was a wrapper nobody used: nothing in the client read its bridge, and the
desktop app is Tauri now (docs/projects/desktop-shells.md). Nothing is carried
over. The docs that named it say app shell, or Tauri, instead; E.4a is open
again until the Tauri shell ships.
Connect reads its query once, as it is set up, so a warm link (a PWA launch,
a shell's appUrlOpen) arriving while the form was open changed the route and
left the form as it was, and Cancel on a link back to the plain form stayed
the link dialog. The Connect route is keyed on its full path: a new query is
a new form. Every other route keeps its component.

link-approval.mjs took the #seance sidebar row as proof of a dial, but an
autojoin channel is a placeholder before the socket opens; it waits for the
socket itself.
helpers/capacitor.ts becomes helpers/shell.ts: window.seanceShell
({platform, version, call, listen}) for a desktop shell, window.Capacitor
adapted to the same contract on the phones, and isShell / isMobileShell /
isDesktopShell beside isIOSShell / isAndroidShell. Haptics, the status bar,
the splash, the system text size and the back button are the phones'; links
and the badge are every shell's. A desktop shell sets data-shell=desktop and
its platform, never native (the phones' safe-area and keyboard CSS), follows
the system's appearance by default but not its text size, and registers no
service worker (pwa.ts, and the early registration in
loading-error-handlers.js).
shells/tauri, Tauri v2: the built public/ compiled in and served as the app's
own origin, a strict CSP, navigation kept inside the app, window state, one
instance, and web+irc: links through deep-link and a second launch's argv.
window.seanceShell comes from a frozen init script and one seance_call
command answers App (getLaunchUrl, appUrlOpen) and Badge; no Tauri plugin API
is exposed to the page. Closing the window follows the platform: the Dock on
macOS, the notification area on Windows, quit on Linux.

A debug build's --smoke checks the bridge and a warm link from inside the
page; tools/shots-macos.sh (WKWebView snapshots) and tools/shots-linux.sh
(Docker, Xvfb, WebKitGTK) walk through connect, join, send, Settings and a
second launch's link against the dev ircd. Both pass on macOS and Linux; a
release .app is 10 MB.
@Josephur

Copy link
Copy Markdown
Contributor

Doh I just submitted spell check fix for electron, LOL. And I'm adding scripting support to add context menus, but I can fix both I suppose if this is adopted.

`tauri dev` serves public/ from the CLI's dev server, which the window's
navigation guard did not count as the app: the start page was handed to
the default browser and the window stayed blank. Under `tauri dev` the
dev server's origin (build.devUrl, which the CLI fills in) is the app's
too; a release build still knows only tauri://localhost.
Only the phone shells have a system text size to follow. On a desktop the
toggle did nothing, said to look in Android's settings, and while it was on
hid the font-size slider.
@rdrake

rdrake commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator Author

Closing for now: the desktop shell work has moved well past this branch and will come back as a fresh PR once it's further along. (The Electron spellcheck menu from #144 has been ported to the Tauri shell there.)

@rdrake rdrake closed this Nov 2, 2026
@rdrake
rdrake deleted the feat/desktop-shells branch November 2, 2026 13:54

This branch was previously deployed

1 inactive deployment
github-pages — 234254c0 Deployed Nov 2, 2026 by rdrake via deploy #402
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants