🚸(frontend) follow antoine's remarks on homepage and header

- show the header on homepage. Not sure we want any header on this app
actually but I guess he's right since we have one it feels more
consistent to have it everywhere
- show logged in email in header. ditched it because i didn't quite get
the value of showing it all the time in this app but i guess it's better
than nothing
- remove user info from settings. Since they are back in the header, no
need
This commit is contained in:
Emmanuel Pelletier
2024-07-25 14:39:34 +02:00
parent d15fb0a19b
commit 668523aa8b
19 changed files with 117 additions and 76 deletions

View File

@@ -181,6 +181,7 @@ const config: Config = {
active: { value: '{colors.gray.300}' }, active: { value: '{colors.gray.300}' },
text: { value: '{colors.default.text}' }, text: { value: '{colors.default.text}' },
border: { value: '{colors.gray.500}' }, border: { value: '{colors.gray.500}' },
subtle: { value: '{colors.gray.400}' },
}, },
primary: { primary: {
DEFAULT: { value: '{colors.blue.700}' }, DEFAULT: { value: '{colors.blue.700}' },

View File

@@ -4,7 +4,6 @@ import { Button, Div, Text, VerticallyOffCenter } from '@/primitives'
import { HStack } from '@/styled-system/jsx' 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 { SettingsButton } from '@/features/settings'
import { Screen } from '@/layout/Screen' import { Screen } from '@/layout/Screen'
import { JoinMeetingDialog } from '../components/JoinMeetingDialog' import { JoinMeetingDialog } from '../components/JoinMeetingDialog'
@@ -12,7 +11,7 @@ export const Home = () => {
const { t } = useTranslation('home') const { t } = useTranslation('home')
const { isLoggedIn } = useUser() const { isLoggedIn } = useUser()
return ( return (
<Screen type="splash"> <Screen>
<VerticallyOffCenter> <VerticallyOffCenter>
<Div margin="auto" width="fit-content"> <Div margin="auto" width="fit-content">
<Text as="h1" variant="display"> <Text as="h1" variant="display">
@@ -41,8 +40,6 @@ export const Home = () => {
</Button> </Button>
<JoinMeetingDialog /> <JoinMeetingDialog />
</DialogTrigger> </DialogTrigger>
<SettingsButton />
</HStack> </HStack>
</Div> </Div>
</VerticallyOffCenter> </VerticallyOffCenter>

View File

@@ -11,7 +11,14 @@ export const Join = ({
return ( return (
<Box title={t('join.heading')} withBackButton> <Box title={t('join.heading')} withBackButton>
<PreJoin persistUserChoices onSubmit={onSubmit} /> <PreJoin
persistUserChoices
onSubmit={onSubmit}
micLabel={t('join.micLabel')}
camLabel={t('join.camlabel')}
joinLabel={t('join.joinLabel')}
userLabel={t('join.userLabel')}
/>
</Box> </Box>
) )
} }

View File

@@ -1,36 +1,12 @@
import { Trans, useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useLanguageLabels } from '@/i18n/useLanguageLabels' import { useLanguageLabels } from '@/i18n/useLanguageLabels'
import { A, Badge, Dialog, Field, H, P } from '@/primitives' import { Dialog, Field, H } from '@/primitives'
import { authUrl, logoutUrl, useUser } from '@/features/auth'
export const SettingsDialog = () => { export const SettingsDialog = () => {
const { t, i18n } = useTranslation('settings') const { t, i18n } = useTranslation('settings')
const { user, isLoggedIn } = useUser()
const { languagesList, currentLanguage } = useLanguageLabels() const { languagesList, currentLanguage } = useLanguageLabels()
return ( return (
<Dialog title={t('dialog.heading')}> <Dialog title={t('dialog.heading')}>
<H lvl={2}>{t('account.heading')}</H>
{isLoggedIn ? (
<>
<P>
<Trans
i18nKey="settings:account.currentlyLoggedAs"
values={{ user: user?.email }}
components={[<Badge />]}
/>
</P>
<P>
<A href={logoutUrl()}>{t('logout', { ns: 'global' })}</A>
</P>
</>
) : (
<>
<P>{t('account.youAreNotLoggedIn')}</P>
<P>
<A href={authUrl()}>{t('login', { ns: 'global' })}</A>
</P>
</>
)}
<H lvl={2}>{t('language.heading')}</H> <H lvl={2}>{t('language.heading')}</H>
<Field <Field
type="select" type="select"

View File

@@ -2,20 +2,23 @@ import { Link } from 'wouter'
import { css } from '@/styled-system/css' import { css } from '@/styled-system/css'
import { Stack } from '@/styled-system/jsx' import { Stack } from '@/styled-system/jsx'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Text } from '@/primitives' import { A, Button, Popover, PopoverList, Text } from '@/primitives'
import { SettingsButton } from '@/features/settings' import { SettingsButton } from '@/features/settings'
import { authUrl, logoutUrl, useUser } from '@/features/auth'
export const Header = () => { export const Header = () => {
const { t } = useTranslation() const { t } = useTranslation()
const isHome = window.location.pathname === '/'
const { user, isLoggedIn } = useUser()
return ( return (
<div <div
className={css({ className={css({
backgroundColor: 'primary.text',
color: 'primary',
borderBottomColor: 'box.border', borderBottomColor: 'box.border',
borderBottomWidth: 1, borderBottomWidth: 1,
borderBottomStyle: 'solid', borderBottomStyle: 'solid',
padding: 1, paddingY: 1,
paddingX: 1,
flexShrink: 0, flexShrink: 0,
})} })}
> >
@@ -26,7 +29,32 @@ export const Header = () => {
</Text> </Text>
</header> </header>
<nav> <nav>
<SettingsButton /> <Stack gap={1} direction="row" align="center">
{isLoggedIn === false && !isHome && (
<A href={authUrl()}>{t('login')}</A>
)}
{!!user && (
<Popover aria-label={t('logout')}>
<Button
size="sm"
invisible
tooltip={t('loggedInUserTooltip')}
tooltipType="delayed"
>
{user.email}
</Button>
<PopoverList
items={[{ value: 'logout', label: t('logout') }]}
onAction={(value) => {
if (value === 'logout') {
window.location.href = logoutUrl()
}
}}
/>
</Popover>
)}
<SettingsButton />
</Stack>
</nav> </nav>
</Stack> </Stack>
</div> </div>

View File

@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
import { BoxScreen } from './BoxScreen' import { BoxScreen } from './BoxScreen'
import { Screen } from './Screen' import { Screen } from './Screen'
import { VerticallyOffCenter } from '@/primitives' import { VerticallyOffCenter } from '@/primitives'
import { Center, Container } from '@/styled-system/jsx' import { Center } from '@/styled-system/jsx'
export const LoadingScreen = ({ export const LoadingScreen = ({
asBox = false, asBox = false,

View File

@@ -14,6 +14,7 @@
"popoverLabel": "" "popoverLabel": ""
}, },
"loading": "", "loading": "",
"loggedInUserTooltip": "",
"login": "Anmelden", "login": "Anmelden",
"logout": "", "logout": "",
"notFound": { "notFound": {

View File

@@ -1,5 +1,9 @@
{ {
"join": { "join": {
"heading": "" "camlabel": "",
"heading": "",
"joinLabel": "",
"micLabel": "",
"userLabel": ""
} }
} }

View File

@@ -1,9 +1,4 @@
{ {
"account": {
"currentlyLoggedAs": "",
"heading": "",
"youAreNotLoggedIn": ""
},
"dialog": { "dialog": {
"heading": "" "heading": ""
}, },

View File

@@ -14,6 +14,7 @@
"popoverLabel": "Choose language" "popoverLabel": "Choose language"
}, },
"loading": "Loading…", "loading": "Loading…",
"loggedInUserTooltip": "Logged in as…",
"login": "Login", "login": "Login",
"logout": "Logout", "logout": "Logout",
"notFound": { "notFound": {

View File

@@ -1,5 +1,9 @@
{ {
"join": { "join": {
"heading": "Verify your settings before joining" "camlabel": "Camera",
"heading": "Join the meeting",
"joinLabel": "Join",
"micLabel": "Microphone",
"userLabel": "Your name"
} }
} }

View File

@@ -1,11 +1,6 @@
{ {
"account": {
"currentlyLoggedAs": "You are currently logged in as <0>{{user}}</0>",
"heading": "Account",
"youAreNotLoggedIn": "You are not logged in."
},
"dialog": { "dialog": {
"heading": "Account and settings" "heading": "Settings"
}, },
"language": { "language": {
"heading": "Language", "heading": "Language",

View File

@@ -14,6 +14,7 @@
"popoverLabel": "Choix de la langue" "popoverLabel": "Choix de la langue"
}, },
"loading": "Chargement…", "loading": "Chargement…",
"loggedInUserTooltip": "Connecté en tant que…",
"login": "Se connecter", "login": "Se connecter",
"logout": "Se déconnecter", "logout": "Se déconnecter",
"notFound": { "notFound": {

View File

@@ -1,5 +1,9 @@
{ {
"join": { "join": {
"heading": "Vérifiez vos paramètres" "camlabel": "Webcam",
"heading": "Rejoindre la réunion",
"joinLabel": "Rejoindre",
"micLabel": "Micro",
"userLabel": "Votre nom"
} }
} }

View File

@@ -1,11 +1,6 @@
{ {
"account": {
"currentlyLoggedAs": "Vous êtes actuellement connecté en tant que <0>{{user}}</0>",
"heading": "Compte",
"youAreNotLoggedIn": "Vous n'êtes pas connecté."
},
"dialog": { "dialog": {
"heading": "Compte et paramètres" "heading": "Paramètres"
}, },
"language": { "language": {
"heading": "Langue", "heading": "Langue",

View File

@@ -7,6 +7,7 @@ const link = cva({
textUnderlineOffset: '2', textUnderlineOffset: '2',
cursor: 'pointer', cursor: 'pointer',
borderRadius: 2, borderRadius: 2,
transition: 'all 0.2s',
'&[data-hovered]': { '&[data-hovered]': {
textDecoration: 'none', textDecoration: 'none',
}, },

View File

@@ -7,7 +7,7 @@ import {
LinkProps, LinkProps,
} from 'react-aria-components' } from 'react-aria-components'
import { cva, type RecipeVariantProps } from '@/styled-system/css' import { cva, type RecipeVariantProps } from '@/styled-system/css'
import { Tooltip, TooltipArrow } from './Tooltip' import { Tooltip } from './Tooltip'
const button = cva({ const button = cva({
base: { base: {
@@ -76,7 +76,7 @@ const button = cva({
backgroundColor: 'none!', backgroundColor: 'none!',
'&[data-hovered]': { '&[data-hovered]': {
backgroundColor: 'none!', backgroundColor: 'none!',
borderColor: 'currentcolor', borderColor: 'colorPalette.active!',
}, },
'&[data-pressed]': { '&[data-pressed]': {
borderColor: 'currentcolor', borderColor: 'currentcolor',
@@ -93,6 +93,7 @@ const button = cva({
type Tooltip = { type Tooltip = {
tooltip?: string tooltip?: string
tooltipType?: 'instant' | 'delayed'
} }
export type ButtonProps = RecipeVariantProps<typeof button> & export type ButtonProps = RecipeVariantProps<typeof button> &
RACButtonsProps & RACButtonsProps &
@@ -102,17 +103,21 @@ type LinkButtonProps = RecipeVariantProps<typeof button> & LinkProps & Tooltip
type ButtonOrLinkProps = ButtonProps | LinkButtonProps type ButtonOrLinkProps = ButtonProps | LinkButtonProps
export const Button = ({ tooltip, ...props }: ButtonOrLinkProps) => { export const Button = ({
tooltip,
tooltipType = 'instant',
...props
}: ButtonOrLinkProps) => {
const [variantProps, componentProps] = button.splitVariantProps(props) const [variantProps, componentProps] = button.splitVariantProps(props)
if ((props as LinkButtonProps).href !== undefined) { if ((props as LinkButtonProps).href !== undefined) {
return ( return (
<TooltipWrapper tooltip={tooltip}> <TooltipWrapper tooltip={tooltip} tooltipType={tooltipType}>
<Link className={button(variantProps)} {...componentProps} /> <Link className={button(variantProps)} {...componentProps} />
</TooltipWrapper> </TooltipWrapper>
) )
} }
return ( return (
<TooltipWrapper tooltip={tooltip}> <TooltipWrapper tooltip={tooltip} tooltipType={tooltipType}>
<RACButton <RACButton
className={button(variantProps)} className={button(variantProps)}
{...(componentProps as RACButtonsProps)} {...(componentProps as RACButtonsProps)}
@@ -123,18 +128,15 @@ export const Button = ({ tooltip, ...props }: ButtonOrLinkProps) => {
const TooltipWrapper = ({ const TooltipWrapper = ({
tooltip, tooltip,
tooltipType,
children, children,
}: { }: {
tooltip?: string
children: ReactNode children: ReactNode
}) => { } & Tooltip) => {
return tooltip ? ( return tooltip ? (
<TooltipTrigger delay={300}> <TooltipTrigger delay={tooltipType === 'instant' ? 300 : 1000}>
{children} {children}
<Tooltip> <Tooltip>{tooltip}</Tooltip>
<TooltipArrow />
{tooltip}
</Tooltip>
</TooltipTrigger> </TooltipTrigger>
) : ( ) : (
children children

View File

@@ -14,10 +14,20 @@ const ListItem = styled(Button, {
width: 'full', width: 'full',
borderRadius: 4, borderRadius: 4,
cursor: 'pointer', cursor: 'pointer',
color: 'primary', color: 'box.text',
border: '1px solid transparent',
'&[data-selected]': {
fontWeight: 'bold',
},
'&[data-focused]': {
color: 'primary.text',
backgroundColor: 'primary',
outline: 'none!',
},
'&[data-hovered]': { '&[data-hovered]': {
color: 'primary.subtle-text', color: 'primary.text',
backgroundColor: 'primary.subtle', backgroundColor: 'primary',
outline: 'none!',
}, },
}, },
}) })

View File

@@ -1,4 +1,9 @@
import { OverlayArrow, Tooltip as RACTooltip } from 'react-aria-components' import { type ReactNode } from 'react'
import {
OverlayArrow,
Tooltip as RACTooltip,
TooltipProps,
} from 'react-aria-components'
import { styled } from '@/styled-system/jsx' import { styled } from '@/styled-system/jsx'
/** /**
@@ -9,7 +14,7 @@ import { styled } from '@/styled-system/jsx'
* *
* Style taken from example at https://react-spectrum.adobe.com/react-aria/Tooltip.html * Style taken from example at https://react-spectrum.adobe.com/react-aria/Tooltip.html
*/ */
export const Tooltip = styled(RACTooltip, { const StyledTooltip = styled(RACTooltip, {
base: { base: {
boxShadow: '0 8px 20px rgba(0 0 0 / 0.1)', boxShadow: '0 8px 20px rgba(0 0 0 / 0.1)',
borderRadius: '4px', borderRadius: '4px',
@@ -18,7 +23,9 @@ export const Tooltip = styled(RACTooltip, {
forcedColorAdjust: 'none', forcedColorAdjust: 'none',
outline: 'none', outline: 'none',
padding: '2px 8px', padding: '2px 8px',
maxWidth: '150px', maxWidth: '200px',
textAlign: 'center',
fontSize: 14,
transform: 'translate3d(0, 0, 0)', transform: 'translate3d(0, 0, 0)',
'&[data-placement=top]': { '&[data-placement=top]': {
marginBottom: '8px', marginBottom: '8px',
@@ -63,7 +70,7 @@ const StyledOverlayArrow = styled(OverlayArrow, {
}, },
}) })
export const TooltipArrow = () => { const TooltipArrow = () => {
return ( return (
<StyledOverlayArrow> <StyledOverlayArrow>
<svg width={8} height={8} viewBox="0 0 8 8"> <svg width={8} height={8} viewBox="0 0 8 8">
@@ -72,3 +79,15 @@ export const TooltipArrow = () => {
</StyledOverlayArrow> </StyledOverlayArrow>
) )
} }
export const Tooltip = ({
children,
...props
}: Omit<TooltipProps, 'children'> & { children: ReactNode }) => {
return (
<StyledTooltip {...props}>
<TooltipArrow />
{children}
</StyledTooltip>
)
}