FN-5903: fix SkillsView mobile row wrapping
Keep mobile discovered-skill rows aligned after toggles and skill enablement. - keep .skills-view-item rows from wrapping at the mobile breakpoint - let .skills-view-item-info flex instead of forcing full-width stacking - add CSS regression coverage for the mobile row layout and toggle geometry - add component coverage that preserves row structure across enabled and disabled toggle states Files changed: packages/dashboard/app/components/SkillsView.css | 5 ++- .../components/__tests__/SkillsView.css.test.ts | 49 ++++++++++++++++++++++ .../app/components/__tests__/SkillsView.test.tsx | 47 +++++++++++++++++++++ .../__tests__/skills-view-mobile.test.tsx | 9 ++-- 4 files changed, 104 insertions(+), 6 deletions(-) Fusion-Task-Id: FN-5903 Fusion-Task-Lineage: 1004a702-28e7-4e7e-af22-591cc122be01
This commit is contained in:
@@ -2,6 +2,36 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
import { loadAllAppCss } from "../../test/cssFixture";
|
||||
|
||||
function extractRuleBlock(css: string, selector: string): string {
|
||||
const escapedSelector = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
const matches = [...css.matchAll(new RegExp(`${escapedSelector}\\s*\\{([^}]*)\\}`, "g"))];
|
||||
return matches.at(-1)?.[1] ?? "";
|
||||
}
|
||||
|
||||
function extractMobileMediaBlocks(content: string): string {
|
||||
const blocks: string[] = [];
|
||||
const regex = /@media[^{]*\(max-width: 768px\)[^{]*\{/g;
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = regex.exec(content)) !== null) {
|
||||
const startIdx = match.index + match[0].length;
|
||||
let braceCount = 1;
|
||||
let endIdx = startIdx;
|
||||
|
||||
while (braceCount > 0 && endIdx < content.length) {
|
||||
if (content[endIdx] === "{") braceCount += 1;
|
||||
if (content[endIdx] === "}") braceCount -= 1;
|
||||
endIdx += 1;
|
||||
}
|
||||
|
||||
if (braceCount === 0) {
|
||||
blocks.push(content.slice(startIdx, endIdx - 1));
|
||||
}
|
||||
}
|
||||
|
||||
return blocks.join("\n");
|
||||
}
|
||||
|
||||
describe("SkillsView/runtime-card token guardrails", () => {
|
||||
it("does not use forbidden runtime fallback literals/tokens", async () => {
|
||||
const css = await loadAllAppCss();
|
||||
@@ -13,4 +43,23 @@ describe("SkillsView/runtime-card token guardrails", () => {
|
||||
expect(css).not.toContain("var(--accent-red, #ef4444)");
|
||||
expect(css).not.toContain("var(--accent, #4f46e5)");
|
||||
});
|
||||
|
||||
it("keeps discovered-skill rows on one line at the mobile breakpoint", async () => {
|
||||
const css = await loadAllAppCss();
|
||||
const mobileMediaBlock = extractMobileMediaBlocks(css);
|
||||
const itemBlock = extractRuleBlock(mobileMediaBlock, ".skills-view-item");
|
||||
const infoBlock = extractRuleBlock(mobileMediaBlock, ".skills-view-item-info");
|
||||
|
||||
expect(itemBlock).toContain("flex-wrap: nowrap");
|
||||
expect(infoBlock).toContain("flex: 1 1 auto");
|
||||
expect(infoBlock).toContain("width: auto");
|
||||
});
|
||||
|
||||
it("keeps checked and unchecked toggle geometry token-aligned", async () => {
|
||||
const css = await loadAllAppCss();
|
||||
|
||||
expect(css).toContain("width: calc(var(--space-xl) + var(--space-lg))");
|
||||
expect(css).toContain("transform: translateX(calc(var(--space-lg) + (var(--space-xs) / 2)))");
|
||||
expect(css).toContain("background: var(--color-success)");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user