chat file headers

This commit is contained in:
Nate Kelley 2025-01-24 13:36:39 -07:00
parent 2fe395b5ea
commit 8b21e0d50c
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
15 changed files with 127 additions and 51 deletions

View File

@ -1,18 +0,0 @@
import React from 'react';
import type { ChatSplitterProps } from './ChatSplitter';
interface ChatContainerProps {
chatHeaderText: string;
chatHeaderOptions: ChatSplitterProps['chatHeaderOptions'];
chatContent: ChatSplitterProps['chatContent'];
}
export const ChatContainer: React.FC<ChatContainerProps> = React.memo(({ chatHeaderText }) => {
return (
<div className="h-full w-full bg-red-500">
{/* <Button onClick={onToggleClick}>Toggle {toggleClose.toString()}</Button> */}
</div>
);
});
ChatContainer.displayName = 'ChatContainer';

View File

@ -0,0 +1,23 @@
import React from 'react';
import type { ChatSplitterProps } from '../ChatSplitter';
import { ChatContainerHeader } from './ChatContainerHeader';
import { SelectedFile } from '../interfaces';
import { ChatContainerContentContainer } from './ChatContainerContentContainer';
interface ChatContainerProps {
chatContent: ChatSplitterProps['chatContent'];
selectedFile: SelectedFile | undefined;
}
export const ChatContainer: React.FC<ChatContainerProps> = React.memo(
({ chatContent, selectedFile }) => {
return (
<div className="flex h-full w-full flex-col">
<ChatContainerHeader selectedFile={selectedFile} />
<ChatContainerContentContainer />
</div>
);
}
);
ChatContainer.displayName = 'ChatContainer';

View File

@ -0,0 +1,5 @@
import React from 'react';
export const ChatContainerContentContainer: React.FC = () => {
return <div className="h-full w-full bg-red-200">ChatContainerContentContainer</div>;
};

View File

@ -0,0 +1,34 @@
import { appContentHeaderHeight } from '@/components/layout/AppContentHeader';
import { createStyles } from 'antd-style';
import React from 'react';
import { SelectedFile } from '../../interfaces';
import { useChatSplitterContextSelector } from '../../ChatSplitterContext';
import { Text } from '@/components/text';
import { ChatContainerHeaderOptions } from './ChatContainerHeaderOptions';
import { ChatContainerHeaderTitle } from './ChatContainerHeaderTitle';
export const ChatContainerHeader: React.FC<{
selectedFile: SelectedFile | undefined;
}> = React.memo(({ selectedFile }) => {
const { cx, styles } = useStyles();
const hasFile = useChatSplitterContextSelector((state) => state.hasFile);
return (
<div className={cx('flex w-full items-center justify-between space-x-2 px-4', styles.header)}>
{hasFile && (
<>
<ChatContainerHeaderTitle />
<ChatContainerHeaderOptions />
</>
)}
</div>
);
});
ChatContainerHeader.displayName = 'ChatContainerHeader';
const useStyles = createStyles(({ token }) => ({
header: {
height: appContentHeaderHeight
}
}));

View File

@ -0,0 +1,13 @@
import { AppMaterialIcons } from '@/components';
import { Button } from 'antd';
import React from 'react';
export const ChatContainerHeaderOptions: React.FC<{}> = React.memo(() => {
return (
<div>
<Button type="text" icon={<AppMaterialIcons icon="more_horiz" />} />
</div>
);
});
ChatContainerHeaderOptions.displayName = 'ChatContainerHeaderOptions';

View File

@ -0,0 +1,16 @@
import { Text } from '@/components/text';
import React from 'react';
import { useChatSplitterContextSelector } from '../../ChatSplitterContext';
export const ChatContainerHeaderTitle: React.FC<{}> = React.memo(() => {
const hasFile = useChatSplitterContextSelector((state) => state.hasFile);
const selectedFileTitle = useChatSplitterContextSelector((state) => state.selectedFileTitle);
return (
<div className="flex items-center">
<Text>{selectedFileTitle}</Text>
</div>
);
});
ChatContainerHeaderTitle.displayName = 'ChatContainerHeaderTitle';

View File

@ -0,0 +1 @@
export * from './ChatContainerHeader';

View File

@ -0,0 +1 @@
export * from './ChatContainer';

View File

