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
67 changes: 67 additions & 0 deletions frontend/app/(non-login)/(landing)/_components/HeroSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"use client";

import React from "react";
import Image from "next/image";
import Link from "next/link";
import styles from "../page.module.scss";
import { IMAGES } from "@/constants/images";
import { ROUTES } from "@/constants/routes";
import { MoveDown } from "lucide-react";

interface HeroSectionProps {
introSectionRef?: React.RefObject<HTMLElement | null>;
}

export default function HeroSection({ introSectionRef }: HeroSectionProps) {
const handleScrollToIntro = () => {
if (introSectionRef?.current) {
introSectionRef.current.scrollIntoView({
behavior: "smooth",
block: "start",
});
}
};
return (
<section className={styles.heroSection}>
<div className={styles.heroInner}>
<div className={styles.heroLeft}>
<div className={styles.textWrapper}>
<Image
src={IMAGES.logo4}
alt="ClassLog Logo"
width={500}
height={120}
className={styles.logo}
/>
<h2>당신의 강의를 더 스마트하게</h2>
<p>수업 녹음, 실시간 소통, AI 기반 퀴즈 생성을 통해</p>
<p>강의 준비부터 피드백까지 한 번에 해결하세요.</p>
</div>
<div className={styles.heroCtas}>
<Link href={ROUTES.login} className={styles.primaryCta}>
시작하기
<span className={styles.arrow} aria-hidden>
</span>
</Link>
</div>
</div>

<div className={styles.introImageWrapper}>
<Image
src={IMAGES.introImage}
alt="소개 이미지"
width={650}
height={300}
className={styles.heroImage}
priority
/>
</div>
</div>

<div className={styles.scrollIndicator} onClick={handleScrollToIntro}>
<MoveDown className={styles.downArrow} size={30} strokeWidth={2.5} />
</div>
</section>
);
}
75 changes: 75 additions & 0 deletions frontend/app/(non-login)/(landing)/_components/IntroSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from "react";
import styles from "../page.module.scss";
import {
MessageCircle,
MessageCircleQuestion,
PencilLine,
Videotape,
} from "lucide-react";

const FEATURES = [
{
icon: <MessageCircle />,
title: "즉시 질문, 즉시 피드백",
description:
"수업 중 궁금한 점은 바로 질문하고 실시간으로 소통할 수 있어요.",
},
{
icon: <MessageCircleQuestion />,
title: "AI 기반 맞춤형 퀴즈",
description:
"강의자료와 녹음을 바탕으로 AI가 자동으로 퀴즈를 만들어요. 복습과 이해도 확인이 더 쉬워집니다.",
},
{
icon: <PencilLine />,
title: "강의자료 업로드 & 수업용 실시간 필기",
description:
"강의 중 자료에 바로 필기하며 핵심 내용을 학생들과 함께 나눌 수 있어요.",
},
{
icon: <Videotape />,
title: "언제든 다시 듣는 수업",
description:
"수업은 자동 녹음되며, 언제든 다시 듣거나 다운로드할 수 있어요.",
},
];

export default function IntroSection({
ref,
}: {
ref: React.RefObject<HTMLElement | null>;
}) {
return (
<section ref={ref} className={styles.introSection}>
<div className={styles.introHeader}>
<h2 className={styles.introTitle}>
What You Can Do
<br />
with ClassLog
</h2>
<div className={styles.introDescription}>
<p className={styles.introSubtitle}>
ClassLog의 핵심 기능 4가지를 소개합니다!
</p>
<p className={styles.introText}>
실시간 질문, AI 기반 퀴즈 생성, 강의자료 업로드 및 필기, 자동 수업
녹음 등 <br />
수업의 전 과정을 하나의 플랫폼에서 관리하고, 학습의 흐름을 놓치지
않도록 도와줍니다.
</p>
</div>
</div>
<div className={styles.featuresContainer}>
{FEATURES.map((feature) => (
<div key={feature.title} className={styles.featureCard}>
<div className={styles.featureIcon}>{feature.icon}</div>
<div className={styles.featureContent}>
<h3 className={styles.featureTitle}>{feature.title}</h3>
<p className={styles.featureDescription}>{feature.description}</p>
</div>
</div>
))}
</div>
</section>
);
}
42 changes: 42 additions & 0 deletions frontend/app/(non-login)/(landing)/_components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"use client";

