Skip to content

Commit

Permalink
add different button variants (gitcoinco#15)
Browse files Browse the repository at this point in the history
* add different button variants

* updated stories and button

* rm opacity

* rename outline -> outlined-primary

* re-add button size

* remove ui-shadcn button story

* use right variant

* update outlined-secondary text color

* updated types

* type updates

* mv button

---------

Co-authored-by: Aditya Anand M C <aditya.anandmc@gmail.com>
  • Loading branch information
0xKurt and thelostone-mc authored Oct 29, 2024
1 parent 7087a82 commit 6d4601e
Show file tree
Hide file tree
Showing 17 changed files with 339 additions and 168 deletions.
2 changes: 1 addition & 1 deletion src/assets/icons/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/assets/icons/clock.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/assets/icons/exclamationCircle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/assets/icons/sparkles.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/assets/icons/x.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions src/primitives/Button/Button.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Meta, Title, Primary, Stories, Controls, Story } from "@storybook/blocks";
import * as ButtonStories from "./Button.stories";
import { Button } from ".";

# Button

<Meta of={ButtonStories} />

The `Button` component is a versatile button that supports various visual styles and sizes. It allows for the inclusion of icons, different states (enabled/disabled), and customizable variants, making it suitable for different use cases across your application.

## Example

### Default Button

<Story of={ButtonStories.Default} />

## Controls

<Controls />

## Other Variations

<Stories />
176 changes: 176 additions & 0 deletions src/primitives/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { Meta, StoryObj } from "@storybook/react";
import { Icon, IconType } from "@/primitives/Icon";
import { Button, ButtonVariants } from ".";

const meta: Meta<typeof Button> = {
title: "Primitives/Button",
component: Button,
args: {
value: "Click Me",
onClick: () => alert("Button clicked!"),
},
argTypes: {
variant: {
control: {
type: "select",
options: [
"primary",
"secondary",
"error",
"success",
"outlined-error",
"outlined-success",
"outlined-primary",
"outlined-disabled",
"disabled",
],
},
table: {
type: {
summary: "ButtonVariants",
},
},
},
size: {
control: {
type: "select",
options: ["default"],
},
table: {
type: {
summary: "ButtonSizes",
},
},
},
iconPosition: {
control: {
type: "select",
options: ["left", "right"],
},
},
className: {
control: "text",
},
},
} satisfies Meta<typeof Button>;

export default meta;

type Story = StoryObj<typeof Button>;

export const Default: Story = {};

export const Buttons: Story = {
render: () => {
const args = [
{
variant: "primary",
value: "Primary",
},
{
variant: "secondary",
value: "Secondary",
},
{
variant: "error",
value: "Error",
},
{
variant: "success",
value: "Success",
},
{
variant: "disabled",
value: "Disabled",
disabled: true,
},
];

return (
<div className="flex space-x-4">
{args.map((arg) => (
<Button
variant={arg.variant as ButtonVariants}
value={arg.value}
disabled={arg.disabled}
/>
))}
</div>
);
},
};

export const Outlined: Story = {
render: () => {
const args = [
{
variant: "outlined-primary",
value: "Outlined Primary",
},
{
variant: "outlined-secondary",
value: "Outlined Secondary",
},
{
variant: "outlined-error",
value: "Outlined Error",
},
{
variant: "outlined-success",
value: "Outlined Success",
},
{
variant: "outlined-disabled",
value: "Outlined Disabled",
disabled: true,
},
];

return (
<div className="flex space-x-4">
{args.map((arg) => (
<Button
variant={arg.variant as ButtonVariants}
value={arg.value}
disabled={arg.disabled}
/>
))}
</div>
);
},
};

export const WithIcon: Story = {
render: () => {
const args = [
{
icon: <Icon type={IconType.CHECK} />,
iconPosition: "left",
value: "Icon Left",
},
{
icon: <Icon type={IconType.SPARKLES} />,
iconPosition: "right",
value: "Icon Right",
},
];

return (
<div className="flex space-x-4">
{args.map((arg) => (
<Button
icon={arg.icon}
iconPosition={arg.iconPosition as "left" | "right"}
value={arg.value}
/>
))}
</div>
);
},
};

export const CustomClassName: Story = {
args: {
className: "bg-blue-900 border border-blue-700 text-white",
},
};
104 changes: 104 additions & 0 deletions src/primitives/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { tv } from "tailwind-variants";
import { cn } from "@/lib/utils";

