Skip to content
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

391/v2 button styling #397

Open
wants to merge 16 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ label {
}

body {
@apply font-body bg-primaryWhite text-primaryBlack;
@apply bg-monoY font-body text-base-120;
}

:focus-visible {
outline: 2px solid #ff8d3c;
outline: 2px solid #ff6f08;
outline-offset: 2px;
nichgalzin marked this conversation as resolved.
Show resolved Hide resolved
}

/*------------------------------------*\
Expand Down
152 changes: 152 additions & 0 deletions components/buttons/MainButton/MainButton.stories.ts
camelPhonso marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { expect, jest } from '@storybook/jest';
import type { Meta, StoryObj } from '@storybook/react';
import MainButton from './MainButton';
import { userEvent, within } from '@storybook/test';

const meta: Meta<typeof MainButton> = {
title: 'components/MainButton',
component: MainButton,
args: {
children: 'Donate Item',
clickHandler: jest.fn(),
type: 'button',
disabled: false,
},
argTypes: {
layout: {
description: 'The display layout of the button',
options: ['desktop', 'mobile'],
control: { type: 'radio' },
table: {
type: { summary: '"desktop" | "mobile"' },
defaultValue: { summary: 'desktop' },
},
},
size: {
description: 'The size of the button',
options: ['small', 'large'],
control: { type: 'radio' },
table: {
type: { summary: '"small" | "large"' },
defaultValue: { summary: 'small' },
},
},
variant: {
description: 'Whether to use light mode styling',
control: { type: 'radio' },
options: ['primary', 'secondary'],
table: {
type: { summary: 'boolean' },
},
},
disabled: {
description: 'Whether the button is disabled',
control: 'boolean',
table: {
type: { summary: 'boolean' },
},
},
type: {
description: 'The HTML button type',
options: ['button', 'submit', 'reset'],
control: { type: 'radio' },
table: {
type: { summary: '"button" | "submit" | "reset"' },
defaultValue: { summary: 'button' },
},
},
clickHandler: {
description: 'Function to be called when the button is clicked',
table: {
type: { summary: '() => void' },
},
},
children: {
description: 'The content to be displayed inside the button',
control: 'text',
table: {
type: { summary: 'ReactNode' },
},
},
},
};

export default meta;
type Story = StoryObj<typeof meta>;

export const MainButtonDefault: Story = {
args: {
layout: 'desktop',
size: 'small',
variant: 'primary',
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button');

expect(button).toBeInTheDocument();
expect(button).not.toBeDisabled();

await userEvent.click(button);
expect(args.clickHandler).toHaveBeenCalled();
},
};

export const LargeDesktopButton: Story = {
args: {
...MainButtonDefault.args,
size: 'large',
layout: 'desktop',
children: 'Large Button',
},
};

export const SmallDesktopButton: Story = {
args: {
...MainButtonDefault.args,
size: 'small',
layout: 'desktop',
children: 'Small Button',
},
};

export const MobileSmallButton: Story = {
args: {
...MainButtonDefault.args,
layout: 'mobile',
size: 'small',
children: 'Mobile Button',
},
};

export const MobileLargeButton: Story = {
args: {
...MainButtonDefault.args,
size: 'large',
layout: 'mobile',
children: 'Large Button',
},
};

export const SecondaryButton: Story = {
args: {
...MainButtonDefault.args,
variant: 'secondary',
children: 'Secondary Button',
},
};

export const DisabledButton: Story = {
args: {
...MainButtonDefault.args,
disabled: true,
children: 'Disabled Button',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button');

expect(button).toBeInTheDocument();
expect(button).toBeDisabled();
},
};
86 changes: 86 additions & 0 deletions components/buttons/MainButton/MainButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use client';
import { ReactNode } from 'react';

interface MainButtonProps {
children: ReactNode;
clickHandler: () => void;
layout: 'mobile' | 'desktop';
size: 'small' | 'large';
variant: 'primary' | 'secondary';
type: 'button' | 'submit' | 'reset';
disabled?: boolean;
ariaLabel?: string;
nichgalzin marked this conversation as resolved.
Show resolved Hide resolved
camelPhonso marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* MainButton Component
nichgalzin marked this conversation as resolved.
Show resolved Hide resolved
*
* @component
* @example
* <KindlyButton
camelPhonso marked this conversation as resolved.
Show resolved Hide resolved
* layout="desktop"
* size="small"
* colour="primary"
* disabled={isLoading}
* type="submit"
* ariaLabel="Submit button"
* clickHandler={() => console.log('clicked')}
* >
* Click Me
* </KindlyButton>
*/

const MainButton: React.FC<MainButtonProps> = ({
children,
clickHandler,
layout = 'desktop',
size = 'small',
nichgalzin marked this conversation as resolved.
Show resolved Hide resolved
variant = 'primary',
type = 'button',
disabled,
ariaLabel,
}) => {
const baseStyles =
'flex items-center justify-center font-medium py-3 min-h-[44px] min-w-[44px] rounded-md';

const layoutStyles = {
mobile: 'text-xl',
desktop: 'text-md',
};

const sizeStyles = {
small: 'w-[163px]',
large: 'w-[255px]',
};

const colourStyles = {
primary:
'bg-brand-100 text-monoY hover:bg-secondaryOrange hover:text-primaryBlack focus:bg-brand-110 focus:text-monoY',
secondary: 'border border-base-120 hover:border-brand-100',
};
camelPhonso marked this conversation as resolved.
Show resolved Hide resolved

const disabledStyles =
'bg-base-80 text-base-100 cursor-not-allowed hover:bg-base-80 hover:text-base-100';
camelPhonso marked this conversation as resolved.
Show resolved Hide resolved

const className = `
${baseStyles}
${layoutStyles[layout]}
${sizeStyles[size]}
${colourStyles[variant]}
${disabled ? disabledStyles : ''}`;

return (
<button
onClick={clickHandler}
className={className}
type={type}
disabled={disabled}
aria-disabled={disabled}
aria-label={ariaLabel}
>
{children}
</button>
camelPhonso marked this conversation as resolved.
Show resolved Hide resolved
);
};

export default MainButton;
37 changes: 37 additions & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,48 @@ module.exports = {
hoverGreen: '#4EA37A',
secondaryGreen: '#B6DFB6',
//New colors
base: {
120: '#111111',
110: '#333333',
100: '#929292',
90: '#CDCDCD',
80: '#F3F3F3',
},
nichgalzin marked this conversation as resolved.
Show resolved Hide resolved
brand: {
80: '#FDEDD4',
90: '##FFC48A',
100: '#FF8D3C',
110: '#FF6F08',
120: '#CC5706',
},
interactive: {
90: '#FFE082',
100: '#FFC107',
110: '#F0CD0E',
},
sucess: {
90: '#52CC8E',
100: '#008944',
110: '#0A6638',
},
error: {
90: '#FF5959',
100: '#CC2929',
110: '#991216',
},
focus: {
90: '#B0E6FF',
100: '#007ACC',
110: '#006BB4',
},
monoY: '#FFFFFF',
primaryWhite: '#FFFFFF',
primaryBlack: '#333333',
primaryGray: '#57666D',
secondaryGray: '#F3F3F3',
primaryOrange: '#FF8D3C',
secondaryOrange: '#FDEDD4',
tertiaryOrange: '#FF6F08',
primaryBlue: '#1461D1',
primaryRed: '#ED0131',
},
Expand Down
Loading