Skip to content

Commit

Permalink
Merge pull request #419 from DishpitDev/staging
Browse files Browse the repository at this point in the history
ligma
  • Loading branch information
Dishpit authored Jan 12, 2025
2 parents 6758899 + de370a0 commit 71871fa
Show file tree
Hide file tree
Showing 25 changed files with 219 additions and 63 deletions.
Binary file added Slopify/public/emojis/ayaya.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/clueless.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/dopepe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/dread.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/endMe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/feelsBadMan.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/kekw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/laughingPepe.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/lfg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/minipog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/monkaGiga.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/monkaS.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/monkaSnake.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/pogU.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/pooga.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/superkek.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/thonk.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Slopify/public/emojis/weirdga.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions Slopify/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Slopify",
"version": "0.6.0",
"version": "0.7.0",
"identifier": "com.slopify.app",
"build": {
"beforeDevCommand": "npm run dev",
Expand All @@ -12,7 +12,7 @@
"app": {
"windows": [
{
"title": "Slopify | v0.6.0",
"title": "Slopify | v0.7.0",
"minWidth": 900,
"minHeight": 800,
"center": true,
Expand Down
86 changes: 54 additions & 32 deletions Slopify/src/components/Message.jsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,76 @@
import emojis, { EMOJI_REGEX, createEmojiElement } from "../utils/emoji.js";

function sanitizeHTML(message) {
// purges script tags
message = message.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, '');
message = message.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, "");

// purges iframe tags
message = message.replace(/<iframe[^>]*>([\s\S]*?)<\/iframe>/gi, '');
message = message.replace(/<iframe[^>]*>([\s\S]*?)<\/iframe>/gi, "");

// purges object tags
message = message.replace(/<(object|embed|applet)[^>]*>[\s\S]*?<\/\1>/gi, '');
message = message.replace(/<(object|embed|applet)[^>]*>[\s\S]*?<\/\1>/gi, "");

// purges event handlers
message = message.replace(/<([a-z][a-z0-9]*)\s+[^>]*\s*on\w+="[^"]*"[^>]*>/gi, '<$1>');
message = message.replace(
/<([a-z][a-z0-9]*)\s+[^>]*\s*on\w+="[^"]*"[^>]*>/gi,
"<$1>",
);

return message;
}

function processEmojis(message) {
const emojis = message.match(EMOJI_REGEX);

if (!emojis) {
return message;
}

for (let emoji of emojis) {
const emojiElement = createEmojiElement(emoji.slice(1, -1));
if (!emojiElement) {
continue;
}
message = message.replace(emoji, emojiElement);
}

return message;
}

export default function Message(data) {
const sanitizedMessage = sanitizeHTML(data.message);
const finalMessage = processEmojis(sanitizedMessage);

return (
<>
<div key={data.key} className="message">
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<div style={{ display: "flex", gap: "10px", maxWidth: "90%" }}>
<img
src={data.photo}
alt="Profile"
style={{
width: "50px",
height: "50px",
objectFit: "cover",
borderRadius: "50%",
}}
<div key={data.id} className="message">
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<div style={{ display: "flex", gap: "10px", maxWidth: "90%" }}>
<img
src={data.photo}
alt="Profile"
style={{
width: "50px",
height: "50px",
objectFit: "cover",
borderRadius: "50%",
}}
/>
<div style={{ maxWidth: "90%" }}>
<strong style={{ color: data.color }}>{data.name}</strong>
<p
style={{ margin: 0, marginTop: "0.5rem" }}
dangerouslySetInnerHTML={{ __html: finalMessage }}
/>
<div style={{ maxWidth: "90%" }}>
<strong style={{ color: data.color }}>{data.name}</strong>
<p style={{ margin: 0, marginTop: "0.5rem" }}><p
style={{ margin: 0, marginTop: "0.5rem" }}
dangerouslySetInnerHTML={{ __html: sanitizedMessage }}
/></p>
</div>
</div>
<small style={{ minWidth: "15%" }}>{data.date}</small>
</div>
<small style={{ minWidth: "15%" }}>{data.date}</small>
</div>
</>
</div>
);
}
80 changes: 72 additions & 8 deletions Slopify/src/components/MessageForm.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useState, useEffect } from "react";
import { supabase } from "../supabaseClient";
import Button from "./Button";
import emojis from "../utils/emoji.js";

