Skip to content

⚙️ Setting: svg sprite setting#14

Merged
jjangminii merged 10 commits intodevelopfrom
setting/#11/svg-sprite-setting
Oct 15, 2025
Merged

⚙️ Setting: svg sprite setting#14
jjangminii merged 10 commits intodevelopfrom
setting/#11/svg-sprite-setting

Conversation

@jjangminii
Copy link
Contributor

@jjangminii jjangminii commented Oct 13, 2025

🔥 작업 내용

  • svg sprite setting

🤔 추후 작업 사항

  • 디자인시스템 토큰 걸러 네이밍 수정후 색상변환 되는지 확인

🔗 이슈

PR Point (To Reviewer)

Icons svg sprite 방식 적용

디자인 시스템에서 icon을 추가할 때 svg icon을 어떻게 사용할지 고민이 필요했어요. 회의를 통해 기존에 svg 파일을 그대로 쓰지 않고 tsx와 같은 컴포넌트 파일로 변경해서 스타일 확장이나, 변경을 용이하게 하자고 결정했지만 svgr/cli 방법에는 다음과 같은 문제가 존재했어요.

많은 svg 파일 존재: 아이콘을 추가할 때마다 svg 파일 + 연관된 tsx 파일 다수 존재
네트워크 오버헤드: 다수의 아이콘이 각 HTTP 요청을 통해 성능 감소
이러한 이유를 통해 svgr/cli로 다수의 tsx를 생성하는 것이 아닌 하나의 svg 파일 안에서 다수의 svg를 정의하고 사용할(use) 아이콘만 선택하여 사용하는 sprite 기법을 선택하게 되었어요.

따라서 generater함수로 source에 있는 원본 svg 리스트(name)를 뽑아와 Icon 컴포넌트에 단 하나의 svg안에 를 통해 svg를 선택하도록 설계하였습니다.

다만 width,height 값이 svg파일에 들어가 있으면 ui가 깨지거나 원하는대로 조정하기가 힘들어 일일이 삭제해줘야하는 번거로움이 있어 svgr로 바꿀까하는 고민이있었습니다. 하지만 다음글에 보면 svgr도 일일이 삭제해줘야하는 번거로움은 동일해보여 svg sprite 방식으로 하기로 결정했습니다.

width,height 자동 삭제

width,height는 개발자가 삭제하거나 피그마에서 export할 때 방식 수정하는 방법이 있었어요. 피그마에서 플러그인 사용해서 설정하는 방식이 익숙하지않아 svgo를 사용해서 명령어로 이미지들의 width,height 가 자동으로 삭제되게하였습니다.

current color 자동 변경

밖에서 컬러 주입하여 사용하려 stroke의 컬러를 기본컬러-> current color로 자동 변환해주는게 1번과 동일하게 svgo 최적화를 적용해두었습니다. 컬러를 따로 입력하지않으면 디폴트로 검정색으로 세팅되고 컬러를 따로 주입하면 해당 컬러로 변합니다 여기서 컬러는 저희 토큰화 되어있는 이름으로만 주입 가능합니다-!

번외로 저희 아이콘에 fill은없고 stroke만 있길래 svgo 자동화로 fill은 none stroke만 currentColor로 변경되게 해뒀습니다 이부분에 대해 다른 생각 있으시면 알려주세요-!!

사용방법

  1. /src/shared/icons/source에 원본 svg를 넣어요.
  2. pnpm icons 을 입력해요
  3. 사용할 파일에서 Icon 컴포넌트를 import 하고 name(필수), width등의 속성을 입력해요.(width,height 디폴트값 20px)
    현재까지 디자인 시스템에 있는 icon들은 다 추가해뒀습니다
//예시
<Icon name='CalendarBlank' size={20} color='gray-900' />
<Icon name='User' size={200} color='blue-400' />
<Icon name='User' width={24} height={24} />

(Icon의 name을 타입화 해둬서 name에 정의 되어 있는 이름이 아닐경우 오류가 발생해요)

명령어 입력하면 자동으로 수정되는 형식이라 source 파일에 원본 파일만 넣고 icons의 파일은 건들면..곤란해져요

📸 피그마 스크린샷 or 기능 GIF

image image

Summary by CodeRabbit

  • New Features

    • Introduced a new icon system with scalable, color-customizable, and rotatable SVG icons.
    • Optimized SVG loading for faster, sprite-based rendering.
    • Updated the homepage to showcase multiple icons.
  • Chores

    • Added scripts to generate and watch icon assets.
    • Implemented SVG optimization and bundling configuration.
  • Style

    • Standardized import quote style across updated files.

