Favorites Folders Fast Followups (#8920)

Fixes :
<img width="716" alt="Screenshot 2024-12-06 at 3 45 41 PM"
src="https://github.com/user-attachments/assets/61fdf355-0d0a-4ed7-befa-ada23341a58f">

Fixes: Reduce menu width to 160px and it should appear below three dots
<img width="394" alt="Screenshot 2024-12-06 at 3 46 49 PM"
src="https://github.com/user-attachments/assets/b1266f83-9b6f-445b-9409-d7f691776bd0">

Fixes: The right margin should be 2px
<img width="1134" alt="Screenshot 2024-12-06 at 3 47 45 PM"
src="https://github.com/user-attachments/assets/b6dd857c-6575-418d-8e32-64cd4e5d4e85">

Fixes:
Requirement: Clicking the heart Icon should put the record as favorite.
It shouldn't open the menu on first click. It should only on second
click, when the record is already a favorite.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
nitin
2024-12-17 16:45:36 +05:30
committed by GitHub
parent ac2894c87c
commit c63842925f
5 changed files with 63 additions and 87 deletions

View File

@ -1,4 +1,3 @@
import { useTheme } from '@emotion/react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { useRecoilState, useRecoilValue } from 'recoil'; import { useRecoilState, useRecoilValue } from 'recoil';
import { import {
@ -26,15 +25,19 @@ import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/compo
import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle'; import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle';
import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection'; import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import styled from '@emotion/styled';
import { DragStart, DropResult, ResponderProvided } from '@hello-pangea/dnd'; import { DragStart, DropResult, ResponderProvided } from '@hello-pangea/dnd';
import { useState } from 'react'; import { useState } from 'react';
const StyledOrphanFavoritesContainer = styled.div`
margin-bottom: ${({ theme }) => theme.betweenSiblingsGap};
`;
export const CurrentWorkspaceMemberFavoritesFolders = () => { export const CurrentWorkspaceMemberFavoritesFolders = () => {
const [isDragging, setIsDragging] = useState(false); const [isDragging, setIsDragging] = useState(false);
const currentPath = useLocation().pathname; const currentPath = useLocation().pathname;
const currentViewPath = useLocation().pathname + useLocation().search; const currentViewPath = useLocation().pathname + useLocation().search;
const theme = useTheme();
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const { sortedFavorites: favorites } = useFavorites(); const { sortedFavorites: favorites } = useFavorites();
const { deleteFavorite } = useDeleteFavorite(); const { deleteFavorite } = useDeleteFavorite();
@ -98,12 +101,13 @@ export const CurrentWorkspaceMemberFavoritesFolders = () => {
onClick={toggleNavigationSection} onClick={toggleNavigationSection}
rightIcon={ rightIcon={
isFavoriteFolderEnabled ? ( isFavoriteFolderEnabled ? (
<IconFolderPlus size={theme.icon.size.sm} /> <LightIconButton
Icon={IconFolderPlus}
onClick={toggleNewFolder}
accent="tertiary"
/>
) : undefined ) : undefined
} }
onRightIconClick={
isFavoriteFolderEnabled ? toggleNewFolder : undefined
}
/> />
</NavigationDrawerAnimatedCollapseWrapper> </NavigationDrawerAnimatedCollapseWrapper>
@ -126,26 +130,28 @@ export const CurrentWorkspaceMemberFavoritesFolders = () => {
index={index} index={index}
isInsideScrollableContainer={true} isInsideScrollableContainer={true}
itemComponent={ itemComponent={
<NavigationDrawerItem <StyledOrphanFavoritesContainer>
key={favorite.id} <NavigationDrawerItem
className="navigation-drawer-item" key={favorite.id}
label={favorite.labelIdentifier} className="navigation-drawer-item"
Icon={() => <FavoriteIcon favorite={favorite} />} label={favorite.labelIdentifier}
active={isLocationMatchingFavorite( Icon={() => <FavoriteIcon favorite={favorite} />}
currentPath, active={isLocationMatchingFavorite(
currentViewPath, currentPath,
favorite, currentViewPath,
)} favorite,
to={favorite.link} )}
rightOptions={ to={favorite.link}
<LightIconButton rightOptions={
Icon={IconHeartOff} <LightIconButton
onClick={() => deleteFavorite(favorite.id)} Icon={IconHeartOff}
accent="tertiary" onClick={() => deleteFavorite(favorite.id)}
/> accent="tertiary"
} />
isDragging={isDragging} }
/> isDragging={isDragging}
/>
</StyledOrphanFavoritesContainer>
} }
/> />
))} ))}

View File

@ -1,10 +1,14 @@
import { FavoriteFolderHotkeyScope } from '@/favorites/constants/FavoriteFolderRightIconDropdownHotkeyScope'; import { FavoriteFolderHotkeyScope } from '@/favorites/constants/FavoriteFolderRightIconDropdownHotkeyScope';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { IconDotsVertical, IconPencil, IconTrash, MenuItem } from 'twenty-ui'; import {
IconDotsVertical,
IconPencil,
IconTrash,
LightIconButton,
MenuItem,
} from 'twenty-ui';
type FavoriteFolderNavigationDrawerItemDropdownProps = { type FavoriteFolderNavigationDrawerItemDropdownProps = {
folderId: string; folderId: string;
@ -13,24 +17,12 @@ type FavoriteFolderNavigationDrawerItemDropdownProps = {
closeDropdown: () => void; closeDropdown: () => void;
}; };
const StyledIconContainer = styled.div`
align-items: center;
background: transparent;
height: 24px;
width: 24px;
justify-content: center;
transition: background 0.1s ease;
display: flex;
`;
export const FavoriteFolderNavigationDrawerItemDropdown = ({ export const FavoriteFolderNavigationDrawerItemDropdown = ({
folderId, folderId,
onRename, onRename,
onDelete, onDelete,
closeDropdown, closeDropdown,
}: FavoriteFolderNavigationDrawerItemDropdownProps) => { }: FavoriteFolderNavigationDrawerItemDropdownProps) => {
const theme = useTheme();
const handleRename = () => { const handleRename = () => {
onRename(); onRename();
closeDropdown(); closeDropdown();
@ -49,15 +41,9 @@ export const FavoriteFolderNavigationDrawerItemDropdown = ({
}} }}
data-select-disable data-select-disable
clickableComponent={ clickableComponent={
<StyledIconContainer> <LightIconButton Icon={IconDotsVertical} accent="tertiary" />
<IconDotsVertical
size={theme.icon.size.sm}
color={theme.font.color.tertiary}
/>
</StyledIconContainer>
} }
dropdownPlacement="right" dropdownPlacement="bottom-start"
dropdownOffset={{ y: -15 }}
dropdownComponents={ dropdownComponents={
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<MenuItem <MenuItem

View File

@ -77,7 +77,7 @@ const StyledItem = styled('button', {
padding-bottom: ${({ theme }) => theme.spacing(1)}; padding-bottom: ${({ theme }) => theme.spacing(1)};
padding-left: ${({ theme }) => theme.spacing(1)}; padding-left: ${({ theme }) => theme.spacing(1)};
padding-right: ${({ theme }) => theme.spacing(1)}; padding-right: ${({ theme }) => theme.spacing(0.5)};
padding-top: ${({ theme }) => theme.spacing(1)}; padding-top: ${({ theme }) => theme.spacing(1)};
margin-top: ${({ indentationLevel }) => margin-top: ${({ indentationLevel }) =>

View File

@ -17,7 +17,10 @@ const StyledTitle = styled.div`
font-size: ${({ theme }) => theme.font.size.xs}; font-size: ${({ theme }) => theme.font.size.xs};
font-weight: ${({ theme }) => theme.font.weight.semiBold}; font-weight: ${({ theme }) => theme.font.weight.semiBold};
height: ${({ theme }) => theme.spacing(5)}; height: ${({ theme }) => theme.spacing(5)};
padding: ${({ theme }) => theme.spacing(1)}; padding-left: ${({ theme }) => theme.spacing(1)};
padding-right: ${({ theme }) => theme.spacing(0.5)};
padding-top: ${({ theme }) => theme.spacing(1)};
padding-bottom: ${({ theme }) => theme.spacing(1)};
justify-content: space-between; justify-content: space-between;
&:hover { &:hover {
@ -36,38 +39,21 @@ type StyledRightIconProps = {
const StyledRightIcon = styled.div<StyledRightIconProps>` const StyledRightIcon = styled.div<StyledRightIconProps>`
cursor: pointer; cursor: pointer;
margin-left: ${({ theme }) => theme.spacing(2)};
transition: opacity 150ms ease-in-out;
opacity: ${({ isMobile }) => (isMobile ? 1 : 0)}; opacity: ${({ isMobile }) => (isMobile ? 1 : 0)};
display: flex;
align-items: center;
justify-content: center;
border-radius: ${({ theme }) => theme.border.radius.sm};
width: ${({ theme }) => theme.spacing(5)};
height: ${({ theme }) => theme.spacing(5)};
:hover {
background: ${({ theme }) => theme.background.transparent.light};
}
.section-title-container:hover & { .section-title-container:hover & {
opacity: 1; opacity: 1;
} }
&:active {
cursor: pointer;
}
`; `;
type NavigationDrawerSectionTitleProps = { type NavigationDrawerSectionTitleProps = {
onClick?: () => void; onClick?: () => void;
onRightIconClick?: () => void;
label: string; label: string;
rightIcon?: React.ReactNode; rightIcon?: React.ReactNode;
}; };
export const NavigationDrawerSectionTitle = ({ export const NavigationDrawerSectionTitle = ({
onClick, onClick,
onRightIconClick,
label, label,
rightIcon, rightIcon,
}: NavigationDrawerSectionTitleProps) => { }: NavigationDrawerSectionTitleProps) => {
@ -85,24 +71,15 @@ export const NavigationDrawerSectionTitle = ({
} }
}; };
const handleRightIconClick = (e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
if (isDefined(onRightIconClick)) {
onRightIconClick();
}
};
if (loading && isDefined(currentUser)) { if (loading && isDefined(currentUser)) {
return <NavigationDrawerSectionTitleSkeletonLoader />; return <NavigationDrawerSectionTitleSkeletonLoader />;
} }
return ( return (
<StyledTitle className="section-title-container" onClick={handleTitleClick}> <StyledTitle className="section-title-container">
<StyledLabel>{label}</StyledLabel> <StyledLabel onClick={handleTitleClick}>{label}</StyledLabel>
{rightIcon && ( {rightIcon && (
<StyledRightIcon isMobile={isMobile} onClick={handleRightIconClick}> <StyledRightIcon isMobile={isMobile}>{rightIcon}</StyledRightIcon>
{rightIcon}
</StyledRightIcon>
)} )}
</StyledTitle> </StyledTitle>
); );

View File

@ -34,13 +34,20 @@ export const RecordShowPageBaseHeader = ({
{!isMobile && ( {!isMobile && (
<> <>
{isFavoriteFolderEnabled ? ( {isFavoriteFolderEnabled ? (
<PageFavoriteFoldersDropdown isFavorite ? (
key={FAVORITE_FOLDER_PICKER_DROPDOWN_ID} <PageFavoriteFoldersDropdown
dropdownId={FAVORITE_FOLDER_PICKER_DROPDOWN_ID} key={FAVORITE_FOLDER_PICKER_DROPDOWN_ID}
isFavorite={isFavorite} dropdownId={FAVORITE_FOLDER_PICKER_DROPDOWN_ID}
record={record} isFavorite={isFavorite}
objectNameSingular={objectNameSingular} record={record}
/> objectNameSingular={objectNameSingular}
/>
) : (
<PageFavoriteButton
isFavorite={isFavorite}
onClick={handleFavoriteButtonClick}
/>
)
) : ( ) : (
<PageFavoriteButton <PageFavoriteButton
isFavorite={isFavorite} isFavorite={isFavorite}