Compare commits

...
+55 -11
View File
@@ -1,6 +1,16 @@
import type { ClawdisSkillMetadata } from 'clawhub-schema'
import { formatInstallCommand, formatInstallLabel } from './skillDetailUtils'
const CAPABILITY_DISPLAY: Record<string, { icon: string; label: string }> = {
shell: { icon: '>_', label: 'Shell commands' },
filesystem: { icon: '\uD83D\uDCC2', label: 'File access' },
network: { icon: '\uD83C\uDF10', label: 'Web search/fetch' },
browser: { icon: '\uD83D\uDD0D', label: 'Browser control' },
sessions: { icon: '\u26A1', label: 'Session orchestration' },
messaging: { icon: '\u2709\uFE0F', label: 'Message sending' },
scheduling: { icon: '\u23F0', label: 'Scheduling/cron' },
}
type SkillInstallCardProps = {
clawdis: ClawdisSkillMetadata | undefined
osLabels: string[]
@@ -12,6 +22,7 @@ export function SkillInstallCard({ clawdis, osLabels }: SkillInstallCardProps) {
const envVars = clawdis?.envVars ?? []
const dependencies = clawdis?.dependencies ?? []
const links = clawdis?.links
const hasCapabilities = Boolean(clawdis?.capabilities?.length)
const hasRuntimeRequirements = Boolean(
clawdis?.emoji ||
osLabels.length ||
@@ -19,18 +30,35 @@ export function SkillInstallCard({ clawdis, osLabels }: SkillInstallCardProps) {
requirements?.anyBins?.length ||
requirements?.env?.length ||
requirements?.config?.length ||
clawdis?.primaryEnv ||
envVars.length,
envVars.length ||
clawdis?.primaryEnv,
)
const hasInstallSpecs = installSpecs.length > 0
const hasDependencies = dependencies.length > 0
const hasLinks = Boolean(links?.homepage || links?.repository || links?.documentation)
if (!hasRuntimeRequirements && !hasInstallSpecs && !hasDependencies && !hasLinks) return null
if (!hasCapabilities && !hasRuntimeRequirements && !hasInstallSpecs && !hasDependencies && !hasLinks) {
return null
}
return (
<div className="skill-hero-content">
<div className="skill-hero-panels">
{hasCapabilities ? (
<div className="skill-panel">
<h3 className="section-title" style={{ fontSize: '1rem', margin: 0 }}>
Capabilities
</h3>
<div className="skill-panel-body">
{clawdis!.capabilities!.map((cap) => (
<div key={cap} className="stat">
<span>{CAPABILITY_DISPLAY[cap]?.icon ?? cap}</span>
<span>{CAPABILITY_DISPLAY[cap]?.label ?? cap}</span>
</div>
))}
</div>
</div>
) : null}
{hasRuntimeRequirements ? (
<div className="skill-panel">
<h3 className="section-title" style={{ fontSize: '1rem', margin: 0 }}>
@@ -79,7 +107,10 @@ export function SkillInstallCard({ clawdis, osLabels }: SkillInstallCardProps) {
<strong>Environment variables</strong>
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem', marginTop: '0.25rem' }}>
{envVars.map((env, index) => (
<div key={`${env.name}-${index}`} style={{ display: 'flex', alignItems: 'baseline', gap: '0.5rem' }}>
<div
key={`${env.name}-${index}`}
style={{ display: 'flex', alignItems: 'baseline', gap: '0.5rem' }}
>
<code style={{ fontSize: '0.85rem' }}>{env.name}</code>
{env.required === false ? (
<span style={{ color: 'var(--ink-soft)', fontSize: '0.75rem' }}>optional</span>
@@ -87,7 +118,9 @@ export function SkillInstallCard({ clawdis, osLabels }: SkillInstallCardProps) {
<span style={{ color: 'var(--ink-accent)', fontSize: '0.75rem' }}>required</span>
) : null}
{env.description ? (
<span style={{ color: 'var(--ink-soft)', fontSize: '0.8rem' }}> {env.description}</span>
<span style={{ color: 'var(--ink-soft)', fontSize: '0.8rem' }}>
{env.description}
</span>
) : null}
</div>
))}
@@ -108,16 +141,21 @@ export function SkillInstallCard({ clawdis, osLabels }: SkillInstallCardProps) {
<div>
<strong>{dep.name}</strong>
<span style={{ color: 'var(--ink-soft)', fontSize: '0.85rem', marginLeft: '0.5rem' }}>
{dep.type}{dep.version ? ` ${dep.version}` : ''}
{dep.type}
{dep.version ? ` ${dep.version}` : ''}
</span>
{dep.url ? (
<div style={{ fontSize: '0.8rem' }}>
<a href={dep.url} target="_blank" rel="noopener noreferrer">{dep.url}</a>
<a href={dep.url} target="_blank" rel="noopener noreferrer">
{dep.url}
</a>
</div>
) : null}
{dep.repository && dep.repository !== dep.url ? (
<div style={{ fontSize: '0.8rem' }}>
<a href={dep.repository} target="_blank" rel="noopener noreferrer">Source</a>
<a href={dep.repository} target="_blank" rel="noopener noreferrer">
Source
</a>
</div>
) : null}
</div>
@@ -160,19 +198,25 @@ export function SkillInstallCard({ clawdis, osLabels }: SkillInstallCardProps) {
{links?.homepage ? (
<div className="stat">
<strong>Homepage</strong>
<a href={links.homepage} target="_blank" rel="noopener noreferrer">{links.homepage}</a>
<a href={links.homepage} target="_blank" rel="noopener noreferrer">
{links.homepage}
</a>
</div>
) : null}
{links?.repository ? (
<div className="stat">
<strong>Repository</strong>
<a href={links.repository} target="_blank" rel="noopener noreferrer">{links.repository}</a>
<a href={links.repository} target="_blank" rel="noopener noreferrer">
{links.repository}
</a>
</div>
) : null}
{links?.documentation ? (
<div className="stat">
<strong>Docs</strong>
<a href={links.documentation} target="_blank" rel="noopener noreferrer">{links.documentation}</a>
<a href={links.documentation} target="_blank" rel="noopener noreferrer">
{links.documentation}
</a>
</div>
) : null}
</div>