Skip to content

Commit 37eb1fb

Browse files
fix(shadcn): grid and bar visualizer styling and configuration (#1287)
1 parent f45131c commit 37eb1fb

8 files changed

Lines changed: 249 additions & 94 deletions

docs/storybook/stories/agents-ui/AgentAudioVisualizerBar.stories.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
1-
import React from 'react';
1+
import * as React from 'react';
22
import { StoryObj } from '@storybook/react-vite';
33
import { useSessionContext } from '@livekit/components-react';
44
import { AgentSessionProvider } from '../../.storybook/lk-decorators/AgentSessionProvider';
5-
import { AgentAudioVisualizerBar, AgentAudioVisualizerBarProps } from '@agents-ui';
5+
import {
6+
AgentAudioVisualizerBar,
7+
AgentAudioVisualizerBarElementVariants,
8+
AgentAudioVisualizerBarProps,
9+
} from '@agents-ui';
10+
import { cn } from '@/lib/utils';
611

712
export default {
813
component: AgentAudioVisualizerBar,
914
decorators: [AgentSessionProvider],
10-
render: (args: AgentAudioVisualizerBarProps) => {
15+
render: ({ color, ...args }: AgentAudioVisualizerBarProps & { color?: string }) => {
1116
const {
1217
local: { microphoneTrack },
1318
} = useSessionContext();
1419

15-
return <AgentAudioVisualizerBar {...args} audioTrack={microphoneTrack} />;
20+
return (
21+
<div style={{ color }}>
22+
<AgentAudioVisualizerBar {...args} audioTrack={microphoneTrack} />
23+
</div>
24+
);
1625
},
1726
args: {
1827
size: 'xl',
@@ -41,6 +50,7 @@ export default {
4150
barCount: {
4251
control: { type: 'range', min: 1, max: 24, step: 1 },
4352
},
53+
color: { control: { type: 'color' } },
4454
className: { control: { type: 'text' } },
4555
},
4656
parameters: {
@@ -54,3 +64,9 @@ export default {
5464
export const Default: StoryObj<AgentAudioVisualizerBarProps> = {
5565
args: {},
5666
};
67+
68+
export const Demo1: StoryObj<AgentAudioVisualizerBarProps> = {
69+
args: {
70+
color: '#F9B11F',
71+
},
72+
};

docs/storybook/stories/agents-ui/AgentAudioVisualizerGrid.stories.tsx

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
import * as React from 'react';
22
import { StoryObj } from '@storybook/react-vite';
33
import { AgentSessionProvider } from '../../.storybook/lk-decorators/AgentSessionProvider';
4-
import { AgentAudioVisualizerGrid, AgentAudioVisualizerGridProps } from '@agents-ui';
4+
import {
5+
AgentAudioVisualizerGrid,
6+
AgentAudioVisualizerGridProps,
7+
AgentAudioVisualizerGridCellVariants,
8+
} from '@agents-ui';
59
import { useSessionContext } from '@livekit/components-react';
10+
import { cn } from '@/lib/utils';
611

712
export default {
813
component: AgentAudioVisualizerGrid,
914
decorators: [AgentSessionProvider],
10-
render: (args: AgentAudioVisualizerGridProps) => {
15+
render: ({ color, ...args }: AgentAudioVisualizerGridProps & { color?: string }) => {
1116
const {
1217
local: { microphoneTrack },
1318
} = useSessionContext();
1419

15-
return <AgentAudioVisualizerGrid {...args} audioTrack={microphoneTrack} />;
20+
return (
21+
<div style={{ color }}>
22+
<AgentAudioVisualizerGrid {...args} audioTrack={microphoneTrack} />
23+
</div>
24+
);
1625
},
1726
args: {
1827
size: 'lg',
@@ -21,6 +30,7 @@ export default {
2130
interval: 100,
2231
rowCount: 9,
2332
columnCount: 9,
33+
color: undefined,
2434
},
2535
argTypes: {
2636
size: {
@@ -54,6 +64,7 @@ export default {
5464
control: { type: 'range', min: 1, max: 40, step: 1 },
5565
},
5666
className: { control: { type: 'text' } },
67+
color: { control: { type: 'color' } },
5768
},
5869
parameters: {
5970
layout: 'centered',
@@ -64,47 +75,69 @@ export default {
6475
};
6576

6677
export const Default: StoryObj<AgentAudioVisualizerGridProps> = {
67-
args: {
68-
69-
},
78+
args: {},
7079
};
7180

7281
export const Demo1: StoryObj<AgentAudioVisualizerGridProps> = {
7382
args: {
74-
className:
75-
'gap-4 *:size-1 *:rounded-full *:bg-foreground/10 [&_>_[data-lk-highlighted=true]]:bg-foreground [&_>_[data-lk-highlighted=true]]:scale-125 [&_>_[data-lk-highlighted=true]]:shadow-[0px_0px_10px_2px_rgba(255,255,255,0.4)]',
83+
className: 'gap-4',
84+
children: (
85+
<div
86+
className={cn(
87+
AgentAudioVisualizerGridCellVariants({ size: 'md' }),
88+
'data-[lk-highlighted=true]:bg-foreground data-[lk-highlighted=true]:scale-125',
89+
'shadow-[0_0_10px_2px_transparent] data-[lk-highlighted=true]:shadow-[0_0_10px_2px_var(--tw-shadow-color,currentColor)]',
90+
)}
91+
/>
92+
),
7693
},
7794
};
7895

7996
export const Demo2: StoryObj<AgentAudioVisualizerGridProps> = {
8097
args: {
81-
className:
82-
'gap-2 *:w-4 *:h-1 *:bg-foreground/10 [&_>_[data-lk-highlighted=true]]:bg-[#F9B11F] [&_>_[data-lk-highlighted=true]]:shadow-[0px_0px_14.8px_2px_#F9B11F]',
98+
color: '#F9B11F',
99+
className: 'gap-2',
100+
children: (
101+
<div
102+
className={cn(
103+
AgentAudioVisualizerGridCellVariants({ size: 'md' }),
104+
'w-4 h-1 bg-foreground/10',
105+
'shadow-[0_0_10px_2px_transparent] data-[lk-highlighted=true]:shadow-[0_0_10px_2px_var(--tw-shadow-color,currentColor)]',
106+
)}
107+
/>
108+
),
83109
},
84110
};
85111

86112
export const Demo3: StoryObj<AgentAudioVisualizerGridProps> = {
87113
args: {
88-
className:
89-
'gap-4 *:size-2 *:rounded-full *:bg-foreground/10 [&_>_[data-lk-highlighted=true]]:bg-[#1F8CF9] [&_>_[data-lk-highlighted=true]]:shadow-[0px_0px_14.8px_2px_#1F8CF9]',
90-
transformer: (index: number, rowCount: number, columnCount: number) => {
91-
const rowMidPoint = Math.floor(rowCount / 2);
92-
const distanceFromCenter = Math.sqrt(
93-
Math.pow(rowMidPoint - (index % columnCount), 2) +
94-
Math.pow(rowMidPoint - Math.floor(index / columnCount), 2),
95-
);
96-
97-
return {
98-
opacity: 1 - distanceFromCenter / columnCount,
99-
transform: `scale(${1 - (distanceFromCenter / (columnCount * 2)) * 1.75})`,
100-
};
101-
},
114+
color: '#1F8CF9',
115+
className: 'gap-4',
116+
children: (
117+
<div
118+
className={cn(
119+
AgentAudioVisualizerGridCellVariants({ size: 'md' }),
120+
'size-2 rounded-full bg-foreground/10',
121+
'shadow-[0_0_10px_2px_transparent] data-[lk-highlighted=true]:shadow-[0_0_10px_2px_var(--tw-shadow-color,currentColor)]',
122+
)}
123+
/>
124+
),
102125
},
103126
};
104127

105128
export const Demo4: StoryObj<AgentAudioVisualizerGridProps> = {
106129
args: {
107-
className:
108-
'gap-x-2.5 gap-y-1 *:w-3 *:h-px *:my-2 *:rotate-45 *:bg-foreground/10 *:rotate-45 *:scale-100 [&_>_[data-lk-highlighted=true]]:bg-[#FFB6C1] [&_>_[data-lk-highlighted=true]]:shadow-[0px_0px_8px_2px_rgba(255,182,193,0.4)] [&_>_[data-lk-highlighted=true]]:rotate-[405deg] [&_>_[data-lk-highlighted=true]]:scale-200',
130+
color: '#FFB6C1',
131+
className: 'gap-x-2.5 gap-y-1',
132+
children: (
133+
<div
134+
className={cn(
135+
AgentAudioVisualizerGridCellVariants({ size: 'md' }),
136+
'w-3 h-px my-2 rotate-45 bg-foreground/10 scale-100',
137+
'data-[lk-highlighted=true]:rotate-405 data-[lk-highlighted=true]:scale-200',
138+
'shadow-[0_0_10px_2px_transparent] data-[lk-highlighted=true]:shadow-[0_0_10px_2px_var(--tw-shadow-color,currentColor)]',
139+
)}
140+
/>
141+
),
109142
},
110143
};

packages/shadcn/components/agents-ui/agent-audio-visualizer-bar.tsx

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
'use client';
22

33
import React, {
4-
type ComponentProps,
5-
type ReactNode,
64
type CSSProperties,
7-
useMemo,
85
Children,
6+
type ComponentProps,
7+
type ReactNode,
98
cloneElement,
109
isValidElement,
10+
useMemo,
1111
} from 'react';
1212
import { type VariantProps, cva } from 'class-variance-authority';
1313
import { type LocalAudioTrack, type RemoteAudioTrack } from 'livekit-client';
@@ -43,20 +43,19 @@ function cloneSingleChild(
4343
});
4444
}
4545

46-
export const AgentAudioVisualizerBarVariants = cva(
46+
export const AgentAudioVisualizerBarElementVariants = cva(
4747
[
48-
'relative flex items-center justify-center',
49-
'*:rounded-full *:transition-colors *:duration-250 *:ease-linear',
50-
'*:bg-transparent *:data-[lk-highlighted=true]:bg-current',
48+
'rounded-full transition-colors duration-250 ease-linear',
49+
'bg-transparent data-[lk-highlighted=true]:bg-current',
5150
],
5251
{
5352
variants: {
5453
size: {
55-
icon: ['h-[24px] gap-[2px]', '*:w-[4px] *:min-h-[4px]'],
56-
sm: ['h-[56px] gap-[4px]', '*:w-[8px] *:min-h-[8px]'],
57-
md: ['h-[112px] gap-[8px]', '*:w-[16px] *:min-h-[16px]'],
58-
lg: ['h-[224px] gap-[16px]', '*:w-[32px] *:min-h-[32px]'],
59-
xl: ['h-[448px] gap-[32px]', '*:w-[64px] *:min-h-[64px]'],
54+
icon: 'w-[4px] min-h-[4px]',
55+
sm: 'w-[8px] min-h-[8px]',
56+
md: 'w-[16px] min-h-[16px]',
57+
lg: 'w-[32px] min-h-[32px]',
58+
xl: 'w-[64px] min-h-[64px]',
6059
},
6160
},
6261
defaultVariants: {
@@ -65,6 +64,21 @@ export const AgentAudioVisualizerBarVariants = cva(
6564
},
6665
);
6766

67+
export const AgentAudioVisualizerBarVariants = cva('relative flex items-center justify-center', {
68+
variants: {
69+
size: {
70+
icon: 'h-[24px] gap-[2px]',
71+
sm: 'h-[56px] gap-[4px]',
72+
md: 'h-[112px] gap-[8px]',
73+
lg: 'h-[224px] gap-[16px]',
74+
xl: 'h-[448px] gap-[32px]',
75+
},
76+
},
77+
defaultVariants: {
78+
size: 'md',
79+
},
80+
});
81+
6882
/**
6983
* Props for the AgentAudioVisualizerBar component.
7084
*/
@@ -93,10 +107,10 @@ export interface AgentAudioVisualizerBarProps {
93107
*/
94108
className?: string;
95109
/**
96-
* Custom children to render as bars. Each child receives data-lk-index,
97-
* data-lk-highlighted, and style props for height.
110+
* Custom div element to render as grid cells. Each child receives data-lk-index,
111+
* data-lk-highlighted props and style props for height. Must be a single div element.
98112
*/
99-
children?: ReactNode | ReactNode[];
113+
children?: ReactNode;
100114
}
101115

102116
/**
@@ -171,6 +185,10 @@ export function AgentAudioVisualizerBar({
171185
[state, volumeBands, _barCount],
172186
);
173187

188+
if (children && Array.isArray(children)) {
189+
throw new Error('AgentAudioVisualizerBar children must be a single element.');
190+
}
191+
174192
return (
175193
<div
176194
data-lk-state={state}
@@ -192,6 +210,7 @@ export function AgentAudioVisualizerBar({
192210
data-lk-index={idx}
193211
data-lk-highlighted={highlightedIndices.includes(idx)}
194212
style={{ height: `${band * 100}%` }}
213+
className={cn(AgentAudioVisualizerBarElementVariants({ size }))}
195214
/>
196215
),
197216
)}

0 commit comments

Comments
 (0)