diff --git a/package-lock.json b/package-lock.json index 572fadc..4850d3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@tailwindcss/vite": "^4.1.18", "react": "^19.2.0", "react-dom": "^19.2.0", + "react-router-dom": "^7.12.0", "tailwindcss": "^4.1.18" }, "devDependencies": { @@ -1872,6 +1873,19 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3058,6 +3072,44 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.12.0.tgz", + "integrity": "sha512-kTPDYPFzDVGIIGNLS5VJykK0HfHLY5MF3b+xj0/tTyNYL1gF1qs7u67Z9jEhQk2sQ98SUaHxlG31g1JtF7IfVw==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.12.0.tgz", + "integrity": "sha512-pfO9fiBcpEfX4Tx+iTYKDtPbrSLLCbwJ5EqP+SPYQu1VYCXdy79GSj0wttR0U4cikVdlImZuEZ/9ZNCgoaxwBA==", + "license": "MIT", + "dependencies": { + "react-router": "7.12.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -3128,6 +3180,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", diff --git a/package.json b/package.json index 00d7353..6191494 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@tailwindcss/vite": "^4.1.18", "react": "^19.2.0", "react-dom": "^19.2.0", + "react-router-dom": "^7.12.0", "tailwindcss": "^4.1.18" }, "devDependencies": { diff --git a/src/App.jsx b/src/App.jsx index 53eb971..bbf75f1 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,11 +1,23 @@ import './App.css' +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import MainPage from './pages/MainPage' +import CoinDetailPage from './pages/CoinDetailPage'; +import NewsDetailPage from './pages/NewsDetailPage'; +import GamePage from './pages/GamePage'; +import LeaderBoardPage from './pages/LeaderBoardPage'; function App() { return ( - <> -
CoinSight
- + + + } /> + } /> + } /> + } /> + } /> + + ) } diff --git a/src/components/common/Navbar.jsx b/src/components/common/Navbar.jsx new file mode 100644 index 0000000..5bf7b0b --- /dev/null +++ b/src/components/common/Navbar.jsx @@ -0,0 +1,35 @@ +import { useNavigate } from "react-router-dom"; + +const Navbar = () => { + const nav = useNavigate(); + return ( +
+
+ CoinSight +
+ +
+
nav("/")} + className="cursor-pointer" + > + 메인 +
+
nav("/game")} + className="cursor-pointer" + > + 게임 +
+
nav("/leaderboard")} + className="cursor-pointer" + > + 리더보드 +
+
+
+ ) +} + +export default Navbar; \ No newline at end of file diff --git a/src/index.css b/src/index.css index f173aa4..b5f37f0 100644 --- a/src/index.css +++ b/src/index.css @@ -1 +1,7 @@ -@import 'tailwindcss'; \ No newline at end of file +@import 'tailwindcss'; + +body { + background-color: #FAFAFA; + margin: 0; + padding: 0; +} \ No newline at end of file diff --git a/src/pages/CoinDetailPage.jsx b/src/pages/CoinDetailPage.jsx new file mode 100644 index 0000000..3489df7 --- /dev/null +++ b/src/pages/CoinDetailPage.jsx @@ -0,0 +1,83 @@ +import { useEffect, useState } from "react"; +import Navbar from "../components/common/Navbar"; + +const CoinDetailPage = () => { + const coinName = "KRW-BTC"; + const [currentPrice, setCurrentPrice] = useState(0); + const [tradePrice, setTradePrice] = useState(0); + const [fluctuationRange, setFluctuationRange] = useState(0); + const [isPositive, setIsPositive] = useState(true); + + const formatPrice = (value) => { + if (!value) return "0억"; + const formatPrice = Number(value) / 100000000; + return `${formatPrice.toLocaleString(undefined, {maximumFractionDigits: 1})}억`; + } + + useEffect (() => { + const options = {method: 'GET', headers: {accept: 'application/json'}}; + + fetch(`https://api.bithumb.com/v1/ticker?markets=${coinName}`, options) + .then(response => response.json()) + .then(response => { + console.log(response); + const formattedPrice = formatPrice(response[0].acc_trade_price_24h); + setTradePrice(formattedPrice); + const p = response[0].trade_price.toLocaleString('ko-KR'); + setCurrentPrice(p); + }) + .catch(err => console.error(err)); + + fetch(`https://api.bithumb.com/public/candlestick/BTC_KRW/1h`, options) + .then(res => res.json()) + .then(res => { + const data = res.data; + const len = data.length; + const currentPrice = parseFloat(data[len - 1][2]); + const prevPrice = parseFloat(data[len - 2][2]); + + const changeRate = ((currentPrice - prevPrice) / prevPrice) * 100; + setFluctuationRange(changeRate.toFixed(2)); + if (changeRate < 0) setIsPositive(false); + }) + .catch(err => console.error(err)); + }, [coinName]); + + return ( +
+ +
+
+
+
+ 비트코인(BTC) +
+ +
+ 2026년 01월 23일 +
+
+ +
+
+

현재가

+

₩{currentPrice}

+
+ +
+

1시간 등락

+

{fluctuationRange}%

+
+ +
+

24시간 거래대금

+

₩{tradePrice}

+
+
+
+
+
+ ) +} + +export default CoinDetailPage; \ No newline at end of file diff --git a/src/pages/GamePage.jsx b/src/pages/GamePage.jsx new file mode 100644 index 0000000..349ed36 --- /dev/null +++ b/src/pages/GamePage.jsx @@ -0,0 +1,12 @@ +import Navbar from "../components/common/Navbar" + +const GamePage = () => { + return ( +
+ + game page +
+ ) +} + +export default GamePage; \ No newline at end of file diff --git a/src/pages/LeaderBoardPage.jsx b/src/pages/LeaderBoardPage.jsx new file mode 100644 index 0000000..832d298 --- /dev/null +++ b/src/pages/LeaderBoardPage.jsx @@ -0,0 +1,12 @@ +import Navbar from "../components/common/Navbar" + +const LeaderBoardPage = () => { + return ( + <> + + LeaderBoardPage + + ) +} + +export default LeaderBoardPage; \ No newline at end of file diff --git a/src/pages/MainPage.jsx b/src/pages/MainPage.jsx new file mode 100644 index 0000000..a5a4161 --- /dev/null +++ b/src/pages/MainPage.jsx @@ -0,0 +1,12 @@ +import Navbar from "../components/common/Navbar"; + +const MainPage = () => { + return ( +
+ + main page +
+ ) +} + +export default MainPage; \ No newline at end of file diff --git a/src/pages/NewsDetailPage.jsx b/src/pages/NewsDetailPage.jsx new file mode 100644 index 0000000..116d298 --- /dev/null +++ b/src/pages/NewsDetailPage.jsx @@ -0,0 +1,12 @@ +import Navbar from "../components/common/Navbar"; + +const NewsDetailPage = () => { + return ( +
+ + News Detail Page +
+ ) +} + +export default NewsDetailPage; \ No newline at end of file