feat: 랜딩 페이지에 MathLive 기반 수학 점역 데모 추가 및 한글·수학 탭 통합 - #177
Open
jessieyeon wants to merge 14 commits into
Open
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- MathTransInput: 박스 전체 클릭 시 math-field 포커스(TransInput과 동일 동작) - readArg: 미종료 중괄호 내용 보존, 제어기호 인자 균형 유지 - DemoChrome: 한글·수학 데모 공통 헤딩/화살표 컴포넌트 추출 - DemoTabs: type=button, aria-controls, role=tabpanel, 좌우 화살표 키 이동 - MathTransInput: latex 상태를 부모에서 단일 관리(controlled), placeholder 흐름 배치로 매직 넘버 제거 - 입출력 박스를 동일 flex-basis 2단 구조로 맞춰 크기(498×500) 통일 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
owjs3901
requested changes
Jul 27, 2026
owjs3901
left a comment
Contributor
There was a problem hiding this comment.
superpowers 를 gitignore에 추가요망
| minH="25dvh" | ||
| onClick={() => fieldRef.current?.focus()} | ||
| p={['16px', null, null, '40px']} | ||
| w="100%" |
Contributor
There was a problem hiding this comment.
이미 flex라서 w="100%"가 필요 없을거에요
Author
There was a problem hiding this comment.
w="100%"를 제거했습니다. 다만 바깥 컨테이너가 row 방향 flex라 align-items: stretch가 가로를 늘리지 않아, w="100%"를 그냥 지우면 입력·출력 박스 너비가 어긋났습니다. 그래서 w="100%" 대신 flex="1"으로 가로를 채우도록 바꿨습니다.
- Trans/MathTrans/MathTransInput의 세로 컨테이너를 Flex→VStack으로 변경 - VStack 기본값과 중복되는 flexDirection="column" 및 불필요한 w="100%" 제거 - DemoArrow의 transform 기본값 rotate(0deg)→null (항등 변환이라 불필요) - 미사용 Flex import 정리 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- MathTransInput: math-field의 인라인 style을 css()로 전환 - Trans/MathTrans: VStack 기본값과 중복되는 flexDirection 맨 앞 column을 null로 - docs/superpowers 플랜 문서 2개 제거
바깥 컨테이너가 row 방향 flex라 align-items stretch가 가로를 늘리지 않아 w=100%가 제거되면 입력·출력 박스 너비가 어긋난다. w=100% 대신 flex=1로 가로를 채워 박스 크기 동일을 유지하면서 명시적 w=100%를 제거한다.
owjs3901
requested changes
Aug 3, 2026
owjs3901
left a comment
Contributor
There was a problem hiding this comment.
폰트에 라이센스 문제가 없는지 확인합시다, 만약 걱정되면 link 태그를 통해서 해결하면 좋을 것 같아요
| maskPosition="center" | ||
| maskRepeat="no-repeat" | ||
| maskSize="contain" | ||
| w={['17px', null, null, '28px']} |
| return ( | ||
| <Flex aria-hidden="true"> | ||
| <Image | ||
| alt="" |
| } | ||
|
|
||
| return ( | ||
| <VStack flex="1" gap={['16px', null, null, '30px']} w="100%"> |
Contributor
There was a problem hiding this comment.
flex 1은 맨 처음 return에서 바로 쓰는 것 보다 이 컴포넌트를 호출하는 곳에서 flex=1을 안쓰더라도 넓게 펼쳐지도록 alignItems center 등의 옵션을 뺴는 것이 이롭습니다
| as="button" | ||
| bg={mode === key ? '$text' : 'transparent'} | ||
| border="1px solid $text" | ||
| borderRadius="9999px" |
Comment on lines
+40
to
+51
| <MathTransInput | ||
| latex={latex} | ||
| onLatexChange={setLatex} | ||
| placeholder="수식을 입력하면 이곳에 수학 점자가 표시됩니다." | ||
| /> | ||
| <DemoArrow /> | ||
| <TransInput | ||
| blurPlaceholder={'예: 사분의 삼 → ⠼⠙⠌⠼⠉'} | ||
| focusPlaceholder={'예: 사분의 삼 → ⠼⠙⠌⠼⠉'} | ||
| readOnly | ||
| value={braille} | ||
| /> |
Contributor
There was a problem hiding this comment.
이것만 따로 클라이언트 컴포넌트로 뺴는게 맞습니다
| const braille = latex.trim() ? translateToUnicode(`$${latex}$`) : '' | ||
|
|
||
| return ( | ||
| <VStack flex="1" gap={['16px', null, null, '30px']}> |
Contributor
There was a problem hiding this comment.
flex 1 위 피드백과 같이 개선되어야 합니다
Comment on lines
+23
to
+64
| export function normalizeFracBraces(latex: string): string { | ||
| let out = '' | ||
| let i = 0 | ||
| while (i < latex.length) { | ||
| if (latex.startsWith('\\frac', i) && !/[a-zA-Z]/.test(latex[i + 5] ?? '')) { | ||
| const [num, j] = readArg(latex, i + 5) | ||
| const [den, k] = readArg(latex, j) | ||
| out += `\\frac${num}${den}` | ||
| i = k | ||
| continue | ||
| } | ||
| out += latex[i] | ||
| i += 1 | ||
| } | ||
| return out | ||
| } | ||
|
|
||
| /** i 위치부터 LaTeX 인자 하나를 읽어 중괄호로 감싼 형태와 다음 인덱스를 돌려준다. */ | ||
| function readArg(latex: string, i: number): [string, number] { | ||
| while (latex[i] === ' ') i += 1 | ||
| if (latex[i] === '{') { | ||
| let depth = 0 | ||
| let j = i | ||
| do { | ||
| if (latex[j] === '{') depth += 1 | ||
| else if (latex[j] === '}') depth -= 1 | ||
| j += 1 | ||
| } while (j < latex.length && depth > 0) | ||
| // depth === 0 이면 짝이 맞는 '}' 를 j-1 에서 소비한 것이고, | ||
| // depth > 0 이면 닫는 중괄호 없이 끝난 것이라 내용을 j 까지 살린다. | ||
| const end = depth === 0 ? j - 1 : j | ||
| return [`{${normalizeFracBraces(latex.slice(i + 1, end))}}`, j] | ||
| } | ||
| if (latex[i] === '\\') { | ||
| let j = i + 1 | ||
| while (j < latex.length && /[a-zA-Z]/.test(latex[j] ?? '')) j += 1 | ||
| // 제어기호(\, \! 등)는 백슬래시 뒤에 글자가 없으므로 기호 한 글자를 포함시킨다. | ||
| if (j === i + 1 && j < latex.length) j += 1 | ||
| return [`{${latex.slice(i, j)}}`, j] | ||
| } | ||
| return [`{${latex[i] ?? ''}}`, i + 1] | ||
| } |
| // 바깥 Flex 는 padding 없는 flex 아이템으로, 출력측 TransInput 의 외곽 | ||
| // Flex(flex=1 h=100% w=100%)와 flex-basis 를 동일하게 맞춰 좌우 박스 너비를 | ||
| // 같게 한다. 실제 배경/여백은 안쪽 박스가 담당한다. | ||
| <Flex flex="1" h="100%" w="100%"> |
| bg="$containerBackground" | ||
| borderRadius={['16px', null, null, '30px']} | ||
| cursor="text" | ||
| flex="1" |
| onClick={() => fieldRef.current?.focus()} | ||
| p={['16px', null, null, '40px']} | ||
| > | ||
| <Flex flex="1" flexDirection="column" gap="8px"> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
개요
랜딩 페이지에 수학 점역 체험 데모를 추가하고, 기존 한글 점역 데모와 함께 '한글' / '수학' 탭 토글 하나로 통합했습니다. 사용자는 MathLive 화면 수식 키보드로 수식을 WYSIWYG 편집하고, 자동 생성된 LaTeX가 실시간으로 한국 수학 점자로 변환되는 것을 체험할 수 있습니다.
주요 변경
수학 점역 데모
mathlive@^0.110.0도입, MathLive 폰트를public/mathlive/fonts/에 self-host (braillify의 "외부 연결 없이 실행" 원칙 유지 — CDN 미사용)MathTransInput— MathLive<math-field>웹 컴포넌트 래퍼. SSR 회피(동적 import), 데스크톱에서도 가상 수식 키보드 노출(manual정책), 언마운트 시 키보드 자동 닫힘$...$로 감싸 기존 braillify WASMtranslateToUnicode에 전달 — 코어 엔진(libs/braillify) 무수정한글·수학 탭 통합
DemoTabs— '한글'/'수학' 탭 토글(기본 '한글'). WAI-ARIAtablist/tab/tabpanel, 좌우 화살표 키 이동 지원DemoChrome— 한글·수학 데모가 공유하는 헤딩/화살표 컴포넌트 추출세부 보정
\frac정규화: MathLive의 중괄호 생략 직렬화(\frac34)를 braillify가 인식하는\frac{3}{4}정규형으로 변환. 미종료 중괄호·제어기호 인자도 안전하게 처리검증
bun run build통과, 기존 테스트 스위트 14,165개 전부 통과(회귀 없음)학교→⠚⠁⠈⠬), 수학 변환(x²+1→⠭⠘⠼⠃⠢⠼⠁,¾→⠼⠙⠌⠼⠉), 탭 전환/화살표 키 이동, 가상 키보드 열림·닫힘, 다크 테마 가독성, 폰트 로컬 서빙(404 없음)알려진 후속 작업 (이 PR 범위 밖)
\frac34을 직접 분수로 인식하도록 일반화 — 현재는 랜딩측normalizeFracBraces로 경계에서 처리. 엔진 수정은 별도 서브시스템(Rust + PDF 근거 테스트)이라 분리함.