diff --git a/.eslintrc.json b/.eslintrc.json index bdd27ad..646a272 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -23,6 +23,7 @@ "import/order": "off", "no-console": "off", "react/function-component-definition": "off", - "arrow-body-style": "off" + "arrow-body-style": "off", + "jsx-a11y/no-autofocus": "off" } } diff --git a/next.config.js b/next.config.js index 3f3be5d..5e98ec0 100644 --- a/next.config.js +++ b/next.config.js @@ -1,8 +1,12 @@ -const { createVanillaExtractPlugin } = require("@vanilla-extract/next-plugin"); +const { createVanillaExtractPlugin } = require('@vanilla-extract/next-plugin'); const withVanillaExtract = createVanillaExtractPlugin(); /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + compiler: { + removeConsole: process.env.NODE_ENV === 'production', + }, +}; module.exports = withVanillaExtract(nextConfig); diff --git a/src/app/layout.tsx b/src/app/layout.tsx index ca878f8..f3108d5 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,5 +1,5 @@ -import ThemeProvider from '@/providers/ThemeProvider/ThemeProvider'; -import '../styles/globalStyles.css.ts'; +import ThemeProvider from '@/commons/providers/ThemeProvider/ThemeProvider.tsx'; +import '../commons/styles/globalStyles.css.ts'; import { Metadata } from 'next'; export const metadata: Metadata = { diff --git a/src/app/page.tsx b/src/app/page.tsx index cb0592a..98618df 100755 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,8 +1,8 @@ -import RemoteControl from '@/components/features/Common/RemoteControl/RemoteControl'; -import Card from '@/components/features/Items/Card/Card'; -import Header from '@/components/widgets/Header/Header'; -import SearchToolbar from '@/components/widgets/SearchToolbar/SearchToolbar'; -import * as styles from '@/styles/rootStyles.css'; +import RemoteControl from '@/commons/components/features/Common/RemoteControl/RemoteControl'; +import Card from '@/commons/components/features/Items/Card/Card'; +import Header from '@/commons/components/widgets/Header/Header'; +import SearchToolbar from '@/commons/components/widgets/SearchToolbar/SearchToolbar'; +import * as styles from '@/commons/styles/rootStyles.css'; export default function RootPage() { return ( diff --git a/src/components/atoms/Icons/ArrowUp/ArrowUp.tsx b/src/commons/components/atoms/Icons/ArrowUp/ArrowUp.tsx similarity index 100% rename from src/components/atoms/Icons/ArrowUp/ArrowUp.tsx rename to src/commons/components/atoms/Icons/ArrowUp/ArrowUp.tsx diff --git a/src/components/atoms/Icons/MagnifyingGlass/MagnifyingGlass.tsx b/src/commons/components/atoms/Icons/MagnifyingGlass/MagnifyingGlass.tsx similarity index 100% rename from src/components/atoms/Icons/MagnifyingGlass/MagnifyingGlass.tsx rename to src/commons/components/atoms/Icons/MagnifyingGlass/MagnifyingGlass.tsx diff --git a/src/components/atoms/Icons/Moon/Moon.tsx b/src/commons/components/atoms/Icons/Moon/Moon.tsx similarity index 100% rename from src/components/atoms/Icons/Moon/Moon.tsx rename to src/commons/components/atoms/Icons/Moon/Moon.tsx diff --git a/src/components/atoms/Icons/Sun/Sun.tsx b/src/commons/components/atoms/Icons/Sun/Sun.tsx similarity index 100% rename from src/components/atoms/Icons/Sun/Sun.tsx rename to src/commons/components/atoms/Icons/Sun/Sun.tsx diff --git a/src/components/atoms/Icons/Tag/Tag.tsx b/src/commons/components/atoms/Icons/Tag/Tag.tsx similarity index 100% rename from src/components/atoms/Icons/Tag/Tag.tsx rename to src/commons/components/atoms/Icons/Tag/Tag.tsx diff --git a/src/commons/components/atoms/boxes/tagBox/tagBox.css.ts b/src/commons/components/atoms/boxes/tagBox/tagBox.css.ts new file mode 100644 index 0000000..9f5ded6 --- /dev/null +++ b/src/commons/components/atoms/boxes/tagBox/tagBox.css.ts @@ -0,0 +1,9 @@ +import { style } from '@vanilla-extract/css'; + +export const tagBox = style({ + padding: '8px 10px', + borderRadius: '50px', + backgroundColor: '#6A6868', + + fontSize: '12px', +}); diff --git a/src/commons/components/atoms/boxes/tagBox/tagBox.tsx b/src/commons/components/atoms/boxes/tagBox/tagBox.tsx new file mode 100644 index 0000000..a0b2369 --- /dev/null +++ b/src/commons/components/atoms/boxes/tagBox/tagBox.tsx @@ -0,0 +1,5 @@ +import * as styles from './tagBox.css'; + +export function TagBox({ tagName }: { tagName: string }) { + return
{tagName}
; +} diff --git a/src/components/features/Common/RemoteControl/RemoteControl.css.ts b/src/commons/components/features/Common/RemoteControl/RemoteControl.css.ts similarity index 100% rename from src/components/features/Common/RemoteControl/RemoteControl.css.ts rename to src/commons/components/features/Common/RemoteControl/RemoteControl.css.ts diff --git a/src/components/features/Common/RemoteControl/RemoteControl.tsx b/src/commons/components/features/Common/RemoteControl/RemoteControl.tsx similarity index 72% rename from src/components/features/Common/RemoteControl/RemoteControl.tsx rename to src/commons/components/features/Common/RemoteControl/RemoteControl.tsx index c7473fb..603384c 100644 --- a/src/components/features/Common/RemoteControl/RemoteControl.tsx +++ b/src/commons/components/features/Common/RemoteControl/RemoteControl.tsx @@ -1,7 +1,7 @@ 'use client'; -import ArrowUp from '@/components/atoms/Icons/ArrowUp/ArrowUp'; -import { scrollToTop } from '@/utils/ui/scrollToTop/scrollToTop'; +import ArrowUp from '@/commons/components/atoms/Icons/ArrowUp/ArrowUp'; +import { scrollToTop } from '@/commons/utils/ui/scrollToTop/scrollToTop'; import * as styles from './RemoteControl.css'; export default function RemoteControl() { diff --git a/src/components/features/Common/Slider/Slider.css.ts b/src/commons/components/features/Common/Slider/Slider.css.ts similarity index 94% rename from src/components/features/Common/Slider/Slider.css.ts rename to src/commons/components/features/Common/Slider/Slider.css.ts index f00ce2a..128ed88 100644 --- a/src/components/features/Common/Slider/Slider.css.ts +++ b/src/commons/components/features/Common/Slider/Slider.css.ts @@ -1,4 +1,4 @@ -import { vars } from '@/styles/globalStyles.css'; +import { vars } from '@/commons/styles/globalStyles.css'; import { keyframes, style } from '@vanilla-extract/css'; export const wrapper = style({ diff --git a/src/components/features/Common/Slider/Slider.tsx b/src/commons/components/features/Common/Slider/Slider.tsx similarity index 100% rename from src/components/features/Common/Slider/Slider.tsx rename to src/commons/components/features/Common/Slider/Slider.tsx diff --git a/src/components/features/Common/ThemeIcon/ThemeIcon.tsx b/src/commons/components/features/Common/ThemeIcon/ThemeIcon.tsx similarity index 67% rename from src/components/features/Common/ThemeIcon/ThemeIcon.tsx rename to src/commons/components/features/Common/ThemeIcon/ThemeIcon.tsx index 43b682c..a52f30e 100644 --- a/src/components/features/Common/ThemeIcon/ThemeIcon.tsx +++ b/src/commons/components/features/Common/ThemeIcon/ThemeIcon.tsx @@ -1,6 +1,6 @@ -import Moon from '@/components/atoms/Icons/Moon/Moon'; -import Sun from '@/components/atoms/Icons/Sun/Sun'; -import { Theme } from '@/types/theme'; +import Moon from '@/commons/components/atoms/Icons/Moon/Moon'; +import Sun from '@/commons/components/atoms/Icons/Sun/Sun'; +import { Theme } from '@/commons/types/theme'; import { ThemeIconProps } from './ThemeIcon.types'; export default function ThemeIcon({ setTheme, resolvedTheme }: ThemeIconProps) { diff --git a/src/components/features/Common/ThemeIcon/ThemeIcon.types.ts b/src/commons/components/features/Common/ThemeIcon/ThemeIcon.types.ts similarity index 100% rename from src/components/features/Common/ThemeIcon/ThemeIcon.types.ts rename to src/commons/components/features/Common/ThemeIcon/ThemeIcon.types.ts diff --git a/src/commons/components/features/Inputs/CollapsedSearch/CollapsedSearch.css.ts b/src/commons/components/features/Inputs/CollapsedSearch/CollapsedSearch.css.ts new file mode 100644 index 0000000..c6a4ebd --- /dev/null +++ b/src/commons/components/features/Inputs/CollapsedSearch/CollapsedSearch.css.ts @@ -0,0 +1,8 @@ +import { style } from '@vanilla-extract/css'; + +export const collapsedSearchWrapper = style({ + display: 'flex', + flexDirection: 'row', + + marginRight: 'auto', +}); diff --git a/src/commons/components/features/Inputs/CollapsedSearch/CollapsedSearch.tsx b/src/commons/components/features/Inputs/CollapsedSearch/CollapsedSearch.tsx new file mode 100644 index 0000000..74958df --- /dev/null +++ b/src/commons/components/features/Inputs/CollapsedSearch/CollapsedSearch.tsx @@ -0,0 +1,27 @@ +import { collapsedSearchWrapper } from './CollapsedSearch.css'; +import { KeyboardEvent } from 'react'; +import Image from 'next/image'; +import { TagList } from '../../Lists/TagList/TagList'; + +export const CollapsedSearch = ({ + tagList, + handleKeyDown, +}: { + tagList: string[]; + handleKeyDown: (event: KeyboardEvent) => void; +}) => { + return ( + <> +
+ +
+ ReadingGlasses + + ); +}; diff --git a/src/commons/components/features/Inputs/ExpandedSearch/ExpandedSearch.css.ts b/src/commons/components/features/Inputs/ExpandedSearch/ExpandedSearch.css.ts new file mode 100644 index 0000000..c479ad4 --- /dev/null +++ b/src/commons/components/features/Inputs/ExpandedSearch/ExpandedSearch.css.ts @@ -0,0 +1,140 @@ +import { style } from '@vanilla-extract/css'; + +export const wrapper = style({ + position: 'relative', + + display: 'flex', + flexDirection: 'row', + backgroundColor: '#fff', + + width: '27rem', + height: '3rem', + padding: '10px 20px', + borderRadius: '50px', + + cursor: 'pointer', +}); + +export const glassesWrapper = style({ + display: 'flex', + flexDirection: 'row', +}); + +export const tagWrapper = style({ + display: 'flex', + flexDirection: 'row', + + marginRight: 'auto', +}); + +export const tagBox = style({ + padding: '6px', + borderRadius: '50px', + backgroundColor: '#6A6868', + + fontSize: '12px', + + marginRight: '10px', +}); + +export const OutExpandedWrapper = style({ + position: 'fixed', + top: '0', + left: '0', + right: '0', + bottom: '0', + + display: 'flex', + justifyContent: 'center', + + width: '100vw', // 100%에서 100vw로 변경 + height: '100vh', // 100%에서 100vh로 변경 + + padding: '80px 54px', + + zIndex: '1000', + backgroundColor: 'rgba(0, 0, 0, 0.65)', // 반투명 검은색으로 변경 +}); + +export const expandedWrapper = style({ + position: 'absolute', + top: '0', + left: '0', + right: '0', + bottom: '0', + + display: 'flex', + flexDirection: 'column', + + width: '37rem', + height: '22rem', + + backgroundColor: '#fff', + + borderRadius: '25px', + padding: '20px', + + zIndex: '2000', +}); + +export const searchInput = style({ + width: '100%', + height: '16px', + + marginBottom: '14px', + + backgroundColor: 'transparent', + color: '#000', + + fontSize: '14px', + + border: 'none', + outline: 'none', +}); + +export const expandedTagWrapper = style({ + display: 'flex', + flexDirection: 'row', + flexWrap: 'wrap', + + fontSize: '12px', +}); + +export const relatedTagWrapper = style({ + display: 'flex', + flexDirection: 'column', + + margin: '0', + padding: '0', +}); + +export const relatedTagBox = style({ + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + + width: '100%', + + gap: '10px', + + cursor: 'pointer', + + ':focus': { + outline: 'none', + backgroundColor: 'rgba(106, 104, 104, 0.1)', + }, + + ':hover': { + backgroundColor: 'rgba(106, 104, 104, 0.1)', + }, +}); + +export const relatedTagText = style({ + fontSize: '12px', + + color: '#000', +}); + +export const focusedTag = style({ + backgroundColor: 'rgba(106, 104, 104, 0.1)', +}); diff --git a/src/commons/components/features/Inputs/ExpandedSearch/ExpandedSearch.tsx b/src/commons/components/features/Inputs/ExpandedSearch/ExpandedSearch.tsx new file mode 100644 index 0000000..9cf5e42 --- /dev/null +++ b/src/commons/components/features/Inputs/ExpandedSearch/ExpandedSearch.tsx @@ -0,0 +1,54 @@ +import { TagType } from '@/domains/tag/tpyes/tag.type'; +import { RelatedTags } from '../../Lists/RelatedTags/RelatedTags'; +import { TagList } from '../../Lists/TagList/TagList'; +import * as styles from './ExpandedSearch.css'; +import { KeyboardEvent } from 'react'; + +export const ExpandedSearch = ({ + inputValue, + setInputValue, + handleKeyDown, + tagList, + relatedTags, + focusedIndex, + onClickRelatedTag, + onClickExpanded, +}: { + inputValue: string; + setInputValue: (value: string) => void; + handleKeyDown: (event: KeyboardEvent) => void; + tagList: string[]; + relatedTags: TagType[]; + focusedIndex: number; + onClickRelatedTag: (tag: TagType) => void; + onClickExpanded: () => void; +}) => { + return ( + <> +
+ setInputValue(e.target.value)} + onKeyDown={handleKeyDown} + autoFocus + /> + + + + +
+ +
+ + ); +}; diff --git a/src/components/features/Inputs/Search/Search.css.ts b/src/commons/components/features/Inputs/Search/Search.css.ts similarity index 88% rename from src/components/features/Inputs/Search/Search.css.ts rename to src/commons/components/features/Inputs/Search/Search.css.ts index d49c8a1..c479ad4 100644 --- a/src/components/features/Inputs/Search/Search.css.ts +++ b/src/commons/components/features/Inputs/Search/Search.css.ts @@ -116,6 +116,17 @@ export const relatedTagBox = style({ width: '100%', gap: '10px', + + cursor: 'pointer', + + ':focus': { + outline: 'none', + backgroundColor: 'rgba(106, 104, 104, 0.1)', + }, + + ':hover': { + backgroundColor: 'rgba(106, 104, 104, 0.1)', + }, }); export const relatedTagText = style({ @@ -123,3 +134,7 @@ export const relatedTagText = style({ color: '#000', }); + +export const focusedTag = style({ + backgroundColor: 'rgba(106, 104, 104, 0.1)', +}); diff --git a/src/commons/components/features/Inputs/Search/Search.tsx b/src/commons/components/features/Inputs/Search/Search.tsx new file mode 100644 index 0000000..c5ed84d --- /dev/null +++ b/src/commons/components/features/Inputs/Search/Search.tsx @@ -0,0 +1,124 @@ +'use client'; + +import { KeyboardEvent, useEffect, useState } from 'react'; +import * as styles from './Search.css'; +import { getTags } from '@/domains/tag/api/tags.api'; +import type { TagType } from '@/domains/tag/tpyes/tag.type'; +import { CollapsedSearch } from '../CollapsedSearch/CollapsedSearch'; +import { ExpandedSearch } from '../ExpandedSearch/ExpandedSearch'; + +export default function Search() { + const [isExpanded, setIsExpanded] = useState(false); + const [tagList, setTagList] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [relatedTags, setRelatedTags] = useState([]); + const [focusedIndex, setFocusedIndex] = useState(-1); + + useEffect(() => { + const searchTags = async () => { + if (inputValue.trim().length > 0) { + try { + const response = await getTags(inputValue); + setRelatedTags(response.tags); + } catch (error) { + console.error('태그 검색 실패:', error); + setRelatedTags([]); + } + } else { + setRelatedTags([]); + } + }; + + const timer = setTimeout(searchTags, 300); + return () => clearTimeout(timer); + }, [inputValue]); + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.nativeEvent.isComposing || event.keyCode === 229) return; + + if (event.key === 'ArrowDown') { + event.preventDefault(); + setFocusedIndex((prev) => { + if (prev === -1) return 0; + return Math.min(prev + 1, relatedTags.length - 1); + }); + return; + } + + if (event.key === 'ArrowUp') { + event.preventDefault(); + setFocusedIndex((prev) => { + const next = prev > 0 ? prev - 1 : -1; + return next; + }); + return; + } + + if (event.key === 'Enter') { + event.preventDefault(); + + if (focusedIndex >= 0 && relatedTags[focusedIndex]) { + const selectedTag = relatedTags[focusedIndex].name; + + setTagList((prev) => { + if (prev.includes(selectedTag)) { + return prev; + } + return [...prev, selectedTag]; + }); + + setInputValue(''); + setRelatedTags([]); + setFocusedIndex(-1); + } else if (inputValue.trim()) { + const newTag = inputValue.trim(); + + setTagList((prev) => { + if (prev.includes(newTag)) { + return prev; + } + return [...prev, newTag]; + }); + + setInputValue(''); + setRelatedTags([]); + } + return; + } + + if (event.key === 'Escape') { + setIsExpanded(false); + setFocusedIndex(-1); + } + }; + + const onClickExpanded = () => { + setIsExpanded((prev) => !prev); + }; + + const onClickRelatedTag = (tag: TagType) => { + setTagList((prev) => [...prev, tag.name]); + setInputValue(''); + setRelatedTags([]); + setFocusedIndex(-1); + }; + + return ( +
+ {isExpanded ? ( + + ) : ( + + )} +
+ ); +} diff --git a/src/components/features/Items/Card/Card.css.ts b/src/commons/components/features/Items/Card/Card.css.ts similarity index 100% rename from src/components/features/Items/Card/Card.css.ts rename to src/commons/components/features/Items/Card/Card.css.ts diff --git a/src/components/features/Items/Card/Card.tsx b/src/commons/components/features/Items/Card/Card.tsx similarity index 100% rename from src/components/features/Items/Card/Card.tsx rename to src/commons/components/features/Items/Card/Card.tsx diff --git a/src/commons/components/features/Lists/RelatedTags/RelatedTags.css.ts b/src/commons/components/features/Lists/RelatedTags/RelatedTags.css.ts new file mode 100644 index 0000000..ba1d464 --- /dev/null +++ b/src/commons/components/features/Lists/RelatedTags/RelatedTags.css.ts @@ -0,0 +1,40 @@ +import { style } from '@vanilla-extract/css'; + +export const relatedTagWrapper = style({ + display: 'flex', + flexDirection: 'column', + + margin: '0', + padding: '0', +}); + +export const relatedTagBox = style({ + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + + width: '100%', + + gap: '10px', + + cursor: 'pointer', + + ':focus': { + outline: 'none', + backgroundColor: 'rgba(106, 104, 104, 0.1)', + }, + + ':hover': { + backgroundColor: 'rgba(106, 104, 104, 0.1)', + }, +}); + +export const relatedTagText = style({ + fontSize: '12px', + + color: '#000', +}); + +export const focusedTag = style({ + backgroundColor: 'rgba(106, 104, 104, 0.1)', +}); diff --git a/src/commons/components/features/Lists/RelatedTags/RelatedTags.tsx b/src/commons/components/features/Lists/RelatedTags/RelatedTags.tsx new file mode 100644 index 0000000..12c9c6b --- /dev/null +++ b/src/commons/components/features/Lists/RelatedTags/RelatedTags.tsx @@ -0,0 +1,31 @@ +import type { TagType } from '@/domains/tag/tpyes/tag.type'; +import * as styles from './RelatedTags.css'; +import Tag from '@/commons/components/atoms/Icons/Tag/Tag'; + +export const RelatedTags = ({ + relatedTags, + focusedIndex, + onClickRelatedTag, +}: { + relatedTags: TagType[]; + focusedIndex: number; + onClickRelatedTag: (tag: TagType) => void; +}) => { + return ( +
    + {relatedTags.map((tag, index) => ( +
  • onClickRelatedTag(tag)} + tabIndex={0} + role="option" + aria-selected={index === focusedIndex} + > + +

    {tag.name}

    +
  • + ))} +
+ ); +}; diff --git a/src/commons/components/features/Lists/TagList/TagList.css.ts b/src/commons/components/features/Lists/TagList/TagList.css.ts new file mode 100644 index 0000000..ba3d37b --- /dev/null +++ b/src/commons/components/features/Lists/TagList/TagList.css.ts @@ -0,0 +1,11 @@ +import { style } from '@vanilla-extract/css'; + +export const tagListWrapper = style({ + display: 'flex', + flexDirection: 'row', + flexWrap: 'wrap', + + gap: '10px', + + fontSize: '12px', +}); diff --git a/src/commons/components/features/Lists/TagList/TagList.tsx b/src/commons/components/features/Lists/TagList/TagList.tsx new file mode 100644 index 0000000..9d402a2 --- /dev/null +++ b/src/commons/components/features/Lists/TagList/TagList.tsx @@ -0,0 +1,12 @@ +import { TagBox } from '@/commons/components/atoms/boxes/tagBox/tagBox'; +import * as styles from './TagList.css'; + +export const TagList = ({ tags }: { tags: string[] }) => { + return ( +
+ {tags.map((tag) => ( + + ))} +
+ ); +}; diff --git a/src/components/widgets/Header/Header.tsx b/src/commons/components/widgets/Header/Header.tsx similarity index 88% rename from src/components/widgets/Header/Header.tsx rename to src/commons/components/widgets/Header/Header.tsx index 6de42ca..e3fdc39 100755 --- a/src/components/widgets/Header/Header.tsx +++ b/src/commons/components/widgets/Header/Header.tsx @@ -1,7 +1,7 @@ 'use client'; import Image from 'next/image'; -import ThemeIcon from '@/components/features/Common/ThemeIcon/ThemeIcon'; +import ThemeIcon from '@/commons/components/features/Common/ThemeIcon/ThemeIcon'; import { useTheme } from 'next-themes'; import * as styles from './header.css'; diff --git a/src/components/widgets/Header/header.css.ts b/src/commons/components/widgets/Header/header.css.ts similarity index 100% rename from src/components/widgets/Header/header.css.ts rename to src/commons/components/widgets/Header/header.css.ts diff --git a/src/components/widgets/SearchToolbar/SearchToolbar.css.ts b/src/commons/components/widgets/SearchToolbar/SearchToolbar.css.ts similarity index 100% rename from src/components/widgets/SearchToolbar/SearchToolbar.css.ts rename to src/commons/components/widgets/SearchToolbar/SearchToolbar.css.ts diff --git a/src/components/widgets/SearchToolbar/SearchToolbar.tsx b/src/commons/components/widgets/SearchToolbar/SearchToolbar.tsx similarity index 56% rename from src/components/widgets/SearchToolbar/SearchToolbar.tsx rename to src/commons/components/widgets/SearchToolbar/SearchToolbar.tsx index 04d088e..d3fb690 100644 --- a/src/components/widgets/SearchToolbar/SearchToolbar.tsx +++ b/src/commons/components/widgets/SearchToolbar/SearchToolbar.tsx @@ -1,5 +1,5 @@ -import Slider from '@/components/features/Common/Slider/Slider'; -import Search from '@/components/features/Inputs/Search/Search'; +import Slider from '@/commons/components/features/Common/Slider/Slider'; +import Search from '@/commons/components/features/Inputs/Search/Search'; import * as styles from './SearchToolbar.css'; export default function SearchToolbar() { diff --git a/src/configs/fetch/http.api.ts b/src/commons/configs/fetch/http.api.ts similarity index 90% rename from src/configs/fetch/http.api.ts rename to src/commons/configs/fetch/http.api.ts index 6bf1b7f..d599fb0 100644 --- a/src/configs/fetch/http.api.ts +++ b/src/commons/configs/fetch/http.api.ts @@ -1,9 +1,3 @@ -interface ResponseData { - code: string; - isSuccess: boolean; - result: T; -} - type FetchOptions = RequestInit & { params?: Record; revalidate?: number | false; @@ -58,7 +52,7 @@ const createFetchInstance = (baseUrl: string) => { export const fetchApi = createFetchInstance(baseURL); const createApiMethods = (instance: (url: string, options?: FetchOptions) => Promise) => ({ - Get: async (url: string, params = {}, options: { revalidate?: number | false } = {}): Promise> => { + Get: async (url: string, params = {}, options: { revalidate?: number | false } = {}): Promise => { try { return await instance(url, { method: 'GET', @@ -70,7 +64,7 @@ const createApiMethods = (instance: (url: string, options?: FetchOptions) => Pro } }, - Post: async (url: string, data?: D, options = {}): Promise> => { + Post: async (url: string, data?: D, options = {}): Promise => { try { return await instance(url, { method: 'POST', @@ -83,7 +77,7 @@ const createApiMethods = (instance: (url: string, options?: FetchOptions) => Pro } }, - Put: async (url: string, data?: D, options = {}): Promise> => { + Put: async (url: string, data?: D, options = {}): Promise => { try { return await instance(url, { method: 'PUT', @@ -96,7 +90,7 @@ const createApiMethods = (instance: (url: string, options?: FetchOptions) => Pro } }, - Delete: async (url: string, options = {}): Promise> => { + Delete: async (url: string, options = {}): Promise => { try { return await instance(url, { method: 'DELETE', @@ -108,7 +102,7 @@ const createApiMethods = (instance: (url: string, options?: FetchOptions) => Pro } }, - Patch: async (url: string, data?: D, options = {}): Promise> => { + Patch: async (url: string, data?: D, options = {}): Promise => { try { return await instance(url, { method: 'PATCH', diff --git a/src/providers/ThemeProvider/ThemeProvider.tsx b/src/commons/providers/ThemeProvider/ThemeProvider.tsx similarity index 83% rename from src/providers/ThemeProvider/ThemeProvider.tsx rename to src/commons/providers/ThemeProvider/ThemeProvider.tsx index bb78d8e..561b366 100644 --- a/src/providers/ThemeProvider/ThemeProvider.tsx +++ b/src/commons/providers/ThemeProvider/ThemeProvider.tsx @@ -1,6 +1,6 @@ 'use client'; -import { darkTheme, lightTheme } from '@/styles/globalStyles.css'; +import { darkTheme, lightTheme } from '@/commons/styles/globalStyles.css'; import { ThemeProvider } from 'next-themes'; const Provider = ({ children }: { children: React.ReactNode }) => { diff --git a/src/styles/globalStyles.css.ts b/src/commons/styles/globalStyles.css.ts similarity index 100% rename from src/styles/globalStyles.css.ts rename to src/commons/styles/globalStyles.css.ts diff --git a/src/styles/rootStyles.css.ts b/src/commons/styles/rootStyles.css.ts similarity index 100% rename from src/styles/rootStyles.css.ts rename to src/commons/styles/rootStyles.css.ts diff --git a/src/types/theme/index.ts b/src/commons/types/theme/index.ts similarity index 100% rename from src/types/theme/index.ts rename to src/commons/types/theme/index.ts diff --git a/src/utils/ui/scrollToTop/scrollToTop.ts b/src/commons/utils/ui/scrollToTop/scrollToTop.ts similarity index 100% rename from src/utils/ui/scrollToTop/scrollToTop.ts rename to src/commons/utils/ui/scrollToTop/scrollToTop.ts diff --git a/src/utils/ui/scrollToTop/scrollToTop.types.ts b/src/commons/utils/ui/scrollToTop/scrollToTop.types.ts similarity index 100% rename from src/utils/ui/scrollToTop/scrollToTop.types.ts rename to src/commons/utils/ui/scrollToTop/scrollToTop.types.ts diff --git a/src/components/features/Inputs/Search/Search.tsx b/src/components/features/Inputs/Search/Search.tsx deleted file mode 100644 index df44070..0000000 --- a/src/components/features/Inputs/Search/Search.tsx +++ /dev/null @@ -1,92 +0,0 @@ -'use client'; - -import { KeyboardEvent, useState } from 'react'; -import Image from 'next/image'; -import Tag from '@/components/atoms/Icons/Tag/Tag'; -import * as styles from './Search.css'; - -export default function Search() { - const [isExpanded, setIsExpanded] = useState(false); - const [tagList, setTagList] = useState([]); - const [inputValue, setInputValue] = useState(''); // 입력값을 저장할 state 추가 - - const handleKeyDown = (event: KeyboardEvent) => { - if (event.nativeEvent.isComposing || event.keyCode === 229) return; - - if (event.key === 'Enter' && inputValue.trim()) { - setTagList((prev) => [...prev, inputValue.trim()]); - setInputValue(''); - } - }; - - const onClickExpanded = () => { - setIsExpanded((prev) => !prev); - }; - - return ( -
- {isExpanded ? ( - <> -
- setInputValue(e.target.value)} - onKeyDown={handleKeyDown} - /> - -
- {tagList.map((el) => ( -
- {el} -
- ))} -
- -
    -
  • - -

    관련 태그

    -
  • -
  • - -

    관련 태그

    -
  • -
-
- -
- - ) : ( - <> -
- {new Array(3).fill('React').map((el, index) => ( -
- {el} -
- ))} -
-
- ReadingGlasses -
- - )} -
- ); -} diff --git a/src/domains/tag/api/tags.api.ts b/src/domains/tag/api/tags.api.ts new file mode 100644 index 0000000..23adf1e --- /dev/null +++ b/src/domains/tag/api/tags.api.ts @@ -0,0 +1,4 @@ +import { Get } from '@/commons/configs/fetch/http.api'; +import type { TagResponse } from '@/domains/tag/tpyes/tag.type'; + +export const getTags = async (search?: string) => Get(`/tags`, { search }); diff --git a/src/domains/tag/tpyes/tag.type.ts b/src/domains/tag/tpyes/tag.type.ts new file mode 100644 index 0000000..d0cd9e9 --- /dev/null +++ b/src/domains/tag/tpyes/tag.type.ts @@ -0,0 +1,11 @@ +interface TagType { + id: number; + name: string; +} + +interface TagResponse { + count: number; + tags: TagType[]; +} + +export type { TagType, TagResponse };