// site-archive.jsx — Archive landing, edition pages, and archive strand pages. // Convert old archive award string → display label function archiveAwardLabel(film) { const a = film.award || ""; const s = film.strand || ""; if (!a) return ""; if (a === "Audience") return "Paper Bird \u2014 Audience Award"; if (a === "Jury" || a === "Documentary" || a === "Fiction" || a === "Animation" || a === "Experimental") { return "Paper Bird \u2014 " + s + " Winner"; } if (a === "Special Mention") return "Special Mention \u2014 " + s; // Already a full label if (a.includes("Paper Bird") || a.includes("Special Mention")) return a; return ""; } const STRAND_C = { Fiction: { hex: "#ff5c70", bg: "var(--pink)", text: "#fff" }, Animation: { hex: "#ffc823", bg: "var(--yellow)", text: "#16151a" }, Documentary: { hex: "#784c95", bg: "var(--purple)", text: "#fff" }, Experimental: { hex: "#65c8d0", bg: "var(--cyan)", text: "#16151a" }, Audience: { hex: "#F0EEE9", hexLight: "#16151a", bg: "#F0EEE9", text: "#16151a" }, }; // ── Enriched archive data ──────────────────────────────────────────────────── const EDITIONS = { 2021: { label: "I", dates: "April 2021", location: "Online", note: "The founding edition — held entirely online during the pandemic. The festival showcased an international collection of student short films across three strands.", filmCount: 29, poster: "https://i0.wp.com/ljmumashortfilmfestival.org/wp-content/uploads/2021/03/ljmu_ma_sff_poster_1st_editionartboard-1.png?resize=750%2C1061&ssl=1", banner: "https://i0.wp.com/ljmumashortfilmfestival.org/wp-content/uploads/2021/03/ljmumasff_thin_banner.png?resize=750%2C141&ssl=1", strands: ["Fiction", "Animation", "Documentary"], trailer: "FynDdF7ESgI", strandTrailers: { Fiction: "2n8EMZYUL1s", Animation: "v5-vuAF83EM", Documentary: "A0hxOd7ZOag" }, ceremony: "6RmawQydVHQ", awards: [ { strand: "Fiction", film: "End of the World", director: "Karol Ulman" }, { strand: "Animation", film: "Blue Monday", director: "Katarzyna Orłowska" }, { strand: "Documentary", film: "Rain Pot", director: "Gordon Moore" }, { strand: "Audience", film: "Lost Ore Abdurrahim", director: "Pınar Yıldırım Karaman" }, ], qas: [ { strand: "Documentary", hosts: "Katherine Morrison", date: "17 Apr, 12:00 GMT+1", video: "OtKAdqcrYV0" }, { strand: "Animation", hosts: "Jess Auger", date: "18 Apr, 12:00 GMT+1", video: "KdtgztWg9h8" }, { strand: "Fiction", hosts: "Connor Norcott", date: "19 Apr, 12:00 GMT+1", video: "chLhmceVnEQ" }, ], }, 2022: { label: "II", dates: "1–8 April 2022", location: "Online", note: "The second edition — 40 films from 22 countries premiered digitally, with Q&A sessions and a live awards ceremony on YouTube.", filmCount: 40, poster: "", banner: "https://i0.wp.com/ljmumashortfilmfestival.org/wp-content/uploads/2022/02/header-1-01.png?resize=750%2C250&ssl=1", strands: ["Fiction", "Animation", "Documentary"], trailer: "wVhPNDU0kzI", strandTrailers: { Fiction: "deizQkaUSnI", Animation: "t463EEO0zUs", Documentary: "3UUITNBipPI" }, ceremony: "FHObScaBbTQ", awards: [ { strand: "Fiction", film: "Well, You Are A Fool Lisa", director: "Oleksandra Konoplia" }, { strand: "Animation", film: "The Pattern", director: "Péter Bogyó" }, { strand: "Documentary", film: "Milo", director: "Nadia Szymańska" }, { strand: "Audience", film: "13 Hertz", director: "Filipa Neves & Rudi Navarro" }, ], qas: [ { strand: "Documentary", hosts: "", date: "2 Apr, 16:00 GMT+1", video: "dGFuAfgAjh8" }, { strand: "Animation", hosts: "", date: "4 Apr, 16:00 GMT+1", video: "Tk6UeieKops" }, { strand: "Fiction", hosts: "", date: "5 Apr, 16:00 GMT+1", video: "FN_tfgV6r_U" }, ], }, 2023: { label: "III", dates: "24–31 March 2023", location: "Online", note: "The third edition — first Experimental strand introduced. Films from around the world premiered digitally across four strands, with Q&A sessions and a live awards ceremony.", filmCount: 42, poster: "https://i0.wp.com/ljmumashortfilmfestival.org/wp-content/uploads/2023/01/poster-2.png?resize=750%2C971&ssl=1", banner: "", strands: ["Fiction", "Animation", "Documentary", "Experimental"], trailer: "HHuvfB2fo7M", strandTrailers: { Fiction: "tLu53lDsOsU", Animation: "p1j1hsqvZg8", Documentary: "jIjxOZ51-iM", Experimental: "g-SR6kaswc8" }, ceremony: "d0sKmj41k4k", awards: [ { strand: "Fiction", film: "Rue", director: "Casey Eldridge" }, { strand: "Animation", film: "Small Hours", director: "Marta Sniezek & Christian Spurling" }, { strand: "Documentary", film: "The Gallery", director: "Cordula Rieger" }, { strand: "Experimental", film: "Soliloquium", director: "Karolina Monwid-Olechnowicz" }, { strand: "Audience", film: "Out of Order", director: "Charlie Ledwidge, Harley Hunt, Sam Stevens, Mariana Sandoval Valencia" }, ], qas: [ { strand: "Documentary", hosts: "Libby Watson-Brown", date: "25 Mar, 16:00 GMT", video: "KdeAHbUEk6c" }, { strand: "Fiction/Experimental", hosts: "Magic Nowak & Shannon Byrne", date: "27 Mar, 16:00 GMT+1", video: "nYOjUnaPBZo" }, { strand: "Animation", hosts: "Lauren Wright", date: "28 Mar, 16:00 GMT+1", video: "6yH1NhX9woc" }, ], }, 2024: { label: "IV", dates: "15–22 March 2024", location: "Online", note: "The fourth edition — films from across the globe premiered digitally across four strands, with Q&A sessions and a live awards ceremony.", filmCount: 36, poster: "https://i0.wp.com/ljmumashortfilmfestival.org/wp-content/uploads/2024/01/2024-Poster-Final.png?resize=214%2C300&ssl=1", banner: "https://i0.wp.com/ljmumashortfilmfestival.org/wp-content/uploads/2024/02/Horizontal-Banner-New-1.png?resize=750%2C277&ssl=1", strands: ["Fiction", "Animation", "Documentary", "Experimental"], trailer: "aheofP1uPJo", strandTrailers: { Fiction: "56_BRYYU9Zg", Animation: "wdmfc7InQH8", Documentary: "Avu4p6Ry55Y", Experimental: "JMKU9tWHvtY" }, ceremony: "dLJGta-Bgl4", awards: [ { strand: "Fiction", film: "Two-Syllable Name", director: "Giovanna Castellari Peixoto" }, { strand: "Animation", film: "Dead Silent", director: "Miriam Fox" }, { strand: "Documentary", film: "Honey Bunny Duracell", director: "Nelisa Alcalde" }, { strand: "Experimental", film: "Obscura", director: "Lucas Kua" }, { strand: "Audience", film: "Valdo", director: "Emilia Ferrari" }, ], qas: [ { strand: "Documentary", hosts: "Peter Sutcliffe & Georgina Taylor", date: "18 Mar, 19:00 GMT", video: "Z1Icnur1Cds" }, { strand: "Animation", hosts: "Nick Box & Gabi Lewcock", date: "19 Mar, 19:00 GMT", video: "9tG9jGmgbHE" }, { strand: "Fiction", hosts: "Mhairi Armstrong & Isaac Moon", date: "20 Mar, 19:00 GMT", video: "DFFBtv3iQaY" }, { strand: "Experimental", hosts: "Frank Greally", date: "21 Mar, 16:00 GMT", video: "WXMCeLQVAvA" }, ], }, 2025: { label: "V", dates: "28 March – 4 April 2025", location: "Liverpool", note: "The fifth edition — 38 films, four strands, and a week of screenings and Q&As across the city.", filmCount: 37, poster: "https://i0.wp.com/ljmumashortfilmfestival.org/wp-content/uploads/2025/02/Poster-A3-Large-v5-final.png?resize=212%2C300&ssl=1", banner: "https://i0.wp.com/ljmumashortfilmfestival.org/wp-content/uploads/2025/02/Banner-date-fixed.jpg?resize=750%2C276&ssl=1", strands: ["Documentary", "Animation", "Fiction", "Experimental"], trailer: "S02-i8DdcP8", strandTrailers: { Fiction: "9Tw0ANujOhw", Animation: "hj6sPRh8_yM", Documentary: "oSf4CHP6Akk", Experimental: "6UQli9a4KM0" }, ceremony: "6Aj47p2jdV4", awards: [ { strand: "Fiction", film: "Count My Lov3", director: "Ewa Japola" }, { strand: "Animation", film: "Why Won't Anyone Eat Me?", director: "Lewis Macaulay" }, { strand: "Documentary", film: "Swim Higher", director: "Cecilia Palmeri" }, { strand: "Experimental", film: "A Train Arrives", director: "Raphael Heinisch" }, { strand: "Audience", film: "Roots", director: "Max Vázquez Montufar" }, ], qas: [ { strand: "Documentary", hosts: "John Mortimer & Bridget Harvey", date: "31 Mar, 18:00 GMT", video: "oWbeHbD2eEY" }, { strand: "Animation", hosts: "Viv Nelson & Oscar Bradshaw", date: "1 Apr, 18:00 GMT", video: "CNJW5a34SKU" }, { strand: "Fiction", hosts: "Jake Butcher & Josh Darlington", date: "2 Apr, 18:00 GMT", video: "tzKcFR7pcMs" }, { strand: "Experimental", hosts: "Harry O'Connell & Devan Jones", date: "3 Apr, 18:00 GMT", video: "0L41pqQeMAs" }, ], }, }; const EDITION_NAMES = { 2021: "First", 2022: "Second", 2023: "Third", 2024: "Fourth", 2025: "Fifth" }; const YEARS = [2025, 2024, 2023, 2022, 2021]; // ── Helper: get archive films for a year/strand ───────────────────────────── function getArchiveFilms(year, strand) { const all = (window.ARCHIVE_FILMS || {})[year] || []; if (!strand) return all; const key = strand.charAt(0).toUpperCase() + strand.slice(1).toLowerCase(); return all.filter((f) => f.strand === key); } // ── Archive router ─────────────────────────────────────────────────────────── function Archive({ navigate, year, strand, filmId }) { if (year && strand && filmId) return ; if (year && strand) return ; if (year && EDITIONS[year]) return ; return ; } // ── Archive landing — all editions ─────────────────────────────────────────── function ArchiveLanding({ navigate }) { const d = useSite(); const totalFilms = YEARS.reduce((s, y) => s + (EDITIONS[y]?.filmCount || 0), 0) + d.films.length; const pg = d.festival?.pages?.archive || {}; const stats = pg.stats || [ { id: "s1", label: "Films screened", value: totalFilms }, { id: "s2", label: "Editions", value: "Six" }, { id: "s3", label: "Paper Birds", value: "30+" }, { id: "s4", label: "Countries", value: "40+" }, ]; return ( {/* Hero */}
Archive · 2021—{d.festival.year}

