diff --git a/src/components/projects/main/ProjectList.tsx b/src/components/projects/main/ProjectList.tsx index b4e6968de..a5b2b11dd 100644 --- a/src/components/projects/main/ProjectList.tsx +++ b/src/components/projects/main/ProjectList.tsx @@ -4,46 +4,44 @@ import { ImpressionArea } from '@toss/impression-area'; import { uniqBy as _uniqBy } from 'lodash-es'; import Link from 'next/link'; -import Responsive from '@/components/common/Responsive'; import Text from '@/components/common/Text'; import useEventLogger from '@/components/eventLogger/hooks/useEventLogger'; import ProjectCard from '@/components/projects/main/ProjectCard'; import useGetProjectListQuery from '@/components/projects/upload/hooks/useGetProjectListQuery'; import { playgroundLink } from '@/constants/links'; import IconPen from '@/public/icons/icon-pen.svg'; -import IconPlusWhite from '@/public/icons/icon-plus-black.svg'; import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery'; import { textStyles } from '@/styles/typography'; +import ProjectSearch from '@/components/projects/main/ProjectSearch'; +import { StringParam, useQueryParam, withDefault } from 'use-query-params'; +import { useDebounce } from '@toss/react'; +import { fonts } from '@sopt-makers/fonts'; +import { useState } from 'react'; const ProjectList = () => { + const [query, setQuery] = useQueryParam('name', withDefault(StringParam, undefined)); + const [value, setValue] = useState(query); + const debouncedChangeName = useDebounce(setQuery, 300); const { data, isLoading, fetchNextPage } = useGetProjectListQuery({ limit: 20, + name: query, }); const { logClickEvent } = useEventLogger(); return ( - - - ✨ 솝트에서 진행된 프로젝트 둘러보기 - - - - logClickEvent('projectUpload', { - referral: 'projectPage', - }) - } - > - - 내 프로젝트 올리기 - - - + { + setValue(value); + debouncedChangeName(value); + }} + placeholder='프로젝트 검색' + /> + - {data?.pages && {data.pages[0].totalCount}개의 프로젝트} + {data?.pages && 전체 {data.pages[0].totalCount}개} logClickEvent('projectUpload', { @@ -66,6 +64,10 @@ const ProjectList = () => { )} + + + 프로젝트 올리기 + ); }; @@ -92,21 +94,6 @@ const StyledContent = styled.div` } `; -const Title = styled(Text)` - ${textStyles.SUIT_32_B}; - - @media ${MOBILE_MEDIA_QUERY} { - margin: 0 6px; - ${textStyles.SUIT_20_B}; - } -`; - -const TopWrapper = styled.div` - display: flex; - align-items: center; - justify-content: space-between; -`; - const ProjectMobileUploadButton = styled(Link)` display: none; @media ${MOBILE_MEDIA_QUERY} { @@ -118,23 +105,43 @@ const ProjectMobileUploadButton = styled(Link)` const ProjectUploadButton = styled(Link)` display: flex; - gap: 12px; + position: fixed; + right: 60px; + bottom: 80px; + gap: 8px; align-items: center; - border-radius: 10px; + border-radius: 18px; background-color: ${colors.gray10}; - padding: 18px 24px 18px 20px; + padding: 14px 30px 14px 27px; color: ${colors.gray950}; + ${fonts.TITLE_20_SB}; &:hover { background-color: ${colors.gray50}; } + + @media ${MOBILE_MEDIA_QUERY} { + right: 16px; + bottom: 16px; + padding: 12px; + ${fonts.LABEL_16_SB} + } `; +const PlusIcon = () => ( + + + +); + const LengthWrapper = styled.div` display: flex; align-items: center; justify-content: space-between; - margin-top: 48px; + margin-top: 20px; @media ${MOBILE_MEDIA_QUERY} { margin: 30px 6px 0; @@ -142,10 +149,10 @@ const LengthWrapper = styled.div` `; const StyledLength = styled(Text)` - ${textStyles.SUIT_18_M}; + ${fonts.BODY_16_M}; @media ${MOBILE_MEDIA_QUERY} { - ${textStyles.SUIT_16_M}; + ${fonts.BODY_14_M}; } `; diff --git a/src/components/projects/main/ProjectSearch.tsx b/src/components/projects/main/ProjectSearch.tsx new file mode 100644 index 000000000..dc12d0a33 --- /dev/null +++ b/src/components/projects/main/ProjectSearch.tsx @@ -0,0 +1,70 @@ +import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery'; + +import styled from '@emotion/styled'; +import { colors } from '@sopt-makers/colors'; +import { fonts } from '@sopt-makers/fonts'; +import { Flex, width100 } from '@toss/emotion-utils'; + +interface ProjectSearchProps { + defaultValue?: string; + value?: string; + onValueChange?: (value: string) => void; + placeholder?: string; +} + +const ProjectSearch = ({ value, defaultValue, onValueChange, placeholder }: ProjectSearchProps) => { + return ( + + onValueChange?.(e.target.value)} + /> + + + ); +}; + +export default ProjectSearch; + +const Container = styled(Flex)` + gap: 8px; + border-radius: 8px; + background-color: ${colors.gray800}; + padding: 16px 14px; + + ${width100} + + @media ${MOBILE_MEDIA_QUERY} { + border-radius: 6px; + padding: 9px 18px; + ${fonts.BODY_14_M}; + } +`; + +const Input = styled.input` + color: ${colors.gray200}; + ${width100}; + ${fonts.BODY_16_M}; + + ::placeholder { + ${colors.gray200}; + } +`; + +const Icon = () => ( + + + + +);