임동욱 임동욱 09-22
feat: 표 열 정렬을 디자인팀 규칙(기본 가운데, 제목·긴 글만 왼쪽)으로 맞춘다
통용 관례 적용을 되돌리고(64b5dee) 디자인팀 회신대로 한다 — 목록의 기본은 시안대로 가운데,
제목 열(가맹점명·업체명·메뉴명·제목·콘텐츠명·질문·금지 키워드·코드명·학생명·이벤트/구분)과
긴 글 열(주소·설명·코드설명·질문내용·키워드·이메일)만 align=start로 왼쪽에 둔다. 머리칸은
본문 열을 따른다.

Co-Authored-By: Claude Opus 5 
@a53fd1f5fd3bb1f5ef8f0b78162bfe442ad947cf
@fox/dev-test/component-registry.tsx
--- @fox/dev-test/component-registry.tsx
+++ @fox/dev-test/component-registry.tsx
@@ -3069,7 +3069,7 @@
     id: "fox-table",
     name: "FoxTable",
     description:
-      "Figma 시안 9종(tbl-basic · tbl-list · tbl-form과 각각의 행·칸)을 FoxTable / FoxTableRow / FoxTableCell 셋으로 옮겼습니다. 진짜 <table>이라 스크린리더가 행·열을 읽어 주고 colSpan·rowSpan이 그대로 동작합니다. 머리행은 head만 주면 <thead>로 알아서 갈립니다. 창을 768px 아래로 좁히면 list는 카드로 접히고 form은 레이블이 입력 위로 올라갑니다.",
+      "Figma 시안 9종(tbl-basic · tbl-list · tbl-form과 각각의 행·칸)을 FoxTable / FoxTableRow / FoxTableCell 셋으로 옮겼습니다. 진짜 <table>이라 스크린리더가 행·열을 읽어 주고 colSpan·rowSpan이 그대로 동작합니다. 머리행은 head만 주면 <thead>로 알아서 갈립니다. 창을 768px 아래로 좁히면 list는 카드로 접히고 form은 레이블이 입력 위로 올라갑니다. 열 정렬은 디자인팀 규칙대로 가운데가 기본이고, 제목 열과 긴 글 열(주소·설명·내용)만 align=\"start\"로 왼쪽입니다.",
     variants: [
       {
         label: "list 표 예시 — 시안 699:6304 그대로. 체크·정렬·버튼·고른 줄",
@fox/styles/_fox-table.scss
--- @fox/styles/_fox-table.scss
+++ @fox/styles/_fox-table.scss
@@ -27,6 +27,10 @@
 // 스크린리더가 행·열을 읽지 못한다. 그래서 `list`의 칸은 `label`을 함께 받아 카드에서
 // 열 이름을 글자로 보여 준다.
 //
+// 열 정렬 규약(디자인팀 확정, 2026-09-22) — 목록·기본 표는 **가운데가 기본**이고, **제목 열
+// (emphasis)과 긴 글 열(주소·설명·내용·키워드·이메일)만 `align="start"`** 로 왼쪽에 둔다.
+// 머리칸은 본문 열과 같은 정렬이다(FoxListContainer가 같은 align을 머리칸에도 준다).
+//
 // 토큰이 아닌 값:
 //   - form 머리칸의 최소 크기 12rem×4.8rem: 시안 값이나 Figma가 변수로 export하지
 //     않는다(사용자 승인).
app/(protected)/(basic)/admins/_components/admin-member-list.tsx
--- app/(protected)/(basic)/admins/_components/admin-member-list.tsx
+++ app/(protected)/(basic)/admins/_components/admin-member-list.tsx
@@ -82,6 +82,7 @@
     {
       key: 'email',
       header: '이메일',
+      align: 'start',
       width: FILL_COLUMN_WIDTH,
       render: (row) => formatOptionalValue(row.email),
     },
app/(protected)/(basic)/boards/_components/board-post-columns.tsx
--- app/(protected)/(basic)/boards/_components/board-post-columns.tsx
+++ app/(protected)/(basic)/boards/_components/board-post-columns.tsx
@@ -82,7 +82,7 @@
   return [
     numberColumn(page, pageSize),
     ...(IS_BOARD_CATEGORY_ENABLED ? [categoryColumn()] : []),
-    { key: 'title', header: '제목', width: 320, emphasis: true },
+    { key: 'title', header: '제목', width: 320, align: 'start', emphasis: true },
     {
       key: 'attachment',
       header: '첨부',
@@ -134,7 +134,7 @@
       // 서버가 조인해 준 이름을 그대로 쓴다. 코드표 조회는 이름이 안 온 행의 보루다.
       render: (row) => row.typeName ?? formatFaqTypeLabel(row.typeCode, typeOptions),
     },
-    { key: 'title', header: '제목', width: 320, emphasis: true },
+    { key: 'title', header: '제목', width: 320, align: 'start', emphasis: true },
     {
       key: 'authorName',
       header: '작성자',
@@ -198,6 +198,7 @@
     {
       key: 'content',
       header: '질문내용',
+      align: 'start',
       width: 280,
       emphasis: true,
       render: (row) => formatContentExcerpt(row.content),
app/(protected)/(basic)/contents/comics/_components/comics-list.tsx
--- app/(protected)/(basic)/contents/comics/_components/comics-list.tsx
+++ app/(protected)/(basic)/contents/comics/_components/comics-list.tsx
@@ -58,6 +58,7 @@
     {
       key: 'name',
       header: '콘텐츠명',
+      align: 'start',
       width: 320,
       emphasis: true,
       render: (row) => formatContentText(row.name || row.title),
@@ -65,6 +66,7 @@
     {
       key: 'keywords',
       header: '키워드',
+      align: 'start',
       width: 200,
       render: (row) => formatKeywordsLabel(row.keywords),
     },
app/(protected)/(basic)/contents/quizzes/_components/quizzes-list.tsx
--- app/(protected)/(basic)/contents/quizzes/_components/quizzes-list.tsx
+++ app/(protected)/(basic)/contents/quizzes/_components/quizzes-list.tsx
@@ -59,12 +59,14 @@
     {
       key: 'keywords',
       header: '키워드',
+      align: 'start',
       width: 200,
       render: (row) => formatContentText(formatKeywordsLabel(row.keywords)),
     },
     {
       key: 'question',
       header: '질문',
+      align: 'start',
       width: 360,
       emphasis: true,
       render: (row) => formatContentText(row.question),
app/(protected)/(basic)/contents/shorts/_components/shorts-list.tsx
--- app/(protected)/(basic)/contents/shorts/_components/shorts-list.tsx
+++ app/(protected)/(basic)/contents/shorts/_components/shorts-list.tsx
@@ -58,6 +58,7 @@
     {
       key: 'title',
       header: '제목',
+      align: 'start',
       width: 320,
       emphasis: true,
       render: (row) => formatContentText(row.title || row.name),
@@ -65,6 +66,7 @@
     {
       key: 'keywords',
       header: '키워드',
+      align: 'start',
       width: 200,
       render: (row) => formatKeywordsLabel(row.keywords),
     },
app/(protected)/(basic)/points/accumulated/_components/point-account-list.tsx
--- app/(protected)/(basic)/points/accumulated/_components/point-account-list.tsx
+++ app/(protected)/(basic)/points/accumulated/_components/point-account-list.tsx
@@ -81,7 +81,7 @@
       render: (_row, index) => (currentPage - 1) * query.pageSize + index + 1,
     },
     { key: 'loginId', header: '아이디', width: 140 },
-    { key: 'studentName', header: '학생명', width: 120, emphasis: true },
+    { key: 'studentName', header: '학생명', align: 'start', width: 120, emphasis: true },
     { key: 'schoolName', header: '학교명', width: 160 },
     { key: 'grade', header: '학년', width: 80, align: 'center' },
     { key: 'classNo', header: '반', width: 80, align: 'center' },
app/(protected)/(basic)/points/standards/_components/point-standard-list.tsx
--- app/(protected)/(basic)/points/standards/_components/point-standard-list.tsx
+++ app/(protected)/(basic)/points/standards/_components/point-standard-list.tsx
@@ -65,6 +65,7 @@
     {
       key: 'eventCode',
       header: '이벤트/구분',
+      align: 'start',
       width: 140,
       emphasis: true,
       // 표에 없는 코드는 지어내지 않고 코드 그대로 보여준다(formatCommonCode 규칙).
@@ -95,7 +96,7 @@
         />
       ),
     },
-    { key: 'description', header: '설명', width: 320 },
+    { key: 'description', header: '설명', align: 'start', width: 320 },
     {
       key: 'isActive',
       header: '사용여부',
app/(protected)/(basic)/students/_components/student-list.tsx
--- app/(protected)/(basic)/students/_components/student-list.tsx
+++ app/(protected)/(basic)/students/_components/student-list.tsx
@@ -95,7 +95,7 @@
       width: 160,
       render: (row) => text(formatPhoneNumber(row.phoneNumber)),
     },
-    { key: 'email', header: '이메일', width: 200, render: (row) => text(row.email) },
+    { key: 'email', header: '이메일', align: 'start', width: 200, render: (row) => text(row.email) },
     {
       key: 'role',
       header: '역할',
app/(protected)/(basic)/system/banned-words/_components/banned-word-list.tsx
--- app/(protected)/(basic)/system/banned-words/_components/banned-word-list.tsx
+++ app/(protected)/(basic)/system/banned-words/_components/banned-word-list.tsx
@@ -85,7 +85,7 @@
       width: 100,
       render: (_row, index) => (currentPage - 1) * query.pageSize + index + 1,
     },
-    { key: 'word', header: '금지 키워드', width: 400, emphasis: true },
+    { key: 'word', header: '금지 키워드', align: 'start', width: 400, emphasis: true },
     {
       key: 'createdAt',
       header: '등록일',
app/(protected)/(basic)/system/codes/_components/code-management.tsx
--- app/(protected)/(basic)/system/codes/_components/code-management.tsx
+++ app/(protected)/(basic)/system/codes/_components/code-management.tsx
@@ -146,10 +146,11 @@
       render: (_row, index) => (groupPage - 1) * COMMON_CODE_PAGE_SIZE + index + 1,
     },
     { key: 'comCd', header: '코드ID', width: 120 },
-    { key: 'name', header: '코드명', width: 160, emphasis: true },
+    { key: 'name', header: '코드명', align: 'start', width: 160, emphasis: true },
     {
       key: 'description',
       header: '코드설명',
+      align: 'start',
       width: 156,
       render: (row) => <Truncated text={row.description} />,
     },
@@ -189,10 +190,11 @@
       render: (row) => row.sortSeq,
     },
     { key: 'comDtlCd', header: '상세코드ID', width: 120 },
-    { key: 'name', header: '상세코드명', width: 120, emphasis: true },
+    { key: 'name', header: '상세코드명', align: 'start', width: 120, emphasis: true },
     {
       key: 'description',
       header: '상세코드설명',
+      align: 'start',
       width: 196,
       render: (row) => <Truncated text={row.description} />,
     },
app/(protected)/(basic)/system/menus/_components/menu-tree-list.tsx
--- app/(protected)/(basic)/system/menus/_components/menu-tree-list.tsx
+++ app/(protected)/(basic)/system/menus/_components/menu-tree-list.tsx
@@ -92,6 +92,7 @@
     {
       key: 'name',
       header: '메뉴명',
+      align: 'start',
       width: 420,
       emphasis: true,
       render: (row) => (
app/(protected)/(basic)/system/merchant-details/_components/merchant-detail-list.tsx
--- app/(protected)/(basic)/system/merchant-details/_components/merchant-detail-list.tsx
+++ app/(protected)/(basic)/system/merchant-details/_components/merchant-detail-list.tsx
@@ -201,7 +201,7 @@
         <MerchantThumbnail src={row.thumbnailUrl} alt={`${row.name} 대표이미지`} />
       ),
     },
-    { key: 'name', header: '업체명', width: 220, emphasis: true },
+    { key: 'name', header: '업체명', align: 'start', width: 220, emphasis: true },
     {
       key: 'category',
       header: '카테고리',
@@ -219,6 +219,7 @@
     {
       key: 'address',
       header: '주소',
+      align: 'start',
       width: 280,
       render: (row) => formatOptionalValue(row.address),
     },
app/(protected)/(basic)/system/merchant-details/_components/merchant-product-table.tsx
--- app/(protected)/(basic)/system/merchant-details/_components/merchant-product-table.tsx
+++ app/(protected)/(basic)/system/merchant-details/_components/merchant-product-table.tsx
@@ -59,8 +59,8 @@
         <FoxTable type="list" caption="메뉴 목록">
           <FoxTableRow head>
             <FoxTableCell head width={140} align="center">이미지</FoxTableCell>
-            <FoxTableCell head width={240}>메뉴명</FoxTableCell>
-            <FoxTableCell head>설명</FoxTableCell>
+            <FoxTableCell head width={240} align="start">메뉴명</FoxTableCell>
+            <FoxTableCell head align="start">설명</FoxTableCell>
             <FoxTableCell head width={140} align="center">가격</FoxTableCell>
             <FoxTableCell head width={180} align="center">배지</FoxTableCell>
             <FoxTableCell head width={96} align="center">노출</FoxTableCell>
@@ -79,8 +79,8 @@
                 <FoxTableCell align="center" label="이미지">
                   <MerchantThumbnail src={product.imageUrl} alt={`${product.name} 이미지`} />
                 </FoxTableCell>
-                <FoxTableCell emphasis label="메뉴명">{product.name}</FoxTableCell>
-                <FoxTableCell label="설명">
+                <FoxTableCell align="start" emphasis label="메뉴명">{product.name}</FoxTableCell>
+                <FoxTableCell align="start" label="설명">
                   <span className={styles.description}>
                     {product.description ?? EMPTY_FIELD_PLACEHOLDER}
                   </span>
app/(protected)/(basic)/system/merchants/_components/merchant-list.tsx
--- app/(protected)/(basic)/system/merchants/_components/merchant-list.tsx
+++ app/(protected)/(basic)/system/merchants/_components/merchant-list.tsx
@@ -68,7 +68,7 @@
       render: (_row, index) => (currentPage - 1) * query.pageSize + index + 1,
     },
     { key: 'code', header: '가맹점코드', width: 140 },
-    { key: 'name', header: '가맹점명', width: 240, emphasis: true },
+    { key: 'name', header: '가맹점명', align: 'start', width: 240, emphasis: true },
     {
       key: 'categoryCode',
       header: '업종',
@@ -84,6 +84,7 @@
     {
       key: 'address',
       header: '주소',
+      align: 'start',
       width: 280,
       render: formatAddressSummary,
     },
Add a comment
List