export default function MessageForm() {
const [message, setMessage] = useState("");
const [charCount, setCharCount] = useState(1000);
const [emojiPickerVisible, setEmojiPickerVisible] = useState(false);

const handleSubmit = async (e) => {
e.preventDefault();
Expand Down Expand Up @@ -41,6 +43,19 @@ export default function MessageForm() {
}
};

const handleEmojiClick = (emojiKey) => {
const emojiText = `:${emojiKey}:`;
const newMessage = message + emojiText;
const newCharCount = 1000 - newMessage.length;

if (newCharCount >= 0) {
setMessage(newMessage);
setCharCount(newCharCount);
}

setEmojiPickerVisible(false);
}

const getColor = () => {
if (charCount <= 0) return "black";
if (charCount <= 10) return "red";
Expand All @@ -52,14 +67,63 @@ export default function MessageForm() {
}, [charCount]);

return (
<form onSubmit={handleSubmit} style={{ marginTop: "1rem" }}>
<input
type="text"
placeholder="Type your message..."
value={message}
onChange={handleInputChange}
style={{ padding: "0.5rem", width: "70%" }}
/>
<form onSubmit={handleSubmit} style={{ marginTop: "1rem", position: "relative", width: "100%", display: "flex", flexDirection: "row", alignItems: "center" }}>
<div style={{ position: "relative", display: "flex", alignItems: "center", width: "100%" }}>
<input
type="text"
placeholder="Message your fellow sloppers..."
value={message}
onChange={handleInputChange}
style={{ padding: "0.5rem", width: "100%", paddingRight: "30px" }}
/>
<button
type="button"
onClick={() => setEmojiPickerVisible(!emojiPickerVisible)}
style={{
marginLeft: "-45px",
background: "none",
border: "none",
cursor: "pointer",
fontSize: "18px",
filter: "grayscale(100%)",
}}
>
😊
</button>
</div>
{emojiPickerVisible && (
<div
style={{
position: "fixed",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
background: "#fff",
border: "1px solid #ccc",
borderRadius: "10px",
padding: "1rem",
display: "grid",
gridTemplateColumns: "repeat(auto-fit, minmax(40px, 1fr))",
gap: "0.75rem",
maxHeight: "300px",
width: "60%",
overflowY: "auto",
zIndex: 1000,
boxShadow: "0 4px 8px rgba(0, 0, 0, 0.2)",
}}
>
{Object.keys(emojis).map((emojiKey) => (
<img
key={emojiKey}
src={emojis[emojiKey]}
alt={emojiKey}
title={emojiKey}
style={{ width: "40px", height: "40px", cursor: "pointer" }}
onClick={() => handleEmojiClick(emojiKey)}
/>
))}
</div>
)}
<Button
action="submit"
content="Send"
Expand Down
62 changes: 42 additions & 20 deletions Slopify/src/components/MessageList.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { supabase } from "../supabaseClient";
import Message from "./Message";
import { sendNotification } from "@tauri-apps/plugin-notification";

const PAGE_SIZE = 50;

export default function MessageList(data) {
const [messages, setMessages] = useState([]);
const [messages, setMessages] = useState({});
const [loading, setLoading] = useState(true);
const [hasMore, setHasMore] = useState(true);
const [scrolling, setScrolling] = useState(false);

const sortedMessages = useMemo(
() =>
Object.values(messages).sort(
(a, b) => new Date(a.created_at) - new Date(b.created_at),
),
[messages],
);

useEffect(() => {
fetchMessages();
const subscription = supabase
Expand All @@ -21,7 +29,10 @@ export default function MessageList(data) {
(payload) => {
const newMessage = payload.new;
attachDisplayName(newMessage).then((msgWithDisplayName) => {
setMessages((prev) => [...prev, msgWithDisplayName]);
setMessages((prev) => ({
...prev,
[newMessage.id]: msgWithDisplayName,
}));
if (
data.currentUser &&
msgWithDisplayName.content.includes(`@${data.currentUser}`)
Expand All @@ -40,6 +51,7 @@ export default function MessageList(data) {

useEffect(() => {
const messageBox = document.getElementById("message-box");

if (messageBox) {
messageBox.scrollTop = messageBox.scrollHeight;
}
Expand All @@ -61,22 +73,24 @@ export default function MessageList(data) {
minute: "2-digit",
second: "2-digit",
})}`;
} else if (isYesterday) {
}

if (isYesterday) {
return `Yesterday, ${messageDate.toLocaleTimeString(undefined, {
hour: "numeric",
minute: "2-digit",
second: "2-digit",
})}`;
} else {
return messageDate.toLocaleString(undefined, {
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
second: "2-digit",
});
}

return messageDate.toLocaleString(undefined, {
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric",
minute: "2-digit",
second: "2-digit",
});
};

const attachDisplayName = async (message) => {
Expand Down Expand Up @@ -125,7 +139,13 @@ export default function MessageList(data) {
const messagesWithDisplayNames = await Promise.all(
data.map(attachDisplayName),
);
setMessages((prev) => [...prev, ...messagesWithDisplayNames]);
setMessages((prev) => ({
...prev,
...messagesWithDisplayNames.reduce((acc, msg) => {
acc[msg.id] = msg;
return acc;
}, {}),
}));
if (data.length < PAGE_SIZE) {
setHasMore(false);
}
Expand All @@ -140,11 +160,13 @@ export default function MessageList(data) {

const handleScroll = (e) => {
const { scrollTop } = e.target;
if (scrollTop === 0 && hasMore) {
const oldestMessage = messages[messages.length - 1];
if (oldestMessage) {
fetchMessages(oldestMessage.created_at);
}
if (!(scrollTop === 0 && hasMore)) {
return;
}

const oldestMessage = sortedMessages[sortedMessages.length - 1];
if (oldestMessage) {
fetchMessages(oldestMessage.created_at);
}
};

Expand All @@ -168,7 +190,7 @@ export default function MessageList(data) {
{loading ? (
<p>Loading...</p>
) : (
messages.map((msg) => (
sortedMessages.map((msg) => (
<Message
key={msg.id}
name={msg.display_name}
Expand Down
2 changes: 1 addition & 1 deletion Slopify/src/pages/ChatPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default function ChatPage() {
};

return (
<div>
<div id="chat-page">
<h2>Welcome back to Slopify, {displayName}!</h2>
<MessageList currentUser={displayName} />
<MessageForm />
Expand Down
8 changes: 8 additions & 0 deletions Slopify/src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,11 @@ form {
#chat-container p {
margin: 0.5rem 0;
}

#chat-page {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 1rem;
}
Loading

0 comments on commit 71871fa

Please sign in to comment.