mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-23 03:51:36 +03:00
Fix: Replace styled logo with Avatar component for workspace logo in NavigationDrawerHeader (#9093)
This PR addresses issue #9042 - Replaced the styled logo with the `Avatar` component. - `Avatar` now handles the case when no `logo` is uploaded by using the workspace name's first character as the `placeholder`. - This ensures a consistent fallback when the `logo` is undefined. --------- Co-authored-by: guillim <guigloo@msn.com> Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
parent
07bde4883e
commit
fb8d193238
@ -14,22 +14,12 @@ import { useTheme } from '@emotion/react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
import { getImageAbsoluteURI } from 'twenty-shared';
|
|
||||||
import {
|
import {
|
||||||
|
Avatar,
|
||||||
IconChevronDown,
|
IconChevronDown,
|
||||||
MenuItemSelectAvatar,
|
MenuItemSelectAvatar,
|
||||||
UndecoratedLink,
|
UndecoratedLink,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
|
||||||
|
|
||||||
const StyledLogo = styled.div<{ logo: string }>`
|
|
||||||
background: url(${({ logo }) => logo});
|
|
||||||
background-position: center;
|
|
||||||
background-size: cover;
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.xs};
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledContainer = styled.div<{ isNavigationDrawerExpanded: boolean }>`
|
const StyledContainer = styled.div<{ isNavigationDrawerExpanded: boolean }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -102,13 +92,9 @@ export const MultiWorkspaceDropdownButton = ({
|
|||||||
data-testid="workspace-dropdown"
|
data-testid="workspace-dropdown"
|
||||||
isNavigationDrawerExpanded={isNavigationDrawerExpanded}
|
isNavigationDrawerExpanded={isNavigationDrawerExpanded}
|
||||||
>
|
>
|
||||||
<StyledLogo
|
<Avatar
|
||||||
logo={
|
placeholder={currentWorkspace?.displayName || ''}
|
||||||
getImageAbsoluteURI({
|
avatarUrl={currentWorkspace?.logo ?? DEFAULT_WORKSPACE_LOGO}
|
||||||
imageUrl: currentWorkspace?.logo ?? '',
|
|
||||||
baseUrl: REACT_APP_SERVER_BASE_URL,
|
|
||||||
}) ?? ''
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<NavigationDrawerAnimatedCollapseWrapper>
|
<NavigationDrawerAnimatedCollapseWrapper>
|
||||||
<StyledLabel>{currentWorkspace?.displayName ?? ''}</StyledLabel>
|
<StyledLabel>{currentWorkspace?.displayName ?? ''}</StyledLabel>
|
||||||
@ -135,13 +121,9 @@ export const MultiWorkspaceDropdownButton = ({
|
|||||||
<MenuItemSelectAvatar
|
<MenuItemSelectAvatar
|
||||||
text={workspace.displayName ?? '(No name)'}
|
text={workspace.displayName ?? '(No name)'}
|
||||||
avatar={
|
avatar={
|
||||||
<StyledLogo
|
<Avatar
|
||||||
logo={
|
placeholder={workspace.displayName || ''}
|
||||||
getImageAbsoluteURI({
|
avatarUrl={workspace.logo ?? DEFAULT_WORKSPACE_LOGO}
|
||||||
imageUrl: workspace.logo ?? DEFAULT_WORKSPACE_LOGO,
|
|
||||||
baseUrl: REACT_APP_SERVER_BASE_URL,
|
|
||||||
}) ?? ''
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
selected={currentWorkspace?.id === workspace.id}
|
selected={currentWorkspace?.id === workspace.id}
|
||||||
|
@ -7,11 +7,11 @@ import { DEFAULT_WORKSPACE_LOGO } from '@/ui/navigation/navigation-drawer/consta
|
|||||||
import { DEFAULT_WORKSPACE_NAME } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceName';
|
import { DEFAULT_WORKSPACE_NAME } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceName';
|
||||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||||
|
|
||||||
|
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
|
||||||
import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper';
|
import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper';
|
||||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { Avatar } from 'twenty-ui';
|
||||||
import { NavigationDrawerCollapseButton } from './NavigationDrawerCollapseButton';
|
import { NavigationDrawerCollapseButton } from './NavigationDrawerCollapseButton';
|
||||||
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -19,20 +19,12 @@ const StyledContainer = styled.div`
|
|||||||
height: ${({ theme }) => theme.spacing(8)};
|
height: ${({ theme }) => theme.spacing(8)};
|
||||||
user-select: none;
|
user-select: none;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledSingleWorkspaceContainer = styled(StyledContainer)`
|
const StyledSingleWorkspaceContainer = styled(StyledContainer)`
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
padding: ${({ theme }) => theme.spacing(1)};
|
padding: ${({ theme }) => theme.spacing(1)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledLogo = styled.div<{ logo: string }>`
|
|
||||||
background: url(${({ logo }) => logo});
|
|
||||||
background-position: center;
|
|
||||||
background-size: cover;
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.xs};
|
|
||||||
height: 16px;
|
|
||||||
width: 16px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledName = styled.div`
|
const StyledName = styled.div`
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
@ -75,9 +67,7 @@ export const NavigationDrawerHeader = ({
|
|||||||
<MultiWorkspaceDropdownButton workspaces={workspaces} />
|
<MultiWorkspaceDropdownButton workspaces={workspaces} />
|
||||||
) : (
|
) : (
|
||||||
<StyledSingleWorkspaceContainer>
|
<StyledSingleWorkspaceContainer>
|
||||||
<StyledLogo
|
<Avatar placeholder={name} avatarUrl={logo} />
|
||||||
logo={isNonEmptyString(logo) ? logo : DEFAULT_WORKSPACE_LOGO}
|
|
||||||
/>
|
|
||||||
<NavigationDrawerAnimatedCollapseWrapper>
|
<NavigationDrawerAnimatedCollapseWrapper>
|
||||||
<StyledName>{name}</StyledName>
|
<StyledName>{name}</StyledName>
|
||||||
</NavigationDrawerAnimatedCollapseWrapper>
|
</NavigationDrawerAnimatedCollapseWrapper>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { workspacePublicDataState } from '@/auth/states/workspacePublicDataState';
|
import { workspacePublicDataState } from '@/auth/states/workspacePublicDataState';
|
||||||
|
import { DEFAULT_WORKSPACE_LOGO } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceLogo';
|
||||||
import { Helmet } from 'react-helmet-async';
|
import { Helmet } from 'react-helmet-async';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { getImageAbsoluteURI } from 'twenty-shared';
|
import { getImageAbsoluteURI } from 'twenty-shared';
|
||||||
@ -16,7 +17,7 @@ export const PageFavicon = () => {
|
|||||||
getImageAbsoluteURI({
|
getImageAbsoluteURI({
|
||||||
imageUrl: workspacePublicData.logo,
|
imageUrl: workspacePublicData.logo,
|
||||||
baseUrl: REACT_APP_SERVER_BASE_URL,
|
baseUrl: REACT_APP_SERVER_BASE_URL,
|
||||||
}) ?? ''
|
}) ?? DEFAULT_WORKSPACE_LOGO
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { styled } from '@linaria/react';
|
import { styled } from '@linaria/react';
|
||||||
import { isNonEmptyString, isUndefined } from '@sniptt/guards';
|
import { isNonEmptyString, isNull, isUndefined } from '@sniptt/guards';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
@ -90,12 +90,10 @@ export const Avatar = ({
|
|||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const noAvatarUrl = !isNonEmptyString(avatarImageURI);
|
|
||||||
|
|
||||||
const placeholderChar = placeholder?.[0]?.toLocaleUpperCase();
|
const placeholderChar = placeholder?.[0]?.toLocaleUpperCase();
|
||||||
|
|
||||||
const showPlaceholder =
|
const showPlaceholder =
|
||||||
noAvatarUrl || invalidAvatarUrls.includes(avatarImageURI);
|
isNull(avatarImageURI) || invalidAvatarUrls.includes(avatarImageURI);
|
||||||
|
|
||||||
const handleImageError = () => {
|
const handleImageError = () => {
|
||||||
if (isNonEmptyString(avatarImageURI)) {
|
if (isNonEmptyString(avatarImageURI)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user