From b33ffa3371b07c4a4add41777c34c4fca8465bd4 Mon Sep 17 00:00:00 2001 From: Caleb Braaten Date: Sat, 18 Oct 2025 16:42:19 -0700 Subject: [PATCH] Complete wip: New Application Architecture Add support for client side routing and updating without loading the AppShell --- index.tsx | 4 ++-- src/frontend/blog.tsx | 1 + src/frontend/home.tsx | 1 + src/public/head.ts | 1 - src/public/onLoad.ts | 53 ++++++++++++++++++++++++++++++++----------- 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/index.tsx b/index.tsx index 3ef1dbb..0faa54f 100644 --- a/index.tsx +++ b/index.tsx @@ -11,8 +11,8 @@ const index = new Elysia() console.log(`Request ${request.method} ${request.url}`); }) .onAfterHandle(({ request, responseValue }) => { - if (request.headers.get("hx-request") === "true") { - return responseValue; // Return the
element if the request is an HTMX request + if (request.headers.get("shell-loaded") === "true") { + return responseValue; // Return the
element if the AppShell has already been loaded } return AppShell(responseValue); // Return the
element wrapped by the AppShell }) diff --git a/src/frontend/blog.tsx b/src/frontend/blog.tsx index 2d175af..25dc769 100644 --- a/src/frontend/blog.tsx +++ b/src/frontend/blog.tsx @@ -4,6 +4,7 @@ export function Blog() { return (

Blog

+ Home
) } \ No newline at end of file diff --git a/src/frontend/home.tsx b/src/frontend/home.tsx index 7459953..bb1ad8a 100644 --- a/src/frontend/home.tsx +++ b/src/frontend/home.tsx @@ -4,6 +4,7 @@ export function Home() { return (

Home

+ Blog
) } \ No newline at end of file diff --git a/src/public/head.ts b/src/public/head.ts index a5843d1..7cac48f 100644 --- a/src/public/head.ts +++ b/src/public/head.ts @@ -9,4 +9,3 @@ logPageInfo(); } })(); - diff --git a/src/public/onLoad.ts b/src/public/onLoad.ts index 3a049d8..0da940f 100644 --- a/src/public/onLoad.ts +++ b/src/public/onLoad.ts @@ -1,16 +1,43 @@ // Client-side script that runs on page load // Example: TypeScript with type annotations -(() => { - const setupPage = (): void => { - const links: NodeListOf = document.querySelectorAll('a'); - console.log(`Found ${links.length} links on the page`); - }; - - // Run setup when DOM is ready - if (document.readyState !== 'loading') { - setupPage(); - } else { - document.addEventListener('DOMContentLoaded', setupPage); - } -})(); +async function loadContent(url: string) { + const response = await fetch(url, { + headers: { + 'shell-loaded': 'true' + } + }); + const html = await response.text(); + const mainElement = document.querySelector('main'); + if (mainElement) { + mainElement.outerHTML = html; + // Re-attach handlers to new links after content swap + attachLinkHandlers(); + } +} + +function attachLinkHandlers() { + const links: NodeListOf = document.querySelectorAll('a'); + console.log('Found links:', links.length); + + links.forEach(link => { + console.log('Attaching listener to:', link.href); + link.onclick = async (e) => { + console.log('clicked', link.href); + e.preventDefault(); + e.stopPropagation(); + e.stopImmediatePropagation(); + window.history.pushState({}, '', link.href); + await loadContent(link.href); + } + }); +} + +// Listen for back/forward button clicks +window.addEventListener('popstate', async (event) => { + await loadContent(window.location.href); +}); + +document.addEventListener('DOMContentLoaded', () => { + attachLinkHandlers(); +});