diff --git a/app/admin/admin.css b/app/admin/admin.css
index 216a0b8..09c521f 100644
--- a/app/admin/admin.css
+++ b/app/admin/admin.css
@@ -1726,3 +1726,415 @@
grid-template-columns: 1fr;
}
}
+
+/* ── Premium Slide-over Drawer & Badges Redesign ──────────────── */
+
+/* Inline SVG Icon Global Styling */
+.svg-icon {
+ display: inline-block;
+ vertical-align: middle;
+ flex-shrink: 0;
+ width: 1em;
+ height: 1em;
+ stroke-width: 2px;
+ transition: transform 0.2s ease, color 0.15s ease;
+}
+
+.svg-drag {
+ width: 12px;
+ height: 18px;
+}
+
+h2 .svg-icon,
+h3 .svg-icon {
+ margin-right: 0.5rem;
+ font-size: 1.15em;
+ color: var(--admin-accent);
+}
+
+/* Album Card Simplification & Grid Spacing */
+.album-list {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
+ gap: 1.25rem;
+ margin: 0.5rem 0 1.25rem;
+}
+
+.album-tile {
+ background: var(--admin-bg-raised);
+ border: 1px solid var(--admin-border);
+ border-radius: 12px;
+ overflow: hidden;
+ position: relative;
+ transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+}
+
+.album-tile:hover {
+ transform: translateY(-2px);
+ border-color: var(--admin-border-hover);
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
+}
+
+[data-theme='light'] .album-tile:hover {
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
+}
+
+.album-tile-cover {
+ aspect-ratio: 16 / 11;
+ border-bottom: 1px solid var(--admin-border);
+ position: relative;
+ background: var(--admin-bg-elevated);
+ overflow: hidden;
+}
+
+.album-tile-placeholder {
+ color: var(--admin-text-muted);
+ font-size: 1.75rem;
+}
+
+.album-tile-overlay {
+ display: flex;
+ gap: 0.5rem;
+}
+
+.album-tile-btn {
+ background: rgba(17, 17, 17, 0.85);
+ backdrop-filter: blur(8px);
+ border: 1px solid var(--admin-border);
+ color: var(--admin-text);
+ width: 32px;
+ height: 32px;
+ border-radius: 8px;
+ transition: all 0.15s ease;
+}
+
+.album-tile-btn:hover {
+ background: var(--admin-accent);
+ color: #000;
+ border-color: var(--admin-accent);
+}
+
+.album-tile-btn-danger:hover {
+ background: var(--admin-error) !important;
+ color: #fff !important;
+ border-color: var(--admin-error) !important;
+}
+
+.album-tile-info {
+ padding: 0.75rem;
+ display: flex;
+ flex-direction: column;
+ gap: 0.25rem;
+}
+
+.album-tile-title-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.5rem;
+}
+
+.album-tile-name {
+ font-size: 0.85rem;
+ font-weight: 600;
+ color: var(--admin-text);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ flex: 1;
+}
+
+.album-tile-name.custom-title {
+ color: var(--admin-accent);
+ font-style: italic;
+}
+
+/* Badges for status indications */
+.album-tile-badges {
+ display: flex;
+ gap: 0.25rem;
+ flex-shrink: 0;
+}
+
+.album-tile-badges .badge {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 18px;
+ height: 18px;
+ border-radius: 4px;
+ font-size: 0.7rem;
+ background: var(--admin-bg-elevated);
+ border: 1px solid var(--admin-border);
+ color: var(--admin-text-secondary);
+}
+
+.album-tile-badges .badge-password {
+ color: var(--admin-accent);
+ border-color: rgba(245, 158, 11, 0.3);
+ background: rgba(245, 158, 11, 0.05);
+}
+
+.album-tile-badges .badge-hero {
+ color: var(--admin-success);
+ border-color: rgba(74, 222, 128, 0.3);
+ background: rgba(74, 222, 128, 0.05);
+}
+
+/* ── Drawer Component styling ── */
+.album-drawer-overlay {
+ position: fixed;
+ inset: 0;
+ z-index: 1000;
+ background: var(--admin-overlay);
+ backdrop-filter: blur(8px);
+ display: flex;
+ justify-content: flex-end;
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+.album-drawer-overlay.open {
+ opacity: 1;
+ pointer-events: auto;
+}
+
+.album-drawer {
+ width: 100%;
+ max-width: 460px;
+ height: 100%;
+ background: var(--admin-bg-raised);
+ border-left: 1px solid var(--admin-border);
+ box-shadow: -8px 0 32px rgba(0, 0, 0, 0.35);
+ display: flex;
+ flex-direction: column;
+ transform: translateX(100%);
+ transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+.album-drawer-overlay.open .album-drawer {
+ transform: translateX(0);
+}
+
+.album-drawer-header {
+ padding: 1.25rem 1.5rem;
+ border-bottom: 1px solid var(--admin-border);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ background: var(--admin-bg-elevated);
+}
+
+.album-drawer-header h3 {
+ font-size: 1.1rem;
+ font-weight: 700;
+ margin: 0;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.album-drawer-body {
+ flex: 1;
+ overflow-y: auto;
+ padding: 1.5rem;
+ display: flex;
+ flex-direction: column;
+ gap: 1.5rem;
+}
+
+.album-drawer-body::-webkit-scrollbar {
+ width: 6px;
+}
+.album-drawer-body::-webkit-scrollbar-track {
+ background: transparent;
+}
+.album-drawer-body::-webkit-scrollbar-thumb {
+ background: var(--admin-border);
+ border-radius: 3px;
+}
+.album-drawer-body::-webkit-scrollbar-thumb:hover {
+ background: var(--admin-border-hover);
+}
+
+.album-drawer-footer {
+ padding: 1.25rem 1.5rem;
+ border-top: 1px solid var(--admin-border);
+ background: var(--admin-bg-elevated);
+ display: flex;
+ gap: 0.75rem;
+}
+
+.album-drawer-footer .admin-btn {
+ flex: 1;
+}
+
+/* Drawer Hero Preview Banner */
+.drawer-hero-section {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ padding: 1rem;
+ background: var(--admin-bg-elevated);
+ border: 1px solid var(--admin-border);
+ border-radius: 10px;
+}
+
+.drawer-hero-cover {
+ width: 90px;
+ height: 60px;
+ border-radius: 6px;
+ overflow: hidden;
+ background: var(--admin-bg);
+ border: 1px solid var(--admin-border);
+ flex-shrink: 0;
+}
+
+.drawer-hero-cover img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.drawer-hero-placeholder {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--admin-text-muted);
+ font-size: 1.25rem;
+}
+
+.drawer-hero-meta {
+ display: flex;
+ flex-direction: column;
+ min-width: 0;
+}
+
+.drawer-hero-name {
+ font-size: 0.9rem;
+ font-weight: 600;
+ color: var(--admin-text);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.drawer-hero-count {
+ font-size: 0.75rem;
+ color: var(--admin-text-secondary);
+}
+
+/* Drawer Copy UUID element */
+.drawer-uuid-section {
+ padding-top: 0.75rem;
+ border-top: 1px solid var(--admin-border);
+}
+
+.drawer-uuid-section label {
+ font-size: 0.7rem;
+ color: var(--admin-text-muted);
+ font-weight: 600;
+ display: block;
+ margin-bottom: 0.35rem;
+ letter-spacing: 0.05em;
+}
+
+.uuid-copy-box {
+ display: flex;
+ align-items: center;
+ background: var(--admin-bg-input);
+ border: 1px solid var(--admin-border);
+ border-radius: 6px;
+ padding: 0.4rem 0.5rem 0.4rem 0.75rem;
+ gap: 0.5rem;
+}
+
+.uuid-copy-box code {
+ font-family: monospace;
+ font-size: 0.75rem;
+ color: var(--admin-text-secondary);
+ flex: 1;
+ word-break: break-all;
+ user-select: all;
+}
+
+.uuid-copy-btn {
+ background: none;
+ border: none;
+ color: var(--admin-text-muted);
+ cursor: pointer;
+ padding: 0.25rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ transition: all 0.15s ease;
+}
+
+.uuid-copy-btn:hover {
+ color: var(--admin-accent);
+ background: var(--admin-bg-elevated);
+}
+
+/* Section Card Improvements */
+.section-card {
+ background: var(--admin-bg-raised);
+ border: 1px solid var(--admin-border);
+ border-radius: 12px;
+ padding: 1.25rem;
+ margin-bottom: 1.25rem;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
+}
+
+.section-card:hover {
+ border-color: var(--admin-border-hover);
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
+}
+
+.section-header {
+ border-bottom: 1px solid var(--admin-border);
+ padding-bottom: 0.5rem;
+ margin-bottom: 0.75rem;
+}
+
+.section-title-input {
+ font-size: 0.95rem !important;
+ font-weight: 700 !important;
+ color: var(--admin-text) !important;
+ border-radius: 6px !important;
+}
+
+.section-desc-input {
+ border-color: transparent !important;
+ background: transparent !important;
+ padding-left: 0.4rem !important;
+ color: var(--admin-text-secondary) !important;
+}
+
+.section-desc-input:focus {
+ border-color: var(--admin-border) !important;
+ background: var(--admin-bg-input) !important;
+}
+
+/* ── Modern Subpage Details Spacing ── */
+.subpage-detail {
+ margin-top: 1.5rem;
+ border: 1px solid var(--admin-border);
+ background: var(--admin-bg-elevated);
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
+}
+
+[data-theme='light'] .subpage-detail {
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.05);
+}
+
+.subpage-meta {
+ padding: 1.25rem;
+ background: var(--admin-bg-raised);
+ border-bottom: 1px solid var(--admin-border);
+}
diff --git a/app/admin/components/PageBuilder.tsx b/app/admin/components/PageBuilder.tsx
index 83db47f..a59ad1e 100644
--- a/app/admin/components/PageBuilder.tsx
+++ b/app/admin/components/PageBuilder.tsx
@@ -22,6 +22,97 @@ import { CSS } from '@dnd-kit/utilities';
import AlbumPicker from './AlbumPicker';
import AssetPicker from './AssetPicker';
+// ── Icons ──────────────────────────────────────────────────────
+const Icons = {
+ Drag: () => (
+
+ ),
+ Edit: () => (
+
+ ),
+ Trash: () => (
+
+ ),
+ Close: () => (
+
+ ),
+ Folder: () => (
+
+ ),
+ Camera: () => (
+
+ ),
+ ExternalLink: () => (
+
+ ),
+ Search: () => (
+
+ ),
+ Lock: () => (
+
+ ),
+ Plus: () => (
+
+ ),
+ Home: () => (
+
+ ),
+ Copy: () => (
+
+ ),
+ Check: () => (
+
+ ),
+ Image: () => (
+
+ ),
+};
+
// ── Types ──────────────────────────────────────────────────────
interface AlbumEntry {
id: string;
@@ -53,6 +144,13 @@ interface GalleryState {
subpages: Subpage[];
}
+interface ActiveEditAlbumAddress {
+ type: 'standalone' | 'subpage' | 'section';
+ subpageIndex?: number;
+ sectionIndex?: number;
+ albumIndex: number;
+}
+
interface ImmichAlbumInfo {
id: string;
albumName: string;
@@ -136,11 +234,11 @@ function SortableHeroTile({
return (
- ⠿
+
{index + 1}
@@ -156,7 +254,7 @@ function SortableAlbumCard({
count,
thumbnailId,
onRemove,
- onUpdate,
+ onEdit,
}: {
album: AlbumEntry;
index: number;
@@ -164,7 +262,7 @@ function SortableAlbumCard({
count: number;
thumbnailId: string | null;
onRemove: () => void;
- onUpdate: (updates: Partial) => void;
+ onEdit: () => void;
}) {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id: `album-${album.id}-${index}`,
@@ -185,7 +283,7 @@ function SortableAlbumCard({
count={count}
thumbnailId={thumbnailId}
onRemove={onRemove}
- onUpdate={onUpdate}
+ onEdit={onEdit}
dragListeners={listeners}
/>
@@ -231,13 +329,15 @@ function SortableSubpageTile({
{...attributes}
>
- ⠿
+
{firstThumb ? (

) : (
-
📂
+
+
+
)}
@@ -265,8 +365,14 @@ export default function PageBuilder() {
subpageIndex?: number;
sectionIndex?: number;
} | null>(null);
- const [showHeroPicker, setShowHeroPicker] = useState(false);
+ const [heroPickerTarget, setHeroPickerTarget] = useState<{
+ albumId?: string;
+ onSelect: (assetId: string) => void;
+ currentAssetIds?: string[];
+ title?: string;
+ } | null>(null);
const [searchQuery, setSearchQuery] = useState('');
+ const [editingAlbumAddress, setEditingAlbumAddress] = useState
(null);
// DnD sensors
const sensors = useSensors(
@@ -449,7 +555,7 @@ export default function PageBuilder() {
// ── Hero Picker ──────────────────────────────────────────────
function handleHeroSelect(assetId: string) {
setGallery((g) => ({ ...g, hero: [...g.hero, assetId] }));
- setShowHeroPicker(false);
+ setHeroPickerTarget(null);
markDirty();
}
@@ -808,9 +914,18 @@ export default function PageBuilder() {
{/* Hero Section */}
-
🏠 Homepage Hero
-
removeStandaloneAlbum(originalIndex)}
- onUpdate={(updates) => {
- setGallery((g) => {
- const albums = [...g.albums];
- albums[originalIndex] = { ...albums[originalIndex], ...updates };
- return { ...g, albums };
- });
- markDirty();
- }}
+ onEdit={() => setEditingAlbumAddress({ type: 'standalone', albumIndex: originalIndex })}
/>
);
})}
@@ -1065,18 +1173,7 @@ export default function PageBuilder() {
count={getAlbumCount(album.id)}
thumbnailId={getAlbumThumbnailId(album.id)}
onRemove={() => removeSubpageAlbum(spIndex, aIndex)}
- onUpdate={(updates) => {
- setGallery((g) => {
- const subpages = [...g.subpages];
- const sp2 = { ...subpages[spIndex] };
- const albums = [...sp2.albums];
- albums[aIndex] = { ...albums[aIndex], ...updates };
- sp2.albums = albums;
- subpages[spIndex] = sp2;
- return { ...g, subpages };
- });
- markDirty();
- }}
+ onEdit={() => setEditingAlbumAddress({ type: 'subpage', subpageIndex: spIndex, albumIndex: aIndex })}
/>
))}
@@ -1104,7 +1201,7 @@ export default function PageBuilder() {
onClick={() => removeSection(spIndex, secIndex)}
title="Remove section"
>
- ×
+
@@ -1128,22 +1225,7 @@ export default function PageBuilder() {
count={getAlbumCount(album.id)}
thumbnailId={getAlbumThumbnailId(album.id)}
onRemove={() => removeSectionAlbum(spIndex, secIndex, aIndex)}
- onUpdate={(updates) => {
- setGallery((g) => {
- const subpages = [...g.subpages];
- const sp2 = { ...subpages[spIndex] };
- const sections = [...(sp2.sections || [])];
- const sec2 = { ...sections[secIndex] };
- const albums = [...sec2.albums];
- albums[aIndex] = { ...albums[aIndex], ...updates };
- sec2.albums = albums;
- sections[secIndex] = sec2;
- sp2.sections = sections;
- subpages[spIndex] = sp2;
- return { ...g, subpages };
- });
- markDirty();
- }}
+ onEdit={() => setEditingAlbumAddress({ type: 'section', subpageIndex: spIndex, sectionIndex: secIndex, albumIndex: aIndex })}
/>
))}
@@ -1194,17 +1276,247 @@ export default function PageBuilder() {
/>
)}
+ {/* Slide-over Drawer for Album Details */}
+ {(() => {
+ if (!editingAlbumAddress) return null;
+ const info = getEditingAlbumInfo(editingAlbumAddress);
+ if (!info) return null;
+ const { album, name, count, thumbnailId, onUpdate, onRemove } = info;
+ const heroThumb = album.heroImage || thumbnailId;
+
+ return (
+ setEditingAlbumAddress(null)}>
+
e.stopPropagation()}>
+
+
+ Edit Album Details
+
+ setEditingAlbumAddress(null)}
+ title="Close details"
+ >
+
+
+
+
+ {/* Album Cover / Hero Preview */}
+
+
+ {heroThumb ? (
+

+ ) : (
+
+
+
+ )}
+
+
+ {name}
+ {count} photos
+
+
+
+ {/* Form Fields */}
+
+
+ onUpdate({ title: e.target.value || undefined })}
+ placeholder={name}
+ />
+
+
+
+
+
+
+
+
+
+ onUpdate({ password: e.target.value || undefined })}
+ placeholder="Leave empty for public access"
+ />
+
+
+
+ {/* Hero Image Selection */}
+
+
+
+ {album.heroImage ? (
+
+

+
onUpdate({ heroImage: undefined })}
+ title="Remove custom hero image"
+ >
+
+
+
+ ) : (
+
Using default album cover
+ )}
+
+ setHeroPickerTarget({
+ albumId: album.id,
+ onSelect: (assetId) => {
+ onUpdate({ heroImage: assetId });
+ setHeroPickerTarget(null);
+ },
+ currentAssetIds: album.heroImage ? [album.heroImage] : [],
+ title: `Pick Hero Image for ${name}`,
+ })
+ }
+ >
+ {album.heroImage ? 'Change Image' : 'Pick Hero Image'}
+
+
+
+
+ {/* Technical UUID */}
+
+
+
+ {album.id}
+ {
+ navigator.clipboard.writeText(album.id);
+ }}
+ title="Copy UUID"
+ >
+
+
+
+
+
+
+ setEditingAlbumAddress(null)}
+ >
+ Done
+
+
+ Remove Album
+
+
+
+
+ );
+ })()}
+
{/* Hero Asset Picker Modal */}
- {showHeroPicker && (
+ {heroPickerTarget && (
setShowHeroPicker(false)}
- currentAssetIds={gallery.hero}
+ albumId={heroPickerTarget.albumId}
+ onSelect={heroPickerTarget.onSelect}
+ onClose={() => setHeroPickerTarget(null)}
+ currentAssetIds={heroPickerTarget.currentAssetIds}
+ title={heroPickerTarget.title}
/>
)}
);
+ function getEditingAlbumInfo(addr: ActiveEditAlbumAddress) {
+ let album: AlbumEntry;
+ let name: string;
+ let count: number;
+ let thumbnailId: string | null;
+ let onUpdate: (updates: Partial) => void;
+ let onRemove: () => void;
+
+ if (addr.type === 'standalone') {
+ album = gallery.albums[addr.albumIndex];
+ if (!album) return null;
+ name = getAlbumName(album.id);
+ count = getAlbumCount(album.id);
+ thumbnailId = getAlbumThumbnailId(album.id);
+ onUpdate = (updates) => {
+ setGallery((g) => {
+ const albums = [...g.albums];
+ albums[addr.albumIndex] = { ...albums[addr.albumIndex], ...updates };
+ return { ...g, albums };
+ });
+ markDirty();
+ };
+ onRemove = () => {
+ removeStandaloneAlbum(addr.albumIndex);
+ };
+ } else if (addr.type === 'subpage') {
+ const sp = gallery.subpages[addr.subpageIndex!];
+ if (!sp) return null;
+ album = sp.albums[addr.albumIndex];
+ if (!album) return null;
+ name = getAlbumName(album.id);
+ count = getAlbumCount(album.id);
+ thumbnailId = getAlbumThumbnailId(album.id);
+ onUpdate = (updates) => {
+ setGallery((g) => {
+ const subpages = [...g.subpages];
+ const sp2 = { ...subpages[addr.subpageIndex!] };
+ const albums = [...sp2.albums];
+ albums[addr.albumIndex] = { ...albums[addr.albumIndex], ...updates };
+ sp2.albums = albums;
+ subpages[addr.subpageIndex!] = sp2;
+ return { ...g, subpages };
+ });
+ markDirty();
+ };
+ onRemove = () => {
+ removeSubpageAlbum(addr.subpageIndex!, addr.albumIndex);
+ };
+ } else {
+ const sp = gallery.subpages[addr.subpageIndex!];
+ if (!sp) return null;
+ const sec = sp.sections?.[addr.sectionIndex!];
+ if (!sec) return null;
+ album = sec.albums[addr.albumIndex];
+ if (!album) return null;
+ name = getAlbumName(album.id);
+ count = getAlbumCount(album.id);
+ thumbnailId = getAlbumThumbnailId(album.id);
+ onUpdate = (updates) => {
+ setGallery((g) => {
+ const subpages = [...g.subpages];
+ const sp2 = { ...subpages[addr.subpageIndex!] };
+ const sections = [...(sp2.sections || [])];
+ const sec2 = { ...sections[addr.sectionIndex!] };
+ const albums = [...sec2.albums];
+ albums[addr.albumIndex] = { ...albums[addr.albumIndex], ...updates };
+ sec2.albums = albums;
+ sections[addr.sectionIndex!] = sec2;
+ sp2.sections = sections;
+ subpages[addr.subpageIndex!] = sp2;
+ return { ...g, subpages };
+ });
+ markDirty();
+ };
+ onRemove = () => {
+ removeSectionAlbum(addr.subpageIndex!, addr.sectionIndex!, addr.albumIndex);
+ };
+ }
+
+ return { album, name, count, thumbnailId, onUpdate, onRemove };
+ }
+
function getAllUsedAlbumIds(): Set {
const ids = new Set();
gallery.albums.forEach((a) => ids.add(a.id));
@@ -1224,7 +1536,7 @@ interface AlbumCardProps {
count: number;
thumbnailId: string | null;
onRemove: () => void;
- onUpdate: (updates: Partial) => void;
+ onEdit: () => void;
dragListeners?: Record;
}
@@ -1234,112 +1546,66 @@ function AlbumCard({
count,
thumbnailId,
onRemove,
- onUpdate,
+ onEdit,
dragListeners,
}: AlbumCardProps) {
- const [expanded, setExpanded] = useState(false);
- const [showHeroPicker, setShowHeroPicker] = useState(false);
+ const heroThumb = album.heroImage || thumbnailId;
+ const hasPassword = !!album.password;
+ const hasTitleOverride = !!album.title;
+ const hasDescription = !!album.description;
return (
-
+
{dragListeners && (
- ⠿
+
)}
- {thumbnailId ? (
-

+ {heroThumb ? (
+

) : (
-
📷
+
+
+
)}
setExpanded(!expanded)}
+ onClick={onEdit}
title="Edit details"
>
- ✏️
+
-
- ×
+
+
- {album.title || name}
- {count} photos
-
- {expanded && (
-
-
-
- onUpdate({ title: e.target.value || undefined })}
- placeholder={name}
- />
-
-
-
- onUpdate({ description: e.target.value || undefined })}
- placeholder="Optional description"
- />
-
-
-
- onUpdate({ password: e.target.value || undefined })}
- placeholder="Leave empty for public"
- />
-
- {/* Hero Image */}
-
-
-
- {album.heroImage ? (
-
-

-
onUpdate({ heroImage: undefined })}
- title="Remove hero image"
- >
- ×
-
-
- ) : (
-
No hero image set
- )}
-
setShowHeroPicker(true)}
- >
- {album.heroImage ? 'Change' : '+ Pick'}
-
-
-
-
-
{album.id}
+
+
+ {album.title || name}
+
+
+ {hasPassword && (
+
+
+
+ )}
+ {album.heroImage && (
+
+
+
+ )}
- )}
- {showHeroPicker && (
-
{
- onUpdate({ heroImage: assetId });
- setShowHeroPicker(false);
- }}
- onClose={() => setShowHeroPicker(false)}
- currentAssetIds={album.heroImage ? [album.heroImage] : []}
- title="Pick Hero Image for Album"
- />
- )}
+ {count} photos
+
);
}