Skip to content

feat: 설정 패널 추가#20

Merged
KwonDeaGeun merged 6 commits intomainfrom
feat/add-setting-panel
Sep 18, 2025
Merged

feat: 설정 패널 추가#20
KwonDeaGeun merged 6 commits intomainfrom
feat/add-setting-panel

Conversation

@KwonDeaGeun
Copy link
Owner

@KwonDeaGeun KwonDeaGeun commented Sep 18, 2025

Summary by CodeRabbit

  • New Features

    • 화면 우측 상단에 고정된 설정 버튼 추가(패널 열기/닫기, 아이콘 상태 전환).
    • 설정 패널에서 앱 언어 선택 가능 및 선택값을 저장해 다음 방문에도 유지, 문의하기·사용 가이드 링크 제공.
    • 패널 접근성 개선: 대화상자 역할, 적절한 aria 속성, 닫기 버튼 레이블, Esc로 닫기 지원.
  • Bug Fixes

    • 동일 정류장 클릭 시 말풍선이 토글되어 닫히도록 동작 개선; 말풍선에서 닫기 동작 지원.
  • Chores

    • 코드 포맷 정리(개행 추가)으로 가독성 개선.

@KwonDeaGeun KwonDeaGeun self-assigned this Sep 18, 2025
@vercel
Copy link

vercel bot commented Sep 18, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
what-the-bus-web Ready Ready Preview Comment Sep 18, 2025 1:23pm

@coderabbitai
Copy link

coderabbitai bot commented Sep 18, 2025

Warning

Rate limit exceeded

@KwonDeaGeun has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 7 minutes and 48 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between e098e6d and c056813.

📒 Files selected for processing (1)
  • src/App.tsx (3 hunks)

Walkthrough

App에 우측 고정 설정 버튼이 추가되어 showSettings로 SettingsPanel을 토글 렌더링하고, useId 기반 langId와 language 상태가 도입되었다. SettingsPanel은 언어 선택, 문의/가이드 링크, Escape 및 닫기 버튼으로 닫기를 지원한다. use-toast에는 단순 개행 추가만 있음.

Changes

Cohort / File(s) Change Summary
설정 기능 통합 (App)
src/App.tsx
설정 버튼(UI, Settings / X 아이콘) 추가, showSettings 상태 및 toggleSettings(useCallback) 도입, langId(useId) 및 language 상태 추가(로컬스토리지에 저장), SettingsPanelReact.lazy로 불러와 Suspense 내 조건부 렌더링 및 props 전달
SettingsPanel 컴포넌트 추가
src/components/SettingsPanel.tsx
새 컴포넌트 추가: 우측 고정 패널(role="dialog", aria-*, tabIndex), 언어 선택(라벨에 langId 사용), setLanguage 바인딩, 문의(구글 폼)/사용 가이드(노션) 링크, Escape 키 및 닫기 버튼으로 종료, onClose 콜백 사용, 인라인 스타일링
Bubble API 변경
src/components/Bubble*
Bubble props에 선택적 onClose?: () => void 추가, 내부에서 닫기 시 해당 콜백 호출하도록 변경(버블 토글 동작 조정 포함)
사소한 포맷 변경
src/components/ui/use-toast.tsx
파일 끝 개행 추가(기능 변경 없음)

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User as 사용자
  participant App as App
  participant Panel as SettingsPanel
  note right of App #DDEBF7: SettingsPanel은 React.lazy로 로드되고\n조건부로 Suspense 내에 렌더링됩니다

  User->>App: 우측 설정 버튼 클릭
  App->>App: toggleSettings() -> showSettings = true
  App->>Panel: 렌더(language, setLanguage, onClose)

  alt 언어 변경
    User->>Panel: 언어 선택
    Panel-->>App: setLanguage(lang)
    App-->>App: language 상태 및 로컬스토리지 업데이트
  end

  User->>Panel: 닫기 클릭 또는 Escape
  Panel-->>App: onClose()
  App->>App: showSettings = false
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

