From 1c73b68e70f9724893a51cf0d6ac35796b127e94 Mon Sep 17 00:00:00 2001 From: JunCastle Date: Sat, 2 Dec 2023 19:40:33 +0900 Subject: [PATCH 01/13] fix: hover transition ease-out --- src/components/Style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Style.css b/src/components/Style.css index 266ac527f..e03b14aa1 100644 --- a/src/components/Style.css +++ b/src/components/Style.css @@ -135,7 +135,7 @@ nav { .Card:hover { transform: scale(1.3); - transition: transform 0.3s; + transition: all 0.5s ease-out; } .Description { From 52752bd8d48862acf4711c1abfa6c068d9582ceb Mon Sep 17 00:00:00 2001 From: JunCastle Date: Sat, 2 Dec 2023 20:14:01 +0900 Subject: [PATCH 02/13] =?UTF-8?q?feat:=20router=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 39 +++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 40 insertions(+) diff --git a/package-lock.json b/package-lock.json index a1e590ee6..07f62f2f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@testing-library/user-event": "^13.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.20.1", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" } @@ -3241,6 +3242,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.13.1.tgz", + "integrity": "sha512-so+DHzZKsoOcoXrILB4rqDkMDy7NLMErRdOxvzvOKb507YINKUP4Di+shbTZDhSE/pBZ+vr7XGIpcOO0VLSA+Q==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -14671,6 +14680,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.20.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.20.1.tgz", + "integrity": "sha512-ccvLrB4QeT5DlaxSFFYi/KR8UMQ4fcD8zBcR71Zp1kaYTC5oJKYAp1cbavzGrogwxca+ubjkd7XjFZKBW8CxPA==", + "dependencies": { + "@remix-run/router": "1.13.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.20.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.20.1.tgz", + "integrity": "sha512-npzfPWcxfQN35psS7rJgi/EW0Gx6EsNjfdJSAk73U/HqMEJZ2k/8puxfwHFgDQhBGmS3+sjnGbMdMSV45axPQw==", + "dependencies": { + "@remix-run/router": "1.13.1", + "react-router": "6.20.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", diff --git a/package.json b/package.json index 7ff0d6b58..38c6f3fa1 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "@testing-library/user-event": "^13.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.20.1", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, From 2a3e020d6a3e97c0ae66f8d3925384823ad222ff Mon Sep 17 00:00:00 2001 From: JunCastle Date: Sat, 2 Dec 2023 23:06:07 +0900 Subject: [PATCH 03/13] =?UTF-8?q?fix:=20api.js=20fetchProfile=20fetchLinks?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Main.js | 12 ++++++++ src/api.js | 21 ++++++++++---- src/components/AddLink.js | 7 +++++ src/components/App.js | 16 +++++----- src/components/Card.js | 2 +- src/components/Folder.js | 17 +++++++++++ src/components/Header.js | 42 +++++++++++++++------------ src/components/{Main.js => Search.js} | 15 +++++----- src/components/Title.js | 6 ++-- src/index.js | 4 +-- 10 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 src/Main.js create mode 100644 src/components/AddLink.js create mode 100644 src/components/Folder.js rename src/components/{Main.js => Search.js} (84%) diff --git a/src/Main.js b/src/Main.js new file mode 100644 index 000000000..8c4588620 --- /dev/null +++ b/src/Main.js @@ -0,0 +1,12 @@ +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import App from "./components/App"; +import Folder from "./components/Folder"; + + +function Main() { + return ( + + ); +} + +export default Main; diff --git a/src/api.js b/src/api.js index 59040648f..431c45ce3 100644 --- a/src/api.js +++ b/src/api.js @@ -1,6 +1,15 @@ -// export async function getProfile() { -// const response = await fetch ('https://bootcamp-api.codeit.kr/api/sample/user') -// const body = await response.json(); -// return body; -// } -// 사용하고 싶은데 사용하지 못해서 남겨둠.. \ No newline at end of file +export async function fetchProfile() { + const response = await fetch( + "https://bootcamp-api.codeit.kr/api/sample/user" + ); + const result = await response.json(); + return result; +} + +export async function fetchLinks() { + const response = await fetch( + "https://bootcamp-api.codeit.kr/api/sample/folder" + ); + const result = await response.json(); + return result; +} diff --git a/src/components/AddLink.js b/src/components/AddLink.js new file mode 100644 index 000000000..beab1aefe --- /dev/null +++ b/src/components/AddLink.js @@ -0,0 +1,7 @@ +function AddLink() { + return ( + 링크를 추가해 보세요 + ); +} + +export default AddLink; \ No newline at end of file diff --git a/src/components/App.js b/src/components/App.js index 359e42ff6..83b97559d 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -1,17 +1,17 @@ import Header from "./Header"; -import Main from "./Main"; +import Search from "./Search"; import Footer from "./Footer"; import Title from "./Title"; function App() { return ( -
-
- - <Main /> - <Footer /> - </div> + <div> + <Header /> + <Title /> + <Search /> + <Footer /> + </div> ); } -export default App; \ No newline at end of file +export default App; diff --git a/src/components/Card.js b/src/components/Card.js index 235d094d1..1be20ab9d 100644 --- a/src/components/Card.js +++ b/src/components/Card.js @@ -4,7 +4,7 @@ function Card({ data }) { {data && data.map((data) => <div className="Contents"> <div className="CardContainer"> - <img className="Card" src={data.imageSource} key={data.id}/> + <img className="Card" src={data.imageSource} key={data.id} alt="이미지 미리보기"/> </div> <div className="CardInfoContainer"> <p className="Description">{data.description}</p> diff --git a/src/components/Folder.js b/src/components/Folder.js new file mode 100644 index 000000000..b1c49bc72 --- /dev/null +++ b/src/components/Folder.js @@ -0,0 +1,17 @@ +import Header from "./Header"; +import AddLink from "./AddLink"; +import Footer from "./Footer"; +import Title from "./Title"; + +function Folder() { + return ( + <div> + <Header /> + <Title /> + <AddLink /> + <Footer /> + </div> + ); +} + +export default Folder; diff --git a/src/components/Header.js b/src/components/Header.js index 42b58fc4c..8674061e8 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -1,42 +1,48 @@ import logoImg from "../assets/logo.svg"; import "./Style.css"; import { useEffect, useState } from "react"; -// import { getProfile } from "../api"; +import { fetchProfile } from "../api"; function Header() { const [profile, setProfile] = useState(null); - const fetchProfile = async () => { + + const getProfile = async () => { try { - const response = await fetch('https://bootcamp-api.codeit.kr/api/sample/user'); - const data = await response.json(); - setProfile(data); + const response = await fetchProfile(); + setProfile(response.data); } catch (error) { - console.error('프로필 데이터를 불러오는 중 에러 발생:', error); + console.error("프로필 데이터를 불러오는 중 에러 발생:", error); } }; useEffect(() => { - fetchProfile(); - },[]); + getProfile(); + }, []); return ( - <header> <nav className="NavBar"> <a href="/"> <img src={logoImg} alt="홈으로 연결된 Linkbrary 로고" /> </a> <div> - {profile ? ( - <div> - <p className="Profile"><img className="ProfileImg" src={profile.profileImageSource} alt="프로필 이미지" />{profile.email}</p> + {profile ? ( + <div> + <p className="Profile"> + <img + className="ProfileImg" + src={profile.profileImageSource} + alt="프로필 이미지" + /> + {profile.email} + </p> + </div> + ) : ( + <a href="/"> + <span className="signin">로그인</span> + </a> + )} </div> - ) : ( - <a href="/"> - <span className="signin">로그인</span> - </a> - )} - </div> </nav> </header> ); diff --git a/src/components/Main.js b/src/components/Search.js similarity index 84% rename from src/components/Main.js rename to src/components/Search.js index e0e0ff42c..b4e0eeeab 100644 --- a/src/components/Main.js +++ b/src/components/Search.js @@ -1,10 +1,11 @@ import "./Style.css"; import Card from "./Card"; -import search from '../assets/search.svg' +import search from "../assets/search.svg"; import { useState, useEffect } from "react"; -function Main() { +function Search() { const [linksData, setLinksData] = useState(); + const fetchLinks = async () => { try { const response = await fetch( @@ -17,7 +18,7 @@ function Main() { console.error("링크 데이터를 불러오는 중 에러 발생:", error); } }; - + useEffect(() => { fetchLinks(); }, []); @@ -25,14 +26,14 @@ function Main() { return ( <main className="MainContainer"> <div className="Finder"> - <input className="Link" type="text" value="링크를 검색해보세요."/> - <img className="SearchIcon" src={search} alt="돋보기 아이콘"/> + <input className="Link" type="text" value="링크를 검색해보세요." /> + <img className="SearchIcon" src={search} alt="돋보기 아이콘" /> </div> <div className="CardDataContainer"> - <Card data={linksData} /> + <Card data={linksData} /> </div> </main> ); } -export default Main; +export default Search; diff --git a/src/components/Title.js b/src/components/Title.js index d3f21070a..f908c1d71 100644 --- a/src/components/Title.js +++ b/src/components/Title.js @@ -1,14 +1,14 @@ import "./Style.css"; import { useState, useEffect } from "react"; +import { fetchLinks } from "../api"; function Title() { const [folderData, setFolderData] = useState(); const fetchUserProfile = async () => { try { - const response = await fetch('https://bootcamp-api.codeit.kr/api/sample/folder'); - const data = await response.json(); - setFolderData(data); + const response = await fetchLinks(); + setFolderData(response.data); } catch (error) { console.error('프로필 데이터를 불러오는 중 에러 발생:', error); } diff --git a/src/index.js b/src/index.js index e0a3b7428..daf74b94e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,6 @@ import ReactDOM from 'react-dom/client'; -import App from './components/App'; +import Main from './Main'; const root = ReactDOM.createRoot(document.getElementById('root')); -root.render(<App />); +root.render(<Main />); From e93f6364cdfeffbaac9fb3bd7df0b30620254032 Mon Sep 17 00:00:00 2001 From: JunCastle <juncastle97@gmail.com> Date: Wed, 6 Dec 2023 19:40:19 +0900 Subject: [PATCH 04/13] =?UTF-8?q?feat:SharePage&FolderPage=20=EB=82=98?= =?UTF-8?q?=EB=88=84=EA=B8=B0(=EC=BB=A4=EB=B0=8B=20=EB=88=84=EB=9D=BD)=20f?= =?UTF-8?q?eat&stlye:=20AddLink=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20input=20css=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Main.js | 16 +++++++++---- src/api.js | 1 + src/assets/kebab.svg | 5 ++++ src/assets/link.svg | 4 ++++ src/assets/star.svg | 10 ++++++++ src/components/AddLink.js | 7 +++++- src/components/App.js | 17 ------------- src/components/Folder.js | 17 ------------- src/components/Header.js | 44 +++++++++++++++------------------- src/components/Search.js | 2 +- src/components/Style.css | 50 +++++++++++++++++++++++++++++++++++++++ src/components/Title.js | 5 ++-- src/pages/FolderPage.js | 13 ++++++++++ src/pages/SharedPage.js | 13 ++++++++++ 14 files changed, 137 insertions(+), 67 deletions(-) create mode 100644 src/assets/kebab.svg create mode 100644 src/assets/link.svg create mode 100644 src/assets/star.svg delete mode 100644 src/components/App.js delete mode 100644 src/components/Folder.js create mode 100644 src/pages/FolderPage.js create mode 100644 src/pages/SharedPage.js diff --git a/src/Main.js b/src/Main.js index 8c4588620..e556b1a3a 100644 --- a/src/Main.js +++ b/src/Main.js @@ -1,11 +1,19 @@ import { BrowserRouter, Routes, Route } from "react-router-dom"; -import App from "./components/App"; -import Folder from "./components/Folder"; - +import SharedPage from "./pages/SharedPage"; +import FolderPage from "./pages/FolderPage"; +import Header from "./components/Header"; +import Footer from "./components/Footer"; function Main() { return ( - <App /> + <BrowserRouter> + <Header /> + <Routes> + <Route path="/shared" element={<SharedPage />}/> + <Route path="/folder" element={<FolderPage />}/> + </Routes> + <Footer /> + </BrowserRouter> ); } diff --git a/src/api.js b/src/api.js index 431c45ce3..c4b6e1bd4 100644 --- a/src/api.js +++ b/src/api.js @@ -13,3 +13,4 @@ export async function fetchLinks() { const result = await response.json(); return result; } + diff --git a/src/assets/kebab.svg b/src/assets/kebab.svg new file mode 100644 index 000000000..f68de3fc2 --- /dev/null +++ b/src/assets/kebab.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="21" height="17" viewBox="0 0 21 17" fill="none"> + <circle cx="3.5" cy="8.5" r="1.5" fill="#333236"/> + <circle cx="10.5" cy="8.5" r="1.5" fill="#333236"/> + <circle cx="17.5" cy="8.5" r="1.5" fill="#333236"/> +</svg> \ No newline at end of file diff --git a/src/assets/link.svg b/src/assets/link.svg new file mode 100644 index 000000000..728d6ba93 --- /dev/null +++ b/src/assets/link.svg @@ -0,0 +1,4 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="20" height="21" viewBox="0 0 20 21" fill="none"> + <path fill-rule="evenodd" clip-rule="evenodd" d="M10.6461 2.79223C11.5891 1.88144 12.8521 1.37747 14.1631 1.38886C15.4741 1.40025 16.7281 1.9261 17.6552 2.85314C18.5822 3.78018 19.108 5.03424 19.1194 6.34523C19.1308 7.65621 18.6269 8.91922 17.7161 9.86223L17.7059 9.87256L15.206 12.3725C14.6991 12.8795 14.0891 13.2717 13.4174 13.5222C12.7456 13.7728 12.0278 13.876 11.3127 13.8248C10.5975 13.7736 9.90176 13.5692 9.27257 13.2254C8.64338 12.8816 8.09547 12.4066 7.66602 11.8325C7.39035 11.4639 7.46563 10.9417 7.83417 10.666C8.20272 10.3903 8.72495 10.4656 9.00063 10.8342C9.28693 11.2169 9.6522 11.5336 10.0717 11.7628C10.4911 11.992 10.955 12.1282 11.4317 12.1624C11.9085 12.1965 12.387 12.1277 12.8349 11.9607C13.2827 11.7936 13.6894 11.5322 14.0273 11.1942L14.0274 11.1941L16.522 8.69945C17.1262 8.07131 17.4604 7.23142 17.4528 6.35971C17.4452 5.48572 17.0947 4.64968 16.4766 4.03165C15.8586 3.41362 15.0226 3.06306 14.1486 3.05546C13.2765 3.04789 12.4363 3.38239 11.808 3.98709L10.3792 5.40761C10.0528 5.7321 9.52517 5.73056 9.20068 5.40417C8.8762 5.07779 8.87774 4.55015 9.20412 4.22567L10.6375 2.80067L10.6461 2.79223Z" fill="#6D6AFE"/> + <path fill-rule="evenodd" clip-rule="evenodd" d="M6.58263 7.47744C7.25439 7.22685 7.97218 7.12367 8.68732 7.17488C9.40247 7.2261 10.0982 7.43052 10.7274 7.77428C11.3566 8.11803 11.9045 8.59309 12.334 9.16722C12.6096 9.53576 12.5344 10.058 12.1658 10.3337C11.7973 10.6093 11.275 10.5341 10.9994 10.1655C10.7131 9.78276 10.3478 9.46606 9.92833 9.23689C9.50887 9.00772 9.04503 8.87144 8.56827 8.83729C8.0915 8.80315 7.61298 8.87194 7.16514 9.03899C6.7173 9.20605 6.31062 9.46747 5.9727 9.80551L3.478 12.3002C2.8738 12.9284 2.53959 13.7683 2.54716 14.64C2.55476 15.514 2.90532 16.35 3.52335 16.968C4.14138 17.5861 4.97742 17.9366 5.85141 17.9442C6.72311 17.9518 7.563 17.6176 8.19114 17.0134L9.61075 15.5938C9.93618 15.2683 10.4638 15.2683 10.7893 15.5938C11.1147 15.9192 11.1147 16.4469 10.7893 16.7723L9.36426 18.1973L9.35393 18.2074C8.41092 19.1182 7.14791 19.6222 5.83692 19.6108C4.52594 19.5994 3.27188 19.0736 2.34484 18.1465C1.4178 17.2195 0.891952 15.9654 0.88056 14.6544C0.869168 13.3435 1.37314 12.0805 2.28393 11.1374L2.29408 11.1271L4.79397 8.62722C4.79394 8.62725 4.79401 8.62718 4.79397 8.62722C5.30084 8.1202 5.91092 7.728 6.58263 7.47744Z" fill="#6D6AFE"/> +</svg> \ No newline at end of file diff --git a/src/assets/star.svg b/src/assets/star.svg new file mode 100644 index 000000000..9d4544be4 --- /dev/null +++ b/src/assets/star.svg @@ -0,0 +1,10 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 30 30" fill="none"> + <g clip-path="url(#clip0_2_49678)"> + <path d="M14.9094 2.25867C14.9453 2.18174 15.0547 2.18174 15.0906 2.25867L18.5603 9.68965C18.7157 10.0225 19.027 10.2557 19.3901 10.3115L27.2014 11.5112C27.2817 11.5235 27.3146 11.6214 27.258 11.6797L21.5645 17.5456C21.3223 17.7951 21.2124 18.1446 21.2681 18.4879L22.6063 26.7349C22.6197 26.8174 22.5321 26.8789 22.459 26.8384L15.5343 22.9904L15.2914 23.4275L15.5343 22.9904C15.202 22.8058 14.7979 22.8058 14.4657 22.9904L14.7085 23.4275L14.4657 22.9904L7.54091 26.8384C7.46789 26.8789 7.38025 26.8174 7.39363 26.7349L8.73188 18.4879C8.78759 18.1446 8.67765 17.7951 8.43541 17.5456L2.74197 11.6797C2.68538 11.6214 2.71825 11.5235 2.79854 11.5112L10.6099 10.3115C10.9729 10.2557 11.2842 10.0225 11.4396 9.68965L14.9094 2.25867Z" fill="black" fill-opacity="0.2" stroke="white"/> + </g> + <defs> + <clipPath id="clip0_2_49678"> + <rect width="30" height="30" fill="white"/> + </clipPath> + </defs> +</svg> \ No newline at end of file diff --git a/src/components/AddLink.js b/src/components/AddLink.js index beab1aefe..a5be9254c 100644 --- a/src/components/AddLink.js +++ b/src/components/AddLink.js @@ -1,6 +1,11 @@ + + function AddLink() { return ( - <input>링크를 추가해 보세요</input> + <div className="AddLink"> + <input className="AddLinkInput" placeholder="링크를 추가해 보세요"/> + <button className="AddLinkButton">추가하기</button> + </div> ); } diff --git a/src/components/App.js b/src/components/App.js deleted file mode 100644 index 83b97559d..000000000 --- a/src/components/App.js +++ /dev/null @@ -1,17 +0,0 @@ -import Header from "./Header"; -import Search from "./Search"; -import Footer from "./Footer"; -import Title from "./Title"; - -function App() { - return ( - <div> - <Header /> - <Title /> - <Search /> - <Footer /> - </div> - ); -} - -export default App; diff --git a/src/components/Folder.js b/src/components/Folder.js deleted file mode 100644 index b1c49bc72..000000000 --- a/src/components/Folder.js +++ /dev/null @@ -1,17 +0,0 @@ -import Header from "./Header"; -import AddLink from "./AddLink"; -import Footer from "./Footer"; -import Title from "./Title"; - -function Folder() { - return ( - <div> - <Header /> - <Title /> - <AddLink /> - <Footer /> - </div> - ); -} - -export default Folder; diff --git a/src/components/Header.js b/src/components/Header.js index 8674061e8..9ad6fd2ab 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -1,51 +1,45 @@ import logoImg from "../assets/logo.svg"; import "./Style.css"; import { useEffect, useState } from "react"; -import { fetchProfile } from "../api"; +// import { getProfile } from "../api"; function Header() { const [profile, setProfile] = useState(null); - - const getProfile = async () => { + const fetchProfile = async () => { try { - const response = await fetchProfile(); - setProfile(response.data); + const response = await fetch('https://bootcamp-api.codeit.kr/api/sample/user'); + const data = await response.json(); + setProfile(data); } catch (error) { - console.error("프로필 데이터를 불러오는 중 에러 발생:", error); + console.error('프로필 데이터를 불러오는 중 에러 발생:', error); } }; useEffect(() => { - getProfile(); - }, []); + fetchProfile(); + },[]); return ( + <header> <nav className="NavBar"> <a href="/"> <img src={logoImg} alt="홈으로 연결된 Linkbrary 로고" /> </a> <div> - {profile ? ( - <div> - <p className="Profile"> - <img - className="ProfileImg" - src={profile.profileImageSource} - alt="프로필 이미지" - /> - {profile.email} - </p> - </div> - ) : ( - <a href="/"> - <span className="signin">로그인</span> - </a> - )} + {profile ? ( + <div> + <p className="Profile"><img className="ProfileImg" src={profile.profileImageSource} alt="프로필 이미지" />{profile.email}</p> </div> + ) : ( + <a href="/"> + <span className="signin">로그인</span> + </a> + )} + </div> </nav> </header> ); } -export default Header; +export default Header; \ No newline at end of file diff --git a/src/components/Search.js b/src/components/Search.js index b4e0eeeab..bce6b96d2 100644 --- a/src/components/Search.js +++ b/src/components/Search.js @@ -26,7 +26,7 @@ function Search() { return ( <main className="MainContainer"> <div className="Finder"> - <input className="Link" type="text" value="링크를 검색해보세요." /> + <input className="Link" type="text" placeholder="링크를 검색해보세요." /> <img className="SearchIcon" src={search} alt="돋보기 아이콘" /> </div> <div className="CardDataContainer"> diff --git a/src/components/Style.css b/src/components/Style.css index e03b14aa1..1daa18c66 100644 --- a/src/components/Style.css +++ b/src/components/Style.css @@ -57,6 +57,56 @@ nav { background-color: #edf7ff; } +.AddLink { + width: 100%; + max-width: auto; + height: 244px; + background-color: #edf7ff; + display: flex; + padding: 60px 320px 90px 320px; + align-items: center; + justify-content: center; + gap: 8px; + position: relative; +} + +.AddLinkInput { + display: flex; + width: 800px; + padding: 16px 20px; + flex-direction: column; + align-items: flex-start; + gap: 8px; + border-radius: 15px; + border: 1px solid var(--linkbrary-primary-color, #6D6AFE); + background: var(--linkbrary-white, #FFF); +} + +.AddLinkInput::placeholder { + background: url('../assets/link.svg') no-repeat left; + background-size: 20px; + padding-left: 25px; + color: var(--linkbrary-gray-60, #9FA6B2); + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 24px; /* 150% */ +} + +.AddLinkButton { + width: 90px; + padding: 10px 16px; + border-radius: 8px; + color: var(--grey-light, #F5F5F5); + font-size: 12px; + font-weight: 600; + line-height: normal; + border: none; + background: var(--gra-purpleblue-to-skyblue, linear-gradient(91deg, #6D6AFE 0.12%, #6AE3FE 101.84%)); + cursor: pointer; + position: absolute; +} + .UserProfileImg { width: 60px; height: 60px; diff --git a/src/components/Title.js b/src/components/Title.js index f908c1d71..9fe5a86c6 100644 --- a/src/components/Title.js +++ b/src/components/Title.js @@ -7,8 +7,9 @@ function Title() { const [folderData, setFolderData] = useState(); const fetchUserProfile = async () => { try { - const response = await fetchLinks(); - setFolderData(response.data); + const response = fetch("https://bootcamp-api.codeit.kr/api/sample/folder"); + const data = await (await response).json(); + setFolderData(data); } catch (error) { console.error('프로필 데이터를 불러오는 중 에러 발생:', error); } diff --git a/src/pages/FolderPage.js b/src/pages/FolderPage.js new file mode 100644 index 000000000..b60ac3ca8 --- /dev/null +++ b/src/pages/FolderPage.js @@ -0,0 +1,13 @@ +import AddLink from "../components/AddLink"; +import Search from "../components/Search"; +import Title from "../components/Title"; +function FolderPage() { + return ( + <> + <AddLink /> + <Search /> + </> + ); +} + +export default FolderPage; diff --git a/src/pages/SharedPage.js b/src/pages/SharedPage.js new file mode 100644 index 000000000..1bc3fe580 --- /dev/null +++ b/src/pages/SharedPage.js @@ -0,0 +1,13 @@ +import Header from "../components/Header"; +import Search from "../components/Search"; +import Title from "../components/Title"; +function SharedPage() { + return ( + <> + <Title /> + <Search /> + </> + ); +} + +export default SharedPage; From 511fc4a75902c93d50a848c9be21d06169522ffe Mon Sep 17 00:00:00 2001 From: JunCastle <juncastle97@gmail.com> Date: Thu, 7 Dec 2023 14:23:03 +0900 Subject: [PATCH 05/13] =?UTF-8?q?Fix:=20AddLink=20Button=EC=9D=84=20input?= =?UTF-8?q?=20=EC=98=A4=EB=A5=B8=EC=AA=BD=EC=97=90=20=EA=B3=A0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AddLink.js | 6 ++++-- src/components/Style.css | 16 ++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/components/AddLink.js b/src/components/AddLink.js index a5be9254c..6889c0844 100644 --- a/src/components/AddLink.js +++ b/src/components/AddLink.js @@ -3,8 +3,10 @@ function AddLink() { return ( <div className="AddLink"> - <input className="AddLinkInput" placeholder="링크를 추가해 보세요"/> - <button className="AddLinkButton">추가하기</button> + <div className="InputContainer"> + <input className="AddLinkInput" placeholder="링크를 추가해 보세요"/> + <button className="AddLinkButton">추가하기</button> + </div> </div> ); } diff --git a/src/components/Style.css b/src/components/Style.css index 1daa18c66..12ea89f63 100644 --- a/src/components/Style.css +++ b/src/components/Style.css @@ -58,25 +58,24 @@ nav { } .AddLink { - width: 100%; - max-width: auto; height: 244px; background-color: #edf7ff; display: flex; padding: 60px 320px 90px 320px; align-items: center; justify-content: center; - gap: 8px; +} + +.InputContainer { position: relative; + display: flex; + align-items: center; + gap: 8px; } .AddLinkInput { - display: flex; width: 800px; padding: 16px 20px; - flex-direction: column; - align-items: flex-start; - gap: 8px; border-radius: 15px; border: 1px solid var(--linkbrary-primary-color, #6D6AFE); background: var(--linkbrary-white, #FFF); @@ -90,7 +89,7 @@ nav { font-size: 16px; font-style: normal; font-weight: 400; - line-height: 24px; /* 150% */ + line-height: 24px; } .AddLinkButton { @@ -105,6 +104,7 @@ nav { background: var(--gra-purpleblue-to-skyblue, linear-gradient(91deg, #6D6AFE 0.12%, #6AE3FE 101.84%)); cursor: pointer; position: absolute; + right: 10px; } .UserProfileImg { From 0cdeec7d930314e39800721e7b5187d1fbf96a14 Mon Sep 17 00:00:00 2001 From: JunCastle <juncastle97@gmail.com> Date: Thu, 7 Dec 2023 17:18:06 +0900 Subject: [PATCH 06/13] =?UTF-8?q?Fix:=20api=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Main.js | 2 - src/api.js | 63 ++++++++++++++++--- .../{Header.js => Header-folder.js} | 19 +----- src/components/Header-shared.js | 28 +++++++++ src/components/Search.js | 22 +------ src/components/Title.js | 27 ++------ src/pages/FolderPage.js | 5 +- src/pages/SharedPage.js | 45 ++++++++++++- 8 files changed, 133 insertions(+), 78 deletions(-) rename src/components/{Header.js => Header-folder.js} (53%) create mode 100644 src/components/Header-shared.js diff --git a/src/Main.js b/src/Main.js index e556b1a3a..fe9a6fb1e 100644 --- a/src/Main.js +++ b/src/Main.js @@ -1,13 +1,11 @@ import { BrowserRouter, Routes, Route } from "react-router-dom"; import SharedPage from "./pages/SharedPage"; import FolderPage from "./pages/FolderPage"; -import Header from "./components/Header"; import Footer from "./components/Footer"; function Main() { return ( <BrowserRouter> - <Header /> <Routes> <Route path="/shared" element={<SharedPage />}/> <Route path="/folder" element={<FolderPage />}/> diff --git a/src/api.js b/src/api.js index c4b6e1bd4..14e301b10 100644 --- a/src/api.js +++ b/src/api.js @@ -1,16 +1,59 @@ export async function fetchProfile() { - const response = await fetch( - "https://bootcamp-api.codeit.kr/api/sample/user" - ); - const result = await response.json(); - return result; + try { + const response = await fetch( + "https://bootcamp-api.codeit.kr/api/sample/user" + ); + const body = await response.json(); + return body; + } catch (err) { + console.log(err.message); + } } export async function fetchLinks() { - const response = await fetch( - "https://bootcamp-api.codeit.kr/api/sample/folder" - ); - const result = await response.json(); - return result; + try { + const response = await fetch( + "https://bootcamp-api.codeit.kr/api/sample/folder" + ); + const body = await response.json(); + return body; + } catch (err) { + console.log(err.message); + } } +export async function getUser() { + try { + const response = await fetch( + "https://bootcamp-api.codeit.kr/api/users/1" + ) + const body = await response.json(); + return body; + } catch (err) { + console.log(err.message); + } +} + +export async function getUserFolder() { + try { + const response = await fetch( + "https://bootcamp-api.codeit.kr/api/users/1/folders" + ) + const body = await response.json(); + return body; + } catch (err) { + console.log(err.message); + } +} + +export async function getUserLink() { + try { + const response = await fetch( + "https://bootcamp-api.codeit.kr/api/users/1/links" + ) + const body = await response.json(); + return body; + } catch (err) { + console.log(err.message); + } +} \ No newline at end of file diff --git a/src/components/Header.js b/src/components/Header-folder.js similarity index 53% rename from src/components/Header.js rename to src/components/Header-folder.js index 9ad6fd2ab..4bfa2fa07 100644 --- a/src/components/Header.js +++ b/src/components/Header-folder.js @@ -1,24 +1,7 @@ import logoImg from "../assets/logo.svg"; import "./Style.css"; -import { useEffect, useState } from "react"; -// import { getProfile } from "../api"; - -function Header() { - const [profile, setProfile] = useState(null); - const fetchProfile = async () => { - try { - const response = await fetch('https://bootcamp-api.codeit.kr/api/sample/user'); - const data = await response.json(); - setProfile(data); - } catch (error) { - console.error('프로필 데이터를 불러오는 중 에러 발생:', error); - } - }; - - useEffect(() => { - fetchProfile(); - },[]); +function Header({profile}) { return ( <header> diff --git a/src/components/Header-shared.js b/src/components/Header-shared.js new file mode 100644 index 000000000..4bfa2fa07 --- /dev/null +++ b/src/components/Header-shared.js @@ -0,0 +1,28 @@ +import logoImg from "../assets/logo.svg"; +import "./Style.css"; + +function Header({profile}) { + return ( + + <header> + <nav className="NavBar"> + <a href="/"> + <img src={logoImg} alt="홈으로 연결된 Linkbrary 로고" /> + </a> + <div> + {profile ? ( + <div> + <p className="Profile"><img className="ProfileImg" src={profile.profileImageSource} alt="프로필 이미지" />{profile.email}</p> + </div> + ) : ( + <a href="/"> + <span className="signin">로그인</span> + </a> + )} + </div> + </nav> + </header> + ); +} + +export default Header; \ No newline at end of file diff --git a/src/components/Search.js b/src/components/Search.js index bce6b96d2..271ea0849 100644 --- a/src/components/Search.js +++ b/src/components/Search.js @@ -1,28 +1,8 @@ import "./Style.css"; import Card from "./Card"; import search from "../assets/search.svg"; -import { useState, useEffect } from "react"; - -function Search() { - const [linksData, setLinksData] = useState(); - - const fetchLinks = async () => { - try { - const response = await fetch( - "https://bootcamp-api.codeit.kr/api/sample/folder" - ); - const data = await response.json(); - const links = data.folder.links; - setLinksData(links); - } catch (error) { - console.error("링크 데이터를 불러오는 중 에러 발생:", error); - } - }; - - useEffect(() => { - fetchLinks(); - }, []); +function Search({linksData}) { return ( <main className="MainContainer"> <div className="Finder"> diff --git a/src/components/Title.js b/src/components/Title.js index 9fe5a86c6..c917ef150 100644 --- a/src/components/Title.js +++ b/src/components/Title.js @@ -1,32 +1,13 @@ import "./Style.css"; -import { useState, useEffect } from "react"; -import { fetchLinks } from "../api"; - -function Title() { - - const [folderData, setFolderData] = useState(); - const fetchUserProfile = async () => { - try { - const response = fetch("https://bootcamp-api.codeit.kr/api/sample/folder"); - const data = await (await response).json(); - setFolderData(data); - } catch (error) { - console.error('프로필 데이터를 불러오는 중 에러 발생:', error); - } - }; - - useEffect(() => { - fetchUserProfile(); - },[]); - +function Title({folderData}) { return ( <div className="Title"> {folderData && ( <div> - <img className="UserProfileImg" src={folderData.folder.owner.profileImageSource} alt="프로필 이미지" /> - <p className="UserName">{folderData.folder.owner.name}</p> - <p className="BookMark">{folderData.folder.name}</p> + <img className="UserProfileImg" src={folderData.owner.profileImageSource} alt="프로필 이미지" /> + <p className="UserName">{folderData.owner.name}</p> + <p className="BookMark">{folderData.name}</p> </div> )} </div> diff --git a/src/pages/FolderPage.js b/src/pages/FolderPage.js index b60ac3ca8..11c3e0da8 100644 --- a/src/pages/FolderPage.js +++ b/src/pages/FolderPage.js @@ -1,9 +1,12 @@ import AddLink from "../components/AddLink"; import Search from "../components/Search"; -import Title from "../components/Title"; +import Header from "../components/Header-folder"; + + function FolderPage() { return ( <> + <Header /> <AddLink /> <Search /> </> diff --git a/src/pages/SharedPage.js b/src/pages/SharedPage.js index 1bc3fe580..9950b2363 100644 --- a/src/pages/SharedPage.js +++ b/src/pages/SharedPage.js @@ -1,11 +1,50 @@ -import Header from "../components/Header"; +import Header from "../components/Header-shared"; import Search from "../components/Search"; import Title from "../components/Title"; +import { useEffect, useState } from "react"; +import { fetchProfile, fetchLinks } from "../api"; + + function SharedPage() { + const [userData, setUserData] = useState(); + const [profile, setProfile] = useState(null); + const [cardData, setCardData] = useState([]); + + const getProfile = async () => { + const { email, profileImageSource } = await fetchProfile(); + + setUserData({ + ...userData, + email, + profileImageSource, + }); + }; + + const getUserInfo = async () => { + const { folder } = await fetchLinks(); + const { name, owner, links } = folder; + + setProfile({ + ...profile, + name, + owner, + }); + + setCardData(links); + }; + + + useEffect(() => { + getProfile(); + getUserInfo(); + }, []); + + return ( <> - <Title /> - <Search /> + <Header profile={userData} /> + <Title folderData={profile} /> + <Search linksData={cardData} /> </> ); } From 4ce3ee93a447130c19c21036348ae2e4319b736d Mon Sep 17 00:00:00 2001 From: JunCastle <juncastle97@gmail.com> Date: Thu, 7 Dec 2023 17:31:44 +0900 Subject: [PATCH 07/13] =?UTF-8?q?Refactor:=20Search=20&=20CardInput=20?= =?UTF-8?q?=EC=BB=A8=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/CardInput.js | 15 +++++++++++++++ src/components/Search.js | 23 +++++++++++------------ src/pages/FolderPage.js | 5 +++-- src/pages/SharedPage.js | 11 +++++------ 4 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 src/components/CardInput.js diff --git a/src/components/CardInput.js b/src/components/CardInput.js new file mode 100644 index 000000000..8bd25d76e --- /dev/null +++ b/src/components/CardInput.js @@ -0,0 +1,15 @@ +import "./Style.css"; +import Card from "./Card"; +import search from "../assets/search.svg"; + +function CardInput({ linksData }) { + return ( + <div className="MainContainer"> + <div className="CardDataContainer"> + <Card data={linksData} /> + </div> + </div> + ); +} + +export default CardInput; diff --git a/src/components/Search.js b/src/components/Search.js index 271ea0849..dbb04604f 100644 --- a/src/components/Search.js +++ b/src/components/Search.js @@ -1,19 +1,18 @@ -import "./Style.css"; -import Card from "./Card"; import search from "../assets/search.svg"; -function Search({linksData}) { +function Search() { return ( - <main className="MainContainer"> + <div className="MainContainer"> <div className="Finder"> - <input className="Link" type="text" placeholder="링크를 검색해보세요." /> - <img className="SearchIcon" src={search} alt="돋보기 아이콘" /> - </div> - <div className="CardDataContainer"> - <Card data={linksData} /> - </div> - </main> + <input + className="Link" + type="text" + placeholder="링크를 검색해보세요." + /> + <img className="SearchIcon" src={search} alt="돋보기 아이콘" /> + </div> + </div> ); } -export default Search; +export default Search; \ No newline at end of file diff --git a/src/pages/FolderPage.js b/src/pages/FolderPage.js index 11c3e0da8..09d22e665 100644 --- a/src/pages/FolderPage.js +++ b/src/pages/FolderPage.js @@ -1,7 +1,7 @@ +import Header from "../components/Header-folder"; import AddLink from "../components/AddLink"; +import CardInput from "../components/CardInput"; import Search from "../components/Search"; -import Header from "../components/Header-folder"; - function FolderPage() { return ( @@ -9,6 +9,7 @@ function FolderPage() { <Header /> <AddLink /> <Search /> + <CardInput /> </> ); } diff --git a/src/pages/SharedPage.js b/src/pages/SharedPage.js index 9950b2363..82c5007e7 100644 --- a/src/pages/SharedPage.js +++ b/src/pages/SharedPage.js @@ -1,14 +1,14 @@ import Header from "../components/Header-shared"; -import Search from "../components/Search"; import Title from "../components/Title"; +import CardInput from "../components/CardInput"; +import Search from "../components/Search"; import { useEffect, useState } from "react"; import { fetchProfile, fetchLinks } from "../api"; - function SharedPage() { const [userData, setUserData] = useState(); const [profile, setProfile] = useState(null); - const [cardData, setCardData] = useState([]); + const [cardData, setCardData] = useState([]); const getProfile = async () => { const { email, profileImageSource } = await fetchProfile(); @@ -33,18 +33,17 @@ function SharedPage() { setCardData(links); }; - useEffect(() => { getProfile(); getUserInfo(); }, []); - return ( <> <Header profile={userData} /> <Title folderData={profile} /> - <Search linksData={cardData} /> + <Search /> + <CardInput linksData={cardData} /> </> ); } From 58a7085a5b5015a3f5ea6cd5050fcc81e7246b6f Mon Sep 17 00:00:00 2001 From: JunCastle <juncastle97@gmail.com> Date: Thu, 7 Dec 2023 18:01:10 +0900 Subject: [PATCH 08/13] =?UTF-8?q?Feat:=20FolderPage=20api=EB=A1=9C=20profi?= =?UTF-8?q?le=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Header-folder.js | 2 +- src/pages/FolderPage.js | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/components/Header-folder.js b/src/components/Header-folder.js index 4bfa2fa07..923f1e5d7 100644 --- a/src/components/Header-folder.js +++ b/src/components/Header-folder.js @@ -12,7 +12,7 @@ function Header({profile}) { <div> {profile ? ( <div> - <p className="Profile"><img className="ProfileImg" src={profile.profileImageSource} alt="프로필 이미지" />{profile.email}</p> + <p className="Profile"><img className="ProfileImg" src={profile.image_source} alt="프로필 이미지" />{profile.email}</p> </div> ) : ( <a href="/"> diff --git a/src/pages/FolderPage.js b/src/pages/FolderPage.js index 09d22e665..3a2d2a10f 100644 --- a/src/pages/FolderPage.js +++ b/src/pages/FolderPage.js @@ -2,11 +2,30 @@ import Header from "../components/Header-folder"; import AddLink from "../components/AddLink"; import CardInput from "../components/CardInput"; import Search from "../components/Search"; +import { useEffect, useState } from "react"; +import { getUser } from "../api"; function FolderPage() { + const [userData, setUserData] = useState(); + + const getProfile = async () => { + const { data } = await getUser(); + const { email, image_source } = data[0]; + + setUserData({ + ...userData, + email, + image_source, + }); + }; + + useEffect(() => { + getProfile(); + }, []); + return ( <> - <Header /> + <Header profile={userData} /> <AddLink /> <Search /> <CardInput /> From d57989bf575972d7da6262f6fd951434b71e2890 Mon Sep 17 00:00:00 2001 From: JunCastle <juncastle97@gmail.com> Date: Thu, 7 Dec 2023 18:37:39 +0900 Subject: [PATCH 09/13] =?UTF-8?q?Feat:=20Card=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EB=A5=BC=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EB=B3=84=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/noneimg.svg | 13 +++++++ src/components/Card-folder.js | 28 +++++++++++++++ src/components/Card-shared.js | 28 +++++++++++++++ src/components/Card.js | 19 ----------- .../{CardInput.js => CardInput-folder.js} | 3 +- src/components/CardInput-shared.js | 14 ++++++++ src/pages/FolderPage.js | 16 ++++++--- src/pages/SharedPage.js | 2 +- src/time.js | 34 +++++++++++++++++++ 9 files changed, 131 insertions(+), 26 deletions(-) create mode 100644 src/assets/noneimg.svg create mode 100644 src/components/Card-folder.js create mode 100644 src/components/Card-shared.js delete mode 100644 src/components/Card.js rename src/components/{CardInput.js => CardInput-folder.js} (77%) create mode 100644 src/components/CardInput-shared.js create mode 100644 src/time.js diff --git a/src/assets/noneimg.svg b/src/assets/noneimg.svg new file mode 100644 index 000000000..ccedf5a0f --- /dev/null +++ b/src/assets/noneimg.svg @@ -0,0 +1,13 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="133" height="24" viewBox="0 0 133 24" fill="none"> + <g opacity="0.2"> + <path d="M5.20583 15.7049V0.792232H0V20.2718H14.9638V15.7049H5.20583Z" fill="#6D6AFE"/> + <path d="M21.6801 20.2718V5.12621H16.4743V20.2718H21.6801ZM21.6801 3.96117V0H16.4743V3.96117H21.6801Z" fill="#6D6AFE"/> + <path d="M33.1713 4.66019C31.117 4.66019 29.5062 5.42913 28.409 6.71068V5.12621H23.2032V20.2718H28.409V13.4913C28.4557 10.5786 29.7397 9.34369 31.8407 9.34369C33.6382 9.34369 34.3385 10.2524 34.3385 12.4194V20.2718H39.5444V11.5107C39.5444 6.92039 37.8169 4.66019 33.1713 4.66019Z" fill="#6D6AFE"/> + <path d="M46.0405 10.0893V0H40.8347V20.2718H46.0405V16.7068L48.2116 14.167L50.7328 20.2718H56.4755L53.184 12.233H49.869L56.0087 5.12621H50.3359L46.0405 10.0893Z" fill="#6D6AFE"/> + <path d="M67.0849 20.7379C70.2364 20.7379 74.1116 18.9437 74.1116 12.699C74.1116 6.45437 70.2364 4.66019 67.0849 4.66019C65.3341 4.66019 63.77 5.17281 62.5094 6.03495V0H57.3035V20.2718H62.5094V19.3631C63.77 20.2485 65.3341 20.7379 67.0849 20.7379ZM65.7076 16.1942C63.91 16.1942 62.5094 15.2854 62.5094 12.699V12.5126C62.5794 10.0893 63.9567 9.20388 65.7076 9.20388C67.7152 9.20388 68.9058 10.2524 68.9058 12.699C68.9058 15.1689 67.7152 16.1942 65.7076 16.1942Z" fill="#6D6AFE"/> + <path d="M74.935 20.2718H80.1409V13.9573C80.1876 11.0214 81.5182 9.32039 86.1638 9.32039V4.66019C83.3624 4.66019 81.3781 5.63883 80.1409 7.1068V5.12621H74.935V20.2718Z" fill="#6D6AFE"/> + <path d="M93.541 20.7379C95.2685 20.7379 96.8559 20.2485 98.1165 19.3631V20.2718H103.322V5.12621H98.1165V6.03495C96.8559 5.17281 95.2685 4.66019 93.541 4.66019C90.3895 4.66019 86.5143 6.45437 86.5143 12.699C86.5143 18.9437 90.3895 20.7379 93.541 20.7379ZM94.9183 16.1942C92.9107 16.1942 91.7201 15.1689 91.7201 12.699C91.7201 10.2524 92.9107 9.20388 94.9183 9.20388C96.7159 9.20388 98.1165 10.1359 98.1165 12.699C98.1165 15.2854 96.7159 16.1942 94.9183 16.1942Z" fill="#6D6AFE"/> + <path d="M104.613 20.2718H109.819V13.9573C109.865 11.0214 111.196 9.32039 115.841 9.32039V4.66019C113.04 4.66019 111.056 5.63883 109.819 7.1068V5.12621H104.613V20.2718Z" fill="#6D6AFE"/> + <path d="M127.794 5.12621V11.7204C127.234 12.3495 126.23 12.6058 125.063 12.6058C122.588 12.6058 121.865 11.8369 121.865 10.4155V5.12621H116.659V10.7883C116.659 14.9359 119.6 17.1728 123.686 17.1728C125.203 17.1728 126.604 16.8466 127.794 16.2874V16.8466C127.794 18.9204 127 19.666 124.946 19.666C123.242 19.666 122.425 19.1534 122.191 17.965H116.962C117.383 22.2524 119.694 24 124.946 24C130.666 24 133 21.9029 133 16.4505V5.12621H127.794Z" fill="#6D6AFE"/> + </g> +</svg> \ No newline at end of file diff --git a/src/components/Card-folder.js b/src/components/Card-folder.js new file mode 100644 index 000000000..b4d3bffad --- /dev/null +++ b/src/components/Card-folder.js @@ -0,0 +1,28 @@ +import noneImg from '../assets/noneimg.svg' +import { timeAgo } from '../time'; + +function formatDate(value) { + const date = new Date(value); + return `${date.getFullYear()}. ${date.getMonth() + 1}. ${date.getDate()}`; +} + +function Card({ data }) { + return ( + <div className="CardGrid"> + {data && data.map((data) => + <div className="Contents"> + <div className="CardContainer"> + <img className="Card" src={data.image_source || noneImg} key={data.id} alt="이미지 미리보기"/> + </div> + <div className="CardInfoContainer"> + <p className="CreatedAt">{timeAgo(data.created_at)}</p> + <p className="Description">{data.description || "no description"}</p> + <p className="makeDate">{formatDate(data.created_at)}</p> + </div> + </div> + )} + </div> + ); +} + +export default Card; diff --git a/src/components/Card-shared.js b/src/components/Card-shared.js new file mode 100644 index 000000000..5b3d00e05 --- /dev/null +++ b/src/components/Card-shared.js @@ -0,0 +1,28 @@ +import noneImg from '../assets/noneimg.svg' +import { timeAgo } from '../time'; + +function formatDate(value) { + const date = new Date(value); + return `${date.getFullYear()}. ${date.getMonth() + 1}. ${date.getDate()}`; +} + +function Card({ data }) { + return ( + <div className="CardGrid"> + {data && data.map((data) => + <div className="Contents"> + <div className="CardContainer"> + <img className="Card" src={data.imageSource || noneImg} key={data.id} alt="이미지 미리보기"/> + </div> + <div className="CardInfoContainer"> + <p className="CreatedAt">{timeAgo(data.createdAt)}</p> + <p className="Description">{data.description || "no description"}</p> + <p className="makeDate">{formatDate(data.createdAt)}</p> + </div> + </div> + )} + </div> + ); +} + +export default Card; diff --git a/src/components/Card.js b/src/components/Card.js deleted file mode 100644 index 1be20ab9d..000000000 --- a/src/components/Card.js +++ /dev/null @@ -1,19 +0,0 @@ -function Card({ data }) { - return ( - <div className="CardGrid"> - {data && data.map((data) => - <div className="Contents"> - <div className="CardContainer"> - <img className="Card" src={data.imageSource} key={data.id} alt="이미지 미리보기"/> - </div> - <div className="CardInfoContainer"> - <p className="Description">{data.description}</p> - <p className="CreatedAt">{data.createdAt}</p> - </div> - </div> - )} - </div> - ); -} - -export default Card; diff --git a/src/components/CardInput.js b/src/components/CardInput-folder.js similarity index 77% rename from src/components/CardInput.js rename to src/components/CardInput-folder.js index 8bd25d76e..26ca91fdf 100644 --- a/src/components/CardInput.js +++ b/src/components/CardInput-folder.js @@ -1,6 +1,5 @@ import "./Style.css"; -import Card from "./Card"; -import search from "../assets/search.svg"; +import Card from "./Card-folder"; function CardInput({ linksData }) { return ( diff --git a/src/components/CardInput-shared.js b/src/components/CardInput-shared.js new file mode 100644 index 000000000..28782e451 --- /dev/null +++ b/src/components/CardInput-shared.js @@ -0,0 +1,14 @@ +import "./Style.css"; +import Card from "./Card-shared"; + +function CardInput({ linksData }) { + return ( + <div className="MainContainer"> + <div className="CardDataContainer"> + <Card data={linksData} /> + </div> + </div> + ); +} + +export default CardInput; diff --git a/src/pages/FolderPage.js b/src/pages/FolderPage.js index 3a2d2a10f..1bbe041fe 100644 --- a/src/pages/FolderPage.js +++ b/src/pages/FolderPage.js @@ -1,16 +1,17 @@ import Header from "../components/Header-folder"; import AddLink from "../components/AddLink"; -import CardInput from "../components/CardInput"; +import CardInput from "../components/CardInput-folder"; import Search from "../components/Search"; import { useEffect, useState } from "react"; -import { getUser } from "../api"; +import { getUser, getUserLink } from "../api"; function FolderPage() { const [userData, setUserData] = useState(); + const [cardData, setCardData] = useState(); const getProfile = async () => { const { data } = await getUser(); - const { email, image_source } = data[0]; + const { email, image_source } = data[0]; // 인덱스로 접근하는 것 말고 다른 방법이 있을까요? setUserData({ ...userData, @@ -19,8 +20,15 @@ function FolderPage() { }); }; + const getCardData = async () => { + const { data } = await getUserLink(); + + setCardData(data); + } + useEffect(() => { getProfile(); + getCardData(); }, []); return ( @@ -28,7 +36,7 @@ function FolderPage() { <Header profile={userData} /> <AddLink /> <Search /> - <CardInput /> + <CardInput linksData={cardData}/> </> ); } diff --git a/src/pages/SharedPage.js b/src/pages/SharedPage.js index 82c5007e7..e5d758cf5 100644 --- a/src/pages/SharedPage.js +++ b/src/pages/SharedPage.js @@ -1,6 +1,6 @@ import Header from "../components/Header-shared"; import Title from "../components/Title"; -import CardInput from "../components/CardInput"; +import CardInput from "../components/CardInput-shared"; import Search from "../components/Search"; import { useEffect, useState } from "react"; import { fetchProfile, fetchLinks } from "../api"; diff --git a/src/time.js b/src/time.js new file mode 100644 index 000000000..bc66cb298 --- /dev/null +++ b/src/time.js @@ -0,0 +1,34 @@ +export function timeAgo(time) { + const toDay = new Date(); + const targetDate = new Date(time); + + const diff = toDay - targetDate; + const seconds = Math.floor(diff / 1000); + const minutes = Math.floor(seconds / 60); + const hours = Math.floor(minutes / 60); + const days = Math.floor(hours / 24); + const months = Math.floor(days / 30); + const years = Math.floor(months / 12); + + if (seconds < 60) { + return "1 minute ago"; + } else if (minutes <= 59) { + return `${minutes} minutes ago`; + } else if (hours <= 1) { + return "1 hour ago"; + } else if (hours <= 23) { + return `${hours} hours ago`; + } else if (days <= 1) { + return "1 day ago"; + } else if (days <= 30) { + return `${days} days ago`; + } else if (months <= 1) { + return "1 month ago"; + } else if (months <= 11) { + return `${months} months ago`; + } else if (years <= 1) { + return "1 year ago"; + } else { + return `${years} years ago`; + } +} \ No newline at end of file From 1e4649ae0302f3dc94600853a7f62fe2cf48278d Mon Sep 17 00:00:00 2001 From: JunCastle <juncastle97@gmail.com> Date: Thu, 7 Dec 2023 20:45:20 +0900 Subject: [PATCH 10/13] =?UTF-8?q?Feat:=20=EC=BC=80=EB=B0=A5=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC,=20=EB=B3=84=20=EB=B2=84=ED=8A=BC=20=EB=84=A3?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Card-folder.js | 38 +++++++++++++++--------- src/components/Card-shared.js | 38 +++++++++++++++--------- src/components/FolderList.js | 25 ++++++++++++++++ src/components/Style.css | 56 +++++++++++++++++++++++++++++++++++ src/pages/FolderPage.js | 12 +++++++- 5 files changed, 140 insertions(+), 29 deletions(-) create mode 100644 src/components/FolderList.js diff --git a/src/components/Card-folder.js b/src/components/Card-folder.js index b4d3bffad..c17ab027b 100644 --- a/src/components/Card-folder.js +++ b/src/components/Card-folder.js @@ -1,5 +1,5 @@ -import noneImg from '../assets/noneimg.svg' -import { timeAgo } from '../time'; +import noneImg from "../assets/noneimg.svg"; +import { timeAgo } from "../time"; function formatDate(value) { const date = new Date(value); @@ -9,18 +9,28 @@ function formatDate(value) { function Card({ data }) { return ( <div className="CardGrid"> - {data && data.map((data) => - <div className="Contents"> - <div className="CardContainer"> - <img className="Card" src={data.image_source || noneImg} key={data.id} alt="이미지 미리보기"/> - </div> - <div className="CardInfoContainer"> - <p className="CreatedAt">{timeAgo(data.created_at)}</p> - <p className="Description">{data.description || "no description"}</p> - <p className="makeDate">{formatDate(data.created_at)}</p> - </div> - </div> - )} + {data && + data.map((data) => ( + <div className="Contents"> + <div className="CardContainer"> + <button className="StarImg"></button> + <img + className="Card" + src={data.image_source || noneImg} + key={data.id} + alt="이미지 미리보기" + /> + </div> + <div className="CardInfoContainer"> + <button className="KebabImg"></button> + <p className="CreatedAt">{timeAgo(data.created_at)}</p> + <p className="Description"> + {data.description || "no description"} + </p> + <p className="makeDate">{formatDate(data.created_at)}</p> + </div> + </div> + ))} </div> ); } diff --git a/src/components/Card-shared.js b/src/components/Card-shared.js index 5b3d00e05..ff0607014 100644 --- a/src/components/Card-shared.js +++ b/src/components/Card-shared.js @@ -1,5 +1,5 @@ -import noneImg from '../assets/noneimg.svg' -import { timeAgo } from '../time'; +import noneImg from "../assets/noneimg.svg"; +import { timeAgo } from "../time"; function formatDate(value) { const date = new Date(value); @@ -9,18 +9,28 @@ function formatDate(value) { function Card({ data }) { return ( <div className="CardGrid"> - {data && data.map((data) => - <div className="Contents"> - <div className="CardContainer"> - <img className="Card" src={data.imageSource || noneImg} key={data.id} alt="이미지 미리보기"/> - </div> - <div className="CardInfoContainer"> - <p className="CreatedAt">{timeAgo(data.createdAt)}</p> - <p className="Description">{data.description || "no description"}</p> - <p className="makeDate">{formatDate(data.createdAt)}</p> - </div> - </div> - )} + {data && + data.map((data) => ( + <div className="Contents"> + <div className="CardContainer"> + <button className="StarImg"></button> + <img + className="Card" + src={data.imageSource || noneImg} + key={data.id} + alt="이미지 미리보기" + /> + </div> + <div className="CardInfoContainer"> + <button className="KebabImg"></button> + <p className="CreatedAt">{timeAgo(data.createdAt)}</p> + <p className="Description"> + {data.description || "no description"} + </p> + <p className="makeDate">{formatDate(data.createdAt)}</p> + </div> + </div> + ))} </div> ); } diff --git a/src/components/FolderList.js b/src/components/FolderList.js new file mode 100644 index 000000000..605d979ac --- /dev/null +++ b/src/components/FolderList.js @@ -0,0 +1,25 @@ +import "./Style.css"; + +function FolderList({ lists }) { + console.log(lists); + return ( + <> + <div className="FolderListContainer"> + <ul className="ListButtonContainer"> + <li> + <button className="ListButton">전체</button> + </li> + {lists?.map((list) => { + return ( + <li> + <button className="ListButton">{list.name}</button> + </li> + ); + })} + </ul> + </div> + </> + ); +} + +export default FolderList; diff --git a/src/components/Style.css b/src/components/Style.css index 12ea89f63..460f740e0 100644 --- a/src/components/Style.css +++ b/src/components/Style.css @@ -147,6 +147,37 @@ nav { transform: translate(0, -50%); } +.FolderListContainer { + max-width: 1140px; + margin: 40px auto; +} + + +.ListButtonContainer { + display: flex; + gap: 12px; +} + +.ListButtonContainer li { + display: flex; +} + +.ListButton { + width: fit-content; + padding: 10px 12px; + border-radius: 5px; + border: 1px solid var(--linkbrary-primary-color, #6D6AFE); + background: #FFF; + cursor: pointer; + font-size: 16px; + font-weight: 400; +} + +.ListButton:hover { + background: #6D6AFE; + color: #FFF; +} + .Link { width: 100%; padding: 15px 16px 15px 30px; @@ -168,9 +199,23 @@ nav { .CardContainer { height: 65%; overflow: hidden; + position: relative; +} + +.StarImg { + background: url("../assets/star.svg") no-repeat; + border: none; + width: 27px; + height: 27px; + position: absolute; + top: 10px; + right: 10px; + cursor: pointer; + z-index: 1; } .CardInfoContainer { + position: relative; height: 35%; padding: 15px 20px; display: flex; @@ -178,6 +223,17 @@ nav { flex-direction: column; } +.KebabImg { + background: url("../assets/kebab.svg") no-repeat; + border: none; + width: 25px; + height: 20px; + position: absolute; + top: 10px; + right: 8px; + cursor: pointer; +} + .Card { width: 100%; height: 100%; diff --git a/src/pages/FolderPage.js b/src/pages/FolderPage.js index 1bbe041fe..e57c67b34 100644 --- a/src/pages/FolderPage.js +++ b/src/pages/FolderPage.js @@ -3,11 +3,13 @@ import AddLink from "../components/AddLink"; import CardInput from "../components/CardInput-folder"; import Search from "../components/Search"; import { useEffect, useState } from "react"; -import { getUser, getUserLink } from "../api"; +import { getUser, getUserLink, getUserFolder } from "../api"; +import FolderList from "../components/FolderList"; function FolderPage() { const [userData, setUserData] = useState(); const [cardData, setCardData] = useState(); + const [folderList, setFolderList] = useState(); const getProfile = async () => { const { data } = await getUser(); @@ -26,9 +28,16 @@ function FolderPage() { setCardData(data); } + const getFolderList = async () => { + const { data } = await getUserFolder(); + + setFolderList(data); + } + useEffect(() => { getProfile(); getCardData(); + getFolderList(); }, []); return ( @@ -36,6 +45,7 @@ function FolderPage() { <Header profile={userData} /> <AddLink /> <Search /> + <FolderList lists={folderList}/> <CardInput linksData={cardData}/> </> ); From 786f956235cc7c24d8378e589bf41ae83c9e3e18 Mon Sep 17 00:00:00 2001 From: JunCastle <juncastle97@gmail.com> Date: Thu, 7 Dec 2023 23:51:21 +0900 Subject: [PATCH 11/13] =?UTF-8?q?Fix:=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=97=86=EC=9D=84=20=EB=95=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Card-folder.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Card-folder.js b/src/components/Card-folder.js index c17ab027b..4a8b129f0 100644 --- a/src/components/Card-folder.js +++ b/src/components/Card-folder.js @@ -9,8 +9,7 @@ function formatDate(value) { function Card({ data }) { return ( <div className="CardGrid"> - {data && - data.map((data) => ( + {data ? (data.map((data) => ( <div className="Contents"> <div className="CardContainer"> <button className="StarImg"></button> @@ -30,7 +29,10 @@ function Card({ data }) { <p className="makeDate">{formatDate(data.created_at)}</p> </div> </div> - ))} + ))) : ( + <p>"저장된 링크가 없습니다"</p> + )} + </div> ); } From dc1bd3c532d0e6f3b69275c39299b2e33edea0e6 Mon Sep 17 00:00:00 2001 From: JunCastle <juncastle97@gmail.com> Date: Fri, 8 Dec 2023 19:27:54 +0900 Subject: [PATCH 12/13] =?UTF-8?q?Feat:=20Kebab=20Button=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=EC=B0=BD=20=EB=A7=8C=EB=93=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Card-folder.js | 35 ++++++++++++++++++++++++----------- src/components/Card-shared.js | 35 ++++++++++++++++++++++++----------- src/components/KebabModal.js | 13 +++++++++++++ src/components/Search.js | 3 --- src/components/Style.css | 32 +++++++++++++++++++++++++++++++- 5 files changed, 92 insertions(+), 26 deletions(-) create mode 100644 src/components/KebabModal.js diff --git a/src/components/Card-folder.js b/src/components/Card-folder.js index 4a8b129f0..85b31d7a9 100644 --- a/src/components/Card-folder.js +++ b/src/components/Card-folder.js @@ -1,5 +1,8 @@ import noneImg from "../assets/noneimg.svg"; import { timeAgo } from "../time"; +import { useState } from "react"; +import KebabModal from "./KebabModal"; +import { Link } from "react-router-dom"; function formatDate(value) { const date = new Date(value); @@ -7,21 +10,31 @@ function formatDate(value) { } function Card({ data }) { + const [modalOpen, setModalOpen] = useState(Array(data).fill(false)); + const showModal = (index) => { + const newModalOpen = [...modalOpen]; + newModalOpen[index] = !newModalOpen[index]; + setModalOpen(newModalOpen); + } + return ( <div className="CardGrid"> - {data ? (data.map((data) => ( + {data ? (data.map((data, index) => ( <div className="Contents"> - <div className="CardContainer"> - <button className="StarImg"></button> - <img - className="Card" - src={data.image_source || noneImg} - key={data.id} - alt="이미지 미리보기" - /> - </div> + <Link to={data.url} target="_blank"> + <div className="CardContainer"> + <button className="StarImg"></button> + <img + className="Card" + src={data.image_source || noneImg} + key={data.id} + alt="이미지 미리보기" + /> + </div> + </Link> <div className="CardInfoContainer"> - <button className="KebabImg"></button> + {modalOpen[index] && <KebabModal />} + <button className="KebabImg" onClick={() => showModal(index)}></button> <p className="CreatedAt">{timeAgo(data.created_at)}</p> <p className="Description"> {data.description || "no description"} diff --git a/src/components/Card-shared.js b/src/components/Card-shared.js index ff0607014..863997f57 100644 --- a/src/components/Card-shared.js +++ b/src/components/Card-shared.js @@ -1,5 +1,8 @@ import noneImg from "../assets/noneimg.svg"; import { timeAgo } from "../time"; +import KebabModal from "./KebabModal"; +import { useState } from "react"; +import { Link } from "react-router-dom"; function formatDate(value) { const date = new Date(value); @@ -7,22 +10,32 @@ function formatDate(value) { } function Card({ data }) { + const [modalOpen, setModalOpen] = useState(Array(data).fill(false)); + const showModal = (index) => { + const newModalOpen = [...modalOpen]; + newModalOpen[index] = !newModalOpen[index]; + setModalOpen(newModalOpen); + } + return ( <div className="CardGrid"> - {data && - data.map((data) => ( + {data && + data.map((data, index) => ( <div className="Contents"> + <Link to={data.url}> <div className="CardContainer"> - <button className="StarImg"></button> - <img - className="Card" - src={data.imageSource || noneImg} - key={data.id} - alt="이미지 미리보기" - /> - </div> + <button className="StarImg"></button> + <img + className="Card" + src={data.imageSource || noneImg} + key={data.id} + alt="이미지 미리보기" + /> + </div> + </Link> <div className="CardInfoContainer"> - <button className="KebabImg"></button> + <button className="KebabImg" onClick={() => showModal(index)}></button> + {modalOpen[index] && <KebabModal />} <p className="CreatedAt">{timeAgo(data.createdAt)}</p> <p className="Description"> {data.description || "no description"} diff --git a/src/components/KebabModal.js b/src/components/KebabModal.js new file mode 100644 index 000000000..deaa39ec8 --- /dev/null +++ b/src/components/KebabModal.js @@ -0,0 +1,13 @@ +function KebabModal() { + + return ( + <> + <div className="KebabModalContainer"> + <button className="KebabModal">삭제하기</button> + <button className="KebabModal">폴더에 추가</button> + </div> + </> + ); +} + +export default KebabModal; \ No newline at end of file diff --git a/src/components/Search.js b/src/components/Search.js index dbb04604f..df66377e0 100644 --- a/src/components/Search.js +++ b/src/components/Search.js @@ -1,5 +1,3 @@ -import search from "../assets/search.svg"; - function Search() { return ( <div className="MainContainer"> @@ -9,7 +7,6 @@ function Search() { type="text" placeholder="링크를 검색해보세요." /> - <img className="SearchIcon" src={search} alt="돋보기 아이콘" /> </div> </div> ); diff --git a/src/components/Style.css b/src/components/Style.css index 460f740e0..e60716759 100644 --- a/src/components/Style.css +++ b/src/components/Style.css @@ -156,6 +156,7 @@ nav { .ListButtonContainer { display: flex; gap: 12px; + flex-wrap: wrap; } .ListButtonContainer li { @@ -186,6 +187,12 @@ nav { border: none; } +.Link::placeholder { + background: url('../assets/search.svg') no-repeat left; + background-size: 15px; + padding-left: 25px; +} + .CardDataContainer { margin: 40px 0; } @@ -234,9 +241,32 @@ nav { cursor: pointer; } +.KebabModalContainer { + position: absolute; + display: flex; + flex-direction: column; + right: 10px; + bottom: 10px; +} + +.KebabModal { + border: none; + padding: 10px; + background: var(--gray-light-gray-00, #FFF); + border-radius: 3px; + box-shadow: 0px 2px 8px 0px rgba(51, 50, 54, 0.10); +} + +.KebabModal:hover { + background: var(--linkbrary-gray-10, #E7EFFB); + color: var(--linkbrary-primary-color, #6D6AFE); + cursor: pointer; +} + .Card { width: 100%; height: 100%; + object-fit: cover; } .Card:hover { @@ -262,7 +292,7 @@ nav { height: 330px; border-radius: 15px; overflow: hidden; - border: none; + border: 2px solid rgba(0,0,0,0); box-shadow: 0px 5px 25px 0px rgba(0, 0, 0, 0.08); } From 16983b4315e4b5c46bae6026631b43d62365d194 Mon Sep 17 00:00:00 2001 From: JunCastle <juncastle97@gmail.com> Date: Sat, 9 Dec 2023 11:09:20 +0900 Subject: [PATCH 13/13] =?UTF-8?q?Feat:=20=ED=8F=B4=EB=8D=94=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EB=88=84=EB=A5=BC=20=EC=8B=9C=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=20=EB=82=98=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/delete.svg | 8 +++++ src/assets/editimg.svg | 5 +++ src/assets/shareimg.svg | 11 +++++++ src/components/FolderList.js | 37 ++++++++++++++++----- src/components/ListButton.js | 17 ++++++++++ src/components/Style.css | 64 ++++++++++++++++++++++++++++++++---- 6 files changed, 126 insertions(+), 16 deletions(-) create mode 100644 src/assets/delete.svg create mode 100644 src/assets/editimg.svg create mode 100644 src/assets/shareimg.svg create mode 100644 src/components/ListButton.js diff --git a/src/assets/delete.svg b/src/assets/delete.svg new file mode 100644 index 000000000..768b0b398 --- /dev/null +++ b/src/assets/delete.svg @@ -0,0 +1,8 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="17" viewBox="0 0 16 17" fill="none"> + <path d="M2.6 4.1H13.4V14.5C13.4 15.2732 12.7732 15.9 12 15.9H4C3.2268 15.9 2.6 15.2732 2.6 14.5V4.1Z" stroke="#9FA6B2" stroke-width="1.2"/> + <path d="M5.48387 2.07385C5.72102 1.59955 6.20579 1.29995 6.73607 1.29995H9.26393C9.79421 1.29995 10.279 1.59955 10.5161 2.07385L11.5292 4.09995H4.47082L5.48387 2.07385Z" stroke="#9FA6B2" stroke-width="1.2"/> + <rect x="0.5" y="3.5" width="15" height="1.2" rx="0.6" fill="#9FA6B2"/> + <rect x="8.59998" y="6.5" width="7" height="1.2" rx="0.6" transform="rotate(90 8.59998 6.5)" fill="#9FA6B2"/> + <rect x="11.2" y="6.5" width="7" height="1.2" rx="0.6" transform="rotate(90 11.2 6.5)" fill="#9FA6B2"/> + <rect x="6.19995" y="6.5" width="7" height="1.2" rx="0.6" transform="rotate(90 6.19995 6.5)" fill="#9FA6B2"/> +</svg> \ No newline at end of file diff --git a/src/assets/editimg.svg b/src/assets/editimg.svg new file mode 100644 index 000000000..0132ba66e --- /dev/null +++ b/src/assets/editimg.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="18" height="19" viewBox="0 0 18 19" fill="none"> + <path fill-rule="evenodd" clip-rule="evenodd" d="M12.3788 2.4083C12.8196 1.96742 13.5333 1.96742 13.9742 2.4083L16.6718 5.10595C17.1127 5.54683 17.1127 6.2605 16.6718 6.70139L7.67596 15.6973C7.59335 15.7799 7.48616 15.8335 7.37049 15.85L3.25285 16.4382C3.08459 16.4623 2.91483 16.4057 2.79464 16.2855C2.67446 16.1653 2.61787 15.9956 2.64191 15.8273L3.23014 11.7097C3.24667 11.594 3.30026 11.4868 3.38288 11.4042L12.3788 2.4083ZM13.2105 3.17197C13.1914 3.15286 13.1616 3.15286 13.1424 3.17197L4.27383 12.0406L3.81288 15.2673L7.03957 14.8063L15.9082 5.93771C15.9273 5.91859 15.9273 5.88874 15.9082 5.86962L13.2105 3.17197Z" fill="#9FA6B2"/> + <path fill-rule="evenodd" clip-rule="evenodd" d="M15.3229 3.75704C15.5338 3.96792 15.5338 4.30983 15.3229 4.52071L8.26412 11.5795C8.05324 11.7904 7.71133 11.7904 7.50045 11.5795C7.28956 11.3687 7.28956 11.0267 7.50045 10.8159L14.5593 3.75704C14.7702 3.54616 15.1121 3.54616 15.3229 3.75704Z" fill="#9FA6B2"/> + <path fill-rule="evenodd" clip-rule="evenodd" d="M3.38302 11.4043C3.5939 11.1934 3.93581 11.1934 4.14669 11.4043L7.6761 14.9337C7.88699 15.1446 7.88699 15.4865 7.6761 15.6973C7.46522 15.9082 7.12331 15.9082 6.91243 15.6973L3.38302 12.1679C3.17213 11.957 3.17213 11.6151 3.38302 11.4043Z" fill="#9FA6B2"/> +</svg> \ No newline at end of file diff --git a/src/assets/shareimg.svg b/src/assets/shareimg.svg new file mode 100644 index 000000000..74c58297b --- /dev/null +++ b/src/assets/shareimg.svg @@ -0,0 +1,11 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="18" height="19" viewBox="0 0 18 19" fill="none"> + <g clip-path="url(#clip0_5014_3307)"> + <path fill-rule="evenodd" clip-rule="evenodd" d="M7.39498 11.045C7.13138 10.7813 7.13138 10.354 7.39498 10.0904L13.8295 3.52012H10.3679C9.99513 3.52012 9.69292 3.21792 9.69292 2.84512C9.69292 2.47233 9.99513 2.17012 10.3679 2.17012H15.4591C15.8319 2.17012 16.1341 2.47233 16.1341 2.84512L16.1341 7.93629C16.1341 8.30909 15.8319 8.61129 15.4591 8.61129C15.0863 8.61129 14.7841 8.30908 14.7841 7.93629L14.7841 4.47472L8.34958 11.045C8.08597 11.3086 7.65859 11.3086 7.39498 11.045Z" fill="#9FA6B2"/> + <path fill-rule="evenodd" clip-rule="evenodd" d="M4.50002 4.77505C3.8787 4.77505 3.37502 5.27873 3.37502 5.90005V14C3.37502 14.6214 3.8787 15.125 4.50002 15.125H12.6C13.2213 15.125 13.725 14.6214 13.725 14V10.85C13.725 10.4773 14.0272 10.175 14.4 10.175C14.7728 10.175 15.075 10.4773 15.075 10.85V14C15.075 15.367 13.9669 16.475 12.6 16.475H4.50002C3.13312 16.475 2.02502 15.367 2.02502 14V5.90005C2.02502 4.53314 3.13312 3.42505 4.50002 3.42505H7.65002C8.02282 3.42505 8.32502 3.72726 8.32502 4.10005C8.32502 4.47284 8.02282 4.77505 7.65002 4.77505H4.50002Z" fill="#9FA6B2"/> + </g> + <defs> + <clipPath id="clip0_5014_3307"> + <rect width="18" height="18" fill="white" transform="translate(0 0.5)"/> + </clipPath> + </defs> +</svg> \ No newline at end of file diff --git a/src/components/FolderList.js b/src/components/FolderList.js index 605d979ac..9fa506bb7 100644 --- a/src/components/FolderList.js +++ b/src/components/FolderList.js @@ -1,22 +1,41 @@ +import ListButton from "./ListButton"; import "./Style.css"; +import { useState } from "react"; function FolderList({ lists }) { - console.log(lists); + const [toggleList, setToggleList] = useState(0); + return ( <> <div className="FolderListContainer"> - <ul className="ListButtonContainer"> - <li> - <button className="ListButton">전체</button> - </li> + <div className="ListButtonContainer"> + <button className="ListButton" onClick={() => setToggleList(0)}> + 전체 + </button> {lists?.map((list) => { return ( - <li> - <button className="ListButton">{list.name}</button> - </li> + <ListButton + key={list.id} + list={list} + setToggleList={() => setToggleList(list.name)} + /> ); })} - </ul> + </div> + <div className="ToggleListNameContainer"> + {toggleList === 0 ? ( + "" + ) : ( + <div className="ToggleListName">{toggleList}</div> + )} + {toggleList !== 0 && ( + <div className="EditButton"> + <button className="Share">공유</button> + <button className="Edit">이름 변경</button> + <button className="Delete">삭제</button> + </div> + )} + </div> </div> </> ); diff --git a/src/components/ListButton.js b/src/components/ListButton.js new file mode 100644 index 000000000..13f47cab1 --- /dev/null +++ b/src/components/ListButton.js @@ -0,0 +1,17 @@ +function ListButton({ list, setToggleList }) { + + const toggleChange = () => { + setToggleList(list.id); + }; + + return ( + <> + <button className="ListButton" onClick={toggleChange}> + {list.name} + </button> + <div></div> + </> + ); +} + +export default ListButton; diff --git a/src/components/Style.css b/src/components/Style.css index e60716759..3e2da3429 100644 --- a/src/components/Style.css +++ b/src/components/Style.css @@ -148,24 +148,22 @@ nav { } .FolderListContainer { - max-width: 1140px; + max-width: 1070px; margin: 40px auto; + display: flex; + flex-direction: column; } - .ListButtonContainer { display: flex; - gap: 12px; flex-wrap: wrap; } -.ListButtonContainer li { - display: flex; -} - .ListButton { width: fit-content; padding: 10px 12px; + margin-left: 10px; + margin-bottom: 3px; border-radius: 5px; border: 1px solid var(--linkbrary-primary-color, #6D6AFE); background: #FFF; @@ -179,6 +177,58 @@ nav { color: #FFF; } +.ToggleListNameContainer { + display: flex; + justify-content: space-between; + align-items: center; + margin: 10px 0 0 10px; +} + +.ToggleListName { + color: #000; + font-size: 24px; + font-style: normal; + font-weight: 600; + line-height: normal; + letter-spacing: -0.2px; +} + +.EditButton button { + border: none; + cursor: pointer; + color: var(--linkbrary-gray-60, #9FA6B2); + font-size: 14px; + font-style: normal; + font-weight: 600; + line-height: normal; +} + +.EditButton .Share { + background: url(../assets/shareimg.svg) no-repeat left; + width: 70px; +} + +.EditButton .Edit { + background: url(../assets/editimg.svg) no-repeat left; + width: 100px; +} + +.EditButton .Delete { + background: url(../assets/delete.svg) no-repeat left; + width: 70px; +} + +.SelectList { + color: #000; + font-family: Pretendard; + font-size: 24px; + font-style: normal; + font-weight: 600; + line-height: normal; + letter-spacing: -0.2px; + padding: 45px 40px 0; +} + .Link { width: 100%; padding: 15px 16px 15px 30px;