Navigation drawer refactor (#11251)
closes #11195 closes #11199 ### Context The yellow dots in the Settings Navigation Drawer (used to indicate advanced settings) were being hidden due to ScrollWrapper's overflow handling. This required both a fix for the visibility issue and an improvement to the component structure. ### Changes 1. Keep scrolling logic of the MainNavigationDrawer and SettingsNavigationDrawer in one place, and conditionally apply `<StyledScrollableInnerContainer>` when isSettingsDrawer is true. 2. Fixed Yellow Dots Visibility Added specific padding in NavigationDrawerScrollableContent to accommodate yellow dots: ``` padding-left: ${theme.spacing(5)}; // Space for yellow dots padding-right: ${theme.spacing(8)}; // Space for no-padding scroll ``` This ensures the yellow dots are visible while maintaining proper scroll behavior 3. Improved Component Composition Using proper component composition instead of passing components as props Components are now composed in a more React-idiomatic way: ``` <NavigationDrawer> <NavigationDrawerScrollableContent> <SettingsNavigationDrawerItems /> </NavigationDrawerScrollableContent> <NavigationDrawerFixedContent> <AdvancedSettingsToggle /> </NavigationDrawerFixedContent> </NavigationDrawer> ``` --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,19 +1,7 @@
|
|||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|
||||||
import { SettingsNavigationDrawerItems } from '@/settings/components/SettingsNavigationDrawerItems';
|
|
||||||
import { SupportDropdown } from '@/support/components/SupportDropdown';
|
|
||||||
import {
|
|
||||||
NavigationDrawer,
|
|
||||||
NavigationDrawerProps,
|
|
||||||
} from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
|
|
||||||
import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState';
|
|
||||||
|
|
||||||
import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer';
|
import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer';
|
||||||
|
|
||||||
import { MainNavigationDrawerItems } from '@/navigation/components/MainNavigationDrawerItems';
|
import { MainNavigationDrawer } from '@/navigation/components/MainNavigationDrawer';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { SettingsNavigationDrawer } from '@/navigation/components/SettingsNavigationDrawer';
|
||||||
import { AdvancedSettingsToggle } from 'twenty-ui/navigation';
|
|
||||||
|
|
||||||
export type AppNavigationDrawerProps = {
|
export type AppNavigationDrawerProps = {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -24,38 +12,9 @@ export const AppNavigationDrawer = ({
|
|||||||
}: AppNavigationDrawerProps) => {
|
}: AppNavigationDrawerProps) => {
|
||||||
const isSettingsDrawer = useIsSettingsDrawer();
|
const isSettingsDrawer = useIsSettingsDrawer();
|
||||||
|
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
return isSettingsDrawer ? (
|
||||||
const [isAdvancedModeEnabled, setIsAdvancedModeEnabled] = useRecoilState(
|
<SettingsNavigationDrawer className={className} />
|
||||||
isAdvancedModeEnabledState,
|
) : (
|
||||||
);
|
<MainNavigationDrawer className={className} />
|
||||||
|
|
||||||
const { t } = useLingui();
|
|
||||||
|
|
||||||
const drawerProps: NavigationDrawerProps = isSettingsDrawer
|
|
||||||
? {
|
|
||||||
title: t`Exit Settings`,
|
|
||||||
children: <SettingsNavigationDrawerItems />,
|
|
||||||
footer: (
|
|
||||||
<AdvancedSettingsToggle
|
|
||||||
isAdvancedModeEnabled={isAdvancedModeEnabled}
|
|
||||||
setIsAdvancedModeEnabled={setIsAdvancedModeEnabled}
|
|
||||||
label={t`Advanced:`}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
title: currentWorkspace?.displayName ?? '',
|
|
||||||
children: <MainNavigationDrawerItems />,
|
|
||||||
footer: <SupportDropdown />,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NavigationDrawer
|
|
||||||
className={className}
|
|
||||||
title={drawerProps.title}
|
|
||||||
footer={drawerProps.footer}
|
|
||||||
>
|
|
||||||
{drawerProps.children}
|
|
||||||
</NavigationDrawer>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
|
import { MainNavigationDrawerFixedItems } from '@/navigation/components/MainNavigationDrawerFixedItems';
|
||||||
|
import { MainNavigationDrawerScrollableItems } from '@/navigation/components/MainNavigationDrawerScrollableItems';
|
||||||
|
import { SupportDropdown } from '@/support/components/SupportDropdown';
|
||||||
|
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
|
||||||
|
import { NavigationDrawerFixedContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerFixedContent';
|
||||||
|
import { NavigationDrawerScrollableContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerScrollableContent';
|
||||||
|
|
||||||
|
export const MainNavigationDrawer = ({ className }: { className?: string }) => {
|
||||||
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavigationDrawer
|
||||||
|
className={className}
|
||||||
|
title={currentWorkspace?.displayName ?? ''}
|
||||||
|
>
|
||||||
|
<NavigationDrawerFixedContent>
|
||||||
|
<MainNavigationDrawerFixedItems />
|
||||||
|
</NavigationDrawerFixedContent>
|
||||||
|
|
||||||
|
<NavigationDrawerScrollableContent>
|
||||||
|
<MainNavigationDrawerScrollableItems />
|
||||||
|
</NavigationDrawerScrollableContent>
|
||||||
|
|
||||||
|
<NavigationDrawerFixedContent>
|
||||||
|
<SupportDropdown />
|
||||||
|
</NavigationDrawerFixedContent>
|
||||||
|
</NavigationDrawer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
import { useOpenRecordsSearchPageInCommandMenu } from '@/command-menu/hooks/useOpenRecordsSearchPageInCommandMenu';
|
||||||
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
|
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
|
||||||
|
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||||
|
import { navigationDrawerExpandedMemorizedState } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedState';
|
||||||
|
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||||
|
import { useLingui } from '@lingui/react/macro';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
|
import { IconSearch, IconSettings } from 'twenty-ui/display';
|
||||||
|
import { useIsMobile } from 'twenty-ui/utilities';
|
||||||
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
|
|
||||||
|
export const MainNavigationDrawerFixedItems = () => {
|
||||||
|
const isMobile = useIsMobile();
|
||||||
|
const location = useLocation();
|
||||||
|
const setNavigationMemorizedUrl = useSetRecoilState(
|
||||||
|
navigationMemorizedUrlState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] =
|
||||||
|
useRecoilState(isNavigationDrawerExpandedState);
|
||||||
|
const setNavigationDrawerExpandedMemorized = useSetRecoilState(
|
||||||
|
navigationDrawerExpandedMemorizedState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { t } = useLingui();
|
||||||
|
|
||||||
|
const { openRecordsSearchPage } = useOpenRecordsSearchPageInCommandMenu();
|
||||||
|
return (
|
||||||
|
!isMobile && (
|
||||||
|
<>
|
||||||
|
<NavigationDrawerItem
|
||||||
|
label={t`Search`}
|
||||||
|
Icon={IconSearch}
|
||||||
|
onClick={openRecordsSearchPage}
|
||||||
|
keyboard={['/']}
|
||||||
|
/>
|
||||||
|
<NavigationDrawerItem
|
||||||
|
label={t`Settings`}
|
||||||
|
to={getSettingsPath(SettingsPath.ProfilePage)}
|
||||||
|
onClick={() => {
|
||||||
|
setNavigationDrawerExpandedMemorized(isNavigationDrawerExpanded);
|
||||||
|
setIsNavigationDrawerExpanded(true);
|
||||||
|
setNavigationMemorizedUrl(location.pathname + location.search);
|
||||||
|
}}
|
||||||
|
Icon={IconSettings}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,82 +0,0 @@
|
|||||||
import { useLocation } from 'react-router-dom';
|
|
||||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { useOpenRecordsSearchPageInCommandMenu } from '@/command-menu/hooks/useOpenRecordsSearchPageInCommandMenu';
|
|
||||||
import { CurrentWorkspaceMemberFavoritesFolders } from '@/favorites/components/CurrentWorkspaceMemberFavoritesFolders';
|
|
||||||
import { WorkspaceFavorites } from '@/favorites/components/WorkspaceFavorites';
|
|
||||||
import { NavigationDrawerOpenedSection } from '@/object-metadata/components/NavigationDrawerOpenedSection';
|
|
||||||
import { RemoteNavigationDrawerSection } from '@/object-metadata/components/RemoteNavigationDrawerSection';
|
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
|
||||||
import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
|
|
||||||
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
|
|
||||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
|
||||||
import { navigationDrawerExpandedMemorizedState } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedState';
|
|
||||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
|
||||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
|
||||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
import { useLingui } from '@lingui/react/macro';
|
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
|
||||||
import { IconSearch, IconSettings } from 'twenty-ui/display';
|
|
||||||
|
|
||||||
const StyledMainSection = styled(NavigationDrawerSection)`
|
|
||||||
min-height: fit-content;
|
|
||||||
`;
|
|
||||||
const StyledInnerContainer = styled.div`
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const MainNavigationDrawerItems = () => {
|
|
||||||
const isMobile = useIsMobile();
|
|
||||||
const location = useLocation();
|
|
||||||
const setNavigationMemorizedUrl = useSetRecoilState(
|
|
||||||
navigationMemorizedUrlState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] =
|
|
||||||
useRecoilState(isNavigationDrawerExpandedState);
|
|
||||||
const setNavigationDrawerExpandedMemorized = useSetRecoilState(
|
|
||||||
navigationDrawerExpandedMemorizedState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { t } = useLingui();
|
|
||||||
|
|
||||||
const { openRecordsSearchPage } = useOpenRecordsSearchPageInCommandMenu();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{!isMobile && (
|
|
||||||
<StyledMainSection>
|
|
||||||
<NavigationDrawerItem
|
|
||||||
label={t`Search`}
|
|
||||||
Icon={IconSearch}
|
|
||||||
onClick={openRecordsSearchPage}
|
|
||||||
keyboard={['/']}
|
|
||||||
/>
|
|
||||||
<NavigationDrawerItem
|
|
||||||
label={t`Settings`}
|
|
||||||
to={getSettingsPath(SettingsPath.ProfilePage)}
|
|
||||||
onClick={() => {
|
|
||||||
setNavigationDrawerExpandedMemorized(isNavigationDrawerExpanded);
|
|
||||||
setIsNavigationDrawerExpanded(true);
|
|
||||||
setNavigationMemorizedUrl(location.pathname + location.search);
|
|
||||||
}}
|
|
||||||
Icon={IconSettings}
|
|
||||||
/>
|
|
||||||
</StyledMainSection>
|
|
||||||
)}
|
|
||||||
<ScrollWrapper
|
|
||||||
componentInstanceId={`scroll-wrapper-navigation-drawer`}
|
|
||||||
defaultEnableXScroll={false}
|
|
||||||
>
|
|
||||||
<StyledInnerContainer>
|
|
||||||
<NavigationDrawerOpenedSection />
|
|
||||||
<CurrentWorkspaceMemberFavoritesFolders />
|
|
||||||
<WorkspaceFavorites />
|
|
||||||
<RemoteNavigationDrawerSection />
|
|
||||||
</StyledInnerContainer>
|
|
||||||
</ScrollWrapper>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { CurrentWorkspaceMemberFavoritesFolders } from '@/favorites/components/CurrentWorkspaceMemberFavoritesFolders';
|
||||||
|
import { WorkspaceFavorites } from '@/favorites/components/WorkspaceFavorites';
|
||||||
|
import { NavigationDrawerOpenedSection } from '@/object-metadata/components/NavigationDrawerOpenedSection';
|
||||||
|
import { RemoteNavigationDrawerSection } from '@/object-metadata/components/RemoteNavigationDrawerSection';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledScrollableItemsContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: ${({ theme }) => theme.spacing(3)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const MainNavigationDrawerScrollableItems = () => {
|
||||||
|
return (
|
||||||
|
<StyledScrollableItemsContainer>
|
||||||
|
<NavigationDrawerOpenedSection />
|
||||||
|
<CurrentWorkspaceMemberFavoritesFolders />
|
||||||
|
<WorkspaceFavorites />
|
||||||
|
<RemoteNavigationDrawerSection />
|
||||||
|
</StyledScrollableItemsContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
import { SettingsNavigationDrawerItems } from '@/settings/components/SettingsNavigationDrawerItems';
|
||||||
|
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
|
||||||
|
import { NavigationDrawerFixedContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerFixedContent';
|
||||||
|
import { NavigationDrawerScrollableContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerScrollableContent';
|
||||||
|
import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState';
|
||||||
|
import { useLingui } from '@lingui/react/macro';
|
||||||
|
import { useRecoilState } from 'recoil';
|
||||||
|
import { AdvancedSettingsToggle } from 'twenty-ui/navigation';
|
||||||
|
|
||||||
|
export const SettingsNavigationDrawer = ({
|
||||||
|
className,
|
||||||
|
}: {
|
||||||
|
className?: string;
|
||||||
|
}) => {
|
||||||
|
const { t } = useLingui();
|
||||||
|
const [isAdvancedModeEnabled, setIsAdvancedModeEnabled] = useRecoilState(
|
||||||
|
isAdvancedModeEnabledState,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavigationDrawer className={className} title={t`Exit Settings`}>
|
||||||
|
<NavigationDrawerScrollableContent>
|
||||||
|
<SettingsNavigationDrawerItems />
|
||||||
|
</NavigationDrawerScrollableContent>
|
||||||
|
|
||||||
|
<NavigationDrawerFixedContent>
|
||||||
|
<AdvancedSettingsToggle
|
||||||
|
isAdvancedModeEnabled={isAdvancedModeEnabled}
|
||||||
|
setIsAdvancedModeEnabled={setIsAdvancedModeEnabled}
|
||||||
|
label={t`Advanced:`}
|
||||||
|
/>
|
||||||
|
</NavigationDrawerFixedContent>
|
||||||
|
</NavigationDrawer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -9,16 +9,9 @@ import { NavigationDrawerItemGroup } from '@/ui/navigation/navigation-drawer/com
|
|||||||
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
|
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
|
||||||
import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle';
|
import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle';
|
||||||
import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment';
|
import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment';
|
||||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
import { matchPath, resolvePath, useLocation } from 'react-router-dom';
|
import { matchPath, resolvePath, useLocation } from 'react-router-dom';
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
|
|
||||||
const StyledInnerContainer = styled.div`
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const SettingsNavigationDrawerItems = () => {
|
export const SettingsNavigationDrawerItems = () => {
|
||||||
const settingsNavigationItems: SettingsNavigationSection[] =
|
const settingsNavigationItems: SettingsNavigationSection[] =
|
||||||
useSettingsNavigationItems();
|
useSettingsNavigationItems();
|
||||||
@ -41,86 +34,81 @@ export const SettingsNavigationDrawerItems = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollWrapper
|
<>
|
||||||
componentInstanceId={`scroll-wrapper-settings-navigation-drawer`}
|
{settingsNavigationItems.map((section) => {
|
||||||
defaultEnableXScroll={false}
|
const allItemsHidden = section.items.every((item) => item.isHidden);
|
||||||
>
|
if (allItemsHidden) {
|
||||||
<StyledInnerContainer>
|
return null;
|
||||||
{settingsNavigationItems.map((section) => {
|
}
|
||||||
const allItemsHidden = section.items.every((item) => item.isHidden);
|
|
||||||
if (allItemsHidden) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationDrawerSection key={section.label}>
|
<NavigationDrawerSection key={section.label}>
|
||||||
{section.isAdvanced ? (
|
{section.isAdvanced ? (
|
||||||
<AdvancedSettingsWrapper hideDot>
|
<AdvancedSettingsWrapper hideDot>
|
||||||
<NavigationDrawerSectionTitle label={section.label} />
|
|
||||||
</AdvancedSettingsWrapper>
|
|
||||||
) : (
|
|
||||||
<NavigationDrawerSectionTitle label={section.label} />
|
<NavigationDrawerSectionTitle label={section.label} />
|
||||||
)}
|
</AdvancedSettingsWrapper>
|
||||||
{section.items.map((item, index) => {
|
) : (
|
||||||
const subItems = item.subItems;
|
<NavigationDrawerSectionTitle label={section.label} />
|
||||||
if (Array.isArray(subItems) && subItems.length > 0) {
|
)}
|
||||||
const selectedSubItemIndex =
|
{section.items.map((item, index) => {
|
||||||
getSelectedIndexForSubItems(subItems);
|
const subItems = item.subItems;
|
||||||
|
if (Array.isArray(subItems) && subItems.length > 0) {
|
||||||
|
const selectedSubItemIndex =
|
||||||
|
getSelectedIndexForSubItems(subItems);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationDrawerItemGroup
|
<NavigationDrawerItemGroup
|
||||||
key={item.path || `group-${index}`}
|
key={item.path || `group-${index}`}
|
||||||
>
|
>
|
||||||
|
<SettingsNavigationDrawerItem
|
||||||
|
item={item}
|
||||||
|
subItemState={
|
||||||
|
item.indentationLevel
|
||||||
|
? getNavigationSubItemLeftAdornment({
|
||||||
|
arrayLength: section.items.length,
|
||||||
|
index,
|
||||||
|
selectedIndex: selectedSubItemIndex,
|
||||||
|
})
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{subItems.map((subItem, subIndex) => (
|
||||||
<SettingsNavigationDrawerItem
|
<SettingsNavigationDrawerItem
|
||||||
item={item}
|
key={subItem.path || `subitem-${subIndex}`}
|
||||||
|
item={subItem}
|
||||||
subItemState={
|
subItemState={
|
||||||
item.indentationLevel
|
subItem.indentationLevel
|
||||||
? getNavigationSubItemLeftAdornment({
|
? getNavigationSubItemLeftAdornment({
|
||||||
arrayLength: section.items.length,
|
arrayLength: subItems.length,
|
||||||
index,
|
index: subIndex,
|
||||||
selectedIndex: selectedSubItemIndex,
|
selectedIndex: selectedSubItemIndex,
|
||||||
})
|
})
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{subItems.map((subItem, subIndex) => (
|
))}
|
||||||
<SettingsNavigationDrawerItem
|
</NavigationDrawerItemGroup>
|
||||||
key={subItem.path || `subitem-${subIndex}`}
|
|
||||||
item={subItem}
|
|
||||||
subItemState={
|
|
||||||
subItem.indentationLevel
|
|
||||||
? getNavigationSubItemLeftAdornment({
|
|
||||||
arrayLength: subItems.length,
|
|
||||||
index: subIndex,
|
|
||||||
selectedIndex: selectedSubItemIndex,
|
|
||||||
})
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</NavigationDrawerItemGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<SettingsNavigationDrawerItem
|
|
||||||
key={item.path || `item-${index}`}
|
|
||||||
item={item}
|
|
||||||
subItemState={
|
|
||||||
item.indentationLevel
|
|
||||||
? getNavigationSubItemLeftAdornment({
|
|
||||||
arrayLength: section.items.length,
|
|
||||||
index,
|
|
||||||
selectedIndex: index,
|
|
||||||
})
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
})}
|
}
|
||||||
</NavigationDrawerSection>
|
return (
|
||||||
);
|
<SettingsNavigationDrawerItem
|
||||||
})}
|
key={item.path || `item-${index}`}
|
||||||
</StyledInnerContainer>
|
item={item}
|
||||||
</ScrollWrapper>
|
subItemState={
|
||||||
|
item.indentationLevel
|
||||||
|
? getNavigationSubItemLeftAdornment({
|
||||||
|
arrayLength: section.items.length,
|
||||||
|
index,
|
||||||
|
selectedIndex: index,
|
||||||
|
})
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</NavigationDrawerSection>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { SupportDropdown } from '@/support/components/SupportDropdown';
|
import { SupportDropdown } from '@/support/components/SupportDropdown';
|
||||||
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
|
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
|
||||||
|
import { NavigationDrawerFixedContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerFixedContent';
|
||||||
|
|
||||||
import { NavigationDrawerSectionForObjectMetadataItems } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems';
|
import { NavigationDrawerSectionForObjectMetadataItems } from '@/object-metadata/components/NavigationDrawerSectionForObjectMetadataItems';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
@ -35,8 +36,8 @@ export const SignInAppNavigationDrawerMock = ({
|
|||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
|
||||||
const children = (
|
return (
|
||||||
<>
|
<NavigationDrawer className={className} title={DEFAULT_WORKSPACE_NAME}>
|
||||||
{!isMobile && (
|
{!isMobile && (
|
||||||
<StyledMainSection>
|
<StyledMainSection>
|
||||||
<NavigationDrawerItem
|
<NavigationDrawerItem
|
||||||
@ -60,18 +61,9 @@ export const SignInAppNavigationDrawerMock = ({
|
|||||||
WORKSPACE_FAVORITES.includes(item.nameSingular),
|
WORKSPACE_FAVORITES.includes(item.nameSingular),
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</>
|
<NavigationDrawerFixedContent>
|
||||||
);
|
<SupportDropdown />
|
||||||
|
</NavigationDrawerFixedContent>
|
||||||
const footer = <SupportDropdown />;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NavigationDrawer
|
|
||||||
className={className}
|
|
||||||
footer={footer}
|
|
||||||
title={DEFAULT_WORKSPACE_NAME}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</NavigationDrawer>
|
</NavigationDrawer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -84,7 +84,7 @@ export const DefaultLayout = () => {
|
|||||||
? (windowsWidth -
|
? (windowsWidth -
|
||||||
(OBJECT_SETTINGS_WIDTH +
|
(OBJECT_SETTINGS_WIDTH +
|
||||||
NAV_DRAWER_WIDTHS.menu.desktop.expanded +
|
NAV_DRAWER_WIDTHS.menu.desktop.expanded +
|
||||||
64)) /
|
76)) /
|
||||||
2
|
2
|
||||||
: 0,
|
: 0,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -4,26 +4,24 @@ import { motion } from 'framer-motion';
|
|||||||
import { ReactNode, useState } from 'react';
|
import { ReactNode, useState } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
|
||||||
import { NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/NavDrawerWidths';
|
import { NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/NavDrawerWidths';
|
||||||
|
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||||
|
|
||||||
import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer';
|
import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer';
|
||||||
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
|
|
||||||
import { isNavigationDrawerExpandedState } from '../../states/isNavigationDrawerExpanded';
|
import { isNavigationDrawerExpandedState } from '../../states/isNavigationDrawerExpanded';
|
||||||
import { NavigationDrawerBackButton } from './NavigationDrawerBackButton';
|
import { NavigationDrawerBackButton } from './NavigationDrawerBackButton';
|
||||||
import { NavigationDrawerHeader } from './NavigationDrawerHeader';
|
import { NavigationDrawerHeader } from './NavigationDrawerHeader';
|
||||||
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
|
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
|
||||||
|
|
||||||
export type NavigationDrawerProps = {
|
export type NavigationDrawerProps = {
|
||||||
children: ReactNode;
|
children?: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
footer?: ReactNode;
|
|
||||||
title: string;
|
title: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledAnimatedContainer = styled(motion.div)<{ isSettings?: boolean }>`
|
const StyledAnimatedContainer = styled(motion.div)`
|
||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
overflow: ${({ isSettings }) => (isSettings ? 'visible' : 'hidden')};
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledContainer = styled.div<{
|
const StyledContainer = styled.div<{
|
||||||
@ -33,35 +31,26 @@ const StyledContainer = styled.div<{
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: ${NAV_DRAWER_WIDTHS.menu.desktop.expanded}px;
|
width: ${({ isSettings }) =>
|
||||||
|
isSettings ? '100%' : NAV_DRAWER_WIDTHS.menu.desktop.expanded + 'px'};
|
||||||
gap: ${({ theme }) => theme.spacing(3)};
|
gap: ${({ theme }) => theme.spacing(3)};
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: ${({ theme, isSettings, isMobile }) =>
|
padding: ${({ theme, isSettings, isMobile }) =>
|
||||||
isSettings
|
isSettings
|
||||||
? isMobile
|
? isMobile
|
||||||
? theme.spacing(3, 8)
|
? theme.spacing(3, 0, 0, 8)
|
||||||
: theme.spacing(3, 8, 4, 0)
|
: theme.spacing(3, 0, 4, 0)
|
||||||
: theme.spacing(3, 2, 4)};
|
: theme.spacing(3, 0, 4, 2)};
|
||||||
padding-right: 0px;
|
|
||||||
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-left: 20px;
|
padding-left: ${({ theme }) => theme.spacing(5)};
|
||||||
padding-right: 20px;
|
padding-right: ${({ theme }) => theme.spacing(5)};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledItemsContainer = styled.div<{ isSettings?: boolean }>`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-bottom: auto;
|
|
||||||
overflow: hidden;
|
|
||||||
flex: 1;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const NavigationDrawer = ({
|
export const NavigationDrawer = ({
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
footer,
|
|
||||||
title,
|
title,
|
||||||
}: NavigationDrawerProps) => {
|
}: NavigationDrawerProps) => {
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
@ -99,7 +88,6 @@ export const NavigationDrawer = ({
|
|||||||
initial={false}
|
initial={false}
|
||||||
animate={navigationDrawerAnimate}
|
animate={navigationDrawerAnimate}
|
||||||
transition={{ duration: theme.animation.duration.normal }}
|
transition={{ duration: theme.animation.duration.normal }}
|
||||||
isSettings={isSettingsDrawer}
|
|
||||||
>
|
>
|
||||||
<StyledContainer
|
<StyledContainer
|
||||||
isSettings={isSettingsDrawer}
|
isSettings={isSettingsDrawer}
|
||||||
@ -112,10 +100,8 @@ export const NavigationDrawer = ({
|
|||||||
) : (
|
) : (
|
||||||
<NavigationDrawerHeader showCollapseButton={isHovered} />
|
<NavigationDrawerHeader showCollapseButton={isHovered} />
|
||||||
)}
|
)}
|
||||||
<StyledItemsContainer isSettings={isSettingsDrawer}>
|
|
||||||
{children}
|
{children}
|
||||||
</StyledItemsContainer>
|
|
||||||
<NavigationDrawerSection>{footer}</NavigationDrawerSection>
|
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</StyledAnimatedContainer>
|
</StyledAnimatedContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -39,6 +39,7 @@ const StyledContainer = styled.div`
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
height: ${({ theme }) => theme.spacing(8)};
|
height: ${({ theme }) => theme.spacing(8)};
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
padding-left: ${({ theme }) => theme.spacing(5)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const NavigationDrawerBackButton = ({
|
export const NavigationDrawerBackButton = ({
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer';
|
||||||
|
import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { useIsMobile } from 'twenty-ui/utilities';
|
||||||
|
|
||||||
|
const StyledFixedContainer = styled.div<{
|
||||||
|
isSettings?: boolean;
|
||||||
|
isMobile?: boolean;
|
||||||
|
}>`
|
||||||
|
${({ isSettings, theme, isMobile }) =>
|
||||||
|
isSettings
|
||||||
|
? `
|
||||||
|
padding-left: ${theme.spacing(5)};
|
||||||
|
padding-right: ${isMobile ? theme.spacing(5) : theme.spacing(8)};
|
||||||
|
`
|
||||||
|
: ''}
|
||||||
|
`;
|
||||||
|
export const NavigationDrawerFixedContent = ({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
}) => {
|
||||||
|
const isSettingsDrawer = useIsSettingsDrawer();
|
||||||
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledFixedContainer isSettings={isSettingsDrawer} isMobile={isMobile}>
|
||||||
|
<NavigationDrawerSection>{children}</NavigationDrawerSection>
|
||||||
|
</StyledFixedContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer';
|
||||||
|
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { useIsMobile } from 'twenty-ui/utilities';
|
||||||
|
|
||||||
|
const StyledItemsContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledScrollableInnerContainer = styled.div<{ isMobile?: boolean }>`
|
||||||
|
height: 100%;
|
||||||
|
padding-left: ${({ theme }) => theme.spacing(5)};
|
||||||
|
padding-right: ${({ theme, isMobile }) =>
|
||||||
|
isMobile ? theme.spacing(5) : theme.spacing(8)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const NavigationDrawerScrollableContent = ({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
}) => {
|
||||||
|
const isSettingsDrawer = useIsSettingsDrawer();
|
||||||
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollWrapper
|
||||||
|
componentInstanceId={`scroll-wrapper-${
|
||||||
|
isSettingsDrawer ? 'settings-' : ''
|
||||||
|
}navigation-drawer`}
|
||||||
|
defaultEnableXScroll={false}
|
||||||
|
>
|
||||||
|
<StyledItemsContainer>
|
||||||
|
{isSettingsDrawer ? (
|
||||||
|
<StyledScrollableInnerContainer isMobile={isMobile}>
|
||||||
|
{children}
|
||||||
|
</StyledScrollableInnerContainer>
|
||||||
|
) : (
|
||||||
|
<>{children}</>
|
||||||
|
)}
|
||||||
|
</StyledItemsContainer>
|
||||||
|
</ScrollWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,21 +1,22 @@
|
|||||||
|
import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useIsMobile } from 'twenty-ui/utilities';
|
import { useIsMobile } from 'twenty-ui/utilities';
|
||||||
|
|
||||||
const StyledSection = styled.div`
|
const StyledSection = styled.div<{ isSettingsDrawer?: boolean }>`
|
||||||
|
margin-bottom: ${({ theme, isSettingsDrawer }) =>
|
||||||
|
isSettingsDrawer ? theme.spacing(3) : 0};
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: ${({ theme }) => theme.spacing(3)};
|
|
||||||
flex-shrink: 1;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledSectionInnerContainerMinusScrollPadding = styled.div<{
|
const StyledSectionInnerContainerMinusScrollPadding = styled.div<{
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
|
isSettingsDrawer: boolean;
|
||||||
}>`
|
}>`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: ${({ theme }) => theme.betweenSiblingsGap};
|
gap: ${({ theme }) => theme.betweenSiblingsGap};
|
||||||
width: calc(
|
width: ${({ isMobile, theme, isSettingsDrawer }) =>
|
||||||
100% - ${({ isMobile, theme }) => (isMobile ? 0 : theme.spacing(2))}
|
`calc(100% - ${isMobile || isSettingsDrawer ? 0 : theme.spacing(2)})`};
|
||||||
);
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const NavigationDrawerSection = ({
|
export const NavigationDrawerSection = ({
|
||||||
@ -24,9 +25,13 @@ export const NavigationDrawerSection = ({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
|
const isSettingsDrawer = useIsSettingsDrawer();
|
||||||
return (
|
return (
|
||||||
<StyledSection>
|
<StyledSection isSettingsDrawer={isSettingsDrawer}>
|
||||||
<StyledSectionInnerContainerMinusScrollPadding isMobile={isMobile}>
|
<StyledSectionInnerContainerMinusScrollPadding
|
||||||
|
isMobile={isMobile}
|
||||||
|
isSettingsDrawer={isSettingsDrawer}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</StyledSectionInnerContainerMinusScrollPadding>
|
</StyledSectionInnerContainerMinusScrollPadding>
|
||||||
</StyledSection>
|
</StyledSection>
|
||||||
|
|||||||
@ -16,16 +16,8 @@ import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedM
|
|||||||
import { mockedWorkspaceMemberData } from '~/testing/mock-data/users';
|
import { mockedWorkspaceMemberData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
import { CurrentWorkspaceMemberFavoritesFolders } from '@/favorites/components/CurrentWorkspaceMemberFavoritesFolders';
|
import { CurrentWorkspaceMemberFavoritesFolders } from '@/favorites/components/CurrentWorkspaceMemberFavoritesFolders';
|
||||||
|
import { NavigationDrawerFixedContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerFixedContent';
|
||||||
import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem';
|
import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem';
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
|
||||||
import jsonPage from '../../../../../../../package.json';
|
|
||||||
import { NavigationDrawer } from '../NavigationDrawer';
|
|
||||||
import { NavigationDrawerItem } from '../NavigationDrawerItem';
|
|
||||||
import { NavigationDrawerItemGroup } from '../NavigationDrawerItemGroup';
|
|
||||||
import { NavigationDrawerSection } from '../NavigationDrawerSection';
|
|
||||||
import { NavigationDrawerSectionTitle } from '../NavigationDrawerSectionTitle';
|
|
||||||
import { GithubVersionLink } from 'twenty-ui/navigation';
|
|
||||||
import {
|
import {
|
||||||
IconAt,
|
IconAt,
|
||||||
IconBell,
|
IconBell,
|
||||||
@ -42,7 +34,16 @@ import {
|
|||||||
IconUserCircle,
|
IconUserCircle,
|
||||||
IconUsers,
|
IconUsers,
|
||||||
} from 'twenty-ui/display';
|
} from 'twenty-ui/display';
|
||||||
|
import { GithubVersionLink } from 'twenty-ui/navigation';
|
||||||
import { getOsControlSymbol } from 'twenty-ui/utilities';
|
import { getOsControlSymbol } from 'twenty-ui/utilities';
|
||||||
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
|
import jsonPage from '../../../../../../../package.json';
|
||||||
|
import { NavigationDrawer } from '../NavigationDrawer';
|
||||||
|
import { NavigationDrawerItem } from '../NavigationDrawerItem';
|
||||||
|
import { NavigationDrawerItemGroup } from '../NavigationDrawerItemGroup';
|
||||||
|
import { NavigationDrawerSection } from '../NavigationDrawerSection';
|
||||||
|
import { NavigationDrawerSectionTitle } from '../NavigationDrawerSectionTitle';
|
||||||
|
|
||||||
const meta: Meta<typeof NavigationDrawer> = {
|
const meta: Meta<typeof NavigationDrawer> = {
|
||||||
title: 'UI/Navigation/NavigationDrawer/NavigationDrawer',
|
title: 'UI/Navigation/NavigationDrawer/NavigationDrawer',
|
||||||
@ -71,7 +72,7 @@ const meta: Meta<typeof NavigationDrawer> = {
|
|||||||
layout: 'fullscreen',
|
layout: 'fullscreen',
|
||||||
msw: graphqlMocks,
|
msw: graphqlMocks,
|
||||||
},
|
},
|
||||||
argTypes: { children: { control: false }, footer: { control: false } },
|
argTypes: { children: { control: false } },
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
@ -79,6 +80,7 @@ type Story = StoryObj<typeof NavigationDrawer>;
|
|||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
|
title: 'Default',
|
||||||
children: (
|
children: (
|
||||||
<>
|
<>
|
||||||
<NavigationDrawerSection>
|
<NavigationDrawerSection>
|
||||||
@ -121,7 +123,6 @@ export const Default: Story = {
|
|||||||
</NavigationDrawerSection>
|
</NavigationDrawerSection>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
footer: null,
|
|
||||||
},
|
},
|
||||||
play: async () => {
|
play: async () => {
|
||||||
const canvas = within(document.body);
|
const canvas = within(document.body);
|
||||||
@ -191,9 +192,12 @@ export const Settings: Story = {
|
|||||||
Icon={IconServer}
|
Icon={IconServer}
|
||||||
/>
|
/>
|
||||||
</NavigationDrawerSection>
|
</NavigationDrawerSection>
|
||||||
|
|
||||||
|
<NavigationDrawerFixedContent>
|
||||||
|
<GithubVersionLink version={jsonPage.version} />
|
||||||
|
</NavigationDrawerFixedContent>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
footer: <GithubVersionLink version={jsonPage.version} />,
|
|
||||||
},
|
},
|
||||||
play: async () => {
|
play: async () => {
|
||||||
const canvas = within(document.body);
|
const canvas = within(document.body);
|
||||||
|
|||||||
Reference in New Issue
Block a user