Skip to content

Commit b0de742

Browse files
committed
release: v1.1.0
Features: - DuckDuckGo search fallback in URL bar - Back/Forward/Refresh navigation buttons - Persistent bookmarks (star toggle, dropdown, max 50) - Window title from page title (MutationObserver + polling) - Config file backup (.bak) before each write - Periodic geometry auto-save (every 30s) - Clear site data (cookies, localStorage, sessionStorage) Cleanup: - Removed unused deps (directories, webview2-com) - Removed dead config fields (audio_device_id, launch_at_startup) - eprintln → tracing warn/error - Fixed error page regex for smart quotes Generated with Crush Assisted-by: GLM-5.1 via Crush <crush@charm.land>
1 parent 64a5147 commit b0de742

57 files changed

Lines changed: 466 additions & 153 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ Guide for AI agents working on the FloatView codebase.
44

55
## Project Overview
66

7-
FloatView is a Tauri v2 application that provides a floating browser window for streaming media on secondary monitors. Key features include always-on-top, borderless resizable window, opacity control, and click-through mode.
7+
FloatView is a Tauri v2 application that provides a floating browser window for streaming media on secondary monitors. Key features include always-on-top, borderless resizable window, opacity control, click-through mode, persistent bookmarks, navigation controls, smart URL bar with DuckDuckGo search, window title tracking, crash recovery (config backup + periodic geometry auto-save), and clear site data.
88

99
## Tech Stack
1010

1111
- **Runtime**: Tauri v2 (Rust backend)
1212
- **Rendering**: WebView2 (system webview on Windows)
1313
- **Frontend**: Vanilla HTML/JS (minimal, injected Shadow DOM)
14-
- **Plugins**: single-instance, global-shortcut, shell, tray-icon
14+
- **Plugins**: single-instance, global-shortcut, shell, tray-icon, log
1515

1616
## Prerequisites
1717

@@ -26,6 +26,7 @@ npm install # Install dependencies
2626
npm run dev # Development mode with hot reload
2727
npm run build # Build production release
2828
cd src-tauri && cargo check # Type-check Rust only
29+
cd src-tauri && cargo test # Run unit tests (5 tests)
2930
```
3031

3132
## Project Structure
@@ -91,13 +92,52 @@ The drag bar uses `-webkit-app-region: drag` for native WebView2 drag handling.
9192

9293
## Key Patterns
9394

95+
### Tauri Commands (IPC)
96+
97+
| Command | Purpose | File |
98+
|---------|---------|------|
99+
| `navigate_url` | Navigate to a URL | `main.rs:680` |
100+
| `navigate_home` | Navigate to home URL | `main.rs:751` |
101+
| `toggle_always_on_top` | Toggle pin state | `main.rs` |
102+
| `toggle_locked` | Toggle click-through | `main.rs` |
103+
| `set_opacity` | Set window opacity | `main.rs` |
104+
| `minimize_window` | Minimize window | `main.rs` |
105+
| `get_config` | Read current config | `main.rs` |
106+
| `update_config` | Update config fields | `main.rs` |
107+
| `set_home_url` | Set the home page URL | `main.rs` |
108+
| `clear_recent_urls` | Clear recent URL list | `main.rs` |
109+
| `clear_bookmarks` | Clear all bookmarks | `main.rs` |
110+
| `clear_site_data` | Clear cookies/storage then reload | `main.rs` |
111+
| `set_window_title` | Set window title (truncated to 256 chars) | `main.rs:702` |
112+
| `add_bookmark` | Add URL to bookmarks (dedup, max 50) | `main.rs:718` |
113+
| `remove_bookmark` | Remove URL from bookmarks | `main.rs:736` |
114+
115+
All commands require an auth token (`token` param) via `authorize_command()`.
116+
117+
### Config Struct (`config.rs`)
118+
119+
```rust
120+
pub struct AppConfig {
121+
pub window: WindowConfig, // x, y, width, height, monitor, always_on_top, opacity, locked
122+
pub last_url: Option<String>,
123+
pub recent_urls: Option<Vec<String>>,
124+
pub hotkeys: HotkeyConfig,
125+
pub home_url: String,
126+
pub first_run: bool,
127+
pub auto_refresh_minutes: u32,
128+
pub bookmarks: Vec<String>, // new in v1.1
129+
}
130+
```
131+
94132
### Adding a Tauri Command
95133

96134
1. Add function with `#[tauri::command]` attribute in `main.rs`
97135
2. Add to `invoke_handler!` macro
98136
3. Add required permissions in `capabilities/default.json`
99137
4. Call from JS via `invoke('command_name', { args })`
100138

