Make the window title reflect what we are doing (#3883)
Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
|||||||
} from '../ui/sidebar';
|
} from '../ui/sidebar';
|
||||||
import { ChatSmart, Gear } from '../icons';
|
import { ChatSmart, Gear } from '../icons';
|
||||||
import { ViewOptions, View } from '../../App';
|
import { ViewOptions, View } from '../../App';
|
||||||
|
import { useChatContext } from '../../contexts/ChatContext';
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
onSelectSession: (sessionId: string) => void;
|
onSelectSession: (sessionId: string) => void;
|
||||||
@@ -23,12 +24,80 @@ interface SidebarProps {
|
|||||||
currentPath?: string;
|
currentPath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main Sidebar Component
|
interface NavigationItem {
|
||||||
|
type: 'item';
|
||||||
|
path: string;
|
||||||
|
label: string;
|
||||||
|
icon: React.ComponentType<{ className?: string }>;
|
||||||
|
tooltip: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NavigationSeparator {
|
||||||
|
type: 'separator';
|
||||||
|
}
|
||||||
|
|
||||||
|
type NavigationEntry = NavigationItem | NavigationSeparator;
|
||||||
|
|
||||||
|
const menuItems: NavigationEntry[] = [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
path: '/',
|
||||||
|
label: 'Home',
|
||||||
|
icon: Home,
|
||||||
|
tooltip: 'Go back to the main chat screen',
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
path: '/pair',
|
||||||
|
label: 'Chat',
|
||||||
|
icon: ChatSmart,
|
||||||
|
tooltip: 'Start pairing with Goose',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
path: '/sessions',
|
||||||
|
label: 'History',
|
||||||
|
icon: History,
|
||||||
|
tooltip: 'View your session history',
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
path: '/recipes',
|
||||||
|
label: 'Recipes',
|
||||||
|
icon: FileText,
|
||||||
|
tooltip: 'Browse your saved recipes',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
path: '/schedules',
|
||||||
|
label: 'Scheduler',
|
||||||
|
icon: Clock,
|
||||||
|
tooltip: 'Manage scheduled runs',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
path: '/extensions',
|
||||||
|
label: 'Extensions',
|
||||||
|
icon: Puzzle,
|
||||||
|
tooltip: 'Manage your extensions',
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
path: '/settings',
|
||||||
|
label: 'Settings',
|
||||||
|
icon: Gear,
|
||||||
|
tooltip: 'Configure Goose settings',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const AppSidebar: React.FC<SidebarProps> = ({ currentPath }) => {
|
const AppSidebar: React.FC<SidebarProps> = ({ currentPath }) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const chatContext = useChatContext();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Trigger animation after a small delay
|
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
// setIsVisible(true);
|
// setIsVisible(true);
|
||||||
}, 100);
|
}, 100);
|
||||||
@@ -36,156 +105,62 @@ const AppSidebar: React.FC<SidebarProps> = ({ currentPath }) => {
|
|||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Helper function to check if a path is active
|
useEffect(() => {
|
||||||
|
const currentItem = menuItems.find(
|
||||||
|
(item) => item.type === 'item' && item.path === currentPath
|
||||||
|
) as NavigationItem | undefined;
|
||||||
|
|
||||||
|
const titleBits = ['Goose'];
|
||||||
|
|
||||||
|
if (
|
||||||
|
currentPath === '/pair' &&
|
||||||
|
chatContext?.chat?.title &&
|
||||||
|
chatContext.chat.title !== 'New Chat'
|
||||||
|
) {
|
||||||
|
titleBits.push(chatContext.chat.title);
|
||||||
|
} else if (currentPath !== '/' && currentItem) {
|
||||||
|
titleBits.push(currentItem.label);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.title = titleBits.join(' - ');
|
||||||
|
}, [currentPath, chatContext?.chat?.title]);
|
||||||
|
|
||||||
const isActivePath = (path: string) => {
|
const isActivePath = (path: string) => {
|
||||||
return currentPath === path;
|
return currentPath === path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderMenuItem = (entry: NavigationEntry, index: number) => {
|
||||||
|
if (entry.type === 'separator') {
|
||||||
|
return <SidebarSeparator key={index} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IconComponent = entry.icon;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarGroup key={entry.path}>
|
||||||
|
<SidebarGroupContent className="space-y-1">
|
||||||
|
<div className="sidebar-item">
|
||||||
|
<SidebarMenuItem>
|
||||||
|
<SidebarMenuButton
|
||||||
|
onClick={() => navigate(entry.path)}
|
||||||
|
isActive={isActivePath(entry.path)}
|
||||||
|
tooltip={entry.tooltip}
|
||||||
|
className="w-full justify-start px-3 rounded-lg h-fit hover:bg-background-medium/50 transition-all duration-200 data-[active=true]:bg-background-medium"
|
||||||
|
>
|
||||||
|
<IconComponent className="w-4 h-4" />
|
||||||
|
<span>{entry.label}</span>
|
||||||
|
</SidebarMenuButton>
|
||||||
|
</SidebarMenuItem>
|
||||||
|
</div>
|
||||||
|
</SidebarGroupContent>
|
||||||
|
</SidebarGroup>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SidebarContent className="pt-16">
|
<SidebarContent className="pt-16">
|
||||||
{/* Menu */}
|
<SidebarMenu>{menuItems.map((entry, index) => renderMenuItem(entry, index))}</SidebarMenu>
|
||||||
<SidebarMenu>
|
|
||||||
{/* Navigation Group */}
|
|
||||||
<SidebarGroup>
|
|
||||||
<SidebarGroupContent className="space-y-1">
|
|
||||||
<div className="sidebar-item">
|
|
||||||
<SidebarMenuItem>
|
|
||||||
<SidebarMenuButton
|
|
||||||
onClick={() => {
|
|
||||||
navigate('/');
|
|
||||||
}}
|
|
||||||
isActive={isActivePath('/')}
|
|
||||||
tooltip="Go back to the main chat screen"
|
|
||||||
className="w-full justify-start px-3 rounded-lg h-fit hover:bg-background-medium/50 transition-all duration-200 data-[active=true]:bg-background-medium"
|
|
||||||
>
|
|
||||||
<Home className="w-4 h-4" />
|
|
||||||
<span>Home</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</div>
|
|
||||||
</SidebarGroupContent>
|
|
||||||
</SidebarGroup>
|
|
||||||
|
|
||||||
<SidebarSeparator />
|
|
||||||
|
|
||||||
{/* Chat & Configuration Group */}
|
|
||||||
<SidebarGroup>
|
|
||||||
<SidebarGroupContent className="space-y-1">
|
|
||||||
<div className="sidebar-item">
|
|
||||||
<SidebarMenuItem>
|
|
||||||
<SidebarMenuButton
|
|
||||||
onClick={() => navigate('/pair')}
|
|
||||||
isActive={isActivePath('/pair')}
|
|
||||||
tooltip="Start pairing with Goose"
|
|
||||||
className="w-full justify-start px-3 rounded-lg h-fit hover:bg-background-medium/50 transition-all duration-200 data-[active=true]:bg-background-medium"
|
|
||||||
>
|
|
||||||
<ChatSmart className="w-4 h-4" />
|
|
||||||
<span>Chat</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="sidebar-item">
|
|
||||||
<SidebarMenuItem>
|
|
||||||
<SidebarMenuButton
|
|
||||||
onClick={() => navigate('/sessions')}
|
|
||||||
isActive={isActivePath('/sessions')}
|
|
||||||
tooltip="View your session history"
|
|
||||||
className="w-full justify-start px-3 rounded-lg h-fit hover:bg-background-medium/50 transition-all duration-200 data-[active=true]:bg-background-medium"
|
|
||||||
>
|
|
||||||
<History className="w-4 h-4" />
|
|
||||||
<span>History</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</div>
|
|
||||||
</SidebarGroupContent>
|
|
||||||
</SidebarGroup>
|
|
||||||
|
|
||||||
<SidebarSeparator />
|
|
||||||
|
|
||||||
{/* Content Group */}
|
|
||||||
<SidebarGroup>
|
|
||||||
<SidebarGroupContent className="space-y-1">
|
|
||||||
{/*<div className="sidebar-item">*/}
|
|
||||||
{/* <SidebarMenuItem>*/}
|
|
||||||
{/* <SidebarMenuButton*/}
|
|
||||||
{/* onClick={() => navigate('/projects')}*/}
|
|
||||||
{/* isActive={isActivePath('/projects')}*/}
|
|
||||||
{/* tooltip="Manage your projects"*/}
|
|
||||||
{/* className="w-full justify-start px-3 rounded-lg h-fit hover:bg-background-medium/50 transition-all duration-200 data-[active=true]:bg-background-medium"*/}
|
|
||||||
{/* >*/}
|
|
||||||
{/* <FolderKanban className="w-4 h-4" />*/}
|
|
||||||
{/* <span>Projects</span>*/}
|
|
||||||
{/* </SidebarMenuButton>*/}
|
|
||||||
{/* </SidebarMenuItem>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
|
|
||||||
<div className="sidebar-item">
|
|
||||||
<SidebarMenuItem>
|
|
||||||
<SidebarMenuButton
|
|
||||||
onClick={() => navigate('/recipes')}
|
|
||||||
isActive={isActivePath('/recipes')}
|
|
||||||
tooltip="Browse your saved recipes"
|
|
||||||
className="w-full justify-start px-3 rounded-lg h-fit hover:bg-background-medium/50 transition-all duration-200 data-[active=true]:bg-background-medium"
|
|
||||||
>
|
|
||||||
<FileText className="w-4 h-4" />
|
|
||||||
<span>Recipes</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="sidebar-item">
|
|
||||||
<SidebarMenuItem>
|
|
||||||
<SidebarMenuButton
|
|
||||||
onClick={() => navigate('/schedules')}
|
|
||||||
isActive={isActivePath('/schedules')}
|
|
||||||
tooltip="Manage scheduled runs"
|
|
||||||
className="w-full justify-start px-3 rounded-lg h-fit hover:bg-background-medium/50 transition-all duration-200 data-[active=true]:bg-background-medium"
|
|
||||||
>
|
|
||||||
<Clock className="w-4 h-4" />
|
|
||||||
<span>Scheduler</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="sidebar-item">
|
|
||||||
<SidebarMenuItem>
|
|
||||||
<SidebarMenuButton
|
|
||||||
onClick={() => navigate('/extensions')}
|
|
||||||
isActive={isActivePath('/extensions')}
|
|
||||||
tooltip="Manage your extensions"
|
|
||||||
className="w-full justify-start px-3 rounded-lg h-fit hover:bg-background-medium/50 transition-all duration-200 data-[active=true]:bg-background-medium"
|
|
||||||
>
|
|
||||||
<Puzzle className="w-4 h-4" />
|
|
||||||
<span>Extensions</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</div>
|
|
||||||
</SidebarGroupContent>
|
|
||||||
</SidebarGroup>
|
|
||||||
|
|
||||||
<SidebarSeparator />
|
|
||||||
|
|
||||||
{/* Settings Group */}
|
|
||||||
<SidebarGroup>
|
|
||||||
<SidebarGroupContent className="space-y-1">
|
|
||||||
<div className="sidebar-item">
|
|
||||||
<SidebarMenuItem>
|
|
||||||
<SidebarMenuButton
|
|
||||||
onClick={() => navigate('/settings')}
|
|
||||||
isActive={isActivePath('/settings')}
|
|
||||||
tooltip="Configure Goose settings"
|
|
||||||
className="w-full justify-start px-3 rounded-lg h-fit hover:bg-background-medium/50 transition-all duration-200 data-[active=true]:bg-background-medium"
|
|
||||||
>
|
|
||||||
<Gear className="w-4 h-4" />
|
|
||||||
<span>Settings</span>
|
|
||||||
</SidebarMenuButton>
|
|
||||||
</SidebarMenuItem>
|
|
||||||
</div>
|
|
||||||
</SidebarGroupContent>
|
|
||||||
</SidebarGroup>
|
|
||||||
</SidebarMenu>
|
|
||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
|
|
||||||
<SidebarFooter />
|
<SidebarFooter />
|
||||||
|
|||||||
Reference in New Issue
Block a user