Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions src/app/(main)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,34 @@ import GoalListDashboardSection from '@/components/goals/GoalListDashboardSectio
import HeatmapSection from '@/components/heatmaps/HeatmapSection';
import ScheduleSection from '@/components/schedule/ScheduleSection';
import TimerWidget from '@/components/timer/TimerWidget';
import { cn } from '@/lib/utils';

export default function DashboardPage() {
return (
<div className={cn('sm:mt-54 sm:ml-0 md:mt-0 md:ml-88 lg:mt-0 lg:ml-0')}>
{/* 모바일/태블릿: 세로 스택 */}
<div className="space-y-24 lg:hidden">
<HeatmapSection />
<CalendarSection />
<ScheduleSection />
<GoalListDashboardSection />
</div>

{/* PC: 복합 레이아웃 */}
<div className="mx-auto hidden max-w-1920 lg:flex lg:h-full lg:flex-col lg:gap-24">
<div className="flex flex-1 gap-24">
<div className="mt-54 md:mt-0">
<div className="mx-auto w-full">
{/* 모바일/태블릿: 세로 스택 */}
<div className="space-y-24 lg:hidden">
<HeatmapSection />
<div className="flex flex-col gap-12">
<CalendarSection />
<ScheduleSection />
</div>
<CalendarSection />
<ScheduleSection />
<GoalListDashboardSection />
</div>

<GoalListDashboardSection />
{/* PC: 복합 레이아웃 */}
<div className="hidden lg:flex lg:h-full lg:flex-col lg:gap-24">
<div className="flex flex-1 gap-24">
<div className="flex-1">
<HeatmapSection />
</div>

<div className="flex flex-1 flex-col gap-12">
<CalendarSection />
<ScheduleSection />
</div>
</div>

<GoalListDashboardSection />
</div>
</div>

<TimerWidget />
Expand Down
12 changes: 6 additions & 6 deletions src/app/(main)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { usePathname } from 'next/navigation';

import { SidebarProvider, useSidebar } from '@/app/providers/SidebarProvider';
import { SidebarProvider } from '@/app/providers/SidebarProvider';
import Sidebar from '@/components/sidebar/Sidebar';

export default function MainLayout({ children }: { children: React.ReactNode }) {
Expand All @@ -16,23 +16,23 @@ export default function MainLayout({ children }: { children: React.ReactNode })
function SidebarLayout({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
const isTodoNoteNewPage = /^\/todo\/[^/]+\/note\/new$/.test(pathname);
const { isOpen } = useSidebar();

return (
<div
className={`${isTodoNoteNewPage ? 'bg-white' : 'bg-background'} ${isOpen ? 'sm:flex-row' : 'sm:flex-col'} flex min-h-screen md:flex-row`}
className={`${isTodoNoteNewPage ? 'bg-white' : 'bg-background'} flex h-screen overflow-hidden`}
>
<Sidebar />

<MainContent>{children}</MainContent>
</div>
);
}

function MainContent({ children }: { children: React.ReactNode }) {
return (
<main className="flex min-w-0 flex-1 transition-all duration-300">
<div className="flex h-full w-full flex-1 justify-center overflow-auto sm:px-16 md:px-13 lg:px-30">
<div className="mx-auto w-full sm:py-16 md:py-36">{children}</div>
<main className="flex min-w-0 flex-1 flex-col overflow-y-auto transition-all duration-300">
<div className="flex w-full flex-1 justify-center sm:px-16 md:pr-13 md:pl-93 lg:px-30">
<div className="w-full max-w-1296 sm:py-16 md:py-36">{children}</div>
</div>
</main>
);
Expand Down
2 changes: 1 addition & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo

return (
<html lang="ko" className={pretendard.variable}>
<body>
<body className="bg-background min-h-screen">
<AuthProvider initialToken={token}>
<MswProvider>
<ReactQueryProvider>{children}</ReactQueryProvider>
Expand Down
2 changes: 1 addition & 1 deletion src/components/calendar/CalendarCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const CalendarCell = ({ date, goals = [], onClick, className }: CalendarCellProp
<button
onClick={handleClick}
className={cn(
'rounded-4 flex h-40 w-full min-w-40 cursor-pointer flex-col items-center p-1 transition md:max-h-44 md:max-w-84 lg:h-40 lg:w-71',
'rounded-4 flex h-40 w-full min-w-40 cursor-pointer flex-col items-center p-1 transition md:max-h-44 md:max-w-84 lg:h-40 lg:max-w-85 lg:min-w-71',
hasGoals && 'hover:bg-tertiary-01',
className,
)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/calendar/CalendarGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const CalendarGrid = forwardRef<HTMLDivElement, CalendarGridProps>(({ data, onCe
{DAYS.map(day => (
<span
key={day}
className="flex h-40 w-full min-w-40 items-center justify-center md:max-w-84 lg:h-20 lg:w-71"
className="flex h-40 w-full min-w-40 items-center justify-center md:max-w-84 lg:h-20 lg:max-w-85 lg:min-w-71"
>
{day}
</span>
Expand Down
2 changes: 1 addition & 1 deletion src/components/goals/GoalListDashboardSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export default function GoalListDashboardSection() {
) : sortedGoals.length === 0 ? (
<NoGoalsGuide />
) : (
<div className="flex w-full flex-col gap-12 md:flex-col lg:flex-row lg:flex-nowrap lg:overflow-x-auto lg:px-16 lg:pb-8">
<div className="flex w-full flex-col gap-12 md:flex-col lg:flex-row lg:flex-nowrap lg:overflow-x-auto">
{sortedGoals.map(goal => (
<GoalListDashboardCard key={goal.goalId} goal={goal} />
))}
Expand Down
2 changes: 1 addition & 1 deletion src/components/heatmaps/HeatmapCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { formatMinutesToHourString } from '@/lib/format';
import { cn } from '@/lib/utils';

const heatmapCellVariants = cva(
'text-body-m-16 rounded-8 flex h-36 w-full min-w-64 items-center justify-center md:h-43 md:max-w-140 lg:h-32 lg:w-112',
'text-body-m-16 rounded-8 flex h-36 w-full min-w-64 items-center justify-center md:h-43 md:max-w-140 lg:h-32 lg:max-w-136 lg:min-w-112',
{
variants: {
intensity: {
Expand Down
2 changes: 1 addition & 1 deletion src/components/heatmaps/HeatmapLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const HeatmapLayout = ({ type, data, children }: HeatmapLayoutProps) => {
{timeKeys.map(key => (
<div
key={key}
className="text-text-04 text-body-m-16 flex h-48 w-full min-w-64 items-center justify-center text-center md:max-w-140 lg:w-112"
className="text-text-04 text-body-m-16 flex h-48 w-full min-w-64 items-center justify-center text-center md:max-w-140 lg:max-w-136 lg:min-w-112"
>
<span className="whitespace-pre-line">{TIME_LABELS[key]}</span>
</div>
Expand Down
193 changes: 111 additions & 82 deletions src/components/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { Suspense } from 'react';
import { Suspense, useEffect } from 'react';

import dynamic from 'next/dynamic';
import Image from 'next/image';
Expand Down Expand Up @@ -31,94 +31,123 @@ export default function Sidebar() {
const { isOpen, setIsOpen } = useSidebar();
const { openGoalModal } = useModalStore();

return isOpen ? (
<div
className={cn(
`border-line md:rounded-tr-50 md:rounded-br-50 sm:rounded-tr-30 sm:rounded-br-30 static z-10 flex h-screen w-320 transform flex-col items-center border-r bg-white py-40 transition-all duration-200 ease-in-out sm:fixed sm:w-280 sm:py-8 md:fixed md:w-320 md:py-40 lg:static`,
{
'translate-x-0 opacity-100': isOpen,
'pointer-events-none -translate-x-full opacity-0': !isOpen,
},
)}
>
<section className="mb-40 shrink-0 px-20">
<SidebarHeader setIsOpen={setIsOpen} />
</section>

<div className="flex flex-1 flex-col overflow-y-auto pb-20 md:pb-0">
<section className="mb-32 shrink-0 px-30 sm:mb-20 sm:px-16 md:mb-32 md:px-30">
<SidebarUser />
</section>

<section className="mb-16 shrink-0 px-20 sm:px-16 md:px-20">
<SidebarMenu />
</section>

<section className="mb-20 flex-1 overflow-y-auto px-20 sm:px-18 md:px-20">
<ErrorBoundary fallback={<ErrorFallback type="general" />}>
<Suspense fallback={<CustomLoading />}>
<SidebarGoalsList />
</Suspense>
</ErrorBoundary>
</section>

<section className="mt-auto shrink-0 px-20">
<Button size="addgoal" disabled={false} onClick={() => openGoalModal()}>
+ 목표추가
</Button>
</section>
</div>
<GoalModal />
</div>
) : (
// 모바일/태블릿(< 1440px)에서 사이드바 열릴 때 뒤 컨텐츠 스크롤 방지
useEffect(() => {
if (isOpen && window.innerWidth < 1440) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
}
return () => {
document.body.style.overflow = '';
};
}, [isOpen]);

return (
<>
{/* 오버레이 - 모바일/태블릿에서만 표시 */}
<div
className={cn(
`border-line rounded-tr-50 rounded-br-50 min-h-screen w-100 transform flex-col items-center gap-36 border-r bg-white px-18 pt-40 transition-all duration-200 ease-in-out sm:fixed sm:hidden md:static md:flex md:w-80 lg:static lg:flex`,
{
'translate-x-0 opacity-100': !isOpen,
'pointer-events-none -translate-x-full opacity-0': isOpen,
},
'fixed inset-0 z-400 bg-black/20 transition-opacity lg:hidden',
isOpen ? 'opacity-100' : 'pointer-events-none opacity-0',
)}
>
<div className="relative h-36 w-36 sm:h-28 sm:w-28 md:h-36 md:w-36">
<Image src={`${CLOUDFRONT_URL}/assets/images/flowIt-logo.svg`} alt="로고 이미지" fill />
</div>

<button
onClick={() => setIsOpen(true)}
className="rounded-12 border-line hover:bg-sidebar-hover flex h-44 w-44 cursor-pointer items-center justify-center border bg-white hover:border-none sm:h-32 sm:w-32 md:h-44 md:w-44"
onClick={() => setIsOpen(false)}
/>

{/* 사이드바 열림 상태 */}
{isOpen ? (
<div
className={cn(
'border-line fixed inset-y-0 left-0 z-500 h-screen transform border-r bg-white',
'w-full sm:max-w-280 md:max-w-320',
'sm:rounded-tr-30 sm:rounded-br-30 md:rounded-tr-50 md:rounded-br-50',
'flex flex-col py-16 sm:py-8 md:py-40',
'translate-x-0 transition-transform duration-200 ease-in-out',
'lg:rounded-tr-50 lg:rounded-br-50 lg:relative lg:h-full lg:max-w-280 lg:rounded-none lg:py-40',
)}
>
<SidebarOpenIcon
className="sm:h-17.45 sm:w-17.45 text-gray-01 h-24 w-24 md:h-24 md:w-24"
fill="currentColor"
/>
</button>
</div>

<div
className={cn(
'z-10 h-48 w-full transform transition-all duration-200 ease-in-out sm:fixed sm:flex sm:items-center sm:gap-12 sm:bg-white sm:px-16 md:fixed md:hidden lg:static lg:hidden',
{
'translate-x-0 opacity-100': !isOpen,
'pointer-events-none -translate-x-full opacity-0': isOpen,
},
)}
>
<div className="sm:gap-4.6 sm:flex sm:items-center">
<div className="sm:relative sm:h-28 sm:w-28">
<Image src={`${CLOUDFRONT_URL}/assets/images/flowIt-logo.svg`} alt="로고 이미지" fill />
</div>
<span className="sm:text-logo-24 sm:text-black">FlowIt</span>
<section className="mb-40 shrink-0 px-20">
<SidebarHeader setIsOpen={setIsOpen} />
</section>

<section className="mb-32 shrink-0 px-30 sm:mb-20 sm:px-16 md:mb-32 md:px-30">
<SidebarUser />
</section>

<section className="mb-16 shrink-0 px-20 sm:px-16 md:px-20">
<SidebarMenu />
</section>

<section className="flex-1 overflow-y-auto px-20 sm:px-18 md:px-20">
<ErrorBoundary fallback={<ErrorFallback type="general" />}>
<Suspense fallback={<CustomLoading />}>
<SidebarGoalsList />
</Suspense>
</ErrorBoundary>
</section>

<section className="sticky bottom-0 z-10 mt-auto shrink-0 px-20 py-8">
<Button size="addgoal" disabled={false} onClick={() => openGoalModal()}>
+ 목표추가
</Button>
</section>

<GoalModal />
</div>
) : (
<>
{/* 사이드바 닫힘 상태 */}
<div
className={cn(
'border-line fixed inset-y-0 left-0 z-30 flex min-h-screen w-100 transform flex-col items-center gap-36 border-r bg-white px-18 pt-40 transition-all duration-200 ease-in-out',
'sm:hidden md:flex md:w-80',
'translate-x-0 opacity-100',
'lg:relative lg:flex lg:h-full lg:w-80',
)}
>
<div className="relative h-36 w-36 sm:h-28 sm:w-28 md:h-36 md:w-36">
<Image
src={`${CLOUDFRONT_URL}/assets/images/flowIt-logo.svg`}
alt="로고 이미지"
fill
/>
</div>

<button
onClick={() => setIsOpen(true)}
className="rounded-12 border-line hover:bg-sidebar-hover flex h-44 w-44 cursor-pointer items-center justify-center border bg-white sm:h-32 sm:w-32 md:h-44 md:w-44"
aria-label="사이드바 열기"
>
<SidebarOpenIcon
className="text-gray-01 sm:h-17.45 sm:w-17.45 h-24 w-24"
fill="currentColor"
/>
</button>
</div>

<button
onClick={() => setIsOpen(true)}
className="sm:rounded-12 sm:border-line hover:bg-sidebar-hover bg-white hover:border-none sm:flex sm:h-32 sm:w-32 sm:cursor-pointer sm:items-center sm:justify-center sm:border"
>
<SidebarOpenIcon className="sm:h-17.45 sm:w-17.45" fill="currentColor" />
</button>
</div>
{/* 모바일 상단 헤더 - sm에서만 표시 (태블릿) */}
<div className="fixed top-0 z-20 hidden h-48 w-full items-center gap-12 bg-white px-16 sm:flex md:hidden">
<div className="sm:gap-4.6 flex items-center">
<div className="relative h-28 w-28">
<Image
src={`${CLOUDFRONT_URL}/assets/images/flowIt-logo.svg`}
alt="로고 이미지"
fill
/>
</div>
<span className="sm:text-logo-24 text-black">FlowIt</span>
</div>

<button
onClick={() => setIsOpen(true)}
className="rounded-12 border-line hover:bg-sidebar-hover flex h-32 w-32 cursor-pointer items-center justify-center border bg-white"
aria-label="사이드바 열기"
>
<SidebarOpenIcon className="h-17.45 w-17.45" fill="currentColor" />
</button>
</div>
</>
)}
</>
);
}
2 changes: 1 addition & 1 deletion src/components/sidebar/SidebarGoalsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function SidebarGoalsList() {
return (
<div
key={goal.goalId}
className="flex h-52 w-260 items-center justify-between px-10 sm:h-40 sm:w-248 md:h-52 md:w-260"
className="flex h-52 w-248 items-center justify-between px-10 sm:h-40 md:h-52 md:w-260 lg:w-240"
>
<div
onClick={() => router.push(ROUTES.GOALS.DETAIL(`${goal.goalId}`))}
Expand Down
2 changes: 1 addition & 1 deletion src/components/sidebar/SidebarHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function SidebarHeader({ setIsOpen }: SidebarHeaderProps) {
};

return (
<div className="flex items-center gap-56 sm:gap-117 md:gap-56">
<div className="flex w-full items-center justify-between">
<div className="sm:gap-4.6 flex items-center gap-6 md:gap-6">
<div className="relative h-36 w-36 sm:h-28 sm:w-28 md:h-36 md:w-36">
<Image src={`${CLOUDFRONT_URL}/assets/images/flowIt-logo.svg`} alt="로고 이미지" fill />
Expand Down
12 changes: 7 additions & 5 deletions src/components/ui/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ const cardVariants = cva('rounded-20 flex flex-col gap-16 px-14 py-20 md:px-20',
gray: 'bg-cardContainer',
},
size: {
auto: 'w-fit',
heatmap: 'h-625 w-full min-w-343 md:h-600 md:max-w-636 lg:h-548 lg:max-w-536',
calendar: 'w-full min-w-343 md:max-w-636 lg:h-368 lg:max-w-536',
schedule: 'h-auto min-h-140 min-w-343 md:max-w-636 lg:h-168 lg:max-w-536',
goal: 'max-h-1146 w-343 w-full md:min-h-428 md:max-w-636 lg:h-388 lg:min-h-388 lg:max-w-1096',
auto: 'mx-auto w-fit lg:mx-0',
heatmap:
'mx-auto h-625 w-full min-w-343 md:h-600 md:max-w-636 lg:mx-0 lg:h-548 lg:max-w-636 lg:min-w-536',
calendar: 'mx-auto w-full min-w-343 md:max-w-636 lg:mx-0 lg:h-368 lg:max-w-636 lg:min-w-536',
schedule:
'mx-auto h-auto min-h-140 min-w-343 md:max-w-636 lg:mx-0 lg:h-auto lg:max-w-636 lg:min-w-536 lg:flex-1',
goal: 'mx-auto max-h-1146 w-full min-w-343 md:min-h-428 md:max-w-636 lg:mx-0 lg:h-388 lg:min-h-388 lg:max-w-1296 lg:min-w-1096',
},
},
defaultVariants: {
Expand Down
Loading