Skip to content

Commit

Permalink
Animated the Sidebar Objects Tree view opening/closing (#9287)
Browse files Browse the repository at this point in the history
  • Loading branch information
ehconitin and FelixMalfait authored Jan 8, 2025
1 parent bec7911 commit 973ec83
Show file tree
Hide file tree
Showing 19 changed files with 419 additions and 333 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { createPortal } from 'react-dom';
import { useLocation } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import {
AnimatedExpandableContainer,
IconFolder,
IconFolderOpen,
IconHeartOff,
Expand Down Expand Up @@ -158,7 +159,12 @@ export const CurrentWorkspaceMemberFavorites = ({
</FavoritesDroppable>
)}

{isOpen && (
<AnimatedExpandableContainer
isExpanded={isOpen}
dimension="height"
mode="fit-content"
containAnimation
>
<Droppable droppableId={`folder-${folder.folderId}`}>
{(provided) => (
<div
Expand Down Expand Up @@ -202,7 +208,7 @@ export const CurrentWorkspaceMemberFavorites = ({
</div>
)}
</Droppable>
)}
</AnimatedExpandableContainer>
</NavigationDrawerItemsCollapsableContainer>

{createPortal(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-dr
import { View } from '@/views/types/View';
import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews';
import { useLocation } from 'react-router-dom';
import { useIcons } from 'twenty-ui';
import { AnimatedExpandableContainer, useIcons } from 'twenty-ui';

export type NavigationDrawerItemForObjectMetadataItemProps = {
objectMetadataItem: ObjectMetadataItem;
Expand Down Expand Up @@ -66,8 +66,14 @@ export const NavigationDrawerItemForObjectMetadataItem = ({
Icon={getIcon(objectMetadataItem.icon)}
active={isActive}
/>
{shouldSubItemsBeDisplayed &&
sortedObjectMetadataViews.map((view, index) => (

<AnimatedExpandableContainer
isExpanded={shouldSubItemsBeDisplayed}
dimension="height"
mode="fit-content"
containAnimation
>
{sortedObjectMetadataViews.map((view, index) => (
<NavigationDrawerSubItem
label={view.name}
to={`/objects/${objectMetadataItem.namePlural}?view=${view.id}`}
Expand All @@ -81,6 +87,7 @@ export const NavigationDrawerItemForObjectMetadataItem = ({
key={view.id}
/>
))}
</AnimatedExpandableContainer>
</NavigationDrawerItemsCollapsableContainer>
);
};
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
import { useExpandedAnimation } from '@/settings/hooks/useExpandedAnimation';
import { ADVANCED_SETTINGS_ANIMATION_DURATION } from '@/settings/constants/AdvancedSettingsAnimationDurations';
import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState';
import styled from '@emotion/styled';
import { AnimatePresence, motion } from 'framer-motion';
import { useRecoilValue } from 'recoil';
import { IconPoint, MAIN_COLORS } from 'twenty-ui';
import { AnimatedExpandableContainer, IconPoint, MAIN_COLORS } from 'twenty-ui';

const StyledAdvancedWrapper = styled.div`
position: relative;
width: 100%;
`;

const StyledIconContainer = styled.div`
const StyledIconContainer = styled.div<{ navigationDrawerItem: boolean }>`
display: flex;
height: 100%;
left: ${({ theme }) => theme.spacing(-4)};
position: absolute;
top: 0;
${({ navigationDrawerItem, theme }) => {
if (navigationDrawerItem) {
return `
height: 100%;
left: ${theme.spacing(-5)};
align-items: center;
`;
}
return `
left: ${theme.spacing(-4)};
top: ${theme.spacing(1)};
`;
}}
`;

const StyledContent = styled.div`
width: 100%;
`;

const StyledIconPoint = styled(IconPoint)`
margin-right: 0;
`;
Expand All @@ -29,43 +40,37 @@ type AdvancedSettingsWrapperProps = {
children: React.ReactNode;
dimension?: 'width' | 'height';
hideIcon?: boolean;
navigationDrawerItem?: boolean;
};

export const AdvancedSettingsWrapper = ({
children,
dimension = 'height',
hideIcon = false,
navigationDrawerItem = false,
}: AdvancedSettingsWrapperProps) => {
const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState);
const { contentRef, motionAnimationVariants } = useExpandedAnimation(
isAdvancedModeEnabled,
dimension,
);

return (
<AnimatePresence>
{isAdvancedModeEnabled && (
<motion.div
ref={contentRef}
initial="initial"
animate="animate"
exit="exit"
variants={motionAnimationVariants}
>
<StyledAdvancedWrapper>
{!hideIcon && (
<StyledIconContainer>
<StyledIconPoint
size={12}
color={MAIN_COLORS.yellow}
fill={MAIN_COLORS.yellow}
/>
</StyledIconContainer>
)}
<StyledContent>{children}</StyledContent>
</StyledAdvancedWrapper>
</motion.div>
)}
</AnimatePresence>
<AnimatedExpandableContainer
isExpanded={isAdvancedModeEnabled}
dimension={dimension}
animationDurations={ADVANCED_SETTINGS_ANIMATION_DURATION}
mode="scroll-height"
containAnimation={false}
>
<StyledAdvancedWrapper>
{!hideIcon && (
<StyledIconContainer navigationDrawerItem={navigationDrawerItem}>
<StyledIconPoint
size={12}
color={MAIN_COLORS.yellow}
fill={MAIN_COLORS.yellow}
/>
</StyledIconContainer>
)}
<StyledContent>{children}</StyledContent>
</StyledAdvancedWrapper>
</AnimatedExpandableContainer>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,18 @@ import {
IconHierarchy2,
IconKey,
IconMail,
IconPoint,
IconRocket,
IconServer,
IconSettings,
IconUserCircle,
IconUsers,
MAIN_COLORS,
} from 'twenty-ui';

import { useAuth } from '@/auth/hooks/useAuth';
import { currentUserState } from '@/auth/states/currentUserState';
import { billingState } from '@/client-config/states/billingState';
import { AdvancedSettingsWrapper } from '@/settings/components/AdvancedSettingsWrapper';
import { SettingsNavigationDrawerItem } from '@/settings/components/SettingsNavigationDrawerItem';
import { useExpandedAnimation } from '@/settings/hooks/useExpandedAnimation';
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { SettingsPath } from '@/types/SettingsPath';
import {
Expand All @@ -35,11 +33,8 @@ import {
import { NavigationDrawerItemGroup } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemGroup';
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle';
import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState';
import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import styled from '@emotion/styled';
import { AnimatePresence, motion } from 'framer-motion';
import { matchPath, resolvePath, useLocation } from 'react-router-dom';
import { FeatureFlagKey } from '~/generated/graphql';

Expand All @@ -51,32 +46,7 @@ type SettingsNavigationItem = {
matchSubPages?: boolean;
};

const StyledIconContainer = styled.div`
position: absolute;
left: ${({ theme }) => theme.spacing(-5)};
height: 100%;
display: flex;
align-items: center;
`;

const StyledContainer = styled.div`
position: relative;
`;

const StyledIconPoint = styled(IconPoint)`
margin-right: 0;
`;

export const SettingsNavigationDrawerItems = () => {
const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState);
const {
contentRef: securityRef,
motionAnimationVariants: securityAnimationVariants,
} = useExpandedAnimation(isAdvancedModeEnabled);
const {
contentRef: developersRef,
motionAnimationVariants: developersAnimationVariants,
} = useExpandedAnimation(isAdvancedModeEnabled);
const { signOut } = useAuth();

const billing = useRecoilValue(billingState);
Expand Down Expand Up @@ -198,81 +168,36 @@ export const SettingsNavigationDrawerItems = () => {
Icon={IconCode}
/>
)}
<AnimatePresence>
{isAdvancedModeEnabled && (
<motion.div
ref={securityRef}
initial="initial"
animate="animate"
exit="exit"
variants={securityAnimationVariants}
>
<StyledContainer>
<StyledIconContainer>
<StyledIconPoint
size={12}
color={MAIN_COLORS.yellow}
fill={MAIN_COLORS.yellow}
/>
</StyledIconContainer>
<SettingsNavigationDrawerItem
label="Security"
path={SettingsPath.Security}
Icon={IconKey}
/>
</StyledContainer>
</motion.div>
)}
</AnimatePresence>
<AdvancedSettingsWrapper navigationDrawerItem={true}>
<SettingsNavigationDrawerItem
label="Security"
path={SettingsPath.Security}
Icon={IconKey}
/>
</AdvancedSettingsWrapper>
</NavigationDrawerSection>

<AnimatePresence>
{isAdvancedModeEnabled && (
<motion.div
ref={developersRef}
initial="initial"
animate="animate"
exit="exit"
variants={developersAnimationVariants}
>
<NavigationDrawerSection>
<NavigationDrawerSectionTitle label="Developers" />
<StyledContainer>
<StyledIconContainer>
<StyledIconPoint
size={12}
color={MAIN_COLORS.yellow}
fill={MAIN_COLORS.yellow}
/>
</StyledIconContainer>

<SettingsNavigationDrawerItem
label="API & Webhooks"
path={SettingsPath.Developers}
Icon={IconCode}
/>
</StyledContainer>
{isFunctionSettingsEnabled && (
<StyledContainer>
<StyledIconContainer>
<StyledIconPoint
size={12}
color={MAIN_COLORS.yellow}
fill={MAIN_COLORS.yellow}
/>
</StyledIconContainer>

<SettingsNavigationDrawerItem
label="Functions"
path={SettingsPath.ServerlessFunctions}
Icon={IconFunction}
/>
</StyledContainer>
)}
</NavigationDrawerSection>
</motion.div>
<NavigationDrawerSection>
<AdvancedSettingsWrapper hideIcon>
<NavigationDrawerSectionTitle label="Developers" />
</AdvancedSettingsWrapper>
<AdvancedSettingsWrapper navigationDrawerItem={true}>
<SettingsNavigationDrawerItem
label="API & Webhooks"
path={SettingsPath.Developers}
Icon={IconCode}
/>
</AdvancedSettingsWrapper>
{isFunctionSettingsEnabled && (
<AdvancedSettingsWrapper navigationDrawerItem={true}>
<SettingsNavigationDrawerItem
label="Functions"
path={SettingsPath.ServerlessFunctions}
Icon={IconFunction}
/>
</AdvancedSettingsWrapper>
)}
</AnimatePresence>
</NavigationDrawerSection>
<NavigationDrawerSection>
<NavigationDrawerSectionTitle label="Other" />
{isAdminPageEnabled && (
Expand Down
Loading

0 comments on commit 973ec83

Please sign in to comment.