Skip to content

Commit

Permalink
feat: add news AssetModal components for picture, video and swiper Modal
Browse files Browse the repository at this point in the history
  • Loading branch information
theo-mesnil committed Jan 29, 2024
1 parent 5a750ab commit c5f33d7
Show file tree
Hide file tree
Showing 9 changed files with 338 additions and 1 deletion.
141 changes: 141 additions & 0 deletions docs/pages/components/modal.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,147 @@ function() {
}
```

## AssetModal

For our cases we need to show an item in a center of a modal, with specific Backdrop background color and a close button. It's a new sub component to the modal: `AssetModal`.

### Image

```jsx
function() {
const modal = useModal()

return (
<>
<Modal.Trigger as={Button} store={modal}>
Open modal
</Modal.Trigger>
<Modal
store={modal}
ariaLabel="asset modal example"
backdrop={<AssetModal.Backdrop hideOnInteractOutside />}
render={<AssetModal />}
>
<AssetModal.Content>
<img src="https://cdn-images.welcometothejungle.com/rUlGHCfE1zos9CVMJELrqCeCVzH27VuBO8GH5yiMkic/rs:auto:1500::/q:85/czM6Ly93dHRqLXByb2R1Y3Rpb24vdXBsb2Fkcy9pbWFnZS9maWxlLzQ0MjIvMTcwMzg2L2NkNGRhNTc5LWQ4YTktNDQ0OC1iMGM2LWI3ZWYwY2U2ZjQ0MS5qcGc" />
</AssetModal.Content>
</Modal>
</>
)
}
```

### Iframe

```jsx
function() {
const modal = useModal({ open: true })

return (
<>
<Modal.Trigger as={Button} store={modal}>
Open modal
</Modal.Trigger>
<Modal
store={modal}
ariaLabel="asset modal example"
backdrop={<AssetModal.Backdrop hideOnInteractOutside />}
render={<AssetModal />}
>
<AssetModal.Content>
<AssetModal.Iframe>
<iframe
src="https://www.youtube.com/embed/1kjATTF4v5A"
title="YouTube video player"
frameBorder="0"
allowFullScreen
/>
</AssetModal.Iframe>
</AssetModal.Content>
</Modal>
</>
)
}
```

### With title and subtitle block

```jsx
function() {
const modal = useModal()

return (
<>
<Modal.Trigger as={Button} store={modal}>
Open modal
</Modal.Trigger>
<Modal
store={modal}
ariaLabel="asset modal example"
backdrop={<AssetModal.Backdrop hideOnInteractOutside />}
render={<AssetModal />}
>
<AssetModal.Content>
<AssetModal.AssetWithTitle
title="This is a caption of the picture"
subtitle="Welcome tot the jungle"
>
<AssetModal.Iframe>
<iframe
src="https://www.youtube.com/embed/1kjATTF4v5A"
title="YouTube video player"
frameBorder="0"
allowFullScreen
/>
</AssetModal.Iframe>
</AssetModal.AssetWithTitle>
</AssetModal.Content>
</Modal>
</>
)
}
```

### With a swiper

```jsx
function() {
const modal = useModal()
const swiper = useSwiper({ spaceBetween: 0 })

return (
<>
<Modal.Trigger as={Button} store={modal}>
Open modal
</Modal.Trigger>
<Modal
store={modal}
ariaLabel="asset modal example"
backdrop={<AssetModal.Backdrop hideOnInteractOutside />}
render={<AssetModal />}
>
<AssetModal.Content>
<Swiper store={swiper} h={400}>
<img
style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }}
src="https://images.unsplash.com/photo-1564460549828-f0219a31bf90?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
/>
<img
style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }}
src="https://images.unsplash.com/photo-1575489272413-cb506258027e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
/>
<img
style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }}
src="https://images.unsplash.com/photo-1541959833400-049d37f98ccd?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
/>
</Swiper>
</AssetModal.Content>
</Modal>
</>
)
}
```

## useModal

We use `useDialogStore` from [Ariakit Dialog](https://ariakit.org/reference/use-dialog-store) for the state of the modal.
Expand Down
2 changes: 2 additions & 0 deletions packages/Modal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@
"dependencies": {
"@ariakit/react": "0.3.4",
"@welcome-ui/box": "^5.0.0",
"@welcome-ui/button": "^5.6.1",
"@welcome-ui/close-button": "^5.6.1",
"@welcome-ui/icons.font": "^5.5.0",
"@welcome-ui/shape": "^5.6.1",
"@welcome-ui/system": "^5.0.0",
"@welcome-ui/text": "^5.6.1",
Expand Down
64 changes: 64 additions & 0 deletions packages/Modal/src/Assets/AssetWithTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from 'react'
import { Box } from '@welcome-ui/box'
import { Text } from '@welcome-ui/text'
import styled from '@xstyled/styled-components'

import { Iframe } from './styles'

type AssetWithTitleProps = {
children: React.ReactNode
subtitle?: JSX.Element
title: JSX.Element
}

const titleBlockMobile = '4rem'
const titleBlockDesktop = '6rem'

const Wrapper = styled.div`
display: flex;
flex-direction: column;
> img {
width: auto;
max-width: fit-content;
max-height: calc(100vh - 2 * 5rem - ${titleBlockMobile});
flex-shrink: 0;
@media (min-width: md) {
max-height: calc(100vh - 2 * 5rem - ${titleBlockDesktop});
}
}
${Iframe} {
background-color: dark-900;
max-height: calc(100vh - 2 * 5rem - ${titleBlockMobile});
@media (min-width: md) {
max-height: calc(100vh - 2 * 5rem - ${titleBlockDesktop});
}
}
`

export const AssetWithTitle: React.FC<AssetWithTitleProps> = ({ children, subtitle, title }) => {
return (
<Wrapper>
{children}
<Box
backgroundColor="light-900"
display="flex"
flexDirection="column"
flexShrink={0}
gap="xxs"
h={{ _: titleBlockMobile, md: titleBlockDesktop }}
justifyContent="center"
px={{ _: 'md', md: 'xl' }}
w="100%"
>
{subtitle && <Text variant="subtitle-sm">{subtitle}</Text>}
<Text lines={1} m="0" variant="h4">
{title}
</Text>
</Box>
</Wrapper>
)
}
38 changes: 38 additions & 0 deletions packages/Modal/src/Assets/Backdrop.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react'
import * as Ariakit from '@ariakit/react'
import { Button } from '@welcome-ui/button'
import { Icons } from '@welcome-ui/icons.font'
import styled, { system } from '@xstyled/styled-components'

import * as S from '../styles'

export const CloseButton = styled(Button)`
position: absolute;
right: xl;
top: xl;
/* Hack for secondary variant on dark mode */
color: dark-900;
border-color: light-900;
background-color: light-900;
&:hover {
background-color: light-700;
}
${system}
`

export const Backdrop = React.forwardRef<HTMLDivElement>((props, ref) => {
return (
<S.Backdrop backgroundColor="rgba(0, 0, 0, 0.9)" {...props} ref={ref}>
<Ariakit.DialogDismiss
render={
<CloseButton shape="circle" variant="secondary">
<Icons.Cross />
</CloseButton>
}
/>
</S.Backdrop>
)
})
18 changes: 18 additions & 0 deletions packages/Modal/src/Assets/Iframe.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react'
import { Box } from '@welcome-ui/box'

import * as S from './styles'

type IframeProps = {
children: React.ReactHTMLElement<HTMLIFrameElement>
}

export const Iframe = ({ children }: IframeProps) => {
return (
<S.Iframe>
<Box h="100%" margin="0 auto" style={{ aspectRatio: 16 / 9 }}>
{children}
</Box>
</S.Iframe>
)
}
12 changes: 12 additions & 0 deletions packages/Modal/src/Assets/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { AssetWithTitle } from './AssetWithTitle'
import { Backdrop } from './Backdrop'
import { Iframe } from './Iframe'
import { Content, Dialog } from './styles'

// Nested exports
export const Assets = Object.assign(Dialog, {
AssetWithTitle,
Backdrop,
Content,
Iframe,
})
58 changes: 58 additions & 0 deletions packages/Modal/src/Assets/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import styled, { th } from '@xstyled/styled-components'

const contentWidthDesktop = 'calc(100vw - 2 * 2rem);'
const contentWidthMobile = 'calc(100vw - 2 * 1rem);'
const contentHeight = 'calc(100vh - 2 * 5rem);'

export const Iframe = styled.div`
width: ${contentWidthMobile};
max-height: ${contentHeight};
flex: 1;
max-width: 1600;
@media (min-width: md) {
aspect-ratio: 16 / 9;
width: ${contentWidthDesktop};
}
iframe {
width: 100%;
height: 100%;
}
`

export const Content = styled.div`
display: block;
transition: margin-top 250ms ease-in-out;
> img,
> div {
max-width: ${contentWidthMobile};
max-height: ${contentHeight};
@media (min-width: md) {
max-width: ${contentWidthDesktop};
}
}
`

export const Dialog = styled.div`
${th('modals.default')};
position: fixed;
inset: 0;
margin: auto;
display: flex;
height: fit-content;
width: fit-content;
flex-direction: column;
opacity: 0;
transition: opacity 250ms ease-in-out;
&[data-enter] {
opacity: 1;
${Content} {
margin-top: 0;
}
}
`
4 changes: 4 additions & 0 deletions packages/Modal/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as S from './styles'
import { Header } from './Header'
import { Footer } from './Footer'
import { Content } from './Content'
import { Assets } from './Assets'

export type Size = 'xs' | 'sm' | 'md' | 'lg' | 'auto'

Expand Down Expand Up @@ -95,3 +96,6 @@ export const Modal = Object.assign(ModalComponent, {
Footer,
Cover,
})

// Asset Modal for pictures / videos / swiper
export const AssetModal = Assets
2 changes: 1 addition & 1 deletion packages/Modal/src/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Size } from './index'

type BackdropProps = Pick<Ariakit.DialogOptions, 'hideOnInteractOutside'>

export const Backdrop = styled.div.withConfig({
export const Backdrop = styled.divBox.withConfig({
shouldForwardProp: prop => !['hideOnInteractOutside'].includes(prop),
})<BackdropProps>(
({ hideOnInteractOutside }) => css`
Expand Down

0 comments on commit c5f33d7

Please sign in to comment.