Skip to content

feat: 랜딩 페이지에 MathLive 기반 수학 점역 데모 추가 및 한글·수학 탭 통합 - #177

Open
jessieyeon wants to merge 22 commits into
dev-five-git:mainfrom
jessieyeon:demo-math-landing
Open

feat: 랜딩 페이지에 MathLive 기반 수학 점역 데모 추가 및 한글·수학 탭 통합#177
jessieyeon wants to merge 22 commits into
dev-five-git:mainfrom
jessieyeon:demo-math-landing

Conversation

@jessieyeon

Copy link
Copy Markdown

개요

랜딩 페이지에 수학 점역 체험 데모를 추가하고, 기존 한글 점역 데모와 함께 '한글' / '수학' 탭 토글 하나로 통합했습니다. 사용자는 MathLive 화면 수식 키보드로 수식을 WYSIWYG 편집하고, 자동 생성된 LaTeX가 실시간으로 한국 수학 점자로 변환되는 것을 체험할 수 있습니다.

주요 변경

수학 점역 데모

  • mathlive@^0.110.0 도입, MathLive 폰트를 public/mathlive/fonts/self-host (braillify의 "외부 연결 없이 실행" 원칙 유지 — CDN 미사용)
  • MathTransInput — MathLive <math-field> 웹 컴포넌트 래퍼. SSR 회피(동적 import), 데스크톱에서도 가상 수식 키보드 노출(manual 정책), 언마운트 시 키보드 자동 닫힘
  • MathLive가 생성한 LaTeX를 $...$로 감싸 기존 braillify WASM translateToUnicode에 전달 — 코어 엔진(libs/braillify) 무수정

한글·수학 탭 통합

  • DemoTabs — '한글'/'수학' 탭 토글(기본 '한글'). WAI-ARIA tablist/tab/tabpanel, 좌우 화살표 키 이동 지원
  • 수학 안내문을 입력창 placeholder로 이동(한글 데모와 동일한 방식), 출력창은 예시만 표시
  • 입력·출력 박스를 동일 flex-basis 2단 구조로 맞춰 전 브레이크포인트에서 크기 통일(모바일 343×203 / 태블릿 693×256 / 데스크톱 498×500, 모두 좌우 동일)
  • DemoChrome — 한글·수학 데모가 공유하는 헤딩/화살표 컴포넌트 추출

세부 보정

  • \frac 정규화: MathLive의 중괄호 생략 직렬화(\frac34)를 braillify가 인식하는 \frac{3}{4} 정규형으로 변환. 미종료 중괄호·제어기호 인자도 안전하게 처리
  • 입력 박스 전체 클릭 시 수식 필드 포커스(기존 한글 데모와 동일 동작)

검증

  • bun run build 통과, 기존 테스트 스위트 14,165개 전부 통과(회귀 없음)
  • 브라우저 확인: 한글 변환(학교⠚⠁⠈⠬), 수학 변환(x²+1⠭⠘⠼⠃⠢⠼⠁, ¾⠼⠙⠌⠼⠉), 탭 전환/화살표 키 이동, 가상 키보드 열림·닫힘, 다크 테마 가독성, 폰트 로컬 서빙(404 없음)
  • 반응형 3개 브레이크포인트에서 좌우 박스 크기 일치 실측

알려진 후속 작업 (이 PR 범위 밖)

  • braillify 엔진의 LaTeX 파서가 중괄호 없는 \frac34을 직접 분수로 인식하도록 일반화 — 현재는 랜딩측 normalizeFracBraces로 경계에서 처리. 엔진 수정은 별도 서브시스템(Rust + PDF 근거 테스트)이라 분리함.

jessieyeon and others added 11 commits July 22, 2026 15:31
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 owjs3901 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

superpowers 를 gitignore에 추가요망

Comment thread apps/landing/src/app/DemoChrome.tsx Outdated
Comment thread apps/landing/src/app/MathTrans.tsx Outdated
Comment thread apps/landing/src/app/MathTransInput.tsx
Comment thread apps/landing/src/app/MathTransInput.tsx Outdated
Comment thread apps/landing/src/app/MathTransInput.tsx Outdated
Comment thread apps/landing/src/app/Trans.tsx Outdated
Comment thread docs/superpowers/plans/2026-07-22-demo-tabs-unify.md Outdated
jessieyeon and others added 3 commits July 28, 2026 13:15
- 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 owjs3901 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

폰트에 라이센스 문제가 없는지 확인합시다, 만약 걱정되면 link 태그를 통해서 해결하면 좋을 것 같아요

Comment thread apps/landing/src/app/DemoChrome.tsx Outdated
maskPosition="center"
maskRepeat="no-repeat"
maskSize="contain"
w={['17px', null, null, '28px']}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

17px같은 홀수는 피해야 합니다

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

네. 18px으로 변경하였습니다.

Comment thread apps/landing/src/app/DemoChrome.tsx Outdated
Comment thread apps/landing/src/app/DemoTabs.tsx Outdated
Comment thread apps/landing/src/app/DemoTabs.tsx Outdated
as="button"
bg={mode === key ? '$text' : 'transparent'}
border="1px solid $text"
borderRadius="9999px"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

50%가 같은 의미일겁니다.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

