[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>
This commit is contained in:
Mina Choi 2026-09-30 14:58:29 +09:00
parent 8219d3f45e
commit fad20e8958
20 changed files with 116 additions and 62 deletions

View File

@ -502,7 +502,15 @@
"simple", "simple",
"magazine", "magazine",
"retro", "retro",
"paper" "paper",
"round",
"cinema",
"bigtype",
"boutique",
"graphic",
"coral",
"minimal",
"pine"
], ],
"sections": [ "sections": [
{ {
@ -629,7 +637,15 @@
"simple", "simple",
"magazine", "magazine",
"retro", "retro",
"paper" "paper",
"round",
"cinema",
"bigtype",
"boutique",
"graphic",
"coral",
"minimal",
"pine"
], ],
"sections": [ "sections": [
{ {
@ -754,7 +770,15 @@
"defaultTemplate": "simple", "defaultTemplate": "simple",
"templates": [ "templates": [
"simple", "simple",
"magazine" "magazine",
"round",
"cinema",
"bigtype",
"boutique",
"graphic",
"coral",
"minimal",
"pine"
], ],
"sections": [ "sections": [
{ {

View File

@ -30,7 +30,7 @@ type PageId = 'home' | 'area' | 'stay' | 'story';
const PAGE_HEAD: Record<Exclude<PageId, 'home'>, {title: string; note: string}> = { const PAGE_HEAD: Record<Exclude<PageId, 'home'>, {title: string; note: string}> = {
area: {title: '지역', note: '대문에서 걸어 닿는 자리와, 이 도시가 남긴 이야기입니다.'}, area: {title: '지역', note: '대문에서 걸어 닿는 자리와, 이 도시가 남긴 이야기입니다.'},
stay: {title: '이용안내', note: '객실 상세와 요금, 예약하는 방법입니다.'}, stay: {title: '이용안내', note: '상세 안내와 요금, 예약하는 방법입니다.'},
story: {title: '이야기', note: '사장님이 남기는 글과 다녀가신 분들의 후기, 그리고 엽서 한 장입니다.'}, story: {title: '이야기', note: '사장님이 남기는 글과 다녀가신 분들의 후기, 그리고 엽서 한 장입니다.'},
}; };

View File

@ -1,9 +1,10 @@
import {useState} from 'react'; import {useState} from 'react';
import {factText, sanitizeUnits} from '@o2o/shared'; import {factText, sanitizeUnits, PlaceCategory} from '@o2o/shared';
import {useSite} from '@site/lib/site-context'; import {useSite} from '@site/lib/site-context';
import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive'; import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive';
import {Car} from '../paper/Car'; import {Car} from '../paper/Car';
import {BOOK_EVENT} from '../paper/Rooms'; import {BOOK_EVENT} from '../paper/Rooms';
import {unitWord} from '../kit/unitWord';
import {Sheet} from '../paper/Sheet'; import {Sheet} from '../paper/Sheet';
import {Idx} from './SectionHead'; import {Idx} from './SectionHead';
@ -32,6 +33,7 @@ function specRows(unit: UnitView, facts: Parameters<typeof factText>[0]) {
export function Rooms() { export function Rooms() {
const payload = useSite(); const payload = useSite();
const lodging = payload.place.category === PlaceCategory.LODGING;
const units = unitViews(payload); const units = unitViews(payload);
const spec = unitSpec(payload); const spec = unitSpec(payload);
const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit])); const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit]));
@ -78,7 +80,7 @@ export function Rooms() {
const [main, sub] = splitName(unit.name); const [main, sub] = splitName(unit.name);
return ( return (
<section key={unit.unitId} id={`unit-${unit.slug}`}> <section key={unit.unitId} id={`unit-${unit.slug}`}>
<Idx title={main} aside={`Room ${letter(i)}${sub ? ` · ${sub}` : ''}`} /> <Idx title={main} aside={`${unitWord(payload.place.category)} ${letter(i)}${sub ? ` · ${sub}` : ''}`} />
{unit.images.length > 0 && ( {unit.images.length > 0 && (
<Car <Car
label={`${main} 사진`} label={`${main} 사진`}
@ -104,14 +106,16 @@ export function Rooms() {
<span>{main} 자세히</span> <span>{main} 자세히</span>
<span>+</span> <span>+</span>
</button> </button>
<button {lodging && (
type="button" <button
className="line line--ink" type="button"
onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))} className="line line--ink"
> onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}
<span>{main} 예약 요청</span> >
<span>→</span> <span>{main} 예약 요청</span>
</button> <span>→</span>
</button>
)}
</section> </section>
); );
})} })}

View File

@ -30,7 +30,7 @@ const PAGE_HEAD: Record<Exclude<PageId, 'home'>, {en: string; title: string; not
stay: { stay: {
en: 'Stay', en: 'Stay',
title: '이용안내 · 예약', title: '이용안내 · 예약',
note: '객실 상세와 요금, 예약하는 방법입니다.', note: '상세 안내와 요금, 예약하는 방법입니다.',
}, },
story: { story: {
en: 'Story', en: 'Story',
@ -131,6 +131,7 @@ function useTabs() {
export function Frame({children}: {children: ReactNode}) { export function Frame({children}: {children: ReactNode}) {
const payload = useSite(); const payload = useSite();
const {place, site} = payload; const {place, site} = payload;
const lodging = place.category === PlaceCategory.LODGING;
const tabs = useTabs(); const tabs = useTabs();
const page = usePage(); const page = usePage();
const solid = useSolid(page); const solid = useSolid(page);
@ -245,7 +246,7 @@ export function Frame({children}: {children: ReactNode}) {
onClick={() => setMenuOpen(false)} onClick={() => setMenuOpen(false)}
> >
<span className="b-menu-no">{pad2(i + 1)}</span> <span className="b-menu-no">{pad2(i + 1)}</span>
<span className="b-menu-en">{PAGE_EN[tab.page]}</span> <span className="b-menu-en">{tab.page === 'stay' && !lodging ? 'Guide' : PAGE_EN[tab.page]}</span>
<span className="b-menu-ko">{tab.label}</span> <span className="b-menu-ko">{tab.label}</span>
</a> </a>
))} ))}
@ -254,7 +255,7 @@ export function Frame({children}: {children: ReactNode}) {
{(Object.keys(PAGE_HEAD) as Exclude<PageId, 'home'>[]).map((id) => ( {(Object.keys(PAGE_HEAD) as Exclude<PageId, 'home'>[]).map((id) => (
<div key={id} data-pg={id}> <div key={id} data-pg={id}>
<section className="b-phead"> <section className="b-phead">
<p className="b-phead-en">{PAGE_HEAD[id].en}</p> <p className="b-phead-en">{id === 'stay' && !lodging ? 'Guide' : PAGE_HEAD[id].en}</p>
<p className="b-phead-ko"> <p className="b-phead-ko">
{id === 'area' ? (place.addressLocality?.replace(/(시|군)$/, '') ?? PAGE_HEAD.area.title) : PAGE_HEAD[id].title} {id === 'area' ? (place.addressLocality?.replace(/(시|군)$/, '') ?? PAGE_HEAD.area.title) : PAGE_HEAD[id].title}
</p> </p>

View File

@ -31,7 +31,7 @@ export function Blog({full}: {full?: boolean}) {
return ( return (
<section className="b-sec" id={full ? 'blog' : undefined} aria-labelledby={full ? 'blog-heading' : undefined}> <section className="b-sec" id={full ? 'blog' : undefined} aria-labelledby={full ? 'blog-heading' : undefined}>
<Sh en="Journal" id={full ? 'blog-heading' : undefined} lead="사장님이 남기는 숙소 이야기입니다."> <Sh en="Journal" id={full ? 'blog-heading' : undefined} lead="사장님이 직접 남기는 소식입니다.">
미니 블로그 미니 블로그
</Sh> </Sh>
<div className="b-wrap"> <div className="b-wrap">

View File

@ -1,9 +1,10 @@
import {useState} from 'react'; import {useState} from 'react';
import {factText, sanitizeUnits} from '@o2o/shared'; import {factText, sanitizeUnits, PlaceCategory} from '@o2o/shared';
import {useSite} from '@site/lib/site-context'; import {useSite} from '@site/lib/site-context';
import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive'; import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive';
import {Car} from '../paper/Car'; import {Car} from '../paper/Car';
import {BOOK_EVENT} from '../paper/Rooms'; import {BOOK_EVENT} from '../paper/Rooms';
import {unitWord} from '../kit/unitWord';
import {Sheet} from '../paper/Sheet'; import {Sheet} from '../paper/Sheet';
function splitName(name: string): [string, string | undefined] { function splitName(name: string): [string, string | undefined] {
@ -31,6 +32,7 @@ const book = () => window.dispatchEvent(new Event(BOOK_EVENT));
export function Rooms() { export function Rooms() {
const payload = useSite(); const payload = useSite();
const lodging = payload.place.category === PlaceCategory.LODGING;
const units = unitViews(payload); const units = unitViews(payload);
const spec = unitSpec(payload); const spec = unitSpec(payload);
const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit])); const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit]));
@ -43,7 +45,7 @@ export function Rooms() {
<div data-pg="home"> <div data-pg="home">
<section id="units" aria-labelledby="units-heading"> <section id="units" aria-labelledby="units-heading">
<div className="wrap"> <div className="wrap">
<p className="label">ROOMS</p> <p className="label">{unitWord(payload.place.category).toUpperCase()}</p>
<h2 id="units-heading">{sectionName(payload, spec.path, `${spec.label} 안내`)}</h2> <h2 id="units-heading">{sectionName(payload, spec.path, `${spec.label} 안내`)}</h2>
</div> </div>
<div className="wrap"> <div className="wrap">
@ -77,7 +79,7 @@ export function Rooms() {
return ( return (
<section key={unit.unitId} className="unit" id={`unit-${unit.slug}`}> <section key={unit.unitId} className="unit" id={`unit-${unit.slug}`}>
<div className="wrap"> <div className="wrap">
<p className="label">ROOM {String(i + 1).padStart(2, '0')}</p> <p className="label">{unitWord(payload.place.category).toUpperCase()} {String(i + 1).padStart(2, '0')}</p>
<h2> <h2>
{main} {sub && <span className="cnt">{sub}</span>} {main} {sub && <span className="cnt">{sub}</span>}
</h2> </h2>
@ -109,9 +111,11 @@ export function Rooms() {
<button type="button" className="btn ghost" onClick={() => setOpen(unit)}> <button type="button" className="btn ghost" onClick={() => setOpen(unit)}>
{main} 자세히 {main} 자세히
</button> </button>
<button type="button" className="btn" onClick={book}> {lodging && (
{main} 예약 요청 <button type="button" className="btn" onClick={book}>
</button> {main} 예약 요청
</button>
)}
</div> </div>
</div> </div>
</section> </section>

View File

@ -36,7 +36,7 @@ const PAGE_HEAD: Record<Exclude<PageId, 'home'>, {label: string; title: string;
stay: { stay: {
label: 'STAY', label: 'STAY',
title: '이용안내 · 예약', title: '이용안내 · 예약',
note: '객실 상세와 요금, 예약하는 방법입니다.', note: '상세 안내와 요금, 예약하는 방법입니다.',
}, },
story: { story: {
label: 'STORY', label: 'STORY',

View File

@ -30,7 +30,7 @@ function Blog({full}: {full?: boolean}) {
<section className="wrap" id={full ? 'blog' : undefined}> <section className="wrap" id={full ? 'blog' : undefined}>
<p className="label">JOURNAL</p> <p className="label">JOURNAL</p>
<h2>미니 블로그</h2> <h2>미니 블로그</h2>
<p className="lead">사장님이 남기는 숙소 이야기입니다.</p> <p className="lead">사장님이 직접 남기는 소식입니다.</p>
<div className="posts" data-blog={full ? 'full' : 'home'}> <div className="posts" data-blog={full ? 'full' : 'home'}>
{shown.map((item) => ( {shown.map((item) => (
<Post key={item.postId} publishedAt={item.publishedAt} body={item.body} /> <Post key={item.postId} publishedAt={item.publishedAt} body={item.body} />

View File

@ -1,9 +1,10 @@
import {useState} from 'react'; import {useState} from 'react';
import {factText, sanitizeUnits} from '@o2o/shared'; import {factText, sanitizeUnits, PlaceCategory} from '@o2o/shared';
import {useSite} from '@site/lib/site-context'; import {useSite} from '@site/lib/site-context';
import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive'; import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive';
import {Car} from '../paper/Car'; import {Car} from '../paper/Car';
import {BOOK_EVENT} from '../paper/Rooms'; import {BOOK_EVENT} from '../paper/Rooms';
import {unitWord} from '../kit/unitWord';
import {Sheet} from '../paper/Sheet'; import {Sheet} from '../paper/Sheet';
function splitName(name: string): [string, string | undefined] { function splitName(name: string): [string, string | undefined] {
@ -32,6 +33,7 @@ const book = () => window.dispatchEvent(new Event(BOOK_EVENT));
export function Rooms() { export function Rooms() {
const payload = useSite(); const payload = useSite();
const lodging = payload.place.category === PlaceCategory.LODGING;
const units = unitViews(payload); const units = unitViews(payload);
const spec = unitSpec(payload); const spec = unitSpec(payload);
const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit])); const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit]));
@ -45,7 +47,7 @@ export function Rooms() {
<div data-pg="home"> <div data-pg="home">
<section id="units" aria-labelledby="units-heading"> <section id="units" aria-labelledby="units-heading">
<div className="wrap"> <div className="wrap">
<p className="label">ROOMS</p> <p className="label">{unitWord(payload.place.category).toUpperCase()}</p>
<h2 id="units-heading">{sectionName(payload, spec.path, `${spec.label} 안내`)}</h2> <h2 id="units-heading">{sectionName(payload, spec.path, `${spec.label} 안내`)}</h2>
<div className="rgrid"> <div className="rgrid">
{units.slice(0, HOME_UNITS).map((unit) => ( {units.slice(0, HOME_UNITS).map((unit) => (
@ -69,7 +71,7 @@ export function Rooms() {
return ( return (
<section key={unit.unitId} className="unit" id={`unit-${unit.slug}`}> <section key={unit.unitId} className="unit" id={`unit-${unit.slug}`}>
<div className="wrap"> <div className="wrap">
<p className="label">ROOM {String(i + 1).padStart(2, '0')}</p> <p className="label">{unitWord(payload.place.category).toUpperCase()} {String(i + 1).padStart(2, '0')}</p>
<h2> <h2>
{main} {sub && <span className="cnt">{sub}</span>} {main} {sub && <span className="cnt">{sub}</span>}
</h2> </h2>
@ -101,9 +103,11 @@ export function Rooms() {
<button type="button" className="btn ghost" onClick={() => setOpen(unit)}> <button type="button" className="btn ghost" onClick={() => setOpen(unit)}>
{main} 자세히 {main} 자세히
</button> </button>
<button type="button" className="btn" onClick={book}> {lodging && (
{main} 예약 요청 <button type="button" className="btn" onClick={book}>
</button> {main} 예약 요청
</button>
)}
</div> </div>
</div> </div>
</section> </section>

View File

@ -36,7 +36,7 @@ const PAGE_HEAD: Record<Exclude<PageId, 'home'>, {kicker: string; title: string;
stay: { stay: {
kicker: 'Reservation', kicker: 'Reservation',
title: '이용안내 · 예약', title: '이용안내 · 예약',
note: '객실 상세와 요금, 예약하는 방법입니다.', note: '상세 안내와 요금, 예약하는 방법입니다.',
}, },
story: { story: {
kicker: 'Story', kicker: 'Story',

View File

@ -1,9 +1,10 @@
import {useState} from 'react'; import {useState} from 'react';
import {factText, sanitizeUnits} from '@o2o/shared'; import {factText, sanitizeUnits, PlaceCategory} from '@o2o/shared';
import {useSite} from '@site/lib/site-context'; import {useSite} from '@site/lib/site-context';
import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive'; import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive';
import {Car} from '../paper/Car'; import {Car} from '../paper/Car';
import {BOOK_EVENT} from '../paper/Rooms'; import {BOOK_EVENT} from '../paper/Rooms';
import {unitWord} from '../kit/unitWord';
import {Sheet} from '../paper/Sheet'; import {Sheet} from '../paper/Sheet';
function splitName(name: string): [string, string | undefined] { function splitName(name: string): [string, string | undefined] {
@ -30,6 +31,7 @@ const HOME_MAX = 4;
export function Rooms() { export function Rooms() {
const payload = useSite(); const payload = useSite();
const lodging = payload.place.category === PlaceCategory.LODGING;
const units = unitViews(payload); const units = unitViews(payload);
const spec = unitSpec(payload); const spec = unitSpec(payload);
const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit])); const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit]));
@ -42,7 +44,7 @@ export function Rooms() {
<> <>
<div data-pg="home"> <div data-pg="home">
<section className="sec" id="units" aria-labelledby="units-heading"> <section className="sec" id="units" aria-labelledby="units-heading">
<p className="kicker">Room View</p> <p className="kicker">{lodging ? 'Room View' : unitWord(payload.place.category)}</p>
<h2 id="units-heading">{sectionName(payload, spec.path, `${spec.label} 안내`)}</h2> <h2 id="units-heading">{sectionName(payload, spec.path, `${spec.label} 안내`)}</h2>
<div className="rooms"> <div className="rooms">
{units.slice(0, HOME_MAX).map((unit, i) => ( {units.slice(0, HOME_MAX).map((unit, i) => (
@ -74,7 +76,7 @@ export function Rooms() {
return ( return (
<section key={unit.unitId} className="sec" id={`unit-${unit.slug}`}> <section key={unit.unitId} className="sec" id={`unit-${unit.slug}`}>
<p className="kicker"> <p className="kicker">
Room {String(i + 1).padStart(2, '0')} {unitWord(payload.place.category)} {String(i + 1).padStart(2, '0')}
</p> </p>
<h2> <h2>
{main} {sub && <span className="sub">{sub}</span>} {main} {sub && <span className="sub">{sub}</span>}
@ -105,9 +107,11 @@ export function Rooms() {
<button type="button" className="btn ghost" onClick={() => setOpen(unit)}> <button type="button" className="btn ghost" onClick={() => setOpen(unit)}>
자세히 자세히
</button> </button>
<button type="button" className="btn" onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}> {lodging && (
예약 요청 <button type="button" className="btn" onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}>
</button> 예약 요청
</button>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@ -29,7 +29,7 @@ type PageId = 'home' | 'area' | 'stay' | 'story';
const PAGE_HEAD: Record<Exclude<PageId, 'home'>, {title: string; note: string}> = { const PAGE_HEAD: Record<Exclude<PageId, 'home'>, {title: string; note: string}> = {
area: {title: '지역 소개', note: '대문에서 걸어 닿는 자리와, 이 도시가 남긴 이야기입니다.'}, area: {title: '지역 소개', note: '대문에서 걸어 닿는 자리와, 이 도시가 남긴 이야기입니다.'},
stay: {title: '이용안내', note: '객실 상세와 요금, 예약하는 방법입니다.'}, stay: {title: '이용안내', note: '상세 안내와 요금, 예약하는 방법입니다.'},
story: {title: '이야기', note: '사장님이 남기는 글과 다녀가신 분들의 후기, 그리고 엽서 한 장입니다.'}, story: {title: '이야기', note: '사장님이 남기는 글과 다녀가신 분들의 후기, 그리고 엽서 한 장입니다.'},
}; };

View File

@ -1,5 +1,5 @@
import {useState} from 'react'; import {useState} from 'react';
import {factText, sanitizeUnits} from '@o2o/shared'; import {factText, sanitizeUnits, PlaceCategory} from '@o2o/shared';
import {useSite} from '@site/lib/site-context'; import {useSite} from '@site/lib/site-context';
import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive'; import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive';
import {Car} from '../paper/Car'; import {Car} from '../paper/Car';
@ -60,6 +60,7 @@ function UnitSheet({unit, onClose}: {unit: UnitView | null; onClose: () => void}
export function Rooms() { export function Rooms() {
const payload = useSite(); const payload = useSite();
const lodging = payload.place.category === PlaceCategory.LODGING;
const units = unitViews(payload); const units = unitViews(payload);
const spec = unitSpec(payload); const spec = unitSpec(payload);
const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit])); const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit]));
@ -136,9 +137,11 @@ export function Rooms() {
<button type="button" className="more" onClick={() => setOpen(unit)}> <button type="button" className="more" onClick={() => setOpen(unit)}>
{main} 자세히 {main} 자세히
</button> </button>
<button type="button" className="cta" onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}> {lodging && (
{main} 예약 요청 <button type="button" className="cta" onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}>
</button> {main} 예약 요청
</button>
)}
</div> </div>
</div> </div>
</section> </section>

View File

@ -36,7 +36,7 @@ const PAGE_HEAD: Record<Exclude<PageId, 'home'>, {kicker: string; title: string;
stay: { stay: {
kicker: 'Reservation', kicker: 'Reservation',
title: '이용안내 · 예약', title: '이용안내 · 예약',
note: '객실 상세와 요금, 예약하는 방법입니다.', note: '상세 안내와 요금, 예약하는 방법입니다.',
}, },
story: { story: {
kicker: 'Story', kicker: 'Story',

View File

@ -1,9 +1,10 @@
import {useState} from 'react'; import {useState} from 'react';
import {factText, sanitizeUnits} from '@o2o/shared'; import {factText, sanitizeUnits, PlaceCategory} from '@o2o/shared';
import {useSite} from '@site/lib/site-context'; import {useSite} from '@site/lib/site-context';
import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive'; import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive';
import {Car} from '../paper/Car'; import {Car} from '../paper/Car';
import {BOOK_EVENT} from '../paper/Rooms'; import {BOOK_EVENT} from '../paper/Rooms';
import {unitWord} from '../kit/unitWord';
import {Sheet} from '../paper/Sheet'; import {Sheet} from '../paper/Sheet';
function splitName(name: string): [string, string | undefined] { function splitName(name: string): [string, string | undefined] {
@ -30,6 +31,7 @@ const HOME_MAX = 4;
export function Rooms() { export function Rooms() {
const payload = useSite(); const payload = useSite();
const lodging = payload.place.category === PlaceCategory.LODGING;
const units = unitViews(payload); const units = unitViews(payload);
const spec = unitSpec(payload); const spec = unitSpec(payload);
const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit])); const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit]));
@ -42,7 +44,7 @@ export function Rooms() {
<> <>
<div data-pg="home"> <div data-pg="home">
<section className="sec" id="units" aria-labelledby="units-heading"> <section className="sec" id="units" aria-labelledby="units-heading">
<p className="kicker">Stay</p> <p className="kicker">{lodging ? 'Stay' : unitWord(payload.place.category)}</p>
<h2 id="units-heading">{sectionName(payload, spec.path, `${spec.label} 안내`)}</h2> <h2 id="units-heading">{sectionName(payload, spec.path, `${spec.label} 안내`)}</h2>
<div className="rooms"> <div className="rooms">
{units.slice(0, HOME_MAX).map((unit) => ( {units.slice(0, HOME_MAX).map((unit) => (
@ -71,7 +73,7 @@ export function Rooms() {
return ( return (
<section key={unit.unitId} className="sec" id={`unit-${unit.slug}`}> <section key={unit.unitId} className="sec" id={`unit-${unit.slug}`}>
<p className="kicker"> <p className="kicker">
Room {String(i + 1).padStart(2, '0')} {unitWord(payload.place.category)} {String(i + 1).padStart(2, '0')}
</p> </p>
<h2> <h2>
{main} {sub && <span className="sub">{sub}</span>} {main} {sub && <span className="sub">{sub}</span>}
@ -102,9 +104,11 @@ export function Rooms() {
<button type="button" className="btn ghost" onClick={() => setOpen(unit)}> <button type="button" className="btn ghost" onClick={() => setOpen(unit)}>
자세히 자세히
</button> </button>
<button type="button" className="btn" onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}> {lodging && (
예약 요청 <button type="button" className="btn" onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}>
</button> 예약 요청
</button>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@ -22,7 +22,7 @@ export function Blog({full}: {full?: boolean}) {
<p className="eyebrow">BLOG</p> <p className="eyebrow">BLOG</p>
<h2>미니 블로그</h2> <h2>미니 블로그</h2>
<p className="note" style={{margin: '-8px 0 14px'}}> <p className="note" style={{margin: '-8px 0 14px'}}>
사장님이 남기는 숙소 이야기입니다. 사장님이 직접 남기는 소식입니다.
</p> </p>
<div data-blog={full ? 'full' : 'home'}> <div data-blog={full ? 'full' : 'home'}>
{shown.map((item) => ( {shown.map((item) => (

View File

@ -36,7 +36,7 @@ const PAGE_HEAD: Record<Exclude<PageId, 'home'>, {kicker: string; title: string;
stay: { stay: {
kicker: '이용안내', kicker: '이용안내',
title: '이용안내 · 예약', title: '이용안내 · 예약',
note: '객실 상세와 요금, 예약하는 방법입니다.', note: '상세 안내와 요금, 예약하는 방법입니다.',
}, },
story: { story: {
kicker: '이야기', kicker: '이야기',

View File

@ -1,5 +1,5 @@
import {useState} from 'react'; import {useState} from 'react';
import {factText, sanitizeUnits} from '@o2o/shared'; import {factText, sanitizeUnits, PlaceCategory} from '@o2o/shared';
import {useSite} from '@site/lib/site-context'; import {useSite} from '@site/lib/site-context';
import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive'; import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive';
import {Car} from '../paper/Car'; import {Car} from '../paper/Car';
@ -30,6 +30,7 @@ const HOME_MAX = 4;
export function Rooms() { export function Rooms() {
const payload = useSite(); const payload = useSite();
const lodging = payload.place.category === PlaceCategory.LODGING;
const units = unitViews(payload); const units = unitViews(payload);
const spec = unitSpec(payload); const spec = unitSpec(payload);
const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit])); const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit]));
@ -102,9 +103,11 @@ export function Rooms() {
<button type="button" className="btn ghost" onClick={() => setOpen(unit)}> <button type="button" className="btn ghost" onClick={() => setOpen(unit)}>
자세히 자세히
</button> </button>
<button type="button" className="btn" onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}> {lodging && (
예약 요청 <button type="button" className="btn" onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}>
</button> 예약 요청
</button>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@ -36,7 +36,7 @@ const PAGE_HEAD: Record<Exclude<PageId, 'home'>, {kicker: string; title: string;
stay: { stay: {
kicker: '이용안내', kicker: '이용안내',
title: '이용안내 · 예약', title: '이용안내 · 예약',
note: '객실 상세와 요금, 예약하는 방법입니다.', note: '상세 안내와 요금, 예약하는 방법입니다.',
}, },
story: { story: {
kicker: '이야기', kicker: '이야기',

View File

@ -1,5 +1,5 @@
import {useState} from 'react'; import {useState} from 'react';
import {factText, sanitizeUnits} from '@o2o/shared'; import {factText, sanitizeUnits, PlaceCategory} from '@o2o/shared';
import {useSite} from '@site/lib/site-context'; import {useSite} from '@site/lib/site-context';
import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive'; import {sectionName, unitSpec, unitViews, type UnitView} from '@site/lib/derive';
import {Car} from '../paper/Car'; import {Car} from '../paper/Car';
@ -30,6 +30,7 @@ const HOME_MAX = 4;
export function Rooms() { export function Rooms() {
const payload = useSite(); const payload = useSite();
const lodging = payload.place.category === PlaceCategory.LODGING;
const units = unitViews(payload); const units = unitViews(payload);
const spec = unitSpec(payload); const spec = unitSpec(payload);
const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit])); const raw = new Map(sanitizeUnits(payload.units).map((unit) => [unit.unitId, unit]));
@ -102,9 +103,11 @@ export function Rooms() {
<button type="button" className="btn ghost" onClick={() => setOpen(unit)}> <button type="button" className="btn ghost" onClick={() => setOpen(unit)}>
자세히 자세히
</button> </button>
<button type="button" className="btn" onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}> {lodging && (
예약 요청 <button type="button" className="btn" onClick={() => window.dispatchEvent(new Event(BOOK_EVENT))}>
</button> 예약 요청
</button>
)}
</div> </div>
</div> </div>
</div> </div>