feat: enhance styling and layout for toolbar, map components, and editor
- Updated toolbar styles for improved layout and appearance, including padding and margin adjustments. - Introduced new styles for scale menu and compact dropdowns. - Enhanced map pin tooltips with better positioning and hover effects. - Added new styles for map sheet filters, including search and date range controls. - Improved editor styles for a more cohesive look and feel, including transport controls for video editing. - Expanded GeoLocation interface to include additional address fields and formatted address. - Updated MediaItem interface to include storage reference and uploadedBy fields. - Enhanced MediaComment interface with author details for better user identification. - Introduced GalleryUser interface to represent signed-in users in the host app.
This commit is contained in:
@@ -55,9 +55,10 @@ what it needs. The full, living checklist is in [`docs/ROADMAP.md`](docs/ROADMAP
|
||||
### Platform
|
||||
| Area | Details |
|
||||
| --- | --- |
|
||||
| **Backend** | Pluggable `StorageAdapter` — zero‑config localStorage/IndexedDB default, or **Supabase** (Postgres + Storage) adapter included |
|
||||
| **Search** | Name / place / tag / object / **OCR text** / **semantic** — blended and relevance‑ranked |
|
||||
| **Theming** | `accentColor` + `borderRadius` props; Light / Dark / Semi‑Dark / System |
|
||||
| **Backend** | Pluggable `StorageAdapter` — zero‑config localStorage/IndexedDB default, or **Supabase** (Postgres + Storage) adapter included; optional **incremental** `applyChanges` + durable `putMedia` for backend‑friendly partial writes |
|
||||
| **Embedding** | Drop into a host app: `embedded` layout, `chrome` suppression, `hiddenViews`, host **`currentUser`** identity (identity‑stamped comments / uploads / versions), `shareBaseUrl`, server‑backed **`lockProvider`**, full‑screen mode — live config (no remount) |
|
||||
| **Search** | Name / place / tag / object / **OCR text** / caption / note / **semantic** — blended and relevance‑ranked |
|
||||
| **Theming** | `accentColor` + `borderRadius` props **and a full `ThemeTokens` map (50+ keys)** → CSS variables; Light / Dark / Semi‑Dark / System |
|
||||
| **A11y / responsive** | Keyboard nav, focus traps, reduced‑motion, ARIA; works down to ~280 px |
|
||||
| **Security** | Per‑request **nonce CSP**, security headers, filename sanitisation, URL‑scheme allow‑list, server‑only API keys |
|
||||
|
||||
@@ -149,14 +150,29 @@ export default function Gallery() {
|
||||
| --- | --- | --- | --- |
|
||||
| `photos` | `MediaItem[] \| { src, … }[]` | `[]` | Initial library; loose inputs are normalised + auto‑classified |
|
||||
| `albums` | `Album[]` | `[]` | Initial user albums |
|
||||
| `adapter` | `StorageAdapter` | localStorage | Persistence backend (swap for S3/DB/REST) |
|
||||
| `adapter` | `StorageAdapter` | localStorage | Persistence backend (swap for S3/DB/REST); supports incremental `applyChanges` + durable `putMedia` |
|
||||
| `ai` | `AIProvider \| boolean` | `false` | Object/face/caption/search/generative provider |
|
||||
| `theme` | `'system' \| 'light' \| 'dark'` | `'system'` | Appearance |
|
||||
| `theme` | `'system' \| 'light' \| 'dark' \| 'semi-dark'` | `'system'` | Appearance |
|
||||
| `accentColor` | `string` | `#0a84ff` | Accent colour |
|
||||
| `borderRadius` | `number` | `10` | Base corner radius (px) for all rounded UI |
|
||||
| `themeTokens` | `ThemeTokens` | – | Per‑theme background / gradient / opacity / sidebar colour + radius overrides |
|
||||
| `themeTokens` | `ThemeTokens` | – | Full per‑theme token map (50+ keys) → CSS variables (backgrounds, cards, glass, separators, text tiers, shadows, radii, sidebar/toolbar sizing…) |
|
||||
| `features` | `Partial<GalleryFeatures>` | all on | Toggle editor / camera / ai / map / import / export / sharing |
|
||||
| `showWindowChrome` | `boolean` | `false` | Render the macOS traffic‑light title bar |
|
||||
| `showWindowChrome` | `boolean` | `false` | Render the macOS traffic‑light title bar (legacy alias of `chrome.titlebar`) |
|
||||
|
||||
**Embedding into a host app** — these props let the gallery drop into an existing product shell instead of running standalone. Full guide, token table and adapter contract: **[`packages/photo-sdk/README.md` → “Embedding in a host app”](packages/photo-sdk/README.md#embedding-in-a-host-app)**.
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `embedded` | `boolean` | `false` | Lay out at `height:100%` inside the host container (not a full viewport); `cursor:pointer` on controls |
|
||||
| `chrome` | `Partial<GalleryChrome>` | `DEFAULT_CHROME` | Suppress the gallery's own `{ titlebar, sidebar, toolbar, themeSwitcher }` when the host provides them |
|
||||
| `hiddenViews` | `ViewId[]` | `[]` | Hide sidebar rows + Collections cards, e.g. `['screenshots', 'sys:documents']` |
|
||||
| `keyboardShortcuts` | `boolean` | `true` | Bind global shortcuts (⌘A, Delete, F, Esc, Enter) to `window` |
|
||||
| `currentUser` | `GalleryUser` | – | Host's signed‑in user; stamps comments / uploads / versions with real identity |
|
||||
| `shareBaseUrl` | `string` | `${origin}/gallery` | Base URL for generated share links |
|
||||
| `defaultFullscreen` | `boolean` | `false` | Start maximised over the host page (`apg--fullscreen`) |
|
||||
| `lockProvider` | `LockProvider` | – | Server‑backed, per‑user Recently‑Deleted lock (replaces the device‑local hash) |
|
||||
|
||||
The live config is applied on every render, so changing `theme`, `themeTokens`, `currentUser` or `chrome` re‑applies without remounting the gallery.
|
||||
|
||||
### 🎨 Customization (props **or** env)
|
||||
|
||||
@@ -188,6 +204,14 @@ const myApiAdapter: StorageAdapter = {
|
||||
<PhotoGallery adapter={myApiAdapter} />;
|
||||
```
|
||||
|
||||
Two optional members make an adapter backend‑friendly (both additive — `save`/`putBlob`‑only adapters keep working):
|
||||
`applyChanges(changes: StateChanges)` — called *instead of* `save()` on each debounced change, sending only
|
||||
`{ upsertMedia?, removeMedia?, upsertAlbums?, removeAlbums?, upsertPeople?, removePeople?, labelAliases?, deletedLabels? }`
|
||||
(a rejection rolls the snapshot back and the next persist retries the same diff); and
|
||||
`putMedia(id, blob, { name, mime }): Promise<{ ref, url }>` — durable byte storage preferred over `putBlob`, where
|
||||
`url` → `MediaItem.src` (renderable now, may be a signed URL) and `ref` → `MediaItem.storageRef` (survives a reload).
|
||||
See [`packages/photo-sdk/README.md` → “Incremental storage adapters”](packages/photo-sdk/README.md#incremental-storage-adapters).
|
||||
|
||||
### Custom AI provider
|
||||
|
||||
Every method is optional and the UI degrades gracefully. Implement object detection client‑side
|
||||
@@ -250,7 +274,8 @@ Still planned / not yet implemented:
|
||||
|
||||
- **Auth & multi‑user sharing** (real recipients, permissions). Sharing today creates device‑local links.
|
||||
- **Captions** (transformers.js BLIP) and a first‑class Hugging Face Inference provider option.
|
||||
- **Map** heatmaps / trips / reverse‑geocode place names; true grid **virtualization** for millions of items.
|
||||
- **Map** heatmaps / trips; true grid **virtualization** for millions of items. (Full‑address **reverse‑geocoding**
|
||||
— road → city → country via OpenStreetMap Nominatim, shown in the Info panel — is now live.)
|
||||
- **Server‑side** 30‑day purge (pg_cron), Storage blob deletion on permanent‑delete.
|
||||
- Storybook + API docs, Docker/K8s, automated CI.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user