From 356fe3b5238373e10bb416f1de836eb46a116167 Mon Sep 17 00:00:00 2001 From: Naomi Gilbert Date: Sat, 1 Aug 2026 15:01:20 -0400 Subject: [PATCH] feat(reports): add orientation, cards per row and condensed card options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Card layouts printed one record per page for wide views, which wastes paper on concise ones. Measured on real records, density is driven by card height, not by a fixed rule: 4.0 records per page with a single field, 1.0 with sixteen. Add three layout options that carry through save, preview, print and PDF: - orientation: portrait or landscape, applied both to Dompdf's paper and to the document's @page rule so the browser prints the iframe the same way - card_columns: 1 to 4 cards side by side, laid out as a grid - compact_cards: drops the 80px column floor and tightens padding, margins and the title size Measured on a table with short titles, 40 records: 5.0 per page by default, 8.0 at two columns, 10.0 with condensed cards, 13.3 at four columns in landscape. More columns is not always denser — narrow cards wrap long titles — so the options are exposed rather than guessed at, and the card ones only appear when a view is selected. --- .../app/Http/Controllers/ReportController.php | 11 +- .../api/resources/views/reports/pdf.blade.php | 155 +++++++++++------- apps/api/tests/Feature/ReportFeatureTest.php | 125 ++++++++++++++ apps/client/src/contexts/I18nContext.tsx | 16 ++ .../__tests__/reports-live-exports.test.tsx | 67 ++++++++ .../routes/reports.$databaseId.$tableId.tsx | 83 +++++++++- 6 files changed, 394 insertions(+), 63 deletions(-) diff --git a/apps/api/app/Http/Controllers/ReportController.php b/apps/api/app/Http/Controllers/ReportController.php index 85c6396..fb957d8 100644 --- a/apps/api/app/Http/Controllers/ReportController.php +++ b/apps/api/app/Http/Controllers/ReportController.php @@ -60,6 +60,9 @@ public function store(Request $request): JsonResponse 'layout.view_id' => 'nullable|uuid|exists:views,id', 'layout.show_headers_only' => 'nullable|boolean', 'layout.per_page' => 'nullable|integer|min:1|max:100', + 'layout.card_columns' => 'nullable|integer|min:1|max:4', + 'layout.orientation' => 'nullable|in:portrait,landscape', + 'layout.compact_cards' => 'nullable|boolean', ]); $report = Report::create($validated); @@ -94,6 +97,9 @@ public function update(Request $request, Report $report): JsonResponse 'layout.view_id' => 'nullable|uuid|exists:views,id', 'layout.show_headers_only' => 'nullable|boolean', 'layout.per_page' => 'nullable|integer|min:1|max:100', + 'layout.card_columns' => 'nullable|integer|min:1|max:4', + 'layout.orientation' => 'nullable|in:portrait,landscape', + 'layout.compact_cards' => 'nullable|boolean', ]); $report->update($validated); @@ -259,12 +265,15 @@ private function generatePdfResponse(string $reportName, array $columns, array $ { $html = $this->renderReportHtml($reportName, $columns, $groups, $groupBy, $layout); + $orientation = ($layout['orientation'] ?? 'portrait') === 'landscape' ? 'landscape' : 'portrait'; + $dompdf = new Dompdf([ 'isHtml5ParserEnabled' => true, 'isPhpEnabled' => false, 'defaultPaperSize' => 'a4', - 'defaultPaperOrientation' => 'portrait', + 'defaultPaperOrientation' => $orientation, ]); + $dompdf->setPaper('a4', $orientation); $dompdf->loadHtml($html); $dompdf->render(); diff --git a/apps/api/resources/views/reports/pdf.blade.php b/apps/api/resources/views/reports/pdf.blade.php index 1c38b60..6660718 100644 --- a/apps/api/resources/views/reports/pdf.blade.php +++ b/apps/api/resources/views/reports/pdf.blade.php @@ -4,6 +4,11 @@ {{ $reportName }}