o2o-site-AEO/solution/site/src/layouts/cinema/Intro.tsx
Mina Choi fad20e8958 [feat] solution/site,shared: 새 템플릿 8종 업종 확장 — 앞 커밋에서 빠진 본체
앞 커밋(18a2874)에 템플릿 등록과 레이아웃 변경이 빠지고 다른 작업의 새 파일
(services/activity_feed.py, 어디서도 아직 import 하지 않음)이 대신 들어갔다.
같은 작업 폴더를 다른 세션이 함께 쓰고 있었다.

- templates.json: cafe · restaurant · clinic 에 라운드~솔숲 8종
- layouts/*/Rooms.tsx: 객실별 '예약 요청' 버튼은 숙박일 때만, 영문 라벨은 unitWord
- layouts/*/Frame.tsx · Intro.tsx: 이용안내 머리말 · 미니 블로그 설명을 업종 중립으로

eslint·tsc 통과, vitest 123 passed, 33개 사이트 굽기 성공

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 14:58:29 +09:00

104 lines
3.2 KiB
TypeScript

import {useSite} from '@site/lib/site-context';
import {heroFacts, sectionBody} from '@site/lib/derive';
function dotDate(iso: string): string {
const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(iso);
return m ? `${m[1]}. ${m[2]}. ${m[3]}` : iso;
}
function Post({publishedAt, body}: {publishedAt: string; body: string}) {
return (
<article className="post">
<time dateTime={publishedAt}>{dotDate(publishedAt)}</time>
<p>{body}</p>
</article>
);
}
const HOME_MAX = 3;
const FULL_FIRST = 5;
function Blog({full}: {full?: boolean}) {
const payload = useSite();
const posts = [...(payload.posts ?? [])].sort((a, b) => b.publishedAt.localeCompare(a.publishedAt));
if (posts.length === 0) return null;
const shown = posts.slice(0, full ? FULL_FIRST : HOME_MAX);
const older = full ? posts.slice(FULL_FIRST) : [];
const more = !full && posts.length > HOME_MAX;
return (
<section className="wrap" id={full ? 'blog' : undefined}>
<p className="label">JOURNAL</p>
<h2>미니 블로그</h2>
<p className="lead">사장님이 직접 남기는 소식입니다.</p>
<div className="posts" data-blog={full ? 'full' : 'home'}>
{shown.map((item) => (
<Post key={item.postId} publishedAt={item.publishedAt} body={item.body} />
))}
</div>
{more && (
<a href="#/story" className="link more-link">
이야기에서 지난 소식 더 보기
</a>
)}
{older.length > 0 && (
<details className="fold">
<summary className="link">지난 소식 {older.length}개</summary>
<div className="posts">
{older.map((item) => (
<Post key={item.postId} publishedAt={item.publishedAt} body={item.body} />
))}
</div>
</details>
)}
</section>
);
}
export function Intro() {
const payload = useSite();
const {narrative, place} = payload;
const own = sectionBody(payload, 'intro');
const about = own.length > 0 ? own : narrative.about;
const facts = heroFacts(payload);
return (
<>
<div data-pg="story">
<Blog full />
</div>
<div data-pg="home">
{about.length > 0 && (
<section className="wrap" id="about" aria-labelledby="about-heading">
<p className="label">ABOUT</p>
<h2 id="about-heading">{place.name} 소개</h2>
{narrative.summary && <p className="lead strong">{narrative.summary}</p>}
<p className="lead">{about[0]}</p>
{about.length > 1 && (
<details className="fold">
<summary className="link">더 읽기</summary>
{about.slice(1).map((paragraph, i) => (
<p key={i} className="lead">
{paragraph}
</p>
))}
</details>
)}
{facts.length > 0 && (
<div className="facts">
{facts.map((row) => (
<div key={row.key ?? row.label}>
<small>{row.label}</small>
<b>{row.value}</b>
</div>
))}
</div>
)}
</section>
)}
<Blog />
</div>
</>
);
}