trepur_components 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Accordion/Accordion.stories.tsx +88 -0
- package/dist/components/Accordion/index.tsx +31 -0
- package/dist/components/AlertBar/AlertBar.stories.tsx +105 -0
- package/dist/components/AlertBar/index.tsx +127 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.stories.tsx +60 -0
- package/dist/components/Breadcrumbs/index.tsx +55 -0
- package/dist/components/BreadcrumbsBordered/BreadcrumbsBordered.stories.tsx +52 -0
- package/dist/components/BreadcrumbsBordered/index.tsx +44 -0
- package/dist/components/BreadcrumbsItem/BreadcrumbsItem.stories.tsx +54 -0
- package/dist/components/BreadcrumbsItem/index.tsx +151 -0
- package/dist/components/Button/button.stories.tsx +148 -0
- package/dist/components/Button/index.tsx +91 -0
- package/dist/components/Card/Card.stories.tsx +150 -0
- package/dist/components/Card/index.tsx +162 -0
- package/dist/components/CardWithTopImage/CardWithTopImage.stories.tsx +48 -0
- package/dist/components/CardWithTopImage/index.tsx +40 -0
- package/dist/components/Carousel/Carousel.stories.tsx +369 -0
- package/dist/components/Carousel/index.tsx +267 -0
- package/dist/components/ChevronCard/ChevronCard.stories.tsx +21 -0
- package/dist/components/ChevronCard/index.tsx +39 -0
- package/dist/components/Collapsible/Collapsible.stories.tsx +70 -0
- package/dist/components/Collapsible/index.tsx +124 -0
- package/dist/components/Column/Column.stories.tsx +82 -0
- package/dist/components/Column/index.tsx +114 -0
- package/dist/components/Container/Container.stories.tsx +38 -0
- package/dist/components/Container/index.tsx +30 -0
- package/dist/components/FooterBar/FooterBar.stories.tsx +57 -0
- package/dist/components/FooterBar/index.tsx +44 -0
- package/dist/components/Form/Form.stories.tsx +93 -0
- package/dist/components/Form/index.tsx +58 -0
- package/dist/components/FyreCard/FyreCard.stories.tsx +29 -0
- package/dist/components/FyreCard/index.tsx +46 -0
- package/dist/components/Greeting/Greeting.stories.tsx +42 -0
- package/dist/components/Greeting/index.tsx +46 -0
- package/dist/components/HamburgerIcon/HamburgerIcon.stories.tsx +50 -0
- package/dist/components/HamburgerIcon/index.tsx +65 -0
- package/dist/components/Icon/Icon.stories.tsx +102 -0
- package/dist/components/Icon/index.tsx +112 -0
- package/dist/components/Image/Image.stories.tsx +88 -0
- package/dist/components/Image/index.tsx +113 -0
- package/dist/components/ImageLink/ImageLink.stories.tsx +60 -0
- package/dist/components/ImageLink/index.tsx +62 -0
- package/dist/components/ImageLinkList/ImageLinkList.stories.tsx +34 -0
- package/dist/components/ImageLinkList/index.tsx +33 -0
- package/dist/components/InformationIcon/InformationIcon.stories.tsx +86 -0
- package/dist/components/InformationIcon/index.tsx +84 -0
- package/dist/components/Input/Input.stories.tsx +99 -0
- package/dist/components/Input/index.tsx +126 -0
- package/dist/components/Jumbotron/Jumbotron.stories.tsx +22 -0
- package/dist/components/Jumbotron/index.tsx +25 -0
- package/dist/components/Nav/Nav.stories.tsx +155 -0
- package/dist/components/Nav/index.tsx +180 -0
- package/dist/components/NavItem/NavItem.stories.tsx +89 -0
- package/dist/components/NavItem/index.tsx +65 -0
- package/dist/components/NewsCard/NewsCard.stories.tsx +71 -0
- package/dist/components/NewsCard/index.tsx +48 -0
- package/dist/components/Profile/Profile.stories.tsx +50 -0
- package/dist/components/Profile/index.tsx +87 -0
- package/dist/components/Row/Row.stories.tsx +51 -0
- package/dist/components/Row/index.tsx +24 -0
- package/dist/components/Search/Search.stories.tsx +58 -0
- package/dist/components/Search/index.tsx +58 -0
- package/dist/components/SocialBlock/SocialBlock.stories.tsx +114 -0
- package/dist/components/SocialBlock/index.tsx +161 -0
- package/dist/components/StarRating/StarRating.stories.tsx +23 -0
- package/dist/components/StarRating/index.tsx +71 -0
- package/dist/components/Testimonial/Testimonial.stories.tsx +110 -0
- package/dist/components/Testimonial/index.tsx +50 -0
- package/dist/components/TextAndTitle/TextAndTitle.stories.tsx +65 -0
- package/dist/components/TextAndTitle/index.tsx +257 -0
- package/dist/components/TextArea/TextArea.stories.tsx +67 -0
- package/dist/components/TextArea/index.tsx +97 -0
- package/dist/components/Timeline/Timeline.stories.tsx +100 -0
- package/dist/components/Timeline/index.css +133 -0
- package/dist/components/Timeline/index.tsx +315 -0
- package/dist/components/Tubestops/Tubestops.stories.tsx +66 -0
- package/dist/components/Tubestops/index.css +92 -0
- package/dist/components/Tubestops/index.tsx +77 -0
- package/dist/components/UserIcon/UserIcon.stories.tsx +67 -0
- package/dist/components/UserIcon/index.tsx +42 -0
- package/dist/components/Video/Video.stories.tsx +23 -0
- package/dist/components/Video/index.tsx +49 -0
- package/dist/fonts/Sora/OFL.txt +93 -0
- package/dist/fonts/Sora/README.txt +70 -0
- package/dist/fonts/Sora/Sora-VariableFont_wght.ttf +0 -0
- package/dist/fonts/Sora/static/Sora-Bold.ttf +0 -0
- package/dist/fonts/Sora/static/Sora-ExtraBold.ttf +0 -0
- package/dist/fonts/Sora/static/Sora-ExtraLight.ttf +0 -0
- package/dist/fonts/Sora/static/Sora-Light.ttf +0 -0
- package/dist/fonts/Sora/static/Sora-Medium.ttf +0 -0
- package/dist/fonts/Sora/static/Sora-Regular.ttf +0 -0
- package/dist/fonts/Sora/static/Sora-SemiBold.ttf +0 -0
- package/dist/fonts/Sora/static/Sora-Thin.ttf +0 -0
- package/dist/index.js +272 -0
- package/dist/styles/base.css +73 -0
- package/package.json +1 -1
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
|
|
4
|
+
export interface Props {
|
|
5
|
+
id?: string
|
|
6
|
+
className?: string
|
|
7
|
+
name: string
|
|
8
|
+
link: string
|
|
9
|
+
type?: string
|
|
10
|
+
firstItem?: boolean
|
|
11
|
+
href?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const BreadcrumbsItem = ({
|
|
15
|
+
id,
|
|
16
|
+
className,
|
|
17
|
+
name,
|
|
18
|
+
link,
|
|
19
|
+
href,
|
|
20
|
+
type,
|
|
21
|
+
firstItem
|
|
22
|
+
}: Props): JSX.Element => {
|
|
23
|
+
const [isHovering, setIsHovering] = useState(false)
|
|
24
|
+
const topArrowClasses = 'top-0'
|
|
25
|
+
const bottomArrowClasses = 'bottom-0'
|
|
26
|
+
const textClassList = 'text-center pt-1'
|
|
27
|
+
const liClassList = 'list-none'
|
|
28
|
+
|
|
29
|
+
const classList = classNames(className, 'item')
|
|
30
|
+
|
|
31
|
+
const itemClassList = classNames({
|
|
32
|
+
'hover:underline': type === 'link',
|
|
33
|
+
'mb-0': isHovering
|
|
34
|
+
}, 'bc-item relative px-4 h-8')
|
|
35
|
+
|
|
36
|
+
const backArrowsClasses = 'absolute w-0 h-0 bg-transparent border-l-transparent'
|
|
37
|
+
const frontArrowClasses = 'absolute top-0 w-0 h-0 border-t'
|
|
38
|
+
|
|
39
|
+
const frontArrow = (
|
|
40
|
+
<span
|
|
41
|
+
style={{
|
|
42
|
+
borderTop: '17px solid transparent',
|
|
43
|
+
borderBottom: '15px solid transparent',
|
|
44
|
+
borderLeft: '16px solid',
|
|
45
|
+
right: '-16px'
|
|
46
|
+
}}
|
|
47
|
+
className={frontArrowClasses}
|
|
48
|
+
/>
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const backArrows = (
|
|
52
|
+
<>
|
|
53
|
+
<span
|
|
54
|
+
style={{
|
|
55
|
+
borderTop: '17px solid',
|
|
56
|
+
borderBottom: '18px solid transparent',
|
|
57
|
+
borderLeft: '17px solid transparent',
|
|
58
|
+
left: '-17px',
|
|
59
|
+
// '-webkit-transform': 'scaleY(-1)',
|
|
60
|
+
transform: 'scaleY(-1)'
|
|
61
|
+
}}
|
|
62
|
+
className={`${backArrowsClasses} ${bottomArrowClasses}`}
|
|
63
|
+
/>
|
|
64
|
+
<span
|
|
65
|
+
style={{
|
|
66
|
+
borderTop: '18px solid',
|
|
67
|
+
borderBottom: '17px solid transparent',
|
|
68
|
+
borderLeft: '17px solid transparent',
|
|
69
|
+
left: '-17px'
|
|
70
|
+
}}
|
|
71
|
+
className={`${backArrowsClasses} ${topArrowClasses}`}
|
|
72
|
+
/>
|
|
73
|
+
</>
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
const renderWithFrontArrow = (
|
|
77
|
+
<div className={itemClassList}>
|
|
78
|
+
<p className={textClassList}>
|
|
79
|
+
{name}
|
|
80
|
+
{frontArrow}
|
|
81
|
+
</p>
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
const renderWithBackArrows = (
|
|
86
|
+
<div className={itemClassList}>
|
|
87
|
+
<p className={textClassList}>
|
|
88
|
+
{backArrows}
|
|
89
|
+
{name}
|
|
90
|
+
{frontArrow}
|
|
91
|
+
</p>
|
|
92
|
+
</div>
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<div
|
|
97
|
+
id={id}
|
|
98
|
+
className={classList}
|
|
99
|
+
>
|
|
100
|
+
{type === 'link'
|
|
101
|
+
? (
|
|
102
|
+
firstItem === true
|
|
103
|
+
? (
|
|
104
|
+
<a
|
|
105
|
+
onMouseOver={() => setIsHovering(true)}
|
|
106
|
+
onMouseOut={() => setIsHovering(false)}
|
|
107
|
+
href={href}
|
|
108
|
+
>
|
|
109
|
+
<li className={liClassList}>
|
|
110
|
+
{renderWithFrontArrow}
|
|
111
|
+
</li>
|
|
112
|
+
</a>
|
|
113
|
+
)
|
|
114
|
+
: (
|
|
115
|
+
<a
|
|
116
|
+
onMouseOver={() => setIsHovering(true)}
|
|
117
|
+
onMouseOut={() => setIsHovering(false)}
|
|
118
|
+
href={href}
|
|
119
|
+
>
|
|
120
|
+
<li className={liClassList}>
|
|
121
|
+
{renderWithBackArrows}
|
|
122
|
+
</li>
|
|
123
|
+
</a>
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
: (
|
|
127
|
+
firstItem === true
|
|
128
|
+
? (
|
|
129
|
+
<li
|
|
130
|
+
className={liClassList}
|
|
131
|
+
onMouseOver={() => setIsHovering(true)}
|
|
132
|
+
onMouseOut={() => setIsHovering(false)}
|
|
133
|
+
>
|
|
134
|
+
{renderWithFrontArrow}
|
|
135
|
+
</li>
|
|
136
|
+
)
|
|
137
|
+
: (
|
|
138
|
+
<li
|
|
139
|
+
className={liClassList}
|
|
140
|
+
onMouseOver={() => setIsHovering(true)}
|
|
141
|
+
onMouseOut={() => setIsHovering(false)}
|
|
142
|
+
>
|
|
143
|
+
{renderWithBackArrows}
|
|
144
|
+
</li>
|
|
145
|
+
)
|
|
146
|
+
)}
|
|
147
|
+
</div>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export default BreadcrumbsItem
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Button from './index'
|
|
3
|
+
import { action } from '@storybook/addon-actions'
|
|
4
|
+
import { idAndClassName } from '@utils/controls'
|
|
5
|
+
import { ComponentStory, ComponentMeta } from '@storybook/react'
|
|
6
|
+
|
|
7
|
+
const componentMeta: ComponentMeta<typeof Button> = {
|
|
8
|
+
title: 'Trepur Components/Rupert Bennett/Atoms/Button',
|
|
9
|
+
component: Button,
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component: 'A Button which can either be internal, external or social as well as a standard design or a slide design.'
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
argTypes: {
|
|
18
|
+
...idAndClassName,
|
|
19
|
+
onClick: {
|
|
20
|
+
type: { name: 'function', required: false },
|
|
21
|
+
description: 'The action to perform when clicking on the component',
|
|
22
|
+
action: 'onClick',
|
|
23
|
+
table: {
|
|
24
|
+
type: {
|
|
25
|
+
summary: 'function'
|
|
26
|
+
},
|
|
27
|
+
defaultValue: { summary: 'undefined' }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
hoverText: {
|
|
31
|
+
type: {
|
|
32
|
+
name: 'string',
|
|
33
|
+
required: false
|
|
34
|
+
},
|
|
35
|
+
description: 'The text to display when hovering on the component',
|
|
36
|
+
table: {
|
|
37
|
+
type: {
|
|
38
|
+
summary: 'string'
|
|
39
|
+
},
|
|
40
|
+
defaultValue: {
|
|
41
|
+
summary: 'undefined'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
variant: {
|
|
46
|
+
type: {
|
|
47
|
+
name: 'string', required: false
|
|
48
|
+
},
|
|
49
|
+
options: ['primary', 'secondary'],
|
|
50
|
+
description: 'The variant of button to render',
|
|
51
|
+
table: {
|
|
52
|
+
type: {
|
|
53
|
+
summary: 'primary'
|
|
54
|
+
},
|
|
55
|
+
defaultValue: {
|
|
56
|
+
summary: 'primary'
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
defaultValue: 'primary',
|
|
60
|
+
control: {
|
|
61
|
+
type: 'radio'
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
type: {
|
|
65
|
+
type: {
|
|
66
|
+
name: 'string',
|
|
67
|
+
required: false
|
|
68
|
+
},
|
|
69
|
+
options: ['default', 'social', 'icon'],
|
|
70
|
+
description: 'The type of button to render',
|
|
71
|
+
table: {
|
|
72
|
+
type: {
|
|
73
|
+
summary: 'default'
|
|
74
|
+
},
|
|
75
|
+
defaultValue: {
|
|
76
|
+
summary: 'default'
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
defaultValue: 'default',
|
|
80
|
+
control: { type: 'radio' }
|
|
81
|
+
},
|
|
82
|
+
href: {
|
|
83
|
+
type: { name: 'string', required: false },
|
|
84
|
+
description: 'The link attached to the component',
|
|
85
|
+
table: {
|
|
86
|
+
type: {
|
|
87
|
+
summary: 'default'
|
|
88
|
+
},
|
|
89
|
+
defaultValue: {
|
|
90
|
+
summary: 'undefined'
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
rounded: {
|
|
95
|
+
type: {
|
|
96
|
+
name: 'boolean',
|
|
97
|
+
required: false
|
|
98
|
+
},
|
|
99
|
+
description: 'rounds the borders when true',
|
|
100
|
+
defaultValue: 'true'
|
|
101
|
+
},
|
|
102
|
+
disabled: {
|
|
103
|
+
type: {
|
|
104
|
+
name: 'boolean',
|
|
105
|
+
required: false
|
|
106
|
+
},
|
|
107
|
+
description: 'Can the carousel be dragged or not'
|
|
108
|
+
},
|
|
109
|
+
isLoading: {
|
|
110
|
+
type: {
|
|
111
|
+
name: 'boolean',
|
|
112
|
+
required: false
|
|
113
|
+
},
|
|
114
|
+
table: {
|
|
115
|
+
defaultValue: {
|
|
116
|
+
summary: 'false'
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
description: 'Toggles the loading state of the compnent'
|
|
120
|
+
},
|
|
121
|
+
openInNewTab: {
|
|
122
|
+
type: { name: 'boolean', required: false },
|
|
123
|
+
description: 'Opens the link in a new tab when set to true',
|
|
124
|
+
defaultValue: 'false'
|
|
125
|
+
},
|
|
126
|
+
children: {
|
|
127
|
+
type: { name: 'other', value: 'string | React.ReactNode' },
|
|
128
|
+
description: 'The child elements to show in the component',
|
|
129
|
+
table: {
|
|
130
|
+
type: {
|
|
131
|
+
summary: 'Array'
|
|
132
|
+
},
|
|
133
|
+
defaultValue: { summary: 'undefined' }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
args: {
|
|
138
|
+
children: 'This is a button',
|
|
139
|
+
rounded: true,
|
|
140
|
+
onClick: action('button clicked')
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />
|
|
145
|
+
|
|
146
|
+
export const _Button = Template.bind({})
|
|
147
|
+
|
|
148
|
+
export default componentMeta
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Icon from '@components/Icon'
|
|
3
|
+
import classNames from 'classnames'
|
|
4
|
+
|
|
5
|
+
export interface Props {
|
|
6
|
+
id?: string
|
|
7
|
+
className?: string
|
|
8
|
+
onClick?: React.MouseEventHandler
|
|
9
|
+
hoverText?: string
|
|
10
|
+
variant?: 'primary' | 'secondary'
|
|
11
|
+
type?: 'social' | 'icon' | 'default'
|
|
12
|
+
href?: string
|
|
13
|
+
rounded?: boolean
|
|
14
|
+
disabled?: boolean
|
|
15
|
+
isLoading?: boolean
|
|
16
|
+
openInNewTab?: boolean
|
|
17
|
+
children?: any
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const Button = ({
|
|
21
|
+
id,
|
|
22
|
+
className,
|
|
23
|
+
onClick,
|
|
24
|
+
hoverText,
|
|
25
|
+
variant = 'primary',
|
|
26
|
+
type = 'default',
|
|
27
|
+
href,
|
|
28
|
+
rounded = true,
|
|
29
|
+
disabled = false,
|
|
30
|
+
isLoading = false,
|
|
31
|
+
openInNewTab = false,
|
|
32
|
+
children
|
|
33
|
+
}: Props): JSX.Element => {
|
|
34
|
+
const padding = classNames({
|
|
35
|
+
'px-1 py-1': type === 'social',
|
|
36
|
+
'px-3': type === 'icon',
|
|
37
|
+
'px-8': type !== 'social' && type !== 'icon'
|
|
38
|
+
}, 'py-2')
|
|
39
|
+
|
|
40
|
+
const loadingClasses = classNames({
|
|
41
|
+
invisible: !isLoading
|
|
42
|
+
}, 'absolute left-2/4 top-1/4 -ml-2')
|
|
43
|
+
|
|
44
|
+
const classList = classNames({
|
|
45
|
+
'bg-primary text-white border-white': variant === 'primary',
|
|
46
|
+
'hover:bg-white hover:text-primary hover:border-primary': !disabled && variant === 'primary',
|
|
47
|
+
'bg-white text-primary border-primary': variant === 'secondary',
|
|
48
|
+
'hover:bg-primary hover:text-white hover:border-primary': !disabled && variant === 'secondary',
|
|
49
|
+
'opacity-50': disabled,
|
|
50
|
+
'rounded-lg': rounded,
|
|
51
|
+
'rounded-none': !rounded
|
|
52
|
+
}, className, padding, 'group border-2 transition-backgroundColor duration-500 transform')
|
|
53
|
+
|
|
54
|
+
const loadingIcon = (
|
|
55
|
+
<Icon
|
|
56
|
+
size={1}
|
|
57
|
+
type='spinner'
|
|
58
|
+
animation='pulse'
|
|
59
|
+
colour='white'
|
|
60
|
+
bgColour='primary'
|
|
61
|
+
/>
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<a
|
|
66
|
+
className='group'
|
|
67
|
+
{...(openInNewTab && { target: '_blank' })}
|
|
68
|
+
href={href}
|
|
69
|
+
>
|
|
70
|
+
<button
|
|
71
|
+
id={id}
|
|
72
|
+
className={classList}
|
|
73
|
+
aria-busy={isLoading}
|
|
74
|
+
{...((onClick != null) &&
|
|
75
|
+
{ onClick })}
|
|
76
|
+
{...(disabled &&
|
|
77
|
+
{ disabled })}
|
|
78
|
+
>
|
|
79
|
+
<div className={classNames({ invisible: isLoading })}>
|
|
80
|
+
{children}
|
|
81
|
+
</div>
|
|
82
|
+
{isLoading &&
|
|
83
|
+
<div className={loadingClasses}>
|
|
84
|
+
{loadingIcon}
|
|
85
|
+
</div>}
|
|
86
|
+
</button>
|
|
87
|
+
</a>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export default Button
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Card from './index'
|
|
3
|
+
import { idAndClassName } from '@utils/controls'
|
|
4
|
+
import Icon from '@components/Icon'
|
|
5
|
+
import { ComponentStory, ComponentMeta } from '@storybook/react'
|
|
6
|
+
|
|
7
|
+
const componentMeta: ComponentMeta<typeof Card> = {
|
|
8
|
+
title: 'Trepur Components/Rupert Bennett/Organisms/Card',
|
|
9
|
+
component: Card,
|
|
10
|
+
argTypes: {
|
|
11
|
+
...idAndClassName,
|
|
12
|
+
title: {
|
|
13
|
+
description: '',
|
|
14
|
+
table: {
|
|
15
|
+
category: 'Card'
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
image: {
|
|
19
|
+
description: '',
|
|
20
|
+
table: {
|
|
21
|
+
category: 'Card'
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
subTitle: {
|
|
25
|
+
description: '',
|
|
26
|
+
table: {
|
|
27
|
+
category: 'Card'
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
description: {
|
|
31
|
+
description: '',
|
|
32
|
+
table: {
|
|
33
|
+
category: 'Card'
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
extraText: {
|
|
37
|
+
description: '',
|
|
38
|
+
table: {
|
|
39
|
+
category: 'Card'
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
imageBelowTitle: {
|
|
43
|
+
description: '',
|
|
44
|
+
table: {
|
|
45
|
+
category: 'Card'
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
bordered: {
|
|
49
|
+
description: '',
|
|
50
|
+
table: {
|
|
51
|
+
category: 'Card'
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
rounded: {
|
|
55
|
+
description: '',
|
|
56
|
+
table: {
|
|
57
|
+
category: 'Card'
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
hasCta: {
|
|
61
|
+
description: '',
|
|
62
|
+
table: {
|
|
63
|
+
category: 'Card'
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
titleLeft: {
|
|
67
|
+
description: '',
|
|
68
|
+
table: {
|
|
69
|
+
category: 'Card'
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
titleRight: {
|
|
73
|
+
description: '',
|
|
74
|
+
table: {
|
|
75
|
+
category: 'Card'
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
titleBold: {
|
|
79
|
+
description: '',
|
|
80
|
+
table: {
|
|
81
|
+
category: 'Card'
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
args: {
|
|
86
|
+
subTitle: 'This is a subtitle',
|
|
87
|
+
description: 'This is a description paragraph',
|
|
88
|
+
extraText: 'This is another paragraph',
|
|
89
|
+
rounded: true,
|
|
90
|
+
bordered: true,
|
|
91
|
+
hasCta: true,
|
|
92
|
+
iconButtonProps: {
|
|
93
|
+
type: 'icon',
|
|
94
|
+
href: '/',
|
|
95
|
+
className: 'mt-8',
|
|
96
|
+
children: <Icon
|
|
97
|
+
type='heart'
|
|
98
|
+
hollow={false}
|
|
99
|
+
/>
|
|
100
|
+
},
|
|
101
|
+
cardButtonProps: {
|
|
102
|
+
children: (
|
|
103
|
+
<div className='flex'>
|
|
104
|
+
<Icon type='heart' />
|
|
105
|
+
<p>buttonText</p>
|
|
106
|
+
<Icon type='heart' />
|
|
107
|
+
</div>
|
|
108
|
+
),
|
|
109
|
+
disabled: false,
|
|
110
|
+
hoverText: 'buttonHoverText',
|
|
111
|
+
href: 'buttonUrl',
|
|
112
|
+
rounded: true
|
|
113
|
+
},
|
|
114
|
+
button2Props: {
|
|
115
|
+
className: 'ml-2 w-full mt-8',
|
|
116
|
+
children: 'Add to basket',
|
|
117
|
+
rounded: false,
|
|
118
|
+
disabled: false
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const Template: ComponentStory<typeof Card> = (args) => <Card {...args} />
|
|
124
|
+
|
|
125
|
+
export const _ImageCard = Template.bind({})
|
|
126
|
+
_ImageCard.args = {
|
|
127
|
+
title: 'This is a title',
|
|
128
|
+
image: 'https://picsum.photos/500/300'
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export const _VideoCard = Template.bind({})
|
|
132
|
+
_VideoCard.args = {
|
|
133
|
+
title: 'This is a title',
|
|
134
|
+
videoProps: {
|
|
135
|
+
mp4File: '/',
|
|
136
|
+
withControls: true,
|
|
137
|
+
autoPlay: true
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export const _ProductCard = Template.bind({})
|
|
142
|
+
_ProductCard.args = {
|
|
143
|
+
image: 'https://picsum.photos/500/300',
|
|
144
|
+
subTitle: 'Product name',
|
|
145
|
+
description: 'Product description',
|
|
146
|
+
extraText: '£123.45',
|
|
147
|
+
onHover: true
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export default componentMeta
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
import Button, { Props as buttonProps } from '@components/Button'
|
|
4
|
+
import Video, { Props as videoProps } from '@components/Video'
|
|
5
|
+
|
|
6
|
+
export interface Props {
|
|
7
|
+
id?: string
|
|
8
|
+
className?: string
|
|
9
|
+
title?: string
|
|
10
|
+
image?: string
|
|
11
|
+
subTitle?: string
|
|
12
|
+
description?: string
|
|
13
|
+
extraText?: string
|
|
14
|
+
hasCta?: boolean
|
|
15
|
+
imageBelowTitle?: boolean
|
|
16
|
+
titleLeft?: boolean
|
|
17
|
+
titleRight?: boolean
|
|
18
|
+
titleBold?: boolean
|
|
19
|
+
imageClass?: string
|
|
20
|
+
subTitleClass?: string
|
|
21
|
+
extraTextClass?: string
|
|
22
|
+
descriptionClass?: string
|
|
23
|
+
altText?: string
|
|
24
|
+
rounded?: boolean
|
|
25
|
+
bordered?: boolean
|
|
26
|
+
videoProps?: videoProps
|
|
27
|
+
onHover?: boolean
|
|
28
|
+
iconButtonProps?: buttonProps
|
|
29
|
+
cardButtonProps?: buttonProps
|
|
30
|
+
button2Props?: buttonProps
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const Card: React.FC<Props> = ({
|
|
34
|
+
id,
|
|
35
|
+
className,
|
|
36
|
+
title,
|
|
37
|
+
image,
|
|
38
|
+
subTitle,
|
|
39
|
+
description,
|
|
40
|
+
extraText,
|
|
41
|
+
hasCta,
|
|
42
|
+
imageBelowTitle,
|
|
43
|
+
titleLeft = false,
|
|
44
|
+
titleRight = false,
|
|
45
|
+
titleBold = false,
|
|
46
|
+
imageClass,
|
|
47
|
+
subTitleClass,
|
|
48
|
+
extraTextClass,
|
|
49
|
+
descriptionClass,
|
|
50
|
+
altText,
|
|
51
|
+
rounded,
|
|
52
|
+
bordered,
|
|
53
|
+
videoProps,
|
|
54
|
+
onHover = false,
|
|
55
|
+
iconButtonProps,
|
|
56
|
+
cardButtonProps,
|
|
57
|
+
button2Props
|
|
58
|
+
}: Props): JSX.Element => {
|
|
59
|
+
const [showHoverButtons, setShowHoverButtons] = useState(false)
|
|
60
|
+
|
|
61
|
+
const orderClass = classNames({ 'order-first': imageBelowTitle })
|
|
62
|
+
const btnClass = 'w-full p-3'
|
|
63
|
+
const border = classNames({ 'border border-grey border-opacity-100:': bordered })
|
|
64
|
+
const cardTitleFont = classNames({ 'font-bold': titleBold })
|
|
65
|
+
const cardTitlePosition = classNames({
|
|
66
|
+
'text-left': titleLeft,
|
|
67
|
+
'text-right': titleRight,
|
|
68
|
+
'text-center': !titleLeft && !titleRight
|
|
69
|
+
})
|
|
70
|
+
const roundedImage = classNames({ 'rounded-t-lg': rounded })
|
|
71
|
+
const roundedCard = classNames({ 'rounded-lg': rounded })
|
|
72
|
+
const contentWrapperClass = 'px-3 order-3'
|
|
73
|
+
const titleWrapperClass = classNames(orderClass, 'pt-3')
|
|
74
|
+
|
|
75
|
+
const cardTitleClasses = classNames({
|
|
76
|
+
[cardTitlePosition]: true
|
|
77
|
+
}, cardTitleFont, 'font-medium text-md text-grey')
|
|
78
|
+
|
|
79
|
+
const cardSubTitleClassList = classNames(subTitleClass, 'font-light text-sm text-grey')
|
|
80
|
+
const cardDescriptionClassList = classNames(descriptionClass, 'font-extraLight text-xs text-light-grey')
|
|
81
|
+
const classList = classNames(className, border, roundedCard, 'flex flex-col')
|
|
82
|
+
|
|
83
|
+
const imageClassList = classNames(roundedImage, imageClass, 'w-full object-cover h-full')
|
|
84
|
+
|
|
85
|
+
const cardExtraTextClassList = classNames({
|
|
86
|
+
'pb-4': hasCta === false
|
|
87
|
+
}, extraTextClass, 'w-full object-cover h-full font-extraLight text-xs text-light-grey')
|
|
88
|
+
|
|
89
|
+
const imageWrapperClassList = classNames({
|
|
90
|
+
'order-2': imageBelowTitle === true,
|
|
91
|
+
[roundedImage]: imageBelowTitle === false,
|
|
92
|
+
'order-1': imageBelowTitle === false
|
|
93
|
+
}, 'h-64 overflow-hidden object-cover')
|
|
94
|
+
|
|
95
|
+
const toggleHover = (isHovering: boolean): void => {
|
|
96
|
+
onHover && setShowHoverButtons(!!isHovering)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<div
|
|
101
|
+
id={id}
|
|
102
|
+
className={classList}
|
|
103
|
+
onMouseEnter={() => toggleHover(true)}
|
|
104
|
+
onMouseLeave={() => toggleHover(false)}
|
|
105
|
+
>
|
|
106
|
+
<div className='card-content flex flex-1 flex-col'>
|
|
107
|
+
{videoProps?.mp4File !== undefined || videoProps?.webmFile !== undefined || videoProps?.ogvFile !== undefined
|
|
108
|
+
? (
|
|
109
|
+
<div className={imageWrapperClassList}>
|
|
110
|
+
<Video {...videoProps} />
|
|
111
|
+
</div>
|
|
112
|
+
)
|
|
113
|
+
: (image !== undefined &&
|
|
114
|
+
<div className={imageWrapperClassList}>
|
|
115
|
+
<img className={imageClassList} src={image} alt={altText} />
|
|
116
|
+
</div>)}
|
|
117
|
+
{!showHoverButtons
|
|
118
|
+
? (
|
|
119
|
+
<>
|
|
120
|
+
<div className={imageBelowTitle !== undefined ? 'order-1' : 'order-3'}>
|
|
121
|
+
{title !== undefined &&
|
|
122
|
+
<div className={titleWrapperClass}>
|
|
123
|
+
<h3 className={cardTitleClasses}>{title}</h3>
|
|
124
|
+
</div>}
|
|
125
|
+
</div>
|
|
126
|
+
<div className={contentWrapperClass}>
|
|
127
|
+
{subTitle !== undefined &&
|
|
128
|
+
<h4 className={cardSubTitleClassList}>
|
|
129
|
+
{subTitle}
|
|
130
|
+
</h4>}
|
|
131
|
+
{description !== undefined &&
|
|
132
|
+
<p className={cardDescriptionClassList}>
|
|
133
|
+
{description}
|
|
134
|
+
</p>}
|
|
135
|
+
{extraText !== undefined &&
|
|
136
|
+
<p className={cardExtraTextClassList}>
|
|
137
|
+
{extraText}
|
|
138
|
+
</p>}
|
|
139
|
+
</div>
|
|
140
|
+
</>
|
|
141
|
+
)
|
|
142
|
+
: (
|
|
143
|
+
<div className='flex p-2 order-last h-24'>
|
|
144
|
+
<Button {...iconButtonProps}>
|
|
145
|
+
{iconButtonProps?.children}
|
|
146
|
+
</Button>
|
|
147
|
+
<Button {...button2Props}>
|
|
148
|
+
{button2Props?.children}
|
|
149
|
+
</Button>
|
|
150
|
+
</div>)}
|
|
151
|
+
</div>
|
|
152
|
+
{(cardButtonProps != null) &&
|
|
153
|
+
<div className={btnClass}>
|
|
154
|
+
<Button {...cardButtonProps}>
|
|
155
|
+
{cardButtonProps.children}
|
|
156
|
+
</Button>
|
|
157
|
+
</div>}
|
|
158
|
+
</div>
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export default Card
|