/* Hash router + slug helper + embeddable Media component */
const { useState: uSr, useEffect: uEr } = React;
function slugify(str) {
return String(str).toLowerCase()
.replace(/[^\w\s-]/g, "")
.trim().replace(/\s+/g, "-").slice(0, 60);
}
function parseHash() {
const h = window.location.hash || "";
const m = h.match(/^#!\/(kegiatan|artikel)\/(.+)$/);
if (m) return { type: m[1], slug: decodeURIComponent(m[2]) };
return { type: "home" };
}
/* navigate("kegiatan/" + slug) ; navigate("") -> home */
function navigate(path) {
const target = path ? "#!/" + path : "#";
if (window.location.hash !== target) window.location.hash = target;
else window.dispatchEvent(new HashChangeEvent("hashchange"));
window.scrollTo({ top: 0, behavior: "instant" in window ? "instant" : "auto" });
}
const useRoute = () => {
const [route, setRoute] = uSr(parseHash());
uEr(() => {
const on = () => { setRoute(parseHash()); window.scrollTo(0, 0); };
window.addEventListener("hashchange", on);
return () => window.removeEventListener("hashchange", on);
}, []);
return route;
};
/* ----- Media: renders image OR video; placeholder when src empty ----- */
const isYouTube = (u) => /youtube\.com|youtu\.be/.test(u);
const Media = ({ media, label = "Media", radius, poster, dark }) => {
const m = media || {};
const style = radius ? { borderRadius: radius } : undefined;
if (m.src && m.kind === "image") {
return ;
}
if (m.src && m.kind === "video") {
if (isYouTube(m.src)) {
return ;
}
return ;
}
// placeholder
const isVideo = m.kind === "video";
return (