This commit is contained in:
mota
2025-11-18 10:42:48 +09:00
parent 4dc8304a1d
commit f4196167c7
42 changed files with 614 additions and 104 deletions

View File

@@ -69,7 +69,9 @@ export default function AccountPage() {
onSubmit={() => {
// TODO: integrate API
}}
devVerificationState={verificationState}
devVerificationState={
verificationState === 'changed' ? 'verified' : verificationState
}
/>
<MenuAccountOption

View File

@@ -1,6 +1,7 @@
'use client';
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useState } from "react";
import ChevronDownSvg from "../../svgs/chevrondownsvg";
@@ -36,14 +37,15 @@ function ProgressBar({ value }: { value: number }) {
export default function CourseCard({ course, defaultOpen = false }: { course: Course; defaultOpen?: boolean }) {
const [open, setOpen] = useState(defaultOpen);
const router = useRouter();
const totalMinutes = course.lessons.reduce((sum, l) => sum + (l.durationMin || 0), 0);
const totalHours = Math.floor(totalMinutes / 60);
const restMinutes = totalMinutes % 60;
const firstIncomplete = course.lessons.find((l) => !l.isCompleted)?.id;
const cardClassName = [
"rounded-xl border bg-white shadow-[0_2px_8px_rgba(0,0,0,0.02)]",
open ? "border-[#384fbf]" : "border-[#ecf0ff]",
"rounded-xl bg-white shadow-[0_2px_8px_rgba(0,0,0,0.02)]",
open ? "border-[3px] border-[#384fbf]" : "border border-[#ecf0ff]",
].join(" ");
const formatDuration = (m: number) => {
@@ -54,33 +56,33 @@ export default function CourseCard({ course, defaultOpen = false }: { course: Co
return (
<article className={cardClassName}>
<header className="flex items-center gap-4 p-4">
<div className="relative h-[76px] w-[120px] overflow-hidden rounded-md bg-[#f1f3f5]">
<header className="flex items-center gap-6 px-8 py-6">
<div className="relative h-[120px] w-[180px] overflow-hidden rounded-[8px] bg-[#f1f3f5]">
<Image
src={`https://picsum.photos/seed/${encodeURIComponent(course.id)}/240/152`}
alt=""
fill
sizes="120px"
sizes="180px"
unoptimized
className="object-cover"
/>
</div>
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2">
<span className="rounded bg-[#e5f5ec] px-2 py-0.5 text-[12px] font-semibold leading-[1.4] text-[#0c9d61]">
<span className="flex h-[20px] items-center justify-center rounded-[4px] bg-[#e5f5ec] px-[4px] text-[13px] font-semibold leading-[1.4] text-[#0c9d61]">
{course.status}
</span>
<h2 className="truncate text-[18px] font-bold leading-[1.5] text-[#1b2027]">
<h2 className="truncate text-[18px] font-semibold leading-normal text-[#333c47]">
{course.title}
</h2>
</div>
<p className="mt-1 line-clamp-2 text-[14px] leading-[1.5] text-[#4c5561]">{course.description}</p>
<p className="mt-1 line-clamp-2 text-[14px] leading-normal text-basic-text">{course.description}</p>
<div className="mt-2 flex items-center justify-between gap-3">
<p className="text-[13px] leading-[1.4] text-[#8c95a1]">
VOD · {course.lessons.length} · {totalHours} {restMinutes}
</p>
<p className="text-[13px] font-semibold leading-[1.4] text-[#384fbf]">
{course.progressPct}%
: {course.progressPct}%
</p>
</div>
<div className="mt-2">
@@ -105,20 +107,15 @@ export default function CourseCard({ course, defaultOpen = false }: { course: Co
</header>
{open ? (
<div className="px-4 pb-4">
<div className="px-6 pb-6">
<ul className="flex flex-col gap-2">
{course.lessons.map((lesson, idx) => (
<li key={lesson.id} className="rounded-lg border border-[#ecf0ff] bg-white">
<div className="flex items-center justify-between gap-4 px-4 py-3">
<li key={lesson.id} className="rounded-lg border border-[#dee1e6] bg-white">
<div className="flex items-center justify-between gap-4 px-[24px] py-[16px]">
<div className="min-w-0 flex-1">
<div className="flex items-center gap-3">
<span className="w-[20px] text-[13px] font-semibold leading-[1.4] text-[#8c95a1]">
{idx + 1}.
</span>
<p className="truncate text-[14px] font-medium leading-[1.5] text-[#333c47]">
{lesson.title}
</p>
</div>
<p className="truncate text-[16px] font-semibold leading-normal text-[#333c47]">
{`${idx + 1}. ${lesson.title}`}
</p>
<div className="mt-2 flex items-center gap-3">
<span className="text-[13px] leading-[1.4] text-[#8c95a1]">
{formatDuration(lesson.durationMin)}
@@ -129,29 +126,59 @@ export default function CourseCard({ course, defaultOpen = false }: { course: Co
<button
type="button"
className={[
"rounded-md px-3 py-2 text-[14px] font-medium leading-[1.5]",
"inline-flex h-[32px] w-[140px] items-center justify-center gap-[6px] rounded-[6px] px-4 text-center whitespace-nowrap cursor-pointer",
lesson.isCompleted
? "text-[#384fbf] border border-transparent bg-white"
: "text-[#4c5561] border border-[#8c95a1] bg-white",
? "bg-white text-[13px] font-medium leading-[1.4] text-[#384fbf]"
: "bg-white text-[14px] font-medium leading-normal text-basic-text border border-[#8c95a1]",
].join(" ")}
>
{lesson.isCompleted ? "학습 제출 완료" : "학습 제출 하기"}
{lesson.isCompleted ? (
<>
<svg
xmlns="http://www.w3.org/2000/svg"
width="10"
height="7"
viewBox="0 0 10 7"
fill="none"
aria-hidden
>
<path
d="M8.75 0.75L3.25 6.25L0.75 3.75"
stroke="#384FBF"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
<span> </span>
</>
) : (
"학습 제출 하기"
)}
</button>
{lesson.isCompleted ? (
<button
type="button"
className="rounded-md border border-[#dee1e6] px-3 py-2 text-[14px] font-medium leading-[1.5] text-[#4c5561] hover:bg-[#f9fafb]"
onClick={() => router.push(`/menu/courses/lessons/${lesson.id}/review`)}
className="inline-flex h-[32px] w-[140px] items-center justify-center rounded-[6px] bg-[#f1f3f5] px-4 text-center text-[14px] font-medium leading-normal text-basic-text whitespace-nowrap cursor-pointer"
>
</button>
) : (
<button
type="button"
onClick={() =>
router.push(
lesson.id === firstIncomplete
? `/menu/courses/lessons/${lesson.id}/continue`
: `/menu/courses/lessons/${lesson.id}/start`,
)
}
className={[
"rounded-md px-3 py-2 text-[14px] font-medium leading-[1.5]",
"inline-flex h-[32px] w-[140px] items-center justify-center rounded-[6px] px-4 text-center text-[14px] font-medium leading-normal whitespace-nowrap cursor-pointer",
lesson.id === firstIncomplete
? "bg-[#ecf0ff] text-[#384fbf]"
: "border border-[#dee1e6] text-[#4c5561] hover:bg-[#f9fafb]",
: "border border-[#dee1e6] text-basic-text",
].join(" ")}
>
{lesson.id === firstIncomplete ? "이어서 수강하기" : "수강하기"}

View File

@@ -0,0 +1,168 @@
'use client';
const imgImage2 = "/imgs/image-2.png";
const imgLine58 = "/imgs/line-58.svg";
const img = "/imgs/asset-base.svg";
const imgArrowsDiagramsArrow = "/imgs/arrows-diagrams-arrow.svg";
const imgIcon = "/imgs/icon.svg";
const imgGroup = "/imgs/group.svg";
const imgEllipse2 = "/imgs/ellipse-2.svg";
const imgMusicAudioPlay = "/imgs/music-audio-play.svg";
const imgIcon1 = "/imgs/icon-1.svg";
const imgIcon2 = "/imgs/icon-2.svg";
const imgIcon3 = "/imgs/icon-3.svg";
const imgIcon4 = "/imgs/icon-4.svg";
export default function FigmaSelectedLessonPage() {
return (
<div className="bg-white content-stretch flex flex-col items-center relative size-full">
<div className="content-stretch flex flex-col items-start max-w-[1440px] relative shrink-0 w-[1440px]">
<div className="box-border content-stretch flex gap-[10px] h-[100px] items-center px-[32px] py-0 relative shrink-0 w-full">
<div className="basis-0 content-stretch flex gap-[12px] grow items-center min-h-px min-w-px relative shrink-0">
<div className="relative shrink-0 size-[32px]">
<img alt="" className="block max-w-none size-full" src={imgArrowsDiagramsArrow} />
</div>
<div className="basis-0 content-stretch flex flex-col grow items-start justify-center leading-[1.5] min-h-px min-w-px not-italic relative shrink-0">
<p className="font-['Pretendard:SemiBold',sans-serif] relative shrink-0 text-[#6c7682] text-[16px] w-full">
</p>
<p className="font-['Pretendard:Bold',sans-serif] relative shrink-0 text-[#1b2027] text-[24px] w-full">
6. ,
</p>
</div>
<div className="content-stretch flex gap-[20px] h-[81px] items-center justify-center relative shrink-0">
<div className="relative shrink-0 w-[52px]">
<div className="bg-clip-padding border-0 border-[transparent] border-solid box-border content-stretch flex flex-col gap-[4px] items-center relative w-[52px]">
<div className="bg-[#384fbf] relative rounded-[2.23696e+07px] shrink-0 size-[32px]">
<div className="bg-clip-padding border-0 border-[transparent] border-solid box-border content-stretch flex items-center justify-center relative size-[32px]">
<p className="font-['Pretendard:Bold',sans-serif] leading-[18px] not-italic relative shrink-0 text-[14px] text-nowrap text-white whitespace-pre">
1
</p>
</div>
</div>
<p className="font-['Pretendard:SemiBold',sans-serif] leading-[1.5] not-italic relative shrink-0 text-[#384fbf] text-[14px] text-nowrap whitespace-pre">
</p>
</div>
</div>
<div className="relative shrink-0 size-[24px]">
<img alt="" className="block max-w-none size-full" src={imgIcon} />
</div>
<div className="relative shrink-0 w-[52px]">
<div className="bg-clip-padding border-0 border-[transparent] border-solid box-border content-stretch flex flex-col gap-[4px] items-center relative w-[52px]">
<div className="bg-[#dee1e6] relative rounded-[2.23696e+07px] shrink-0 size-[32px]">
<div className="bg-clip-padding border-0 border-[transparent] border-solid box-border content-stretch flex items-center justify-center relative size-[32px]">
<p className="font-['Pretendard:Bold',sans-serif] leading-[18px] not-italic relative shrink-0 text-[#6c7682] text-[14px] text-nowrap whitespace-pre">
2
</p>
</div>
</div>
<p className="font-['Pretendard:SemiBold',sans-serif] leading-[1.5] not-italic relative shrink-0 text-[#6c7682] text-[14px] text-nowrap whitespace-pre">
XR
</p>
</div>
</div>
<div className="relative shrink-0 size-[24px]">
<img alt="" className="block max-w-none size-full" src={imgIcon} />
</div>
<div className="relative shrink-0 w-[52px]">
<div className="bg-clip-padding border-0 border-[transparent] border-solid box-border content-stretch flex flex-col gap-[4px] items-center relative w-[52px]">
<div className="bg-[#dee1e6] relative rounded-[2.23696e+07px] shrink-0 size-[32px]">
<div className="bg-clip-padding border-0 border-[transparent] border-solid box-border content-stretch flex items-center justify-center relative size-[32px]">
<p className="font-['Pretendard:Bold',sans-serif] leading-[18px] not-italic relative shrink-0 text-[#6c7682] text-[14px] text-nowrap whitespace-pre">
3
</p>
</div>
</div>
<p className="font-['Pretendard:SemiBold',sans-serif] leading-[1.5] not-italic relative shrink-0 text-[#6c7682] text-[14px] text-nowrap whitespace-pre">
</p>
</div>
</div>
</div>
</div>
</div>
<div className="box-border content-stretch flex flex-col gap-[24px] items-center overflow-clip pb-[80px] pt-[24px] px-8 relative rounded-[8px] shrink-0 w-full">
<div className="aspect-[1920/1080] bg-black overflow-clip relative rounded-[8px] shrink-0 w-full">
<div className="absolute left-1/2 size-[120px] top-1/2 translate-x-[-50%] translate-y-[-50%]">
<div className="absolute contents inset-0">
<img alt="" className="block max-w-none size-full" src={imgGroup} />
</div>
</div>
<div className="absolute bg-gradient-to-t bottom-0 box-border content-stretch flex flex-col from-[rgba(0,0,0,0.8)] gap-[20px] items-center justify-center left-[-0.5px] px-[16px] py-[24px] to-[rgba(0,0,0,0)] w-[1376px]">
<div className="bg-[#333c47] h-[4px] relative rounded-[3.35544e+07px] shrink-0 w-full">
<div className="absolute left-0 size-[12px] top-1/2 translate-y-[-50%]">
<img alt="" className="block max-w-none size-full" src={imgEllipse2} />
</div>
</div>
<div className="content-stretch flex h-[32px] items-center justify-between relative shrink-0 w-full">
<div className="relative shrink-0">
<div className="bg-clip-padding border-0 border-[transparent] border-solid box-border content-stretch flex gap-[8px] items-center relative">
<div className="content-stretch flex gap-[16px] items-center relative shrink-0">
<div className="relative shrink-0 size-[32px]">
<img alt="" className="block max-w-none size-full" src={imgMusicAudioPlay} />
</div>
<div className="content-stretch flex gap-[8px] h-[32px] items-center relative shrink-0 w-[120px]">
<div className="relative rounded-[4px] shrink-0 size-[32px]">
<div className="bg-clip-padding border-0 border-[transparent] border-solid box-border content-stretch flex items-center justify-center relative size-[32px]">
<div className="relative shrink-0 size-[18px]">
<img alt="" className="block max-w-none size-full" src={imgIcon1} />
</div>
</div>
</div>
<div className="basis-0 grow h-[4px] min-h-px min-w-px relative rounded-[3.35544e+07px] shrink-0">
<div className="bg-clip-padding border-0 border-[transparent] border-solid box-border h-[4px] w-full" />
</div>
</div>
<p className="font-['Pretendard:Medium',sans-serif] leading-[19.5px] not-italic relative shrink-0 text-[13px] text-nowrap text-white whitespace-pre">
0:00 / 12:26
</p>
</div>
</div>
</div>
<div className="relative shrink-0">
<div className="bg-clip-padding border-0 border-[transparent] border-solid box-border content-stretch flex gap-[12px] items-center relative">
<div className="bg-[#333c47] box-border content-stretch flex gap-[4px] h-[32px] items-center justify-center px-[16px] py-[3px] relative rounded-[6px] shrink-0 w-[112px]">
<div className="relative shrink-0 size-[16px]">
<img alt="" className="block max-w-none size-full" src={imgIcon2} />
</div>
<p className="font-['Pretendard:Medium',sans-serif] leading-[1.5] not-italic relative shrink-0 text-[14px] text-center text-nowrap text-white whitespace-pre">
</p>
</div>
<div className="bg-[#333c47] box-border content-stretch flex gap-[4px] h-[32px] items-center justify-center px-[16px] py-[3px] relative rounded-[6px] shrink-0 w-[112px]">
<p className="font-['Pretendard:Medium',sans-serif] leading-[1.5] not-italic relative shrink-0 text-[14px] text-center text-nowrap text-white whitespace-pre">
</p>
<div className="flex items-center justify-center relative shrink-0">
<div className="flex-none rotate-[180deg] scale-y-[-100%]">
<div className="relative size-[16px]">
<img alt="" className="block max-w-none size-full" src={imgIcon3} />
</div>
</div>
</div>
</div>
<div className="content-stretch flex items-center justify-center relative rounded-[4px] shrink-0 size-[32px]">
<div className="relative shrink-0 size-[18px]">
<img alt="" className="block max-w-none size-full" src={imgIcon4} />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="bg-[#fff9ee] border border-[#ffdd82] border-solid box-border content-stretch flex flex-col h-[55px] items-start pb-px pt-[17px] px-[17px] relative rounded-[8px] shrink-0 w-full">
<ul className="[white-space-collapse:collapse] block font-['Pretendard:Medium',sans-serif] leading-[0] not-italic relative shrink-0 text-[#333c47] text-[14px] text-nowrap">
<li className="ms-[21px]">
<span className="leading-[1.5]"> .</span>
</li>
</ul>
</div>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,8 @@
'use client';
import FigmaSelectedLessonPage from '../../FigmaSelectedLessonPage';
export default function ContinueLessonPage() {
return <FigmaSelectedLessonPage />;
}

View File

@@ -0,0 +1,7 @@
import { redirect } from "next/navigation";
export default function ReviewLessonPage({ params }: { params: { lessonId: string } }) {
redirect(`/${params.lessonId}/review`);
}

View File

@@ -0,0 +1,8 @@
'use client';
import FigmaSelectedLessonPage from '../../FigmaSelectedLessonPage';
export default function StartLessonPage() {
return <FigmaSelectedLessonPage />;
}

View File

@@ -7,10 +7,10 @@ type Props = {
onClose: () => void;
};
const imgImage1 = "http://localhost:3845/assets/89fda8e949171025b1232bae70fc9d442e4e70c8.png";
const imgContainer = "http://localhost:3845/assets/d04df6bb7fe1bd29946d04be9442029bca1503b0.png";
const img = "http://localhost:3845/assets/7adf9a5e43b6c9e5f9bee6adfee64e85eabac44a.svg";
const img1 = "http://localhost:3845/assets/9e3b52939dbaa99088659a82db437772ef1ad40e.svg";
const imgImage1 = "/imgs/image-1.png";
const imgContainer = "/imgs/certificate-container.png";
const img = "/imgs/certificate-asset.svg";
const img1 = "/imgs/certificate-asset-1.svg";
export default function FigmaCertificateContent({ onClose }: Props) {
return (

View File

@@ -10,8 +10,8 @@ type Props = {
scoreText?: string;
};
const img = "http://localhost:3845/assets/7adf9a5e43b6c9e5f9bee6adfee64e85eabac44a.svg";
const img1 = "http://localhost:3845/assets/498f1d9877c6da3dadf581f98114a7f15bfc6769.svg";
const img = "/imgs/feedback-asset.svg";
const img1 = "/imgs/feedback-asset-1.svg";
export default function FigmaFeedbackContent({
onClose,