Navbar with AI chats (#18161)
## Summary Add Home/Chat tabs and a dedicated threads list in the navigation drawer. ## Changes - **Navbar tabs:** Tabs in the drawer to switch between Home and Chat (with “New chat” button). Shown on desktop when expanded and on mobile below the workspace selector. - **Navbar threads list:** New `NavigationDrawerAIChatThreadsList` for the Chat tab with date groups (Today / Yesterday / Older), thread rows as `NavigationDrawerItem` (IconComment, title, timestamp). Shared `useAIChatThreadClick` hook used by navbar and command menu; navbar passes `resetNavigationStack: true`. - **NavigationDrawerItem:** New `alwaysShowRightOptions` prop so the timestamp is always visible (no hover-only). --------- Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com> Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
+35
-21
@@ -2,13 +2,11 @@ import { DEFAULT_WORKSPACE_LOGO } from '@/ui/navigation/navigation-drawer/consta
|
||||
|
||||
import { useAuth } from '@/auth/hooks/useAuth';
|
||||
import { availableWorkspacesState } from '@/auth/states/availableWorkspacesState';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { countAvailableWorkspaces } from '@/auth/utils/availableWorkspacesUtils';
|
||||
import { supportChatState } from '@/client-config/states/supportChatState';
|
||||
import { useBuildWorkspaceUrl } from '@/domain-manager/hooks/useBuildWorkspaceUrl';
|
||||
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
||||
import { supportChatState } from '@/client-config/states/supportChatState';
|
||||
import { getDocumentationUrl } from '@/support/utils/getDocumentationUrl';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
@@ -19,22 +17,27 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { MULTI_WORKSPACE_DROPDOWN_ID } from '@/ui/navigation/navigation-drawer/constants/MultiWorkspaceDropdownId';
|
||||
import { multiWorkspaceDropdownState } from '@/ui/navigation/navigation-drawer/states/multiWorkspaceDropdownState';
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
import { navigationDrawerExpandedMemorizedState } from '@/ui/navigation/states/navigationDrawerExpandedMemorizedState';
|
||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||
import { useColorScheme } from '@/ui/theme/hooks/useColorScheme';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { type ApolloError } from '@apollo/client';
|
||||
import styled from '@emotion/styled';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { AppPath, SettingsPath } from 'twenty-shared/types';
|
||||
import { getSettingsPath } from 'twenty-shared/utils';
|
||||
import {
|
||||
Avatar,
|
||||
IconDotsVertical,
|
||||
IconHelpCircle,
|
||||
IconLogout,
|
||||
IconMessage,
|
||||
IconPlus,
|
||||
IconSettings,
|
||||
IconSwitchHorizontal,
|
||||
IconUserPlus,
|
||||
} from 'twenty-ui/display';
|
||||
@@ -57,7 +60,6 @@ const StyledDescription = styled.div`
|
||||
|
||||
export const MultiWorkspaceDropdownDefaultComponents = () => {
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState);
|
||||
const { t } = useLingui();
|
||||
const { redirectToWorkspaceDomain } = useRedirectToWorkspaceDomain();
|
||||
const availableWorkspaces = useAtomStateValue(availableWorkspacesState);
|
||||
@@ -79,19 +81,21 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
||||
multiWorkspaceDropdownState,
|
||||
);
|
||||
|
||||
const location = useLocation();
|
||||
const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] =
|
||||
useAtomState(isNavigationDrawerExpandedState);
|
||||
const setNavigationDrawerExpandedMemorized = useSetAtomState(
|
||||
navigationDrawerExpandedMemorizedState,
|
||||
);
|
||||
const setNavigationMemorizedUrl = useSetAtomState(
|
||||
navigationMemorizedUrlState,
|
||||
);
|
||||
|
||||
const handleSupport = () => {
|
||||
window.FrontChat?.('show');
|
||||
closeDropdown(MULTI_WORKSPACE_DROPDOWN_ID);
|
||||
};
|
||||
|
||||
const handleDocumentation = () => {
|
||||
window.open(
|
||||
getDocumentationUrl({ locale: currentWorkspaceMember?.locale }),
|
||||
'_blank',
|
||||
);
|
||||
closeDropdown(MULTI_WORKSPACE_DROPDOWN_ID);
|
||||
};
|
||||
|
||||
const handleChange = async (availableWorkspace: AvailableWorkspace) => {
|
||||
redirectToWorkspaceDomain(
|
||||
getWorkspaceUrl(availableWorkspace.workspaceUrls),
|
||||
@@ -149,6 +153,11 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
||||
text={t`Create Workspace`}
|
||||
onClick={createWorkspace}
|
||||
/>
|
||||
<MenuItem
|
||||
LeftIcon={IconLogout}
|
||||
text={t`Log out`}
|
||||
onClick={signOut}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
@@ -223,6 +232,17 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
||||
>
|
||||
<MenuItem LeftIcon={IconUserPlus} text={t`Invite user`} />
|
||||
</UndecoratedLink>
|
||||
<UndecoratedLink
|
||||
to={getSettingsPath(SettingsPath.ProfilePage)}
|
||||
onClick={() => {
|
||||
setNavigationDrawerExpandedMemorized(isNavigationDrawerExpanded);
|
||||
setIsNavigationDrawerExpanded(true);
|
||||
setNavigationMemorizedUrl(location.pathname + location.search);
|
||||
closeDropdown(MULTI_WORKSPACE_DROPDOWN_ID);
|
||||
}}
|
||||
>
|
||||
<MenuItem LeftIcon={IconSettings} text={t`Settings`} />
|
||||
</UndecoratedLink>
|
||||
{isSupportChatConfigured && (
|
||||
<MenuItem
|
||||
LeftIcon={IconMessage}
|
||||
@@ -230,12 +250,6 @@ export const MultiWorkspaceDropdownDefaultComponents = () => {
|
||||
onClick={handleSupport}
|
||||
/>
|
||||
)}
|
||||
<MenuItem
|
||||
LeftIcon={IconHelpCircle}
|
||||
text={t`Documentation`}
|
||||
onClick={handleDocumentation}
|
||||
/>
|
||||
<MenuItem LeftIcon={IconLogout} text={t`Log out`} onClick={signOut} />
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
);
|
||||
|
||||
+18
-19
@@ -3,19 +3,22 @@ import { type ReactNode, useState } from 'react';
|
||||
|
||||
import { useIsSettingsDrawer } from '@/navigation/hooks/useIsSettingsDrawer';
|
||||
import { tableWidthResizeIsActiveState } from '@/object-record/record-table/states/tableWidthResizeIsActivedState';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { ResizablePanelEdge } from '@/ui/layout/resizable-panel/components/ResizablePanelEdge';
|
||||
import { NAVIGATION_DRAWER_COLLAPSED_WIDTH } from '@/ui/layout/resizable-panel/constants/NavigationDrawerCollapsedWidth';
|
||||
import { NAVIGATION_DRAWER_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/NavigationDrawerConstraints';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
|
||||
import { NavigationDrawerWidthEffect } from '@/ui/navigation/components/NavigationDrawerWidthEffect';
|
||||
import { NAVIGATION_DRAWER_CLICK_OUTSIDE_ID } from '@/ui/navigation/navigation-drawer/constants/NavigationDrawerClickOutsideId';
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
import { navigationDrawerActiveTabState } from '@/ui/navigation/states/navigationDrawerActiveTabState';
|
||||
import { NAVIGATION_DRAWER_TABS } from '@/ui/navigation/states/navigationDrawerTabs';
|
||||
import {
|
||||
NAVIGATION_DRAWER_WIDTH_VAR,
|
||||
navigationDrawerWidthState,
|
||||
} from '@/ui/navigation/states/navigationDrawerWidthState';
|
||||
import { NavigationDrawerWidthEffect } from '@/ui/navigation/components/NavigationDrawerWidthEffect';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
|
||||
import { NavigationDrawerBackButton } from './NavigationDrawerBackButton';
|
||||
import { NavigationDrawerHeader } from './NavigationDrawerHeader';
|
||||
|
||||
@@ -47,11 +50,13 @@ const StyledAnimatedContainer = styled.div<{
|
||||
const StyledContainer = styled.div<{
|
||||
isSettings?: boolean;
|
||||
isMobile?: boolean;
|
||||
isExpanded?: boolean;
|
||||
}>`
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: var(${NAVIGATION_DRAWER_WIDTH_VAR});
|
||||
width: ${({ isExpanded }) =>
|
||||
isExpanded ? `var(${NAVIGATION_DRAWER_WIDTH_VAR})` : '100%'};
|
||||
gap: ${({ theme }) => theme.spacing(3)};
|
||||
height: 100%;
|
||||
padding: ${({ theme, isSettings, isMobile }) =>
|
||||
@@ -72,7 +77,6 @@ export const NavigationDrawer = ({
|
||||
className,
|
||||
title,
|
||||
}: NavigationDrawerProps) => {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const [isResizing, setIsResizing] = useState(false);
|
||||
const isMobile = useIsMobile();
|
||||
const isSettingsDrawer = useIsSettingsDrawer();
|
||||
@@ -82,20 +86,16 @@ export const NavigationDrawer = ({
|
||||
const [navigationDrawerWidth, setNavigationDrawerWidth] = useAtomState(
|
||||
navigationDrawerWidthState,
|
||||
);
|
||||
const setNavigationDrawerActiveTab = useSetAtomState(
|
||||
navigationDrawerActiveTabState,
|
||||
);
|
||||
const setTableWidthResizeIsActive = useSetAtomState(
|
||||
tableWidthResizeIsActiveState,
|
||||
);
|
||||
|
||||
const handleHover = () => {
|
||||
setIsHovered(true);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
setIsHovered(false);
|
||||
};
|
||||
|
||||
const handleCollapse = () => {
|
||||
setIsNavigationDrawerExpanded(false);
|
||||
setNavigationDrawerActiveTab(NAVIGATION_DRAWER_TABS.NAVIGATION_MENU);
|
||||
setIsResizing(false);
|
||||
setTableWidthResizeIsActive(true);
|
||||
};
|
||||
@@ -116,21 +116,20 @@ export const NavigationDrawer = ({
|
||||
<NavigationDrawerWidthEffect />
|
||||
<StyledAnimatedContainer
|
||||
className={className}
|
||||
data-click-outside-id={NAVIGATION_DRAWER_CLICK_OUTSIDE_ID}
|
||||
isExpanded={isNavigationDrawerExpanded}
|
||||
isResizing={isResizing}
|
||||
>
|
||||
<StyledContainer
|
||||
isSettings={isSettingsDrawer}
|
||||
isMobile={isMobile}
|
||||
onMouseEnter={handleHover}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
isExpanded={isNavigationDrawerExpanded}
|
||||
>
|
||||
{isSettingsDrawer && title ? (
|
||||
!isMobile && <NavigationDrawerBackButton title={title} />
|
||||
) : (
|
||||
<NavigationDrawerHeader showCollapseButton={isHovered} />
|
||||
<NavigationDrawerHeader showCollapseButton />
|
||||
)}
|
||||
|
||||
{children}
|
||||
</StyledContainer>
|
||||
|
||||
|
||||
+16
-11
@@ -1,4 +1,7 @@
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
import { navigationDrawerActiveTabState } from '@/ui/navigation/states/navigationDrawerActiveTabState';
|
||||
import { NAVIGATION_DRAWER_TABS } from '@/ui/navigation/states/navigationDrawerTabs';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
@@ -26,26 +29,28 @@ export const NavigationDrawerCollapseButton = ({
|
||||
className,
|
||||
direction = 'left',
|
||||
}: NavigationDrawerCollapseButtonProps) => {
|
||||
const setIsNavigationDrawerExpanded = useSetAtomState(
|
||||
isNavigationDrawerExpandedState,
|
||||
const [isNavigationDrawerExpanded, setIsNavigationDrawerExpanded] =
|
||||
useAtomState(isNavigationDrawerExpandedState);
|
||||
const setNavigationDrawerActiveTab = useSetAtomState(
|
||||
navigationDrawerActiveTabState,
|
||||
);
|
||||
|
||||
const handleClick = () => {
|
||||
if (isNavigationDrawerExpanded) {
|
||||
setNavigationDrawerActiveTab(NAVIGATION_DRAWER_TABS.NAVIGATION_MENU);
|
||||
}
|
||||
setIsNavigationDrawerExpanded((previousIsExpanded) => !previousIsExpanded);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledCollapseButton
|
||||
className={className}
|
||||
onClick={() =>
|
||||
setIsNavigationDrawerExpanded(
|
||||
(previousIsExpanded) => !previousIsExpanded,
|
||||
)
|
||||
}
|
||||
>
|
||||
<StyledCollapseButton className={className} onClick={handleClick}>
|
||||
<LightIconButton
|
||||
Icon={
|
||||
direction === 'left'
|
||||
? IconLayoutSidebarLeftCollapse
|
||||
: IconLayoutSidebarRightCollapse
|
||||
}
|
||||
accent="tertiary"
|
||||
accent="secondary"
|
||||
size="small"
|
||||
/>
|
||||
</StyledCollapseButton>
|
||||
|
||||
+37
-17
@@ -1,30 +1,42 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconSearch } from 'twenty-ui/display';
|
||||
import { LightIconButton } from 'twenty-ui/input';
|
||||
|
||||
import { MultiWorkspaceDropdownButton } from '@/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/MultiWorkspaceDropdownButton';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
|
||||
import { useOpenRecordsSearchPageInCommandMenu } from '@/command-menu/hooks/useOpenRecordsSearchPageInCommandMenu';
|
||||
import { PAGE_BAR_MIN_HEIGHT } from '@/ui/layout/page/constants/PageBarMinHeight';
|
||||
import { MultiWorkspaceDropdownButton } from '@/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/MultiWorkspaceDropdownButton';
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { NavigationDrawerCollapseButton } from './NavigationDrawerCollapseButton';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
const StyledContainer = styled.div<{ isExpanded: boolean }>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: ${({ isExpanded }) => (isExpanded ? 'row' : 'column')};
|
||||
gap: ${({ theme, isExpanded }) => (isExpanded ? 0 : theme.spacing(4))};
|
||||
user-select: none;
|
||||
padding-right: ${({ theme }) => theme.spacing(2)};
|
||||
min-height: ${PAGE_BAR_MIN_HEIGHT}px;
|
||||
transition: gap ${({ theme }) => theme.animation.duration.normal}s ease;
|
||||
`;
|
||||
|
||||
const StyledRightActions = styled.div<{ isExpanded: boolean }>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: ${({ isExpanded }) => (isExpanded ? 'row' : 'column')};
|
||||
gap: ${({ theme, isExpanded }) => (isExpanded ? 0 : theme.spacing(1))};
|
||||
margin-left: ${({ isExpanded }) => (isExpanded ? 'auto' : 0)};
|
||||
transition: gap ${({ theme }) => theme.animation.duration.normal}s ease;
|
||||
`;
|
||||
|
||||
const StyledNavigationDrawerCollapseButton = styled(
|
||||
NavigationDrawerCollapseButton,
|
||||
)<{ show?: boolean }>`
|
||||
height: ${({ theme }) => theme.spacing(4)};
|
||||
margin-left: auto;
|
||||
opacity: ${({ show }) => (show ? 1 : 0)};
|
||||
)`
|
||||
height: ${({ theme }) => theme.spacing(6)};
|
||||
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||
transition: opacity ${({ theme }) => theme.animation.duration.normal}s;
|
||||
width: ${({ theme }) => theme.spacing(4)};
|
||||
width: ${({ theme }) => theme.spacing(6)};
|
||||
`;
|
||||
|
||||
type NavigationDrawerHeaderProps = {
|
||||
@@ -35,19 +47,27 @@ export const NavigationDrawerHeader = ({
|
||||
showCollapseButton,
|
||||
}: NavigationDrawerHeaderProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const { openRecordsSearchPage } = useOpenRecordsSearchPageInCommandMenu();
|
||||
const isNavigationDrawerExpanded = useAtomStateValue(
|
||||
isNavigationDrawerExpandedState,
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledContainer isExpanded={isNavigationDrawerExpanded}>
|
||||
<MultiWorkspaceDropdownButton />
|
||||
{!isMobile && isNavigationDrawerExpanded && (
|
||||
<StyledNavigationDrawerCollapseButton
|
||||
direction="left"
|
||||
show={showCollapseButton}
|
||||
/>
|
||||
{!isMobile && (
|
||||
<StyledRightActions isExpanded={isNavigationDrawerExpanded}>
|
||||
<LightIconButton
|
||||
Icon={IconSearch}
|
||||
accent="secondary"
|
||||
size="small"
|
||||
onClick={openRecordsSearchPage}
|
||||
aria-label={t`Search`}
|
||||
/>
|
||||
{isNavigationDrawerExpanded && showCollapseButton && (
|
||||
<StyledNavigationDrawerCollapseButton direction="left" />
|
||||
)}
|
||||
</StyledRightActions>
|
||||
)}
|
||||
</StyledContainer>
|
||||
);
|
||||
|
||||
+7
-2
@@ -51,6 +51,7 @@ export type NavigationDrawerItemProps = {
|
||||
count?: number;
|
||||
keyboard?: string[];
|
||||
rightOptions?: ReactNode;
|
||||
alwaysShowRightOptions?: boolean;
|
||||
isDragging?: boolean;
|
||||
isRightOptionsDropdownOpen?: boolean;
|
||||
triggerEvent?: TriggerEventType;
|
||||
@@ -257,6 +258,7 @@ const visibleStateStyles = css`
|
||||
const StyledRightOptionsVisbility = styled.div<{
|
||||
isMobile: boolean;
|
||||
isRightOptionsDropdownOpen?: boolean;
|
||||
alwaysVisible?: boolean;
|
||||
}>`
|
||||
display: block;
|
||||
opacity: 0;
|
||||
@@ -269,8 +271,9 @@ const StyledRightOptionsVisbility = styled.div<{
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
|
||||
${({ isMobile, isRightOptionsDropdownOpen }) =>
|
||||
(isMobile || isRightOptionsDropdownOpen) && visibleStateStyles}
|
||||
${({ isMobile, isRightOptionsDropdownOpen, alwaysVisible }) =>
|
||||
(isMobile || isRightOptionsDropdownOpen || alwaysVisible) &&
|
||||
visibleStateStyles}
|
||||
|
||||
.navigation-drawer-item:hover & {
|
||||
${visibleStateStyles}
|
||||
@@ -294,6 +297,7 @@ export const NavigationDrawerItem = ({
|
||||
keyboard,
|
||||
subItemState,
|
||||
rightOptions,
|
||||
alwaysShowRightOptions = false,
|
||||
isDragging,
|
||||
isRightOptionsDropdownOpen,
|
||||
triggerEvent,
|
||||
@@ -456,6 +460,7 @@ export const NavigationDrawerItem = ({
|
||||
}}
|
||||
>
|
||||
<StyledRightOptionsVisbility
|
||||
alwaysVisible={alwaysShowRightOptions}
|
||||
isMobile={isMobile}
|
||||
isRightOptionsDropdownOpen={
|
||||
isRightOptionsDropdownOpen || false
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
export const NAVIGATION_DRAWER_CLICK_OUTSIDE_ID = 'navigation-drawer';
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
|
||||
|
||||
import {
|
||||
type NavigationDrawerActiveTab,
|
||||
NAVIGATION_DRAWER_TABS,
|
||||
} from '@/ui/navigation/states/navigationDrawerTabs';
|
||||
|
||||
export const navigationDrawerActiveTabState =
|
||||
createAtomState<NavigationDrawerActiveTab>({
|
||||
key: 'navigationDrawerActiveTab',
|
||||
defaultValue: NAVIGATION_DRAWER_TABS.NAVIGATION_MENU,
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
export const NAVIGATION_DRAWER_TABS = {
|
||||
NAVIGATION_MENU: 'home',
|
||||
AI_CHAT_HISTORY: 'chat',
|
||||
} as const;
|
||||
|
||||
export type NavigationDrawerActiveTab =
|
||||
(typeof NAVIGATION_DRAWER_TABS)[keyof typeof NAVIGATION_DRAWER_TABS];
|
||||
Reference in New Issue
Block a user