Library: - Clear CTA hierarchy: "Build New Script" primary, "Import Script" ghost, "Manage" demoted to text link - "New from Script" → "Import Script" (clearer label) Script Builder: - Add suggestion chips for first-time users (4 common MSP tasks) - Chips auto-hide after first message Design system normalization: - ScriptPreviewModal: bg-black/80 → bg-black/40, text-blue-400 → text-accent-text, emerald save button → primary, inline rgba → CSS variables - ScriptCodeBlock: bg-[rgba(0,0,0,0.3)] → bg-code, text-blue-400 → text-accent-text, text-text-muted typo fixed, emerald button → ghost style - TemplateCard: emerald/amber/rose badges → success-dim/warning-dim/danger-dim, ShieldAlert amber → warning token - ParameterDetectorStepper: blue focus ring → orange, amber → warning token, "Candidate" → "Variable" in stepper progress Jargon clarification: - "Detect Parameters" → "Find Variables" - "Detected Parameters" → "Configurable Variables" - "Parameters (N)" → "Variables (N)" - Detection summary copy reworded for clarity Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
73 lines
2.5 KiB
TypeScript
73 lines
2.5 KiB
TypeScript
import { ShieldAlert } from 'lucide-react'
|
||
import { cn } from '@/lib/utils'
|
||
import type { ScriptTemplateListItem } from '@/types'
|
||
|
||
const COMPLEXITY_CLASSES: Record<ScriptTemplateListItem['complexity'], string> = {
|
||
beginner: 'text-success bg-success-dim',
|
||
intermediate: 'text-warning bg-warning-dim',
|
||
advanced: 'text-danger bg-danger-dim',
|
||
}
|
||
|
||
interface Props {
|
||
template: ScriptTemplateListItem
|
||
onConfigure: (id: string) => void
|
||
}
|
||
|
||
export function TemplateCard({ template, onConfigure }: Props) {
|
||
return (
|
||
<div
|
||
className={cn(
|
||
'w-full px-4 py-3 rounded-xl border transition-all',
|
||
'border-border bg-transparent'
|
||
)}
|
||
>
|
||
<div className="flex items-start justify-between gap-2 mb-1">
|
||
<span className="text-sm font-medium text-foreground line-clamp-1">
|
||
{template.name}
|
||
</span>
|
||
<div className="flex items-center gap-1.5 shrink-0">
|
||
{template.requires_elevation && (
|
||
<span title="Requires administrator elevation">
|
||
<ShieldAlert size={13} className="text-warning" />
|
||
</span>
|
||
)}
|
||
<span className={cn('font-sans text-[0.625rem] uppercase tracking-wide px-1.5 py-0.5 rounded', COMPLEXITY_CLASSES[template.complexity])}>
|
||
{template.complexity}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
{template.description && (
|
||
<p className="text-xs text-muted-foreground line-clamp-2 mb-2">
|
||
{template.description}
|
||
</p>
|
||
)}
|
||
|
||
<div className="flex items-center justify-between gap-3">
|
||
<div className="flex items-center gap-3 text-[0.625rem] text-muted-foreground font-sans">
|
||
<span>{template.usage_count}× used</span>
|
||
{template.tags.length > 0 && (
|
||
<div className="flex gap-1 flex-wrap">
|
||
{template.tags.slice(0, 3).map(tag => (
|
||
<span key={tag} className="bg-white/5 border border-border rounded px-1.5 py-0.5">
|
||
{tag}
|
||
</span>
|
||
))}
|
||
{template.tags.length > 3 && (
|
||
<span className="text-muted-foreground">+{template.tags.length - 3}</span>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
<button
|
||
type="button"
|
||
onClick={() => onConfigure(template.id)}
|
||
className="shrink-0 bg-accent-dim border border-primary/20 text-accent-text text-xs px-2.5 py-1 rounded-md hover:bg-primary/20 transition-colors"
|
||
>
|
||
Configure →
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|