export type ButtonVariants =
| "primary"
| "secondary"
| "error"
| "success"
| "outlined-error"
| "outlined-success"
| "outlined-primary"
| "outlined-secondary"
| "outlined-disabled"
| "disabled"
| undefined;

export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: string;
size?: string;
disabled?: boolean;
asChild?: boolean;
value?: string;
icon?: React.ReactNode;
iconPosition?: "left" | "right";
}

export type ButtonSizes = "default" | "sm" | "md" | "lg" | "icon" | undefined;

const buttonVariants = tv({
base: "inline-flex h-[32px] items-center justify-center gap-2 whitespace-nowrap rounded-[8px] px-[12px] py-[8px] font-mono text-[14px] font-medium leading-[16px] ring-offset-white transition-colors hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 disabled:pointer-events-none dark:ring-offset-neutral-950",
variants: {
variant: {
primary: "border-brand bg-brand text-white",
secondary: "border-neutral-100 bg-neutral-100 text-black",
error: "border-orange-50 bg-orange-50 text-orange-600",
success: "border-moss-50 bg-moss-50 text-moss-300",
"outlined-error": "border-2 border-orange-600 bg-orange-50 text-orange-600",
"outlined-success": "border-2 border-moss-300 bg-moss-50 text-moss-300",
"outlined-primary": "border-2 border-brand bg-white text-brand",
"outlined-secondary": "border-2 border-neutral-600 bg-white text-black",
disabled: "border-neutral-100 bg-neutral-100 text-neutral-600",
"outlined-disabled": "border-2 border-neutral-600 bg-white text-neutral-600",
},
size: {
sm: "h-[24px] px-[8px] py-[6px]",
md: "h-[32px] px-[12px] py-[8px]",
lg: "h-[40px] px-[16px] py-[10px]",
icon: "size-32 p-0",
default: "h-[32px] px-[12px] py-[8px]",
},
},
defaultVariants: {
variant: "primary",
size: "default",
},
});

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(
{
className,
variant,
size = "default",
disabled,
asChild = false,
value,
icon,
iconPosition = "left",
...props
},
ref,
) => {
const Comp = asChild ? Slot : "button";
const appliedVariant = disabled
? variant?.startsWith("outlined")
? "outlined-disabled"
: "disabled"
: variant;

return (
<Comp
className={cn(
buttonVariants({
variant: appliedVariant as ButtonVariants,
size: size as ButtonSizes,
className,
}),
)}
ref={ref}
disabled={disabled}
{...props}
>
{icon && iconPosition === "left" && <span>{icon}</span>}
{value && <span className={icon ? "" : "mt-0.5"}>{value}</span>}
{icon && iconPosition === "right" && <span>{icon}</span>}
</Comp>
);
},
);
Button.displayName = "Button";

export { Button, buttonVariants };
1 change: 1 addition & 0 deletions src/primitives/Button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "@/primitives/Button/Button";
4 changes: 1 addition & 3 deletions src/primitives/Indicators/CircleStat/CircleStat.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import React from "react";



import { tv } from "tailwind-variants";

interface CircleStatProps {
Expand Down Expand Up @@ -56,4 +54,4 @@ export const CircleStat: React.FC<CircleStatProps> = ({
{`${value}${showPercentageSymbol ? "%" : ""}`}
</div>
);
};
};
23 changes: 17 additions & 6 deletions src/tokens/colors.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
import { Colors } from "./types";

export const colors: Colors = {
brand: "#307168",
black: "#000000",
white: "#ffffff",
green: {
"300": "#c4f092",
"600": "#558A17",
},
grey: {
"50": "#f7f7f7",
"100": "#EBEBEB",
"400": "#555555",
"500": "#000000",
},
white: "#ffffff",
black: "#000000",
moss: {
"50": "#F5FEFD",
"300": "#307168",
},
neutral: {
"100": "#ebebeb",
"600": "#979998",
},
orange: {
"50": "#FFF7F5",
"200": "#F68561",
"300": "#ff9776",
},
green: {
"300": "#c4f092",
"600": "#558A17",
"600": "#A2401F",
},
yellow: {
"300": "#ffea7d",
Expand Down
Loading

0 comments on commit 6d4601e

Please sign in to comment.