Collapsible menu (#5846)
A mini PR to discuss with @Bonapara tomorrow Separating remote objects from others and making the menu collapsible (style to be changed) <img width="225" alt="Screenshot 2024-06-12 at 23 25 59" src="https://github.com/twentyhq/twenty/assets/6399865/b4b69d36-6770-43a2-a5e8-bfcdf0a629ea"> Biggest issue is we don't use local storage today so the collapsed state gets lost. I see we have localStorageEffect with recoil. Maybe store it there? Seems easy but don't want to introduce a bad pattern. Todo: - style update - collapsible favorites - persistent storage
This commit is contained in:
@ -2,21 +2,34 @@ import styled from '@emotion/styled';
|
||||
|
||||
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
|
||||
import { NavigationDrawerSectionTitleSkeletonLoader } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitleSkeletonLoader';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
type NavigationDrawerSectionTitleProps = {
|
||||
onClick?: () => void;
|
||||
label: string;
|
||||
};
|
||||
|
||||
const StyledTitle = styled.div`
|
||||
const StyledTitle = styled.div<{ onClick?: () => void }>`
|
||||
align-items: center;
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
display: flex;
|
||||
font-size: ${({ theme }) => theme.font.size.xs};
|
||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||
height: ${({ theme }) => theme.spacing(4)};
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
padding-top: 0;
|
||||
|
||||
${({ onClick, theme }) =>
|
||||
!isUndefinedOrNull(onClick)
|
||||
? `&:hover {
|
||||
cursor: pointer;
|
||||
background-color:${theme.background.transparent.light};
|
||||
}`
|
||||
: ''}
|
||||
`;
|
||||
|
||||
export const NavigationDrawerSectionTitle = ({
|
||||
onClick,
|
||||
label,
|
||||
}: NavigationDrawerSectionTitleProps) => {
|
||||
const loading = useIsPrefetchLoading();
|
||||
@ -24,5 +37,5 @@ export const NavigationDrawerSectionTitle = ({
|
||||
if (loading) {
|
||||
return <NavigationDrawerSectionTitleSkeletonLoader />;
|
||||
}
|
||||
return <StyledTitle>{label}</StyledTitle>;
|
||||
return <StyledTitle onClick={onClick}>{label}</StyledTitle>;
|
||||
};
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { isNavigationSectionOpenComponentState } from '@/ui/navigation/navigation-drawer/states/isNavigationSectionOpenComponentState';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
|
||||
export const useNavigationSection = (scopeId: string) => {
|
||||
const closeNavigationSection = useRecoilCallback(
|
||||
({ set }) =>
|
||||
() => {
|
||||
set(
|
||||
isNavigationSectionOpenComponentState({
|
||||
scopeId,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
},
|
||||
[scopeId],
|
||||
);
|
||||
|
||||
const openNavigationSection = useRecoilCallback(
|
||||
({ set }) =>
|
||||
() => {
|
||||
set(
|
||||
isNavigationSectionOpenComponentState({
|
||||
scopeId,
|
||||
}),
|
||||
true,
|
||||
);
|
||||
},
|
||||
[scopeId],
|
||||
);
|
||||
|
||||
const toggleNavigationSection = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
() => {
|
||||
const isNavigationSectionOpen = snapshot
|
||||
.getLoadable(isNavigationSectionOpenComponentState({ scopeId }))
|
||||
.getValue();
|
||||
|
||||
if (isNavigationSectionOpen) {
|
||||
closeNavigationSection();
|
||||
} else {
|
||||
openNavigationSection();
|
||||
}
|
||||
},
|
||||
[closeNavigationSection, openNavigationSection, scopeId],
|
||||
);
|
||||
|
||||
const isNavigationSectionOpenState = extractComponentState(
|
||||
isNavigationSectionOpenComponentState,
|
||||
scopeId,
|
||||
);
|
||||
|
||||
return {
|
||||
isNavigationSectionOpenState,
|
||||
closeNavigationSection,
|
||||
openNavigationSection,
|
||||
toggleNavigationSection,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,9 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
import { localStorageEffect } from '~/utils/recoil-effects';
|
||||
|
||||
export const isNavigationSectionOpenComponentState =
|
||||
createComponentState<boolean>({
|
||||
key: 'isNavigationSectionOpenComponentState',
|
||||
defaultValue: true,
|
||||
effects: [localStorageEffect()],
|
||||
});
|
||||
@ -1,16 +1,19 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
import { AtomEffect, atomFamily } from 'recoil';
|
||||
|
||||
import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
|
||||
|
||||
export const createComponentState = <ValueType>({
|
||||
key,
|
||||
defaultValue,
|
||||
effects,
|
||||
}: {
|
||||
key: string;
|
||||
defaultValue: ValueType;
|
||||
effects?: AtomEffect<ValueType>[];
|
||||
}) => {
|
||||
return atomFamily<ValueType, ComponentStateKey>({
|
||||
key,
|
||||
default: defaultValue,
|
||||
effects: effects,
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user