diff --git a/docs/ReviewsTab-print.md b/docs/ReviewsTab-print.md new file mode 100644 index 0000000..004fa5b --- /dev/null +++ b/docs/ReviewsTab-print.md @@ -0,0 +1,162 @@ +# ReviewsTab Print Support + +Campaign: **GrantFox FWC26** +Ticket type: UI/UX +Status: Shipped + +--- + +## What this change does + +When a user prints the API Detail page while viewing the **Reviews** tab, the print output now: + +1. **Hides chrome controls** — the "Sort by" dropdown and "Write a Review" button are suppressed with `display: none !important` via the existing `.no-print` mechanism. Neither element is meaningful on paper. +2. **Expands all review cards** — every `.preview-card` inside the reviews section is forced to `display: block`, `max-height: none`, `overflow: visible` so no review body text is clipped. +3. **Expands collapsible regions** — any element using `aria-hidden="true"`, `[hidden]`, or `
` that may exist inside the reviews panel is forced open so nothing is silently omitted from the printed page. +4. **Single-column layout** — the `.reviews-list` grid is forced to `grid-template-columns: 1fr` for predictable paper width usage. +5. **Page-break avoidance** — each review card carries `break-inside: avoid` so a card is not split across page boundaries. + +The **light-theme override** and general **chrome hiding** (`topbar`, tabs, sidebar, hero CTAs) are handled by the existing `@media print` block already present in `index.css` and are unaffected by this change. + +--- + +## Files changed + +| File | Change | +|---|---| +| `src/pages/ApiDetailPage.tsx` | Added `reviews-sort-controls no-print` class to the sort-by row; added `no-print` to the Write a Review button; added `data-reviews-section` attribute to the reviews `
`; added `reviews-list` class to the review cards grid | +| `src/index.css` | Extended the existing `@media print` block with ReviewsTab-specific rules under `[data-reviews-section]` | +| `src/pages/ReviewsTab.print.test.ts` | New file — 13 contract tests covering markup and CSS | + +No new files were added to `src/styles/`. The existing project contract (`src/print.test.ts`) asserts that `main.tsx` must not import a `print.css` file; all print styles live in `src/index.css`. + +--- + +## How it works + +### Markup anchors (ApiDetailPage.tsx) + +```tsx +{/* Section anchor — CSS scopes to this */} +
+
+

Developer Feedback

