Showing
34 changed files
with
477 additions
and
110 deletions
This diff is collapsed. Click to expand it.
... | @@ -11679,6 +11679,11 @@ | ... | @@ -11679,6 +11679,11 @@ |
11679 | "picomatch": "^2.2.1" | 11679 | "picomatch": "^2.2.1" |
11680 | } | 11680 | } |
11681 | }, | 11681 | }, |
11682 | + "recoil": { | ||
11683 | + "version": "0.1.2", | ||
11684 | + "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.1.2.tgz", | ||
11685 | + "integrity": "sha512-hIRrHlkmW4yITlBFprVYjVPhzPKYrJKoaDrrJtAtbkMeXfXaa/XE5OlyR10n+rNfnKWNToCKb3Z4fo86IGjkzg==" | ||
11686 | + }, | ||
11682 | "recursive-readdir": { | 11687 | "recursive-readdir": { |
11683 | "version": "2.2.2", | 11688 | "version": "2.2.2", |
11684 | "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", | 11689 | "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", | ... | ... |
... | @@ -2,6 +2,7 @@ | ... | @@ -2,6 +2,7 @@ |
2 | "name": "straight-up", | 2 | "name": "straight-up", |
3 | "version": "0.1.0", | 3 | "version": "0.1.0", |
4 | "private": true, | 4 | "private": true, |
5 | + "homepage": "http://khuhub.khu.ac.kr/2019102240/Straight-Up", | ||
5 | "dependencies": { | 6 | "dependencies": { |
6 | "@testing-library/jest-dom": "^5.11.4", | 7 | "@testing-library/jest-dom": "^5.11.4", |
7 | "@testing-library/react": "^11.1.0", | 8 | "@testing-library/react": "^11.1.0", |
... | @@ -19,12 +20,11 @@ | ... | @@ -19,12 +20,11 @@ |
19 | "react-dom": "^17.0.1", | 20 | "react-dom": "^17.0.1", |
20 | "react-router-dom": "^5.2.0", | 21 | "react-router-dom": "^5.2.0", |
21 | "react-scripts": "4.0.1", | 22 | "react-scripts": "4.0.1", |
23 | + "recoil": "^0.1.2", | ||
22 | "web-vitals": "^0.2.4" | 24 | "web-vitals": "^0.2.4" |
23 | }, | 25 | }, |
24 | "scripts": { | 26 | "scripts": { |
25 | - "start": "npm-run-all --parallel start:**", | 27 | + "start": "react-scripts start", |
26 | - "start:client": "react-scripts start", | ||
27 | - "start:server": "node ./server/app.js", | ||
28 | "build": "react-scripts build", | 28 | "build": "react-scripts build", |
29 | "test": "react-scripts test", | 29 | "test": "react-scripts test", |
30 | "eject": "react-scripts eject" | 30 | "eject": "react-scripts eject" | ... | ... |
straight-up/server/app.js
deleted
100644 → 0
1 | -const express = require('express'); | ||
2 | -const bodyParser = require('body-parser') | ||
3 | -const app = express(); | ||
4 | -const api = require('./routes/index'); | ||
5 | - | ||
6 | -app.use(bodyParser.json()); | ||
7 | -app.use('/api', api); | ||
8 | - | ||
9 | -const port = 3001; | ||
10 | -app.listen(port, () => console.log(`Listening on port ${port}`)); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
straight-up/server/routes/index.js
deleted
100644 → 0
... | @@ -52,13 +52,13 @@ const checkStraight = (resData, position) => { //resData: API로 받은 JSON 객 | ... | @@ -52,13 +52,13 @@ const checkStraight = (resData, position) => { //resData: API로 받은 JSON 객 |
52 | var d_right = distance(x_position[ear + 1], y_position[ear + 1], x_position[shoulder + 1], y_position[shoulder + 1]); | 52 | var d_right = distance(x_position[ear + 1], y_position[ear + 1], x_position[shoulder + 1], y_position[shoulder + 1]); |
53 | var gap = difference(d_left, d_right); | 53 | var gap = difference(d_left, d_right); |
54 | 54 | ||
55 | - if (gap >= 20) { //기운 각도가 20도를 넘을 경우 | 55 | + if (gap >= 15) { //기운 각도가 15도를 넘을 경우 |
56 | if (d_left > d_right) { //오른쪽으로 기울인 경우 | 56 | if (d_left > d_right) { //오른쪽으로 기울인 경우 |
57 | return 'leaning right by ' + gap + 'percent.'; | 57 | return 'leaning right by ' + gap + 'percent.'; |
58 | } else if (d_left < d_right) { //왼쪽으로 기울인 경우 | 58 | } else if (d_left < d_right) { //왼쪽으로 기울인 경우 |
59 | return 'leaning left by ' + gap + 'percent.'; | 59 | return 'leaning left by ' + gap + 'percent.'; |
60 | } | 60 | } |
61 | - } else { //기운 각도가 20도 미만인 경우 | 61 | + } else { //기운 각도가 15도 미만인 경우 |
62 | return 'okay'; | 62 | return 'okay'; |
63 | } | 63 | } |
64 | 64 | ... | ... |
straight-up/src/App.css
deleted
100644 → 0
1 | -.App { | ||
2 | - text-align: center; | ||
3 | -} | ||
4 | - | ||
5 | -.App-logo { | ||
6 | - height: 40vmin; | ||
7 | - pointer-events: none; | ||
8 | -} | ||
9 | - | ||
10 | -@media (prefers-reduced-motion: no-preference) { | ||
11 | - .App-logo { | ||
12 | - animation: App-logo-spin infinite 20s linear; | ||
13 | - } | ||
14 | -} | ||
15 | - | ||
16 | -.App-header { | ||
17 | - background-color: #282c34; | ||
18 | - min-height: 100vh; | ||
19 | - display: flex; | ||
20 | - flex-direction: column; | ||
21 | - align-items: center; | ||
22 | - justify-content: center; | ||
23 | - font-size: calc(10px + 2vmin); | ||
24 | - color: white; | ||
25 | -} | ||
26 | - | ||
27 | -.App-link { | ||
28 | - color: #61dafb; | ||
29 | -} | ||
30 | - | ||
31 | -@keyframes App-logo-spin { | ||
32 | - from { | ||
33 | - transform: rotate(0deg); | ||
34 | - } | ||
35 | - to { | ||
36 | - transform: rotate(360deg); | ||
37 | - } | ||
38 | -} |
1 | import React from 'react'; | 1 | import React from 'react'; |
2 | +import {RecoilRoot} from 'recoil'; | ||
2 | import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'; | 3 | import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'; |
3 | import Landing from './Landing'; | 4 | import Landing from './Landing'; |
4 | import Main from './Main'; | 5 | import Main from './Main'; |
6 | +import Result from './Result'; | ||
5 | 7 | ||
6 | 8 | ||
7 | class App extends React.Component { | 9 | class App extends React.Component { |
8 | render() { | 10 | render() { |
9 | return ( | 11 | return ( |
10 | - <Router> | 12 | + <RecoilRoot> |
11 | - <Switch> | 13 | + <Router> |
12 | - <Route exact path="/landing" component={Landing} /> | 14 | + <Switch> |
13 | - <Route exact path="/main" component={Main} /> | 15 | + <Route exact path="/landing" component={Landing} /> |
14 | - <Redirect path="*" to="/landing" /> | 16 | + <Route exact path="/main" component={Main} /> |
15 | - </Switch> | 17 | + <Route exact path="/result" component={Result} /> |
16 | - </Router> | 18 | + <Redirect path="*" to="/landing" /> |
19 | + </Switch> | ||
20 | + </Router> | ||
21 | + | ||
22 | + </RecoilRoot> | ||
23 | + | ||
17 | ); | 24 | ); |
18 | } | 25 | } |
19 | } | 26 | } | ... | ... |
... | @@ -8,10 +8,14 @@ export default function Landing() { | ... | @@ -8,10 +8,14 @@ export default function Landing() { |
8 | <div className="Landingbg"> | 8 | <div className="Landingbg"> |
9 | <Header /> | 9 | <Header /> |
10 | <div className="mainTextContainer"> | 10 | <div className="mainTextContainer"> |
11 | - | ||
12 | <h1 className="mainText">Welcome to Straight Up</h1> | 11 | <h1 className="mainText">Welcome to Straight Up</h1> |
13 | <span className="mainText">We support posture correction for you.</span> | 12 | <span className="mainText">We support posture correction for you.</span> |
14 | - <Button /> | 13 | + <Button btnText="Get Started!" /> |
14 | + <div className="mainBtnContainer"> | ||
15 | + <a target="blank" href="http://khuhub.khu.ac.kr/2019102240/Straight-Up"> | ||
16 | + <button className="startBtn">Contact Us</button> | ||
17 | + </a> | ||
18 | + </div> | ||
15 | </div> | 19 | </div> |
16 | </div> | 20 | </div> |
17 | ) | 21 | ) | ... | ... |
1 | -import React, { useState } from 'react' | 1 | +import React, { useState } from 'react'; |
2 | +import { Link } from 'react-router-dom'; | ||
3 | +import { useRecoilState, useSetRecoilState } from 'recoil'; | ||
2 | import Header from './components/Header'; | 4 | import Header from './components/Header'; |
5 | +import Checkbox from './components/Checkbox'; | ||
3 | import checkStraight from './AnalysisPose'; | 6 | import checkStraight from './AnalysisPose'; |
7 | +import { selectedPosState, analysisResultState } from './store/Global'; | ||
4 | import './style/Main.css'; | 8 | import './style/Main.css'; |
5 | require('dotenv').config(); | 9 | require('dotenv').config(); |
6 | 10 | ||
7 | const axios = require('axios'); | 11 | const axios = require('axios'); |
8 | -const API_KEY = "1f14e860f7f53f39a4dfe0a2a919a8c7"; | 12 | +const API_KEY = process.env.REACT_APP_APIKEY; |
9 | -//process.env.api_key; | 13 | +console.log(API_KEY); |
10 | let imageFormData = new FormData(); | 14 | let imageFormData = new FormData(); |
11 | 15 | ||
12 | export default function Main() { | 16 | export default function Main() { |
13 | const [imgBase64, setImgBase64] = useState(""); | 17 | const [imgBase64, setImgBase64] = useState(""); |
14 | const [img, setImage] = useState(null); | 18 | const [img, setImage] = useState(null); |
19 | + const setAnalysisResult = useSetRecoilState(analysisResultState); | ||
20 | + const [selectedPosition, setPosition] = useRecoilState(selectedPosState); | ||
15 | const handleChangeFile = (event) => { | 21 | const handleChangeFile = (event) => { |
16 | let reader = new FileReader(); | 22 | let reader = new FileReader(); |
17 | reader.onloadend = () => { | 23 | reader.onloadend = () => { |
... | @@ -40,10 +46,7 @@ export default function Main() { | ... | @@ -40,10 +46,7 @@ export default function Main() { |
40 | }).then(function (response) { | 46 | }).then(function (response) { |
41 | const resdata = response.data[0].keypoints; | 47 | const resdata = response.data[0].keypoints; |
42 | console.log(resdata[0]); | 48 | console.log(resdata[0]); |
43 | - const result = checkStraight(resdata, 'front'); | 49 | + setAnalysisResult(checkStraight(resdata, 'front')); |
44 | - console.log(result); | ||
45 | - | ||
46 | - // console.log(resdata[0] === ) | ||
47 | }).catch(function (error) { | 50 | }).catch(function (error) { |
48 | if (error.response) { | 51 | if (error.response) { |
49 | // 요청이 이루어졌으며 서버가 2xx의 범위를 벗어나는 상태 코드로 응답했습니다. | 52 | // 요청이 이루어졌으며 서버가 2xx의 범위를 벗어나는 상태 코드로 응답했습니다. |
... | @@ -61,19 +64,38 @@ export default function Main() { | ... | @@ -61,19 +64,38 @@ export default function Main() { |
61 | // 오류를 발생시킨 요청을 설정하는 중에 문제가 발생했습니다. | 64 | // 오류를 발생시킨 요청을 설정하는 중에 문제가 발생했습니다. |
62 | console.log('Error', error.message); | 65 | console.log('Error', error.message); |
63 | } | 66 | } |
67 | + setAnalysisResult('error'); | ||
64 | console.log(error.config); | 68 | console.log(error.config); |
65 | }); | 69 | }); |
66 | } | 70 | } |
67 | return ( | 71 | return ( |
68 | - <div> | 72 | + <div className="MainPageContainer"> |
69 | <Header /> | 73 | <Header /> |
70 | - <span>This is Main Page</span> | 74 | + <div className="ImagePreviewContainer"> |
71 | - <div className="Image-Preview-Container" style={{ "backgroundColor": "#efefef", "width": "400px", "height": "400px" }}> | 75 | + <img className="ImagePreview" alt="" src={imgBase64}></img> |
72 | - <img className="Image-Preview" alt="preview" src={imgBase64}></img> | 76 | + <div className="ImageInput"> |
77 | + <input type="file" name="file" onChange={handleChangeFile} /> | ||
78 | + </div> | ||
73 | </div> | 79 | </div> |
74 | - <div className="Image_input"> | 80 | + <div className="ImageInputSetting"> |
75 | - <input type="file" name="file" onChange={handleChangeFile} /> | 81 | + <div className="PositionSelector"> |
76 | - <button type="button" onClick={analysisImage} >Submit</button> | 82 | + <h3>전면 사진</h3> |
83 | + <Checkbox checked={selectedPosition === "front"} onChange={(isChecked) => { isChecked ? setPosition('front') : setPosition(undefined) }} /> | ||
84 | + <h3>측면 사진 - 왼쪽</h3> | ||
85 | + <Checkbox checked={selectedPosition === "left"} onChange={(isChecked) => { isChecked ? setPosition('left') : setPosition(undefined) }} /> | ||
86 | + <h3>측면 사진 - 오른쪽</h3> | ||
87 | + <Checkbox checked={selectedPosition === "right"} onChange={(isChecked) => { isChecked ? setPosition('right') : setPosition(undefined) }} /> | ||
88 | + </div> | ||
89 | + <div className="Caution"> | ||
90 | + <p>-- 이미지 업로드 시 유의사항 --</p> | ||
91 | + <p>1. 업로드 되는 이미지는 JPEG, PNG 포맷만 지원합니다.</p> | ||
92 | + <p>2. 업로드할 수 있는 이미지의 최대 용량은 2MB입니다.</p> | ||
93 | + <p>3. 이미지의 권장 비율은 가로:세로 기준 16:9 ~ 9:16 입니다.</p> | ||
94 | + <p>4. 이미지의 가로와 세로 길이는 320px~2048px 범위 내여야 합니다.</p> | ||
95 | + </div> | ||
96 | + <Link to="/result"> | ||
97 | + <button className="startBtn" type="button" onClick={analysisImage}>Submit</button> | ||
98 | + </Link> | ||
77 | </div> | 99 | </div> |
78 | </div> | 100 | </div> |
79 | ) | 101 | ) | ... | ... |
straight-up/src/Result.js
0 → 100644
1 | +import React from 'react' | ||
2 | +import { useRecoilValue } from 'recoil'; | ||
3 | +import { analysisResultState } from './store/Global'; | ||
4 | +import Header from './components/Header'; | ||
5 | +import ResultContent from './components/ResultContent'; | ||
6 | +import './style/ResultContent.css'; | ||
7 | + | ||
8 | +const Result = () => { | ||
9 | + const analysisResult = useRecoilValue(analysisResultState); | ||
10 | + return ( | ||
11 | + <div className="resultPageContainer"> | ||
12 | + <Header /> | ||
13 | + <ResultContent | ||
14 | + result={analysisResult} | ||
15 | + /> | ||
16 | + </div> | ||
17 | + ) | ||
18 | +} | ||
19 | + | ||
20 | +export default Result; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -2,11 +2,11 @@ import React from 'react' | ... | @@ -2,11 +2,11 @@ import React from 'react' |
2 | import { Link } from 'react-router-dom'; | 2 | import { Link } from 'react-router-dom'; |
3 | import "../style/Landing.css"; | 3 | import "../style/Landing.css"; |
4 | 4 | ||
5 | -const Button = () => { | 5 | +const Button = (props) => { |
6 | return ( | 6 | return ( |
7 | <div className="mainBtnContainer"> | 7 | <div className="mainBtnContainer"> |
8 | <Link to="/main"> | 8 | <Link to="/main"> |
9 | - <button className="startBtn">Get Started!</button> | 9 | + <button className="startBtn">{props.btnText}</button> |
10 | </Link> | 10 | </Link> |
11 | </div> | 11 | </div> |
12 | ) | 12 | ) | ... | ... |
straight-up/src/components/Checkbox.js
0 → 100644
1 | +import React from 'react' | ||
2 | + | ||
3 | +const Checkbox = (props) => { | ||
4 | + return ( | ||
5 | + <input | ||
6 | + className="Checkbox" | ||
7 | + type="checkbox" | ||
8 | + checked={props.checked} | ||
9 | + onChange={(e) => props.onChange(e.target.checked)} | ||
10 | + /> | ||
11 | + ) | ||
12 | +} | ||
13 | +export default Checkbox; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
straight-up/src/components/ResultContent.js
0 → 100644
1 | +import React from 'react' | ||
2 | +import { useRecoilValue } from 'recoil'; | ||
3 | +import ResultForLn from './ResultForLn'; | ||
4 | +import ResultForErr from './ResultForErr'; | ||
5 | +import ResultForOk from './ResultForOk'; | ||
6 | +import ResultForBn from './ResultForBn'; | ||
7 | +import ResultForBb from './ResultForBb'; | ||
8 | +import ResultForErrTrust from './ResultForErrTrust'; | ||
9 | +import ResultLoading from './ResultLoading'; | ||
10 | +import { selectedPosState } from '../store/Global'; | ||
11 | +const ResultContent = (props) => { | ||
12 | + const resultStr = props.result.toString(); | ||
13 | + const headLetters = resultStr.substr([0, 4]); | ||
14 | + const direction = useRecoilValue(selectedPosState); | ||
15 | + if (resultStr === "loading") { | ||
16 | + return <ResultLoading /> | ||
17 | + } | ||
18 | + else if (headLetters === 'error') { | ||
19 | + return <ResultForErrTrust />; | ||
20 | + } | ||
21 | + else if (resultStr === "okay") { | ||
22 | + return <ResultForOk />; | ||
23 | + } | ||
24 | + else if (headLetters === "leani") { | ||
25 | + return <ResultForLn direction={direction} /> | ||
26 | + } | ||
27 | + else if (resultStr === "bent-neck") { | ||
28 | + return <ResultForBn />; | ||
29 | + } | ||
30 | + else if (resultStr === "bent-back") { | ||
31 | + return <ResultForBb />; | ||
32 | + } | ||
33 | + else { | ||
34 | + return <ResultForErr />; | ||
35 | + } | ||
36 | +} | ||
37 | + | ||
38 | +export default ResultContent; |
straight-up/src/components/ResultForBb.js
0 → 100644
1 | +import React from 'react' | ||
2 | +import RetryBtn from './RetryBtn'; | ||
3 | +import '../style/ResultContent.css'; | ||
4 | + | ||
5 | +const ResultForBb = () => { | ||
6 | + return ( | ||
7 | + <div className="resultContainer"> | ||
8 | + <div className="resultPhoto Bb"> | ||
9 | + </div> | ||
10 | + <div className="resultTextContainer"> | ||
11 | + <h1>분석 결과 : [굽은등] 증상이 의심됩니다.</h1> | ||
12 | + <p>척추 자세를 바로잡아 등을 곧게 하고 어깨를 펴주세요.</p> | ||
13 | + <p>주기적으로 일어나 척추 스트레칭이나 요가를 해주시면 도움이 됩니다.</p> | ||
14 | + <a href="https://terms.naver.com/entry.nhn?docId=2119027&cid=51035&categoryId=51035" target="blank">https://terms.naver.com/entry.nhn?docId=2119027&cid=51035&categoryId=51035</a> <br /> | ||
15 | + <a href="https://www.youtube.com/watch?v=fFIL0rlRH78&feature=youtu.be" target="blank">https://www.youtube.com/watch?v=fFIL0rlRH78&feature=youtu.be</a> | ||
16 | + <RetryBtn btnText="Try Again" /> | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + ) | ||
20 | +} | ||
21 | + | ||
22 | +export default ResultForBb; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
straight-up/src/components/ResultForBn.js
0 → 100644
1 | +import React from 'react' | ||
2 | +import RetryBtn from './RetryBtn'; | ||
3 | +import '../style/ResultContent.css'; | ||
4 | + | ||
5 | +const ResultForBn = () => { | ||
6 | + return ( | ||
7 | + <div className="resultContainer"> | ||
8 | + <div className="resultPhoto Bn"> | ||
9 | + </div> | ||
10 | + <div className="resultTextContainer"> | ||
11 | + <h1>분석 결과 : [거북목] 증상이 의심됩니다.</h1> | ||
12 | + <p>모니터에서 떨어져 목을 곧게 하고 어깨를 펴주세요.</p> | ||
13 | + <p>20~30분마다 목을 뒤로 젖혀 주는 신전 운동을 해주시면 도움이 됩니다.</p> | ||
14 | + <a href="https://terms.naver.com/entry.nhn?docId=927290&cid=51007&categoryId=51007" target="blank">https://terms.naver.com/entry.nhn?docId=927290&cid=51007&categoryId=51007</a> <br /> | ||
15 | + <a href="https://youtu.be/oYaal-ir9cc" target="blank">https://youtu.be/oYaal-ir9cc</a> | ||
16 | + <RetryBtn btnText="Try Again" /> | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + ) | ||
20 | +} | ||
21 | + | ||
22 | +export default ResultForBn; |
straight-up/src/components/ResultForErr.js
0 → 100644
1 | +import React from 'react' | ||
2 | +import RetryBtn from './RetryBtn'; | ||
3 | +import '../style/ResultContent.css'; | ||
4 | + | ||
5 | +const ResultForErr = () => { | ||
6 | + return ( | ||
7 | + <div className="resultContainer"> | ||
8 | + <div className="resultPhoto Err"> | ||
9 | + </div> | ||
10 | + <div className="resultTextContainer"> | ||
11 | + <h1>분석 결과 : 자세 분석 실패</h1> | ||
12 | + <p>자세 분석에 실패했습니다.</p> | ||
13 | + <p>다시 시도해주시기 바랍니다.</p> | ||
14 | + <RetryBtn btnText="Try Again" /> | ||
15 | + </div> | ||
16 | + </div> | ||
17 | + ) | ||
18 | +} | ||
19 | + | ||
20 | +export default ResultForErr; |
1 | +import React from 'react' | ||
2 | +import RetryBtn from './RetryBtn'; | ||
3 | +import '../style/ResultContent.css'; | ||
4 | + | ||
5 | +const ResultForErr = () => { | ||
6 | + return ( | ||
7 | + <div className="resultContainer"> | ||
8 | + <div className="resultPhoto Err"> | ||
9 | + </div> | ||
10 | + <div className="resultTextContainer"> | ||
11 | + <h1>분석 결과 : 자세 분석 실패</h1> | ||
12 | + <p>자세 분석에 실패했습니다.</p> | ||
13 | + <p>주의사항에 맞게 사진을 업로드했는지 확인해주세요.</p> | ||
14 | + <RetryBtn btnText="Try Again" /> | ||
15 | + </div> | ||
16 | + </div> | ||
17 | + ) | ||
18 | +} | ||
19 | + | ||
20 | +export default ResultForErr; |
straight-up/src/components/ResultForLn.js
0 → 100644
1 | +import React from 'react' | ||
2 | +import RetryBtn from './RetryBtn'; | ||
3 | +import '../style/ResultContent.css'; | ||
4 | + | ||
5 | +const ResultForLn = (props) => { | ||
6 | + const direction = props.direction === 'left' ? '왼쪽' : '오른쪽'; | ||
7 | + const conclusion = `어깨와 머리가 ${direction}으로 기울어져 있습니다.`; | ||
8 | + return ( | ||
9 | + <div className="resultContainer"> | ||
10 | + <div className="resultPhoto Ln"> | ||
11 | + </div> | ||
12 | + <div className="resultTextContainer"> | ||
13 | + <h1>분석 결과 : 어깨 비대칭</h1> | ||
14 | + <p>{conclusion}</p> | ||
15 | + <p>턱을 괴거나 삐딱하게 화면을 주시하는 경우가 많다면 어깨 비대칭을 의심해볼 수 있습니다.</p> | ||
16 | + <p>주기적으로 어깨와 목 스트레칭을 해주시면 도움이 됩니다.</p> | ||
17 | + <a href="https://terms.naver.com/entry.nhn?docId=3567879&cid=58904&categoryId=589109" target="blank">https://terms.naver.com/entry.nhn?docId=3567879&cid=58904&categoryId=58910</a><br /> | ||
18 | + <a href="https://youtu.be/n4T4bRINdp" target="blank">https://youtu.be/n4T4bRINdp</a> | ||
19 | + <RetryBtn btnText="Try Again" /> | ||
20 | + </div> | ||
21 | + </div> | ||
22 | + ) | ||
23 | +} | ||
24 | + | ||
25 | +export default ResultForLn; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
straight-up/src/components/ResultForOk.js
0 → 100644
1 | +import React from 'react' | ||
2 | +import RetryBtn from './RetryBtn'; | ||
3 | +import '../style/ResultContent.css'; | ||
4 | + | ||
5 | +const ResultForOk = () => { | ||
6 | + return ( | ||
7 | + <div className="resultContainer"> | ||
8 | + <div className="resultPhoto Ok"> | ||
9 | + </div> | ||
10 | + <div className="resultTextContainer"> | ||
11 | + <h1>분석 결과 : 정상</h1> | ||
12 | + <p>아주 건강한 자세를 유지하고 계시네요!</p> | ||
13 | + <p>지금처럼 건강한 자세를 유지하는데 도움이 될 스트레칭을 추천해드릴게요!</p> | ||
14 | + <a href="http://bakc.net/health/main/index.php?m_cd=109" target="blank">http://bakc.net/health/main/index.php?m_cd=109</a> | ||
15 | + <RetryBtn btnText="Try Again" /> | ||
16 | + </div> | ||
17 | + </div> | ||
18 | + ) | ||
19 | +} | ||
20 | + | ||
21 | +export default ResultForOk; |
straight-up/src/components/ResultLoading.js
0 → 100644
1 | +import React from 'react' | ||
2 | +import '../style/ResultContent.css'; | ||
3 | + | ||
4 | +const ResultLoading = () => { | ||
5 | + return ( | ||
6 | + <div className="resultContainer"> | ||
7 | + <div className="resultPhoto Loading"> | ||
8 | + </div> | ||
9 | + <div className="resultTextContainer"> | ||
10 | + <h1>분석중..</h1> | ||
11 | + <p></p> | ||
12 | + <p>자세를 분석중입니다... 분석에는 5~10초가 소요됩니다.</p> | ||
13 | + </div> | ||
14 | + </div> | ||
15 | + ) | ||
16 | +} | ||
17 | + | ||
18 | +export default ResultLoading; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
straight-up/src/components/RetryBtn.js
0 → 100644
1 | +import React from 'react' | ||
2 | +import { useSetRecoilState } from 'recoil'; | ||
3 | +import { Link } from 'react-router-dom'; | ||
4 | +import "../style/Landing.css"; | ||
5 | +import { selectedPosState, analysisResultState } from '../store/Global'; | ||
6 | + | ||
7 | +const RetryBtn = (props) => { | ||
8 | + const setPosition = useSetRecoilState(selectedPosState); | ||
9 | + const setResult = useSetRecoilState(analysisResultState); | ||
10 | + const reset = () => { | ||
11 | + setPosition('front'); | ||
12 | + setResult('loading'); | ||
13 | + } | ||
14 | + return ( | ||
15 | + <div className="mainBtnContainer"> | ||
16 | + <Link to="/main"> | ||
17 | + <button className="startBtn" onClick={reset}>{props.btnText}</button> | ||
18 | + </Link> | ||
19 | + </div> | ||
20 | + ) | ||
21 | +} | ||
22 | +export default RetryBtn; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
straight-up/src/setProxy.js
deleted
100644 → 0
straight-up/src/store/Global.js
0 → 100644
... | @@ -16,20 +16,11 @@ body { | ... | @@ -16,20 +16,11 @@ body { |
16 | margin: 0; | 16 | margin: 0; |
17 | width: 100vw; | 17 | width: 100vw; |
18 | height: 100vh; | 18 | height: 100vh; |
19 | + text-align: center; | ||
20 | + align-items: center; | ||
21 | + justify-content: center; | ||
19 | } | 22 | } |
20 | -/* | 23 | + |
21 | -.Landingbg:after { | ||
22 | - content: ''; | ||
23 | - position: absolute; | ||
24 | - top: 0; | ||
25 | - left: 0; | ||
26 | - width: 100vw; | ||
27 | - height: 100vh; | ||
28 | - z-index: 0; | ||
29 | - background: rgba(0,0,0,0.001); | ||
30 | - box-shadow: inset 100px 100px 250px #000000, inset -100px -100px 250px #000000; | ||
31 | -} | ||
32 | -*/ | ||
33 | .mainTextContainer{ | 24 | .mainTextContainer{ |
34 | text-align: center; | 25 | text-align: center; |
35 | position: relative; | 26 | position: relative; | ... | ... |
straight-up/src/style/Loading.JPG
0 → 100644
11 KB
1 | -.Image-Preview{ | 1 | +html, body { |
2 | - width: 400px; | 2 | + width: 100vw; |
3 | + height: 100vh; | ||
4 | +} | ||
5 | + | ||
6 | +body { | ||
7 | + margin: 0; | ||
8 | +} | ||
9 | + | ||
10 | +.MainPageContainer { | ||
11 | + background: url("Landing.jpg"); | ||
12 | + background-repeat: no-repeat; | ||
13 | + background-size: cover; | ||
14 | + background-position: center; | ||
15 | + overflow: hidden; | ||
16 | + margin: 0; | ||
17 | + width: 100vw; | ||
18 | + height: 100vh; | ||
19 | + text-align: center; | ||
20 | + align-items: center; | ||
21 | + justify-content: center; | ||
22 | +} | ||
23 | + | ||
24 | +.ImagePreviewContainer{ | ||
25 | + display: inline-block; | ||
26 | + background: lightgrey; | ||
27 | + border-radius: 15px; | ||
28 | +} | ||
29 | + | ||
30 | +.ImagePreview{ | ||
31 | + width: 300px; | ||
3 | height: 400px; | 32 | height: 400px; |
4 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
33 | + background-color: #efefef; | ||
34 | + border-radius: 15px; | ||
35 | +} | ||
36 | + | ||
37 | +.PositionSelector { | ||
38 | + display: flex; | ||
39 | + justify-content: center; | ||
40 | + align-items: center; | ||
41 | +} | ||
42 | + | ||
43 | +.Checkbox { | ||
44 | + padding: 1rem; | ||
45 | +} | ||
46 | + | ||
47 | +h3{ | ||
48 | + color: white; | ||
49 | + padding: 1rem; | ||
50 | +} | ||
51 | + | ||
52 | +.Caution{ | ||
53 | + color: pink; | ||
54 | +} | ... | ... |
straight-up/src/style/ResultContent.css
0 → 100644
1 | +html, body { | ||
2 | + width: 100vw; | ||
3 | + height: 100vh; | ||
4 | +} | ||
5 | + | ||
6 | +body { | ||
7 | + margin: 0; | ||
8 | +} | ||
9 | + | ||
10 | +a { | ||
11 | + color: #4b70fd; | ||
12 | + text-decoration : none; | ||
13 | +} | ||
14 | + | ||
15 | +.logo { | ||
16 | + height: 100px; | ||
17 | +} | ||
18 | + | ||
19 | +.resultPageContainer{ | ||
20 | + text-align: center; | ||
21 | + align-items: center; | ||
22 | + justify-content: center; | ||
23 | +} | ||
24 | + | ||
25 | +.resultContainer{ | ||
26 | + background: url("Landing.jpg"); | ||
27 | + background-repeat: no-repeat; | ||
28 | + background-size: cover; | ||
29 | + background-position: center; | ||
30 | + overflow: hidden; | ||
31 | + margin: 0; | ||
32 | + width: 100vw; | ||
33 | + height: 100vh; | ||
34 | + text-align: center; | ||
35 | + align-items: center; | ||
36 | + justify-content: center; | ||
37 | +} | ||
38 | + | ||
39 | +.resultPhoto { | ||
40 | + margin: auto; | ||
41 | + margin-top : 1rem; | ||
42 | + width: 40vw; | ||
43 | + height: 40vh; | ||
44 | +} | ||
45 | + | ||
46 | +.Bb { | ||
47 | + background: url(bent-back.jpg); | ||
48 | + background-repeat: no-repeat; | ||
49 | + background-size: contain; | ||
50 | + background-position: center; | ||
51 | +} | ||
52 | + | ||
53 | +.Bn { | ||
54 | + background: url(bent-neck.jpg); | ||
55 | + background-repeat: no-repeat; | ||
56 | + background-size: contain; | ||
57 | + background-position: center; | ||
58 | +} | ||
59 | + | ||
60 | +.Err { | ||
61 | + background: url(oops.jpg); | ||
62 | + background-repeat: no-repeat; | ||
63 | + background-size: contain; | ||
64 | + background-position: center; | ||
65 | +} | ||
66 | + | ||
67 | +.Ln { | ||
68 | + background: url(lean.jpg); | ||
69 | + background-repeat: no-repeat; | ||
70 | + background-size: contain; | ||
71 | + background-position: center; | ||
72 | +} | ||
73 | + | ||
74 | +.Loading { | ||
75 | + background: url(Loading.JPG); | ||
76 | + background-repeat: no-repeat; | ||
77 | + background-size: contain; | ||
78 | + background-position: center; | ||
79 | +} | ||
80 | + | ||
81 | +.Ok { | ||
82 | + background: url(okay.jpg); | ||
83 | + background-repeat: no-repeat; | ||
84 | + background-size: contain; | ||
85 | + background-position: center; | ||
86 | +} | ||
87 | + | ||
88 | +.resultTextContainer { | ||
89 | + margin-left: 3rem; | ||
90 | + margin-right: 3rem; | ||
91 | + height : 350px; | ||
92 | + text-align: center; | ||
93 | + background-color: lightcyan; | ||
94 | + color: black; | ||
95 | +} | ||
96 | +.mainBtnContainer { | ||
97 | + display: flex; | ||
98 | + align-items: center; | ||
99 | + justify-content: center; | ||
100 | +} |
straight-up/src/style/bent-back.jpg
0 → 100644
13.9 KB
straight-up/src/style/bent-neck.jpg
0 → 100644
57.1 KB
straight-up/src/style/lean.jpg
0 → 100644
73.9 KB
straight-up/src/style/okay.jpg
0 → 100644
2.08 MB
straight-up/src/style/oops.jpg
0 → 100644
2.3 MB
-
Please register or login to post a comment