설정 창에 깡충 뛴 토끼 🐇
버튼 한 번에 빛이 열리네.
언어 고르고 링크로 냠냠,
Escape로 살짝 문 닫고,
코드에 작은 당근 하나 남기네.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 제목 "feat: 설정 패널 추가"는 변경의 핵심인 설정 패널 추가를 명확히 요약합니다. 짧고 구체적이며 컨벤션(feat:)을 따르고 있어 변경 이력을 스캔하는 동료가 주요 변경사항을 바로 이해할 수 있습니다. 파일 목록, 이모지, 또는 모호한 표현이 없어 적절합니다.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
src/components/SettingsPanel.tsx (2)

43-53: 초기 포커스 지정으로 키보드 사용성 개선

패널 오픈 시 닫기 버튼에 초점이 가도록 autoFocus를 권장합니다.

                 <button
                     type="button"
                     onClick={onClose}
                     aria-label="닫기"
+                    autoFocus
                     style={{
                         background: "transparent",
                         border: "none",
                         cursor: "pointer",
                     }}
                 >

3-8: 언어 타입을 리터럴 유니온으로 한정

string 전체보다 "ko" | "en"으로 좁히면 오입력 방지 및 타입 안전성이 올라갑니다.

 interface SettingsPanelProps {
     langId: string;
-    language: string;
-    setLanguage: (lang: string) => void;
+    language: "ko" | "en";
+    setLanguage: (lang: "ko" | "en") => void;
     onClose: () => void;
 }
src/App.tsx (3)

13-13: 언어 상태를 리터럴 유니온으로 제한

상태를 "ko" | "en"으로 한정하면 SettingsPanel과 타입 일관성이 생깁니다.

-    const [language, setLanguage] = useState("ko");
+    const [language, setLanguage] = useState<"ko" | "en">("ko");

414-436: 설정 버튼 ARIA 보강

토글 상태 전달과 다이얼로그 호출 표기를 추가하세요.

             <button
                 type="button"
                 aria-label="설정"
                 onClick={toggleSettings}
