feat: 세션 중, 끝났을 때 목표 표시
This commit is contained in:
@@ -54,7 +54,7 @@
|
|||||||
--card-foreground: oklch(0.129 0.042 264.695);
|
--card-foreground: oklch(0.129 0.042 264.695);
|
||||||
--popover: oklch(1 0 0);
|
--popover: oklch(1 0 0);
|
||||||
--popover-foreground: oklch(15.152% 0.01301 277.362);
|
--popover-foreground: oklch(15.152% 0.01301 277.362);
|
||||||
--primary: oklch(0.208 0.042 265.755);
|
--primary: oklch(0.574 0.202 262);
|
||||||
--primary-foreground: oklch(0.984 0.003 247.858);
|
--primary-foreground: oklch(0.984 0.003 247.858);
|
||||||
--secondary: oklch(0.968 0.007 247.896);
|
--secondary: oklch(0.968 0.007 247.896);
|
||||||
--secondary-foreground: oklch(0.208 0.042 265.755);
|
--secondary-foreground: oklch(0.208 0.042 265.755);
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
--destructive: oklch(0.577 0.245 27.325);
|
--destructive: oklch(0.577 0.245 27.325);
|
||||||
--border: oklch(0.929 0.013 255.508);
|
--border: oklch(0.929 0.013 255.508);
|
||||||
--input: oklch(0.929 0.013 255.508);
|
--input: oklch(0.929 0.013 255.508);
|
||||||
--ring: oklch(0.704 0.04 256.788);
|
--ring: oklch(0.62 0.202 262);
|
||||||
--chart-1: oklch(0.646 0.222 41.116);
|
--chart-1: oklch(0.646 0.222 41.116);
|
||||||
--chart-2: oklch(0.6 0.118 184.704);
|
--chart-2: oklch(0.6 0.118 184.704);
|
||||||
--chart-3: oklch(0.398 0.07 227.392);
|
--chart-3: oklch(0.398 0.07 227.392);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export default function HomePage() {
|
|||||||
params.set("mode", mode);
|
params.set("mode", mode);
|
||||||
|
|
||||||
if (goal && goal.trim().length > 0) {
|
if (goal && goal.trim().length > 0) {
|
||||||
localStorage.setItem("goal", goal.trim());
|
localStorage.setItem("hushroom:session-goal", goal.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
router.push(`/session?${params.toString()}`);
|
router.push(`/session?${params.toString()}`);
|
||||||
@@ -197,7 +197,7 @@ function SessionGoalDialog({
|
|||||||
value={goal}
|
value={goal}
|
||||||
onChange={(e) => setGoal(e.target.value)}
|
onChange={(e) => setGoal(e.target.value)}
|
||||||
placeholder="목표를 입력하세요"
|
placeholder="목표를 입력하세요"
|
||||||
className="text-lg border-[#2F6FED] focus-visible:ring-[#2F6FED] focus-visible:ring-1"
|
className="text-lg"
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<div className="text-xs text-slate-500">
|
<div className="text-xs text-slate-500">
|
||||||
@@ -209,11 +209,7 @@ function SessionGoalDialog({
|
|||||||
<Button variant="ghost" onClick={() => onOpenChange(false)}>
|
<Button variant="ghost" onClick={() => onOpenChange(false)}>
|
||||||
취소
|
취소
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button onClick={onStart} className="rounded-xl" disabled={!mode}>
|
||||||
onClick={onStart}
|
|
||||||
className="rounded-xl bg-[#2F6FED]"
|
|
||||||
disabled={!mode}
|
|
||||||
>
|
|
||||||
시작하기
|
시작하기
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useMemo } from "react";
|
import { useMemo, useState } from "react";
|
||||||
|
|
||||||
type Mode = "freeflow" | "sprint" | "deepwork";
|
type Mode = "freeflow" | "sprint" | "deepwork";
|
||||||
|
|
||||||
@@ -34,11 +34,17 @@ export default function SessionEndPage() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const params = useSearchParams();
|
const params = useSearchParams();
|
||||||
|
|
||||||
const mode = useMemo(() => clampMode(params.get("mode")), [params]);
|
const [elapsed, setElapsed] = useState(() => {
|
||||||
const elapsed = useMemo(() => {
|
const v = Number(localStorage.getItem("hushroom:session-elapsed") ?? "0");
|
||||||
const v = Number(params.get("elapsed") ?? "0");
|
|
||||||
return Number.isFinite(v) ? v : 0;
|
return Number.isFinite(v) ? v : 0;
|
||||||
}, [params]);
|
});
|
||||||
|
|
||||||
|
const [goal, setGoal] = useState(() => {
|
||||||
|
const goal = localStorage.getItem("hushroom:session-goal");
|
||||||
|
return goal;
|
||||||
|
});
|
||||||
|
|
||||||
|
const mode = useMemo(() => clampMode(params.get("mode")), [params]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen w-full" style={{ backgroundColor: BG }}>
|
<main className="min-h-screen w-full" style={{ backgroundColor: BG }}>
|
||||||
@@ -59,6 +65,22 @@ export default function SessionEndPage() {
|
|||||||
<div className="mt-3 text-[44px] font-semibold leading-none text-slate-900 tabular-nums">
|
<div className="mt-3 text-[44px] font-semibold leading-none text-slate-900 tabular-nums">
|
||||||
{hhmmss(elapsed)}
|
{hhmmss(elapsed)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Goal */}
|
||||||
|
{goal && (
|
||||||
|
<div
|
||||||
|
className="mt-4 rounded-2xl border bg-[#F1F5FF] px-4 py-3"
|
||||||
|
style={{ borderColor: BORDER }}
|
||||||
|
>
|
||||||
|
<div className="text-xs font-semibold text-slate-600">
|
||||||
|
이번 목표
|
||||||
|
</div>
|
||||||
|
<div className="mt-1 text-xl font-semibold text-slate-900 line-clamp-2">
|
||||||
|
{goal}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="mt-3 text-base text-slate-700">세션이 종료됐어요</div>
|
<div className="mt-3 text-base text-slate-700">세션이 종료됐어요</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -293,13 +293,20 @@ export default function SessionPage() {
|
|||||||
}
|
}
|
||||||
}, [elapsed, mode]);
|
}, [elapsed, mode]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const goal = localStorage.getItem("hushroom:session-goal") ?? "";
|
||||||
|
setGoal(goal);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const timeMain = useMemo(() => {
|
const timeMain = useMemo(() => {
|
||||||
if (mode === "freeflow") return formatHHMMSS(elapsed);
|
if (mode === "freeflow") return formatHHMMSS(elapsed);
|
||||||
return formatHHMMSS(remaining);
|
return formatHHMMSS(remaining);
|
||||||
}, [elapsed, remaining, mode]);
|
}, [elapsed, remaining, mode]);
|
||||||
|
|
||||||
const onEnd = () =>
|
const onEnd = () => {
|
||||||
router.push(`/session/end?mode=${mode}&elapsed=${elapsed}`);
|
localStorage.setItem("hushroom:session-elapsed", elapsed.toString());
|
||||||
|
router.push(`/session/end?mode=${mode}`);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen w-full" style={{ backgroundColor: BG }}>
|
<main className="min-h-screen w-full" style={{ backgroundColor: BG }}>
|
||||||
@@ -330,6 +337,21 @@ export default function SessionPage() {
|
|||||||
? "원할 때 종료"
|
? "원할 때 종료"
|
||||||
: "한 번 실행되고 끝나면 요약으로 이동"}
|
: "한 번 실행되고 끝나면 요약으로 이동"}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Goal */}
|
||||||
|
{goal && (
|
||||||
|
<div
|
||||||
|
className="mt-4 rounded-2xl border bg-[#F1F5FF] px-4 py-3"
|
||||||
|
style={{ borderColor: BORDER }}
|
||||||
|
>
|
||||||
|
<div className="text-xs font-semibold text-slate-600">
|
||||||
|
이번 목표
|
||||||
|
</div>
|
||||||
|
<div className="mt-1 text-xl font-semibold text-slate-900 line-clamp-2">
|
||||||
|
{goal}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-[44px] font-semibold leading-none text-slate-900 tabular-nums">
|
<div className="text-[44px] font-semibold leading-none text-slate-900 tabular-nums">
|
||||||
{timeMain}
|
{timeMain}
|
||||||
|
|||||||
18
src/components/Modal.tsx
Normal file
18
src/components/Modal.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// import { ReactNode } from "react";
|
||||||
|
|
||||||
|
// interface ModalProps {
|
||||||
|
// open: boolean;
|
||||||
|
// onClose: () => void;
|
||||||
|
// children: ReactNode;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export default function Modal({ open, onClose, children }: ModalProps) {
|
||||||
|
// return (
|
||||||
|
// <div
|
||||||
|
// onClick={onClose}
|
||||||
|
// className={`flex fixed inset-0 justify-center items-center transition-colors ${open ? "visible bg-black/20" : "invisible"}`}
|
||||||
|
// >
|
||||||
|
// {children}
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
Reference in New Issue
Block a user