From 23001ac17d89a59a9d6063655163048672524a0b Mon Sep 17 00:00:00 2001 From: "gitstart-app[bot]" <57568882+gitstart-app[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:04:07 +0200 Subject: [PATCH] Settings Advanced Mode (#7130) ### Description - We implemented the Advanced Mode state and used this on a section of the settings sidebar - in DefaultLayout.tsx, was updated because of the 64 + 16(container size of IconTool + the margins) ### ### Refs #6147 Fixes #6147 --------- Co-authored-by: gitstart-twenty Co-authored-by: gitstart-twenty <140154534+gitstart-twenty@users.noreply.github.com> --- .../components/AppNavigationDrawer.tsx | 4 +- .../SettingsNavigationDrawerItems.tsx | 91 +++++++++++++++---- .../hooks/useExpandedHeightAnimation.tsx | 57 ++++++++++++ .../modules/ui/layout/page/DefaultLayout.tsx | 12 +-- .../components/AdvancedSettingsToggle.tsx | 62 +++++++++++++ .../components/NavigationDrawer.tsx | 10 +- .../components/NavigationDrawerBackButton.tsx | 1 + .../components/NavigationDrawerSection.tsx | 1 + .../states/isAdvancedModeEnabledState.ts | 8 ++ .../src/pages/settings/SettingsWorkspace.tsx | 4 + .../display/icon/components/TablerIcons.ts | 1 + 11 files changed, 221 insertions(+), 30 deletions(-) create mode 100644 packages/twenty-front/src/modules/settings/hooks/useExpandedHeightAnimation.tsx create mode 100644 packages/twenty-front/src/modules/ui/navigation/link/components/AdvancedSettingsToggle.tsx create mode 100644 packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState.ts diff --git a/packages/twenty-front/src/modules/navigation/components/AppNavigationDrawer.tsx b/packages/twenty-front/src/modules/navigation/components/AppNavigationDrawer.tsx index da636fe025e5..a6d3b1045cc9 100644 --- a/packages/twenty-front/src/modules/navigation/components/AppNavigationDrawer.tsx +++ b/packages/twenty-front/src/modules/navigation/components/AppNavigationDrawer.tsx @@ -4,7 +4,6 @@ import { useRecoilValue, useSetRecoilState } from 'recoil'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { SettingsNavigationDrawerItems } from '@/settings/components/SettingsNavigationDrawerItems'; import { SupportDropdown } from '@/support/components/SupportDropdown'; -import { GithubVersionLink } from '@/ui/navigation/link/components/GithubVersionLink'; import { NavigationDrawer, NavigationDrawerProps, @@ -16,6 +15,7 @@ import { getImageAbsoluteURI } from '~/utils/image/getImageAbsoluteURI'; import { useIsSettingsPage } from '../hooks/useIsSettingsPage'; import { currentMobileNavigationDrawerState } from '../states/currentMobileNavigationDrawerState'; +import { AdvancedSettingsToggle } from '@/ui/navigation/link/components/AdvancedSettingsToggle'; import { MainNavigationDrawerItems } from './MainNavigationDrawerItems'; export type AppNavigationDrawerProps = { @@ -44,7 +44,7 @@ export const AppNavigationDrawer = ({ isSubMenu: true, title: 'Exit Settings', children: , - footer: , + footer: , } : { logo: diff --git a/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx b/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx index 04f11020758a..e721e8d8e60e 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx @@ -13,13 +13,16 @@ import { IconMail, IconRocket, IconSettings, + IconTool, IconUserCircle, IconUsers, + MAIN_COLORS, } from 'twenty-ui'; import { useAuth } from '@/auth/hooks/useAuth'; import { billingState } from '@/client-config/states/billingState'; import { SettingsNavigationDrawerItem } from '@/settings/components/SettingsNavigationDrawerItem'; +import { useExpandedHeightAnimation } from '@/settings/hooks/useExpandedHeightAnimation'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { @@ -29,10 +32,38 @@ 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 { getNavigationSubItemState } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemState'; 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'; +const StyledNavigationDrawerSection = styled(NavigationDrawerSection)<{ + withLeftMargin?: boolean; +}>` + margin-left: ${({ withLeftMargin, theme }) => + withLeftMargin && theme.spacing(5)}; + margin-top: ${({ theme }) => theme.spacing(3)}; +`; + +const StyledIconContainer = styled.div` + border-right: 1px solid ${MAIN_COLORS.yellow}; + display: flex; + margin-top: ${({ theme }) => theme.spacing(5)}; + width: 16px; +`; + +const StyledDeveloperSection = styled.div` + display: flex; + width: 100%; + gap: ${({ theme }) => theme.spacing(1)}; +`; + +const StyledIconTool = styled(IconTool)` + margin-right: ${({ theme }) => theme.spacing(0.5)}; +`; + type SettingsNavigationItem = { label: string; path: SettingsPath; @@ -42,6 +73,10 @@ type SettingsNavigationItem = { }; export const SettingsNavigationDrawerItems = () => { + const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState); + const { contentRef, motionAnimationVariants } = useExpandedHeightAnimation( + isAdvancedModeEnabled, + ); const { signOut } = useAuth(); const billing = useRecoilValue(billingState); @@ -88,7 +123,7 @@ export const SettingsNavigationDrawerItems = () => { return ( <> - + { /> ))} - - + + { Icon={IconHierarchy2} matchSubPages /> - - {isFunctionSettingsEnabled && ( - - )} { Icon={IconCode} /> )} - - + + + {isAdvancedModeEnabled && ( + + + + + + + + + {isFunctionSettingsEnabled && ( + + )} + + + + )} + + { onClick={signOut} Icon={IconDoorEnter} /> - + ); }; diff --git a/packages/twenty-front/src/modules/settings/hooks/useExpandedHeightAnimation.tsx b/packages/twenty-front/src/modules/settings/hooks/useExpandedHeightAnimation.tsx new file mode 100644 index 000000000000..3a48c3bb20b9 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/hooks/useExpandedHeightAnimation.tsx @@ -0,0 +1,57 @@ +import { useEffect, useRef, useState } from 'react'; +import { isDefined } from 'twenty-ui'; + +const transitionValues = { + transition: { + opactity: { duration: 0.2 }, + height: { duration: 0.4 }, + }, + transitionEnd: { + overflow: 'visible', + }, +}; + +const commonStyles = { + opacity: 0, + height: 0, + overflow: 'hidden', + ...transitionValues, +}; + +const advancedSectionAnimationConfig = ( + isExpanded: boolean, + measuredHeight: number, +) => ({ + initial: { + ...commonStyles, + }, + animate: { + opacity: 1, + height: isExpanded ? measuredHeight : 0, + ...transitionValues, + overflow: 'hidden', + }, + exit: { + ...commonStyles, + }, +}); + +export const useExpandedHeightAnimation = (isExpanded: boolean) => { + const contentRef = useRef(null); + const [measuredHeight, setMeasuredHeight] = useState(0); + + useEffect(() => { + if (isDefined(contentRef.current)) { + setMeasuredHeight(contentRef.current.scrollHeight); + } + }, [isExpanded]); + + return { + contentRef, + measuredHeight, + motionAnimationVariants: advancedSectionAnimationConfig( + isExpanded, + measuredHeight, + ), + }; +}; diff --git a/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx b/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx index 4108f6a5cee6..555e068d6290 100644 --- a/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx +++ b/packages/twenty-front/src/modules/ui/layout/page/DefaultLayout.tsx @@ -1,7 +1,4 @@ -import { css, Global, useTheme } from '@emotion/react'; -import styled from '@emotion/styled'; -import { AnimatePresence, LayoutGroup, motion } from 'framer-motion'; -import { Outlet } from 'react-router-dom'; +import { AuthModal } from '@/auth/components/AuthModal'; import { CommandMenu } from '@/command-menu/components/CommandMenu'; import { AppErrorBoundary } from '@/error-handler/components/AppErrorBoundary'; import { KeyboardShortcutMenu } from '@/keyboard-shortcut-menu/components/KeyboardShortcutMenu'; @@ -14,7 +11,10 @@ import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal'; import { DESKTOP_NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/DesktopNavDrawerWidths'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useScreenSize } from '@/ui/utilities/screen-size/hooks/useScreenSize'; -import { AuthModal } from '@/auth/components/AuthModal'; +import { css, Global, useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { AnimatePresence, LayoutGroup, motion } from 'framer-motion'; +import { Outlet } from 'react-router-dom'; const StyledLayout = styled.div` background: ${({ theme }) => theme.background.noisy}; @@ -85,7 +85,7 @@ export const DefaultLayout = () => { ? (windowsWidth - (OBJECT_SETTINGS_WIDTH + DESKTOP_NAV_DRAWER_WIDTHS.menu + - 64)) / + 88)) / 2 : 0, }} diff --git a/packages/twenty-front/src/modules/ui/navigation/link/components/AdvancedSettingsToggle.tsx b/packages/twenty-front/src/modules/ui/navigation/link/components/AdvancedSettingsToggle.tsx new file mode 100644 index 000000000000..a4581469146e --- /dev/null +++ b/packages/twenty-front/src/modules/ui/navigation/link/components/AdvancedSettingsToggle.tsx @@ -0,0 +1,62 @@ +import { Toggle } from '@/ui/input/components/Toggle'; +import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; +import styled from '@emotion/styled'; +import { useRecoilState } from 'recoil'; +import { IconTool, MAIN_COLORS } from 'twenty-ui'; + +const StyledContainer = styled.div` + align-items: center; + display: flex; + width: 100%; + gap: ${({ theme }) => theme.spacing(2)}; +`; + +const StyledText = styled.span` + color: ${({ theme }) => theme.font.color.secondary}; + font-size: ${({ theme }) => theme.font.size.sm}; + font-weight: ${({ theme }) => theme.font.weight.medium}; + padding: ${({ theme }) => theme.spacing(1)}; +`; + +const StyledIconContainer = styled.div` + border-right: 1px solid ${MAIN_COLORS.yellow}; + display: flex; + height: 16px; +`; + +const StyledToggleContainer = styled.div` + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; +`; + +const StyledIconTool = styled(IconTool)` + margin-right: ${({ theme }) => theme.spacing(0.5)}; +`; + +export const AdvancedSettingsToggle = () => { + const [isAdvancedModeEnabled, setIsAdvancedModeEnabled] = useRecoilState( + isAdvancedModeEnabledState, + ); + + const onChange = (newValue: boolean) => { + setIsAdvancedModeEnabled(newValue); + }; + + return ( + + + + + + Advanced + + + + ); +}; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx index 35fb3cae0d54..28b3640cc394 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawer.tsx @@ -40,6 +40,7 @@ const StyledContainer = styled.div<{ isSubMenu?: boolean }>` ${({ isSubMenu, theme }) => isSubMenu ? css` + padding-left: ${theme.spacing(0)}; padding-right: ${theme.spacing(8)}; ` : ''} @@ -48,13 +49,12 @@ const StyledContainer = styled.div<{ isSubMenu?: boolean }>` width: 100%; } `; - -const StyledItemsContainer = styled.div` +const StyledItemsContainer = styled.div<{ isSubMenu?: boolean }>` display: flex; flex-direction: column; - gap: ${({ theme }) => theme.spacing(3)}; margin-bottom: auto; overflow-y: auto; + ${({ isSubMenu, theme }) => !isSubMenu && `gap: ${theme.spacing(3)}`} `; export const NavigationDrawer = ({ @@ -111,7 +111,9 @@ export const NavigationDrawer = ({ showCollapseButton={isHovered} /> )} - {children} + + {children} + {footer} diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerBackButton.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerBackButton.tsx index 96490d7f0a7e..d906f45aa881 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerBackButton.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerBackButton.tsx @@ -35,6 +35,7 @@ const StyledContainer = styled.div` flex-direction: row; height: ${({ theme }) => theme.spacing(8)}; justify-content: space-between; + margin-left: ${({ theme }) => theme.spacing(5)}; `; export const NavigationDrawerBackButton = ({ diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSection.tsx b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSection.tsx index bea1d0f8e46a..c1fd938476a8 100644 --- a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSection.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/components/NavigationDrawerSection.tsx @@ -4,6 +4,7 @@ const StyledSection = styled.div` display: flex; flex-direction: column; gap: ${({ theme }) => theme.betweenSiblingsGap}; + width: 100%; `; export { StyledSection as NavigationDrawerSection }; diff --git a/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState.ts b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState.ts new file mode 100644 index 000000000000..05fd34d432a3 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState.ts @@ -0,0 +1,8 @@ +import { atom } from 'recoil'; +import { localStorageEffect } from '~/utils/recoil-effects'; + +export const isAdvancedModeEnabledState = atom({ + key: 'isAdvancedModeEnabledAtom', + default: false, + effects: [localStorageEffect()], +}); diff --git a/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx b/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx index 359961d24d87..4f32d08b2374 100644 --- a/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsWorkspace.tsx @@ -9,6 +9,7 @@ import { WorkspaceLogoUploader } from '@/settings/workspace/components/Workspace import { SettingsPath } from '@/types/SettingsPath'; import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; +import { GithubVersionLink } from '@/ui/navigation/link/components/GithubVersionLink'; export const SettingsWorkspace = () => ( (
+
+ +
); diff --git a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts index 2daafb4ec61f..97a8013b6b0d 100644 --- a/packages/twenty-ui/src/display/icon/components/TablerIcons.ts +++ b/packages/twenty-ui/src/display/icon/components/TablerIcons.ts @@ -173,6 +173,7 @@ export { IconTestPipe, IconTextSize, IconTimelineEvent, + IconTool, IconTrash, IconUnlink, IconUpload,