function slugify(text) {
return String(text || "")
.toLowerCase()
.trim()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
}
function parseRoute(pathname) {
const path = pathname.replace(/\/+$|^\/+/g, "").split("/");
if (!path[0]) return { page: "home" };
if (["about", "work", "services", "insights", "contact", "publish", "login"].includes(path[0])) {
return { page: path[0] };
}
if (path[0] === "post" && path[1]) {
return { page: "post", slug: decodeURIComponent(path[1]) };
}
return { page: "home" };
}
function routePath(page, slug) {
if (page === "home") return "/";
if (page === "post") return slug ? `/post/${encodeURIComponent(slug)}` : "/insights";
return `/${page}`;
}
function App() {
const initialRoute = parseRoute(location.pathname);
const [route, setRoute] = useState(initialRoute);
const [openPost, setOpenPost] = useState(null);
const [admin, setAdmin] = useState(() => window.isAdmin?.() || false);
function updateRoute(nextRoute) {
const path = routePath(nextRoute.page, nextRoute.slug);
window.history.pushState(null, "", path);
setRoute(nextRoute);
}
function go(p) {
let targetPage = p;
if (p === "publish" && !window.isAdmin?.()) targetPage = "login";
if (p === "login" && window.isAdmin?.()) targetPage = "publish";
updateRoute({ page: targetPage });
setOpenPost(null);
window.scrollTo({ top: 0, behavior: "smooth" });
}
function openPostFn(post) {
const slug = post.slug || slugify(post.title);
setOpenPost({ ...post, slug });
updateRoute({ page: "post", slug });
window.scrollTo({ top: 0, behavior: "smooth" });
}
useEffect(() => {
const onClick = (e) => {
const a = e.target.closest("[data-nav]");
if (a) {
e.preventDefault();
go(a.dataset.nav);
}
};
document.addEventListener("click", onClick);
return () => document.removeEventListener("click", onClick);
}, []);
useEffect(() => {
const onPop = () => {
const nextRoute = parseRoute(location.pathname);
setRoute(nextRoute);
if (nextRoute.page !== "post") {
setOpenPost(null);
}
};
window.addEventListener("popstate", onPop);
return () => window.removeEventListener("popstate", onPop);
}, []);
useEffect(() => {
if (route.page === "post" && route.slug) {
const existing = openPost && openPost.slug === route.slug ? openPost : null;
if (existing) return;
const fallback = window.DATA.posts.find((p) => (p.slug || slugify(p.title)) === route.slug);
if (fallback) {
setOpenPost({ ...fallback, slug: route.slug });
return;
}
(async () => {
try {
const wpPost = await window.getWordPressPostBySlug(route.slug);
if (wpPost) setOpenPost({ ...wpPost, slug: route.slug });
} catch (err) {
console.warn("Failed to load post route", err);
}
})();
}
}, [route.page, route.slug]);
useEffect(() => {
const fab = document.querySelector(".fab");
if (!fab) return;
const onScroll = () => {
if (window.scrollY > 600 && route.page !== "contact") fab.classList.add("is-visible");
else fab.classList.remove("is-visible");
};
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, [route.page]);
useEffect(() => {
const bar = document.getElementById("scroll-bar");
if (!bar) return;
const onScroll = () => {
const h = document.documentElement;
const p = h.scrollTop / (h.scrollHeight - h.clientHeight);
bar.style.width = Math.min(100, Math.max(0, p * 100)) + "%";
};
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
const Pages = {
home: window.HomePage,
about: window.AboutPage,
work: window.WorkPage,
services: window.ServicesPage,
insights: window.InsightsPage,
contact: window.ContactPage,
publish: window.PublishPage,
login: window.LoginPage,
};
let content;
if (route.page === "post") {
content = openPost ? (
Loading post…