Commit Graph

108 Commits

Author SHA1 Message Date
LyAhn 4f9ab0b821 fix: support AVIF thumbnail processing
github/actions/ci GitHub Actions CI finished: success
Route AVIF thumbnail generation through the bundled FFmpeg path instead of the Rust image decoder, avoiding unsupported-format failures without requiring system dav1d dependencies.

Requeue existing AVIF jobs that previously failed with unsupported-format errors and feed generated JPEG derivatives to embedding/tagging preprocessing while leaving lightbox display on the original AVIF file.
2026-06-22 20:43:46 +01:00
LyAhn a06e76c7a7 fix: resolve Rust Clippy CI failures
github/actions/ci GitHub Actions CI finished: success
Derive default implementations for captioner and tagger option enums, simplify sorting and progress multiple checks, and remove redundant iterator conversions.
2026-06-21 21:00:46 +01:00
LyAhn 1e008244ae fix(db): suppress too_many_arguments clippy lint on count_images
github/actions/ci GitHub Actions CI finished: failure
2026-06-21 19:40:35 +01:00
LyAhn ebed194f17 Merge feat/qol-02: QoL polish — folder picker, settings, duplicate finder
github/actions/ci GitHub Actions CI finished: failure
- Custom multi-folder picker replaces the native OS dialog: browse the
  filesystem in-app, stage multiple folders at once, and add them in one
  shot. Virtualised list handles large directory trees without jank.
- Duplicate Finder group list is now virtualised, keeping the UI
  responsive even with hundreds of duplicate groups.
- Settings panel reordered: General is now the first (default) section.
- Lightbox video playback toggles (autoplay / auto-mute) added to
  General settings, wired to the store with ARIA switch roles.
- "Rebuild Semantic Index" maintenance action added to Settings.
- Folder picker QoL fixes: chevron tooltip, Unix breadcrumb root label,
  and partial-failure staging panel cleanup.
2026-06-21 19:30:35 +01:00
LyAhn 3684b98d55 fix(folder-picker): address QoL issues from PR review
- Fix chevron tooltip: was "Open folder" in both branches; now shows
  "No subfolders" when the entry has no children (consistent with the
  existing opacity-45 visual cue on the same chevron icon)
- Fix Unix breadcrumb root label: was always "Home" even for non-home
  paths like /mnt/data — now labelled "/" which is always accurate
- Fix partial-failure staging: on a mixed add result, successfully-added
  entries are now removed from the staging panel so only genuinely failed
  folders remain for the user to retry (index-pairing is safe because the
  backend returns results in input order via a preserved .map())
2026-06-21 19:21:00 +01:00
LyAhn 74a4134f2f feat: add custom multi-folder picker
Replace native add-folder dialogs with an in-app folder picker that supports collecting folders from multiple locations before adding them together.

Add backend directory listing and batch add commands with duplicate skipping, plus store actions and a themed picker UI with a dedicated folders-to-add panel.
2026-06-21 17:38:01 +01:00
LyAhn f66fbe7931 feat(settings): add "Rebuild semantic index" maintenance action
Drops and recreates the sqlite-vec tables at the current model dimension, then
re-queues every image for embedding. Fixes "dimension mismatch" search errors
that occur when the vector table was built for a different model/dimension (e.g.
after experimenting with 768-dim models against this 512-dim build).

The rebuild runs under the embedding worker's DB write lock and resets the job
queue inside a single transaction, so it can't interleave with an in-flight
embedding batch (per code review).
2026-06-21 15:17:34 +01:00
LyAhn 5870205047 feat(settings): General-first layout + lightbox video playback toggles
Reorder the Settings sections so General is the top and default section instead
of AI Workspace. Add two persisted settings under a new "Video playback" group:
- Autoplay in lightbox (default on)
- Start muted (default off)

