@t3q-ui/design-system 0.0.0-stage โ 1.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1977 -0
- package/LICENSE.md +88 -0
- package/README.md +464 -2
- package/cli/doctor.mjs +196 -0
- package/cli/lib.mjs +425 -0
- package/cli/setup.mjs +181 -0
- package/cli/t3q-design.mjs +78 -0
- package/dist/chunk-IPF3K4BS.js +4274 -0
- package/dist/chunk-IPF3K4BS.js.map +1 -0
- package/dist/chunk-MHAO45AL.cjs +4427 -0
- package/dist/chunk-MHAO45AL.cjs.map +1 -0
- package/dist/fonts.css +12 -0
- package/dist/index-Ci1Wh5sA.d.cts +253 -0
- package/dist/index-Ci1Wh5sA.d.ts +253 -0
- package/dist/index.cjs +10998 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +332 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +2554 -0
- package/dist/index.d.ts +2554 -0
- package/dist/index.js +10354 -0
- package/dist/index.js.map +1 -0
- package/dist/patterns/index.cjs +885 -0
- package/dist/patterns/index.cjs.map +1 -0
- package/dist/patterns/index.css +265 -0
- package/dist/patterns/index.css.map +1 -0
- package/dist/patterns/index.d.cts +373 -0
- package/dist/patterns/index.d.ts +373 -0
- package/dist/patterns/index.js +873 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/styles.css +2014 -0
- package/package.json +212 -4
- package/skills/tds/SKILL.md +91 -0
- package/skills/tds/examples/dashboard-page.tsx +344 -0
- package/skills/tds/examples/detail-page.tsx +388 -0
- package/skills/tds/examples/form-page.tsx +460 -0
- package/skills/tds/examples/list-page.tsx +275 -0
- package/skills/tds/reference/components.md +1424 -0
- package/skills/tds/rules.md +28 -0
package/package.json
CHANGED
|
@@ -1,6 +1,214 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@t3q-ui/design-system",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.56.0",
|
|
4
|
+
"description": "T3Q Design System - React Components",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"typesVersions": {
|
|
10
|
+
"*": {
|
|
11
|
+
"patterns": [
|
|
12
|
+
"./dist/patterns/index.d.ts"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"require": {
|
|
23
|
+
"types": "./dist/index.d.cts",
|
|
24
|
+
"default": "./dist/index.cjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"./patterns": {
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./dist/patterns/index.d.ts",
|
|
30
|
+
"default": "./dist/patterns/index.js"
|
|
31
|
+
},
|
|
32
|
+
"require": {
|
|
33
|
+
"types": "./dist/patterns/index.d.cts",
|
|
34
|
+
"default": "./dist/patterns/index.cjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"./styles.css": "./dist/styles.css",
|
|
38
|
+
"./fonts.css": "./dist/fonts.css"
|
|
39
|
+
},
|
|
40
|
+
"sideEffects": [
|
|
41
|
+
"*.css"
|
|
42
|
+
],
|
|
43
|
+
"bin": {
|
|
44
|
+
"t3q-design": "cli/t3q-design.mjs"
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"dist",
|
|
48
|
+
"cli",
|
|
49
|
+
"skills",
|
|
50
|
+
"CHANGELOG.md",
|
|
51
|
+
"!cli/*.test.mjs"
|
|
52
|
+
],
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsup && node scripts/fix-dts.mjs && npm run build:css",
|
|
55
|
+
"check": "pnpm lint && pnpm typecheck && pnpm build",
|
|
56
|
+
"build:css": "cp src/styles/fonts.css dist/fonts.css && echo '@source \"./**/*.js\";' > dist/styles.css && cat src/styles/tokens.css >> dist/styles.css && cat src/styles/utilities.css >> dist/styles.css && cat src/components/agGridTable/style.css >> dist/styles.css && cat src/components/parameterTable/parameterTable.css >> dist/styles.css",
|
|
57
|
+
"build:dev": "vite build --config vite.config.dev.ts",
|
|
58
|
+
"dev": "vite --config vite.config.dev.ts",
|
|
59
|
+
"dev:watch": "tsup --watch",
|
|
60
|
+
"lint": "eslint src/",
|
|
61
|
+
"test": "vitest run --project unit",
|
|
62
|
+
"test:audit": "vitest run --project audit",
|
|
63
|
+
"test:cli": "vitest run --project cli",
|
|
64
|
+
"test:eval": "vitest run --project eval",
|
|
65
|
+
"eval:judge": "node scripts/eval/judge.mjs",
|
|
66
|
+
"test:a11y": "node scripts/audit/tds-a11y.mjs --ci --md docs/audits/tds-a11y.md --json docs/audits/tds-a11y.json",
|
|
67
|
+
"test:keyboard": "node scripts/audit/tds-keyboard.mjs --ci --md docs/audits/tds-a11y-keyboard.md",
|
|
68
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.examples.json",
|
|
69
|
+
"prepublishOnly": "npm run build && npm run build:css",
|
|
70
|
+
"prepare": "husky && npm run build",
|
|
71
|
+
"storybook": "storybook dev -p 6006",
|
|
72
|
+
"build-storybook": "storybook build && node scripts/mcp/build-skill-reference.mjs",
|
|
73
|
+
"cz": "cz",
|
|
74
|
+
"semantic-release": "semantic-release",
|
|
75
|
+
"audit:tokens": "node scripts/audit/audit-tokens.mjs",
|
|
76
|
+
"audit:mcp": "node scripts/audit/mcp-docs-check.mjs",
|
|
77
|
+
"mcp:serve": "node scripts/mcp/serve-static.mjs",
|
|
78
|
+
"audit:storybook": "node scripts/audit/storybook-export-audit.mjs --md docs/audits/storybook-export-audit.md --json docs/audits/storybook-export-audit.json && node scripts/audit/storybook-ai-readiness.mjs --md docs/audits/storybook-ai-readiness.md --json docs/audits/storybook-ai-readiness.json",
|
|
79
|
+
"eval": "node scripts/eval/run.mjs",
|
|
80
|
+
"eval:init": "node scripts/eval/init-sandbox.mjs",
|
|
81
|
+
"eval:html": "node scripts/eval/html-coverage.mjs",
|
|
82
|
+
"eval:errors": "node scripts/eval/run.mjs errors"
|
|
83
|
+
},
|
|
84
|
+
"peerDependencies": {
|
|
85
|
+
"@dnd-kit/core": "^6.3.1",
|
|
86
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
87
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
88
|
+
"@radix-ui/react-accordion": "^1.2.11",
|
|
89
|
+
"@radix-ui/react-alert-dialog": "^1.1.15",
|
|
90
|
+
"@radix-ui/react-checkbox": "^1.1.4",
|
|
91
|
+
"@radix-ui/react-dialog": "^1.1.6",
|
|
92
|
+
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
|
93
|
+
"@radix-ui/react-label": "^2.1.2",
|
|
94
|
+
"@radix-ui/react-popover": "^1.1.6",
|
|
95
|
+
"@radix-ui/react-progress": "^1.1.2",
|
|
96
|
+
"@radix-ui/react-radio-group": "^1.2.3",
|
|
97
|
+
"@radix-ui/react-select": "^2.1.6",
|
|
98
|
+
"@radix-ui/react-separator": "^1.1.2",
|
|
99
|
+
"@radix-ui/react-slider": "^1.2.3",
|
|
100
|
+
"@radix-ui/react-slot": "^1.1.2",
|
|
101
|
+
"@radix-ui/react-switch": "^1.1.3",
|
|
102
|
+
"@radix-ui/react-tabs": "^1.1.3",
|
|
103
|
+
"@radix-ui/react-toggle-group": "^1.1.0",
|
|
104
|
+
"@radix-ui/react-tooltip": "^1.1.8",
|
|
105
|
+
"ag-grid-community": "^33.2.3 || ^36.0.0",
|
|
106
|
+
"ag-grid-react": "^33.2.3 || ^36.0.0",
|
|
107
|
+
"react": "^18.0.0",
|
|
108
|
+
"react-dom": "^18.0.0",
|
|
109
|
+
"react-hook-form": "^7.0.0",
|
|
110
|
+
"sonner": "^1.7.4 || ^2",
|
|
111
|
+
"tailwindcss": "^4.0.0"
|
|
112
|
+
},
|
|
113
|
+
"dependencies": {
|
|
114
|
+
"@tanstack/react-virtual": "^3.10.0",
|
|
115
|
+
"class-variance-authority": "^0.7.1",
|
|
116
|
+
"clsx": "^2.1.1",
|
|
117
|
+
"cmdk": "^1.0.0",
|
|
118
|
+
"date-fns": "^3.6.0",
|
|
119
|
+
"es-toolkit": "^1.0.0",
|
|
120
|
+
"lucide-react": "^0.468.0",
|
|
121
|
+
"pretendard": "^1.3.9",
|
|
122
|
+
"react-day-picker": "^8.10.1",
|
|
123
|
+
"react-lottie": "^1.2.10",
|
|
124
|
+
"react-textarea-autosize": "^8.5.3",
|
|
125
|
+
"tailwind-merge": "^2.6.0"
|
|
126
|
+
},
|
|
127
|
+
"devDependencies": {
|
|
128
|
+
"@chromatic-com/storybook": "^5.4.0",
|
|
129
|
+
"@commitlint/cli": "^20.4.1",
|
|
130
|
+
"@commitlint/config-conventional": "^20.4.1",
|
|
131
|
+
"@dnd-kit/core": "^6.3.1",
|
|
132
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
133
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
134
|
+
"@eslint/js": "^9.39.1",
|
|
135
|
+
"@radix-ui/react-accordion": "^1.2.11",
|
|
136
|
+
"@radix-ui/react-toggle-group": "^1.1.0",
|
|
137
|
+
"@semantic-release/gitlab": "^13.3.0",
|
|
138
|
+
"@storybook/addon-a11y": "^10.6.1",
|
|
139
|
+
"@storybook/addon-docs": "^10.6.1",
|
|
140
|
+
"@storybook/addon-mcp": "10.6.1",
|
|
141
|
+
"@storybook/addon-onboarding": "^10.6.1",
|
|
142
|
+
"@storybook/addon-vitest": "^10.6.1",
|
|
143
|
+
"@storybook/mcp": "10.6.1",
|
|
144
|
+
"@storybook/nextjs-vite": "^10.6.1",
|
|
145
|
+
"@tailwindcss/postcss": "^4.1.3",
|
|
146
|
+
"@tailwindcss/vite": "^4.1.18",
|
|
147
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
148
|
+
"@testing-library/react": "^16.3.2",
|
|
149
|
+
"@testing-library/user-event": "^14.6.1",
|
|
150
|
+
"@types/node": "^22.15.21",
|
|
151
|
+
"@types/react": "^18.3.18",
|
|
152
|
+
"@types/react-dom": "^18.3.5",
|
|
153
|
+
"@types/react-lottie": "^1.2.10",
|
|
154
|
+
"@typescript-eslint/eslint-plugin": "^8.48.0",
|
|
155
|
+
"@typescript-eslint/parser": "^8.48.0",
|
|
156
|
+
"@vitejs/plugin-react": "^5.1.4",
|
|
157
|
+
"@vitest/browser-playwright": "^4.0.16",
|
|
158
|
+
"@vitest/coverage-v8": "^4.0.16",
|
|
159
|
+
"ag-grid-community": "^36.2.0",
|
|
160
|
+
"ag-grid-react": "^36.2.0",
|
|
161
|
+
"commitizen": "^4.3.1",
|
|
162
|
+
"cz-conventional-changelog": "^3.3.0",
|
|
163
|
+
"eslint": "^8.57.1",
|
|
164
|
+
"eslint-config-prettier": "^10.1.8",
|
|
165
|
+
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
166
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
167
|
+
"eslint-plugin-react": "^7.37.5",
|
|
168
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
169
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
170
|
+
"eslint-plugin-storybook": "^10.6.1",
|
|
171
|
+
"globals": "^17.0.0",
|
|
172
|
+
"husky": "^9.1.7",
|
|
173
|
+
"jsdom": "^28.0.0",
|
|
174
|
+
"lint-staged": "^15.5.2",
|
|
175
|
+
"next": "^15.5.6",
|
|
176
|
+
"playwright": "^1.57.0",
|
|
177
|
+
"postcss": "^8.5.3",
|
|
178
|
+
"postcss-cli": "^11.0.0",
|
|
179
|
+
"prettier": "^3.7.3",
|
|
180
|
+
"react-hook-form": "^7.71.1",
|
|
181
|
+
"semantic-release": "^25.0.3",
|
|
182
|
+
"storybook": "^10.6.1",
|
|
183
|
+
"tailwindcss": "^4.1.3",
|
|
184
|
+
"tsup": "^8.3.5",
|
|
185
|
+
"typescript": "^5.7.3",
|
|
186
|
+
"typescript-eslint": "^8.51.0",
|
|
187
|
+
"vite": "^7.3.0",
|
|
188
|
+
"vitest": "^4.0.16"
|
|
189
|
+
},
|
|
190
|
+
"repository": {
|
|
191
|
+
"type": "git",
|
|
192
|
+
"url": "https://github.com/t3q-platform-service/t3q-ui-design-system"
|
|
193
|
+
},
|
|
194
|
+
"keywords": [
|
|
195
|
+
"design-system",
|
|
196
|
+
"react",
|
|
197
|
+
"components",
|
|
198
|
+
"tailwindcss",
|
|
199
|
+
"t3q"
|
|
200
|
+
],
|
|
201
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
202
|
+
"lint-staged": {
|
|
203
|
+
"src/**/*.{ts,tsx}": [
|
|
204
|
+
"eslint --fix",
|
|
205
|
+
"bash -c 'npm run typecheck'"
|
|
206
|
+
]
|
|
207
|
+
},
|
|
208
|
+
"config": {
|
|
209
|
+
"commitizen": {
|
|
210
|
+
"path": "cz-conventional-changelog"
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264"
|
|
214
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tds
|
|
3
|
+
description: '@t3q-ui/design-system(TDS) ๋ก ํ๋ฉด์ด๋ UI ๋ฅผ ๋ง๋ค๊ฑฐ๋ ๊ณ ์น ๋ ์ด๋ค. ํ๋ฉด ์ ํ ๋ถ๋ฅ โ Pattern ์ ํ โ Storybook MCP ์กฐํ โ ์กฐ๋ฆฝ โ ๊ฒ์ฆ ์์.'
|
|
4
|
+
license: Proprietary. See LICENSE.md in the @t3q-ui/design-system package
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# TDS ๋ก ํ๋ฉด ๋ง๋ค๊ธฐ
|
|
8
|
+
|
|
9
|
+
๊ท์น 9๊ฐ๋ `AGENTS.md` ์ TDS ๋ธ๋ก์ ์๋ค(ํญ์ ์ ์ฉ). ์ด Skill ์ ๊ทธ ๊ท์น์ ์งํค๋ฉฐ **์ ํ๋ฉด์ ๋ง๋๋ ์์**๋ค.
|
|
10
|
+
|
|
11
|
+
## ์ ์ฐจ
|
|
12
|
+
|
|
13
|
+
1. **ํ๋ฉด ์ ํ์ ์ ํ๋ค.** ์์ฒญ์ List / Detail / Form / Dashboard ์ค ํ๋๋ก ๋ถ๋ฅํ๊ณ ์๋ ํ๋ก Pattern ์ ๊ณ ๋ฅธ๋ค.
|
|
14
|
+
2. **Pattern ๋ถํฐ ์์ํ๋ค.** `@t3q-ui/design-system/patterns` ์์ import ํ๋ค. ํค๋ยท๋ณธ๋ฌธยท์ํ ํ์๋ Pattern ์ด ๊ฐ์ง๋ค. ๋ง๋ Pattern ์ด ์์ ๋๋ง PageHeader + Component ๋ก ์กฐ๋ฆฝํ๋ค.
|
|
15
|
+
3. **์กฐํํ๋ค.** MCP `docs-list` ๋ก ID ๋ฅผ ์ฐพ๊ณ , `docs-show <id>` ๋ก propsยทvariantยท"์ธ์ ์ฐ๋" ๋ฅผ ์ฝ๊ณ , ํ์ํ๋ฉด `docs-show-story` ๋ก ์์ ์ฝ๋๋ฅผ ๋ณธ๋ค. MCP ๋ฅผ ๋ถ๋ฅด์ง ์๊ฑฐ๋ ์์ผ๋ฉด ์ด Skill ์ [reference/components.md](reference/components.md)(๊ฐ์ ๋ด์ฉ โ IDยท์ธ์ ์ฐ๋ยทpropsยท์์ ์ฝ๋, ํจํด์ด ๋จผ์ )๋ฅผ ์ฝ๊ณ , ๊ทธ๊ฒ๋ ์์ผ๋ฉด `node_modules/@t3q-ui/design-system/dist/index.d.ts`ยท`dist/patterns/index.d.ts` ๋ฅผ ์ฝ๋๋ค. ํ์
์ ์ธ์๋ ์์ ์ฝ๋๊ฐ ์๋ค(2026-10-27 ํ๋์์ 13: d.ts ๋ง ์ฝ์ run ์ด MCP ๋ฅผ ๋ถ๋ฅธ run ๋ณด๋ค Patternยทprops ๋ฅผ ๋ ์ผ๋ค).
|
|
16
|
+
4. **์กฐ๋ฆฝํ๋ค.** ๋ฐ์ดํฐ ์กฐํยท์ํ ๊ด๋ฆฌ๋ ์ฑ์ด, ๋ฐฐ์นยท์ํ ํ์๋ Pattern ์ด ๋งก๋๋ค. ๋น ์ํ(`empty`)ยท๋ก๋ฉ(`loading`)ยท์ค๋ฅ(`error` + `onRetry`)๋ฅผ ๋ฐ๋์ ๋๊ธด๋ค. ํ์ด์ง๋ ์ฑ ๋ ์ด์์์ `<main>` ํ๋ ์์ ๋๋ **`<main>` ์ paddingยทmax-widthยท๋ฐฐ๊ฒฝ์ ์ฃผ์ง ์๋๋ค**(Pattern ์ด ํค๋ ๋ ์ ๋ณธ๋ฌธ ์ฌ๋ฐฑ 24px ์ ๊ฐ์ง๋ค โ `<main className='p-8'>` ๋ก ๊ฐ์ธ๋ฉด ํค๋๊ฐ ๊ฐ์ฅ์๋ฆฌ์์ ๋ ๋ณด์ธ๋ค, 2026-10-18 ํ ์ค ํ). **์์ฒญ๋ฌธ์ ์์ยท๋์์ ๋น ์ง์์ด**(๊ท์น 9) โ Pattern ์ ์๋ ๊ฒ์ ์๋ตํ์ง ๋ง๊ณ ์ฌ๋กฏ(`filters`ยท`titleRight`ยท`detail`ยท`banner`ยท`footer`ยท`note`ยท`actionsNote`) ์์ Component ๋ก ๋ง๋ ๋ค.
|
|
17
|
+
5. **๊ฒ์ฆํ๋ค.** ํ์
๊ฒ์ฌยท๋น๋๋ฅผ ๋๋ฆฐ๋ค. ์ง์ ์ด `<button>`/`<input>`/`<table>`, raw hex, `red-500` ๊ฐ์ ๊ธฐ๋ณธ ํ๋ ํธ, `bg-[#โฆ]` ๊ฐ์ ์์๊ฐ์ด ์๋์ง ํ๋๋ค. ๋ง์ง๋ง์ผ๋ก ์์ฒญ๋ฌธ์ ์ฒดํฌ๋ฆฌ์คํธ๋ก ์ผ์ ์ดยทํํฐยท์ ๋ ฌ ํ์ยท์์ธ ํญ๋ชฉยท๋ฒํผ๊ณผ ๋นํ์ฑ ์ฌ์ ยทํ์ธ ์ฐฝยท๋ก๋ฉ/๋น/์ค๋ฅยท์ ์ถ ์ค ์ํ๋ฅผ ํ๋์ฉ ๋์กฐํ๋ค.
|
|
18
|
+
|
|
19
|
+
## ์์ โ ๋จผ์ ์ด์ด ๋ณธ๋ค
|
|
20
|
+
|
|
21
|
+
- ๋ชฉ๋ก ํ๋ฉด: [examples/list-page.tsx](examples/list-page.tsx) โ ๊ฒ์ยทํํฐ(์ํ์ ๊ฑด์ ๋ฑ์ง ์ธ๊ทธ๋จผํธ) โ ํ(์ ๋ ฌ ๊ฐ๋ฅ ์ด์ `sortable: true` ๋ก ์์ด์ฝ์ด ๋ณด์, ์ด๋ฆ ์๋ ๋ณด์กฐ ์ค์ `secondaryField`) โ ํ ํด๋ฆญ ์์ธ ํจ๋(`detail` ์ฌ๋กฏ, ๋ชฉ๋ก ์ค๋ฅธ์ชฝ์ ๋๋ํ, ๋นํ์ฑ ์ฌ์ ๋ `note`) โ ์ญ์ ํ์ธ. TDS ์ ์ฅ์์์ ํ์
๊ฒ์ฌยท๋ ๋ ํ
์คํธ๋ฅผ ํต๊ณผํ ์ฝ๋๋ค. ์ ๋ชฉ๋ก ํ๋ฉด์ ์ด ๊ตฌ์กฐ๋ฅผ ๋ณต์ฌํด ์์ํ๊ณ , ํ๋ยท์ปฌ๋ผ๋ง ๊ณผ์ ์ ๋ง๊ฒ ๋ฐ๊พผ๋ค.
|
|
22
|
+
- ์์ธ ํ๋ฉด: [examples/detail-page.tsx](examples/detail-page.tsx) โ ํค๋(์ํยท**๋ฉํ `meta` ํ ๊ณณ**(`MetaGroup columns={3}` + `MetaItem` โ IDยท๋ฒ์ ยท์์ ์ยท์์ ์ผ ๋ฑ ํต์ฌ ์ ๋ณด, ํญ ์์ ํญ์)ยทํ๋ ์ฌ๋กฏ) โ ํญ(๊ฑด์ ๋ฑ์ง) โ ๋ณธ๋ฌธ ์ ํญ โ ์ญ์ ํ์ธ. ๋ฉํ ์๋ฆฌ๋ฅผ ๋ ๊ฐ๋ก ๋๋์ง ์๋๋ค(2026-10-30 ์ฌ์ฉ์ ๊ฒฐ์ โ ๋ณ๋ ์์ฝ ์์ ์์). ์ค๋ฅธ์ชฝ ํจ๋(`aside`)์ ์ฐ์ง ์๋๋ค(์งง์ ์ค๋ฅธ์ชฝ ํจ๋์ ์ฒซ ํ๋ฉด ์๋๊ฐ ๋น์ด ํ๋์์ 9~12 ์ฐ์ ๊ฐ์ ). ์์ธ ํ๋ฉด์ ์๋ด ํ ์ค(`actionsNote`)์ ๋์ง ์๋๋ค(๋ณธ๋ฌธ ์์ ๋ ๋ณด์ฌ 4๋ผ์ด๋ ์ฐ์ ๊ฐ์ , 2026-10-18 11์ฐจ) โ ๋นํ์ฑ ๋ฒํผ์ ๋นํ์ฑ์ผ๋ก๋ง, ์ํ ์๋ด๋ `banner`. ์ค๋ฅยท์์์ `error`/`notFound` prop. ๊ฐ์ ํญ์ ์์ฝ ํจ๋ + ์ต๊ทผ Nํ ํ.
|
|
23
|
+
- ์์ฑยท์์ ํผ: [examples/form-page.tsx](examples/form-page.tsx) โ PageHeader โ ์น์
4๊ฐ โ ๋๋ฅด๋ฉด ๊ฒ์ฆ(`FormMessage`) โ ์ ์ถ ์ค ์ํ(`submitting`, ๋ฒํผ ์ ๊ธยท์ค๋ณต ์ ์ถ ๋ฐฉ์ง) โ ์ทจ์ ํ์ธ โ ์ฑ๊ณต toast. ์ ํ์ง ๋ก๋ฉ ์คํจ๋ ํผ์ ์ ์งํ ์ฑ ๊ทธ ์น์
์์ `Alert variant='danger'` ํ ์ค + `AlertActions` ๋ค์ ์๋.
|
|
24
|
+
- ๋์๋ณด๋: [examples/dashboard-page.tsx](examples/dashboard-page.tsx) โ ์์ฝ ํ์ผ(`ratio`ยท`tone`) โ ๊ธฐ๊ฐ ์ ํ + SVG ์ถ์ด ์ฐจํธ โ ํ โ `EventList`. ์ค๋ฅยท์์์ `error`/`empty` prop.
|
|
25
|
+
- ๋ค ์์ ๋ชจ๋ ๊ฐ์ ๊ตฌ์กฐ๋ค: ๋ฐ์ดํฐ๋ `fetch*` prop ์ผ๋ก ๋ฐ๊ณ , ์ํ(๋ก๋ฉยท์ค๋ฅยท์์)๋ ํจํด prop ์ผ๋ก ๋๊ธฐ๊ณ , ํ๋ฉด ์กฐ๋ฆฝ๋ง ํ๋ค.
|
|
26
|
+
|
|
27
|
+
## ํ๋ฉด ์ ํ โ Pattern
|
|
28
|
+
|
|
29
|
+
| ํ๋ฉด | Pattern | ์ธ์ ์ฐ๋ |
|
|
30
|
+
| ---------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
+
| ๋ชฉ๋ก | `ListPage` | ๊ฒ์/ํํฐ โ ํ โ ์์ธ ์ง์
ํ๋ฆ์ ๋ฆฌ์์ค ๋ชฉ๋ก |
|
|
32
|
+
| ์์ธ | `DetailPage` | ๋ฆฌ์์ค ํ๋์ ์์ธ. ํต์ฌ ์ ๋ณด๋ ํค๋ `meta` ํ ๊ณณ(`MetaGroup columns={3}` + `MetaItem`) โ ๋ณธ๋ฌธ ์ ํญ. `aside` ๋ ์ฐ์ง ์๋๋ค. ํ๋ ๋ฒํผ์ `deleteAction`ยท`secondaryActions`ยท`primaryAction` ์ฌ๋กฏ โ ํจํด์ด ์ ๋ชฉ ์ค ์ค๋ฅธ์ชฝ์ [๋๋ณด๊ธฐ โฏ][๋ณด์กฐ โค2][์ฃผ ํ๋]์ผ๋ก ๋๊ณ ์ญ์ ๋ โฏ ๋ฉ๋ด ์ |
|
|
33
|
+
| ์
๋ ฅ โ ์ ์ฉ URL | `FormPage` | ์คํฌ๋กค์ด ์๊ธฐ๋ ๊ธด ํผ โ ์น์
3๊ฐ ์ด์, ํ ํ๋ฉด์ ๋๊น, ๋๋ ์ฌ๋ฌ ๋จ๊ณ. ์์ฑยท์์ ํ๋ฉด์ ๊ธฐ๋ณธ |
|
|
34
|
+
| ์
๋ ฅ โ ๋ชฉ๋ก ์์ | `FormDrawer` | ๋ชฉ๋ก ๋งฅ๋ฝ์ ์ ์งํด์ผ ํ๊ณ **Drawer ํ ํ๋ฉด ์์ ๋ค์ด๊ฐ๋** ํผ(์น์
1~2๊ฐ). ์คํฌ๋กค์ด ์๊ธฐ๋ฉด FormPage |
|
|
35
|
+
| ์
๋ ฅ โ ์งง๊ฒ | `FormDialog` | ์ด๋ฆ ๋ณ๊ฒฝยทํ๊ทธ ์ถ๊ฐ์ฒ๋ผ ํ๋ 1~4๊ฐ |
|
|
36
|
+
| ๋์๋ณด๋ | `DashboardLayout` + `DashboardSection`(`columns`) + `DashboardPanel` | ์ซ์ ํ์ผยท์ฐจํธ๋ก ํ์ฌ ์ํ๋ฅผ ํ๋์ |
|
|
37
|
+
|
|
38
|
+
๋๋๋ฆด ์ ์๋ ์์
์ ํ์ธ๋ง ๋ฐ์ ๋๋ Pattern ์ด ์๋๋ผ `AlertDialog` ๋ฅผ ์ด๋ค.
|
|
39
|
+
|
|
40
|
+
**ํผ์ ์ด๋์ ๋๋** โ ํ๋ ์์ ์คํฌ๋กค๋ก ์ ํ๋ค(CarbonยทShopifyยทAtlassian ์ ๊ด๋ก์ ๊ฐ๋ค, 2026-10-13): ํ๋ 1~4๊ฐ โ `FormDialog`, ๋ชฉ๋ก ๋งฅ๋ฝ์ด ํ์ํ๊ณ Drawer ํ ํ๋ฉด ์์ ๋ค์ด๊ฐ๋ฉด โ `FormDrawer`, ์คํฌ๋กค์ด ์๊ธฐ๊ฑฐ๋ ์น์
์ด ์
์ด์์ด๊ฑฐ๋ ์ฌ๋ฌ ๋จ๊ณ๋ฉด โ `FormPage`. **๊ธด ํผ์ Drawer ๋ Dialog ์ ๋ฃ์ง ์๋๋ค.** ํผ ์์ ํ ์ด, ๋ผ๋ฒจ์ ์, ์น์
์ ๋ชฉ์ผ๋ก ๋ฌถ๊ณ (FormSection), ์ ์ฅ ๋ฒํผ์ ์ ๊ทธ์ง ์๋๋ค(`submitMode='always'`). **FormPage ์๋ ๊ฒํ ํจ๋(`aside`)์ ํญ์ ๋๋ค** โ ์ง๊ธ๊น์ง ์
๋ ฅํ ๊ฐ์ ์์ฝ๊ณผ ์์ ๋น์ฉยท์ํฅ์ฒ๋ผ ์ ์ถ ์ ์ ํ์ธํ ๊ฒ์ ๋ณด์ฌ ์ค๋ค(์์ form-page.tsx ์ `aside`). ํผ ์ด๋ง ๋๊ณ ์ค๋ฅธ์ชฝ์ ๋น์ฐ์ง ์๋๋ค.
|
|
41
|
+
|
|
42
|
+
## ์์ฃผ ํ๋ฆฌ๋ ๊ฒ
|
|
43
|
+
|
|
44
|
+
- Pattern ๋ณธ๋ฌธ์ ์ด๋ฏธ `<section>` landmark ๋ค. `<main>` ์ผ๋ก ๋ ๊ฐ์ธ์ง ์๋๋ค. ์ฑ์ `<main>` ์๋ `p-8`ยท`max-w-*`ยท๋ฐฐ๊ฒฝ์ ์ฃผ์ง ์๋๋ค โ Pattern ์ด ํค๋ ๋ (ํ๋ฉด ๋๊น์ง)์ ๋ณธ๋ฌธ ์ฌ๋ฐฑ(24px)์ ๊ฐ์ง๋ฏ๋ก, ๊ฐ์ธ๋ฉด ํค๋๊ฐ ๊ฐ์ฅ์๋ฆฌ์์ 32px ๋ ๋ณด์ธ๋ค(2026-10-18 ํ ์ค ํ run). **์ฌ์ด๋๋ฐยท์๋จ๋ฐ ๊ฐ์ ์ฑ ์
ธ์ ์๋ก ๊ทธ๋ฆฌ์ง ์๋๋ค** โ ๊ณผ์ ๋ ํ์ด์ง ํ๋์ด๊ณ Pattern ์ด ํค๋(์ ๋ชฉยทํ๋)๋ฅผ ๊ทธ๋ฆฐ๋ค. ์
ธ์ด ๊ผญ ํ์ํ๋ฉด `DashboardLayout` ์ ์ฐ๊ณ , `fixed` ์ฌ์ด๋๋ฐ๋ก Pattern ์ ๋ฎ์ง ์๋๋ค(2026-10-20 17์ฐจ: Codex ๊ฐ ๊ทธ๋ฆฐ ์ฌ์ด๋๋ฐ๊ฐ ListPage ์ ๋ชฉ์ ๋ฎ์ด 27์ ).
|
|
45
|
+
- `ListPage` ์ `onResetFilters` ๋ **ํญ์** ๋๊ธฐ๊ณ , ํํฐ๊ฐ ์์ ๋๋ `filtersActive={false}` ๋ก ๋ณด์ด์ง ์๊ฒ ํ๋ค(์๋ฆฌ๋ ์ ์ง). ์กฐ๊ฑด๋ถ๋ก ๋๊ธฐ๋ฉด ๋น ๊ฒฐ๊ณผ ํ๋ฉด์์ ๋ฒํผ์ด ํ์ด๋์ ๋ฐฐ์น๊ฐ ๋ฐ๋๋ค. ๋ฒํผ์ ํจํด์ด ๋น ๋ฅธ ํํฐ ์ค ์ค๋ฅธ์ชฝ์ ๊ทธ๋ฆฐ๋ค โ ๊ฒ์์ฐฝ ์์ ์ง์ ๋ง๋ค์ง ์๋๋ค.
|
|
46
|
+
- `ListPage` ์ `tableTitle`("์คํํ๊ฒฝ ๋ชฉ๋ก" ๊ฐ์ ํ ์ ๋ชฉ)์ ๋๊ธฐ์ง ์๋๋ค โ ํค๋ ์ ๋ชฉ๊ณผ ์ค๋ณต์ด๊ณ ๋น ๋ฅธ ํํฐ ์์์ ๋นฝ๋นฝํด ๋ณด์ธ๋ค(2026-10-18 10์ฐจ). ๋น ๋ฅธ ํํฐ ์ค์๋ ์นฉ๊ณผ "ํํฐ ์ด๊ธฐํ"๋ง.
|
|
47
|
+
- **๋ผ์ด๋๋ ํ ๊ณ์ด** โ ๋ฑ์งยทํ๊ทธ 4px, ์นฉยท๋ฒํผยท์
๋ ฅ 6px, ํยท์นด๋ 8px. ์ปดํฌ๋ํธ ๊ธฐ๋ณธ๊ฐ์ด ์ด๋ฏธ ๊ทธ๋ ๋ค. `rounded-full`ยท`shape='rounded'`ยท`rounded='full'` ์ ๋ง์์ pill ์ ๋ง๋ค์ง ์๋๋ค(๊ฐ์ง ๊ฒ ์์ pill ์ ์ธ ๋ผ์ด๋ ์ฐ์ ๊ฐ์ , 2026-10-18 10์ฐจ).
|
|
48
|
+
- ํ์ ๋๋ฌ ๋ณด๋ ์์ธ๋ `ListPage detail={{ title, description, onClose, children, note, footer }}` ๋ก **๋ชฉ๋ก ์ค๋ฅธ์ชฝ์ ๋๋ํ** ์ฐ๋ค(ํ๊ฐ ์ข์์ง๊ณ ๋ชฉ๋ก์ ๊ณ์ ๋ณด์ธ๋ค, ๋ซ๊ธฐ ๋ฒํผยทEsc). `activeRowId={selected?.id ?? null}` ๋ก ์ด๋ฆฐ ํ์ ํ์ํ๊ณ , ์์ธ ํ๋๋ `MetaList` ์์ `MetaRow` ๋ก ์ธ๋ก๋ก ์๋๋ค. `Stack` ์ ๊ธฐ๋ณธ ๋ฐฉํฅ์ด ๊ฐ๋ก๋ผ MetaRow ๋ฅผ ๊ฐ์ธ๋ฉด ์์ผ๋ก ๋์ด์ ์๋ฆฐ๋ค. ํ๋ฅผ ์ขํ๋ฉด ์ ๋ ๋๋ง `<Drawer modal={false}>` ์ ํจ๋(๋ฎ๋ ํํ)์ ์ด๋ค.
|
|
49
|
+
- **`DetailPage asideTitle` ์ ์ฃผ๋ฉด ํจ๋ ์์ ๊ฐ์ ์ ๋ชฉ์ ๋ ์ฐ์ง ์๋๋ค** โ ํจํด์ด ํจ๋ ์ ๋ชฉ์ ๊ทธ๋ฆฌ๋ฏ๋ก ์์ชฝ `MetaList`ยท์นด๋์ "์์
์ ๋ณด" ๊ฐ์ ๋จธ๋ฆฌ๊ธ์ ๋ฐ๋ณตํ๋ฉด ์ ๋ชฉ์ด ์ฐ๋ฌ์ ๋ ๋ฒ ๋ณด์ธ๋ค(2026-10-27 ํ๋์์ 12, ์ฌํ 2๊ฑด). ํจ๋ ์์ ํญ๋ชฉ(`MetaRow`)๋ถํฐ ์์ํ๋ค.
|
|
50
|
+
- **"์์ ๋ฐ์ดํฐ๋ก ๊ตฌ์ฑ๋ ํ์ด์ง์
๋๋ค" ๊ฐ์ ๊ฐ๋ฐ์ ๋ฉด์ฑ
๋ฌธยท'์ํ ๋ฐ์ดํฐ' ๋ฑ์ง๋ฅผ ํ๋ฉด์ ๋ฃ์ง ์๋๋ค** โ ๋ชฉ ๋ฐ์ดํฐ์์ ์ฝ๋ ์ฃผ์์๋ง ์ ๋๋ค. ์ฌํ์ ์ด๋ฅผ ์ ํ ๋ฌธ๊ตฌ์ ๊ฒฐํจ์ผ๋ก ์ฝ๋๋ค(2026-10-27 ํ๋์์ 12, ๋ฌธ๊ตฌ ์ฐจ์ ๊ฐ์ ).
|
|
51
|
+
- **๋ชฉ๋ก์ ๊ฒ์ ์
๋ ฅ์ `ColumnFilter` + `ColumnFilterInput`**(์คํ ๋ฆฌ์ ๊ฐ์ ์กฐํฉ). ํํฐ ์นฉ(`TableFilter*`, ์ฑ์ํ) ์์ `TextField`(์ธ๊ณฝ์ )๋ฅผ ๋ฐ๋ก ๋๋ฉด ๋ ๋ชจ์์ด ์ด๊ธ๋ ๊ฐ์ (2026-10-26 ํ๋์์ 11, ์ฌํ 4๊ฑด). ํ ์
์ ๋ ฌ์ `TableCell align='right'`(`className='text-right'` ๋ ๊ฐ์ ํจ๊ณผ), ์ซ์ ์ด์ `type: 'number'`(cellClass ๋ฅผ ๋ํด๋ ์ ๋ ฌ์ด ์ ์ง๋๋ค), ๊ธ์ก ์๋ ์ฌ์ฉ๋ ๊ฐ์ ๋ ์ค ์
์ `TwoLineCellRenderer`(์ง์ flex ๋ก ๋ ์ค์ ๊ทธ๋ฆฌ๋ฉด ์ยท์๋๋ก ๋ฒ์ด์ง๋ค).
|
|
52
|
+
- ์ ๋ ฌํ ์ ์๋ ์ด์ `sortable: true` ๋ฅผ **๋ช
์**ํ๋ค โ ์ ๋ ฌ ์ ์๋ ์์ด์ฝ์ด ๋ณด์ด๊ณ , ๋๋ฅด๋ฉด ๋ฐฉํฅ์ด ๋ฐ๋๋ค. ์์ฒญ๋ฌธ์ "์ ๋ ฌ ๊ฐ๋ฅ" ์ด ์์ผ๋ฉด ๋ฐ๋์.
|
|
53
|
+
- **๊ฒํ ํจ๋(`aside`)์ด ์๋ ํผ์ ์ทจ์ยท์ ์ถ ๋ฒํผ์ ํจ๋ ๋ฐ๋ฅ** โ FormPage ๊ฐ ๊ทธ๋ฆฐ๋ค(ํผ ๋์ ๋ฐ๋ก ๋์ง ์๋๋ค). ๊ธด ํผ ์์์ ํจ๋์ด ์งง๊ฒ ๋๋๊ณ ์ ์ถ์ด ๋ฉ์ด ๋ ์ฌํ ๋ชจ๋ ๊ฐ์ ํ๋ค(2026-10-20 16์ฐจ). ์์ฝ ํจ๋์๋ ์
๋ ฅ๊ฐ ์์ฝ๊ณผ ์์ ๋น์ฉยท์๊ฐ๋ง.
|
|
54
|
+
- **ํ์ ์งํ๋ฅ ์ด์ ๊ณ ์ ํญ ๋ง๋ + % ๊ธ์ ํ ์ค** โ `<Progress value={p} className='w-[120px]' aria-label={`GPU ์ฌ์ฉ๋ฅ ${p}%`} />` ์ค๋ฅธ์ชฝ์ `tabular-nums` ๋ก `{p}%`. **๋ง๋๋ง๋ค `aria-label` ๋ก '๋ฌด์ ๋ช %' ์ด๋ฆ์ ์ค๋ค** โ ์ด๋ฆ ์๋ progressbar ๋ ํ๋ง๋ค axe serious(17์ฐจ ํ์ดํ๋ผ์ธ ๋ชฉ๋ก 21๊ฑด; DS ๊ฐ ๊ธฐ๋ณธ ์ด๋ฆ '46%' ๋ฅผ ๋ถ์ด์ง๋ง ๋ป์ด ์ฝํ๋ค). ๋ถ์(816 / 1,200)๋ ์์ธ๋ ํดํ์ผ๋ก. ๊ธ์ ์๋ ๋ง๋๋ฅผ ์์ผ๋ฉด ํ๋ง๋ค ๋ง๋ ํญ์ด ๋ฌ๋ผ์ ธ ๊ฐ์ (2026-10-20 ํ๋์์ 8 Codex ๋ชฉ๋ก).
|
|
55
|
+
- ์ ์ถ ์ค ์ํ๋ ์ฑ์ด `const [submitting, setSubmitting] = useState(false)` ๋ก ๊ฐ๊ณ `FormPage submitting={submitting}` ์ ๋๊ธด๋ค(`onSubmit` ์์์ try/finally). FormPage ๊ฐ ๋ฒํผ์ ์ ๊ทธ๊ณ ์คํผ๋๋ฅผ ๋ณด์ด์ง๋ง, ์ํ๊ฐ ์ฝ๋์ ๋๋ฌ๋์ผ ์ค๋ณต ์ ์ถ ๋ฐฉ์ง๊ฐ ํ์ธ๋๋ค.
|
|
56
|
+
- ๋น ๊ฒฐ๊ณผ๋ ํจํด์ด ์์ด์ฝยท์ ๋ชฉยท์ค๋ช
ยท"ํํฐ ์ด๊ธฐํ" ๋ฒํผ ์์๋ก ๊ทธ๋ฆฐ๋ค. `emptyState` ์๋ `{ title: '์กฐ๊ฑด์ ๋ง๋ ๋ชจ๋ธ์ด ์์ต๋๋ค', description: '๊ฒ์์ด๋ ํํฐ๋ฅผ ๋ฐ๊ฟ ๋ณด์ธ์.' }` ๋๋ ๋ ๋ฌธ์ฅ ๋ฌธ์์ด("โฆ์์ต๋๋ค. โฆํด ๋ณด์ธ์.")๋ง ๋๊ธด๋ค. ๋ฒํผยท์์ด์ฝยท`<div>` ๋ฅผ ์ง์ ๋ง๋ค์ด ๋ฃ์ง ์๋๋ค.
|
|
57
|
+
- ๋นํ์ฑ ๋ฒํผ์ `disabled` ๋ก๋ง ๋๋ค. DetailPage ์๋ ์ฌ์ ์๋ด ํ ์ค(`actionsNote`)์ **์ฐ์ง ์๋๋ค**(2026-10-18 11์ฐจ) โ ์ํ ์์ฒด์ ์๋ด๊ฐ ํ์ํ๋ฉด `banner`(Alert). ListPage ์์ธ ํจ๋์ `detail.note` ๋ ๊ทธ๋๋ก. `disabled` ๋ฅผ ๋นผ๋จน๊ณ ๋ฐฐ๋๋ง ๋์ง ์๋๋ค.
|
|
58
|
+
- **`banner` ๋ ์ค๋ฅยท๊ฒฝ๊ณ ์๋ง**(์คํจยท์ค๋จยท๊ถํยท์ญ์ ์์ ). "์คํ์ด ์งํ ์ค์
๋๋ค" ๊ฐ์ ์ํ ์๋ด๋ฅผ ํฐ ๋ฐฐ๋๋ก ์ฌ๋ฆฌ์ง ์๋๋ค โ ์ํ๋ ์ํ `Badge` ๊ฐ ๋ณด์ฌ ์ค๋ค(2026-10-19 14์ฐจ, 13์ฐจ ์์ธ colorยทlayout ๊ฐ์ ).
|
|
59
|
+
- **ํญ ๊ฑด์(`badge`)ยท์งํ๋ฅ ยท"์ต๊ทผ Nํ" ํ์ ํ ์๋ ๊ฐ์ ๋ฐฐ์ด์์ ๊ณ์ฐํ๋ค** โ ์ซ์๋ฅผ ๋ฐ๋ก ์ง์ด ์ฐ๋ฉด ์ฌ์ฌ์๊ฐ ๋ชจ์์ผ๋ก ๋ณธ๋ค("์คํ 18" ํญ vs "15/24 ์๋ฃ"). ์๊ฐยท๊ธฐ๊ฐ์ 0 ๋จ์๋ฅผ ์๋ตํ๋ค("0์๊ฐ 41๋ถ" โ "41๋ถ").
|
|
60
|
+
- **์ฃผ์ ํ๋ ๋ฒํผ ์๋ฆฌ๋ ํจํด์ด ์ ํ๋ค โ ์ ๋ชฉ ์ค ์ค๋ฅธ์ชฝ.** ListPage `actions`ยทDashboardLayout `actions`ยทDetailPage ์ฌ๋กฏ ๋ชจ๋ PageHeader ์ ๋ชฉ ์ค์ ๋์ธ๋ค(2026-10-19 14์ฐจ, PolarisยทGitHub IssuesยทPrimer ๊ด๋ก). ํํฐ ์ค์๋ ๊ฒ์ยทํํฐยท"ํํฐ ์ด๊ธฐํ"๋ง ๋๋ค. **ํ๋ ์ค์๋ ๋ฒํผ๋ง** โ `Tag`ยท`Badge` ๋ฅผ ๋ฒํผ ์์ ๋๋ฉด ๋ฒํผ์ฒ๋ผ ๋ณด์ธ๋ค("the 'GPU ๋
ธ๋' tag looks like the buttons beside it", 2026-10-21 18์ฐจ); ํ๊ทธยท์ข
๋ฅ๋ ์ ๋ชฉ ์ ์ํ ๋ฑ์ง๋ ๋ฉํ ์ค์.
|
|
61
|
+
- ๋ชฉ๋ก์ ์ฃผ ์๋ณ์ ์ด์ ListPage ๊ฐ `onRowClick` ์ด ์์ผ๋ฉด `name` ์ด์ ์๋์ผ๋ก ๊ฐ์กฐํ๋ค(๊ตต๊ฒ, hover ๋ฐ์ค). ์ด๋ฆ ์ด field ๊ฐ `name` ์ด ์๋๋ฉด `primaryField` ๋ก ์ง์ ํ๊ณ , ์
๋ ๋๋ฌ๋ก ํ๋ ๋งํฌ๋ฅผ ์ง์ ๋ง๋ค์ง ์๋๋ค. ํ ์ ์ ๋ชฉยท๊ฑด์๋ `tableTitle` ๊ณผ `pagination.total` ๋ก ๋ณด์ธ๋ค.
|
|
62
|
+
- **์ํ์ฒ๋ผ ์ ํ์ง๊ฐ 3~6๊ฐ์ธ ๋ค์ค ์ ํ ํํฐ๋ `ListPage quickFilter`** ๋ก ํ ์ผ์ชฝ ์์ ์ธ๊ทธ๋จผํธ(ToggleGroup)๋ก ๋๋ค โ ๋๋กญ๋ค์ด์ ์ด์ง ์์๋ ์ ํ์ง๊ฐ ๋ณด์ด๊ณ , `count` ๋ก ํญ๋ชฉ๋ง๋ค ๊ฑด์๋ฅผ ๋ถ์ด๊ณ **`countVariant` ์ ํ์ ์ํ ๋ฑ์ง์ ๊ฐ์ tone**(`STATUS[s].tone`: `success`ยท`secondary`ยท`danger`โฆ)์ ์ค๋ค โ ๊ฑด์๋ ์ํ์ pill ๋ฑ์ง๋ก ๊ทธ๋ ค์ ธ ์นฉ๊ณผ ํ๊ฐ ๊ฐ์ ์ ์ธ์ด๊ฐ ๋๋ค(์์ ์ `statusCounts`; "์ ์ฒด" ๋ ํจํด์ด primary, 2026-10-18 13์ฐจ). ๋๋กญ๋ค์ด์ ์จ๊ธฐ์ง ์๋๋ค. ์ ํ์ง๊ฐ ๋ง๊ฑฐ๋(7๊ฐ ์ด์) ๊ฒ์์ด ํ์ํ ์ถ๋ง `TableFilterSingleSelect`/`TableFilterMultiSelect` ๋ก `filters` ์ ๋๊ณ , ๊ทธ๋๋ `title`(์: 'ํ๋ ์์ํฌ')์ ์ฃผ๋ฉด "ํ๋ ์์ํฌ ยท ์ ์ฒด" ์ฒ๋ผ ๋์์ด ํญ์ ๋ณด์ธ๋ค. placeholder ์ "์ ์ฒด" ๋ง ๋ฃ์ง ์๋๋ค. ์ผ๋ฐ `Select` ๋ฅผ ํํฐ๋ก ์ฐ๋ฉด placeholder ์ "์ ์ฒด ์ํ" ์ฒ๋ผ ๋์ ์ด๋ฆ์ ๋ฃ๋๋ค. ๋ผ๋ฒจ ์์ด "์ ์ฒด" ๋ง ๋ณด์ด๋ ํํฐ๋ฅผ ๋ง๋ค์ง ์๋๋ค.
|
|
63
|
+
- ํ๋ `AgGridTable` ๋ก ๋ง๋ ๋ค. `ag-grid-react` ๋ฅผ ์ง์ ์ฐ์ง ์๋๋ค. ํ ํด๋ฆญ๊ณผ ํค๋ณด๋ Enter ๋ ๊ฐ์ ํ ํด๋ฆญ ํธ๋ค๋ฌ๋ก ๋ค์ด์จ๋ค.
|
|
64
|
+
- ์ฃผ์ ํ๋ ๋ฒํผ(์์ฑยท๋ฑ๋ก)์ `ListPage actions` ์ ๋๋ค โ ํจํด์ด ์ ๋ชฉ ์ค ์ค๋ฅธ์ชฝ์ ๋๋๋ค(์ง์ ํํฐ ์ฌ๋กฏ์ด๋ `titleRight` ์ ๋ฃ์ง ์๋๋ค). `PageHeader actions` ๋ ์ ๋ชฉ ์ค ์ค๋ฅธ์ชฝ(ํญ์ด ์์ด๋ ๊ฐ๋ค, 2026-10-19 14์ฐจ).
|
|
65
|
+
- **์ ํยท๋ฐฉ์ ์ ํ(์์ค ์ ํยท๊ณต๊ฐ ๋ฒ์ยท์
๋ ฅ ๋ฐฉ์์ฒ๋ผ ์ ํ์ง 2๊ฐ ์ด์์ ์ ๋ชฉยท์ค๋ช
์ด ๋ถ๋ ๊ฒ)์ `RadioSectionGroup` + `RadioSection`(์นด๋ํ)** ์ผ๋ก โ dl-ui-v3 ์ ๊ด๋ก(21๊ณณ). ๋ฐฐ์น๋ ๊ทธ๋ฃน์ด ๊ฐ์๋ก ์ ํ๋ค: 1~3๊ฐ ํ ์ค, **4๊ฐ๋ 2ร2, 5๊ฐ ์ด์์ ์ธ๋ก ์๊ธฐ**(์นด๋ ์์ ์ ๋ชฉ ยท ์ค๋ช
๊ฐ๋ก) โ `className` ์ผ๋ก grid ๋ฅผ ์ง์ ์ง์ง ์๋๋ค. ์ค๋ช
์๋ ์งง์ ์ ํ(์ยท์๋์ค)๋ง `RadioGroup`, ์ ํ์ง 7๊ฐ ์ด์ยท๊ฒ์์ด ํ์ํ๋ฉด `Select`. **๋ณต์ ์ ํ์ ์ ๋ชฉยท์ค๋ช
์ด ๋ถ์ผ๋ฉด `CheckboxSectionGroup` + `CheckboxSection`**(์๋ฆผ ์ฑ๋), ์ค๋ช
์๋ ์งง์ ์ต์
๋ง `Checkbox`. **์ผ๊ธฐ/๋๊ธฐ ํ๋์ ์ค์ (๊ท์น ์ฌ์ฉ, ์คํจ ์ ์๋ฆผ, ๋
ธํธ๋ถ ์ง์)์ `SwitchSection`**(๋ฐ์ค + ์ ๋ชฉยท์ค๋ช
+ Switch, dl-ui-v3 ToggleField ๊ด๋ก) โ ํผ ์ ์ถ๊ฐ์ด์ด๋ Checkbox ๋ก ๋ง๋ค์ง ์๋๋ค. ์์ form-page.tsx ์ ์ค์ผ์ค ์ ํ(RadioSectionGroup)๊ณผ ์คํจ ์๋ฆผ(SwitchSection)์ด ๋ณธ๋ณด๊ธฐ(`FormLabel id` + ๊ทธ๋ฃน `aria-labelledby`).
|
|
66
|
+
- ๋ฒํผ ๋ฌถ์ ์ฌ์ด ๊ฐ๊ฒฉ์ 8px. PageHeaderยทDialogยทDrawerยทForm ์ ๋ฒํผ ์ฌ๋กฏ์ด ์ด๋ฏธ ๊ทธ๋ ๊ฒ ๊ทธ๋ฆฐ๋ค.
|
|
67
|
+
- **์ํ ํ์๋ `Badge` ์ ์์ด์ฝ + ๊ธ์** โ `<Badge variant='success'><LucideIcon iconComponentName='circle-check' />์๋ฃ</Badge>`. ์์ด์ฝ์ Badge ์ ์์์ผ๋ก ๋ฐ๋ก ๋ฃ๊ณ (Badge ๊ฐ 16pxยท๊ธ์์์ผ๋ก ๋ง์ถ๋ค), ํฌ๊ธฐ๋ ๊ธฐ๋ณธ(`size` ๋ฅผ ์ฃผ์ง ์๋๋ค โ ๊ฑด์ ๋ฑ์ง์ ๊ฐ์ 20px). **๋ณ๋ ์ํ ์ปดํฌ๋ํธยท๋ํผ๋ฅผ ๋ง๋ค์ง ์๋๋ค**(2026-10-30 ์ฌ์ฉ์ ๊ฒฐ์ โ ์์ ์ ์ํ ์ ์ฉ ๋ํผ๋ ํฌ๊ธฐยท์ฌ๋ฐฑ์ด ๋ฌ๋ผ ํ๊ทธ์ธ์ง ๋ฑ์ง์ธ์ง ๋ชจ๋ฅผ ๋ถํ์ด ๋๋ค). ์ํ๊ฐ โ `variant`ยท์์ด์ฝ ๋งคํ์ ์์ ํ ๊ณณ์. **์ดํ**: ์์
ยท๋
ธํธ๋ถยทํ์ดํ๋ผ์ธยท์๋ฒ์ฒ๋ผ ๋์๊ฐ๋ ํ๋ก์ธ์ค์ '์คํ ์ค' `primary` + `play`(โถ), ํ์ฑยท์ฌ์ฉ ์คยท๊ฐ์ ์คยทํ์ฉยท์ฐ๊ฒฐ๋จ ๊ฐ์ ์ผ์ง ์ํ `primary` + `circle-dot`(โ) โ โถ ๋ฅผ ์ผ์ง ์ํ์ ๋ถ์ด๋ฉด ์ฌ์ ๋ฒํผ์ฒ๋ผ ์ฝํ๋ค(2026-10-21 18์ฐจ), ์๋ฃยท์ค๋น๋จ `success` + `circle-check`(โ) โ ์คํ ์ค์ โ ๋ฅผ ๋ถ์ด๋ฉด ๋๋ ๊ฒ์ผ๋ก ์ฝํ๋ค(2026-10-20 17์ฐจ), ํ์ต ์คยท๋ฐฐํฌ ์ค์ฒ๋ผ ๋์ด ์๋ ์งํ `info` + `loader-circle`(์ ์ ์์ด์ฝ โ ์คํผ๋๋ ์ ์ง ํ๋ฉด์์ ์ ๋ญ์น๋ก ๋ณด์ธ๋ค), ๋๊ธฐ `secondary` + `clock`, ์ค์งยท๋นํ์ฑ `secondary` + `circle-pause`, ์คํจ `danger` + `circle-x`, ๊ฒฝ๊ณ ยท์๋ฆผ ๋ฐ์ `warning` + `triangle-alert`. **ํ ํ๋ฉด์ ๊ฐ์ variant ์ ์ํ ๋์ ๋์ง ์๋๋ค** โ '์ค๋น๋จ'(`success` โ)๊ณผ '์ฌ์ฉ ์ค'(`primary` โ)์ฒ๋ผ ์ํ๋ง๋ค ์์ด ๋ฌ๋ผ์ผ ํ๋ค(2026-10-21 19์ฐจ "two different states look the same"). ๊ธฐ๋ณธ์ ์ฐํ ์ ์ฑ์(`appearance` ๋ฅผ ์ฃผ์ง ์๋๋ค โ 2026-10-18 10์ฐจ). **lucide ์ด๋ฆ์ ์ ์ ์ด๋ฆ๋ง**(`circle-pause`ยท`loader-circle`ยท`triangle-alert`; ์ alias `pause-circle` ๊ฐ์ ๊ฒ์ ์ฐ์ง ์๋๋ค). ๊ฐ์ ํ๋ฉด์ ์ํ ๋ฑ์ง๋ **์ ๋ถ ์์ด์ฝ์ด ์๊ฒ** โ ์์ด๋ฉด ์ฌ์ฌ์๊ฐ ๋ถ์ผ์น๋ก ๋ณธ๋ค. ์์ `variant` ๋ก ์ ํ๊ณ `className` ์ผ๋ก ๋ง์์ฐ์ง ์๋๋ค.
|
|
68
|
+
- **์ฃผ์ ํ๋ ๋ฒํผ์๋ lucide ์์ด์ฝ**์ ๊ธ์ ์์ ๋ถ์ธ๋ค โ ์์ฑ `plus`, ์ญ์ `trash-2`, ์ค์ง `square`, ๋ฐฐํฌ `rocket`, ๋ค์ ์๋ `refresh-cw`, ๋ด๋ณด๋ด๊ธฐ `download`(`<Button variant='primaryBold'><LucideIcon iconComponentName='plus' /> ์์ฑ</Button>`). `LucideIcon` ์ ๊ธฐ๋ณธ ํฌ๊ธฐ๋ 16px ์ด๊ณ ๋ฒํผ ์ ์์ด์ฝ์ ๊ทธ ํฌ๊ธฐ๋ก ๋๋ค(`size={20}`ยท`24` ๋ฅผ ์ฃผ๋ฉด ๋ฒํผ๋ณด๋ค ์ปค ๋ณด์ธ๋ค). ์์ด์ฝ ์๋ ๊ธ์ ๋ฒํผ๋ง ๋์ด๋์ง ์๋๋ค.
|
|
69
|
+
- **์ซ์ ์ด(๊ฐ์ยทํฌ๊ธฐยท๋น์จยท์๊ฐ)์ `type: 'number'`** โ AgGridTable ์ด ์
๊ณผ ์ ๋ชฉ์ ์ค๋ฅธ์ชฝ ์ ๋ ฌํ๊ณ ์ซ์ ํญ์ ๊ณ ์ ํ๋ค(์
๋ ๋๋ฌ๊ฐ ์์ด๋ ์ ์ฉ). ํญ์ ์ ์ฃผ๋ฉด 140 ์ผ๋ก ์ก๋๋ค(ag-grid ๊ธฐ๋ณธ 200 ์ ์ซ์ ์ด์ด ๋น์ด ๋ณด์ธ๋ค โ 2026-10-27 ํ๋์์ 13 layout ์ง์ "wide empty area"). ์ซ์๋ฅผ ์ผ์ชฝ ์ ๋ ฌ๋ก ๋์ง ์๋๋ค.
|
|
70
|
+
- **์์ธ ํจ๋ยท์ค๋ฅธ์ชฝ ์ ๋ณด ์ด์ ํ๋๋ `MetaRow align='start'`** โ ๊ฐ์ด ๋ผ๋ฒจ ๋ฐ๋ก ์์ ๋ถ๋๋ค. ๊ธฐ๋ณธ(`end`)์ ๊ฐ์ ํ ์ค๋ฅธ์ชฝ ๋์ ๋์ด ๋์ ํจ๋์์ ๋ผ๋ฒจ๊ณผ ๊ฐ ์ฌ์ด๊ฐ ๋น๋ค.
|
|
71
|
+
- **์งํ ๋ง๋์ ์์ ์ํ์ ๋ง์ถ๋ค** โ ์คํจํ ์์
์ `Progress variant='danger'`, ๊ฒฝ๊ณ ๋ `warning`, ์๋ฃ๋ `success`. ์คํจํ ์์
์ ํ๋ ๋ง๋๋ฅผ ๋์ง ์๋๋ค.
|
|
72
|
+
- **ํค๋ `meta` ์ ์ด ๊ฐ(IDยท๋ฒ์ ยท์์ ์ยท์์ ์ผ)์ ๋ณธ๋ฌธ Panel ์ ๋ค์ ์ฐ์ง ์๋๋ค** โ ๊ฐ์ ๊ฐ์ด ๋ ๋ฒ ๋ณด์ฌ๋ ์ฌ์ฌ์๊ฐ ์ค๋ณต์ผ๋ก ๋ณธ๋ค. ํค์๋ยท๋ถ๋ฅ ํ๊ทธ๋ `Tag variant='secondary'`(๊ธฐ๋ณธ ๊ฐ์ง 4px) โ ์ํ ๋ฑ์งยท์นฉยท์
๋ ฅ๊ณผ ๊ฐ์ ๋ผ์ด๋ ๊ณ์ด. pill(`shape='rounded'`)๋ก ๊ทธ๋ฆฌ์ง ์๋๋ค(2026-10-18 10์ฐจ).
|
|
73
|
+
- **์ค๋ช
๋ฌธ์ฅ์ PageHeader `description` ํ ๊ณณ์๋ง.** ๊ฐ์ ๋ฌธ์ฅ์ ๋ณธ๋ฌธ ์ยท์นด๋ ์์ ๋ค์ ์ฐ์ง ์๊ณ , ๋ณธ๋ฌธ์ "์ค๋ช
" Panel ์ ๋ฐ๋ก ๋ง๋ค์ง ์๋๋ค(์์ detail-page ์ ๊ฐ์ด โ ๊ฐ์ ๋ฌธ์ฅ์ด ๋ ๋ฒ ๋ณด์ด๋ฉด ์ฌ์ฌ์๊ฐ ์ค๋ณต์ผ๋ก ๋ณธ๋ค). ๋ณธ๋ฌธ์ `<p>` ์๋ด๋ฌธ์ ์ฌ์ฉ์๊ฐ ์ง๊ธ ํด์ผ ํ ์ผ์ด ์์ ๋๋ง. ๋ณธ๋ฌธ ๋ฌธ๋จ์๋ `break-keep wrap-break-word` ๋ฅผ ๋ถ์ธ๋ค(ํ๊ตญ์ด๊ฐ ๋จ์ด ์ค๊ฐ์์ ๊บพ์ด์ง ์๊ฒ).
|
|
74
|
+
- **์์ธ ๊ฐ์ ํญ์ ๋ธ๋ก(์ ๋ณดยทํยท๋ชฉ๋ก)์ ์ ๋ถ `Panel` ์์** โ ํ ๋ธ๋ก๋ `Panel title='์ต๊ทผ ์คํ' titleRight={<Button variant='primaryLink'>์ ์ฒด ๋ณด๊ธฐ</Button>}` ์์ ๋ฃ๊ณ , ์ ๋ชฉ(`h2`) + ํ๋ฅผ ๋งจ๋ชธ์ผ๋ก ๋์ง ์๋๋ค(์ด์์ด ์นด๋์ธ๋ฐ ํ๋๋ง ์นด๋ ๋ฐ์ด๋ฉด "sits outside a card unlike its neighbors", 2026-10-21 18์ฐจ ์์ธ 4/6 run). **์นด๋ ์์ ํ๋ ์์ ์ฒ๋ผ `Table`(๊ฐ๋ฒผ์ด ํ)๋ก** โ `AgGridTable`(ํ์ ๋จธ๋ฆฌ์คยท๋ฅ๊ทผ ํ
๋๋ฆฌ ์์)์ ๋ชฉ๋ก ํ๋ฉด๊ณผ ์ ์ฉ ํญ์๋ง ์ฐ๊ณ ์นด๋ ์์ ๋ฃ์ง ์๋๋ค("bordered table header inside the jobs card while the other cards use plain rows", 2026-10-21 19์ฐจ). **๊ฐ์ ํญ์ ์์ฝ ํจ๋ + ์์ ํ** โ `Panel '์ฃผ์ ์ ๋ณด'`(MetaList) ์๋ `Panel '์ต๊ทผ ๋ฐฐํฌ'`(๋๋ ์ต๊ทผ ์คํยท์ต๊ทผ ๋ฒ์ ) Table **4์ดยท5ํ๊น์ง**(์ด๋ฆยท์ํยทํต์ฌ ์งํ 1ยท์๊ฐ) + `titleRight` ์ '์ ์ฒด ๋ณด๊ธฐ' ๋งํฌ(`Button variant='primaryLink'`)๋ก ์ ์ฉ ํญ. ์ด์ด ๋ ํ์ํ ํ๋ ์ ์ฉ ํญ์์ โ ํจํด์ด `aside` ์๋ ํญ์ **์ ์ฒด ํญ**์ผ๋ก ๊ทธ๋ฆฐ๋ค(GitHub PR ์: Conversation ์ 2๋จ, Files changed ๋ ์ ์ฒด ํญ). ์ด 5~7๊ฐ ํ๋ฅผ 2/3 ์ด์ ๋ฃ์ผ๋ฉด ์ด๋ฆยท๋ ์ง๊ฐ ์ค๋ฐ๊ฟํด ๋ ์ฌํ ๋ชจ๋ ๊ฐ์ (2026-10-19 15์ฐจ). ํจ๋ ํ๋๋ง ๋๋ฉด ์ค๋ฅธ์ชฝ ์ด ์๋๊ฐ ๋น์ด "large empty area" ๊ฐ์ (11์ฐจ).
|
|
75
|
+
- **์์ธ ์ฃผ ํ๋์ ์์ฐ์ ํ๋ ํ๋** โ `primaryAction` ์ ๋ฐฐํฌยท์คํยท์ ์ฅ์ฒ๋ผ ๋๋๋ฆด ์ ์๋ ๊ฒ. ์ค์งยท์ญ์ ยท์ด๊ธฐํ๋ `secondaryActions`(ํ์) ๋๋ โฏ ๋ฉ๋ด(`deleteAction`) โ primary ํ๋๋ ๋นจ๊ฐ ์ฑ์๋ ์ฃผ์ง ์๋๋ค(5์ฐจ ๋นจ๊ฐ ๋ฒํผยท15์ฐจ ํ๋ "์คํ ์ค์ง" ๊ฐ์ ).
|
|
76
|
+
- **์ํ ๋จ์ด๋ ํ ํ์์** โ ์ํ๊ฐ โ ๋ผ๋ฒจยทtone ๋งคํ ๊ฐ์ฒด ํ๋๋ฅผ ํค๋ ๋ฑ์งยทํยทํญ์ด ๊ฐ์ด ์ด๋ค("์งํ ์ค" vs "์คํ ์ค" ์ฒ๋ผ ๊ฐ๋ฆฌ๋ฉด ๊ฐ์ , 15์ฐจ). ์งํ๋ฅ ์ "์๋ฃ 10 / ์ ์ฒด 12 ยท ์คํจ 2" ์ฒ๋ผ ํ์ด ์ด๋ค.
|
|
77
|
+
- **์์ด์ฝยท๊ธ์** โ ์ค์ง๋ `circle-stop`(`square` ๋ ์ฒดํฌ๋ฐ์ค๋ก ์ฝํ). ํ๊ทธยท๋ฑ์ง ๊ธ์๋ ํ๊ตญ์ด, ์๋ฌธ์ ๊ณ ์ ๋ช
์ฌ๋ง("Best run" ๊ฐ์ ์ฅ์ ์๋ฌธ ๊ฐ์ , 15์ฐจ).
|
|
78
|
+
- **์์ธ ๋ณธ๋ฌธ ๊ตฌ์ญ์ `Panel title='โฆ'` ์์ `MetaList`** โ ๊ตฌ์ญ๋ง๋ค ์์ ํ๋, ์์ ์ฌ์ด 16px. `Separator`ยท`Card`ยท๋งจ `<h2>` ๋ก ๋๋์ง ์๋๋ค. ์ ํจ๋(`aside`)ยท๋ชฉ๋ก์ ์์ธ ํจ๋(`detail`)ยทํผ์ ๊ฒํ ํจ๋(`aside`)์ ํจํด์ด ๊ฐ์ Panel ๋ก ๊ทธ๋ฆฌ๋ฏ๋ก ์์ ์์๋ฅผ ๋ ๋๋ฅด์ง ์๋๋ค. ํ(`Table`ยท`AgGridTable`)๋ ์๊ธฐ ์์๊ฐ ์์ผ๋ Panel ๋ก ๊ฐ์ธ์ง ์๋๋ค.
|
|
79
|
+
- **ํผ ์ ๊ฒํ ยท์์ฝ ํจ๋์ `FormPage aside={โฆ} asideTitle='๊ฒํ '`** ๋ก โ ํจํด์ด ํผ ์ด ์์ ์ธ๋ก์ ์ผ๋ก ๊ตฌ๋ถํด sticky ๋ก ๋ฐ๋ผ์ค๊ฒ ๊ทธ๋ฆฐ๋ค(์ข์ผ๋ฉด ํผ ์๋). FormPage ๋ฅผ `<div className='flex'>` ๋ก ๊ฐ์ธ ์์ `<aside>` ๋ฅผ ๋์ง ์๋๋ค: ํค๋๊ฐ ํ๋ฉด ํญ์ ๋ค ๋ชป ์จ ๊ตฌ๋ถ์ ์ด ํจ๋์์ ๋๊ธฐ๊ณ , ํจ๋์ด ์ค๊ฐ์์ ์๋ฆฐ๋ค. Card(๊ทธ๋ฆผ์)๋ก ๋ง๋ค์ง๋ ์๋๋ค. FormPage ๋ ํค๋ ๋ด์ฉ๊ณผ ๋ณธ๋ฌธ์ ๊ฐ์ ๊ฐ์ด๋ฐ ํญ(ํจ๋ ์์ผ๋ฉด 1152, ์์ผ๋ฉด 720)์ ๊ฐ๋๋ค(2026-10-26 22์ฐจ) โ ๋ฐ๊นฅ์์ `max-w`ยท`mx-auto` ๋ก ๋ ๊ฐ์ธ์ง ์๋๋ค.
|
|
80
|
+
- **๋ ์งยท์๊ฐ ์
๋ ฅ์ `DatePicker`ยท`TimePicker` ๋ก, ํผ ์นธ์ ์ฑ์ฐ๊ฒ** โ ๊ธฐ๋ณธ ํญ์ด 250ยท160px ๋ผ ๋ ์นธ ์ค์์ ์ ๋ฐ์ด ๋น๋ค(2026-10-28 ํ๋์์ 14, OpusยทGemini "date/time fields leave a lot of unused space"). `DatePicker classNames={{ button: 'w-full' }}`ยท`TimePicker classNames={{ trigger: 'w-full' }}`(๋ ๋ถํ์ ํต๋ก ์ด๋ฆ์ด ๋ค๋ฅด๋ค). `<input type='date'>` ๋ฅผ ์ง์ ์ฐ์ง ์๋๋ค.
|
|
81
|
+
- **๋ชฉ ๋ฐ์ดํฐ๋ ์๋ฏธ๊ฐ ๋ง๊ฒ, ์๋ ํ๋ฉด์ ์ฑ์ธ ๋งํผ** โ ํ์คํฌยทํ๋ ์์ํฌยท์ด๋ฆยท์ํ๊ฐ ์๋ก ์ด์ธ๋ฆฌ๋ ์กฐํฉ(์: `yolo-v8-detector` ๋ `object-detection` + `PyTorch`), ๋ ์ง๋ ์์ฑ์ผ โค ์์ ์ผ, ๊ฑด์๋ ๋ชฉ๋ก ๊ธธ์ด์ ์ผ์น. **๋ชฉ๋ก์ 20ํ ์ด์**(ํ์ด์ง ํฌ๊ธฐ 20 ์ด๋ฉด ๋ ํ์ด์ง ๋ถ๋) โ 10~12ํ์ด๋ฉด ํ ์๋๊ฐ ๋น์ด ์ฌ์ฌ์๊ฐ "๋น ๊ณต๊ฐ" ์ผ๋ก ๊น๋๋ค(ํ ์ค ํ 12์ฐจ 6์, 2026-10-18). ์ฌ์ฌ์๋ ๋ฐ์ดํฐ๊ฐ ๋ง์ด ๋๋์ง๋ ๋ณธ๋ค.
|
|
82
|
+
- **ํ ์ด ํญ** โ ์ด๋ฆ ์ด `flex: 2, minWidth: 200, maxWidth: 480`, **๊ธ์๊ฐ ๋ค์ด๊ฐ๋ ์ด์ ๋ชจ๋** `flex: 1, minWidth: 120`(์์ ์ยทํยทํ๋ ์์ํฌยท์ค๋ช
โ ํ๋๋ง ๊ณ ๋ฅด์ง ์๋๋ค. ๋จ๋ ํญ์ด ์ฌ๋ฌ ์ด๋ก ํฉ์ด์ ธ์ผ ์ด๋ฆ ์ด๋ง ๋์ด์ง์ง ์๋๋ค; ๊ธ์ ์ด์ด ํ๋๋ฟ์ด๋ฉด 2:1 ๋ก ๋๋ ๋ ์ด๋ฆ ์ด์ด 500px ๋ผ "name column leaves substantial whitespace", 2026-10-20 17์ฐจยท18์ฐจ), ์ซ์ยท๋ ์งยท์ํยท์งํ๋ฅ ์ด์ `width` ๋ก โ **์ซ์ ์ด์ `type: 'number'` ๋ง ์ฃผ๊ณ `flex` ๋ฅผ ์ฃผ์ง ์๋๋ค**(ํญ ์์ผ๋ฉด 140). DS `Table` ์ ์ซ์ ์ด์ `TableHead align='right'` ๋ก โ ํญ 140 ์ผ๋ก ๊ณ ์ ๋ผ ๊ธ์ ์ด์ด ๋จ๋ ํญ์ ๊ฐ์ง๋ค(ํ๊ฐ `table-fixed` ๋ผ ๋จธ๋ฆฌ๊ธ์ `align` ์ด ์ด ํญ์ ์ ํ๋ค). **DS `Table` ์ ์ํ ์ด์ `TableHead className='w-32'`, ๋ ์งยท์๊ฐ ์ด์ `className='w-44'` ๋ก ํญ์ ์ค๋ค** โ ํญ ์๋ ์ด์ ๋จ๋ ํญ์ ๋๊ฐ์ด ๋๋ ๊ฐ์ ธ ๋ฑ์ง ํ๋๋ฟ์ธ ์ํ ์ด์ด 400px ๊ฐ ๋๋ค(2026-10-30 ํ๋์์ 17 "large empty gap between the status and GPU columns"). ๋จ๋ ํญ์ ์ด๋ฆยท๊ธ์ ์ด์ด ๋๋๋ค. ๊ธ์ ์ด์ด ํ๋๋ ์์ผ๋ฉด `maxWidth` ๋ฅผ ๋บ๋ค(ํ ์ค๋ฅธ์ชฝ์ด ๋น๋ค โ ์ํ ์๋ flex ์ด์ด ์์ผ๋ฉด AgGridTable ์ด flex ์ด์ `maxWidth` ๋ฅผ ๋ผ์ด ํ๋ฅผ ์ฑ์ด๋ค, 2026-10-28 ํ๋์์ 14 "row dividers stop around 1330px")(์ ๋ชฉ ๊ธ์๊ฐ ๋ค์ด๊ฐ๋ ์ต์ ํญ์ AgGridTable ์ด ๋ณด์ ํ๊ณ ๋์น๋ ์
๊ธ์๋ ๋ง์ค์ํ๋ก ๋๋๋ค). ์ด์ 6~7๊ฐ ์ด๋ด๋ก โ **๋ณด์กฐ ์ ๋ณด(idยท์ด๋ฏธ์งยท๊ฒฝ๋กยท์ค๋ช
)๋ ์ด์ ๋๋ฆฌ์ง ๋ง๊ณ `ListPage secondaryField='image'` ๋ก ์ด๋ฆ ์๋ 12px ์ค์**(dl-ui-v3 ๋ชฉ๋ก์ ์ด๋ฆ / ์ค๋ช
์
; ํจํด์ด ํ์ 56 ์ผ๋ก ๊ทธ๋ฆฐ๋ค). ์
๋ง๋ค `cellStyle`ยท`width: 110` ๊ฐ์ ์ข์ ํญ์ ์์ผ๋ก ๋ง์ถ์ง ์๋๋ค(2026-10-18 13์ฐจ). **์ฃผ ์๋ณ์๊ฐ ์งง์ IDยท์ฝ๋(์์ฒญ IDยท์ปค๋ฐ ํด์ยทํค)๋ฉด ์ด๋ฆ ์ด ๊ณต์(`flex: 2`) ๋์ `width: 200` ์ผ๋ก ๊ณ ์ **ํ๊ณ , ๋จ๋ ํญ์ ์๋ํฌ์ธํธยท๋ชจ๋ธยท์ค๋ช
๊ฐ์ ๊ธ์ ์ด(`flex: 1`)์ด ๋๋๋ค โ ID ์ด์ด ๋จ๋ ํญ์ ๋ค ๋ฐ์ผ๋ฉด "request ID column is too wide"(2026-10-28 ํ๋์์ 14, ๋ชฉ๋ก 3/3).
|
|
83
|
+
- **๋์๋ง ๋ฌธ๊ตฌ(`FormDescription`)๋ ๊ท์นยท์ ์ ยท์ถ์ฒ๊ฐ** โ "์คํ ๊ฒฝ๋ก์ ์ฐ์ฌ ๋ง๋ ๋ค ๋ฐ๊ฟ ์ ์์ต๋๋ค. ์๋ฌธ ์๋ฌธ์ยท์ซ์ยทํ์ดํ 3~40์", "1~32 ์ฝ์ด. ์ ์ฒ๋ฆฌ๋ 2~4, ํ์ต์ 8 ์ด์์ ๊ถํฉ๋๋ค". placeholder ์ ๊ฐ์ ๋ง("1~64" / "1~64")์ ๋ํ์ดํ์ง ์๊ณ , placeholder ๋ "์: 4" ๊ฐ์ ๋ณด๊ธฐ ํ๋. **๋์๋งยท์ ํ์ง ์ค๋ช
์ ๋ฌธ์ฅ ๋ ๋ง์นจํ ์์ด ํต์ผ**ํ๋ค(๋ ๋ฌธ์ฅ์ ์ด์ ๋๋ง ๊ฐ์ด๋ฐ ๋ง์นจํ โ "1~32 ์ฝ์ด. ์ ์ฒ๋ฆฌ๋ 2~4") โ ์ผ๋ถ๋ง ๋ง์นจํ๊ฐ ๋ถ์ผ๋ฉด ์ฌ์ฌ์๊ฐ copy ๋ถ์ผ์น๋ก ๋ณธ๋ค(2026-10-18 13์ฐจ ํผ). ๊ฒํ ยท์์ฝ ํจ๋์ **๋น ๊ฐ์ "โ" ํ๋**(๋จ์๋ ๊ฐ์ด ์์ ๋๋ง โ "CPU โ์ฝ์ด ยท ๋ฉ๋ชจ๋ฆฌ โGB" ์ฒ๋ผ ์ด์ด ๋ถ์ด์ง ์๊ณ ํญ๋ชฉ๋ง๋ค ํ ํ). ์์ form-page.tsx ์ ๋ฆฌ์์ค ์น์
ยท๊ฒํ ํจ๋์ด ๋ณธ๋ณด๊ธฐ(2026-10-18 13์ฐจ, ๊ธฐ์ค์ copy 12์ ๋ฒค์น๋งํน).
|
|
84
|
+
- **๊ธ์ ์("0 / 500์") ๊ฐ์ ๋ณด์กฐ ํ์๋ `FormDescription icon={false}`** โ `FormDescription` ์ ์์ ์ ๋ณด ์์ด์ฝ์ ๊ทธ๋ฆฌ๋ฏ๋ก ์๋ด ๋ฌธ์ฅ์๋ง ์ด๋ค(2026-10-28 ํ๋์์ 15, OpusยทGemini "info icon next to a simple character counter").
|
|
85
|
+
- **ํ ์ ์งํ๋ฅ ์ด์ `type: 'number'` ๋ฅผ ์ฃผ์ง ์๋๋ค** โ ์ค๋ฅธ์ชฝ ์ ๋ ฌ์ด ๋๋ฉด % ๊ธ์ ํญ์ ๋ฐ๋ผ ๋ง๋ ์์์ ์ด ํ๋ค๋ฆฐ๋ค. ์
์์์ `Progress` ๋ ๊ณ ์ ํญ(`w-24`), % ๊ธ์๋ ๊ณ ์ ํญ(`w-10 text-right tabular-nums`)์ผ๋ก ๋๋ํ ๋๊ณ , ์ ์งยท๋๊ธฐ ํ๋ ๋น ๋ง๋(`value={0}`)๋ฅผ ๊ทธ๋ฆฐ๋ค(2026-10-28 ํ๋์์ 15, "progress bars have uneven lengths and starting points").
|
|
86
|
+
- **์ค๋ฅยท์์ ํ๋ฉด์ ํจํด prop ์ผ๋ก** โ DetailPage `error`/`notFound`, DashboardLayout `error`/`empty`, ListPage `error`/`emptyState`. ํจํด์ด ๊ทธ๋ฆผ(๋น ์ํ๋ `EmptyBoxIllustration` ์์ ์ผ๋ฌ์คํธ, ์ค๋ฅ๋ ๊ฒฝ๊ณ ์์ด์ฝ)ยท์ ๋ชฉยท์ค๋ช
ยท"๋ค์ ์๋" ์์๋ก ๊ทธ๋ฆฐ๋ค. ๋นจ๊ฐ `Alert` ์ค์ด๋ `<div>` ๋ก ๋ณธ๋ฌธ์ ๋์ฒดํ์ง ์๋๋ค. ํจํด ๋ฐ(ํผ์ ์ ํ์ง ๋ชฉ๋ก ๋ฑ)์์๋ `@t3q-ui/design-system/patterns` ์ `ErrorState`ยท`EmptyState` ๋ฅผ ์ด๋ค.
|
|
87
|
+
- ํผ์ ์ ํ์ง ๋ชฉ๋ก(์คํํ๊ฒฝ ๋ฑ)์ ๋ชป ๋ถ๋ฌ์์ผ๋ฉด **ํผ์ ์ง์ฐ์ง ๋ง๊ณ ** ๊ทธ ์น์
์์ `Alert variant='danger'`(์์ด์ฝ + ํ ์ค ์ ๋ชฉ + ์ค๋ช
+ `AlertActions` ์ ๋งํฌํ "๋ค์ ์๋")๋ฅผ ๋๋ค. `ErrorState` ์์๋ ํ๋ฉดยทํจ๋ ๋ณธ๋ฌธ์ ํต์งธ๋ก ๋ชป ๋ถ๋ฌ์์ ๋๋ง. ์ ์ถ ๋ฒํผ์ ๊ธฐ๋ณธ์ผ๋ก ํญ์ ๋๋ฆฌ๊ณ ๋๋ฅด๋ฉด ๊ฒ์ฆํด ํ๋ฆฐ ํญ๋ชฉ๋ง๋ค `FormMessage` ๋ฅผ ๋ณด์ธ๋ค(`submitMode` ๊ธฐ๋ณธ `always`).
|
|
88
|
+
- ์ซ์ ์
๋ ฅ์ ๋จ์(๊ฐยทGBยท์ฝ์ด)๋ `TextField elemAfterInput='๊ฐ'` ๋ก ์
๋ ฅ ์นธ ์์ ๋ถ์ธ๋ค. ๋ผ๋ฒจ์ "(GB)" ๋ฅผ ๋ฃ๊ฑฐ๋ ์์ `<span>` ์ ๋์ง ์๋๋ค.
|
|
89
|
+
- **๊ฐ๊ฒฉ์ ์ธ ๋จ๊ณ** โ ๋ถ์ด ์๋ ์์ 8, ํ ๋ฌถ์ ์ 16, ๋ฌถ์(์น์
) ์ฌ์ด 32(ํผ ์น์
์ฌ์ด 48, ์์ธ ํจ๋ ์ฌ์ด๋ ํจํด ๊ธฐ๋ณธ 24). ํจํด์ด ๊ธฐ๋ณธ์ผ๋ก ๊ทธ๋ฆฌ๋ `gap`ยท`space-y` ๋ฅผ ๋ง๋ถ์ฌ ํํํ๊ฒ ๋ง๋ค์ง ์๋๋ค. ๊ฐ์ 16 ์ด๋ 24 ๊ฐ ํ๋ฉด ์ ์ฒด์ ๋ฐ๋ณต๋๋ฉด ํ๋ฆฐ ๊ฒ์ด๋ค(2026-10-17).
|
|
90
|
+
- ์์ธ ํจ๋ยท์ ๋ณด ์ด์ ๊ฐ์ 14px ๊ธฐ๋ณธ, ๋ผ๋ฒจ 12px โ **ํ๋ง๋ค ๊ฐ ํฌ๊ธฐ๋ฅผ ๋ฐ๊พธ์ง ์๋๋ค**(8์ฐจ์ ๊ฑด์ยท์ฉ๋ ํ๋ง 20px ๋ก ํค์ ๋๋ ์ฌํ์ด "ํจ๋ ์ ํฌ๊ธฐ๊ฐ ๋ค์ญ๋ ์ญ"์ผ๋ก ์ฝ์ด ๊ฐ์ , 2026-10-18 ๋๋๋ฆผ).
|
|
91
|
+
- ๋์๋ณด๋ ์์ฝ ํ์ผ์ ์ฌ์ฉ๋ฅ ์ `stats` ํญ๋ชฉ์ `ratio`(0~1 โ ์งํ ๋ง๋)์ `tone`(๊ธฐ์ค ์ด๊ณผ๋ฉด `'warning'`)์ ์ค๋ค. ์ต๊ทผ ์ด๋ฒคํธ๋ `EventList`(๋ ๋ฒจ ์ ๋ + Badge + ์๊ฐ).
|