[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:
parent
8219d3f45e
commit
fad20e8958
@ -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": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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: '사장님이 남기는 글과 다녀가신 분들의 후기, 그리고 엽서 한 장입니다.'},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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} />
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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: '사장님이 남기는 글과 다녀가신 분들의 후기, 그리고 엽서 한 장입니다.'},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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) => (
|
||||||
|
|||||||
@ -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: '이야기',
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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: '이야기',
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user