VideoPlayer reads these when a video opens — autoplaying only when enabled and
starting muted when enabled, otherwise falling back to the session's last-used
mute state. Settings apply to the next opened video, not the current one.
2026-06-21 14:39:41 +01:00
LyAhn 3db95a4489 perf: virtualize the Duplicate Finder group list
The duplicate view rendered every group and every thumbnail at once — a 5,000-pair
result mounted ~10K <img> elements, making scroll lag heavily (same class of bug
as the old per-month Timeline). Virtualize the group list so only on-screen cards
mount; heights are measured dynamically since each group wraps a variable number
of copies.
2026-06-21 13:45:11 +01:00
LyAhn c1ab651131 Merge: drop dead settings-modal theme CSS
github/actions/ci GitHub Actions CI finished: failure
Removes subtle-light .settings-modal overrides that targeted classes no component
on main applies (dead rules), keeping the Settings modal flat and themed via the
global accent variables.
2026-06-21 12:58:21 +01:00
LyAhn 166ffdb189 chore: remove dead .settings-modal theme overrides
These subtle-light overrides target classes (settings-modal, settings-nav-active,
settings-model-card) that no component on main applies, so the rules never took
effect. They also pulled the Settings modal toward a card look we don't want. The
accent-text readability is now handled globally by the theme's accent variables,
so the modal themes correctly (flat) without this block.
2026-06-21 12:58:19 +01:00
LyAhn 58750b169a Merge Subtle Light accent-text readability fix
Coloured text/icons (warnings, errors, status) used pastel accent shades tuned
for dark UIs and washed out on the light theme — e.g. "Update check failed" in
Settings was near-invisible. Darken those accent variables in the subtle-light
theme while resetting them to the bright originals inside .media-dark-surface,
so light chrome reads clearly and on-photo overlays keep their signal colours.
2026-06-21 12:53:44 +01:00
LyAhn 1e148bdf18 fix: make accent text readable in Subtle Light theme
Pastel accent shades (amber/red/rose/emerald/sky/violet/blue -200..-400) are
tuned for dark UIs and washed out on the light chrome — e.g. "Update check
failed" in the Settings updates row was near-invisible. Darken those accent
variables in the subtle-light theme so coloured text/icons stay readable, and
reset them to Tailwind's bright defaults inside .media-dark-surface so on-photo
overlays (ratings, failed badges, the lightbox region tool) keep their signal
colours. Remapping the variable rather than the utility also covers opacity
variants like text-amber-300/90.
2026-06-21 12:34:04 +01:00
LyAhn 7367845f8b Merge 0.1.1 QoL fixes
github/actions/ci GitHub Actions CI finished: failure
Post-release quality-of-life work for 0.1.1:

- Timeline: right-edge year/month scrubber, full-library load so the scrubber
  spans everything, and per-row virtualization so dense months scroll smoothly.
- Gallery grid row-virtualization; folder reordering (drag + keyboard) with
  persisted custom order and A-Z/Z-A/Custom sort.
- Theme system (Phokus, Subtle Light, Conventional Dark) with an onboarding
  theme picker, plus subtle-light parity fixes for the lightbox panel, media
  overlays, duplicate finder, and window controls.
- Failed AI-tagging locate/filter from the background worker prompt.
- Perf: background media-updated batches no longer re-sort the whole image set.
- Video embedding jobs no longer churn through false failures before their
  thumbnail exists.
