mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Nav: functions for nav/icon visibility #356
This commit is contained in:
@@ -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.
|
||||
|
||||
+50
-26
@@ -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);
|
||||
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;
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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 (
|
||||
<Tooltip disableInteractive enterDelay={600} key={'n-m-' + item.route.slice(1)} title={item.name}>
|
||||
<DesktopNavIcon
|
||||
disabled={isNotForUser}
|
||||
variant={isActive ? 'solid' : undefined}
|
||||
onClick={isDrawerable ? toggleDrawer : () => Router.push(item.route)}
|
||||
className={`${navItemClasses.typeApp} ${isActive ? navItemClasses.active : ''} ${isPaneOpen ? navItemClasses.paneOpen : ''}`}
|
||||
>
|
||||
{/*{(isActive && item.iconActive) ? <item.iconActive /> : <item.icon />}*/}
|
||||
<item.icon />
|
||||
</DesktopNavIcon>
|
||||
</Tooltip>
|
||||
);
|
||||
})
|
||||
// (disabled) add this code after the map to add a divider
|
||||
.toSpliced(-2, 0, <Divider sx={{ my: 1, width: '50%', mx: 'auto' }} />);
|
||||
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 <Divider key={'div-' + appIdx} sx={{ my: 1, width: '50%', mx: 'auto' }} />;
|
||||
|
||||
return (
|
||||
<Tooltip key={'n-m-' + app.route.slice(1)} disableInteractive enterDelay={600} title={app.name}>
|
||||
<DesktopNavIcon
|
||||
variant={isActive ? 'solid' : undefined}
|
||||
onClick={isDrawerable ? toggleDrawer : () => Router.push(app.landingRoute || app.route)}
|
||||
className={`${navItemClasses.typeApp} ${isActive ? navItemClasses.active : ''} ${isPaneOpen ? navItemClasses.paneOpen : ''}`}
|
||||
>
|
||||
{/*{(isActive && app.iconActive) ? <app.iconActive /> : <app.icon />}*/}
|
||||
<app.icon />
|
||||
</DesktopNavIcon>
|
||||
</Tooltip>
|
||||
);
|
||||
});
|
||||
}, [props.currentApp, isDrawerOpen, toggleDrawer]);
|
||||
|
||||
|
||||
|
||||
@@ -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 =>
|
||||
<Button
|
||||
key={'app-' + app.name}
|
||||
disabled={!!app.automatic}
|
||||
size='sm'
|
||||
variant={app == props.currentApp ? 'soft' : 'solid'}
|
||||
onClick={() => Router.push(app.route)}
|
||||
>
|
||||
{app == props.currentApp ? app.name : <app.icon />}
|
||||
</Button>,
|
||||
)}
|
||||
{navItems.apps
|
||||
.filter(app => checkVisibileIcon(app))
|
||||
.map((app, appIdx) => {
|
||||
const isActive = app === props.currentApp;
|
||||
|
||||
if (checkDivider(app))
|
||||
return null;
|
||||
// return <Divider orientation='vertical' key={'div-' + appIdx} />;
|
||||
|
||||
return (
|
||||
<Tooltip key={'n-m-' + app.route.slice(1)} disableInteractive enterDelay={600} title={app.name}>
|
||||
<Button
|
||||
key={'app-' + app.name}
|
||||
size='sm'
|
||||
variant={isActive ? 'soft' : 'solid'}
|
||||
onClick={() => Router.push(app.landingRoute || app.route)}
|
||||
>
|
||||
{isActive ? app.name : <app.icon />}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</ButtonGroup>
|
||||
|
||||
{/* Group 2: Social Links */}
|
||||
|
||||
@@ -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
|
||||
|
||||
<PanelGroup direction='horizontal' id='desktop-layout'>
|
||||
|
||||
{!currentApp?.hideNav && <DesktopNav currentApp={currentApp} />}
|
||||
{checkVisibleNav(currentApp) && <DesktopNav currentApp={currentApp} />}
|
||||
|
||||
<DesktopDrawer currentApp={currentApp} />
|
||||
|
||||
|
||||
@@ -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
|
||||
<InvertedBar direction='horizontal' sx={props.sx}>
|
||||
|
||||
{/* [Mobile] Drawer button */}
|
||||
{(!!props.isMobile || props.currentApp?.hideNav) && (
|
||||
{(!!props.isMobile || !checkVisibleNav(props.currentApp)) && (
|
||||
<InvertedBarCornerItem>
|
||||
|
||||
{(!appDrawerContent || props.currentApp?.hideNav) ? (
|
||||
{(!appDrawerContent || !checkVisibleNav(props.currentApp)) ? (
|
||||
<IconButton component={Link} href={ROUTE_INDEX} noLinkStyle>
|
||||
<ArrowBackIcon />
|
||||
</IconButton>
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user