{(pg.heroTitle || "Six editions of looking.").replace(/\s+(\S+\.)$/, "")} {(pg.heroTitle || "Six editions of looking.").match(/\s+(\S+\.)$/)?.[1] || "of looking."}

{pg.heroLead || "Welcome to the archive of the LJMU MA Short Film Festival."}

{stats.map(({id,label,value}, i) => (
{label} {value}
))}
{/* Edition rows */} {YEARS.map((year, idx) => { const ed = EDITIONS[year]; const isDark = idx % 2 === 0; const bg = isDark ? "var(--ink)" : "var(--paper)"; const fg = isDark ? "var(--paper)" : "var(--ink)"; const muted = isDark ? "var(--muted-d)" : "var(--muted)"; const line = isDark ? "var(--line-d)" : "var(--line)"; return (
navigate("/archive/" + year)}>
{EDITION_NAMES[year] || ed.label} Edition · {ed.dates} {ed.filmCount} films · {ed.location}

{year}

{ed.note}

{/* All awards */}
{ed.awards.map((a) => (
{a.strand} {a.film}
))}
); })}
); } // ── Archive edition page ───────────────────────────────────────────────────── function ArchiveEdition({ navigate, year }) { const ed = EDITIONS[year]; if (!ed) return ; return ( {/* Hero */}
{EDITION_NAMES[year] || ed.label} Edition · {ed.dates}

