diff --git a/src/App.jsx b/src/App.jsx index 43e0970..b0b1d87 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -7,7 +7,6 @@ import { ModalProvider } from "./librarys/context.jsx"; import PlayerPage from "./pages/PlayerPage.jsx"; import store from "./redux/store.js"; -import LoginModal from "./components/LoginModal.jsx"; import { useEffect } from "react"; import { loadToken } from "./librarys/login-api.js"; import { login } from "./redux/userSlice.js"; @@ -53,7 +52,6 @@ function App() { - {routerList.map((item, index) => ( diff --git a/src/App.scss b/src/App.scss index a75022f..5dd5204 100644 --- a/src/App.scss +++ b/src/App.scss @@ -2,6 +2,6 @@ width: 100%; height: 100vh; margin: 0 auto; - background-color: #fff; + background-color: #1E1E1E; font-family: "SUIT Variable", sans-serif; } diff --git a/src/assets/icons/LOGO.png b/src/assets/icons/LOGO.png new file mode 100644 index 0000000..2198d04 Binary files /dev/null and b/src/assets/icons/LOGO.png differ diff --git a/src/assets/icons/iconsearch.png b/src/assets/icons/iconsearch.png new file mode 100644 index 0000000..90f9760 Binary files /dev/null and b/src/assets/icons/iconsearch.png differ diff --git a/src/assets/icons/iconupload.png b/src/assets/icons/iconupload.png new file mode 100644 index 0000000..a59c7e6 Binary files /dev/null and b/src/assets/icons/iconupload.png differ diff --git a/src/components/ExerciseCard.jsx b/src/components/ExerciseCard.jsx new file mode 100644 index 0000000..c7480c1 --- /dev/null +++ b/src/components/ExerciseCard.jsx @@ -0,0 +1,93 @@ +import { Link } from 'react-router-dom'; +import styled from 'styled-components'; +import PropTypes from 'prop-types'; + +const CourseCardContainer = styled.div` + width: 360px; + height: 310px; +`; + + +const CourseImage = styled.div` + height: 240px; + width: 360px; + background-image: url(${props => props.image}); + background-size: cover; + position: relative; + margin-bottom: 10px; +`; + + +const TimeInfo = styled.div` + width: 57px; + height: 23px; + background-color: rgba(14, 13, 13, 0.8); + border-radius: 4px; + position: absolute; + bottom: 0; + right: 0; + display: flex; + align-items: center; + justify-content: center; +`; + +const TimeText = styled.span` + color: #F2F2F2; + font-size: 12px; +`; + +const CourseTitle = styled.span` + font-size: 20px; + color: #F2F2F2; +`; + +const TagButton = styled.span` + margin-top: 10px; + height: 28px; + padding: 0 10px; + background-color: #242424; + border-radius: 50px; + border: 1px solid #444444; + font-size: 16px; + color: #F2F2F2; + margin-right: 5px; + display: inline-flex; + align-items: center; +`; + +const Hash = styled.span` + color: #727272; +`; + +const ExerciseCard = ({ id, image, title, tags }) => { + return ( + + + + + 00:00 + + + + {title} +
+ {tags && tags.map((tag, index) => ( + + # + {tag} + + ))} +
+
+ + ); +}; + +ExerciseCard.propTypes = { + id: PropTypes.number.isRequired, + image: PropTypes.string, + title: PropTypes.string.isRequired, + tags: PropTypes.arrayOf(PropTypes.string) +}; + +export default ExerciseCard; diff --git a/src/components/ExerciseList.jsx b/src/components/ExerciseList.jsx new file mode 100644 index 0000000..29cfd1b --- /dev/null +++ b/src/components/ExerciseList.jsx @@ -0,0 +1,36 @@ +import { useState, useEffect } from "react"; +import { getAllCourses } from "../librarys/exercise-api"; +import ExerciseCard from "../components/ExerciseCard"; +import styled from "styled-components"; + +const Container = styled.div` + width: 1200px; + display: flex; + flex-wrap: wrap; + gap: 20px; + margin-top: 20px; + margin-left:10px; +`; + +function ExerciseList() { + const [courses, setCourses] = useState([]); + + useEffect(() => { + async function fetchCourses() { + const data = await getAllCourses(); + setCourses(data); + } + + fetchCourses(); + }, []); + + return ( + + {courses.map((course) => ( + + ))} + + ); +} + +export default ExerciseList; diff --git a/src/components/FilterButtons.jsx b/src/components/FilterButtons.jsx new file mode 100644 index 0000000..6e91168 --- /dev/null +++ b/src/components/FilterButtons.jsx @@ -0,0 +1,87 @@ +import { useState } from "react"; +import styled from "styled-components"; + +const FilterSection = styled.div` + display: flex; + align-items: center; + margin-right: 10px; + margin-top: 20px; +`; + +const Title = styled.span` + font-size: 20px; + font-weight: bold; + color: #5f5f5f; + width: 120px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-right: 10px; +`; + +const Divider = styled.div` + width: 2px; + height: 20px; + background-color: #5f5f5f; + margin-right: 10px; +`; + +const Button = styled.button` + width: 100px; + height: 36px; + background-color: ${(props) => (props.selected ? "#6968CC" : "#1E1E1E")}; + color: #f2f2f2; + border-radius: 10px; + font-size: 16px; + border: none; + margin-right: 5px; + + &:focus { + outline: none; + } +`; + +const FilterButtons = () => { + const [selectedCategory, setSelectedCategory] = useState("전체"); + const [selectedPose, setSelectedPose] = useState("전체"); + + return ( +
+ + 카테고리 + + {["전체", "팔", "어깨", "무릎", "허벅지"].map((category) => ( + + ))} + + + + 자세 + + {["전체", "선 자세", "앉은 자세", "누운 자세"].map((pose) => ( + + ))} + +
+ ); +}; + +export default FilterButtons; diff --git a/src/components/Header.jsx b/src/components/Header.jsx index 135bafa..9cff5e0 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -1,116 +1,33 @@ +import SearchBar from "./SearchBar"; +import UploadButton from "./UploadButton"; import styled from "styled-components"; -import { Link } from "react-router-dom"; -import { useDispatch, useSelector } from "react-redux"; -import { - selectName, - selectIsLoggedIn, - selectIsAdmin, - logout, -} from "../redux/userSlice.js"; -import { show } from "../redux/modalSlice.js"; -import { clearToken } from "../librarys/login-api.js"; +import LogoImage from "../assets/icons/LOGO.png"; -const HeaderWrapper = styled.header` +const HeaderContainer = styled.div` display: flex; align-items: center; - padding: 10px 20px; - font-weight: bold; - position: relative; - margin-top: 20px; -`; - -const Logo = styled.div` - font-size: 24px; - font-weight: bold; - position: absolute; - left: 100px; - top: 50%; - transform: translateY(-50%); -`; - -const Nav = styled.nav` - display: flex; - position: absolute; - right: 70px; - align-items: center; + margin-bottom:-10px; `; -const MainLink = styled(Link)` - text-decoration: none; - color: black; - &:hover, - &:active, - &:focus { - text-decoration: none; - outline: none; - } +const Logo = styled.img` + margin-top: 20px; + margin-left: 420px; + margin-right: 10px; `; -const Divider = styled.div` - height: 30px; - width: 1px; - background-color: black; - margin-left: 20px; - margin-right: 30px; +const Spacer = styled.div` + width: 10px; `; const Header = () => { - const dispatch = useDispatch(); - - const userName = useSelector(selectName); - const isLoggedIn = useSelector(selectIsLoggedIn); - const isAdmin = useSelector(selectIsAdmin); - - const handleLoginClick = () => { - if (isLoggedIn) { - if (confirm("로그아웃 하시겠습니끼?")) { - clearToken(); - dispatch(logout()); - } - } else { - dispatch(show("login")); // 로그인 모달을 표시 - } - }; - return ( - - - Re:Hab - - - + + + + + + + ); }; diff --git a/src/components/SearchBar.jsx b/src/components/SearchBar.jsx new file mode 100644 index 0000000..7c26b08 --- /dev/null +++ b/src/components/SearchBar.jsx @@ -0,0 +1,46 @@ +import styled from 'styled-components'; +import Iconsearch from '../assets/icons/iconsearch.png'; + +const SearchContainer = styled.div` + width: 750px; + height: 50px; + background-color: #242424; + border: 1px solid #444444; + border-radius: 50px; + display: flex; + align-items: center; + margin-top: 20px; +`; + +const SearchIcon = styled.img` + width: 20px; + height: 20px; + margin-left: 10px; +`; + +const SearchInput = styled.input` + width: calc(100% - 40px); + height: 100%; + border: none; + background-color: transparent; + font-size: 14px; + color: #000; + padding-left: 10px; + &::placeholder { + color: #C8C8C8; + } + &:focus { + outline: none; + } +`; + +const SearchBar = () => { + return ( + + + + + ); +}; + +export default SearchBar; diff --git a/src/components/UploadButton.jsx b/src/components/UploadButton.jsx new file mode 100644 index 0000000..a3471e2 --- /dev/null +++ b/src/components/UploadButton.jsx @@ -0,0 +1,38 @@ +import styled from 'styled-components'; +import Iconupload from '../assets/icons/iconupload.png'; + +const ButtonContainer = styled.button` + width: 170px; + height: 44px; + background-color: #6968CC; + border-radius: 10px; + display: flex; + align-items: center; + border: none; + padding: 0 10px; + cursor: pointer; + margin-top: 20px; +`; + +const ButtonIcon = styled.img` + width: 30px; + height: 20px; + margin-left:10px; + margin-right: 10px; +`; + +const ButtonText = styled.span` + font-size: 16px; + color: #F2F2F2; +`; + +const UploadButton = () => { + return ( + + + 영상 게시하기 + + ); +}; + +export default UploadButton; diff --git a/src/index.scss b/src/index.scss index d3f9f43..6784a79 100644 --- a/src/index.scss +++ b/src/index.scss @@ -21,7 +21,7 @@ html { } @font-face { - font-family: "SUITE Variable"; + font-family: "SUIT Variable"; font-weight: 300 900; src: url("https://cdn.jsdelivr.net/gh/sunn-us/SUITE/fonts/variable/woff2/SUITE-Variable.woff2") format("woff2-variations"); diff --git a/src/pages/MainPage.jsx b/src/pages/MainPage.jsx index c49a010..3889e53 100644 --- a/src/pages/MainPage.jsx +++ b/src/pages/MainPage.jsx @@ -1,11 +1,45 @@ +import styled from "styled-components"; import Header from "../components/Header"; +import FilterButtons from "../components/FilterButtons"; +import ExerciseList from "../components/ExerciseList"; +const PageContainer = styled.div` + display: flex; + flex-direction: column; + height: 100vh; +`; + +const CenteredContainer = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + flex: 1; + margin-top: 50px; +`; + +const FilterGroup = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + flex: 1; + margin-top: -10px; + margin-left: -500px; + margin-bottom: 20px; +`; const MainPage = () => { return ( -
+
-
+ + + + + + + ); };