@jjangminii jjangminii self-assigned this Oct 13, 2025
@jjangminii jjangminii linked an issue Oct 13, 2025 that may be closed by this pull request
@vercel
Copy link

vercel bot commented Oct 13, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
af-fe Ready Ready Preview Comment Oct 14, 2025 4:38pm

@github-actions github-actions bot added the setting 패키지 설치, 개발 설정 label Oct 13, 2025
@github-actions
Copy link

🏷️ Labeler has automatically applied labels based on your PR title, branch name, or commit message.
Please verify that they are correct before merging.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 13, 2025

Walkthrough

Adds an SVG sprite system: new Icon React component, generated icon name list and index, a generation script, SVGO config, package scripts/deps, and a Next.js webpack hook to process icons directory with svg-sprite-loader; wires icons into the app and uses them on the homepage.

Changes

Cohort / File(s) Summary
Next/Build config & tooling
next.config.ts, svgo.config.mjs, package.json
Adds ICON_DIR handling in Next webpack config to exclude and specially load SVGs via svg-sprite-loader; adds svgo.config.mjs; introduces scripts icons:clean, icons:gen, icons and dependencies clsx, svgo, devDep svg-sprite-loader.
Icons runtime & exports
src/shared/icons/components/icon.tsx, src/shared/icons/index.ts, src/shared/icons/iconNames.ts
New Icon component with props (name, size, color, rotate, etc.); generated iconNames const and IconName type; index that side-effect imports SVG sources and re-exports Icon.
Icon generation script
src/shared/icons/scripts/generate-icon-list.ts
New script that reads source/*.svg, produces iconNames.ts and index.ts (side-effect SVG imports + re-export of Icon), and writes generated files.
App wiring & usage
src/pages/_app.tsx, src/pages/index.tsx
Imports @/shared/icons for side-effect sprite registration; homepage imports and renders multiple Icon components; minor import/style literal adjustments.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer
  participant NPM as NPM Scripts
  participant Gen as generate-icon-list.ts
  participant FS as File System
  participant Repo as Icons Repo

  Dev->>NPM: run icons:gen / icons
  NPM->>Gen: execute script
  Gen->>FS: read src/shared/icons/source/*.svg
  Gen->>Repo: write iconNames.ts (const tuple + type)
  Gen->>Repo: write index.ts (side-effect SVG imports + export { Icon })
  Note over Repo: Generated files used by app build
Loading
sequenceDiagram
  autonumber
  participant Next as Next.js Build
  participant WP as Webpack
  participant Ldr as svg-sprite-loader
  participant App as _app.tsx (side-effect imports)
  participant Icon as Icon Component
  participant DOM as Sprite Sheet

  App->>Next: import "@/shared/icons"
  Next->>WP: compile
  WP->>Ldr: process ICON_DIR SVGs -> generate sprite symbols
  Ldr-->>DOM: emit sprite with <symbol id="icon-...">
  Page->>Icon: render <Icon name="User" />
  Icon->>DOM: <svg><use href="#icon-User"/></svg>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • skyblue1232

Poem

(_/)
(•_•) I stitch small symbols into one bright sheet,
Tiny paths aligned so every icon meets,
I spin a sprite, then hum a nimble tune—
Hop, nibble, push: the sprites are ready soon! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR includes unrelated UI modifications in src/pages/index.tsx and code style changes in src/pages/_app.tsx that are not required for configuring the SVG sprite feature. Consider moving the icon usage demonstration and unrelated formatting fixes into a separate PR or limiting this PR to sprite configuration only.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed Title accurately reflects setting up an SVG sprite configuration, which is the pull request’s primary change.
Linked Issues Check ✅ Passed The pull request fully implements the SVG sprite setup defined in issue #11 by adding webpack configuration, generator scripts, SVGO optimizations, and the Icon component consistent with the linked issue’s requirements.
Description Check ✅ Passed The pull request description closely follows the repository’s template by including the required headings for 작업 내용, 추후 작업 사항, 이슈, PR Point, and screenshots, and provides detailed context on the SVG sprite approach, SVGO optimizations, and usage instructions; however, the PR Point section is present but contains no specific guidance for reviewers.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch setting/#11/svg-sprite-setting

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

🏷️ Labeler has automatically applied labels based on your PR title, branch name, or commit message.
Please verify that they are correct before merging.

@github-actions github-actions bot added comment 필요한 주석 추가 및 변경 style 코드 스타일 변경(기능 변경 없음) labels Oct 13, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (6)
package.json (1)

11-11: Consider adding tsx as a devDependency for consistency.

The icons:gen script uses pnpm dlx tsx, which downloads and executes tsx on-the-fly. While this works, it can lead to inconsistent behavior across environments and slower execution. Consider adding tsx as a devDependency and updating the script to pnpm tsx.

Apply this diff:

   "devDependencies": {
     "@eslint/eslintrc": "^3",
     "@tailwindcss/postcss": "^4",
     "@types/node": "^20",
     "@types/react": "^19",
     "@types/react-dom": "^19",
     "eslint": "^9",
     "eslint-config-next": "15.5.4",
     "svg-sprite-loader": "^6.0.11",
     "tailwindcss": "4.1.14",
+    "tsx": "^4.0.0",
     "typescript": "^5"
   }

Then update the script:

-    "icons:gen": "pnpm dlx tsx src/shared/icons/scripts/generate-icon-list.ts ",
+    "icons:gen": "tsx src/shared/icons/scripts/generate-icon-list.ts",
next.config.ts (1)

10-11: Consider a more type-safe approach to finding the SVG rule.

The current approach uses @ts-ignore and relies on runtime checks. Consider using a type guard or asserting the rule structure more safely.

You could refactor to:

const svgRule = config.module.rules.find((rule): rule is { test: RegExp; exclude?: any } => {
  return (
    typeof rule === 'object' &&
    rule !== null &&
    'test' in rule &&
    rule.test instanceof RegExp &&
    rule.test.test('.svg')
  );
});
src/pages/index.tsx (1)

6-15: Consider moving icon showcase to a dedicated demo page.

While the Icon usage demonstrates the functionality, the production home page might not be the best place for this showcase. Consider creating a separate /icons-demo page or a Storybook setup for icon previews.

src/shared/icons/components/icon.tsx (3)

43-53: Remove redundant className from IconProps.

The className property is already included in React.SVGProps<SVGSVGElement> via React.HTMLAttributes, making this declaration redundant.

Apply this diff:

 interface IconProps extends React.SVGProps<SVGSVGElement> {
   name: IconName;
   size?: number | string;
   width?: number | string;
   height?: number | string;
   color?: IconColor;
-  className?: string;
   rotate?: IconRotate;
   hasRotateAnimation?: boolean;
   ariaHidden?: boolean;
 }

79-84: Consider the inline-block default display.

The inline-block display is always applied, which works well for most use cases but may require overrides in flex or grid contexts where inline-flex or block might be more appropriate.

This is generally acceptable, but document that consumers can override via className if needed, or consider making display configurable if you encounter frequent overrides in practice.


86-99: Consider aria-hidden default for semantic icons.

The ariaHidden default of true is appropriate for decorative icons but may not suit icons that convey semantic meaning without accompanying text. Consumers must remember to set ariaHidden={false} and add aria-label for semantic icons.

Consider either:

  1. Documenting this behavior clearly (when to override ariaHidden)
  2. Detecting when aria-label or aria-labelledby is provided and automatically setting ariaHidden={false}:
const shouldHideFromAria = ariaHidden ?? !(rest['aria-label'] || rest['aria-labelledby']);

// Then use:
aria-hidden={shouldHideFromAria}

Additionally, consider adding a development-mode warning if an icon is missing from the sprite (the <use> element would silently fail):

if (process.env.NODE_ENV === 'development') {
  // Validate icon exists after initial render
  React.useEffect(() => {
    const symbolExists = document.getElementById(`icon-${name}`);
    if (!symbolExists) {
      console.warn(`Icon "${name}" not found in sprite. Did you forget to run "pnpm icons"?`);
    }
  }, [name]);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be34278 and e89e537.

⛔ Files ignored due to path filters (16)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • src/shared/icons/source/CalendarBlank.svg is excluded by !**/*.svg
  • src/shared/icons/source/Caret.svg is excluded by !**/*.svg
  • src/shared/icons/source/ChatCircle.svg is excluded by !**/*.svg
  • src/shared/icons/source/Check.svg is excluded by !**/*.svg
  • src/shared/icons/source/CopySimple.svg is excluded by !**/*.svg
  • src/shared/icons/source/Export.svg is excluded by !**/*.svg
  • src/shared/icons/source/FadersHorizontal.svg is excluded by !**/*.svg
  • src/shared/icons/source/HeartStraight.svg is excluded by !**/*.svg
  • src/shared/icons/source/HouseSimple.svg is excluded by !**/*.svg
  • src/shared/icons/source/MapPin.svg is excluded by !**/*.svg
  • src/shared/icons/source/MapPin_.svg is excluded by !**/*.svg
  • src/shared/icons/source/Save.svg is excluded by !**/*.svg
  • src/shared/icons/source/User.svg is excluded by !**/*.svg
  • src/shared/icons/source/backto.svg is excluded by !**/*.svg
  • src/shared/icons/source/x.svg is excluded by !**/*.svg