@ -1,51 +1,44 @@
import React, { useEffect, useImperativeHandle, useMemo, useRef } from 'react';
import React, { useMemo, useRef } from 'react';
import { AppSplitter, AppSplitterRef } from '@/components/layout/AppSplitter';
import { AppChatMessageFileType } from '@/components/messages/AppChatMessageContainer';
import { ChatContainer } from './ChatContainer';
import { FileContainer } from './FileContainer';
import { useUpdateEffect } from 'ahooks';
import { ChatSplitterContextProvider } from './ChatSplitterContext';
import { useChatSplitter } from './ChatSplitterContext/useChatSplitter';
import { useChatSplitter } from './ChatSplitterContext';
import { SelectedFile } from './interfaces';
export interface ChatSplitterProps {
chatHeaderText: string;
chatHeaderOptions?: [];
chatContent?: React.ReactNode;
fileHeader?: React.ReactNode;
defaultShowFile?: boolean;
showChatCollapse?: boolean;
defaultShowLayout?: 'chat' | 'file' | 'both';
defaultSelectedFile?: SelectedFile;
}
export const ChatSplitter: React.FC<ChatSplitterProps> = React.memo(
({
chatHeaderText,
defaultShowFile = false,
defaultSelectedFile,
chatHeaderOptions,
chatContent,
fileHeader
}) => {
({ defaultSelectedFile, defaultShowLayout = 'chat', chatHeaderOptions, chatContent }) => {
const appSplitterRef = useRef<AppSplitterRef>(null);
const defaultLayout = useMemo(() => {
return defaultShowFile ? ['20%', '80%'] : ['100%', '0%'];
}, [defaultShowFile]);
if (defaultShowLayout === 'chat') {
return ['100%', '0%'];
}
if (defaultShowLayout === 'file') {
return ['0%', '100%'];
}
return ['325px', 'auto'];
}, [defaultShowLayout]);
const useChatSplitterProps = useChatSplitter({ defaultSelectedFile, appSplitterRef });
const useChatSplitterProps = useChatSplitter({
defaultSelectedFile,
appSplitterRef
});
const { selectedFile, hasFile } = useChatSplitterProps;
return (
<ChatSplitterContextProvider useChatSplitterProps={useChatSplitterProps}>
<AppSplitter
ref={appSplitterRef}
leftChildren={
<ChatContainer
chatHeaderText={chatHeaderText}
chatHeaderOptions={chatHeaderOptions}
chatContent={chatContent}
/>
}
leftChildren={<ChatContainer selectedFile={selectedFile} chatContent={chatContent} />}
rightChildren={<FileContainer selectedFile={selectedFile} />}
autoSaveId="chat-splitter"
defaultLayout={defaultLayout}

View File

@ -5,7 +5,6 @@ import {
useContextSelector
} from '@fluentui/react-context-selector';
import { useChatSplitter } from './useChatSplitter';
import { AppSplitterRef } from '@/components/layout/AppSplitter';
const ChatSplitterContext = createContext<ReturnType<typeof useChatSplitter>>(
{} as ReturnType<typeof useChatSplitter>

View File

@ -1 +1,2 @@
export * from './ChatSplitterContext';
export * from './useChatSplitter';

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useMemo, useState } from 'react';
import { SelectedFile } from '../interfaces';
import { useUpdateEffect } from 'ahooks';
import type { AppSplitterRef } from '@/components/layout/AppSplitter';
@ -14,6 +14,11 @@ export const useChatSplitter = ({ appSplitterRef, defaultSelectedFile }: UseChat
const hasFile = !!selectedFile;
const selectedFileTitle: string = useMemo(() => {
if (!selectedFile) return '';
return 'This is a test';
}, [selectedFile]);
const onSetSelectedFile = (file: SelectedFile) => {
setSelectedFile(file);
};
@ -25,13 +30,12 @@ export const useChatSplitter = ({ appSplitterRef, defaultSelectedFile }: UseChat
appSplitterRef.current?.animateWidth('50%', 'right');
}, 1000);
// appSplitterRef.current.animateWidth('200px', 'left');
appSplitterRef.current?.animateWidth('100px', 'right');
}
}, [defaultSelectedFile]);
return {
selectedFileTitle,
hasFile,
selectedFile,
onSetSelectedFile

View File

@ -1,6 +1,6 @@
import React from 'react';
import type { ChatSplitterProps } from './ChatSplitter';
import { SelectedFile } from './interfaces';
import type { ChatSplitterProps } from '../ChatSplitter';
import { SelectedFile } from '../interfaces';
interface FileContainerProps {
selectedFile: SelectedFile | undefined;

View File

@ -0,0 +1 @@
export * from './FileContainer';

View File

@ -11,7 +11,10 @@ export default function Page() {
const [toggleClose, setToggleClose] = useState(false);
const ref = useRef<AppSplitterRef>(null);
const [defaultFile, setDefaultFile] = useState<SelectedFile | undefined>(undefined);
const [defaultFile, setDefaultFile] = useState<SelectedFile | undefined>({
id: '1',
type: 'metric'
});
const onToggleClick = useMemoizedFn(() => {
if (toggleClose) {
@ -25,7 +28,7 @@ export default function Page() {
return (
<div className="h-screen w-screen border">
<ChatSplitter chatHeaderText="Chat" defaultSelectedFile={defaultFile} />
<ChatSplitter defaultShowLayout="both" defaultSelectedFile={defaultFile} />
<Button onClick={() => setDefaultFile({ id: '1', type: 'metric' })}>Set Default File</Button>
</div>