Skip to content

Commit

Permalink
feat: Add Thumbnail component
Browse files Browse the repository at this point in the history
code from cozy-mespapiers-lib
  • Loading branch information
JF-Cozy committed Jun 1, 2023
1 parent df8647f commit f060e70
Show file tree
Hide file tree
Showing 16 changed files with 408 additions and 1 deletion.
3 changes: 2 additions & 1 deletion docs/styleguide.config.js
Expand Up @@ -35,7 +35,8 @@ module.exports = {
'../react/Progress',
'../react/ProgressionBanner',
'../react/Spinner',
'../react/Stack'
'../react/Stack',
'../react/Thumbnail'
]
},
{
Expand Down
16 changes: 16 additions & 0 deletions react/Thumbnail/Readme.md
@@ -0,0 +1,16 @@
```jsx
import Thumbnail from 'cozy-ui/transpiled/react/Thumbnail'
import Icon from 'cozy-ui/transpiled/react/Icon'
import PeopleIcon from 'cozy-ui/transpiled/react/Icons/People'
import Box from 'cozy-ui/transpiled/react/Box'

;

<>
<Thumbnail className="u-mb-1" />
<Thumbnail className="u-mb-1" image="https://viewerdemo.cozycloud.cc/IMG_0062.PNG" isStacked={false} />
<Thumbnail className="u-mb-1" image="https://viewerdemo.cozycloud.cc/IMG_0062.PNG" isStacked={true} />
<Thumbnail className="u-mb-1" icon={PeopleIcon} isStacked={false} />
<Thumbnail className="u-mb-1" icon={PeopleIcon} isStacked={true} />
</>
```
100 changes: 100 additions & 0 deletions react/Thumbnail/Thumbnail.spec.jsx
@@ -0,0 +1,100 @@
import '@testing-library/jest-dom'
import { render } from '@testing-library/react'
import React from 'react'

import Thumbnail from '.'

const MockIcon = <svg />

const setup = ({ image, icon, isStacked } = {}) => {
return render(<Thumbnail image={image} icon={icon} isStacked={isStacked} />)
}

describe('Thumbnail components:', () => {
describe('Thumbnail without Skeleton', () => {
describe('Thumbnail with "image" prop without Skeleton', () => {
it('should display an unstacked image', () => {
const { getByTestId, queryByTestId } = setup({
image: '/fakeImagePath'
})

expect(getByTestId('ThumbnailImage')).toBeInTheDocument()
expect(queryByTestId('BackgroundThumbnailImage')).toBeNull()
expect(queryByTestId('Skeleton')).toBeNull()
})

it('should display an stacked image', () => {
const { getByTestId, queryByTestId } = setup({
image: '/fakeImagePath',
isStacked: true
})

expect(getByTestId('ThumbnailImage')).toBeInTheDocument()
expect(getByTestId('BackgroundThumbnailImage')).toBeInTheDocument()
expect(queryByTestId('Skeleton')).toBeNull()
})
})

describe('Thumbnail with "icon" prop without Skeleton', () => {
it('should display an unstacked icon String', () => {
const { getByTestId, queryByTestId } = setup({
icon: 'fake-icon-string'
})

expect(getByTestId('ThumbnailIcon')).toBeInTheDocument()
expect(queryByTestId('BackgroundThumbnailIcon')).toBeNull()
expect(queryByTestId('Skeleton')).toBeNull()
})

it('should display an unstacked icon Component', () => {
const { getByTestId, queryByTestId } = setup({
icon: MockIcon
})

expect(getByTestId('ThumbnailIcon')).toBeInTheDocument()
expect(queryByTestId('BackgroundThumbnailIcon')).toBeNull()
expect(queryByTestId('Skeleton')).toBeNull()
})

it('should display an stacked icon String', () => {
const { getByTestId, queryByTestId } = setup({
icon: 'fake-icon-string',
isStacked: true
})

expect(getByTestId('ThumbnailIcon')).toBeInTheDocument()
expect(getByTestId('BackgroundThumbnailIcon')).toBeInTheDocument()
expect(queryByTestId('Skeleton')).toBeNull()
})

it('should display an stacked icon Component', () => {
const { getByTestId, queryByTestId } = setup({
icon: MockIcon,
isStacked: true
})

expect(getByTestId('ThumbnailIcon')).toBeInTheDocument()
expect(getByTestId('BackgroundThumbnailIcon')).toBeInTheDocument()
expect(queryByTestId('Skeleton')).toBeNull()
})
})
})

describe('Thumbnail with Skeleton', () => {
it('should display only one Thumbnail with Skeleton', () => {
const { getByTestId, queryByTestId } = setup()

expect(getByTestId('ThumbnailWrapper')).toBeInTheDocument()
expect(getByTestId('Skeleton')).toBeInTheDocument()
expect(queryByTestId('ThumbnailBackgroundWrapper')).toBeNull()
})

it('should display Thumbnail stacked with Skeleton', () => {
const { getByTestId } = setup({ isStacked: true })

expect(getByTestId('ThumbnailWrapper')).toBeInTheDocument()
expect(getByTestId('SkeletonBackground')).toBeInTheDocument()
expect(getByTestId('ThumbnailBackgroundWrapper')).toBeInTheDocument()
})
})
})
41 changes: 41 additions & 0 deletions react/Thumbnail/Thumbnail.styl
@@ -0,0 +1,41 @@
.container
align-items center
box-sizing border-box
display flex
height 32px
justify-content center
position relative
width 32px

.image__wrapper
background-color var(--paperBackgroundColor)
border 3px solid var(--paperBackgroundColor)
border-radius 3px
box-shadow 0px 0px 0px 1px rgba(29, 33, 42, 0.24), 0px 2px 4px rgba(29, 33, 42, 0.08), 0px 4px 16px rgba(29, 33, 42, 0.06)
box-sizing border-box
display inline-block
max-height 32px
max-width 32px
z-index 1


&.image__wrapper__background
position absolute
transform translate(3px, -3px)
z-index 0

&.image__wrapper__multiple
max-height 29px
max-width 29px

.image
display block
max-height 26px
max-width 26px

&.image__background
opacity 0

&.image__multiple
max-height 23px
max-width 23px
@@ -0,0 +1,23 @@
import React from 'react'

import Skeleton from '../../Skeleton'
import { getSkeletonSize } from '../helpers'
import ThumbnailBackgroundWrapper from './ThumbnailBackgroundWrapper'

const ThumbnailBackgroundFallback = () => {
const skeletonSize = getSkeletonSize(true)

return (
<ThumbnailBackgroundWrapper>
<Skeleton
data-testid="SkeletonBackground"
variant="rect"
animation={false}
width={skeletonSize}
height={skeletonSize}
/>
</ThumbnailBackgroundWrapper>
)
}

export default ThumbnailBackgroundFallback
22 changes: 22 additions & 0 deletions react/Thumbnail/ThumbnailBackground/ThumbnailBackgroundIcon.jsx
@@ -0,0 +1,22 @@
import React from 'react'

import Icon from '../../Icon'
import { getSkeletonSize } from '../helpers'
import ThumbnailBackgroundWrapper from './ThumbnailBackgroundWrapper'

const ThumbnailBackgroundIcon = ({ icon }) => {
const skeletonSize = getSkeletonSize(true)

return (
<ThumbnailBackgroundWrapper>
<Icon
icon={icon}
height={skeletonSize}
width={skeletonSize}
data-testid="BackgroundThumbnailIcon"
/>
</ThumbnailBackgroundWrapper>
)
}

export default ThumbnailBackgroundIcon
25 changes: 25 additions & 0 deletions react/Thumbnail/ThumbnailBackground/ThumbnailBackgroundImage.jsx
@@ -0,0 +1,25 @@
import React from 'react'
import cx from 'classnames'

import ThumbnailBackgroundWrapper from './ThumbnailBackgroundWrapper'

import styles from '../Thumbnail.styl'

const ThumbnailBackgroundImage = ({ image }) => {
return (
<ThumbnailBackgroundWrapper>
<img
src={image}
alt=""
className={cx(
styles['image'],
styles['image__background'],
styles['image__multiple']
)}
data-testid="BackgroundThumbnailImage"
/>
</ThumbnailBackgroundWrapper>
)
}

export default ThumbnailBackgroundImage
21 changes: 21 additions & 0 deletions react/Thumbnail/ThumbnailBackground/ThumbnailBackgroundWrapper.jsx
@@ -0,0 +1,21 @@
import React from 'react'
import cx from 'classnames'

import styles from '../Thumbnail.styl'

const ThumbnailBackgroundWrapper = ({ children }) => {
return (
<div
className={cx(
styles['image__wrapper'],
styles['image__wrapper__background'],
styles['image__wrapper__multiple']
)}
data-testid="ThumbnailBackgroundWrapper"
>
{children}
</div>
)
}

export default ThumbnailBackgroundWrapper
37 changes: 37 additions & 0 deletions react/Thumbnail/ThumbnailByType.jsx
@@ -0,0 +1,37 @@
import React from 'react'

import ThumbnailIcon from './ThumbnailIcon'
import ThumbnailImage from './ThumbnailImage'
import ThumbnailFallback from './ThumbnailFallback'
import ThumbnailBackgroundIcon from './ThumbnailBackground/ThumbnailBackgroundIcon'
import ThumbnailBackgroundImage from './ThumbnailBackground/ThumbnailBackgroundImage'
import ThumbnailBackgroundFallback from './ThumbnailBackground/ThumbnailBackgroundFallback'

const ThumbnailByType = ({ image, icon, isStacked }) => {
if (icon) {
return (
<>
<ThumbnailIcon icon={icon} isStacked={isStacked} />
{isStacked && <ThumbnailBackgroundIcon icon={icon} />}
</>
)
}

if (image) {
return (
<>
<ThumbnailImage image={image} isStacked={isStacked} />
{isStacked && <ThumbnailBackgroundImage image={image} />}
</>
)
}

return (
<>
<ThumbnailFallback isStacked={isStacked} />
{isStacked && <ThumbnailBackgroundFallback />}
</>
)
}

export default ThumbnailByType
24 changes: 24 additions & 0 deletions react/Thumbnail/ThumbnailFallback.jsx
@@ -0,0 +1,24 @@
import React from 'react'

import Skeleton from '../Skeleton'
import ThumbnailWrapper from './ThumbnailWrapper'
import { getSkeletonSize } from './helpers'

const ThumbnailFallback = ({ isStacked }) => {
const skeletonSize = getSkeletonSize(isStacked)

return (
<ThumbnailWrapper>
<Skeleton
variant="rect"
animation="wave"
width={skeletonSize}
height={skeletonSize}
style={{ borderRadius: 3 }}
data-testid="Skeleton"
/>
</ThumbnailWrapper>
)
}

export default ThumbnailFallback
22 changes: 22 additions & 0 deletions react/Thumbnail/ThumbnailIcon.jsx
@@ -0,0 +1,22 @@
import React from 'react'

import Icon from '../Icon'
import ThumbnailWrapper from './ThumbnailWrapper'
import { getSkeletonSize } from './helpers'

const ThumbnailIcon = ({ icon, isStacked }) => {
const skeletonSize = getSkeletonSize(isStacked)

return (
<ThumbnailWrapper isStacked={isStacked}>
<Icon
data-testid="ThumbnailIcon"
icon={icon}
height={skeletonSize}
width={skeletonSize}
/>
</ThumbnailWrapper>
)
}

export default ThumbnailIcon
23 changes: 23 additions & 0 deletions react/Thumbnail/ThumbnailImage.jsx
@@ -0,0 +1,23 @@
import cx from 'classnames'
import React from 'react'

import ThumbnailWrapper from './ThumbnailWrapper'

import styles from './Thumbnail.styl'

const ThumbnailImage = ({ image, isStacked }) => {
return (
<ThumbnailWrapper isStacked={isStacked}>
<img
className={cx(styles['image'], {
[styles['image__multiple']]: isStacked
})}
data-testid="ThumbnailImage"
src={image}
alt=""
/>
</ThumbnailWrapper>
)
}

export default ThumbnailImage
19 changes: 19 additions & 0 deletions react/Thumbnail/ThumbnailWrapper.jsx
@@ -0,0 +1,19 @@
import React from 'react'
import cx from 'classnames'

import styles from './Thumbnail.styl'

const ThumbnailWrapper = ({ children, isStacked }) => {
return (
<div
className={cx(styles['image__wrapper'], {
[styles['image__wrapper__multiple']]: isStacked
})}
data-testid="ThumbnailWrapper"
>
{children}
</div>
)
}

export default ThumbnailWrapper
1 change: 1 addition & 0 deletions react/Thumbnail/helpers.js
@@ -0,0 +1 @@
export const getSkeletonSize = isStacked => (isStacked ? 23 : 26)

0 comments on commit f060e70

Please sign in to comment.