mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-17 10:06:17 +08:00
refactor(infra): directory structure (#4615)
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import { FlexWrapper, Input } from '@affine/component';
|
||||
import { Button } from '@toeverything/components/button';
|
||||
import { useAtom } from 'jotai';
|
||||
import { type ReactElement, useCallback } from 'react';
|
||||
|
||||
import { openAIApiKeyAtom } from '../core/hooks';
|
||||
import { conversationHistoryDBName } from '../core/langchain/message-history';
|
||||
|
||||
export const DebugContent = (): ReactElement => {
|
||||
const [key, setKey] = useAtom(openAIApiKeyAtom);
|
||||
return (
|
||||
<div>
|
||||
<FlexWrapper justifyContent="space-between">
|
||||
<Input
|
||||
width={280}
|
||||
defaultValue={key ?? undefined}
|
||||
onChange={useCallback(
|
||||
(newValue: string) => {
|
||||
setKey(newValue);
|
||||
},
|
||||
[setKey]
|
||||
)}
|
||||
placeholder="Enter your API_KEY here"
|
||||
/>
|
||||
<Button
|
||||
size="large"
|
||||
onClick={() => {
|
||||
indexedDB.deleteDatabase(conversationHistoryDBName);
|
||||
location.reload();
|
||||
}}
|
||||
>
|
||||
{'Clean conversations'}
|
||||
</Button>
|
||||
</FlexWrapper>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
import { SendIcon } from '@blocksuite/icons';
|
||||
import { IconButton } from '@toeverything/components/button';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import type { ReactElement } from 'react';
|
||||
import { Suspense, useCallback, useState } from 'react';
|
||||
|
||||
import { ConversationList } from '../core/components/conversation-list';
|
||||
import { FollowingUp } from '../core/components/following-up';
|
||||
import { openAIApiKeyAtom, useChatAtoms } from '../core/hooks';
|
||||
import {
|
||||
detailContentActionsStyle,
|
||||
detailContentStyle,
|
||||
sendButtonStyle,
|
||||
textareaStyle,
|
||||
} from './index.css';
|
||||
|
||||
const Actions = () => {
|
||||
const { conversationAtom, followingUpAtoms } = useChatAtoms();
|
||||
const call = useSetAtom(conversationAtom);
|
||||
const questions = useAtomValue(followingUpAtoms.questionsAtom);
|
||||
const generateFollowingUp = useSetAtom(followingUpAtoms.generateChatAtom);
|
||||
const [input, setInput] = useState('');
|
||||
return (
|
||||
<>
|
||||
<FollowingUp questions={questions} />
|
||||
<div className={detailContentActionsStyle}>
|
||||
<textarea
|
||||
className={textareaStyle}
|
||||
value={input}
|
||||
placeholder="Type here ask Copilot some thing..."
|
||||
onChange={e => {
|
||||
setInput(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<IconButton
|
||||
className={sendButtonStyle}
|
||||
onClick={useCallback(() => {
|
||||
call(input)
|
||||
.then(() => generateFollowingUp())
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
}, [call, generateFollowingUp, input])}
|
||||
>
|
||||
<SendIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const DetailContentImpl = () => {
|
||||
const { conversationAtom } = useChatAtoms();
|
||||
const conversations = useAtomValue(conversationAtom);
|
||||
|
||||
return (
|
||||
<div className={detailContentStyle}>
|
||||
<ConversationList conversations={conversations} />
|
||||
<Suspense fallback="generating follow-up question">
|
||||
<Actions />
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const DetailContent = (): ReactElement => {
|
||||
const key = useAtomValue(openAIApiKeyAtom);
|
||||
if (!key) {
|
||||
return <span>Please set OpenAI API Key in the debug panel.</span>;
|
||||
}
|
||||
return <DetailContentImpl />;
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
import { deleteLayoutAtom, pushLayoutAtom } from '@affine/sdk/entry';
|
||||
import { AiIcon } from '@blocksuite/icons';
|
||||
import { IconButton } from '@toeverything/components/button';
|
||||
import { Tooltip } from '@toeverything/components/tooltip';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import type { ComponentType, PropsWithChildren, ReactElement } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import { DetailContent } from './detail-content';
|
||||
|
||||
export const HeaderItem = ({
|
||||
Provider,
|
||||
}: {
|
||||
Provider: ComponentType<PropsWithChildren>;
|
||||
}): ReactElement => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const pushLayout = useSetAtom(pushLayoutAtom);
|
||||
const deleteLayout = useSetAtom(deleteLayoutAtom);
|
||||
return (
|
||||
<Tooltip content="Chat with AI" side="bottom">
|
||||
<IconButton
|
||||
onClick={useCallback(() => {
|
||||
if (!open) {
|
||||
setOpen(true);
|
||||
pushLayout('@affine/copilot-plugin', div => {
|
||||
const root = createRoot(div);
|
||||
root.render(
|
||||
<Provider>
|
||||
<DetailContent />
|
||||
</Provider>
|
||||
);
|
||||
return () => {
|
||||
root.unmount();
|
||||
};
|
||||
});
|
||||
} else {
|
||||
setOpen(false);
|
||||
deleteLayout('@affine/copilot-plugin');
|
||||
}
|
||||
}, [Provider, deleteLayout, open, pushLayout])}
|
||||
>
|
||||
<AiIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const detailContentStyle = style({
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.04)',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'auto',
|
||||
padding: '10px',
|
||||
borderLeft: '1px solid var(--affine-border-color)',
|
||||
borderTop: '1px solid var(--affine-border-color)',
|
||||
});
|
||||
|
||||
export const detailContentActionsStyle = style({
|
||||
marginTop: 'auto',
|
||||
marginBottom: '10px',
|
||||
fontSize: 'var(--affine-font-xs)',
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
});
|
||||
export const textareaStyle = style({
|
||||
fontSize: 'var(--affine-font-xs)',
|
||||
border: '1px solid var(--affine-border-color)',
|
||||
width: '100%',
|
||||
borderRadius: '4px',
|
||||
background: 'var(--affine-hover-color)',
|
||||
height: '117px',
|
||||
padding: '8px 10px',
|
||||
'::placeholder': {
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
},
|
||||
});
|
||||
export const sendButtonStyle = style({
|
||||
fontSize: 'var(--affine-font-xs)',
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
marginLeft: '8px',
|
||||
':hover': {
|
||||
cursor: 'pointer',
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user