From dd689b97b6ef23eb4b24b8c267d3138669b00321 Mon Sep 17 00:00:00 2001 From: choibk Date: Wed, 17 Dec 2025 21:49:30 +0900 Subject: [PATCH] =?UTF-8?q?Unsplash=20Photo=20API=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/icon-arrowLeft.svg | 3 + src/assets/icons/icon-arrowRight.svg | 3 + .../common/footer/CommonFooter.module.scss | 65 ++++++++++++++ src/components/common/footer/CommonFooter.tsx | 85 ++++++++++++++++++ .../common/navigation/CommanNav.tsx | 47 ++++++++++ .../common/navigation/CommonNav.module.scss | 37 ++++++++ src/components/common/navigation/nav.json | 86 +++++++++++++++++++ src/main.tsx | 8 +- src/pages/index/components/Card.module.scss | 22 +++++ src/pages/index/components/Card.tsx | 25 ++++++ src/pages/index/index.tsx | 47 +++++++++- src/pages/index/types/card.ts | 53 ++++++++++++ tsconfig.json | 2 +- 13 files changed, 473 insertions(+), 10 deletions(-) create mode 100644 src/assets/icons/icon-arrowLeft.svg create mode 100644 src/assets/icons/icon-arrowRight.svg create mode 100644 src/components/common/footer/CommonFooter.module.scss create mode 100644 src/components/common/footer/CommonFooter.tsx create mode 100644 src/components/common/navigation/CommanNav.tsx create mode 100644 src/components/common/navigation/CommonNav.module.scss create mode 100644 src/components/common/navigation/nav.json create mode 100644 src/pages/index/components/Card.module.scss create mode 100644 src/pages/index/components/Card.tsx create mode 100644 src/pages/index/types/card.ts diff --git a/src/assets/icons/icon-arrowLeft.svg b/src/assets/icons/icon-arrowLeft.svg new file mode 100644 index 0000000..5d922da --- /dev/null +++ b/src/assets/icons/icon-arrowLeft.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/icon-arrowRight.svg b/src/assets/icons/icon-arrowRight.svg new file mode 100644 index 0000000..c05beb7 --- /dev/null +++ b/src/assets/icons/icon-arrowRight.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/common/footer/CommonFooter.module.scss b/src/components/common/footer/CommonFooter.module.scss new file mode 100644 index 0000000..e283d2a --- /dev/null +++ b/src/components/common/footer/CommonFooter.module.scss @@ -0,0 +1,65 @@ +.footer { + display: flex; + align-items: center; + justify-content: center; + + width: 100%; + height: 56px; + + padding: 0 16px; + + border: 1px solid $color-gray-100; + background-color: $color-white-000; +} +.pagination { + display: flex; + align-items: center; + justify-content: center; + + width: 100%; + + gap: 8px; + + &__button { + display: flex; + align-items: center; + justify-content: center; + + width: 24px; + height: 24px; + + padding: 3px 7px; + + color: $color-gray-500; + + font-family: 'Public Sans', sans-serif; + font-size: 16px; + font-weight: 700; + line-height: 16px; + + background: transparent; + border: none; + outline: none; + + cursor: pointer; + + &:hover { + background-color: $color-gray-100; + border-radius: 4px; + + color: $color-black-900; + } + &.active { + background-color: $color-gray-100; + border-radius: 4px; + + color: $color-black-900; + } + &.inactive { + background-color: $color-white-000; + border-radius: 4px; + + color: $color-black-900; + } + } +} \ No newline at end of file diff --git a/src/components/common/footer/CommonFooter.tsx b/src/components/common/footer/CommonFooter.tsx new file mode 100644 index 0000000..40a3699 --- /dev/null +++ b/src/components/common/footer/CommonFooter.tsx @@ -0,0 +1,85 @@ +// import { useEffect, useState } from 'react' +// import { useRecoilState, useRecoilValue, useRecoilValueLoadable } from 'recoil' +// import { imageData } from '@/recoil/selectors/imageSelector' +// import { pageState } from '@/recoil/atoms/pageState' +import styles from './CommonFooter.module.scss' +// import { searchState } from '@/recoil/atoms/searchState' +import IconImageLeft from '@/assets/icons/icon-arrowLeft.svg' +import IconImageRight from '@/assets/icons/icon-arrowRight.svg' + +function CommonFooter() { + // const imgSelector = useRecoilValueLoadable(imageData) + // const search = useRecoilValue(searchState) + // const [page, setPage] = useRecoilState(pageState) + // const [step, setStep] = useState(0) + + // useEffect(() => { + // setStep(0) + // }, [search]) + + // // 페이지 리스트 UI 생성 + // const newArr: number[] = new Array() + // for (let i = 1; i <= imgSelector.contents.total_pages; i++) { + // newArr.push(i) + // } + // const length = newArr.length + // const divide = Math.floor(length / 10) + (Math.floor(length % 10) > 0 ? 1 : 0) + // const res = [] + + // for (let i = 0; i <= divide; i++) { + // // 배열 0부터 n개씩 잘라 새 배열에 넣기 + // res.push(newArr.splice(0, 10)) + // } + + // // ---------------------------------------------------------------------------------------------------- + + // const moveToPage = (selected: number) => { + // setPage(selected) + // } + // const moveToPrev = () => { + // if (step === 0) return + // else { + // setStep(step - 1) + // setPage(res[step - 1][0]) + // } + // } + // const moveToNext = () => { + // if (step < res[step].length - 2) { + // setStep(step + 1) + // setPage(res[step + 1][0]) + // } else return + // } + + return ( + + ) +} + +export default CommonFooter \ No newline at end of file diff --git a/src/components/common/navigation/CommanNav.tsx b/src/components/common/navigation/CommanNav.tsx new file mode 100644 index 0000000..9fd422e --- /dev/null +++ b/src/components/common/navigation/CommanNav.tsx @@ -0,0 +1,47 @@ +import { useEffect, useState } from 'react' +import { Link, useLocation } from 'react-router-dom' +import styles from './CommonNav.module.scss' +import navJson from './nav.json' +// import { useRecoilState } from 'recoil' +// import { pageState } from '@/recoil/atoms/pageState' +// import { searchState } from '@/recoil/atoms/searchState' + +interface Navigation { + index: number + path: string + label: string + searchValue: string + isActive: boolean +} + +function CommonNav() { + const location = useLocation() + const [navigation, setNavigation] = useState(navJson) + // const [, setPage] = useRecoilState(pageState) + // const [, setSearch] = useRecoilState(searchState) + + // useEffect(() => { + // navigation.forEach((nav: Navigation) => { + // nav.isActive = false + + // if (nav.path === location.pathname || location.pathname.includes(nav.path)) { + // nav.isActive = true + // setSearch(nav.searchValue) + // setPage(1) + // } + // }) + // setNavigation([...navigation]) + // }, [location.pathname]) + + // useState로 선언한 반응성을 가진 데이터를 기반으로 UI를 반복호출해보도록 한다. + const navLinks = navigation.map((item: Navigation) => { + return ( + + {item.label} + + ) + }) + return +} + +export default CommonNav \ No newline at end of file diff --git a/src/components/common/navigation/CommonNav.module.scss b/src/components/common/navigation/CommonNav.module.scss new file mode 100644 index 0000000..571f2b5 --- /dev/null +++ b/src/components/common/navigation/CommonNav.module.scss @@ -0,0 +1,37 @@ +.navigation { + display: flex; + align-items: center; + justify-content: center; + + width: 100%; + height: 50px; + + gap: 32px; + + border-bottom: 1px solid $color-white-300; + + &__menu { + display: flex; + align-items: center; + justify-content: center; + + height: 100%; + + text-decoration: none; // 추후에 div 태그를 React Router 속성 중 Link 태그로 바꿀 것이기 때문입니다. + color: $color-white-700; + font-weight: 500; + + &.inactive { + color: $color-white-700; + border-bottom: none; + } + &.active { + color: $color-black-900; + border-bottom: 2px solid $color-white-700; + } + &:hover { + color: $color-black-900; + font-weight: 600; + } + } +} \ No newline at end of file diff --git a/src/components/common/navigation/nav.json b/src/components/common/navigation/nav.json new file mode 100644 index 0000000..f715fce --- /dev/null +++ b/src/components/common/navigation/nav.json @@ -0,0 +1,86 @@ +[ + { + "index": 0, + "path": "/search/edit", + "label": "보도/편집 전용", + "searchValue": "edit", + "isActive": false + }, + { + "index": 1, + "path": "/search/following", + "label": "팔로잉", + "searchValue": "following", + "isActive": false + }, + { + "index": 2, + "path": "/search/photoPlus", + "label": "Unsplash Photo+", + "searchValue": "photo", + "isActive": false + }, + { + "index": 3, + "path": "/search/oneColor", + "label": "단색", + "searchValue": "one color", + "isActive": false + }, + { + "index": 4, + "path": "/search/3dRender", + "label": "3D 렌더링", + "searchValue": "3d rendering", + "isActive": false + }, + { + "index": 5, + "path": "/search/nature", + "label": "자연", + "searchValue": "nature", + "isActive": false + }, + { + "index": 6, + "path": "/search/texture", + "label": "텍스쳐 및 패턴", + "searchValue": "texture", + "isActive": false + }, + { + "index": 7, + "path": "/search/interior", + "label": "인테리어", + "searchValue": "interior", + "isActive": false + }, + { + "index": 8, + "path": "/search/film", + "label": "필름", + "searchValue": "film", + "isActive": false + }, + { + "index": 9, + "path": "/search/experimental", + "label": "실험적인", + "searchValue": "experimental", + "isActive": false + }, + { + "index": 10, + "path": "/search/travel", + "label": "여행", + "searchValue": "travel", + "isActive": false + }, + { + "index": 11, + "path": "/search/sports", + "label": "스포츠", + "searchValue": "sports", + "isActive": false + } +] \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index 4aff025..6343bf8 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,9 +1,5 @@ -import { StrictMode } from 'react' +// import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import App from './App.tsx' -createRoot(document.getElementById('root')!).render( - - - , -) +createRoot(document.getElementById('root')!).render() diff --git a/src/pages/index/components/Card.module.scss b/src/pages/index/components/Card.module.scss new file mode 100644 index 0000000..8c9cc0a --- /dev/null +++ b/src/pages/index/components/Card.module.scss @@ -0,0 +1,22 @@ +.card { + width: 260px; + height: 260px; + + background-color: $color-gray-200; + border-radius: 6px; + + cursor: pointer; + + @media (min-width: 1024px) and (max-width: 1440px) { + width: 200px; + height: 200px; + } + + &__image { + width: 100%; + height: 100%; + + border-radius: 6px; + object-fit: cover; + } +} diff --git a/src/pages/index/components/Card.tsx b/src/pages/index/components/Card.tsx new file mode 100644 index 0000000..ba6aaf5 --- /dev/null +++ b/src/pages/index/components/Card.tsx @@ -0,0 +1,25 @@ +import type { CardDTO } from '../types/card' +import styles from './Card.module.scss' + + +interface Props { + data: CardDTO + handleDialog: (eventValue: boolean) => void + handleSetData: (eventValue: CardDTO) => void +} + +function Card({ data/*, handleDialog, handleSetData */}: Props) { + const openDialog = () => { + console.log('함수호출') + // handleDialog(true) + // handleSetData(data) + } + + return ( +
+ {data.alt_description} +
+ ) +} + +export default Card diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx index 3b22bc8..e305f6b 100644 --- a/src/pages/index/index.tsx +++ b/src/pages/index/index.tsx @@ -1,13 +1,51 @@ import CommonHeader from "@/components/common/header/CommonHeader" -import styles from "./styles/index.module.scss" import CommonSearchBar from "@/components/common/searchBar/CommonSearchBar" +import CommonNav from "@/components/common/navigation/CommanNav" +import CommonFooter from "@/components/common/footer/CommonFooter" +import Card from "./components/Card" +import styles from "./styles/index.module.scss" +import axios from "axios" +import { useEffect, useState } from "react" +import type { CardDTO } from "./types/card" function index() { + const [imgUrls, setImgUrls] = useState([]) + + const getData = async() => { + // Open API 호출 + const API_URL = 'https://api.unsplash.com/search/photos' + const API_KEY = 'nloztIOd94-5EH6vAJUU3L66l79z9Dv2KwwbKHShAnY' + const PER_PAGE = 30 + + const searchValue = 'Korea' + const pageValue = 100 + + try { + const res = await axios.get(`${API_URL}?query=${searchValue}&client_id=${API_KEY}&page=${pageValue}&per_page=${PER_PAGE}`) + console.log(res) + if(res.status === 200) { + setImgUrls(res.data.results) + } + } catch (error) { + console.log(error) + } + + } + + const cardList = imgUrls.map((card: CardDTO) => { + return + }) + + useEffect(()=> { + getData() + }, []) + return (
{/*공통 헤더 UI 부분*/} {/*공통 네비게이션 UI 부분*/} +
@@ -17,12 +55,15 @@ function index() { 모든 지역에 있는 크리에이터들의 지원을 받습니다. {/*검색창 UI 부분*/} - +
-
+
+ {cardList} +
{/* 공통 푸터 UI 부분 */} +
) } diff --git a/src/pages/index/types/card.ts b/src/pages/index/types/card.ts new file mode 100644 index 0000000..ba2e020 --- /dev/null +++ b/src/pages/index/types/card.ts @@ -0,0 +1,53 @@ +export interface CardDTO { + alt_description: string + blur_hash: string + breadcrumbs: [] + color: string + created_at: string + current_user_collections: [] + description: string + height: number + id: string + liked_by_user: boolean + likes: number + links: Link + promoted_at?: string + slug: string + sponsorship?: string + tags: Tag[] + topic_submissions: any + updated_at: string + urls: Url + user: any + width: number +} + +interface Link { + download: string + download_location: string + html: string + self: string +} + +export interface Tag { + source: { + ancestry: any + cover_photo: any + description: string + meta_description: string + meta_title: string + subtitle: string + title: string + } + title: string + type: string +} + +interface Url { + full: string + raw: string + regular: string + small: string + small_s3: string + thumb: string +} diff --git a/tsconfig.json b/tsconfig.json index 0ac150d..f02c488 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,3 +1,3 @@ { - "extends": "./tsconfig.app.json" + "extends": "./tsconfig.app.json" }