시안(관리자페이지 5199:9014)을 다시 대조해 고쳤다. 1·2·5는 내가 잘못 읽은 것이고, 3·4는
@fox에 기능이 없어 추가했다(사용자 확정).
1. 이름 열의 bold를 뺐다. 시안 셀 서체가 `Pretendard:Regular`인데 `emphasis`를 넣었다.
2. 역할을 배지로 바꿨다. 시안 셀에 `type=pastel, color=primary, size=md` 배지가 들어 있는데
평문으로 그렸다.
3. 관리 열을 없애고 행을 눌러 상세를 열게 했다. FoxTableRow에 `onSelect`,
FoxListContainer에 `onRowSelect`를 추가했다. ``에 `role="button"`은 씌우지 않는다 —
보조기술에서 행이 표의 일부가 아니게 되어 열 이름 읽기가 끊긴다. 초점만 받게 하고
Enter·Space를 직접 듣는다. 모달 상태는 student-list가 갖고, 쓰임이 사라진
student-row-actions는 지웠다.
4. 정렬 셀렉트 아이콘을 ArrowsDownUp으로 바꿨다. 시안은 정렬과 페이지 크기가 같은 select-txt를
쓰면서 아이콘만 다른데(노드 293:138376 vs 293:139748), FoxSelectText가 캐럿을 하드코딩해
교체할 수 없었다. `icon` prop을 넣고 기본값은 캐럿 그대로 뒀다.
5. 엑셀 버튼을 secondary + DownloadSimple 아이콘으로 바꿨다. 시안 글자색이
`button/secondary-font`(#0b50d0)이고 20px 아이콘이 붙어 있다.
검증 — 이름 굵기 400, 역할 `fox-badge--primary --pastel --md`, 열 12개(마지막 가입일)에
행이 clickable·tabIndex 0이고 클릭 시 모달이 열린다, 정렬 아이콘이 페이지 크기 아이콘과 다르다,
엑셀 버튼이 `fox-button--secondary`에 아이콘을 갖는다.
Co-Authored-By: Claude Opus 5
시안: 관리자페이지(QsFVFFUKGH68xAPVkF3SJ9) container 5199:9014.
@fox에 없는 조각은 없었다 — 지난 작업의 FoxListContainer가 머리말·도구 줄·표·페이지네이션을
한 번에 덮고, 정렬 셀렉트는 FoxSelectText, 검색은 FoxListSearch, 버튼은 FoxButton이다.
데이터도 이미 맞물려 있었다: StudentMember에 시안의 13열이 전부 있고 StudentMemberQuery에
검색필드·정렬·페이지크기·buildStudentMemberHref가 있다.
- students/_components/student-list.tsx 신설. 이 화면 고유의 것만 갖는다 — 13열 정의,
정렬·페이지 크기 셀렉트, 엑셀 다운로드, URL 갱신 방법.
- page.tsx는 조회만 하고 넘긴다(Server Component 유지).
- student-search-bar · student-list-toolbar · student-table 3종을 지웠다. 셋이 하던 일을
FoxListContainer가 대신한다.
이동은 두 갈래다. 페이지네이션은 `buildHref`로 링크가 되고(주소가 곧 상태), 검색·정렬·페이지
크기는 `router.replace`로 같은 주소 규칙을 태운다. 조건이 바뀌면 늘 1페이지로 되돌린다.
사용자 확정 2건
- 열 폭 합계가 1880px로 컨테이너(1552)보다 넓어 FoxListContainer에 가로 스크롤 래퍼를 넣었다.
좁은 화면에서는 목록표가 카드로 바뀌므로(FoxTable의 mobile 규칙) PC에서만 건다.
- 관리 열을 "학생 회원 조회" 텍스트 버튼으로 바꿨다. 앞서 기획 시안을 근거로 돋보기 아이콘을
넣었으나 이 Figma 시안이 더 최신이다. 누르면 상세 팝업이 열리는 동작은 그대로다.
지킨 것 — 순번은 저장된 값이 아니라 현재 페이지 기준 표시 순번((page-1)*pageSize+index+1)으로
종전 표와 같은 규칙이다. 엑셀은 네이티브 GET 폼이라야 첨부파일 응답을 브라우저가 받는다.
검증 — 실측이 시안과 일치한다. 제목·총 123건·정렬 셀렉트("가입일순"·"10개씩 보기")·검색 대상
"회원명"·엑셀 버튼, 13열 이름 전부, 관리 버튼 "학생 회원 조회", 표 1880/래퍼 1552로 가로
스크롤, 페이지 링크 `/students?page=2`, 모바일용 셀 라벨은 PC에서 display:none.
Co-Authored-By: Claude Opus 5
시안: 관리자페이지(QsFVFFUKGH68xAPVkF3SJ9) container 3019:8608.
시안 조각 대부분은 이미 @fox에 있었다(FoxPageHeader·FoxTable·FoxPagination·FoxSelectText·
FoxChipArea·FoxBadge·FoxButtonGroup). 없던 것은 list-toolbar 하나였고, 그 안의 검색 상자까지
합쳐 셋을 새로 만들었다.
- FoxListSearch: 앞쪽에 검색 대상 셀렉트가 들어가는 상자. FoxInput에는 그 슬롯이 없어 따로
만들었다. `
아코디언(194:3563 box · 194:3680 line)과 카드(441:6006)를 옮겼다.
FoxAccordion — 계열 둘이 성격이 다르다. box는 색을 깐 상자로 여백·모서리를 상자가 갖고
제목이 강조 색이며, line은 위쪽 선 하나로 나뉘는 목록형이라 바탕이 없고 제목 줄이 세로
여백을 갖는다. 크기 lg·md가 여백·글자·모서리를 함께 바꾼다.
열림은 넘기면 호출부가, 안 넘기면 컴포넌트가 쥔다 — 여러 개 중 하나만 열리게 하려면
호출부가 쥐면 된다. 닫히면 내용을 DOM에서 뺀다. 안의 초점 가능한 것들이 탭 순서에 남으면
보이지 않는 곳으로 초점이 사라진다.
FoxCard — 크기 넷은 여백과 모서리만 바꾼다. 폭은 놓이는 자리가 정한다(시안은 320px 자리에
뒀을 뿐 카드 자체의 값이 아니다). 아래쪽 동작 줄은 좌우·아래 여백만 갖는다 — 위쪽은 글
영역의 아래 여백이 이미 띄워 준다.
검증: 아코디언 16항목 중 15개 일치(나머지 1건은 내 예상값 오류였고 코드가 맞다 —
action/secondary는 투명 검정이 아니라 투명 흰색이다). 카드 18항목 전부 일치.
sass 694규칙 · tsc · eslint 통과.
승인된 비토큰 값: 그림 비율 16/9.
Co-Authored-By: Claude Opus 5
제목을 안 넘기면 제목 줄이 통째로 빠져 닫기 아이콘이 내용 위로 내려앉았다. 시안의 tit
프레임은 제목이 없어도 28px(제목 글자 크기 × 줄높이)을 차지한다.
줄은 항상 내고 `
`만 제목이 있을 때 낸다 — 빈 제목을 심으면 이름 없는 heading이 되어
스크린리더가 헛읽는다. 높이는 토큰에서 계산해 브레이크포인트가 바뀌어도 따라간다.
검증: 제목이 있든 없든 제목줄 높이 28 · 위치 41 · 내용 시작 85로 같다. 제목이 없을 때
닫기 아이콘 아래끝 56이 내용 시작 85보다 위라 겹치지 않는다.
Co-Authored-By: Claude Opus 5
시안은 버튼이 80×40인데 51×40으로 나왔다. 최소 폭 80px이 빠져 있었다.
btn 컴포넌트 세트 전체를 뒤져 보니 최소 폭 표기가 한 건도 없다 — 버튼 자체의 성질이
아니라 모달 아래쪽 자리의 규칙이다. 그래서 FoxButton이 아니라 모달 쪽에 준다. 글자가
짧아도 두 버튼의 폭이 같아 보이게 하려는 값이다.
검증: 버튼 80×40 · 묶음 168 · 오른쪽 끝이 내용 영역과 맞는다(시안과 동일).
Co-Authored-By: Claude Opus 5
디자인시스템 파일의 modal(190:1136)을 옮겼다. 크기 넷(sm 400 · md 560 · lg 760 · full)이
모두 폭 토큰이고, 모바일에서는 넷 다 같은 폭으로 모이며 여백·모서리·닫기 버튼도 함께
줄어든다 — 반응형 토큰이 그렇게 정의돼 있다.
네이티브 `
오른쪽 끝에 붙기는 했지만 그건 제목 칸이 `flex: 1`이라 밀려난 결과였을 뿐, 정렬을 선언한
것이 아니었다. 제목 칸이 좁아지거나 빠지면 자리가 흔들린다.
`justify-content: flex-end`와 `margin-inline-start: auto`로 못박고, 안에 든 것이 여러 개라
줄이 넘어가도 오른쪽에 맞도록 자식에도 같은 정렬을 준다.
세로는 시안대로 위 정렬(`align-items: flex-start`)을 유지한다.
Co-Authored-By: Claude Opus 5
관리자페이지 파일의 page-tit-area(3002:6823)를 옮겼다. 현재 위치와 제목을 얹고 본문과의
간격(아래 여백 36px)까지 갖는다 — 시안이 그렇게 묶어 놓아 화면마다 따로 띄우지 않아도 된다.
현재 위치는 FoxBreadcrumb를 그대로 쓴다(시안에서도 breadcrumb 인스턴스다). 항목 배열만
넘기면 되고, 넘기지 않으면 그 줄을 그리지 않는다.
제목은 화면에 하나뿐인 이름이라 `
`으로 낸다. 시안은 `
`지만 그건 Figma에 문단밖에
없어서고, 마크업에서는 제목이 맞다.
`actions` 자리를 열어 뒀다. 시안에 들어간 것은 없지만 배치가 자리를 비워 두고 있다 —
제목 칸이 `flex: 1`이고 오른쪽에 24px 간격이 남는다. 값을 지어내지 않고 그 자리만 연다.
검증: 바깥 간격 24 · 아래 여백 36 · 안쪽 간격 8 · 제목 32px w800 #1e2124 줄높이 48 ·
자간 -0.8px이 시안과 일치. 오른쪽 자리를 쓸 때 제목이 남는 폭을 먹고 24px이 유지되며,
제목이 길어져도 오른쪽을 침범하지 않는다. sass 634규칙 · tsc · eslint 통과.
Co-Authored-By: Claude Opus 5
카탈로그 등록 파일에서 충돌 일곱 구역이 났다. 양쪽이 같은 배열 끝에 항목을 붙였는데
git이 서로 다른 항목의 앞뒤를 맞물려 갈라 놓아, 구역별로 이어 붙이면 남의 항목 머리에
내 항목 꼬리가 붙는다.
그래서 충돌 파일을 손보지 않고 양쪽 원본을 꺼내 항목 단위로 다시 합쳤다. 중괄호를 세어
최상위 항목을 잘라내므로 JSX 안의 괄호나 타입 표기의 대괄호에 속지 않는다.
- 겹치는 항목 없음: 우리 12개(breadcrumb·pagination·carousel 3·bullet-list·badge 3·
table·tab·spinner), 상대 6개(chip·chip-area·select-text·segmented-control 2·
toggle-quantity)
- fox-select는 상대만 고쳤으므로(다중 선택 지원) 그쪽 판을 쓴다
- fox-toggle-switch는 둘 다 고친 것으로 보였지만 뒤에 항목이 붙으며 닫는 괄호가 옮겨진
것뿐이라 실제 충돌이 아니다
components.scss는 자동 병합되며 `@use "fox-toggle-switch"`가 두 번 들어가 Sass가 같은
네임스페이스 중복으로 컴파일을 멈췄다. 중복을 지웠다.
검증: 카탈로그 45개 항목이 모두 뜨고 양쪽 새 컴포넌트가 화면에 그려진다. 파티셜 50개가
빠짐없이 등록돼 있고 배럴도 폴더 수와 같다. sass 630규칙 · tsc · eslint 통과.
Co-Authored-By: Claude Opus 5
전환 중 뜨는 표시가 Tailwind 클래스(animate-spin·border-t-transparent·size-8)로만
그려져 있었는데, Tailwind가 제거된 뒤로 그 클래스들이 정의되지 않아 아무것도 보이지
않는 상태였다. 감싸던 배치 클래스(flex·flex-1·items-center)도 마찬가지였다.
- components/ui/spinner.tsx가 FoxSpinner를 그리도록 바꿨다. size·tone 축은 그대로 둬서
호출부 다섯 곳을 건드리지 않는다(loading.tsx 넷 + 전역 오버레이 하나).
- 계열 색은 CSS 모듈로 옮겼다. FoxSpinner 기본이 테마색이라 inverse·muted만 덮는다.
- 화면 넷의 loading.tsx가 같은 내용이라 PageLoading 공용 컴포넌트로 모으고, 죽어 있던
배치를 CSS 모듈로 되살렸다.
확인한 것: 두 CSS 모듈이 토큰 var()로 컴파일되고, FoxSpinner가 32px에서 시안대로
그려지며, tsc·eslint가 통과한다.
확인하지 못한 것: 전환 화면 자체는 로그인이 필요한 라우트라 눈으로 보지 못했다.
Co-Authored-By: Claude Opus 5
관리자페이지 파일의 img-loading(5384:9710)을 옮겼다. 시안은 80px 그림 한 장으로 왔지만
래스터를 그대로 쓰지 않았다 — 크기를 바꾸면 뭉개지고 색도 토큰을 못 쓴다. 원본 픽셀을
재서 같은 도형을 CSS로 다시 그렸다.
잰 값: 바깥 반지름 40 · 안쪽 28 → 굵기 12px(지름의 15%), 앞머리 원 12px이 6시 자리 고리
중심선 위. 색은 6시에서 시작해 시계방향 60°까지 알파 1.00이고 나머지 300°에 걸쳐 0까지
선형으로 준다(5°마다 샘플링해 확인).
굵기·앞머리를 퍼센트로 잡아 어떤 지름에서도 비율이 같다. `size`만 주면 된다.
FoxButton의 로딩 자리는 "시안 미정"으로 비어 있었는데 이제 이 스피너가 들어간다.
버튼 안에서는 `color: inherit`으로 되돌려 계열별 글자색을 따라간다 — 요소에 준 색이
상속보다 강해서, 기본색을 두는 한 감싸기만으로는 바뀌지 않기 때문이다.
승인된 비토큰 값: 지름 8rem, 굵기·앞머리 15%, 마스크 정지점 70%, 그라디언트 60°.
한 바퀴 도는 시간 1초는 시안이 정지 그림이라 정보가 없어 흔한 기본값을 썼다.
검증: 지름 80 · 색 #256ef4 · 앞머리 12×12가 중심에서 아래로 34px(시안과 동일) ·
그라디언트 from 180deg 0~60deg 불투명. 버튼 세 크기에서 스피너 색이 글자색과 일치하고
아이콘 슬롯 크기를 그대로 채운다.
Co-Authored-By: Claude Opus 5
사이드바 폭 문제의 뿌리가 전역 리셋 부재였다. @fox 컴포넌트는 각자 `box-sizing: border-box`를
선언하지만 앱 쪽에는 기준이 없어 모듈마다 따로 챙겨야 했고, 빠뜨리면 `inline-size: 100%`에
패딩이 더해져 자식이 부모보다 넓어졌다.
globals.scss에 리셋을 넣고, 직전 커밋에서 사이드바 모듈에 넣었던 범위 한정 리셋은 지웠다 —
같은 일을 두 곳에서 하지 않는다.
@fox는 이미 스스로 선언하고 있어 영향이 없다. 검증도 그렇게 나왔다 — 헤더 64/pill 44/아이콘
버튼 40, 사이드바 240·216·216·216·200(3개), 본문 x240·여백 24, 로그인 카드 440·입력 56×360·
버튼 360×56·토글 세로중앙차 0으로 전부 종전과 같다.
Co-Authored-By: Claude Opus 5
원인이 둘이었다.
1. `box-sizing`이 기본값 `content-box`였다. 앱에 전역 리셋이 없고(@fox 컴포넌트는 각자
선언한다) 이 모듈은 `.sidebar`에만 줘서, `inline-size: 100%`에 패딩·테두리가 더해졌다.
2depth 판이 233, 그 안의 행이 231이 됐다(시안 216/200). 이 파일이 그리는 조각 전체에
`border-box`를 적용했다.
2. 테두리가 폭을 먹었다. Figma stroke는 안쪽에 그려지지만 CSS `border`는 박스를 줄인다.
사이드바 오른쪽 구분선 때문에 안쪽 폭이 216에서 215로(사용자가 본 값), 2depth 판의
테두리 때문에 행이 200에서 198로 줄었다. 둘 다 레이아웃에 관여하지 않는 inset 그림자로
같은 선을 그렸다 — 헤더 프로필 pill에서 쓴 것과 같은 처리다.
검증 — 실측이 시안과 일치한다. 사이드바 240, 내부 리스트·1depth 행·2depth 판 216,
2depth 행 200(3개 모두), 즐겨찾기 행 216. 흰 판과 구분선은 그대로 보인다.
Co-Authored-By: Claude Opus 5
버튼·입력칸이 Pretendard가 아니라 Arial 13.33px으로 그려지고 있었다. 폼 조작기는 CSS
명세상 `font`를 상속받지 않는데 그걸 되돌리는 규칙이 없어, 아무도 서체를 지정하지 않은
자리는 브라우저 기본값이 이겼다. 그래서 제목·본문은 Pretendard인데 그 옆 버튼만 다른
서체로 나와 한 화면에 두 서체가 섞였다.
app/globals.scss에 조작기 리셋을 한 번 둔다. 타입 선택자(0,0,1)라 클래스로 서체·크기를
정한 곳은 그대로 이긴다.
확인한 범위:
- @fox 컴포넌트: 글자 크기(17/15/13px)·상자 크기(360×40) 모두 그대로. 서체를 지정하지
않았던 FoxInput의 지우기 버튼만 Arial → Pretendard로 바뀐다(아이콘만 있어 보이는 변화 없음).
- 카탈로그: Arial이던 버튼 49개가 전부 Pretendard로. 크기·굵기는 유지되고 높이만 1px
줄어드는데 서체가 바뀌면서 `line-height: normal` 계산이 달라진 결과다.
- 로그인 화면: 조작기 4개 모두 Pretendard. Arial 0건.
폰트 파일 자체와 시안 대조는 이상이 없었다 — 파일은 정품 Pretendard 400/600/700/800이고,
탭 label(20px/800)의 잉크 폭이 자간 반영 시 42px로 Figma 렌더와 같다.
Co-Authored-By: Claude Opus 5