feat(F-068): completed feature
This commit is contained in:
96
work/artifacts/F-068/implementer.md
Normal file
96
work/artifacts/F-068/implementer.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# F-068 — Implementer evidence
|
||||
|
||||
## Scope delivered
|
||||
|
||||
F-067 had replaced `aspect-[5/7] max-h-72` with `w-full max-h-72`. The
|
||||
container filled the card width but the height was only bounded by
|
||||
`max-h`, so all cards ended up roughly the same height as `max-h-72`
|
||||
(288 px) regardless of the source image aspect — they looked "flat".
|
||||
The product description was still rendered as plain text via
|
||||
`{product.description}`, so any HTML markup that the admin now types
|
||||
into the WYSIWYG editor (F-064) shows up as literal tags.
|
||||
|
||||
## Change
|
||||
|
||||
Both defects share one fix: a stable square aspect ratio for the
|
||||
listing cards and a `prose` HTML renderer for the description.
|
||||
|
||||
`project/frontend/src/app/products/page.tsx`,
|
||||
`project/frontend/src/app/brands/[slug]/page.tsx`,
|
||||
`project/frontend/src/app/search/page.tsx`,
|
||||
`project/frontend/src/app/categories/[slug]/page.tsx`,
|
||||
`project/frontend/src/components/home/FeaturedProducts.tsx`
|
||||
|
||||
```diff
|
||||
- <div className="relative w-full max-h-72 bg-white flex items-center justify-center overflow-hidden">
|
||||
+ <div className="relative aspect-square w-full bg-white flex items-center justify-center overflow-hidden">
|
||||
{product.images?.[0] ? (
|
||||
<Image … fill className="object-contain" … />
|
||||
) : (
|
||||
<span className="text-5xl">🌿</span>
|
||||
)}
|
||||
</div>
|
||||
- <p className="text-gray-500 text-xs mt-1 line-clamp-2">{product.description}</p>
|
||||
+ {product.description && (
|
||||
+ <div
|
||||
+ className="text-gray-500 text-xs mt-1 line-clamp-2 prose prose-xs max-w-none"
|
||||
+ dangerouslySetInnerHTML={{ __html: product.description }}
|
||||
+ />
|
||||
+ )}
|
||||
```
|
||||
|
||||
The container now enforces `aspect-square` so the card height always
|
||||
equals the card width (square cards in the 4-col grid). The image
|
||||
keeps `object-contain`, so non-square sources still display without
|
||||
distortion — they're letterboxed inside a square.
|
||||
|
||||
The description is rendered via `dangerouslySetInnerHTML` so HTML tags
|
||||
typed into the WYSIWYG editor (F-062 / F-064) are interpreted on the
|
||||
listing cards. `prose prose-xs` adds the small-typography Tailwind
|
||||
prose styles (paragraph spacing, list bullets, bold/italic) without
|
||||
needing extra CSS.
|
||||
|
||||
## Acceptance traceability
|
||||
|
||||
| Acceptance criterion | How it is met |
|
||||
| -------------------- | ------------- |
|
||||
| Each listing card has a 1:1 aspect ratio and the image fits inside without distortion | `aspect-square w-full` enforces a square; `object-contain` keeps the visual inside without cropping. |
|
||||
| Product description renders HTML tags on listing cards | `dangerouslySetInnerHTML` on the description; `prose prose-xs` styles the inline HTML. |
|
||||
| Existing products without HTML still display | Plain text descriptions render unchanged through `dangerouslySetInnerHTML` (text nodes only). |
|
||||
| `verify.sh` is green | Exit 0. |
|
||||
|
||||
## Manual verification
|
||||
|
||||
```
|
||||
$ curl -X PATCH /api/products/13a65dc0-… \
|
||||
-d '{"description":"<p>Proteína <strong>ecológica</strong> de alta calidad.</p><ul><li>Vegana</li><li>Sin gluten</li></ul>"}'
|
||||
{ … description: "<p>Proteína <strong>ecológica</strong> … </ul>" … }
|
||||
|
||||
$ curl http://192.168.18.93:3003/products | grep -oE 'prose[^"]*"[^>]*>[^<]*'
|
||||
prose prose-xs max-w-none">Aceite de Oliva Virgen Extra Bio…
|
||||
prose prose-xs max-w-none">Almendras Crudas Ecologicas…
|
||||
… (one per card)
|
||||
|
||||
# Spot-check the HTML-rendered card
|
||||
$ curl … | grep -oE 'Protei.*?</div>' | head -1
|
||||
Proteina Guisante Ecologica</h3><div class="text-gray-500 text-xs mt-1 line-clamp-2 prose prose-xs max-w-none"><p>Proteína <strong>ecológica</strong> de alta calidad.</p><ul><li>Vegana</li><li>Sin gluten</li></ul></div>
|
||||
```
|
||||
|
||||
The description was restored to its original plain text after the
|
||||
test.
|
||||
|
||||
## Build verification
|
||||
|
||||
- `npx tsc --noEmit` (frontend) — exit 0
|
||||
- `monolith.sh prod restart frontend` → 200
|
||||
- `./scripts/verify.sh` — exit 0
|
||||
|
||||
## Files touched
|
||||
|
||||
```
|
||||
project/frontend/src/app/products/page.tsx (aspect-square + dangerouslySetInnerHTML)
|
||||
project/frontend/src/app/brands/[slug]/page.tsx (aspect-square + dangerouslySetInnerHTML)
|
||||
project/frontend/src/app/search/page.tsx (aspect-square + dangerouslySetInnerHTML)
|
||||
project/frontend/src/app/categories/[slug]/page.tsx (aspect-square + dangerouslySetInnerHTML)
|
||||
project/frontend/src/components/home/FeaturedProducts.tsx (aspect-square + dangerouslySetInnerHTML)
|
||||
```
|
||||
Reference in New Issue
Block a user