Skip to content

Commit

Permalink
[explorer] Implement badge component (MystenLabs#5274)
Browse files Browse the repository at this point in the history
* Start migrating to new storybook

* Migrate all stories to CSF 3

* Implement badge

* update lockfile

* Remove component anti-aliasing

* Format

* Add license header
  • Loading branch information
Jordan-Mysten authored Oct 17, 2022
1 parent 74180e5 commit 32a141a
Show file tree
Hide file tree
Showing 23 changed files with 2,835 additions and 4,924 deletions.
10 changes: 10 additions & 0 deletions apps/explorer/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ module.exports = {
},
],
'import/no-duplicates': ['error'],
'import/no-anonymous-default-export': 'off',
'@typescript-eslint/consistent-type-imports': [
'error',
{
Expand All @@ -43,4 +44,13 @@ module.exports = {
],
],
},
overrides: [
{
files: ['*.stories.*'],
rules: {
// Story files have render functions that this rule incorrectly warns on:
'react-hooks/rules-of-hooks': 'off',
},
},
],
};
15 changes: 6 additions & 9 deletions apps/explorer/.storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@

module.exports = {
stories: [
'../src/**/*.stories.mdx',
'../src/**/*.stories.@(js|jsx|ts|tsx)',
{
directory: '../src/ui/stories/',
titlePrefix: 'UI',
files: '*.stories.*',
},
],
addons: ['@storybook/addon-a11y', '@storybook/addon-essentials'],
framework: '@storybook/react',
core: {
builder: '@storybook/builder-vite',
},
features: {
storyStoreV7: true,
},
framework: '@storybook/react-vite',
staticDirs: ['../public'],
};
10 changes: 10 additions & 0 deletions apps/explorer/.storybook/manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { addons } from '@storybook/addons';
import { themes } from '@storybook/theming';