{year}

{ed.note}

{[["Films", ed.filmCount], ["Location", ed.location], ["Awards", ed.awards.length]].map(([k, v]) => ( {k}: {v} ))}
{ed.poster && (
{"Edition
)}
{/* Strand buttons */}
{ed.strands.map((strand) => { const sc = STRAND_C[strand] || {}; return ( ); })}
{ed.trailer && (
{EDITION_NAMES[year] || ed.label} Edition · Trailer

Watch the {year} trailer.

{ed.filmCount} films across {ed.strands.length} strands. The {EDITION_NAMES[year] || ed.label} Edition of the LJMU MA Short Film Festival.

)} {/* Strand trailers */} {Object.keys(ed.strandTrailers).length > 0 && (
Strand Trailers
{Object.entries(ed.strandTrailers).map(([strand, vid]) => (
{strand} Trailer · {year}
))}
)} {/* Paper Bird Awards */}
Paper Bird Awards

The honour roll.

{ed.awards.map((a) => (
{a.strand} {a.film} dir. {a.director}
))}
{ed.ceremony && (
Awards Ceremony

Ceremony highlights.

)}
{/* Q&As */} {ed.qas.length > 0 && (
Q&A Sessions

Filmmaker Q&As.

Recorded conversations with the filmmakers from each strand.

{ed.qas.map((qa) => (
{qa.strand} Q&A
Hosted by {qa.hosts} · {qa.date}
))}
)} {/* Navigate to other editions */}
More editions
{YEARS.map((y) => { const e = EDITIONS[y]; const isCurrent = String(y) === String(year); return ( ); })}
); } // ── Archive strand page ────────────────────────────────────────────────────── function ArchiveStrand({ navigate, year, strand }) { const key = strand ? strand.charAt(0).toUpperCase() + strand.slice(1).toLowerCase() : ""; const ed = EDITIONS[year]; if (!ed) return ; const sc = STRAND_C[key] || {}; const winner = ed.awards.find((a) => a.strand === key); const strandTrailer = ed.strandTrailers?.[key]; const films = getArchiveFilms(year, key); const [q, setQ] = React.useState(""); const shown = q ? films.filter((f) => (f.title + f.directors + f.country).toLowerCase().includes(q.toLowerCase())) : films; return ( {/* Hero */}

