From 9f0d7a2b175167c02bd72de03367406a1f44969a Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Sun, 25 Jan 2026 03:52:20 +1000 Subject: [PATCH] fix(skills): refactor skills section to use design system tokens - Replace hardcoded purple/blue colors with primary/10 backgrounds - Use text-primary for icons instead of hardcoded colors - Use error tokens for error states instead of red-* - Use ProgressBar component instead of custom div progress bars - Use EmptyState component for empty activity feed - Use Card components consistently with proper padding - Fix TypeScript types in integration tests --- .../components/skills/SkillsActivityFeed.tsx | 30 +++-- .../src/components/skills/SkillsSection.tsx | 103 +++++++++--------- .../web/src/components/skills/SkillsStats.tsx | 55 +++++----- .../scenarios-crud.integration.test.ts | 4 +- .../scenarios-run.integration.test.ts | 2 +- 5 files changed, 102 insertions(+), 92 deletions(-) diff --git a/apps/web/src/components/skills/SkillsActivityFeed.tsx b/apps/web/src/components/skills/SkillsActivityFeed.tsx index 120d4ae..a4a2eff 100644 --- a/apps/web/src/components/skills/SkillsActivityFeed.tsx +++ b/apps/web/src/components/skills/SkillsActivityFeed.tsx @@ -2,6 +2,7 @@ import { Badge } from '@tpmjs/ui/Badge/Badge'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@tpmjs/ui/Card/Card'; +import { EmptyState } from '@tpmjs/ui/EmptyState/EmptyState'; import { Icon } from '@tpmjs/ui/Icon/Icon'; import { Skeleton } from '@tpmjs/ui/Skeleton/Skeleton'; @@ -88,9 +89,12 @@ export function SkillsActivityFeed({ if (error) { return ( - + -

{error}

+
+ +

{error}

