diff --git a/frontend/src/features/auth/index.ts b/frontend/src/features/auth/index.ts index 25e8975f..2f08b46f 100644 --- a/frontend/src/features/auth/index.ts +++ b/frontend/src/features/auth/index.ts @@ -1,5 +1,6 @@ export { AuthProvider } from './model/AuthProvider' export { useAuth } from './model/useAuth' +export { useGetStartedTarget } from './model/useGetStartedTarget' export { useLogout } from './model/useLogout' export type { AuthContextValue, AuthStatus } from './model/AuthContext' export { GithubLoginButton } from './ui/GithubLoginButton' diff --git a/frontend/src/features/auth/model/useGetStartedTarget.ts b/frontend/src/features/auth/model/useGetStartedTarget.ts new file mode 100644 index 00000000..24c42ed0 --- /dev/null +++ b/frontend/src/features/auth/model/useGetStartedTarget.ts @@ -0,0 +1,9 @@ +import { useAuth } from './useAuth' + +// "Get Started" CTA 목적지. 헤더(SiteNav)와 동일한 분기: +// 로그인 상태면 워크스페이스, 아니면 로그인 페이지. +// (loading 중에도 로그인으로 — 로그인 페이지가 인증 사용자를 워크스페이스로 보낸다.) +export function useGetStartedTarget(): string { + const { status } = useAuth() + return status === 'authenticated' ? '/workspace' : '/login' +} diff --git a/frontend/src/features/interview/ui/live/InterviewStage.tsx b/frontend/src/features/interview/ui/live/InterviewStage.tsx index 3492b799..317a1cdd 100644 --- a/frontend/src/features/interview/ui/live/InterviewStage.tsx +++ b/frontend/src/features/interview/ui/live/InterviewStage.tsx @@ -73,9 +73,11 @@ export function InterviewStage({ className="absolute inset-0 bg-cover bg-center" style={{ backgroundImage: `url(${BG})` }} /> + {/* 배경 사진이 보이도록 옅은 스크림만. 텍스트 가독성은 헤더·질문 카드· + 컴포저가 각자 배경(반투명+blur / solid)으로 확보한다. */}
{/* 진행도 바 */} diff --git a/frontend/src/widgets/home-cta/ui/HomeCta.tsx b/frontend/src/widgets/home-cta/ui/HomeCta.tsx index 953fca4f..226afca2 100644 --- a/frontend/src/widgets/home-cta/ui/HomeCta.tsx +++ b/frontend/src/widgets/home-cta/ui/HomeCta.tsx @@ -1,4 +1,8 @@ +import { Link } from 'react-router-dom' +import { useGetStartedTarget } from '@/features/auth' + export function HomeCta() { + const getStartedTo = useGetStartedTarget() return (
@@ -31,8 +35,8 @@ export function HomeCta() { 지금 GitHub 계정만 연결하면, 30초 안에 첫 모의면접이 시작됩니다.

- Get Started @@ -42,7 +46,7 @@ export function HomeCta() { > → - +
diff --git a/frontend/src/widgets/home-hero/ui/ScreenContent.tsx b/frontend/src/widgets/home-hero/ui/ScreenContent.tsx index 0d50d1fb..b2d37f94 100644 --- a/frontend/src/widgets/home-hero/ui/ScreenContent.tsx +++ b/frontend/src/widgets/home-hero/ui/ScreenContent.tsx @@ -1,3 +1,5 @@ +import { Link } from 'react-router-dom' +import { useGetStartedTarget } from '@/features/auth' import { useTypewriter } from '@/shared/hooks' const TYPED_TEXT = 'Stack Up' @@ -7,6 +9,7 @@ export function ScreenContent() { startDelayMs: 850, stepMs: 130, }) + const getStartedTo = useGetStartedTarget() return (
@@ -42,8 +45,8 @@ export function ScreenContent() {
- Get Started @@ -53,7 +56,7 @@ export function ScreenContent() { > → - +
) diff --git a/frontend/src/widgets/home-services/ui/HomeServices.tsx b/frontend/src/widgets/home-services/ui/HomeServices.tsx index 25b58b1a..e64274e6 100644 --- a/frontend/src/widgets/home-services/ui/HomeServices.tsx +++ b/frontend/src/widgets/home-services/ui/HomeServices.tsx @@ -1,11 +1,12 @@ -import { Link } from 'react-router-dom' +import { useState } from 'react' +import { Link, useNavigate } from 'react-router-dom' +import { Modal } from '@/shared/ui' type ServiceCard = { tag: string title: string image: string - to: string -} +} & ({ to: string } | { modal: 'role' }) const services: ServiceCard[] = [ { @@ -18,7 +19,8 @@ const services: ServiceCard[] = [ tag: 'Free Plan', title: '직무 기술 면접\nRole-based Interview', image: '/second-section-backend-interview.avif', - to: '/practice/role', + // 직무는 프론트/백엔드를 모달에서 고른 뒤 해당 연습으로 이동. + modal: 'role', }, { tag: 'Free Plan', @@ -28,7 +30,61 @@ const services: ServiceCard[] = [ }, ] +const ROLE_OPTIONS = [ + { track: 'frontend', label: '프론트엔드', desc: 'HTML·CSS·JS·React·브라우저' }, + { track: 'backend', label: '백엔드', desc: 'OS·네트워크·DB·자바·스프링' }, +] as const + +const cardClass = + 'group relative block rounded-2xl overflow-hidden aspect-[3/4] bg-sage-800 text-left' + +function CardInner({ card }: { card: ServiceCard }) { + return ( + <> + {card.title} +
+ + + {card.tag} + + +
+

+ {card.title} +

+ + → + +
+ + ) +} + export function HomeServices() { + const navigate = useNavigate() + const [roleOpen, setRoleOpen] = useState(false) + + const goRole = (track: (typeof ROLE_OPTIONS)[number]['track']) => { + setRoleOpen(false) + navigate(`/practice/${track}`) + } + return (
@@ -40,47 +96,43 @@ export function HomeServices() {
- {services.map((s) => ( - - {s.title} -
- - - {s.tag} - + {services.map((s) => + 'to' in s ? ( + + + + ) : ( + + ), + )} +
+
-
-

- {s.title} -

- - → - -
- + setRoleOpen(false)} title="직무 기술 면접"> +

+ 연습할 직무를 선택하면 해당 분야 질문이 무작위로 출제됩니다. +

+
+ {ROLE_OPTIONS.map((opt) => ( + ))}
-
+
) } diff --git a/frontend/src/widgets/site-footer/ui/SiteFooter.tsx b/frontend/src/widgets/site-footer/ui/SiteFooter.tsx index 4bf93371..8e534aa7 100644 --- a/frontend/src/widgets/site-footer/ui/SiteFooter.tsx +++ b/frontend/src/widgets/site-footer/ui/SiteFooter.tsx @@ -1,4 +1,5 @@ import { Link } from 'react-router-dom' +import { useGetStartedTarget } from '@/features/auth' // 단순 뷰 섹션 widgets 에선 굳이 나누지 않는게 좋다고 판단했습니다. // 상수, 메세지 등 마찬가지 @@ -33,6 +34,7 @@ const columns: { title: string; links: FooterLink[] }[] = [ ] export function SiteFooter() { + const getStartedTo = useGetStartedTarget() return (