From 0add2cd4172b4f0a8884ab9d9eb514b999f3e0a1 Mon Sep 17 00:00:00 2001 From: zio Date: Mon, 13 Jul 2026 00:29:12 +0900 Subject: [PATCH] fix(web): restore public header login + track-tab icons/tooltips, visitor CTA to /tickets/lookup, accent-button white-text sweep - PublicShell: track tabs get icons + title tooltips (right-aligned), login link restored at >=768px - VisitorTrackPage: wayfinding/checkin CTAs point to #guide/#transport//tickets/lookup instead of /login - accent buttons: enforce --color-on-accent (white text) across approval/docs/home/movein/schedule/work/public Co-Authored-By: Claude Opus 4.8 --- .../src/screens/approval/review-details.css | 6 +-- src/frontend/src/screens/docs/docs.css | 8 ++-- src/frontend/src/screens/home/home.css | 14 +++--- src/frontend/src/screens/movein/movein.css | 6 +-- .../src/screens/public/PublicShell.tsx | 48 ++++++++++++++----- .../src/screens/public/VisitorTrackPage.tsx | 18 ++++--- src/frontend/src/screens/public/public.css | 30 ++++++++---- .../src/screens/schedule/calendarView.css | 2 +- src/frontend/src/screens/work/work.css | 12 ++--- 9 files changed, 93 insertions(+), 51 deletions(-) diff --git a/src/frontend/src/screens/approval/review-details.css b/src/frontend/src/screens/approval/review-details.css index 84b0275..ec23d22 100644 --- a/src/frontend/src/screens/approval/review-details.css +++ b/src/frontend/src/screens/approval/review-details.css @@ -420,15 +420,15 @@ } .kx-rev__step--cur .kx-rev__step-no { background: #1f29fc; - color: #fff; + color: var(--color-on-accent); } .kx-rev__step--ok .kx-rev__step-no { background: #10b981; - color: #fff; + color: var(--color-on-accent); } .kx-rev__step--bad .kx-rev__step-no { background: #ef4444; - color: #fff; + color: var(--color-on-accent); } .kx-rev__step--skip { opacity: 0.6; diff --git a/src/frontend/src/screens/docs/docs.css b/src/frontend/src/screens/docs/docs.css index 0eafd58..bddb17b 100644 --- a/src/frontend/src/screens/docs/docs.css +++ b/src/frontend/src/screens/docs/docs.css @@ -143,7 +143,7 @@ .kx-doc__step.is-done .kx-doc__node { background: var(--color-primary-600); border-color: var(--color-primary-600); - color: #fff; + color: var(--color-on-accent); } .kx-doc__step.is-active .kx-doc__node { background: var(--color-white); @@ -354,7 +354,7 @@ .kx-doc__stat { border-radius: var(--radius-lg); background: var(--color-primary-700); - color: #fff; + color: var(--color-on-accent); padding: var(--space-5); } .kx-doc__stat-label { @@ -426,7 +426,7 @@ } .kx-rep__acc.is-open .kx-rep__acc-head { background: var(--color-primary-600); - color: #fff; + color: var(--color-on-accent); } .kx-rep__acc-head h3 { font-size: var(--fs-h3); @@ -592,7 +592,7 @@ transform: translateX(-50%); z-index: 60; background: var(--color-neutral-900); - color: #fff; + color: var(--color-white); padding: 10px 18px; border-radius: var(--radius-lg); font-size: var(--fs-body); diff --git a/src/frontend/src/screens/home/home.css b/src/frontend/src/screens/home/home.css index 01643bf..14c3e25 100644 --- a/src/frontend/src/screens/home/home.css +++ b/src/frontend/src/screens/home/home.css @@ -153,7 +153,7 @@ background: linear-gradient(120deg, var(--color-primary-600), var(--color-ai-accent)); } .kx-home__banner-text h2 { - color: #fff; + color: var(--color-on-accent); font-size: var(--fs-h1); margin: 0 0 8px; } @@ -167,7 +167,7 @@ left: var(--space-8); bottom: var(--space-6); right: 30%; - color: #fff; + color: var(--color-on-accent); } .kx-home__banner-title { font-size: var(--fs-h1); @@ -293,7 +293,7 @@ background: linear-gradient(140deg, var(--color-primary-600), var(--color-ai-accent)); } .kx-poster__fallback-text { - color: #fff; + color: var(--color-on-accent); font-size: var(--fs-h3); font-weight: var(--fw-bold); text-align: center; @@ -539,7 +539,7 @@ } .kx-home__cal-cell.is-today .kx-home__cal-daynum { background: var(--color-primary-600); - color: #fff; + color: var(--color-on-accent); border-radius: var(--radius-pill); padding: 1px 7px; font-weight: var(--fw-bold); @@ -564,7 +564,7 @@ border-radius: 3px; font-size: var(--fs-micro); padding: 0 6px; - color: #fff; + color: var(--color-on-accent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -721,7 +721,7 @@ } .kx-home__count-badge { background: var(--color-primary-600); - color: #fff; + color: var(--color-on-accent); border-radius: var(--radius-pill); min-width: 20px; height: 20px; @@ -885,7 +885,7 @@ } .kx-home__new { background: var(--color-error); - color: #fff; + color: var(--color-on-accent); font-size: var(--fs-nano); font-weight: var(--fw-bold); border-radius: var(--radius-sm); diff --git a/src/frontend/src/screens/movein/movein.css b/src/frontend/src/screens/movein/movein.css index 5064113..aedb1e9 100644 --- a/src/frontend/src/screens/movein/movein.css +++ b/src/frontend/src/screens/movein/movein.css @@ -159,7 +159,7 @@ } .kx-dock__block--booked { background: var(--color-primary-600); - color: #fff; + color: var(--color-on-accent); } .kx-dock__block--priority { background: var(--color-violation-warn-bg); @@ -266,7 +266,7 @@ padding: var(--space-4); border-radius: var(--radius-lg); background: var(--color-primary-700); - color: #fff; + color: var(--color-on-accent); cursor: pointer; border: none; text-align: left; @@ -365,7 +365,7 @@ transform: translateX(-50%); z-index: 60; background: var(--color-neutral-900); - color: #fff; + color: var(--color-white); padding: 10px 18px; border-radius: var(--radius-lg); font-size: var(--fs-body); diff --git a/src/frontend/src/screens/public/PublicShell.tsx b/src/frontend/src/screens/public/PublicShell.tsx index ae1e0e0..7055f2f 100644 --- a/src/frontend/src/screens/public/PublicShell.tsx +++ b/src/frontend/src/screens/public/PublicShell.tsx @@ -3,10 +3,24 @@ * COEX 벤치마크(docs/analysis/coex-website.md): 상단 트랙 스위처 + 유틸을 하나의 상단 바로 통합. * design.md §3B/§3C-0: 3-트랙 스위처(role=tablist·로빙 탭인덱스)·GNB·다국어 토글을 단일 헤더로 흡수. */ -import { useRef, useState, type KeyboardEvent, type ReactNode } from 'react'; +import { + useRef, + useState, + type ComponentType, + type KeyboardEvent, + type ReactNode, + type SVGProps, +} from 'react'; import { useTranslation } from 'react-i18next'; import { Link, useNavigate } from 'react-router-dom'; -import { IconMenu, IconClose, IconSearch } from './publicIcons'; +import { + IconMenu, + IconClose, + IconSearch, + IconPerson, + IconBuyer, + IconFactory, +} from './publicIcons'; import { LanguageSwitcher } from '../../components/ui/LanguageSwitcher'; import { useAuthStore } from '../../store/authStore'; import { usePublicMotion } from './usePublicMotion'; @@ -22,10 +36,17 @@ const GNB = [ /** 3-트랙 진입 레이어 키 (§3C). 관문(SCR-T0)은 미선택 → undefined. */ export type PublicTrack = 'visitor' | 'business' | 'agency'; -const TRACK_TABS: { key: PublicTrack; to: string; i18n: string }[] = [ - { key: 'visitor', to: '/visitor', i18n: 'track.shell.tab.visitor' }, - { key: 'business', to: '/business', i18n: 'track.shell.tab.business' }, - { key: 'agency', to: '/agency', i18n: 'track.shell.tab.agency' }, +type TabIcon = ComponentType>; + +/** + * 3-트랙 진입 탭. 텍스트 대신 선 SVG 아이콘 + 툴팁(title)·aria-label로 의미 전달 + * (아이콘만으로 의미 전달 금지 원칙 → 항상 라벨 텍스트를 접근성 속성에 부여). + * 관람=사람 · 비즈니스=바이어(브리프케이스) · 협력사=시공(공장) 계열. + */ +const TRACK_TABS: { key: PublicTrack; to: string; i18n: string; icon: TabIcon }[] = [ + { key: 'visitor', to: '/visitor', i18n: 'track.shell.tab.visitor', icon: IconPerson }, + { key: 'business', to: '/business', i18n: 'track.shell.tab.business', icon: IconBuyer }, + { key: 'agency', to: '/agency', i18n: 'track.shell.tab.agency', icon: IconFactory }, ]; /** @@ -58,6 +79,8 @@ function TrackTabs({ track, variant }: { track?: PublicTrack; variant: 'bar' | ' > {TRACK_TABS.map((it, i) => { const isActive = it.key === track; + const Icon = it.icon; + const label = t(it.i18n); return ( onKeyDown(e, i)} > - {t(it.i18n)} + + {variant === 'menu' && {label}} ); })} @@ -120,10 +146,6 @@ export function PublicShell({ {brand} - - - -
+
+ +
+ {search && (
diff --git a/src/frontend/src/screens/public/VisitorTrackPage.tsx b/src/frontend/src/screens/public/VisitorTrackPage.tsx index 1fe8207..cf5fe30 100644 --- a/src/frontend/src/screens/public/VisitorTrackPage.tsx +++ b/src/frontend/src/screens/public/VisitorTrackPage.tsx @@ -46,7 +46,8 @@ type Ico = ComponentType>; const AI_TILES: { key: string; icon: Ico; to: string; soon?: boolean }[] = [ { key: 'assistant', icon: IconSparkles, to: '#hero' }, { key: 'recommend', icon: IconTarget, to: '#recommend' }, - { key: 'wayfinding', icon: IconMap, to: '/login' }, + // 실내 길찾기는 로그인/앱 기능 → 공개 방문가이드 섹션으로 안내(로그인 유도 금지). + { key: 'wayfinding', icon: IconMap, to: '#guide' }, { key: 'schedule', icon: IconCalendar, to: '#briefing' }, { key: 'crowd', icon: IconCloud, to: '#briefing', soon: true }, { key: 'render', icon: IconRobot, to: '/business', soon: true }, @@ -56,7 +57,8 @@ const AI_TILES: { key: string; icon: Ico; to: string; soon?: boolean }[] = [ const GUIDE_CARDS: { key: string; icon: Ico; to: string }[] = [ { key: 'transport', icon: IconTrain, to: '#transport' }, { key: 'parking', icon: IconParking, to: '#transport' }, - { key: 'wayfinding', icon: IconMap, to: '/login' }, + // 길찾기는 공개 교통·오시는 길 안내로 대체(로그인 유도 금지). + { key: 'wayfinding', icon: IconMap, to: '#transport' }, { key: 'amenities', icon: IconInfo, to: '#guide' }, { key: 'accessibility', icon: IconShield, to: '#guide' }, { key: 'inquiry', icon: IconChat, to: '/public/exhibit-inquiry' }, @@ -65,11 +67,12 @@ const GUIDE_CARDS: { key: string; icon: Ico; to: string }[] = [ /** 관심사 추천 칩(정적 카테고리 라벨). */ const INTEREST_KEYS = ['robot', 'smartfactory', 'healthcare', 'eco', 'mobility', 'content'] as const; -/** 관람객 여정 3-스텝. */ -const JOURNEY: { key: string; icon: Ico; to: string }[] = [ +/** 관람객 여정 3-스텝. `linkKey`=기본 link 라벨 대체(로그인 유도 라벨 제거 시). */ +const JOURNEY: { key: string; icon: Ico; to: string; linkKey?: string }[] = [ { key: 'register', icon: IconTicket, to: '#showcase' }, { key: 'badge', icon: IconQr, to: '/tickets/lookup' }, - { key: 'checkin', icon: IconCheckCircle, to: '/login' }, + // 현장 체크인은 로그인 대신 공개 입장권/QR 조회로 안내(로그인 유도 금지). + { key: 'checkin', icon: IconCheckCircle, to: '/tickets/lookup', linkKey: 'track.visitor.guideMore' }, ]; function LinkOrAnchor({ @@ -351,7 +354,7 @@ export function VisitorTrackPage() {
    - {JOURNEY.map(({ key, icon: Icon, to }, i) => ( + {JOURNEY.map(({ key, icon: Icon, to, linkKey }, i) => (
  1. {i + 1} @@ -363,7 +366,8 @@ export function VisitorTrackPage() {
    {t(`track.visitor.journey.${key}.title`)}

    {t(`track.visitor.journey.${key}.desc`)}

    - {t(`track.visitor.journey.${key}.link`)} + {t(linkKey ?? `track.visitor.journey.${key}.link`)}{' '} + {i < JOURNEY.length - 1 && ( diff --git a/src/frontend/src/screens/public/public.css b/src/frontend/src/screens/public/public.css index e90aa30..fa71d70 100644 --- a/src/frontend/src/screens/public/public.css +++ b/src/frontend/src/screens/public/public.css @@ -384,14 +384,16 @@ .kxp-header__burger { display: none; } + /* 데스크톱(버거 숨김 시점)부터 로그인/내 홈은 항상 헤더 우측에 노출 — + 이전엔 1024px부터만 보여 768~1023 구간에서 로그인이 사라지던 결함 복구. */ + .kxp-header__login { + display: inline-flex; + } } @media (min-width: 1024px) { .kxp-header__cta { display: inline-flex; } - .kxp-header__login { - display: inline-flex; - } } /* ═══ 메인 ═══ */ @@ -2805,9 +2807,10 @@ * 신규 토큰 0 (기존 color·radius·kxp-maxw 변수 재사용). WCAG AA. * =================================================================== */ -/* -- 3-트랙 탭 (단일 헤더 내부 흡수 · COEX 통합 top bar) -- - * 상단 프레임은 1개(.kxp-header)뿐. 별도 topbar 바 제거(이중 프레임 해소). - * 라이트 헤더 배경 위 탭 스타일(하단 보더 활성). 모바일은 헤더에서 숨기고 버거 메뉴로. */ +/* -- 3-트랙 탭 (단일 헤더 우측 · 아이콘 + 툴팁) -- + * 상단 프레임은 1개(.kxp-header)뿐. 좌측=로고+GNB, 우측=트랙 아이콘 탭(로그인/언어 옆). + * 텍스트 대신 선 SVG 아이콘 + title 툴팁/aria-label. 활성 트랙=배경 틴트+하단 보더. + * 모바일은 헤더에서 숨기고 버거 메뉴에서 아이콘+텍스트로 노출. */ .kxp-tracktabs { display: none; align-items: stretch; @@ -2817,20 +2820,29 @@ .kxp-tracktab { display: inline-flex; align-items: center; - padding: 8px 12px; + gap: 8px; + padding: 8px 10px; font-size: var(--fs-body); font-weight: 600; color: var(--color-neutral-600); border-bottom: 2px solid transparent; + border-radius: var(--radius-sm) var(--radius-sm) 0 0; white-space: nowrap; - transition: color 0.15s, border-color 0.15s; + transition: color 0.15s, background 0.15s, border-color 0.15s; +} +.kxp-tracktab__ic { + width: 20px; + height: 20px; + flex-shrink: 0; } .kxp-tracktab:hover { color: var(--color-primary-600); + background: var(--color-primary-050); } .kxp-tracktab.is-active { color: var(--color-primary-700); font-weight: 800; + background: var(--color-primary-050); border-bottom-color: var(--color-primary-600); } .kxp-tracktab:focus-visible { @@ -3068,7 +3080,7 @@ height: 24px; border-radius: 9999px; background: var(--color-primary-600, #0066b3); - color: #fff; + color: var(--color-on-accent); font-size: 12px; font-weight: 800; } diff --git a/src/frontend/src/screens/schedule/calendarView.css b/src/frontend/src/screens/schedule/calendarView.css index ef50055..fd62ea0 100644 --- a/src/frontend/src/screens/schedule/calendarView.css +++ b/src/frontend/src/screens/schedule/calendarView.css @@ -59,7 +59,7 @@ } .kx-cv-switch button.is-active { background: var(--color-primary-600); - color: #fff; + color: var(--color-on-accent); } .kx-cv-muted { font-size: var(--fs-caption); diff --git a/src/frontend/src/screens/work/work.css b/src/frontend/src/screens/work/work.css index 85c8879..cb14759 100644 --- a/src/frontend/src/screens/work/work.css +++ b/src/frontend/src/screens/work/work.css @@ -309,7 +309,7 @@ .kx-msg__rail-count { font-size: var(--fs-caption); background: var(--color-primary-600); - color: #fff; + color: var(--color-on-accent); border-radius: var(--radius-pill); padding: 0 7px; min-width: 18px; @@ -479,7 +479,7 @@ } .kx-cal__cell.is-today .kx-cal__daynum { background: var(--color-primary-600); - color: #fff; + color: var(--color-on-accent); border-radius: 50%; width: 20px; height: 20px; @@ -492,7 +492,7 @@ line-height: 16px; padding: 1px 6px; border-radius: 4px; - color: #fff; + color: var(--color-on-accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -703,7 +703,7 @@ .kx-chip.is-active { background: var(--color-primary-600); border-color: var(--color-primary-600); - color: #fff; + color: var(--color-on-accent); } .kx-noti__item { display: flex; @@ -795,7 +795,7 @@ height: 64px; border-radius: 50%; background: var(--color-primary-600); - color: #fff; + color: var(--color-on-accent); font-size: 26px; font-weight: var(--fw-bold); display: flex; @@ -817,7 +817,7 @@ transform: translateX(-50%); z-index: 60; background: var(--color-neutral-900); - color: #fff; + color: var(--color-white); padding: 10px 18px; border-radius: var(--radius-lg); font-size: var(--fs-body);