Skip to content

Commit 25ff125

Browse files
authored
Merge ver 0.8 develop branch into master
Merge develop into master (v0.8)
2 parents 7009836 + eb02107 commit 25ff125

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+3058
-1456
lines changed

โ€ŽREADME.md

+120-122
Large diffs are not rendered by default.

โ€Žclient/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"prop-types": "^15.7.2",
99
"react": "^16.11.0",
1010
"react-dom": "^16.11.0",
11+
"react-dropzone": "^10.2.1",
1112
"react-router": "^5.1.2",
1213
"react-router-dom": "^5.1.2",
1314
"react-scripts": "3.2.0",

โ€Žclient/src/App.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import React from 'react';
22
import Router from './Router';
33
import ToastProvider from './components/common/ToastProvider';
4+
import ModalProvider from './components/common/ModalProvider';
45

56
function App() {
67
return (
78
<ToastProvider>
8-
<Router />
9+
<ModalProvider>
10+
<Router />
11+
</ModalProvider>
912
</ToastProvider>
1013
);
1114
}

โ€Žclient/src/Router.js

+10-8
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,23 @@ import EditPage from './pages/host/EditPage';
77
import PlayerGameRoom from './pages/player/PlayerGameRoom';
88
import CallBackPage from './pages/login/CallBackPage';
99
import SelectRoom from './pages/host/SelectRoom';
10+
import GameOver from './pages/Gameover';
1011

1112
export default function() {
1213
return (
1314
<Router>
1415
<Switch>
1516
<Route exact path="/" component={MainPage} />
16-
<Route path="/nickname" component={MainPage} />
17-
<Route path="/login" component={MainPage} />
17+
<Route exact path="/nickname" component={MainPage} />
18+
<Route exact path="/login" component={MainPage} />
19+
<Route exact path="/host" component={HostGameRoom} />
20+
<Route exact path="/player" component={PlayerGameRoom} />
21+
<Route exact path="/edit" component={EditPage} />
22+
<Route exact path="/callback" component={CallBackPage} />
23+
<Route exact path="/host/room/select" component={SelectRoom} />
24+
<Route exact path="/host/room/detail" component={HostDetailRoom} />
25+
<Route component={GameOver} />
1826
</Switch>
19-
<Route exact path="/host" component={HostGameRoom} />
20-
<Route exact path="/player" component={PlayerGameRoom} />
21-
<Route exact path="/edit" component={EditPage} />
22-
<Route exact path="/callback" component={CallBackPage} />
23-
<Route exact path="/host/room/select" component={SelectRoom} />
24-
<Route exact path="/host/room/detail" component={HostDetailRoom} />
2527
</Router>
2628
);
2729
}

โ€Žclient/src/components/common/Dashboard.js

+7-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useState, useEffect } from 'react';
2+
import PropTypes from 'prop-types';
23
import styled, { keyframes } from 'styled-components';
34
import DESKTOP_MIN_WIDTH from '../../constants/media';
45

@@ -114,19 +115,6 @@ const Score = styled.span`
114115
}
115116
`;
116117