- Tooling: changelog helper + notes.
2026-06-21 08:48:53 +01:00
LyAhn 50e8bc8e4d docs: record 0.1.1 QoL fixes in changelog 2026-06-21 08:48:20 +01:00
LyAhn 779a18f56e fix: use valid end-of-input anchor in changelog-add
JS regex has no \z anchor — it matched a literal 'z', so appending to the last
section under [Unreleased] silently failed and duplicated the heading. Use
$(?![\s\S]) to anchor to true end-of-input.
2026-06-21 08:48:19 +01:00
LyAhn d027de675b fix: debounce folder keyboard-reorder persistence
Holding Up/Down on a folder's drag handle fired a reorder_folders DB write per
keystroke. Update the local order immediately for responsiveness, but debounce
the persist (400ms) with cleanup on unmount.
2026-06-21 08:48:18 +01:00
LyAhn b7cfc9177e fix: subtle-light theme parity for lightbox panel and media surfaces
In subtle-light, the lightbox dragged its whole surface (including the metadata
panel) dark via media-dark-surface, while conventional-dark themed the panel
normally. Scope the dark surface to the media canvas and re-light the panel by
remapping --color-* variables on a .lightbox-panel wrapper (Tailwind v4 resolves
every colour utility through these vars, so this re-themes the subtree —
including accents — with no !important). Mark gallery/duplicate media tiles as
media-dark-surface so their on-image overlays stay light-on-dark, and theme the
window restore icon via var(--color-gray-950) instead of a hardcoded hex.
2026-06-21 08:48:05 +01:00
LyAhn 479de76ebb perf: stop full re-sort on media-updated batches
replaceExistingImages re-sorted the entire loaded image array on every
media-updated event. Harmless for the ~200-item gallery window, but in Timeline
(which loads the whole library) it was an O(n log n) pass many times per second
during background indexing — severe lag, occasional crashes. Thumbnail/metadata
fills don't change list position (Timeline re-buckets by taken_at separately), so
replace records in place and skip the sort; return the same array reference when
nothing matched to avoid a wasted re-render.
2026-06-21 08:48:05 +01:00
LyAhn 21f6c30d25 perf: row-virtualize Timeline instead of per-month
Each month was a single virtual item that rendered all of its tiles, so
scrolling into a busy month mounted thousands of ImageTiles at once. Flatten
months into a fixed-height row list (header rows + tile rows of `cols` images),
mirroring the Gallery grid, so only on-screen rows render and thumbnails stream
in as you scroll. Active-month tracking and scrubber jump-to-month are remapped
to the flat row model.
2026-06-21 08:47:48 +01:00
LyAhn 1df75fd490 Refine explore and settings theming 2026-06-20 18:08:39 +01:00
LyAhn a4c928345c chore: add changelog helper and unreleased notes 2026-06-18 00:49:30 +01:00
LyAhn ca58c2ddd4 fix: add failed tag locate and filter controls
Add a failed-tag discovery flow for background worker failures.

Changes:
- Add a Failed Tags toolbar filter that appears when tag failures exist.
- Add Locate buttons for failed tag tasks in the background worker prompt.
- Route Locate to the affected folder and filter the gallery to images with tagger errors.
- Fetch and display failed tag filenames/errors in the expanded worker details.
- Add a backend query and gallery filter flag for images with failed AI tagging.
- Improve subtle-light contrast for failed worker chips, filenames, and Locate/Retry buttons.
- Also slightly increases the title bar update indicator pulse size for better visibility.
2026-06-18 00:36:02 +01:00
LyAhn c97fec2eb3 fix: improve light theme onboarding controls
Make the onboarding tour theme-aware across the app themes, add the first-run theme picker, and keep fake media previews on the dark media surface. Update light-mode secondary controls in onboarding, settings, dropdowns, toolbar controls, and duplicate actions so they no longer render as dark buttons on subtle-light.
2026-06-17 22:07:35 +01:00
LyAhn 9047c8053a feat: 0.1.1 — timeline scrubber, gallery virtualisation, folder reorder, QoL polish
Timeline:
- Add a right-edge scrubber (year labels + month dots) that jumps to any
  period; runs in the same direction as the scrolled content
- Load the full filtered set in Timeline view so the scrubber spans the whole
  library instead of just the first page

Gallery & UI:
- Virtualise the gallery grid
- Folder reordering in the sidebar (drag + persisted sort_order) and a themed
  dropdown component
- Subtle Light theme contrast fixes for toggles, secondary buttons and the
  update toast

Embedding workers now defer video jobs without a thumbnail at claim time and
requeue any previously-failed deferred jobs on startup, so videos no longer
churn through failed embeddings.

QoL polish across BackgroundTasks, DuplicateFinder, Lightbox and VideoPlayer.
2026-06-17 18:37:37 +01:00
LyAhn f049f8c997 Update ci.yml
flip paths-ignore to paths and point to src + src-tauri
2026-06-15 21:44:34 +01:00
LyAhn 3e0f59300e feat(website): launch phokus.jezz.wtf product site
github/actions/ci GitHub Actions CI finished: cancelled
Single-page marketing site built with React 19, Vite 7, and Tailwind v4.
Covers the full product story: local-first privacy, semantic search, explore/timeline,
curation, deduplication, and download. Screenshots transcoded to AVIF/WebP at build
(~5.3 MB masters → ~0.5 MB served). Self-hosted Inter and Space Grotesk variable fonts.
Mobile-first redesign with phone-optimised hero, swipeable feature cards, and touch-friendly
navigation. Includes the standalone Phokus aperture SVG asset.

