Skip to content

Commit

Permalink
style:调整默认缩进
Browse files Browse the repository at this point in the history
  • Loading branch information
nowscott committed Jul 27, 2024
1 parent 88fa63f commit ade07c8
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 194 deletions.
126 changes: 63 additions & 63 deletions src/components/layout/InputPrompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,76 @@ import React, { useState } from 'react';
import { HiOutlineTrash, HiOutlineAnnotation } from "react-icons/hi";

const InputPrompt = ({ onSend, onClear }) => {
const [prompt, setPrompt] = useState('');
const [isComposing, setIsComposing] = useState(false);
const [prompt, setPrompt] = useState('');
const [isComposing, setIsComposing] = useState(false);

const handleChange = (e) => {
setPrompt(e.target.value);
};
const handleChange = (e) => {
setPrompt(e.target.value);
};

const handleCompositionStart = () => {
setIsComposing(true);
};
const handleCompositionStart = () => {
setIsComposing(true);
};

const handleCompositionEnd = () => {
setIsComposing(false);
};
const handleCompositionEnd = () => {
setIsComposing(false);
};

const handleKeyDown = (e) => {
if (!isComposing && e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSend();
}
};
const handleKeyDown = (e) => {
if (!isComposing && e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSend();
}
};

const handleSend = () => {
if (prompt.trim() === '') return;
onSend(prompt);
setPrompt('');
};
const handleSend = () => {
if (prompt.trim() === '') return;
onSend(prompt);
setPrompt('');
};

const handleClear = () => {
const confirmed = window.confirm('确定要清空消息记录吗?');
if (confirmed) {
onClear();
}
};
const handleClear = () => {
const confirmed = window.confirm('确定要清空消息记录吗?');
if (confirmed) {
onClear();
}
};

return (
<div className="flex-0 w-full bg-slate-400 dark:bg-slate-900 p-2">
<div className="p-2 bg-white dark:bg-black rounded-lg flex items-center relative max-w-screen-md w-full mx-auto">
<div className="flex flex-grow items-center border-2 rounded border-slate-300 bg-stone-50 dark:bg-stone-900">
<button
className="p-1 text-rose-500"
onClick={handleClear}
>
<HiOutlineTrash className="h-6 w-6" />
</button>
<textarea
className="bg-stone-50 text-gray-900 dark:bg-stone-900 dark:text-yellow-50 w-full p-1 border-none outline-none resize-none overflow-auto whitespace-pre-wrap break-words disable-ring-shadow"
style={{ maxHeight: '10rem', minHeight: '1rem' }}
rows="1"
value={prompt}
onChange={handleChange}
onKeyDown={handleKeyDown}
onInput={(e) => {
e.target.style.height = 'auto';
e.target.style.height = `${e.target.scrollHeight}px`;
}}
onCompositionStart={handleCompositionStart}
onCompositionEnd={handleCompositionEnd}
placeholder="發送訊息..."
/>
<button
className="p-1 text-slate-500"
onClick={handleSend}
>
<HiOutlineAnnotation className="h-6 w-6" />
</button>
</div>
</div>
</div>
);
return (
<div className="flex-0 w-full bg-slate-400 dark:bg-slate-900 p-2">
<div className="p-2 bg-white dark:bg-black rounded-lg flex items-center relative max-w-screen-md w-full mx-auto">
<div className="flex flex-grow items-center border-2 rounded border-slate-300 bg-stone-50 dark:bg-stone-900">
<button
className="p-1 text-rose-500"
onClick={handleClear}
>
<HiOutlineTrash className="h-6 w-6" />
</button>
<textarea
className="bg-stone-50 text-gray-900 dark:bg-stone-900 dark:text-yellow-50 w-full p-1 border-none outline-none resize-none overflow-auto whitespace-pre-wrap break-words disable-ring-shadow"
style={{ maxHeight: '10rem', minHeight: '1rem' }}
rows="1"
value={prompt}
onChange={handleChange}
onKeyDown={handleKeyDown}
onInput={(e) => {
e.target.style.height = 'auto';
e.target.style.height = `${e.target.scrollHeight}px`;
}}
onCompositionStart={handleCompositionStart}
onCompositionEnd={handleCompositionEnd}
placeholder="發送訊息..."
/>
<button
className="p-1 text-slate-500"
onClick={handleSend}
>
<HiOutlineAnnotation className="h-6 w-6" />
</button>
</div>
</div>
</div>
);
};

