Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions packages/ui/src/components/checklist/checklist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { useState } from "react";

import { cn } from "../../lib/utils";

export const CHECKLIST_PROGRESS_EVENT = "vllnt:checklist-progress-change";

export type ChecklistItem = {
description?: string;
id: string;
Expand Down Expand Up @@ -159,6 +161,11 @@ export function Checklist({
`checklist:${persistKey}`,
JSON.stringify([...newChecked]),
);
window.dispatchEvent(
new CustomEvent(CHECKLIST_PROGRESS_EVENT, {
detail: { persistKey },
}),
);
} catch {
/* skip */
}
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/components/checklist/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export {
Checklist,
CHECKLIST_PROGRESS_EVENT,
type ChecklistItem,
type ChecklistProps,
} from "./checklist";
19 changes: 19 additions & 0 deletions packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,25 @@ export {
type ProgressCardProgress,
type ProgressCardProps,
} from "./progress-card";
export {
ProgressTracker,
ProgressTrackerBadge,
type ProgressTrackerBadgeProps,
ProgressTrackerModule,
type ProgressTrackerModuleItem,
type ProgressTrackerModuleProps,
ProgressTrackerModules,
type ProgressTrackerModulesProps,
type ProgressTrackerModuleStatus,
ProgressTrackerOverview,
type ProgressTrackerOverviewProps,
type ProgressTrackerProps,
ProgressTrackerStat,
type ProgressTrackerStatProps,
ProgressTrackerStats,
type ProgressTrackerStatsProps,
useProgressTrackerContext,
} from "./progress-tracker";
export {
CommonMistake,
type CommonMistakeProps,
Expand Down
19 changes: 19 additions & 0 deletions packages/ui/src/components/progress-tracker/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export {
ProgressTracker,
ProgressTrackerBadge,
type ProgressTrackerBadgeProps,
ProgressTrackerModule,
type ProgressTrackerModuleItem,
type ProgressTrackerModuleProps,
ProgressTrackerModules,
type ProgressTrackerModulesProps,
type ProgressTrackerModuleStatus,
ProgressTrackerOverview,
type ProgressTrackerOverviewProps,
type ProgressTrackerProps,
ProgressTrackerStat,
type ProgressTrackerStatProps,
ProgressTrackerStats,
type ProgressTrackerStatsProps,
useProgressTrackerContext,
} from "./progress-tracker";
49 changes: 49 additions & 0 deletions packages/ui/src/components/progress-tracker/progress-tracker.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Canvas, Controls, Meta, Primary } from '@storybook/addon-docs/blocks'
import * as Stories from './progress-tracker.stories'

<Meta of={Stories} />

# Progress Tracker

Curriculum-level learning dashboard for modules, lessons, exercises, streaks, and earned skills.

<Primary />

## Installation

```bash
pnpm dlx shadcn@latest add https://ui.vllnt.com/r/progress-tracker.json
```

## Import

```tsx
import { ProgressTracker } from '@vllnt/ui'
```

## Usage

```tsx
<ProgressTracker modules={modules} overallProgress={0.65} streak={7}>
<ProgressTracker.Overview />
<ProgressTracker.Stats>
<ProgressTracker.Stat label="Streak" value="7 days" />
<ProgressTracker.Stat label="Time Spent" value="24h" />
</ProgressTracker.Stats>
<ProgressTracker.Modules>
<ProgressTracker.Module
title="React Fundamentals"
progress={0.4}
status="in-progress"
lessons={8}
completedLessons={3}
/>
</ProgressTracker.Modules>
</ProgressTracker>
```

<Canvas of={Stories.Default} sourceState="shown" />

## API Reference

<Controls />
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import type { Meta, StoryObj } from "@storybook/react-vite";

import {
ProgressTracker,
ProgressTrackerModule,
ProgressTrackerModules,
ProgressTrackerOverview,
ProgressTrackerStat,
ProgressTrackerStats,
type ProgressTrackerProps,
} from "./progress-tracker";

const meta = {
args: {
modules: [
{
badge: "Foundation",
completedExercises: 18,
completedLessons: 12,
currentLesson: "Final assessment",
description: "Build confidence with variables, functions, and arrays.",
exercises: 18,
lessons: 12,
progress: 1,
skills: ["Syntax", "Functions", "Arrays"],
status: "completed",
timeSpent: "8h 10m",
title: "JavaScript Basics",
},
{
badge: "Now learning",
completedExercises: 5,
completedLessons: 3,
currentLesson: "Hooks in action",
description: "Move from JSX to reusable interactive interfaces.",
exercises: 12,
lessons: 8,
progress: 0.4,
skills: ["Components", "Hooks", "State"],
status: "in-progress",
timeSpent: "6h 20m",
title: "React Fundamentals",
},
{
badge: "Next up",
completedExercises: 0,
completedLessons: 0,
currentLesson: "Unlock after React Fundamentals",
description: "Design resilient APIs and asynchronous application flows.",
exercises: 10,
lessons: 6,
progress: 0,
skills: ["REST", "Caching", "Error handling"],
status: "available",
timeSpent: "0h",
title: "API Design",
},
{
badge: "Locked",
completedExercises: 0,
completedLessons: 0,
currentLesson: "Requires API Design",
description: "Bring everything together with deployment and observability.",
exercises: 14,
lessons: 9,
progress: 0,
skills: ["CI", "Monitoring", "Release"],
status: "locked",
timeSpent: "0h",
title: "Ship to production",
},
],
overallProgress: 0.65,
streak: 7,
title: "Frontend mastery path",
},
component: ProgressTracker,
title: "Learning/ProgressTracker",
} satisfies Meta<typeof ProgressTracker>;

export default meta;
type Story = StoryObj<typeof meta>;

function ProgressTrackerStory(args: ProgressTrackerProps): React.ReactNode {
return (
<ProgressTracker {...args} className="max-w-6xl">
<ProgressTrackerOverview description="A curriculum-level dashboard for lessons, exercises, and learning streaks." />
<ProgressTrackerStats>
<ProgressTrackerStat label="Streak" value="7 days" />
<ProgressTrackerStat label="Time Spent" value="24h" />
<ProgressTrackerStat label="Exercises" value="45/80" />
<ProgressTrackerStat label="Skills unlocked" value="12" />
</ProgressTrackerStats>
<ProgressTrackerModules>
{args.modules?.map((module) => (
<ProgressTrackerModule key={module.title} {...module} />
))}
</ProgressTrackerModules>
</ProgressTracker>
);
}

export const Default: Story = {
render: (args) => <ProgressTrackerStory {...args} />,
};

export const CompactDashboard: Story = {
args: {
overallProgress: 0.82,
streak: 12,
title: "Bootcamp progress",
},
render: (args) => <ProgressTrackerStory {...args} />,
};
Loading