# @fox — 포터블 디자인 시스템 프로젝트에 종속되지 않는 디자인 시스템. **이 폴더를 통째로 복사하고 설정 몇 줄을 추가하면** 다른 프로젝트에서 그대로 동작합니다. ``` @fox/ styles/ SCSS — 여기가 디자인의 전부입니다 index.scss 토큰 진입점 (앱이 한 번 @use) components.scss 공용 컴포넌트 스타일 묶음 진입점 _fox-*.scss 컴포넌트별 스타일 (개별 @use 가능) abstracts.scss 저작 진입점 — 함수·믹스인 (CSS 출력 0) tokens/ 토큰 map = 단일 진실 공급원 (자동 생성) _root.scss map → --fox-* 커스텀 프로퍼티 _functions.scss fox.color() 등 토큰 접근 + 이름 검증 _mixins.scss fox.pc / fox.mobile core/ components/ React 래퍼 (선택 — 아래 "React 없이 쓰기" 참고) utils/ cx() 등 의존성 없는 유틸 dev-test/ 개발 전용 테스트·감사 화면 tools/build-tokens.py Figma JSON → SCSS 변환기 ``` ## 이식하기 1. `@fox/` 폴더를 대상 프로젝트에 복사합니다. 2. `sass`를 설치합니다. ```bash npm install --save-dev sass ``` 3. **SCSS 로드 경로**를 설정합니다. Next.js면 `next.config.ts`: ```ts sassOptions: { loadPaths: [path.join(process.cwd())] } ``` 다른 번들러면 그 도구의 Sass 옵션(`includePaths` / `loadPaths`)에 프로젝트 루트를 넣으면 됩니다. 이게 있어야 `@use "@fox/styles/..."` 같은 절대 표기가 해석되고, 없으면 컴포넌트마다 `../../../` 상대 경로를 써야 해서 폴더 복사가 불가능해집니다. 4. 글로벌 스타일에서 진입점을 불러옵니다. ```scss @use "@fox/styles"; // 토큰 @use "@fox/styles/components"; // 공용 컴포넌트 스타일 (전부) ``` 골라 쓰려면 묶음 대신 개별 파티셜을 가져옵니다 — 안 쓰는 CSS가 번들에 실리지 않습니다. 둘을 같이 써도 Sass가 모듈을 한 번만 로드해 중복되지 않습니다. ```scss @use "@fox/styles/fox-button"; ``` 5. (TypeScript 프로젝트에서 React 래퍼도 쓸 경우) 경로 별칭을 추가합니다. ```json { "compilerOptions": { "paths": { "@fox/*": ["./@fox/*"] } } } ``` 6. (선택) 폰트를 주입합니다 — 아래 "호스트 앱과의 계약" 참고. ## React 없이 쓰기 **디자인 레이어는 프레임워크에 의존하지 않습니다.** 토큰도 컴포넌트 스타일도 순수 SCSS이고, 클래스명이 `fox-` 접두사 + BEM이라 전역에 풀어도 충돌하지 않습니다. Vue·Svelte·서버 템플릿·순수 HTML 어디서든 위 2~4번만 하고 마크업 계약을 지키면 같은 결과가 나옵니다. 각 컴포넌트의 **마크업 계약은 해당 스타일 파일 상단 주석**에 있습니다. 버튼 네 종류는 이렇습니다. ```html
``` - 비활성은 네이티브 `disabled` 속성으로 표현합니다(별도 클래스 없음). 앵커에는 `disabled`가 없으므로 `aria-disabled="true"`를 쓰고 `href`를 뺍니다. - 로딩은 앞 아이콘 자리에 `fox-button__spinner`를 두고 `disabled`를 함께 겁니다. - 토글은 `fox-icon-button`에 `aria-pressed="true|false"`를 더합니다. - 버튼 묶음은 간격·방향·정렬만 담당합니다. 자식 버튼의 크기 클래스를 그룹 크기로 맞추는 건 작성자 몫입니다(React 래퍼는 `size` prop으로 자동화합니다). 세로(`--vertical`)는 자식이 폭을 채웁니다. - 아이콘 SVG는 `currentColor`로 그려야 계열별 색이 적용됩니다. 크기는 슬롯이 정합니다. `core/`의 React 컴포넌트는 이 클래스를 조립해주는 **얇은 래퍼**일 뿐입니다 — 쓰지 않아도 디자인은 그대로 얻습니다. 토큰만 쓰는 것도 물론 됩니다. ```scss @use "@fox/styles/abstracts" as fox; .whatever { padding: fox.padding(6); color: fox.color(font-neutral-default); @include fox.pc { padding: fox.padding(8); } } ``` ## 핵심 설계 **토큰의 SSOT는 `tokens/`의 SCSS map 하나입니다.** 여기서 두 가지가 함께 파생됩니다 — `_root.scss`가 만드는 `--fox-*` 커스텀 프로퍼티와, `_functions.scss`가 검증에 쓰는 유효 이름 목록. 값과 이름이 한 곳에만 있으므로 둘이 어긋날 수 없습니다. **토큰은 Figma에서 자동 생성됩니다. 손으로 고치지 않습니다.** Figma 변수를 재수출한 뒤 변환기를 다시 돌리면 됩니다. 생성물이 재현 가능해서 재실행 diff가 곧 Figma 변경분입니다. ```bash FOX_TOKENS_SRC=