Compare commits
No commits in common. "f6df3901b188fc1385bae919404b9909225ffeb2" and "5c4d2583840d657ceee785aab96823c07741cb19" have entirely different histories.
f6df3901b1
...
5c4d258384
@ -20,10 +20,7 @@
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
],
|
||||
"rules": {
|
||||
"react/jsx-no-target-blank": "off"
|
||||
}
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
@ -76,7 +76,7 @@ function Chat({user, setUser}) {
|
||||
|
||||
return (
|
||||
<div className="Chat h-full flex flex-col">
|
||||
<MessageList messages={messages} setMessages={setMessages} />
|
||||
<MessageList messages={messages} user={user} updateUser={updateUser} />
|
||||
<UserList users={users} updateUser={updateUser} user={user} socket={socket} />
|
||||
<ChatInput sendMessage={sendMessage} user={user} updateUser={updateUser} setSettingsModalOpen={setSettingsModalOpen} socket={socket} />
|
||||
<SettingsModal open={settingsModalOpen} setOpen={setSettingsModalOpen} user={user} updateUser={updateUser} />
|
||||
@ -90,50 +90,56 @@ function Chat({user, setUser}) {
|
||||
|
||||
|
||||
|
||||
function MessageList({messages, setMessages}) {
|
||||
var [atBottom, setAtBottom] = useState(true);
|
||||
var [atTop, setAtTop] = useState(false);
|
||||
var endRef = useRef();
|
||||
function MessageList({messages, user, updateUser}) {
|
||||
|
||||
var [scrollLock, setScrollLock] = useState(true);
|
||||
var endRef = useRef();
|
||||
function onScroll(event) {
|
||||
var { scrollTop, scrollHeight, clientHeight } = event.target;
|
||||
setAtBottom(scrollHeight - (scrollTop + clientHeight) < 32);
|
||||
setAtTop(scrollTop < 32);
|
||||
setScrollLock(scrollHeight - (scrollTop + clientHeight) < 32);
|
||||
};
|
||||
|
||||
var scrollToBottom = () => endRef.current?.scrollIntoView();
|
||||
useEffect(() => {
|
||||
if (atBottom) scrollToBottom();
|
||||
});
|
||||
var observer = new ResizeObserver(() => atBottom && scrollToBottom());
|
||||
|
||||
useEffect(()=>{
|
||||
if (atTop) loadOlderMessages();
|
||||
}, [atTop]);
|
||||
|
||||
async function loadOlderMessages() {
|
||||
var olderMessages = await fetch(BASE_URL+"/messages?before="+messages[0].timestamp).then(res => res.json());
|
||||
console.debug("loadOlderMessages", olderMessages);
|
||||
setMessages(messages => [...olderMessages, ...messages]);
|
||||
function scrollToBottom() {
|
||||
endRef.current?.scrollIntoView();
|
||||
}
|
||||
useEffect(() => {
|
||||
if (scrollLock) scrollToBottom();
|
||||
});
|
||||
|
||||
var observer = new ResizeObserver(entries => {
|
||||
if (scrollLock) scrollToBottom();
|
||||
});
|
||||
|
||||
return <ul className="p-4 w-full flex-1 overflow-y-auto break-words" onScroll={onScroll} onLoad={e => observer.observe(e.target)}>
|
||||
{messages.map(message => <Message message={message} key={message._id} />)}
|
||||
<div ref={endRef}></div>
|
||||
</ul>
|
||||
}
|
||||
{messages.map(message => {
|
||||
|
||||
function Message({message}) {
|
||||
if (message.user) {
|
||||
var prefix = <b>{message.user.website ? <a href={message.user.website} target="_blank" rel="noopener" className={message.user.website && "hover:underline"}>{message.user.name}</a> : message.user.name}: </b>
|
||||
function onAuthorClick(event) {
|
||||
if (message.user.uuid !== user.uuid) return;
|
||||
event.preventDefault();
|
||||
var website = prompt("Set website URL", user.website);
|
||||
if (website) updateUser({website});
|
||||
}
|
||||
var content = <span className={(message.user ? '' : " font-bold")} style={{color: message.color || message.user?.color}} title={new Date(message.timestamp).toLocaleString()}>{processMessageContent(message.content)}</span>
|
||||
|
||||
if (message.user)
|
||||
// eslint-disable-next-line react/jsx-no-target-blank
|
||||
var prefix = <b>{message.user.website ? <a
|
||||
href={message.user.website}
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
//onClick={onAuthorClick}
|
||||
className={message.user.website && "hover:underline"}
|
||||
>{message.user.name}</a> : message.user.name}: </b>
|
||||
|
||||
var content = <span
|
||||
className={(message.user ? '' : " font-bold")}
|
||||
style={{color: message.color || message.user?.color}}
|
||||
title={new Date(message.timestamp).toLocaleString()}
|
||||
>{processMessageContent(message.content)}</span>
|
||||
|
||||
if (message.file) {
|
||||
let url = BASE_URL + `/file/${message._id}/${message.file.name}`;
|
||||
var file =
|
||||
let embed =
|
||||
message.file.type?.startsWith("image") ?
|
||||
<a href={url} target="_blank" rel="noopener" style={{color:"revert",textDecoration:"revert"}}><img src={url} alt={message.file.name} className="max-h-32 inline-block align-top border" /></a>
|
||||
<img src={url} alt={message.file.name} className="max-h-32 inline-block align-top border" />
|
||||
: message.file.type?.startsWith("video") ?
|
||||
<video className='max-h-64 inline-block align-top border' controls>
|
||||
<source src={url} type={message.file.type} />
|
||||
@ -142,10 +148,18 @@ function Message({message}) {
|
||||
<audio className='max-h-64 inline-block align-top' controls>
|
||||
<source src={url} type={message.file.type} />
|
||||
</audio>
|
||||
: <a href={url} target="_blank" rel="noopener" style={{color:"revert",textDecoration:"revert"}}>{message.file.name}</a>
|
||||
: <span>{message.file.name}</span>
|
||||
// eslint-disable-next-line react/jsx-no-target-blank
|
||||
var file = <a href={url} target="_blank" rel="noopener" style={{color:"revert",textDecoration:"revert"}}>{embed}</a>;
|
||||
}
|
||||
|
||||
return <li>{prefix} {content} {file}</li>
|
||||
return <li key={message._id}>
|
||||
{prefix} {content} {file}
|
||||
</li>
|
||||
|
||||
})}
|
||||
<div ref={endRef}></div>
|
||||
</ul>
|
||||
}
|
||||
|
||||
|
||||
@ -230,10 +244,8 @@ function EmojiPicker({open, setOpen, setChatInputContent}) {
|
||||
setChatInputContent(content => `${content} :${event.target.dataset.emoji}:`);
|
||||
};
|
||||
if (open)
|
||||
return <div className='fixed top-0 left-0 w-full h-full' onClick={e=>setOpen(false)}>
|
||||
<div className='w-[258px] h-64 rounded border fixed right-6 bottom-16 overflow-auto bg-white dark:bg-black p-2' onClick={e=>e.stopPropagation()}>
|
||||
{emojis.map(emoji => <img src={BASE_URL+"/emoji/"+emoji} title={`:${emoji}:`} alt={`:${emoji}:`} key={emoji} data-emoji={emoji} className="w-10 h-10 inline-block p-0.5 cursor-pointer border border-transparent hover:border-gray-600" onClick={onEmojiClick} />)}
|
||||
</div>
|
||||
return <div className='w-64 h-64 rounded border fixed right-6 bottom-16 overflow-auto bg-white dark:bg-black'>
|
||||
{emojis.map(emoji => <img src={BASE_URL+"/emoji/"+emoji} title={`:${emoji}:`} alt={`:${emoji}:`} key={emoji} data-emoji={emoji} className="w-8 h-8 inline-block m-1 cursor-pointer hover:border" onClick={onEmojiClick} />)}
|
||||
</div>
|
||||
}
|
||||
|
||||
@ -331,6 +343,7 @@ function processMessageContent(content) {
|
||||
if (!content) return;
|
||||
// hyperlinks
|
||||
content = reactStringReplace(content, /(https?:\/\/\S+)/gi, link =>
|
||||
// eslint-disable-next-line react/jsx-no-target-blank
|
||||
<a href={link} target="_blank" rel="noopener" style={{color: "revert", textDecoration: "revert"}}>{link}</a>
|
||||
)
|
||||
// emoji
|
||||
|
@ -24,12 +24,6 @@ app.use((req, res, next) => {
|
||||
res.header("Access-Control-Allow-Methods", "*");
|
||||
next();
|
||||
});
|
||||
app.get("/messages", (req, res, next) => {
|
||||
var query = req.query.before ? {timestamp: {$lt: new Date(req.query.before)}} : {};
|
||||
messages.find(query).project({"file.data": 0, "user.ip": 0}).sort({timestamp: -1}).limit(100).toArray().then(messages => {
|
||||
res.send(messages.reverse());
|
||||
}).catch(e => next(e));
|
||||
});
|
||||
app.get("/file/:message_id/:filename", async (req, res, next) => {
|
||||
try {
|
||||
var doc = await messages.findOne({_id: new ObjectId(req.params.message_id)}, {file:1});
|
||||
@ -113,7 +107,7 @@ dbclient.connect().then(async () => {
|
||||
type: m.file.type?.substring(0,64)
|
||||
} : undefined
|
||||
}));
|
||||
var history = await messages.find().project({"file.data": 0, "user.ip": 0}).sort({timestamp: -1}).limit(100).toArray();
|
||||
var history = await messages.find().project({"file.data": 0}).sort({timestamp: -1}).limit(100).toArray();
|
||||
history = history.reverse();
|
||||
socket.emit("messages", history);
|
||||
socket.on("type", () => {
|
||||
|
Loading…
Reference in New Issue
Block a user