Files
advance-photo-gallery-web-sdk/packages/photo-sdk/src/components/views/VersionsView.tsx
T
KaushikRK99 7673fc63ea 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.
2026-07-23 07:34:20 +05:30

90 lines
3.4 KiB
TypeScript

'use client';
import { formatDate, formatTime } from '../../lib/format';
import { Icon } from '../../icons';
import { useGallery, useGalleryStoreApi } from '../../store/context';
import { EmptyState } from './EmptyState';
/**
* Audit browser — every photo/video that has an edit history or comments.
* Click an item to open it with the Info panel showing the full version
* timeline (v1 = original, never overwritten) and comment thread.
*/
export function VersionsView() {
const api = useGalleryStoreApi();
const media = useGallery((s) => s.media);
const tracked = media
.filter((m) => !m.deletedAt && ((m.versions?.length ?? 0) > 0 || (m.comments?.length ?? 0) > 0))
.sort((a, b) => (b.editedAt ?? b.importedAt) - (a.editedAt ?? a.importedAt));
const open = (id: string) => {
const s = api.getState();
s.openLightbox(id);
s.setInfoOpen(true);
};
if (tracked.length === 0) {
return (
<EmptyState
icon="clock"
title="No Version History Yet"
subtitle="Edit a photo or video (the original is always kept as version 1) or add a comment, and it will appear here with its full audit log."
/>
);
}
return (
<div className="apg-scroll" style={{ padding: 16, maxWidth: 760 }}>
<div style={{ fontSize: 22, fontWeight: 700, marginBottom: 4 }}>Versions &amp; Audit Log</div>
<div style={{ color: 'var(--apg-text-secondary)', fontSize: 13, marginBottom: 14 }}>
{tracked.length} item{tracked.length === 1 ? '' : 's'} with edit history or comments. Originals are
never overwritten.
</div>
<div className="apg-audit-list">
{tracked.map((m) => {
const versions = m.versions ?? [];
const latest = versions[versions.length - 1];
const comments = m.comments?.length ?? 0;
return (
<button key={m.id} type="button" className="apg-audit-card" onClick={() => open(m.id)}>
<span className="apg-audit-card__thumb-wrap">
<img className="apg-audit-card__thumb" src={m.thumbnail ?? m.src} alt="" />
{m.kind === 'video' ? (
<span className="apg-audit-card__play">
<Icon name="play" size={14} />
</span>
) : null}
</span>
<span className="apg-audit-card__body">
<span className="apg-audit-card__name">{m.name}</span>
<span className="apg-audit-card__tags">
<span className="apg-audit-card__tag">
<Icon name="clock" size={12} />
{versions.length || 1} version{(versions.length || 1) === 1 ? '' : 's'}
</span>
{comments > 0 ? (
<span className="apg-audit-card__tag">
<Icon name="chat" size={12} />
{comments} comment{comments === 1 ? '' : 's'}
</span>
) : null}
</span>
{latest ? (
<span className="apg-audit-card__latest">
Latest: {latest.changes.join(', ')} · {formatDate(latest.createdAt)}{' '}
{formatTime(latest.createdAt)}
{latest.author ? ` · ${latest.author}` : ''}
</span>
) : null}
</span>
<Icon name="chevron-right" size={16} />
</button>
);
})}
</div>
</div>
);
}