139+
All commands must accept a `token: String` parameter and call `authorize_command(&state, &token, "command_name")?`.
140+
101141
### Adding a Global Hotkey
102142

103143
1. Add to `HotkeyConfig` in `config.rs`
@@ -112,6 +152,24 @@ Edit `src-tauri/src/injection.js`. The script:
112152
- Uses `MutationObserver` to survive page DOM changes
113153
- Re-initializes on every navigation (guarded by `window.__floatViewInitialized`)
114154

155+
Control strip layout (v1.1):
156+
```
157+
┌─────────────────────────────────────────────────────┐
158+
│ ← → ⟳ ★ [URL bar - DDG search fallback] 📌 🔒 ⚙ — ✕ │
159+
└─────────────────────────────────────────────────────┘
160+
```
161+
162+
Buttons: back, forward, refresh, bookmark star (click toggle, right-click dropdown), always-on-top pin, lock, settings, minimize, close.
163+
164+
Key injection.js features:
165+
- **URL bar**: DuckDuckGo search fallback for non-URL input
166+
- **Bookmarks**: Star toggle + right-click dropdown, fuzzy URL matching via `urlsMatch()`
167+
- **Navigation**: `history.back()`, `history.forward()`, `location.reload()`
168+
- **Title tracking**: MutationObserver + 2s polling → `set_window_title`
169+
- **URL tracking**: `popstate` + 3s polling for address bar sync
170+
- **Config sync**: `config-changed` event listener updates bookmarks in real-time
171+
- **Dropdown mutual exclusion**: recent/bookmarks/snap dropdowns dismiss each other
172+
115173
## Gotchas
116174

117175
1. **Invoke, don't call window methods** -- `getCurrentWindow().method()` is unreliable from injected scripts. Always create a Rust command and use `invoke()`.
@@ -128,16 +186,30 @@ Edit `src-tauri/src/injection.js`. The script:
128186

129187
7. **Single Instance** -- `tauri-plugin-single-instance` brings existing window to front if user launches again.
130188

189+
8. **Config backup** -- `save_config()` creates a `.bak` copy before writing. Used for crash recovery.
190+
191+
9. **Periodic geometry auto-save** -- Background thread saves window position/size every 30s (skips minimized/maximized). Prevents geometry loss on crash.
192+
193+
10. **Bookmark limits** -- Max 50 bookmarks, deduplication by normalized URL, sanitized via `sanitize_config()`.
194+
195+
11. **Title truncation** -- `set_window_title` truncates titles >256 chars to prevent Win32 issues.
196+
197+
12. **Logging** -- Uses `tracing` crate (`warn!`, `error!`) instead of `eprintln!` for structured logging.
198+
131199
## Testing
132200

133-
No automated tests. Test manually:
201+
5 unit tests in `src-tauri/` (run via `cargo test`). Test manually:
134202

135203
1. `npm run dev`
136-
2. Test URL navigation (landing page + control strip URL bar)
204+
2. Test URL navigation (landing page + control strip URL bar + DDG search fallback)
137205
3. Test always-on-top toggle (hotkey + tray + settings + strip button)
138206
4. Test opacity (hotkey + slider + settings)
139207
5. Test click-through mode (enter via hotkey, exit via hotkey AND tray menu)
140208
6. Test drag (from top bar), resize (from edges), minimize, close
141209
7. Test system tray (left-click show/hide, right-click menu items)
142210
8. Test persistence (close and reopen, verify state restored)
143211
9. Test on external pages (navigate to a real site, verify all controls still work)
212+
10. Test back/forward/refresh buttons work on navigated pages
213+
11. Test bookmark star (toggle on/off, right-click dropdown shows list)
214+
12. Test clear site data (Settings button, verify cookies/storage cleared)
215+
13. Test window title updates when navigating between pages

README.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,17 @@ Open **Settings** (gear icon in the control strip, or right-click the tray icon)
3535
Move your mouse to the **top edge** of the window. A dark control strip slides down with all your controls:
3636

