mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-22 19:41:53 +03:00
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:
parent
65586a00cc
commit
784bc78ed0
@ -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}
|
||||||
|
@ -59,6 +59,7 @@ export const CurrentWorkspaceMemberOrphanFavorites = () => {
|
|||||||
accent="tertiary"
|
accent="tertiary"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
objectName={favorite.objectNameSingular}
|
||||||
isDragging={isDragging}
|
isDragging={isDragging}
|
||||||
/>
|
/>
|
||||||
</StyledOrphanFavoritesContainer>
|
</StyledOrphanFavoritesContainer>
|
||||||
|
@ -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>
|
||||||
|
@ -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}
|
||||||
|
Loading…
Reference in New Issue
Block a user