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

@@ -0,0 +1,11 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group">
<g id="Group_2">
<path id="Path" fill-rule="evenodd" clip-rule="evenodd" d="M16 4V4C22.628 4 28 9.372 28 16V16C28 22.628 22.628 28 16 28V28C9.372 28 4 22.628 4 16V16C4 9.372 9.372 4 16 4Z" fill="var(--fill-0, #8C95A1)" stroke="var(--stroke-0, #8C95A1)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Path_2" d="M10.6667 16H21.3333" stroke="var(--stroke-0, white)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Path_3" d="M14.6667 20L10.6667 16L14.6667 12" stroke="var(--stroke-0, white)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<g id="Path_4">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 836 B

View File

@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Icon (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M0.292893 0.292893C0.683417 -0.0976311 1.31658 -0.0976311 1.70711 0.292893L7.70711 6.29289C8.09763 6.68342 8.09763 7.31658 7.70711 7.70711L1.70711 13.7071C1.31658 14.0976 0.683417 14.0976 0.292893 13.7071C-0.0976311 13.3166 -0.0976311 12.6834 0.292893 12.2929L5.58579 7L0.292893 1.70711C-0.0976311 1.31658 -0.0976311 0.683418 0.292893 0.292893Z" fill="var(--fill-0, white)"/>
</svg>

After

Width:  |  Height:  |  Size: 620 B

View File

@@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group">
<path id="Path" d="M12.9684 9.26294L10.0038 12.2275L7.03923 9.26294" stroke="var(--stroke-0, #4C5561)" stroke-width="1.5625" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Path_2" d="M10.0041 3.33439V12.2273" stroke="var(--stroke-0, #4C5561)" stroke-width="1.5625" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Path_3" d="M16.6737 13.7087C16.6737 15.346 15.3464 16.6733 13.7091 16.6733H6.29937C4.66208 16.6733 3.3348 15.346 3.3348 13.7087" stroke="var(--stroke-0, #4C5561)" stroke-width="1.5625" stroke-linecap="round" stroke-linejoin="round"/>
<g id="Rectangle">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 791 B

View File

@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Icon (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M0.317301 0.317301C0.740369 -0.105767 1.4263 -0.105767 1.84937 0.317301L7.58333 6.05127L13.3173 0.317301C13.7404 -0.105767 14.4263 -0.105767 14.8494 0.317301C15.2724 0.740369 15.2724 1.4263 14.8494 1.84937L9.1154 7.58333L14.8494 13.3173C15.2724 13.7404 15.2724 14.4263 14.8494 14.8494C14.4263 15.2724 13.7404 15.2724 13.3173 14.8494L7.58333 9.1154L1.84937 14.8494C1.4263 15.2724 0.740369 15.2724 0.317301 14.8494C-0.105767 14.4263 -0.105767 13.7404 0.317301 13.3173L6.05127 7.58333L0.317301 1.84937C-0.105767 1.4263 -0.105767 0.740369 0.317301 0.317301Z" fill="var(--fill-0, #333C47)"/>
</svg>

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

View File

@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle id="Ellipse 2" cx="6" cy="6" r="6" fill="var(--fill-0, white)"/>
</svg>

After

Width:  |  Height:  |  Size: 250 B

View File

@@ -0,0 +1,4 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id=" Min Width">
</g>
</svg>

After

Width:  |  Height:  |  Size: 202 B

View File

@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Icon (Stroke)" fill-rule="evenodd" clip-rule="evenodd" d="M0.317301 0.317301C0.740369 -0.105767 1.4263 -0.105767 1.84937 0.317301L7.58333 6.05127L13.3173 0.317301C13.7404 -0.105767 14.4263 -0.105767 14.8494 0.317301C15.2724 0.740369 15.2724 1.4263 14.8494 1.84937L9.1154 7.58333L14.8494 13.3173C15.2724 13.7404 15.2724 14.4263 14.8494 14.8494C14.4263 15.2724 13.7404 15.2724 13.3173 14.8494L7.58333 9.1154L1.84937 14.8494C1.4263 15.2724 0.740369 15.2724 0.317301 14.8494C-0.105767 14.4263 -0.105767 13.7404 0.317301 13.3173L6.05127 7.58333L0.317301 1.84937C-0.105767 1.4263 -0.105767 0.740369 0.317301 0.317301Z" fill="var(--fill-0, #333C47)"/>
</svg>

After

Width:  |  Height:  |  Size: 832 B

8
public/imgs/group.svg Normal file
View File

@@ -0,0 +1,8 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group">
<g id="Path">
</g>
<path id="Path_2" fill-rule="evenodd" clip-rule="evenodd" d="M105 60V60C105 84.855 84.855 105 60 105V105C35.145 105 15 84.855 15 60V60C15 35.145 35.145 15 60 15V15C84.855 15 105 35.145 105 60Z" stroke="var(--stroke-0, white)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Path_3" fill-rule="evenodd" clip-rule="evenodd" d="M54.703 45.2904L74.113 56.7703C76.568 58.2203 76.568 61.7754 74.113 63.2254L54.703 74.7054C52.203 76.1854 49.043 74.3804 49.043 71.4754V48.5204C49.043 45.6154 52.203 43.8104 54.703 45.2904V45.2904Z" fill="var(--fill-0, white)" stroke="var(--stroke-0, white)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 896 B

7
public/imgs/icon-1.svg Normal file
View File

@@ -0,0 +1,7 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Icon">
<path id="Vector" d="M8.25 3.52652C8.24985 3.42206 8.21876 3.31998 8.16065 3.23316C8.10254 3.14635 8.02001 3.0787 7.92349 3.03874C7.82697 2.99878 7.72077 2.98831 7.61831 3.00865C7.51584 3.02899 7.42169 3.07923 7.34775 3.15302L4.80975 5.69027C4.7118 5.7888 4.59528 5.86692 4.46692 5.92009C4.33856 5.97326 4.20093 6.00043 4.062 6.00002H2.25C2.05109 6.00002 1.86032 6.07904 1.71967 6.21969C1.57902 6.36034 1.5 6.55111 1.5 6.75002V11.25C1.5 11.4489 1.57902 11.6397 1.71967 11.7804C1.86032 11.921 2.05109 12 2.25 12H4.062C4.20093 11.9996 4.33856 12.0268 4.46692 12.08C4.59528 12.1331 4.7118 12.2112 4.80975 12.3098L7.347 14.8478C7.42095 14.9219 7.51523 14.9723 7.61789 14.9928C7.72056 15.0133 7.82699 15.0028 7.92369 14.9627C8.0204 14.9226 8.10303 14.8548 8.16112 14.7677C8.21921 14.6806 8.25015 14.5782 8.25 14.4735V3.52652Z" stroke="var(--stroke-0, white)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M12 6.75C12.4868 7.39911 12.75 8.18861 12.75 9C12.75 9.81139 12.4868 10.6009 12 11.25" stroke="var(--stroke-0, white)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_3" d="M14.5234 13.7731C15.1502 13.1463 15.6475 12.4021 15.9867 11.5832C16.3259 10.7642 16.5005 9.88648 16.5005 9.00005C16.5005 8.11362 16.3259 7.23587 15.9867 6.41692C15.6475 5.59797 15.1502 4.85385 14.5234 4.22705" stroke="var(--stroke-0, white)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

5
public/imgs/icon-2.svg Normal file
View File

@@ -0,0 +1,5 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Icon">
<path id="Vector" d="M10 12L6 8L10 4" stroke="var(--stroke-0, white)" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 338 B

5
public/imgs/icon-3.svg Normal file
View File

@@ -0,0 +1,5 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Icon">
<path id="Vector" d="M10 12L6 8L10 4" stroke="var(--stroke-0, white)" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 338 B

8
public/imgs/icon-4.svg Normal file
View File

@@ -0,0 +1,8 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Icon">
<path id="Vector" d="M11.25 2.25H15.75V6.75" stroke="var(--stroke-0, white)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M15.75 2.25L10.5 7.5" stroke="var(--stroke-0, white)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_3" d="M2.25 15.75L7.5 10.5" stroke="var(--stroke-0, white)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_4" d="M6.75 15.75H2.25V11.25" stroke="var(--stroke-0, white)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 778 B

5
public/imgs/icon.svg Normal file
View File

@@ -0,0 +1,5 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Icon">
<path id="Vector" d="M9 18L15 12L9 6" stroke="var(--stroke-0, #B1B8C0)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 336 B

BIN
public/imgs/image-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

BIN
public/imgs/image-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

3
public/imgs/line-58.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 16 1" fill="none" xmlns="http://www.w3.org/2000/svg">
<line id="Line 58" y1="0.25" x2="16" y2="0.25" stroke="var(--stroke-0, #B1B8C0)" stroke-width="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 278 B

View File

@@ -0,0 +1,7 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group">
<g id="Path">
</g>
<path id="Path_2" fill-rule="evenodd" clip-rule="evenodd" d="M12.5735 8.27696L22.7652 14.3048C24.0543 15.0662 24.0543 16.9328 22.7652 17.6942L12.5735 23.7221C11.2608 24.4992 9.60156 23.5514 9.60156 22.0261V9.97295C9.60156 8.4476 11.2608 7.49984 12.5735 8.27696V8.27696Z" fill="var(--fill-0, white)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 517 B

8
public/imgs/play.svg Normal file
View File

@@ -0,0 +1,8 @@
<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group">
<g id="Path">
</g>
<path id="Path_2" fill-rule="evenodd" clip-rule="evenodd" d="M14 8V8C14 11.314 11.314 14 8 14V14C4.686 14 2 11.314 2 8V8C2 4.686 4.686 2 8 2V2C11.314 2 14 4.686 14 8Z" fill="var(--fill-0, #B1B8C0)" stroke="var(--stroke-0, #B1B8C0)" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Path_3" fill-rule="evenodd" clip-rule="evenodd" d="M7.29373 6.03871L9.88173 7.56938C10.2091 7.76271 10.2091 8.23671 9.88173 8.43005L7.29373 9.96071C6.9604 10.158 6.53906 9.91738 6.53906 9.53005V6.46938C6.53906 6.08205 6.9604 5.84138 7.29373 6.03871V6.03871Z" fill="var(--fill-0, white)" stroke="var(--stroke-0, white)" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 875 B

BIN
public/imgs/thumb-a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
public/imgs/thumb-b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
public/imgs/thumb-c.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
public/imgs/thumb-d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

View File

@@ -17,6 +17,7 @@ export default function NavBar() {
const [isUserMenuOpen, setIsUserMenuOpen] = useState(false);
const userMenuRef = useRef<HTMLDivElement | null>(null);
const userButtonRef = useRef<HTMLButtonElement | null>(null);
const hideCenterNav = /^\/[^/]+\/review$/.test(pathname);
useEffect(() => {
if (!isUserMenuOpen) return;
@@ -50,21 +51,21 @@ export default function NavBar() {
<MainLogoSvg width={46.703} height={36} />
<span className="text-2xl font-extrabold leading-[1.45] text-white">XR LMS</span>
</Link>
<nav className="flex h-full items-center">
{NAV_ITEMS.map((item) => {
return (
<Link
key={item.href}
href={item.href}
className={[
"px-4 py-2 text-[16px] font-semibold text-white",
].join(" ")}
>
{item.label}
</Link>
);
})}
</nav>
{!hideCenterNav && (
<nav className="flex h-full items-center">
{NAV_ITEMS.map((item) => {
return (
<Link
key={item.href}
href={item.href}
className={["px-4 py-2 text-[16px] font-semibold text-white"].join(" ")}
>
{item.label}
</Link>
);
})}
</nav>
)}
</div>
<div className="relative flex items-center gap-2">
<Link href="/menu/courses" className="px-4 py-2 text-[16px] font-semibold text-white">

View File

@@ -0,0 +1,9 @@
'use client';
import FigmaSelectedLessonPage from "../../menu/courses/lessons/FigmaSelectedLessonPage";
export default function SimpleReviewPage() {
return <FigmaSelectedLessonPage />;
}

View File

@@ -39,7 +39,7 @@ export default function Footer() {
<img
src="/imgs/talk.png"
alt="talk"
className="self-end ml-auto mr-[40px] mb-[40px]"
className="self-end ml-auto mr-[40px] mb-[0px]"
/>
</div>
</div>

View File

@@ -0,0 +1,17 @@
'use client';
import { usePathname } from "next/navigation";
import Footer from "./Footer";
const HIDE_FOOTER_PREFIXES = ["/pages"];
export default function FooterVisibility() {
const pathname = usePathname();
const shouldHide = HIDE_FOOTER_PREFIXES.some(
(prefix) => pathname === prefix || pathname.startsWith(prefix + "/")
);
if (shouldHide) return null;
return <Footer />;
}

View File

@@ -3,11 +3,12 @@
import { usePathname } from "next/navigation";
import NavBar from "../NavBar";
const HIDE_HEADER_PREFIXES = ["/login", "/register", "/reset-password", "/find-id"];
const HIDE_HEADER_PREFIXES = ["/login", "/register", "/reset-password", "/find-id", "/pages"];
export default function HeaderVisibility() {
const pathname = usePathname();
const shouldHide = HIDE_HEADER_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(prefix + "/"));
const shouldHide =
HIDE_HEADER_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(prefix + "/"));
if (shouldHide) return null;
return <NavBar />;
}

View File

@@ -1,58 +1,153 @@
'use client';
import { useMemo, useState } from 'react';
import ChevronDownSvg from '../svgs/chevrondownsvg';
// 피그마 선택 컴포넌트의 구조/스타일(타이포/여백/색상)을 반영한 리스트 UI
// - 프로젝트는 Tailwind v4(@import "tailwindcss")를 사용하므로 클래스 그대로 적용
// - 헤더/푸터는 레이아웃에서 처리되므로 본 페이지에는 포함하지 않음
// - 카드 구성: 섬네일(rounded 8px) + 상태 태그 + 제목 + 메타(재생 아이콘 + 텍스트)
const imgPlay = '/imgs/play.svg'; // public/imgs/play.svg
const imgThumbA = '/imgs/thumb-a.png'; // public/imgs/thumb-a.png
const imgThumbB = '/imgs/thumb-b.png'; // public/imgs/thumb-b.png
const imgThumbC = '/imgs/thumb-c.png'; // public/imgs/thumb-c.png
const imgThumbD = '/imgs/thumb-d.png'; // public/imgs/thumb-d.png
function ColorfulTag({ text }: { text: string }) {
return (
<div className="bg-[#e5f5ec] box-border flex h-[20px] items-center justify-center px-[4px] rounded-[4px]">
<p className="font-['Pretendard:SemiBold',sans-serif] text-[#0c9d61] text-[13px] leading-[1.4]">{text}</p>
</div>
);
}
type Course = { id: string; title: string; image: string; inProgress?: boolean };
export default function CourseListPage() {
const courses = [
{
id: "p1",
title: "원자로 운전 및 계통",
description:
"원자로 운전 원리와 주요 계통의 구조 및 기능을 이해하고, 실제 운전 상황을 가상 환경에서 체험합니다.",
},
{
id: "p2",
title: "확률론",
description:
"확률과 통계의 핵심 개념을 직관적으로 이해하고 문제 해결력을 기릅니다.",
},
{
id: "p3",
title: "부서간 협업",
description:
"협업 절차, 기록 기준, 리스크 관리까지 실제 사례 기반으로 배우는 협업 가이드.",
},
{
id: "p4",
title: "방사선의 이해",
description:
"방사선 안전 기준과 보호 장비 선택법을 배우는 실무형 과정.",
},
const ITEMS_PER_PAGE = 20;
const [page, setPage] = useState(1);
const base: Omit<Course, 'id'>[] = [
{ title: '원자로 운전 및 계통', image: imgThumbA, inProgress: true },
{ title: '핵연료', image: imgThumbB },
{ title: '방사선 안전', image: imgThumbC },
{ title: '방사선 폐기물', image: imgThumbD },
{ title: '원자로 운전 및 계통', image: imgThumbA },
{ title: '핵연료', image: imgThumbB },
{ title: '방사선 안전', image: imgThumbC },
];
const courses: Course[] = Array.from({ length: 28 }, (_, i) => {
const item = base[i % base.length];
return {
id: `p${i + 1}`,
title: item.title,
image: item.image,
inProgress: item.inProgress ?? (i % 7 === 0),
};
});
const totalPages = Math.ceil(courses.length / ITEMS_PER_PAGE);
const pagedCourses = useMemo(
() => courses.slice((page - 1) * ITEMS_PER_PAGE, page * ITEMS_PER_PAGE),
[courses, page]
);
return (
<main className="flex w-full flex-col">
<div className="flex h-[100px] items-center px-8">
<h1 className="text-[24px] font-bold leading-[1.5] text-white"> </h1>
<main className="flex w-full flex-col items-center">
{/* 상단 타이틀 영역 */}
<div className="flex h-[100px] w-full max-w-[1440px] items-center px-8">
<h1 className="text-[24px] font-bold leading-normal text-[#1b2027]"> </h1>
</div>
<section className="px-8 pb-16">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
{courses.map((c) => (
<article
key={c.id}
className="rounded-xl border border-[#ecf0ff] bg-white p-4 shadow-[0_2px_8px_rgba(0,0,0,0.02)]"
>
<h2 className="truncate text-[18px] font-bold leading-[1.5] text-[#1b2027]">{c.title}</h2>
<p className="mt-1 line-clamp-3 text-[14px] leading-[1.5] text-[#4c5561]">{c.description}</p>
<div className="mt-3">
<button
type="button"
className="h-9 rounded-md border border-[#dee1e6] px-3 text-[14px] font-medium leading-[1.5] text-[#4c5561] hover:bg-[#f9fafb]"
>
</button>
</div>
</article>
))}
{/* 콘텐츠 래퍼: Figma 기준 1440 컨테이너, 내부 1376 그리드 폭 */}
<section className="w-full max-w-[1440px] px-8 pt-8 pb-20">
{/* 상단 카운트/정렬 영역 */}
<div className="flex items-center justify-between">
<p className="text-[15px] font-medium leading-normal text-[#333c47]">
<span className="text-[#384fbf]">{courses.length}</span>
</p>
<div className="h-[40px] w-[114px]" />
</div>
{/* 카드 그리드(고정 5열, gap 32px) */}
<div className="mt-4 flex flex-col items-center">
<div className="w-[1376px] grid grid-cols-5 gap-[32px]">
{pagedCourses.map((c) => (
<article
key={c.id}
className="flex h-[260px] w-[249.6px] flex-col gap-[16px] rounded-[8px] bg-white"
>
{/* 섬네일 */}
<div className="relative h-[166.4px] w-full overflow-clip rounded-[8px]">
<img
src={c.image}
alt=""
className="absolute inset-0 size-full object-cover"
/>
</div>
{/* 본문 텍스트 블록 */}
<div className="flex w-full flex-col gap-[4px]">
<div className="flex flex-col gap-[4px]">
{c.inProgress && <ColorfulTag text="수강 중" />}
<h2 className="text-[18px] font-semibold leading-normal text-[#333c47]">
{c.title}
</h2>
</div>
<div className="flex items-center gap-[4px]">
<img src={imgPlay} alt="" className="size-[16px]" />
<p className="text-[13px] font-medium leading-[1.4] text-[#8c95a1]">
VOD · 6 · 4 20
</p>
</div>
</div>
</article>
))}
</div>
</div>
{/* 페이지네이션 (피그마 스타일 반영) */}
<div className="mt-8 flex items-center justify-center gap-[8px]">
{/* Prev */}
<button
type="button"
onClick={() => setPage((p) => Math.max(1, p - 1))}
aria-label="이전 페이지"
className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40"
disabled={page === 1}
>
<ChevronDownSvg width={14.8} height={14.8} className="rotate-90" />
</button>
{/* Numbers */}
{Array.from({ length: totalPages }, (_, i) => i + 1).map((n) => {
const active = n === page;
return (
<button
key={n}
type="button"
onClick={() => setPage(n)}
aria-current={active ? 'page' : undefined}
className={[
'flex items-center justify-center rounded-[1000px] size-[32px]',
active ? 'bg-[#ecf0ff]' : 'bg-white',
].join(' ')}
>
<span className="text-[16px] leading-[1.4] text-[#333c47]">{n}</span>
</button>
);
})}
{/* Next */}
<button
type="button"
onClick={() => setPage((p) => Math.min(totalPages, p + 1))}
aria-label="다음 페이지"
className="flex items-center justify-center rounded-[1000px] p-[8.615px] size-[32px] text-[#333c47] disabled:opacity-40"
disabled={page === totalPages}
>
<ChevronDownSvg width={14.8} height={14.8} className="-rotate-90" />
</button>
</div>
</section>
</main>

View File

@@ -2,7 +2,7 @@ import type { Metadata } from "next";
import "./globals.css";
import { pretendard } from "./fonts";
import HeaderVisibility from "./components/HeaderVisibility";
import Footer from "./components/Footer";
import FooterVisibility from "./components/FooterVisibility";
export const metadata: Metadata = {
title: "XRLMS",
@@ -19,7 +19,7 @@ export default function RootLayout({
<main className="flex-1 min-h-0">
{children}
</main>
<Footer />
<FooterVisibility />
</body>
</html>
);

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,

69
src/app/pages/page.tsx Normal file
View File

@@ -0,0 +1,69 @@
import Link from "next/link";
type RouteItem = { label: string; href: string };
const STATIC_ROUTES: RouteItem[] = [
{ label: "홈", href: "/" },
{ label: "교육 과정 목록", href: "/course-list" },
{ label: "학습 자료실 목록", href: "/resources" },
{ label: "공지사항 목록", href: "/notices" },
{ label: "내 강좌실 - 강좌 목록", href: "/menu/courses" },
{ label: "내 강좌실 - 학습 결과", href: "/menu/results" },
{ label: "내 정보 수정", href: "/menu/account" },
{ label: "로그인", href: "/login" },
{ label: "회원가입", href: "/register" },
{ label: "아이디 찾기", href: "/find-id" },
{ label: "비밀번호 재설정", href: "/reset-password" },
];
// 예시가 필요한 동적 라우트
const DYNAMIC_EXAMPLES: RouteItem[] = [
{ label: "공지사항 상세(예시)", href: "/notices/1" },
{ label: "자료실 상세(예시)", href: "/resources/1" },
{ label: "강좌 상세(예시)", href: "/menu/courses/abc123" },
{ label: "레슨 시작(예시)", href: "/menu/courses/lessons/c1l1/start" },
{ label: "레슨 이어서(예시)", href: "/menu/courses/lessons/c1l1/continue" },
{ label: "레슨 리뷰(새 경로 예시)", href: "/c1l1/review" },
];
export default function AllPages() {
return (
<main className="mx-auto max-w-[960px] p-8">
<h1 className="mb-6 text-[24px] font-bold leading-[1.5] text-[#1b2027]">
</h1>
<section className="mb-10">
<h2 className="mb-3 text-[18px] font-semibold leading-[1.5] text-[#333c47]">
/
</h2>
<ul className="list-disc pl-6">
{STATIC_ROUTES.map((r) => (
<li key={r.href} className="mb-1">
<Link href={r.href} className="text-[#1f2b91] underline">
{r.label}
</Link>
</li>
))}
</ul>
</section>
<section>
<h2 className="mb-3 text-[18px] font-semibold leading-[1.5] text-[#333c47]">
( )
</h2>
<ul className="list-disc pl-6">
{DYNAMIC_EXAMPLES.map((r) => (
<li key={r.href} className="mb-1">
<Link href={r.href} className="text-[#1f2b91] underline">
{r.label}
</Link>
</li>
))}
</ul>
</section>
</main>
);
}

View File

@@ -1,10 +1,12 @@
import type { ReactElement } from "react";
export default function BackCircleSvg(
{
width = 32,
height = 32,
className = '',
}: { width?: number | string; height?: number | string; className?: string }
): JSX.Element {
): ReactElement {
return (
<svg
xmlns="http://www.w3.org/2000/svg"

View File

@@ -1,10 +1,12 @@
import type { ReactElement } from "react";
export default function ChevronDownSvg(
{
width = 24,
height = 24,
className = '',
}: { width?: number | string; height?: number | string; className?: string }
): JSX.Element {
): ReactElement {
return (
<svg
xmlns="http://www.w3.org/2000/svg"

View File

@@ -1,10 +1,12 @@
import type { ReactElement } from "react";
export default function PaperClipSvg(
{
width = 16,
height = 16,
className = '',
}: { width?: number | string; height?: number | string; className?: string }
): JSX.Element {
): ReactElement {
return (
<svg
xmlns="http://www.w3.org/2000/svg"