+ {/* Hidden on print — interaction not possible on paper */} + +
+ + {/* ... rating histogram (visible on print) ... */} + + {/* Hidden on print — sort order irrelevant on paper */} +
+ + +
+ + {/* Print-expanded grid */} +
+ {sortedReviews.map(…)} +
+
+``` + +### CSS rules (index.css, inside `@media print`) + +```css +/* ── ReviewsTab: hide chrome, expand collapsibles (FWC26) ──── */ + +/* Expand every review card */ +[data-reviews-section] .preview-card { + display: block !important; + overflow: visible !important; + max-height: none !important; + height: auto !important; +} + +/* Expand aria-hidden collapsible regions */ +[data-reviews-section] [aria-hidden="true"] { + display: block !important; + visibility: visible !important; + opacity: 1 !important; + max-height: none !important; + height: auto !important; + overflow: visible !important; +} + +/* Expand
elements */ +[data-reviews-section] details { display: block !important; } +[data-reviews-section] details > * { display: block !important; } + +/* Expand [hidden] elements */ +[data-reviews-section] [hidden] { display: block !important; } + +/* Rating histogram — no overflow clip */ +[data-reviews-section] .rating-histogram, +[data-reviews-section] .rating-histogram__bar-track, +[data-reviews-section] .rating-histogram__bar-fill { + overflow: visible !important; + max-width: 100% !important; +} + +/* Single-column list */ +[data-reviews-section] .reviews-list { + display: grid !important; + grid-template-columns: 1fr !important; + gap: 16px !important; +} + +/* Avoid splitting a review card across a page break */ +[data-reviews-section] .preview-card { + break-inside: avoid !important; + page-break-inside: avoid !important; +} +``` + +> **Why `[data-reviews-section]` as the scope selector?** +> A data-attribute selector is immune to CSS specificity collisions from class-based resets elsewhere in the `@media print` block. It also serves as clear self-documentation in the markup. + +--- + +## Testing + +Run the focused test suite: + +```bash +npm test -- --run src/pages/ReviewsTab.print.test.ts +``` + +All 13 tests should pass. The existing `src/print.test.ts` (10 tests) also continues to pass. + +### What the tests cover + +| Test group | Tests | +|---|---| +| **Markup: no-print chrome** | Sort controls wrapper has `reviews-sort-controls no-print`; Write a Review button has `no-print`; section has `data-reviews-section`; grid has `reviews-list` | +| **CSS: expansion rules** | Review cards expand (`display: block`, `max-height: none`); `aria-hidden` regions expand; `
` expand; `[hidden]` expand; single-column layout; page-break avoidance; rules are inside `@media print` | +| **Import guard** | `main.tsx` does not import a `print.css` file | + +--- + +## Accessibility notes + +- The `data-reviews-section` attribute is not exposed in the accessibility tree and has no effect on screen reader behaviour. +- The `no-print` class uses `display: none !important` only inside `@media print`, so all controls remain fully keyboard-accessible in the normal viewing context. +- The single-column print layout maintains left-to-right reading order without requiring any additional ARIA markup. + +--- + +## Design token compliance + +All `@media print` rules use absolute values (`#f5f7fa`, `#1a2332`, `1fr`, etc.) because the intent is to override any token-based dark theme and force a legible light appearance. This matches the pattern established by the existing print block above. No tokens are used in print context — this is intentional and consistent with the rest of the file. + +--- + +## Browser notes + +`break-inside: avoid` / `page-break-inside: avoid` is supported by all modern browsers. `max-height: none` overrides any inline-style or class-based collapse pattern that sets a pixel height. If a future collapsible inside the reviews section uses a CSS `transition` on `height`, the `height: auto !important` rule will override it since `@media print` transitions are ignored by all major browsers. diff --git a/src/index.css b/src/index.css index 1b3ba58..efa7a7b 100644 --- a/src/index.css +++ b/src/index.css @@ -6873,6 +6873,96 @@ code, color: #444; } + /* ── ReviewsTab: hide chrome, expand collapsibles ──────────────────── + FWC26 — When printing the reviews section: + 1. .reviews-sort-controls (.no-print) is already hidden by the generic + .no-print rule above; this comment preserves intent for reviewers. + 2. Every review card (data-reviews-section .preview-card) is forced + visible and fully expanded so no content is clipped on paper. + 3. The RatingHistogram bars use inline `width` — overflow:visible + ensures they are never cut off. + 4. The collapsed-content pattern used elsewhere in the app + ([aria-hidden="true"], [hidden], details/summary) is expanded so + any future collapsible that lands inside the reviews panel prints + in full without JS intervention. + ─────────────────────────────────────────────────────────────────── */ + + /* Force every review card to be fully visible and expanded */ + [data-reviews-section] .preview-card { + display: block !important; + overflow: visible !important; + max-height: none !important; + height: auto !important; + } + + /* Expand any aria-hidden collapsible regions inside the reviews panel */ + [data-reviews-section] [aria-hidden="true"] { + display: block !important; + visibility: visible !important; + opacity: 1 !important; + max-height: none !important; + height: auto !important; + overflow: visible !important; + } + + /* Expand
elements that may appear in reviews */ + [data-reviews-section] details { + display: block !important; + } + + [data-reviews-section] details > * { + display: block !important; + } + + /* Expand hidden elements inside the reviews panel */ + [data-reviews-section] [hidden] { + display: block !important; + } + + /* Rating histogram: allow bars to render at full width without overflow clip */ + [data-reviews-section] .rating-histogram, + [data-reviews-section] .rating-histogram__bar-track, + [data-reviews-section] .rating-histogram__bar-fill { + overflow: visible !important; + max-width: 100% !important; + } + + /* Review list grid: single column, consistent spacing */ + [data-reviews-section] .reviews-list { + display: grid !important; + grid-template-columns: 1fr !important; + gap: 16px !important; + } + + /* Review cards: avoid splitting across page breaks */ + [data-reviews-section] .preview-card { + break-inside: avoid !important; + page-break-inside: avoid !important; + } +} + +/* Share Snapshot Button */ +.share-snapshot-button { + display: inline-flex; + align-items: center; + gap: 6px; + margin-left: 8px; +} + +/* ─── Category Pills ──────────────────────────────────────────────────────── */ +.pill-bar { + display: flex; + gap: 8px; + overflow-x: auto; + padding-bottom: 8px; + margin-bottom: 16px; + scrollbar-width: thin; +} + +.pill-bar::-webkit-scrollbar { + height: 6px; +} + /* Expand EndpointSummary collapsibles when printing */ .endpoint-summary-content--collapsed { display: block !important; diff --git a/src/pages/ApiDetailPage.tsx b/src/pages/ApiDetailPage.tsx index 33c02e3..3535bf0 100644 --- a/src/pages/ApiDetailPage.tsx +++ b/src/pages/ApiDetailPage.tsx @@ -916,10 +916,17 @@ print(response.json())`; * any runtime JS. See issue #580 and src/styles/print.css. */} {tab === "reviews" && ( -
+

Developer Feedback

- + {/* Write a Review button: not meaningful on paper */} +
{rawReviews.length === 0 ? ( @@ -934,6 +941,12 @@ print(response.json())`; + {/* Sort controls: hidden when printing — sort order is irrelevant on paper */} +
+