117-
const datas = [
118-
{ nickname: '๊ตฌ๋ผ์žฌ๋ฏผ1', score: 12345 },
119-
{ nickname: '๊ตฌ๋ผ์žฌ๋ฏผ2', score: 10000 },
120-
{ nickname: '๊ตฌ๋ผ์žฌ๋ฏผ3', score: 10020 },
121-
{ nickname: '๊ตฌ๋ผ์žฌ๋ฏผ4', score: 9000 },
122-
{ nickname: '๊ตฌ๋ผ์žฌ๋ฏผ5', score: 9000 },
123-
{ nickname: '๊ตฌ๋ผ์žฌ๋ฏผ6', score: 9000 },
124-
{ nickname: '๊ตฌ๋ผ์žฌ๋ฏผ7', score: 8000 },
125-
{ nickname: '๊ตฌ๋ผ์žฌ๋ฏผ8', score: 7000 },
126-
{ nickname: '๊ตฌ๋ผ์žฌ๋ฏผ9', score: 6000 },
127-
{ nickname: '๊ตฌ๋ผ์žฌ๋ฏผ10', score: 5000 },
128-
];
129-
130118
function sortByHighScore(player1, player2) {
131119
if (player1.score < player2.score) return 1;
132120
if (player1.score > player2.score) return -1;
@@ -135,8 +123,9 @@ function sortByHighScore(player1, player2) {
135123
return 0;
136124
}
137125

138-
function DashBoard() {
126+
function DashBoard({ ranking }) {
139127
const [lines, setLines] = useState([]);
128+
const datas = ranking;
140129

141130
useEffect(() => {
142131
datas.sort(sortByHighScore);
@@ -180,4 +169,8 @@ function DashBoard() {
180169
);
181170
}
182171

172+
DashBoard.propTypes = {
173+
ranking: PropTypes.arrayOf.isRequired,
174+
};
175+
183176
export default DashBoard;

โ€Žclient/src/components/common/FlexibleInput.js

+61-11
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React, { useState, useRef, useEffect } from 'react';
22
import styled from 'styled-components';
33
import PropTypes from 'prop-types';
44
import { InputStyle } from '../../styles/common';
55
import DESKTOP_MIN_WIDTH from '../../constants/media';
66
import * as colors from '../../constants/colors';
77

88
const BACKSPACE = 8;
9+
const ENTER = 13;
910
const COUNTER_RATE = 0.5;
1011
const PLACEHOLDER_RATE = 0.75;
12+
const A_KEY = 65;
13+
const DIRECTION_KEY = [37, 38, 39, 40]; // ์ขŒ, ์šฐ, ์ƒ, ํ•˜ ์ˆœ์„œ
1114

1215
const InputContainer = styled.div.attrs({
1316
className: 'inputContainer',
@@ -57,9 +60,11 @@ const Placeholder = styled.span`
5760
position: absolute;
5861
top: 50%;
5962
left: 50%;
63+
width: 100%;
6064
transform: translate(-50%, -50%);
6165
font-size: calc(${props => props.mobileFontSize} * ${PLACEHOLDER_RATE});
6266
font-weight: bold;
67+
text-align: center;
6368
color: ${colors.TEXT_GRAY};
6469
user-select: none;
6570
pointer-events: none;
@@ -70,32 +75,74 @@ const Placeholder = styled.span`
7075
}
7176
`;
7277

73-
function FlexibleInput({ maxLength, mobileFontSize, placeholder, callback }) {
78+
const Warning = styled.div`
79+
background-color: #ffc6c6;
80+
color: red;
81+
border-radius: 5px;
82+
font-weight: bold;
83+
text-align: center;
84+
@media (min-width: ${DESKTOP_MIN_WIDTH}) {
85+
font-size: 1.5rem;
86+
}
87+
`;
88+
89+
function FlexibleInput({
90+
maxLength,
91+
mobileFontSize,
92+
placeholder,
93+
callback,
94+
title,
95+
}) {
7496
const [inputValue, setInputValue] = useState('');
7597
const [isFocus, setFocus] = useState(false);
76-
77-
// useEffect(() => {
78-
// setInputValue(title);
79-
// document.querySelector('.inputTitle').innerText = title;
80-
// }, [title]);
98+
const warningRef = useRef(null);
99+
const inputRef = useRef();
100+
101+
useEffect(() => {
102+
if (title === undefined) return;
103+
inputRef.current.textContent = title;
104+
setInputValue(title);
105+
if (title.length < maxLength) {
106+
warningRef.current.textContent = '';
107+
return;
108+
}
109+
warningRef.current.textContent = `${maxLength}๊ธ€์ž๋ฅผ ๋„˜์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค`;
110+
}, [title]);
81111

82112
function handleKeyDown(event) {
113+
if (event.keyCode === ENTER) event.preventDefault();
83114
if (
84-
event.target.innerText.length >= maxLength &&
85-
event.keyCode !== BACKSPACE
86-
)
115+
event.target.textContent.length >= maxLength &&
116+
event.keyCode !== BACKSPACE &&
117+
!event.ctrlKey &&
118+
!(event.ctrlKey && event.keyCode === A_KEY) &&
119+
!DIRECTION_KEY.includes(event.keyCode)
120+
) {
87121
event.preventDefault();
122+
} else {
123+
warningRef.current.textContent = '';
124+
}
88125
}
89126

90127
function handleInput(event) {
91-
const value = event.target.innerText;
128+
let value = event.target.textContent;
129+
130+
if (value.length >= maxLength) {
131+
value = value.substring(0, maxLength);
132+
if (inputValue.length === maxLength) value = inputValue;
133+
134+
event.target.textContent = value;
135+
warningRef.current.textContent = `${maxLength}๊ธ€์ž๋ฅผ ๋„˜์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค`;
136+
}
137+
92138
setInputValue(value);
93139
if (callback !== undefined) callback(value);
94140
}
95141

96142
return (
97143
<InputContainer>
98144
<Input
145+
ref={inputRef}
99146
onKeyDown={handleKeyDown}
100147
onInput={handleInput}
101148
onFocus={() => setFocus(true)}
@@ -112,6 +159,7 @@ function FlexibleInput({ maxLength, mobileFontSize, placeholder, callback }) {
112159
<Counter isOn={isFocus} mobileFontSize={mobileFontSize}>
113160
{maxLength - inputValue.length}
114161
</Counter>
162+
<Warning ref={warningRef} />
115163
</InputContainer>
116164
);
117165
}
@@ -120,13 +168,15 @@ FlexibleInput.defaultProps = {
120168
placeholder: 'placeholder',
121169
mobileFontSize: '1.5rem',
122170
callback: undefined,
171+
title: '',
123172
};
124173

125174
FlexibleInput.propTypes = {
126175
maxLength: PropTypes.number.isRequired,
127176
mobileFontSize: PropTypes.string,
128177
placeholder: PropTypes.string,
129178
callback: PropTypes.func,
179+
title: PropTypes.string,
130180
};
131181

132182
export default FlexibleInput;

โ€Žclient/src/components/common/Header.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import PropTypes from 'prop-types';
55
import * as colors from '../../constants/colors';
66
import DESKTOP_MIN_WIDTH from '../../constants/media';
77

8-
const HeaderHeight = '6rem';
8+
const HeaderHeight = '8vmin';
99

10-
const HeaderArea = styled.div`
10+
const HeaderArea = styled.div.attrs({
11+
className: 'headerArea',
12+
})`
1113
position: relative;
1214
width: 100%;
1315
height: ${HeaderHeight};
@@ -44,7 +46,6 @@ function Header({ children }) {
4446
<Link to="/">
4547
<ServiceLogoImage />
4648
</Link>
47-
4849
{children}
4950
</HeaderStyle>
5051
</HeaderArea>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import React from 'react';
2+
import styled, { keyframes } from 'styled-components';
3+
import PropTypes from 'prop-types';
4+
5+
const degrees = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330];
6+
7+
const Container = styled.div`
8+
position: absolute;
9+
display: flex;
10+
justify-content: center;
11+
top: 50%;
12+
left: 50%;
13+
transform: translate(-50%, -50%);
14+
width: ${props => props.size};
15+
height: ${props => props.size};
16+
`;
17+
18+
const CapsuleWrapper = styled.div`
19+
position: absolute;
20+
width: calc(${props => props.size} / 12);
21+
height: calc(${props => props.size} / 2);
22+
transform: rotateZ(${props => props.degree}deg);
23+
transform-origin: 50% 100%;
24+
`;
25+
26+
const Animation = keyframes`
27+
from{
28+
opacity: 1;
29+
}
30+
to{
31+
opacity: 0;
32+
}
33+
`;
34+
35+
const Capsule = styled.div`
36+
position: absolute;
37+
width: 100%;
38+
height: 40%;
39+
background-color: ${props => props.color};
40+
border-radius: 10000px;
41+
42+
animation-name: ${Animation};
43+
animation-iteration-count: infinite;
44+
animation-timing-function: linear;
45+
animation-duration: 1.2s;
46+
animation-delay: ${props => props.delay};
47+
`;
48+
49+
function LoadingCircle({ size, color }) {
50+
return (
51+
<Container size={size}>
52+
{degrees.map((degree, index) => (
53+
<CapsuleWrapper key={degree} size={size} degree={degree}>
54+
<Capsule delay={`${-1.1 + index * 0.1}s`} color={color} />
55+
</CapsuleWrapper>
56+
))}
57+
</Container>
58+
);
59+
}
60+
61+
LoadingCircle.defaultProps = {
62+
size: '15vw',
63+
color: 'salmon',
64+
};
65+
66+
LoadingCircle.propTypes = {
67+
size: PropTypes.string,
68+
color: PropTypes.string,
69+
};
70+
71+
export default LoadingCircle;
72+
73+
//https://loading.io/css/

0 commit comments

Comments
ย (0)