mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-04 08:38:34 +00:00
feat(core): show ai-island and navigate to chat page if not available in sidebar (#13085)
close AI-318, AI-317 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Updated the AI chat button label to "AFFiNE Intelligence" and changed its icon for improved clarity. * Enhanced the AI chat button's placement in the sidebar for better accessibility. * Improved the AI chat button’s visibility and interaction logic based on current view and sidebar state. * **Style** * Adjusted button styles to disable interaction when hidden, enhancing user experience. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -18,7 +18,7 @@ import { useI18n } from '@affine/i18n';
|
||||
import { track } from '@affine/track';
|
||||
import type { Store } from '@blocksuite/affine/store';
|
||||
import {
|
||||
AiIcon,
|
||||
AiOutlineIcon,
|
||||
AllDocsIcon,
|
||||
ImportIcon,
|
||||
JournalIcon,
|
||||
@@ -97,8 +97,8 @@ const AIChatButton = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<MenuLinkItem icon={<AiIcon />} active={aiChatActive} to={'/chat'}>
|
||||
<span data-testid="ai-chat">Intelligent</span>
|
||||
<MenuLinkItem icon={<AiOutlineIcon />} active={aiChatActive} to={'/chat'}>
|
||||
<span data-testid="ai-chat">AFFiNE Intelligence</span>
|
||||
</MenuLinkItem>
|
||||
);
|
||||
};
|
||||
@@ -198,10 +198,10 @@ export const RootAppSidebar = memo((): ReactElement => {
|
||||
/>
|
||||
<AddPageButton />
|
||||
</div>
|
||||
<AIChatButton />
|
||||
<AllDocsButton />
|
||||
<AppSidebarJournalButton />
|
||||
{sessionStatus === 'authenticated' && <NotificationButton />}
|
||||
<AIChatButton />
|
||||
<MenuItem
|
||||
data-testid="slider-bar-workspace-setting-button"
|
||||
icon={<SettingsIcon />}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { IslandContainer } from './container';
|
||||
import { AIIcon } from './icons';
|
||||
import { aiIslandBtn, aiIslandWrapper, toolStyle } from './styles.css';
|
||||
|
||||
const hideChat: Array<string | ((path: string) => boolean)> = [
|
||||
'/chat',
|
||||
path => path.includes('attachments'),
|
||||
];
|
||||
|
||||
export const AIIsland = () => {
|
||||
// to make sure ai island is hidden first and animate in
|
||||
const [hide, setHide] = useState(true);
|
||||
@@ -16,12 +21,33 @@ export const AIIsland = () => {
|
||||
const haveChatTab = useLiveData(
|
||||
activeView.sidebarTabs$.map(tabs => tabs.some(t => t.id === 'chat'))
|
||||
);
|
||||
const activeLocation = useLiveData(activeView.location$);
|
||||
const activeTab = useLiveData(activeView.activeSidebarTab$);
|
||||
const sidebarOpen = useLiveData(workbench.sidebarOpen$);
|
||||
|
||||
useEffect(() => {
|
||||
setHide((sidebarOpen && activeTab?.id === 'chat') || !haveChatTab);
|
||||
}, [activeTab, haveChatTab, sidebarOpen]);
|
||||
let hide = true;
|
||||
if (haveChatTab) {
|
||||
hide = !!sidebarOpen && activeTab?.id === 'chat';
|
||||
} else {
|
||||
const path = activeLocation.pathname;
|
||||
hide = hideChat.some(item =>
|
||||
typeof item === 'string' ? path === item : item(path)
|
||||
);
|
||||
}
|
||||
setHide(hide);
|
||||
}, [activeLocation.pathname, activeTab, haveChatTab, sidebarOpen]);
|
||||
|
||||
const onOpenChat = useCallback(() => {
|
||||
if (hide) return;
|
||||
if (haveChatTab) {
|
||||
workbench.openSidebar();
|
||||
activeView.activeSidebarTab('chat');
|
||||
} else {
|
||||
workbench.open('/chat');
|
||||
workbench.closeSidebar();
|
||||
}
|
||||
}, [activeView, haveChatTab, hide, workbench]);
|
||||
|
||||
return (
|
||||
<IslandContainer className={clsx(toolStyle, { hide })}>
|
||||
@@ -29,11 +55,7 @@ export const AIIsland = () => {
|
||||
<button
|
||||
className={aiIslandBtn}
|
||||
data-testid="ai-island"
|
||||
onClick={() => {
|
||||
if (hide) return;
|
||||
workbench.openSidebar();
|
||||
activeView.activeSidebarTab('chat');
|
||||
}}
|
||||
onClick={onOpenChat}
|
||||
>
|
||||
<AIIcon />
|
||||
</button>
|
||||
|
||||
@@ -57,6 +57,8 @@ export const rightSidebarButton = style({
|
||||
opacity: 0,
|
||||
maxWidth: 0,
|
||||
marginLeft: 0,
|
||||
// prevent click event from being triggered
|
||||
pointerEvents: 'none',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user