[fix] solution/site: 흐린 보조 글자 대비 올림 · 예약 달력 기본으로 펼침

여러 섹션의 opacity-55~70 짜리 보조 텍스트가 밝은 배경에서 너무 흐렸다 — 85~100 으로
올림(Carousel 카운터·SectionHead 리드문·SNS 소식·주변 안내 거리·공식 채널 링크).
StayBookingDemo: "날짜·시간 선택" 토글을 없애고 달력을 기본으로 펼쳐 보여준다 —
접어 두면 손님이 그 버튼을 눌러야만 날짜를 볼 수 있었다.
This commit is contained in:
Mina Choi 2026-09-23 13:18:02 +09:00
parent 362c76d6c9
commit b7b8cb856c
8 changed files with 13 additions and 28 deletions

View File

@ -154,7 +154,7 @@ export function Shell({children}: {children: ReactNode}) {
href={link.url} href={link.url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="underline underline-offset-4 opacity-80 transition-opacity hover:opacity-100" className="underline underline-offset-4 opacity-90 transition-opacity hover:opacity-100"
> >
{channelLabel(link)} {channelLabel(link)}
</a> </a>

View File

@ -38,7 +38,7 @@ export function SectionHead({
{/* 설명은 한 줄이다. 없으면 그리지 않는다 — 없는 문구를 지어내지 않는다. */} {/* 설명은 한 줄이다. 없으면 그리지 않는다 — 없는 문구를 지어내지 않는다. */}
{lead && ( {lead && (
<p className="measure text-[length:var(--fs-sm)] leading-relaxed opacity-65">{lead}</p> <p className="measure text-[length:var(--fs-sm)] leading-relaxed opacity-85">{lead}</p>
)} )}
{aside && <div className="text-[length:var(--fs-sm)]">{aside}</div>} {aside && <div className="text-[length:var(--fs-sm)]">{aside}</div>}

View File

@ -257,7 +257,7 @@ export function Carousel({
))} ))}
</ul> </ul>
)} )}
<span className="text-current/80 text-[length:var(--fs-xs)] tabular-nums"> <span className="text-current/90 text-[length:var(--fs-xs)] tabular-nums">
{selected + 1} / {snaps.length} {selected + 1} / {snaps.length}
</span> </span>
</div> </div>

View File

@ -261,7 +261,7 @@ function PlaceList({
{(Number.isFinite(distanceOf(open)) || open.distanceText) && ( {(Number.isFinite(distanceOf(open)) || open.distanceText) && (
<p className="text-[length:var(--fs-sm)] font-semibold opacity-100"> <p className="text-[length:var(--fs-sm)] font-semibold opacity-100">
{walkText(distanceOf(open)) ?? open.distanceText} {walkText(distanceOf(open)) ?? open.distanceText}
{open.distanceText && <span className="ml-1 font-normal opacity-70">{open.distanceText}</span>} {open.distanceText && <span className="ml-1 font-normal opacity-85">{open.distanceText}</span>}
</p> </p>
)} )}
{open.location && ( {open.location && (

View File

@ -60,7 +60,7 @@ export function MobileTabBar() {
{phone && ( {phone && (
<a <a
href={`tel:${phone}`} href={`tel:${phone}`}
className="tap border-line flex flex-1 items-center justify-center gap-1.5 rounded-lg border text-[length:var(--fs-sm)] font-bold" className="tap border-line flex flex-1 items-center justify-center gap-1.5 rounded-lg border px-2 text-[length:var(--fs-sm)] font-bold"
> >
<Phone className="size-4" /> <Phone className="size-4" />
<span>전화</span> <span>전화</span>
@ -72,7 +72,7 @@ export function MobileTabBar() {
<button <button
type="button" type="button"
onClick={() => setBookingOpen(true)} onClick={() => setBookingOpen(true)}
className="tap flex min-w-0 flex-[1.4] items-center justify-center truncate rounded-lg px-2 text-[length:var(--fs-sm)] font-bold" className="tap flex min-w-0 flex-1 items-center justify-center truncate rounded-lg border border-transparent px-2 text-[length:var(--fs-sm)] font-bold"
style={{backgroundColor: 'var(--color-brand)', color: 'var(--tpl-bg, #fff)'}} style={{backgroundColor: 'var(--color-brand)', color: 'var(--tpl-bg, #fff)'}}
> >
예약하기 예약하기
@ -82,7 +82,7 @@ export function MobileTabBar() {
href={booking.url} href={booking.url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="tap flex min-w-0 flex-[1.4] items-center justify-center truncate rounded-lg px-2 text-[length:var(--fs-sm)] font-bold" className="tap flex min-w-0 flex-1 items-center justify-center truncate rounded-lg border border-transparent px-2 text-[length:var(--fs-sm)] font-bold"
style={{backgroundColor: 'var(--color-brand)', color: 'var(--tpl-bg, #fff)'}} style={{backgroundColor: 'var(--color-brand)', color: 'var(--tpl-bg, #fff)'}}
> >
{/* ★ channelLabel() 은 수집된 제목("스테이,머뭄 네이버 플레이스")을 준다 — {/* ★ channelLabel() 은 수집된 제목("스테이,머뭄 네이버 플레이스")을 준다 —

View File

@ -6,9 +6,9 @@ export function SocialPostsSection() {
if (!posts.length) return null; if (!posts.length) return null;
return <section id="social-posts" className="mx-auto w-full max-w-5xl px-6 py-12"> return <section id="social-posts" className="mx-auto w-full max-w-5xl px-6 py-12">
<h2 className="mb-3 text-2xl font-semibold">함께 발행한 소식</h2> <h2 className="mb-3 text-2xl font-semibold">함께 발행한 소식</h2>
<p className="mb-6 text-sm opacity-70">사장님이 승인해 홈페이지와 Threads에 함께 전한 소식입니다.</p> <p className="mb-6 text-sm opacity-85">사장님이 승인해 홈페이지와 Threads에 함께 전한 소식입니다.</p>
<div className="grid gap-4 md:grid-cols-3">{posts.map((post) => <article key={post.postId} className="rounded-xl border border-current/15 p-5"> <div className="grid gap-4 md:grid-cols-3">{posts.map((post) => <article key={post.postId} className="rounded-xl border border-current/15 p-5">
<time dateTime={post.postedAt} className="text-sm opacity-70">{new Date(post.postedAt).toLocaleDateString('sv-SE', {timeZone: 'Asia/Seoul'})} (한국시간)</time> <time dateTime={post.postedAt} className="text-sm opacity-85">{new Date(post.postedAt).toLocaleDateString('sv-SE', {timeZone: 'Asia/Seoul'})} (한국시간)</time>
<p className="my-4 whitespace-pre-wrap break-words">{post.body}</p> <p className="my-4 whitespace-pre-wrap break-words">{post.body}</p>
{post.permalink && <a href={post.permalink} target="_blank" rel="noopener noreferrer" className="text-sm underline underline-offset-4">SNS에 올린 글 보기</a>} {post.permalink && <a href={post.permalink} target="_blank" rel="noopener noreferrer" className="text-sm underline underline-offset-4">SNS에 올린 글 보기</a>}
</article>)}</div> </article>)}</div>

View File

@ -1,6 +1,6 @@
import {useEffect, useMemo, useState} from 'react'; import {useEffect, useMemo, useState} from 'react';
import {BookingRequestSection} from './BookingRequestSection'; import {BookingRequestSection} from './BookingRequestSection';
import {CalendarDays, Check, ChevronLeft, ChevronRight, Clock, Minus, Phone, Plus, RotateCcw} from 'lucide-react'; import {Check, ChevronLeft, ChevronRight, Clock, Minus, Phone, Plus, RotateCcw} from 'lucide-react';
import {factText, sanitizeUnits, selectPublishable, type SitePayload} from '@o2o/shared'; import {factText, sanitizeUnits, selectPublishable, type SitePayload} from '@o2o/shared';
import {useSite} from '@site/lib/site-context'; import {useSite} from '@site/lib/site-context';
import {unitBaseRate} from '@site/seo/jsonld'; import {unitBaseRate} from '@site/seo/jsonld';
@ -155,10 +155,6 @@ export function StayBookingDemo() {
const [unitId, setUnitId] = useState<string | null>(units[0]?.unitId ?? null); const [unitId, setUnitId] = useState<string | null>(units[0]?.unitId ?? null);
const [guests, setGuests] = useState(2); const [guests, setGuests] = useState(2);
const [submitted, setSubmitted] = useState(false); const [submitted, setSubmitted] = useState(false);
/* ★ 달력은 접어 둔다. 3.5화면짜리 섹션의 절반이 달력이었는데, 손님 대부분은 예약 창구
버튼을 누르러 온다 — 날짜를 고르려는 사람만 펼친다. */
const [pickerOpen, setPickerOpen] = useState(false);
const selectedDay = cells.find((cell): cell is DayCell => cell !== null && cell.iso === dateIso) ?? null; const selectedDay = cells.find((cell): cell is DayCell => cell !== null && cell.iso === dateIso) ?? null;
const selectedUnit = units.find((unit) => unit.unitId === unitId) ?? null; const selectedUnit = units.find((unit) => unit.unitId === unitId) ?? null;
const maxGuests = selectedUnit?.maxCapacity ?? 8; const maxGuests = selectedUnit?.maxCapacity ?? 8;
@ -181,24 +177,13 @@ export function StayBookingDemo() {
className="mt-4 overflow-hidden rounded-2xl border border-black/8 lg:mt-6" className="mt-4 overflow-hidden rounded-2xl border border-black/8 lg:mt-6"
style={{backgroundColor: 'var(--color-surface)'}} style={{backgroundColor: 'var(--color-surface)'}}
> >
<button
type="button"
onClick={() => setPickerOpen((value) => !value)}
aria-expanded={pickerOpen}
className="tap flex w-full items-center gap-2 border-b border-black/8 px-4 text-[length:var(--fs-sm)] font-bold sm:px-5"
>
<CalendarDays className="size-4 opacity-100" />
<span className="flex-1 text-left">날짜 · 시간 선택</span>
<span className="opacity-100">{pickerOpen ? '−' : '+'}</span>
</button>
{/* 서버 렌더 · 자바스크립트 꺼짐: 달력 대신 사실만 내보낸다(머리주석). */} {/* 서버 렌더 · 자바스크립트 꺼짐: 달력 대신 사실만 내보낸다(머리주석). */}
{today === null || cursor === null ? ( {today === null || cursor === null ? (
<p className="px-4 py-6 text-[length:var(--fs-xs)] leading-relaxed opacity-100 sm:px-5"> <p className="px-4 py-6 text-[length:var(--fs-xs)] leading-relaxed opacity-100 sm:px-5">
날짜 선택은 브라우저에서 열립니다. 실제 예약 가능 여부와 결제는 아래 예약 창구에서 날짜 선택은 브라우저에서 열립니다. 실제 예약 가능 여부와 결제는 아래 예약 창구에서
확인해 주세요. 확인해 주세요.
</p> </p>
) : !pickerOpen && !submitted ? null : submitted ? ( ) : submitted ? (
<ConfirmPanel <ConfirmPanel
payload={payload} payload={payload}
onReset={() => setSubmitted(false)} onReset={() => setSubmitted(false)}

View File

@ -107,10 +107,10 @@ export function WeatherSection() {
{bandLine && ( {bandLine && (
<p <p
key={bandLine} key={bandLine}
className="w4-note-fade measure flex items-start gap-2.5 text-[length:var(--fs-sm)] leading-relaxed opacity-100" className="w4-note-fade measure flex items-center gap-2.5 text-[length:var(--fs-sm)] leading-relaxed opacity-100"
> >
<span <span
className="border-line mt-0.5 shrink-0 rounded-full border px-2 py-0.5 text-[length:var(--fs-sm)] font-bold" className="border-line shrink-0 rounded-full border px-2 py-0.5 text-[length:var(--fs-sm)] font-bold"
aria-hidden aria-hidden
> >
{band} {band}