+
); @@ -99,11 +103,13 @@ export function SkillsActivityFeed({ if (questions.length === 0) { return ( - - -

- No questions yet. Be the first to ask! -

+ +
); @@ -112,7 +118,7 @@ export function SkillsActivityFeed({ return (
{questions.map((q) => ( - +
@@ -127,13 +133,13 @@ export function SkillsActivityFeed({ - + {q.answer.slice(0, 150)} {q.answer.length > 150 ? '...' : ''}
-
+
{q.skillNodes.slice(0, 2).map((sn, i) => ( {sn.skill.name} @@ -145,11 +151,11 @@ export function SkillsActivityFeed({ )}
-
+
{q.similarCount > 0 && ( - {q.similarCount} similar + {q.similarCount} )} {formatRelativeTime(new Date(q.createdAt))} diff --git a/apps/web/src/components/skills/SkillsSection.tsx b/apps/web/src/components/skills/SkillsSection.tsx index 51007bb..e36bb1c 100644 --- a/apps/web/src/components/skills/SkillsSection.tsx +++ b/apps/web/src/components/skills/SkillsSection.tsx @@ -1,6 +1,7 @@ 'use client'; import { Button } from '@tpmjs/ui/Button/Button'; +import { Card, CardContent } from '@tpmjs/ui/Card/Card'; import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock'; import { Icon } from '@tpmjs/ui/Icon/Icon'; import Link from 'next/link'; @@ -52,29 +53,29 @@ curl -X POST "${skillsUrl}" \\ }`; return ( -
+
{/* Header */}
-
-
- +
+
+

Skills

-

+

Proven in the wild — not declared on paper

@@ -82,34 +83,36 @@ curl -X POST "${skillsUrl}" \\ {/* API Documentation Toggle */} {showApiDocs && ( -
-
-

API Endpoint

-
- POST {skillsUrl} + + +
+

API Endpoint

+
+ POST {skillsUrl} +
-
-
-

Example Request

- -
+
+

Example Request

+ +
-
-

Example Response

- -
+
+

Example Response

+ +
-
- - View full API documentation - -
-
+
+ + View full API documentation → + +
+ + )} {/* Main Content */} -
+
{/* Stats Column */}
@@ -117,32 +120,34 @@ curl -X POST "${skillsUrl}" \\ {/* Activity Feed Column */}
-
-

Recent Questions

+
+

Recent Questions

- {/* CTA for empty state */} -
-
-
- + {/* CTA */} + + +
+
+ +
+
+

+ Ask questions to build the skill graph +

+

+ Every question helps improve future responses for all agents. +

+
+
-
-

- Ask questions to build the skill graph -

-

- Every question helps improve future responses for all agents. -

-
- -
-
+ +
); } diff --git a/apps/web/src/components/skills/SkillsStats.tsx b/apps/web/src/components/skills/SkillsStats.tsx index 7a10710..f8ba888 100644 --- a/apps/web/src/components/skills/SkillsStats.tsx +++ b/apps/web/src/components/skills/SkillsStats.tsx @@ -3,6 +3,7 @@ import { Badge } from '@tpmjs/ui/Badge/Badge'; import { Card, CardContent, CardHeader, CardTitle } from '@tpmjs/ui/Card/Card'; import { Icon } from '@tpmjs/ui/Icon/Icon'; +import { ProgressBar } from '@tpmjs/ui/ProgressBar/ProgressBar'; import { Skeleton } from '@tpmjs/ui/Skeleton/Skeleton'; import { useEffect, useState } from 'react'; @@ -46,7 +47,7 @@ export function SkillsStats({ collectionId }: SkillsStatsProps): React.ReactElem if (loading) { return ( -
+
{[1, 2].map((i) => ( @@ -61,9 +62,12 @@ export function SkillsStats({ collectionId }: SkillsStatsProps): React.ReactElem if (error) { return ( - + -

{error}

+
+ +

{error}

+
); @@ -76,15 +80,15 @@ export function SkillsStats({ collectionId }: SkillsStatsProps): React.ReactElem return (
{/* Summary Stats */} -
+
-
-
- +
+
+
-

{stats.totalQuestions}

+

{stats.totalQuestions}

Questions

@@ -93,12 +97,12 @@ export function SkillsStats({ collectionId }: SkillsStatsProps): React.ReactElem -
-
- +
+
+
-

{stats.totalSkills}

+

{stats.totalSkills}

Skills

@@ -115,26 +119,21 @@ export function SkillsStats({ collectionId }: SkillsStatsProps): React.ReactElem -
+
{stats.topSkills.slice(0, 5).map((skill, i) => ( -
-
- +
+
+ {skill.name} + {skill.questionCount} Q
-
- {skill.questionCount} Q -
-
-
-
+
))}
diff --git a/apps/web/src/test/integration/scenarios/scenarios-crud.integration.test.ts b/apps/web/src/test/integration/scenarios/scenarios-crud.integration.test.ts index 9bc5fe3..38c95f4 100644 --- a/apps/web/src/test/integration/scenarios/scenarios-crud.integration.test.ts +++ b/apps/web/src/test/integration/scenarios/scenarios-crud.integration.test.ts @@ -36,8 +36,8 @@ async function isServerAvailable(): Promise { describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Scenarios CRUD Integration', () => { let serverAvailable = false; - let testCollection: { id: string; slug: string; userId: string } | null = null; - const testScenarioId: string | null = null; + let testCollection: { id: string; slug: string | null; userId: string } | null = null; + let testScenarioId: string | null = null; beforeAll(async () => { serverAvailable = await isServerAvailable(); diff --git a/apps/web/src/test/integration/scenarios/scenarios-run.integration.test.ts b/apps/web/src/test/integration/scenarios/scenarios-run.integration.test.ts index 62d28e6..5dab026 100644 --- a/apps/web/src/test/integration/scenarios/scenarios-run.integration.test.ts +++ b/apps/web/src/test/integration/scenarios/scenarios-run.integration.test.ts @@ -30,7 +30,7 @@ async function isServerAvailable(): Promise { describe.skipIf(!INTEGRATION_TESTS_ENABLED)('Scenario Execution Integration', () => { let serverAvailable = false; - let testScenario: { id: string; name: string; collectionId: string } | null = null; + let testScenario: { id: string; name: string | null; collectionId: string | null } | null = null; beforeAll(async () => { serverAvailable = await isServerAvailable();