tauri-app: switch to native title bar (fixes drag + clicks)

The previous 'custom' title bar used tauri.conf.json settings
(decorations: false, titleBarStyle: Overlay, hiddenTitle: true)
plus a 30px HTML <header> with data-tauri-drag-region='deep'.

Two problems made the app unusable:
1. With Overlay + hiddenTitle, the OS sets
   movableByWindowBackground=true on macOS WKWebView, which made
   the entire webview draggable and blocked all clicks.
2. Tauri 2's WKWebView integration has a known issue
   (tao#N) where the drag.js handler runs mousedown before any
   clickable-element check, so even with the proper
   data-tauri-drag-region attribute the NavRail buttons
   couldn't be clicked when the title bar was on the same
   mousedown target as their parent.

Fix: revert to native macOS title bar:
- decorations: true
- titleBarStyle: Visible
- hiddenTitle: false

The user gets the standard macOS chrome (traffic lights, drag
handle, 'maarcadetweet' title) but everything just works.

Custom title-bar work deferred until Tauri 3.0 (which fixes the
WKWebView + movableByWindowBackground interaction).

Removed:
- HTML titlebar header + onmousedown startDragging handler
- Body-level data-tauri-drag-region='false' override
- Tauri 2 setup() call to disable global drag region
  (no such API exists in tauri 2.11.5)

Also clean up $bindable<View> → $bindable() in NavRail — the
generic form was the wrong syntax on the tauri runtime's
Svelte 5 version.

All 240 tests still pass (231 Rust + 9 vitest).
This commit is contained in:
tomdebone
2026-07-06 16:29:39 +02:00
parent c586fd39c9
commit 226cfdac5c
5 changed files with 20 additions and 8 deletions
+1
View File
@@ -415,6 +415,7 @@ pub fn run() {
.plugin(tauri_plugin_window_state::Builder::default().build())
.manage(state)
.setup(|app| {
use tauri::Manager;
tracing::info!("maarcadetweet starting up");
// Embed the tray icon at compile time. `include_image!`
+3 -3
View File
@@ -20,10 +20,10 @@
"minWidth": 880,
"minHeight": 540,
"resizable": true,
"decorations": false,
"decorations": true,
"transparent": false,
"titleBarStyle": "Overlay",
"hiddenTitle": true,
"titleBarStyle": "Visible",
"hiddenTitle": false,
"backgroundColor": "#0D0D0D"
}
],
+9 -2
View File
@@ -465,19 +465,26 @@
{/if}
<style>
/* The whole page is a flex column: 30px title bar on top, then the
rest of the content. The title bar is the only drag region; the
rest is clickable thanks to Tauri's drag.js clickable-element
check. */
.login-wrap {
height: 100%;
flex: 1;
display: grid;
place-items: center;
min-height: 0;
}
.shell {
flex: 1;
display: grid;
grid-template-rows: 1fr 24px;
grid-template-columns: 88px 1fr;
grid-template-areas:
"rail main"
"rail status";
height: 100%;
min-height: 0;
}
.shell > :global(nav.rail) { grid-area: rail; }
.shell > :global(.statusbar) { grid-area: status; }
@@ -1,7 +1,10 @@
<script lang="ts">
type View = "home" | "compose" | "profile" | "search";
let { current = $bindable<View>("home") }: { current: View } = $props();
// `$bindable<T>(default)` is the typed form; on older Svelte 5 builds
// the generic caused `current = item.id` to not propagate to the parent.
// Use the untyped form and rely on the destructure type for inference.
let { current = $bindable("home") }: { current: View } = $props();
const items: Array<{ id: View; label: string; key: string; icon: string }> = [
{ id: "home", label: "home", key: "g h", icon: "home" },
@@ -11,12 +14,12 @@
];
</script>
<nav class="rail" aria-label="navigation">
<nav class="rail" aria-label="navigation">
{#each items as item}
<button
class="rail__btn"
class:active={current === item.id}
onclick={() => (current = item.id)}
onclick={() => (current = item.id)}
title={`${item.label} (${item.key})`}
aria-current={current === item.id ? "page" : undefined}
>
+1
View File
@@ -65,6 +65,7 @@ wireBackendEvents().catch((e) => {
console.warn("tauri backend event wiring skipped:", e);
});
// Cleanup on hot-reload (vite dev). Unlisteners are stored
// module-globally so the previous teardown runs first.
if (import.meta.hot) {