Files
jimi-gallery/index.html
yakenator 098b55e3b0 feat: initial Jimi Gallery prototype
- Public site (Home/Artists/Exhibitions/News/About/Contact) with EN/KO/JA i18n
- Admin panel with login, CRUD, image upload, multilingual editing
- Exhibition slider/lightbox view
- FastAPI + MongoDB backend, JWT auth
- Docker Compose deployment, behind nginx at jimi.yakenator.io
2026-04-25 12:47:36 +09:00

107 lines
3.7 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Jimi Gallery — Contemporary Art, New York</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Cinzel:wght@500;600&family=Cormorant+Garamond:wght@400;500;600&family=Inter:wght@300;400;500&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="assets/styles.css" />
</head>
<body>
<div id="nav-slot"></div>
<main>
<section id="hero" class="hero"></section>
<hr class="divider" />
<section class="section">
<div class="eyebrow" id="ex-eyebrow"></div>
<div id="exhibitions-preview" class="grid grid-3"></div>
</section>
<hr class="divider" />
<section class="section">
<div class="eyebrow" id="ar-eyebrow"></div>
<div id="artists-preview" class="grid grid-4"></div>
</section>
</main>
<div id="footer-slot"></div>
<script src="assets/i18n.js"></script>
<script src="assets/data.js"></script>
<script src="assets/app.js"></script>
<script>
(async () => {
try { await Store.load(); } catch (e) { return showBootError(e); }
renderChrome("home");
document.getElementById("ex-eyebrow").textContent = t("eyebrow.upcoming_recent");
document.getElementById("ar-eyebrow").textContent = t("eyebrow.artists");
const current = Store.exhibitions().find((e) => e.status === "current") || Store.exhibitions()[0];
const currentArtists = current.artistIds
.map((id) => Store.artist(id)?.name)
.filter(Boolean)
.join(", ");
mount(
"hero",
`
<img class="hero-image" src="${current.hero}" alt="${L(current.title)}" />
<div class="hero-meta">
<div>
<div class="eyebrow">${t("eyebrow.now_on_view")}</div>
<h1>${currentArtists}<br><em style="font-style:italic">${L(current.title)}</em></h1>
</div>
<div class="hero-sub">
<strong>${fmtRange(current.startDate, current.endDate)}</strong>
${current.venue}<br><br>
<a href="exhibition.html?id=${current.id}" style="text-decoration:underline">${t("cta.view_exhibition")}</a>
</div>
</div>
`
);
const others = Store.exhibitions()
.filter((e) => e.id !== current.id)
.slice(0, 3);
mount(
"exhibitions-preview",
others
.map((e) => {
const artistNames = e.artistIds
.map((id) => Store.artist(id)?.name)
.filter(Boolean)
.join(", ");
return `
<a href="exhibition.html?id=${e.id}">
<img class="card-image wide" src="${e.hero}" alt="${L(e.title)}" />
<div class="card-title">${artistNames} — <em>${L(e.title)}</em></div>
<div class="card-sub">${fmtRange(e.startDate, e.endDate)} · ${t("status." + e.status)}</div>
</a>
`;
})
.join("")
);
mount(
"artists-preview",
Store.artists()
.slice(0, 8)
.map(
(a) => `
<a href="artist.html?id=${a.id}">
<img class="card-image" src="${a.portrait}" alt="${a.name}" />
<div class="card-title">${a.name}</div>
<div class="card-sub">${L(a.born)}</div>
</a>
`
)
.join("")
);
})();
</script>
</body>
</html>