diff --git a/src/App.tsx b/src/App.tsx index 5a958a3..9d6aef5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -27,9 +27,23 @@ import RandomLettersPage from './pages/RandomLetters'; import RollingPaperPage from './pages/RollingPaper'; import WritePage from './pages/Write'; import ShareApprovalPage from './pages/Share'; +import useThemeStore from './stores/themeStore'; +import { useServerSentEvents } from './hooks/useServerSentEvents'; const App = () => { + const theme = useThemeStore((state) => state.theme); useViewport(); + useServerSentEvents(); + + const initializeTheme = () => { + if (theme === 'dark') { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + }; + + initializeTheme(); return ( diff --git a/src/assets/images/background-dark.png b/src/assets/images/background-dark.png new file mode 100644 index 0000000..ed737c5 Binary files /dev/null and b/src/assets/images/background-dark.png differ diff --git a/src/assets/images/field-4-dark.png b/src/assets/images/field-4-dark.png new file mode 100644 index 0000000..0f6ab5b Binary files /dev/null and b/src/assets/images/field-4-dark.png differ diff --git a/src/assets/images/field-theme-asset-bird-dark.png b/src/assets/images/field-theme-asset-bird-dark.png new file mode 100644 index 0000000..ffaac1c Binary files /dev/null and b/src/assets/images/field-theme-asset-bird-dark.png differ diff --git a/src/assets/images/home-left-mountain-dark.png b/src/assets/images/home-left-mountain-dark.png new file mode 100644 index 0000000..f49e739 Binary files /dev/null and b/src/assets/images/home-left-mountain-dark.png differ diff --git a/src/assets/images/home-right-mountain-bottom-dark.png b/src/assets/images/home-right-mountain-bottom-dark.png new file mode 100644 index 0000000..efde328 Binary files /dev/null and b/src/assets/images/home-right-mountain-bottom-dark.png differ diff --git a/src/assets/images/home-right-mountain-top-dark.png b/src/assets/images/home-right-mountain-top-dark.png new file mode 100644 index 0000000..ca10f5f Binary files /dev/null and b/src/assets/images/home-right-mountain-top-dark.png differ diff --git a/src/assets/images/landing-dark.png b/src/assets/images/landing-dark.png new file mode 100644 index 0000000..14ebe02 Binary files /dev/null and b/src/assets/images/landing-dark.png differ diff --git a/src/components/BackgroundBottom.tsx b/src/components/BackgroundBottom.tsx index 6f8e830..6310b4b 100644 --- a/src/components/BackgroundBottom.tsx +++ b/src/components/BackgroundBottom.tsx @@ -1,13 +1,17 @@ import BgItem from '@/assets/images/field-4.png'; +import BgItemDark from '@/assets/images/field-4-dark.png'; import BackgroundImageWrapper from './BackgroundImageWrapper'; +import useThemeStore from '@/stores/themeStore'; const BackgroundBottom = () => { + const theme = useThemeStore((state) => state.theme); + return ( ); }; diff --git a/src/components/NoticeRollingPaper.tsx b/src/components/NoticeRollingPaper.tsx index 7c80fe3..fb1252b 100644 --- a/src/components/NoticeRollingPaper.tsx +++ b/src/components/NoticeRollingPaper.tsx @@ -46,12 +46,12 @@ const NoticeRollingPaper = () => {
- +

{ return ( -

+

{children}

); diff --git a/src/layouts/Header.tsx b/src/layouts/Header.tsx index 5d91ef6..c199a1f 100644 --- a/src/layouts/Header.tsx +++ b/src/layouts/Header.tsx @@ -2,8 +2,14 @@ import { Link, useNavigate } from 'react-router'; import { ArrowLeftIcon, PersonIcon } from '@/assets/icons'; import NotificationButton from '@/components/NotificationButton'; +import FlareRoundedIcon from '@mui/icons-material/FlareRounded'; +import DarkModeOutlinedIcon from '@mui/icons-material/DarkModeOutlined'; +import useThemeStore from '@/stores/themeStore'; const Header = () => { + const theme = useThemeStore((state) => state.theme); + const toggleTheme = useThemeStore((state) => state.toggleTheme); + const navigate = useNavigate(); return ( @@ -12,6 +18,11 @@ const Header = () => {
+ {theme === 'light' ? ( + + ) : ( + + )} diff --git a/src/layouts/MobileLayout.tsx b/src/layouts/MobileLayout.tsx index 3229467..d4d7dd6 100644 --- a/src/layouts/MobileLayout.tsx +++ b/src/layouts/MobileLayout.tsx @@ -3,7 +3,7 @@ import { Outlet } from 'react-router'; const MobileLayout = () => { return (
-
+
diff --git a/src/pages/Home/components/GoToLetterBoard.tsx b/src/pages/Home/components/GoToLetterBoard.tsx index 2f86778..ddce857 100644 --- a/src/pages/Home/components/GoToLetterBoard.tsx +++ b/src/pages/Home/components/GoToLetterBoard.tsx @@ -6,7 +6,7 @@ const GoToLetterBoard = () => { return (
-

게시판

+

게시판

go to letter board diff --git a/src/pages/Home/components/GoToLetterBox.tsx b/src/pages/Home/components/GoToLetterBox.tsx index ca8b3fe..d5be9a5 100644 --- a/src/pages/Home/components/GoToLetterBox.tsx +++ b/src/pages/Home/components/GoToLetterBox.tsx @@ -23,7 +23,7 @@ const GoToLetterBox = () => { return (
-

내 편지함

+

내 편지함

{ return ( <>
-

고민편지 보러가기

+

+ 고민편지 보러가기 +

go to random letter diff --git a/src/pages/Home/components/GoToWrite.tsx b/src/pages/Home/components/GoToWrite.tsx index 9c4d589..cdfc9c6 100644 --- a/src/pages/Home/components/GoToWrite.tsx +++ b/src/pages/Home/components/GoToWrite.tsx @@ -5,7 +5,9 @@ import goToWrite from '@/assets/images/postoffice-letter.png'; const GoToWrite = () => { return (
-

속마음 나누기

+

+ 속마음 나누기 +

go to write diff --git a/src/pages/Home/components/HomeBackgroundLeft.tsx b/src/pages/Home/components/HomeBackgroundLeft.tsx index 43b9f91..eb53aa6 100644 --- a/src/pages/Home/components/HomeBackgroundLeft.tsx +++ b/src/pages/Home/components/HomeBackgroundLeft.tsx @@ -1,12 +1,17 @@ import homeLeftMountain from '@/assets/images/home-left-mountain.png'; +import homeLeftMountainDark from '@/assets/images/home-left-mountain-dark.png'; + import BackgroundImageWrapper from '@/components/BackgroundImageWrapper'; +import useThemeStore from '@/stores/themeStore'; const HomeBackgroundLeft = () => { + const theme = useThemeStore((state) => state.theme); + return ( ); }; diff --git a/src/pages/Home/components/HomeBackgroundRightBottom.tsx b/src/pages/Home/components/HomeBackgroundRightBottom.tsx index 6b55d0c..db74245 100644 --- a/src/pages/Home/components/HomeBackgroundRightBottom.tsx +++ b/src/pages/Home/components/HomeBackgroundRightBottom.tsx @@ -1,12 +1,16 @@ import homeRightMountainBottom from '@/assets/images/home-right-mountain-bottom.png'; +import homeRightMountainBottomDark from '@/assets/images/home-right-mountain-bottom-dark.png'; import BackgroundImageWrapper from '@/components/BackgroundImageWrapper'; +import useThemeStore from '@/stores/themeStore'; const HomeBackgroundRightBottom = () => { + const theme = useThemeStore((state) => state.theme); + return ( ); }; diff --git a/src/pages/Home/components/HomeBackgroundRightTop.tsx b/src/pages/Home/components/HomeBackgroundRightTop.tsx index 966424e..9795f12 100644 --- a/src/pages/Home/components/HomeBackgroundRightTop.tsx +++ b/src/pages/Home/components/HomeBackgroundRightTop.tsx @@ -1,11 +1,17 @@ import homeRightMountainTop from '@/assets/images/home-right-mountain-top.png'; +import homeRightMountainTopDark from '@/assets/images/home-right-mountain-top-dark.png'; + import BackgroundImageWrapper from '@/components/BackgroundImageWrapper'; +import useThemeStore from '@/stores/themeStore'; + const HomeBackgroundRightTop = () => { + const theme = useThemeStore((state) => state.theme); + return ( ); }; diff --git a/src/pages/Home/components/HomeHeader.tsx b/src/pages/Home/components/HomeHeader.tsx index a1ea28f..567dfa3 100644 --- a/src/pages/Home/components/HomeHeader.tsx +++ b/src/pages/Home/components/HomeHeader.tsx @@ -1,12 +1,23 @@ import { Link } from 'react-router'; import { PersonIcon } from '@/assets/icons'; +import FlareRoundedIcon from '@mui/icons-material/FlareRounded'; +import DarkModeOutlinedIcon from '@mui/icons-material/DarkModeOutlined'; +import useThemeStore from '@/stores/themeStore'; import NotificationButton from '@/components/NotificationButton'; const HomeHeader = () => { + const theme = useThemeStore((state) => state.theme); + const toggleTheme = useThemeStore((state) => state.toggleTheme); + return (
+ {theme === 'light' ? ( + + ) : ( + + )} diff --git a/src/pages/Home/components/LetterActions.tsx b/src/pages/Home/components/LetterActions.tsx index a7259cd..45444de 100644 --- a/src/pages/Home/components/LetterActions.tsx +++ b/src/pages/Home/components/LetterActions.tsx @@ -34,7 +34,7 @@ const LetterActions = () => { diff --git a/src/pages/Home/components/RandomCheer.tsx b/src/pages/Home/components/RandomCheer.tsx index 5d3ac5a..f257844 100644 --- a/src/pages/Home/components/RandomCheer.tsx +++ b/src/pages/Home/components/RandomCheer.tsx @@ -1,10 +1,13 @@ import { useState } from 'react'; import randomCheerBird from '@/assets/images/field-theme-asset-bird.png'; +import randomCheerBirdDark from '@/assets/images/field-theme-asset-bird-dark.png'; import { RANDOM_CHEER_LIST } from '../constants'; +import useThemeStore from '@/stores/themeStore'; const RandomCheer = () => { + const theme = useThemeStore((state) => state.theme); const getRandomCheer = (): string => { const randomIndex = Math.floor(Math.random() * RANDOM_CHEER_LIST.length); return RANDOM_CHEER_LIST[randomIndex]; @@ -22,7 +25,7 @@ const RandomCheer = () => {
random cheer bird setRandomCheer(getRandomCheer())} diff --git a/src/pages/Landing/index.tsx b/src/pages/Landing/index.tsx index b89bfda..2b2fb90 100644 --- a/src/pages/Landing/index.tsx +++ b/src/pages/Landing/index.tsx @@ -3,7 +3,9 @@ import { Navigate, useNavigate } from 'react-router'; import { twMerge } from 'tailwind-merge'; import LandingImg from '@/assets/images/landing.png'; +import LandingImgDark from '@/assets/images/landing-dark.png'; import useAuthStore from '@/stores/authStore'; +import useThemeStore from '@/stores/themeStore'; import { STYLE_CLASS } from './constants'; @@ -11,6 +13,7 @@ const Landing = () => { const [step, setStep] = useState(0); const isLoggedIn = useAuthStore((state) => state.isLoggedIn); const navigate = useNavigate(); + const theme = useThemeStore((state) => state.theme); useEffect(() => { if (isLoggedIn) navigate('/'); @@ -21,7 +24,7 @@ const Landing = () => { return (
setStep((prev) => prev + 1)}> 서비스 소개 이미지 { <> 게시판 -

+

따숨이에게 힘이 되었던 다양한 편지들을 모아두었어요

diff --git a/src/pages/LetterBox/index.tsx b/src/pages/LetterBox/index.tsx index df65f7d..2ac397d 100644 --- a/src/pages/LetterBox/index.tsx +++ b/src/pages/LetterBox/index.tsx @@ -43,13 +43,13 @@ const LetterBoxPage = () => {
내 편지함
-

+

나와 연락한 사람들 {letterBox?.length}

{isLoading ? ( -

로딩중..

+

로딩중..

) : letterBox.length > 0 ? ( chunkBox( letterBox.map((data: LetterBoxData, index) => ( diff --git a/src/pages/LetterBoxDetail/components/InformationTooltip.tsx b/src/pages/LetterBoxDetail/components/InformationTooltip.tsx index 820652f..37f9526 100644 --- a/src/pages/LetterBoxDetail/components/InformationTooltip.tsx +++ b/src/pages/LetterBoxDetail/components/InformationTooltip.tsx @@ -20,7 +20,7 @@ const InformationTooltip = () => { return (
{ ? '게시판에 올릴 편지를 선택해주세요' : `${userInfo.zipCode}님과 주고 받은 편지`} -
+

주고 받은 편지 {mailLists.length}

{!userInfo.isClosed && ( @@ -207,7 +207,7 @@ const LetterBoxDetailPage = () => { {!isShareMode && !userInfo.isClosed && !isLoading && (
diff --git a/src/pages/RollingPaper/index.tsx b/src/pages/RollingPaper/index.tsx index 06069c1..9f829d6 100644 --- a/src/pages/RollingPaper/index.tsx +++ b/src/pages/RollingPaper/index.tsx @@ -102,7 +102,9 @@ const RollingPaperPage = () => {
{title} -

등록된 편지 {totalComments}

+

+ 등록된 편지 {totalComments} +

{isSuccess && diff --git a/src/pages/Write/CategorySelect.tsx b/src/pages/Write/CategorySelect.tsx index 89b9331..64e908a 100644 --- a/src/pages/Write/CategorySelect.tsx +++ b/src/pages/Write/CategorySelect.tsx @@ -73,7 +73,7 @@ export default function CategorySelect({ {send && !isReply && (
- + 두근두근! 답장이 언제 올까요?
diff --git a/src/pages/Write/components/CategoryList.tsx b/src/pages/Write/components/CategoryList.tsx index 78cde3c..5e70229 100644 --- a/src/pages/Write/components/CategoryList.tsx +++ b/src/pages/Write/components/CategoryList.tsx @@ -9,7 +9,9 @@ function CategoryList() { return (
-

{stamp.title}

+

+ {stamp.title} +

); })} diff --git a/src/stores/authStore.ts b/src/stores/authStore.ts index a0b56c1..ff69b02 100644 --- a/src/stores/authStore.ts +++ b/src/stores/authStore.ts @@ -1,7 +1,6 @@ import { create } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; - -// import { postLogout } from '@/apis/auth'; +import useThemeStore from './themeStore'; interface AuthStore { isLoggedIn: boolean; @@ -21,6 +20,12 @@ const useAuthStore = create( zipCode: '', login: () => set({ isLoggedIn: true }), logout: async () => { + const theme = useThemeStore.getState().theme; + const toggleTheme = useThemeStore.getState().toggleTheme; + + if (theme === 'dark') { + toggleTheme(); + } set({ isLoggedIn: false, zipCode: '', accessToken: '' }); // location.reload(); // try { diff --git a/src/stores/themeStore.ts b/src/stores/themeStore.ts new file mode 100644 index 0000000..42c597e --- /dev/null +++ b/src/stores/themeStore.ts @@ -0,0 +1,33 @@ +import { create } from 'zustand'; +import { persist, createJSONStorage } from 'zustand/middleware'; + +interface ThemeStore { + theme: 'light' | 'dark'; + toggleTheme: () => void; +} + +const useThemeStore = create( + persist( + (set, get) => ({ + theme: get()?.theme ?? 'light', + toggleTheme: () => + set((state) => { + const newTheme = state.theme === 'light' ? 'dark' : 'light'; + + if (newTheme === 'dark') { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + + return { theme: newTheme }; + }), + }), + { + name: 'theme', + storage: createJSONStorage(() => sessionStorage), + }, + ), +); + +export default useThemeStore; diff --git a/src/styles/animations.css b/src/styles/animations.css index 293b084..d8d5398 100644 --- a/src/styles/animations.css +++ b/src/styles/animations.css @@ -105,7 +105,7 @@ transform-origin: bottom; } 100% { - transform: translateY(100%); + transform: translateY(160%); transform-origin: bottom; } } @@ -140,7 +140,7 @@ /* envelope out animation*/ @keyframes envelopeOut { 0% { - transform: translateY(100%); + transform: translateY(160%); } 100% { transform: translateY(2000%); diff --git a/src/styles/index.css b/src/styles/index.css index 910bae5..e2950ba 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -6,3 +6,5 @@ @import './utilities.css'; @import './fonts.css'; @import './animations.css'; + +@custom-variant dark (&:where(.dark, .dark *)); diff --git a/src/styles/preflight.css b/src/styles/preflight.css index c23d658..dbc3ff5 100644 --- a/src/styles/preflight.css +++ b/src/styles/preflight.css @@ -64,6 +64,32 @@ #f2f2f2; background-blend-mode: overlay, normal, normal; } + .dark .mobile-bg { + position: relative; /* ::before의 위치 기준 */ + background: + linear-gradient( + 180deg, + rgba(0, 0, 0, 1) 0%, + rgba(7, 0, 146, 0.5) 40%, + rgba(150, 150, 150, 0.5) 80% + ) + fixed, + rgba(109, 109, 109, 0.3); + } + + .dark .mobile-bg::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 50%; + background: url('/src/assets/images/background-dark.png') repeat center top; + background-size: cover; + opacity: 1; + z-index: 1; + } + .mobile-layout { display: flex; flex-direction: column;