All checks were successful
Publish / Test, build, and push image (push) Successful in 4m8s
245 lines
6.9 KiB
Markdown
245 lines
6.9 KiB
Markdown
# 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.
|