feat(FN-1890): improve mobile UX for SkillsView component

- Add comprehensive mobile CSS overrides for skills page layout and responsiveness
- Improve touch targets for toggle switches and interactive elements (44px minimum per Apple HIG)
- Polish skills view base styles with refined toggle dimensions
- Expand mobile CSS tests to cover touch target sizes and responsive layout
This commit is contained in:
Fusion
2026-04-16 06:16:50 -07:00
committed by gsxdsm
parent fdaf1cacfe
commit 261bfff9ae
3 changed files with 157 additions and 14 deletions

View File

@@ -128,19 +128,19 @@ export function SkillsView({ projectId, addToast, onClose }: SkillsViewProps) {
<Wrench size={20} />
Skills
</h2>
<span className="skills-view-count">{discoveredSkills.length} discovered</span>
<span className="skills-view-count" aria-label={`${discoveredSkills.length} discovered skills`}>{discoveredSkills.length} discovered</span>
</div>
<div className="skills-view-actions">
<button
className="btn-icon skills-view-close"
className="btn-icon skills-view-close touch-target"
onClick={onClose}
aria-label="Close skills view"
>
<X size={16} />
</button>
<button
className="btn btn-sm"
className="btn btn-sm touch-target"
onClick={() => void loadDiscoveredSkills()}
disabled={isLoadingDiscovered}
>

View File

@@ -76,9 +76,88 @@ describe("skills-view mobile css", () => {
it("defines .skills-view-toggle-slider with minimum dimensions on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-toggle-slider");
const block = extractRuleBlock(cssContent, ".skills-view-toggle-slider");
expect(block).toContain("min-width: 32px");
expect(block).toContain("min-height: 18px");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-toggle-slider");
expect(block).toContain("min-width: 40px");
expect(block).toContain("min-height: 22px");
});
it("defines .skills-view-section with reduced margin-bottom on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-section");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-section");
expect(block).toMatch(/margin-bottom:\s*var\(--space-md\)/);
});
it("defines .skills-view-section-title with smaller font on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-section-title");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-section-title");
expect(block).toContain("font-size: 13px");
});
it("defines .skills-view-card with reduced padding on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-card");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-card");
expect(block).toContain("padding: var(--space-sm)");
});
it("defines .skills-view-card-title with smaller font on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-card-title");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-card-title");
expect(block).toContain("font-size: 13px");
});
it("defines .skills-view-card-description with smaller font on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-card-description");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-card-description");
expect(block).toContain("font-size: 12px");
});
it("defines .skills-view-empty with reduced padding on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-empty");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-empty");
expect(block).toContain("padding: var(--space-lg)");
});
it("defines .skills-view-error with reduced padding on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-error");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-error");
expect(block).toContain("padding: var(--space-lg)");
});
it("defines .skills-view-loading with reduced padding on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-loading");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-loading");
expect(block).toContain("padding: var(--space-md)");
});
it("defines .skills-view-item with padding on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-item");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-item");
expect(block).toContain("padding: var(--space-md)");
});
it("defines .skills-view-item-info with full width on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-item-info");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-item-info");
expect(block).toContain("width: 100%");
});
it("defines .skills-view-item-toggle with padding on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-item-toggle");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-item-toggle");
expect(block).toContain("padding: var(--space-sm)");
});
it("defines .skills-view-count with smaller font on mobile", () => {
expect(mobileMediaBlock).toContain(".skills-view-count");
const block = extractRuleBlock(mobileMediaBlock, ".skills-view-count");
expect(block).toContain("font-size: 12px");
});
it("defines .badge--sm base class in CSS", () => {
expect(cssContent).toContain(".badge--sm {");
const block = extractRuleBlock(cssContent, ".badge--sm");
expect(block).toContain("font-size: 10px");
expect(block).toContain("padding: 1px 6px");
});
it("skills-view base styles are defined in styles.css", () => {

View File

@@ -24011,6 +24011,11 @@ html .column.drag-over * {
white-space: nowrap;
}
.badge--sm {
font-size: 10px;
padding: 1px 6px;
}
/* === Agent Metrics Bar === */
.agent-metrics-bar {
display: flex;
@@ -25713,16 +25718,39 @@ html .column.drag-over * {
/* Skills View mobile */
.skills-view-header {
padding: var(--space-sm) var(--space-md);
flex-wrap: wrap;
}
.skills-view-title h2 {
font-size: 16px;
}
.skills-view-count {
font-size: 12px;
}
.skills-view-actions {
min-height: 36px;
display: flex;
align-items: center;
}
.skills-view-actions .btn {
min-height: 36px;
}
.skills-view-content {
padding: var(--space-md);
}
.skills-view-section {
margin-bottom: var(--space-md);
}
.skills-view-section-title {
font-size: 13px;
}
.skills-view-search .form-input {
max-width: none;
width: 100%;
@@ -25735,11 +25763,44 @@ html .column.drag-over * {
.skills-view-item {
flex-wrap: wrap;
gap: var(--space-sm);
padding: var(--space-md);
}
.skills-view-item-info {
width: 100%;
}
.skills-view-item-toggle {
padding: var(--space-sm);
}
.skills-view-toggle-slider {
min-width: 32px;
min-height: 18px;
min-width: 40px;
min-height: 22px;
}
.skills-view-card {
padding: var(--space-sm);
}
.skills-view-card-title {
font-size: 13px;
}
.skills-view-card-description {
font-size: 12px;
}
.skills-view-empty {
padding: var(--space-lg);
}
.skills-view-error {
padding: var(--space-lg);
}
.skills-view-loading {
padding: var(--space-md);
}
.agent-tree__indent--1 { padding-left: 16px; }
@@ -27570,6 +27631,8 @@ html .column.drag-over * {
font-weight: 600;
color: var(--text);
margin-bottom: var(--space-md);
padding-bottom: var(--space-sm);
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
gap: var(--space-sm);
@@ -27647,8 +27710,8 @@ html .column.drag-over * {
.skills-view-toggle-slider {
position: relative;
width: 32px;
height: 18px;
width: 40px;
height: 22px;
background: var(--border);
border-radius: var(--radius-md);
transition: background var(--transition-normal);
@@ -27660,8 +27723,8 @@ html .column.drag-over * {
position: absolute;
top: 2px;
left: 2px;
width: 14px;
height: 14px;
width: 18px;
height: 18px;
background: var(--card);
border-radius: 50%;
transition: transform var(--transition-normal);
@@ -27672,7 +27735,7 @@ html .column.drag-over * {
}
.skills-view-item-toggle input:checked + .skills-view-toggle-slider::after {
transform: translateX(14px);
transform: translateX(18px);
}
/* Catalog search */
@@ -27697,6 +27760,7 @@ html .column.drag-over * {
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: var(--space-md);
min-height: 120px;
display: flex;
flex-direction: column;
gap: var(--space-sm);
@@ -27729,7 +27793,7 @@ html .column.drag-over * {
.skills-view-card-tags {
display: flex;
flex-wrap: wrap;
gap: 4px;
gap: var(--space-xs);
}
.skills-view-card-installs {