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
14 changes: 3 additions & 11 deletions .github/workflows/ui-tests.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
name: UI Tests (Playwright + tauri-driver)
name: UI Tests

on:
push:
branches: [ main ]
branches: [ master ]
pull_request:

jobs:
Expand All @@ -16,19 +16,11 @@ jobs:
with:
node-version: '22'

- name: Set up Rust
uses: dtolnay/rust-toolchain@stable

- name: Install JS deps
run: npm install --no-fund

- name: Install Playwright browsers
run: npx playwright install --with-deps

- name: Install tauri-driver
run: cargo install tauri-driver --locked

- name: Run Playwright tests
env:
PATH: "$HOME/.cargo/bin:${PATH}"
- name: Run Playwright smoke tests
run: npm run test:ui
26 changes: 13 additions & 13 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "always-on-top"
name = "float"
version = "0.1.0"
edition = "2021"
description = "Float - minimal utility to keep a window always on top."
Expand Down
Binary file added dist/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dist/favicon.ico
Binary file not shown.
85 changes: 83 additions & 2 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<meta charset="utf-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' tauri: asset: file: data: blob: filesystem:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; connect-src 'self' ipc:">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<title>Float</title>
<style>
html, body { height: 100%; margin: 0; font-family: -apple-system, system-ui, Segoe UI, Roboto, Arial, sans-serif; background: #111; color: #ccc; }
Expand Down Expand Up @@ -41,6 +43,13 @@
<div class="controls no-drag">
<button id="prevBtn" class="btn no-drag" type="button">Previous</button>
<button id="nextBtn" class="btn no-drag" type="button">Next</button>
<button id="slideshowBtn" class="btn no-drag" type="button">Slideshow: Off</button>
<select id="slideshowInterval" class="btn no-drag" aria-label="Slideshow interval">
<option value="2000">2s</option>
<option value="5000" selected>5s</option>
<option value="10000">10s</option>
<option value="15000">15s</option>
</select>
</div>
</div>
<script>
Expand All @@ -58,8 +67,17 @@
const statusEl = document.getElementById('status');
const prevBtn = document.getElementById('prevBtn');
const nextBtn = document.getElementById('nextBtn');
const slideshowBtn = document.getElementById('slideshowBtn');
const slideshowIntervalEl = document.getElementById('slideshowInterval');
const appEl = document.getElementById('app');

const slideshowState = {
enabled: false,
intervalMs: 5000,
total: 0,
};
let slideshowTimer = null;

const defaultPlaceholder = () => {
const platform =
navigator?.userAgentData?.platform ||
Expand All @@ -78,6 +96,42 @@
statusEl.textContent = '';
prevBtn.disabled = true;
nextBtn.disabled = true;
slideshowState.total = 0;
syncSlideshowUi();
stopSlideshow();
};

const stopSlideshow = () => {
if (slideshowTimer) {
clearInterval(slideshowTimer);
slideshowTimer = null;
}
};

const syncSlideshowUi = () => {
if (!slideshowBtn || !slideshowIntervalEl) return;
slideshowBtn.textContent = `Slideshow: ${slideshowState.enabled ? 'On' : 'Off'}`;
slideshowIntervalEl.value = String(slideshowState.intervalMs);
const disabled = slideshowState.total <= 1;
slideshowBtn.disabled = disabled;
slideshowIntervalEl.disabled = disabled;
};

const startSlideshowIfNeeded = () => {
stopSlideshow();
if (!slideshowState.enabled || slideshowState.total <= 1) return;
const interval = Number(slideshowState.intervalMs) || 5000;
slideshowTimer = setInterval(() => {
invoke('next_file');
}, interval);
};

const persistSettings = async (update) => {
try {
await invoke('set_settings', { update });
} catch (err) {
console.warn('Failed to persist settings', err);
}
};

const buildSources = (path) => {
Expand Down Expand Up @@ -141,20 +195,24 @@
const index = payload?.index ?? null;
const total = payload?.total ?? null;
if (!path) {
showPlaceholder();
return;
showPlaceholder();
return;
}
const fileName = path.split(/[\\/]/).pop() || path;
fileInfoEl.textContent = fileName;
if (typeof index === 'number' && typeof total === 'number' && total > 0) {
statusEl.textContent = `File ${index + 1} of ${total}`;
prevBtn.disabled = index <= 0;
nextBtn.disabled = index >= total - 1;
slideshowState.total = total;
} else {
statusEl.textContent = '';
prevBtn.disabled = false;
nextBtn.disabled = false;
slideshowState.total = 0;
}
syncSlideshowUi();
startSlideshowIfNeeded();
showImage(path);
};

Expand All @@ -179,6 +237,13 @@
const bootstrap = async () => {
try {
const settings = await invoke('get_settings');
if (typeof settings?.slideshow_enabled === 'boolean') {
slideshowState.enabled = settings.slideshow_enabled;
}
if (typeof settings?.slideshow_interval_ms === 'number') {
slideshowState.intervalMs = settings.slideshow_interval_ms;
}
syncSlideshowUi();
if (settings?.last_file) {
renderState({ path: settings.last_file });
return;
Expand Down Expand Up @@ -223,6 +288,22 @@
showChrome();
invoke('next_file');
});
slideshowBtn?.addEventListener('click', async () => {
showChrome();
slideshowState.enabled = !slideshowState.enabled;
syncSlideshowUi();
startSlideshowIfNeeded();
await persistSettings({ slideshow_enabled: slideshowState.enabled });
});
slideshowIntervalEl?.addEventListener('change', async () => {
showChrome();
const next = Number(slideshowIntervalEl.value);
if (!Number.isFinite(next) || next < 1000) return;
slideshowState.intervalMs = next;
syncSlideshowUi();
startSlideshowIfNeeded();
await persistSettings({ slideshow_interval_ms: next });
});
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ tauri-build:

# Cross-build Windows release executable from macOS using cargo-xwin
tauri-build-windows:
set -euo pipefail; TARGET="x86_64-pc-windows-msvc"; if ! rustup target list --installed | grep -q "^${TARGET}$"; then rustup target add "${TARGET}"; fi; if ! command -v cargo-xwin >/dev/null 2>&1; then echo "cargo-xwin not found; installing..." >&2; cargo install cargo-xwin --locked; fi; if [ "$(uname -s)" != "Darwin" ]; then echo "tauri-build-windows is intended to run from macOS hosts" >&2; fi; cargo xwin build --release --target "${TARGET}" --manifest-path src-tauri/Cargo.toml; APP_EXE="src-tauri/target/${TARGET}/release/always-on-top-tauri.exe"; FLOAT_EXE="src-tauri/target/${TARGET}/release/Float.exe"; if [ ! -f "${APP_EXE}" ]; then echo "Expected executable not found at ${APP_EXE}" >&2; exit 1; fi; cp "${APP_EXE}" "${FLOAT_EXE}"; echo "Windows executable ready at ${FLOAT_EXE}"
set -euo pipefail; TARGET="x86_64-pc-windows-msvc"; if ! rustup target list --installed | grep -q "^${TARGET}$"; then rustup target add "${TARGET}"; fi; if ! command -v cargo-xwin >/dev/null 2>&1; then echo "cargo-xwin not found; installing..." >&2; cargo install cargo-xwin --locked; fi; if [ "$(uname -s)" != "Darwin" ]; then echo "tauri-build-windows is intended to run from macOS hosts" >&2; fi; cargo xwin build --release --target "${TARGET}" --manifest-path src-tauri/Cargo.toml; APP_EXE="src-tauri/target/${TARGET}/release/float-tauri.exe"; FLOAT_EXE="src-tauri/target/${TARGET}/release/Float.exe"; if [ ! -f "${APP_EXE}" ]; then echo "Expected executable not found at ${APP_EXE}" >&2; exit 1; fi; cp "${APP_EXE}" "${FLOAT_EXE}"; echo "Windows executable ready at ${FLOAT_EXE}"

# Open built macOS .app from Tauri
tauri-open:
Expand Down
4 changes: 2 additions & 2 deletions openspec/changes/rename-project-to-float/proposal.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ rename-project-to-float
## What Changes
- Rebrand the application to "Float" across UI strings (window titles, menus, dialogs) and native metadata.
- Update bundler config and outputs (app bundle/installer names, product metadata) plus documentation and release instructions to use the Float name and paths.
- Adjust identifiers and persisted paths as needed to align with the new name while preserving existing user data.
- Adjust identifiers and persisted paths to align with the new name before first release.

## Scope
- Naming/branding changes only; functionality remains the same.
Expand All @@ -20,4 +20,4 @@ rename-project-to-float
- Platform support changes.

## Open Questions
- Resolved: use the `com.havesomecode` namespace for identifiers/settings; migrate prior data into the Float-branded path.
- Resolved: use the `com.havesomecode` namespace for identifiers/settings; no migration is needed before first release.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The application MUST present the product name as "Float" across UI, metadata, bu
- When they follow build/run instructions or view app details
- Then the product name referenced is "Float" with updated paths/output names, and no "Always On Top" strings remain

#### Scenario: Settings namespace aligns with Float without data loss
- Given existing users have persisted settings under the previous app name
- When launching the renamed app
- Then persisted settings continue working under a Float-branded identifier, migrating prior data if the identifier changed
#### Scenario: Settings namespace uses Float branding
- Given the app stores settings on disk
- When inspecting the settings namespace or config path
- Then it uses the Float-branded identifier and does not reference legacy app names
2 changes: 1 addition & 1 deletion openspec/changes/rename-project-to-float/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
- [x] 1.1 Inventory all "Always On Top" references across code, config, docs, bundle outputs, and persisted paths.
- [x] 1.2 Update UI strings (window titles, menu labels, dialogs) to show "Float" everywhere.
- [x] 1.3 Update bundler metadata/productName and bundle output names to use "Float" on macOS and Windows.
- [x] 1.4 Decide and apply the Float bundle identifier/settings namespace; migrate or alias existing persisted settings if the namespace changes.
- [x] 1.4 Decide and apply the Float bundle identifier/settings namespace.

## 2. Documentation
- [x] 2.1 Refresh README/release notes and any package metadata to use the Float name and updated bundle paths/installers.
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"@playwright/test": "^1.50.0"
},
"scripts": {
"test:ui": "playwright test tests/tauri-driver.spec.ts"
"test:ui": "playwright test tests/ui-mock.spec.ts",
"test:ui:tauri": "playwright test tests/tauri-driver.spec.ts"
}
}
34 changes: 17 additions & 17 deletions src-tauri/Cargo.lock

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

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "always-on-top-tauri"
name = "float-tauri"
version = "0.1.0"
description = "Float - Tauri shell"
authors = ["Float Team"]
Expand Down
Binary file added src-tauri/icons/128x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/128x128@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/Square107x107Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/Square142x142Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/Square150x150Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/Square284x284Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/Square30x30Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/Square310x310Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/Square44x44Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/Square71x71Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/Square89x89Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src-tauri/icons/StoreLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src-tauri/icons/icon.icns
Binary file not shown.
Binary file modified src-tauri/icons/icon.ico
Binary file not shown.
Binary file modified src-tauri/icons/icon.png
Binary file modified src-tauri/icons/icon_base_1024.png
Binary file added src-tauri/icons/ios/AppIcon-20x20@1x.png
Binary file added src-tauri/icons/ios/AppIcon-20x20@2x-1.png
Binary file added src-tauri/icons/ios/AppIcon-20x20@2x.png
Binary file added src-tauri/icons/ios/AppIcon-20x20@3x.png
Binary file added src-tauri/icons/ios/AppIcon-29x29@1x.png
Binary file added src-tauri/icons/ios/AppIcon-29x29@2x-1.png
Binary file added src-tauri/icons/ios/AppIcon-29x29@2x.png
Binary file added src-tauri/icons/ios/AppIcon-29x29@3x.png
Binary file added src-tauri/icons/ios/AppIcon-40x40@1x.png
Binary file added src-tauri/icons/ios/AppIcon-40x40@2x-1.png
Binary file added src-tauri/icons/ios/AppIcon-40x40@2x.png
Binary file added src-tauri/icons/ios/AppIcon-40x40@3x.png
Binary file added src-tauri/icons/ios/AppIcon-512@2x.png
Binary file added src-tauri/icons/ios/AppIcon-60x60@2x.png
Binary file added src-tauri/icons/ios/AppIcon-60x60@3x.png
Binary file added src-tauri/icons/ios/AppIcon-76x76@1x.png
Binary file added src-tauri/icons/ios/AppIcon-76x76@2x.png
Binary file added src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
Loading
Loading