Files
jimi-gallery/assets/app.js
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

130 lines
3.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Shared helpers for public pages.
function fmtDate(iso) {
if (!iso) return "";
const d = new Date(iso + "T00:00:00");
return d.toLocaleDateString(getLocale(), {
month: "long",
day: "numeric",
year: "numeric"
});
}
function fmtRange(start, end) {
if (!start || !end) return "";
const locale = getLocale();
const s = new Date(start + "T00:00:00");
const e = new Date(end + "T00:00:00");
const sMonth = s.toLocaleDateString(locale, { month: "long" });
const eMonth = e.toLocaleDateString(locale, { month: "long" });
const sameYear = s.getFullYear() === e.getFullYear();
if (sMonth === eMonth && sameYear) {
return `${sMonth} ${s.getDate()} ${e.getDate()}, ${e.getFullYear()}`;
}
if (sameYear) {
return `${sMonth} ${s.getDate()} ${eMonth} ${e.getDate()}, ${e.getFullYear()}`;
}
return `${sMonth} ${s.getDate()}, ${s.getFullYear()} ${eMonth} ${e.getDate()}, ${e.getFullYear()}`;
}
function qs(key) {
return new URLSearchParams(location.search).get(key);
}
function mount(id, html) {
const el = document.getElementById(id);
if (el) el.innerHTML = html;
}
const LOGO_SVG = `
<svg class="brand-mark" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<circle cx="50" cy="50" r="50" fill="#6b3d8f"/>
<g fill="#ffffff" font-family="'Cormorant Garamond','Playfair Display','Times New Roman',serif" font-weight="500" font-style="italic">
<text x="37" y="70" text-anchor="middle" font-size="60">J</text>
<text x="63" y="70" text-anchor="middle" font-size="60">M</text>
</g>
</svg>
`;
function navHtml(active) {
const items = [
["index.html", t("nav.home"), "home"],
["artists.html", t("nav.artists"), "artists"],
["exhibitions.html", t("nav.exhibitions"), "exhibitions"],
["news.html", t("nav.news"), "news"],
["about.html", t("nav.about"), "about"],
["contact.html", t("nav.contact"), "contact"]
];
const s = Store.settings();
return `
<nav class="nav">
<div class="nav-inner">
<a href="index.html" class="brand">
${LOGO_SVG}
<span class="brand-word">${s.galleryName}</span>
</a>
<div class="nav-right">
<div class="nav-links">
${items
.map(
([href, label, key]) =>
`<a href="${href}" class="${
active === key ? "active" : ""
}">${label}</a>`
)
.join("")}
</div>
${langSwitcherHtml()}
</div>
</div>
</nav>
`;
}
function footerHtml() {
const s = Store.settings();
return `
<footer>
<div class="footer-inner">
<div>
<strong>${s.galleryName}</strong>
<div>${L(s.tagline)}</div>
<div style="margin-top:12px">${s.address}</div>
</div>
<div>
<strong>${t("footer.hours")}</strong>
<div>${L(s.hours)}</div>
</div>
<div>
<strong>${t("footer.contact")}</strong>
<a href="tel:${s.phone}">${s.phone}</a>
<a href="mailto:${s.email}">${s.email}</a>
</div>
<div>
<strong>${t("footer.follow")}</strong>
<a href="#">${t("footer.instagram")} ${s.instagram}</a>
<a href="news.html">${t("misc.newsletter")}</a>
</div>
</div>
<div class="footer-inner footer-admin">
<div>© ${new Date().getFullYear()} ${s.galleryName}. ${t("misc.rights_suffix")}</div>
<div></div>
<div></div>
<div style="text-align:right"><a href="admin/index.html">${t("misc.staff_login")}</a></div>
</div>
</footer>
`;
}
function renderChrome(active) {
mount("nav-slot", navHtml(active));
mount("footer-slot", footerHtml());
wireLangSwitcher();
// Update document title if page key maps to a known title
if (active) {
const titleKey = "title." + active;
const s = Store.settings();
document.title = `${t(titleKey)}${s.galleryName}`;
}
}