CI: exclude website/ and docs/ from the Rust/Tauri check workflow.
2026-06-15 21:25:55 +01:00
LyAhn 00bf7da344 feat(website): redesign the mobile experience
Replace the stacked desktop layout with a phone-first product flow featuring an image-led hero, inline privacy proof, compact semantic search, swipeable feature cards with live pagination, expandable technical details, and touch-friendly navigation and calls to action. Add the standalone Phokus aperture SVG asset.
2026-06-15 21:15:18 +01:00
LyAhn e14dbda41d feat(website): finish responsive polish
Self-host the Inter and Space Grotesk variable fonts, tighten the mobile layout, hide oversized edge marks on narrow screens, and add keyboard focus plus reduced-motion safeguards. Exclude website and documentation-only changes from the desktop CI workflow.
2026-06-15 19:55:01 +01:00
LyAhn 072c3887cf feat(website): add Phokus product site with optimized media pipeline
Single-page marketing site for phokus.jezz.wtf in the website/ pnpm workspace
(React 19 + Vite 7 + Tailwind v4). Sections: Hero, Local-first, Search, Explore
& timeline, Curate, Cleanup, Tech facts, Download. Product-first composition with
a recurring aperture motif (EdgeMark) bleeding off alternating edges.

Screenshots are transcoded to AVIF/WebP at build via vite-imagetools (sharp);
~5.3MB of masters -> ~0.5MB served. Commits only the 7 in-use captures.
2026-06-15 19:39:56 +01:00
LyAhn 584a92b7cd ci: report GitHub Actions status to Gitea
github/actions/ci GitHub Actions CI finished: failure
2026-06-15 00:36:25 +01:00
LyAhn 6a5cf0afe3 docs(changelog): date the 0.1.0 release (2026-06-14)
CI / check (push) Has been cancelled
2026-06-14 20:28:22 +01:00
LyAhn ce804f5aa5 chore(gitignore): drop blanket *.json ignore, track configs directly
CI / check (push) Has been cancelled
The global *.json rule (added for transient ComfyUI workflow dumps) forced
git add -f on real configs and hid tauri.conf.json from tauri-action's
gitignore-aware globbing. Removed it and the negation workarounds; local-only
ignores (e.g. skills-lock.json) live in .git/info/exclude instead.
2026-06-14 20:10:18 +01:00
LyAhn 40fcd1b469 ci(release): un-ignore tauri.conf.json + fix updater-json input
CI / check (push) Has been cancelled
Release / release (push) Has been cancelled
- tauri-action globs for tauri.conf.json honoring .gitignore; the global
  *.json rule hid it (force-added but still ignore-matched), so detection
  failed with 'Failed to resolve Tauri path' and it tried to re-init.
  Negate it like the cuda overlay already is.
- rename uploadUpdaterJson -> includeUpdaterJson (valid v0.6.2 input).
v0.1.0
2026-06-14 19:58:54 +01:00
LyAhn 6b504aaae1 ci(release): pin tauri-action to v0.6.2 (the v1 ref does not exist)
Release / release (push) Has been cancelled
CI / check (push) Has been cancelled
2026-06-14 19:31:12 +01:00
LyAhn 0bd99e2c7a release: Phokus 0.1.0 release preparation
CI / check (push) Has been cancelled
Release / release (push) Has been cancelled
Merge chore/release-prep into main for the first public release.

- Release pipeline: CI (fmt, clippy -D warnings, tsc) + tag-triggered
  GitHub Actions building the NSIS installer as a draft release.
- Self-updater via GitHub Releases — launch check, Settings UI, update
  toast, and a title-bar focal-point indicator that lights up when a new
  version is ready.
