♻️(dialogs) new DialogContent component to ease up code splitting
this better permits us to have a Dialog content component somewhere else than its trigger button. Mainly did this so that the dialog title is localized with its content.
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Div, Field, Ul, H, P, Form } from '@/primitives'
|
import { Field, Ul, H, P, Form, DialogContent } from '@/primitives'
|
||||||
import { isRoomValid, navigateToRoom } from '@/features/rooms'
|
import { isRoomValid, navigateToRoom } from '@/features/rooms'
|
||||||
|
|
||||||
export const JoinMeetingDialog = () => {
|
export const JoinMeetingDialogContent = () => {
|
||||||
const { t } = useTranslation('home')
|
const { t } = useTranslation('home')
|
||||||
return (
|
return (
|
||||||
<Div>
|
<DialogContent title={t('joinMeeting')}>
|
||||||
<Form
|
<Form
|
||||||
onSubmit={(data) => {
|
onSubmit={(data) => {
|
||||||
navigateToRoom((data.roomId as string).trim())
|
navigateToRoom((data.roomId as string).trim())
|
||||||
@@ -34,6 +34,6 @@ export const JoinMeetingDialog = () => {
|
|||||||
</Form>
|
</Form>
|
||||||
<H lvl={2}>{t('joinMeetingTipHeading')}</H>
|
<H lvl={2}>{t('joinMeetingTipHeading')}</H>
|
||||||
<P last>{t('joinMeetingTipContent')}</P>
|
<P last>{t('joinMeetingTipContent')}</P>
|
||||||
</Div>
|
</DialogContent>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ import { HStack } from '@/styled-system/jsx'
|
|||||||
import { authUrl, useUser } from '@/features/auth'
|
import { authUrl, useUser } from '@/features/auth'
|
||||||
import { navigateToNewRoom } from '@/features/rooms'
|
import { navigateToNewRoom } from '@/features/rooms'
|
||||||
import { Screen } from '@/layout/Screen'
|
import { Screen } from '@/layout/Screen'
|
||||||
import { JoinMeetingDialog } from '../components/JoinMeetingDialog'
|
import { JoinMeetingDialogContent } from '../components/JoinMeetingDialogContent'
|
||||||
|
|
||||||
export const Home = () => {
|
export const Home = () => {
|
||||||
const { t } = useTranslation('home')
|
const { t } = useTranslation('home')
|
||||||
@@ -33,11 +33,11 @@ export const Home = () => {
|
|||||||
{isLoggedIn ? t('createMeeting') : t('login', { ns: 'global' })}
|
{isLoggedIn ? t('createMeeting') : t('login', { ns: 'global' })}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Dialog title={t('joinMeeting')}>
|
<Dialog>
|
||||||
<Button variant="primary" outline>
|
<Button variant="primary" outline>
|
||||||
{t('joinMeeting')}
|
{t('joinMeeting')}
|
||||||
</Button>
|
</Button>
|
||||||
<JoinMeetingDialog />
|
<JoinMeetingDialogContent />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</HStack>
|
</HStack>
|
||||||
</Div>
|
</Div>
|
||||||
|
|||||||
@@ -5,17 +5,12 @@ import {
|
|||||||
Modal,
|
Modal,
|
||||||
type DialogProps as RACDialogProps,
|
type DialogProps as RACDialogProps,
|
||||||
ModalOverlay,
|
ModalOverlay,
|
||||||
Heading,
|
|
||||||
OverlayTriggerStateContext,
|
OverlayTriggerStateContext,
|
||||||
} from 'react-aria-components'
|
} from 'react-aria-components'
|
||||||
import { RiCloseLine } from '@remixicon/react'
|
import { RiCloseLine } from '@remixicon/react'
|
||||||
import { styled } from '@/styled-system/jsx'
|
|
||||||
import { Box } from './Box'
|
|
||||||
import { Div } from './Div'
|
|
||||||
import { VerticallyOffCenter } from './VerticallyOffCenter'
|
|
||||||
import { text } from './Text'
|
|
||||||
import { Button } from './Button'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { styled } from '@/styled-system/jsx'
|
||||||
|
import { Button, Box, Div, VerticallyOffCenter } from '@/primitives'
|
||||||
|
|
||||||
const StyledModalOverlay = styled(ModalOverlay, {
|
const StyledModalOverlay = styled(ModalOverlay, {
|
||||||
base: {
|
base: {
|
||||||
@@ -54,7 +49,6 @@ const StyledRACDialog = styled(RACDialog, {
|
|||||||
})
|
})
|
||||||
|
|
||||||
export type DialogProps = {
|
export type DialogProps = {
|
||||||
title: string
|
|
||||||
children: [
|
children: [
|
||||||
trigger: ReactNode,
|
trigger: ReactNode,
|
||||||
dialogContent:
|
dialogContent:
|
||||||
@@ -64,9 +58,9 @@ export type DialogProps = {
|
|||||||
} & RACDialogProps
|
} & RACDialogProps
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a Dialog is a tuple of a trigger component (most usually a Button) that toggles some interactive content in a Dialog on top of the app
|
* a Dialog is a tuple of a trigger component (most usually a Button) that toggles some interactive content in a Dialog on top of the app. You should mostly use a DialogContent as second child.
|
||||||
*/
|
*/
|
||||||
export const Dialog = ({ title, children, ...dialogProps }: DialogProps) => {
|
export const Dialog = ({ children, ...dialogProps }: DialogProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const isAlert = dialogProps['role'] === 'alertdialog'
|
const isAlert = dialogProps['role'] === 'alertdialog'
|
||||||
const [trigger, dialogContent] = children
|
const [trigger, dialogContent] = children
|
||||||
@@ -88,13 +82,6 @@ export const Dialog = ({ title, children, ...dialogProps }: DialogProps) => {
|
|||||||
pointerEvents="auto"
|
pointerEvents="auto"
|
||||||
>
|
>
|
||||||
<Box size="sm" type="dialog">
|
<Box size="sm" type="dialog">
|
||||||
<Heading
|
|
||||||
slot="title"
|
|
||||||
level={1}
|
|
||||||
className={text({ variant: 'h1' })}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</Heading>
|
|
||||||
{typeof dialogContent === 'function'
|
{typeof dialogContent === 'function'
|
||||||
? dialogContent({ close })
|
? dialogContent({ close })
|
||||||
: dialogContent}
|
: dialogContent}
|
||||||
|
|||||||
28
src/frontend/src/primitives/DialogContent.tsx
Normal file
28
src/frontend/src/primitives/DialogContent.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { type ReactNode } from 'react'
|
||||||
|
import { Heading } from 'react-aria-components'
|
||||||
|
import { text } from './Text'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialog content Wrapper.
|
||||||
|
*
|
||||||
|
* Use this in a <Dialog>, next to the button triggering the dialog.
|
||||||
|
* This is helpful to easily add the title to the dialog and keep it
|
||||||
|
* next to the actual content code, if you happen to separate the dialog
|
||||||
|
* trigger from the dialog content in the code.
|
||||||
|
*/
|
||||||
|
export const DialogContent = ({
|
||||||
|
children,
|
||||||
|
title,
|
||||||
|
}: {
|
||||||
|
title: ReactNode
|
||||||
|
children: ReactNode
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Heading slot="title" level={1} className={text({ variant: 'h1' })}>
|
||||||
|
{title}
|
||||||
|
</Heading>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ export { Bold } from './Bold'
|
|||||||
export { Box } from './Box'
|
export { Box } from './Box'
|
||||||
export { Button } from './Button'
|
export { Button } from './Button'
|
||||||
export { Dialog, useCloseDialog } from './Dialog'
|
export { Dialog, useCloseDialog } from './Dialog'
|
||||||
|
export { DialogContent } from './DialogContent'
|
||||||
export { Div } from './Div'
|
export { Div } from './Div'
|
||||||
export { Field } from './Field'
|
export { Field } from './Field'
|
||||||
export { Form } from './Form'
|
export { Form } from './Form'
|
||||||
|
|||||||
Reference in New Issue
Block a user