118 lines
4.1 KiB
JavaScript
118 lines
4.1 KiB
JavaScript
import React from 'react';
|
|
import { Plus, CheckCircle2, Lightbulb, History, Layers } from 'lucide-react';
|
|
import { cn } from '@/lib/utils';
|
|
import { statusOf } from './challengeMeta';
|
|
|
|
const CREATE_STEPS = [
|
|
'Define skill',
|
|
'Add training',
|
|
'Define proof',
|
|
'Configure Owliver',
|
|
'Publish',
|
|
];
|
|
|
|
const TIPS = [
|
|
'Keep training focused on one skill.',
|
|
'Prefer practical evidence over recall.',
|
|
'Define clear verification criteria.',
|
|
'Use real workplace scenarios.',
|
|
'Keep training concise.',
|
|
];
|
|
|
|
export function ForgeRail({ recent = [], onCreate, onOpen, onAskOwliver }) {
|
|
return (
|
|
<aside
|
|
className="grid grid-cols-1 gap-4 sm:grid-cols-3 lg:grid-cols-3 items-stretch"
|
|
aria-label="Forge guidance"
|
|
>
|
|
{/* 1. Create Skill Card */}
|
|
<Panel
|
|
title="Create Skill"
|
|
icon={Layers}
|
|
iconColor="text-blue-600"
|
|
>
|
|
<ol className="space-y-2.5">
|
|
{CREATE_STEPS.map((label, i) => (
|
|
<li key={label} className="flex items-center gap-2.5 text-body-sm text-ink-2">
|
|
<span className="flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-blue-100 dark:bg-blue-950 text-[10px] font-bold tabular-nums text-blue-600 dark:text-blue-400 border border-blue-200/50">
|
|
{i + 1}
|
|
</span>
|
|
<span className="min-w-0 font-medium">{label}</span>
|
|
</li>
|
|
))}
|
|
</ol>
|
|
<button
|
|
type="button"
|
|
onClick={onCreate}
|
|
className="mt-4 inline-flex w-full items-center justify-center gap-2 rounded-xl bg-blue-600 px-4 py-2.5 text-caption font-bold text-white shadow-md shadow-blue-500/20 transition-all hover:bg-blue-700 active:scale-[0.98]"
|
|
>
|
|
<Plus className="h-4 w-4" />
|
|
Start a new skill
|
|
</button>
|
|
</Panel>
|
|
|
|
|
|
{/* 3. Quick Tips Card */}
|
|
<Panel
|
|
title="Quick Tips"
|
|
icon={Lightbulb}
|
|
iconColor="text-amber-500"
|
|
>
|
|
<ul className="space-y-2.5">
|
|
{TIPS.map((tip) => (
|
|
<li key={tip} className="flex items-start gap-2 text-caption leading-relaxed text-ink-2">
|
|
<CheckCircle2 className="h-3.5 w-3.5 shrink-0 text-emerald-500 mt-0.5" aria-hidden="true" />
|
|
<span className="min-w-0 font-medium">{tip}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</Panel>
|
|
|
|
{/* 4. Recent Skills Card */}
|
|
{recent.length > 0 && (
|
|
<Panel
|
|
title="Recent Skills"
|
|
icon={History}
|
|
iconColor="text-purple-600"
|
|
>
|
|
<ul className="divide-y divide-border/60">
|
|
{recent.map((course) => (
|
|
<li key={course.id}>
|
|
<button
|
|
type="button"
|
|
onClick={() => onOpen(course)}
|
|
className="group flex w-full items-center justify-between gap-3 py-2.5 text-left transition-colors hover:text-blue-600"
|
|
>
|
|
<span className="min-w-0">
|
|
<span className="block truncate text-body-sm font-semibold text-ink-1 group-hover:text-blue-600">
|
|
{course.title}
|
|
</span>
|
|
<span className="block truncate text-[10px] text-ink-4">{course.category}</span>
|
|
</span>
|
|
<span className="shrink-0 rounded-full bg-surface-subtle px-2 py-0.5 text-[9px] font-bold uppercase tracking-wider text-ink-3">
|
|
{statusOf(course)}
|
|
</span>
|
|
</button>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</Panel>
|
|
)}
|
|
</aside>
|
|
);
|
|
}
|
|
|
|
function Panel({ title, icon: Icon, iconColor, children }) {
|
|
return (
|
|
<section className="rounded-2xl border border-border/80 bg-surface p-5 shadow-xs transition-all hover:border-blue-500/30">
|
|
<div className="flex items-center gap-2 mb-3.5 pb-2 border-b border-border/60">
|
|
{Icon && <Icon className={cn('h-4 w-4', iconColor)} />}
|
|
<h2 className="font-heading text-[11px] font-bold uppercase tracking-wider text-ink-3">
|
|
{title}
|
|
</h2>
|
|
</div>
|
|
{children}
|
|
</section>
|
|
);
|
|
}
|