diff --git a/src/components/CardModal.jsx b/src/components/CardModal.jsx
index 8a250de..262ebb3 100644
--- a/src/components/CardModal.jsx
+++ b/src/components/CardModal.jsx
@@ -2,15 +2,21 @@ import styles from './CardModal.module.scss';
import Modal from '@/components/Modal';
import SenderProfile from '@/components/SenderProfile';
import Editor from '@/components/Editor/Editor';
+import Button from './Button/Button';
const CardModal = ({ modalItems, onClose }) => {
- const { sender, imageUrl, createdAt, content, font } = modalItems;
+ const { sender, relationship, imageUrl, createdAt, content, font } = modalItems;
console.log('CardModal', modalItems);
return (
-
+
@@ -19,7 +25,9 @@ const CardModal = ({ modalItems, onClose }) => {
-
+
);
diff --git a/src/components/PostHeader/EmojiGroup/EmojiBadge.module.scss b/src/components/PostHeader/EmojiGroup/EmojiBadge.module.scss
index cedfb59..d4fb7dc 100644
--- a/src/components/PostHeader/EmojiGroup/EmojiBadge.module.scss
+++ b/src/components/PostHeader/EmojiGroup/EmojiBadge.module.scss
@@ -4,7 +4,7 @@
display: inline-flex;
align-items: center;
justify-content: center;
- background: #666666;
+ background-color: rgba(0,0,0,0.54);
border-radius: 16px;
color: #ffffff;
white-space: nowrap;
diff --git a/src/contexts/ModalProvider.jsx b/src/contexts/ModalProvider.jsx
index c7705cc..d7ef6f1 100644
--- a/src/contexts/ModalProvider.jsx
+++ b/src/contexts/ModalProvider.jsx
@@ -56,6 +56,7 @@ export const ModalProvider = ({ children }) => {
useEffect(() => {
if (!isOpen) return;
+ if (isClosing) return;
const handleMouseDown = (e) => {
if (modalWrapperRef.current?.contains(e.target)) {
isMouseDownInsideModal.current = true;
@@ -85,7 +86,7 @@ export const ModalProvider = ({ children }) => {
document.removeEventListener('mousedown', handleMouseDown);
document.removeEventListener('mouseup', handleMouseUp);
};
- }, [isOpen]);
+ }, [isOpen, isClosing]);
//Modal이 열렸을 때 esc를 누르면 Modal Close
useEffect(() => {
diff --git a/src/pages/HomePage/HomePage.module.scss b/src/pages/HomePage/HomePage.module.scss
index 99f966c..cefdd21 100644
--- a/src/pages/HomePage/HomePage.module.scss
+++ b/src/pages/HomePage/HomePage.module.scss
@@ -28,9 +28,11 @@ body {
width: 1200px;
padding: 90px;
overflow: hidden;
+ animation: slide-in-left 1s ease;
&--reverse {
flex-direction: row-reverse;
+ animation: slide-in-right 1s ease;
}
&__context {
@@ -111,3 +113,25 @@ body {
}
}
}
+
+@keyframes slide-in-left {
+ 0% {
+ opacity: 0.5;
+ transform: translateX(50px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+@keyframes slide-in-right {
+ 0% {
+ opacity: 0.5;
+ transform: translateX(-50px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
\ No newline at end of file
diff --git a/src/pages/ListPage/components/ItemCard.jsx b/src/pages/ListPage/components/ItemCard.jsx
index 6838093..c2d3896 100644
--- a/src/pages/ListPage/components/ItemCard.jsx
+++ b/src/pages/ListPage/components/ItemCard.jsx
@@ -1,11 +1,10 @@
-// src/components/ItemCard/ItemCard.jsx
-import React from 'react';
import { Link } from 'react-router-dom';
import styles from './ItemCard.module.scss';
import ShowAvatars from './ShowAvatars';
import ShowEmoji from './ShowEmoji';
import { getBackgroundStylesFromPostData } from '@/utils/getBackgroundStylesFromPostData';
import { getContentStylesFromPostData } from '@/utils/getContentStylesFromPostData';
+import { getIsCardDarkFromPostData } from '../../../utils/getIsCardDarkFromPostData';
const ItemCard = ({
id,
@@ -24,43 +23,79 @@ const ItemCard = ({
// 이미지: 하얀색 텍스트 / 어두운색 overlay 적용
const contentStyle = getContentStylesFromPostData(backgroundImageURL);
+ //카드가 밝은 색인지 어두운 색인지 판별
+ //이미지: true
+ //어두운 색: true
+ //밝은 색: false
+ const isCardDark = getIsCardDarkFromPostData(backgroundImageURL);
+
+ //isCardDark true: 밝은색 선
+ //isCardDark false: 어두운색 선
+ const myDivClassName = isCardDark
+ ? `${styles['item-card__myDiv']} ${styles['card-dark']}`
+ : `${styles['item-card__myDiv']} ${styles['card-light']}`;
+
return (
+ {/* 밝은조명 효과 */}
+
+ {/* 어두운 음영 효과 */}
+
To. {name}
-
{messageCount}명이 작성했어요!
- {/* 프로필 아바타 영역 (최대 3) */}
- {recentMessages.length > 0 ? (
+
+ {/* 프로필 아바타 영역 (최대 3) */}
+
- ) : (
-
- )}
+
-
+
+ {!messageCount ? (
+ `아직 받은 메세지가 없어요🥲`
+ ) : (
+
+ {messageCount}명이 작성했어요!
+
+ )}
+
+
+
{/* 반응 이모지 영역 (최대 3) */}
- {topReactions.length > 0 ? (
+
);
};
+const Skeleton = () => {
+ return (
+
+
+
+
+
+
+
+ {new Array(3).fill(0).map((_, i) => (
+
+ ))}
+
+
+
+ );
+};
+
+ItemCard.skeleton = Skeleton;
+
export default ItemCard;
diff --git a/src/pages/ListPage/components/ItemCard.module.scss b/src/pages/ListPage/components/ItemCard.module.scss
index 2f70c89..3ed95e5 100644
--- a/src/pages/ListPage/components/ItemCard.module.scss
+++ b/src/pages/ListPage/components/ItemCard.module.scss
@@ -17,15 +17,36 @@
transform: translateZ(0);
&:hover {
transform: scale(1.05);
- }
+ }
+
+ &__shinning {
+ position: absolute;
+ width: 90px;
+ height: 200px;
+ right: 20px;
+ top: 20px;
+ background-color: #ffffff;
+ filter: blur(60px);
+ z-index: -1;
+ }
+
+ &__shadow {
+ position: absolute;
+ width: 10px;
+ height: 200px;
+ left: 20px;
+ top: 20px;
+ background-color: #222222;
+ filter: blur(55px);
+ z-index: -1;
+ }
&__content {
display: flex;
flex-direction: column;
- justify-content: center;
- gap: 10px;
+ gap: 12px;
height: 100%;
- padding: 30px 24px;
+ padding: 30px 24px 20px;
color: var(--color-gray-900);
}
@@ -39,13 +60,27 @@
margin: 0;
font-size: var(--font-size-24);
font-weight: var(--font-weight-bold);
+ line-height: 36px;
+ height:36px;
}
+ &__avatars-area {
+ height: 29px;
+ }
+
&__meta {
- margin: 4px 0;
font-size: var(--font-size-16);
+ line-height: 26px;
+ height: 26px;
+ flex-grow: 1;
}
+ &__emojis-area {
+ height: 36px;
+ display: flex;
+ align-items: center;
+ }
+
&__top-reactions {
display: flex;
gap: 8px;
@@ -64,6 +99,73 @@
&__myDiv {
width: 100%;
margin: 1% 0;
- border: 0.5px solid rgba(0, 0, 0, 0.12);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.12);
+ &.card-dark {
+ border: 1px solid rgba(255, 255, 255, 0.4);
+ }
+ &.card-light {
+ border: 1px solid rgba(0, 0, 0, 0.12);
+ }
}
}
+
+.skeleton-card {
+ position: relative;
+ width: 275px;
+ height: 260px;
+ overflow: hidden;
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+ border-radius: 16px;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ transform: scale(1);
+ transition: transform 0.5s;
+ will-change: transform;
+ transform: translateZ(0);
+
+ &__content {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ height: 100%;
+ padding: 30px 24px 20px;
+ }
+
+ &__title {
+ @include skeleton-style;
+ width: 100%;
+ height:36px;
+ }
+
+ &__profile {
+ @include skeleton-style;
+ width: 30%;
+ height: 30px;
+ border-radius: 16px;
+ }
+
+ &__meta {
+ @include skeleton-style;
+ height: 26px;
+ flex-grow: 1;
+ }
+
+ &__emojis-area {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ height: 36px;
+ }
+
+ &__emoji {
+ @include skeleton-style;
+ width: 64px;
+ height: 32px;
+ border-radius: 16px;
+ }
+
+ &__myDiv {
+ width: 100%;
+ margin: 1% 0;
+ border: 1px solid rgba(0, 0, 0, 0.12);
+ }
+}
\ No newline at end of file
diff --git a/src/pages/ListPage/components/Slider.jsx b/src/pages/ListPage/components/Slider.jsx
index 9331fd3..515f913 100644
--- a/src/pages/ListPage/components/Slider.jsx
+++ b/src/pages/ListPage/components/Slider.jsx
@@ -41,6 +41,8 @@ const Slider = ({ cards, hasNext, loadMore }) => {
{isDesktop ? (
+ {visibleCards.length === 0 &&
+ new Array(4).fill(0).map((_, i) =>
)}
{visibleCards.map((card) => (
{
scrollObserverRef={scrollObserverRef}
>
+ {visibleCards.length === 0 &&
+ new Array(4).fill(0).map((_, i) => )}
{visibleCards.map((card) => (
{
sender,
imageUrl: profileImageURL,
createdAt: formatDateKRW(createdAt),
+ relationship: relationship,
content: content,
font: font,
});
diff --git a/src/pages/RollingPaperItemPage/components/ListCard.module.scss b/src/pages/RollingPaperItemPage/components/ListCard.module.scss
index f19609d..2171e0a 100644
--- a/src/pages/RollingPaperItemPage/components/ListCard.module.scss
+++ b/src/pages/RollingPaperItemPage/components/ListCard.module.scss
@@ -145,6 +145,15 @@
align-items: center;
box-shadow: 0px 2px 12px 0px #00000014;
+ @include tablet {
+ aspect-ratio: 352 / 284;
+ max-width: none;
+ }
+
+ @include desktop {
+ aspect-ratio: 384 / 280;
+ }
+
&__container {
width: clamp(272px, 80vw, 384px);
height: 100%;
diff --git a/src/utils/getBackgroundStylesFromPostData.js b/src/utils/getBackgroundStylesFromPostData.js
index 44b0094..f70cd7f 100644
--- a/src/utils/getBackgroundStylesFromPostData.js
+++ b/src/utils/getBackgroundStylesFromPostData.js
@@ -4,7 +4,7 @@ export const getBackgroundStylesFromPostData = ({ backgroundColor, backgroundIma
let backgroundStyle = {
backgroundColor: 'none',
backgroundImage: 'none',
- backgroundRepeat: 'no-repeaet',
+ backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
backgroundSize: 'cover',
};
diff --git a/src/utils/getIsCardDarkFromPostData.js b/src/utils/getIsCardDarkFromPostData.js
new file mode 100644
index 0000000..a17392f
--- /dev/null
+++ b/src/utils/getIsCardDarkFromPostData.js
@@ -0,0 +1,25 @@
+import { getColorFromCloudinaryImageUrl } from './getColorFromCloudinaryImageUrl';
+import { getIsColorDark } from './getIsColorDark';
+
+export const getIsCardDarkFromPostData = (backgroundImageURL) => {
+ if (!backgroundImageURL) {
+ return false;
+ } else {
+ const urlObj = new URL(backgroundImageURL);
+ const parts = urlObj.pathname.split('/'); // ['','dxho7f5dm','image','upload','v1749409044','colors','6a6a6a.png']
+ const folderCandidate = parts[5]; // public_id 시작 부분 (index 5)
+ if (folderCandidate === 'colors') {
+ const imageHexColor = getColorFromCloudinaryImageUrl(backgroundImageURL);
+ const isColorDark = getIsColorDark(imageHexColor);
+ if (isColorDark) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (folderCandidate === 'images') {
+ return true;
+ } else {
+ return true;
+ }
+ }
+};