export default InputPrompt;
200 changes: 100 additions & 100 deletions src/components/layout/MessageList.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useRef, useCallback, useState,useContext } from 'react';
import React, { useEffect, useRef, useCallback, useState, useContext } from 'react';
import moment from 'moment';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
Expand All @@ -8,114 +8,114 @@ import copy from 'copy-to-clipboard';
import { ThemeContext } from 'contexts/ThemeContext';

const MessageList = ({ messages, onDelete }) => {
const { darkMode } = useContext(ThemeContext);
const messageEndRef = useRef(null);
const containerRef = useRef(null);
const [copied, setCopied] = useState(null);
const [pendingDelete, setPendingDelete] = useState({});
const { darkMode } = useContext(ThemeContext);
const messageEndRef = useRef(null);
const containerRef = useRef(null);
const [copied, setCopied] = useState(null);
const [pendingDelete, setPendingDelete] = useState({});

const scrollToBottom = () => {
if (messageEndRef.current) {
messageEndRef.current.scrollIntoView({ behavior: 'smooth' });
}
};
const scrollToBottom = () => {
if (messageEndRef.current) {
messageEndRef.current.scrollIntoView({ behavior: 'smooth' });
}
};

useEffect(() => {
scrollToBottom();
}, [messages]);
useEffect(() => {
scrollToBottom();
}, [messages]);

const handleCopy = useCallback((content, messageId) => {
const trimmedContent = content.replace(/^\n+/, ''); // 去除开头的空行
copy(trimmedContent);
setCopied(messageId);
setTimeout(() => {
setCopied(null);
}, 5000);
}, []);
const handleCopy = useCallback((content, messageId) => {
const trimmedContent = content.replace(/^\n+/, ''); // 去除开头的空行
copy(trimmedContent);
setCopied(messageId);
setTimeout(() => {
setCopied(null);
}, 5000);
}, []);

const handleDeleteClick = (messageId) => {
if (pendingDelete[messageId]) {
onDelete(messageId);
} else {
setPendingDelete({ ...pendingDelete, [messageId]: true });
setTimeout(() => {
setPendingDelete((prev) => {
const newState = { ...prev };
delete newState[messageId];
return newState;
});
}, 5000);
}
};
const handleDeleteClick = (messageId) => {
if (pendingDelete[messageId]) {
onDelete(messageId);
} else {
setPendingDelete({ ...pendingDelete, [messageId]: true });
setTimeout(() => {
setPendingDelete((prev) => {
const newState = { ...prev };
delete newState[messageId];
return newState;
});
}, 5000);
}
};

const customRenderers = {
p: ({ node, ...props }) => <p {...props} className="whitespace-pre-wrap text-justify" />,
code: ({ node, inline, className, children, ...props }) => {
const match = /language-(\w+)/.exec(className || '');
const content = String(children).replace(/^\n+/, '').replace(/\n+$/, ''); // 去除开头和结尾的空行
return match ? (
<CodeBlock language={match[1]} value={content} />
) : (
<code className={`${className} whitespace-pre-wrap break-words`} {...props}>
{content}
</code>
);
},
ol: ({ node, ...props }) => <ol {...props} className="list-decimal ml-6" />,
ul: ({ node, ...props }) => <ul {...props} className="list-disc ml-6" />,
li: ({ node, ...props }) => <li {...props} className="whitespace-normal break-words" />
};
const customRenderers = {
p: ({ node, ...props }) => <p {...props} className="whitespace-pre-wrap text-justify" />,
code: ({ node, inline, className, children, ...props }) => {
const match = /language-(\w+)/.exec(className || '');
const content = String(children).replace(/^\n+/, '').replace(/\n+$/, ''); // 去除开头和结尾的空行
return match ? (
<CodeBlock language={match[1]} value={content} />
) : (
<code className={`${className} whitespace-pre-wrap break-words`} {...props}>
{content}
</code>
);
},
ol: ({ node, ...props }) => <ol {...props} className="list-decimal ml-6" />,
ul: ({ node, ...props }) => <ul {...props} className="list-disc ml-6" />,
li: ({ node, ...props }) => <li {...props} className="whitespace-normal break-words" />
};

return (
<div ref={containerRef} className='flex-1 overflow-auto p-4' style={{ msOverflowStyle: 'none', scrollbarWidth: 'none' }}>
{messages.length === 0 ? (
<div className="flex items-center justify-center h-full">
<div className="text-center">
<p className="text-6xl text-gray-500 dark:text-yellow-50 mb-4 tracking-widest">對🐮彈琴</p>
<p className="text-sm text-gray-400 dark:text-yellow-100">每壹次對話,都是壹場思想碰撞</p>
</div>
</div>
) : (
messages.map((message, index) => (
<div
key={message.mid}
className={`shadow-md rounded-lg p-2 relative max-w-screen-md w-full mx-auto
return (
<div ref={containerRef} className='flex-1 overflow-auto p-4' style={{ msOverflowStyle: 'none', scrollbarWidth: 'none' }}>
{messages.length === 0 ? (
<div className="flex items-center justify-center h-full">
<div className="text-center">
<p className="text-6xl text-gray-500 dark:text-yellow-50 mb-4 tracking-widest">對🐮彈琴</p>
<p className="text-sm text-gray-400 dark:text-yellow-100">每壹次對話,都是壹場思想碰撞</p>
</div>
</div>
) : (
messages.map((message, index) => (
<div
key={message.mid}
className={`shadow-md rounded-lg p-2 relative max-w-screen-md w-full mx-auto
${message.role === 'user' ? (darkMode ? 'bg-violet-900 text-yellow-50' : 'bg-rose-50') : (darkMode ? 'bg-cyan-900 text-yellow-50' : 'bg-indigo-50')}
${index !== messages.length - 1 ? 'mb-4' : ''}`}
>
<div>
<ReactMarkdown
components={customRenderers}
remarkPlugins={[remarkGfm]}
className="break-words markdown-content whitespace-nowrap"
>
{message.content}
</ReactMarkdown>
</div>
<div className="text-gray-600 dark:text-gray-200 text-xs">{moment(message.timestamp).format('YYYY-MM-DD HH:mm:ss')}</div>
{message.totalTokens !== null && (
<div className="text-gray-600 dark:text-gray-200 text-xs">Token: {message.totalTokens}</div>
)}
<div className="absolute bottom-2 right-2 flex space-x-2">
<button
className={`text-xs ${pendingDelete[message.mid] ? 'text-rose-500' : 'text-emerald-400'}`}
onClick={() => handleDeleteClick(message.mid)}
>
{pendingDelete[message.mid] ? <HiExclamation className="h-4 w-4 text-rose-500" /> : <HiOutlineTrash className="h-4 w-4" />}
</button>
<button
className="text-xs text-sky-500"
onClick={() => handleCopy(message.content, message.mid)}
>
{copied === message.mid ? <HiCheckCircle className="h-4 w-4 text-emerald-400" /> : <HiOutlineDuplicate className="h-4 w-4" />}
</button>
</div>
</div>
))
>
<div>
<ReactMarkdown
components={customRenderers}
remarkPlugins={[remarkGfm]}
className="break-words markdown-content whitespace-nowrap"
>
{message.content}
</ReactMarkdown>
</div>
<div className="text-gray-600 dark:text-gray-200 text-xs">{moment(message.timestamp).format('YYYY-MM-DD HH:mm:ss')}</div>
{message.totalTokens !== null && (
<div className="text-gray-600 dark:text-gray-200 text-xs">Token: {message.totalTokens}</div>
)}
<div ref={messageEndRef}></div>
</div>
);
<div className="absolute bottom-2 right-2 flex space-x-2">
<button
className={`text-xs ${pendingDelete[message.mid] ? 'text-rose-500' : 'text-emerald-400'}`}
onClick={() => handleDeleteClick(message.mid)}
>
{pendingDelete[message.mid] ? <HiExclamation className="h-4 w-4 text-rose-500" /> : <HiOutlineTrash className="h-4 w-4" />}
</button>
<button
className="text-xs text-sky-500"
onClick={() => handleCopy(message.content, message.mid)}
>
{copied === message.mid ? <HiCheckCircle className="h-4 w-4 text-emerald-400" /> : <HiOutlineDuplicate className="h-4 w-4" />}
</button>
</div>
</div>
))
)}
<div ref={messageEndRef}></div>
</div>
);
};

export default MessageList;
Loading

0 comments on commit ade07c8

Please sign in to comment.