Learning Objectives

Lists learning goals for educational content.

Report a bug

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Installation

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/learning-objectives.json

Storybook

Explore all variants, controls, and accessibility checks in the interactive Storybook playground.

View in Storybook

2 stories available:

Code

"use client"; import { CheckCircle2, Clock, GraduationCap, Target } from "lucide-react"; import type { ReactNode } from "react"; import type { HeadingTag } from "../../lib/types"; export type LearningObjectivesProps = { /** Heading tag for the title. Defaults to `h4`. */ as?: HeadingTag; estimatedTime?: string; objectives: string[]; title?: string; }; export function LearningObjectives({ as: Heading = "h4", estimatedTime, objectives, title = "What you'll learn", }: LearningObjectivesProps) { return ( <div className="my-6 rounded-lg border bg-gradient-to-br from-primary/5 to-primary/10 p-6"> <div className="flex items-center justify-between mb-4"> <div className="flex items-center gap-2"> <Target className="size-5 text-primary" /> <Heading className="font-semibold text-foreground">{title}</Heading> </div> {estimatedTime ? ( <div className="flex items-center gap-1 text-sm text-muted-foreground"> <Clock className="size-4" /> <span>{estimatedTime}</span> </div> ) : null} </div> <ul className="space-y-2"> {objectives.map((objective) => ( <li className="flex items-start gap-2" key={objective}> <CheckCircle2 className="size-4 text-primary flex-shrink-0 mt-0.5" /> <span className="text-sm text-muted-foreground">{objective}</span> </li> ))} </ul> </div> ); } export type PrerequisitesProps = { items: string[]; level?: "advanced" | "beginner" | "intermediate"; title?: string; }; export function Prerequisites({ items, level, title = "Prerequisites", }: PrerequisitesProps) { return ( <div className="my-6 rounded-lg border bg-muted/30 p-6"> <div className="flex items-center justify-between mb-4"> <div className="flex items-center gap-2"> <GraduationCap className="size-5 text-muted-foreground" /> <h4 className="font-semibold text-foreground">{title}</h4> </div> {level ? ( <span className="text-xs font-medium px-2 py-1 rounded-full bg-primary/10 text-primary capitalize"> {level} </span> ) : null} </div> <ul className="space-y-2"> {items.map((item) => ( <li className="flex items-start gap-2 text-sm text-muted-foreground" key={item} > <span className="text-primary"></span> {item} </li> ))} </ul> </div> ); } export type SummaryProps = { children: ReactNode; keyTakeaways?: string[]; title?: string; }; export function Summary({ children, keyTakeaways, title = "Summary", }: SummaryProps) { return ( <div className="my-6 rounded-lg border bg-muted/30 p-6"> <h4 className="font-semibold text-foreground mb-3 flex items-center gap-2"> <GraduationCap className="size-5" /> {title} </h4> <div className="text-sm text-muted-foreground [&>p]:mb-2">{children}</div> {keyTakeaways && keyTakeaways.length > 0 ? ( <div className="mt-4 pt-4 border-t border-border"> <p className="text-xs font-medium uppercase tracking-wider text-muted-foreground mb-2"> Key Takeaways </p> <ul className="space-y-1"> {keyTakeaways.map((takeaway) => ( <li className="flex items-start gap-2 text-sm" key={takeaway}> <CheckCircle2 className="size-4 text-green-500 flex-shrink-0 mt-0.5" /> <span className="text-muted-foreground">{takeaway}</span> </li> ))} </ul> </div> ) : null} </div> ); }

Dependencies

  • @vllnt/ui@^0.2.1