# Round 4 Plan: Public Shell, HTMX Partials, and Smoother Navigation ## Goal Refactor the public interface so `base.html` is the single public shell for header, footer, DaisyUI drawer, overlay root, and the stable main content container. Public pages should render either as a full document on direct visits or as main-content partials during HTMX navigation. This keeps the current architecture portfolio style and functionality while making page structure easier to maintain. ## Current State - Public pages call `{{template "site_start" .}}`, then render their own `
`, then call `{{template "site_end" .}}`. - Public navigation generally uses `hx-boost="true"` with `hx-target="body"` and full `body` replacement. - The mobile sidebar now uses DaisyUI drawer structure. - Admin already has a better partial pattern: full page for direct requests, partial panel for HTMX requests, plus out-of-band tab updates. ## Target Structure Use `base.html` as the public shell. Recommended template ownership: - `base.html` - `head` - full public document shell - header - desktop nav - DaisyUI mobile drawer - footer - `#main-content` - `#overlay-root` - OOB nav fragments - Page templates - define only page content partials, for example: - `home_content` - `projects_content` - `project_content` - `studio_content` - `services_content` - `contact_content` ## Rendering Model ### Direct Page Load Normal browser requests render the full shell: ```html ...
...
page content
...
``` ### HTMX Navigation HTMX requests return: - the new `#main-content` element - out-of-band desktop nav active state - out-of-band drawer nav active state - optionally an out-of-band document title update if needed later This mirrors the admin partial strategy. ## HTMX Navigation Changes Change public internal navigation from body replacement: ```html hx-target="body" hx-swap="outerHTML transition:true" ``` to main-content replacement: ```html hx-target="#main-content" hx-swap="outerHTML transition:true" hx-push-url="true" ``` The header, drawer, footer, and overlay root remain stable across page transitions. ## Active Navigation Because only the main content will swap, active navigation state needs to update separately. Use out-of-band fragments: - `#site-desktop-nav` - `#site-drawer-nav` The full shell and HTMX partial responses both render nav from the same template definitions, avoiding duplicated active-state logic. ## Drawer Behavior Keep the DaisyUI drawer: - `drawer drawer-end` - `drawer-toggle` - `drawer-content` - `drawer-side` - `drawer-overlay` Improvements: - Keep the drawer as part of the stable shell, not page content. - Close drawer after clicking a drawer nav link. - Close drawer on Escape. - Keep the matted glass visual: - `bg-neutral-950/45` - `backdrop-blur-xl` - white text - active item underlined ## Smoother Transitions ### Page Content Apply transitions to `#main-content`, not the full body. Recommended CSS: - old content: slight fade out and 4-6px downward motion - new content: fade in and return to zero offset - short duration, around 160-220ms - respect `prefers-reduced-motion` The existing View Transition CSS can be adjusted so: - `#main-content` has `view-transition-name: main-content` - root transitions are less dominant or removed for public navigation - admin panel transitions remain independent ### Drawer DaisyUI handles the structural entry/exit, but add a small custom polish layer if needed: - slightly longer transform duration, around 240ms - eased slide-in/out - backdrop fade around 180-220ms Avoid custom JavaScript animation. Prefer CSS. ## Backend Changes Add a public render helper similar to admin rendering: ```go func (s *Server) renderPublic(w http.ResponseWriter, r *http.Request, fullTemplate, partialTemplate string, data pageData) ``` Behavior: - normal request: render full shell with the correct page content - HTMX request: render partial content plus OOB nav fragments Each public handler should call `renderPublic` instead of `render`. ## Template Naming Plan Suggested full/partial template names: - `home.html` full shell, `home_partial.html` - `projects.html` full shell, `projects_partial.html` - `project.html` full shell, `project_partial.html` - `about.html` full shell, `about_partial.html` - `services.html` full shell, `services_partial.html` - `contact.html` full shell, `contact_partial.html` Alternatively, each page file can define: - `page_full` - `page_partial` - `page_content` Pick one convention and use it everywhere. ## Preserve Current Functionality Must continue working: - direct URL visits - browser back/forward with pushed URLs - non-JavaScript navigation fallback - project image overlay HTMX requests - contact form HTMX submission - admin tab partial behavior - health endpoints - DaisyUI mobile drawer ## Testing Plan Update or add tests for: - direct public routes return full HTML document - HTMX public route requests return partial content, not full document - HTMX public partial responses include OOB nav fragments - active nav state updates for each page - project image overlay still returns only overlay fragment - contact form submission still returns only `contact_result.html` - existing admin HTMX tests still pass Manual checks: - mobile drawer opens/closes on every public page - drawer closes after nav click - drawer closes with Escape - page transitions feel smooth on desktop and mobile - reduced-motion setting disables meaningful animation - browser back/forward updates main content and nav state ## Implementation Order 1. Refactor `base.html` into the full public shell. 2. Convert one page, preferably Home, to full/partial/content templates. 3. Add `renderPublic`. 4. Convert remaining public pages. 5. Add OOB nav fragments. 6. Update HTMX targets in header, drawer, and internal CTAs. 7. Adjust transition CSS for `#main-content`. 8. Add drawer close-on-link/Escape behavior. 9. Update tests. 10. Run full test suite and manually verify key routes. ## Risks - OOB nav fragments can become noisy if duplicated in every page template. Keep them in `base.html`. - Contact form and overlay requests should not use `renderPublic`; they should keep returning small fragments. - Page title will not automatically update if only `#main-content` swaps. This can be handled later with an OOB `` strategy or small JS. - DaisyUI CDN use is acceptable for now, but a proper Tailwind/DaisyUI build pipeline would be better for production performance and version control. ## Recommended Scope For Round 4 Implement the public shell and main-content HTMX navigation first. Do not refactor admin forms or public content sections in the same round. Keep this round focused on layout architecture, navigation maintainability, and smoother transitions.