ui(sidebar): split editable vs read-only between Edit and Metadata
The Metadata collapsible was hosting two editable widgets (TagsEditor and TakenAtEditor) buried inside the readonly sub-sections — Tags as its own Section, taken-at wedged into Basic Info between size/dims and the filepath. With both top-level collapsibles in place, the clearer split is editable up top, readonly below. Moved into the Edit collapsible (in identification → description → categorization order): Filename, Title, Date Taken, Notes, Tags, Rating, Color, Flag Metadata now holds only readonly sub-sections: Basic Info (size, dims, path), Camera, Location Dropped the now-empty Tags Section from Metadata and the 'tags' key from the default-expanded set. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -143,7 +143,7 @@ export function PhotoInfoPanel({ photoId, darkTheme = false }: PhotoInfoPanelPro
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const [expandedSections, setExpandedSections] = useState<Set<string>>(
|
||||
new Set(['edit', 'metadata', 'basic', 'camera', 'location', 'tags'])
|
||||
new Set(['edit', 'metadata', 'basic', 'camera', 'location'])
|
||||
)
|
||||
const toggleSection = (section: string) => {
|
||||
const next = new Set(expandedSections)
|
||||
@@ -447,6 +447,14 @@ export function PhotoInfoPanel({ photoId, darkTheme = false }: PhotoInfoPanelPro
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TakenAtEditor
|
||||
photo={photo}
|
||||
draft={takenAtDraft}
|
||||
onDraftChange={setTakenAtDraft}
|
||||
onCommit={commitTakenAt}
|
||||
darkTheme={darkTheme}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<label className="mb-1 block text-xs text-text-muted">Notes</label>
|
||||
<Textarea
|
||||
@@ -459,6 +467,22 @@ export function PhotoInfoPanel({ photoId, darkTheme = false }: PhotoInfoPanelPro
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="mb-1 block text-xs text-text-muted">Tags</label>
|
||||
<TagsEditor
|
||||
photoTags={photo.tags ?? []}
|
||||
allTags={allTags}
|
||||
tagInput={tagInput}
|
||||
onTagInputChange={setTagInput}
|
||||
onAttachExisting={(id) => attachExistingTagMutation.mutate(id)}
|
||||
onCreateAndAttach={(name) => {
|
||||
addTagMutation.mutate(name)
|
||||
setTagInput('')
|
||||
}}
|
||||
onRemove={(id) => removeTagMutation.mutate(id)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Rating */}
|
||||
<div>
|
||||
<label className="mb-1 block text-xs text-text-muted">Rating</label>
|
||||
@@ -581,25 +605,6 @@ export function PhotoInfoPanel({ photoId, darkTheme = false }: PhotoInfoPanelPro
|
||||
)}
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<Section
|
||||
title="Tags"
|
||||
expanded={expandedSections.has('tags')}
|
||||
onToggle={() => toggleSection('tags')}
|
||||
>
|
||||
<TagsEditor
|
||||
photoTags={photo.tags ?? []}
|
||||
allTags={allTags}
|
||||
tagInput={tagInput}
|
||||
onTagInputChange={setTagInput}
|
||||
onAttachExisting={(id) => attachExistingTagMutation.mutate(id)}
|
||||
onCreateAndAttach={(name) => {
|
||||
addTagMutation.mutate(name)
|
||||
setTagInput('')
|
||||
}}
|
||||
onRemove={(id) => removeTagMutation.mutate(id)}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<Section
|
||||
title="Basic Info"
|
||||
expanded={expandedSections.has('basic')}
|
||||
@@ -616,13 +621,6 @@ export function PhotoInfoPanel({ photoId, darkTheme = false }: PhotoInfoPanelPro
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<TakenAtEditor
|
||||
photo={photo}
|
||||
draft={takenAtDraft}
|
||||
onDraftChange={setTakenAtDraft}
|
||||
onCommit={commitTakenAt}
|
||||
darkTheme={darkTheme}
|
||||
/>
|
||||
{/* Filepath spans the full sidebar width — most paths are long
|
||||
* enough that the two-column grid above wraps them painfully.
|
||||
* Mono so each character lines up under the next, break-all
|
||||
|
||||
Reference in New Issue
Block a user