{key}

{EDITION_NAMES[year] || ed.label} Edition · {year} · {ed.location} · {films.length} films {films.length > 4 && setQ(e.target.value)} style={{ maxWidth: 220, color: "#000", background: "rgba(255,255,255,0.2)", border: "1px solid rgba(255,255,255,0.3)", color: sc.text, fontSize: 13 }} />}
{/* Film grid */}
{shown.length === 0 ? (

No films match your search.

) : (
{shown.map((film, i) => (
navigate("/archive/" + year + "/" + strand + "/" + film.id)}>
{archiveAwardLabel(film) ? "★ Winner" : key} {film.runtime && {film.runtime}}
{film.title}
{film.directors &&
{film.directors}{film.country ? " · " + film.country : ""}
}
))}
)}
{/* Winner highlight */} {winner && (
Paper Bird Award · {key}

{winner.film}

dir. {winner.director}

Winner of the Paper Bird Award for Best {key} Film at the {year} LJMU MA Short Film Festival, the {EDITION_NAMES[year] || ed.label} Edition.

)} {/* Strand trailer */} {strandTrailer && (
{key} Strand Trailer · {year}
)} {/* Other strands */}
Other strands · {year}
{ed.strands.map((s) => { const c = STRAND_C[s] || {}; const isCurrent = s === key; return ( ); })}
); } // ── Archive film detail ────────────────────────────────────────────────────── function ArchiveFilmDetail({ navigate, year, strand, filmId }) { const ed = EDITIONS[year]; const allFilms = getArchiveFilms(year, strand); const film = allFilms.find((f) => f.id === filmId) || ((window.ARCHIVE_FILMS || {})[year] || []).find((f) => f.id === filmId); const key = strand ? strand.charAt(0).toUpperCase() + strand.slice(1).toLowerCase() : (film?.strand || ""); const sc = STRAND_C[key] || {}; const meta = { hex: sc.hex || "var(--ink)", textOn: sc.text || "#fff" }; if (!film || !ed) { return (

