FN-6764: make research and insights tablet layouts full width

Research and Insights now reflow at tablet widths to avoid cut-off content while preserving mobile and desktop behavior.

- Add tablet-specific full-width Research layout rules with shrink-safe reader/history containers.
- Add tablet-specific Insights layout rules that stack the category rail above the detail pane.
- Cover Research and Insights responsive CSS contracts across desktop, mobile, and tablet tiers.

Files changed:
 packages/dashboard/app/components/InsightsView.css | 67 ++++++++++++++++++++++
 packages/dashboard/app/components/ResearchView.css | 47 +++++++++++++++
 .../app/components/__tests__/InsightsView.test.tsx | 20 +++++++
 .../app/components/__tests__/ResearchView.test.tsx | 13 +++++
 4 files changed, 147 insertions(+)

Fusion-Task-Id: FN-6764

Fusion-Task-Lineage: ed528038-e69b-4794-9885-fb3b5f47b3ed
This commit is contained in:
gsxdsm
2026-06-20 01:27:54 -07:00
parent aaa1aa2fed
commit 10208ecd63
4 changed files with 147 additions and 0 deletions

View File

@@ -613,3 +613,70 @@
max-width: 200px;
}
}
/*
FNXC:InsightsView 2026-06-20-00:34:
Insights tablets at 769px–1024px were inheriting the desktop fixed category sidebar, which squeezed the detail pane inside the .project-content flex chain. Stack the category rail above the detail pane and keep both panes shrinkable so long insight content cannot force horizontal cut-off.
*/
@media (min-width: 769px) and (max-width: 1024px) {
.insights-view {
flex: 1;
inline-size: 100%;
min-inline-size: 0;
min-block-size: 0;
overflow: hidden;
}
.insights-view-header {
min-inline-size: 0;
}
.insights-view-title {
flex: 1 1 auto;
min-inline-size: 0;
}
.insights-view-actions {
flex-shrink: 0;
}
.insights-body {
flex-direction: column;
inline-size: 100%;
min-width: 0;
min-inline-size: 0;
min-block-size: 0;
overflow: hidden;
}
.insights-sidebar {
width: 100%;
min-width: 0;
min-inline-size: 0;
border-right: none;
border-bottom: var(--btn-border-width) solid var(--border);
overflow-x: auto;
overflow-y: hidden;
}
.insights-category-list {
flex-direction: row;
flex-wrap: nowrap;
}
.insights-category-list > li {
flex-shrink: 0;
}
.insights-category-item {
white-space: nowrap;
}
.insights-detail {
flex: 1 1 0;
min-width: 0;
min-inline-size: 0;
min-block-size: 0;
overflow-y: auto;
}
}

View File

@@ -293,3 +293,50 @@
min-height: calc(var(--space-lg) * 2 + var(--space-sm));
}
}
/*
FNXC:ResearchView 2026-06-20-00:33:
Research tablets at 769px–1024px were inheriting the desktop two-column grid, leaving the reader cramped inside the .project-content flex chain. Reflow to one full-width column while preserving internal history and reader scroll containers so the document itself does not overflow horizontally.
*/
@media (min-width: 769px) and (max-width: 1024px) {
.research-view {
flex: 1;
inline-size: 100%;
min-inline-size: 0;
min-block-size: 0;
overflow: hidden;
}
.research-view__layout {
display: flex;
flex-direction: column;
grid-template-columns: minmax(0, 1fr);
inline-size: 100%;
min-width: 0;
min-inline-size: 0;
min-block-size: 0;
overflow: hidden;
}
.research-view__sidebar,
.research-view__reader,
.research-view__sidebar-content,
.research-view__reader-content {
min-width: 0;
min-inline-size: 0;
min-block-size: 0;
}
.research-view__sidebar {
flex: 0 1 auto;
}
.research-view__reader {
flex: 1 1 0;
overflow: auto;
}
.research-view__history {
overflow: auto;
}
}

View File

