diff --git a/src/pages/generate/pages/result/ResultPage.css.ts b/src/pages/generate/pages/result/ResultPage.css.ts
index 8ab3b3ad1..52a559507 100644
--- a/src/pages/generate/pages/result/ResultPage.css.ts
+++ b/src/pages/generate/pages/result/ResultPage.css.ts
@@ -11,17 +11,13 @@ export const wrapper = style({
display: 'flex',
flexDirection: 'column',
width: '100%',
- height: `calc(100dvh - ${layoutVars.titleNavBarHeight})`, // TitleNavBar height
- overflow: 'hidden',
+ minHeight: `calc(100dvh - ${layoutVars.titleNavBarHeight})`, // TitleNavBar height
});
export const resultSection = style({
display: 'flex',
flexDirection: 'column',
width: '100%',
- height: '100%',
- minHeight: 0,
- overflow: 'hidden',
});
export const imgArea = recipe({
diff --git a/src/pages/generate/pages/result/components/GeneratedImg.css.ts b/src/pages/generate/pages/result/components/GeneratedImg.css.ts
index c269b0c9b..0747c4b21 100644
--- a/src/pages/generate/pages/result/components/GeneratedImg.css.ts
+++ b/src/pages/generate/pages/result/components/GeneratedImg.css.ts
@@ -1,4 +1,4 @@
-import { style } from '@vanilla-extract/css';
+import { globalStyle, style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';
// import { zIndex } from '@/shared/styles/tokens/zIndex';
@@ -75,25 +75,55 @@ export const slideNumSkeleton = style({
animation: `${animationTokens.skeletonWave} 1.6s ease-in-out infinite`,
});
+export const slideBtnCircle = style({
+ position: 'absolute',
+ top: '50%',
+ left: '50%',
+ transform: 'translate(-50%, -50%)',
+ width: '2.4rem',
+ height: '2.4rem',
+ borderRadius: '1.2rem',
+ backgroundColor: colorVars.color.gray999,
+ pointerEvents: 'none',
+ transition: 'opacity 0.2s ease-in-out',
+});
+
+export const slideBtnIcon = style({
+ position: 'relative',
+ zIndex: 1,
+ width: '1.2rem',
+ height: '1.2rem',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+});
+
+globalStyle(`${slideBtnIcon} > svg`, {
+ width: '1.2rem',
+ height: '1.2rem',
+});
+
export const slidePrevBtn = style({
position: 'absolute',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
- left: '1.2rem',
- bottom: '50%',
+ left: '0.6rem',
+ top: 'calc(50% + 0.8rem)',
+ transform: 'translateY(-50%)',
width: '3.6rem',
height: '3.6rem',
- backgroundColor: colorVars.color.gray999_30,
borderRadius: '99.9rem',
+ padding: 0,
+ border: 'none',
+ background: 'transparent',
+ appearance: 'none',
+ WebkitTapHighlightColor: 'transparent',
zIndex: 1,
-
- ':active': {
- backgroundColor: colorVars.color.gray999_50,
- },
-
- ':disabled': {
- backgroundColor: colorVars.color.gray999_04,
+ selectors: {
+ '&:disabled': {
+ cursor: 'default',
+ },
},
});
@@ -102,21 +132,47 @@ export const slideNextBtn = style({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
- right: '1.2rem',
- bottom: '50%',
+ right: '0.6rem',
+ top: 'calc(50% + 0.8rem)',
+ transform: 'translateY(-50%)',
width: '3.6rem',
height: '3.6rem',
- backgroundColor: colorVars.color.gray999_30,
borderRadius: '99.9rem',
+ padding: 0,
+ border: 'none',
+ background: 'transparent',
+ appearance: 'none',
+ WebkitTapHighlightColor: 'transparent',
zIndex: 1,
-
- ':active': {
- backgroundColor: colorVars.color.gray999_50,
+ selectors: {
+ '&:disabled': {
+ cursor: 'default',
+ },
},
+});
- ':disabled': {
- backgroundColor: colorVars.color.gray999_04,
- },
+globalStyle(`${slidePrevBtn} ${slideBtnCircle}`, {
+ opacity: 0.3,
+});
+
+globalStyle(`${slidePrevBtn}:active:not(:disabled) ${slideBtnCircle}`, {
+ opacity: 0.5,
+});
+
+globalStyle(`${slidePrevBtn}:disabled ${slideBtnCircle}`, {
+ opacity: 0.04,
+});
+
+globalStyle(`${slideNextBtn} ${slideBtnCircle}`, {
+ opacity: 0.3,
+});
+
+globalStyle(`${slideNextBtn}:active:not(:disabled) ${slideBtnCircle}`, {
+ opacity: 0.5,
+});
+
+globalStyle(`${slideNextBtn}:disabled ${slideBtnCircle}`, {
+ opacity: 0.04,
});
export const imgAreaBlurred = recipe({
diff --git a/src/pages/generate/pages/result/components/GeneratedImgA.tsx b/src/pages/generate/pages/result/components/GeneratedImgA.tsx
index 6dc650990..24317835a 100644
--- a/src/pages/generate/pages/result/components/GeneratedImgA.tsx
+++ b/src/pages/generate/pages/result/components/GeneratedImgA.tsx
@@ -201,7 +201,10 @@ const GeneratedImgA = ({
className={styles.slidePrevBtn}
disabled={!swiper || currentSlideIndex === 0}
>
- {currentSlideIndex === 0 ? : }
+
+
+ {currentSlideIndex === 0 ? : }
+
{images.map((image, index) => {
const cachedDetection =
@@ -252,11 +255,14 @@ const GeneratedImgA = ({
className={styles.slideNextBtn}
disabled={!swiper || currentSlideIndex === totalSlideCount - 1}
>
- {currentSlideIndex === totalSlideCount - 1 ? (
-
- ) : (
-
- )}
+
+
+ {currentSlideIndex === totalSlideCount - 1 ? (
+
+ ) : (
+
+ )}
+
diff --git a/src/pages/generate/pages/result/curationSheet/CurationSheet.css.ts b/src/pages/generate/pages/result/curationSheet/CurationSheet.css.ts
index 488f5c8a0..65a25883d 100644
--- a/src/pages/generate/pages/result/curationSheet/CurationSheet.css.ts
+++ b/src/pages/generate/pages/result/curationSheet/CurationSheet.css.ts
@@ -7,13 +7,10 @@ import { colorVars } from '@styles/tokens/color.css';
export const container = style({
width: '100%',
- flex: '1 1 auto',
- minHeight: 0,
display: 'flex',
flexDirection: 'column',
padding: '2rem 2rem 0',
backgroundColor: colorVars.color.gray000,
- overflow: 'hidden',
});
export const title = style({
@@ -63,13 +60,11 @@ export const filterSkeletonChipWidth = styleVariants({
});
export const content = style({
- flex: 1,
- minHeight: 0,
+ width: '100%',
display: 'flex',
flexDirection: 'column',
- overflowY: 'auto',
marginTop: '0.8rem',
- overscrollBehavior: 'contain',
+ paddingBottom: '2.4rem',
selectors: {
'&::-webkit-scrollbar': {
@@ -84,16 +79,14 @@ export const gridbox = style({
width: '100%',
height: 'fit-content',
display: 'grid',
- gridTemplateColumns: 'repeat(2, 16.4rem)',
+ gridTemplateColumns: 'repeat(2, minmax(16.4rem, 1fr))',
columnGap: '0.7rem',
rowGap: 0,
- justifyContent: 'space-between',
- justifyItems: 'start',
});
export const statusContainer = style({
width: '100%',
- height: '100%',
+ minHeight: '22rem',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
diff --git a/src/pages/generate/pages/result/curationSheet/CurationSheet.tsx b/src/pages/generate/pages/result/curationSheet/CurationSheet.tsx
index 5af0a4c46..fced36342 100644
--- a/src/pages/generate/pages/result/curationSheet/CurationSheet.tsx
+++ b/src/pages/generate/pages/result/curationSheet/CurationSheet.tsx
@@ -38,6 +38,40 @@ type ProductPrefetchQueryKey = [
},
];
+const RESULT_CARD_UI_FALLBACK = {
+ productName: '상품명 준비중',
+ mallName: '브랜드 준비중',
+ originalPrice: 0,
+ discountPrice: 0,
+ discountRate: 0,
+ colorHexes: ['#E7EBF0', '#D7DFE8', '#C3CFDD', '#AEBED0'],
+ saveCount: 0,
+} as const;
+
+const normalizeText = (value: unknown, fallback: string) => {
+ if (typeof value !== 'string') return fallback;
+ const normalized = value.trim();
+ return normalized.length > 0 ? normalized : fallback;
+};
+
+const toFiniteNumber = (value: unknown) => {
+ const numeric = Number(value);
+ return Number.isFinite(numeric) ? numeric : null;
+};
+
+const normalizeColorHexes = (value: unknown) => {
+ if (!Array.isArray(value)) return [...RESULT_CARD_UI_FALLBACK.colorHexes];
+
+ const normalized = value
+ .filter((hex): hex is string => typeof hex === 'string')
+ .map((hex) => hex.trim())
+ .filter((hex) => /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(hex));
+
+ return normalized.length > 0
+ ? normalized
+ : [...RESULT_CARD_UI_FALLBACK.colorHexes];
+};
+
interface CurationSheetProps {
groupId?: number | null;
}
@@ -96,37 +130,37 @@ export const CurationSheet = ({ groupId = null }: CurationSheetProps) => {
? byProductId
: index + 1;
- const originalPrice = Number(product.furnitureProductOriginalPrice);
- const discountPrice = Number(product.furnitureProductDiscountPrice);
- const discountRate = Number(product.furnitureProductDiscountRate);
- const saveCount = Number(product.furnitureProductSaveCount);
+ const originalPrice = toFiniteNumber(product.furnitureProductOriginalPrice);
+ const discountPrice = toFiniteNumber(product.furnitureProductDiscountPrice);
+ const discountRate = toFiniteNumber(product.furnitureProductDiscountRate);
+ const saveCount = toFiniteNumber(product.furnitureProductSaveCount);
return {
id: recommendId,
isRecommendId: Boolean(recommendId),
furnitureProductId: safeProductId,
- furnitureProductName: product.furnitureProductName,
- furnitureProductMallName: product.furnitureProductMallName,
+ furnitureProductName: normalizeText(
+ product.furnitureProductName,
+ RESULT_CARD_UI_FALLBACK.productName
+ ),
+ furnitureProductMallName: normalizeText(
+ product.furnitureProductMallName,
+ RESULT_CARD_UI_FALLBACK.mallName
+ ),
furnitureProductImageUrl:
product.furnitureProductImageUrl || product.baseFurnitureImageUrl,
furnitureProductSiteUrl: product.furnitureProductSiteUrl,
- furnitureProductOriginalPrice: Number.isFinite(originalPrice)
- ? originalPrice
- : undefined,
- furnitureProductDiscountPrice: Number.isFinite(discountPrice)
- ? discountPrice
- : undefined,
- furnitureProductDiscountRate: Number.isFinite(discountRate)
- ? discountRate
- : undefined,
- furnitureProductColorHexes: Array.isArray(
+ furnitureProductOriginalPrice:
+ originalPrice ?? RESULT_CARD_UI_FALLBACK.originalPrice,
+ furnitureProductDiscountPrice:
+ discountPrice ?? RESULT_CARD_UI_FALLBACK.discountPrice,
+ furnitureProductDiscountRate:
+ discountRate ?? RESULT_CARD_UI_FALLBACK.discountRate,
+ furnitureProductColorHexes: normalizeColorHexes(
product.furnitureProductColorHexes
- )
- ? product.furnitureProductColorHexes
- : undefined,
- furnitureProductSaveCount: Number.isFinite(saveCount)
- ? saveCount
- : undefined,
+ ),
+ furnitureProductSaveCount:
+ saveCount ?? RESULT_CARD_UI_FALLBACK.saveCount,
};
});
}, [productsData]);
diff --git a/src/shared/assets/icons/nextAbled.svg b/src/shared/assets/icons/nextAbled.svg
index ef58a66e1..1dda8421b 100644
--- a/src/shared/assets/icons/nextAbled.svg
+++ b/src/shared/assets/icons/nextAbled.svg
@@ -1,3 +1,3 @@
-