opensourceui
GitHubTwitter/X
  1. Home
  2. Components
  3. Dashboard
  4. Ai Script Card
Back to Dashboard

Components / Dashboard

Ai Script Card

Free Dashboard React component — AiScriptCard. MIT licensed, copy-paste ready for Next.js and Tailwind CSS.

AI script card with duration badge, edit/regenerate actions, and audio waveform playback row.

Preview

Track

1:38

Corporate AI helps you hire smarter by instantly analyzing resumes, scoring candidates, and delivering clear, data-driven insights—so you can focus on the best talent

00:00 / 01:20

Setup

How to use

Free for personal and commercial use. No UI attribution required. Include the MIT copyright notice when copying component source into your project. Read the MIT license.

  1. 1

    Run in your terminal:

    $npm install clsx tailwind-merge lucide-react
  2. 2

    Copy lib/cn.ts below. Skip if you already have cn().

  3. 3

    Copy the code below and create components/dashboard/ai-script-card.tsx in your project.

  4. 4

    Import and render:

    Example

    import { AiScriptCard } from "@/components/dashboard/ai-script-card";

    <AiScriptCard duration="1:38" currentTime="00:00" totalTime="01:20" />

lib/cn.ts

1
2
3
4
5
6
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

components/dashboard/ai-script-card.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
"use client";
 
import {
forwardRef,
useState,
type ComponentPropsWithoutRef,
} from "react";
 
import { Clock3, Pause, Play, Sparkles } from "lucide-react";
 
import { cn } from "@/lib/cn";
 
export type AiScriptCardProps = Readonly<
{
title?: string;
duration?: string;
body?: string;
currentTime?: string;
totalTime?: string;
waveform?: readonly number[];
onEdit?: () => void;
onRegenerate?: () => void;
onTogglePlayback?: (playing: boolean) => void;
} & ComponentPropsWithoutRef<"article">
>;
 
const DEFAULT_WAVE = [
2, 4, 6, 3, 7, 5, 8, 4, 6, 9, 5, 7, 4, 8, 6, 5, 7, 9, 4, 6, 8, 5, 7, 6,
] as const;
 
function barHeightClass(value: number): string {
const index = Math.min(4, Math.max(0, Math.round(value / 2)));
return ["h-1", "h-2", "h-3", "h-4", "h-5"][index];
}
 
// AI script card — generated script with playback controls and waveform.
export const AiScriptCard = forwardRef<HTMLElement, AiScriptCardProps>(
(
{
className,
title = "Track",
duration = "1:38",
body = "Corporate AI helps you hire smarter by instantly analyzing resumes, scoring candidates, and delivering clear, data-driven insights—so you can focus on the best talent",
currentTime = "00:00",
totalTime = "01:20",
waveform = DEFAULT_WAVE,
onEdit,
onRegenerate,
onTogglePlayback,
...props
},
ref,
) => {
const [playing, setPlaying] = useState(false);
 
const togglePlayback = () => {
setPlaying((value) => {
const next = !value;
onTogglePlayback?.(next);
return next;
});
};
 
return (
<article
ref={ref}
data-slot="ai-script-card"
className={cn(
"w-md max-w-full rounded-3xl border border-neutral-100 bg-white p-5 font-sans shadow-lg shadow-black/5",
className,
)}
{...props}
>
<header className="flex flex-wrap items-center justify-between gap-3">
<div className="flex items-center gap-2">
<Sparkles size={15} aria-hidden className="text-neutral-700" />
<h2 className="text-base font-semibold text-neutral-900">{title}</h2>
<span className="inline-flex items-center gap-1 rounded-full bg-neutral-100 px-2 py-0.5 text-[10px] font-medium text-neutral-600">
<Clock3 size={11} aria-hidden />
{duration}
</span>
</div>
 
<div className="flex items-center gap-2">
<button
type="button"
onClick={onEdit}
className="rounded-full bg-neutral-100 px-3 py-1.5 text-xs font-medium text-neutral-700 transition-colors hover:bg-neutral-200"
>
Edit
</button>
<button
type="button"
onClick={onRegenerate}
className="rounded-full bg-neutral-900 px-3 py-1.5 text-xs font-medium text-white transition-opacity hover:opacity-90"
>
Regenerate
</button>
</div>
</header>
 
<p className="mt-4 text-sm leading-relaxed text-neutral-600">{body}</p>
 
<div className="mt-5 flex items-center gap-3">
<button
type="button"
aria-label={playing ? "Pause script" : "Play script"}
onClick={togglePlayback}
className="flex size-9 shrink-0 items-center justify-center rounded-full bg-neutral-100 text-neutral-800 transition-colors hover:bg-neutral-200"
>
{playing ? (
<Pause size={14} aria-hidden fill="currentColor" />
) : (
<Play size={14} aria-hidden className="ml-0.5" fill="currentColor" />
)}
</button>
 
<div className="flex h-8 flex-1 items-center gap-0.5 overflow-hidden">
{waveform.map((height, index) => (
<span
key={`script-wave-${index}`}
aria-hidden
className={cn(
"w-0.5 shrink-0 rounded-full bg-lime-300",
barHeightClass(height),
)}
/>
))}
</div>
 
<span className="shrink-0 text-[11px] text-neutral-400 tabular-nums">
{currentTime} / {totalTime}
</span>
</div>
</article>
);
},
);
 
AiScriptCard.displayName = "AiScriptCard";
PreviousNext

On this

page

Jump to a section on this page.

  • lib/cn.ts
  • components/dashboard/ai-script-card.tsx

Sponsor spot · demo preview

Logo

Your brand name

Your tagline or category

A short pitch about your product or service goes here. This is a preview of how sponsor cards will look in this sidebar.

Your call to action

This slot is available. Sponsor Opensource UI and reach developers browsing components every day.