Conversation
Canorus
commented
Feb 25, 2026
- 입력창 폰트 사이즈가 작아 15px; 로 고정했습니다.
- custom CSS 항목을 설정에 넣었습니다.
- gemini-cli로 작성되었습니다.
deholic
left a comment
There was a problem hiding this comment.
코드 리뷰 남깁니다. Custom CSS 기능의 방향은 좋습니다만, 몇 가지 개선 포인트가 있습니다.
| onCustomCssApply={(value) => { | ||
| localStorage.setItem("textodon.customCss", value); | ||
| window.location.reload(); | ||
| }} |
There was a problem hiding this comment.
🔴 Critical: onCustomCssApply와 useEffect 로직 단절
useEffect(L454-466)에서 customCss state를 감시하며 동적으로 <style> 태그를 관리하고 있지만, 이 콜백에서는 setCustomCss()를 호출하지 않고 window.location.reload()로 페이지를 리로드합니다.
현재 "우연히 동작하는" 구조입니다:
- 리로드 →
useState(() => localStorage.getItem(...))초기값 로드 → useEffect 발화
문제점:
- useEffect의 동적 CSS 주입 로직이 apply 시점에는 사용되지 않음 (dead path)
- 리로드로 인해 스크롤 위치, 모달 상태 등 모든 UI 상태 손실
- 두 가지 메커니즘(state 기반 주입 vs 리로드 기반 적용)이 혼재
수정 방향: setCustomCss(value)를 호출하여 useEffect가 실시간 반영하도록 통일하고, 리로드를 제거합니다. 이 경우 SettingsModal의 버튼 텍스트도 적용 (페이지 새로고침) → 적용으로 변경이 필요합니다.
| onCustomCssApply={(value) => { | |
| localStorage.setItem("textodon.customCss", value); | |
| window.location.reload(); | |
| }} | |
| onCustomCssApply={(value) => { | |
| setCustomCss(value); | |
| localStorage.setItem("textodon.customCss", value); | |
| }} |
| <textarea | ||
| value={localCustomCss} | ||
| onChange={(e) => setLocalCustomCss(e.target.value)} | ||
| placeholder="/* 여기에 CSS를 입력하세요 */" | ||
| rows={10} | ||
| /> |
There was a problem hiding this comment.
🟡 접근성: aria-label 누락
AGENTS.md 원칙("버튼/아이콘에 aria-label, 텍스트 대체를 제공한다")에 따라 입력 요소에 접근성 레이블이 필요합니다. placeholder는 스크린 리더에서 일관되게 지원되지 않으므로 aria-label을 추가해주세요.
| <textarea | |
| value={localCustomCss} | |
| onChange={(e) => setLocalCustomCss(e.target.value)} | |
| placeholder="/* 여기에 CSS를 입력하세요 */" | |
| rows={10} | |
| /> | |
| <textarea | |
| value={localCustomCss} | |
| onChange={(e) => setLocalCustomCss(e.target.value)} | |
| placeholder="/* 여기에 CSS를 입력하세요 */" | |
| rows={10} | |
| aria-label="Custom CSS 입력" | |
| /> |
| .settings-custom-css summary { | ||
| padding: 12px 16px; | ||
| cursor: pointer; | ||
| background: var(--color-input-bg); | ||
| user-select: none; | ||
| list-style: none; | ||
| } | ||
|
|
||
| .settings-custom-css summary::-webkit-details-marker { | ||
| display: none; | ||
| } |
There was a problem hiding this comment.
🟡 <details> 접힘/펼침 시각적 인디케이터 누락
기본 마커(▶)를 display: none과 list-style: none으로 숨겼는데, 대체 시각적 인디케이터가 없어 사용자가 이 요소가 토글 가능하다는 것을 인지하기 어렵습니다.
summary에 ::after pseudo-element로 chevron을 추가하는 것을 권장합니다:
| .settings-custom-css summary { | |
| padding: 12px 16px; | |
| cursor: pointer; | |
| background: var(--color-input-bg); | |
| user-select: none; | |
| list-style: none; | |
| } | |
| .settings-custom-css summary::-webkit-details-marker { | |
| display: none; | |
| } | |
| .settings-custom-css summary { | |
| padding: 12px 16px; | |
| cursor: pointer; | |
| background: var(--color-input-bg); | |
| user-select: none; | |
| list-style: none; | |
| position: relative; | |
| } | |
| .settings-custom-css summary::after { | |
| content: "▶"; | |
| position: absolute; | |
| right: 16px; | |
| top: 12px; | |
| font-size: 10px; | |
| transition: transform 0.2s; | |
| } | |
| .settings-custom-css[open] summary::after { | |
| transform: rotate(90deg); | |
| } | |
| .settings-custom-css summary::-webkit-details-marker { | |
| display: none; | |
| } |
| border: none !important; | ||
| border-radius: 0 !important; | ||
| font-family: inherit; | ||
| font-size: 15px; |
There was a problem hiding this comment.
🟢 Nit: 폰트 사이즈 하드코딩
15px이 두 곳(L847, L929)에서 반복됩니다. 추후 변경 용이성을 위해 CSS 변수로 추출하는 것을 고려해보세요:
/* 예: theme variables에 추가 */
--font-size-compose: 15px;단, 현재 코드베이스에서 사이즈 변수를 별도 관리하지 않는다면 현행대로 유지해도 무방합니다.
| <button | ||
| type="button" | ||
| className="settings-apply-button" | ||
| onClick={() => onCustomCssApply(localCustomCss)} | ||
| > | ||
| 적용 (페이지 새로고침) | ||
| </button> |
There was a problem hiding this comment.
🟡 Critical 수정 시 연동 필요: 버튼 텍스트 변경
App.tsx의 onCustomCssApply에서 window.location.reload()를 제거하고 setCustomCss()로 실시간 반영하도록 수정할 경우, 이 버튼의 텍스트에서 (페이지 새로고침) 안내도 함께 제거해야 합니다.
| <button | |
| type="button" | |
| className="settings-apply-button" | |
| onClick={() => onCustomCssApply(localCustomCss)} | |
| > | |
| 적용 (페이지 새로고침) | |
| </button> | |
| <button | |
| type="button" | |
| className="settings-apply-button" | |
| onClick={() => onCustomCssApply(localCustomCss)} | |
| aria-label="Custom CSS 적용" | |
| > | |
| 적용 | |
| </button> |