Files
learning-lab-express/src/components/Icon.tsx
Iqbal 42464d88b3 Show the workspace credit balance in the topbar
Read from GET /organizations/me, refreshed after every action and every
30 seconds, since agents and schedules spend credits in the background.
The date is dropped from the topbar, and its items wrap on phones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:57:01 +07:00

53 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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"/>',
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"/>',
logout: '<path d="M10 4H4v16h6M10 12h11m-4-4 4 4-4 4"/>',
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"/>',
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>
)
}