Film not found

); } const others = allFilms.filter((f) => f.id !== filmId).slice(0, 4); // Director bios const dirBios = film.directorBio ? film.directors.split(/\s*[&,]\s*/).map((n) => ({ name: n.trim(), bio: film.directorBio })).filter((d) => d.name) : film.directors ? film.directors.split(/\s*[&,]\s*/).map((n) => ({ name: n.trim(), bio: "" })).filter((d) => d.name) : []; // Credits const rawCredits = film.credits || {}; const creditFields = [ ["Director", film.directors || "—"], ["Country", film.country || "—"], ["Runtime", film.runtime || "—"], ["Strand", key], ["Film School", film.school || "—"], ...Object.entries(rawCredits).filter(([k]) => k !== "Director"), ]; return ( {/* ── Hero: full-bleed poster background + gradient overlay ── */}
{/* Poster — full bleed background */}
{/* Gradient: solid strand colour on left → transparent on right */}
{/* Bottom fade into strand colour */}
{/* Content layer */}
{/* Back link */} {/* Title block — left side, max 62% width so poster shows through on right */}

{film.title}

{film.directors}
{[film.country, film.runtime ? film.runtime + " min" : null, film.school].filter(Boolean).join(" · ")}
{archiveAwardLabel(film) && (
{archiveAwardLabel(film)}
)}
{/* ── Synopsis + meta ── */}
Synopsis {film.synopsis ?

{film.synopsis}

:

Synopsis to be added.

}
{[["Country", film.country || "—"], ["Runtime", film.runtime || "—"], ["Strand", key], ...(film.school ? [["School", film.school]] : []), ["Edition", (EDITION_NAMES[year] || ed.label) + " Edition · " + year]].map(([k, v]) => (
{k} {v}
))}
{/* ── Director(s) — bigger photo, full bio ── */}
{dirBios.length > 1 ? "Directors" : "Director"}
{dirBios.map((dir) => (
openLightbox([{ url: "https://i.pravatar.cc/600?u=" + encodeURIComponent(dir.name + film.id), caption: dir.name }])}> {dir.name}
{dir.name}
Director{film.country ? " · " + film.country : ""}{film.school ? " · " + film.school : ""}
{dir.bio ?

{dir.bio}

:

Director biography to be added.

}
))}
{/* ── Stills ── */} {(() => { const urls = Array.from({ length: 3 }, (_, i) => autoSrc(film.title + "s" + i + year, undefined, "16/9")); const items = urls.map(u => ({ url: u, caption: film.title })); return (
Stills
{urls.map((u, i) => (
openLightbox(items, i)}> {film.title
))}
); })()} {/* ── Full credits ── */}
Full credits
{creditFields.map(([k, v]) => (
{k} {v}
))}
{/* ── More from this strand ── */} {others.length > 0 && (

More {key}

navigate("/archive/" + year + "/" + strand)}>All {key} · {year}
{others.map((o, i) => (
navigate("/archive/" + year + "/" + strand + "/" + o.id)}>
{archiveAwardLabel(o) ? "★ Winner" : key} {o.runtime && {o.runtime}}
{o.title}
{o.directors &&
{o.directors}
}
))}
)}
); } Object.assign(window, { Archive, EDITIONS, EDITION_NAMES, getArchiveFilms });