@teamturing/icons
v2.6.0
Published
Icon components for React based project
Readme
@teamturing/icons
React 프로젝트용 아이콘 컴포넌트. 세 갈래로 나뉜다.
| 엔트리 | 내용 | 형태 | 앞으로 |
| --- | --- | --- | --- |
| @teamturing/icons | 구 자사 아이콘 291개 | 두꺼운 면, fill="currentColor" | 동결 |
| @teamturing/icons/lucide | lucide 1776개 | 선, stroke-width="2" | 업스트림 버전 업 |
| @teamturing/icons/gpai | GPAI 디자인 시스템 아이콘 16개 | 얇은 외곽선 중심, fill="currentColor" | 신규 추가 |
import { SearchIcon } from '@teamturing/icons';
import { SearchIcon as LucideSearchIcon } from '@teamturing/icons/lucide';세 갈래 다 Icon 접미사를 쓴다. 이름이 겹치면 한 파일에서 함께 쓸 때 별칭이 필요하다.
별칭을 써도 번들에는 아무것도 더해지지 않는다.
lucide 이름은 공식 문서의 이름에 접미사만 붙인 형태다. search → SearchIcon,
trash-2 → Trash2Icon.
엔트리끼리는 서로를 참조하지 않는다. 자사 아이콘만 쓰는 앱의 번들에는 lucide 코드가 한 바이트도 들어가지 않는다.
세 갈래를 가르는 것은 스타일이다
"어느 아이콘 세트에 있느냐"가 아니라 어느 디자인 언어로 그려졌느냐로 나뉜다.
gpai는 디자이너가 새로 그리고 있는 GPAI 디자인 시스템의 아이콘이고, 루트 291개는
그 이전 세대다. 같은 개념을 다시 그린 것이 있어 이름이 겹친다.
새로 필요한 아이콘이 생겼다
├─ GPAI 디자인 시스템에 있다 → svg/gpai/ 에 넣는다 (yarn svgr)
└─ 없다 (범용 · 임시) → @teamturing/icons/lucide 에서 가져다 쓴다
거기에도 없으면 lucide-static 버전을 올려 본다루트 svg/의 291개는 동결이다. 새 아이콘을 그쪽에 넣지 않는다. 기존 아이콘의 형태를
고치는 것은 되지만, 목록이 늘어나지는 않는다.
이름이 겹치는 아이콘
현재 gpai 16개 중 10개가 루트에 같은 이름으로 있다 — AiSquareIcon, ArrowCurvedIcon,
ArrowElbowIcon, EyesTwoIcon, LandscapeArrowIcon, PortraitArrowIcon, RootXIcon,
ThunderIcon, TwinkleIcon, YoutubeIcon. 전부 같은 개념을 새 스타일로 다시 그린 것이다.
새로 쓰는 화면이라면 gpai 쪽을 고른다.
import { TwinkleIcon } from '@teamturing/icons/gpai'; // 새 스타일
import { TwinkleIcon as LegacyTwinkleIcon } from '@teamturing/icons'; // 구 스타일한 화면에 두 세대를 섞으면 선 두께가 눈에 띄게 어긋나므로, 화면 단위로 한쪽을 고른다.
lucide와 겹치는 것은 BaselineIcon·BoldIcon 둘이고, 루트와 lucide 사이에는 72개가 겹친다.
gpai는 브랜드 네임스페이스이기도 하다. packages/token-studio가 색을 gpai/aisaac으로
나누는 것과 같은 구분이고, 아이콘도 같은 축을 따른다.
버전
2.0.0부터 lucide가 포함된다. 코드 상으로 깨지는 변경은 없으므로 1.x에서 올라올 때
고칠 것은 없다. 자사 아이콘만 쓰던 앱은 import를 그대로 두면 되고, 번들도 그대로다
(두 엔트리가 서로를 참조하지 않는다).
메이저를 올린 것은 패키지의 성격이 달라졌다는 신호다. 291개짜리 자사 전용 패키지에서 2060개짜리 두 갈래 패키지가 됐고, 앞으로 lucide 업스트림의 아이콘 제거·개명이 이 패키지의 메이저 사유가 된다.
하지 말 것 — 네임스페이스 import
// ✅ 아이콘 하나당 1KB 남짓
import { SearchIcon } from '@teamturing/icons/lucide';
// ❌ 1.07MB — lucide 전체가 번들에 들어간다
import * as Lucide from '@teamturing/icons/lucide';
const Icon = Lucide[iconName];번들러는 어떤 키가 쓰일지 정적으로 알 수 없으면 전부 남길 수밖에 없다. 이름을 런타임에 정해야 한다면 네임스페이스 대신 필요한 아이콘만 담은 맵을 직접 만든다.
import { SearchIcon, SettingsIcon, Trash2Icon } from '@teamturing/icons/lucide';
const ICONS = { search: SearchIcon, settings: SettingsIcon, trash: Trash2Icon };
const Icon = ICONS[iconName];lucide의 선 두께
lucide의 stroke-width="2"는 24px로 그렸을 때 기준이다. 16px나 20px로 줄이면 선도 같은
비율로 얇아져 자사 아이콘 옆에서 흐리게 보인다. 필요하면 strokeWidth로 보정한다.
<SearchIcon width={16} height={16} strokeWidth={3} />react-kit을 쓴다면 StyledIcon의 strokeWidth prop이 같은 일을 한다.
라이선스
이 패키지의 코드는 MIT다. @teamturing/icons/lucide의 아이콘은 lucide에서
파생된 것으로 ISC를 따르고, 그중 search·check·calendar처럼 Feather 프로젝트에서
파생된 약 110개는 별도의 MIT(Copyright (c) 2013-present Cole Bemis)를 따른다.
두 라이선스 모두 저작권 표시와 허가 문구를 사본에 유지할 것을 조건으로 한다. 그래서
THIRD-PARTY-NOTICES.md에 전문을 싣고, 빌드 산출물의 lucide 모듈마다 @license 배너를 붙인다.
배너를 엔트리에만 붙이면 트리셰이킹이 배럴을 걷어낼 때 표시도 함께 사라지므로,
상류인 lucide-react와 마찬가지로 아이콘 파일마다 붙인다.
자사 아이콘 쪽에는 붙지 않는다. lucide를 쓰지 않는 번들에 lucide 표시가 들어가면 그것대로 잘못된 출처 표시이기 때문이다.
아이콘 추가·갱신
yarn svgr # svg/ 와 svg/gpai/ → src/ 와 src/gpai/
yarn svgr:lucide # lucide-static → src/lucide/SVGR은 svg/ 아래 폴더 구조를 그대로 보존하고 폴더마다 index.ts를 따로 생성한다.
그래서 gpai 아이콘은 svg/gpai/에 넣기만 하면 되고, 명령은 기존 yarn svgr 그대로다.
루트 src/index.ts는 하위 폴더의 아이콘을 끌어오지 않으므로 두 엔트리가 섞이지 않는다.
디자이너 export가 맞춰야 할 것은 세 가지다. 24×24 캔버스, viewBox="0 0 24 24",
그리고 단색 아이콘은 #8D94A0으로 그려져 있을 것. #8D94A0만 currentColor로 치환되므로
다른 색으로 넘어오면 에러 없이 그대로 통과하고, 나중에 color가 안 먹는 것으로 드러난다.
여러 색으로 그려진 아이콘은 그대로 두고 이름에 -color를 붙인다.
파일명은 svg/gpai/에서 kebab-case(chart-area-stacked.svg), 루트 svg/에서는
snake_case다. SVGR이 양쪽 다 같은 이름으로 정규화하므로(ChartAreaStackedIcon) 결과는
같지만, 폴더 안에서는 섞지 않는다.
src/·src/gpai/·src/lucide/의 .tsx는 생성물이지만 커밋한다. 빌드가 생성 단계에
의존하지 않아 CI에서 결과가 갈리지 않고, 릴리스에 실제로 무엇이 들어가는지 PR에서 보인다.
yarn svgr 끝에 verify-icons.mjs가 돌아 대소문자 충돌·viewBox 유실·Icon 접미사·
index와 파일 불일치를 검사한다. gpai 아이콘에 색이 하드코딩돼 있으면 경고를 남긴다
(color를 상속하지 못한다 — 다만 여러 색으로 그려진 아이콘이면 정상이므로 실패시키지는 않는다).
lucide 원본 svg만은 커밋하지 않는다. lucide의 search.svg가 디자이너의 search.svg와
이름이 겹치는 데다, 1700개가 넘는 원본을 리포에 넣을 이유도 없다. lucide-static 의존성에서
그때그때 읽어 .lucide-svg/(gitignore)에 모은 뒤 변환한다.
lucide 버전을 올릴 때는 yarn svgr:lucide를 다시 돌린다. 마지막의 verify-lucide.mjs가
개수·export 이름 중복·대소문자 충돌·viewBox 유실을 검사하고 어긋나면 빌드를 멈춘다.
업스트림에서 아이콘이 제거되거나 이름이 바뀌면 breaking change이므로 feat(icons)!로 커밋한다.
브랜드 폴더를 더 만들려면
aisaac 등을 추가할 때는 svg/aisaac/를 만들고 세 곳에 한 줄씩 더하면 된다.
package.json—exports의./aisaac,typesVersions의aisaacrollup.config.js—entry('src/aisaac/index.ts', 'dist/aisaac')tsconfig.esm.json—files에./src/aisaac/index.ts
scripts/verify-icons.mjs의 TARGETS에도 추가한다. SVGR·gen_icon.sh 쪽은 손댈 것이 없다.
