157 lines
5.3 KiB
TypeScript
157 lines
5.3 KiB
TypeScript
/* =============================================================================
|
|
* A01_Home_UI_Page.ts
|
|
* 로그인 전 01: 홈 (소개 히어로 + 최신 소식 + 주요 기능)
|
|
*
|
|
* 제약 준수:
|
|
* - 모든 문구는 ui_template_locale.ts 참조 (하드코딩 금지).
|
|
* - 색상/간격은 A01_Home_UI_Style.css + theme.css 변수만 사용.
|
|
* - 공통 컴포넌트(createButton/createCard/createTag) 우선 사용.
|
|
* - 이벤트 핸들러는 on[페이지]_[기능]_[액션] 명명.
|
|
* ========================================================================== */
|
|
|
|
import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale";
|
|
import { createButton, createCard, createTag } from "@ui/ui_template_elements";
|
|
import { navigateTo } from "../A00_Common/router";
|
|
import { ROUTES } from "@config/config_frontend";
|
|
import "./A01_Home_UI_Style.css";
|
|
|
|
/** locale 헬퍼 */
|
|
function L(key: keyof typeof ui_locales): string {
|
|
return ui_locales[key][currentLanguageIndex];
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Mock 데이터 (백엔드 연결 전) — 나중에 GET /api/a01/news로 교체
|
|
* -------------------------------------------------------------------------- */
|
|
interface NewsItem {
|
|
id: number;
|
|
title: string;
|
|
date: string;
|
|
}
|
|
|
|
const MOCK_NEWS: NewsItem[] = [
|
|
{ id: 1, title: "v0.1 프론트엔드 프로토타입 공개", date: "2026-07-05" },
|
|
{ id: 2, title: "3D 지형 뷰어 Three.js 엔진 확정", date: "2026-07-04" },
|
|
{ id: 3, title: "임도 설계 워크플로우 6단계 정의 완료", date: "2026-07-01" },
|
|
];
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 이벤트 핸들러
|
|
* -------------------------------------------------------------------------- */
|
|
function onA01_Home_GetStarted_Click(): void {
|
|
navigateTo(ROUTES.A07_REGISTER);
|
|
}
|
|
|
|
function onA01_Home_Explore_Click(): void {
|
|
navigateTo(ROUTES.A02_PROG_DETAIL);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 섹션 빌더
|
|
* -------------------------------------------------------------------------- */
|
|
function buildHero(): HTMLElement {
|
|
const hero = document.createElement("section");
|
|
hero.className = "a01-hero";
|
|
|
|
const inner = document.createElement("div");
|
|
inner.className = "a01-hero__inner";
|
|
|
|
const title = document.createElement("h1");
|
|
title.className = "a01-hero__title";
|
|
title.textContent = L("A01_Home_Title");
|
|
|
|
const subtitle = document.createElement("p");
|
|
subtitle.className = "a01-hero__subtitle";
|
|
subtitle.textContent = L("A01_Home_Hero_Subtitle");
|
|
|
|
const ctas = document.createElement("div");
|
|
ctas.className = "a01-hero__ctas";
|
|
ctas.append(
|
|
createButton({
|
|
label: L("A01_Home_Hero_CtaPrimary"),
|
|
variant: "filled",
|
|
onClick: onA01_Home_GetStarted_Click,
|
|
}),
|
|
createButton({
|
|
label: L("A01_Home_Hero_CtaSecondary"),
|
|
variant: "ghost",
|
|
onClick: onA01_Home_Explore_Click,
|
|
}),
|
|
);
|
|
|
|
inner.append(title, subtitle, ctas);
|
|
hero.append(inner);
|
|
return hero;
|
|
}
|
|
|
|
function buildNews(): HTMLElement {
|
|
const section = document.createElement("section");
|
|
section.className = "a01-section";
|
|
|
|
const heading = document.createElement("h2");
|
|
heading.className = "a01-section__title";
|
|
heading.textContent = L("A01_Home_News_SectionTitle");
|
|
|
|
const list = document.createElement("div");
|
|
list.className = "a01-news-list";
|
|
|
|
for (const item of MOCK_NEWS) {
|
|
const row = document.createElement("div");
|
|
row.className = "a01-news-row";
|
|
|
|
const tag = createTag(L("A01_Home_News_Tag"), "accent");
|
|
const titleEl = document.createElement("span");
|
|
titleEl.className = "a01-news-row__title";
|
|
titleEl.textContent = item.title;
|
|
const dateEl = document.createElement("span");
|
|
dateEl.className = "a01-news-row__date";
|
|
dateEl.textContent = item.date;
|
|
|
|
row.append(tag, titleEl, dateEl);
|
|
list.append(row);
|
|
}
|
|
|
|
section.append(heading, list);
|
|
return section;
|
|
}
|
|
|
|
function buildFeatures(): HTMLElement {
|
|
const section = document.createElement("section");
|
|
section.className = "a01-section";
|
|
|
|
const heading = document.createElement("h2");
|
|
heading.className = "a01-section__title";
|
|
heading.textContent = L("A01_Home_Features_SectionTitle");
|
|
|
|
const grid = document.createElement("div");
|
|
grid.className = "a01-feature-grid";
|
|
|
|
const features: [keyof typeof ui_locales, keyof typeof ui_locales][] = [
|
|
["A01_Home_Feature1_Title", "A01_Home_Feature1_Desc"],
|
|
["A01_Home_Feature2_Title", "A01_Home_Feature2_Desc"],
|
|
["A01_Home_Feature3_Title", "A01_Home_Feature3_Desc"],
|
|
];
|
|
|
|
for (const [titleKey, descKey] of features) {
|
|
const desc = document.createElement("p");
|
|
desc.className = "a01-feature__desc";
|
|
desc.textContent = L(descKey);
|
|
const card = createCard({ title: L(titleKey), body: [desc] });
|
|
card.classList.add("a01-feature-card");
|
|
grid.append(card);
|
|
}
|
|
|
|
section.append(heading, grid);
|
|
return section;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 페이지 진입점
|
|
* -------------------------------------------------------------------------- */
|
|
export function renderA01Home(root: HTMLElement): void {
|
|
const page = document.createElement("div");
|
|
page.className = "a01-home";
|
|
page.append(buildHero(), buildNews(), buildFeatures());
|
|
root.append(page);
|
|
}
|