feat(sidebar): distinguish guest users visually

This change adds a little guest icon next to the active indicator
showing that a user is not logged-in.
Furthermore, the active indicator now has a tooltip explaining it.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
Erik Michelson 2023-10-09 06:19:01 +02:00
parent a0a0547157
commit f6780c44c4
4 changed files with 37 additions and 37 deletions

View file

@ -231,7 +231,10 @@
"infoToc": "Structure your note with headings to see a table-of-contents here.", "infoToc": "Structure your note with headings to see a table-of-contents here.",
"onlineStatus": { "onlineStatus": {
"online": "Online", "online": "Online",
"you": "(You)" "you": "(You)",
"guestUser": "This is a guest user",
"active": "This user is active",
"inactive": "This user has been inactive for some time"
}, },
"error": { "error": {
"noPermission": { "noPermission": {

View file

@ -9,6 +9,8 @@
border-radius: $indicator-size; border-radius: $indicator-size;
height: $indicator-size; height: $indicator-size;
width: $indicator-size; width: $indicator-size;
margin: 0 calc($indicator-size / 2);
display: block;
&.active { &.active {
background-color: #5cb85c; background-color: #5cb85c;
@ -18,11 +20,3 @@
background-color: #d20000; background-color: #d20000;
} }
} }
.active-indicator-container {
height: 100%;
display: flex;
flex: 0 0 20px;
align-items: center;
justify-content: center;
}

View file

@ -5,6 +5,7 @@
*/ */
import styles from './active-indicator.module.scss' import styles from './active-indicator.module.scss'
import React from 'react' import React from 'react'
import { useTranslatedText } from '../../../../../hooks/common/use-translated-text'
export interface ActiveIndicatorProps { export interface ActiveIndicatorProps {
active: boolean active: boolean
@ -16,9 +17,13 @@ export interface ActiveIndicatorProps {
* @param status The state of the indicator to render * @param status The state of the indicator to render
*/ */
export const ActiveIndicator: React.FC<ActiveIndicatorProps> = ({ active }) => { export const ActiveIndicator: React.FC<ActiveIndicatorProps> = ({ active }) => {
const textActive = useTranslatedText('editor.onlineStatus.active')
const textInactive = useTranslatedText('editor.onlineStatus.inactive')
return ( return (
<div className={styles['active-indicator-container']}> <span
<span className={`${styles['activeIndicator']} ${active ? styles.active : styles.inactive}`} /> title={active ? textActive : textInactive}
</div> className={`${styles['activeIndicator']} ${active ? styles.active : styles.inactive}`}
/>
) )
} }

View file

@ -10,6 +10,9 @@ import { ActiveIndicator } from '../active-indicator'
import styles from './user-line.module.scss' import styles from './user-line.module.scss'
import React, { useMemo } from 'react' import React, { useMemo } from 'react'
import { Trans, useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
import { ShowIf } from '../../../../../common/show-if/show-if'
import { Incognito as IconIncognito } from 'react-bootstrap-icons'
import { useTranslatedText } from '../../../../../../hooks/common/use-translated-text'
export interface UserLineProps { export interface UserLineProps {
username: string | null username: string | null
@ -30,37 +33,32 @@ export interface UserLineProps {
*/ */
export const UserLine: React.FC<UserLineProps> = ({ username, displayName, active, own = false, color }) => { export const UserLine: React.FC<UserLineProps> = ({ username, displayName, active, own = false, color }) => {
useTranslation() useTranslation()
const guestUserTitle = useTranslatedText('editor.onlineStatus.guestUser')
const avatar = useMemo(() => { const avatar = useMemo(() => {
if (username) { return username ? (
return ( <UserAvatarForUsername username={username} additionalClasses={'flex-fill overflow-hidden px-2 text-nowrap'} />
<UserAvatarForUsername ) : (
username={username} <UserAvatar displayName={displayName} additionalClasses={'flex-fill overflow-hidden px-2 text-nowrap'} />
additionalClasses={'flex-fill overflow-hidden px-2 text-nowrap w-100'} )
/>
)
} else {
return (
<UserAvatar displayName={displayName} additionalClasses={'flex-fill overflow-hidden px-2 text-nowrap w-100'} />
)
}
}, [displayName, username]) }, [displayName, username])
return ( return (
<div className={'d-flex align-items-center h-100 w-100'}> <div className={'d-flex h-100 w-100'}>
<div <div className={`${styles['user-line-color-indicator']} ${createCursorCssClass(color)}`} />
className={`d-inline-flex align-items-bottom ${styles['user-line-color-indicator']} ${createCursorCssClass(
color
)}`}
/>
{avatar} {avatar}
{own ? ( <div className={'ms-auto d-flex align-items-center gap-1 h-100'}>
<span className={'px-1'}> <ShowIf condition={!username}>
<Trans i18nKey={'editor.onlineStatus.you'}></Trans> <IconIncognito title={guestUserTitle} size={'16px'} className={'text-muted'} />
</span> </ShowIf>
) : ( {own ? (
<ActiveIndicator active={active} /> <span className={'px-1'}>
)} <Trans i18nKey={'editor.onlineStatus.you'}></Trans>
</span>
) : (
<ActiveIndicator active={active} />
)}
</div>
</div> </div>
) )
} }