- Production hardening: real CSP, scoped asset protocol, rotating file
  logging, single-instance, window-state.
- Guided first-run onboarding with background FFmpeg provisioning and
  resilient (curl-based, resumable) model/DLL downloads.
- Branding: Phokus aperture mark across the icon set + title bar, with a
  reusable PhokusMark component.
- CUDA installer variant with bundled runtime DLLs (built locally).
- MIT license, bundle metadata, NSIS-only target, and docs (README
  install/privacy, CHANGELOG, 0.1.0 release notes).
2026-06-14 18:27:48 +01:00
LyAhn 0144526a3d feat(onboarding): add a closing 'Staying current' step on updates + the app mark
- new StepUpdates: explains the title-bar update indicator with a mini
  app-window mockup, and introduces the aperture mark as the app's identity
- move the tour-closing copy off the AI features step onto this final step
- changelog: note the title-bar update indicator + one-click install, and the
  new onboarding step
2026-06-14 18:26:35 +01:00
LyAhn 2785b7d5e6 feat(updates): titlebar update indicator + dev injectors for the update flow
- light up the Phokus iris's focal point (pulsing amber) in the titlebar when
  an update is pending; click goes straight to install, with a fast custom
  tooltip (native title delay was too slow)
- PhokusMark gains an optional dotClassName to render the central focal point
- DemoPanel: inject every updater state (available/downloading/installing/
  error/up-to-date), which is otherwise unreachable without a remote latest.json
2026-06-14 17:11:00 +01:00
LyAhn 797247e900 feat(branding): replace default Tauri icon with the Phokus aperture mark
- regenerate src-tauri/icons from the new branding/phokus-aperture.svg master
- add reusable PhokusMark component (inline SVG, inherits currentColor)
- use it for the titlebar app mark, retiring the placeholder
2026-06-14 15:15:28 +01:00
LyAhn e4373195fe chore(dev): add a dev-only demo panel for screenshotting transient UI
The background-worker pipeline drains in under a second on a fast machine,
making it impossible to screenshot live. This adds a dev-only panel
(Ctrl+Shift+D) that injects a frozen mid-pipeline state into mediaJobProgress
so the worker bar can be captured at leisure, then cleared. Gated by
import.meta.env.DEV and verified absent from the production bundle, so it
never ships. A first rough cut of the broader screenshot/demo mode.
2026-06-14 09:39:29 +01:00
LyAhn 72a1a886a7 fix(sidebar): refresh UI immediately when removing a library
Removing a folder only reloaded the gallery when that exact folder was the
active selection, so on All Media (or another view) its images stayed on
screen until a manual refresh. Now the folder is dropped from the sidebar
optimistically (instant feedback while the backend deletes its images), the
gallery is always reloaded, and a failed delete resyncs the folder list.
2026-06-13 23:10:09 +01:00
LyAhn c15eed6655 fix(onboarding): no image flash when switching search demos
Switching search modes briefly showed the next demo's result images because
the results container stayed mounted and faded its opacity down from the
previous demo's visible state. Key it by demoIndex so it remounts fresh at
opacity-0 and only fades in once the new query finishes typing.
2026-06-13 21:48:41 +01:00
LyAhn 602c271531 feat(tagger): resilient model and runtime-DLL downloads via curl
ureq's read timeout doesn't fire on a stalled large transfer on some Windows
TLS stacks (schannel), so a stall hangs the download forever with no recovery.
Download the ONNX runtime DLLs and the tagger model through the system
curl.exe (Win10 1803+/Win11), which has a real inactivity timeout
(--speed-time) plus resume (-C -). The size probe uses curl too, so nothing in
the download path depends on ureq.

A stalled download discards its partial when it gives up (no more deleting the
model folder by hand to restart) and fails to a retryable error in a couple of
minutes rather than locking the UI on 'preparing'. Adds progress, extraction,
and runtime-init logging. Verified downloading both models on real Windows 11
hardware.
2026-06-13 21:48:41 +01:00
LyAhn 54fa8ab117 build(cuda): ship a CUDA installer variant with bundled runtime DLLs
The default build (default = candle-cuda) load-time-imports the CUDA runtime,
so it crashes on any machine without the toolkit. Add a CUDA release variant
that bundles the redistributable runtime DLLs (cudart/cublas/cublasLt/curand,
verified via dumpbin) so it runs on any NVIDIA machine with just a driver.

