Skip to content

Commit 5d0faaa

Browse files
authored
feat(swingset): proptable badges, inline variables reset, folder source links (#8822)
1 parent be44bae commit 5d0faaa

7 files changed

Lines changed: 89 additions & 21 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

packages/swingset/src/components/ClientRoot.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function ClientRoot({ children }: { children: React.ReactNode }) {
3535
<SidebarProvider>
3636
<AppSidebar />
3737
<SidebarInset>
38-
<header className='bg-background sticky top-0 flex h-12 shrink-0 items-center gap-2 border-b px-4'>
38+
<header className='bg-background sticky top-0 z-10 flex h-12 shrink-0 items-center gap-2 border-b px-4'>
3939
<SidebarTrigger className='-ml-1' />
4040
<Separator
4141
orientation='vertical'

packages/swingset/src/components/PropTable.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client';
22

3+
import { Badge } from '@/components/ui/badge';
34
import type { StoryMeta } from '@/lib/types';
45

56
import { KnobControl } from './KnobControl';
@@ -54,7 +55,12 @@ export function PropTable({ meta, extra = [] }: PropTableProps) {
5455
return (
5556
<tr key={row.name}>
5657
<td>
57-
<code>{row.name}</code>
58+
<Badge
59+
variant='secondary'
60+
className='font-mono'
61+
>
62+
{row.name}
63+
</Badge>
5864
</td>
5965
<td>
6066
<code>{row.type}</code>

packages/swingset/src/components/StoryPreview.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { MosaicProvider } from '@clerk/ui/mosaic/MosaicProvider';
44
import { RotateCcwIcon, SlidersHorizontalIcon } from 'lucide-react';
55
import type React from 'react';
6+
import { useState } from 'react';
67

78
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
89
import { generateKnobs, initKnobValues } from '@/lib/generateKnobs';
@@ -25,6 +26,7 @@ interface StoryPreviewProps {
2526
export function StoryPreview({ name, storyModule }: StoryPreviewProps) {
2627
const StoryComp = storyModule[name] as React.ComponentType<Record<string, unknown>>;
2728
const playground = usePlayground();
29+
const [variablesOpen, setVariablesOpen] = useState(false);
2830

2931
if (!StoryComp) {
3032
return (
@@ -37,7 +39,11 @@ export function StoryPreview({ name, storyModule }: StoryPreviewProps) {
3739
const variables = playground?.variables ?? {};
3840

3941
return (
40-
<Collapsible className='not-prose border-border bg-background my-4 overflow-hidden rounded-lg border'>
42+
<Collapsible
43+
open={variablesOpen}
44+
onOpenChange={setVariablesOpen}
45+
className='not-prose border-border bg-background my-4 overflow-hidden rounded-lg border'
46+
>
4147
<div className='flex items-center justify-end border-b px-2 py-1.5'>
4248
<button
4349
type='button'
@@ -56,11 +62,21 @@ export function StoryPreview({ name, storyModule }: StoryPreviewProps) {
5662
</MosaicProvider>
5763
</div>
5864

59-
<div className='flex items-center justify-start border-t px-2 py-1.5'>
60-
<CollapsibleTrigger className='text-muted-foreground hover:text-foreground flex items-center gap-1 rounded px-2 py-1 text-xs'>
65+
<div className='flex items-center justify-start gap-1 border-t px-2 py-1.5'>
66+
<CollapsibleTrigger className='text-muted-foreground hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground flex items-center gap-1 rounded px-2 py-1 text-xs'>
6167
<SlidersHorizontalIcon className='size-3' />
6268
Variables
6369
</CollapsibleTrigger>
70+
{variablesOpen && playground ? (
71+
<button
72+
type='button'
73+
onClick={() => playground.setVariables({})}
74+
className='text-muted-foreground hover:text-foreground flex items-center gap-1 rounded px-2 py-1 text-xs'
75+
>
76+
<RotateCcwIcon className='size-3' />
77+
Reset
78+
</button>
79+
) : null}
6480
</div>
6581

6682
{playground ? (

packages/swingset/src/components/VariablesPanel.tsx

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import type { MosaicVariables } from '@clerk/ui/mosaic/variables';
44
import { defaultMosaicVariables } from '@clerk/ui/mosaic/variables';
55

6-
import { Button } from '@/components/ui/button';
76
import { Input } from '@/components/ui/input';
87
import { Label } from '@/components/ui/label';
98

@@ -30,18 +29,6 @@ export function VariablesPanel({ variables, onChange }: VariablesPanelProps) {
3029

3130
return (
3231
<div className='flex flex-col gap-1'>
33-
<div className='flex items-center justify-between gap-2 border-b px-3 py-2'>
34-
<span className='text-muted-foreground text-[10px] font-semibold uppercase tracking-widest'>Variables</span>
35-
<Button
36-
variant='ghost'
37-
size='sm'
38-
className='text-muted-foreground h-6 px-2 text-xs'
39-
onClick={() => onChange({})}
40-
>
41-
Reset
42-
</Button>
43-
</div>
44-
4532
<div className='flex flex-col gap-4 p-3'>
4633
<section className='flex flex-col gap-2'>
4734
<div className='text-brand text-[10px] font-semibold uppercase tracking-widest'>Colors</div>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { mergeProps } from '@base-ui/react/merge-props';
2+
import { useRender } from '@base-ui/react/use-render';
3+
import { cva, type VariantProps } from 'class-variance-authority';
4+
5+
import { cn } from '@/lib/utils';
6+
7+
const badgeVariants = cva(
8+
'group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!',
9+
{
10+
variants: {
11+
variant: {
12+
default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',
13+
secondary: 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80',
14+
destructive:
15+
'bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20',
16+
outline: 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground',
17+
ghost: 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50',
18+
link: 'text-primary underline-offset-4 hover:underline',
19+
},
20+
},
21+
defaultVariants: {
22+
variant: 'default',
23+
},
24+
},
25+
);
26+
27+
function Badge({
28+
className,
29+
variant = 'default',
30+
render,
31+
...props
32+
}: useRender.ComponentProps<'span'> & VariantProps<typeof badgeVariants>) {
33+
return useRender({
34+
defaultTagName: 'span',
35+
props: mergeProps<'span'>(
36+
{
37+
className: cn(badgeVariants({ variant }), className),
38+
},
39+
props,
40+
),
41+
render,
42+
state: {
43+
slot: 'badge',
44+
variant,
45+
},
46+
});
47+
}
48+
49+
export { Badge, badgeVariants };
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
// The repo these components are documented from. `source` paths in `StoryMeta` are
22
// relative to the monorepo root and resolved against this base on the default branch.
3-
const REPO_BLOB_BASE = 'https://github.com/clerk/javascript/blob/main';
3+
const REPO_BASE = 'https://github.com/clerk/javascript';
4+
const BRANCH = 'main';
45

5-
/** Build a GitHub URL to the file that exports a component, from a repo-root-relative path. */
6+
/**
7+
* Build a GitHub URL from a repo-root-relative path. Index/barrel files (`index.ts`,
8+
* `index.tsx`, …) resolve to their containing folder as a `tree` view — the folder of
9+
* source files is more useful than the re-export file. Any other path links straight
10+
* to the file as a `blob` view.
11+
*/
612
export function sourceUrl(path: string): string {
7-
return `${REPO_BLOB_BASE}/${path.replace(/^\/+/, '')}`;
13+
const clean = path.replace(/^\/+/, '');
14+
const folder = clean.match(/^(.*)\/index\.[jt]sx?$/)?.[1];
15+
return folder ? `${REPO_BASE}/tree/${BRANCH}/${folder}` : `${REPO_BASE}/blob/${BRANCH}/${clean}`;
816
}

0 commit comments

Comments
 (0)