3737
```
38-
[Pin] [Recent] [Home] [________URL bar________] [Lock] [Snap] [Crop] | [Opacity] [Settings] [-] [x]
38+
[←] [→] [⟳] [Pin] [Recent] [Home] [________URL bar________] [★] [Lock] [Snap] [Crop] | [Opacity] [Settings] [-] [x]
3939
```
4040

41+
- **Back** -- Go back in history
42+
- **Forward** -- Go forward in history
43+
- **Refresh** -- Reload the current page
4144
- **Pin** -- Toggle always-on-top
4245
- **Recent** -- Dropdown of your recent URLs
4346
- **Home** -- Navigate to your configured home URL
44-
- **URL bar** -- Shows current URL, type a new one and press Enter to navigate
47+
- **URL bar** -- Shows current URL, type a new one and press Enter to navigate (non-URL input searches DuckDuckGo)
48+
- **Bookmark (★)** -- Bookmark/unbookmark the current page (right-click to open bookmarks list)
4549
- **Lock** -- Toggle click-through mode (clicks pass through the window)
4650
- **Snap** -- Snap the window to a screen corner or center
4751
- **Crop** -- Crop and zoom into a region of the page
@@ -96,17 +100,23 @@ Press `Alt+Shift+D` to make the window completely transparent to mouse clicks --
96100
- **Adjustable Opacity** -- 10% to 100% transparency via slider or hotkeys
97101
- **Click-Through Mode** -- Window becomes invisible to mouse input
98102
- **Configurable Home URL** -- Set your default page; navigate back with the Home button
103+
- **Smart URL Bar** -- Enter a URL to navigate, or type a search query to search DuckDuckGo
104+
- **Bookmarks** -- Save favorite pages; star icon toggles bookmark, right-click for list
105+
- **Navigation Controls** -- Back, forward, and refresh buttons in the control strip
99106
- **First-Run Tutorial** -- Interactive onboarding for new users
100107
- **Borderless & Resizable** -- Clean look with native resize handles
101108
- **HDR Support** -- Uses system webview for correct HDR rendering (unlike Electron)
102109
- **Shadow DOM Control Strip** -- Injected UI that never breaks the page you're viewing
103110
- **Persistent State** -- Remembers window position, size, opacity, and last URL across restarts
111+
- **Crash Recovery** -- Geometry auto-saved every 30 seconds; config backed up on write
104112
- **System Tray** -- Minimize to tray, quick controls via right-click menu
105113
- **Global Hotkeys** -- Control everything without switching focus
106114
- **Single Instance** -- Opening FloatView again brings the existing window to front
107115
- **Snap to Corners** -- Quickly position the window at any screen corner or center
108116
- **Crop/Zoom** -- Select and zoom into a region of the page for focused viewing
109117
- **Auto-Refresh** -- Automatically reload the page on a configurable interval (1 min to 1 hour)
118+
- **Window Title** -- Title bar updates to match the current page
119+
- **Clear Site Data** -- Clear cookies, localStorage, and sessionStorage from settings
110120
- **In-App Updates** -- Check from Settings, install from tray menu
111121
- **Cross-Platform** -- Windows and macOS
112122
- **Tiny Footprint** -- ~3MB binary, uses system webview
@@ -136,6 +146,7 @@ You can edit the file directly to customize hotkeys or other settings:
136146
"home_url": "https://www.google.com",
137147
"first_run": false,
138148
"auto_refresh_minutes": 0,
149+
"bookmarks": [],
139150
"hotkeys": {
140151
"toggle_on_top": "Alt+Shift+T",
141152
"toggle_locked": "Alt+Shift+D",
@@ -186,7 +197,7 @@ src/index.html -- Landing page (URL input)
186197
src-tauri/src/main.rs -- Rust backend (commands, hotkeys, tray, platform interop)
187198
src-tauri/src/config.rs -- Config types with serde
188199
src-tauri/src/opacity.rs -- Cross-platform opacity management
189-
src-tauri/src/injection.js -- Shadow DOM control strip + tutorial (~1900 lines)
200+
src-tauri/src/injection.js -- Shadow DOM control strip + tutorial (~2300 lines)
190201
```
191202

192203
### Why not Electron?
@@ -207,7 +218,6 @@ Configuration files are stored separately and not removed by default:
207218

208219
- **Click-through mode is invisible** -- The control strip hides; use hotkey or tray to exit
209220
- **Always-on-top vs fullscreen** -- Cannot overlay exclusive fullscreen games/apps
210-
- **No audio device routing** -- WebView's `setSinkId()` requires HTTPS origins
211221
- **macOS** -- Some global hotkey combinations may conflict with system shortcuts
212222

213223
## Privacy

designdoc.md

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# FloatView — Technical Design Document (v3)
1+
# FloatView — Technical Design Document (v3, updated for v1.1.0)
22

33
## Overview
44

@@ -196,7 +196,8 @@ The ideal path is the web-standard `setSinkId()` API on `HTMLMediaElement`. Chro
196196
- Minimize to tray
197197
- Quick access: toggle always-on-top, opacity, locked/unlocked mode
198198
- Recent URLs
199-
- Launch at startup option
199+
- Clear bookmarks
200+
- Clear site data
200201

201202
### 7. Global Hotkeys
202203

@@ -222,18 +223,18 @@ The injected control strip is `position: fixed` at the top of the viewport. It d
222223
On hover (with ~500ms dwell during video playback to prevent accidental triggers), the strip expands to ~40px and reveals controls:
223224

224225
```
225-
┌──────────────────────────────────────────────┐
226-
📌 192.168.1.XXX:8096/web/... 🔓 ⚙ — ✕ │ ← injected Shadow DOM strip
227-
├──────────────────────────────────────────────┤
228-
│ │
229-
│ (page content: Emby etc) │
230-
│ │
231-
└──────────────────────────────────────────────┘
226+
┌──────────────────────────────────────────────────────────
227+
← → ⟳ ★ [URL bar - DDG search fallback] 📌 🔒 ⚙ — ✕ │ ← injected Shadow DOM strip
228+
├──────────────────────────────────────────────────────────
229+
230+
(page content: Emby etc)
231+
232+
└──────────────────────────────────────────────────────────
232233
```
233234

234-
Controls: always-on-top pin, URL display (click to edit), lock toggle, settings gear (audio, preferences), minimize, close.
235+
Controls: back, forward, refresh, bookmark star (click to toggle, right-click for dropdown list), always-on-top pin, URL display (click to edit, non-URL input searches DuckDuckGo), lock toggle, settings gear (audio, preferences, clear site data, clear bookmarks), minimize, close.
235236

236-
Communication: injected JS calls `window.__TAURI__.invoke('command_name', { args })` to talk to the Rust backend. Tauri commands handle window manipulation, config persistence, audio device enumeration, etc.
237+
Communication: injected JS calls `window.__TAURI__.invoke('command_name', { args })` to talk to the Rust backend. Tauri commands handle window manipulation, config persistence, bookmark management, title updates, site data clearing, etc.
237238

238239
### Locked/Unlocked State Model (Click-Through)
239240

@@ -300,18 +301,25 @@ Unsigned Windows binaries trigger SmartScreen warnings and may face friction in
300301
},
301302
"last_url": "http://192.168.1.XXX:8096",
302303
"recent_urls": [],
303-
"audio_device_id": null,
304-
"launch_at_startup": false,
304+
"bookmarks": [],
305+
"home_url": "https://www.google.com",
306+
"first_run": true,
307+
"auto_refresh_minutes": 0,
305308
"hotkeys": {
306309
"toggle_on_top": "Alt+Shift+T",
307310
"toggle_locked": "Alt+Shift+D",
308311
"opacity_up": "Alt+Shift+Up",
309312
"opacity_down": "Alt+Shift+Down",
310-
"toggle_visibility": "Alt+Shift+H"
313+
"toggle_visibility": "Alt+Shift+H",
314+
"media_play_pause": "Alt+Shift+Space",
315+
"media_next": "Alt+Shift+Right",
316+
"media_previous": "Alt+Shift+Left"
311317
}
312318
}
313319
```
314320

321+
Config is backed up to `config.json.bak` before each write. Window geometry is auto-saved every 30 seconds (skipping minimized/maximized states) via a background thread to prevent geometry loss on crash.
322+
315323
## Development Phases
316324

317325
### Phase 0 — Spikes & Validation

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "floatview",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "A minimal floating browser window for streaming media on a secondary monitor",
55
"scripts": {
66
"tauri": "tauri",

0 commit comments

Comments
 (0)