diff --git a/ai-button-preview.html b/ai-button-preview.html new file mode 100644 index 00000000..3b9dbd05 --- /dev/null +++ b/ai-button-preview.html @@ -0,0 +1,381 @@ + + + + + +AI 요약하기 — Periwinkle CTA Preview + + + + + + + + +
+ + +
+ + Default +
+ + +
+ + Hover +
+ +
+ + +
+

Color reference

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RoleValueSwatch
Icon gradient start
Sparkle — left edge
#6B8EF5
Icon gradient end
Sparkle — right edge / arrow
#A78BFA
Label
font-weight 700, 13px, -0.02em
#4B7BF5
Background default#EEF2FF
Background hover#E5EAFF
Border default#C7D2FE
Border hover#A5B4FC
Glow (hover)
box-shadow 0 0 12px
rgba(107,142,245, 0.35)
Page background#EEF2F7
+
+ + + diff --git a/src/assets/icon/chevron/chevron-right.svg b/src/assets/icon/chevron/chevron-right.svg new file mode 100644 index 00000000..6fd1b50e --- /dev/null +++ b/src/assets/icon/chevron/chevron-right.svg @@ -0,0 +1,3 @@ + + + diff --git "a/src/assets/logo/service-logo/ai-\354\232\224\354\225\275\353\262\204\355\212\274.svg" "b/src/assets/logo/service-logo/ai-\354\232\224\354\225\275\353\262\204\355\212\274.svg" index 625b4264..21bf98de 100644 --- "a/src/assets/logo/service-logo/ai-\354\232\224\354\225\275\353\262\204\355\212\274.svg" +++ "b/src/assets/logo/service-logo/ai-\354\232\224\354\225\275\353\262\204\355\212\274.svg" @@ -1,11 +1,14 @@ - - - - - - + + + + - + + + + + + diff --git a/src/components/common/drawer/Drawer.tsx b/src/components/common/drawer/Drawer.tsx index 33196254..8eb3919e 100644 --- a/src/components/common/drawer/Drawer.tsx +++ b/src/components/common/drawer/Drawer.tsx @@ -113,7 +113,7 @@ export default function Drawer({ // [데스크톱] 우측 슬라이드 "relative w-full rounded-l-4xl overflow-hidden max-w-md bg-white shadow-2xl h-full flex flex-col transform transition-transform duration-300 ease-in-out", // [태블릿] 하단 bottom sheet - "tablet:rounded-t-4xl tablet:h-auto tablet:max-h-[85vh] tablet:max-w-none tablet:border-t tablet:border-bg-disabled", + "tablet:rounded-t-4xl tablet:rounded-bl-none tablet:h-auto tablet:max-h-[85vh] tablet:max-w-none tablet:border-t tablet:border-bg-disabled", isOpen ? "translate-x-0 tablet:translate-y-0" : "translate-x-full tablet:translate-x-0 tablet:translate-y-full", diff --git a/src/components/dashboard/charts/BudgetGaugeChart.tsx b/src/components/dashboard/charts/BudgetGaugeChart.tsx index 63dd91ad..ee890cda 100644 --- a/src/components/dashboard/charts/BudgetGaugeChart.tsx +++ b/src/components/dashboard/charts/BudgetGaugeChart.tsx @@ -1,4 +1,4 @@ -import { memo, useMemo } from "react"; +import { memo } from "react"; import { twMerge } from "tailwind-merge"; import { useIsMounted } from "@/hooks/common/useIsMounted"; @@ -51,22 +51,6 @@ const BudgetGaugeChart = memo(function BudgetGaugeChart({ const isOverBudget = spent > totalBudget; const remaining = isOverBudget ? spent - totalBudget : totalBudget - spent; - const { periodElapsedDays, periodTotalDays, periodElapsedRate } = - useMemo(() => { - const now = new Date(); - const elapsed = now.getDate(); - const total = new Date( - now.getFullYear(), - now.getMonth() + 1, - 0, - ).getDate(); - return { - periodElapsedDays: elapsed, - periodTotalDays: total, - periodElapsedRate: Math.round((elapsed / total) * 100), - }; - }, []); - const status = getBudgetStatus(percentage, warningThreshold, dangerThreshold); // 데이터 인사이트 메시지 @@ -74,31 +58,20 @@ const BudgetGaugeChart = memo(function BudgetGaugeChart({ if (isOverBudget) { insightDesc = "예산을 초과했습니다. 캠페인 조정이 필요해요."; - } else if ( - percentage >= dangerThreshold || - percentage > periodElapsedRate + 15 - ) { + } else if (percentage >= dangerThreshold) { insightDesc = "예산 소진이 빨라요. 일일 한도 점검을 추천해요."; - } else if ( - percentage >= warningThreshold || - percentage > periodElapsedRate + 5 - ) { + } else if (percentage >= warningThreshold) { insightDesc = "예산 소진 속도가 다소 높아요. 매체 효율을 확인해 보세요."; - } else if (percentage < periodElapsedRate - 5) { - insightDesc = "예산이 여유로워요. 효율이 좋은 매체에 더 투자해 보세요."; } else { - insightDesc = "계획된 일정에 맞게 예산이 잘 사용되고 있어요."; + insightDesc = "계획된 예산 범위 내에서 잘 사용되고 있어요."; } return (
-
-
- - 이번 달 사용 예산 - -
- +
+

+ 사용 예산 +

{percentage}% @@ -109,10 +82,10 @@ const BudgetGaugeChart = memo(function BudgetGaugeChart({
-
+
-
-
- - 남은 예산 - - - {isOverBudget ? "-" : ""}₩{remaining.toLocaleString()} - -
- -
-
- - 기간 진행률 - - - {periodElapsedRate}% - -
- - {periodElapsedDays}일 - - {" "} - / {periodTotalDays}일 - - -
+
+ + 남은 예산 + + + {isOverBudget ? "-" : ""}₩{remaining.toLocaleString()} +
diff --git a/src/index.css b/src/index.css index 21bb614a..8e3ef1f0 100644 --- a/src/index.css +++ b/src/index.css @@ -370,6 +370,30 @@ button { } } + /* AI 요약 버튼 스파클 pulse 애니메이션 */ + @keyframes sparkle-pulse { + 0%, + 100% { + transform: scale(1); + opacity: 0.7; + } + 50% { + transform: scale(1.2); + opacity: 1; + } + } + + .animate-sparkle-pulse { + animation: sparkle-pulse 2.8s ease-in-out infinite; + } + + @media (prefers-reduced-motion: reduce) { + .animate-sparkle-pulse { + animation: none; + opacity: 1; + } + } + /* 토스트 애니메이션 */ @keyframes fade-in-up { from {