sabisan/ROUND_4.md

245 lines
6.9 KiB
Markdown
Raw Permalink Normal View History

2026-05-17 12:55:41 +00:00
# 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"` 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
<!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-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 `<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.