diff --git a/src/app/search/page.tsx b/src/app/search/page.tsx index 6e7a947..28be5ec 100644 --- a/src/app/search/page.tsx +++ b/src/app/search/page.tsx @@ -1,10 +1,10 @@ -import SearchBodySection from '@/components/search/SearchBodySection'; -import SearchHeadSection from '@/components/search/SearchHeadSection'; +import SearchBodySection from '@/components/search/searchBodySection/SearchBodySection'; +import SearchHeaderSection from '@/components/search/searchHeaderSection/SearchHeaderSection'; const SearchPage = () => { return ( <> - + ); diff --git a/src/components/search/AutoCompleteContainer.tsx b/src/components/search/AutoCompleteContainer.tsx deleted file mode 100644 index 415084f..0000000 --- a/src/components/search/AutoCompleteContainer.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { useSearchAutoCompleteQuery } from '@/hooks/useSearchAutoCompleteQuery'; -import { useRouter } from 'next/navigation'; -import styled from 'styled-components'; - -interface AutoProps { - searchInput: string; -} - -const AutoCompleteContainer = ({ searchInput }: AutoProps) => { - const router = useRouter(); - const { data: dropdownList, isLoading } = useSearchAutoCompleteQuery(searchInput); - - if (isLoading) { - return ( - - 검색중... - - ); - } - - return ( - - {dropdownList && dropdownList.length > 0 ? ( - dropdownList.map((title, idx) => ( - router.push(`search/?search=${title}`)}> - {title} - - )) - ) : ( - 검색결과가 없습니다. - )} - - ); -}; - -const BoxWrapper = styled.div` - // position: absolute; - display: flex; - flex-direction: column; - width: 40vw; - background-color: white; - margin-left: 2%; - gap: 10px; - box-shadow: 2px 2px 2px black; - z-index: 1; -`; - -const ItemWrapper = styled.div` - padding: 15px; - font-size: 1.4rem; - cursor: pointer; - &:hover { - background-color: lightgrey; - } -`; - -const NoResultWrapper = styled.div` - padding: 15px; - font-size: 1.4rem; - box-shadow: 2px 2px 2px black; -`; - -export default AutoCompleteContainer; diff --git a/src/components/search/SearchForm.tsx b/src/components/search/SearchForm.tsx index d11d616..658c86b 100644 --- a/src/components/search/SearchForm.tsx +++ b/src/components/search/SearchForm.tsx @@ -1,5 +1,5 @@ -import SearchHeaderForm from './SearchHeaderForm'; -import SearchPageForm from './SearchPageForm'; +import SearchHeaderForm from './searchHeaderForm/SearchHeaderForm'; +import SearchPageForm from './searchPageForm/SearchPageForm'; interface SearchFormProps { type: string; diff --git a/src/components/search/SearchFound.tsx b/src/components/search/SearchFound.tsx deleted file mode 100644 index 62dc65a..0000000 --- a/src/components/search/SearchFound.tsx +++ /dev/null @@ -1,104 +0,0 @@ -'use client'; - -import { IGenerations } from '@/types/request'; -import type { SearchResult } from '@/types/search'; -import Image from 'next/image'; -import { useRouter } from 'next/navigation'; -import styled from 'styled-components'; - -const SearchFound = ({ searchResult }: { searchResult: SearchResult[] }) => { - const router = useRouter(); - - const handleClickSearchResult = (id: number) => { - const selectedDocTitle = searchResult.filter((result) => result.id === id)[0].title; - const encodedTitle = encodeURIComponent(selectedDocTitle); - router.push(`viewer?title=${encodedTitle}`); - }; - - return ( - - {searchResult.map((result) => ( - - - - - handleClickSearchResult(result.id)}> - {result.title} - {result.content} - {getGenerationFormat(result.generations)} - - - ))} - - ); -}; - -const getGenerationFormat = (generations: IGenerations[]) => { - const genFormat: string[] = []; - generations.forEach((data) => { - genFormat.push(data.generation); - }); - return genFormat.join(', '); -}; - -const SearchFoundWrapper = styled.div` - display: flex; - flex-direction: column; - align-items: center; - margin-top: 20px; - @media screen and (max-width: 540px) { - margin-left: 15rem; - } -`; - -const SearchResult = styled.div` - display: flex; - align-items: end; - justify-content: center; - gap: 20px; - margin: 30px; -`; - -const LionImageWrapper = styled.div` - width: 13rem; - display: flex; - align-items: center; -`; - -const StyledImage = styled(Image)` - position: relative !important; - height: unset !important; -`; - -const SearchResultBox = styled.div` - width: 65vw; - display: flex; - flex-direction: column; - justify-content: center; - background-color: white; - border: 3px solid black; - border-radius: 10px; - padding: 30px; - cursor: pointer; -`; - -const SearchResultTitle = styled.div` - font-size: 1.8rem; - font-weight: bold; -`; - -const SearchResultContent = styled.div` - height: 6rem; - overflow: hidden; - line-height: 2rem; - margin-top: 10px; - margin-bottom: 10px; - font-size: 1.4rem; -`; - -const SearchResultDirectory = styled.div` - font-size: 1.6rem; - font-weight: bold; -`; - -export default SearchFound; diff --git a/src/components/search/SearchHeadSection.tsx b/src/components/search/SearchHeadSection.tsx deleted file mode 100644 index a6f80ad..0000000 --- a/src/components/search/SearchHeadSection.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client'; - -import Image from 'next/image'; -import styled from 'styled-components'; - -const SearchHeadSection = () => { - return ( - - - - - - ); -}; - -const SearchHeadWrapper = styled.div` - display: flex; - flex-direction: column; - gap: 10px; - padding: 50px; -`; - -const StyledImage = styled(Image)` - position: relative !important; - height: unset !important; -`; - -const HeartImageWrapper = styled.div` - position: relative; - width: 25rem; -`; - -export default SearchHeadSection; diff --git a/src/components/search/SearchHeaderForm.tsx b/src/components/search/SearchHeaderForm.tsx deleted file mode 100644 index 3e437a6..0000000 --- a/src/components/search/SearchHeaderForm.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import useSearchForm from '@/hooks/useSearchForm'; -import Image from 'next/image'; -import React from 'react'; -import styled from 'styled-components'; - -const SearchHeaderForm = ({ searchKeyword }: { searchKeyword?: string }) => { - const { values, handleChange, handleSearchSubmit } = useSearchForm({ - initialValue: { searchInput: '', searchHeaderInput: '' }, - searchKeyword, - }); - - return ( - - - - {'search'} - - - - - ); -}; -const FormWrapper = styled.form``; - -const SearchWrapper = styled.div` - display: flex; - align-items: center; - border-bottom: 1px solid black; - padding: 2px 0rem; -`; - -const SearchHeaderInput = styled.input` - font-family: NeoDunggeunmo Pro; - width: 100%; - height: 100%; - font-size: 1.5rem; - border: none; - outline: none; - padding-left: 1rem; -`; - -const ImageButtonWrapper = styled.button` - border: none; - outline: none; - background-color: inherit; -`; - -export default SearchHeaderForm; diff --git a/src/components/search/SearchNotFound.tsx b/src/components/search/SearchNotFound.tsx deleted file mode 100644 index 6b345f3..0000000 --- a/src/components/search/SearchNotFound.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import Image from 'next/image'; -import styled from 'styled-components'; - -const SearchNotFound = ({ searchKeyword }: { searchKeyword: string }) => { - return ( - - 해당 문서가 없습니다. 위키에 {searchKeyword} 문서를 만드세요! - - - - - - - ); -}; - -const SearchNotFoundWrapper = styled.div` - margin-top: 10px; -`; - -const NotFoundSearchText = styled.div` - font-size: 1.5rem; - font-weight: bold; - color: red; - margin-left: 12%; -`; - -const BottomImageWrapper = styled.div` - display: flex; - justify-content: center; - align-items: flex-end; -`; - -const LionImageWrapper = styled.div` - width: 65vw; - position: absolute; - bottom: 0; -`; - -const StyledImage = styled(Image)` - position: relative !important; - height: unset !important; - object-fit: cover; -`; - -export default SearchNotFound; diff --git a/src/components/search/SearchResult.tsx b/src/components/search/SearchResult.tsx index 639f527..1eb1ea1 100644 --- a/src/components/search/SearchResult.tsx +++ b/src/components/search/SearchResult.tsx @@ -1,8 +1,8 @@ import { ISearchResult, ISearchResultList } from '@/types/search'; import React from 'react'; import Loading from '../common/Loading'; -import SearchFound from './SearchFound'; -import SearchNotFound from './SearchNotFound'; +import SearchFound from './searchFound/SearchFound'; +import SearchNotFound from './searchNotFound/SearchNotFound'; interface SearchResultProps { searchResult: ISearchResult | ISearchResultList | undefined; diff --git a/src/components/search/autoCompleteContainer/AutoCompleteContainer.styled.ts b/src/components/search/autoCompleteContainer/AutoCompleteContainer.styled.ts new file mode 100644 index 0000000..295c124 --- /dev/null +++ b/src/components/search/autoCompleteContainer/AutoCompleteContainer.styled.ts @@ -0,0 +1,27 @@ +import styled from 'styled-components'; + +export const BoxWrapper = styled.div` + display: flex; + flex-direction: column; + width: 40vw; + background-color: white; + margin-left: 2%; + gap: 10px; + box-shadow: 2px 2px 2px black; + z-index: 1; +`; + +export const ItemWrapper = styled.div` + padding: 15px; + font-size: 1.4rem; + cursor: pointer; + &:hover { + background-color: lightgrey; + } +`; + +export const NoResultWrapper = styled.span` + padding: 15px; + font-size: 1.4rem; + box-shadow: 2px 2px 2px black; +`; diff --git a/src/components/search/autoCompleteContainer/AutoCompleteContainer.tsx b/src/components/search/autoCompleteContainer/AutoCompleteContainer.tsx new file mode 100644 index 0000000..ee92815 --- /dev/null +++ b/src/components/search/autoCompleteContainer/AutoCompleteContainer.tsx @@ -0,0 +1,36 @@ +import { useSearchAutoCompleteQuery } from '@/hooks/useSearchAutoCompleteQuery'; +import { useRouter } from 'next/navigation'; +import * as S from './AutoCompleteContainer.styled'; + +interface AutoProps { + searchInput: string; +} + +const AutoCompleteContainer = ({ searchInput }: AutoProps) => { + const router = useRouter(); + const { data: dropdownList, isLoading } = useSearchAutoCompleteQuery(searchInput); + + if (isLoading) { + return ( + + 검색중... + + ); + } + + return ( + + {dropdownList && dropdownList.length > 0 ? ( + dropdownList.map((title, idx) => ( + router.push(`search/?search=${title}`)}> + {title} + + )) + ) : ( + 검색결과가 없습니다. + )} + + ); +}; + +export default AutoCompleteContainer; diff --git a/src/components/search/searchBodySection/SearchBodySection.styled.ts b/src/components/search/searchBodySection/SearchBodySection.styled.ts new file mode 100644 index 0000000..d76eb43 --- /dev/null +++ b/src/components/search/searchBodySection/SearchBodySection.styled.ts @@ -0,0 +1,19 @@ +import Image from 'next/image'; +import styled from 'styled-components'; + +export const SearchBarWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 20px; + margin-left: 10%; +`; + +export const TextImageWrapper = styled.div` + position: relative; + width: 30rem; +`; + +export const StyledImage = styled(Image)` + position: relative !important; + height: unset !important; +`; diff --git a/src/components/search/SearchBodySection.tsx b/src/components/search/searchBodySection/SearchBodySection.tsx similarity index 66% rename from src/components/search/SearchBodySection.tsx rename to src/components/search/searchBodySection/SearchBodySection.tsx index 921914b..1004033 100644 --- a/src/components/search/SearchBodySection.tsx +++ b/src/components/search/searchBodySection/SearchBodySection.tsx @@ -2,12 +2,10 @@ import { useRouter, useSearchParams } from 'next/navigation'; import React, { useEffect, useState } from 'react'; -import styled from 'styled-components'; -import SearchForm from './SearchForm'; -import Image from 'next/image'; - +import SearchForm from '../SearchForm'; +import * as S from './SearchBodySection.styled'; import { useSearchQuery } from '@/hooks/useSearchQuery'; -import SearchResultContainer from './SearchResult'; +import SearchResultContainer from '../SearchResult'; const SearchBodySection = () => { const router = useRouter(); @@ -29,38 +27,21 @@ const SearchBodySection = () => { return ( <> - - - + + - + - + ); }; -const SearchBarWrapper = styled.div` - display: flex; - flex-direction: column; - gap: 20px; - margin-left: 10%; -`; - -const TextImageWrapper = styled.div` - position: relative; - width: 30rem; -`; - -const StyledImage = styled(Image)` - position: relative !important; - height: unset !important; -`; - export default SearchBodySection; diff --git a/src/components/search/searchFound/SearchFound.styled.ts b/src/components/search/searchFound/SearchFound.styled.ts new file mode 100644 index 0000000..2d5cfaa --- /dev/null +++ b/src/components/search/searchFound/SearchFound.styled.ts @@ -0,0 +1,62 @@ +import styled from 'styled-components'; +import Image from 'next/image'; + +export const SearchFoundWrapper = styled.div` + display: flex; + flex-direction: column; + align-items: center; + margin-top: 20px; + @media screen and (max-width: 540px) { + margin-left: 15rem; + } +`; + +export const SearchResultWrapper = styled.div` + display: flex; + align-items: end; + justify-content: center; + gap: 20px; + margin: 30px; +`; + +export const LionImageWrapper = styled.div` + width: 13rem; + display: flex; + align-items: center; +`; + +export const StyledImage = styled(Image)` + position: relative !important; + height: unset !important; +`; + +export const SearchResultBox = styled.div` + width: 65vw; + display: flex; + flex-direction: column; + justify-content: center; + background-color: white; + border: 3px solid black; + border-radius: 10px; + padding: 30px; + cursor: pointer; +`; + +export const SearchResultTitle = styled.div` + font-size: 1.8rem; + font-weight: bold; +`; + +export const SearchResultContent = styled.div` + height: 6rem; + overflow: hidden; + line-height: 2rem; + margin-top: 10px; + margin-bottom: 10px; + font-size: 1.4rem; +`; + +export const SearchResultDirectory = styled.div` + font-size: 1.6rem; + font-weight: bold; +`; diff --git a/src/components/search/searchFound/SearchFound.tsx b/src/components/search/searchFound/SearchFound.tsx new file mode 100644 index 0000000..fb98f8c --- /dev/null +++ b/src/components/search/searchFound/SearchFound.tsx @@ -0,0 +1,35 @@ +'use client'; + +import { useRouter } from 'next/navigation'; +import * as S from './SearchFound.styled'; +import type { SearchResult } from '@/types/search'; +import { getGenerationFormat } from './SearchFound.utils'; + +const SearchFound = ({ searchResult }: { searchResult: SearchResult[] }) => { + const router = useRouter(); + + const handleClickSearchResult = (id: number) => { + const selectedDocTitle = searchResult.filter((result) => result.id === id)[0].title; + const encodedTitle = encodeURIComponent(selectedDocTitle); + router.push(`viewer?title=${encodedTitle}`); + }; + + return ( + + {searchResult.map((result) => ( + + + + + handleClickSearchResult(result.id)}> + {result.title} + {result.content} + {getGenerationFormat(result.generations)} + + + ))} + + ); +}; + +export default SearchFound; diff --git a/src/components/search/searchFound/SearchFound.utils.ts b/src/components/search/searchFound/SearchFound.utils.ts new file mode 100644 index 0000000..16ec2d3 --- /dev/null +++ b/src/components/search/searchFound/SearchFound.utils.ts @@ -0,0 +1,9 @@ +import { IGenerations } from '@/types/request'; + +export const getGenerationFormat = (generations: IGenerations[]) => { + const genFormat: string[] = []; + generations.forEach((data) => { + genFormat.push(data.generation); + }); + return genFormat.join(', '); +}; diff --git a/src/components/search/searchHeaderForm/SearchHeaderForm.styled.ts b/src/components/search/searchHeaderForm/SearchHeaderForm.styled.ts new file mode 100644 index 0000000..0171103 --- /dev/null +++ b/src/components/search/searchHeaderForm/SearchHeaderForm.styled.ts @@ -0,0 +1,26 @@ +import styled from 'styled-components'; + +export const FormWrapper = styled.form``; + +export const SearchWrapper = styled.div` + display: flex; + align-items: center; + border-bottom: 1px solid black; + padding: 2px 0rem; +`; + +export const SearchHeaderInput = styled.input` + font-family: NeoDunggeunmo Pro; + width: 100%; + height: 100%; + font-size: 1.5rem; + border: none; + outline: none; + padding-left: 1rem; +`; + +export const ImageButtonWrapper = styled.button` + border: none; + outline: none; + background-color: inherit; +`; diff --git a/src/components/search/searchHeaderForm/SearchHeaderForm.tsx b/src/components/search/searchHeaderForm/SearchHeaderForm.tsx new file mode 100644 index 0000000..e7aa0c6 --- /dev/null +++ b/src/components/search/searchHeaderForm/SearchHeaderForm.tsx @@ -0,0 +1,30 @@ +import useSearchForm from '@/hooks/useSearchForm'; +import Image from 'next/image'; +import React from 'react'; +import * as S from './SearchHeaderForm.styled'; + +const SearchHeaderForm = ({ searchKeyword }: { searchKeyword?: string }) => { + const { values, handleChange, handleSearchSubmit } = useSearchForm({ + initialValue: { searchInput: '', searchHeaderInput: '' }, + searchKeyword, + }); + + return ( + + + + {'search'} + + + + + ); +}; + +export default SearchHeaderForm; diff --git a/src/components/search/searchHeaderSection/SearchHeaderSection.styled.ts b/src/components/search/searchHeaderSection/SearchHeaderSection.styled.ts new file mode 100644 index 0000000..4a14efa --- /dev/null +++ b/src/components/search/searchHeaderSection/SearchHeaderSection.styled.ts @@ -0,0 +1,19 @@ +import Image from 'next/image'; +import styled from 'styled-components'; + +export const SearchHeaderWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 10px; + padding: 50px; +`; + +export const StyledImage = styled(Image)` + position: relative !important; + height: unset !important; +`; + +export const HeartImageWrapper = styled.div` + position: relative; + width: 25rem; +`; diff --git a/src/components/search/searchHeaderSection/SearchHeaderSection.tsx b/src/components/search/searchHeaderSection/SearchHeaderSection.tsx new file mode 100644 index 0000000..c9d7cfb --- /dev/null +++ b/src/components/search/searchHeaderSection/SearchHeaderSection.tsx @@ -0,0 +1,15 @@ +'use client'; + +import * as S from './SearchHeaderSection.styled'; + +const SearchHeaderSection = () => { + return ( + + + + + + ); +}; + +export default SearchHeaderSection; diff --git a/src/components/search/searchNotFound/SearchNotFound.styled.ts b/src/components/search/searchNotFound/SearchNotFound.styled.ts new file mode 100644 index 0000000..dfd5533 --- /dev/null +++ b/src/components/search/searchNotFound/SearchNotFound.styled.ts @@ -0,0 +1,31 @@ +import Image from 'next/image'; +import styled from 'styled-components'; + +export const SearchNotFoundWrapper = styled.div` + margin-top: 10px; +`; + +export const NotFoundSearchText = styled.div` + font-size: 1.5rem; + font-weight: bold; + color: red; + margin-left: 12%; +`; + +export const BottomImageWrapper = styled.div` + display: flex; + justify-content: center; + align-items: flex-end; +`; + +export const LionImageWrapper = styled.div` + width: 65vw; + position: absolute; + bottom: 0; +`; + +export const StyledImage = styled(Image)` + position: relative !important; + height: unset !important; + object-fit: cover; +`; diff --git a/src/components/search/searchNotFound/SearchNotFound.tsx b/src/components/search/searchNotFound/SearchNotFound.tsx new file mode 100644 index 0000000..90600e1 --- /dev/null +++ b/src/components/search/searchNotFound/SearchNotFound.tsx @@ -0,0 +1,16 @@ +import * as S from './SearchNotFound.styled'; + +const SearchNotFound = ({ searchKeyword }: { searchKeyword: string }) => { + return ( + + 해당 문서가 없습니다. 위키에 {searchKeyword} 문서를 만드세요! + + + + + + + ); +}; + +export default SearchNotFound; diff --git a/src/components/search/searchPageForm/SearchPageForm.styled.ts b/src/components/search/searchPageForm/SearchPageForm.styled.ts new file mode 100644 index 0000000..db27540 --- /dev/null +++ b/src/components/search/searchPageForm/SearchPageForm.styled.ts @@ -0,0 +1,20 @@ +import styled from 'styled-components'; + +export const FormWrapper = styled.form``; + +export const SearchBarInput = styled.input` + background: url('/img/search_bar.png'); + background-repeat: no-repeat; + background-size: contain; + border: none; + font-size: 2rem; + font-family: Pretendard; + padding: 10px; + padding-left: 30px; + width: 55rem; + height: 2.5rem; + + &:focus { + outline: none; + } +`; diff --git a/src/components/search/SearchPageForm.tsx b/src/components/search/searchPageForm/SearchPageForm.tsx similarity index 69% rename from src/components/search/SearchPageForm.tsx rename to src/components/search/searchPageForm/SearchPageForm.tsx index c8a3467..f9ca4a4 100644 --- a/src/components/search/SearchPageForm.tsx +++ b/src/components/search/searchPageForm/SearchPageForm.tsx @@ -1,8 +1,8 @@ +import { useEffect } from 'react'; import useDebounceValue from '@/hooks/useDebounce'; import useSearchForm from '@/hooks/useSearchForm'; -import { useEffect } from 'react'; -import styled from 'styled-components'; -import AutoCompleteContainer from './AutoCompleteContainer'; +import AutoCompleteContainer from '../autoCompleteContainer/AutoCompleteContainer'; +import * as S from './SearchPageForm.styled'; const SearchPageForm = ({ searchKeyword }: { searchKeyword?: string }) => { const { values, isFocused, handleFocus, handleBlur, handleChange, handleSearchSubmit } = useSearchForm({ @@ -26,8 +26,8 @@ const SearchPageForm = ({ searchKeyword }: { searchKeyword?: string }) => { }, []); return ( - - + { autoComplete="off" /> {isFocused && values.searchInput.length > 0 && } - + ); }; -const FormWrapper = styled.form``; - -const SearchBarInput = styled.input` - background: url('/img/search_bar.png'); - background-repeat: no-repeat; - background-size: contain; - border: none; - font-size: 2rem; - font-family: Pretendard; - padding: 10px; - padding-left: 30px; - width: 55rem; - height: 2.5rem; - - &:focus { - outline: none; - } -`; - export default SearchPageForm;