release: v0.19.0

Release v0.19.0. See the `## [0.19.0] — 2026-09-29` section of
[CHANGELOG.md](https://github.com/ralksta/immich-folio/blob/dev/CHANGELOG.md)
for the full list.

Highlights: client proofing links (#683), custom content pages (#738),
asset picker search (#740), concurrent-edit detection (#742), env-locked
settings (#739), an accessibility baseline (#741), three security fixes
with advisories (#737, #755, #759), and a pre-release quality pass
(#780–#797).

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Ralf <rohlenbo79@gmail.com>
Co-authored-by: Paul Thies <110185070+ImScheinox@users.noreply.github.com>
Co-authored-by: lancetm714 <108419425+lancetm714@users.noreply.github.com>
Co-authored-by: Lance Martin <lancetaylor95@gmail.com>
This commit is contained in:
Ralksta
2026-09-29 22:50:30 +02:00
committed by GitHub
parent 5f251923f0
commit ad8b09700b
297 changed files with 19398 additions and 1800 deletions

View File

@@ -14,6 +14,22 @@ export interface GalleryState {
hero: string[];
albums: AlbumEntry[];
subpages: Subpage[];
/**
* Content pages in the menu (#722): `- page: <slug>` among the subpages.
* Optional so a draft saved before pages existed still loads.
*/
pageRefs?: PageRef[];
}
/**
* A content page placed in the menu. `position` is the number of subpages in
* front of it, so the subpage list keeps its own indexes — every drawer and
* album address in the builder is one — and the menu order is rebuilt from
* both lists when saving. Refs sharing a position keep their array order.
*/
export interface PageRef {
slug: string;
position: number;
}
/**
@@ -27,8 +43,18 @@ export function parseGalleryYaml(raw: Record<string, unknown>): GalleryState {
);
let subpages: Subpage[] = [];
const pageRefs: PageRef[] = [];
if (Array.isArray(raw.subpages)) {
subpages = (raw.subpages as Array<Record<string, unknown>>).map((sp) => ({
const entries = raw.subpages as Array<Record<string, unknown>>;
const subpageEntries: Array<Record<string, unknown>> = [];
for (const entry of entries) {
if (entry && typeof entry.page === 'string') {
pageRefs.push({ slug: entry.page, position: subpageEntries.length });
} else {
subpageEntries.push(entry);
}
}
subpages = subpageEntries.map((sp) => ({
name: (sp.name as string) || '',
title: sp.title as string | undefined,
subtitle: sp.subtitle as string | undefined,
@@ -77,7 +103,7 @@ export function parseGalleryYaml(raw: Record<string, unknown>): GalleryState {
});
}
return { hero, albums, subpages };
return { hero, albums, subpages, pageRefs };
}
/** The gallery.yaml object for a builder state. Empty groups are left out. */
@@ -90,8 +116,9 @@ export function serializeGallery(gallery: GalleryState): Record<string, unknown>
if (gallery.albums.length > 0) {
yamlData.albums = serializeAlbumEntries(gallery.albums);
}
if (gallery.subpages.length > 0) {
yamlData.subpages = gallery.subpages.map((sp) => {
const pageRefs = gallery.pageRefs ?? [];
if (gallery.subpages.length > 0 || pageRefs.length > 0) {
const subpageEntries = gallery.subpages.map((sp) => {
const entry: Record<string, unknown> = { name: sp.name };
if (sp.title) entry.title = sp.title;
if (sp.subtitle) entry.subtitle = sp.subtitle;
@@ -124,7 +151,25 @@ export function serializeGallery(gallery: GalleryState): Record<string, unknown>
return entry;
});
yamlData.subpages = interleave(subpageEntries, pageRefs);
}
return yamlData;
}
/** Subpage entries with `{ page }` entries placed at their positions. */
function interleave(
subpageEntries: Record<string, unknown>[],
pageRefs: PageRef[],
): Record<string, unknown>[] {
const out: Record<string, unknown>[] = [];
for (let i = 0; i <= subpageEntries.length; i++) {
// A ref beyond the end (a subpage was removed) lands at the end.
for (const ref of pageRefs) {
const at = Math.min(ref.position, subpageEntries.length);
if (at === i) out.push({ page: ref.slug });
}
if (i < subpageEntries.length) out.push(subpageEntries[i]);
}
return out;
}