- tauri.cuda.conf.json: a 'tauri build --config' overlay (CPU release
  untouched) that points the updater at latest-cuda.json so a CUDA install
  never self-updates into the CPU build
- windows/cuda-hooks.nsh: NSIS hook embeds the DLLs via File and extracts them
  next to phokus.exe, where the Windows loader searches
- build:app:cuda script; cuda-redist/ gitignored (DLLs copied from the toolkit
  locally), with a negation so the overlay stays tracked
2026-06-13 21:48:40 +01:00
LyAhn 23095a6d05 docs: add installation, privacy, changelog, and 0.1.0 release notes
Phase 6 release collateral:
- README: Installation (unsigned-build/SmartScreen note, requirements,
  first-run downloads) and Privacy & local-first sections
- CHANGELOG.md seeded with the 0.1.0 feature set
- docs/release-notes-0.1.0.md draft for the GitHub Release body

Also corrects the CLIP model download size from ~330 MB to ~580 MB (the
actual model.safetensors is 577 MB) across the docs and the onboarding UI.
2026-06-13 10:34:15 +01:00
LyAhn 075c7e4cfb feat(sidebar): pause/resume all background work from folder context menu
The onboarding tour tells users they can right-click a folder to pause its
background work, but only the per-worker buttons in the BackgroundTasks bar
existed. Add a 'Pause/Resume background work' context-menu item that toggles
all four workers (thumbnail/metadata/embedding/tagging) for the folder.

To keep the bar and the menu in sync, worker-pause state moves from
BackgroundTasks' local state into the store (the canonical owner of app
state), so pausing from either surface reflects in both. Reuses the existing
set_worker_paused / get_worker_states commands; no backend change.
2026-06-13 09:42:51 +01:00
LyAhn 2f66b0bdb8 feat(onboarding): fuller, varied semantic search demo results
Replace the two near-identical pale ocean sunsets with three distinct
'golden sunset over water' stills — a vivid coastal sunset, a soft golden
ocean, and a golden alpine lake — so the /s demo shows a convincing,
varied result set. Drops the redundant sunset2 asset.
2026-06-13 09:29:40 +01:00
LyAhn ed9c061ac1 fix(onboarding): hide search results until typed, trim gallery grid to 2 rows
- search demo results were greyed-but-visible while the query was still
  typing, as if the app pre-knew the search; they're now invisible (space
  reserved, no layout jump) and fade in only once typing completes
- gallery preview dropped from 3 rows to 2 so the 'Click any tile' explainer
  text is visible without scrolling
2026-06-13 09:23:30 +01:00
LyAhn 09810cb868 refactor(onboarding): play animations once with replay, fix search demo results
Two refinements from testing:
- the gallery-reveal, pipeline-drain, and search-typing animations looped
  forever; they now play once and stop, with a Replay button to re-run
- the search demo's result tiles didn't match the queries. Now: a filename
  search returns one exact file, '/s golden sunset over water' shows only
  ocean-sunset stills (added a second), and '/t landscape' shows the three
  actual landscapes (valleys + alpine lake), not a foggy forest
2026-06-13 09:19:38 +01:00
LyAhn f8e981c6f6 feat(tagger): real byte progress for model download instead of a spinner
The 1.3 GB model.onnx downloaded via hf-hub's repo.get() and the ONNX
runtime DLLs via a read_to_end — neither reported bytes, so the user saw
only an indeterminate spinner on a multi-minute download.

- tagger model files now download via repo.download_with_progress with a
  HubProgress adapter over hf-hub's Progress trait (throttled 200ms events
  carrying downloaded/total bytes)
- captioner's nuget DLL download streams in 64 KB chunks, parsing
  content-length, and reports per-chunk byte progress
- TaggerModelProgress carries downloaded_bytes/total_bytes; onboarding and
  Settings show a determinate bar plus 'X MB / Y MB' for the current file
2026-06-13 08:56:49 +01:00