add: objectName in fav folder (#8785)

Closes: #8549 

It was quite complex to get this right. So, I went through Notion's
website to see how they implemented it.
Instead of using `display: none` or having a space reserved for the
Icon, I used clip-path & opacity trick to achieve the desired behaviour.
This maintains accessibility and helps in label or ObjectName to take
the full space.

Also, truncation now works for label & objectName as a whole instead of
separately, as seen in my previous PR.

**Caveats**

The only problem that now remains is not having
`NavigationDrawerAnimatedCollapseWrapper`. Having it on top of any text
or div won't let the flex or truncation property work.

[Screencast from 2024-11-28
13-37-31.webm](https://github.com/user-attachments/assets/29255cd2-3f15-4b1d-b1e1-c041c70052e5)

---------

Co-authored-by: ehconitin <nitinkoche03@gmail.com>
Co-authored-by: martmull <martmull@hotmail.fr>
This commit is contained in:
Harsh Singh 2024-12-19 16:21:03 +05:30 committed by GitHub
parent 65586a00cc
commit 784bc78ed0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 115 additions and 45 deletions

View File

@ -173,6 +173,7 @@ export const CurrentWorkspaceMemberFavorites = ({
itemComponent={ itemComponent={
<NavigationDrawerSubItem <NavigationDrawerSubItem
label={favorite.labelIdentifier} label={favorite.labelIdentifier}
objectName={favorite.objectNameSingular}
Icon={() => <FavoriteIcon favorite={favorite} />} Icon={() => <FavoriteIcon favorite={favorite} />}
to={favorite.link} to={favorite.link}
active={index === selectedFavoriteIndex} active={index === selectedFavoriteIndex}

View File

@ -59,6 +59,7 @@ export const CurrentWorkspaceMemberOrphanFavorites = () => {
accent="tertiary" accent="tertiary"
/> />
} }
objectName={favorite.objectNameSingular}
isDragging={isDragging} isDragging={isDragging}
/> />
</StyledOrphanFavoritesContainer> </StyledOrphanFavoritesContainer>

View File

@ -6,7 +6,7 @@ import { NavigationDrawerSubItemState } from '@/ui/navigation/navigation-drawer/
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded'; import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import isPropValid from '@emotion/is-prop-valid'; import isPropValid from '@emotion/is-prop-valid';
import { useTheme } from '@emotion/react'; import { css, useTheme } from '@emotion/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
@ -18,6 +18,7 @@ import {
TablerIconsProps, TablerIconsProps,
} from 'twenty-ui'; } from 'twenty-ui';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
import { capitalize } from '~/utils/string/capitalize';
const DEFAULT_INDENTATION_LEVEL = 1; const DEFAULT_INDENTATION_LEVEL = 1;
@ -26,6 +27,7 @@ export type NavigationDrawerItemIndentationLevel = 1 | 2;
export type NavigationDrawerItemProps = { export type NavigationDrawerItemProps = {
className?: string; className?: string;
label: string; label: string;
objectName?: string;
indentationLevel?: NavigationDrawerItemIndentationLevel; indentationLevel?: NavigationDrawerItemIndentationLevel;
subItemState?: NavigationDrawerSubItemState; subItemState?: NavigationDrawerSubItemState;
to?: string; to?: string;
@ -87,13 +89,15 @@ const StyledItem = styled('button', {
width: ${(props) => width: ${(props) =>
!props.isNavigationDrawerExpanded !props.isNavigationDrawerExpanded
? `${NAV_DRAWER_WIDTHS.menu.desktop.collapsed - 24}px` ? `calc(${NAV_DRAWER_WIDTHS.menu.desktop.collapsed}px - ${props.theme.spacing(6)})`
: '100%'}; : `calc(100% - ${props.theme.spacing(2)})`};
${({ isDragging }) => ${({ isDragging }) =>
isDragging && isDragging &&
` `
cursor: grabbing; cursor: grabbing;
`} `}
:hover { :hover {
background: ${({ theme }) => theme.background.transparent.light}; background: ${({ theme }) => theme.background.transparent.light};
color: ${(props) => color: ${(props) =>
@ -111,19 +115,37 @@ const StyledItem = styled('button', {
} }
`; `;
const StyledItemElementsContainer = styled.span` const StyledItemElementsContainer = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
gap: ${({ theme }) => theme.spacing(2)};
width: 100%; width: 100%;
`; `;
const StyledItemLabel = styled.span` const StyledLabelParent = styled.div`
font-weight: ${({ theme }) => theme.font.weight.medium}; display: flex;
align-items: center;
flex: 1 1 auto;
white-space: nowrap;
min-width: 0px;
overflow: hidden;
text-overflow: clip;
`;
const StyledEllipsisContainer = styled.div`
color: ${({ theme }) => theme.font.color.light};
overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
`; `;
const StyledItemLabel = styled.span`
color: ${({ theme }) => theme.font.color.secondary};
font-weight: ${({ theme }) => theme.font.weight.medium};
`;
const StyledItemObjectName = styled.span`
color: ${({ theme }) => theme.font.color.light};
font-weight: ${({ theme }) => theme.font.weight.regular};
`;
const StyledItemCount = styled.span` const StyledItemCount = styled.span`
align-items: center; align-items: center;
background-color: ${({ theme }) => theme.color.blue}; background-color: ${({ theme }) => theme.color.blue};
@ -149,7 +171,7 @@ const StyledKeyBoardShortcut = styled.span`
visibility: hidden; visibility: hidden;
`; `;
const StyledNavigationDrawerItemContainer = styled.span` const StyledNavigationDrawerItemContainer = styled.div`
display: flex; display: flex;
width: 100%; width: 100%;
`; `;
@ -158,30 +180,58 @@ const StyledSpacer = styled.span`
flex-grow: 1; flex-grow: 1;
`; `;
const StyledRightOptionsContainer = styled.div<{ const StyledIcon = styled.div`
isMobile: boolean; flex-shrink: 0;
active: boolean; flex-grow: 0;
}>` margin-right: ${({ theme }) => theme.spacing(2)};
margin-left: auto; `;
visibility: ${({ isMobile, active }) =>
isMobile || active ? 'visible' : 'hidden'}; const StyledRightOptionsContainer = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
:hover { flex-shrink: 0;
background: ${({ theme }) => theme.background.transparent.light}; flex-grow: 0;
}
width: ${({ theme }) => theme.spacing(6)};
height: ${({ theme }) => theme.spacing(6)}; height: ${({ theme }) => theme.spacing(6)};
border-radius: ${({ theme }) => theme.border.radius.sm}; border-radius: ${({ theme }) => theme.border.radius.sm};
`;
const visibleStateStyles = css`
clip-path: unset;
display: flex;
height: unset;
opacity: 1;
overflow: unset;
position: unset;
width: unset;
`;
const StyledRightOptionsVisbility = styled.div<{
isMobile: boolean;
active: boolean;
}>`
display: block;
opacity: 0;
transition: opacity 150ms;
position: absolute;
padding-left: ${({ theme }) => theme.spacing(2)};
overflow: hidden;
clip-path: inset(1px);
white-space: nowrap;
height: 1px;
width: 1px;
${({ isMobile, active }) => (isMobile || active) && visibleStateStyles}
.navigation-drawer-item:hover & { .navigation-drawer-item:hover & {
visibility: visible; ${visibleStateStyles}
} }
`; `;
export const NavigationDrawerItem = ({ export const NavigationDrawerItem = ({
className, className,
label, label,
objectName,
indentationLevel = DEFAULT_INDENTATION_LEVEL, indentationLevel = DEFAULT_INDENTATION_LEVEL,
Icon, Icon,
to, to,
@ -228,28 +278,41 @@ export const NavigationDrawerItem = ({
isNavigationDrawerExpanded={isNavigationDrawerExpanded} isNavigationDrawerExpanded={isNavigationDrawerExpanded}
isDragging={isDragging} isDragging={isDragging}
> >
{showBreadcrumb && (
<NavigationDrawerAnimatedCollapseWrapper>
<NavigationDrawerItemBreadcrumb state={subItemState} />
</NavigationDrawerAnimatedCollapseWrapper>
)}
<StyledItemElementsContainer> <StyledItemElementsContainer>
{Icon && ( {showBreadcrumb && (
<Icon <NavigationDrawerAnimatedCollapseWrapper>
style={{ minWidth: theme.icon.size.md }} <NavigationDrawerItemBreadcrumb state={subItemState} />
size={theme.icon.size.md} </NavigationDrawerAnimatedCollapseWrapper>
stroke={theme.icon.stroke.md}
color={
showBreadcrumb && !isSettingsPage && !isNavigationDrawerExpanded
? theme.font.color.light
: 'currentColor'
}
/>
)} )}
<NavigationDrawerAnimatedCollapseWrapper> {Icon && (
<StyledItemLabel>{label}</StyledItemLabel> <StyledIcon>
</NavigationDrawerAnimatedCollapseWrapper> <Icon
style={{ minWidth: theme.icon.size.md }}
size={theme.icon.size.md}
stroke={theme.icon.stroke.md}
color={
showBreadcrumb &&
!isSettingsPage &&
!isNavigationDrawerExpanded
? theme.font.color.light
: 'currentColor'
}
/>
</StyledIcon>
)}
<StyledLabelParent>
<StyledEllipsisContainer>
<StyledItemLabel>{label}</StyledItemLabel>
{objectName && (
<StyledItemObjectName>
{' · '}
{capitalize(objectName)}
</StyledItemObjectName>
)}
</StyledEllipsisContainer>
</StyledLabelParent>
<StyledSpacer /> <StyledSpacer />
@ -275,14 +338,17 @@ export const NavigationDrawerItem = ({
<NavigationDrawerAnimatedCollapseWrapper> <NavigationDrawerAnimatedCollapseWrapper>
{rightOptions && ( {rightOptions && (
<StyledRightOptionsContainer <StyledRightOptionsContainer
isMobile={isMobile}
active={active || false}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
}} }}
> >
{rightOptions} <StyledRightOptionsVisbility
isMobile={isMobile}
active={active || false}
>
{rightOptions}
</StyledRightOptionsVisbility>
</StyledRightOptionsContainer> </StyledRightOptionsContainer>
)} )}
</NavigationDrawerAnimatedCollapseWrapper> </NavigationDrawerAnimatedCollapseWrapper>

View File

@ -8,6 +8,7 @@ type NavigationDrawerSubItemProps = NavigationDrawerItemProps;
export const NavigationDrawerSubItem = ({ export const NavigationDrawerSubItem = ({
className, className,
label, label,
objectName,
Icon, Icon,
to, to,
onClick, onClick,
@ -24,6 +25,7 @@ export const NavigationDrawerSubItem = ({
<NavigationDrawerItem <NavigationDrawerItem
className={className} className={className}
label={label} label={label}
objectName={objectName}
indentationLevel={2} indentationLevel={2}
subItemState={subItemState} subItemState={subItemState}
Icon={Icon} Icon={Icon}