Commit 3fd86fbd authored by 健杭 徐's avatar 健杭 徐
Browse files

frontend

parent 6f2fe003
import ChatRoom from "./pages/ChatRoom/ChatRoom";
import "./globals.css";
export default function Page() {
return (
<div>
<ChatRoom />
</div>
);
}
\ No newline at end of file
.chat-room {
display: flex;
position: relative;
width: 100vw;
height: 100vh;
box-sizing: border-box;
overflow: hidden;
}
.chat-room-nav {
position: fixed;
padding: 10px;
width: 15%;
height: 100%;
background-color: #f5f5f5;
border-bottom: 1px solid #ddd;
z-index: 10;
}
.open {
display: flex;
position: fixed;
width: 100vw;
height: 100vh;
box-sizing: border-box;
overflow: hidden;
background-color: rgba(255, 255, 255, 0.75);
z-index: 0;
}
.open .roomName-input {
background-color: #fff;
display: flex;
flex-direction: column;
position: fixed;
top: 40%;
left: 30%;
z-index: 0;
width: 40%;
height: 25%;
border-radius: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
h3 {
align-items: center;
text-align: center;
}
input {
width: 80%;
height: 20px;
margin: 20px auto;
padding: 10px;
border-radius: 20px;
border: 1px solid #ccc;
font-size: 16px;
}
.button-container {
display: flex;
justify-content: center;
margin-top: -5px;
button {
width: 100px;
height: 40px;
background-color: #007bff;
color: white;
border: none;
border-radius: 20px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
margin-left: 10px;
margin-right: 10px;
&:hover {
background-color: #0056b3;
}
}
}
}
.chat-room-nav .chat-list {
display: flex;
flex-direction: column;
height: 100%;
overflow-y: auto;
padding: 10px;
box-sizing: border-box;
z-index: 1;
.chat-item {
display: flex;
position: relative;
align-items: center;
padding: 10px;
margin-bottom: 10px;
border-radius: 8px;
cursor: pointer;
&:hover {
background-color: #e0e0e0;
}
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 10px;
}
.chat-info {
height: 40px;
flex-grow: 1;
right: 0;
width: 80%;
h3 {
margin: 0;
margin-left: 5px;
font-size: 1.2em;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.chat-message {
position: relative;
margin-bottom: 10px;
margin-left: 5px;
max-width:100px;
font-weight: bold;
color: #333;
max-height: 20px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
}
.chat-time {
position: absolute;
color: #666;
font-size: 0.9em;
right: 5px;
bottom: 10px;
}
}
}
}
.message-item {
position: relative;
left: 15%;
width: 85%;
height: 100vh;
display: flex;
flex-direction: column;
box-sizing: border-box;
background-image: url('../../public/backGround.jpg');
background-size: cover;
z-index: 2;
.message-header {
z-index: 5;
width: 100%;
position: sticky;
top: 0;
background-color: #fff;
height: 70px;
display: flex;
align-items: center;
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
margin-left: 40px;
}
h2 {
width: 10%;
color: #333;
text-align: center;
margin: 0;
padding: 0;
}
border-bottom: 1px solid #000000;
}
.message-list {
flex: 1;
overflow-y: auto;
padding: 10px;
box-sizing: border-box;
z-index: 3;
.message {
display: flex;
max-width: 80%;
padding: 10px;
margin-bottom: 15px;
margin-left: 15px;;
border-radius: 15px;
overflow-wrap: break-word;
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
margin-right: 10px;
flex-shrink: 0;
}
.message-content {
min-width: 0;
.message-info {
height: auto;
.message-sender {
font-weight: bold;
color: #333;
margin-right: 8px;
}
.message-time {
font-size: 0.8em;
color: #999;
}
}
.message-text {
padding: 8px 12px;
margin: 5px 0;
border-radius: 10px;
color: #555;
background-color: #f5f5f5;
display: block;
word-break: break-word;
}
}
}
}
.message-input {
position: sticky;
bottom: 0;
width: 90%;
padding: 15px;
box-sizing: border-box;
z-index: 4;
display: flex;
margin-left: 5%;
input {
flex: 1;
padding: 12px 15px;
border-radius: 25px;
font-size: 16px;
margin-right: 10px;
background-color: transparent;
}
input:hover {
border: #000000 1px solid;
}
}
}
/* From Uiverse.io by njesenberger */
.button {
-webkit-appearance: none;
appearance: none;
position: relative;
border-width: 0;
padding: 0 8px 12px;
min-width: 10em;
box-sizing: border-box;
background: transparent;
font: inherit;
cursor: pointer;
}
.button-top {
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 0;
padding: 8px 16px;
transform: translateY(0);
text-align: center;
color: #fff;
text-shadow: 0 -1px rgba(0, 0, 0, .25);
transition-property: transform;
transition-duration: .2s;
-webkit-user-select: none;
user-select: none;
}
.button:active .button-top {
transform: translateY(6px);
}
.button-top::after {
content: '';
position: absolute;
z-index: -1;
border-radius: 4px;
width: 100%;
height: 100%;
box-sizing: content-box;
background-image: radial-gradient(#cd3f64, #9d3656);
text-align: center;
color: #fff;
box-shadow: inset 0 0 0px 1px rgba(255, 255, 255, .2), 0 1px 2px 1px rgba(255, 255, 255, .2);
transition-property: border-radius, padding, width, transform;
transition-duration: .2s;
}
.button:active .button-top::after {
border-radius: 6px;
padding: 0 2px;
}
.button-bottom {
position: absolute;
z-index: -1;
bottom: 4px;
left: 4px;
border-radius: 8px / 16px 16px 8px 8px;
padding-top: 6px;
width: calc(100% - 8px);
height: calc(100% - 10px);
box-sizing: content-box;
background-color: #803;
background-image: radial-gradient(4px 8px at 4px calc(100% - 8px), rgba(255, 255, 255, .25), transparent), radial-gradient(4px 8px at calc(100% - 4px) calc(100% - 8px), rgba(255, 255, 255, .25), transparent), radial-gradient(16px at -4px 0, white, transparent), radial-gradient(16px at calc(100% + 4px) 0, white, transparent);
box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.5), inset 0 -1px 3px 3px rgba(0, 0, 0, .4);
transition-property: border-radius, padding-top;
transition-duration: .2s;
}
.button:active .button-bottom {
border-radius: 10px 10px 8px 8px / 8px;
padding-top: 0;
}
.button-base {
position: absolute;
z-index: -2;
top: 4px;
left: 0;
border-radius: 12px;
width: 100%;
height: calc(100% - 4px);
background-color: rgba(0, 0, 0, .15);
box-shadow: 0 1px 1px 0 rgba(255, 255, 255, .75), inset 0 2px 2px rgba(0, 0, 0, .25);
}
.message-item {
/* From Uiverse.io by adamgiebl */
button {
font-family: inherit;
font-size: 20px;
background: transparent;
color: white;
padding: 0.7em 1em;
padding-left: 0.9em;
display: flex;
align-items: center;
border: none;
border-radius: 16px;
overflow: hidden;
transition: all 0.2s;
cursor: pointer;
}
button span {
display: block;
margin-left: 0.3em;
transition: all 0.3s ease-in-out;
}
button svg {
display: block;
transform-origin: center center;
transition: transform 0.3s ease-in-out;
}
button:hover .svg-wrapper {
animation: fly-1 0.6s ease-in-out infinite alternate;
}
button:hover svg {
transform: translateX(1.2em) rotate(45deg) scale(1.1);
}
button:hover span {
transform: translateX(5em);
}
button:active {
transform: scale(0.95);
}
@keyframes fly-1 {
from {
transform: translateY(0.1em);
}
to {
transform: translateY(-0.1em);
}
}
}
\ No newline at end of file
'use client';
import "./ChatRoom.css";
import React, { Component } from "react";
// profile
const Profile = [ 'https://pic4.zhimg.com/v2-c5a0d0d57c1a85c6db56e918707f54a3_r.jpg',
'https://pic2.zhimg.com/v2-c2e79191533fdc7fced2f658eef987c9_r.jpg',
'https://pic4.zhimg.com/v2-bf5f58e7b583cd69ac228db9fdff377f_r.jpg',
'https://pic1.zhimg.com/v2-10e9368af9eb405c8844584ad3ad9dd8_r.jpg',
'https://picx.zhimg.com/50/v2-63e3500bfd25b6ae7013a6a3b6ce045b_720w.jpg',
'https://c-ssl.duitang.com/uploads/blog/202109/20/20210920000906_53764.png']
const RoomProfile = 'https://tse1-mm.cn.bing.net/th/id/OIP-C.0KyBJKAdIGi9SAQc_X62tQHaLr?cb=thvnextc2&rs=1&pid=ImgDetMain';
interface RoomEntryProps {
roomId: number; // room id
roomName: string; // room name
lastSender: string; // the lasted User name
lastContent: string; // content
lastTime: number; // the lasted message time
}
function RoomEntry (props: RoomEntryProps) {
return (
<div className="chat-room-nav">
<div className="sidebar-action">
<button type="button" className="button" onClick={openOpenDiv}>
<div className="button-top">New Chat</div>
<div className="button-bottom"></div>
<div className="button-base"></div>
</button>
</div>
<div className="chat-list">
<div className="chat-item">
<img src={RoomProfile} alt="Avatar" className="avatar" />
<div className="chat-info">
<h3>{props.roomName}</h3>
<span className="chat-message">{props.lastSender}: {props.lastContent}</span>
<span className="chat-time">Time</span>
</div>
</div>
</div>
</div>
);
// Button From Uiverse.io by njesenberger
}
function addNewRoom() {
const RoomNameInput = (document.getElementsByClassName("RoomNameInput")[0] as HTMLInputElement).value;
if (RoomNameInput === "") {
alert("Please enter a room name.");
return;
}
const chatList = document.getElementsByClassName("chat-list")[0];
const newRoom = document.createElement("div");
newRoom.className = "chat-item";
newRoom.innerHTML = `
<img src="${RoomProfile}" alt="Avatar" class="avatar" />
<div class="chat-info">
<h3>${RoomNameInput}</h3>
<span class="chat-message">New message</span>
<span class="chat-time">Time</span>
</div>
`;
chatList.appendChild(newRoom);
closeOpenDiv();
}
function openOpenDiv() {
const openDiv = document.getElementsByClassName("open")[0] as HTMLDivElement;
openDiv.style.zIndex = "1000";
const roomNameInput = document.getElementsByClassName("RoomNameInput")[0] as HTMLInputElement;
roomNameInput.style.zIndex = "1001";
}
function closeOpenDiv() {
const openDiv = document.getElementsByClassName("open")[0] as HTMLDivElement;
openDiv.style.zIndex = "0";
const roomNameInput = document.getElementsByClassName("RoomNameInput")[0] as HTMLInputElement;
roomNameInput.style.zIndex = "0";
(document.getElementsByClassName("RoomNameInput")[0] as HTMLInputElement).value = '';
}
// 单个聊天房间组件
interface MessageProps {
roomId: number; // room id
roomName: string; // room name
messages: Array<{
profile: number; // profile index
sender: string; // sender name
content: string; // message content
time: number; // message time
}>;
}
function MessageItem (props: MessageProps) {
return (
<div className="message-item">
<div className="message-header">
<img src={RoomProfile} alt="Avatar" className="avatar" />
<h2>{props.roomName}</h2>
</div>
<div className="message-list">
{props.messages.map((msg, index) => (
<div key={index} className="message">
<img src={Profile[msg.profile]} alt={`${msg.sender}'s avatar`} className="avatar" />
<div className="message-content">
<div className="message-info">
<span className="message-sender">{msg.sender}</span>
<span className="message-time">{new Date(msg.time).toLocaleTimeString()}</span>
</div>
<p className="message-text">{msg.content}</p>
</div>
</div>
))}
</div>
<div className="message-input">
<input type="text" placeholder="Type a message..." className="Inputarea" onKeyUpCapture={
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
addNewComment(props.roomId, "蔡徐坤", (e.target as HTMLInputElement).value);
}
}}/>
<button className="send-button" onClick={() => addNewComment(props.roomId, "蔡徐坤", (document.getElementsByClassName("Inputarea")[0] as HTMLInputElement).value)}>
<div className="svg-wrapper-1">
<div className="svg-wrapper">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
>
<path fill="none" d="M0 0h24v24H0z"></path>
<path
fill="currentColor"
d="M1.946 9.315c-.522-.174-.527-.455.01-.634l19.087-6.362c.529-.176.832.12.684.638l-5.454 19.086c-.15.529-.455.547-.679.045L12 14l6-8-8 6-8.054-2.685z"
></path>
</svg>
</div>
</div>
<span>Send</span>
</button>
</div>
</div>
);
// From Uiverse.io by adamgiebl
}
// add new comment
function addNewComment(roomId: number, sender: string, content: string) {
const messageList = document.getElementsByClassName("message-list");
if (content === "") {
alert("Please enter a message before sending.");
return;
}
var profileId = 0;
if (sender === "蔡徐坤") {
profileId = Profile.length - 1;
}
else {
profileId = Math.floor(Math.random() * (Profile.length-1));
}
const message = document.createElement("div");
message.className = "message";
message.innerHTML = `
<img src="${Profile[profileId]}" alt="${sender}'s avatar" class="avatar">
<div class="message-content">
<div class="message-info">
<span class="message-sender">${sender}</span>
<span class="message-time">${new Date().toLocaleTimeString()}</span>
</div>
<p class="message-text">${content}</p>
</div>
`;
(document.getElementsByClassName("Inputarea")[0] as HTMLInputElement).value = '';
messageList[0].appendChild(message);
}
export default function ChatRoom() {
return (
<div className="chat-room">
<RoomEntry roomId={1} roomName="General" lastSender="Alice" lastContent="Hello!aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" lastTime={Date.now()} />
<MessageItem
roomId={1}
roomName="General"
messages={[
{ profile: 2, sender: "Alice", content: "Hello!", time: Date.now() - 60000 }
]}
/>
<div className="open">
<div className="roomName-input">
<h3>Please Enter the New Room Name</h3>
<input
type="text"
className="RoomNameInput"
placeholder="Search or start new chat"
onKeyUpCapture={(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
addNewRoom();
}
else if (e.key === 'Escape') {
closeOpenDiv();
}
}}
/>
<div className="button-container">
<button className="create-button" onClick={addNewRoom}>Submit</button>
<button className="cancel-button" onClick={closeOpenDiv}>Cancel</button>
</div>
</div>
</div>
</div>
);
}
\ No newline at end of file
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
{
"name": "myproject",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment