-
Notifications
You must be signed in to change notification settings - Fork 943
chore: create collapsible summary component (#16705)
This is based on the Figma designs here: https://www.figma.com/design/WfqIgsTFXN2BscBSSyXWF8/Coder-kit?node-id=507-1525&m=dev --------- Co-authored-by: Steven Masley <stevenmasley@gmail.com>
- Loading branch information
There are no files selected for viewing
120 changes: 120 additions & 0 deletions
120
site/src/components/CollapsibleSummary/CollapsibleSummary.stories.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
import { Button } from "../Button/Button"; | ||
import { CollapsibleSummary } from "./CollapsibleSummary"; | ||
|
||
const meta: Meta<typeof CollapsibleSummary> = { | ||
title: "components/CollapsibleSummary", | ||
component: CollapsibleSummary, | ||
args: { | ||
label: "Advanced options", | ||
children: ( | ||
<> | ||
<div className="p-2 border border-border rounded-md border-solid"> | ||
Option 1 | ||
</div> | ||
<div className="p-2 border border-border rounded-md border-solid"> | ||
Option 2 | ||
</div> | ||
|
||
Option 3 | ||
</div> | ||
</> | ||
), | ||
}, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof CollapsibleSummary>; | ||
|
||
export const Default: Story = {}; | ||
|
||
export const DefaultOpen: Story = { | ||
args: { | ||
defaultOpen: true, | ||
}, | ||
}; | ||
|
||
export const MediumSize: Story = { | ||
args: { | ||
size: "md", | ||
}, | ||
}; | ||
|
||
export const SmallSize: Story = { | ||
args: { | ||
size: "sm", | ||
}, | ||
}; | ||
|
||
export const CustomClassName: Story = { | ||
args: { | ||
className: "text-blue-500 font-bold", | ||
}, | ||
}; | ||
|
||
export const ManyChildren: Story = { | ||
args: { | ||
defaultOpen: true, | ||
children: ( | ||
<> | ||
{Array.from({ length: 10 }).map((_, i) => ( | ||
<div | ||
key={`option-${i + 1}`} | ||
className="p-2 border border-border rounded-md border-solid" | ||
> | ||
Option {i + 1} | ||
</div> | ||
))} | ||
</> | ||
), | ||
}, | ||
}; | ||
|
||
export const NestedCollapsible: Story = { | ||
args: { | ||
defaultOpen: true, | ||
children: ( | ||
<> | ||
<div className="p-2 border border-border rounded-md border-solid"> | ||
Option 1 | ||
</div> | ||
<CollapsibleSummary label="Nested options" size="sm"> | ||
<div className="p-2 border border-border rounded-md border-solid"> | ||
Nested Option 1 | ||
</div> | ||
<div className="p-2 border border-border rounded-md border-solid"> | ||
Nested Option 2 | ||
</div> | ||
</CollapsibleSummary> | ||
<div className="p-2 border border-border rounded-md border-solid"> | ||
Option 3 | ||
</div> | ||
</> | ||
), | ||
}, | ||
}; | ||
|
||
export const ComplexContent: Story = { | ||
args: { | ||
defaultOpen: true, | ||
children: ( | ||
<div className="p-4 border border-border rounded-md bg-surface-secondary"> | ||
<h3 className="text-lg font-bold mb-2">Complex Content</h3> | ||
<p className="mb-4"> | ||
This is a more complex content example with various elements. | ||
</p> | ||
<div className="flex gap-2"> | ||
<Button>Action 1</Button> | ||
<Button>Action 2</Button> | ||
</div> | ||
</div> | ||
), | ||
}, | ||
}; | ||
|
||
export const LongLabel: Story = { | ||
args: { | ||
label: | ||
"This is a very long label that might wrap or cause layout issues if not handled properly", | ||
}, | ||
}; |
91 changes: 91 additions & 0 deletions
91
site/src/components/CollapsibleSummary/CollapsibleSummary.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { type VariantProps, cva } from "class-variance-authority"; | ||
import { ChevronRightIcon } from "lucide-react"; | ||
import { type FC, type ReactNode, useState } from "react"; | ||
import { cn } from "utils/cn"; | ||
|
||
const collapsibleSummaryVariants = cva( | ||
`flex items-center gap-1 p-0 bg-transparent border-0 text-inherit cursor-pointer | ||
transition-colors text-content-secondary hover:text-content-primary font-medium | ||
whitespace-nowrap`, | ||
{ | ||
variants: { | ||
size: { | ||
md: "text-sm", | ||
sm: "text-xs", | ||
}, | ||
}, | ||
defaultVariants: { | ||
size: "md", | ||
}, | ||
}, | ||
); | ||
|
||
export interface CollapsibleSummaryProps | ||
extends VariantProps<typeof collapsibleSummaryVariants> { | ||
/** | ||
* The label to display for the collapsible section | ||
*/ | ||
label: string; | ||
/** | ||
* The content to show when expanded | ||
*/ | ||
children: ReactNode; | ||
/** | ||
* Whether the section is initially expanded | ||
*/ | ||
defaultOpen?: boolean; | ||
/** | ||
* Optional className for the button | ||
*/ | ||
className?: string; | ||
/** | ||
* The size of the component | ||
*/ | ||
size?: "md" | "sm"; | ||
} | ||
|
||
export const CollapsibleSummary: FC<CollapsibleSummaryProps> = ({ | ||
label, | ||
children, | ||
defaultOpen = false, | ||
className, | ||
size, | ||
}) => { | ||
const [isOpen, setIsOpen] = useState(defaultOpen); | ||
|
||
return ( | ||
<div className="flex flex-col gap-4"> | ||
<button | ||
className={cn( | ||
collapsibleSummaryVariants({ size }), | ||
isOpen && "text-content-primary", | ||
className, | ||
)} | ||
type="button" | ||
onClick={() => { | ||
setIsOpen((v) => !v); | ||
}} | ||
> | ||
<div | ||
className={cn( | ||
"flex items-center justify-center transition-transform duration-200", | ||
isOpen ? "rotate-90" : "rotate-0", | ||
)} | ||
> | ||
<ChevronRightIcon | ||
className={cn( | ||
"p-0.5", | ||
size === "sm" ? "size-icon-xs" : "size-icon-sm", | ||
)} | ||
/> | ||
</div> | ||
<span className="sr-only"> | ||
({isOpen ? "Hide" : "Show"}) {label} | ||
</span> | ||
<span className="[&:first-letter]:uppercase">{label}</span> | ||
</button> | ||
|
||
{isOpen && <div className="flex flex-col gap-4">{children}</div>} | ||
</div> | ||
); | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
feat: enable agent connection reports by default, remove flag (cherry-pick #16778) #16809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
feat: enable agent connection reports by default, remove flag (cherry-pick #16778) #16809
Changes from 1 commit
172e523
38c0e8a
c5a265f
a2cc1b8
2971957
f1b357d
b94d2cb
7c035a4
7cd6e9c
5295902
1cb864b
81ef9e9
2aa749a
6b69635
5cdc13b
b3d6755
95363c9
6dd51f9
4ba5a8a
cccdf1e
464fccd
bf5b002
91a4a98
0ea0601
7e33902
b23e05b
3997eee
64fec8b
ec44f06
6889ad2
e27953d
930816f
4216e28
fc2815c
ca23abe
d0e2060
c074f77
a5842e5
9c5d496
0f4f6bd
88f0131
04c3396
ca23abc
7dc05cc
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.