+
{skill.tags.slice(0, MAX_VISIBLE_TAGS).map((tag) => (
- {tag}
+ #{tag}
))}
{extraTags > 0 && (
@@ -86,7 +97,7 @@ export function SkillCard({
)}
-
+
+
+
)
}
diff --git a/desktop/src/components/market/SkillDetailView.test.tsx b/desktop/src/components/market/SkillDetailView.test.tsx
index c4ba2a8b..50665beb 100644
--- a/desktop/src/components/market/SkillDetailView.test.tsx
+++ b/desktop/src/components/market/SkillDetailView.test.tsx
@@ -1,5 +1,5 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
-import { render, screen, fireEvent } from '@testing-library/react'
+import { render, screen, fireEvent, within } from '@testing-library/react'
import '@testing-library/jest-dom'
vi.mock('../markdown/MarkdownRenderer', () => ({
@@ -113,6 +113,9 @@ describe('SkillDetailView', () => {
it('renders custom actions in the decision area', () => {
renderView({ actions:
})
- expect(screen.getByText('Install now')).toBeInTheDocument()
+ const decisionSidebar = screen.getByTestId('skill-detail-sidebar')
+ expect(within(decisionSidebar).getByText('Install now')).toBeInTheDocument()
+ expect(within(decisionSidebar).getByText('Author')).toBeInTheDocument()
+ expect(within(decisionSidebar).getByText('Alice')).toBeInTheDocument()
})
})
diff --git a/desktop/src/components/market/SkillDetailView.tsx b/desktop/src/components/market/SkillDetailView.tsx
index 82b649c8..a5887b96 100644
--- a/desktop/src/components/market/SkillDetailView.tsx
+++ b/desktop/src/components/market/SkillDetailView.tsx
@@ -1,4 +1,5 @@
import { useState, type ReactNode } from 'react'
+import { ArrowLeft, CircleSlash2, FileText, Folder } from 'lucide-react'
import { useTranslation } from '../../i18n'
import type {
InstallState,
@@ -10,6 +11,7 @@ import { InstallStateBadge } from './InstallStateBadge'
import { SecurityBadge } from './SecurityBadge'
import { FilePreview, type PreviewFile, type PreviewFileContent } from './FilePreview'
import { MarkdownRenderer } from '../markdown/MarkdownRenderer'
+import { SkillAvatar } from './SkillAvatar'
export type SkillDetailMetaItem = {
label: string
@@ -48,79 +50,70 @@ export function SkillDetailView(props: SkillDetailViewProps) {
const [tab, setTab] = useState<'overview' | 'files'>('overview')
return (
-
-
+
+
- {/* Install decision area */}
-
-
-
- {props.iconUrl ? (
-

- ) : (
-
- auto_awesome
-
- )}
-
-
-
{props.name}
- {props.version && (
-
- v{props.version}
-
- )}
-
-
-
- {props.sourceLabel}
-
- {props.securityStatus && }
- {props.installState && }
-
- {props.summary && (
-
- {props.summary}
-
+
+
+
+
+
+ {props.sourceLabel}
+ {props.version && (
+ <>
+ ·
+ v{props.version}
+ >
)}
+
+ {props.name}
+
+
+ {props.securityStatus && }
+ {props.installState && }
+
+ {props.summary && (
+
+ {props.summary}
+
+ )}
- {props.actions &&
{props.actions}
}
{props.installState === 'not-installable' && props.notInstallableReason && (
-
- block
-
+
{t(`market.reason.${props.notInstallableReason}`)}
)}
{props.securityReports && props.securityReports.length > 0 && (
-
-
+
+
{t('market.detail.securityReport')}
{props.securityReports.map((report) => (
{report.vendor}
{report.statusText}
@@ -141,61 +134,104 @@ export function SkillDetailView(props: SkillDetailViewProps) {
)}
{props.banner}
-
+
- {/* Meta grid */}
- {props.meta.length > 0 && (
-
- {props.meta.map((item) => (
-
-
{item.label}
-
{item.value}
-
- ))}
-
- )}
-
- {/* Tabs */}
-
- {(['overview', 'files'] as const).map((key) => (
-
)
diff --git a/desktop/src/components/market/SourceStatusBar.tsx b/desktop/src/components/market/SourceStatusBar.tsx
index 73e12d16..db26b2bc 100644
--- a/desktop/src/components/market/SourceStatusBar.tsx
+++ b/desktop/src/components/market/SourceStatusBar.tsx
@@ -27,7 +27,10 @@ export function SourceStatusBar({
}) {
const t = useTranslation()
return (
-
+
{MARKET_SOURCES.map((source) => {
const info = sources[source]
if (!info) return null
@@ -40,11 +43,11 @@ export function SourceStatusBar({
key={source}
data-testid={`market-source-status-${source}`}
title={info.error || undefined}
- className="inline-flex items-center gap-1.5 rounded-full border border-[var(--color-border)] bg-[var(--color-surface)] px-2.5 py-1 text-[11px] text-[var(--color-text-secondary)]"
+ className="inline-flex min-h-7 items-center gap-1.5 rounded-md px-2 text-[11px] text-[var(--color-text-secondary)]"
>
-
+
{t(`market.source.${source}`)}
- {statusLabel}
+ {statusLabel}
)
})}