diff --git a/src/_BacktestingPage/utils/backtestFormSchema.ts b/src/_BacktestingPage/utils/backtestFormSchema.ts index 09f9cb3..81affbf 100644 --- a/src/_BacktestingPage/utils/backtestFormSchema.ts +++ b/src/_BacktestingPage/utils/backtestFormSchema.ts @@ -1,10 +1,9 @@ import { z } from "zod"; -import { differenceInMonths, differenceInYears } from "date-fns"; +import { differenceInMonths } from "date-fns"; const TODAY = new Date(); const MIN_DATE = new Date("1990-01-01"); // 1990년 1월 1일 const MIN_MONTHS_DIFF = 3; // 최소 3개월 -const MAX_YEARS_DIFF = 10; // 최대 10년 export const backtestFormSchema = z .object({ @@ -33,15 +32,5 @@ export const backtestFormSchema = z message: `시작일은 종료일보다 최소 ${MIN_MONTHS_DIFF}개월 전이어야 합니다.`, path: ["startDate"], } - ) - .refine( - (data) => { - const yearsDiff = differenceInYears(data.endDate, data.startDate); - return yearsDiff <= MAX_YEARS_DIFF; - }, - { - message: `시작일은 종료일보다 최대 ${MAX_YEARS_DIFF}년 전까지 가능합니다.`, - path: ["startDate"], - } ); export type BacktestFormSchema = z.infer; diff --git a/src/_MainPage/components/HeroSection.tsx b/src/_MainPage/components/HeroSection.tsx index 3397db2..c908375 100644 --- a/src/_MainPage/components/HeroSection.tsx +++ b/src/_MainPage/components/HeroSection.tsx @@ -6,8 +6,8 @@ import { Link } from "react-router-dom"; export default function HeroSection() { return ( -
-

+
+

{HERO_CONTENT.title.split("\n").map((line, i) => ( {line} @@ -15,22 +15,36 @@ export default function HeroSection() { ))}

-

- {HERO_CONTENT.description.split("\n").map((line, i) => ( - - {line} -
-
- ))} +

+ {/* 모바일 환경에서만 표시되는 텍스트 */} + + {"과거 시장 데이터를 기반으로\n당신의 투자 전략을 시뮬레이션하여\n수익률과 안정성을 미리 예측할 수 있습니다." + .split("\n") + .map((line, i) => ( + + {line} +
+
+ ))} +
+ {/* 태블릿 이상 환경에서 표시되는 텍스트 */} + + {HERO_CONTENT.description.split("\n").map((line, i) => ( + + {line} +
+
+ ))} +

diff --git a/src/_MainPage/components/MarketIndexCard.tsx b/src/_MainPage/components/MarketIndexCard.tsx index 00c947a..46bcfa6 100644 --- a/src/_MainPage/components/MarketIndexCard.tsx +++ b/src/_MainPage/components/MarketIndexCard.tsx @@ -30,13 +30,15 @@ const MarketIndexCard = ({ marketType, marketIndex, isLoading, error }: MarketIn // 로딩 상태 if (isLoading) { return ( - - - {marketType} + + + + {marketType} + - +
- +
@@ -50,13 +52,15 @@ const MarketIndexCard = ({ marketType, marketIndex, isLoading, error }: MarketIn axiosError.response?.data?.detail || "데이터를 불러오는 중 오류가 발생했습니다."; return ( - - - {marketType} + + + + {marketType} + - +
-

{errorMessage}

+

{errorMessage}

@@ -66,13 +70,15 @@ const MarketIndexCard = ({ marketType, marketIndex, isLoading, error }: MarketIn // 데이터가 없는 경우 if (!marketIndex) { return ( - - - {marketType} + + + + {marketType} + - +
-

데이터가 없습니다.

+

데이터가 없습니다.

@@ -84,13 +90,15 @@ const MarketIndexCard = ({ marketType, marketIndex, isLoading, error }: MarketIn if (!latestData) { return ( - - - {marketType} + + + + {marketType} + - +
-

데이터가 없습니다.

+

데이터가 없습니다.

@@ -108,18 +116,22 @@ const MarketIndexCard = ({ marketType, marketIndex, isLoading, error }: MarketIn })); return ( - - - {marketType} + + + + {marketType} + - -

{latestData.closePrice.toLocaleString()}

-

+ +

{latestData.closePrice.toLocaleString()}

+

{arrow} {Math.abs(latestData.changeAmount).toFixed(2)} ({sign} {latestData.changeRate.toFixed(2)}%)

-
+
diff --git a/src/components/Navbar/Logo.tsx b/src/components/Navbar/Logo.tsx index 402eb2c..5066f6c 100644 --- a/src/components/Navbar/Logo.tsx +++ b/src/components/Navbar/Logo.tsx @@ -2,8 +2,10 @@ import { Link } from "react-router-dom"; const Logo = () => { return ( -
- STPT +
+ + STPT +
); }; diff --git a/src/components/Navbar/Navbar.tsx b/src/components/Navbar/Navbar.tsx index 099ca98..f7b9822 100644 --- a/src/components/Navbar/Navbar.tsx +++ b/src/components/Navbar/Navbar.tsx @@ -1,17 +1,82 @@ import Logo from "@/components/Navbar/Logo"; import NavItem from "@/components/Navbar/NavItem"; import SearchBar from "@/components/Navbar/SearchBar"; +import SideBarButton from "@/components/Navbar/SideBarButton"; +import { Link } from "react-router-dom"; +import { useState, useEffect, useRef } from "react"; const Navbar = () => { + const [isSideBarOpen, setIsSideBarOpen] = useState(false); + const modalRef = useRef(null); + const buttonRef = useRef(null); + + // 외부 클릭 시 모달 닫기 + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + const target = event.target as Node; + if ( + modalRef.current && + !modalRef.current.contains(target) && + buttonRef.current && + !buttonRef.current.contains(target) + ) { + setIsSideBarOpen(false); + } + }; + + if (isSideBarOpen) { + document.addEventListener("mousedown", handleClickOutside); + } + + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, [isSideBarOpen]); + return ( - + <> + + ); }; diff --git a/src/components/Navbar/SideBarButton.tsx b/src/components/Navbar/SideBarButton.tsx new file mode 100644 index 0000000..505ad0e --- /dev/null +++ b/src/components/Navbar/SideBarButton.tsx @@ -0,0 +1,34 @@ +import { Button } from "@/components/ui/button"; + +interface SideBarButtonProps { + isOpen: boolean; + onClick: () => void; +} + +export default function SideBarButton({ isOpen, onClick }: SideBarButtonProps) { + return ( + + ); +}