Add second adapter, thumbnails, a11y pass, and a real test suite
- Immich adapter (adapters/immich.js): swipe a self-hosted photo library over its REST API, proving the adapter contract works for remote sources, not just the filesystem. - Refactor the preview contract from resolvePreviewPath() to streamPreview()/streamThumbnail(), so adapters can serve previews from anywhere (local file, proxied fetch, etc). - macOS Quick Look-backed thumbnail cache (lib/thumbnails.js): real resized thumbnails, HEIC/HEIF, and video poster frames, with a hard timeout and graceful fallback to the original file everywhere else. - Native "Browse..." folder picker (osascript) in Settings, with manual typing as the fallback on other platforms. - Confirm-guarded "Empty trash" action -- the only place this project permanently deletes anything. - Session resume: progress now survives a server restart and an unchanged Rescan via .swipeanything-session.json. - Accessibility pass: live region item announcements, aria-labels on action buttons, focus-trapped shortcuts dialog with focus restore, visible focus rings, a real role="progressbar", and <button>s instead of <a href="#"> in the header. - node:test suite (23 tests) covering the folder adapter, the Immich adapter (mocked fetch, no live server needed), and the HTTP API end-to-end; wired up as `npm test`. - Also includes the keyboard shortcuts (up/down undo/skip), swipe stamps, and shortcuts modal from the previous session that hadn't been committed yet.
This commit is contained in:
+28
-2
@@ -11,16 +11,42 @@
|
||||
<header>
|
||||
<h1>SwipeAnything</h1>
|
||||
<div class="header-actions">
|
||||
<a class="icon-link" href="#" id="rescanLink">Rescan</a>
|
||||
<button type="button" class="icon-link" id="shortcutsLink" title="Keyboard shortcuts (Shift+?)" aria-haspopup="dialog" aria-controls="shortcutsModal">?</button>
|
||||
<button type="button" class="icon-link" id="rescanLink">Rescan</button>
|
||||
<button type="button" class="icon-link" id="emptyTrashLink" hidden>Empty trash</button>
|
||||
<a class="icon-link" href="settings.html">Settings</a>
|
||||
</div>
|
||||
</header>
|
||||
<div class="source-label" id="sourceLabel"></div>
|
||||
<div class="progress-track"><div class="progress-fill" id="progressFill" style="width:0%"></div></div>
|
||||
<div class="progress-track">
|
||||
<div class="progress-fill" id="progressFill" role="progressbar" aria-label="Review progress" aria-valuemin="0" aria-valuemax="0" aria-valuenow="0" style="width:0%"></div>
|
||||
</div>
|
||||
<div class="stats" id="statsLine"></div>
|
||||
<div class="deck" id="deck"></div>
|
||||
<div class="actions-row" id="actionsRow"></div>
|
||||
<div id="liveRegion" class="sr-only" aria-live="polite" aria-atomic="true"></div>
|
||||
</div>
|
||||
|
||||
<div id="shortcutsModal" class="modal" hidden aria-hidden="true">
|
||||
<div class="modal-card" role="dialog" aria-modal="true" aria-labelledby="shortcutsTitle">
|
||||
<div class="modal-header">
|
||||
<h2 id="shortcutsTitle">Shortcuts</h2>
|
||||
<button type="button" class="icon-link modal-close" id="shortcutsClose" aria-label="Close shortcuts help">✕</button>
|
||||
</div>
|
||||
<dl class="shortcut-list">
|
||||
<div><dt>→</dt><dd>Keep</dd></div>
|
||||
<div><dt>←</dt><dd>Reject (to trash)</dd></div>
|
||||
<div><dt>↓</dt><dd>Skip / next</dd></div>
|
||||
<div><dt>↑</dt><dd>Undo / go back</dd></div>
|
||||
<div><dt>Space</dt><dd>Skip / next</dd></div>
|
||||
<div><dt>Ctrl/Cmd+Z</dt><dd>Undo</dd></div>
|
||||
<div><dt>Shift+?</dt><dd>Toggle this help</dd></div>
|
||||
<div><dt>Esc</dt><dd>Close help</dd></div>
|
||||
</dl>
|
||||
<p class="modal-hint">Drag the card left or right, or use the buttons below.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user