Initial commit: Learning Lab Express
Includes fixes found while reviewing the app: - Results: open each result by a type+agent+id key, so a video and a material draft with the same id no longer open each other's popup - AuthGate: clear the query cache during render, before pages build their queries, and remount pages on organization switch (pages no longer stay on skeletons for up to a minute after sign-in or refresh) - Instruction: keep only failed rules after a partial approve, so retrying does not create the successful schedules twice; drop the monthly note once count or frequency is edited - Parser/schedules: never schedule a count below one - Audio: ignore the end event of a cancelled utterance when changing speed - Downloads: revoke the object URL later so Safari/Firefox can read it - Results: refetch SCORM content when any part's revision changes; show a failed video as failed instead of "still rendering" Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
51
src/components/Icon.tsx
Normal file
51
src/components/Icon.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
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"/>',
|
||||
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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user