// Force the theme to light, as our components do not suppor theming
addons.setConfig({
theme: themes.light,
});
16 changes: 10 additions & 6 deletions apps/explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"lint": "pnpm eslint:check && pnpm prettier:check && pnpm stylelint:check",
"lint:fix": "pnpm eslint:fix && pnpm prettier:fix && pnpm stylelint:fix",
"preview": "vite preview",
"storybook": "start-storybook --port 6007",
"build-storybook": "build-storybook",
"storybook": "storybook dev -p 6007",
"build-storybook": "storybook build",
"preview-storybook": "pnpm dlx serve ./storybook-static -l 6007"
},
"dependencies": {
Expand Down Expand Up @@ -52,10 +52,13 @@
"vanilla-cookieconsent": "^2.8.0"
},
"devDependencies": {
"@storybook/addon-a11y": "^6.5.10",
"@storybook/addon-essentials": "^6.5.10",
"@storybook/builder-vite": "^0.2.2",
"@storybook/react": "^6.5.10",
"@babel/core": "^7.19.3",
"@storybook/addon-a11y": "7.0.0-alpha.38",
"@storybook/addon-essentials": "7.0.0-alpha.38",
"@storybook/addons": "7.0.0-alpha.38",
"@storybook/react": "7.0.0-alpha.38",
"@storybook/react-vite": "7.0.0-alpha.38",
"@storybook/theming": "7.0.0-alpha.38",
"@testing-library/dom": "^8.17.1",
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^13.3.0",
Expand All @@ -78,6 +81,7 @@
"postcss": "^8.4.6",
"prettier": "2.5.1",
"start-server-and-test": "^1.14.0",
"storybook": "7.0.0-alpha.38",
"stylelint": "^14.5.0",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^25.0.0",
Expand Down
4 changes: 2 additions & 2 deletions apps/explorer/src/app/App.module.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.app {
@apply font-sans w-full;
@apply w-full;

background: linear-gradient(
to bottom,
Expand All @@ -11,7 +11,7 @@
}

main {
@apply relative z-10 py-2 min-h-[77vh]
@apply relative z-10 py-2 min-h-[77vh]
bg-offwhite rounded-[20px] shadow-2xl;
}

Expand Down
44 changes: 44 additions & 0 deletions apps/explorer/src/ui/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { cva, type VariantProps } from 'class-variance-authority';
import { type ReactNode } from 'react';

import { ReactComponent as CheckIcon } from './icons/check.svg';
import { ReactComponent as XIcon } from './icons/x.svg';

const badgeStyles = cva(
[
'inline-flex justify-center items-center gap-1.5 py-1 px-2 rounded-md text-body font-medium',
],
{
variants: {
variant: {
current: 'bg-sui-grey-45 text-sui-grey-75',
success: 'bg-success-light text-success-dark',
failure: 'bg-issue-light text-issue-dark',
},
},
defaultVariants: {
variant: 'current',
},
}
);

export interface BadgeProps extends VariantProps<typeof badgeStyles> {
children?: ReactNode;
}

export function Badge({ variant, children }: BadgeProps) {
return (
<div className={badgeStyles({ variant })}>
{variant === 'current' && (
<div className="bg-success rounded-full w-2 h-2" />
)}
{variant === 'failure' && <XIcon />}
{variant === 'success' && <CheckIcon />}

<span>{children}</span>
</div>
);
}
2 changes: 1 addition & 1 deletion apps/explorer/src/ui/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const buttonStyles = cva(
[
'inline-flex items-center justify-center',
// TODO: Remove when CSS reset is applied.
'cursor-pointer font-sans no-underline',
'cursor-pointer no-underline',
],
{
variants: {
Expand Down
1 change: 0 additions & 1 deletion apps/explorer/src/ui/Heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { type ReactNode } from 'react';

const headingStyles = cva(
[
'font-sans',
// TODO: Remove when CSS reset is applied.
'my-0',
],
Expand Down
2 changes: 1 addition & 1 deletion apps/explorer/src/ui/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { cva, type VariantProps } from 'class-variance-authority';
import { type ReactNode } from 'react';

const textStyles = cva(['font-sans'], {
const textStyles = cva([], {
variants: {
weight: {
medium: 'font-medium',
Expand Down
2 changes: 1 addition & 1 deletion apps/explorer/src/ui/VerticalList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function ListItem({ active, children, onClick }: ListItemProps) {
<button
type="button"
className={clsx(
'cursor-pointer px-3 py-2 rounded-md text-body block w-full font-sans border-1 border-solid text-left',
'cursor-pointer px-3 py-2 rounded-md text-body block w-full border-1 border-solid text-left',
active
? 'bg-sui-grey-45 text-sui-grey-90 font-semibold border-sui-grey-50 shadow-sm'
: 'bg-white text-sui-grey-80 font-medium border-transparent'
Expand Down
3 changes: 3 additions & 0 deletions apps/explorer/src/ui/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.
3 changes: 3 additions & 0 deletions apps/explorer/src/ui/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.
24 changes: 24 additions & 0 deletions apps/explorer/src/ui/stories/Badge.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { type Meta, type StoryObj } from '@storybook/react';

import { Badge, type BadgeProps } from '../Badge';

export default {
component: Badge,
} as Meta;

export const Current: StoryObj<BadgeProps> = {
render: (props) => <Badge {...props}>Badge</Badge>,
};

export const Success: StoryObj<BadgeProps> = {
...Current,
args: { variant: 'success' },
};

export const Failure: StoryObj<BadgeProps> = {
...Current,
args: { variant: 'failure' },
};
69 changes: 36 additions & 33 deletions apps/explorer/src/ui/stories/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { type ComponentStory, type ComponentMeta } from '@storybook/react';
import { type StoryObj, type Meta } from '@storybook/react';
import { MemoryRouter } from 'react-router-dom';

import { Button } from '../Button';
import { Button, type ButtonProps } from '../Button';

export default {
title: 'UI/Button',
component: Button,
decorators: [
(Story) => (
Expand All @@ -16,36 +15,40 @@ export default {
</MemoryRouter>
),
],
} as ComponentMeta<typeof Button>;
} as Meta;

const Template: ComponentStory<typeof Button> = (args) => (
<div className="flex flex-col items-start gap-2">
<Button to="/relative" {...args}>
Router Link
</Button>
<Button to="/relative" size="lg" {...args}>
Large Router Link
</Button>
<Button href="https://google.com" {...args}>
External Link
</Button>
<Button href="https://google.com" size="lg" {...args}>
Large External Link
</Button>
<Button onClick={() => alert('on click')} {...args}>
Button
</Button>
<Button onClick={() => alert('on click')} size="lg" {...args}>
Large Button
</Button>
</div>
);
export const Primary: StoryObj<ButtonProps> = {
render: (props) => (
<div className="flex flex-col items-start gap-2">
<Button to="/relative" {...props}>
Router Link
</Button>
<Button to="/relative" size="lg" {...props}>
Large Router Link
</Button>
<Button href="https://google.com" {...props}>
External Link
</Button>
<Button href="https://google.com" size="lg" {...props}>
Large External Link
</Button>
<Button onClick={() => alert('on click')} {...props}>
Button
</Button>
<Button onClick={() => alert('on click')} size="lg" {...props}>
Large Button
</Button>
</div>
),
args: { variant: 'primary' },
};

export const Primary = Template.bind({});
Primary.args = { variant: 'primary' };
export const Secondary: StoryObj<ButtonProps> = {
...Primary,
args: { variant: 'secondary' },
};

export const Secondary = Template.bind({});
Secondary.args = { variant: 'secondary' };

export const Outline = Template.bind({});
Outline.args = { variant: 'outline' };
export const Outline: StoryObj<ButtonProps> = {
...Primary,
args: { variant: 'outline' },
};
28 changes: 14 additions & 14 deletions apps/explorer/src/ui/stories/Card.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { type ComponentStory, type ComponentMeta } from '@storybook/react';
import { type Meta, type StoryObj } from '@storybook/react';

import { Card } from '../Card';
import { Card, type CardProps } from '../Card';

export default {
title: 'UI/Card',
component: Card,
} as ComponentMeta<typeof Card>;
} as Meta;

const Template: ComponentStory<typeof Card> = (args) => (
<Card {...args}>This is card content.</Card>
);
export const Default: StoryObj<CardProps> = {
render: (props) => <Card {...props}>This is card content.</Card>,
};

export const Default = Template.bind({});
Default.args = {};
export const Small: StoryObj<CardProps> = {
...Default,
args: { spacing: 'sm' },
};

export const Small = Template.bind({});
Small.args = { spacing: 'sm' };

export const Large = Template.bind({});
Large.args = { spacing: 'lg' };
export const Large: StoryObj<CardProps> = {
...Default,
args: { spacing: 'lg' },
};
31 changes: 12 additions & 19 deletions apps/explorer/src/ui/stories/DateFilter.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,26 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import { type Meta, type StoryObj } from '@storybook/react';

import {
DateFilter,
useDateFilterState,
type DateFilterProps,
} from '../DateFilter';

import type { ComponentMeta, ComponentStory } from '@storybook/react';

export default {
title: 'UI/DateFilter',
component: DateFilter,
} as ComponentMeta<typeof DateFilter>;

function DateFilterWithState(
props: Omit<DateFilterProps, 'value' | 'onChange'>
) {
const [value, onChange] = useDateFilterState('D');
return <DateFilter {...props} value={value} onChange={onChange} />;
}
} as Meta;

const Template: ComponentStory<typeof DateFilter> = (args) => (
<DateFilterWithState {...args} />
);

export const Default = Template.bind({});
export const Default: StoryObj<DateFilterProps> = {
render: (props) => {
const [value, onChange] = useDateFilterState('D');
return <DateFilter {...props} value={value} onChange={onChange} />;
},
};

export const CustomOptions = Template.bind({});
CustomOptions.args = {
options: ['D', 'ALL'],
export const CustomOptions: StoryObj<DateFilterProps> = {
...Default,
args: { options: ['D', 'ALL'] },
};
Loading

0 comments on commit 32a141a

Please sign in to comment.