📒 Files selected for processing (9)
  • next.config.ts (1 hunks)
  • package.json (2 hunks)
  • src/pages/_app.tsx (1 hunks)
  • src/pages/index.tsx (1 hunks)
  • src/shared/icons/components/icon.tsx (1 hunks)
  • src/shared/icons/iconNames.ts (1 hunks)
  • src/shared/icons/index.ts (1 hunks)
  • src/shared/icons/scripts/generate-icon-list.ts (1 hunks)
  • svgo.config.mjs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
src/shared/icons/scripts/generate-icon-list.ts (2)
eslint.config.mjs (2)
  • __filename (5-5)
  • __dirname (6-6)
src/shared/icons/iconNames.ts (1)
  • iconNames (2-18)
src/shared/icons/components/icon.tsx (2)
src/shared/icons/iconNames.ts (1)
  • IconName (19-19)
src/shared/icons/index.ts (1)
  • Icon (18-18)
src/pages/index.tsx (2)
src/shared/icons/index.ts (1)
  • Icon (18-18)
src/shared/icons/components/icon.tsx (1)
  • Icon (55-100)
next.config.ts (1)
eslint.config.mjs (1)
  • __dirname (6-6)
🔇 Additional comments (6)
src/pages/_app.tsx (1)

1-3: LGTM!

