diff --git a/src/app/(sidebar)/(my-info)/apis/useGetCardTags.ts b/src/app/(sidebar)/(my-info)/apis/useGetCardTags.ts index 75edf9ca..047e1427 100644 --- a/src/app/(sidebar)/(my-info)/apis/useGetCardTags.ts +++ b/src/app/(sidebar)/(my-info)/apis/useGetCardTags.ts @@ -2,7 +2,7 @@ import { http } from '@/apis/http'; import { TagType } from '@/types'; import { useQuery } from '@tanstack/react-query'; -export const GET_TAGS = 'tags'; +export const GET_TAGS = 'tagList'; type GetCardTagsRseponse = TagType[]; diff --git a/src/app/(sidebar)/(my-info)/components/InfoCardSkeleton.tsx b/src/app/(sidebar)/(my-info)/components/InfoCardSkeleton.tsx index 1b77c7aa..715b1834 100644 --- a/src/app/(sidebar)/(my-info)/components/InfoCardSkeleton.tsx +++ b/src/app/(sidebar)/(my-info)/components/InfoCardSkeleton.tsx @@ -1,5 +1,4 @@ import { motion } from 'framer-motion'; -import { match } from 'ts-pattern'; interface InfoCardSkeletonProps { count: number; diff --git a/src/app/(sidebar)/layout.tsx b/src/app/(sidebar)/layout.tsx index d9b05b11..e891e9c1 100644 --- a/src/app/(sidebar)/layout.tsx +++ b/src/app/(sidebar)/layout.tsx @@ -1,11 +1,14 @@ import { Sidebar } from '@/container/Sidebar/Sidebar'; import { PropsWithChildren } from 'react'; +import { CardWindowLayout } from '@/components/CardWindow/context'; export default function SidebarLayout({ children }: PropsWithChildren) { return (
-
{children}
+
+ {children} +
); } diff --git a/src/app/(sidebar)/my-recruit/[id]/mocks.ts b/src/app/(sidebar)/my-recruit/[id]/mocks.ts index e8fba7f4..bebd8f60 100644 --- a/src/app/(sidebar)/my-recruit/[id]/mocks.ts +++ b/src/app/(sidebar)/my-recruit/[id]/mocks.ts @@ -582,6 +582,7 @@ export const colorStyle = { default: 'bg-[#F1F2F3] text-[#37383C]', blue: 'bg-[#E8F1FF] text-[#418CC3]', purple: 'bg-[#F1E8FF] text-[#9C6BB3]', + yellow: 'bg-[#FFF3C2] text-[#D77B0F]', }; export const DEFAULT_TAG_MOCKS: TagType[] = [ diff --git a/src/app/(sidebar)/write/[id]/page.tsx b/src/app/(sidebar)/write/[id]/page.tsx index d70a7cb5..92da36ab 100644 --- a/src/app/(sidebar)/write/[id]/page.tsx +++ b/src/app/(sidebar)/write/[id]/page.tsx @@ -99,7 +99,8 @@ export default function Page({ params: { id } }: { params: { id: string } }) { - {categoryTags.map((tag) => ( + {/* FIXME */} + {/* {categoryTags.map((tag) => ( {tag.name} - ))} + ))} */} diff --git a/src/components/CardWindow/CardWindow.tsx b/src/components/CardWindow/CardWindow.tsx new file mode 100644 index 00000000..546ebe09 --- /dev/null +++ b/src/components/CardWindow/CardWindow.tsx @@ -0,0 +1,159 @@ +import { TouchButton } from '@/components/TouchButton'; +import { Icon, Tag } from '@/system/components'; +import { color } from '@/system/token/color'; +import { ReactNode, useState } from 'react'; +import { useGetInfoCardDetail } from '../../hooks/apis/useGetInfoCardDetail'; +import { Spacing } from '@/system/utils/Spacing'; +import { formatToYYMMDD } from '@/utils/date'; +import { motion } from 'framer-motion'; +import { If } from '@/system/utils/If'; +import { useRouter } from 'next/navigation'; + +interface CardWindowProps { + cardId: number; + onClose: () => void; +} + +export function CardWindow({ cardId, onClose }: CardWindowProps) { + const router = useRouter(); + const [isRight, setIsRight] = useState(true); + + const { data: card, isLoading } = useGetInfoCardDetail(cardId); + + return ( + +
+
+
+ { + router.push(`/write/${cardId}`); + onClose(); + }} + description="해당 글로 이동하기"> + + + setIsRight((prev) => !prev)} + description={`${isRight ? '왼쪽' : '오른쪽'}으로 옮기기`}> + svg]:rotate-180' : undefined}> + + + +
+ + + +
+
+ + + + +
+
+

+ {card?.title || '제목을 입력해주세요'} +

+

+ {formatToYYMMDD(card?.updatedDate || '', { separator: '.' })} +

+
+ +
+ {card?.cardTypeValueList.map((type) => ( + + {type.replaceAll('_', ' ')} + + ))} + {card?.tagList.map(({ id, name, type }) => ( + + {name} + + ))} +
+ +
{card?.content || '내용을 입력해주세요'}
+
+
+
+ ); +} + +interface WindowButtonProps { + onClick?: () => void; + description?: string; + children: ReactNode; +} + +function WindowButton({ onClick, children, description }: WindowButtonProps) { + return ( + + {children} + + {description} + + + ); +} + +function Skeleton() { + return ( + + + + + ); +} diff --git a/src/components/CardWindow/context.tsx b/src/components/CardWindow/context.tsx new file mode 100644 index 00000000..d0add7d0 --- /dev/null +++ b/src/components/CardWindow/context.tsx @@ -0,0 +1,39 @@ +'use client'; + +import { generateContext } from '@/lib'; +import { useState } from 'react'; +import { CardWindow } from './CardWindow'; +import { AnimatePresence } from 'framer-motion'; + +interface CardWindowContext { + isOpen: boolean; + open: (cardId: number) => void; + close: () => void; +} + +const [CardWindowProvider, useCardWindowContext] = generateContext({ + name: 'CardWindow', +}); + +function CardWindowLayout({ children }: { children: React.ReactNode }) { + const [cardId, setCardId] = useState(null); + + const isOpen = cardId !== null; + + const open = (cardId: number) => { + setCardId(cardId); + }; + + const close = () => { + setCardId(null); + }; + + return ( + + {children} + {isOpen && } + + ); +} + +export { CardWindowLayout, useCardWindowContext }; diff --git a/src/components/InfoCard.tsx b/src/components/InfoCard.tsx index 32ac9156..1324015c 100644 --- a/src/components/InfoCard.tsx +++ b/src/components/InfoCard.tsx @@ -12,12 +12,14 @@ import { color } from '@/system/token/color'; import { useDeleteCard } from '@/app/(sidebar)/(my-info)/apis/useDeleteCard'; import Link from 'next/link'; import { MouseEventHandler } from 'react'; +import { useCardWindowContext } from './CardWindow/context'; type InfoCardProps = InfoCardType; export function InfoCard({ id, title, updatedDate, tagList }: InfoCardProps) { const formattedDate = formatToYYMMDD(updatedDate, { separator: '.' }); + const { open } = useCardWindowContext(); const { mutate: deleteCard } = useDeleteCard(); const handleDeleteCard: MouseEventHandler = (event) => { @@ -26,6 +28,12 @@ export function InfoCard({ id, title, updatedDate, tagList }: InfoCardProps) { deleteCard(id); }; + const handleOpenCardWindow: MouseEventHandler = (event) => { + event.stopPropagation(); + + open(id); + }; + return (
@@ -46,7 +54,7 @@ export function InfoCard({ id, title, updatedDate, tagList }: InfoCardProps) {
삭제하기
- +
개별창으로 띄우기
@@ -64,4 +72,4 @@ export function InfoCard({ id, title, updatedDate, tagList }: InfoCardProps) {
); -} \ No newline at end of file +} diff --git a/src/hooks/apis/useGetInfoCardDetail.ts b/src/hooks/apis/useGetInfoCardDetail.ts new file mode 100644 index 00000000..a3a52430 --- /dev/null +++ b/src/hooks/apis/useGetInfoCardDetail.ts @@ -0,0 +1,26 @@ +import { http } from '@/apis/http'; +import { InfoType, TagType } from '@/types'; +import { useQuery } from '@tanstack/react-query'; + +export interface GetInfoCardDetailResponse { + title: string; + content: string; + updatedDate: string; + cardTypeValueList: InfoType[]; + tagList: TagType[]; +} + +const getInfoCardDetail = (cardId: number) => + http.get({ + url: `/cards/${cardId}`, + }); + +export const useGetInfoCardDetail = (cardId: number) => + useQuery({ + queryKey: ['get-info-card-detail', cardId], + queryFn: async () => { + const res = await getInfoCardDetail(cardId); + + return res.data; + }, + }); diff --git a/src/system/components/Icon/Icon.tsx b/src/system/components/Icon/Icon.tsx index 0648eb6e..5e5ca901 100644 --- a/src/system/components/Icon/Icon.tsx +++ b/src/system/components/Icon/Icon.tsx @@ -1,24 +1,15 @@ -import { RemoveMemo } from '@/system/components/Icon/SVG/RemoveMemo'; -import { SubmitArrow } from '@/system/components/Icon/SVG/SubmitArrow'; import type { IconBaseType } from '@/system/components/Icon/SVG/type'; import { Add } from './SVG/Add'; import { Bell } from './SVG/Bell'; -import { Calendar } from './SVG/Calendar'; -import { CalendarFill } from './SVG/CalendarFill'; import { Check } from './SVG/Check'; -import { Close } from './SVG/Close'; -import { Clover } from './SVG/Clover'; import { CodingSignUp } from './SVG/CodingSignUp'; import { Copy } from './SVG/Copy'; import { Delete } from './SVG/Delete'; import { DesignSignup } from './SVG/DesignSignup'; import { Division } from './SVG/Division'; import { Down } from './SVG/Down'; -import { DownChevron } from './SVG/DownChevron'; import { Empty } from './SVG/Empty'; -import { FilledMemo } from './SVG/FilledMemo'; import { Folder } from './SVG/Folder'; -import { FolderFill } from './SVG/FolderFill'; import { Link } from './SVG/Link'; import { LogoOnly } from './SVG/LogoOnly'; import { Logout } from './SVG/Logout'; @@ -37,6 +28,17 @@ import { Shoes } from './SVG/Shoes'; import { Tag } from './SVG/Tag'; import { Trash } from './SVG/Trash'; import { Unlink } from './SVG/Unlink'; +import { Calendar } from './SVG/Calendar'; +import { CalendarFill } from './SVG/CalendarFill'; +import { SubmitArrow } from '@/system/components/Icon/SVG/SubmitArrow'; +import { FilledMemo } from './SVG/FilledMemo'; +import { RemoveMemo } from '@/system/components/Icon/SVG/RemoveMemo'; +import { Clover } from './SVG/Clover'; +import { DownChevron } from './SVG/DownChevron'; +import { FolderFill } from './SVG/FolderFill'; +import { Close } from './SVG/Close'; +import { FullScreenCorner } from './SVG/FullScreenCorner'; +import { ToLeft } from './SVG/ToLeft'; import { Up } from './SVG/Up'; import { X } from './SVG/X'; import { WorkFill } from './SVG/WorkFill'; @@ -74,6 +76,8 @@ const iconMap = { filledMemo: FilledMemo, removeMemo: RemoveMemo, clover: Clover, + fullScreenCorner: FullScreenCorner, + toLeft: ToLeft, refresh: Refresh, empty: Empty, tag: Tag, diff --git a/src/system/components/Icon/SVG/FullScreenCorner.tsx b/src/system/components/Icon/SVG/FullScreenCorner.tsx new file mode 100644 index 00000000..22d34f29 --- /dev/null +++ b/src/system/components/Icon/SVG/FullScreenCorner.tsx @@ -0,0 +1,11 @@ +import { IconBaseType } from './type'; + +export function FullScreenCorner({ size, color }: IconBaseType) { + return ( + + + + + + ); +} diff --git a/src/system/components/Icon/SVG/ToLeft.tsx b/src/system/components/Icon/SVG/ToLeft.tsx new file mode 100644 index 00000000..4b5f332a --- /dev/null +++ b/src/system/components/Icon/SVG/ToLeft.tsx @@ -0,0 +1,11 @@ +import { IconBaseType } from './type'; + +export function ToLeft({ size, color }: IconBaseType) { + return ( + + + + + + ); +} diff --git a/src/system/components/Tag/Tag.tsx b/src/system/components/Tag/Tag.tsx index d77a671a..5f9b0f31 100644 --- a/src/system/components/Tag/Tag.tsx +++ b/src/system/components/Tag/Tag.tsx @@ -1,7 +1,7 @@ import { cn } from '@/utils/tailwind-util'; import { PropsWithChildren } from 'react'; -export type TagColor = 'default' | 'blue' | 'purple'; +export type TagColor = 'default' | 'blue' | 'purple' | 'yellow'; export interface TagProps { color?: TagColor; } @@ -12,6 +12,7 @@ const colorStyle = { default: 'bg-[#F1F2F3] text-[#37383C]', blue: 'bg-[#E8F1FF] text-[#418CC3]', purple: 'bg-[#F1E8FF] text-[#9C6BB3]', + yellow: 'bg-[#FFF3C2] text-[#D77B0F]', }; export function Tag({ color = 'default', children }: PropsWithChildren) {