+                aria-pressed={showSettings}
+                aria-haspopup="dialog"
                 style={{
                     position: "fixed",
                     top: 12,
                     right: 12,
                     zIndex: 10000,

437-444: 오버레이 추가로 외부 클릭 닫기 + 배경 상호작용 차단

패널 뒤에 반투명 오버레이를 렌더링해 외부 클릭으로 닫고 배경 상호작용을 막는 것을 권장합니다. 패널 z-index는 10001로 상향(위 코멘트 반영).

-            {showSettings ? (
-                <SettingsPanel
-                    langId={langId}
-                    language={language}
-                    setLanguage={setLanguage}
-                    onClose={toggleSettings}
-                />
-            ) : null}
+            {showSettings ? (
+                <>
+                    <div
+                        onClick={toggleSettings}
+                        aria-hidden="true"
+                        style={{
+                            position: "fixed",
+                            inset: 0,
+                            background: "rgba(0,0,0,0.3)",
+                            zIndex: 10000,
+                        }}
+                    />
+                    <SettingsPanel
+                        langId={langId}
+                        language={language}
+                        setLanguage={setLanguage}
+                        onClose={toggleSettings}
+                    />
+                </>
+            ) : null}

추가 권장(선택):

  • showSettings 변경 시 document.body.style.overflow = "hidden" 토글로 배경 스크롤 잠금.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3410044 and c17f65b.

📒 Files selected for processing (3)
  • src/App.tsx (2 hunks)
  • src/components/SettingsPanel.tsx (1 hunks)
  • src/components/ui/use-toast.tsx (1 hunks)
🔇 Additional comments (3)
src/components/ui/use-toast.tsx (1)

91-91: 개행 추가만: 기능 영향 없음

파일 끝 개행 추가 변경만 있습니다. 머지해도 무방합니다.

src/components/SettingsPanel.tsx (1)

98-105: 외부 링크 자리표시자 교체 필요

현재 구글폼/노션 링크가 플레이스홀더입니다. 릴리스 전 실제 URL로 교체해 주세요.

Also applies to: 118-126

src/App.tsx (1)

1-2: lucide-react 의존성 확인

빌드 실패 방지를 위해 lucide-react가 package.json에 추가되어 있는지 확인해 주세요.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
src/App.tsx (4)

2-2: SettingsPanel 지연 로딩으로 초기 번들 축소 제안

설정 패널은 비가시 영역 기능이므로 lazy import로 초기 JS 페이로드를 줄이는 것을 권장합니다. Suspense로 감싸면 동작 동일합니다.

-import { useCallback, useEffect, useId, useState } from "react";
+import { lazy, Suspense, useCallback, useEffect, useId, useState } from "react";
@@
-import SettingsPanel from "./components/SettingsPanel";
+const SettingsPanel = lazy(() => import("./components/SettingsPanel"));
@@
-            {showSettings ? (
-                <SettingsPanel
-                    langId={langId}
-                    language={language}
-                    setLanguage={setLanguage}
-                    onClose={toggleSettings}
-                />
-            ) : null}
+            {showSettings ? (
+                <Suspense fallback={null}>
+                    <SettingsPanel
+                        langId={langId}
+                        language={language}
+                        setLanguage={setLanguage}
+                        onClose={toggleSettings}
+                    />
+                </Suspense>
+            ) : null}

Also applies to: 5-5, 437-444


12-16: 언어 설정 영속화(localStorage) 권장

앱 재방문 시 선택 언어가 유지되도록 클라이언트 저장을 권장합니다. SSR 고려가 없다면 아래처럼 간단히 적용 가능합니다.

// 초기화 시 로컬 저장값 우선
const [language, setLanguage] = useState(
  () => localStorage.getItem("wtb:lang") ?? "ko"
);

// 변경 시 반영
useEffect(() => {
  try { localStorage.setItem("wtb:lang", language); } catch {}
}, [language]);

414-436: 접근성: 토글 버튼 상태 노출 및 아이콘 크기 통일

Disclosure 역할에 맞춰 aria-expanded/haspopup을 추가하고, 아이콘 크기를 통일하면 시각적 점프를 줄일 수 있습니다.

-            <button
+            <button
                 type="button"
                 aria-label="설정"
+                aria-haspopup="dialog"
+                aria-expanded={showSettings}
                 onClick={toggleSettings}
                 style={{
@@
-                {showSettings ? <X size={18} /> : <Settings size={24} />}
+                {showSettings ? <X size={20} /> : <Settings size={20} />}

437-444: onClose는 토글보다 명시적 종료로 안전

패널 내부에서 onClose가 중복 호출되면 토글 방식은 재오픈될 수 있습니다. idempotent하게 닫히도록 명시 종료를 권장합니다.

-                    onClose={toggleSettings}
+                    onClose={() => setShowSettings(false)}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 28c9c4e and 9dac3c1.

📒 Files selected for processing (1)
  • src/App.tsx (2 hunks)
🔇 Additional comments (1)
src/App.tsx (1)

1-2: 임포트 변경 LGTM

아이콘/훅 임포트 적절하며 불필요 임포트 없음.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
src/App.tsx (5)

14-18: 초기 언어 상태(localStorage) 접근에 SSR/WebView 안전장치가 없습니다.

서버 렌더링(또는 일부 WebView) 환경에서 localStorage 접근 시 ReferenceError가 날 수 있습니다. 초기화 시 try/catch와 typeof window 가드를 권장합니다.

다음 변경을 제안합니다:

-    const [language, setLanguage] = useState(
-        () => localStorage.getItem("wtb:lang") ?? "ko"
-    );
+    const [language, setLanguage] = useState(() => {
+        try {
+            return typeof window !== "undefined" && window.localStorage
+                ? localStorage.getItem("wtb:lang") ?? "ko"
+                : "ko";
+        } catch {
+            return "ko";
+        }
+    });

23-30: 로컬스토리지 중복 쓰기 방지로 자잘한 비용을 줄일 수 있습니다.

값이 변하지 않았을 때는 setItem을 스킵하세요.

 useEffect(() => {
   try {
-      localStorage.setItem("wtb:lang", language);
+      if (localStorage.getItem("wtb:lang") !== language) {
+          localStorage.setItem("wtb:lang", language);
+      }
   } catch {
       /* ignore */
   }
 }, [language]);

428-452: 설정 버튼 a11y 보완(aria 사용) 및 프리페치로 UX 향상 권장.

  • 대화상자 트리거에는 aria-expanded 대신 aria-pressed(토글 버튼) 또는 aria-controls와 함께 쓰는 패턴이 더 일관됩니다. 현재는 role="dialog" 컨트롤을 시사하므로 aria-controls 추가를 권장합니다.
  • 호버 시 지연 로드 프리페치를 붙이면 첫 열림 지연을 줄일 수 있습니다.

아래처럼 제안합니다(설정 패널 루트에 id="settings-panel"이 존재해야 합니다. 없으면 SettingsPanel에 추가 필요):

             <button
                 type="button"
                 aria-label="설정"
-                aria-haspopup="dialog"
-                aria-expanded={showSettings}
+                aria-haspopup="dialog"
+                aria-pressed={showSettings}
+                aria-controls="settings-panel"
                 onClick={toggleSettings}
+                onMouseEnter={() => import("./components/SettingsPanel")}
                 style={{

검증: SettingsPanel 루트 엘리먼트에 id="settings-panel"이 있는지 확인 부탁드립니다. 없다면 추가해 주세요.


453-462: Suspense fallback을 스크린리더 친화적으로.

지금은 null이라 초기에 공백입니다. 시각적 잡음 없이도 aria-live로 로딩을 알릴 수 있습니다.

-                <Suspense fallback={null}>
+                <Suspense
+                    fallback={
+                        <span className="sr-only" role="status" aria-live="polite">
+                            설정 패널 로딩 중…
+                        </span>
+                    }
+                >

483-483: 말풍선 토글에 참조 동일성 비교는 취약합니다.

prev === stop는 동일 객체 참조일 때만 참입니다. 동일 정류장을 새 객체로 전달하면 토글이 깨질 수 있습니다. 구조 동등성(또는 id) 비교로 바꿔주세요.

-                        setBubbleStop((prev) => (prev === stop ? undefined : stop));
+                        setBubbleStop((prev) => {
+                            if (!prev || !stop) return stop;
+                            const same =
+                                prev.lat === stop.lat &&
+                                prev.lng === stop.lng &&
+                                prev.name === stop.name;
+                            return same ? undefined : stop;
+                        });

대안: stop.id가 있다면 id 기반 비교가 가장 안전합니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9dac3c1 and e098e6d.

📒 Files selected for processing (2)
  • src/App.tsx (3 hunks)
  • src/components/SettingsPanel.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/SettingsPanel.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
src/App.tsx (1)
src/components/ui/use-toast.tsx (1)
  • useToast (83-89)
🔇 Additional comments (2)
src/App.tsx (2)

1-2: 아이콘/React API 임포트 적절합니다.

트리셰이킹되는 임포트이며 불필요한 전역 임포트가 없습니다.


20-21: 설정 열림 토글 핸들러 깔끔합니다.

불필요한 재생성을 피하는 useCallback 사용이 적절합니다.

@KwonDeaGeun KwonDeaGeun merged commit 2e5ccd7 into main Sep 18, 2025
4 checks passed
@KwonDeaGeun KwonDeaGeun deleted the feat/add-setting-panel branch September 18, 2025 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant