App.js
import React, { useState } from "react";
import "./App.scss";
import Box from "./components/Box";
function App() {
// * 4. 가위바위보 중 선택한 것을 넣어 줄 변수(관리)
const [userSelect, setUserSelect] = useState(); // 내가 선택
// * 5-2. 컴퓨터가 선택한 것을 넣어 줄 변수(관리)
const [computerSelect, setComputerSelect] = useState(); // 컴퓨터가 선택
// * 6-2. 승패 결과값을 넣어 줄 변수
const [result, setResult] = useState("");
// * 1. 가위바위보 각각의 아이템을 가진 객체(오브젝트) 생성
// 키값과 아래 문자열이 동일함
const choice = {
scissor: { name: "Scissor", img: "scissor.png" },
rock: { name: "Rock", img: "rock.png" },
paper: { name: "Paper", img: "paper.png" },
};
// * 2-2. play 함수 선언. 아래 button의 인자를 받아옴
const play = (userChioce) => {
// console.log("userChioce는? : ", userChioce); // 그냥 결과값
// console.log("choice[userChioce]는? : ", choice[userChioce]); // 객체로 반환. key값의 value를 사용하기 위해 작성
// * 4-2. choice 객체의 아이템을 가져오기 위함
setUserSelect(choice[userChioce]); // setUserSelect의 리턴값이 userSelect가 됨(결과값)
// * 5. play가 실행되는 순간 랜덤함수 발생
let computerChoice = randomChoice();
setComputerSelect(computerChoice);
// *6. 승패 비교 함수 실행
// const aa = judgement(choice[userChioce], computerChoice);
setResult(judgement(choice[userChioce], computerChoice));
};
// * 6. 승패 비교 함수 선언
// 컴퓨터가 선택한것과 내가 선택한 것을 매개변수로 받아옴
const judgement = (user, computer) => {
console.log("내가 선택 : ", user, "\n컴퓨터가 선택 : ", computer);
/*
user == computer : tie(비김)
user == rock, computer == scissor : user win(이김)
user == rock, computer == paper : user lose(짐)
user == scissor, computer == rock : user lose
user == scissor, computer == paper : user win
user == paper, computer == rock : user win
user == paper, computer == scissor : user lose
*/
if (user.name == computer.name) return "tie";
else if (user.name === "Rock") return computer.name === "Scissor" ? "win" : "lose";
else if (user.name === "Scissor") return computer.name === "Paper" ? "win" : "lose";
else if (user.name === "Paper") return computer.name === "rock" ? "win" : "lose";
};
// * 5. 랜덤함수 선언
const randomChoice = () => {
let itemArray = Object.keys(choice); // choice 오브젝트의 키값을 가져옴
// Object.keys(오브젝트) - 객체의 키값만 뽑아서 array로 만들어 줌
let randomItem = Math.floor(Math.random() * itemArray.length); // floor : 버림
let final = itemArray[randomItem]; // key값이 랜덤으로 출력됨
return choice[final];
};
return (
<>
<div className="main">
{/* // *3. props */}
<Box title="Me" item={userSelect} result={result} />
<Box title="Computer" item={computerSelect} result={result} />
</div>
<div className="main">
{/* 함수 소괄호 안에 작성하면 이벤트가 발생하지 않아도 실행됨 */}
{/* 콜백함수스타일 사용 ()=>{} */}
{/* // *2. 문자열이 choice 오브젝트의 키값과 동일하게 설정 */}
<button onClick={() => play("scissor")}>가위</button>
<button onClick={() => play("rock")}>바위</button>
<button onClick={() => play("paper")}>보</button>
</div>
<p className="resultP">{result}</p>
</>
);
}
export default App;
Box.jsx
// rfc (emmet)
import React from "react";
export default function Box(props) {
// console.log("props는? : ", props);
// *6-3. 승패 결과가 user와 컴퓨터에 반대로 나오게
let result;
if (props.title === "Computer" && props.result !== "tie" && props.result !== "") {
result = props.result === "win" ? "lose" : "win";
} else {
result = props.result;
}
return (
// box와 result 클래스 2개 지정
<div className={`box ${result}`}>
{/* // *3. props */}
<h1>{props.title}</h1>
{/* props.item이 있을 때만 이미지 보이게 */}
<img src={props.item && props.item.img} alt="" className="item-img" />
<h2>{result}</h2>
</div>
);
}
App.scss
.main {
display: flex;
justify-content: center;
}
.box {
max-width: 500px;
display: flex;
flex-direction: column;
align-items: center;
margin: 10px;
box-sizing: border-box;
img {
width: 80%;
}
}
button {
background-color: cornsilk;
padding: 10px 20px;
border-radius: 12px;
margin: 8px;
border: 1px solid #ddd699;
cursor: pointer;
&:hover {
background-color: #d6ca83;
color: white;
}
}
.tie {
border: 5px solid gray;
color: gray;
}
.lose {
border: 5px solid black;
color: black;
// background: fade-out(rgba(#555, 0.5), 0.4);
filter: opacity(30%);
}
.win {
border: 10px solid red;
color: red;
}
.resultP {
font-size: 50px;
font-weight: 700;
text-transform: uppercase;
text-align: center;
}
시작 화면
각 버튼 클릭 시 출력 화면
- 버튼 클릭할 때 마다 컴퓨터의 이미지 랜덤으로 변경됨
가위
바위
보
main.scss
@import "./mixVariables"; // 번수, 믹스인을 제일 처음에
@import "./reset";
@import "./layout";
@import "./index";
@import "./chatList";
@import "./chat";
_reset.scss
@font-face {
font-family: 'SUITE-Regular';
src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2304-2@1.0/SUITE-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'SUITE-Bold';
src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2304-2@1.0/SUITE-Bold.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'SUITE-Regular';
}
html {
height: 100%;
}
body {
height: 100%;
min-width: 350px;
}
a {
text-decoration: none;
color: inherit;
}
li { list-style: none; }
_mixVariables.scss
$bg-color: #ffeb35;
$main-color: #381e1f;
$gray1: #666;
$gray2: #aaa;
$gray3: #eee;
$gray4: #f7f7f7;
$opacityBlack: rgba(0, 0, 0, 0.2);
// height를 필수로 넣을 수 있도록 맨 앞에
@mixin set-box($height, $width: 100%, $border-radius: 0) {
height: $height;
width: $width;
border-radius: $border-radius;
}
_layout.scss
nav {
@include set-box(100%, 70px);
background: $opacityBlack;
position: fixed;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 50px 0;
cursor: pointer;
.nav_list {
.nav_btn {
padding-bottom: 40px;
color: $gray2;
&.active {
color: #000;
}
&:hover {
color: #000;
}
}
}
.logout {
color: $gray2;
&:hover {
color: #000;
}
}
}
header {
background: #fff;
display: flex;
justify-content: space-between;
padding: 50px 20px 20px;
position: sticky; top: 0;
z-index: 1;
.header_title {
font-size: 1.2rem;
span {
font-size: 0.8rem;
}
}
.header_menu {
span {
@include set-box(36px, 36px, 18px);
display: inline-block;
text-align: center;
line-height: 36px;
cursor: pointer;
&:hover {
background: $opacityBlack;
}
}
}
}
_chatList.scss
.chats {
margin-left: 70px;
}
.previews {
.preview_list {
}
}
.preview_wrap {
display: block;
.preview {
display: flex;
padding: 16px;
position: relative;
.preview_col {
&:nth-child(1) {
margin-right: 16px;
}
.preview_pic {
@include set-box(50px, 50px, 8px);
background: $main-color;
}
.preview_title {
width: 50vw;
font-size: 0.88rem;
margin-bottom: 6px;
// 말줄임표. 부모 영역이 확실하게 고정되어 있어야 사용 가능
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.preview_msg {
width: 50vw;
font-size: 0.83rem;
color: $gray1;
display: -webkit-box;
word-wrap: break-word;
-webkit-line-clamp: 2; // webkit 무조건 사용
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.preview_time {
position: absolute;
right: 16px;
top: 16px;
font-size: 0.75rem;
color: $gray2;
}
}
&:hover {
background: $gray4;
}
}
&:first-child > .preview {
background: $gray3;
}
}
chatList.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/style.css" />
<!-- fontawesome -->
<script src="https://kit.fontawesome.com/05f6febec9.js" crossorigin="anonymous"></script>
<title>채팅목록</title>
</head>
<body>
<nav class="nav">
<ul class="nav_list">
<li class="nav_btn">
<i class="fa-solid fa-user fa-xl"></i>
</li>
<li class="nav_btn active">
<i class="fa-solid fa-comment fa-xl"></i>
</li>
<li class="nav_btn">
<i class="fa-solid fa-ellipsis fa-xl"></i>
</li>
</ul>
<p class="logout">
<a href="">
<i class="fa-solid fa-arrow-right-from-bracket fa-xl"></i>
</a>
</p>
</nav>
<div class="chats">
<header class="header">
<h3 class="header_title">채팅 <span>▼</span></h3>
<div class="header_menu">
<span><i class="fa-solid fa-magnifying-glass"></i></span>
<span><i class="fa-regular fa-comments"></i></span>
<span><i class="fa-solid fa-plus"></i></span>
</div>
</header>
<main class="previews">
<div class="preview_list">
<a href="./chat.html" class="preview_wrap">
<div class="preview">
<div class="preview_col">
<div class="preview_pic">
</div>
</div>
<div class="preview_col">
<h4 class="preview_title">채팅방이름채팅방이름채팅방이름채팅방이름채팅방이름채팅방이름채팅방이름채팅방이름</h4>
<p class="preview_msg">채팅방 미리보기입니다. 미리보기 채팅방 미리보기입니다. 미리보기 채팅방 미리보기입니다. 미리보기 채팅방 미리보기입니다. 미리보기 채팅방 미리보기입니다. 미리보기 채팅방 미리보기입니다. 미리보기</p>
<span class="preview_time">오후 2:33</span>
</div>
</div>
</a>
<a href="./chat.html" class="preview_wrap">
<div class="preview">
<div class="preview_col">
<div class="preview_pic">
</div>
</div>
<div class="preview_col">
<h4 class="preview_title">채팅방이름</h4>
<p class="preview_msg">채팅방 미리보기입니다. 미리보기</p>
<span class="preview_time">오후 2:33</span>
</div>
</div>
</a>
<a href="./chat.html" class="preview_wrap">
<div class="preview">
<div class="preview_col">
<div class="preview_pic">
</div>
</div>
<div class="preview_col">
<h4 class="preview_title">채팅방이름</h4>
<p class="preview_msg">채팅방 미리보기입니다. 미리보기</p>
<span class="preview_time">오후 2:33</span>
</div>
</div>
</a>
<a href="./chat.html" class="preview_wrap">
<div class="preview">
<div class="preview_col">
<div class="preview_pic">
</div>
</div>
<div class="preview_col">
<h4 class="preview_title">채팅방이름</h4>
<p class="preview_msg">채팅방 미리보기입니다. 미리보기</p>
<span class="preview_time">오후 2:33</span>
</div>
</div>
</a>
<a href="./chat.html" class="preview_wrap">
<div class="preview">
<div class="preview_col">
<div class="preview_pic">
</div>
</div>
<div class="preview_col">
<h4 class="preview_title">채팅방이름</h4>
<p class="preview_msg">채팅방 미리보기입니다. 미리보기</p>
<span class="preview_time">오후 2:33</span>
</div>
</div>
</a>
<a href="./chat.html" class="preview_wrap">
<div class="preview">
<div class="preview_col">
<div class="preview_pic">
</div>
</div>
<div class="preview_col">
<h4 class="preview_title">채팅방이름</h4>
<p class="preview_msg">채팅방 미리보기입니다. 미리보기</p>
<span class="preview_time">오후 2:33</span>
</div>
</div>
</a>
<a href="./chat.html" class="preview_wrap">
<div class="preview">
<div class="preview_col">
<div class="preview_pic">
</div>
</div>
<div class="preview_col">
<h4 class="preview_title">채팅방이름</h4>
<p class="preview_msg">채팅방 미리보기입니다. 미리보기</p>
<span class="preview_time">오후 2:33</span>
</div>
</div>
</a>
<a href="./chat.html" class="preview_wrap">
<div class="preview">
<div class="preview_col">
<div class="preview_pic">
</div>
</div>
<div class="preview_col">
<h4 class="preview_title">채팅방이름</h4>
<p class="preview_msg">채팅방 미리보기입니다. 미리보기</p>
<span class="preview_time">오후 2:33</span>
</div>
</div>
</a>
<a href="./chat.html" class="preview_wrap">
<div class="preview">
<div class="preview_col">
<div class="preview_pic">
</div>
</div>
<div class="preview_col">
<h4 class="preview_title">채팅방이름</h4>
<p class="preview_msg">채팅방 미리보기입니다. 미리보기</p>
<span class="preview_time">오후 2:33</span>
</div>
</div>
</a>
<a href="./chat.html" class="preview_wrap">
<div class="preview">
<div class="preview_col">
<div class="preview_pic">
</div>
</div>
<div class="preview_col">
<h4 class="preview_title">채팅방이름</h4>
<p class="preview_msg">채팅방 미리보기입니다. 미리보기</p>
<span class="preview_time">오후 2:33</span>
</div>
</div>
</a>
</div>
</main>
</div>
</body>
</html>