Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
55 changes: 48 additions & 7 deletions src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,61 @@
import React from 'react'
import {Story, Meta} from '@storybook/react'

import {Icon} from '../Icons/Icon'
import {Button} from './Button'

export default {
title: 'Components/Button',
component: Button,
argTypes: {
backgroundColor: {control: 'color'}
style: {
defaultValue: 'gray',
options: ['gray', 'primary', 'outline', 'ghost', 'link'],
control: {type: 'select'}
},
size: {
defaultValue: 'md',
options: ['xs', 'sm', 'md', 'lg', 'responsive'],
control: {type: 'select'}
},
status: {
defaultValue: 'normal',
options: ['normal', 'disabled'],
control: {type: 'radio'}
},
outline: {
defaultValue: 'square',
options: ['square', 'round'],
control: {type: 'radio'}
}
}
} as Meta

const Template: Story = args => <Button {...args} />
const RandomIcon = ({className}) => (
<svg
aria-hidden="true"
focusable="false"
className={className}
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 496 512"
>
<path
fill="currentColor"
d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm80 168c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm-160 0c17.7 0 32 14.3 32 32s-14.3 32-32 32-32-14.3-32-32 14.3-32 32-32zm194.8 170.2C334.3 380.4 292.5 400 248 400s-86.3-19.6-114.8-53.8c-13.6-16.3 11-36.7 24.6-20.5 22.4 26.9 55.2 42.2 90.2 42.2s67.8-15.4 90.2-42.2c13.4-16.2 38.1 4.2 24.6 20.5z"
/>
</svg>
)

export const Primary = Template.bind({})
Primary.args = {
variant: 'primary',
children: 'Button'
const Template: Story = args => {
return (
<>
<Button {...args}>
<Icon {...args} style="ghost" icon={RandomIcon} />
<span>Button</span>
<Icon {...args} style="ghost" icon={RandomIcon} />
</Button>
</>
)
}

export const Buttons = Template.bind({})
74 changes: 70 additions & 4 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,74 @@
import React from 'react'
import cn from 'classnames'
import type {ComponentProps} from 'react'

// minor example
export function Button(props: ComponentProps<'button'>) {
return <button className={cn('p-4 bg-blue-500 text-white', props.className)} {...props} />
type ButtonStyles = 'gray' | 'primary' | 'outline' | 'ghost' | 'link'
type ButtonSizes = 'xs' | 'sm' | 'md' | 'lg' | 'responsive'
type ButtonStatus = 'normal' | 'disabled'
type ButtonOutline = 'round' | 'square'

const buttonSizes = {
xs: 'p-2 text-xs',
sm: 'p-2 text-sm',
md: 'py-2 px-3 text-base',
lg: 'py-3 px-4 text-lg'
}

export function Button({
style = 'gray',
size = 'md',
status = 'normal',
outline = 'square',
disabled,
className,
...props
}: {
style: ButtonStyles
size: ButtonSizes
status: ButtonStatus
outline: ButtonOutline
className: string
disabled: boolean
}) {
const buttonSize = buttonSizes[size]
const fontWeight = 'font-bold'
const linkHover = style === 'link' ? 'inline-block hover:underline cursor-pointer' : ''
const radius = outline === 'square' ? 'rounded' : 'rounded-full'
const textColor = 'text-primary-600'
const backgroundColor = 'bg-transparent'
const borderColor = 'border-transparent'

let hover = 'hover:from-gradient-white'
let buttonClasses = `${textColor} ${backgroundColor} ${borderColor}`

if (style === 'gray') {
buttonClasses = 'text-primary-200 bg-gray-800 bg-gradient-to-r'
} else if (style === 'primary') {
buttonClasses = 'text-white bg-primary-500 bg-gradient-to-r border-primary-600'
} else if (style === 'outline') {
const border = size === 'md' || size === 'lg' ? 'border-2' : 'border'
buttonClasses = `${textColor} hover:text-white border-primary-500 hover:bg-primary-500 ${border}`
} else if (style === 'ghost') {
hover += ' hover:bg-primary-100'
}

const classes = cn(
'flex items-center text-center space-x-2',
fontWeight,
buttonSize,
textColor,
borderColor,
backgroundColor,
linkHover,
radius,
hover,
buttonClasses,
disabled && 'opacity-40 cursor-not-allowed',
className
)

if (style === 'link') {
return <a {...props} className={classes} />
}

return <button {...props} className={classes} />
}
65 changes: 65 additions & 0 deletions src/components/ProgressCircle/ProgressCircle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const cleanPercentage = percentage => {
const isNegativeOrNaN = !Number.isFinite(+percentage) || percentage < 0 // we can set non-numbers to 0 here
const isTooHigh = percentage > 100
return isNegativeOrNaN ? 0 : isTooHigh ? 100 : +percentage
}

const Circle = ({color, percentage, stroke}) => {
const r = 50
const circ = 2 * Math.PI * r
const strokePct = ((100 - percentage) * circ) / 100 // where stroke will start, e.g. from 15% to 100%.
const circleColor = stroke ? stroke : color
return (
<circle
r={r}
cx={126}
cy={75}
fill="transparent"
stroke={strokePct !== circ ? circleColor : ''} // remove color as 0% sets full circumference
strokeWidth="6"
strokeDasharray={circ}
stroke-linecap="round"
strokeDashoffset={percentage ? strokePct : 0}
></circle>
)
}

const Percent = ({percentage}) => {
return (
<text
x="50%"
y="50%"
dominantBaseline="central"
textAnchor="middle"
fontSize="1.125rem"
font-family="Fira Code"
font-weight="400"
stroke="#20afdf"
stroke-width="1"
>
{percentage.toFixed(0)}%
</text>
)
}

export const ProgressCircle = percentage => {
const pct = cleanPercentage(percentage)
return (
<>
<hr />
<svg width={150} height={150}>
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#ffffff" />
<stop offset="100%" stop-color="#20afdf" />
</linearGradient>
</defs>
<g transform="rotate(-90 100 100)">
<Circle color="#e3e2e9" />
<Circle stroke="url(#gradient)" color="#20afdf" percentage={pct} />
</g>
<Percent percentage={pct} />
</svg>
</>
)
}
115 changes: 115 additions & 0 deletions src/components/Sidebar/Sidebar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from 'react'
import {Story, Meta} from '@storybook/react'
import {Sidebar} from './Sidebar'

export default {
title: 'Components/Sidebar',
component: Sidebar,
argTypes: {
// style: {
// defaultValue: 'gray',
// options: ['gray', 'primary', 'outline', 'ghost', 'link'],
// control: {type: 'select'}
// },
// size: {
// defaultValue: 'md',
// options: ['xs', 'sm', 'md', 'lg', 'responsive'],
// control: {type: 'select'}
// },
// status: {
// defaultValue: 'normal',
// options: ['normal', 'disabled'],
// control: {type: 'radio'}
// },
// outline: {
// defaultValue: 'square',
// options: ['square', 'round'],
// control: {type: 'radio'}
// }
}
} as Meta

const smileyIcon = () => (
<svg width="16" height="16" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M14 0.9375C6.50781 0.9375 0.4375 7.00781 0.4375 14.5C0.4375 21.9922 6.50781 28.0625 14 28.0625C21.4922 28.0625 27.5625 21.9922 27.5625 14.5C27.5625 7.00781 21.4922 0.9375 14 0.9375ZM18.375 10.125C19.3047 10.125 20.125 10.9453 20.125 11.875C20.125 12.8594 19.3047 13.625 18.375 13.625C17.3906 13.625 16.625 12.8594 16.625 11.875C16.625 10.9453 17.3906 10.125 18.375 10.125ZM9.625 10.125C10.5547 10.125 11.375 10.9453 11.375 11.875C11.375 12.8594 10.5547 13.625 9.625 13.625C8.64062 13.625 7.875 12.8594 7.875 11.875C7.875 10.9453 8.64062 10.125 9.625 10.125ZM20.2344 19.4766C18.7031 21.3359 16.4062 22.375 14 22.375C11.5391 22.375 9.24219 21.3359 7.71094 19.4766C6.94531 18.5469 8.3125 17.4531 9.02344 18.3281C10.2812 19.8047 12.0859 20.625 14 20.625C15.9141 20.625 17.6641 19.8047 18.9219 18.3281C19.6328 17.4531 21 18.5469 20.2344 19.4766Z"
fill="#2D2B3A"
/>
</svg>
)

const smileyIcon24 = () => (
<svg width="24" height="24" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M14 0.9375C6.50781 0.9375 0.4375 7.00781 0.4375 14.5C0.4375 21.9922 6.50781 28.0625 14 28.0625C21.4922 28.0625 27.5625 21.9922 27.5625 14.5C27.5625 7.00781 21.4922 0.9375 14 0.9375ZM18.375 10.125C19.3047 10.125 20.125 10.9453 20.125 11.875C20.125 12.8594 19.3047 13.625 18.375 13.625C17.3906 13.625 16.625 12.8594 16.625 11.875C16.625 10.9453 17.3906 10.125 18.375 10.125ZM9.625 10.125C10.5547 10.125 11.375 10.9453 11.375 11.875C11.375 12.8594 10.5547 13.625 9.625 13.625C8.64062 13.625 7.875 12.8594 7.875 11.875C7.875 10.9453 8.64062 10.125 9.625 10.125ZM20.2344 19.4766C18.7031 21.3359 16.4062 22.375 14 22.375C11.5391 22.375 9.24219 21.3359 7.71094 19.4766C6.94531 18.5469 8.3125 17.4531 9.02344 18.3281C10.2812 19.8047 12.0859 20.625 14 20.625C15.9141 20.625 17.6641 19.8047 18.9219 18.3281C19.6328 17.4531 21 18.5469 20.2344 19.4766Z"
fill="#2D2B3A"
/>
</svg>
)

const simpleLinks = Array.from({length: 3}, () => ({
title: 'Text Here',
target: 'https://openmined.org',
disabled: false
}))

const iconLinks = Array.from({length: 3}, () => ({
title: 'Text Here',
target: 'https://openmined.org',
icon: smileyIcon
}))

const numberLinks = Array.from([1, 2, 3], n => ({
title: 'Text Here',
target: 'https://openmined.org',
number: n
}))

const iconLinks24 = Array.from({length: 3}, () => ({
title: 'Text Here',
target: 'https://openmined.org',
icon: smileyIcon24
}))

const avatarLinks = Array.from({length: 3}, () => ({
title: 'Text Here',
target: 'https://openmined.org',
avatar:
'https://avataaars.io/?avatarStyle=Circle&topType=LongHairStraight&accessoriesType=Blank&hairColor=BrownDark&facialHairType=Blank&clotheType=BlazerShirt&eyeType=Default&eyebrowType=Default&mouthType=Default&skinColor=Light'
}))

const prereqs = [
{
title: 'Text Here',
target: 'https://openmined.org',
disabled: false
},
{
title: 'Text Here',
target: 'https://openmined.org',
disabled: true
}
]

const Template: Story = args => {
return (
<div className="flex">
<div className="sm:w-1/2">
<Sidebar {...args} links={simpleLinks} heading="Heading 5" />
<Sidebar {...args} links={iconLinks} progressPct={50} heading="Heading 5" />
<br />
<br />
<Sidebar {...args} links={numberLinks} hasMessage={true} />
</div>
<div className="sm:w-1/2">
<Sidebar {...args} links={avatarLinks} heading="Heading 5" />
<Sidebar {...args} links={iconLinks24} heading="Heading 5" progressPct={25} />
<br />
<br />
<Sidebar {...args} links={iconLinks24} borderLeft={true} hasMessage={true} prereqs={prereqs} />
</div>
</div>
)
}

export const main = Template.bind({})
Loading