The side-effect import of '@/shared/icons' is necessary to ensure that all SVG sprites are loaded and registered with svg-sprite-loader before any components attempt to use them.

src/shared/icons/index.ts (1)

1-18: LGTM!

This auto-generated file correctly imports all SVG sources as side effects (required for svg-sprite-loader) and re-exports the Icon component. The structure aligns with the generator script's output.

src/shared/icons/iconNames.ts (1)

1-19: LGTM!

This auto-generated file correctly exports a readonly tuple of icon names and derives a union type from it, providing type safety for the Icon component's name prop.

svgo.config.mjs (1)

6-10: All SVG icons are stroke-only
No fill attributes found in src/shared/icons/source; the SVGO config change is safe.

src/shared/icons/components/icon.tsx (2)

1-2: LGTM!

The imports are appropriate: clsx for composing class names and IconName for type safety.


67-77: LGTM!

The size computation correctly prioritizes width/height over size with a sensible default of 20px. The rotation class mapping properly handles Tailwind's standard rotation classes and arbitrary value syntax for 270 degrees.

Comment on lines +9 to +16
const svgRule = config.module.rules.find(
// @ts-ignore
(rule) => rule.test && rule.test.test && rule.test.test('.svg'),
);
if (svgRule) {
// @ts-ignore
svgRule.exclude = [...(svgRule.exclude || []), ICON_DIR];
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Safely handle the svgRule.exclude mutation.

The code assumes svgRule.exclude is either undefined or an array, but it could be a single value (string/RegExp) or have other configurations. Spreading a non-array will cause a runtime error.

Apply this diff to safely handle the exclude property:

     if (svgRule) {
       // @ts-ignore
-      svgRule.exclude = [...(svgRule.exclude || []), ICON_DIR];
+      const currentExclude = Array.isArray(svgRule.exclude)
+        ? svgRule.exclude
+        : svgRule.exclude
+        ? [svgRule.exclude]
+        : [];
+      svgRule.exclude = [...currentExclude, ICON_DIR];
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const svgRule = config.module.rules.find(
// @ts-ignore
(rule) => rule.test && rule.test.test && rule.test.test('.svg'),
);
if (svgRule) {
// @ts-ignore
svgRule.exclude = [...(svgRule.exclude || []), ICON_DIR];
}
const svgRule = config.module.rules.find(
// @ts-ignore
(rule) => rule.test && rule.test.test && rule.test.test('.svg'),
);
if (svgRule) {
// @ts-ignore
const currentExclude = Array.isArray(svgRule.exclude)
? svgRule.exclude
: svgRule.exclude
? [svgRule.exclude]
: [];
svgRule.exclude = [...currentExclude, ICON_DIR];
}
🤖 Prompt for AI Agents
In next.config.ts around lines 9 to 16, the code unsafely spreads
svgRule.exclude assuming it's an array which can throw if exclude is a string,
RegExp, or other value; change the mutation to normalize exclude into an array
first (if Array.isArray(use it), else if exclude is defined wrap it in
[exclude], otherwise use []), then set svgRule.exclude = [...normalizedExclude,
ICON_DIR]; this preserves existing values and avoids spreading non-array types.

<main className='flex flex-col items-center justify-center w-full flex-1 px-4 sm:px-20 text-center'>
<h1 className='text-4xl sm:text-6xl font-extrabold text-gray-900 mb-4'>
초기 세팅 완료
<Icon name='User' width={24} hanging={24} />
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix the typo: hanging should be height.

The prop name hanging is not valid for the Icon component. Based on the Icon component definition, it should be height.

Apply this diff:

-            <Icon name='User' width={24} hanging={24} />
+            <Icon name='User' width={24} height={24} />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Icon name='User' width={24} hanging={24} />
<Icon name='User' width={24} height={24} />
🤖 Prompt for AI Agents
In src/pages/index.tsx around line 10 the Icon component is given an invalid
prop name "hanging"; change that prop to "height" so the component receives the
correct prop (i.e., replace hanging={24} with height={24}) leaving other props
unchanged.

Comment on lines +12 to +14
const files = readdirSync(ICON_DIR, { withFileTypes: true })
.filter((d) => d.isFile() && d.name.toLowerCase().endsWith('.svg'))
.map((d) => d.name);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add error handling for missing or empty icon directory.

If the ICON_DIR doesn't exist or contains no SVG files, the script will proceed to generate empty or incorrect output files without warning.

Apply this diff to add validation:

+import { existsSync } from 'fs';
 import { readdirSync, writeFileSync } from 'fs';
 import { basename, dirname, join } from 'path';
 import { fileURLToPath } from 'url';

 const __filename = fileURLToPath(import.meta.url);
 const __dirname = dirname(__filename);

 const ICON_DIR = join(__dirname, '../source');
 const NAMES_OUT = join(__dirname, '../iconNames.ts');
 const INDEX_OUT = join(__dirname, '../index.ts');

+if (!existsSync(ICON_DIR)) {
+  console.error(`Error: Icon directory not found at ${ICON_DIR}`);
+  process.exit(1);
+}
+
 const files = readdirSync(ICON_DIR, { withFileTypes: true })
   .filter((d) => d.isFile() && d.name.toLowerCase().endsWith('.svg'))
   .map((d) => d.name);
+
+if (files.length === 0) {
+  console.warn(`Warning: No SVG files found in ${ICON_DIR}`);
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const files = readdirSync(ICON_DIR, { withFileTypes: true })
.filter((d) => d.isFile() && d.name.toLowerCase().endsWith('.svg'))
.map((d) => d.name);
import { existsSync } from 'fs';
import { readdirSync, writeFileSync } from 'fs';
import { basename, dirname, join } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const ICON_DIR = join(__dirname, '../source');
const NAMES_OUT = join(__dirname, '../iconNames.ts');
const INDEX_OUT = join(__dirname, '../index.ts');
if (!existsSync(ICON_DIR)) {
console.error(`Error: Icon directory not found at ${ICON_DIR}`);
process.exit(1);
}
const files = readdirSync(ICON_DIR, { withFileTypes: true })
.filter((d) => d.isFile() && d.name.toLowerCase().endsWith('.svg'))
.map((d) => d.name);
if (files.length === 0) {
console.warn(`Warning: No SVG files found in ${ICON_DIR}`);
}
🤖 Prompt for AI Agents
In src/shared/icons/scripts/generate-icon-list.ts around lines 12 to 14, the
code blindly reads ICON_DIR and proceeds even if the directory is missing or
contains no SVGs; update it to validate the directory and file list by wrapping
the readdirSync in a try/catch (or using existsSync/statSync) to produce a clear
error and exit if the directory cannot be read, then check that the filtered SVG
files array has length > 0 and if empty log/throw an informative message and
exit non-zero so downstream file generation is not run with empty input.

Copy link
Contributor

@KongMezu KongMezu left a comment

Choose a reason for hiding this comment

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

SVG 작업 수고하셨습니다 ! 간단한 코드 리뷰 달아놨으니 확인 부탁드립니다
여담으로 추후 작업하면서 SSR 환경이니 만큼, 하이드레이션 오류 발생을 염두하고 작업해야할 듯 합니다!
global.css 부분은 제가 수정해서 올려두도록 하겠습니다

? 'rotate-180'
: rotate === 270
? 'rotate-[270deg]'
: '';
Copy link
Contributor

Choose a reason for hiding this comment

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

이 부분 일관성을 위해 rotate-[270deg] → rotate-270 으로 통일 하는게 좋을거 같습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

진짜 거짓말같은데 Tailwind에는 rotate-90, rotate-180는 있지만 rotate-270는 없다고해요... 그래서 저렇게 되었습니다

hasRotateAnimation && 'transform transition-transform duration-200',
className,
);

Copy link
Contributor

Choose a reason for hiding this comment

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

지금 코드에서는 hasRotateAnimation이 false 일때
회전(rotate)이 적용안될 수 도 있을 거 같아요

'inline-block', ' -> 'inline-block transform',

이렇게 항상 transform 클래스 포함시키도록 하면 어떨까요?

참고문헌
https://tailwindcss.com/docs/transform?utm_source=chatgpt.com
https://tailwindcss.com/docs/transition-property?utm_source=chatgpt.com

skyblue1232
skyblue1232 previously approved these changes Oct 14, 2025
Copy link
Contributor

@skyblue1232 skyblue1232 left a comment

Choose a reason for hiding this comment

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

전체적으로 아이콘 시스템을 자동화하고, 유지보수성 높은 구조로 정리한 점이 인상 깊네요

특히 svg-sprite-loader를 활용해 SVG를 스프라이트 형태로 관리하는 구조는, 추후 확장성 측면에서 좋은 선택이라고 생각합니다. generate-icon-list.ts로 자동화한 것도 실무에서 자주 쓰이는 접근인 것 같습니다!

🍎Good 포인트

  • 아이콘 로테이션 처리
    transform 클래스 항상 포함되게 하신 것도 좋네요!
    회전값만 분기하고 나머지는 일관되게 유지돼서 깔끔한 것 같습니다😊
  • 빌드 자동화 확장
    pnpm icons:clean && pnpm icons:gen으로 자동 생성 파이프라인을 구성한 점이 훌륭합니다. 추가로, 이 작업을 CI/CD에 포함시켜서 커밋 전 자동 실행되게 해놔도 좋을 것 같네요:)
  • 참고 자료
    혹시 이 구조 설계 시 참고하신 블로그나 오픈소스가 있다면 알려주세요🙇‍♂️

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/shared/icons/components/icon.tsx (1)

95-95: Consider accessibility when icons are sole interactive content.

Defaulting ariaHidden to true works well for decorative icons but may require explicit override when an icon is the only content inside buttons or links. Consider documenting this guideline for consumers.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e89e537 and 884af66.

📒 Files selected for processing (3)
  • package.json (2 hunks)
  • src/pages/index.tsx (1 hunks)
  • src/shared/icons/components/icon.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • src/pages/index.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
src/shared/icons/components/icon.tsx (2)
src/shared/icons/iconNames.ts (1)
  • IconName (19-19)
src/shared/icons/index.ts (1)
  • Icon (18-18)
🔇 Additional comments (2)
src/shared/icons/components/icon.tsx (2)

67-68: LGTM! Clean implementation with good fallback patterns.

The dimension fallback logic (width/height → size → 20), className composition with clsx (including the transform class as suggested in past reviews), and dimension-to-px conversion are all well implemented.

Also applies to: 79-86, 91-92


94-94: Verify CSS variable format when resolving IconColor mismatch.

When addressing the IconColor/CSS variable alignment flagged in the previous review, confirm whether the format should be var(--${color}) (current) or var(--color-${color}) depending on the final naming convention chosen for the CSS custom properties.

Based on past review comments.

@skyblue1232
Copy link
Contributor

수고하셨습니다!! 비로 공동 컴포넌트 만들도록 하겠습니다!

@jjangminii jjangminii merged commit 36b3f43 into develop Oct 15, 2025
8 checks passed
@jjangminii jjangminii changed the title Setting: svg sprite setting ⚙️ Setting: svg sprite setting Oct 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comment 필요한 주석 추가 및 변경 setting 패키지 설치, 개발 설정 style 코드 스타일 변경(기능 변경 없음)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[setting] svg sprite 설정

3 participants