[fix] solution/site: 고택 — 날씨를 첫 화면 바로 아래로 · 예약 요청 창은 달력부터 펼친다

섹션 순서가 업종 기본(날씨 맨 뒤)을 따라가서 stay2 와 달리 날씨가 맨 아래로 갔고,
예약 요청 창은 '날짜 · 시간 선택' 을 접어 두어 손님이 한 번 더 눌러야 달력이 보였다.

- paper/Hero: 날씨 섹션이 켜져 있으면 첫 화면 바로 뒤에 그린다(레이아웃의 weather 자리는 비움)
- paper/BookingForm: 날짜·시간 칸을 처음부터 펼친다
- app.test: 날씨를 섹션 목록 맨 뒤에 둬도 첫 화면 바로 다음에 나오는지

site tsc·eslint·vitest 107 passed, 로컬 발행(stayyyy v3)에서 순서와 예약 창 확인

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mina Choi 2026-09-28 17:05:39 +09:00
parent 0a0ae4e054
commit 7f6f16f307
4 changed files with 54 additions and 33 deletions

View File

@ -38,3 +38,16 @@ it('첫 화면 문구가 따로 있어도 한 줄 요약이 화면에 나온다'
expect(renderToStaticMarkup(<App payload={payload} />)).toContain('검색에 쓰는 한 줄 요약'); expect(renderToStaticMarkup(<App payload={payload} />)).toContain('검색에 쓰는 한 줄 요약');
} }
}); });
it('고택은 섹션 순서와 상관없이 날씨를 첫 화면 바로 아래에 둔다', () => {
const payload = withTemplate('paper');
const weather = payload.theme.sections.find((section) => section.id === 'weather');
if (weather) weather.enabled = true;
payload.theme.sections = [...payload.theme.sections.filter((s) => s.id !== 'weather'), ...(weather ? [weather] : [])];
const html = renderToStaticMarkup(<App payload={payload} />);
const hero = html.indexOf('class="hero"');
const brief = html.indexOf('class="wbrief"');
expect(hero).toBeGreaterThan(-1);
expect(brief).toBeGreaterThan(hero);
expect(html.slice(hero, brief)).not.toContain('class="sec');
});

View File

@ -17,7 +17,6 @@ import {SectionHead as PaperSectionHead} from './paper/SectionHead';
import {Story as PaperStory} from './paper/Story'; import {Story as PaperStory} from './paper/Story';
import {StoryTail as PaperStoryTail} from './paper/StoryTail'; import {StoryTail as PaperStoryTail} from './paper/StoryTail';
import {Video as PaperVideo} from './paper/Video'; import {Video as PaperVideo} from './paper/Video';
import {Weather as PaperWeather} from './paper/Weather';
const Nothing = () => null; const Nothing = () => null;
@ -29,7 +28,7 @@ export const LAYOUTS: Record<LayoutId, Layout> = {
SectionHead: PaperSectionHead, SectionHead: PaperSectionHead,
sections: { sections: {
hero: PaperHero, hero: PaperHero,
weather: PaperWeather, weather: Nothing,
intro: PaperIntro, intro: PaperIntro,
blog: Nothing, blog: Nothing,
rooms: PaperRooms, rooms: PaperRooms,

View File

@ -30,7 +30,7 @@ export function BookingForm() {
const slots = useMemo(() => buildArrivalSlots(checkIn), [checkIn]); const slots = useMemo(() => buildArrivalSlots(checkIn), [checkIn]);
const [today, setToday] = useState<Date | null>(null); const [today, setToday] = useState<Date | null>(null);
const [offset, setOffset] = useState(0); const [offset, setOffset] = useState(0);
const [openStep, setOpenStep] = useState(false); const [openStep, setOpenStep] = useState(true);
const [dateIso, setDateIso] = useState<string | null>(null); const [dateIso, setDateIso] = useState<string | null>(null);
const [slot, setSlot] = useState<string | null>(null); const [slot, setSlot] = useState<string | null>(null);
const [unitId, setUnitId] = useState<string | null>(units[0]?.unitId ?? null); const [unitId, setUnitId] = useState<string | null>(units[0]?.unitId ?? null);

View File

@ -1,5 +1,7 @@
import {HeroCatchphrase} from '@site/sections/HeroCatchphrase'; import {HeroCatchphrase} from '@site/sections/HeroCatchphrase';
import {useSite} from '@site/lib/site-context'; import {useSite} from '@site/lib/site-context';
import {isSectionEnabled} from '@site/lib/derive';
import {Weather} from './Weather';
import {Car} from './Car'; import {Car} from './Car';
const MAX_SLIDES = 5; const MAX_SLIDES = 5;
@ -14,35 +16,42 @@ export function Hero() {
const fixed = narrative.tagline ?? narrative.heroSubline; const fixed = narrative.tagline ?? narrative.heroSubline;
return ( return (
<section className="hero" id="top" data-pg="home"> <>
<Car <section className="hero" id="top" data-pg="home">
label={`${place.name} 사진`} <Car
autoplay={5000} label={`${place.name} 사진`}
dots autoplay={5000}
style={{height: '100%'}} dots
slides={slides.map((image, i) => ( style={{height: '100%'}}
<img slides={slides.map((image, i) => (
key={image.mediaId} <img
src={image.url} key={image.mediaId}
alt={image.alt} src={image.url}
fetchPriority={i === 0 ? 'high' : 'low'} alt={image.alt}
loading={i === 0 ? undefined : 'lazy'} fetchPriority={i === 0 ? 'high' : 'low'}
decoding="async" loading={i === 0 ? undefined : 'lazy'}
style={{height: '100%'}} decoding="async"
/> style={{height: '100%'}}
))} />
/> ))}
<div className="veil" /> />
<div className="herocopy"> <div className="veil" />
{(place.addressLocality ?? place.addressRegion) && ( <div className="herocopy">
<p className="eyebrow">{place.addressLocality ?? place.addressRegion}</p> {(place.addressLocality ?? place.addressRegion) && (
)} <p className="eyebrow">{place.addressLocality ?? place.addressRegion}</p>
<h1 className="mj">{place.name}</h1> )}
{fixed && <p className="tagline">{fixed}</p>} <h1 className="mj">{place.name}</h1>
<p className="cp"> {fixed && <p className="tagline">{fixed}</p>}
<HeroCatchphrase /> <p className="cp">
</p> <HeroCatchphrase />
</div> </p>
</section> </div>
</section>
{isSectionEnabled(payload, 'weather') && (
<div data-editor-id="weather" style={{display: 'contents'}}>
<Weather />
</div>
)}
</>
); );
} }