web: 8-color label palette + VIDEO badge in carousel
Expand color labels from the 4-swatch Lightroom culling palette to 8
neutral colors (red/orange/yellow/green/teal/blue/purple/pink) with no
attached semantics, rendered as outlines that fill in when picked.
Carousel tiles now show a VIDEO badge, and the folder row in the right
sidebar always renders ("/" for root) instead of disappearing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
import { push as pushUndo } from '$lib/stores/undo.svelte';
|
||||
import { getMetadataSectionOpen, setMetadataSection } from '$lib/stores/view.svelte';
|
||||
import { primaryFile, type PpPhoto } from '$lib/types/photoprism';
|
||||
import { COLOR_SWATCHES } from '$lib/utils/tagGroups';
|
||||
import RelatedStrip from './RelatedStrip.svelte';
|
||||
|
||||
interface Props {
|
||||
@@ -225,29 +226,20 @@
|
||||
}
|
||||
|
||||
/** Click-to-toggle: clicking the current color clears it; clicking a
|
||||
* different swatch swaps. Same four-swatch palette as mule-image. */
|
||||
* different swatch swaps. */
|
||||
function setColor(next: string) {
|
||||
const value = currentColor === next ? '' : next;
|
||||
if (value === currentColor) return;
|
||||
void applyMark({ color: value });
|
||||
}
|
||||
|
||||
// Tooltips follow the Lightroom culling convention so the swatches
|
||||
// read as actions, not just colors. Red = reject, Yellow = pick,
|
||||
// Green = keep, Orange = review-later.
|
||||
const COLOR_SWATCHES: { key: string; bg: string; title: string }[] = [
|
||||
{ key: 'red', bg: 'bg-red-500', title: 'Red — reject' },
|
||||
{ key: 'orange', bg: 'bg-orange-500', title: 'Orange — review' },
|
||||
{ key: 'yellow', bg: 'bg-yellow-400', title: 'Yellow — pick' },
|
||||
{ key: 'green', bg: 'bg-green-500', title: 'Green — keep' }
|
||||
];
|
||||
|
||||
const photoMark = $derived<PhotoMark>(marksQuery.data?.[photo.UID] ?? {});
|
||||
const currentRating = $derived(photoMark.rating ?? 0);
|
||||
const currentColor = $derived(photoMark.color ?? '');
|
||||
|
||||
const pf = $derived(primaryFile(photo));
|
||||
const dirPath = $derived(splitName(pf.Name ?? '').dir);
|
||||
const folderLabel = $derived(dirPath ? `${dirPath}/` : '/');
|
||||
const dims = $derived(pf.Width && pf.Height ? `${pf.Width}×${pf.Height}` : '—');
|
||||
const sizeStr = $derived(
|
||||
pf.Size
|
||||
@@ -336,15 +328,14 @@
|
||||
<!-- Folder (read-only). The `px-1 py-0.5` mirrors the input
|
||||
padding on filename / date so the read-only text starts at the
|
||||
same x-offset as the editable rows above — otherwise spans
|
||||
hug the icon while inputs sit 4px in. -->
|
||||
{#if dirPath}
|
||||
<div class="flex items-center gap-2">
|
||||
<Folder class="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
||||
<span class="min-w-0 flex-1 truncate px-1 py-0.5 text-muted-foreground" title={dirPath}>
|
||||
{dirPath}/
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
hug the icon while inputs sit 4px in. Root-level files render
|
||||
as `/` so the row never disappears and the layout stays stable. -->
|
||||
<div class="flex items-center gap-2">
|
||||
<Folder class="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
||||
<span class="min-w-0 flex-1 truncate px-1 py-0.5 text-muted-foreground" title={folderLabel}>
|
||||
{folderLabel}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Dimensions -->
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -434,14 +425,16 @@
|
||||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
<div class="text-[10px] uppercase tracking-wide text-muted-foreground">Color label</div>
|
||||
<div class="flex items-center gap-1" role="group" aria-label="Color label">
|
||||
<div class="text-[10px] uppercase tracking-wide text-muted-foreground">Colors</div>
|
||||
<div class="flex flex-wrap items-center gap-1.5" role="group" aria-label="Colors">
|
||||
{#each COLOR_SWATCHES as c (c.key)}
|
||||
{@const picked = currentColor === c.key}
|
||||
<button
|
||||
type="button"
|
||||
class="h-4 w-4 rounded-full ring-2 transition-all {c.bg}"
|
||||
class:ring-foreground={currentColor === c.key}
|
||||
class:ring-transparent={currentColor !== c.key}
|
||||
class="h-4 w-4 rounded-full border-2 transition-all {c.border} {picked
|
||||
? c.bg
|
||||
: 'bg-transparent'}"
|
||||
aria-pressed={picked}
|
||||
onclick={() => setColor(c.key)}
|
||||
title={c.title}
|
||||
aria-label={`Color ${c.key}`}
|
||||
|
||||
Reference in New Issue
Block a user