Files
praxis-page/docs/specs/2026-05-21-praxis-visual-parity-2-design.md
T

158 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Visual Parity Pass 2 — Design Spec
**Date:** 2026-05-21
**Phase:** 1.6 (regression follow-up to Phase 1.5)
**Status:** approved (auto-mode, in-session execution)
## Goal
Close the remaining visual gaps reported by the editor after Phase 1.5 deploy:
the team carousel that was silently dropped during the Grav→Zola content port,
the image-size distortion on the employee block, and a small set of markdown
parsing / template autoescape glitches.
## Non-Goals
- No Phase 2 modernization (typography, mobile, accessibility) — still 1:1 parity.
- No CSS edits — the live theme CSS is the contract; we change markup to match it.
- No production cutover. Staging only.
## Reference
- Live source-of-truth (read-only): `/home/brummel/dev/praxis/orig/`
- Current Zola build output: `/home/brummel/dev/praxis/public/`
- Phase 1.5 spec: `docs/specs/2026-05-20-praxis-visual-parity-design.md`
- Phase 1.5 plan: `docs/plans/2026-05-20-praxis-visual-parity.md`
## Findings
### 1. Team carousel missing on `/team/`
Live (`orig/user/themes/praxis/templates/modular/employees.html.twig`) renders a
Bootstrap-3 carousel: `<section class="employees">``<div id="employeesSlider"
class="carousel slide" data-ride="carousel">` with one `.item` per slide
(blockquote / ul / li-img + li.name + p.description), plus `.left/.right
carousel-control` anchors. Source data is a `slides` list in the
`employees.md` front matter. CSS rules in
`orig/user/themes/praxis/css/_style.css:18381846` force `img { width:160px;
height:200px }` for items inside `#employeesSlider .carousel-inner`.
Current Zola output for `/team/` `employees` section is just sequential
`<img class="float-right">` blocks with `<strong>name</strong>` paragraphs —
the carousel container, controls, and item wrapping are entirely missing.
### 2. Image-size distortion (carousel slot only)
`templates/macros/image.html` resizes with `op="fit_width"`. For 311×400
originals at `width=200`, that produces 200×257 — the wrong aspect for the
160×200 CSS slot. The live site avoids this by serving the raw image and
letting CSS pin it to 160×200. Doctor portraits (400×400) and services
thumbnails (600×400) are visually fine; the bug is isolated to the carousel
images.
### 3. `<h5>` headings not parsed in `content/team/doctors.md`
Markdown source has `#####Qualifikation` with no space after the hashes.
Grav's markdown parser was tolerant; pulldown-cmark (Zola) is not — output is
`<p>#####Qualifikation</p>`. Six occurrences across three doctor blocks.
### 4. `</th>` closing tag mismatch in doctors.md tables
`<td>…</th>` pairs in the three doctor schedule tables (six total). Browsers
recover, but the markup is wrong and inconsistent with the live (which uses
`<td>…</td>` everywhere).
### 5. Nav-link URLs HTML-entity-encoded
`templates/partials/navbar.html` renders `{{ sub.permalink }}` and
`{{ cpage.permalink }}` without `| safe`. Tera autoescape converts the
slashes to `&#x2F;`. Functional but markup-ugly and not parity. Live uses
relative paths (`/services/`).
## Architecture
### New: `templates/macros/team_carousel.html`
Renders a `<section class="employees">` block:
- Reuses the section-title structure from `section_title.html` (or inlines it
identically — anchor optional).
- Renders `<div id="employeesSlider" class="carousel slide"
data-ride="carousel">` with `.carousel-inner` containing one `<div
class="item{% if loop.first %} active{% endif %}">` per slide.
- Each item: `<blockquote><ul><li><img src="/images/team/{{ slide.image }}"
alt="{{ slide.name }}"></li><li class="name">{{ slide.name }}</li></ul><p>{{
slide.description }}</p></blockquote>`.
- Carousel controls: `.left` / `.right` anchors with FA `fa-angle-left/right`.
Images are served raw from `static/images/team/` — no `width`/`height`
attribute, no resize_image. The CSS slot (`#employeesSlider .carousel-inner
.item img`) forces the final 160×200 dimensions, exactly as the live site
does it.
### Modified: `templates/section.html`
When iterating `section.pages`, branch on `page.extra.layout`:
- `"carousel"` → call `team_carousel(title, anchor, slides)` macro with
values pulled from `page.extra`.
- otherwise → existing `section_title` + `page.content` render.
### Modified: `content/team/employees.md`
Front matter holds the carousel data; body is empty. Schema:
```toml
+++
title = "Unser Praxis-Team"
weight = 20
[extra]
anchor = "employees"
layout = "carousel"
[[extra.slides]]
name = "Frau Berscheidt"
image = "Berscheidt.jpg"
description = "Medizinische Fachangestellte, Diabetes-Assistentin"
# … repeated for Bolz, Frohne, Merhof, Rodrigues (5 total, matching live order)
+++
```
### Modified: `content/team/doctors.md`
- Replace each `#####X` with `##### X` (six occurrences).
- Replace each `</th>` with `</td>` inside `<td>…</th>` pairs (six occurrences).
### Modified: `templates/partials/navbar.html`
Replace `{{ sub.permalink }}` and `{{ cpage.permalink }}` with the equivalent
relative-path form: `{{ sub.permalink | replace(from=config.base_url,
to='') | safe }}` (and same for `cpage`). Mobile-menu list inside the same
file gets the same treatment.
## Per-Route Definition of Done
- `/team/`:
- `<section class="employees">` present, contains `<div
id="employeesSlider" class="carousel slide" data-ride="carousel">`.
- Exactly five `.item` divs, first with `.active`; each wraps a
`<blockquote><ul>…</ul><p>…</p></blockquote>`.
- `.left` and `.right` carousel-control anchors with `fa-angle-left/right`
icons.
- Carousel `<img>` tags have no `width`/`height` attributes (CSS does the
sizing).
- Doctor block: `<h5>Qualifikation</h5>` and `<h5>Tätigkeitsschwerpunkte</h5>`
(etc.) replace the previous `<p>#####…</p>` literals.
- Doctor schedule tables: zero `</th>` tags in the rendered HTML.
- Site-wide nav: no `&#x2F;` sequences in `<a href>` values.
## Risks / Notes
- The `team_carousel` macro intentionally duplicates the section-title
markup rather than reusing `section_title.html`, because the live theme
wraps it in `<section class="employees">` and the empty-anchor branch is
different. Keeping it inline avoids a fragile macro-of-macro chain.
- `page.extra.layout == "carousel"` is the dispatch key. If we later add
other layouts (`map`, `news`, etc. — the live theme has those as modular
templates), the same dispatch extends naturally.
- Image-macro stays unchanged; the carousel deliberately bypasses it.