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:
@@ -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}
|
||||
>
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user