@@ -4,6 +4,7 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, screen, fireEvent, waitFor, act } from "@testing-library/react";
import { loadAllAppCss, loadAllAppCssBaseOnly } from "../../test/cssFixture";
import { InsightsView } from "../InsightsView";
// Mock the useInsights hook
@@ -1351,4 +1352,23 @@ describe("InsightsView", () => {
expect(dismiss2Button).toBeDisabled(); // All actions disabled when any is in-flight
});
});
describe("responsive CSS contracts", () => {
it("FN-6764: adds a tablet full-width reflow without regressing desktop or mobile tiers", () => {
const baseCss = loadAllAppCssBaseOnly();
const css = loadAllAppCss();
expect(baseCss).toMatch(/\.insights-body\s*\{[^}]*display:\s*flex;[^}]*overflow:\s*hidden;[^}]*\}/);
expect(baseCss).toMatch(/\.insights-sidebar\s*\{[^}]*width:\s*calc\(var\(--space-2xl\)\s*\*\s*7\s*\+\s*var\(--space-lg\)\);[^}]*flex-shrink:\s*0;[^}]*overflow-y:\s*auto;[^}]*\}/);
expect(baseCss).toMatch(/\.insights-detail\s*\{[^}]*flex:\s*1;[^}]*min-width:\s*0;[^}]*overflow-y:\s*auto;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(max-width:\s*768px\)[^{]*\{[\s\S]*?\.insights-body\s*\{[^}]*flex-direction:\s*column;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(max-width:\s*768px\)[^{]*\{[\s\S]*?\.insights-sidebar\s*\{[^}]*width:\s*100%;[^}]*border-right:\s*none;[^}]*overflow-x:\s*auto;[^}]*overflow-y:\s*hidden;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(min-width:\s*769px\)\s*and\s*\(max-width:\s*1024px\)[^{]*\{[\s\S]*?\.insights-view\s*\{[^}]*inline-size:\s*100%;[^}]*min-inline-size:\s*0;[^}]*overflow:\s*hidden;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(min-width:\s*769px\)\s*and\s*\(max-width:\s*1024px\)[^{]*\{[\s\S]*?\.insights-body\s*\{[^}]*flex-direction:\s*column;[^}]*inline-size:\s*100%;[^}]*min-width:\s*0;[^}]*min-inline-size:\s*0;[^}]*overflow:\s*hidden;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(min-width:\s*769px\)\s*and\s*\(max-width:\s*1024px\)[^{]*\{[\s\S]*?\.insights-sidebar\s*\{[^}]*width:\s*100%;[^}]*min-width:\s*0;[^}]*min-inline-size:\s*0;[^}]*border-right:\s*none;[^}]*border-bottom:\s*var\(--btn-border-width\)\s+solid\s+var\(--border\);[^}]*overflow-x:\s*auto;[^}]*overflow-y:\s*hidden;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(min-width:\s*769px\)\s*and\s*\(max-width:\s*1024px\)[^{]*\{[\s\S]*?\.insights-detail\s*\{[^}]*flex:\s*1\s+1\s+0;[^}]*min-width:\s*0;[^}]*min-inline-size:\s*0;[^}]*overflow-y:\s*auto;[^}]*\}/);
});
});
});

View File

@@ -561,4 +561,17 @@ describe("ResearchView", () => {
expect(css).toMatch(/@media[^{]*\(max-width:\s*768px\)[^{]*\{[\s\S]*?\.research-view__layout\s*\{[^}]*display:\s*flex;[^}]*flex-direction:\s*column;[^}]*overflow:\s*visible;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(max-width:\s*768px\)[^{]*\{[\s\S]*?\.research-view__history\s*\{[^}]*overflow:\s*visible;[^}]*\}/);
});
it("FN-6764: adds a tablet full-width reflow without regressing desktop or mobile tiers", () => {
const baseCss = loadAllAppCssBaseOnly();
const css = loadAllAppCss();
expect(baseCss).toMatch(/\.research-view__layout\s*\{[^}]*display:\s*grid;[^}]*grid-template-columns:\s*minmax\(0,\s*1fr\)\s*minmax\(0,\s*2fr\);[^}]*overflow:\s*hidden;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(max-width:\s*768px\)[^{]*\{[\s\S]*?\.research-view__layout\s*\{[^}]*display:\s*flex;[^}]*flex-direction:\s*column;[^}]*grid-template-columns:\s*minmax\(0,\s*1fr\);[^}]*overflow:\s*visible;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(min-width:\s*769px\)\s*and\s*\(max-width:\s*1024px\)[^{]*\{[\s\S]*?\.research-view\s*\{[^}]*inline-size:\s*100%;[^}]*min-inline-size:\s*0;[^}]*overflow:\s*hidden;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(min-width:\s*769px\)\s*and\s*\(max-width:\s*1024px\)[^{]*\{[\s\S]*?\.research-view__layout\s*\{[^}]*display:\s*flex;[^}]*flex-direction:\s*column;[^}]*grid-template-columns:\s*minmax\(0,\s*1fr\);[^}]*min-width:\s*0;[^}]*min-inline-size:\s*0;[^}]*overflow:\s*hidden;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(min-width:\s*769px\)\s*and\s*\(max-width:\s*1024px\)[^{]*\{[\s\S]*?\.research-view__reader\s*\{[^}]*flex:\s*1\s+1\s+0;[^}]*overflow:\s*auto;[^}]*\}/);
expect(css).toMatch(/@media[^{]*\(min-width:\s*769px\)\s*and\s*\(max-width:\s*1024px\)[^{]*\{[\s\S]*?\.research-view__history\s*\{[^}]*overflow:\s*auto;[^}]*\}/);
});
});