border-radius: 50%는 가로 반경이 폭의 절반, 세로 반경이 높이의 절반이라 가로로 긴 버튼에서는 타원이 됩니다. 저장소 기존 알약 버튼(components/home/PillButton.tsx)은 1000px을 쓰고 있어 우선 그 값으로 맞춰뒀습니다. 혹시 타원형으로 수정하는 바가 더 좋을까요?

Comment thread apps/landing/src/app/MathTrans.tsx Outdated
Comment on lines +40 to +51
<MathTransInput
latex={latex}
onLatexChange={setLatex}
placeholder="수식을 입력하면 이곳에 수학 점자가 표시됩니다."
/>
<DemoArrow />
<TransInput
blurPlaceholder={'예: 사분의 삼 → ⠼⠙⠌⠼⠉'}
focusPlaceholder={'예: 사분의 삼 → ⠼⠙⠌⠼⠉'}
readOnly
value={braille}
/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이것만 따로 클라이언트 컴포넌트로 뺴는게 맞습니다

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

반영했습니다. 입출력부를 MathTransPanel.tsx로 분리하고, MathTrans는 헤딩만 남기면서 'use client'를 뗐습니다.

Comment thread apps/landing/src/app/MathTrans.tsx Outdated
const braille = latex.trim() ? translateToUnicode(`$${latex}$`) : ''

return (
<VStack flex="1" gap={['16px', null, null, '30px']}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

flex 1 위 피드백과 같이 개선되어야 합니다

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

제거하였습니다

Comment thread apps/landing/src/app/MathTransInput.tsx Outdated
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]
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

순수 함수는 ts파일로 빼는게 낫습니다

@jessieyeon jessieyeon Aug 7, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

normalizeFracBraces.ts로 분리했습니다. 파서라 회귀 테스트도 붙였고 bun test에서 돌아갑니다.

Comment thread apps/landing/src/app/MathTransInput.tsx Outdated
// 바깥 Flex 는 padding 없는 flex 아이템으로, 출력측 TransInput 의 외곽
// Flex(flex=1 h=100% w=100%)와 flex-basis 를 동일하게 맞춰 좌우 박스 너비를
// 같게 한다. 실제 배경/여백은 안쪽 박스가 담당한다.
<Flex flex="1" h="100%" w="100%">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

위 피드백과 같은 이슈

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

제거하였습니다

Comment thread apps/landing/src/app/MathTransInput.tsx Outdated
bg="$containerBackground"
borderRadius={['16px', null, null, '30px']}
cursor="text"
flex="1"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이건 flex 1이 필요 없지 않나요

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

제거하였습니다

Comment thread apps/landing/src/app/MathTransInput.tsx Outdated
…ve-git#10 dev-five-git#11)

- 전역 box-sizing:border-box 로 padding 이 flex-basis 를 어긋내지 않으므로
  바깥 Flex 래퍼를 제거하고, 대신 minW=0 으로 콘텐츠 최소 폭 확장을 막는다.
- 안쪽 Flex flexDirection=column 을 VStack 으로 교체.
- oxlint 지적(prop 정렬, no-namespace) 정리.
…five-git#7)

세로 높이는 데모 안쪽 행의 h=[auto,500px] 하나가 결정하므로 그 위 체인
(DemoTabs 루트/tabpanel, Trans/MathTrans 루트)의 flex=1 은 전부 no-op 이었다.
…ve-git#3)

DemoChrome 은 devup 린트 규칙(파일명=컴포넌트명)에 맞춰
DemoHeading.tsx / DemoArrow.tsx 로 분리했다.
브라우저에서 측정한 결과 래퍼 제거 시 좌우 박스가 538/458 로 어긋났다.
flex-basis:0 이라도 flex 아이템의 border-box 크기는 padding 합보다 작아질 수
없어(좌우 40px x2 = 80px), padding 을 가진 아이템이 그만큼 기본 크기를 더 갖는다.
box-sizing:border-box 로는 해결되지 않는 문제라 래퍼를 되살리고 주석을 정정했다.
같이 빠졌던 minH=25dvh 도 복구(모바일 121px -> 203px, 출력 박스와 동일).
…-git#9 dev-five-git#10)

- dev-five-git#5 탭 borderRadius 를 50% 로 변경
- dev-five-git#6 수학 데모의 입출력부를 MathTransPanel 클라이언트 컴포넌트로 분리,
  MathTrans 는 헤딩만 남기고 use client 제거
- dev-five-git#9 dev-five-git#10 MathTransInput 의 flex=1 두 개 제거, 좌우 폭 분배는 호출부
  (MathTransPanel 의 행)에서 selectors 로 지정
…dev-five-git#4 dev-five-git#5)

dev-five-git#4 의 취지대로 호출부에서 alignItems=center 를 빼 자식이 기본값 stretch 로
펼쳐지게 했다. 덕분에 MathTransInput 루트의 h=100% w=100% 가 불필요해져
제거했고, 가운데 화살표만 alignSelf=center 로 유지한다.
@jessieyeon

Copy link
Copy Markdown
Author

폰트에 라이센스 문제가 없는지 확인합시다, 만약 걱정되면 link 태그를 통해서 해결하면 좋을 것 같아요

지금 KaTeX 폰트는 모두 MIT 라이선스인데 재배포, 상업적 이용에 제약은 없고 저작권 고지 의무가 있어서 public/mathlive/LICENSE.txt에 출처와 라이선스 전문을 추가했습니다.

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
apps/landing/src/app/normalizeFracBraces.ts 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Changepacks

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.

2 participants