6.9 KiB
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<main>, then call{{template "site_end" .}}. - Public navigation generally uses
hx-boost="true"withhx-target="body"and fullbodyreplacement. - 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.htmlhead- 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_contentprojects_contentproject_contentstudio_contentservices_contentcontact_content
- define only page content partials, for example:
Rendering Model
Direct Page Load
Normal browser requests render the full shell:
<!doctype html>
<html>
<head>...</head>
<body>
<div class="drawer drawer-end">
...
<main id="main-content">
page content
</main>
...
</div>
</body>
</html>
HTMX Navigation
HTMX requests return:
- the new
#main-contentelement - 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:
hx-target="body"
hx-swap="outerHTML transition:true"
to main-content replacement:
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-enddrawer-toggledrawer-contentdrawer-sidedrawer-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/45backdrop-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-contenthasview-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:
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.htmlfull shell,home_partial.htmlprojects.htmlfull shell,projects_partial.htmlproject.htmlfull shell,project_partial.htmlabout.htmlfull shell,about_partial.htmlservices.htmlfull shell,services_partial.htmlcontact.htmlfull shell,contact_partial.html
Alternatively, each page file can define:
page_fullpage_partialpage_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
- Refactor
base.htmlinto the full public shell. - Convert one page, preferably Home, to full/partial/content templates.
- Add
renderPublic. - Convert remaining public pages.
- Add OOB nav fragments.
- Update HTMX targets in header, drawer, and internal CTAs.
- Adjust transition CSS for
#main-content. - Add drawer close-on-link/Escape behavior.
- Update tests.
- 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-contentswaps. This can be handled later with an OOB<title>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.