Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@
"react-dom": "^19.1.1"
},
"devDependencies": {
"@pivanov/vite-plugin-svg-sprite": "^3.1.3",
"@eslint/js": "^9.33.0",
"@pinback/design-system": "workspace:*",
"@pinback/eslint-config": "workspace:*",
"@pinback/typescript-config": "workspace:*",
"@pinback/tailwind-config": "workspace:*",
"@pinback/design-system": "workspace:*",
"@pinback/typescript-config": "workspace:*",
"@pivanov/vite-plugin-svg-sprite": "^3.1.3",
"@tailwindcss/vite": "^4.1.12",
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@vitejs/plugin-react-swc": "^4.0.0",
"eslint": "^9.33.0",
"eslint-plugin-react-hooks": "^5.2.0",
Expand Down
1 change: 0 additions & 1 deletion apps/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { useState } from 'react';
import './App.css';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';

function App() {
const [count, setCount] = useState(0);

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"@storybook/addon-vitest": "^9.1.3",
"@storybook/react-vite": "^9.1.3",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@types/react": "19",
"@types/react-dom": "19",
"prettier": "^3.6.2",
"prettier-plugin-tailwindcss": "^0.6.14",
"storybook": "^9.1.3",
Expand Down
2 changes: 0 additions & 2 deletions packages/design-system/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
"@tailwindcss/vite": "^4.1.12",
"@turbo/gen": "^2.5.0",
"@types/node": "^22.15.3",
"@types/react": "19.1.0",
"@types/react-dom": "19.1.1",
"@vitejs/plugin-react": "^4.5.2",
"@vitest/browser": "^3.2.4",
"@vitest/coverage-v8": "^3.2.4",
Expand Down
54 changes: 54 additions & 0 deletions packages/design-system/src/components/badge/Badge.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { within, userEvent } from '@storybook/test';
import Badge, { type BadgeProps } from './Badge';

Check warning on line 3 in packages/design-system/src/components/badge/Badge.stories.tsx

View workflow job for this annotation

GitHub Actions / lint

'BadgeProps' is defined but never used

const meta: Meta<typeof Badge> = {
title: 'Components/Badge',
component: Badge,
tags: ['autodocs'],
args: {
text: '알림',
countNum: 3,
},
argTypes: {
text: { control: 'text', description: '뱃지 라벨 텍스트' },
countNum: {
control: { type: 'number', min: 0 },
description: '카운트 숫자(옵션)',
},
},
parameters: {
docs: {
description: {
component:
'클릭 시 내부 state(isClick)가 true로 바뀌며 스타일이 활성화됩니다. 토글 방식은 아닙니다.',
},
},
},
};

export default meta;
type Story = StoryObj<typeof Badge>;

export const Default: Story = {};

export const NoCount: Story = {
args: { text: '카운트 없음', countNum: undefined },
};

export const LargeCount: Story = {
args: { text: '메시지', countNum: 12000 },
};

export const Clicked: Story = {
args: { text: '클릭해줘', countNum: 5 },
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
await userEvent.click(await canvas.findByText(String(args.text)));
},
parameters: {
docs: {
description: { story: '로드 직후 자동 클릭으로 활성 상태 미리보기.' },
},
},
};
45 changes: 45 additions & 0 deletions packages/design-system/src/components/badge/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { cva } from 'class-variance-authority';
import { useState } from 'react';
export interface BadgeProps {
text: string;
countNum?: number;
}
const BadgeTxtStyleVariants = cva('sub3-b', {
variants: {
click: {
Copy link
Member

Choose a reason for hiding this comment

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

boolean값이니 isClick으로 바꾸는 것은 어떨까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

오 boolean은 최대한 가독성 위해서 is~으로 맞춰서 작업해두겠습니다

true: 'text-font-black-1',
false: 'text-font-ltgray-4',
} as const,
},
defaultVariants: {
click: false,
},
});
const BadgeStyleVariants = cva(
'text-white-bg sub5-sb rounded-[0.4rem] px-[0.8rem] py-[0.4rem]',
{
Comment on lines +18 to +20
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

오타 추정: text-white-bgtext-white

Tailwind/DS 네이밍 관례상 text-white-bg는 비정상입니다. 베이스에 텍스트 색만 두고 배경은 variant에서 제어 중이므로 text-white가 맞습니다.

다음 패치를 제안합니다:

-const BadgeStyleVariants = cva(
-  'text-white-bg sub5-sb rounded-[0.4rem] px-[0.8rem] py-[0.4rem]',
+const BadgeStyleVariants = cva(
+  'text-white sub5-sb rounded-[0.4rem] px-[0.8rem] py-[0.4rem]',
📝 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 BadgeStyleVariants = cva(
'text-white-bg sub5-sb rounded-[0.4rem] px-[0.8rem] py-[0.4rem]',
{
// packages/design-system/src/components/badge/Badge.tsx
const BadgeStyleVariants = cva(
'text-white sub5-sb rounded-[0.4rem] px-[0.8rem] py-[0.4rem]',
{
/* variants… */
}
);
🤖 Prompt for AI Agents
In packages/design-system/src/components/badge/Badge.tsx around lines 18 to 20,
the base cva class string contains a typo "text-white-bg" which should be
"text-white"; update the class list to replace "text-white-bg" with "text-white"
so text color is applied in the base and background variants remain controlled
by the variant definitions.

variants: {
click: {
true: 'bg-main500',
false: 'bg-gray300',
} as const,
},
defaultVariants: {
click: false,
},
}
);
const Badge = ({ text, countNum }: BadgeProps) => {
const [isClick, setIsClick] = useState(false);
return (
<div
className="flex cursor-pointer items-center justify-center gap-[0.8rem]"
onClick={() => setIsClick(true)}
>
<span className={BadgeTxtStyleVariants({ click: isClick })}>{text}</span>
<span className={BadgeStyleVariants({ click: isClick })}>{countNum}</span>
</div>
Comment on lines +34 to +41
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

클릭 가능한 요소의 접근성/키보드 조작 개선 (divbutton)

현재 div에 onClick만 있어 스크린리더/키보드 접근성이 떨어집니다. 토글 동작도 없고 한 번 true가 되면 해제 불가합니다. 버튼 요소와 aria-pressed를 사용하고 토글 처리로 개선하는 것이 좋습니다.

다음 패치를 제안합니다:

-  return (
-    <div
-      className="flex cursor-pointer items-center justify-center gap-[0.8rem]"
-      onClick={() => setIsClick(true)}
-    >
+  return (
+    <button
+      type="button"
+      className="inline-flex items-center gap-[0.8rem] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main500"
+      aria-pressed={isClick}
+      onClick={() => setIsClick((prev) => !prev)}
+    >
@@
-    </div>
+    </button>
📝 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
return (
<div
className="flex cursor-pointer items-center justify-center gap-[0.8rem]"
onClick={() => setIsClick(true)}
>
<span className={BadgeTxtStyleVariants({ click: isClick })}>{text}</span>
<span className={BadgeStyleVariants({ click: isClick })}>{countNum}</span>
</div>
return (
- <div
- className="flex cursor-pointer items-center justify-center gap-[0.8rem]"
- onClick={() => setIsClick(true)}
<button
type="button"
className="inline-flex items-center gap-[0.8rem] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-main500"
aria-pressed={isClick}
onClick={() => setIsClick((prev) => !prev)}
>
<span className={BadgeTxtStyleVariants({ click: isClick })}>{text}</span>
<span className={BadgeStyleVariants({ click: isClick })}>{countNum}</span>
</button>
);

);
};

export default Badge;
1 change: 1 addition & 0 deletions packages/design-system/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default as Button } from './button/Button';
export { Switch } from './switch/Switch';
export { default as Badge } from './badge/Badge';
export { default as Input } from './input/Input';
export { default as Level } from './level/Level';
export { Textarea } from './textarea/Textarea';
Expand Down
2 changes: 1 addition & 1 deletion packages/design-system/src/components/switch/Switch.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import * as SwitchPrimitive from '@radix-ui/react-switch';
import { cn } from '@/lib/utils';
import { cn } from '@lib/utils';

function Switch({
className,
Expand Down
3 changes: 2 additions & 1 deletion packages/design-system/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"outDir": "dist",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
"@/*": ["./src/*"],
"@lib/*": ["./src/lib/*"]
},
"jsx": "react-jsx"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/design-system/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@utils': path.resolve(__dirname, './src/utils'),
'@lib': path.resolve(__dirname, '/src/lib'),
},
Comment on lines 27 to 29
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

중대: @lib 별칭이 절대경로(/src/lib)로 설정됨 — 빌드/스토리북 경로 해석 오류 유발

path.resolve(__dirname, '/src/lib')는 루트 절대경로로 해석됩니다. 로컬 소스에 맞춰 상대 경로 'src/lib'를 사용해야 TS paths와 일관성이 맞고, 번들/테스트에서도 정상 동작합니다.

아래 패치 적용을 권장합니다.

 resolve: {
   alias: {
     '@': path.resolve(__dirname, 'src'),
-    '@lib': path.resolve(__dirname, '/src/lib'),
+    '@lib': path.resolve(__dirname, 'src/lib'),
   },
 },

적용 후 @lib/utils import가 정상적으로 해석되는지 스토리북/빌드를 통해 확인해 주세요.

다음 스크립트로 최소한의 정적 확인을 할 수 있습니다.


🏁 Script executed:

#!/bin/bash
# @lib 사용처 나열 및 실존 파일 확인
rg -nP --type=ts --type=tsx "\@lib/" packages/design-system | sed -n '1,100p'
test -d packages/design-system/src/lib && echo "src/lib 디렉터리 존재" || echo "src/lib 없음"

Length of output: 187


중대한 경로 해석 오류: /src/libsrc/lib로 수정 필요

  • 파일: packages/design-system/vite.config.ts
    대상 라인: 27–29
  • 현상:
    • path.resolve(__dirname, '/src/lib') 호출 시 최상위 루트(/src/lib)로 해석되어 실제 코드 위치(packages/design-system/src/lib)를 가리키지 않습니다.
    • 스크립트 실행 결과 packages/design-system/src/lib 디렉터리가 존재함이 확인되었습니다.
  • 영향:
    • @lib/... import가 빌드 및 스토리북에서 올바르게 해석되지 않아 모듈을 찾지 못하는 오류가 발생합니다.

아래와 같이 패치 적용을 권장합니다:

 resolve: {
   alias: {
     '@': path.resolve(__dirname, 'src'),
-    '@lib': path.resolve(__dirname, '/src/lib'),
+    '@lib': path.resolve(__dirname, 'src/lib'),
   },
 },

적용 후 @lib/utils 등 모든 @lib/ import가 스토리북 및 번들 빌드에서 정상 해석되는지 반드시 확인해 주세요.

🤖 Prompt for AI Agents
In packages/design-system/vite.config.ts around lines 27–29, the alias for
'@lib' uses path.resolve(__dirname, '/src/lib') which resolves to the filesystem
root (/src/lib) instead of the package's src; change it to
path.resolve(__dirname, 'src/lib') (remove the leading slash) so it points to
packages/design-system/src/lib, then rebuild and verify all @lib/... imports
(e.g., @lib/utils) resolve correctly in Storybook and bundle builds.

},
build: {
Expand Down
Loading
Loading