ui(sidebar): wrap edit form in collapsible, drop Header X button

Mirror the Metadata collapsible: an 'Edit' wrapper around filename,
title, notes, rating, color, and flag so the editable form is hidden
with one click. Default expanded.

Drop the clear-selection X from the panel Header — Esc still clears
selection and grid clicks do too. The X felt out of place once the
panel restructured around two equal collapsible groups (Edit /
Metadata) below a plain title bar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claudio
2026-05-10 21:43:33 +02:00
parent 172f869e15
commit 1695eae226
2 changed files with 27 additions and 22 deletions

View File

@@ -31,7 +31,7 @@ import { formatApiError } from '../../lib/apiError'
* rating / color / discard / pick across the entire selection. * rating / color / discard / pick across the entire selection.
*/ */
export function RightSidebar() { export function RightSidebar() {
const { selectedPhotos, activePhotoId, clearSelection } = usePhotoStore() const { selectedPhotos, activePhotoId } = usePhotoStore()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const { const {
@@ -182,9 +182,10 @@ export function RightSidebar() {
}, },
}) })
// Unified header rendered in every branch so the collapse button is // Unified header rendered in every branch so the panel always has
// always reachable regardless of selection state. Title and the // a title strip regardless of selection state. The title adapts to
// clear-selection X adapt to what's selected. // what's selected; selection is cleared via Esc or by clicking
// empty space in the grid.
const headerTitle = const headerTitle =
selectedPhotos.length === 0 selectedPhotos.length === 0
? 'Metadata' ? 'Metadata'
@@ -193,24 +194,10 @@ export function RightSidebar() {
: `${selectedPhotos.length} Photos Selected` : `${selectedPhotos.length} Photos Selected`
const Header = () => ( const Header = () => (
<div className="flex h-9 flex-shrink-0 items-center justify-between border-b border-border px-3"> <div className="flex h-9 flex-shrink-0 items-center border-b border-border px-3">
<h2 className="text-[11px] font-semibold uppercase tracking-[0.14em] text-text-muted"> <h2 className="text-[11px] font-semibold uppercase tracking-[0.14em] text-text-muted">
{headerTitle} {headerTitle}
</h2> </h2>
<div className="flex items-center gap-0.5">
{selectedPhotos.length > 0 && (
<Button
variant="ghost"
size="icon"
className="h-6 w-6 text-text-muted"
onClick={clearSelection}
title="Clear selection (Esc)"
aria-label="Clear selection"
>
<X className="h-3.5 w-3.5" />
</Button>
)}
</div>
</div> </div>
) )

View File

@@ -143,7 +143,7 @@ export function PhotoInfoPanel({ photoId, darkTheme = false }: PhotoInfoPanelPro
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [expandedSections, setExpandedSections] = useState<Set<string>>( const [expandedSections, setExpandedSections] = useState<Set<string>>(
new Set(['metadata', 'basic', 'camera', 'location', 'tags']) new Set(['edit', 'metadata', 'basic', 'camera', 'location', 'tags'])
) )
const toggleSection = (section: string) => { const toggleSection = (section: string) => {
const next = new Set(expandedSections) const next = new Set(expandedSections)
@@ -390,8 +390,24 @@ export function PhotoInfoPanel({ photoId, darkTheme = false }: PhotoInfoPanelPro
isPlaceholderData && 'opacity-70' isPlaceholderData && 'opacity-70'
)} )}
> >
{/* Edit fields */} {/* Edit fields — collapsible group so the user can hide the
<div className="space-y-2.5 border-b border-border p-3"> * editable form (filename, title, notes, rating, color, flag)
* the same way they can hide the readonly metadata block below. */}
<Collapsible
open={expandedSections.has('edit')}
onOpenChange={() => toggleSection('edit')}
className="border-b border-border"
>
<CollapsibleTrigger className="flex w-full items-center justify-between border-b border-border bg-surface-2/40 px-3 py-2 text-[11px] font-semibold uppercase tracking-[0.14em] text-text-muted hover:bg-surface-2 hover:text-text">
<span>Edit</span>
{expandedSections.has('edit') ? (
<ChevronDown className="h-3 w-3" />
) : (
<ChevronRight className="h-3 w-3" />
)}
</CollapsibleTrigger>
<CollapsibleContent>
<div className="space-y-2.5 p-3">
<div> <div>
<label className="mb-1 block text-xs text-text-muted">Filename</label> <label className="mb-1 block text-xs text-text-muted">Filename</label>
<Input <Input
@@ -544,6 +560,8 @@ export function PhotoInfoPanel({ photoId, darkTheme = false }: PhotoInfoPanelPro
</div> </div>
</div> </div>
</div> </div>
</CollapsibleContent>
</Collapsible>
{/* Read-only metadata — collapsed/expanded as one block so the user {/* Read-only metadata — collapsed/expanded as one block so the user
* can hide everything below the editable form with a single click. * can hide everything below the editable form with a single click.