diff --git a/packages/twenty-front/src/modules/navigation/components/AppNavigationDrawer.tsx b/packages/twenty-front/src/modules/navigation/components/AppNavigationDrawer.tsx
index da636fe02..a6d3b1045 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 04f110207..e721e8d8e 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 000000000..3a48c3bb2
--- /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 4108f6a5c..555e068d6 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 000000000..a45814691
--- /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 35fb3cae0..28b3640cc 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 96490d7f0..d906f45aa 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 bea1d0f8e..c1fd93847 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 000000000..05fd34d43
--- /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 359961d24..4f32d08b2 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 2daafb4ec..97a8013b6 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,