💄(frontend) enhance home page
I've totally rework the homepage, heavily inspired by GMeet. Goal: make it more pro, and polished.
This commit is contained in:
committed by
aleb_the_flash
parent
5de9cec688
commit
b06880be15
@@ -1,10 +1,9 @@
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { DialogTrigger, MenuItem, Menu as RACMenu } from 'react-aria-components'
|
import { DialogTrigger, MenuItem, Menu as RACMenu } from 'react-aria-components'
|
||||||
import { Button, Menu, Text } from '@/primitives'
|
import { Button, Menu } from '@/primitives'
|
||||||
import { HStack } from '@/styled-system/jsx'
|
import { HStack, styled } from '@/styled-system/jsx'
|
||||||
import { navigateTo } from '@/navigation/navigateTo'
|
import { navigateTo } from '@/navigation/navigateTo'
|
||||||
import { Screen } from '@/layout/Screen'
|
import { Screen } from '@/layout/Screen'
|
||||||
import { Centered } from '@/layout/Centered'
|
|
||||||
import { generateRoomId } from '@/features/rooms'
|
import { generateRoomId } from '@/features/rooms'
|
||||||
import { useUser, UserAware } from '@/features/auth'
|
import { useUser, UserAware } from '@/features/auth'
|
||||||
import { JoinMeetingDialog } from '../components/JoinMeetingDialog'
|
import { JoinMeetingDialog } from '../components/JoinMeetingDialog'
|
||||||
@@ -14,7 +13,125 @@ import { usePersistentUserChoices } from '@livekit/components-react'
|
|||||||
import { menuItemRecipe } from '@/primitives/menuItemRecipe'
|
import { menuItemRecipe } from '@/primitives/menuItemRecipe'
|
||||||
import { RiAddLine, RiLink } from '@remixicon/react'
|
import { RiAddLine, RiLink } from '@remixicon/react'
|
||||||
import { LaterMeetingDialog } from '@/features/home/components/LaterMeetingDialog'
|
import { LaterMeetingDialog } from '@/features/home/components/LaterMeetingDialog'
|
||||||
import { useState } from 'react'
|
import { IntroSlider } from '@/features/home/components/IntroSlider'
|
||||||
|
import { MoreLink } from '@/features/home/components/MoreLink'
|
||||||
|
import { ReactNode, useState } from 'react'
|
||||||
|
|
||||||
|
import { css } from '@/styled-system/css'
|
||||||
|
|
||||||
|
const Columns = ({ children }: { children?: ReactNode }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={css({
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'inline-flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
height: '100%',
|
||||||
|
minHeight: '100%',
|
||||||
|
justifyContent: 'normal',
|
||||||
|
padding: '0 1rem',
|
||||||
|
width: 'calc(100%-2rem)',
|
||||||
|
lg: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-evenly',
|
||||||
|
width: '100%',
|
||||||
|
padding: 0,
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const LeftColumn = ({ children }: { children?: ReactNode }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={css({
|
||||||
|
alignItems: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
display: 'inline-flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexBasis: 'auto',
|
||||||
|
flexShrink: 0,
|
||||||
|
maxWidth: '39rem',
|
||||||
|
width: '100%',
|
||||||
|
padding: '1rem 3%',
|
||||||
|
marginTop: 'auto',
|
||||||
|
lg: {
|
||||||
|
margin: 0,
|
||||||
|
textAlign: 'left',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
flexShrink: '1',
|
||||||
|
flexBasis: '45rem',
|
||||||
|
maxWidth: '45rem',
|
||||||
|
padding: '1em 3em',
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const RightColumn = ({ children }: { children?: ReactNode }) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={css({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
overflow: 'hidden',
|
||||||
|
padding: '1rem 3%',
|
||||||
|
marginBottom: 'auto',
|
||||||
|
flexBasis: 'auto',
|
||||||
|
flexShrink: 0,
|
||||||
|
maxWidth: '39rem',
|
||||||
|
lg: {
|
||||||
|
margin: 0,
|
||||||
|
flexBasis: '45%',
|
||||||
|
padding: '1em 3em',
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Separator = styled('div', {
|
||||||
|
base: {
|
||||||
|
borderBottom: '1px solid',
|
||||||
|
borderColor: '#747775',
|
||||||
|
marginTop: '2.5rem',
|
||||||
|
maxWidth: '30rem',
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const Heading = styled('h1', {
|
||||||
|
base: {
|
||||||
|
fontSize: '3rem',
|
||||||
|
lineHeight: '3.2rem',
|
||||||
|
letterSpacing: '0',
|
||||||
|
fontWeight: '500',
|
||||||
|
fontStyle: 'normal',
|
||||||
|
fontStretch: 'normal',
|
||||||
|
fontOpticalSizing: 'auto',
|
||||||
|
marginBottom: 0,
|
||||||
|
paddingBottom: '0.75rem',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const IntroText = styled('div', {
|
||||||
|
base: {
|
||||||
|
marginBottom: '3rem',
|
||||||
|
fontSize: '1.375rem',
|
||||||
|
lineHeight: '1.8rem',
|
||||||
|
textWrap: 'pretty',
|
||||||
|
maxWidth: '28rem',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
export const Home = () => {
|
export const Home = () => {
|
||||||
const { t } = useTranslation('home')
|
const { t } = useTranslation('home')
|
||||||
@@ -30,72 +147,83 @@ export const Home = () => {
|
|||||||
return (
|
return (
|
||||||
<UserAware>
|
<UserAware>
|
||||||
<Screen>
|
<Screen>
|
||||||
<Centered width="fit-content">
|
<Columns>
|
||||||
<Text as="h1" variant="display">
|
<LeftColumn>
|
||||||
{t('heading')}
|
<Heading>{t('heading')}</Heading>
|
||||||
</Text>
|
<IntroText>{t('intro')}</IntroText>
|
||||||
<Text as="p" variant="h3">
|
<HStack gap="gutter" alignItems="start">
|
||||||
{t('intro')}
|
{isLoggedIn ? (
|
||||||
</Text>
|
<Menu>
|
||||||
{!isLoggedIn && (
|
<Button variant="primary" data-attr="create-meeting">
|
||||||
<Text margin="sm" variant="note">
|
{t('createMeeting')}
|
||||||
{t('loginToCreateMeeting')}
|
</Button>
|
||||||
</Text>
|
<RACMenu>
|
||||||
)}
|
<MenuItem
|
||||||
<HStack gap="gutter" alignItems="start">
|
className={menuItemRecipe({ icon: true })}
|
||||||
{isLoggedIn ? (
|
onAction={async () => {
|
||||||
<Menu>
|
const slug = generateRoomId()
|
||||||
<Button variant="primary" data-attr="create-meeting">
|
createRoom({ slug, username }).then((data) =>
|
||||||
{t('createMeeting')}
|
navigateTo('room', data.slug, {
|
||||||
|
state: { create: true, initialRoomData: data },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
data-attr="create-option-instant"
|
||||||
|
>
|
||||||
|
<RiAddLine size={18} />
|
||||||
|
{t('createMenu.instantOption')}
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
className={menuItemRecipe({ icon: true })}
|
||||||
|
onAction={() => {
|
||||||
|
const slug = generateRoomId()
|
||||||
|
createRoom({ slug, username }).then((data) =>
|
||||||
|
setLaterRoomId(data.slug)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
data-attr="create-option-later"
|
||||||
|
>
|
||||||
|
<RiLink size={18} />
|
||||||
|
{t('createMenu.laterOption')}
|
||||||
|
</MenuItem>
|
||||||
|
</RACMenu>
|
||||||
|
</Menu>
|
||||||
|
) : (
|
||||||
|
<ProConnectButton hint={false} />
|
||||||
|
)}
|
||||||
|
<DialogTrigger>
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
outline
|
||||||
|
style={{
|
||||||
|
height: !isLoggedIn ? '56px' : undefined, // Temporary, Align with ProConnect Button fixed height
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('joinMeeting')}
|
||||||
</Button>
|
</Button>
|
||||||
<RACMenu>
|
<JoinMeetingDialog />
|
||||||
<MenuItem
|
</DialogTrigger>
|
||||||
className={menuItemRecipe({ icon: true })}
|
</HStack>
|
||||||
onAction={async () => {
|
<Separator />
|
||||||
const slug = generateRoomId()
|
<div
|
||||||
createRoom({ slug, username }).then((data) =>
|
className={css({
|
||||||
navigateTo('room', data.slug, {
|
display: { base: 'none', lg: 'inline' },
|
||||||
state: { create: true, initialRoomData: data },
|
})}
|
||||||
})
|
>
|
||||||
)
|
<MoreLink />
|
||||||
}}
|
</div>
|
||||||
data-attr="create-option-instant"
|
</LeftColumn>
|
||||||
>
|
<RightColumn>
|
||||||
<RiAddLine size={18} />
|
<IntroSlider />
|
||||||
{t('createMenu.instantOption')}
|
<div
|
||||||
</MenuItem>
|
className={css({
|
||||||
<MenuItem
|
display: { base: 'inline', lg: 'none' },
|
||||||
className={menuItemRecipe({ icon: true })}
|
})}
|
||||||
onAction={() => {
|
>
|
||||||
const slug = generateRoomId()
|
<MoreLink />
|
||||||
createRoom({ slug, username }).then((data) =>
|
</div>
|
||||||
setLaterRoomId(data.slug)
|
</RightColumn>
|
||||||
)
|
</Columns>
|
||||||
}}
|
|
||||||
data-attr="create-option-later"
|
|
||||||
>
|
|
||||||
<RiLink size={18} />
|
|
||||||
{t('createMenu.laterOption')}
|
|
||||||
</MenuItem>
|
|
||||||
</RACMenu>
|
|
||||||
</Menu>
|
|
||||||
) : (
|
|
||||||
<ProConnectButton />
|
|
||||||
)}
|
|
||||||
<DialogTrigger>
|
|
||||||
<Button
|
|
||||||
variant="primary"
|
|
||||||
outline
|
|
||||||
style={{
|
|
||||||
height: !isLoggedIn ? '56px' : undefined, // Temporary, Align with ProConnect Button fixed height
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('joinMeeting')}
|
|
||||||
</Button>
|
|
||||||
<JoinMeetingDialog />
|
|
||||||
</DialogTrigger>
|
|
||||||
</HStack>
|
|
||||||
</Centered>
|
|
||||||
<LaterMeetingDialog
|
<LaterMeetingDialog
|
||||||
roomId={laterRoomId || ''}
|
roomId={laterRoomId || ''}
|
||||||
onOpenChange={() => setLaterRoomId(null)}
|
onOpenChange={() => setLaterRoomId(null)}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"createMeeting": "Create a meeting",
|
"createMeeting": "Create a meeting",
|
||||||
"heading": "Welcome in Visio",
|
"heading": "Simple and Secure Video Conferencing",
|
||||||
"intro": "Work easily, from anywhere.",
|
"intro": "Communicate and work with ease, without compromising your sovereignty",
|
||||||
"joinInputError": "Use a meeting link or code. Examples:",
|
"joinInputError": "Use a meeting link or code. Examples:",
|
||||||
"joinInputExample": "URL or 10-letter code",
|
"joinInputExample": "URL or 10-letter code",
|
||||||
"joinInputLabel": "Meeting link",
|
"joinInputLabel": "Meeting link",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"createMeeting": "Créer une réunion",
|
"createMeeting": "Créer une réunion",
|
||||||
"heading": "Visio",
|
"heading": "Visioconférences simples et sécurisées",
|
||||||
"intro": "Collaborez en toute simplicité, où que vous soyez.",
|
"intro": "Communiquez et travaillez en toute simplicité, sans compromis sur votre souveraineté",
|
||||||
"joinInputError": "Saisissez un lien ou un code de réunion. Exemples :",
|
"joinInputError": "Saisissez un lien ou un code de réunion. Exemples :",
|
||||||
"joinInputExample": "Un code de réunion ressemble à ceci : abc-defg-hij",
|
"joinInputExample": "Un code de réunion ressemble à ceci : abc-defg-hij",
|
||||||
"joinInputLabel": "Lien complet ou code de la réunion",
|
"joinInputLabel": "Lien complet ou code de la réunion",
|
||||||
|
|||||||
Reference in New Issue
Block a user