diff --git a/src/apps/chat/components/message/ChatMessage.tsx b/src/apps/chat/components/message/ChatMessage.tsx index 45ad5d794..41880e3b2 100644 --- a/src/apps/chat/components/message/ChatMessage.tsx +++ b/src/apps/chat/components/message/ChatMessage.tsx @@ -48,7 +48,7 @@ import { parseBlocks } from './blocks'; // How long is the user collapsed message const USER_COLLAPSED_LINES: number = 8; -// Enable the automatic menu on text selection +// Enable the menu on text selection const ENABLE_SELECTION_RIGHT_CLICK_MENU: boolean = true; // Enable the hover button to copy the whole message. The Copy button is also available in Blocks, or in the Avatar Menu. diff --git a/src/common/app.nav.ts b/src/common/app.nav.ts index add12385c..35cca0ba7 100644 --- a/src/common/app.nav.ts +++ b/src/common/app.nav.ts @@ -13,13 +13,14 @@ import EventNoteIcon from '@mui/icons-material/EventNote'; import EventNoteOutlinedIcon from '@mui/icons-material/EventNoteOutlined'; import FormatPaintIcon from '@mui/icons-material/FormatPaint'; import FormatPaintOutlinedIcon from '@mui/icons-material/FormatPaintOutlined'; +import ImageIcon from '@mui/icons-material/Image'; +import ImageOutlinedIcon from '@mui/icons-material/ImageOutlined'; +import IosShareIcon from '@mui/icons-material/IosShare'; +import IosShareOutlinedIcon from '@mui/icons-material/IosShareOutlined'; import TextsmsIcon from '@mui/icons-material/Textsms'; import TextsmsOutlinedIcon from '@mui/icons-material/TextsmsOutlined'; import WorkspacesIcon from '@mui/icons-material/Workspaces'; import WorkspacesOutlinedIcon from '@mui/icons-material/WorkspacesOutlined'; -// Automatic apps -import ImageOutlinedIcon from '@mui/icons-material/ImageOutlined'; -import IosShareIcon from '@mui/icons-material/IosShare'; // Link icons import GitHubIcon from '@mui/icons-material/GitHub'; import { DiscordIcon } from '~/common/components/icons/DiscordIcon'; @@ -29,11 +30,14 @@ import SettingsIcon from '@mui/icons-material/Settings'; import { Brand } from '~/common/app.config'; +import { hasNoChatLinkItems } from '~/modules/trade/chatlink/store-chatlink'; // enable to show all items, for layout development const SHOW_ALL_APPS = false; +const SPECIAL_DIVIDER = '__DIVIDER__'; + // Nav items @@ -47,12 +51,14 @@ interface ItemBase { export interface NavItemApp extends ItemBase { type: 'app', route: string, + landingRoute?: string, // specify a different route than the nextjs page router route, to land to barTitle?: string, // set to override the name as the bar title (unless custom bar content is used) + hideIcon?: boolean + | (() => boolean), // set to true to hide the icon, unless this is the active app hideBar?: boolean, // set to true to hide the page bar hideDrawer?: boolean, // set to true to hide the drawer - hideNav?: boolean, // set to hide the Nav bar (note: must have a way to navigate back) - hideOnMobile?: boolean, // set to true to hide on mobile - automatic?: boolean, // only accessible by the machine + hideNav?: boolean + | (() => boolean), // set to hide the Nav bar (note: must have a way to navigate back) fullWidth?: boolean, // set to true to override the user preference _delete?: boolean, // delete from the UI } @@ -131,6 +137,13 @@ export const navItems: { route: '/workspace', _delete: true, }, + // <-- divider here --> + { + name: SPECIAL_DIVIDER, + type: 'app', + route: SPECIAL_DIVIDER, + icon: () => null, + }, { name: 'Personas', icon: Diversity2OutlinedIcon, @@ -139,6 +152,24 @@ export const navItems: { route: '/personas', hideBar: true, }, + { + name: 'Media Library', + icon: ImageOutlinedIcon, + iconActive: ImageIcon, + type: 'app', + route: '/media', + _delete: true, + }, + { + name: 'Shared Chat', + icon: IosShareOutlinedIcon, + iconActive: IosShareIcon, + type: 'app', + route: '/link/chat/[chatLinkId]', + landingRoute: '/link/chat/list', + hideIcon: hasNoChatLinkItems, + hideNav: hasNoChatLinkItems, + }, { name: 'News', icon: EventNoteOutlinedIcon, @@ -148,25 +179,6 @@ export const navItems: { hideBar: true, hideDrawer: true, }, - - // non-user-selectable ('automatic') Apps - { - name: 'Media Library', - icon: ImageOutlinedIcon, - type: 'app', - route: '/media', - automatic: true, - hideNav: true, - _delete: true, - }, - { - name: 'Shared Chat', - icon: IosShareIcon, - type: 'app', - route: '/link/chat/[chatLinkId]', - automatic: true, - hideNav: true, - }, ], // Modals @@ -210,4 +222,16 @@ export const navItems: { }; // apply UI filtering right away - do it here, once, and for all -navItems.apps = navItems.apps.filter(app => !app._delete || SHOW_ALL_APPS); \ No newline at end of file +navItems.apps = navItems.apps.filter(app => !app._delete || SHOW_ALL_APPS); + +export function checkDivider(app?: NavItemApp) { + return app?.name === SPECIAL_DIVIDER; +} + +export function checkVisibileIcon(app: NavItemApp, currentApp?: NavItemApp) { + return app === currentApp ? true : typeof app.hideIcon === 'function' ? !app.hideIcon() : !app.hideIcon; +} + +export function checkVisibleNav(app?: NavItemApp) { + return !app ? false : typeof app.hideNav === 'function' ? !app.hideNav() : !app.hideNav; +} \ No newline at end of file diff --git a/src/common/layout/optima/DesktopDrawer.tsx b/src/common/layout/optima/DesktopDrawer.tsx index c1c9482e5..0d43b194d 100644 --- a/src/common/layout/optima/DesktopDrawer.tsx +++ b/src/common/layout/optima/DesktopDrawer.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { Box, Sheet, styled } from '@mui/joy'; -import type { NavItemApp } from '~/common/app.nav'; +import { checkVisibleNav, NavItemApp } from '~/common/app.nav'; import { themeZIndexDesktopDrawer } from '~/common/app.theme'; import { useOptimaDrawers } from './useOptimaDrawers'; @@ -81,7 +81,7 @@ export function DesktopDrawer(props: { currentApp?: NavItemApp }) { }, [closeDrawer, currentAppUsesDrawer]); // [special case] remove in the future - const shallOpenNavForSharedLink = !props.currentApp?.hideDrawer && !!props.currentApp?.hideNav; + const shallOpenNavForSharedLink = !props.currentApp?.hideDrawer && checkVisibleNav(props.currentApp); React.useEffect(() => { if (shallOpenNavForSharedLink) openDrawer(); diff --git a/src/common/layout/optima/DesktopNav.tsx b/src/common/layout/optima/DesktopNav.tsx index 436422dde..5e9b34758 100644 --- a/src/common/layout/optima/DesktopNav.tsx +++ b/src/common/layout/optima/DesktopNav.tsx @@ -7,7 +7,7 @@ import MenuIcon from '@mui/icons-material/Menu'; import { useModelsStore } from '~/modules/llms/store-llms'; import { AgiSquircleIcon } from '~/common/components/icons/AgiSquircleIcon'; -import { NavItemApp, navItems } from '~/common/app.nav'; +import { checkDivider, checkVisibileIcon, NavItemApp, navItems } from '~/common/app.nav'; import { themeZIndexDesktopNav } from '~/common/app.theme'; import { BringTheLove } from './components/BringTheLove'; @@ -47,27 +47,29 @@ export function DesktopNav(props: { currentApp?: NavItemApp }) { // App items const navAppItems = React.useMemo(() => { - return navItems.apps.filter(app => !app.hideNav).map(item => { - const isActive = item === props.currentApp; - const isDrawerable = isActive && !item.hideDrawer; - const isPaneOpen = isDrawerable && isDrawerOpen; - const isNotForUser = !!item.automatic && !isActive; - return ( - - Router.push(item.route)} - className={`${navItemClasses.typeApp} ${isActive ? navItemClasses.active : ''} ${isPaneOpen ? navItemClasses.paneOpen : ''}`} - > - {/*{(isActive && item.iconActive) ? : }*/} - - - - ); - }) - // (disabled) add this code after the map to add a divider - .toSpliced(-2, 0, ); + return navItems.apps + .filter(_app => checkVisibileIcon(_app, props.currentApp)) + .map((app, appIdx) => { + const isActive = app === props.currentApp; + const isDrawerable = isActive && !app.hideDrawer; + const isPaneOpen = isDrawerable && isDrawerOpen; + + if (checkDivider(app)) + return ; + + return ( + + Router.push(app.landingRoute || app.route)} + className={`${navItemClasses.typeApp} ${isActive ? navItemClasses.active : ''} ${isPaneOpen ? navItemClasses.paneOpen : ''}`} + > + {/*{(isActive && app.iconActive) ? : }*/} + + + + ); + }); }, [props.currentApp, isDrawerOpen, toggleDrawer]); diff --git a/src/common/layout/optima/MobileNavListItem.tsx b/src/common/layout/optima/MobileNavListItem.tsx index 96c03ae0f..b0bac5b6c 100644 --- a/src/common/layout/optima/MobileNavListItem.tsx +++ b/src/common/layout/optima/MobileNavListItem.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import Router from 'next/router'; -import { Button, ButtonGroup, ListItem } from '@mui/joy'; +import { Button, ButtonGroup, ListItem, Tooltip } from '@mui/joy'; -import { NavItemApp, navItems } from '~/common/app.nav'; +import { checkDivider, checkVisibileIcon, NavItemApp, navItems } from '~/common/app.nav'; import { BringTheLove } from './components/BringTheLove'; @@ -27,17 +27,28 @@ export function MobileNavListItem(props: { currentApp?: NavItemApp }) { gap: 1, }} > - {navItems.apps.filter(app => !app.hideOnMobile && !app.hideNav).map(app => - , - )} + {navItems.apps + .filter(app => checkVisibileIcon(app)) + .map((app, appIdx) => { + const isActive = app === props.currentApp; + + if (checkDivider(app)) + return null; + // return ; + + return ( + + + + ); + })} {/* Group 2: Social Links */} diff --git a/src/common/layout/optima/OptimaLayout.tsx b/src/common/layout/optima/OptimaLayout.tsx index d745c6954..10a67d978 100644 --- a/src/common/layout/optima/OptimaLayout.tsx +++ b/src/common/layout/optima/OptimaLayout.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { useRouter } from 'next/router'; import { PanelGroup } from 'react-resizable-panels'; -import { navItems } from '~/common/app.nav'; +import { checkVisibleNav, navItems } from '~/common/app.nav'; import { useIsMobile } from '~/common/components/useMatchMedia'; import { DesktopDrawer } from './DesktopDrawer'; @@ -50,7 +50,7 @@ export function OptimaLayout(props: { suspendAutoModelsSetup?: boolean, children - {!currentApp?.hideNav && } + {checkVisibleNav(currentApp) && } diff --git a/src/common/layout/optima/PageBar.tsx b/src/common/layout/optima/PageBar.tsx index c47a93422..6de96e61b 100644 --- a/src/common/layout/optima/PageBar.tsx +++ b/src/common/layout/optima/PageBar.tsx @@ -9,7 +9,7 @@ import MenuIcon from '@mui/icons-material/Menu'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined'; -import type { NavItemApp } from '~/common/app.nav'; +import { checkVisibleNav, NavItemApp } from '~/common/app.nav'; import { AgiSquircleIcon } from '~/common/components/icons/AgiSquircleIcon'; import { Brand } from '~/common/app.config'; import { CloseableMenu } from '~/common/components/CloseableMenu'; @@ -125,10 +125,10 @@ export function PageBar(props: { currentApp?: NavItemApp, isMobile?: boolean, sx {/* [Mobile] Drawer button */} - {(!!props.isMobile || props.currentApp?.hideNav) && ( + {(!!props.isMobile || !checkVisibleNav(props.currentApp)) && ( - {(!appDrawerContent || props.currentApp?.hideNav) ? ( + {(!appDrawerContent || !checkVisibleNav(props.currentApp)) ? ( diff --git a/src/modules/trade/chatlink/store-chatlink.ts b/src/modules/trade/chatlink/store-chatlink.ts index d8d0324fe..1c4246312 100644 --- a/src/modules/trade/chatlink/store-chatlink.ts +++ b/src/modules/trade/chatlink/store-chatlink.ts @@ -64,3 +64,4 @@ export const useLinkStorageOwnerId = () => export const rememberChatLinkItem = useTradeStore.getState().rememberChatLinkItem; export const forgetChatLinkItem = useTradeStore.getState().forgetChatLinkItem; export const updateChatLinkDeletionKey = useTradeStore.getState().updateChatLinkDeletionKey; +export const hasNoChatLinkItems = () => !useTradeStore.getState().chatLinkItems.length;