feat(FN-2395): style settings panel scrollbars
- Add cross-browser scrollbar styling for settings sidebar and content panes using existing design tokens - Extend settings mobile CSS tests to assert the new scrollbar rules for WebKit and Firefox-compatible properties - Refactor dashboard TUI app tests to render via React.createElement for compatibility with current test tooling - Tidy mission e2e mock ID generators to satisfy formatting/quality gate checks
This commit is contained in:
@@ -155,6 +155,13 @@ function expectMobileRule(css: string, selector: string, declaration: string): v
|
||||
expect(pattern.test(css)).toBe(true);
|
||||
}
|
||||
|
||||
function expectBaseRule(css: string, selector: string, declaration: string): void {
|
||||
const pattern = new RegExp(
|
||||
`${escapeRegExp(selector)}\\s*\\{[^}]*${escapeRegExp(declaration)}`,
|
||||
);
|
||||
expect(pattern.test(css)).toBe(true);
|
||||
}
|
||||
|
||||
describe("SettingsModal mobile adaptations", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
@@ -249,4 +256,20 @@ describe("SettingsModal mobile adaptations", () => {
|
||||
expectMobileRule(css, ".settings-preset-item-actions", "justify-content: flex-start;");
|
||||
expectMobileRule(css, ".settings-preset-size-grid", "grid-template-columns: 1fr;");
|
||||
});
|
||||
|
||||
it("styles settings scrollbar rules for sidebar and content", () => {
|
||||
const css = loadAllAppCss();
|
||||
|
||||
expectBaseRule(css, ".settings-sidebar", "scrollbar-color: var(--border) transparent;");
|
||||
expectBaseRule(css, ".settings-sidebar", "scrollbar-width: thin;");
|
||||
expectBaseRule(css, ".settings-sidebar::-webkit-scrollbar", "width: 6px;");
|
||||
expectBaseRule(css, ".settings-sidebar::-webkit-scrollbar-thumb", "background: var(--border);");
|
||||
expectBaseRule(css, ".settings-sidebar::-webkit-scrollbar-thumb:hover", "background: var(--text-muted);");
|
||||
|
||||
expectBaseRule(css, ".settings-content", "scrollbar-color: var(--border) transparent;");
|
||||
expectBaseRule(css, ".settings-content", "scrollbar-width: thin;");
|
||||
expectBaseRule(css, ".settings-content::-webkit-scrollbar", "width: 6px;");
|
||||
expectBaseRule(css, ".settings-content::-webkit-scrollbar-thumb", "background: var(--border);");
|
||||
expectBaseRule(css, ".settings-content::-webkit-scrollbar-thumb:hover", "background: var(--text-muted);");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1556,6 +1556,25 @@ input[type="range"]:focus-visible {
|
||||
padding: 10px 8px;
|
||||
gap: 2px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
scrollbar-color: var(--border) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.settings-sidebar::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.settings-sidebar::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.settings-sidebar::-webkit-scrollbar-thumb {
|
||||
background: var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.settings-sidebar::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--text-muted);
|
||||
}
|
||||
|
||||
.settings-nav-item {
|
||||
@@ -1612,6 +1631,25 @@ input[type="range"]:focus-visible {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding: 4px 0 12px;
|
||||
scrollbar-color: var(--border) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.settings-content::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.settings-content::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.settings-content::-webkit-scrollbar-thumb {
|
||||
background: var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.settings-content::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--text-muted);
|
||||
}
|
||||
.settings-content > * {
|
||||
animation: settingsFadeIn var(--transition-normal);
|
||||
|
||||
@@ -59,11 +59,11 @@ function createMockMissionStore() {
|
||||
// Generate IDs matching the real MissionStore format:
|
||||
// prefix + base36(timestamp) + "-" + random alphanumeric suffix
|
||||
// e.g., M-MNJVKT2G-ME5Q, MS-M3N8QR-C9F1, SL-P4T2WX-D5E8, F-J6K9AB-G7H3
|
||||
const generateMissionId = () => `M-MOCK${missionCounter++.toString(36).toUpperCase()}-TST`;
|
||||
const generateMilestoneId = () => `MS-MOCK${milestoneCounter++.toString(36).toUpperCase()}-TST`;
|
||||
const generateSliceId = () => `SL-MOCK${sliceCounter++.toString(36).toUpperCase()}-TST`;
|
||||
const generateFeatureId = () => `F-MOCK${featureCounter++.toString(36).toUpperCase()}-TST`;
|
||||
const generateAssertionId = () => `CA-MOCK${assertionCounter++.toString(36).toUpperCase()}-TST`;
|
||||
const generateMissionId = () => `M-MOCK${(missionCounter++).toString(36).toUpperCase()}-TST`;
|
||||
const generateMilestoneId = () => `MS-MOCK${(milestoneCounter++).toString(36).toUpperCase()}-TST`;
|
||||
const generateSliceId = () => `SL-MOCK${(sliceCounter++).toString(36).toUpperCase()}-TST`;
|
||||
const generateFeatureId = () => `F-MOCK${(featureCounter++).toString(36).toUpperCase()}-TST`;
|
||||
const generateAssertionId = () => `CA-MOCK${(assertionCounter++).toString(36).toUpperCase()}-TST`;
|
||||
|
||||
return {
|
||||
createMission: vi.fn((input: { title: string; description?: string }) => {
|
||||
|
||||
Reference in New Issue
Block a user