The page now lives at /instruction; /brain and /perintah redirect there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
3.3 KiB
TypeScript
61 lines
3.3 KiB
TypeScript
import type { ContentKind, Rule } from '../express/parse'
|
||
|
||
// Line icons from the mockup (24×24, stroke = currentColor).
|
||
const paths: Record<string, string> = {
|
||
book: '<path d="M3 5c3-1 6 0 9 2 3-2 6-3 9-2v14c-3-1-6 0-9 2-3-2-6-3-9-2z"/><path d="M12 7v14M6 9l3 1M15 10l3-1"/>',
|
||
home: '<path d="m3 10 9-7 9 7v10H3z"/><path d="M9 20v-7h6v7"/>',
|
||
spark: '<path d="m12 3 2.5 6.5L21 12l-6.5 2.5L12 21l-2.5-6.5L3 12l6.5-2.5z"/><path d="m20 2 .5 1.5L22 4l-1.5.5L20 6l-.5-1.5L18 4l1.5-.5z"/>',
|
||
calendar: '<rect x="3" y="5" width="18" height="16" rx="2"/><path d="M7 3v4M17 3v4M3 11h18M7 15h3M14 15h3"/>',
|
||
clock: '<circle cx="12" cy="12" r="9"/><path d="M12 7v6l4 2"/>',
|
||
layers: '<path d="m12 3 10 5-10 5L2 8zM2 12l10 5 10-5M2 16l10 5 10-5"/>',
|
||
download: '<path d="M12 3v12m-5-5 5 5 5-5M4 16v5h16v-5"/>',
|
||
upload: '<path d="M12 16V4m-5 5 5-5 5 5M4 16v5h16v-5"/>',
|
||
file: '<path d="M5 3h9l5 5v13H5zM14 3v6h5M8 13h8M8 17h6"/>',
|
||
'arrow-right': '<path d="M4 12h16m-6-6 6 6-6 6"/>',
|
||
external: '<path d="M14 4h6v6M20 4l-9 9M18 14v6H4V6h6"/>',
|
||
close: '<path d="M6 6l12 12M18 6 6 18"/>',
|
||
search: '<circle cx="10" cy="10" r="6"/><path d="m15 15 5 5"/>',
|
||
info: '<circle cx="12" cy="12" r="9"/><path d="M12 11v6M12 7v.2"/>',
|
||
check: '<path d="m5 12 4 4L19 6"/>',
|
||
'chevron-down': '<path d="m6 9 6 6 6-6"/>',
|
||
expand: '<path d="M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5"/>',
|
||
shrink: '<path d="M9 4v5H4M15 4v5h5M9 20v-5H4M15 20v-5h5"/>',
|
||
sidebar: '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M9 4v16"/>',
|
||
'chevron-updown': '<path d="m8 9 4-4 4 4M8 15l4 4 4-4"/>',
|
||
logout:'<path d="M10 4H4v16h6M10 12h11m-4-4 4 4-4 4"/>',
|
||
user: '<circle cx="12" cy="8" r="4"/><path d="M4 21c1-4 4-6 8-6s7 2 8 6"/>',
|
||
plus: '<path d="M12 4v16M4 12h16"/>',
|
||
trash: '<path d="M3 6h18M9 3h6l1 3M6 6l1 15h10l1-15M10 10v7M14 10v7"/>',
|
||
video: '<rect x="3" y="5" width="18" height="14" rx="3"/><path d="m10 9 5 3-5 3z"/>',
|
||
audio: '<path d="M4 13v-2a8 8 0 0 1 16 0v2"/><rect x="3" y="11" width="4" height="8" rx="2"/><rect x="17" y="11" width="4" height="8" rx="2"/>',
|
||
scorm: '<path d="m12 3 9 5-9 5-9-5zM3 8v9l9 5 9-5V8M12 13v9"/>',
|
||
chart: '<path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/>',
|
||
coin: '<circle cx="12" cy="12" r="9"/><path d="M15 9.5c-.5-1-1.6-1.5-3-1.5-1.7 0-3 .8-3 2s1.3 1.7 3 2 3 .8 3 2-1.3 2-3 2c-1.4 0-2.5-.5-3-1.5M12 6v2M12 16v2"/>',
|
||
brain: '<path d="M12 5c-3-4-8-1-7 3-4 2-3 7 0 8-1 4 5 6 7 2M12 5c3-4 8-1 7 3 4 2 3 7 0 8 1 4-5 6-7 2M12 5v15M7 9l3 2M17 9l-3 2M6 15l3-1M18 15l-3-1"/>',
|
||
}
|
||
|
||
export type IconName = keyof typeof paths
|
||
|
||
export const KIND_ICON: Record<ContentKind, IconName> = {
|
||
summary: 'file', quiz: 'check', flashcards: 'layers', roleplay: 'spark', simulator: 'spark', slide_deck: 'layers',
|
||
video: 'video', audio: 'audio', scorm: 'scorm',
|
||
}
|
||
|
||
export const ruleIcon = (rule: Rule): IconName => (rule.type === 'research' ? 'search' : KIND_ICON[rule.kind])
|
||
|
||
export function Icon({ name }: { name: IconName }) {
|
||
return (
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.7} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"
|
||
dangerouslySetInnerHTML={{ __html: paths[name] ?? paths.file }} />
|
||
)
|
||
}
|
||
|
||
export function Brand() {
|
||
return (
|
||
<span className="brand">
|
||
<span className="brand-mark"><Icon name="book" /></span>
|
||
<span>Learning Lab <b>Express</b><small>by BAWANA</small></span>
|
||
</span>
|
||
)
|
||
}
|