@lobehub/lobehub 2.0.0-next.319 → 2.0.0-next.320
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/changelog/v1.json +5 -0
- package/package.json +1 -1
- package/src/app/[variants]/(main)/home/_layout/Body/BottomMenu/index.tsx +4 -4
- package/src/app/[variants]/(main)/home/_layout/Header/components/Nav.tsx +5 -4
- package/src/config/routes/index.ts +104 -0
- package/src/features/CommandMenu/MainMenu.tsx +31 -55
- package/src/features/Conversation/hooks/useChatItemContextMenu.tsx +18 -3
- package/src/features/Electron/navigation/routeMetadata.ts +28 -23
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.320](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.319...v2.0.0-next.320)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-01-20**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **ShareModal**: Wrap ShareMessageModal with Provider in context menu.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **ShareModal**: Wrap ShareMessageModal with Provider in context menu, closes [#11434](https://github.com/lobehub/lobe-chat/issues/11434) [#11382](https://github.com/lobehub/lobe-chat/issues/11382) ([0d30e5f](https://github.com/lobehub/lobe-chat/commit/0d30e5f))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
## [Version 2.0.0-next.319](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.318...v2.0.0-next.319)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2026-01-20**</sup>
|
package/changelog/v1.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.320",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Flexbox } from '@lobehub/ui';
|
|
2
|
-
import { BrainCircuit, LibraryBigIcon, Settings } from 'lucide-react';
|
|
3
2
|
import { memo, useMemo } from 'react';
|
|
4
3
|
import { useTranslation } from 'react-i18next';
|
|
5
4
|
import { Link, useNavigate } from 'react-router-dom';
|
|
6
5
|
|
|
6
|
+
import { getRouteById } from '@/config/routes';
|
|
7
7
|
import NavItem from '@/features/NavPanel/components/NavItem';
|
|
8
8
|
import { useActiveTabKey } from '@/hooks/useActiveTabKey';
|
|
9
9
|
import { SidebarTabKey } from '@/store/global/initialState';
|
|
@@ -25,19 +25,19 @@ const BottomMenu = memo(() => {
|
|
|
25
25
|
() =>
|
|
26
26
|
[
|
|
27
27
|
{
|
|
28
|
-
icon:
|
|
28
|
+
icon: getRouteById('settings')!.icon,
|
|
29
29
|
key: SidebarTabKey.Setting,
|
|
30
30
|
title: t('tab.setting'),
|
|
31
31
|
url: '/settings',
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
|
-
icon:
|
|
34
|
+
icon: getRouteById('resource')!.icon,
|
|
35
35
|
key: SidebarTabKey.Resource,
|
|
36
36
|
title: t('tab.resource'),
|
|
37
37
|
url: '/resource',
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
|
-
icon:
|
|
40
|
+
icon: getRouteById('memory')!.icon,
|
|
41
41
|
key: SidebarTabKey.Memory,
|
|
42
42
|
title: t('tab.memory'),
|
|
43
43
|
url: '/memory',
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { Flexbox } from '@lobehub/ui';
|
|
4
|
-
import {
|
|
4
|
+
import { HomeIcon, SearchIcon } from 'lucide-react';
|
|
5
5
|
import { memo, useMemo } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { Link, useNavigate } from 'react-router-dom';
|
|
8
8
|
|
|
9
|
+
import { getRouteById } from '@/config/routes';
|
|
9
10
|
import { useActiveTabKey } from '@/hooks/useActiveTabKey';
|
|
10
11
|
import { useGlobalStore } from '@/store/global';
|
|
11
12
|
import { SidebarTabKey } from '@/store/global/initialState';
|
|
@@ -48,21 +49,21 @@ const Nav = memo(() => {
|
|
|
48
49
|
url: '/',
|
|
49
50
|
},
|
|
50
51
|
{
|
|
51
|
-
icon:
|
|
52
|
+
icon: getRouteById('page')!.icon,
|
|
52
53
|
key: SidebarTabKey.Pages,
|
|
53
54
|
title: t('tab.pages'),
|
|
54
55
|
url: '/page',
|
|
55
56
|
},
|
|
56
57
|
{
|
|
57
58
|
hidden: !showAiImage,
|
|
58
|
-
icon:
|
|
59
|
+
icon: getRouteById('image')!.icon,
|
|
59
60
|
key: SidebarTabKey.Image,
|
|
60
61
|
title: t('tab.aiImage'),
|
|
61
62
|
url: '/image',
|
|
62
63
|
},
|
|
63
64
|
{
|
|
64
65
|
hidden: !showMarket,
|
|
65
|
-
icon:
|
|
66
|
+
icon: getRouteById('community')!.icon,
|
|
66
67
|
key: SidebarTabKey.Community,
|
|
67
68
|
title: t('tab.community'),
|
|
68
69
|
url: '/community',
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BrainCircuit,
|
|
3
|
+
FilePenIcon,
|
|
4
|
+
Image,
|
|
5
|
+
LibraryBigIcon,
|
|
6
|
+
type LucideIcon,
|
|
7
|
+
Settings,
|
|
8
|
+
ShapesIcon,
|
|
9
|
+
} from 'lucide-react';
|
|
10
|
+
|
|
11
|
+
export interface NavigationRoute {
|
|
12
|
+
/** CMDK i18n key in common namespace */
|
|
13
|
+
cmdkKey: string;
|
|
14
|
+
/** Electron i18n key in electron namespace */
|
|
15
|
+
electronKey: string;
|
|
16
|
+
/** Route icon component */
|
|
17
|
+
icon: LucideIcon;
|
|
18
|
+
/** Unique route identifier */
|
|
19
|
+
id: string;
|
|
20
|
+
/** Keywords for CMDK search */
|
|
21
|
+
keywords?: string[];
|
|
22
|
+
/** Route path */
|
|
23
|
+
path: string;
|
|
24
|
+
/** Path prefix for checking current location */
|
|
25
|
+
pathPrefix: string;
|
|
26
|
+
/** Whether route supports dynamic titles (for specific items) */
|
|
27
|
+
useDynamicTitle?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Shared navigation route configuration
|
|
32
|
+
* Used by both Electron navigation and CommandMenu (CMDK)
|
|
33
|
+
*/
|
|
34
|
+
export const NAVIGATION_ROUTES: NavigationRoute[] = [
|
|
35
|
+
{
|
|
36
|
+
cmdkKey: 'cmdk.community',
|
|
37
|
+
electronKey: 'navigation.discover',
|
|
38
|
+
icon: ShapesIcon,
|
|
39
|
+
id: 'community',
|
|
40
|
+
keywords: ['discover', 'market', 'assistant', 'model', 'provider', 'mcp'],
|
|
41
|
+
path: '/community',
|
|
42
|
+
pathPrefix: '/community',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
cmdkKey: 'cmdk.painting',
|
|
46
|
+
electronKey: 'navigation.image',
|
|
47
|
+
icon: Image,
|
|
48
|
+
id: 'image',
|
|
49
|
+
keywords: ['painting', 'art', 'generate', 'draw'],
|
|
50
|
+
path: '/image',
|
|
51
|
+
pathPrefix: '/image',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
cmdkKey: 'cmdk.resource',
|
|
55
|
+
electronKey: 'navigation.resources',
|
|
56
|
+
icon: LibraryBigIcon,
|
|
57
|
+
id: 'resource',
|
|
58
|
+
keywords: ['knowledge', 'files', 'library', 'documents'],
|
|
59
|
+
path: '/resource',
|
|
60
|
+
pathPrefix: '/resource',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
cmdkKey: 'cmdk.pages',
|
|
64
|
+
electronKey: 'navigation.pages',
|
|
65
|
+
icon: FilePenIcon,
|
|
66
|
+
id: 'page',
|
|
67
|
+
keywords: ['documents', 'write', 'notes'],
|
|
68
|
+
path: '/page',
|
|
69
|
+
pathPrefix: '/page',
|
|
70
|
+
useDynamicTitle: true,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
cmdkKey: 'cmdk.memory',
|
|
74
|
+
electronKey: 'navigation.memory',
|
|
75
|
+
icon: BrainCircuit,
|
|
76
|
+
id: 'memory',
|
|
77
|
+
keywords: ['identities', 'contexts', 'preferences', 'experiences'],
|
|
78
|
+
path: '/memory',
|
|
79
|
+
pathPrefix: '/memory',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
cmdkKey: 'cmdk.settings',
|
|
83
|
+
electronKey: 'navigation.settings',
|
|
84
|
+
icon: Settings,
|
|
85
|
+
id: 'settings',
|
|
86
|
+
keywords: ['settings', 'preferences', 'configuration', 'options'],
|
|
87
|
+
path: '/settings',
|
|
88
|
+
pathPrefix: '/settings',
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get route configuration by id
|
|
94
|
+
*/
|
|
95
|
+
export const getRouteById = (id: string): NavigationRoute | undefined =>
|
|
96
|
+
NAVIGATION_ROUTES.find((r) => r.id === id);
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get navigable routes for CMDK (excludes settings which has separate handling)
|
|
100
|
+
*/
|
|
101
|
+
export const getNavigableRoutes = (): NavigationRoute[] =>
|
|
102
|
+
NAVIGATION_ROUTES.filter((r) =>
|
|
103
|
+
['community', 'image', 'resource', 'page', 'memory'].includes(r.id),
|
|
104
|
+
);
|
|
@@ -3,21 +3,18 @@ import { DiscordIcon } from '@lobehub/ui/icons';
|
|
|
3
3
|
import { Command } from 'cmdk';
|
|
4
4
|
import {
|
|
5
5
|
Bot,
|
|
6
|
-
BrainCircuit,
|
|
7
6
|
FilePen,
|
|
8
7
|
Github,
|
|
9
|
-
Image,
|
|
10
8
|
LibraryBig,
|
|
11
9
|
MailIcon,
|
|
12
10
|
MessageSquarePlusIcon,
|
|
13
11
|
Monitor,
|
|
14
|
-
Settings,
|
|
15
|
-
Shapes,
|
|
16
12
|
Star,
|
|
17
13
|
} from 'lucide-react';
|
|
18
14
|
import { memo } from 'react';
|
|
19
15
|
import { useTranslation } from 'react-i18next';
|
|
20
16
|
|
|
17
|
+
import { getNavigableRoutes, getRouteById } from '@/config/routes';
|
|
21
18
|
import { FEEDBACK } from '@/const/url';
|
|
22
19
|
import { useFeedbackModal } from '@/hooks/useFeedbackModal';
|
|
23
20
|
|
|
@@ -88,16 +85,20 @@ const MainMenu = memo(() => {
|
|
|
88
85
|
{t('cmdk.newLibrary')}
|
|
89
86
|
</CommandItem>
|
|
90
87
|
|
|
91
|
-
{menuContext !== 'settings' && (
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
88
|
+
{menuContext !== 'settings' && (() => {
|
|
89
|
+
const settingsRoute = getRouteById('settings');
|
|
90
|
+
const SettingsIcon = settingsRoute?.icon;
|
|
91
|
+
return (
|
|
92
|
+
<CommandItem
|
|
93
|
+
icon={SettingsIcon && <SettingsIcon />}
|
|
94
|
+
keywords={settingsRoute?.keywords}
|
|
95
|
+
onSelect={() => handleNavigate(settingsRoute?.path || '/settings')}
|
|
96
|
+
value="settings"
|
|
97
|
+
>
|
|
98
|
+
{t('cmdk.settings')}
|
|
99
|
+
</CommandItem>
|
|
100
|
+
);
|
|
101
|
+
})()}
|
|
101
102
|
|
|
102
103
|
<CommandItem
|
|
103
104
|
icon={<Monitor />}
|
|
@@ -109,47 +110,22 @@ const MainMenu = memo(() => {
|
|
|
109
110
|
</Command.Group>
|
|
110
111
|
|
|
111
112
|
<Command.Group heading={t('cmdk.navigate')}>
|
|
112
|
-
{
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
icon={<LibraryBig />}
|
|
129
|
-
onSelect={() => handleNavigate('/resource')}
|
|
130
|
-
value="resource"
|
|
131
|
-
>
|
|
132
|
-
{t('cmdk.resource')}
|
|
133
|
-
</CommandItem>
|
|
134
|
-
)}
|
|
135
|
-
{!pathname?.startsWith('/page') && (
|
|
136
|
-
<CommandItem
|
|
137
|
-
icon={<FilePen />}
|
|
138
|
-
onSelect={() => handleNavigate('/page')}
|
|
139
|
-
value="page documents write"
|
|
140
|
-
>
|
|
141
|
-
{t('cmdk.pages')}
|
|
142
|
-
</CommandItem>
|
|
143
|
-
)}
|
|
144
|
-
{!pathname?.startsWith('/memory') && (
|
|
145
|
-
<CommandItem
|
|
146
|
-
icon={<BrainCircuit />}
|
|
147
|
-
onSelect={() => handleNavigate('/memory')}
|
|
148
|
-
value="memory"
|
|
149
|
-
>
|
|
150
|
-
{t('cmdk.memory')}
|
|
151
|
-
</CommandItem>
|
|
152
|
-
)}
|
|
113
|
+
{getNavigableRoutes().map((route) => {
|
|
114
|
+
const RouteIcon = route.icon;
|
|
115
|
+
return (
|
|
116
|
+
!pathname?.startsWith(route.pathPrefix) && (
|
|
117
|
+
<CommandItem
|
|
118
|
+
icon={<RouteIcon />}
|
|
119
|
+
key={route.id}
|
|
120
|
+
keywords={route.keywords}
|
|
121
|
+
onSelect={() => handleNavigate(route.path)}
|
|
122
|
+
value={route.id}
|
|
123
|
+
>
|
|
124
|
+
{t(route.cmdkKey as any)}
|
|
125
|
+
</CommandItem>
|
|
126
|
+
)
|
|
127
|
+
);
|
|
128
|
+
})}
|
|
153
129
|
</Command.Group>
|
|
154
130
|
|
|
155
131
|
<Command.Group heading={t('cmdk.about')}>
|
|
@@ -18,8 +18,10 @@ import { sessionSelectors } from '@/store/session/selectors';
|
|
|
18
18
|
import { useUserStore } from '@/store/user';
|
|
19
19
|
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
|
20
20
|
|
|
21
|
-
import ShareMessageModal from '../components/ShareMessageModal';
|
|
21
|
+
import ShareMessageModal, { type ShareModalProps } from '../components/ShareMessageModal';
|
|
22
22
|
import {
|
|
23
|
+
Provider,
|
|
24
|
+
createStore,
|
|
23
25
|
dataSelectors,
|
|
24
26
|
messageStateSelectors,
|
|
25
27
|
useConversationStore,
|
|
@@ -187,13 +189,26 @@ export const useChatItemContextMenu = ({
|
|
|
187
189
|
if (!item || item.role !== 'assistant') return;
|
|
188
190
|
|
|
189
191
|
createRawModal(
|
|
190
|
-
|
|
192
|
+
(props: ShareModalProps) => (
|
|
193
|
+
<Provider
|
|
194
|
+
createStore={() => {
|
|
195
|
+
const state = storeApi.getState();
|
|
196
|
+
return createStore({
|
|
197
|
+
context: state.context,
|
|
198
|
+
hooks: state.hooks,
|
|
199
|
+
skipFetch: state.skipFetch,
|
|
200
|
+
});
|
|
201
|
+
}}
|
|
202
|
+
>
|
|
203
|
+
<ShareMessageModal {...props} />
|
|
204
|
+
</Provider>
|
|
205
|
+
),
|
|
191
206
|
{
|
|
192
207
|
message: item,
|
|
193
208
|
},
|
|
194
209
|
{ onCloseKey: 'onCancel', openKey: 'open' },
|
|
195
210
|
);
|
|
196
|
-
}, [getMessage]);
|
|
211
|
+
}, [getMessage, storeApi]);
|
|
197
212
|
|
|
198
213
|
const handleAction = useCallback(
|
|
199
214
|
async (action: ContextMenuEvent) => {
|
|
@@ -3,20 +3,17 @@
|
|
|
3
3
|
* Provides title and icon information based on route path
|
|
4
4
|
*/
|
|
5
5
|
import {
|
|
6
|
-
Brain,
|
|
7
6
|
Circle,
|
|
8
|
-
Compass,
|
|
9
|
-
Database,
|
|
10
|
-
FileText,
|
|
11
7
|
Home,
|
|
12
|
-
Image,
|
|
13
8
|
type LucideIcon,
|
|
14
9
|
MessageSquare,
|
|
15
10
|
Rocket,
|
|
16
|
-
|
|
11
|
+
ShapesIcon,
|
|
17
12
|
Users,
|
|
18
13
|
} from 'lucide-react';
|
|
19
14
|
|
|
15
|
+
import { getRouteById } from '@/config/routes';
|
|
16
|
+
|
|
20
17
|
export interface RouteMetadata {
|
|
21
18
|
icon?: LucideIcon;
|
|
22
19
|
/** i18n key for the title (namespace: electron) */
|
|
@@ -34,18 +31,26 @@ interface RoutePattern {
|
|
|
34
31
|
useDynamicTitle?: boolean;
|
|
35
32
|
}
|
|
36
33
|
|
|
34
|
+
// Get shared icons
|
|
35
|
+
const communityIcon = getRouteById('community')?.icon;
|
|
36
|
+
const resourceIcon = getRouteById('resource')?.icon;
|
|
37
|
+
const memoryIcon = getRouteById('memory')?.icon;
|
|
38
|
+
const imageIcon = getRouteById('image')?.icon;
|
|
39
|
+
const pageIcon = getRouteById('page')?.icon;
|
|
40
|
+
const settingsIcon = getRouteById('settings')?.icon;
|
|
41
|
+
|
|
37
42
|
/**
|
|
38
43
|
* Route patterns ordered by specificity (most specific first)
|
|
39
44
|
*/
|
|
40
45
|
const routePatterns: RoutePattern[] = [
|
|
41
46
|
// Settings routes
|
|
42
47
|
{
|
|
43
|
-
icon:
|
|
48
|
+
icon: settingsIcon,
|
|
44
49
|
test: (p) => p.startsWith('/settings/provider'),
|
|
45
50
|
titleKey: 'navigation.provider',
|
|
46
51
|
},
|
|
47
52
|
{
|
|
48
|
-
icon:
|
|
53
|
+
icon: settingsIcon,
|
|
49
54
|
test: (p) => p.startsWith('/settings'),
|
|
50
55
|
titleKey: 'navigation.settings',
|
|
51
56
|
},
|
|
@@ -78,86 +83,86 @@ const routePatterns: RoutePattern[] = [
|
|
|
78
83
|
|
|
79
84
|
// Community/Discover routes
|
|
80
85
|
{
|
|
81
|
-
icon:
|
|
86
|
+
icon: ShapesIcon,
|
|
82
87
|
test: (p) => p.startsWith('/community/agent'),
|
|
83
88
|
titleKey: 'navigation.discoverAssistants',
|
|
84
89
|
},
|
|
85
90
|
{
|
|
86
|
-
icon:
|
|
91
|
+
icon: communityIcon,
|
|
87
92
|
test: (p) => p.startsWith('/community/model'),
|
|
88
93
|
titleKey: 'navigation.discoverModels',
|
|
89
94
|
},
|
|
90
95
|
{
|
|
91
|
-
icon:
|
|
96
|
+
icon: communityIcon,
|
|
92
97
|
test: (p) => p.startsWith('/community/provider'),
|
|
93
98
|
titleKey: 'navigation.discoverProviders',
|
|
94
99
|
},
|
|
95
100
|
{
|
|
96
|
-
icon:
|
|
101
|
+
icon: communityIcon,
|
|
97
102
|
test: (p) => p.startsWith('/community/mcp'),
|
|
98
103
|
titleKey: 'navigation.discoverMcp',
|
|
99
104
|
},
|
|
100
105
|
{
|
|
101
|
-
icon:
|
|
106
|
+
icon: communityIcon,
|
|
102
107
|
test: (p) => p.startsWith('/community'),
|
|
103
108
|
titleKey: 'navigation.discover',
|
|
104
109
|
},
|
|
105
110
|
|
|
106
111
|
// Resource/Knowledge routes
|
|
107
112
|
{
|
|
108
|
-
icon:
|
|
113
|
+
icon: resourceIcon,
|
|
109
114
|
test: (p) => p.startsWith('/resource/library'),
|
|
110
115
|
titleKey: 'navigation.knowledgeBase',
|
|
111
116
|
},
|
|
112
117
|
{
|
|
113
|
-
icon:
|
|
118
|
+
icon: resourceIcon,
|
|
114
119
|
test: (p) => p.startsWith('/resource'),
|
|
115
120
|
titleKey: 'navigation.resources',
|
|
116
121
|
},
|
|
117
122
|
|
|
118
123
|
// Memory routes
|
|
119
124
|
{
|
|
120
|
-
icon:
|
|
125
|
+
icon: memoryIcon,
|
|
121
126
|
test: (p) => p.startsWith('/memory/identities'),
|
|
122
127
|
titleKey: 'navigation.memoryIdentities',
|
|
123
128
|
},
|
|
124
129
|
{
|
|
125
|
-
icon:
|
|
130
|
+
icon: memoryIcon,
|
|
126
131
|
test: (p) => p.startsWith('/memory/contexts'),
|
|
127
132
|
titleKey: 'navigation.memoryContexts',
|
|
128
133
|
},
|
|
129
134
|
{
|
|
130
|
-
icon:
|
|
135
|
+
icon: memoryIcon,
|
|
131
136
|
test: (p) => p.startsWith('/memory/preferences'),
|
|
132
137
|
titleKey: 'navigation.memoryPreferences',
|
|
133
138
|
},
|
|
134
139
|
{
|
|
135
|
-
icon:
|
|
140
|
+
icon: memoryIcon,
|
|
136
141
|
test: (p) => p.startsWith('/memory/experiences'),
|
|
137
142
|
titleKey: 'navigation.memoryExperiences',
|
|
138
143
|
},
|
|
139
144
|
{
|
|
140
|
-
icon:
|
|
145
|
+
icon: memoryIcon,
|
|
141
146
|
test: (p) => p.startsWith('/memory'),
|
|
142
147
|
titleKey: 'navigation.memory',
|
|
143
148
|
},
|
|
144
149
|
|
|
145
150
|
// Image routes
|
|
146
151
|
{
|
|
147
|
-
icon:
|
|
152
|
+
icon: imageIcon,
|
|
148
153
|
test: (p) => p.startsWith('/image'),
|
|
149
154
|
titleKey: 'navigation.image',
|
|
150
155
|
},
|
|
151
156
|
|
|
152
157
|
// Page routes - use dynamic title for specific page names
|
|
153
158
|
{
|
|
154
|
-
icon:
|
|
159
|
+
icon: pageIcon,
|
|
155
160
|
test: (p) => p.startsWith('/page/'),
|
|
156
161
|
titleKey: 'navigation.page',
|
|
157
162
|
useDynamicTitle: true,
|
|
158
163
|
},
|
|
159
164
|
{
|
|
160
|
-
icon:
|
|
165
|
+
icon: pageIcon,
|
|
161
166
|
test: (p) => p === '/page',
|
|
162
167
|
titleKey: 'navigation.pages',
|
|
163
168
|
},
|