import Link from "next/link";
import Image from "next/image";
import { useEffect, useState } from "react";
import styles from "../page.module.scss";
import { ROUTES } from "@/constants/routes";
import { IMAGES } from "@/constants/images";

export default function Navbar() {
const [isScrolled, setIsScrolled] = useState(false);

useEffect(() => {
const handleScroll = () => {
const scrollTop = window.scrollY;
setIsScrolled(scrollTop > 50);
};

handleScroll();

window.addEventListener("scroll", handleScroll, { passive: true });

return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);

return (
<nav className={`${styles.navbar} ${isScrolled ? styles.scrolled : ""}`}>
<Image
src={isScrolled ? IMAGES.logo3 : IMAGES.logo5}
alt="logo"
width={200}
height={100}
className={styles.logo}
/>
<Link href={ROUTES.login} className={styles.login}>
Login
</Link>
</nav>
);
}
66 changes: 66 additions & 0 deletions frontend/app/(non-login)/(landing)/_components/RoadMapSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import styles from "../page.module.scss";

const ROAD_MAP = [
{
title: "강사",
steps: [
"클래스 생성",
"클래스별 강의 생성",
"강의자료 업로드",
"강의 시작 (필기 + 질문 뷰어 + 자동 녹음)",
"강의 종료 후 AI 퀴즈 자동 생성 및 배포",
"퀴즈 결과 기반 대시보드 제공",
],
},
{
title: "학생",
steps: [
"클래스 입장",
"강의자료 다운로드",
"실시간 질문 참여",
"녹음 파일 다운로드 및 다시 듣기",
"AI 퀴즈 풀기 + 결과 확인",
],
},
];

export default function RoadMapSection() {
return (
<section className={styles.roadMapSection}>
<div className={styles.roadMapHeader}>
<h2 className={styles.roadMapTitle}>HOW IT WORKS?</h2>
<div className={styles.roadMapDescription}>
<div className={styles.roadMapText}>
ClassLog, 어떻게 활용할 수 있을까요?
<br />
강사와 학생 각각의 흐름에 맞춰 스마트한 학습 경험을 제공합니다.
<br />
수업 전부터 수업 중, 수업 후까지 — 모든 과정을 ClassLog 하나로
완성하세요.
</div>
<div className={styles.roadMapCta}>
<p>
Get to know More <br />
about ClassLog
</p>
</div>
</div>
</div>
<div className={styles.roadMapCards}>
{ROAD_MAP.map((item) => (
<div key={item.title} className={styles.roadMapCard}>
<h3 className={styles.cardTitle}>{item.title}</h3>
<ul className={styles.stepsList}>
{item.steps.map((step, index) => (
<li key={step} className={styles.stepItem}>
<span className={styles.stepNumber}>{index + 1}</span>
<span className={styles.stepText}>{step}</span>
</li>
))}
</ul>
</div>
))}
</div>
</section>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { IMAGES } from "@/constants/images";
import styles from "../page.module.scss";
import { MoveRight } from "lucide-react";
import Image from "next/image";
import { ROUTES } from "@/constants/routes";
import { useRouter } from "next/navigation";

export function StartButtonSection() {
const router = useRouter();
return (
<section className={styles.startButtonSection}>
<Image src={IMAGES.logo5} alt="ClassLog Logo" width={98} height={28} />
<div>
<h2>
지금 바로 ClassLog를
<br />
시작해보세요!
</h2>
<p>
수업의 시작부터 끝까지, 지금 ClassLog와 함께하세요.
<br />
기록하고, 공유하고, 더 깊이 있게 배우는 경험을 제공합니다.
</p>
<button
onClick={() => {
router.push(ROUTES.login);
}}
>
<p>시작하기</p>
<MoveRight />
</button>
</div>
<Image src={IMAGES.logo6} alt="ClassLog Logo" width={293} height={320} />
</section>
);
}
Loading