Working.
This commit is contained in:
parent
b9c9249bb1
commit
d8146c3723
7 changed files with 2872 additions and 112 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
145
index.html
145
index.html
|
@ -5,116 +5,34 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Messaging</title>
|
<title>Messaging</title>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
<script src="script.js"></script>
|
<script type="module" src="script.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav><a href="#">home</a><a href="#">not home</a></nav>
|
<div id="login">
|
||||||
|
<h1 class="large-header">Login</h1>
|
||||||
|
<div>
|
||||||
|
<input type="text" placeholder="Username" />
|
||||||
|
<button class="button-circle">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
fill="currentColor"
|
||||||
|
class="bi bi-pencil"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<nav><a href="#">Home</a><a href="#">Also home</a></nav>
|
||||||
|
|
||||||
<div id="messages">
|
<div id="messages">
|
||||||
<div class="message">
|
<div class="message message-right"></div>
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text">Hi there!</span>
|
|
||||||
<p class="message-timestamp">10 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text">Hey!</span>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text"
|
|
||||||
>So how are you etc... etc...</span
|
|
||||||
>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text">Hey!</span>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text"
|
|
||||||
>So how are you etc... etc...</span
|
|
||||||
>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text">Hey!</span>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text"
|
|
||||||
>So how are you etc... etc...</span
|
|
||||||
>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text">Hey!</span>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text"
|
|
||||||
>So how are you etc... etc...</span
|
|
||||||
>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text">Hey!</span>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text"
|
|
||||||
>So how are you etc... etc...</span
|
|
||||||
>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text">Hey!</span>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text"
|
|
||||||
>So how are you etc... etc...</span
|
|
||||||
>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text">Hey!</span>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="message message-right">
|
|
||||||
<div class="message-content">
|
|
||||||
<span class="message-text"
|
|
||||||
>So how are you etc... etc...</span
|
|
||||||
>
|
|
||||||
<p class="message-timestamp">9 minutes ago</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
|
@ -124,7 +42,20 @@
|
||||||
cols="30"
|
cols="30"
|
||||||
rows="3"
|
rows="3"
|
||||||
></textarea>
|
></textarea>
|
||||||
<button>Send</button>
|
<button id="send" class="button-primary">Send</button>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="message">
|
||||||
|
<div class="message-content">
|
||||||
|
<span class="message-text"></span>
|
||||||
|
|
||||||
|
<span class="message-info"
|
||||||
|
><span class="message-user"></span>
|
||||||
|
<span class="message-timestamp"></span
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
2629
package-lock.json
generated
Normal file
2629
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
17
package.json
Normal file
17
package.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"name": "messaging",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Messaging app",
|
||||||
|
"main": "script.js",
|
||||||
|
"scripts": {
|
||||||
|
"devStart": "nodemon server.js"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"socket.io": "^4.4.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"nodemon": "^2.0.15"
|
||||||
|
}
|
||||||
|
}
|
65
script.js
65
script.js
|
@ -0,0 +1,65 @@
|
||||||
|
import moment from "https://jspm.dev/moment"
|
||||||
|
import { io } from "https://cdn.socket.io/4.3.2/socket.io.esm.min.js"
|
||||||
|
const socket = io(":3000")
|
||||||
|
const messageButton = document.querySelector("#send")
|
||||||
|
const nameButton = document.querySelector("button")
|
||||||
|
const nameInput = document.querySelector("input")
|
||||||
|
const messageInput = document.querySelector("textarea")
|
||||||
|
|
||||||
|
setInterval(
|
||||||
|
() =>
|
||||||
|
document.querySelectorAll(".message-timestamp").forEach((element) => {
|
||||||
|
element.innerText = moment(
|
||||||
|
new Date(Number(element.closest(".message").dataset.time))
|
||||||
|
).fromNow()
|
||||||
|
}),
|
||||||
|
45000
|
||||||
|
)
|
||||||
|
|
||||||
|
const addMessage = (messageObject) => {
|
||||||
|
const { message, isYours, isSystem, user } = messageObject
|
||||||
|
const messageDiv = document
|
||||||
|
.querySelector("template")
|
||||||
|
.content.cloneNode(true)
|
||||||
|
.querySelector(".message")
|
||||||
|
|
||||||
|
if (isYours) messageDiv.classList.add("message-right")
|
||||||
|
else if (isSystem) messageDiv.classList.add("system")
|
||||||
|
messageDiv.querySelector(".message-text").innerText = message
|
||||||
|
const time = Date.now()
|
||||||
|
messageDiv.dataset.time = time
|
||||||
|
messageDiv.querySelector(".message-timestamp").innerText =
|
||||||
|
moment(time).fromNow()
|
||||||
|
if (user) messageDiv.querySelector(".message-user").innerText = `${user} • `
|
||||||
|
document.querySelector("#messages").prepend(messageDiv)
|
||||||
|
}
|
||||||
|
|
||||||
|
nameButton.addEventListener("click", () => {
|
||||||
|
if (!nameInput.value) return (nameInput.required = true)
|
||||||
|
document.querySelector("#login").classList.add("done")
|
||||||
|
socket.emit("new-user", nameInput.value)
|
||||||
|
addMessage({
|
||||||
|
message: "You joined",
|
||||||
|
isYours: true,
|
||||||
|
isSystem: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
messageButton.addEventListener("click", () => {
|
||||||
|
if (!messageInput.value) return (messageInput.required = true)
|
||||||
|
socket.emit("send-chat-message", messageInput.value)
|
||||||
|
addMessage({ user: "you", message: messageInput.value, isYours: true })
|
||||||
|
messageInput.value = ""
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on("chat-message", (message, user) => {
|
||||||
|
addMessage({ message, user })
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on("user-connected", (name) => {
|
||||||
|
addMessage({ message: `${name} joined`, isSystem: true })
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on("user-disconnected", (name) => {
|
||||||
|
addMessage({ message: `${name} disconnected`, isSystem: true })
|
||||||
|
})
|
27
server.js
Normal file
27
server.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
const io = require("socket.io")(3000, {
|
||||||
|
cors: {
|
||||||
|
origin: [
|
||||||
|
"http://localhost:5500",
|
||||||
|
"http://127.0.0.1:5500",
|
||||||
|
"http//192.168.1.226:5500",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const users = {}
|
||||||
|
|
||||||
|
io.on("connection", (socket) => {
|
||||||
|
socket.on("new-user", (name) => {
|
||||||
|
users[socket.id] = name
|
||||||
|
socket.broadcast.emit("user-connected", name)
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on("send-chat-message", (message) =>
|
||||||
|
socket.broadcast.emit("chat-message", message, users[socket.id])
|
||||||
|
)
|
||||||
|
|
||||||
|
socket.on("disconnect", () => {
|
||||||
|
socket.broadcast.emit("user-disconnected", users[socket.id])
|
||||||
|
delete users[socket.id]
|
||||||
|
})
|
||||||
|
})
|
100
style.css
100
style.css
|
@ -16,9 +16,9 @@ body {
|
||||||
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
|
height: 100vh;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 100px 1fr 175px;
|
grid-template-rows: 100px 1fr 175px;
|
||||||
height: 100vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nav,
|
nav,
|
||||||
|
@ -33,7 +33,6 @@ footer {
|
||||||
nav a {
|
nav a {
|
||||||
margin: 0 0.5em;
|
margin: 0 0.5em;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
text-transform: capitalize;
|
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
color: white;
|
color: white;
|
||||||
grid-template-columns: 1fr 500px;
|
grid-template-columns: 1fr 500px;
|
||||||
|
@ -49,7 +48,8 @@ footer {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea,
|
||||||
|
input[type="text"] {
|
||||||
border: none;
|
border: none;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
|
@ -60,7 +60,7 @@ textarea {
|
||||||
max-height: 90%;
|
max-height: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea::placeholder {
|
:is(textarea, input[type="text"])::placeholder {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,19 +68,38 @@ button {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 2em;
|
border-radius: 2em;
|
||||||
color: #f5f0f0;
|
color: #f5f0f0;
|
||||||
|
background-color: transparent;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
cursor: pointer;
|
||||||
padding: 0.7rem 1.6rem;
|
padding: 0.7rem 1.6rem;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-primary {
|
||||||
background-color: var(--primary);
|
background-color: var(--primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-secondary {
|
||||||
|
background-color: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-circle {
|
||||||
|
padding: 0.85em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
height: 1.5em;
|
||||||
|
width: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
button:hover {
|
button:hover {
|
||||||
filter: brightness(0.9);
|
filter: brightness(0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-timestamp {
|
.message-info {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: white;
|
color: white;
|
||||||
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-text {
|
.message-text {
|
||||||
|
@ -101,6 +120,8 @@ button:hover {
|
||||||
background-color: var(--primary);
|
background-color: var(--primary);
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
#messages::-webkit-scrollbar {
|
#messages::-webkit-scrollbar {
|
||||||
|
@ -126,6 +147,7 @@ button:hover {
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -135,7 +157,75 @@ button:hover {
|
||||||
justify-content: right;
|
justify-content: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message-middle {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.message-right .message-text {
|
.message-right .message-text {
|
||||||
background-color: #e9e932;
|
background-color: #e9e932;
|
||||||
color: #424242;
|
color: #424242;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.system .message-text {
|
||||||
|
background-color: #05d0eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login {
|
||||||
|
background-color: var(--primary);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login.done {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login:not(.done) + nav,
|
||||||
|
#login:not(.done) + nav + div,
|
||||||
|
#login:not(.done) + nav + div + footer {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.medium-header {
|
||||||
|
font-size: 3rem;
|
||||||
|
font-weight: 250;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.large-header {
|
||||||
|
font-size: 5rem;
|
||||||
|
font-weight: 300;
|
||||||
|
line-height: 1.2;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(input[type="text"], textarea):required {
|
||||||
|
animation: shake 0.2s ease-in-out 0s 2;
|
||||||
|
color: #ff0000;
|
||||||
|
border-color: red !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(input[type="text"], textarea):required::placeholder {
|
||||||
|
color: #f20000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shake {
|
||||||
|
0% {
|
||||||
|
margin-left: 0rem;
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
margin-left: -0.5rem;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
margin-left: 0rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in a new issue