Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: lobehub/lobe-vidol
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: fee4fbfc0e59e1aa16bc239fb34e4949e579bed2
Choose a base ref
..
head repository: lobehub/lobe-vidol
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: b53cee38509255b6c6fb65d59054b86abc063e69
Choose a head ref
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -123,7 +123,7 @@
"@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^16.0.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "20.14.8",
"@types/node": "20.14.9",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/three": "^0.165.0",
8 changes: 0 additions & 8 deletions src/app/chat/ViewerMode/ChatDialog/index.tsx
Original file line number Diff line number Diff line change
@@ -29,14 +29,6 @@ const Dialog = (props: DialogProps) => {

const [showChatDialog, setChatDialog] = useState(true);

// ChatItem too long scroll to bottom
// const currentChatString = useSettingStore((s) => sessionSelectors.currentChatsString(s));
// useEffect(() => {
// if (chatLoading && currentChatString && ref.current) {
// ref.current.scrollTop = ref.current.scrollHeight;
// }
// }, [chatLoading, currentChatString]);

useEffect(() => {
if (chatLoading) setChatDialog(true);
}, [chatLoading]);
12 changes: 7 additions & 5 deletions src/app/chat/ViewerMode/ChatDialog/style.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { createStyles } from 'antd-style';

export const useStyles = createStyles(({ css }) => ({
dialog: css`
overflow-y: auto;
max-height: 480px;
`,
export const useStyles = createStyles(({ css, cx }) => ({
dialog: cx(
'chat-dialog',
css`
max-height: 640px;
`,
),
}));
25 changes: 25 additions & 0 deletions src/components/ChatItem/components/Actions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import { ChatItemProps } from '@/components/ChatItem';

import { useStyles } from '../style';

export interface ActionsProps {
actions: ChatItemProps['actions'];
editing?: boolean;
placement?: ChatItemProps['placement'];
type?: ChatItemProps['type'];
}

const Actions = memo<ActionsProps>(({ actions, placement, type, editing }) => {
const { styles } = useStyles({ editing, placement, type });

return (
<Flexbox align={'flex-start'} className={styles.actions} role="menubar">
{actions}
</Flexbox>
);
});

export default Actions;
47 changes: 47 additions & 0 deletions src/components/ChatItem/components/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Avatar as A } from '@lobehub/ui';
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import { useStyles } from '../style';
import type { ChatItemProps } from '../type';
import Loading from './Loading';

export interface AvatarProps {
addon?: ChatItemProps['avatarAddon'];
avatar: ChatItemProps['avatar'];
loading?: ChatItemProps['loading'];
onClick?: ChatItemProps['onAvatarClick'];
placement?: ChatItemProps['placement'];
size?: number;
unoptimized?: boolean;
}

const Avatar = memo<AvatarProps>(
({ loading, avatar, placement, unoptimized, addon, onClick, size = 40 }) => {
const { styles } = useStyles({ avatarSize: size });
const avatarContent = (
<div className={styles.avatarContainer}>
<A
animation={loading}
avatar={avatar.avatar}
background={avatar.backgroundColor}
onClick={onClick}
size={size}
title={avatar.title}
unoptimized={unoptimized}
/>
<Loading loading={loading} placement={placement} />
</div>
);

if (!addon) return avatarContent;
return (
<Flexbox align={'center'} className={styles.avatarGroupContainer} gap={8}>
{avatarContent}
{addon}
</Flexbox>
);
},
);

export default Avatar;
13 changes: 13 additions & 0 deletions src/components/ChatItem/components/BorderSpacing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { memo } from 'react';

export interface BorderSpacingProps {
borderSpacing?: number;
}

const BorderSpacing = memo<BorderSpacingProps>(({ borderSpacing }) => {
if (!borderSpacing) return null;

return <div style={{ flex: 'none', width: borderSpacing }} />;
});

export default BorderSpacing;
25 changes: 25 additions & 0 deletions src/components/ChatItem/components/ErrorContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Alert } from '@lobehub/ui';
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import { ChatItemProps } from '@/components/ChatItem';

import { useStyles } from '../style';

export interface ErrorContentProps {
error?: ChatItemProps['error'];
message?: ChatItemProps['errorMessage'];
placement?: ChatItemProps['placement'];
}

const ErrorContent = memo<ErrorContentProps>(({ message, error, placement }) => {
const { styles } = useStyles({ placement });

return (
<Flexbox className={styles.errorContainer}>
<Alert closable={false} extra={message} showIcon type={'error'} {...error} />
</Flexbox>
);
});

export default ErrorContent;
27 changes: 27 additions & 0 deletions src/components/ChatItem/components/Loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Icon } from '@lobehub/ui';
import { Loader2 } from 'lucide-react';
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import { ChatItemProps } from '@/components/ChatItem';

import { useStyles } from '../style';

export interface LoadingProps {
loading?: ChatItemProps['loading'];
placement?: ChatItemProps['placement'];
}

const Loading = memo<LoadingProps>(({ loading, placement }) => {
const { styles } = useStyles({ placement });

if (!loading) return null;

return (
<Flexbox align={'center'} className={styles.loading} justify={'center'}>
<Icon icon={Loader2} size={{ fontSize: 12, strokeWidth: 3 }} spin />
</Flexbox>
);
});

export default Loading;
77 changes: 77 additions & 0 deletions src/components/ChatItem/components/MessageContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { EditableMessage } from '@lobehub/ui';
import { useResponsive } from 'antd-style';
import { type ReactNode, memo, useEffect, useRef } from 'react';
import { Flexbox } from 'react-layout-kit';

import { ChatItemProps } from '@/components/ChatItem';

import { useStyles } from '../style';

export interface MessageContentProps {
editing?: ChatItemProps['editing'];
fontSize?: number;
message?: ReactNode;
messageExtra?: ChatItemProps['messageExtra'];
onChange?: ChatItemProps['onChange'];
onDoubleClick?: ChatItemProps['onDoubleClick'];
onEditingChange?: ChatItemProps['onEditingChange'];
placement?: ChatItemProps['placement'];
primary?: ChatItemProps['primary'];
renderMessage?: ChatItemProps['renderMessage'];
text?: ChatItemProps['text'];
type?: ChatItemProps['type'];
}

const MessageContent = ({
editing,
onChange,
onEditingChange,
text,
message,
placement,
messageExtra,
renderMessage,
type,
primary,
onDoubleClick,
fontSize,
}: MessageContentProps) => {
const { cx, styles } = useStyles({ editing, placement, primary, type });
const { mobile } = useResponsive();
const ref = useRef<HTMLDivElement>(null);

const content = (
<EditableMessage
classNames={{ input: styles.editingInput }}
editButtonSize={'small'}
editing={editing}
fontSize={fontSize}
fullFeaturedCodeBlock
onChange={onChange}
onEditingChange={onEditingChange}
openModal={mobile ? editing : undefined}
text={text}
value={message ? String(message).trim() : ''}
/>
);
const messageContent = renderMessage ? renderMessage(content) : content;

useEffect(() => {
if (ref.current) {
ref.current.scrollTop = ref.current.scrollHeight;
}
}, [message]);

return (
<Flexbox
ref={ref}
className={cx(styles.message, editing && styles.editingContainer)}
onDoubleClick={onDoubleClick}
>
{messageContent}
{messageExtra && !editing ? <div className={styles.messageExtra}>{messageExtra}</div> : null}
</Flexbox>
);
};

export default memo(MessageContent);
31 changes: 31 additions & 0 deletions src/components/ChatItem/components/Title.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import { ChatItemProps } from '@/components/ChatItem';
import { formatTime } from '@/utils/formatTime';

import { useStyles } from '../style';

export interface TitleProps {
avatar: ChatItemProps['avatar'];
placement?: ChatItemProps['placement'];
showTitle?: ChatItemProps['showTitle'];
time?: ChatItemProps['time'];
}

const Title = memo<TitleProps>(({ showTitle, placement, time, avatar }) => {
const { styles } = useStyles({ placement, showTitle, time });

return (
<Flexbox
className={styles.name}
direction={placement === 'left' ? 'horizontal' : 'horizontal-reverse'}
gap={4}
>
{showTitle ? avatar.title || 'untitled' : undefined}
{time && <time>{formatTime(time)}</time>}
</Flexbox>
);
});

export default Title;
Loading