From 1c0cbfa40877cb2b6b98ce18743107d745c8ee58 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Mon, 4 Nov 2024 00:42:14 +0900 Subject: [PATCH 01/49] =?UTF-8?q?feat:=20merge=20animation=20=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=20=EC=9E=A1=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[locale]/mypage/my-pet/MergePersona.tsx | 14 + .../app/[locale]/mypage/my-pet/Merging.tsx | 364 ++++++++++++++++++ .../src/app/[locale]/mypage/my-pet/page.tsx | 3 + 3 files changed, 381 insertions(+) create mode 100644 apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx create mode 100644 apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx diff --git a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx new file mode 100644 index 00000000..ed9780ed --- /dev/null +++ b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { FullModalBase } from '@gitanimals/ui-panda'; + +import MergeAnimation from './Merging'; + +function MergePersona() { + return ( + {}}> + + + ); +} + +export default MergePersona; diff --git a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx new file mode 100644 index 00000000..66e83673 --- /dev/null +++ b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx @@ -0,0 +1,364 @@ +/* eslint-disable @next/next/no-img-element */ +import React, { useState } from 'react'; +import { css } from '_panda/css'; +import { flex } from '_panda/patterns'; +import { AnimatePresence, motion } from 'framer-motion'; + +const MergeAnimation = () => { + const [isMerging, setIsMerging] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [showResult, setShowResult] = useState(false); + + const handleMerge = async () => { + setIsMerging(true); + setIsLoading(true); + + try { + await new Promise((resolve) => setTimeout(resolve, 2000)); + setIsLoading(false); + startMergeAnimation(); + } catch (error) { + setIsMerging(false); + setIsLoading(false); + } + }; + + const startMergeAnimation = () => { + setTimeout(() => { + setShowResult(true); + }, 300); + }; + + const handleReset = () => { + setIsMerging(false); + setIsLoading(false); + setShowResult(false); + }; + + return ( +
+
+ {/* First Item */} +
+ + Level 1 Cat +
Level 1
+
+ + {/* First Item Clone */} + + {isMerging && !isLoading && !showResult && ( + +
+ Level 1 Clone +
+
+ )} +
+
+ + {/* Plus Sign */} + + + + + + {/* Second Item */} +
+ + Level 3 Fish +
Level 3
+
+ + {/* Second Item Clone */} + + {isMerging && !isLoading && !showResult && ( + +
+ Level 3 Clone +
+
+ )} +
+
+ + {/* Arrow */} +
=
+ + {/* Result Item */} + + Level 4 Result +
Level 4
+ + {/* Result Flash Effect */} + {showResult && ( + + )} + +
+ + {/* Impact Lines */} + {isMerging && !isLoading && ( +
+ {[...Array(8)].map((_, i) => ( + + ))} +
+ )} + + {/* Loading Indicator */} + {isLoading && ( + +
+ + )} + + {/* Buttons */} + + {isLoading ? 'Merging...' : 'Merge'} + + + {showResult && ( + + Reset + + )} +
+ ); +}; + +const containerStyle = css({ + position: 'relative', + padding: '32px', + overflow: 'hidden', +}); + +const itemContainerStyle = flex({ + alignItems: 'center', + justifyContent: 'center', + gap: '16px', +}); + +const itemWrapperStyle = css({ + position: 'relative', +}); + +const itemStyle = css({ + width: '96px', + height: '96px', + backgroundColor: 'gray.700', + borderRadius: '8px', + padding: '8px', +}); + +const imageStyle = css({ + width: '100%', + height: '100%', + objectFit: 'contain', +}); + +const levelTextStyle = css({ + textAlign: 'center', + marginTop: '8px', + fontSize: '14px', +}); + +const cloneWrapperStyle = css({ + width: '96px', + height: '96px', + position: 'absolute', + top: 0, + left: 0, +}); + +const plusSignStyle = css({ + fontSize: '24px', + fontWeight: 'bold', +}); + +const arrowStyle = css({ + marginX: '16px', +}); + +const resultItemStyle = css({ + width: '96px', + height: '96px', + backgroundImage: 'linear-gradient(to bottom right, teal.700, blue.700)', + borderRadius: '8px', + padding: '8px', + position: 'relative', +}); + +const flashEffectStyle = css({ + position: 'absolute', + inset: 0, + backgroundColor: 'white', + borderRadius: '8px', +}); + +const impactLinesContainerStyle = css({ + position: 'absolute', + left: '50%', + top: '50%', + transform: 'translate(-50%, -50%)', +}); + +const impactLineStyle = css({ + position: 'absolute', + height: '2px', + backgroundColor: 'orange.400', + transformOrigin: 'left', +}); + +const loadingContainerStyle = css({ + position: 'absolute', + left: '50%', + top: '50%', + transform: 'translate(-50%, -50%)', +}); + +const spinnerStyle = css({ + width: '32px', + height: '32px', + border: '4px solid', + borderColor: 'blue.500', + borderTopColor: 'transparent', + borderRadius: '50%', + animation: 'spin 1s linear infinite', +}); + +const mergeButtonStyle = css({ + marginTop: '32px', + paddingX: '24px', + paddingY: '8px', + backgroundColor: 'blue.500', + color: 'white', + borderRadius: '9999px', + '&:hover': { + backgroundColor: 'blue.600', + }, + transition: 'all 0.3s', + marginX: 'auto', + display: 'block', +}); + +const resetButtonStyle = css({ + marginTop: '16px', + paddingX: '24px', + paddingY: '8px', + backgroundColor: 'gray.500', + color: 'white', + borderRadius: '9999px', + '&:hover': { + backgroundColor: 'gray.600', + }, + transition: 'all 0.3s', + marginX: 'auto', + display: 'block', +}); + +export default MergeAnimation; diff --git a/apps/web/src/app/[locale]/mypage/my-pet/page.tsx b/apps/web/src/app/[locale]/mypage/my-pet/page.tsx index 8be0feb2..b1cad555 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/page.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/page.tsx @@ -18,6 +18,8 @@ import { getPersonaImage } from '@/utils/image'; import { SelectPersonaList } from '../PersonaList'; +import MergePersona from './MergePersona'; + function MypageMyPets() { const t = useTranslations('Mypage'); const [selectPersona, setSelectPersona] = useState(null); @@ -170,6 +172,7 @@ function SelectedPetTable({ currentPersona, reset }: { currentPersona: Persona | )}
+ ); } From fe56da23236e9aaa91f0b9a4d782a3c4102d2c9d Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Mon, 4 Nov 2024 00:45:31 +0900 Subject: [PATCH 02/49] =?UTF-8?q?refactor:=20clone=20item=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/[locale]/mypage/my-pet/Merging.tsx | 93 +++++++++---------- 1 file changed, 43 insertions(+), 50 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx index 66e83673..6d6486a3 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx @@ -1,8 +1,9 @@ /* eslint-disable @next/next/no-img-element */ +import type { PropsWithChildren } from 'react'; import React, { useState } from 'react'; import { css } from '_panda/css'; import { flex } from '_panda/patterns'; -import { AnimatePresence, motion } from 'framer-motion'; +import { AnimatePresence, AnimatePresence, motion } from 'framer-motion'; const MergeAnimation = () => { const [isMerging, setIsMerging] = useState(false); @@ -53,30 +54,11 @@ const MergeAnimation = () => { {/* First Item Clone */} - - {isMerging && !isLoading && !showResult && ( - -
- Level 1 Clone -
-
- )} -
+ +
+ Level 1 Clone +
+
{/* Plus Sign */} @@ -103,31 +85,11 @@ const MergeAnimation = () => { {/* Second Item Clone */} - - {isMerging && !isLoading && !showResult && ( - -
- Level 3 Clone -
-
- )} -
+ +
+ Level 3 Clone +
+
{/* Arrow */} @@ -362,3 +324,34 @@ const resetButtonStyle = css({ }); export default MergeAnimation; + +function CloneItem({ + isVisible, + children, + position, +}: PropsWithChildren<{ isVisible: boolean; position: 'left' | 'right' }>) { + return ( + + {isVisible && ( + + {children} + + )} + + ); +} From d464805a5a1baa84e821bab2c855699f325bffae Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Mon, 4 Nov 2024 00:53:15 +0900 Subject: [PATCH 03/49] =?UTF-8?q?refactor:=20merge=20=EC=95=A0=EB=8B=88?= =?UTF-8?q?=EB=A7=A4=EC=9D=B4=EC=85=98=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/public/mypage/merge/merge-empty.svg | 10 ++ .../app/[locale]/mypage/my-pet/Merging.tsx | 114 +++++++++--------- 2 files changed, 69 insertions(+), 55 deletions(-) create mode 100644 apps/web/public/mypage/merge/merge-empty.svg diff --git a/apps/web/public/mypage/merge/merge-empty.svg b/apps/web/public/mypage/merge/merge-empty.svg new file mode 100644 index 00000000..d50fbfac --- /dev/null +++ b/apps/web/public/mypage/merge/merge-empty.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx index 6d6486a3..1faad38c 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx @@ -3,7 +3,7 @@ import type { PropsWithChildren } from 'react'; import React, { useState } from 'react'; import { css } from '_panda/css'; import { flex } from '_panda/patterns'; -import { AnimatePresence, AnimatePresence, motion } from 'framer-motion'; +import { AnimatePresence, motion } from 'framer-motion'; const MergeAnimation = () => { const [isMerging, setIsMerging] = useState(false); @@ -41,86 +41,44 @@ const MergeAnimation = () => {
{/* First Item */}
- + Level 1 Cat
Level 1
-
+ {/* First Item Clone */} - +
Level 1 Clone
-
+
- {/* Plus Sign */} - - + - +
+
{/* Second Item */}
- + Level 3 Fish
Level 3
-
+ {/* Second Item Clone */} - +
Level 3 Clone
-
+
{/* Arrow */}
=
{/* Result Item */} - + Level 4 Result
Level 4
- - {/* Result Flash Effect */} - {showResult && ( - - )} - +
{/* Impact Lines */} @@ -325,7 +283,7 @@ const resetButtonStyle = css({ export default MergeAnimation; -function CloneItem({ +function CloneItemAnimation({ isVisible, children, position, @@ -355,3 +313,49 @@ function CloneItem({ ); } + +function MergeMaterialItemAnimation({ isMerged }: PropsWithChildren<{ isMerged: boolean }>) { + return ( + + Level 3 Fish +
Level 3
+
+ ); +} + +function ResultItemAnimation({ isVisible }: PropsWithChildren<{ isVisible: boolean }>) { + return ( + + Level 4 Result +
Level 4
+ + {/* Result Flash Effect */} + {isVisible && ( + + )} + + ); +} From 8093445e0f80bc212191a6dcfaad6db424f4eb7a Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Fri, 8 Nov 2024 16:54:49 +0900 Subject: [PATCH 04/49] =?UTF-8?q?feat:=20select=20persona=20logic=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[locale]/mypage/my-pet/MergePersona.tsx | 108 +++++++++++++++++- .../app/[locale]/mypage/my-pet/Merging.tsx | 3 +- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx index ed9780ed..fa724c8c 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx @@ -1,14 +1,116 @@ -import React from 'react'; -import { FullModalBase } from '@gitanimals/ui-panda'; +'use client'; + +import React, { useState } from 'react'; +import { css, cx } from '_panda/css'; +import { flex } from '_panda/patterns'; +import type { Persona } from '@gitanimals/api'; +import { userQueries } from '@gitanimals/react-query'; +import { Banner, FullModalBase } from '@gitanimals/ui-panda'; +import { BannerSkeleton } from '@gitanimals/ui-panda/src/components/Banner/Banner'; +import { wrap } from '@suspensive/react'; +import { useSuspenseQuery } from '@tanstack/react-query'; + +import { customScrollStyle } from '@/styles/scrollStyle'; +import { useClientUser } from '@/utils/clientAuth'; +import { getPersonaImage } from '@/utils/image'; import MergeAnimation from './Merging'; function MergePersona() { + const [selectPersona, setSelectPersona] = useState([]); + + const onSelectPersona = (persona: Persona) => { + if (selectPersona.find((p) => p.id === persona.id)) { + setSelectPersona((prev) => prev.filter((p) => p.id !== persona.id)); + } else { + if (selectPersona.length >= 2) return; + setSelectPersona((prev) => [...prev, persona]); + } + }; + + const targetPersona = selectPersona.length > 0 ? selectPersona[0] : undefined; + const materialPersona = selectPersona.length > 1 ? selectPersona[1] : undefined; + return ( {}}> - + + +
+ persona.id)} + onSelectPersona={onSelectPersona} + /> +
); } export default MergePersona; + +const listStyle = cx( + flex({ + gap: 4, + w: '100%', + h: '100%', + minH: '0', + overflowY: 'auto', + display: 'flex', + flexWrap: 'wrap', + justifyContent: 'center', + }), + customScrollStyle, +); + +interface SelectPersonaListProps { + selectPersona: string[]; + onSelectPersona: (persona: Persona) => void; + initSelectPersonas?: (list: Persona[]) => void; + loadingPersona?: string[]; +} + +const SelectPersonaList = wrap + .ErrorBoundary({ + // TODO: 공통 에러 컴포넌트로 대체 + fallback:
error
, + }) + .Suspense({ + fallback: ( + <> + {Array.from({ length: 6 }).map((_, index) => ( + + ))} + + ), + }) + .on(function SelectPersonaList({ selectPersona, onSelectPersona }: SelectPersonaListProps) { + const { name } = useClientUser(); + const { data } = useSuspenseQuery(userQueries.allPersonasOptions(name)); + + return ( + <> + {data.personas.map((persona) => ( + + ))} + + ); + }); diff --git a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx index 1faad38c..f3b57af6 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx @@ -3,9 +3,10 @@ import type { PropsWithChildren } from 'react'; import React, { useState } from 'react'; import { css } from '_panda/css'; import { flex } from '_panda/patterns'; +import type { Persona } from '@gitanimals/api'; import { AnimatePresence, motion } from 'framer-motion'; -const MergeAnimation = () => { +const MergeAnimation = ({ materialPersona, targetPersona }: { materialPersona?: Persona; targetPersona?: Persona }) => { const [isMerging, setIsMerging] = useState(false); const [isLoading, setIsLoading] = useState(false); const [showResult, setShowResult] = useState(false); From 26c71a93c9d96ddf9dbc7b9e13a1233f4c5b5ebe Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 9 Nov 2024 22:20:24 +0900 Subject: [PATCH 05/49] =?UTF-8?q?feat:=20merge=20item=20style=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20API=20=EC=B4=88=EC=95=88=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[locale]/mypage/my-pet/MergePersona.tsx | 84 +++++++-- .../app/[locale]/mypage/my-pet/Merging.tsx | 161 ++++++++---------- packages/api/src/render/index.ts | 1 + packages/api/src/render/mergePersonaLevel.ts | 23 +++ packages/lib/react-query/src/render/index.ts | 1 + packages/lib/react-query/src/render/merge.ts | 26 +++ 6 files changed, 196 insertions(+), 100 deletions(-) create mode 100644 packages/api/src/render/mergePersonaLevel.ts create mode 100644 packages/lib/react-query/src/render/merge.ts diff --git a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx index fa724c8c..30f19240 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx @@ -4,36 +4,87 @@ import React, { useState } from 'react'; import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; import type { Persona } from '@gitanimals/api'; -import { userQueries } from '@gitanimals/react-query'; -import { Banner, FullModalBase } from '@gitanimals/ui-panda'; +import { useMergePersonaLevelByToken, userQueries } from '@gitanimals/react-query'; +import { Banner, Button, FullModalBase } from '@gitanimals/ui-panda'; import { BannerSkeleton } from '@gitanimals/ui-panda/src/components/Banner/Banner'; import { wrap } from '@suspensive/react'; import { useSuspenseQuery } from '@tanstack/react-query'; import { customScrollStyle } from '@/styles/scrollStyle'; -import { useClientUser } from '@/utils/clientAuth'; +import { useClientSession, useClientUser } from '@/utils/clientAuth'; import { getPersonaImage } from '@/utils/image'; import MergeAnimation from './Merging'; function MergePersona() { - const [selectPersona, setSelectPersona] = useState([]); + const [selectPersonaObj, setSelectPersonaObj] = useState<{ + material: Persona | undefined; + target: Persona | undefined; + }>({ + material: undefined, + target: undefined, + }); + + const session = useClientSession(); + const token = session.data?.user.accessToken; + + if (!token) { + return null; + } + + const { mutate: mergePersonaLevel, isPending: isMerging, isSuccess: isMerged } = useMergePersonaLevelByToken(token); + console.log('isMerging: ', isMerging); + const isMergeDisabled = !selectPersonaObj.material || !selectPersonaObj.target; + + const onMergeAction = () => { + if (!selectPersonaObj.target?.id || !selectPersonaObj.material?.id) { + return; + } + + mergePersonaLevel({ + increasePersonaId: selectPersonaObj.target.id, + deletePersonaId: selectPersonaObj.material.id, + }); + + console.log('aa ', { + increasePersonaId: selectPersonaObj.target.id, + decreasePersonaId: selectPersonaObj.material.id, + }); + }; const onSelectPersona = (persona: Persona) => { - if (selectPersona.find((p) => p.id === persona.id)) { - setSelectPersona((prev) => prev.filter((p) => p.id !== persona.id)); + if (selectPersonaObj.target?.id === persona.id) { + setSelectPersonaObj((prev) => ({ + ...prev, + target: undefined, + })); + return; + } + + if (selectPersonaObj.material?.id === persona.id) { + setSelectPersonaObj((prev) => ({ + ...prev, + material: undefined, + })); + return; + } + + if (selectPersonaObj.target) { + setSelectPersonaObj((prev) => ({ + ...prev, + material: persona, + })); } else { - if (selectPersona.length >= 2) return; - setSelectPersona((prev) => [...prev, persona]); + setSelectPersonaObj((prev) => ({ + ...prev, + target: persona, + })); } }; - const targetPersona = selectPersona.length > 0 ? selectPersona[0] : undefined; - const materialPersona = selectPersona.length > 1 ? selectPersona[1] : undefined; - return ( {}}> - +
persona.id)} + selectPersona={Object.values(selectPersonaObj).map((persona) => persona?.id ?? '')} onSelectPersona={onSelectPersona} />
+ +
+ + +
); } diff --git a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx index f3b57af6..46dda594 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx @@ -6,11 +6,24 @@ import { flex } from '_panda/patterns'; import type { Persona } from '@gitanimals/api'; import { AnimatePresence, motion } from 'framer-motion'; +import { getPersonaImage } from '@/utils/image'; + +const mergePersona = ({ targetPersona, materialPersona }: { targetPersona?: Persona; materialPersona?: Persona }) => { + if (!targetPersona || !materialPersona) return undefined; + + return { + ...targetPersona, + level: targetPersona.level + materialPersona.level, + }; +}; + const MergeAnimation = ({ materialPersona, targetPersona }: { materialPersona?: Persona; targetPersona?: Persona }) => { const [isMerging, setIsMerging] = useState(false); const [isLoading, setIsLoading] = useState(false); const [showResult, setShowResult] = useState(false); + const resultPersona = mergePersona({ targetPersona, materialPersona }); + const handleMerge = async () => { setIsMerging(true); setIsLoading(true); @@ -42,73 +55,38 @@ const MergeAnimation = ({ materialPersona, targetPersona }: { materialPersona?:
{/* First Item */}
- - Level 1 Cat -
Level 1
+ + {targetPersona ? : } - {/* First Item Clone */} - -
- Level 1 Clone -
-
+ {/* + {targetPersona ? : } + */}
+
- {/* Second Item */}
- - Level 3 Fish -
Level 3
+ + {materialPersona ? : } - - {/* Second Item Clone */} - -
- Level 3 Clone -
-
- {/* Arrow */}
=
- {/* Result Item */} - - Level 4 Result -
Level 4
+ + {resultPersona ? : }
- {/* Impact Lines */} - {isMerging && !isLoading && ( -
- {[...Array(8)].map((_, i) => ( - - ))} -
- )} - {/* Loading Indicator */} {isLoading && ( Reset - )} + )} */} ); }; @@ -169,10 +147,9 @@ const itemWrapperStyle = css({ }); const itemStyle = css({ - width: '96px', - height: '96px', + width: '120px', + height: '120px', backgroundColor: 'gray.700', - borderRadius: '8px', padding: '8px', }); @@ -189,8 +166,8 @@ const levelTextStyle = css({ }); const cloneWrapperStyle = css({ - width: '96px', - height: '96px', + width: '120px', + height: '120px', position: 'absolute', top: 0, left: 0, @@ -206,9 +183,9 @@ const arrowStyle = css({ }); const resultItemStyle = css({ - width: '96px', - height: '96px', - backgroundImage: 'linear-gradient(to bottom right, teal.700, blue.700)', + width: '120px', + height: '120px', + // backgroundImage: 'linear-gradient(to bottom right, teal.700, blue.700)', borderRadius: '8px', padding: '8px', position: 'relative', @@ -221,20 +198,6 @@ const flashEffectStyle = css({ borderRadius: '8px', }); -const impactLinesContainerStyle = css({ - position: 'absolute', - left: '50%', - top: '50%', - transform: 'translate(-50%, -50%)', -}); - -const impactLineStyle = css({ - position: 'absolute', - height: '2px', - backgroundColor: 'orange.400', - transformOrigin: 'left', -}); - const loadingContainerStyle = css({ position: 'absolute', left: '50%', @@ -315,7 +278,10 @@ function CloneItemAnimation({ ); } -function MergeMaterialItemAnimation({ isMerged }: PropsWithChildren<{ isMerged: boolean }>) { +function MergeMaterialItemAnimation({ + isMerged, + children, +}: PropsWithChildren<{ isMerged: boolean; persona?: Persona }>) { return ( - Level 3 Fish -
Level 3
+ {children}
); } -function ResultItemAnimation({ isVisible }: PropsWithChildren<{ isVisible: boolean }>) { +function MergeEmptyItem() { + return ( + <> + empty +
Level ?
+ + ); +} + +function MergeItem({ persona }: PropsWithChildren<{ persona: Persona }>) { + return ( + <> +
+ Level 3 Fish +
+
Level {persona.level}
+ + ); +} + +const mergeItemStyle = css({ + borderRadius: '16px', + border: '2px solid rgba(255, 255, 255, 0.25)', + background: 'rgba(255, 255, 255, 0.25)', +}); + +function ResultItemAnimation({ isVisible, children }: PropsWithChildren<{ isVisible: boolean }>) { return ( - Level 4 Result -
Level 4
- - {/* Result Flash Effect */} + {children} {isVisible && ( ; +export type MergePersonaLevelResponse = z.infer; + +export const mergePersonaLevel = async (request: MergePersonaLevelRequest) => + safeRenderPut(MergePersonaLevelResponseSchema)(`/personas/merges`, request); + +// token 강제 삽입 임시 +export const mergePersonaLevelByToken = async (request: MergePersonaLevelRequest, token: string) => + safeRenderPut(MergePersonaLevelResponseSchema)(`/personas/merges`, request, { + headers: { + Authorization: `Bearer ${token}`, + }, + }); diff --git a/packages/lib/react-query/src/render/index.ts b/packages/lib/react-query/src/render/index.ts index a627b237..e23a2949 100644 --- a/packages/lib/react-query/src/render/index.ts +++ b/packages/lib/react-query/src/render/index.ts @@ -1,2 +1,3 @@ export * from './queries'; export * from './user'; +export * from './merge'; diff --git a/packages/lib/react-query/src/render/merge.ts b/packages/lib/react-query/src/render/merge.ts new file mode 100644 index 00000000..a092af20 --- /dev/null +++ b/packages/lib/react-query/src/render/merge.ts @@ -0,0 +1,26 @@ +// mergePersonaLevel + +import { + MergePersonaLevelResponse, + MergePersonaLevelRequest, + mergePersonaLevel, + mergePersonaLevelByToken, +} from '@gitanimals/api'; +import { UseMutationOptions, useMutation } from '@tanstack/react-query'; + +export const useMergePersonaLevel = ( + options?: UseMutationOptions, +) => + useMutation({ + mutationFn: (request: MergePersonaLevelRequest) => mergePersonaLevel(request), + ...options, + }); + +export const useMergePersonaLevelByToken = ( + token: string, + options?: UseMutationOptions, +) => + useMutation({ + mutationFn: (request: MergePersonaLevelRequest) => mergePersonaLevelByToken(request, token), + ...options, + }); From 456e277fccc18964a0cda7e0f047c285b6684fbd Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Tue, 12 Nov 2024 18:57:37 +0900 Subject: [PATCH 06/49] =?UTF-8?q?feat:=20merge=20result=20=EB=B3=B4?= =?UTF-8?q?=EC=97=AC=EC=A3=BC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AvailablePetSection/AnimalSlider.tsx | 3 +- .../[locale]/mypage/my-pet/MergePersona.tsx | 77 +++---- .../[locale]/mypage/my-pet/MergeResult.tsx | 155 ++++++++++++++ .../app/[locale]/mypage/my-pet/Merging.tsx | 190 +----------------- apps/web/src/components/Modal/Modal.tsx | 2 +- .../src/components/Portal2/AnimatePortal.tsx | 27 +++ .../src/components/{ => Portal2}/Portal.tsx | 0 apps/web/src/components/portal/Portal.tsx | 23 --- packages/api/src/render/mergePersonaLevel.ts | 8 +- 9 files changed, 243 insertions(+), 242 deletions(-) create mode 100644 apps/web/src/app/[locale]/mypage/my-pet/MergeResult.tsx create mode 100644 apps/web/src/components/Portal2/AnimatePortal.tsx rename apps/web/src/components/{ => Portal2}/Portal.tsx (100%) delete mode 100644 apps/web/src/components/portal/Portal.tsx diff --git a/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalSlider.tsx b/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalSlider.tsx index c375b655..8ff38085 100644 --- a/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalSlider.tsx +++ b/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalSlider.tsx @@ -1,12 +1,13 @@ 'use client'; +import { cx } from '_panda/css'; + import { AnimalCard } from '@/components/AnimalCard'; import { useGetAllPersona } from '@/hooks/query/render/useGetAllPersona'; import * as styles from './AnimalSlider.style'; import AnimalSliderContainer from './AnimalSliderContainer'; import AnimalSliderContainerMobile from './AnimalSliderContainerMobile'; -import { cx } from '_panda/css'; interface Animal { type: string; diff --git a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx index 30f19240..bfd16e2e 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; -import type { Persona } from '@gitanimals/api'; +import type { MergePersonaLevelResponse, Persona } from '@gitanimals/api'; import { useMergePersonaLevelByToken, userQueries } from '@gitanimals/react-query'; import { Banner, Button, FullModalBase } from '@gitanimals/ui-panda'; import { BannerSkeleton } from '@gitanimals/ui-panda/src/components/Banner/Banner'; @@ -14,9 +14,11 @@ import { customScrollStyle } from '@/styles/scrollStyle'; import { useClientSession, useClientUser } from '@/utils/clientAuth'; import { getPersonaImage } from '@/utils/image'; +import { MergeResultModal } from './MergeResult'; import MergeAnimation from './Merging'; function MergePersona() { + const [resultData, setResultData] = useState(null); const [selectPersonaObj, setSelectPersonaObj] = useState<{ material: Persona | undefined; target: Persona | undefined; @@ -26,13 +28,18 @@ function MergePersona() { }); const session = useClientSession(); - const token = session.data?.user.accessToken; - - if (!token) { - return null; - } - - const { mutate: mergePersonaLevel, isPending: isMerging, isSuccess: isMerged } = useMergePersonaLevelByToken(token); + const token = session.data?.user.accessToken as string; + + const { + mutate: mergePersonaLevel, + isPending: isMerging, + isSuccess: isMerged, + } = useMergePersonaLevelByToken(token, { + onSuccess: (data) => { + setResultData(data); + }, + }); + console.log('isMerged: ', isMerged); console.log('isMerging: ', isMerging); const isMergeDisabled = !selectPersonaObj.material || !selectPersonaObj.target; @@ -45,11 +52,6 @@ function MergePersona() { increasePersonaId: selectPersonaObj.target.id, deletePersonaId: selectPersonaObj.material.id, }); - - console.log('aa ', { - increasePersonaId: selectPersonaObj.target.id, - decreasePersonaId: selectPersonaObj.material.id, - }); }; const onSelectPersona = (persona: Persona) => { @@ -84,29 +86,36 @@ function MergePersona() { return ( {}}> - - -
- persona?.id ?? '')} - onSelectPersona={onSelectPersona} +
+ + +
+ persona?.id ?? '')} + onSelectPersona={onSelectPersona} + /> +
+ +
+ + +
+ setResultData(null)} + result={resultData as MergePersonaLevelResponse} />
- -
- - -
); } diff --git a/apps/web/src/app/[locale]/mypage/my-pet/MergeResult.tsx b/apps/web/src/app/[locale]/mypage/my-pet/MergeResult.tsx new file mode 100644 index 00000000..bd475630 --- /dev/null +++ b/apps/web/src/app/[locale]/mypage/my-pet/MergeResult.tsx @@ -0,0 +1,155 @@ +/* eslint-disable @next/next/no-img-element */ +import type { PropsWithChildren } from 'react'; +import React from 'react'; +import { css } from '_panda/css'; +import type { MergePersonaLevelResponse } from '@gitanimals/api'; +import { snakeToTitleCase } from '@gitanimals/util-common'; +import { AnimatePresence, motion } from 'framer-motion'; +import { X } from 'lucide-react'; + +import { getPersonaImage } from '@/utils/image'; + +// 가챠 결과 모달 컴포넌트 +export const MergeResultModal = ({ + isOpen, + onClose, + result, +}: { + isOpen: boolean; + onClose: () => void; + result: MergePersonaLevelResponse; +}) => { + if (!isOpen) return null; + + return ( + +

🎉 합성 결과 🎉

+
+ {result.type} +
+
+

{snakeToTitleCase(result.type)}

+ Level {result.level} +
+
+ ); +}; + +const mergeItemStyle = css({ + borderRadius: '16px', + border: '2px solid rgba(255, 255, 255, 0.25)', + background: 'rgba(255, 255, 255, 0.25)', + width: 'fit-content', +}); + +const resultTextStyle = css({ + textStyle: 'glyph18.bold', + + '& > span': { + marginTop: '4px', + }, +}); + +function MotionContainer({ children, onClose }: PropsWithChildren<{ onClose: () => void }>) { + return ( + + { + onClose(); + e.stopPropagation(); + }} + > + e.stopPropagation()} + > +
+ + + {children} + +
+
+
+
+ ); +} + +const containerStyle = css({ + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + left: 0, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: 'black.black_50', + zIndex: 50, +}); + +const containerVariants = { + initial: { opacity: 0, y: -20 }, + animate: { opacity: 1, y: 0 }, + exit: { opacity: 0, y: -20 }, +}; + +const containerInnerVariants = { + initial: { scale: 0, rotate: -180 }, + animate: { + scale: 1, + rotate: 0, + transition: { + type: 'spring', + duration: 0.7, + bounce: 0.5, + }, + }, + exit: { scale: 0, rotate: 180, transition: { duration: 0.5 } }, +}; + +const containerInnerStyle = css({ + backgroundColor: 'gray.gray_150', + position: 'relative', + borderRadius: '16px', + padding: '36px 48px', +}); + +const closeButtonStyle = css({ + position: 'absolute', + top: '8px', + right: '8px', + padding: '2px', + borderRadius: 'full', + _hover: { + backgroundColor: 'gray.100', + }, +}); + +const contentStyle = css({ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + gap: '12px', + textAlign: 'center', +}); + +const contentStranggerVariants = { + initial: { opacity: 0, y: 20 }, + animate: { opacity: 1, y: 0, transition: { delay: 0.3 } }, +}; diff --git a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx index 46dda594..ad765d4b 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx @@ -1,10 +1,10 @@ /* eslint-disable @next/next/no-img-element */ import type { PropsWithChildren } from 'react'; -import React, { useState } from 'react'; +import React from 'react'; import { css } from '_panda/css'; import { flex } from '_panda/patterns'; import type { Persona } from '@gitanimals/api'; -import { AnimatePresence, motion } from 'framer-motion'; +import { motion } from 'framer-motion'; import { getPersonaImage } from '@/utils/image'; @@ -18,114 +18,22 @@ const mergePersona = ({ targetPersona, materialPersona }: { targetPersona?: Pers }; const MergeAnimation = ({ materialPersona, targetPersona }: { materialPersona?: Persona; targetPersona?: Persona }) => { - const [isMerging, setIsMerging] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const [showResult, setShowResult] = useState(false); - const resultPersona = mergePersona({ targetPersona, materialPersona }); - const handleMerge = async () => { - setIsMerging(true); - setIsLoading(true); - - try { - await new Promise((resolve) => setTimeout(resolve, 2000)); - setIsLoading(false); - startMergeAnimation(); - } catch (error) { - setIsMerging(false); - setIsLoading(false); - } - }; - - const startMergeAnimation = () => { - setTimeout(() => { - setShowResult(true); - }, 300); - }; - - const handleReset = () => { - setIsMerging(false); - setIsLoading(false); - setShowResult(false); - }; - return (
- {/* First Item */} -
- - {targetPersona ? : } - - - {/* - {targetPersona ? : } - */} -
- +
{targetPersona ? : }
+
- -
- - {materialPersona ? : } - +
+ {materialPersona ? : }
=
- {resultPersona ? : }
- - {/* Loading Indicator */} - {isLoading && ( - -
- - )} - - {/* Buttons */} - {/* - {isLoading ? 'Merging...' : 'Merge'} - - - {showResult && ( - - Reset - - )} */}
); }; @@ -142,11 +50,8 @@ const itemContainerStyle = flex({ gap: '16px', }); -const itemWrapperStyle = css({ - position: 'relative', -}); - const itemStyle = css({ + position: 'relative', width: '120px', height: '120px', backgroundColor: 'gray.700', @@ -165,14 +70,6 @@ const levelTextStyle = css({ fontSize: '14px', }); -const cloneWrapperStyle = css({ - width: '120px', - height: '120px', - position: 'absolute', - top: 0, - left: 0, -}); - const plusSignStyle = css({ fontSize: '24px', fontWeight: 'bold', @@ -215,82 +112,11 @@ const spinnerStyle = css({ animation: 'spin 1s linear infinite', }); -const mergeButtonStyle = css({ - marginTop: '32px', - paddingX: '24px', - paddingY: '8px', - backgroundColor: 'blue.500', - color: 'white', - borderRadius: '9999px', - '&:hover': { - backgroundColor: 'blue.600', - }, - transition: 'all 0.3s', - marginX: 'auto', - display: 'block', -}); - -const resetButtonStyle = css({ - marginTop: '16px', - paddingX: '24px', - paddingY: '8px', - backgroundColor: 'gray.500', - color: 'white', - borderRadius: '9999px', - '&:hover': { - backgroundColor: 'gray.600', - }, - transition: 'all 0.3s', - marginX: 'auto', - display: 'block', -}); - export default MergeAnimation; -function CloneItemAnimation({ - isVisible, - children, - position, -}: PropsWithChildren<{ isVisible: boolean; position: 'left' | 'right' }>) { +function MergeMaterialItemAnimation({ children }: PropsWithChildren<{ persona?: Persona }>) { return ( - - {isVisible && ( - - {children} - - )} - - ); -} - -function MergeMaterialItemAnimation({ - isMerged, - children, -}: PropsWithChildren<{ isMerged: boolean; persona?: Persona }>) { - return ( - + {children} ); diff --git a/apps/web/src/components/Modal/Modal.tsx b/apps/web/src/components/Modal/Modal.tsx index 184d4490..4f925091 100644 --- a/apps/web/src/components/Modal/Modal.tsx +++ b/apps/web/src/components/Modal/Modal.tsx @@ -4,7 +4,7 @@ import { center } from '_panda/patterns'; import { useBodyLock, useOutsideClick } from '@gitanimals/react'; import { X } from 'lucide-react'; -import Portal from '../Portal'; +import Portal from '../Portal2/Portal'; interface ModalProps { isOpen: boolean; diff --git a/apps/web/src/components/Portal2/AnimatePortal.tsx b/apps/web/src/components/Portal2/AnimatePortal.tsx new file mode 100644 index 00000000..49ef295d --- /dev/null +++ b/apps/web/src/components/Portal2/AnimatePortal.tsx @@ -0,0 +1,27 @@ +import type { ComponentProps } from 'react'; +import { AnimatePresence } from 'framer-motion'; + +import Portal from './Portal'; + +interface Props extends ComponentProps { + /** + * children의 렌더링 여부 + */ + isShowing: boolean; + /** + * framer-motion AnimatePresence의 mode + * @default 'wait' + */ + mode?: ComponentProps['mode']; +} + +/** + * @description Portal을 AnimatePresence와 함께 사용합니다 + */ +export const AnimatePortal = ({ children, isShowing, mode = 'wait' }: Props) => { + return ( + + {isShowing && children} + + ); +}; diff --git a/apps/web/src/components/Portal.tsx b/apps/web/src/components/Portal2/Portal.tsx similarity index 100% rename from apps/web/src/components/Portal.tsx rename to apps/web/src/components/Portal2/Portal.tsx diff --git a/apps/web/src/components/portal/Portal.tsx b/apps/web/src/components/portal/Portal.tsx deleted file mode 100644 index 11e9299d..00000000 --- a/apps/web/src/components/portal/Portal.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client'; - -import { type PropsWithChildren, useEffect, useState } from 'react'; -import { createPortal } from 'react-dom'; - -/** - * @description react.createPortal을 이용해 document.body에 children을 렌더링합니다 - */ -const Portal = ({ children }: PropsWithChildren) => { - const [container, setContainer] = useState(null); - - useEffect(() => { - if (document) { - setContainer(document.body); - } - }, []); - - if (!container) return null; - - return createPortal(<>{children}, container); -}; - -export default Portal; diff --git a/packages/api/src/render/mergePersonaLevel.ts b/packages/api/src/render/mergePersonaLevel.ts index f9d347d3..f16c413a 100644 --- a/packages/api/src/render/mergePersonaLevel.ts +++ b/packages/api/src/render/mergePersonaLevel.ts @@ -6,7 +6,13 @@ const MergePersonaLevelRequestSchema = z.object({ deletePersonaId: z.string(), }); -const MergePersonaLevelResponseSchema = z.object({}); +const MergePersonaLevelResponseSchema = z.object({ + id: z.string(), + type: z.string(), + level: z.string(), + visible: z.boolean(), + dropRate: z.string(), +}); export type MergePersonaLevelRequest = z.infer; export type MergePersonaLevelResponse = z.infer; From 011dd30297a79709f46fc3e76fd6cec56a6d3015 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Wed, 13 Nov 2024 11:45:26 +0900 Subject: [PATCH 07/49] =?UTF-8?q?feat:=20merge=20result=20=EC=95=A0?= =?UTF-8?q?=EB=8B=88=EB=A7=A4=EC=9D=B4=EC=85=98=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A1=9C=EB=94=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/panda.config.ts | 8 + .../[locale]/mypage/my-pet/MergePersona.tsx | 159 ++++++++++-------- .../[locale]/mypage/my-pet/MergeResult.tsx | 19 +-- .../app/[locale]/mypage/my-pet/Merging.tsx | 2 +- 4 files changed, 101 insertions(+), 87 deletions(-) diff --git a/apps/web/panda.config.ts b/apps/web/panda.config.ts index 3e0766bb..e4d4de71 100644 --- a/apps/web/panda.config.ts +++ b/apps/web/panda.config.ts @@ -98,6 +98,14 @@ export default defineConfig({ backgroundPosition: '-200% 0', }, }, + animateSpin: { + from: { + transform: 'rotate(0deg)', + }, + to: { + transform: 'rotate(360deg)', + }, + }, }, }, }, diff --git a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx index bfd16e2e..5aa47a2e 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx @@ -29,19 +29,11 @@ function MergePersona() { const session = useClientSession(); const token = session.data?.user.accessToken as string; + const isMergeDisabled = !selectPersonaObj.material || !selectPersonaObj.target; - const { - mutate: mergePersonaLevel, - isPending: isMerging, - isSuccess: isMerged, - } = useMergePersonaLevelByToken(token, { - onSuccess: (data) => { - setResultData(data); - }, + const { mutate: mergePersonaLevel, isPending: isMerging } = useMergePersonaLevelByToken(token, { + onSuccess: (data) => setResultData(data), }); - console.log('isMerged: ', isMerged); - console.log('isMerging: ', isMerging); - const isMergeDisabled = !selectPersonaObj.material || !selectPersonaObj.target; const onMergeAction = () => { if (!selectPersonaObj.target?.id || !selectPersonaObj.material?.id) { @@ -54,74 +46,65 @@ function MergePersona() { }); }; - const onSelectPersona = (persona: Persona) => { - if (selectPersonaObj.target?.id === persona.id) { - setSelectPersonaObj((prev) => ({ - ...prev, - target: undefined, - })); - return; - } - - if (selectPersonaObj.material?.id === persona.id) { - setSelectPersonaObj((prev) => ({ - ...prev, - material: undefined, - })); - return; - } - - if (selectPersonaObj.target) { - setSelectPersonaObj((prev) => ({ - ...prev, - material: persona, - })); - } else { - setSelectPersonaObj((prev) => ({ - ...prev, - target: persona, - })); - } + const onSelectPersona = (currentSelectPersona: Persona) => { + setSelectPersonaObj(getMergePersona({ ...selectPersonaObj, currentSelectPersona })); }; return ( {}}> -
- - -
- persona?.id ?? '')} - onSelectPersona={onSelectPersona} - /> -
- -
- - -
- setResultData(null)} - result={resultData as MergePersonaLevelResponse} + + +
+ persona?.id ?? '')} + onSelectPersona={onSelectPersona} />
+ +
+ + +
+ setResultData(null)} + result={resultData as MergePersonaLevelResponse} + /> + {isMerging && } ); } export default MergePersona; +const getMergePersona = ({ + target, + material, + currentSelectPersona, +}: { + target?: Persona; + material?: Persona; + currentSelectPersona: Persona; +}) => { + if (currentSelectPersona.id === target?.id) { + return { target: undefined, material }; + } + + if (currentSelectPersona.id === material?.id) { + return { target, material: undefined }; + } + + if (target) { + return { target, material: currentSelectPersona }; + } + + return { target: currentSelectPersona, material }; +}; + +const bottomButtonStyle = css({ display: 'flex', justifyContent: 'center', gap: 12 }); + const listStyle = cx( flex({ gap: 4, @@ -132,6 +115,8 @@ const listStyle = cx( display: 'flex', flexWrap: 'wrap', justifyContent: 'center', + maxHeight: 'calc(100vh - 542px)', + overflow: 'auto', }), customScrollStyle, ); @@ -167,17 +152,43 @@ const SelectPersonaList = wrap ))} ); }); + +const SpinningLoader = () => { + return ( +
+
+
+ ); +}; + +const spinningLoaderContainerStyle = css({ + position: 'absolute', + top: '0', + left: '0', + right: '0', + bottom: '0', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + width: '100%', + zIndex: 100, + height: '100%', + background: 'rgba(0, 0, 0, 0.5)', +}); + +const spinningLoaderStyle = css({ + width: '64px', + height: '64px', + border: '4px solid transparent', + borderTop: '4px solid #fff', + borderRadius: '50%', + animation: 'animateSpin 1s linear infinite', +}); diff --git a/apps/web/src/app/[locale]/mypage/my-pet/MergeResult.tsx b/apps/web/src/app/[locale]/mypage/my-pet/MergeResult.tsx index bd475630..1829f2b8 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/MergeResult.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/MergeResult.tsx @@ -1,3 +1,5 @@ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ /* eslint-disable @next/next/no-img-element */ import type { PropsWithChildren } from 'react'; import React from 'react'; @@ -53,12 +55,8 @@ const resultTextStyle = css({ function MotionContainer({ children, onClose }: PropsWithChildren<{ onClose: () => void }>) { return ( - { onClose(); e.stopPropagation(); @@ -85,7 +83,7 @@ function MotionContainer({ children, onClose }: PropsWithChildren<{ onClose: ()
- +
); } @@ -96,19 +94,16 @@ const containerStyle = css({ right: 0, bottom: 0, left: 0, + width: '100%', + height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', backgroundColor: 'black.black_50', zIndex: 50, + cursor: 'pointer', }); -const containerVariants = { - initial: { opacity: 0, y: -20 }, - animate: { opacity: 1, y: 0 }, - exit: { opacity: 0, y: -20 }, -}; - const containerInnerVariants = { initial: { scale: 0, rotate: -180 }, animate: { diff --git a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx index ad765d4b..dfb0411e 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx @@ -13,7 +13,7 @@ const mergePersona = ({ targetPersona, materialPersona }: { targetPersona?: Pers return { ...targetPersona, - level: targetPersona.level + materialPersona.level, + level: String(Number(targetPersona.level) + Number(materialPersona.level)), }; }; From dec8af30c55b32321e16b19fc2cf9a9ab6b9ecc5 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Wed, 13 Nov 2024 12:47:29 +0900 Subject: [PATCH 08/49] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=EB=8B=A4=EA=B5=AD=EC=96=B4=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/messages/en_US.json | 8 +++- apps/web/messages/ko_KR.json | 8 +++- .../[locale]/mypage/my-pet/MergePersona.tsx | 42 ++++++++++------- .../[locale]/mypage/my-pet/MergeResult.tsx | 17 ++++--- .../app/[locale]/mypage/my-pet/Merging.tsx | 37 +++------------ .../src/app/[locale]/mypage/my-pet/page.tsx | 45 +++++++++---------- 6 files changed, 74 insertions(+), 83 deletions(-) diff --git a/apps/web/messages/en_US.json b/apps/web/messages/en_US.json index 624f197c..c3172819 100644 --- a/apps/web/messages/en_US.json +++ b/apps/web/messages/en_US.json @@ -60,6 +60,7 @@ "edit": "Edit", "pet-sold": "Pet sold successfully for [money]!", "prepare": "Prepare", + "merge": "Merge", "Background": { "buy-success": "Background purchased successfully", "buy-fail": "Failed to purchase background", @@ -95,7 +96,12 @@ "github-custom": "Github Custom", "invalid-size-error": "Invalid size", "farm-type-select-pet": "Select a pet for Farm Type", - "line-type-select-pet": "Select a pet for Line Type" + "line-type-select-pet": "Select a pet for Line Type", + "Merge": { + "merge": "Merge", + "merge-result": "Merge result", + "cancel": "Cancel" + } }, "Event": { "Halloween": { diff --git a/apps/web/messages/ko_KR.json b/apps/web/messages/ko_KR.json index 4c486fc9..382b381e 100644 --- a/apps/web/messages/ko_KR.json +++ b/apps/web/messages/ko_KR.json @@ -62,6 +62,7 @@ "sell-error": "판매에 실패했습니다.", "many-error-message": "계속해서 문제가 발생한다면 Github로 문의 부탁드립니다.", "prepare": "준비중", + "merge": "펫 합치기", "Background": { "buy-success": "배경 구매 완료!", "buy-fail": "배경 구매에 실패했습니다.", @@ -97,7 +98,12 @@ "github-custom": "Github Custom", "invalid-size-error": "유효하지 않은 사이즈", "farm-type-select-pet": "Farm Type에 사용할 펫을 선택해주세요.", - "line-type-select-pet": "Line Type에 사용할 펫을 선택해주세요." + "line-type-select-pet": "Line Type에 사용할 펫을 선택해주세요.", + "Merge": { + "merge": "합치기", + "merge-result": "합치기 결과", + "cancel": "취소" + } }, "Event": { "Halloween": { diff --git a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx index 5aa47a2e..17096017 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx @@ -1,6 +1,7 @@ 'use client'; -import React, { useState } from 'react'; +import { useState } from 'react'; +import { useTranslations } from 'next-intl'; import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; import type { MergePersonaLevelResponse, Persona } from '@gitanimals/api'; @@ -8,31 +9,40 @@ import { useMergePersonaLevelByToken, userQueries } from '@gitanimals/react-quer import { Banner, Button, FullModalBase } from '@gitanimals/ui-panda'; import { BannerSkeleton } from '@gitanimals/ui-panda/src/components/Banner/Banner'; import { wrap } from '@suspensive/react'; -import { useSuspenseQuery } from '@tanstack/react-query'; +import { useQueryClient, useSuspenseQuery } from '@tanstack/react-query'; import { customScrollStyle } from '@/styles/scrollStyle'; import { useClientSession, useClientUser } from '@/utils/clientAuth'; import { getPersonaImage } from '@/utils/image'; import { MergeResultModal } from './MergeResult'; -import MergeAnimation from './Merging'; +import { MergeAnimation } from './Merging'; -function MergePersona() { +const INITIAL_SELECT_PERSONA_OBJ = { material: undefined, target: undefined } as const; + +interface MergePersonaProps { + isOpen: boolean; + onClose: () => void; +} + +export function MergePersona({ isOpen, onClose }: MergePersonaProps) { + const queryClient = useQueryClient(); + const t = useTranslations('Mypage.Merge'); const [resultData, setResultData] = useState(null); - const [selectPersonaObj, setSelectPersonaObj] = useState<{ - material: Persona | undefined; - target: Persona | undefined; - }>({ - material: undefined, - target: undefined, - }); + const [selectPersonaObj, setSelectPersonaObj] = useState<{ material?: Persona; target?: Persona }>( + INITIAL_SELECT_PERSONA_OBJ, + ); const session = useClientSession(); const token = session.data?.user.accessToken as string; const isMergeDisabled = !selectPersonaObj.material || !selectPersonaObj.target; const { mutate: mergePersonaLevel, isPending: isMerging } = useMergePersonaLevelByToken(token, { - onSuccess: (data) => setResultData(data), + onSuccess: (data) => { + setSelectPersonaObj((prev) => ({ ...prev, material: undefined, target: data })); + setResultData(data); + queryClient.invalidateQueries({ queryKey: userQueries.allPersonasKey() }); + }, }); const onMergeAction = () => { @@ -51,7 +61,7 @@ function MergePersona() { }; return ( - {}}> +
@@ -62,9 +72,9 @@ function MergePersona() {
- +
void; result: MergePersonaLevelResponse; -}) => { +} + +export const MergeResultModal = ({ isOpen, onClose, result }: MergeResultModalProps) => { + const t = useTranslations('Mypage.Merge'); + if (!isOpen) return null; return ( -

🎉 합성 결과 🎉

+

{t('merge-result')}

{result.type}
diff --git a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx index dfb0411e..0fedba77 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx @@ -1,6 +1,5 @@ /* eslint-disable @next/next/no-img-element */ import type { PropsWithChildren } from 'react'; -import React from 'react'; import { css } from '_panda/css'; import { flex } from '_panda/patterns'; import type { Persona } from '@gitanimals/api'; @@ -17,7 +16,13 @@ const mergePersona = ({ targetPersona, materialPersona }: { targetPersona?: Pers }; }; -const MergeAnimation = ({ materialPersona, targetPersona }: { materialPersona?: Persona; targetPersona?: Persona }) => { +export const MergeAnimation = ({ + materialPersona, + targetPersona, +}: { + materialPersona?: Persona; + targetPersona?: Persona; +}) => { const resultPersona = mergePersona({ targetPersona, materialPersona }); return ( @@ -82,7 +87,6 @@ const arrowStyle = css({ const resultItemStyle = css({ width: '120px', height: '120px', - // backgroundImage: 'linear-gradient(to bottom right, teal.700, blue.700)', borderRadius: '8px', padding: '8px', position: 'relative', @@ -95,33 +99,6 @@ const flashEffectStyle = css({ borderRadius: '8px', }); -const loadingContainerStyle = css({ - position: 'absolute', - left: '50%', - top: '50%', - transform: 'translate(-50%, -50%)', -}); - -const spinnerStyle = css({ - width: '32px', - height: '32px', - border: '4px solid', - borderColor: 'blue.500', - borderTopColor: 'transparent', - borderRadius: '50%', - animation: 'spin 1s linear infinite', -}); - -export default MergeAnimation; - -function MergeMaterialItemAnimation({ children }: PropsWithChildren<{ persona?: Persona }>) { - return ( - - {children} - - ); -} - function MergeEmptyItem() { return ( <> diff --git a/apps/web/src/app/[locale]/mypage/my-pet/page.tsx b/apps/web/src/app/[locale]/mypage/my-pet/page.tsx index b1cad555..641aab77 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/page.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/page.tsx @@ -18,28 +18,25 @@ import { getPersonaImage } from '@/utils/image'; import { SelectPersonaList } from '../PersonaList'; -import MergePersona from './MergePersona'; +import { MergePersona } from './MergePersona'; function MypageMyPets() { const t = useTranslations('Mypage'); const [selectPersona, setSelectPersona] = useState(null); + const [isMergeOpen, setIsMergeOpen] = useState(false); return ( <>
- setSelectPersona(null)} /> + setSelectPersona(null)} + onMergeClick={() => setIsMergeOpen(true)} + />

{t('pet-list')}

-
+
setSelectPersona(persona)} @@ -52,6 +49,7 @@ function MypageMyPets() {

{t('sell-to-other')}

{t('no-mobile-support')}
+ setIsMergeOpen(false)} /> ); } @@ -60,6 +58,8 @@ export default MypageMyPets; const listStyle = cx( flex({ + maxHeight: 'calc(100vh - 542px)', + overflow: 'auto', gap: 4, w: '100%', h: '100%', @@ -115,7 +115,13 @@ const selectPetContainerStyle = css({ }, }); -function SelectedPetTable({ currentPersona, reset }: { currentPersona: Persona | null; reset: () => void }) { +interface SelectedPetTableProps { + currentPersona: Persona | null; + reset: () => void; + onMergeClick: () => void; +} + +function SelectedPetTable({ currentPersona, reset, onMergeClick }: SelectedPetTableProps) { const queryClient = useQueryClient(); const t = useTranslations('Shop'); @@ -136,10 +142,6 @@ function SelectedPetTable({ currentPersona, reset }: { currentPersona: Persona | dropPetMutation(currentPersona.id); }; - const onMergeClick = () => { - console.log('merge'); - }; - return (
@@ -165,14 +167,13 @@ function SelectedPetTable({ currentPersona, reset }: { currentPersona: Persona | 100P {t('sell')} {/* TODO: 합치기 기능 추가 시*/} -
)}
-
); } @@ -228,9 +229,3 @@ const rowStyle = css({ textOverflow: 'ellipsis', }, }); - -const tbodyCss = css({ - display: 'flex', - flexDir: 'column', - gap: 4, -}); From 55e99f54c46566070ba17f4dbb791499eb98d572 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Fri, 15 Nov 2024 17:23:43 +0900 Subject: [PATCH 09/49] =?UTF-8?q?refactor:=20merge=20=EB=B0=A9=EC=8B=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-pet/{ => (merge)}/MergePersona.tsx | 59 +++++++------------ .../{Merging.tsx => (merge)/MergePreview.tsx} | 46 ++++++--------- .../my-pet/{ => (merge)}/MergeResult.tsx | 8 +-- .../[locale]/mypage/my-pet/(merge)/index.ts | 1 + .../src/app/[locale]/mypage/my-pet/page.tsx | 19 +++--- 5 files changed, 49 insertions(+), 84 deletions(-) rename apps/web/src/app/[locale]/mypage/my-pet/{ => (merge)}/MergePersona.tsx (74%) rename apps/web/src/app/[locale]/mypage/my-pet/{Merging.tsx => (merge)/MergePreview.tsx} (77%) rename apps/web/src/app/[locale]/mypage/my-pet/{ => (merge)}/MergeResult.tsx (96%) create mode 100644 apps/web/src/app/[locale]/mypage/my-pet/(merge)/index.ts diff --git a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx similarity index 74% rename from apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx rename to apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index 17096017..a6c81d23 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -15,58 +15,63 @@ import { customScrollStyle } from '@/styles/scrollStyle'; import { useClientSession, useClientUser } from '@/utils/clientAuth'; import { getPersonaImage } from '@/utils/image'; +import { MergePreview } from './MergePreview'; import { MergeResultModal } from './MergeResult'; -import { MergeAnimation } from './Merging'; - -const INITIAL_SELECT_PERSONA_OBJ = { material: undefined, target: undefined } as const; interface MergePersonaProps { isOpen: boolean; onClose: () => void; + targetPersona: Persona; } -export function MergePersona({ isOpen, onClose }: MergePersonaProps) { +export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona }: MergePersonaProps) { const queryClient = useQueryClient(); const t = useTranslations('Mypage.Merge'); + const [resultData, setResultData] = useState(null); - const [selectPersonaObj, setSelectPersonaObj] = useState<{ material?: Persona; target?: Persona }>( - INITIAL_SELECT_PERSONA_OBJ, - ); + + const [meterialPersona, setMeterialPersona] = useState(null); + const [targetPersona, setTargetPersona] = useState(initTargetPersona); const session = useClientSession(); const token = session.data?.user.accessToken as string; - const isMergeDisabled = !selectPersonaObj.material || !selectPersonaObj.target; + const isMergeDisabled = !meterialPersona || !targetPersona; const { mutate: mergePersonaLevel, isPending: isMerging } = useMergePersonaLevelByToken(token, { onSuccess: (data) => { - setSelectPersonaObj((prev) => ({ ...prev, material: undefined, target: data })); + setMeterialPersona(null); setResultData(data); + setTargetPersona(data); queryClient.invalidateQueries({ queryKey: userQueries.allPersonasKey() }); }, }); const onMergeAction = () => { - if (!selectPersonaObj.target?.id || !selectPersonaObj.material?.id) { + if (!targetPersona?.id || !meterialPersona?.id) { return; } mergePersonaLevel({ - increasePersonaId: selectPersonaObj.target.id, - deletePersonaId: selectPersonaObj.material.id, + increasePersonaId: targetPersona.id, + deletePersonaId: meterialPersona.id, }); }; const onSelectPersona = (currentSelectPersona: Persona) => { - setSelectPersonaObj(getMergePersona({ ...selectPersonaObj, currentSelectPersona })); + if (currentSelectPersona.id === targetPersona.id) { + setMeterialPersona(null); + } else { + setMeterialPersona(currentSelectPersona); + } }; return ( - +
persona?.id ?? '')} + selectPersona={meterialPersona ? [meterialPersona.id] : []} onSelectPersona={onSelectPersona} />
@@ -87,30 +92,6 @@ export function MergePersona({ isOpen, onClose }: MergePersonaProps) { ); } -const getMergePersona = ({ - target, - material, - currentSelectPersona, -}: { - target?: Persona; - material?: Persona; - currentSelectPersona: Persona; -}) => { - if (currentSelectPersona.id === target?.id) { - return { target: undefined, material }; - } - - if (currentSelectPersona.id === material?.id) { - return { target, material: undefined }; - } - - if (target) { - return { target, material: currentSelectPersona }; - } - - return { target: currentSelectPersona, material }; -}; - const bottomButtonStyle = css({ display: 'flex', justifyContent: 'center', gap: 12 }); const listStyle = cx( diff --git a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePreview.tsx similarity index 77% rename from apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx rename to apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePreview.tsx index 0fedba77..1d0b368a 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/Merging.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePreview.tsx @@ -7,32 +7,31 @@ import { motion } from 'framer-motion'; import { getPersonaImage } from '@/utils/image'; -const mergePersona = ({ targetPersona, materialPersona }: { targetPersona?: Persona; materialPersona?: Persona }) => { +type MergePersonaProps = { + targetPersona: Persona | null; + materialPersona: Persona | null; +}; + +const mergePersona = ({ targetPersona, materialPersona }: MergePersonaProps) => { if (!targetPersona || !materialPersona) return undefined; + const materialLevel = Number(materialPersona.level) > 0 ? Number(materialPersona.level) : 1; + return { ...targetPersona, - level: String(Number(targetPersona.level) + Number(materialPersona.level)), + level: String(Number(targetPersona.level) + materialLevel), }; }; -export const MergeAnimation = ({ - materialPersona, - targetPersona, -}: { - materialPersona?: Persona; - targetPersona?: Persona; -}) => { +export const MergePreview = ({ materialPersona, targetPersona }: MergePersonaProps) => { const resultPersona = mergePersona({ targetPersona, materialPersona }); return (
-
{targetPersona ? : }
+ {targetPersona ? : }
+
-
- {materialPersona ? : } -
+ {materialPersona ? : }
=
@@ -47,6 +46,7 @@ const containerStyle = css({ position: 'relative', padding: '32px', overflow: 'hidden', + minHeight: 'fit-content', }); const itemContainerStyle = flex({ @@ -58,7 +58,7 @@ const itemContainerStyle = flex({ const itemStyle = css({ position: 'relative', width: '120px', - height: '120px', + // height: '120px', backgroundColor: 'gray.700', padding: '8px', }); @@ -84,14 +84,6 @@ const arrowStyle = css({ marginX: '16px', }); -const resultItemStyle = css({ - width: '120px', - height: '120px', - borderRadius: '8px', - padding: '8px', - position: 'relative', -}); - const flashEffectStyle = css({ position: 'absolute', inset: 0, @@ -101,21 +93,21 @@ const flashEffectStyle = css({ function MergeEmptyItem() { return ( - <> +
empty
Level ?
- +
); } function MergeItem({ persona }: PropsWithChildren<{ persona: Persona }>) { return ( - <> +
Level 3 Fish
Level {persona.level}
- +
); } @@ -128,7 +120,7 @@ const mergeItemStyle = css({ function ResultItemAnimation({ isVisible, children }: PropsWithChildren<{ isVisible: boolean }>) { return ( void }>) { return ( -
{ - onClose(); - e.stopPropagation(); - }} - > +
onClose()}> (null); - const [isMergeOpen, setIsMergeOpen] = useState(false); return ( <>
- setSelectPersona(null)} - onMergeClick={() => setIsMergeOpen(true)} - /> + setSelectPersona(null)} />

{t('pet-list')}

@@ -49,7 +44,6 @@ function MypageMyPets() {

{t('sell-to-other')}

{t('no-mobile-support')}
- setIsMergeOpen(false)} /> ); } @@ -118,12 +112,12 @@ const selectPetContainerStyle = css({ interface SelectedPetTableProps { currentPersona: Persona | null; reset: () => void; - onMergeClick: () => void; } -function SelectedPetTable({ currentPersona, reset, onMergeClick }: SelectedPetTableProps) { +function SelectedPetTable({ currentPersona, reset }: SelectedPetTableProps) { const queryClient = useQueryClient(); const t = useTranslations('Shop'); + const [isMergeOpen, setIsMergeOpen] = useState(false); const { mutate: dropPetMutation } = useMutation({ mutationFn: (personaId: string) => dropPet({ personaId }), @@ -167,13 +161,16 @@ function SelectedPetTable({ currentPersona, reset, onMergeClick }: SelectedPetTa 100P {t('sell')} {/* TODO: 합치기 기능 추가 시*/} -
)}
+ {currentPersona && ( + setIsMergeOpen(false)} targetPersona={currentPersona} /> + )}
); } From 40aa011e7aa1939c9e1837ddb666e78f093c3de0 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Fri, 15 Nov 2024 18:22:02 +0900 Subject: [PATCH 10/49] =?UTF-8?q?feat:=20levelbanner=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx | 9 +++++++-- packages/ui/panda/src/components/Banner/LevelBanner.tsx | 5 ++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index a6c81d23..1825e5c1 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -6,7 +6,7 @@ import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; import type { MergePersonaLevelResponse, Persona } from '@gitanimals/api'; import { useMergePersonaLevelByToken, userQueries } from '@gitanimals/react-query'; -import { Banner, Button, FullModalBase } from '@gitanimals/ui-panda'; +import { Button, FullModalBase, LevelBanner } from '@gitanimals/ui-panda'; import { BannerSkeleton } from '@gitanimals/ui-panda/src/components/Banner/Banner'; import { wrap } from '@suspensive/react'; import { useQueryClient, useSuspenseQuery } from '@tanstack/react-query'; @@ -143,7 +143,12 @@ const SelectPersonaList = wrap onClick={() => onSelectPersona(persona)} className={css({ outline: 'none' })} > - + ))} diff --git a/packages/ui/panda/src/components/Banner/LevelBanner.tsx b/packages/ui/panda/src/components/Banner/LevelBanner.tsx index ab392c0f..94e0b991 100644 --- a/packages/ui/panda/src/components/Banner/LevelBanner.tsx +++ b/packages/ui/panda/src/components/Banner/LevelBanner.tsx @@ -11,7 +11,7 @@ export function LevelBanner({ image, level, ...styleProps }: Props) { return (
{typeof image === 'string' ? {image} : image} -

{level}

+

Lv.{level}

); } @@ -24,4 +24,7 @@ const levelTagStyle = css({ textStyle: 'glyph12.regular', fontSize: 10, lineHeight: '20px', + position: 'absolute', + bottom: '3px', + right: '3px', }); From c5202344a0b235a8c906dd7f0f84a280fedeb653 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Fri, 15 Nov 2024 18:24:19 +0900 Subject: [PATCH 11/49] =?UTF-8?q?fix:=20merge=20person=20=EC=95=88?= =?UTF-8?q?=EB=B0=94=EB=80=8C=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/app/[locale]/mypage/my-pet/page.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/page.tsx b/apps/web/src/app/[locale]/mypage/my-pet/page.tsx index d588c3a6..18ae07d3 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/page.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/page.tsx @@ -169,7 +169,12 @@ function SelectedPetTable({ currentPersona, reset }: SelectedPetTableProps) { )}
{currentPersona && ( - setIsMergeOpen(false)} targetPersona={currentPersona} /> + setIsMergeOpen(false)} + targetPersona={currentPersona} + /> )}
); From bdac7e785d75dadd2e3129c93ba70eee71e92d1c Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Fri, 15 Nov 2024 18:27:30 +0900 Subject: [PATCH 12/49] =?UTF-8?q?feat:=20=EC=84=A0=ED=83=9D=ED=95=9C=20?= =?UTF-8?q?=ED=8E=AB=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index 1825e5c1..009595cd 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -36,6 +36,7 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona const session = useClientSession(); const token = session.data?.user.accessToken as string; const isMergeDisabled = !meterialPersona || !targetPersona; + const selectPersona = [targetPersona.id, meterialPersona?.id].filter(Boolean) as string[]; const { mutate: mergePersonaLevel, isPending: isMerging } = useMergePersonaLevelByToken(token, { onSuccess: (data) => { @@ -70,10 +71,7 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona
- +
From 05faf7e49becacd6dd4e6923fb00d02dfc7cb352 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Fri, 15 Nov 2024 18:31:46 +0900 Subject: [PATCH 13/49] =?UTF-8?q?refactor:=20portal=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=20=EC=BB=A8=EB=B2=A4=EC=85=98=20=EB=A7=9E=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20=ED=8F=B4=EB=8D=94=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/components/Modal/Modal.tsx | 2 +- apps/web/src/components/{Portal2 => Portal}/AnimatePortal.tsx | 2 +- apps/web/src/components/{Portal2 => Portal}/Portal.tsx | 4 +--- apps/web/src/components/Portal/index.ts | 2 ++ 4 files changed, 5 insertions(+), 5 deletions(-) rename apps/web/src/components/{Portal2 => Portal}/AnimatePortal.tsx (94%) rename apps/web/src/components/{Portal2 => Portal}/Portal.tsx (85%) create mode 100644 apps/web/src/components/Portal/index.ts diff --git a/apps/web/src/components/Modal/Modal.tsx b/apps/web/src/components/Modal/Modal.tsx index 4f925091..96fdb2cc 100644 --- a/apps/web/src/components/Modal/Modal.tsx +++ b/apps/web/src/components/Modal/Modal.tsx @@ -4,7 +4,7 @@ import { center } from '_panda/patterns'; import { useBodyLock, useOutsideClick } from '@gitanimals/react'; import { X } from 'lucide-react'; -import Portal from '../Portal2/Portal'; +import { Portal } from '../portal'; interface ModalProps { isOpen: boolean; diff --git a/apps/web/src/components/Portal2/AnimatePortal.tsx b/apps/web/src/components/Portal/AnimatePortal.tsx similarity index 94% rename from apps/web/src/components/Portal2/AnimatePortal.tsx rename to apps/web/src/components/Portal/AnimatePortal.tsx index 49ef295d..b46a6e12 100644 --- a/apps/web/src/components/Portal2/AnimatePortal.tsx +++ b/apps/web/src/components/Portal/AnimatePortal.tsx @@ -1,7 +1,7 @@ import type { ComponentProps } from 'react'; import { AnimatePresence } from 'framer-motion'; -import Portal from './Portal'; +import { Portal } from '../portal'; interface Props extends ComponentProps { /** diff --git a/apps/web/src/components/Portal2/Portal.tsx b/apps/web/src/components/Portal/Portal.tsx similarity index 85% rename from apps/web/src/components/Portal2/Portal.tsx rename to apps/web/src/components/Portal/Portal.tsx index 708ba543..1891b059 100644 --- a/apps/web/src/components/Portal2/Portal.tsx +++ b/apps/web/src/components/Portal/Portal.tsx @@ -5,7 +5,7 @@ import { createPortal } from 'react-dom'; * @description react.createPortal을 이용해 document.body에 children을 렌더링합니다 * @param children */ -const Portal = ({ children }: PropsWithChildren) => { +export const Portal = ({ children }: PropsWithChildren) => { const [container, setContainer] = useState(null); useEffect(() => { @@ -18,5 +18,3 @@ const Portal = ({ children }: PropsWithChildren) => { return createPortal(children, container); }; - -export default Portal; diff --git a/apps/web/src/components/Portal/index.ts b/apps/web/src/components/Portal/index.ts new file mode 100644 index 00000000..146e0f2d --- /dev/null +++ b/apps/web/src/components/Portal/index.ts @@ -0,0 +1,2 @@ +export * from './AnimatePortal'; +export * from './Portal'; From 7d74938cb767e827d965cd9949dbf3fdcb2c2236 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Fri, 15 Nov 2024 18:56:26 +0900 Subject: [PATCH 14/49] =?UTF-8?q?feat:=20shadow=20panda=20=EC=84=A4?= =?UTF-8?q?=EC=B9=98=20=EB=B0=8F=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/package.json | 2 + apps/web/panda.config.ts | 2 +- apps/web/src/app/[locale]/dev/page.tsx | 17 +++ packages/ui/panda/package.json | 11 +- packages/ui/panda/panda.config.ts | 2 +- packages/ui/panda/src/components/index.ts | 1 + .../src/components/ui/accordion/index.tsx | 40 ++++++ pnpm-lock.yaml | 118 ++++++++++++++++++ 8 files changed, 187 insertions(+), 6 deletions(-) create mode 100644 packages/ui/panda/src/components/ui/accordion/index.tsx diff --git a/apps/web/package.json b/apps/web/package.json index 80b48af2..f7811307 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -26,6 +26,7 @@ "@gitanimals/util-common": "workspace:*", "@next/third-parties": "^14.2.5", "@octokit/core": "^6.1.2", + "@shadow-panda/style-context": "^0.7.1", "@suspensive/react": "^2.17.1", "@tanstack/react-query": "*", "axios": "^1.6.8", @@ -51,6 +52,7 @@ "@gitanimals/util-common": "workspace:*", "@next/bundle-analyzer": "^14.2.5", "@pandacss/dev": "^0.41.0", + "@shadow-panda/preset": "^0.7.1", "@storybook/addon-essentials": "^8.0.9", "@storybook/addon-interactions": "^8.0.9", "@storybook/addon-links": "^8.0.9", diff --git a/apps/web/panda.config.ts b/apps/web/panda.config.ts index 3e0766bb..e55a24d9 100644 --- a/apps/web/panda.config.ts +++ b/apps/web/panda.config.ts @@ -116,5 +116,5 @@ export default defineConfig({ outdir: 'styled-system', // delete default presets - presets: [], + presets: ['@shadow-panda/preset'], }); diff --git a/apps/web/src/app/[locale]/dev/page.tsx b/apps/web/src/app/[locale]/dev/page.tsx index 09d5f50d..c215964e 100644 --- a/apps/web/src/app/[locale]/dev/page.tsx +++ b/apps/web/src/app/[locale]/dev/page.tsx @@ -1,5 +1,6 @@ import { css } from '_panda/css'; import { Box } from '_panda/jsx'; +import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@gitanimals/ui-panda'; import GNB from '@/components/GNB/GNB'; @@ -13,6 +14,22 @@ async function DevPage() {

client

+ + + Is it accessible? + Yes. It adheres to the WAI-ARIA design pattern. + + + Is it styled? + + Yes. It comes with default styles that matches the other components' aesthetic. + + + + Is it animated? + Yes. It's animated by default, but you can disable it if you prefer. + + ); } diff --git a/packages/ui/panda/package.json b/packages/ui/panda/package.json index b133c045..42f994af 100644 --- a/packages/ui/panda/package.json +++ b/packages/ui/panda/package.json @@ -9,18 +9,21 @@ "generate:component": "turbo gen react-component" }, "dependencies": { - "lucide-react": "^0.408.0", - "@gitanimals/react": "workspace:*" + "@gitanimals/react": "workspace:*", + "@radix-ui/react-accordion": "^1.2.1", + "@shadow-panda/style-context": "^0.7.1", + "lucide-react": "^0.408.0" }, "devDependencies": { - "@pandacss/dev": "^0.41.0", "@gitanimals/eslint-config": "workspace:*", "@gitanimals/typescript-config": "workspace:*", "@gitanimals/ui-token": "workspace:*", "@gitanimals/util-typescript": "workspace:*", + "@pandacss/dev": "^0.41.0", + "@shadow-panda/preset": "^0.7.1", "@turbo/gen": "^1.12.4", - "@types/node": "^20.11.24", "@types/eslint": "^8.56.5", + "@types/node": "^20.11.24", "@types/react": "*", "@types/react-dom": "^18.2.19", "eslint": "^8.57.0", diff --git a/packages/ui/panda/panda.config.ts b/packages/ui/panda/panda.config.ts index 07d20f09..176d6fe1 100644 --- a/packages/ui/panda/panda.config.ts +++ b/packages/ui/panda/panda.config.ts @@ -35,5 +35,5 @@ export default defineConfig({ outdir: 'styled-system', // delete default presets - presets: [], + presets: ['@shadow-panda/preset'], }); diff --git a/packages/ui/panda/src/components/index.ts b/packages/ui/panda/src/components/index.ts index 915fb975..22a5a1ea 100644 --- a/packages/ui/panda/src/components/index.ts +++ b/packages/ui/panda/src/components/index.ts @@ -4,3 +4,4 @@ export * from './Modal'; export * from './Skeleton'; export * from './Banner'; export * from './Textfield'; +export * from './ui/accordion'; diff --git a/packages/ui/panda/src/components/ui/accordion/index.tsx b/packages/ui/panda/src/components/ui/accordion/index.tsx new file mode 100644 index 00000000..2e13ec6b --- /dev/null +++ b/packages/ui/panda/src/components/ui/accordion/index.tsx @@ -0,0 +1,40 @@ +'use client'; + +import * as React from 'react'; +import * as AccordionPrimitive from '@radix-ui/react-accordion'; +import { ChevronDown } from 'lucide-react'; +import { createStyleContext } from '@shadow-panda/style-context'; +import { styled } from '_panda/jsx'; +import { accordion } from '_panda/recipes'; + +const { withProvider, withContext } = createStyleContext(accordion); + +const Header = withContext(styled(AccordionPrimitive.Header), 'header'); + +const Trigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ children, ...props }, ref) => ( +
+ + {children} + + +
+)); +Trigger.displayName = AccordionPrimitive.Trigger.displayName; + +const Content = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ children, ...props }, ref) => ( + +
{children}
+
+)); +Content.displayName = AccordionPrimitive.Content.displayName; + +export const Accordion = withProvider(styled(AccordionPrimitive.Root), 'root'); +export const AccordionItem = withContext(styled(AccordionPrimitive.Item), 'item'); +export const AccordionTrigger = withContext(styled(Trigger), 'trigger'); +export const AccordionContent = withContext(styled(Content), 'content'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bacb78cc..7466908c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -183,6 +183,9 @@ importers: '@octokit/core': specifier: ^6.1.2 version: 6.1.2 + '@shadow-panda/style-context': + specifier: ^0.7.1 + version: 0.7.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) '@suspensive/react': specifier: ^2.17.1 version: 2.17.1(react@18.2.0) @@ -250,6 +253,9 @@ importers: '@pandacss/dev': specifier: ^0.41.0 version: 0.41.0(typescript@5.4.5) + '@shadow-panda/preset': + specifier: ^0.7.1 + version: 0.7.1(@pandacss/dev@0.41.0(typescript@5.4.5)) '@storybook/addon-essentials': specifier: ^8.0.9 version: 8.1.9(@types/react-dom@18.2.19)(@types/react@18.2.61)(prettier@3.2.5)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) @@ -479,6 +485,12 @@ importers: '@gitanimals/react': specifier: workspace:* version: link:../../lib/react + '@radix-ui/react-accordion': + specifier: ^1.2.1 + version: 1.2.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@shadow-panda/style-context': + specifier: ^0.7.1 + version: 0.7.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) lucide-react: specifier: ^0.408.0 version: 0.408.0(react@18.2.0) @@ -498,6 +510,9 @@ importers: '@pandacss/dev': specifier: ^0.41.0 version: 0.41.0(typescript@5.4.5) + '@shadow-panda/preset': + specifier: ^0.7.1 + version: 0.7.1(@pandacss/dev@0.41.0(typescript@5.4.5)) '@turbo/gen': specifier: ^1.12.4 version: 1.12.4(@types/node@20.11.24)(typescript@5.4.5) @@ -1884,6 +1899,7 @@ packages: '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} @@ -1891,6 +1907,7 @@ packages: '@humanwhocodes/object-schema@2.0.2': resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + deprecated: Use @eslint/object-schema instead '@img/sharp-darwin-arm64@0.33.4': resolution: {integrity: sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==} @@ -2290,6 +2307,19 @@ packages: '@radix-ui/primitive@1.1.0': resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} + '@radix-ui/react-accordion@1.2.1': + resolution: {integrity: sha512-bg/l7l5QzUjgsh8kjwDFommzAshnUsuVMV5NM56QVCm+7ZckYdd9P/ExR8xG/Oup0OajVxNLaHJ1tb8mXk+nzQ==} + peerDependencies: + '@types/react': ^18 + '@types/react-dom': '*' + react: ^18 + react-dom: ^18.3.1 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-arrow@1.1.0': resolution: {integrity: sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==} peerDependencies: @@ -2329,6 +2359,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-collapsible@1.1.1': + resolution: {integrity: sha512-1///SnrfQHJEofLokyczERxQbWfCGQlQ2XsCZMucVs6it+lq9iw4vXy+uDn1edlb58cOZOWSldnfPAYcT4O/Yg==} + peerDependencies: + '@types/react': ^18 + '@types/react-dom': '*' + react: ^18 + react-dom: ^18.3.1 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-collection@1.1.0': resolution: {integrity: sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==} peerDependencies: @@ -2378,6 +2421,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-context@1.1.1': + resolution: {integrity: sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==} + peerDependencies: + '@types/react': ^18 + react: ^18 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-dialog@1.0.5': resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==} peerDependencies: @@ -2592,6 +2644,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-presence@1.1.1': + resolution: {integrity: sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==} + peerDependencies: + '@types/react': ^18 + '@types/react-dom': '*' + react: ^18 + react-dom: ^18.3.1 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-primitive@1.0.3': resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: @@ -5251,6 +5316,7 @@ packages: eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@9.6.1: @@ -5663,6 +5729,7 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -5911,6 +5978,7 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -7903,6 +7971,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true ripemd160@2.0.2: @@ -10986,6 +11055,23 @@ snapshots: '@radix-ui/primitive@1.1.0': {} + '@radix-ui/react-accordion@1.2.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-collapsible': 1.1.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-direction': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.61)(react@18.2.0) + react: 18.2.0 + react-dom: 18.3.1(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + '@radix-ui/react-arrow@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': dependencies: '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) @@ -11023,6 +11109,22 @@ snapshots: '@types/react': 18.2.61 '@types/react-dom': 18.2.19 + '@radix-ui/react-collapsible@1.1.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.61)(react@18.2.0) + react: 18.2.0 + react-dom: 18.3.1(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + '@radix-ui/react-collection@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.61)(react@18.2.0) @@ -11061,6 +11163,12 @@ snapshots: optionalDependencies: '@types/react': 18.2.61 + '@radix-ui/react-context@1.1.1(@types/react@18.2.61)(react@18.2.0)': + dependencies: + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.61 + '@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.7 @@ -11290,6 +11398,16 @@ snapshots: '@types/react': 18.2.61 '@types/react-dom': 18.2.19 + '@radix-ui/react-presence@1.1.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.61)(react@18.2.0) + react: 18.2.0 + react-dom: 18.3.1(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.7 From d10abd9582563c6f085960954e7f34f6504d0e35 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Fri, 15 Nov 2024 18:59:41 +0900 Subject: [PATCH 15/49] =?UTF-8?q?feat:=20=ED=8F=B4=EB=8D=94=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EB=B0=8F=20dialog=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ui/panda/package.json | 1 + .../index.tsx => Accordion/Accordion.tsx} | 0 .../panda/src/components/Accordion/index.ts | 1 + .../ui/panda/src/components/Dialog/Dialog.tsx | 40 ++++++ .../ui/panda/src/components/Dialog/index.ts | 0 .../panda/src/components/Modal/FullModal.tsx | 1 + .../ui/panda/src/components/Modal/Modal.tsx | 2 +- .../src/components/Modal/ScreenModal.tsx | 1 + packages/ui/panda/src/components/index.ts | 3 +- pnpm-lock.yaml | 123 ++++++++++++++++++ 10 files changed, 170 insertions(+), 2 deletions(-) rename packages/ui/panda/src/components/{ui/accordion/index.tsx => Accordion/Accordion.tsx} (100%) create mode 100644 packages/ui/panda/src/components/Accordion/index.ts create mode 100644 packages/ui/panda/src/components/Dialog/Dialog.tsx create mode 100644 packages/ui/panda/src/components/Dialog/index.ts diff --git a/packages/ui/panda/package.json b/packages/ui/panda/package.json index 42f994af..c862b76b 100644 --- a/packages/ui/panda/package.json +++ b/packages/ui/panda/package.json @@ -11,6 +11,7 @@ "dependencies": { "@gitanimals/react": "workspace:*", "@radix-ui/react-accordion": "^1.2.1", + "@radix-ui/react-dialog": "^1.1.2", "@shadow-panda/style-context": "^0.7.1", "lucide-react": "^0.408.0" }, diff --git a/packages/ui/panda/src/components/ui/accordion/index.tsx b/packages/ui/panda/src/components/Accordion/Accordion.tsx similarity index 100% rename from packages/ui/panda/src/components/ui/accordion/index.tsx rename to packages/ui/panda/src/components/Accordion/Accordion.tsx diff --git a/packages/ui/panda/src/components/Accordion/index.ts b/packages/ui/panda/src/components/Accordion/index.ts new file mode 100644 index 00000000..63f62bc6 --- /dev/null +++ b/packages/ui/panda/src/components/Accordion/index.ts @@ -0,0 +1 @@ +export * from './Accordion'; diff --git a/packages/ui/panda/src/components/Dialog/Dialog.tsx b/packages/ui/panda/src/components/Dialog/Dialog.tsx new file mode 100644 index 00000000..a75008d0 --- /dev/null +++ b/packages/ui/panda/src/components/Dialog/Dialog.tsx @@ -0,0 +1,40 @@ +'use client'; + +import * as React from 'react'; +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { X } from 'lucide-react'; +import { createStyleContext } from '@shadow-panda/style-context'; +import { styled } from '_panda/jsx'; +import { css } from '_panda/css'; +import { dialog, icon } from '_panda/recipes'; + +const { withProvider, withContext } = createStyleContext(dialog); + +const DialogPortal = withContext(styled(DialogPrimitive.Portal), 'portal'); +const DialogOverlay = withContext(styled(DialogPrimitive.Overlay), 'overlay'); +const DialogClose = withContext(styled(DialogPrimitive.Close), 'close'); + +const Content = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +Content.displayName = DialogPrimitive.Content.displayName; + +export const Dialog = withProvider(styled(DialogPrimitive.Root), 'root'); +export const DialogTrigger = withContext(styled(DialogPrimitive.Trigger), 'trigger'); +export const DialogContent = withContext(styled(Content), 'content'); +export const DialogHeader = withContext(styled('div'), 'header'); +export const DialogFooter = withContext(styled('div'), 'footer'); +export const DialogTitle = withContext(styled(DialogPrimitive.Title), 'title'); +export const DialogDescription = withContext(styled(DialogPrimitive.Description), 'description'); diff --git a/packages/ui/panda/src/components/Dialog/index.ts b/packages/ui/panda/src/components/Dialog/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/ui/panda/src/components/Modal/FullModal.tsx b/packages/ui/panda/src/components/Modal/FullModal.tsx index 798d1db0..559223c0 100644 --- a/packages/ui/panda/src/components/Modal/FullModal.tsx +++ b/packages/ui/panda/src/components/Modal/FullModal.tsx @@ -95,6 +95,7 @@ export const FullModal = Object.assign(FullModalRoot, { Content: FullModalContent, }); +/** @deprecated */ export function FullModalBase({ isOpen, onClose, children }: PropsWithChildren) { return ( diff --git a/packages/ui/panda/src/components/Modal/Modal.tsx b/packages/ui/panda/src/components/Modal/Modal.tsx index f9b9ab55..118b91de 100644 --- a/packages/ui/panda/src/components/Modal/Modal.tsx +++ b/packages/ui/panda/src/components/Modal/Modal.tsx @@ -11,7 +11,7 @@ interface Props { isOpen: boolean; onClose?: () => void; } - +/** @deprecated */ export function Modal({ isOpen, onClose, children }: PropsWithChildren) { const { dialogRef } = useDialog({ isOpen, onClose }); diff --git a/packages/ui/panda/src/components/Modal/ScreenModal.tsx b/packages/ui/panda/src/components/Modal/ScreenModal.tsx index 313f988f..d203cd41 100644 --- a/packages/ui/panda/src/components/Modal/ScreenModal.tsx +++ b/packages/ui/panda/src/components/Modal/ScreenModal.tsx @@ -14,6 +14,7 @@ interface ScreenModalProps { /** * 화면 전체를 덮는 모달 컴포넌트 + * @deprecated */ function ScreenModalRoot({ isOpen, onClose, children }: PropsWithChildren) { const { dialogRef } = useDialog({ isOpen, onClose }); diff --git a/packages/ui/panda/src/components/index.ts b/packages/ui/panda/src/components/index.ts index 22a5a1ea..8e3b84c7 100644 --- a/packages/ui/panda/src/components/index.ts +++ b/packages/ui/panda/src/components/index.ts @@ -4,4 +4,5 @@ export * from './Modal'; export * from './Skeleton'; export * from './Banner'; export * from './Textfield'; -export * from './ui/accordion'; +export * from './Accordion'; +export * from './Dialog'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7466908c..d3196517 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -488,6 +488,9 @@ importers: '@radix-ui/react-accordion': specifier: ^1.2.1 version: 1.2.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-dialog': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) '@shadow-panda/style-context': specifier: ^0.7.1 version: 0.7.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) @@ -2443,6 +2446,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-dialog@1.1.2': + resolution: {integrity: sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==} + peerDependencies: + '@types/react': ^18 + '@types/react-dom': '*' + react: ^18 + react-dom: ^18.3.1 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-direction@1.1.0': resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} peerDependencies: @@ -2478,6 +2494,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-dismissable-layer@1.1.1': + resolution: {integrity: sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==} + peerDependencies: + '@types/react': ^18 + '@types/react-dom': '*' + react: ^18 + react-dom: ^18.3.1 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-dropdown-menu@2.1.1': resolution: {integrity: sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==} peerDependencies: @@ -2509,6 +2538,15 @@ packages: '@types/react': optional: true + '@radix-ui/react-focus-guards@1.1.1': + resolution: {integrity: sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==} + peerDependencies: + '@types/react': ^18 + react: ^18 + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-focus-scope@1.0.4': resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} peerDependencies: @@ -2618,6 +2656,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-portal@1.1.2': + resolution: {integrity: sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==} + peerDependencies: + '@types/react': ^18 + '@types/react-dom': '*' + react: ^18 + react-dom: ^18.3.1 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-presence@1.0.1': resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} peerDependencies: @@ -7770,6 +7821,16 @@ packages: '@types/react': optional: true + react-remove-scroll@2.6.0: + resolution: {integrity: sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^18 + react: ^18 + peerDependenciesMeta: + '@types/react': + optional: true + react-router-dom@6.25.0: resolution: {integrity: sha512-BhcczgDWWgvGZxjDDGuGHrA8HrsSudilqTaRSBYLWDayvo1ClchNIDVt5rldqp6e7Dro5dEFx9Mzc+r292lN0w==} engines: {node: '>=14.0.0'} @@ -11192,6 +11253,28 @@ snapshots: '@types/react': 18.2.61 '@types/react-dom': 18.2.19 + '@radix-ui/react-dialog@1.1.2(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-context': 1.1.1(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-id': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-portal': 1.1.2(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.61)(react@18.2.0) + aria-hidden: 1.2.4 + react: 18.2.0 + react-dom: 18.3.1(react@18.2.0) + react-remove-scroll: 2.6.0(@types/react@18.2.61)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + '@radix-ui/react-direction@1.1.0(@types/react@18.2.61)(react@18.2.0)': dependencies: react: 18.2.0 @@ -11225,6 +11308,19 @@ snapshots: '@types/react': 18.2.61 '@types/react-dom': 18.2.19 + '@radix-ui/react-dismissable-layer@1.1.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.61)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.2.61)(react@18.2.0) + react: 18.2.0 + react-dom: 18.3.1(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + '@radix-ui/react-dropdown-menu@2.1.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -11253,6 +11349,12 @@ snapshots: optionalDependencies: '@types/react': 18.2.61 + '@radix-ui/react-focus-guards@1.1.1(@types/react@18.2.61)(react@18.2.0)': + dependencies: + react: 18.2.0 + optionalDependencies: + '@types/react': 18.2.61 + '@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.7 @@ -11377,6 +11479,16 @@ snapshots: '@types/react': 18.2.61 '@types/react-dom': 18.2.19 + '@radix-ui/react-portal@1.1.2(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.61)(react@18.2.0) + react: 18.2.0 + react-dom: 18.3.1(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + '@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.24.7 @@ -18102,6 +18214,17 @@ snapshots: optionalDependencies: '@types/react': 18.2.61 + react-remove-scroll@2.6.0(@types/react@18.2.61)(react@18.2.0): + dependencies: + react: 18.2.0 + react-remove-scroll-bar: 2.3.6(@types/react@18.2.61)(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.61)(react@18.2.0) + tslib: 2.6.2 + use-callback-ref: 1.3.2(@types/react@18.2.61)(react@18.2.0) + use-sidecar: 1.1.2(@types/react@18.2.61)(react@18.2.0) + optionalDependencies: + '@types/react': 18.2.61 + react-router-dom@6.25.0(react-dom@18.3.1(react@18.2.0))(react@18.2.0): dependencies: '@remix-run/router': 1.18.0 From 4dfb8c921f86a00e05e085912b409c3d4e124818 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 16 Nov 2024 17:52:43 +0900 Subject: [PATCH 16/49] =?UTF-8?q?refactor:=20=EB=9E=98=EB=B9=97=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EB=A6=AC=EB=B7=B0=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/my-pet/(merge)/MergePersona.tsx | 22 ++++++++++--------- .../src/components/Portal/AnimatePortal.tsx | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index 009595cd..e5fff7e5 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -30,17 +30,17 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona const [resultData, setResultData] = useState(null); - const [meterialPersona, setMeterialPersona] = useState(null); + const [materialPersona, setMaterialPersona] = useState(null); const [targetPersona, setTargetPersona] = useState(initTargetPersona); const session = useClientSession(); const token = session.data?.user.accessToken as string; - const isMergeDisabled = !meterialPersona || !targetPersona; - const selectPersona = [targetPersona.id, meterialPersona?.id].filter(Boolean) as string[]; + const isMergeDisabled = !materialPersona || !targetPersona; + const selectPersona = [targetPersona.id, materialPersona?.id].filter(Boolean) as string[]; const { mutate: mergePersonaLevel, isPending: isMerging } = useMergePersonaLevelByToken(token, { onSuccess: (data) => { - setMeterialPersona(null); + setMaterialPersona(null); setResultData(data); setTargetPersona(data); queryClient.invalidateQueries({ queryKey: userQueries.allPersonasKey() }); @@ -48,34 +48,36 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona }); const onMergeAction = () => { - if (!targetPersona?.id || !meterialPersona?.id) { + if (!targetPersona?.id || !materialPersona?.id) { return; } mergePersonaLevel({ increasePersonaId: targetPersona.id, - deletePersonaId: meterialPersona.id, + deletePersonaId: materialPersona.id, }); }; const onSelectPersona = (currentSelectPersona: Persona) => { if (currentSelectPersona.id === targetPersona.id) { - setMeterialPersona(null); + setMaterialPersona(null); } else { - setMeterialPersona(currentSelectPersona); + setMaterialPersona(currentSelectPersona); } }; return ( - +
- + diff --git a/apps/web/src/components/Portal/AnimatePortal.tsx b/apps/web/src/components/Portal/AnimatePortal.tsx index b46a6e12..26ab3188 100644 --- a/apps/web/src/components/Portal/AnimatePortal.tsx +++ b/apps/web/src/components/Portal/AnimatePortal.tsx @@ -1,7 +1,7 @@ import type { ComponentProps } from 'react'; import { AnimatePresence } from 'framer-motion'; -import { Portal } from '../portal'; +import { Portal } from './Portal'; interface Props extends ComponentProps { /** From 435993cc7afbca09ac591f90bad7f966e09af548 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 16 Nov 2024 19:59:24 +0900 Subject: [PATCH 17/49] =?UTF-8?q?fix:=20=EC=BF=BC=EB=A6=AC=20=EB=AC=B4?= =?UTF-8?q?=ED=9A=A8=ED=99=94=EA=B0=80=20=EC=95=84=EB=8B=8C=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A1=B0=EC=9E=91?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20optimistic=20update=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/my-pet/(merge)/MergePersona.tsx | 39 ++++++++++++++++++- .../src/app/[locale]/mypage/my-pet/page.tsx | 3 -- packages/lib/react-query/src/user/queries.ts | 2 +- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index e5fff7e5..dc676e84 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -4,7 +4,7 @@ import { useState } from 'react'; import { useTranslations } from 'next-intl'; import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; -import type { MergePersonaLevelResponse, Persona } from '@gitanimals/api'; +import type { GetAllMyPersonasResponse, MergePersonaLevelResponse, Persona } from '@gitanimals/api'; import { useMergePersonaLevelByToken, userQueries } from '@gitanimals/react-query'; import { Button, FullModalBase, LevelBanner } from '@gitanimals/ui-panda'; import { BannerSkeleton } from '@gitanimals/ui-panda/src/components/Banner/Banner'; @@ -39,11 +39,45 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona const selectPersona = [targetPersona.id, materialPersona?.id].filter(Boolean) as string[]; const { mutate: mergePersonaLevel, isPending: isMerging } = useMergePersonaLevelByToken(token, { + onMutate: async (variables) => { + const oldData = queryClient.getQueryData(userQueries.allPersonasKey()); // 현재 캐시된 데이터 가져오기 + + if (!oldData) { + return; + } + // 새로운 데이터로 가공 + const newData = { ...oldData }; // 객체 복사 + + newData.personas = [...oldData.personas].filter( + // 내부 데이터 복사 + (item) => item.id !== variables.deletePersonaId, + ); + + queryClient.setQueryData(userQueries.allPersonasKey(), { ...newData }); + + return { oldData }; // 다음 context로 넘기기 위해 반환 + }, + onError: (err, newData, context: any) => { + // 에러 발생시 이전 데이터로 캐시 저장 + if (context?.oldData) { + queryClient.setQueryData(userQueries.allPersonasKey(), context.oldData); + } + }, + onSuccess: (data) => { setMaterialPersona(null); setResultData(data); setTargetPersona(data); - queryClient.invalidateQueries({ queryKey: userQueries.allPersonasKey() }); + const prevAllPersonaData = queryClient.getQueryData(userQueries.allPersonasKey()); // 현재 캐시된 데이터 가져오기 + + const newPersonas = prevAllPersonaData?.personas.map((item) => { + if (item.id === data.id) { + return { ...data }; + } + return item; + }); + + queryClient.setQueryData(userQueries.allPersonasKey(), { ...prevAllPersonaData, personas: newPersonas }); }, }); @@ -83,6 +117,7 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona
setResultData(null)} result={resultData as MergePersonaLevelResponse} diff --git a/apps/web/src/app/[locale]/mypage/my-pet/page.tsx b/apps/web/src/app/[locale]/mypage/my-pet/page.tsx index 18ae07d3..589c3928 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/page.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/page.tsx @@ -35,9 +35,6 @@ function MypageMyPets() { setSelectPersona(persona)} - initSelectPersonas={(list) => { - setSelectPersona(list[0]); - }} />
diff --git a/packages/lib/react-query/src/user/queries.ts b/packages/lib/react-query/src/user/queries.ts index 552b88ec..4153462a 100644 --- a/packages/lib/react-query/src/user/queries.ts +++ b/packages/lib/react-query/src/user/queries.ts @@ -12,7 +12,7 @@ export const userQueries = { allPersonasKey: () => [...userQueries.allKey(), 'all-persona'], allPersonasOptions: (username: string) => queryOptions({ - queryKey: [...userQueries.allPersonasKey(), username], + queryKey: userQueries.allPersonasKey(), queryFn: () => getAllMyPersonas(username), }), }; From f751dedc19e7d4fb4e008888e3ce551c66f17bfa Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 16 Nov 2024 21:21:43 +0900 Subject: [PATCH 18/49] =?UTF-8?q?fix:=20=EC=98=A4=ED=83=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/[locale]/mypage/my-pet/(merge)/MergeResult.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergeResult.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergeResult.tsx index 3ac311d2..c6c6b36a 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergeResult.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergeResult.tsx @@ -66,12 +66,7 @@ function MotionContainer({ children, onClose }: PropsWithChildren<{ onClose: () - + {children}
@@ -137,7 +132,7 @@ const contentStyle = css({ textAlign: 'center', }); -const contentStranggerVariants = { +const contentStaggerVariants = { initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0, transition: { delay: 0.3 } }, }; From a1f08a7cbe459956de04f6c8dbeded16f2c59c57 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 16 Nov 2024 21:22:01 +0900 Subject: [PATCH 19/49] =?UTF-8?q?fix:=20=EC=84=A0=ED=83=9D=EB=90=9C=20?= =?UTF-8?q?=ED=8E=AB=EC=9D=B4=20=EC=97=86=EC=9D=84=20=EB=95=8C=EB=A7=8C=20?= =?UTF-8?q?=EC=B2=AB=EB=B2=88=EC=A7=B8=20=EC=84=A0=ED=83=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/app/[locale]/mypage/my-pet/page.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/page.tsx b/apps/web/src/app/[locale]/mypage/my-pet/page.tsx index 589c3928..b6966fba 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/page.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/page.tsx @@ -35,6 +35,11 @@ function MypageMyPets() { setSelectPersona(persona)} + initSelectPersonas={(list) => { + if (!selectPersona) { + setSelectPersona(list[0]); + } + }} />
From ceb8a3428436a04978cf1e143f6ab7961aafe58b Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sat, 16 Nov 2024 22:00:40 +0900 Subject: [PATCH 20/49] =?UTF-8?q?fix:=20=EC=84=B1=EB=8A=A5=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88=20=ED=95=B4=EA=B2=B0=20memo=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/[locale]/mypage/PersonaList.tsx | 43 ++++++--- .../mypage/my-pet/(merge)/MergePersona.tsx | 96 +++++++------------ .../ui/panda/src/components/Banner/Banner.tsx | 10 ++ 3 files changed, 74 insertions(+), 75 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/PersonaList.tsx b/apps/web/src/app/[locale]/mypage/PersonaList.tsx index cdc9e76d..1e6314bb 100644 --- a/apps/web/src/app/[locale]/mypage/PersonaList.tsx +++ b/apps/web/src/app/[locale]/mypage/PersonaList.tsx @@ -55,24 +55,41 @@ export const SelectPersonaList = wrap return viewListSorted; }, [data]); - return ( <> {viewList.map((persona) => ( - + isLoading={loadingPersona?.includes(persona.id) ?? false} + /> ))} ); }); + +interface PersonaItemProps { + persona: Persona; + isSelected: boolean; + onClick: () => void; + isLoading: boolean; +} + +function PersonaItem({ persona, isSelected, onClick, isLoading }: PersonaItemProps) { + return ( + + ); +} + +const MemoizedPersonaItem = React.memo(PersonaItem, (prev, next) => { + return prev.isSelected === next.isSelected && prev.persona.level === next.persona.level; +}); diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index dc676e84..d44ac7f8 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -1,13 +1,13 @@ 'use client'; -import { useState } from 'react'; +import { memo, useState } from 'react'; import { useTranslations } from 'next-intl'; import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; -import type { GetAllMyPersonasResponse, MergePersonaLevelResponse, Persona } from '@gitanimals/api'; +import type { MergePersonaLevelResponse, Persona } from '@gitanimals/api'; import { useMergePersonaLevelByToken, userQueries } from '@gitanimals/react-query'; import { Button, FullModalBase, LevelBanner } from '@gitanimals/ui-panda'; -import { BannerSkeleton } from '@gitanimals/ui-panda/src/components/Banner/Banner'; +import { BannerSkeletonList } from '@gitanimals/ui-panda/src/components/Banner/Banner'; import { wrap } from '@suspensive/react'; import { useQueryClient, useSuspenseQuery } from '@tanstack/react-query'; @@ -39,45 +39,11 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona const selectPersona = [targetPersona.id, materialPersona?.id].filter(Boolean) as string[]; const { mutate: mergePersonaLevel, isPending: isMerging } = useMergePersonaLevelByToken(token, { - onMutate: async (variables) => { - const oldData = queryClient.getQueryData(userQueries.allPersonasKey()); // 현재 캐시된 데이터 가져오기 - - if (!oldData) { - return; - } - // 새로운 데이터로 가공 - const newData = { ...oldData }; // 객체 복사 - - newData.personas = [...oldData.personas].filter( - // 내부 데이터 복사 - (item) => item.id !== variables.deletePersonaId, - ); - - queryClient.setQueryData(userQueries.allPersonasKey(), { ...newData }); - - return { oldData }; // 다음 context로 넘기기 위해 반환 - }, - onError: (err, newData, context: any) => { - // 에러 발생시 이전 데이터로 캐시 저장 - if (context?.oldData) { - queryClient.setQueryData(userQueries.allPersonasKey(), context.oldData); - } - }, - onSuccess: (data) => { setMaterialPersona(null); setResultData(data); setTargetPersona(data); - const prevAllPersonaData = queryClient.getQueryData(userQueries.allPersonasKey()); // 현재 캐시된 데이터 가져오기 - - const newPersonas = prevAllPersonaData?.personas.map((item) => { - if (item.id === data.id) { - return { ...data }; - } - return item; - }); - - queryClient.setQueryData(userQueries.allPersonasKey(), { ...prevAllPersonaData, personas: newPersonas }); + queryClient.invalidateQueries({ queryKey: userQueries.allPersonasKey() }); }, }); @@ -153,19 +119,8 @@ interface SelectPersonaListProps { } const SelectPersonaList = wrap - .ErrorBoundary({ - // TODO: 공통 에러 컴포넌트로 대체 - fallback:
error
, - }) - .Suspense({ - fallback: ( - <> - {Array.from({ length: 6 }).map((_, index) => ( - - ))} - - ), - }) + .ErrorBoundary({ fallback:
error
}) + .Suspense({ fallback: }) .on(function SelectPersonaList({ selectPersona, onSelectPersona }: SelectPersonaListProps) { const { name } = useClientUser(); const { data } = useSuspenseQuery(userQueries.allPersonasOptions(name)); @@ -173,23 +128,40 @@ const SelectPersonaList = wrap return ( <> {data.personas.map((persona) => ( - + /> ))} ); }); +interface PersonaItemProps { + persona: Persona; + isSelected: boolean; + onClick: () => void; +} + +function PersonaItem({ persona, isSelected, onClick }: PersonaItemProps) { + return ( + + ); +} + +const MemoizedPersonaItem = memo(PersonaItem, (prev, next) => { + return prev.isSelected === next.isSelected && prev.persona.level === next.persona.level; +}); + const SpinningLoader = () => { return (
diff --git a/packages/ui/panda/src/components/Banner/Banner.tsx b/packages/ui/panda/src/components/Banner/Banner.tsx index 644fb724..b414dc12 100644 --- a/packages/ui/panda/src/components/Banner/Banner.tsx +++ b/packages/ui/panda/src/components/Banner/Banner.tsx @@ -50,3 +50,13 @@ const labelStyle = css({ export function BannerSkeleton(props: BannerStyleProps) { return
; } + +export function BannerSkeletonList({ length, ...props }: BannerStyleProps & { length: number }) { + return ( + <> + {Array.from({ length }).map((_, index) => ( + + ))} + + ); +} From 9e22dd3eae6eda3e254fc8c154ee08fcb95a615e Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sun, 17 Nov 2024 23:15:40 +0900 Subject: [PATCH 21/49] =?UTF-8?q?fix:=20=EB=94=94=EC=9E=90=EC=9D=B8?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EB=94=94=ED=85=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/my-pet/(merge)/MergePersona.tsx | 8 +++ .../mypage/my-pet/(merge)/MergePreview.tsx | 54 +++++++++---------- .../src/components/Banner/LevelBanner.tsx | 2 +- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index d44ac7f8..96d5e3bb 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -68,6 +68,7 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona return ( +

Merge Persona Level

@@ -93,6 +94,13 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona ); } +const headingStyle = css({ + textStyle: 'glyph48.bold', + color: 'white.white_100', + textAlign: 'center', + marginTop: 40, +}); + const bottomButtonStyle = css({ display: 'flex', justifyContent: 'center', gap: 12 }); const listStyle = cx( diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePreview.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePreview.tsx index 1d0b368a..162b6fe9 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePreview.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePreview.tsx @@ -1,9 +1,10 @@ /* eslint-disable @next/next/no-img-element */ import type { PropsWithChildren } from 'react'; -import { css } from '_panda/css'; +import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; import type { Persona } from '@gitanimals/api'; import { motion } from 'framer-motion'; +import { EqualIcon, PlusIcon } from 'lucide-react'; import { getPersonaImage } from '@/utils/image'; @@ -30,10 +31,10 @@ export const MergePreview = ({ materialPersona, targetPersona }: MergePersonaPro
{targetPersona ? : } -
+
+ {materialPersona ? : } -
=
+ {resultPersona ? : } @@ -52,38 +53,19 @@ const containerStyle = css({ const itemContainerStyle = flex({ alignItems: 'center', justifyContent: 'center', - gap: '16px', + gap: 24, +}); + +const iconStyle = css({ + marginBottom: 34, }); const itemStyle = css({ position: 'relative', - width: '120px', - // height: '120px', backgroundColor: 'gray.700', padding: '8px', }); -const imageStyle = css({ - width: '100%', - height: '100%', - objectFit: 'contain', -}); - -const levelTextStyle = css({ - textAlign: 'center', - marginTop: '8px', - fontSize: '14px', -}); - -const plusSignStyle = css({ - fontSize: '24px', - fontWeight: 'bold', -}); - -const arrowStyle = css({ - marginX: '16px', -}); - const flashEffectStyle = css({ position: 'absolute', inset: 0, @@ -95,7 +77,7 @@ function MergeEmptyItem() { return (
empty -
Level ?
+
Level ?
); } @@ -110,6 +92,22 @@ function MergeItem({ persona }: PropsWithChildren<{ persona: Persona }>) {
); } +const imageStyle = css({ + objectFit: 'contain', + width: 120, + height: 120, +}); + +const levelTextStyle = css({ + textAlign: 'center', + marginTop: '12px', + textStyle: 'glyph18.bold', + color: 'white.white_100', +}); + +const levelEmptyTextStyle = css({ + color: 'white.white_75', +}); const mergeItemStyle = css({ borderRadius: '16px', diff --git a/packages/ui/panda/src/components/Banner/LevelBanner.tsx b/packages/ui/panda/src/components/Banner/LevelBanner.tsx index 94e0b991..14e96884 100644 --- a/packages/ui/panda/src/components/Banner/LevelBanner.tsx +++ b/packages/ui/panda/src/components/Banner/LevelBanner.tsx @@ -10,7 +10,7 @@ type Props = BannerStyleProps & { export function LevelBanner({ image, level, ...styleProps }: Props) { return (
- {typeof image === 'string' ? {image} : image} + {typeof image === 'string' ? {image} : image}

Lv.{level}

); From a8a5007eb716458cfb256873428b0bc6ee635969 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Sun, 17 Nov 2024 23:25:01 +0900 Subject: [PATCH 22/49] =?UTF-8?q?refactor:=20select=20option=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=98=AE=EA=B8=B0=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/my-pet/(merge)/MergePersona.tsx | 71 +++++++++++-------- .../shop/AuctionSection/DefaultTabRight.tsx | 2 +- .../shop/SearchOption/SortDirectionSelect.tsx | 15 ---- .../app/[locale]/shop/SearchOption/index.ts | 4 -- .../SelectOption}/OrderTypeSelect.tsx | 8 +-- .../SelectOption/SelectOption.tsx} | 12 ++-- .../SelectOption/SortDirectionSelect.tsx | 13 ++++ apps/web/src/components/SelectOption/index.ts | 3 + 8 files changed, 70 insertions(+), 58 deletions(-) delete mode 100644 apps/web/src/app/[locale]/shop/SearchOption/SortDirectionSelect.tsx delete mode 100644 apps/web/src/app/[locale]/shop/SearchOption/index.ts rename apps/web/src/{app/[locale]/shop/SearchOption => components/SelectOption}/OrderTypeSelect.tsx (52%) rename apps/web/src/{app/[locale]/shop/SearchOption/SearchOptionSelect.tsx => components/SelectOption/SelectOption.tsx} (78%) create mode 100644 apps/web/src/components/SelectOption/SortDirectionSelect.tsx create mode 100644 apps/web/src/components/SelectOption/index.ts diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index 96d5e3bb..0ca78307 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -71,9 +71,7 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona

Merge Persona Level

-
- -
+
-

{t('choose-one-card')}

- - {isRunning && ( -

- {count} {t('close-notice-message')} -

- )} - {/* {isRunning &&

{t('close-notice', { count: 3 })}

} */} -
- + +

{t('choose-one-card')}

+ + {isRunning && ( +

{t('close-notice-message').replace('[count]', count.toString())}

+ )} +
); } @@ -125,34 +127,6 @@ const noticeMessageStyle = css({ textAlign: 'center', }); -const modalStyle = center({ - position: 'fixed', - top: 0, - left: 0, - width: '100%', - height: '100%', - backgroundColor: 'black.black_75', - zIndex: 1000, -}); - -const modalContentStyle = center({ - backgroundColor: 'gray.gray_150', - flexDirection: 'column', - width: 'calc(100% - 400px)', - minWidth: '1260px', - maxWidth: '1540px', - height: 'calc(100% - 120px)', - maxHeight: '840px', - borderRadius: '20px', - position: 'relative', -}); - -const closeButtonStyle = css({ - position: 'absolute', - right: '28px', - top: '28px', -}); - const headingStyle = css({ textStyle: 'glyph48.bold', color: 'white', diff --git a/apps/web/src/app/[locale]/shop/PetGotcha/PetGotcha.tsx b/apps/web/src/app/[locale]/shop/PetGotcha/PetGotcha.tsx index 7527ca47..e89165c1 100644 --- a/apps/web/src/app/[locale]/shop/PetGotcha/PetGotcha.tsx +++ b/apps/web/src/app/[locale]/shop/PetGotcha/PetGotcha.tsx @@ -7,6 +7,7 @@ import { css } from '_panda/css'; import { Button } from '@gitanimals/ui-panda'; import OnePet from './OnePet'; +import { TenPet } from './TenPet'; export function PetGotcha() { const t = useTranslations('Gotcha'); @@ -21,8 +22,8 @@ export function PetGotcha() { - {/* */}
@@ -30,6 +31,7 @@ export function PetGotcha() { pet-gotcha-pet
{openModal === 'one-pet' && setOpenModal(null)} />} + {openModal === 'ten-pet' && setOpenModal(null)} />}
); } diff --git a/apps/web/src/app/[locale]/shop/PetGotcha/TenCardFlipGame.tsx b/apps/web/src/app/[locale]/shop/PetGotcha/TenCardFlipGame.tsx new file mode 100644 index 00000000..63fb8da8 --- /dev/null +++ b/apps/web/src/app/[locale]/shop/PetGotcha/TenCardFlipGame.tsx @@ -0,0 +1,156 @@ +import React, { useEffect, useState } from 'react'; +import { css, cx } from '_panda/css'; +import type { GotchaResult } from '@gitanimals/api'; +import { CardBack } from '@gitanimals/ui-panda'; +import { motion } from 'framer-motion'; + +import { AnimalCard } from '@/components/AnimalCard'; + +const Card = ({ + onClick, + persona, + isFlipped, +}: { + onClick: () => void; + persona: GotchaResult | null; + isFlipped: boolean; +}) => { + return ( + + ); +}; + +const cardStyle = css({ + position: 'relative', + cursor: 'pointer', + width: '220px', + height: '272px', + perspective: '1000px', +}); + +const cardInnerStyle = css({ + width: '100%', + height: '100%', + position: 'relative', + transformStyle: 'preserve-3d', +}); + +const cardFaceStyle = css({ + position: 'absolute', + width: '100%', + height: '100%', + borderRadius: 'xl', + boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)', +}); + +const cardFrontFaceStyle = css({ backfaceVisibility: 'hidden' }); +const cardBackFaceStyle = css({ backfaceVisibility: 'hidden', transform: 'rotateY(180deg)' }); + +export const TenCardFlipGame = ({ + onGetPersona, + getPersona, +}: { + onGetPersona: () => void; + getPersona: GotchaResult[] | null; +}) => { + const [flippedCards, setFlippedCards] = useState(Array(10).fill(false)); + const [isAnimating, setIsAnimating] = useState(false); + + // 모든 카드 순차적으로 뒤집기 + const handleFlipAll = async () => { + if (isAnimating) return; + setIsAnimating(true); + + // 현재 상태 확인 (하나라도 뒤집혀있으면 모두 원래대로, 아니면 모두 뒤집기) + + // 순차적으로 뒤집기 + for (let i = 0; i < 10; i++) { + await new Promise((resolve) => setTimeout(resolve, 100)); + setFlippedCards((prev) => { + const newState = [...prev]; + newState[i] = true; + return newState; + }); + } + setTimeout(() => setIsAnimating(false), 200); + }; + + const onCardClick = () => { + onGetPersona(); + }; + + useEffect(() => { + if (getPersona) { + handleFlipAll(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [getPersona]); + + return ( + <> +
+
+
+
+ {[0, 1, 2, 3, 4].map((index) => ( + onCardClick()} + persona={getPersona ? getPersona[index] : null} + /> + ))} +
+ {/* 하단 행 */} +
+ {[5, 6, 7, 8, 9].map((index) => ( + onCardClick()} + persona={getPersona ? getPersona[index] : null} + /> + ))} +
+
+
+
+ + ); +}; + +const gameContainerStyle = css({ + width: '100%', +}); + +const cardGridStyle = css({ + display: 'flex', + flexDirection: 'column', + gap: '6', +}); + +const rowStyle = css({ + display: 'grid', + gridTemplateRows: '2', + gap: '12px', +}); + +const cardRowStyle = css({ + display: 'flex', + gap: '12px', + justifyContent: 'center', +}); diff --git a/apps/web/src/app/[locale]/shop/PetGotcha/TenPet.tsx b/apps/web/src/app/[locale]/shop/PetGotcha/TenPet.tsx new file mode 100644 index 00000000..eda366e6 --- /dev/null +++ b/apps/web/src/app/[locale]/shop/PetGotcha/TenPet.tsx @@ -0,0 +1,124 @@ +import React, { useEffect, useState } from 'react'; +import { signOut, useSession } from 'next-auth/react'; +import { useTranslations } from 'next-intl'; +import { css } from '_panda/css'; +import type { GotchaResult } from '@gitanimals/api'; +import { CustomException } from '@gitanimals/exception'; +import { usePostGotcha, userQueries } from '@gitanimals/react-query'; +import { ScreenModalBase } from '@gitanimals/ui-panda/src/components/Modal'; +import { useQueryClient } from '@tanstack/react-query'; +import { toast } from 'sonner'; + +import { sendMessageToErrorChannel } from '@/apis/slack/sendMessage'; +import { useTimer } from '@/hooks/useTimer'; +import { trackEvent } from '@/lib/analytics'; + +import { TenCardFlipGame } from './TenCardFlipGame'; + +const GITHUB_ISSUE_URL = 'https://github.com/git-goods/gitanimals/issues'; + +interface Props { + onClose: () => void; +} + +export function TenPet({ onClose }: Props) { + const queryClient = useQueryClient(); + const t = useTranslations('Gotcha'); + + const [getPersona, setGetPersona] = useState(null); + + const { count, isRunning, isFinished, startTimer, resetTimer } = useTimer(3); + + const { data } = useSession(); + const { + mutate: postGotcha, + isPending, + isSuccess, + } = usePostGotcha({ + onSuccess: async (res) => { + const resultPersona = res.gotchaResults; + setGetPersona(resultPersona); + + queryClient.invalidateQueries({ queryKey: userQueries.allKey() }); + startTimer(); + + trackEvent('gotcha', { + type: '10-pet', + status: 'success', + }); + }, + onError: (error) => { + trackEvent('gotcha', { + type: '10-pet', + status: 'error', + }); + + toast.error(t('get-persona-fail'), { + description: + error instanceof CustomException && error.code === 'TOKEN_EXPIRED' + ? t('token-expired') + : t('many-error-message'), + action: { + label: t('contact-us'), + onClick: () => { + window.location.href = GITHUB_ISSUE_URL; + }, + }, + }); + onClose(); + if (error instanceof CustomException && error.code === 'TOKEN_EXPIRED') { + signOut(); + return; + } + sendMessageToErrorChannel(` +🔥 펫 뽑기 실패 🔥 +Error Message: ${(error as Error).message} +\`\`\` +Error Stack: ${(error as Error).stack} +\`\`\` + +User: ${data?.user.name} +Token: ${data?.user.accessToken} + `); + }, + }); + + const onAction = async () => { + postGotcha({ count: 10 }); + }; + + useEffect(() => { + // 3초 후에 닫기 + if (isFinished) { + onClose(); + resetTimer(); + } + }, [isFinished, onClose, resetTimer]); + + return ( + +

+ {isPending ? t('gotcha-in-progress') : isSuccess ? t('get-persona-success') : t('click-card-to-flip')} +

+ {isRunning && ( +

{t('close-notice-message').replace('[count]', count.toString())}

+ )} +
+ +
+
+ ); +} + +const noticeMessageStyle = css({ + textStyle: 'glyph28.bold', + color: 'white', + textAlign: 'center', + mt: 12, +}); + +const headingStyle = css({ + textStyle: 'glyph48.bold', + color: 'white', + textAlign: 'center', +}); diff --git a/apps/web/src/components/GlobalComponent/GlobalComponent.tsx b/apps/web/src/components/GlobalComponent/GlobalComponent.tsx index fa4aada3..18b544d0 100644 --- a/apps/web/src/components/GlobalComponent/GlobalComponent.tsx +++ b/apps/web/src/components/GlobalComponent/GlobalComponent.tsx @@ -1,3 +1,6 @@ +'use client'; + +import { createPortal } from 'react-dom'; import { Toaster } from 'sonner'; import NoticeToast from '../NoticeToast/NoticeToast'; @@ -5,7 +8,7 @@ import NoticeToast from '../NoticeToast/NoticeToast'; import FeedBack from './FeedbackForm'; function GlobalComponent() { - return ( + return createPortal( <> - + , + document.body, ); } diff --git a/packages/api/src/gotcha/postGotcha.ts b/packages/api/src/gotcha/postGotcha.ts index 805413b5..5e918033 100644 --- a/packages/api/src/gotcha/postGotcha.ts +++ b/packages/api/src/gotcha/postGotcha.ts @@ -23,10 +23,14 @@ export type PostGotchaResponse = z.infer; export type PostGotchaRequest = z.infer; export const postGotcha = async (request?: PostGotchaRequest): Promise => { - return await safePost(PostGotchaResponseSchema)(`/gotchas`, request ? convertCamelObjToKebab(request) : undefined, { - headers: { - 'Api-Version': '2', + return await safePost(PostGotchaResponseSchema)( + `/gotchas?count=${request?.count}`, + request ? convertCamelObjToKebab(request) : undefined, + { + headers: { + 'Api-Version': '2', + }, + timeout: 150000, }, - timeout: 150000, - }); + ); }; diff --git a/packages/lib/react-query/src/gotcha/index.ts b/packages/lib/react-query/src/gotcha/index.ts new file mode 100644 index 00000000..d2cc1f40 --- /dev/null +++ b/packages/lib/react-query/src/gotcha/index.ts @@ -0,0 +1 @@ +export * from './useGotcha'; diff --git a/packages/lib/react-query/src/gotcha/useGotcha.ts b/packages/lib/react-query/src/gotcha/useGotcha.ts new file mode 100644 index 00000000..e1e74231 --- /dev/null +++ b/packages/lib/react-query/src/gotcha/useGotcha.ts @@ -0,0 +1,8 @@ +import { postGotcha, PostGotchaResponse } from '@gitanimals/api'; +import { useMutation, UseMutationOptions } from '@tanstack/react-query'; + +type PostGotchaRequest = Parameters[0]; + +export const usePostGotcha = (options?: UseMutationOptions) => { + return useMutation({ mutationFn: (request: PostGotchaRequest) => postGotcha(request), ...options }); +}; diff --git a/packages/lib/react-query/src/index.ts b/packages/lib/react-query/src/index.ts index 47264514..a3469697 100644 --- a/packages/lib/react-query/src/index.ts +++ b/packages/lib/react-query/src/index.ts @@ -1,4 +1,5 @@ export * from './coupon'; +export * from './gotcha'; export * from './render'; export * from './auction'; export * from './user'; diff --git a/packages/lib/react/src/hooks/useBodyLock/useBodyLock.ts b/packages/lib/react/src/hooks/useBodyLock/useBodyLock.ts index 5f1e6b0e..a0d792a5 100644 --- a/packages/lib/react/src/hooks/useBodyLock/useBodyLock.ts +++ b/packages/lib/react/src/hooks/useBodyLock/useBodyLock.ts @@ -8,9 +8,6 @@ import { useEffect } from 'react'; */ export function useBodyLock(isLocked: boolean): void { useEffect(() => { - const originalStyle = window.getComputedStyle(document.body); - const originalOverflow = originalStyle.overflow; - if (isLocked) { // 현재 스크롤 위치 저장 const scrollY = window.scrollY; @@ -18,18 +15,31 @@ export function useBodyLock(isLocked: boolean): void { // body에 스타일 적용 document.body.style.position = 'fixed'; document.body.style.top = `-${scrollY}px`; - document.body.style.width = '100%'; - document.body.style.overflowY = 'scroll'; + document.body.style.left = '0'; + document.body.style.right = '0'; + document.body.style.overflow = 'hidden'; // scroll 대신 hidden 사용 } else { - // body 스타일 제거 - const scrollY = document.body.style.top; - document.body.style.overflow = originalOverflow; + // 스크롤 위치 복원을 위해 먼저 저장된 위치 가져오기 + const scrollY = parseInt(document.body.style.top || '0') * -1; + + // body 스타일 초기화 document.body.style.position = ''; document.body.style.top = ''; - document.body.style.width = ''; + document.body.style.left = ''; + document.body.style.right = ''; + document.body.style.overflow = ''; // 스크롤 위치 복원 - window.scrollTo(0, Number(scrollY.replace('px', '') || '0') * -1); + window.scrollTo(0, scrollY); } + + // cleanup 함수 추가 + return () => { + document.body.style.position = ''; + document.body.style.top = ''; + document.body.style.left = ''; + document.body.style.right = ''; + document.body.style.overflow = ''; + }; }, [isLocked]); } diff --git a/packages/ui/panda/src/components/Card/Card.tsx b/packages/ui/panda/src/components/Card/Card.tsx index 20c977e2..d83c8501 100644 --- a/packages/ui/panda/src/components/Card/Card.tsx +++ b/packages/ui/panda/src/components/Card/Card.tsx @@ -19,13 +19,13 @@ export function Card(props: Props) { return (
- {props.tier} + {props.tier}
- {props.tier} + {props.tier}
- {props.type} + {props.type}

{snakeToTitleCase(props.type)}

@@ -73,6 +73,7 @@ export const container = css({ position: 'relative', height: '100%', width: '100%', + color: 'black', }); export const bgImage = css({ diff --git a/packages/ui/panda/src/components/Card/CardBack.tsx b/packages/ui/panda/src/components/Card/CardBack.tsx index e45cc824..fe369675 100644 --- a/packages/ui/panda/src/components/Card/CardBack.tsx +++ b/packages/ui/panda/src/components/Card/CardBack.tsx @@ -10,7 +10,7 @@ export function CardBack(props: Props) { return (
- {props.tier} + {props.tier}
); } diff --git a/packages/ui/panda/src/components/Modal/ScreenModal.tsx b/packages/ui/panda/src/components/Modal/ScreenModal.tsx new file mode 100644 index 00000000..313f988f --- /dev/null +++ b/packages/ui/panda/src/components/Modal/ScreenModal.tsx @@ -0,0 +1,103 @@ +'use client'; + +import { useBodyLock } from '@gitanimals/react'; +import { css } from '_panda/css'; +import { XIcon } from 'lucide-react'; +import { PropsWithChildren } from 'react'; +import { flex } from '_panda/patterns'; +import { useDialog } from './useDialog'; + +interface ScreenModalProps { + isOpen: boolean; + onClose?: () => void; +} + +/** + * 화면 전체를 덮는 모달 컴포넌트 + */ +function ScreenModalRoot({ isOpen, onClose, children }: PropsWithChildren) { + const { dialogRef } = useDialog({ isOpen, onClose }); + + useBodyLock(isOpen); + + return ( + + {children} + + ); +} + +const dialogStyle = css({ + margin: 'auto', + borderRadius: '16px', + backgroundColor: 'gray.gray_150', + padding: '24px', + width: '100vw', + height: '100vh', + + '&::backdrop': { + background: 'black.black_75', + }, + + '@media (min-width: 1920px)': { + width: '1400px', + height: 'fit-content', + }, +}); + +function ScreenModalCloseButton({ onClose }: { onClose: () => void }) { + return ( + + ); +} + +const closeButtonStyle = css({ + position: 'absolute', + top: 24, + right: 24, +}); + +function ScreenModalHeading({ children }: { children: React.ReactNode }) { + return

{children}

; +} + +const headingStyle = css({ + textStyle: 'glyph48.bold', + color: 'white', + textAlign: 'center', + + '@media (max-width: 1200px)': { + textStyle: 'glyph32.bold', + }, +}); + +function ScreenModalContent({ children }: { children: React.ReactNode }) { + return
{children}
; +} + +const contentStyle = flex({ + width: '100%', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + gap: '28px', + color: 'white', + height: '100%', +}); + +export const ScreenModal = Object.assign(ScreenModalRoot, { + CloseButton: ScreenModalCloseButton, + Heading: ScreenModalHeading, + Content: ScreenModalContent, +}); + +export function ScreenModalBase({ isOpen, onClose, children }: PropsWithChildren) { + return ( + + {onClose && } + {children} + + ); +} diff --git a/packages/ui/panda/src/components/Modal/index.ts b/packages/ui/panda/src/components/Modal/index.ts index 6dd5b19b..80f4fb8a 100644 --- a/packages/ui/panda/src/components/Modal/index.ts +++ b/packages/ui/panda/src/components/Modal/index.ts @@ -1,2 +1,3 @@ export * from './Modal'; export * from './FullModal'; +export * from './ScreenModal'; From e59660006d38485b84071a59cb09bfb636a1cef0 Mon Sep 17 00:00:00 2001 From: "sumi.byun" Date: Fri, 8 Nov 2024 11:57:08 +0900 Subject: [PATCH 28/49] =?UTF-8?q?=ED=95=A0=EB=A1=9C=EC=9C=88=20=EC=9D=B4?= =?UTF-8?q?=EB=B2=A4=ED=8A=B8=20=EB=81=9D=20(#231)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/messages/en_US.json | 1 + apps/web/messages/ko_KR.json | 1 + .../app/[locale]/event/[eventCode]/page.tsx | 82 +++++++++++++------ .../components/NoticeToast/NoticeToast.tsx | 6 +- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/apps/web/messages/en_US.json b/apps/web/messages/en_US.json index 9271eafe..9281925f 100644 --- a/apps/web/messages/en_US.json +++ b/apps/web/messages/en_US.json @@ -106,6 +106,7 @@ } }, "Event": { + "event-end": "Event has ended.", "Halloween": { "description": "Halloween has come to Gitanimals\nDraw Halloween pet for free!", "draw-button": "Draw!", diff --git a/apps/web/messages/ko_KR.json b/apps/web/messages/ko_KR.json index fa0e87cd..d1555a88 100644 --- a/apps/web/messages/ko_KR.json +++ b/apps/web/messages/ko_KR.json @@ -108,6 +108,7 @@ } }, "Event": { + "event-end": "이벤트가 종료되었습니다.", "Halloween": { "description": "할로윈이 Gitanimals에 찾아왔어요.\n공짜 할로윈 펫을 뽑아보세요!", "draw-button": "할로윈 펫 뽑기!", diff --git a/apps/web/src/app/[locale]/event/[eventCode]/page.tsx b/apps/web/src/app/[locale]/event/[eventCode]/page.tsx index 1aaf9b0d..15de634b 100644 --- a/apps/web/src/app/[locale]/event/[eventCode]/page.tsx +++ b/apps/web/src/app/[locale]/event/[eventCode]/page.tsx @@ -1,12 +1,11 @@ import React from 'react'; import Image from 'next/image'; import { notFound } from 'next/navigation'; +import { useTranslations } from 'next-intl'; import { getTranslations } from 'next-intl/server'; import { css } from '_panda/css'; import { flex } from '_panda/patterns'; -import { sendMessageToErrorChannel } from '@/apis/slack/sendMessage'; - import { CardList, MobileCardList } from './CardList'; import { Draw } from './Draw'; @@ -23,39 +22,74 @@ async function HalloweenEventPage({ params }: { params: Params }) { const isAfterHalloween = now.getMonth() === 10 && now.getDate() > 7; if (isAfterHalloween) { // NOTE: 11월이 되면 그냥 이벤트 종료하는 식으로 하드 코딩 - sendMessageToErrorChannel('할로윈 기간 지낫음 하드코딩한거 바꾸삼'); - notFound(); + // sendMessageToErrorChannel('할로윈 기간 지낫음 하드코딩한거 바꾸삼'); + // notFound(); } const t = await getTranslations('Event.Halloween'); return ( -
- gitanimals halloween event - -

{t('description')}

-
- -
-
- + <> +
+ gitanimals halloween event + +

{t('description')}

+
+ +
+
+ +
+ +
- - -
+ {isAfterHalloween && } + ); } export default HalloweenEventPage; +function EventEndOverlay() { + const t = useTranslations('Event'); + + return ( +
+

+ {t('event-end')} +

+
+ ); +} + const showDesktop = css({ display: 'block', diff --git a/apps/web/src/components/NoticeToast/NoticeToast.tsx b/apps/web/src/components/NoticeToast/NoticeToast.tsx index 595da6d0..575b9951 100644 --- a/apps/web/src/components/NoticeToast/NoticeToast.tsx +++ b/apps/web/src/components/NoticeToast/NoticeToast.tsx @@ -82,11 +82,7 @@ function NoticeToast() { renderList.forEach((notice) => renderToast(notice)); }); - return ( - <> - - - ); + return <>{/* */}; } export default NoticeToast; From 87f5f09374c2de024f32fda84a145e994e6c0961 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Mon, 11 Nov 2024 16:03:45 +0900 Subject: [PATCH 29/49] =?UTF-8?q?hotfeat:=20=EC=A4=80=EC=98=81=EB=8B=98=20?= =?UTF-8?q?=EC=9D=B4=EC=8A=88=20=ED=95=A0=EB=8B=B9=EC=97=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/constants/github.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/constants/github.ts b/apps/web/src/constants/github.ts index a3f717d4..97824b42 100644 --- a/apps/web/src/constants/github.ts +++ b/apps/web/src/constants/github.ts @@ -1,5 +1,5 @@ // maintainer -export const SERVICE_MAINTAINER = ['sumi-0011', 'hyesungoh', 'git-good-w']; +export const SERVICE_MAINTAINER = ['sumi-0011', 'hyesungoh', 'git-good-w', 'devxb']; // issue export const GITHUB_ISSUE_TYPE = { From 2d66f0944f4e5970ab73543fe4ae029e14bfda4e Mon Sep 17 00:00:00 2001 From: hyesung oh Date: Wed, 13 Nov 2024 20:14:57 +0900 Subject: [PATCH 30/49] chore: append comma at shot and background section (#232) --- .../app/[locale]/shop/BackgroundSection/BackgroundSection.tsx | 3 ++- apps/web/src/components/ProductTable/ShopTableRowView.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/[locale]/shop/BackgroundSection/BackgroundSection.tsx b/apps/web/src/app/[locale]/shop/BackgroundSection/BackgroundSection.tsx index 2debb922..907b2335 100644 --- a/apps/web/src/app/[locale]/shop/BackgroundSection/BackgroundSection.tsx +++ b/apps/web/src/app/[locale]/shop/BackgroundSection/BackgroundSection.tsx @@ -15,6 +15,7 @@ import { toast } from 'sonner'; import { trackEvent } from '@/lib/analytics'; import { useClientUser } from '@/utils/clientAuth'; import { getBackgroundImage } from '@/utils/image'; +import { addNumberComma } from '@/utils/number'; export const BackgroundSection = wrap .ErrorBoundary({ @@ -99,7 +100,7 @@ function BackgroundItem({
{item.type}
-
{item.price} P
+
{addNumberComma(item.price)} P
diff --git a/apps/web/src/components/ProductTable/ShopTableRowView.tsx b/apps/web/src/components/ProductTable/ShopTableRowView.tsx index 228da533..9b9c38aa 100644 --- a/apps/web/src/components/ProductTable/ShopTableRowView.tsx +++ b/apps/web/src/components/ProductTable/ShopTableRowView.tsx @@ -9,6 +9,7 @@ import { snakeToTitleCase } from '@gitanimals/util-common'; import { useGetAllPersona } from '@/hooks/query/render/useGetAllPersona'; import { ANIMAL_TIER_TEXT_MAP, getAnimalTierInfo } from '@/utils/animals'; import { getPersonaImage } from '@/utils/image'; +import { addNumberComma } from '@/utils/number'; interface Props extends Pick { onAction: (itemId: Product['id']) => void; @@ -33,7 +34,7 @@ function ShopTableRowView({ onAction, actionLabel, actionColor, ...item }: Props {snakeToTitleCase(item.persona.personaType)} {ANIMAL_TIER_TEXT_MAP[getAnimalTierInfo(Number(currentPersona.dropRate.replace('%', '')))]} {item.persona.personaLevel} - {item.price} + {addNumberComma(item.price)}
+ */} + + ); +} + +export function LargeDialog({ children, ...props }: PropsWithChildren & ComponentProps) { + return ( + + {children} + + ); +} + +const largeDialogContentStyle = css({ + margin: 'auto', + borderRadius: '16px', + backgroundColor: 'gray.gray_150', + padding: '24px', + + width: 'calc(100vw - 400px)', + height: 'calc(100vh - 240px)', + + '@media (max-width: 1200px)': { + width: 'calc(100vw - 240px)', + height: 'calc(100vh - 120px)', + }, + _mobile: { + width: '100vw', + height: '100vh', + }, +}); diff --git a/packages/ui/panda/src/components/Dialog/index.ts b/packages/ui/panda/src/components/Dialog/index.ts index a5d31597..0a219ae6 100644 --- a/packages/ui/panda/src/components/Dialog/index.ts +++ b/packages/ui/panda/src/components/Dialog/index.ts @@ -1 +1,2 @@ export * from './Dialog'; +export * from './LargeDialog'; From 63f5e5ef135ac26a167cd07da3cf54ab96d664dc Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Mon, 18 Nov 2024 19:01:04 +0900 Subject: [PATCH 35/49] refactor: shadow panda style issue fix --- .../app/components/layout/Header/Header.tsx | 8 ++++---- .../app/components/layout/Header/Nav.tsx | 4 ++-- .../app/[locale]/event/[eventCode]/layout.tsx | 2 +- .../app/[locale]/event/[eventCode]/page.tsx | 10 +++++----- .../AvailablePetSection/AnimalCardList.tsx | 2 +- .../AvailablePetSection/AnimalSlider.style.ts | 2 +- .../[locale]/landing/Footer/Footer.style.ts | 20 +++++++++---------- .../landing/Footer/TeammateProfile.style.ts | 14 ++++++------- .../(github-custom)/FarmBackgroundSelect.tsx | 6 +++--- .../(github-custom)/FarmPersonaSelect.tsx | 4 ++-- .../mypage/(github-custom)/FarmType.tsx | 6 +++--- .../(github-custom)/LinePersonaSelect.tsx | 4 ++-- .../mypage/(github-custom)/LinePreview.tsx | 6 +++--- .../mypage/(github-custom)/LineType.tsx | 4 ++-- .../[locale]/mypage/(github-custom)/page.tsx | 10 +++++----- .../app/[locale]/mypage/ProfileSection.tsx | 10 +++++----- apps/web/src/app/[locale]/mypage/layout.tsx | 20 +++---------------- .../mypage/my-pet/(merge)/MergePersona.tsx | 19 +++++++++++------- .../mypage/my-pet/(merge)/MergePreview.tsx | 8 ++++---- .../src/app/[locale]/mypage/my-pet/page.tsx | 20 +++++++++---------- .../shop/AuctionSection/Background.tsx | 10 +++++----- .../shop/AuctionSection/DefaultTabRight.tsx | 2 +- .../shop/AuctionSection/PersonaSearch.tsx | 20 +++++++++---------- .../AuctionSection/SellSection/PetList.tsx | 2 +- .../SellSection/SellInputRow.tsx | 7 +------ .../SellSection/SellSection.tsx | 2 +- .../app/[locale]/shop/AuctionSection/Tab.tsx | 2 +- .../shop/AuctionSection/table.styles.ts | 10 +++++----- .../BackgroundSection/BackgroundSection.tsx | 6 +++--- .../FloatingPointSection.tsx | 12 +++++------ .../app/[locale]/shop/PetGotcha/TenPet.tsx | 2 +- apps/web/src/components/Error/ErrorPage.tsx | 4 ++-- apps/web/src/components/GNB/DesktopGNB.tsx | 4 ++-- apps/web/src/components/GNB/MobileGNB.tsx | 8 ++++---- .../ProductTable/ShopTableRowView.tsx | 8 ++++---- .../src/components/Banner/LevelBanner.tsx | 4 ++-- .../ui/panda/src/components/Banner/cva.ts | 2 +- .../panda/src/components/Modal/FullModal.tsx | 4 ++-- .../ui/panda/src/components/Modal/Modal.tsx | 4 ++-- .../src/components/Modal/ScreenModal.tsx | 4 ++-- 40 files changed, 141 insertions(+), 155 deletions(-) diff --git a/apps/admin/app/components/layout/Header/Header.tsx b/apps/admin/app/components/layout/Header/Header.tsx index f0527638..87a1e20a 100644 --- a/apps/admin/app/components/layout/Header/Header.tsx +++ b/apps/admin/app/components/layout/Header/Header.tsx @@ -1,6 +1,6 @@ import { css } from '_panda/css'; import Nav from './Nav'; -import { Avatar, AvatarImage, AvatarFallback } from '@radix-ui/react-avatar'; +import { Avatar, AvatarImage } from '@radix-ui/react-avatar'; const PROFILE_IMG = 'https://avatars.githubusercontent.com/u/171903401?s=200&v=4'; function Header() { @@ -19,12 +19,12 @@ function Header() { export default Header; const containerStyle = css({ - h: '16', + h: '16px', bg: 'background', shadow: 'md', zIndex: 'sticky', - px: 4, - py: 3, + px: '4px', + py: '3px', display: 'flex', alignItems: 'center', diff --git a/apps/admin/app/components/layout/Header/Nav.tsx b/apps/admin/app/components/layout/Header/Nav.tsx index 726a7b6a..5fe866c9 100644 --- a/apps/admin/app/components/layout/Header/Nav.tsx +++ b/apps/admin/app/components/layout/Header/Nav.tsx @@ -43,8 +43,8 @@ export default function Example() { const listStyle = css({ display: 'flex', flexDirection: 'column', - gap: '3', - p: '6', + gap: '3px', + p: '6px', md: { w: '400px', }, diff --git a/apps/web/src/app/[locale]/event/[eventCode]/layout.tsx b/apps/web/src/app/[locale]/event/[eventCode]/layout.tsx index 27149801..73c8dd73 100644 --- a/apps/web/src/app/[locale]/event/[eventCode]/layout.tsx +++ b/apps/web/src/app/[locale]/event/[eventCode]/layout.tsx @@ -79,7 +79,7 @@ const imageStyle = css({ zIndex: 1, minHeight: 'calc(100vh - 60px)', pointerEvents: 'none', - top: -60, + top: '-60px', _mobile: { display: 'none', }, diff --git a/apps/web/src/app/[locale]/event/[eventCode]/page.tsx b/apps/web/src/app/[locale]/event/[eventCode]/page.tsx index 15de634b..3c2eadd4 100644 --- a/apps/web/src/app/[locale]/event/[eventCode]/page.tsx +++ b/apps/web/src/app/[locale]/event/[eventCode]/page.tsx @@ -129,16 +129,16 @@ const logoImageStyle = css({ }); const descriptionStyle = css({ - marginTop: 24, - fontSize: 28, - lineHeight: 1.5, + marginTop: '24px', + fontSize: '28px', + lineHeight: '1.5', textAlign: 'center', color: '#fff', - mb: 40, + mb: '40px', whiteSpace: 'pre-line', fontWeight: 600, _mobile: { - fontSize: 24, + fontSize: '24px', }, }); diff --git a/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalCardList.tsx b/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalCardList.tsx index 67021dcc..2bc7b270 100644 --- a/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalCardList.tsx +++ b/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalCardList.tsx @@ -67,7 +67,7 @@ function AnimalCardContainer() { export default AnimalCardContainer; const container = grid({ - gap: 20, + gap: '20px', justifyContent: 'center', gridTemplateColumns: 'repeat(4, 1fr)', width: '1120px', diff --git a/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalSlider.style.ts b/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalSlider.style.ts index c7d3525d..c4ba1d80 100644 --- a/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalSlider.style.ts +++ b/apps/web/src/app/[locale]/landing/AvailablePetSection/AnimalSlider.style.ts @@ -35,7 +35,7 @@ export const showMobile = css({ }); export const cardContainer = grid({ - gap: 20, + gap: '20px', justifyContent: 'center', gridTemplateColumns: 'repeat(4, 1fr)', gridTemplateRows: 'repeat(3, 1fr)', diff --git a/apps/web/src/app/[locale]/landing/Footer/Footer.style.ts b/apps/web/src/app/[locale]/landing/Footer/Footer.style.ts index 23bcaf85..d30be28c 100644 --- a/apps/web/src/app/[locale]/landing/Footer/Footer.style.ts +++ b/apps/web/src/app/[locale]/landing/Footer/Footer.style.ts @@ -12,7 +12,7 @@ export const footer = css({ _mobile: { padding: '80px 16px', - gap: 60, + gap: '60px', }, }); @@ -24,7 +24,7 @@ export const article = css({ _mobile: { flexDir: 'column', - gap: 24, + gap: '24px', }, }); @@ -45,11 +45,11 @@ const defaultContentWrapper: SystemStyleObject = { export const teamContentWrapper = css(defaultContentWrapper, { display: 'flex', - gap: 12, + gap: '12px', _mobile: { flexDir: 'column', - gap: 16, + gap: '16px', }, }); @@ -61,24 +61,24 @@ export const repoContentWrapper = css(defaultContentWrapper, { export const repoLi = css({ display: 'flex', - gap: 8, + gap: '8px', _mobile: { flexDir: 'column', - gap: 1, + gap: '1px', }, }); export const repoLiTitle = css({ display: 'flex', alignItems: 'center', - gap: 8, - width: 226, + gap: '8px', + width: '226px', textStyle: 'glyph18.bold', _mobile: { textStyle: 'glyph15.bold', - gap: 17, + gap: '17px', }, }); @@ -89,6 +89,6 @@ export const repoLiLink = css({ _mobile: { textStyle: 'glyph12.regular', - marginLeft: 37, + marginLeft: '37px', }, }); diff --git a/apps/web/src/app/[locale]/landing/Footer/TeammateProfile.style.ts b/apps/web/src/app/[locale]/landing/Footer/TeammateProfile.style.ts index 32fe4a33..a9bf93ce 100644 --- a/apps/web/src/app/[locale]/landing/Footer/TeammateProfile.style.ts +++ b/apps/web/src/app/[locale]/landing/Footer/TeammateProfile.style.ts @@ -8,7 +8,7 @@ export const wrapperCss = css({ _mobile: { width: '100%', flexDir: 'row', - gap: 5, + gap: '5px', }, }); @@ -16,9 +16,9 @@ export const imageCss = css({ marginBottom: 8, _mobile: { - width: 32, - height: 24, - marginBottom: 0, + width: '32px', + height: '24px', + marginBottom: '0px', objectFit: 'contain', objectPosition: 'left 50%', }, @@ -32,8 +32,8 @@ export const textWrapperCss = css({ export const nicknameWrapperCss = css({ display: 'flex', alignItems: 'center', - gap: 5, - marginBottom: 4, + gap: '5px', + marginBottom: '4px', '& span': { textStyle: 'glyph18.bold', @@ -41,7 +41,7 @@ export const nicknameWrapperCss = css({ }, _mobile: { - marginBottom: 1, + marginBottom: '1px', '& span': { textStyle: 'glyph15.bold', fontWeight: 'bold', diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmBackgroundSelect.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmBackgroundSelect.tsx index 6e1fabbe..4f699f7a 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmBackgroundSelect.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmBackgroundSelect.tsx @@ -80,7 +80,7 @@ const backgroundListStyle = cx( width: 'fit-content', display: 'flex', flexWrap: 'nowrap', - gap: 4, + gap: '4px', }), ); @@ -93,8 +93,8 @@ const backgroundContainerStyle = cx( const backgroundItemStyle = css({ border: '1px solid transparent', - width: 248, - borderRadius: 8, + width: '248px', + borderRadius: '8px', overflow: 'hidden', }); diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx index f5a3f93c..381893be 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx @@ -98,7 +98,7 @@ export function FarmPersonaSelect({ } const listStyle = cx( flex({ - gap: 4, + gap: '4px', w: '100%', h: '100%', minH: '0', @@ -117,7 +117,7 @@ const flexOverflowStyle = css({ overflowY: 'auto', overflowX: 'hidden', width: '100%', - gap: 4, + gap: '4px', height: '100%', minHeight: '0', flexWrap: 'wrap', diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx index 3cbbe3d7..09aa0bb3 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx @@ -53,8 +53,8 @@ const farmSectionStyle = css({ flexDirection: 'column', width: '100%', maxHeight: '100%', - py: 40, - gap: 40, + py: '40px', + gap: '40px', _mobile: { background: 'none', @@ -65,4 +65,4 @@ const farmSectionStyle = css({ }, }); -const farmStyle = css({ borderRadius: '12px', overflow: 'hidden', width: 'fit-content', mt: 24 }); +const farmStyle = css({ borderRadius: '12px', overflow: 'hidden', width: 'fit-content', mt: '24px' }); diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx index 4eba0596..fc35a9b4 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx @@ -56,7 +56,7 @@ const flexOverflowStyle = css({ overflowY: 'auto', overflowX: 'hidden', width: '100%', - gap: 4, + gap: '4px', height: '100%', minHeight: '0', flexWrap: 'wrap', @@ -66,7 +66,7 @@ const flexOverflowStyle = css({ const listStyle = cx( flex({ - gap: 4, + gap: '4px', w: '100%', h: '100%', minH: '0', diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx index b5db907c..24ba84c2 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx @@ -52,7 +52,7 @@ export function LinePreview({ selectPersona }: { selectPersona: string | null }) const sectionContainerStyle = css({ display: 'flex', flexDirection: 'column', - gap: 24, + gap: '24px', }); const lineContainerStyle = css({ @@ -80,7 +80,7 @@ function SizeInputList({ onApply }: { onApply: (width: number, height: number) = return (

{t('customize-size')}

-
+
setWidth(parseInt(e.target.value))} name="width" /> setHeight(parseInt(e.target.value))} name="height" /> diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index 92305688..84f85481 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -1,12 +1,5 @@ @layer reset, base, tokens, recipes, utilities; @layer reset { - @font-face { - font-family: 'DNFBitBitv2'; - font-style: normal; - font-weight: 700; - src: url('//cdn.df.nexon.com/img/common/font/DNFBitBitv2.otf') format('opentype'); - } - *, *::before, *::after { @@ -14,11 +7,6 @@ } body { - font-family: 'DNFBitBitv2'; - font-style: normal; - font-weight: 400; - line-height: 140%; /* 107.8px */ - /* background-color: #2a7442; */ position: relative; } @@ -26,23 +14,9 @@ cursor: pointer; border: transparent; background-color: transparent; - font-family: 'DNFBitBitv2'; - line-height: 1.5; - font-style: normal; - font-weight: 400; - line-height: 140%; padding: 0; } - input { - font-family: 'DNFBitBitv2'; - } - - input::placeholder { - color: #b5b5b5; - font-family: 'DNFBitBitv2'; - } - .mobile { display: none; } diff --git a/packages/ui/panda/src/components/Textfield/TextField.tsx b/packages/ui/panda/src/components/Textfield/TextField.tsx index 75225e4f..64b847cc 100644 --- a/packages/ui/panda/src/components/Textfield/TextField.tsx +++ b/packages/ui/panda/src/components/Textfield/TextField.tsx @@ -6,11 +6,11 @@ export const TextField = (props: ComponentProps<'input'>) => { }; const textFieldStyle = css({ - height: 55, + height: '55px', padding: '14px 20px', alignItems: 'flex-start', - gap: 8, - borderRadius: 8, + gap: '8px', + borderRadius: '8px', border: '1px solid', borderColor: 'white.white_25', color: 'white.white_50', From 629b3a6f727135be703814bd10d7fe9af4543fa4 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Mon, 18 Nov 2024 17:11:13 +0900 Subject: [PATCH 37/49] =?UTF-8?q?refactor:=20dialog=20export=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/panda/src/components/Dialog/Dialog.tsx | 25 +++++++++++++------ .../ui/panda/src/components/Dialog/index.ts | 1 + 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/ui/panda/src/components/Dialog/Dialog.tsx b/packages/ui/panda/src/components/Dialog/Dialog.tsx index a75008d0..0a172948 100644 --- a/packages/ui/panda/src/components/Dialog/Dialog.tsx +++ b/packages/ui/panda/src/components/Dialog/Dialog.tsx @@ -31,10 +31,21 @@ const Content = React.forwardRef< )); Content.displayName = DialogPrimitive.Content.displayName; -export const Dialog = withProvider(styled(DialogPrimitive.Root), 'root'); -export const DialogTrigger = withContext(styled(DialogPrimitive.Trigger), 'trigger'); -export const DialogContent = withContext(styled(Content), 'content'); -export const DialogHeader = withContext(styled('div'), 'header'); -export const DialogFooter = withContext(styled('div'), 'footer'); -export const DialogTitle = withContext(styled(DialogPrimitive.Title), 'title'); -export const DialogDescription = withContext(styled(DialogPrimitive.Description), 'description'); +const DialogRoot = withProvider(styled(DialogPrimitive.Root), 'root'); +const DialogTrigger = withContext(styled(DialogPrimitive.Trigger), 'trigger'); +const DialogContent = withContext(styled(Content), 'content'); +const DialogHeader = withContext(styled('div'), 'header'); +const DialogFooter = withContext(styled('div'), 'footer'); +const DialogTitle = withContext(styled(DialogPrimitive.Title), 'title'); +const DialogDescription = withContext(styled(DialogPrimitive.Description), 'description'); + +const Dialog = Object.assign(DialogRoot, { + Trigger: DialogTrigger, + Content: DialogContent, + Header: DialogHeader, + Footer: DialogFooter, + Title: DialogTitle, + Description: DialogDescription, +}); + +export { Dialog }; diff --git a/packages/ui/panda/src/components/Dialog/index.ts b/packages/ui/panda/src/components/Dialog/index.ts index e69de29b..a5d31597 100644 --- a/packages/ui/panda/src/components/Dialog/index.ts +++ b/packages/ui/panda/src/components/Dialog/index.ts @@ -0,0 +1 @@ +export * from './Dialog'; From 0ccbdf6888e5ff2aa134999f33c57ca8210ff099 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Mon, 18 Nov 2024 18:44:53 +0900 Subject: [PATCH 38/49] =?UTF-8?q?feat:=20large=20dialog=20=EC=B4=88?= =?UTF-8?q?=EC=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Dialog/LargeDialog.tsx | 45 +++++++++++++++++++ .../ui/panda/src/components/Dialog/index.ts | 1 + 2 files changed, 46 insertions(+) create mode 100644 packages/ui/panda/src/components/Dialog/LargeDialog.tsx diff --git a/packages/ui/panda/src/components/Dialog/LargeDialog.tsx b/packages/ui/panda/src/components/Dialog/LargeDialog.tsx new file mode 100644 index 00000000..d62c5925 --- /dev/null +++ b/packages/ui/panda/src/components/Dialog/LargeDialog.tsx @@ -0,0 +1,45 @@ +import { ComponentProps, PropsWithChildren } from 'react'; +import { Dialog } from './Dialog'; +import { css } from '_panda/css'; + +export function LargeDialogContent({ children }: PropsWithChildren) { + return ( + + {/* + Edit profile + Make changes to your profile here. Click save when you're done. + */} + {children} + {/* + + */} + + ); +} + +export function LargeDialog({ children, ...props }: PropsWithChildren & ComponentProps) { + return ( + + {children} + + ); +} + +const largeDialogContentStyle = css({ + margin: 'auto', + borderRadius: '16px', + backgroundColor: 'gray.gray_150', + padding: '24px', + + width: 'calc(100vw - 400px)', + height: 'calc(100vh - 240px)', + + '@media (max-width: 1200px)': { + width: 'calc(100vw - 240px)', + height: 'calc(100vh - 120px)', + }, + _mobile: { + width: '100vw', + height: '100vh', + }, +}); diff --git a/packages/ui/panda/src/components/Dialog/index.ts b/packages/ui/panda/src/components/Dialog/index.ts index a5d31597..0a219ae6 100644 --- a/packages/ui/panda/src/components/Dialog/index.ts +++ b/packages/ui/panda/src/components/Dialog/index.ts @@ -1 +1,2 @@ export * from './Dialog'; +export * from './LargeDialog'; From bd5c6fa0d5d4730ff7d83e9619210d89ffb6c0ef Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Tue, 19 Nov 2024 00:26:14 +0900 Subject: [PATCH 39/49] =?UTF-8?q?feat:=20large=20dialog=20=ED=8B=80=20?= =?UTF-8?q?=EC=9E=A1=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/my-pet/(merge)/MergePersona.tsx | 9 ++++----- .../panda/src/components/Dialog/LargeDialog.tsx | 17 +++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index fadba5b5..2ef4e402 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -6,7 +6,7 @@ import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; import type { MergePersonaLevelResponse, Persona } from '@gitanimals/api'; import { useMergePersonaLevelByToken, userQueries } from '@gitanimals/react-query'; -import { Button, FullModalBase, LevelBanner } from '@gitanimals/ui-panda'; +import { Button, LargeDialog, LevelBanner } from '@gitanimals/ui-panda'; import { BannerSkeletonList } from '@gitanimals/ui-panda/src/components/Banner/Banner'; import { wrap } from '@suspensive/react'; import { useQueryClient, useSuspenseQuery } from '@tanstack/react-query'; @@ -67,8 +67,8 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona }; return ( - // - + + {/* */}

Merge Persona Level

@@ -89,8 +89,7 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona result={resultData as MergePersonaLevelResponse} /> {isMerging && } -
- //
+
); // return ( // diff --git a/packages/ui/panda/src/components/Dialog/LargeDialog.tsx b/packages/ui/panda/src/components/Dialog/LargeDialog.tsx index d62c5925..78da7dd9 100644 --- a/packages/ui/panda/src/components/Dialog/LargeDialog.tsx +++ b/packages/ui/panda/src/components/Dialog/LargeDialog.tsx @@ -26,20 +26,21 @@ export function LargeDialog({ children, ...props }: PropsWithChildren & Componen } const largeDialogContentStyle = css({ - margin: 'auto', borderRadius: '16px', backgroundColor: 'gray.gray_150', - padding: '24px', + padding: '60px 40px', - width: 'calc(100vw - 400px)', - height: 'calc(100vh - 240px)', + maxWidth: 'calc(100% - 400px)', + maxHeight: 'calc(100% - 240px)', + width: '100%', + height: '100%', '@media (max-width: 1200px)': { - width: 'calc(100vw - 240px)', - height: 'calc(100vh - 120px)', + maxWidth: 'calc(100vw - 240px)', + maxHeight: 'calc(100vh - 120px)', }, _mobile: { - width: '100vw', - height: '100vh', + maxWidth: '100vw', + maxHeight: '100vh', }, }); From b57d1e36d54d7e8c1d9c70d55b86b42d9fd4df59 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Tue, 19 Nov 2024 16:12:37 +0900 Subject: [PATCH 40/49] =?UTF-8?q?refactor:=20full=20modal=20base=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0,=20Dialog=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EB=A1=9C=20=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mypage/my-pet/(merge)/MergePersona.tsx | 71 +++++++++---------- .../mypage/my-pet/(merge)/MergePreview.tsx | 1 - apps/web/src/app/globals.css | 1 + .../ui/panda/src/components/Button/cva.ts | 1 + .../components/Dialog/Dialog.styles.ts.tsx | 29 ++++++++ .../ui/panda/src/components/Dialog/Dialog.tsx | 37 ++++++++-- .../src/components/Dialog/LargeDialog.tsx | 46 ------------ .../ui/panda/src/components/Dialog/index.ts | 2 +- .../panda/src/components/Modal/FullModal.tsx | 10 --- 9 files changed, 97 insertions(+), 101 deletions(-) create mode 100644 packages/ui/panda/src/components/Dialog/Dialog.styles.ts.tsx delete mode 100644 packages/ui/panda/src/components/Dialog/LargeDialog.tsx diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index 2ef4e402..53a0efdc 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -6,7 +6,7 @@ import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; import type { MergePersonaLevelResponse, Persona } from '@gitanimals/api'; import { useMergePersonaLevelByToken, userQueries } from '@gitanimals/react-query'; -import { Button, LargeDialog, LevelBanner } from '@gitanimals/ui-panda'; +import { Button, Dialog, dialogContentCva, LevelBanner } from '@gitanimals/ui-panda'; import { BannerSkeletonList } from '@gitanimals/ui-panda/src/components/Banner/Banner'; import { wrap } from '@suspensive/react'; import { useQueryClient, useSuspenseQuery } from '@tanstack/react-query'; @@ -67,44 +67,37 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona }; return ( - - {/* */} -

Merge Persona Level

- - - - -
- - -
- setResultData(null)} - result={resultData as MergePersonaLevelResponse} - /> - {isMerging && } -
+ + + Merge Persona Level + + + + + +
+ + +
+
+ setResultData(null)} + result={resultData as MergePersonaLevelResponse} + /> + {isMerging && } +
+
); - // return ( - // - - // - // ); } -const headingStyle = css({ - textStyle: 'glyph48.bold', - color: 'white.white_100', - textAlign: 'center', - marginTop: '40px', -}); - +const headingStyle = css({ marginTop: '40px' }); +const footerStyle = css({ justifyContent: 'center', height: '40px' }); const bottomButtonStyle = css({ display: 'flex', justifyContent: 'center', gap: '12px' }); interface SelectPersonaListProps { @@ -163,6 +156,10 @@ const listStyle = cx( flexWrap: 'wrap', maxHeight: 'calc(100vh - 780px)', overflow: 'auto', + + '@media (max-width: 1200px)': { + maxHeight: 'calc(100vh - 600px)', + }, }), customScrollStyle, ); @@ -175,7 +172,7 @@ interface PersonaItemProps { function PersonaItem({ persona, isSelected, onClick }: PersonaItemProps) { return ( - - */} - - ); -} - -export function LargeDialog({ children, ...props }: PropsWithChildren & ComponentProps) { - return ( - - {children} - - ); -} - -const largeDialogContentStyle = css({ - borderRadius: '16px', - backgroundColor: 'gray.gray_150', - padding: '60px 40px', - - maxWidth: 'calc(100% - 400px)', - maxHeight: 'calc(100% - 240px)', - width: '100%', - height: '100%', - - '@media (max-width: 1200px)': { - maxWidth: 'calc(100vw - 240px)', - maxHeight: 'calc(100vh - 120px)', - }, - _mobile: { - maxWidth: '100vw', - maxHeight: '100vh', - }, -}); diff --git a/packages/ui/panda/src/components/Dialog/index.ts b/packages/ui/panda/src/components/Dialog/index.ts index 0a219ae6..3cd3685e 100644 --- a/packages/ui/panda/src/components/Dialog/index.ts +++ b/packages/ui/panda/src/components/Dialog/index.ts @@ -1,2 +1,2 @@ export * from './Dialog'; -export * from './LargeDialog'; +export * from './Dialog.styles.ts'; diff --git a/packages/ui/panda/src/components/Modal/FullModal.tsx b/packages/ui/panda/src/components/Modal/FullModal.tsx index 4a74de3e..77071d72 100644 --- a/packages/ui/panda/src/components/Modal/FullModal.tsx +++ b/packages/ui/panda/src/components/Modal/FullModal.tsx @@ -94,13 +94,3 @@ export const FullModal = Object.assign(FullModalRoot, { Heading: FullModalHeading, Content: FullModalContent, }); - -/** @deprecated */ -export function FullModalBase({ isOpen, onClose, children }: PropsWithChildren) { - return ( - - {onClose && } - {children} - - ); -} From bfd53569543dd443afd884136c699ee44b2b6639 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Tue, 19 Nov 2024 18:51:58 +0900 Subject: [PATCH 41/49] =?UTF-8?q?feat:=20farm=20persona=20select=EC=97=90?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(github-custom)/FarmPersonaSelect.tsx | 45 +++++++++++-------- .../mypage/my-pet/(merge)/MergePersona.tsx | 31 ++++++++++--- .../components/Dialog/Dialog.styles.ts.tsx | 2 +- .../ui/panda/src/components/Dialog/Dialog.tsx | 12 ++++- 4 files changed, 63 insertions(+), 27 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx index 381893be..c38face2 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx @@ -4,7 +4,7 @@ import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; import type { Persona } from '@gitanimals/api'; import { userQueries } from '@gitanimals/react-query'; -import { FullModal } from '@gitanimals/ui-panda'; +import { Dialog, dialogContentCva } from '@gitanimals/ui-panda'; import { useQueryClient } from '@tanstack/react-query'; import { ExpandIcon } from 'lucide-react'; @@ -79,10 +79,9 @@ export function FarmPersonaSelect({ initSelectPersonas={initSelectPersonas} /> - setIsOpen(false)}> - setIsOpen(false)} /> - - {t('farm-type-select-pet')} + + + {t('farm-type-select-pet')}
-
-
+ +
); } @@ -112,18 +111,26 @@ const listStyle = cx( customScrollStyle, ); -const flexOverflowStyle = css({ - display: 'flex', - overflowY: 'auto', - overflowX: 'hidden', - width: '100%', - gap: '4px', - height: '100%', - minHeight: '0', - flexWrap: 'wrap', - justifyContent: 'center', - maxHeight: 'calc(100% - 100px)', -}); +const flexOverflowStyle = cx( + css({ + display: 'flex', + overflowY: 'auto', + overflowX: 'hidden', + width: '100%', + gap: '4px', + height: '100%', + minHeight: '0', + flexWrap: 'wrap', + justifyContent: 'center', + maxHeight: 'calc(100% )', + marginTop: '40px', + + '@media (max-width: 1200px)': { + marginTop: '24px', + }, + }), + customScrollStyle, +); const selectPetContainerStyle = css({ position: 'relative', diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index 53a0efdc..e6de15b2 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -117,11 +117,11 @@ const SelectPersonaList = wrap // TODO: 정렬 return ( -
+

Please choose a pet to use to merge the level. The pet used disappears.

-
+
{data.personas.map((persona) => ( )); -const titleStyle = css({ textStyle: 'glyph48.bold', color: 'white.white_100', textAlign: 'center' }); +const titleStyle = css({ + textStyle: 'glyph48.bold', + color: 'white.white_100', + textAlign: 'center', + '@media (max-width: 1200px)': { + textStyle: 'glyph32.bold', + }, + _mobile: { + textStyle: 'glyph24.bold', + }, +}); Title.displayName = DialogPrimitive.Title.displayName; From 74f9db9f1711240eb8b2d91c69bcab3dd06138cc Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Tue, 19 Nov 2024 22:14:16 +0900 Subject: [PATCH 42/49] fix: merge persona overflow height fix --- .../mypage/my-pet/(merge)/MergePersona.tsx | 40 +++++-------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index e6de15b2..43503201 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -3,7 +3,6 @@ import { memo, useState } from 'react'; import { useTranslations } from 'next-intl'; import { css, cx } from '_panda/css'; -import { flex } from '_panda/patterns'; import type { MergePersonaLevelResponse, Persona } from '@gitanimals/api'; import { useMergePersonaLevelByToken, userQueries } from '@gitanimals/react-query'; import { Button, Dialog, dialogContentCva, LevelBanner } from '@gitanimals/ui-panda'; @@ -117,7 +116,7 @@ const SelectPersonaList = wrap // TODO: 정렬 return ( -
+

Please choose a pet to use to merge the level. The pet used disappears.

@@ -135,10 +134,18 @@ const SelectPersonaList = wrap ); }); +const seactionStyle = css({ + height: '100%', + maxHeight: '100%', + minHeight: '0', + display: 'flex', + flexDirection: 'column', + gap: '16px', +}); + const listSectionTitleStyle = css({ textStyle: 'glyph16.regular', color: 'white.white_50', - mb: '16px', display: 'flex', justifyContent: 'space-between', }); @@ -153,32 +160,7 @@ const flexOverflowStyle = cx( height: '100%', minHeight: '0', flexWrap: 'wrap', - justifyContent: 'center', - maxHeight: 'calc(100% )', - marginTop: '40px', - - '@media (max-width: 1200px)': { - marginTop: '24px', - }, - }), - customScrollStyle, -); - -const listStyle = cx( - flex({ - gap: '4px', - w: '100%', - h: '100%', - minH: '0', - overflowY: 'auto', - display: 'flex', - flexWrap: 'wrap', - maxHeight: 'calc(100vh - 760px)', - overflow: 'auto', - - '@media (max-width: 1200px)': { - maxHeight: 'calc(100vh - 560px)', - }, + maxHeight: 'calc(100% - 24px)', }), customScrollStyle, ); From 7ff5484b79984629cbca61f045322494a8f8b459 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Tue, 19 Nov 2024 23:44:48 +0900 Subject: [PATCH 43/49] =?UTF-8?q?refactor:=20style=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/messages/en_US.json | 5 ++- apps/web/messages/ko_KR.json | 5 ++- .../(github-custom)/FarmPersonaSelect.tsx | 8 +--- .../mypage/(github-custom)/FarmType.tsx | 2 +- .../(github-custom)/LinePersonaSelect.tsx | 41 ++++++++++--------- .../mypage/(github-custom)/LinePreview.tsx | 10 ++--- .../app/[locale]/mypage/ProfileSection.tsx | 4 +- .../mypage/my-pet/(merge)/MergePersona.tsx | 25 +++++------ .../mypage/my-pet/(merge)/MergeResult.tsx | 3 -- .../components/Dialog/Dialog.styles.ts.tsx | 1 + .../ui/panda/src/components/Dialog/Dialog.tsx | 1 + 11 files changed, 51 insertions(+), 54 deletions(-) diff --git a/apps/web/messages/en_US.json b/apps/web/messages/en_US.json index 9281925f..f9e0b36b 100644 --- a/apps/web/messages/en_US.json +++ b/apps/web/messages/en_US.json @@ -87,7 +87,7 @@ "copy-link-success": "Copy success!", "line-set-error": "Cannot set more than 1000.", "apply-button": "Apply", - "customize-size": "Line TypeCustomize Size", + "customize-size": "Customize Size", "extend-button": "Extend", "shrink-button": "Shrink", "change-pet": "Change pet", @@ -102,7 +102,8 @@ "Merge": { "merge": "Merge", "merge-result": "Merge result", - "cancel": "Cancel" + "cancel": "Cancel", + "please-choose-pet": "Please choose a pet to use to merge the level. The pet used disappears." } }, "Event": { diff --git a/apps/web/messages/ko_KR.json b/apps/web/messages/ko_KR.json index d1555a88..d70b79a6 100644 --- a/apps/web/messages/ko_KR.json +++ b/apps/web/messages/ko_KR.json @@ -89,7 +89,7 @@ "copy-link-success": "복사 성공!", "line-set-error": "1000 이상은 설정할 수 없습니다.", "apply-button": "적용하기", - "customize-size": "Line Type 사이즈 조정", + "customize-size": "Customize Size", "extend-button": "확장", "shrink-button": "축소", "change-pet": "펫 변경", @@ -104,7 +104,8 @@ "Merge": { "merge": "합치기", "merge-result": "합치기 결과", - "cancel": "취소" + "cancel": "취소", + "please-choose-pet": "합치기에 사용할 펫을 선택해주세요. 합친 펫은 사라집니다." } }, "Event": { diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx index c38face2..869625a2 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx @@ -122,12 +122,8 @@ const flexOverflowStyle = cx( minHeight: '0', flexWrap: 'wrap', justifyContent: 'center', - maxHeight: 'calc(100% )', - marginTop: '40px', - - '@media (max-width: 1200px)': { - marginTop: '24px', - }, + maxHeight: 'calc(100%)', + marginTop: '24px', }), customScrollStyle, ); diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx index 09aa0bb3..e85fa99a 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx @@ -38,7 +38,7 @@ export function FarmType() {
-
diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx index fc35a9b4..855e5f97 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx @@ -4,7 +4,7 @@ import React, { useState } from 'react'; import { useTranslations } from 'next-intl'; import { css, cx } from '_panda/css'; import { flex } from '_panda/patterns'; -import { FullModal } from '@gitanimals/ui-panda'; +import { Dialog, dialogContentCva } from '@gitanimals/ui-panda'; import { ExpandIcon } from 'lucide-react'; import { customScrollStyle } from '@/styles/scrollStyle'; @@ -35,34 +35,37 @@ export const LinePersonaSelect = ({ selectPersona, onChangePersona }: Props) => onSelectPersona={(persona) => onChangePersona(persona.id)} />
- setIsExtend(false)}> - setIsExtend(false)} /> - - {t('line-type-select-pet')} + setIsExtend(false)}> + + {t('line-type-select-pet')}
onChangePersona(persona.id)} />
-
-
+ +
); }; -const flexOverflowStyle = css({ - display: 'flex', - overflowY: 'auto', - overflowX: 'hidden', - width: '100%', - gap: '4px', - height: '100%', - minHeight: '0', - flexWrap: 'wrap', - justifyContent: 'center', - maxHeight: 'calc(100% - 100px)', -}); +const flexOverflowStyle = cx( + css({ + display: 'flex', + overflowY: 'auto', + overflowX: 'hidden', + width: '100%', + gap: '4px', + height: '100%', + minHeight: '0', + flexWrap: 'wrap', + justifyContent: 'center', + maxHeight: 'calc(100%)', + marginTop: '24px', + }), + customScrollStyle, +); const listStyle = cx( flex({ diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx index 24ba84c2..a88642e9 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { useTranslations } from 'next-intl'; import { css } from '_panda/css'; -import { flex } from '_panda/patterns'; +import { Flex } from '_panda/jsx'; import { Button, TextField } from '@gitanimals/ui-panda'; import { toast } from 'sonner'; @@ -41,7 +41,7 @@ export function LinePreview({ selectPersona }: { selectPersona: string | null })
- @@ -66,6 +66,7 @@ const lineContainerStyle = css({ '& img': { maxWidth: '100%', }, + _mobile: { maxWidth: '100%', }, @@ -80,7 +81,7 @@ function SizeInputList({ onApply }: { onApply: (width: number, height: number) = return (

{t('customize-size')}

-
+ setWidth(parseInt(e.target.value))} name="width" /> setHeight(parseInt(e.target.value))} name="height" /> -
+
); } const sizeInputStyle = css({ position: 'relative', - mt: '24px', '& .heading': { textStyle: 'glyph18.bold', diff --git a/apps/web/src/app/[locale]/mypage/ProfileSection.tsx b/apps/web/src/app/[locale]/mypage/ProfileSection.tsx index 59e83321..c647c65a 100644 --- a/apps/web/src/app/[locale]/mypage/ProfileSection.tsx +++ b/apps/web/src/app/[locale]/mypage/ProfileSection.tsx @@ -144,14 +144,14 @@ const profileNameStyle = css({ _mobile: { textStyle: 'glyph24.bold', margin: 0, - mb: 2, + mb: '2px', }, }); const pointStyle = flex({ color: 'white.white', textStyle: 'glyph24.regular', - gap: '6', + gap: '6px', alignItems: 'center', _mobile: { textStyle: 'glyph14.regular', diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx index 43503201..5533ab90 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergePersona.tsx @@ -74,14 +74,12 @@ export function MergePersona({ isOpen, onClose, targetPersona: initTargetPersona -
- - -
+ +
+
-

Please choose a pet to use to merge the level. The pet used disappears.

+

{t('please-choose-pet')}

{data.personas.map((persona) => ( @@ -134,7 +131,7 @@ const SelectPersonaList = wrap ); }); -const seactionStyle = css({ +const sectionStyle = css({ height: '100%', maxHeight: '100%', minHeight: '0', diff --git a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergeResult.tsx b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergeResult.tsx index c6c6b36a..f5d6fafe 100644 --- a/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergeResult.tsx +++ b/apps/web/src/app/[locale]/mypage/my-pet/(merge)/MergeResult.tsx @@ -119,9 +119,6 @@ const closeButtonStyle = css({ right: '8px', padding: '2px', borderRadius: 'full', - _hover: { - backgroundColor: 'gray.100', - }, }); const contentStyle = css({ diff --git a/packages/ui/panda/src/components/Dialog/Dialog.styles.ts.tsx b/packages/ui/panda/src/components/Dialog/Dialog.styles.ts.tsx index a2237ba1..52fe0f9e 100644 --- a/packages/ui/panda/src/components/Dialog/Dialog.styles.ts.tsx +++ b/packages/ui/panda/src/components/Dialog/Dialog.styles.ts.tsx @@ -22,6 +22,7 @@ export const dialogContentCva = cva({ _mobile: { maxWidth: '100vw', maxHeight: '100vh', + borderRadius: '0px', }, }, }, diff --git a/packages/ui/panda/src/components/Dialog/Dialog.tsx b/packages/ui/panda/src/components/Dialog/Dialog.tsx index 8b3f2d60..d309d5a4 100644 --- a/packages/ui/panda/src/components/Dialog/Dialog.tsx +++ b/packages/ui/panda/src/components/Dialog/Dialog.tsx @@ -39,6 +39,7 @@ const contentStyle = css({ border: '1px solid', borderColor: 'gray.gray_150', zIndex: 3001, + color: 'white.white_100', }); const closeStyle = css({ background: 'transparent', outline: 'none', padding: '0' }); From 1fba56b472361beb05ae9113f3a66c69c7bc49bb Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Wed, 20 Nov 2024 00:12:31 +0900 Subject: [PATCH 44/49] =?UTF-8?q?refactor:=20full=20modal=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../panda/src/components/Modal/FullModal.tsx | 96 ------------------- .../ui/panda/src/components/Modal/index.ts | 1 - 2 files changed, 97 deletions(-) delete mode 100644 packages/ui/panda/src/components/Modal/FullModal.tsx diff --git a/packages/ui/panda/src/components/Modal/FullModal.tsx b/packages/ui/panda/src/components/Modal/FullModal.tsx deleted file mode 100644 index 77071d72..00000000 --- a/packages/ui/panda/src/components/Modal/FullModal.tsx +++ /dev/null @@ -1,96 +0,0 @@ -'use client'; - -import { useBodyLock } from '@gitanimals/react'; -import { css } from '_panda/css'; -import { XIcon } from 'lucide-react'; -import { PropsWithChildren } from 'react'; -import { flex } from '_panda/patterns'; -import { useDialog } from './useDialog'; - -interface FullModalProps { - isOpen: boolean; - onClose?: () => void; -} - -function FullModalRoot({ isOpen, onClose, children }: PropsWithChildren) { - const { dialogRef } = useDialog({ isOpen, onClose }); - - useBodyLock(isOpen); - - return ( - - {children} - - ); -} - -const dialogStyle = css({ - margin: 'auto', - borderRadius: '16px', - backgroundColor: 'gray.gray_150', - padding: '24px', - - width: 'calc(100vw - 400px)', - height: 'calc(100vh - 240px)', - - '&::backdrop': { - background: 'black.black_75', - }, - - '@media (max-width: 1200px)': { - width: 'calc(100vw - 240px)', - height: 'calc(100vh - 120px)', - }, - _mobile: { - width: '100vw', - height: '100vh', - }, -}); - -function FullModalCloseButton({ onClose }: { onClose: () => void }) { - return ( - - ); -} - -const closeButtonStyle = css({ - position: 'absolute', - top: '24px', - right: '24px', -}); - -function FullModalHeading({ children }: { children: React.ReactNode }) { - return

{children}

; -} - -const headingStyle = css({ - textStyle: 'glyph48.bold', - color: 'white', - textAlign: 'center', - - '@media (max-width: 1200px)': { - textStyle: 'glyph32.bold', - }, -}); - -function FullModalContent({ children }: { children: React.ReactNode }) { - return
{children}
; -} - -const contentStyle = flex({ - width: '100%', - flexDirection: 'column', - justifyContent: 'center', - alignItems: 'center', - gap: '28px', - color: 'white', - height: '100%', -}); - -export const FullModal = Object.assign(FullModalRoot, { - CloseButton: FullModalCloseButton, - Heading: FullModalHeading, - Content: FullModalContent, -}); diff --git a/packages/ui/panda/src/components/Modal/index.ts b/packages/ui/panda/src/components/Modal/index.ts index 80f4fb8a..3bacd5c6 100644 --- a/packages/ui/panda/src/components/Modal/index.ts +++ b/packages/ui/panda/src/components/Modal/index.ts @@ -1,3 +1,2 @@ export * from './Modal'; -export * from './FullModal'; export * from './ScreenModal'; From 245148a575edeec4546753ec6297dad49799d9d2 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Wed, 20 Nov 2024 00:52:47 +0900 Subject: [PATCH 45/49] =?UTF-8?q?feat:=20drive=20js=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/package.json | 1 + apps/web/src/app/layout.tsx | 1 + pnpm-lock.yaml | 126 ++++++++---------------------------- 3 files changed, 28 insertions(+), 100 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index f7811307..ace77c48 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -30,6 +30,7 @@ "@suspensive/react": "^2.17.1", "@tanstack/react-query": "*", "axios": "^1.6.8", + "driver.js": "^1.3.1", "framer-motion": "^11.1.7", "google-auth-library": "^9.11.0", "google-spreadsheet": "^4.1.2", diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index 73bbccfa..cffa06ce 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -9,6 +9,7 @@ import { import './globals.css'; import '@gitanimals/asset-font/product-sans/index.css'; +import 'driver.js/dist/driver.css'; export const metadata: Metadata = { metadataBase: new URL('https://www.gitanimals.org/'), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3196517..754ef7e0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -195,6 +195,9 @@ importers: axios: specifier: ^1.6.8 version: 1.7.2 + driver.js: + specifier: ^1.3.1 + version: 1.3.1 framer-motion: specifier: ^11.1.7 version: 11.2.10(@emotion/is-prop-valid@1.2.2)(react-dom@18.3.1(react@18.2.0))(react@18.2.0) @@ -374,7 +377,7 @@ importers: version: 2.0.0(eslint@8.57.0) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + version: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: specifier: ^6.8.0 version: 6.8.0(eslint@8.57.0) @@ -5006,6 +5009,9 @@ packages: resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} engines: {node: '>=12'} + driver.js@1.3.1: + resolution: {integrity: sha512-MvUdXbqSgEsgS/H9KyWb5Rxy0aE6BhOVT4cssi2x2XjmXea6qQfgdx32XKVLLSqTaIw7q/uxU5Xl3NV7+cN6FQ==} + duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} @@ -13398,10 +13404,10 @@ snapshots: '@typescript-eslint/eslint-plugin': 6.17.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/parser': 6.17.0(eslint@8.57.0)(typescript@5.4.5) eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)) - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jest: 27.6.0(@typescript-eslint/eslint-plugin@7.1.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-playwright: 0.16.0(eslint-plugin-jest@27.6.0(@typescript-eslint/eslint-plugin@6.17.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) @@ -14671,6 +14677,8 @@ snapshots: dotenv@16.0.3: {} + driver.js@1.3.1: {} + duplexer@0.1.2: {} duplexify@3.7.1: @@ -14962,8 +14970,8 @@ snapshots: '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.33.2(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0) @@ -14982,9 +14990,9 @@ snapshots: eslint: 8.57.0 eslint-plugin-turbo: 2.0.0(eslint@8.57.0) - eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)): + eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)): dependencies: - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-import-resolver-node@0.3.9: dependencies: @@ -14994,29 +15002,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0): - dependencies: - debug: 4.3.4 - enhanced-resolve: 5.17.0 - eslint: 8.57.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) - fast-glob: 3.3.2 - get-tsconfig: 4.7.2 - is-core-module: 2.13.1 - is-glob: 4.0.3 - transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-node - - eslint-import-resolver-webpack - - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: debug: 4.3.4 enhanced-resolve: 5.17.0 eslint: 8.57.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.2 @@ -15028,13 +15019,13 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: debug: 4.3.4 enhanced-resolve: 5.17.0 eslint: 8.57.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.2 is-core-module: 2.13.1 @@ -15045,18 +15036,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 6.17.0(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -15067,14 +15047,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -15084,33 +15064,6 @@ snapshots: eslint: 8.57.0 ignore: 5.3.1 - eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): - dependencies: - array-includes: 3.1.7 - array.prototype.findlastindex: 1.2.3 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - hasown: 2.0.0 - is-core-module: 2.13.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.7 - object.groupby: 1.0.1 - object.values: 1.1.7 - semver: 6.3.1 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 6.17.0(eslint@8.57.0)(typescript@5.4.5) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: array-includes: 3.1.7 @@ -15121,7 +15074,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -15138,34 +15091,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): - dependencies: - array-includes: 3.1.7 - array.prototype.findlastindex: 1.2.3 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - hasown: 2.0.0 - is-core-module: 2.13.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.fromentries: 2.0.7 - object.groupby: 1.0.1 - object.values: 1.1.7 - semver: 6.3.1 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 7.1.0(eslint@8.57.0)(typescript@5.4.5) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: array-includes: 3.1.7 array.prototype.findlastindex: 1.2.3 @@ -15175,7 +15101,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.1.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.0 is-core-module: 2.13.1 is-glob: 4.0.3 From 90d9f4c8f7310421708db80e3c0966639960f7ee Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Wed, 20 Nov 2024 00:53:02 +0900 Subject: [PATCH 46/49] =?UTF-8?q?feat:=20line=20mode=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=EC=97=90=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(github-custom)/LinePersonaSelect.tsx | 6 +- .../mypage/(github-custom)/LinePreview.tsx | 10 +-- .../mypage/(github-custom)/LineType.tsx | 7 +- .../mypage/(github-custom)/useLineTutorial.ts | 67 +++++++++++++++++++ 4 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 apps/web/src/app/[locale]/mypage/(github-custom)/useLineTutorial.ts diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx index 855e5f97..f22f35f2 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePersonaSelect.tsx @@ -11,6 +11,8 @@ import { customScrollStyle } from '@/styles/scrollStyle'; import { SelectPersonaList } from '../PersonaList'; +import { LINE_TUTORIAL } from './useLineTutorial'; + interface Props { selectPersona: string | null; onChangePersona: (personaId: string) => void; @@ -22,10 +24,10 @@ export const LinePersonaSelect = ({ selectPersona, onChangePersona }: Props) => const [isExtend, setIsExtend] = useState(false); return ( -
+

{t('change-pet')}

-
diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx index a88642e9..01bb3e9c 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/LinePreview.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { useTranslations } from 'next-intl'; -import { css } from '_panda/css'; +import { css, cx } from '_panda/css'; import { Flex } from '_panda/jsx'; import { Button, TextField } from '@gitanimals/ui-panda'; import { toast } from 'sonner'; @@ -11,6 +11,8 @@ import { getGitanimalsLineString, GitanimalsLine } from '@/components/Gitanimals import { useClientUser } from '@/utils/clientAuth'; import { copyClipBoard } from '@/utils/copy'; +import { LINE_TUTORIAL } from './useLineTutorial'; + const DEFAULT_SIZE = { width: 600, height: 120 }; export function LinePreview({ selectPersona }: { selectPersona: string | null }) { @@ -34,14 +36,14 @@ export function LinePreview({ selectPersona }: { selectPersona: string | null }) }; return ( -
+
{/* TODO: 임시로 모바일에선 input 안보이게 처리 */} setSizes({ width, height })} />
-
@@ -79,7 +81,7 @@ function SizeInputList({ onApply }: { onApply: (width: number, height: number) = const [height, setHeight] = useState(DEFAULT_SIZE.height); return ( -
+

{t('customize-size')}

setWidth(parseInt(e.target.value))} name="width" /> diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/LineType.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/LineType.tsx index 9adb7b46..f0db12b9 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/LineType.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/LineType.tsx @@ -1,16 +1,17 @@ 'use client'; import React, { useState } from 'react'; -import { css } from '_panda/css'; +import { css, cx } from '_panda/css'; import { LinePersonaSelect } from './LinePersonaSelect'; import { LinePreview } from './LinePreview'; +import { LINE_TUTORIAL, useLineTutorial } from './useLineTutorial'; export function LineType() { const [selectPersona, setSelectPersona] = useState(null); - + useLineTutorial(); return ( -
+
setSelectPersona(personaId)} />
diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/useLineTutorial.ts b/apps/web/src/app/[locale]/mypage/(github-custom)/useLineTutorial.ts new file mode 100644 index 00000000..59a6004f --- /dev/null +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/useLineTutorial.ts @@ -0,0 +1,67 @@ +import { driver } from 'driver.js'; + +export const LINE_TUTORIAL = { + container: 'line-type-tutorial-container', + preview: 'preview', + personaSelect: 'persona-select', + customizeSize: 'customize-size', + copyButton: 'copy-button', + selectExpand: 'select-expand', +}; + +export const useLineTutorial = () => { + const driverObj = driver({ + showProgress: true, + steps: [ + { + element: `.${LINE_TUTORIAL.container}`, + popover: { + title: 'Line Type', + description: 'Line Mode는 자신이 가지고 있는 펫중 하나를 지정해서, 지정한 범위에서 움직이게 할 수 있어요.', + }, + }, + + { + element: `.${LINE_TUTORIAL.personaSelect}`, + popover: { + title: '펫 선택', + description: '먼저 돌아다닐 펫을 하나를 선택해요.', + }, + }, + { + element: `.${LINE_TUTORIAL.selectExpand}`, + popover: { + title: '펫 선택 확장', + description: '선택 리스트가 작아서 불편하다면, 확장 버튼을 눌러서 펫 선택 리스트를 확장할 수 있어요.', + }, + }, + { + element: `.${LINE_TUTORIAL.customizeSize}`, + popover: { + title: '돌아다닐 범위 설정', + description: '펫이 돌아다닐 범위를 설정할 수 있어요. ', + side: 'right', + align: 'start', + }, + }, + { + element: `.${LINE_TUTORIAL.preview}`, + popover: { + title: 'Line 미리보기', + description: '설정한 범위에서 펫이 돌아다니는 모습을 미리볼 수 있어요.', + }, + }, + { + element: `.${LINE_TUTORIAL.copyButton}`, + popover: { + title: '이미지 링크 복사', + description: '복사 버튼을 눌러서 펫이 돌아다니는 이미지를 복사할 수 있어요!', + side: 'right', + align: 'start', + }, + }, + ], + }); + + driverObj.drive(); +}; From afa681dd8ed2bc38d7d473c46e4bf9216e98dd95 Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Wed, 20 Nov 2024 21:43:06 +0900 Subject: [PATCH 47/49] =?UTF-8?q?feat:=20style=20=EC=A1=B0=EA=B8=88=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/app/globals.css | 43 ++++++++++++++++++++++++++++++++++++ apps/web/src/app/layout.tsx | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index 3cb5d317..ce3cd2b5 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -67,3 +67,46 @@ width: fit-content; gap: 12px; } + +.driver-popover-footer { + flex-direction: column; + align-items: flex-start; + gap: 4px; +} + +.driver-popover-navigation-btns { + width: 100%; +} + +.driver-popover-footer button.driver-popover-prev-btn, +.driver-popover-footer button.driver-popover-next-btn { + display: flex; + height: 32px; + padding: 0 20px; + justify-content: center; + align-items: center; + gap: 4px; + text-align: center; + color: var(--black, #000); + text-align: center; + font-family: 'Product Sans'; + font-size: 14px; +} +.driver-popover-footer button.driver-popover-prev-btn { + border-radius: 6px; + border: 1px solid var(--black, #000); + background: var(--white, #fff); + box-shadow: + 0px 4px 4px 0px rgba(0, 0, 0, 0.25), + 0px -3px 0px 0px #a1a1b1 inset, + 0px 3px 0px 0px #d2dcfe inset; +} +.driver-popover-footer button.driver-popover-next-btn { + border-radius: 6px; + border: 1px solid var(--black, #000); + background: var(--brand-color-canary, #fcfd9c); + box-shadow: + 0px 4px 4px 0px rgba(0, 0, 0, 0.25), + 0px -3px 0px 0px #c4c382 inset, + 0px 3px 0px 0px #fdfed2 inset; +} diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index cffa06ce..6fafded8 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -7,9 +7,9 @@ import { interceptorResponseRejected, } from '@/apis/interceptor'; -import './globals.css'; import '@gitanimals/asset-font/product-sans/index.css'; import 'driver.js/dist/driver.css'; +import './globals.css'; export const metadata: Metadata = { metadataBase: new URL('https://www.gitanimals.org/'), From 94f08e1ec2023d54295c4761f324bb17ad6e7d3c Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Wed, 20 Nov 2024 22:53:08 +0900 Subject: [PATCH 48/49] =?UTF-8?q?feat:=20farm=20mode=20tutorial=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(github-custom)/FarmPersonaSelect.tsx | 5 +- .../(github-custom)/FarmTutorialProvider.tsx | 72 +++++++++++++++++++ .../mypage/(github-custom)/FarmType.tsx | 10 +-- .../[locale]/mypage/(github-custom)/page.tsx | 7 +- .../mypage/(github-custom)/useLineTutorial.ts | 23 +----- 5 files changed, 90 insertions(+), 27 deletions(-) create mode 100644 apps/web/src/app/[locale]/mypage/(github-custom)/FarmTutorialProvider.tsx diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx index 869625a2..a632eb88 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx @@ -13,6 +13,8 @@ import { customScrollStyle } from '@/styles/scrollStyle'; import { SelectPersonaList } from '../PersonaList'; +import { useFarmTutorial } from './FarmTutorial'; + export function FarmPersonaSelect({ onChangeStatus, }: { @@ -20,6 +22,7 @@ export function FarmPersonaSelect({ }) { const queryClient = useQueryClient(); const t = useTranslations('Mypage'); + const { classes: farmTutorialClasses } = useFarmTutorial(); const [selectPersona, setSelectPersona] = useState([]); const [loadingPersona, setLoadingPersona] = useState([]); @@ -64,7 +67,7 @@ export function FarmPersonaSelect({ }; return ( -
+

{t('change-pet')}

diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/page.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/page.tsx index de844b77..fcdd7f95 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/page.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/page.tsx @@ -5,6 +5,7 @@ import { updateUrlSearchParams } from '@gitanimals/util-common'; import { Link } from '@/i18n/routing'; +import { FarmTutorialProvider } from './FarmTutorial'; import { FarmType } from './FarmType'; import { LineType } from './LineType'; @@ -21,7 +22,11 @@ async function Mypage({ const MYPAGE_TAB_INNER_MAP: Record = { 'line-type': , - 'farm-type': , + 'farm-type': ( + + + + ), }; return ( diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/useLineTutorial.ts b/apps/web/src/app/[locale]/mypage/(github-custom)/useLineTutorial.ts index 59a6004f..7ded8884 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/useLineTutorial.ts +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/useLineTutorial.ts @@ -4,9 +4,7 @@ export const LINE_TUTORIAL = { container: 'line-type-tutorial-container', preview: 'preview', personaSelect: 'persona-select', - customizeSize: 'customize-size', copyButton: 'copy-button', - selectExpand: 'select-expand', }; export const useLineTutorial = () => { @@ -20,35 +18,18 @@ export const useLineTutorial = () => { description: 'Line Mode는 자신이 가지고 있는 펫중 하나를 지정해서, 지정한 범위에서 움직이게 할 수 있어요.', }, }, - { element: `.${LINE_TUTORIAL.personaSelect}`, popover: { title: '펫 선택', - description: '먼저 돌아다닐 펫을 하나를 선택해요.', - }, - }, - { - element: `.${LINE_TUTORIAL.selectExpand}`, - popover: { - title: '펫 선택 확장', - description: '선택 리스트가 작아서 불편하다면, 확장 버튼을 눌러서 펫 선택 리스트를 확장할 수 있어요.', - }, - }, - { - element: `.${LINE_TUTORIAL.customizeSize}`, - popover: { - title: '돌아다닐 범위 설정', - description: '펫이 돌아다닐 범위를 설정할 수 있어요. ', - side: 'right', - align: 'start', + description: '먼저 돌아다닐 펫을 하나를 선택해요.\n우측 버튼으로 펫 선택 리스트를 확장할 수 있어요.', }, }, { element: `.${LINE_TUTORIAL.preview}`, popover: { title: 'Line 미리보기', - description: '설정한 범위에서 펫이 돌아다니는 모습을 미리볼 수 있어요.', + description: '돌아다닐 범위를 설정한 후, 설정한 범위 내에서 펫이 돌아다니는 모습을 미리볼 수 있어요.', }, }, { From 878c575f123891a206ea452de7e53cf3c689dbdf Mon Sep 17 00:00:00 2001 From: sumi-0011 Date: Wed, 20 Nov 2024 22:53:25 +0900 Subject: [PATCH 49/49] =?UTF-8?q?refactor:=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx | 2 +- apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx | 2 +- apps/web/src/app/[locale]/mypage/(github-custom)/page.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx index a632eb88..65a4054e 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmPersonaSelect.tsx @@ -13,7 +13,7 @@ import { customScrollStyle } from '@/styles/scrollStyle'; import { SelectPersonaList } from '../PersonaList'; -import { useFarmTutorial } from './FarmTutorial'; +import { useFarmTutorial } from './FarmTutorialProvider'; export function FarmPersonaSelect({ onChangeStatus, diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx index baf3dbdb..1c58006f 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/FarmType.tsx @@ -12,7 +12,7 @@ import { copyClipBoard } from '@/utils/copy'; import { FarmBackgroundSelect } from './FarmBackgroundSelect'; import { FarmPersonaSelect } from './FarmPersonaSelect'; -import { useFarmTutorial } from './FarmTutorial'; +import { useFarmTutorial } from './FarmTutorialProvider'; export function FarmType() { const t = useTranslations('Mypage'); diff --git a/apps/web/src/app/[locale]/mypage/(github-custom)/page.tsx b/apps/web/src/app/[locale]/mypage/(github-custom)/page.tsx index fcdd7f95..a50ef944 100644 --- a/apps/web/src/app/[locale]/mypage/(github-custom)/page.tsx +++ b/apps/web/src/app/[locale]/mypage/(github-custom)/page.tsx @@ -5,7 +5,7 @@ import { updateUrlSearchParams } from '@gitanimals/util-common'; import { Link } from '@/i18n/routing'; -import { FarmTutorialProvider } from './FarmTutorial'; +import { FarmTutorialProvider } from './FarmTutorialProvider'; import { FarmType } from './FarmType'; import { LineType } from './LineType';