@spectrabrain/eds 0.1.0 → 0.2.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.
Files changed (62) hide show
  1. package/AI.md +13 -63
  2. package/AI_CONTEXT.json +26 -95
  3. package/CHANGELOG.md +70 -4
  4. package/CONSUMER_AGENT.md +86 -164
  5. package/FRONTEND_CONVENTIONS.md +252 -0
  6. package/QUICKSTART.md +24 -29
  7. package/README.md +29 -73
  8. package/TAILWIND_V4.md +52 -184
  9. package/TOKEN_CONTEXT.md +79 -36
  10. package/consumer/align/templates/components.json +21 -0
  11. package/consumer/align/templates/env.mock +1 -0
  12. package/consumer/align/templates/eslint.config.js +35 -0
  13. package/consumer/align/templates/package.scripts.json +10 -0
  14. package/consumer/align/templates/prettierignore +2 -0
  15. package/consumer/align/templates/prettierrc.json +7 -0
  16. package/consumer/align/templates/src/app/App.tsx +16 -0
  17. package/consumer/align/templates/src/app/main.tsx +27 -0
  18. package/consumer/align/templates/src/app/providers/ErrorBoundary.tsx +58 -0
  19. package/consumer/align/templates/src/app/providers/ErrorHandler.tsx +29 -0
  20. package/consumer/align/templates/src/app/router/index.tsx +23 -0
  21. package/consumer/align/templates/src/app/styles/index.css +2 -0
  22. package/consumer/align/templates/src/mocks/browser.ts +5 -0
  23. package/consumer/align/templates/src/mocks/handlers.ts +4 -0
  24. package/consumer/align/templates/src/shared/api/index.ts +23 -0
  25. package/consumer/align/templates/src/shared/api/queryClient.ts +24 -0
  26. package/consumer/align/templates/src/shared/lib/eventBus.ts +44 -0
  27. package/consumer/align/templates/src/shared/lib/utils/index.ts +6 -0
  28. package/consumer/align/templates/src/vite-env.d.ts +2 -0
  29. package/consumer/align/templates/tsconfig.json +22 -0
  30. package/consumer/align/templates/vite.config.babel.ts +36 -0
  31. package/consumer/align/templates/vite.config.rolldown.ts +35 -0
  32. package/consumer/align-analysis.mjs +1159 -0
  33. package/consumer/align-plan.mjs +377 -0
  34. package/consumer/align-rules.mjs +473 -0
  35. package/consumer/align.mjs +401 -0
  36. package/consumer/cli.mjs +90 -40
  37. package/consumer/css-root.mjs +24 -4
  38. package/consumer/doctor.mjs +47 -21
  39. package/consumer/generate-tailwind.mjs +41 -1
  40. package/consumer/init.mjs +39 -25
  41. package/consumer/managed-block.mjs +11 -5
  42. package/consumer/paths.mjs +69 -14
  43. package/consumer/register-scripts.mjs +17 -12
  44. package/consumer/scan-classes.mjs +24 -5
  45. package/consumer/sync.mjs +35 -13
  46. package/consumer/update-agent-context.mjs +63 -7
  47. package/consumer-postinstall.mjs +8 -7
  48. package/dist/components/Button/README.md +66 -95
  49. package/dist/components/Button/spec.json +19 -138
  50. package/dist/components.css +102 -366
  51. package/dist/index.d.mts +20 -18
  52. package/dist/index.d.ts +20 -18
  53. package/dist/index.js +301 -1
  54. package/dist/index.mjs +301 -1
  55. package/dist/tokens.css +30 -0
  56. package/dist/tokens.d.mts +7 -3
  57. package/dist/tokens.d.ts +7 -3
  58. package/dist/tokens.js +301 -1
  59. package/dist/tokens.json +360 -0
  60. package/dist/tokens.mjs +301 -1
  61. package/llms.txt +20 -14
  62. package/package.json +3 -1
package/TAILWIND_V4.md CHANGED
@@ -1,122 +1,56 @@
1
- # EVA token을 Tailwind CSS v4에서 사용하는 가이드
1
+ # EDS token을 Tailwind CSS v4에서 쓰는 방법
2
2
 
3
- 이 문서는 소비처가 `@spectrabrain/eds`의 공개 semantic token을 Tailwind CSS v4 `className`으로 사용하는 방법을 안내합니다. EDS는 Tailwind utility API를 패키지에 포함하지 않으며, 소비처가 공개 CSS variable을 자체 alias로 연결합니다. 필수 읽기는 package root의 `QUICKSTART.md`이며, 이 문서는 Tailwind CSS v4 설정을 다룰 때 읽습니다.
3
+ Tailwind CSS v4 저장소에서 `eds sync`가 공개 token을 `text-eds-*`·`bg-eds-*`·`border-eds-*`·`eds-typography-*` class로 쓸 수 있게 연결하는 설정 절차입니다. 필수 규칙은 package root의 `QUICKSTART.md`에, class를 고르는 기준은 `TOKEN_CONTEXT.md`에 있습니다.
4
4
 
5
5
  ## 공개 경로
6
6
 
7
- 소비처는 다음 경로만 사용합니다.
7
+ CSS 진입점은 `@spectrabrain/eds/styles.css` 하나를 권장합니다. 개별 파일(`@spectrabrain/eds/tokens.css`, `@spectrabrain/eds/components.css`, `@spectrabrain/eds/fonts.css`, 선택 `@spectrabrain/eds/base.css`)의 구성 규칙은 `CONSUMER_AGENT.md` 「font 정책」에 있습니다. 전체 공개 경로는 `README.md`의 「공개 경로」 표에 있으며, 그 밖의 패키지 내부 경로와 token 값은 소비처에 복사하지 않습니다.
8
8
 
9
- | 경로 | 용도 |
10
- | --- | --- |
11
- | `@spectrabrain/eds/styles.css` | `fonts.css`, `tokens.css`, `base.css`, `components.css`를 순서대로 불러옵니다. |
12
- | `@spectrabrain/eds/tokens.css` | semantic CSS variable만 불러옵니다. |
13
- | `@spectrabrain/eds/components.css` | Button CSS만 불러옵니다. font는 포함하지 않습니다. |
14
- | `@spectrabrain/eds/fonts.css` | Pretendard font만 불러옵니다. EDS text style이 참조하는 family를 선언하므로 생략하지 않습니다. |
15
- | `@spectrabrain/eds/base.css` | `:where(html)`에 body1 font family를 지정합니다. `styles.css`에 포함되며 개별 구성에서는 선택입니다. |
16
- | `@spectrabrain/eds/tokens.json` | 공개 token 이름과 타입을 생성 도구에서 확인합니다. |
17
- | `@spectrabrain/eds/tokens` | TypeScript token 이름과 `cssVar()`를 사용합니다. |
9
+ ## 설정 순서
18
10
 
19
- 개별 파일로 구성할 때는 `@spectrabrain/eds/tokens.css`, `@spectrabrain/eds/components.css`, `@spectrabrain/eds/fonts.css`를 함께 import하고 `@spectrabrain/eds/base.css`는 선택합니다. 다른 출처의 Pretendard로 EDS `fonts.css`를 대체하는 구성은 지원하지 않습니다. 패키지 내부의 다른 경로와 token 값을 소비처에 복사하지 않습니다.
11
+ 1. 「adapter 선택」 표에서 저장소에 맞는 행 하나를 골라 설치하고 연결합니다.
12
+ 2. 앱의 전역 CSS 파일 하나에 `@import "tailwindcss";`를 둡니다. 이 파일이 Tailwind root이며, 이미 있으면 새로 만들지 않습니다.
13
+ 3. `npm run sync:eds`를 실행합니다. script가 없으면 `npx @spectrabrain/eds init`을 실행합니다(패키지 매니저별 명령은 `CONSUMER_AGENT.md` 「첫 setup 절차」). init을 2단계보다 먼저 실행했다면 2단계 뒤에 sync를 다시 실행합니다.
14
+ 4. 「완료 기준」을 확인합니다.
20
15
 
21
- ## 사전 조건과 설치
16
+ CSS가 `@tailwind` 지시어를 쓰는 Tailwind CSS v3 저장소는 이 절차 대신 `CONSUMER_AGENT.md` 「Tailwind root 결정」을 따릅니다.
22
17
 
23
- React 웹 프로젝트와 Tailwind CSS v4를 준비합니다. 프로젝트의 bundler에 맞는 adapter 하나만 선택합니다.
18
+ ## adapter 선택
24
19
 
25
- ```sh
26
- npm install @spectrabrain/eds
27
- ```
28
-
29
- Vite를 사용한다면 다음을 설치합니다.
30
-
31
- ```sh
32
- npm install -D tailwindcss @tailwindcss/vite
33
- ```
34
-
35
- PostCSS를 사용한다면 다음을 설치합니다.
36
-
37
- ```sh
38
- npm install -D tailwindcss @tailwindcss/postcss postcss
39
- ```
40
-
41
- Vite adapter와 PostCSS adapter를 동시에 추가하지 않습니다. 기존 framework plugin과 PostCSS 설정은 제거하지 않고 adapter만 추가합니다.
42
-
43
- ## 소비처 setup과 생성 구조
44
-
45
- npm 10·11에서는 EDS의 `postinstall`이 소비처 `package.json`에 setup script만 등록합니다. npm 12, pnpm 10, yarn berry, bun처럼 의존성의 install script를 기본으로 실행하지 않는 환경과 `npm install --ignore-scripts` 환경에서는 `npx @spectrabrain/eds init`이 같은 script를 등록하고 첫 동기화까지 실행합니다. `init`은 패키지 매니저를 감지해 npm 12 이상에서는 `allowScripts`를 기록하고, pnpm·bun·yarn berry에서는 승인 설정을 안내만 합니다. 소비처 `package.json`에 `workspaces`가 있으면 postinstall은 script를 등록하지 않고 앱 package 안에서 `npx eds init`을 실행하도록 안내하며, pnpm 설치에서는 pnpm이 설치 중의 `package.json` 편집을 버리므로 `pnpm exec eds init`을 안내합니다. 세부 동작과 `--no-allow-scripts`, `--print-ci gitlab|github`, `eds doctor --warn`은 `CONSUMER_AGENT.md`를 따릅니다. Tailwind root CSS, 생성 CSS, `AGENTS.md`는 `npm run sync:eds`를 명시적으로 실행할 때만 바뀝니다.
46
-
47
- ```json
48
- {
49
- "scripts": {
50
- "sync:eds": "eds sync",
51
- "eds:doctor": "eds doctor",
52
- "pretypecheck": "eds doctor",
53
- "prebuild": "eds doctor"
54
- }
55
- }
56
- ```
57
-
58
- `sync:eds`·`eds:doctor`는 같은 이름의 script가 `eds sync`·`eds doctor`를 포함하면 그대로 두고, 다른 명령이면 덮어쓰지 않고 안내만 출력합니다. 설치는 실패하지 않으며 `eds doctor`가 `scripts:` 항목으로 보고합니다. `pretypecheck`·`prebuild`는 소비처에 `typecheck`·`build` script가 있고 같은 이름의 pre-hook이 없을 때만 등록하며, 이미 다른 pre-hook이 있으면 그대로 두고 안내만 출력합니다. yarn berry는 pre-hook을 실행하지 않으므로 `typecheck`·`build` script 앞에 `eds doctor && `를 직접 붙입니다. 소비처는 별도 generator 파일을 소유하지 않으며, `sync:eds`가 만드는 파일은 다음 하나입니다.
59
-
60
- ```text
61
- src/styles/
62
- eds-tokens.css
63
- ```
64
-
65
- `eds sync`는 설치된 package의 공개 `@spectrabrain/eds/tokens.json`에서 이름만 읽어 이 파일을 생성합니다. 현재 공개 manifest의 목록을 생성하며, 다음 버전에서 개수가 달라져도 manifest가 source of truth가 됩니다. 생성 결과의 형태는 다음과 같습니다.
66
-
67
- ```css
68
- /* Generated from @spectrabrain/eds@<version>. Do not edit manually. */
69
- @theme inline {
70
- --color-eds-fg-brand: var(--eds-color-fg-brand);
71
- /* 공개 color token마다 한 줄씩 생성합니다. */
72
- --font-sans: var(--eds-typography-body1-fontFamily);
73
- }
74
-
75
- @utility eds-typography-body2 {
76
- font-family: var(--eds-typography-body2-fontFamily);
77
- font-weight: var(--eds-typography-body2-fontWeight);
78
- font-size: var(--eds-typography-body2-fontSize);
79
- line-height: var(--eds-typography-body2-lineHeight);
80
- letter-spacing: var(--eds-typography-body2-letterSpacing);
81
- }
82
- ```
83
-
84
- `--font-sans`는 `@theme inline`의 마지막 줄이며 Tailwind의 기본 sans font를 EDS body1 font family로 바꿉니다. 생성물에는 `$value`, resolved color, 내부 경로, 비공개 token 이름을 기록하지 않습니다. 수동으로 alias를 추가하지 않고 EDS를 업데이트할 때마다 `npm run sync:eds`를 다시 실행합니다.
85
-
86
- ## Tailwind root 지정
87
-
88
- `eds sync`와 `eds doctor`는 환경 변수 `EDS_TAILWIND_ROOT`, 소비처 `package.json`의 `eds.tailwindRoot`, 자동 검출 순서로 Tailwind root를 정합니다. 자동 검출은 `@import "tailwindcss"`가 있는 CSS 파일 하나를 root로 사용하며, `@import "tailwindcss/theme.css"`·`@import "tailwindcss/utilities.css"`와 `@import url("tailwindcss")` 형태도 인식하고 `/* */` 주석 안의 import는 세지 않습니다. `node_modules`, `dist`, `build`, `.git`, `storybook-static`, `coverage`와 생성 파일은 후보에서 제외합니다. 후보가 둘 이상이면 후보 목록을 출력하고 아무 파일도 쓰지 않은 채 실패하므로 경로를 한 번 명시합니다. 후보가 없고 `EDS_TAILWIND_ROOT`와 `eds.tailwindRoot`도 없으면 Tailwind를 사용하지 않는 저장소로 보고 이 문서의 배선을 건너뛰며, `eds doctor`도 Tailwind 항목을 보고하지 않습니다.
89
-
90
- ```sh
91
- EDS_TAILWIND_ROOT=src/app/styles/index.css npm run sync:eds
92
- ```
93
-
94
- `EDS_TAILWIND_ROOT`로 sync에 성공하면 sync가 `package.json`에 `"eds": { "tailwindRoot": "src/app/styles/index.css" }`를 기록하므로, 이후 `eds doctor`, `eds sync`, `pretypecheck`·`prebuild` hook은 환경 변수 없이 같은 root를 사용합니다. 기록된 경로나 `EDS_TAILWIND_ROOT`가 존재하지 않는 파일을 가리키면 exit 2로 실패합니다.
20
+ 명령은 npm 기준이며 다른 패키지 매니저는 그 add 명령을 씁니다.
95
21
 
96
- ## Tailwind adapter 연결
22
+ | 저장소 | 설치 | 연결 |
23
+ | --- | --- | --- |
24
+ | `vite.config.*`가 있음 | `npm install -D tailwindcss @tailwindcss/vite` | `vite.config`의 `plugins`에 `tailwindcss()`를 추가합니다. `postcss.config.*`에 `@tailwindcss/postcss` 항목이 있으면 그 항목과 devDependency를 지웁니다. |
25
+ | `vite.config.*` 없이 PostCSS를 씀 | `npm install -D tailwindcss @tailwindcss/postcss postcss` | PostCSS 설정의 `plugins`에 `"@tailwindcss/postcss": {}`를 추가합니다. |
97
26
 
98
- Vite에서는 기존 plugin을 유지하면서 Tailwind plugin을 추가합니다.
27
+ Vite에서 `@tailwindcss/postcss`로 빌드하면 import한 EDS CSS의 상대 `url()`이 옮겨지지 않아 `fonts.css`의 Pretendard 파일이 번들에 들어가지 않습니다. 기존 framework plugin과 Tailwind 외 PostCSS plugin은 유지합니다.
99
28
 
100
29
  ```ts
30
+ import react from "@vitejs/plugin-react"; // 기존 import는 유지합니다.
101
31
  import tailwindcss from "@tailwindcss/vite";
102
32
  import { defineConfig } from "vite";
103
33
 
104
34
  export default defineConfig({
105
- plugins: [tailwindcss()],
35
+ // 기존 설정(server.proxy, resolve.alias 등)은 그대로 둡니다.
36
+ plugins: [react(), tailwindcss()], // 기존 plugin 배열 끝에 tailwindcss()만 추가합니다.
106
37
  });
107
38
  ```
108
39
 
109
- PostCSS에서는 기존 설정을 유지하면서 adapter를 추가합니다.
40
+ `vite.config.*`가 없는 저장소의 PostCSS 설정은 다음과 같습니다.
110
41
 
111
42
  ```js
112
43
  export default {
113
44
  plugins: {
45
+ // 기존 plugin 항목에 추가합니다.
114
46
  "@tailwindcss/postcss": {},
115
47
  },
116
48
  };
117
49
  ```
118
50
 
119
- Tailwind root CSS에는 Tailwind를 한 번만 불러오고, 마지막 Tailwind import 바로 다음 줄에 EDS style과 소비처 생성 CSS를 각각 한 번씩 `@import`합니다. `tailwindcss/theme.css`와 `tailwindcss/utilities.css`를 따로 불러오는 root에서는 `utilities.css` 다음 줄에 들어갑니다. `npm run sync:eds`가 이 두 줄을 추가하며, 이미 있으면 다시 추가하지 않습니다. `src/index.css`가 root인 구조에서는 다음과 같습니다.
51
+ ## sync가 만드는 것
52
+
53
+ sync는 설치된 package의 공개 `@spectrabrain/eds/tokens.json`에서 token 이름만 읽어 `src/styles/eds-tokens.css`를 생성하고, Tailwind root의 마지막 Tailwind import 바로 다음 줄에 `@spectrabrain/eds/styles.css`와 `eds-tokens.css`의 `@import`를 한 번씩 추가합니다. `tailwindcss/theme.css`와 `tailwindcss/utilities.css`를 따로 불러오는 root에서는 `utilities.css` 다음 줄입니다. 생성 CSS의 상대 경로는 root 위치에 맞춰 sync가 계산하므로 경로를 직접 쓰지 않습니다. `src/index.css`가 root이면 다음과 같습니다.
120
54
 
121
55
  ```css
122
56
  @import "tailwindcss";
@@ -124,110 +58,44 @@ Tailwind root CSS에는 Tailwind를 한 번만 불러오고, 마지막 Tailwind
124
58
  @import "./styles/eds-tokens.css";
125
59
  ```
126
60
 
127
- `src/app/styles/index.css`가 root이고 생성 CSS가 `src/styles/eds-tokens.css`에 있다면 상대 경로가 달라집니다.
61
+ 생성 CSS의 color alias는 공개 color token마다 한 줄씩 생기며, 형태는 다음과 같습니다.
128
62
 
129
63
  ```css
130
- @import "tailwindcss";
131
- @import "@spectrabrain/eds/styles.css";
132
- @import "../../styles/eds-tokens.css";
133
- ```
134
-
135
- `eds-tokens.css`는 `@theme`과 `@utility`를 담고 있으므로 Tailwind root CSS에서 import해야 compile됩니다. `src/main.tsx` 같은 JS·TS 진입점에서 `import "./styles/eds-tokens.css";`로 불러오던 이전 구조는 `sync:eds`가 해당 줄을 제거합니다. `@spectrabrain/eds/styles.css`는 root CSS와 JS 진입점 중 한 곳에서만 불러오며, 기존 JS import가 있거나 `tokens.css`·`components.css`·`fonts.css`가 모두 import되어 있으면 sync가 root CSS에 다시 추가하지 않습니다. `styles.css`와 `eds-tokens.css`를 여러 경로에서 중복 import하지 않습니다.
136
-
137
- ## Color alias
138
-
139
- 생성된 `@theme inline`은 공개 CSS variable을 Tailwind alias로 연결합니다.
140
-
141
- | EDS token | Tailwind alias | utility 예시 |
142
- | --- | --- | --- |
143
- | `color-fg-brand` | `--color-eds-fg-brand` | `text-eds-fg-brand` |
144
- | `color-bg-brand-primary` | `--color-eds-bg-brand-primary` | `bg-eds-bg-brand-primary` |
145
- | `color-stroke-neutral-secondary` | `--color-eds-stroke-neutral-secondary` | `border-eds-stroke-neutral-secondary` |
146
-
147
- ```tsx
148
- <div className="bg-eds-bg-neutral-primary text-eds-fg-neutral border border-eds-stroke-neutral-secondary">
149
- 콘텐츠입니다.
150
- </div>
151
- ```
152
-
153
- 상태가 있는 표현은 해당 semantic 상태 token을 사용합니다.
154
-
155
- ```tsx
156
- <a className="text-eds-fg-brand hover:text-eds-fg-brand-contrast" href="/details">
157
- 자세히 보기
158
- </a>
159
- ```
160
-
161
- ## Typography preset
162
-
163
- 생성된 `@utility`는 font family, weight, size, line height, letter spacing을 함께 적용합니다.
164
-
165
- ```tsx
166
- <h1 className="eds-typography-heading1 text-eds-fg-neutral">
167
- 제목입니다.
168
- </h1>
169
-
170
- <p className="eds-typography-body2 text-eds-fg-neutral-secondary">
171
- 본문입니다.
172
- </p>
173
- ```
174
-
175
- 생성되는 preset 이름은 다음 다섯 그룹입니다.
176
-
177
- ```text
178
- display1, display2
179
- heading1, heading2, heading3, heading4
180
- title1, title2, title3, title4
181
- body1, body2, body3, body4
182
- caption1, caption2, caption3
183
- ```
184
-
185
- ## Spacing과 radius
186
-
187
- EDS의 공개 semantic token에는 소비처용 spacing·radius alias가 없습니다. 소비처 Tailwind 기본 scale을 사용하고, 기존 scale로 표현할 수 없는 요구가 있을 때만 디자인 시스템 담당자에게 목적과 대체 가능성을 요청합니다.
188
-
189
- ## TypeScript token 자동완성
190
-
191
- CSS가 아닌 CSS-in-JS 또는 inline style에서 token을 선택해야 하면 공개 TypeScript API를 사용합니다.
192
-
193
- ```ts
194
- import { cssVar, type SemanticTokenName } from "@spectrabrain/eds/tokens";
64
+ /* Generated from @spectrabrain/eds@<version>. Do not edit manually. */
65
+ @theme inline {
66
+ --color-eds-fg-brand: var(--eds-color-fg-brand);
67
+ --spacing-eds-spacing-0-5: var(--eds-spacing-0\.5);
68
+ --radius-eds-radius-1: var(--eds-radius-1);
69
+ --font-sans: var(--eds-typography-body1-fontFamily);
70
+ }
195
71
 
196
- const token: SemanticTokenName = "color-fg-brand";
197
- const color = cssVar(token);
198
- // var(--eds-color-fg-brand)
72
+ @utility eds-typography-body2 {
73
+ font-family: var(--eds-typography-body2-fontFamily);
74
+ font-weight: var(--eds-typography-body2-fontWeight);
75
+ font-size: var(--eds-typography-body2-fontSize);
76
+ line-height: var(--eds-typography-body2-lineHeight);
77
+ letter-spacing: var(--eds-typography-body2-letterSpacing);
78
+ }
199
79
  ```
200
80
 
201
- ## 금지 사항
202
-
203
- - EDS 내부 파일을 import하거나 token 값을 소비처에 복사하지 않습니다.
204
- - raw hex·px·rem 값을 EDS token 대신 작성하지 않습니다.
205
- - `@theme`에 EDS token의 resolved 값을 직접 입력하지 않습니다.
206
- - `@spectrabrain/eds`의 공개 목록에 없는 deep import를 사용하지 않습니다.
207
- - Tailwind class로 EDS가 관리하는 컴포넌트 내부 스타일을 임의로 덮어쓰지 않습니다.
208
- - EDS token 이름과 다른 의미의 alias를 만들지 않습니다.
209
- - 새 컴포넌트별 규칙을 `index.css`에 추가하지 않고 `className`을 우선 작성합니다.
210
- - 공개 token이 없는 `eds-*` class는 Tailwind가 조용히 버립니다. `npm run eds:doctor`가 `unknown:`으로 보고하며, `-- --scan`은 raw 색상 class도 나열합니다.
81
+ - `--font-sans`는 `@theme inline`의 마지막 줄이며 Tailwind의 기본 sans font를 EDS body1 font family로 바꿉니다.
82
+ - 공개 spacing·radius token은 Tailwind CSS-safe alias로 연결합니다. `spacing-0.5`는 `p-eds-spacing-0-5`, `radius-1`은 `rounded-eds-radius-1`처럼 사용합니다. alias의 점은 `-`로 바뀌며, 생성 CSS의 `var(--eds-spacing-0\.5)`에서만 점을 escape합니다.
83
+ - `@theme`의 EDS alias는 sync가 생성한 `var(--eds-*)` 참조만 두고, EDS를 업데이트할 때마다 `npm run sync:eds`로 다시 생성합니다.
84
+ - `eds-tokens.css`는 `@theme`·`@utility`를 담으므로 Tailwind root CSS에서만 import합니다. `@spectrabrain/eds/styles.css`와 `eds-tokens.css`는 각각 한 곳에서만 import합니다.
85
+ - `src/styles/eds-tokens.css`는 생성물이지만 저장소에 commit합니다. install은 이 파일을 만들지 않으므로, 파일이 없으면 Tailwind root의 `@import`가 깨지고, `pretypecheck`·`prebuild` hook(yarn berry는 `typecheck`·`build` 앞의 `eds doctor`)과 `--print-ci` CI job의 `eds doctor`가 `missing:`으로 실패합니다.
211
86
 
212
- ## 버전 업데이트와 검증
87
+ ## Tailwind root 지정
213
88
 
214
- EDS 버전을 업데이트하면 다음 명령으로 root CSS import, alias, managed block을 함께 갱신합니다.
89
+ `eds sync`와 `eds doctor`는 `@import "tailwindcss"`가 있는 CSS 파일 하나를 Tailwind root로 찾습니다. 후보가 둘 이상이면 둘 다 exit 2로 멈추며, 사용자에게 root를 확인하는 절차는 `CONSUMER_AGENT.md` 「Tailwind root 결정」을 따릅니다. 확인한 root는 다음처럼 한 번 지정하고, sync가 그 경로를 소비처 `package.json`의 `eds.tailwindRoot`에 기록합니다.
215
90
 
216
91
  ```sh
217
- npm run sync:eds
92
+ EDS_TAILWIND_ROOT=src/app/styles/index.css npm run sync:eds
218
93
  ```
219
94
 
220
- 생성 파일의 diff를 확인하고 소비처의 typecheck·lint·test·build를 실행합니다. 등록된 `prebuild`·`pretypecheck` hook이 `eds doctor`를 먼저 실행하므로, sync를 빠뜨린 업데이트는 build 전에 `[EDS] Run npm run sync:eds to fix.`와 `[EDS] Then read the AGENTS.md managed block and QUICKSTART.md in the package root before UI work.` 안내와 함께 실패합니다. CI에서 같은 점검을 실행하려면 `npx eds init --print-ci gitlab` 또는 `--print-ci github`가 출력하는 job snippet을 붙입니다. `sync:eds`는 소비처 CI에 연결할 수 있지만 EDS package의 `postinstall`에서 자동 실행하지 않습니다. 설치 script가 실행되지 않는 환경을 위해 생성 파일은 커밋하거나 CI에서 먼저 생성합니다.
221
-
222
- setup이 끝나면 다음을 확인합니다.
95
+ ## 완료 기준
223
96
 
224
- 1. framework와 Tailwind v4 adapter가 현재 프로젝트 방식에 맞게 연결되어 있습니다.
225
- 2. EDS style과 소비처 생성 CSS가 Tailwind root CSS에서 각각 한 번씩 import되어 있습니다.
226
- 3. color alias가 `var(--eds-...)`를 참조합니다.
227
- 4. 모든 typography preset이 다섯 속성을 함께 적용합니다.
228
- 5. 생성 CSS에 raw 값이나 비공개 경로가 없습니다.
229
- 6. 예시 `className`이 실제 Tailwind compile 결과에 포함됩니다.
230
- 7. 새 UI 코드가 token과 `className`을 우선 사용합니다.
231
- 8. `npm run eds:doctor`가 exit 0으로 끝납니다.
97
+ 1. `npm run eds:doctor`가 `[EDS] synced with` 줄을 출력하고, 출력에 `No Tailwind root CSS found`·`Tailwind CSS v3 detected` note가 없습니다.
98
+ 2. Vite 저장소는 `vite.config.*`의 `plugins`에 `@tailwindcss/vite`의 `tailwindcss()`가 있고, 그 밖의 저장소는 PostCSS 설정에 `@tailwindcss/postcss`가 있습니다. doctor는 이 연결을 점검하지 않습니다.
99
+ 3. `@spectrabrain/eds/styles.css`는 Tailwind root CSS나 앱 진입점 가운데 한 곳에서만 import됩니다.
232
100
 
233
- 설정 후 변경 파일, 설치 package, 사용할 수 있는 `eds-*` class, 추가하지 않은 alias, 검증 결과를 작업 요약에 기록합니다.
101
+ EDS를 업데이트한 뒤에는 `CONSUMER_AGENT.md` 「버전 업데이트」를 따릅니다.
package/TOKEN_CONTEXT.md CHANGED
@@ -1,71 +1,114 @@
1
1
  # EVA semantic token 사용 맥락
2
2
 
3
- 이 문서는 `@spectrabrain/eds`의 공개 semantic token을 소비처의 화면 맥락에 맞춰 선택하기 위한 보조 안내입니다. 필수 읽기는 package root의 `QUICKSTART.md`이며, 이 문서는 token을 직접 고를 때 읽습니다. 정확한 이름과 값은 설치된 버전의 `dist/tokens.json`(`@spectrabrain/eds/tokens.json`)과 `@spectrabrain/eds/tokens`를 기준으로 합니다.
3
+ 이 문서는 `@spectrabrain/eds`의 공개 semantic token을 화면 맥락에 맞춰 고르는 방법을 안내합니다. 필수 규칙은 package root의 `QUICKSTART.md`에 있습니다. class 이름은 `src/styles/eds-tokens.css`에, CSS variable과 `cssVar()`에 쓰는 token 이름은 설치된 버전의 `@spectrabrain/eds/tokens`(`SemanticTokenName`)와 `dist/tokens.json`에 있습니다.
4
4
 
5
5
  ## 색상 역할
6
6
 
7
- | 역할 | 적용 대상 | Tailwind class 패턴 | 선택 기준 |
7
+ | 역할 | 적용 대상 | Tailwind class 패턴 | CSS variable 패턴 |
8
8
  | --- | --- | --- | --- |
9
- | `fg` | 제목, 본문, placeholder, 아이콘, inverted content | `text-eds-fg-*` | 콘텐츠가 전달하는 의미와 대비를 먼저 결정합니다. |
10
- | `bg` | 페이지, 카드, 입력, 버튼, 상태 surface | `bg-eds-bg-*` | surface의 위계와 interaction state를 결정합니다. |
11
- | `stroke` | border, divider, focus ring | `border-eds-stroke-*` | 경계의 중요도와 keyboard focus 여부를 결정합니다. |
9
+ | `fg` | 제목, 본문, placeholder, 아이콘, inverted content | `text-eds-fg-*`(SVG 아이콘은 `currentColor`로 따라갑니다), `fill-eds-fg-*` | `var(--eds-color-fg-*)` |
10
+ | `bg` | 페이지, 카드, 입력, 버튼, 상태 surface | `bg-eds-bg-*` | `var(--eds-color-bg-*)` |
11
+ | `stroke` | border, divider, keyboard focus ring | `border-eds-stroke-*`, `divide-eds-stroke-*`, `outline-eds-stroke-*`, `ring-eds-stroke-*` | `var(--eds-color-stroke-*)` |
12
12
 
13
- 역할을 고른 뒤 `brand`, `neutral`, `critical`, `informative`, `positive`, `warning`의 의미와 `primary`, `weak`, `disabled`, `hover`, `focus` 상태를 맞춥니다. 색상 취향만으로 역할을 고르지 않습니다.
13
+ Tailwind class는 Tailwind root CSS가 있는 저장소에서 `eds sync`가 생성하며, 그 밖의 저장소에서는 CSS variable 또는 `cssVar()`를 씁니다. class 이름은 token 이름의 대소문자를 그대로 씁니다(예: focus ring은 `focus-visible:outline-eds-stroke-focusRing`). 공개 token이 없는 `eds-*` class는 Tailwind가 오류 없이 버리며 doctor의 `unknown:`으로만 드러납니다.
14
14
 
15
- ### 행동 맥락 예시
15
+ 역할을 고른 뒤 의미, 강도, 상태를 아래 표의 이름에서 고릅니다. 의미는 주변 화면의 색이 아니라 콘텐츠가 전달하는 상태로 고릅니다: `critical` 오류·위험, `warning` 주의, `positive` 성공·완료, `informative` 정보·안내, `brand` 제품 강조, `neutral` 그 밖의 모든 것.
16
16
 
17
- | 화면 맥락 | 우선 검토할 표현 | 이유 |
18
- | --- | --- | --- |
19
- | 생성·저장·관리·확인 같은 화면의 핵심 행동 | `brand`의 primary 표현 | 사용자가 완료해야 할 대표 행동을 분명히 합니다. |
20
- | 검색·조회·일반적인 주요 실행 | `neutral`의 primary 표현 | 핵심 행동보다 낮은 브랜드 주목도로 일반 행동을 표현합니다. |
21
- | 취소·닫기·수정 같은 보조 작업 | `neutral`의 outline 표현 | 주 행동과 시각적 위계를 분리합니다. |
22
- | 초기화·갱신·되돌리기처럼 부담이 낮은 반복 행동 | `neutral`의 weak 표현 | 주 행동을 보조하는 반복 가능한 행동을 낮은 위계로 표현합니다. |
23
- | 되돌리기 어려운 삭제·초기화 | `critical`의 weak 표현 | 위험을 분명히 하고 확인 절차와 함께 사용합니다. |
24
- | 비동기 처리 중 | 컴포넌트의 `loading` contract | 라벨 공간과 접근성 이름을 유지하면서 중복 실행을 막습니다. |
17
+ 앞의 두 열은 `color-<역할>-<의미>` 뒤에 붙는 이름이고, 마지막 열은 `color-<역할>-` 뒤에 바로 붙는 이름입니다(예: `color-bg-critical-weak`, `color-fg-neutral`, `color-bg-layer-default`). 표에 없는 조합은 없는 token입니다. hover 상태는 bg 이름 뒤에 `-hover`를 붙이며(`bg-disabled` 제외), fg와 stroke에는 hover token이 없습니다.
18
+
19
+ | 역할 | 의미 색(`brand`·`critical`·`informative`·`positive`·`warning`) | `neutral` | 의미 없이 쓰는 이름 |
20
+ | --- | --- | --- | --- |
21
+ | `bg` | `-primary`, `-weak` | `-primary`, `-weak`, `-inverted` | `layer-basement`, `layer-default`, `layer-floating`, `transparent`, `disabled` |
22
+ | `fg` | 접미사 없음, `-contrast` | 접미사 없음, `-secondary`, `-tertiary`, `-inverted` | `disabled`, `placeholder`, `focus` |
23
+ | `stroke` | `-primary`, `-weak` | `-contrast`, `-primary`, `-secondary`, `-tertiary`, `-weak` | `focusRing` |
24
+
25
+ Button 계약에 있는 배경·글자 조합은 `bg-critical-weak`와 `fg-critical`, `bg-neutral-weak`와 `fg-neutral`, `bg-brand-primary`·`bg-neutral-inverted`와 `fg-neutral-inverted`입니다. 본문보다 낮은 위계의 글자는 `fg-neutral-secondary`, 그보다 낮으면 `fg-neutral-tertiary`를 씁니다. 그 밖의 배경 위 글자 색(`brand`·`informative`·`positive`·`warning`의 `weak`·`primary` 배경), 상태 안내(오류 border, badge)의 stroke·fg 조합, `-contrast` fg의 용도, `layer` 계열과 `neutral` 배경의 구분은 `미결`입니다.
26
+
27
+ exact token이 없으면 아래 순서로 조건을 하나씩 완화하고, 처음 존재하는 이름을 씁니다.
28
+
29
+ 1. 역할(`fg`·`bg`·`stroke`)은 바꾸지 않습니다.
30
+ 2. disabled는 `fg`·`bg`에서 `color-<역할>-disabled`를 쓰고, keyboard focus는 `color-stroke-focusRing`(focus ring)이나 `color-fg-focus`를 씁니다. disabled·hover token이 없는 역할은 기본 token을 그대로 씁니다.
31
+ 3. 강도를 같은 의미 안의 가까운 단계로 바꿉니다(`primary`↔`weak`, `neutral`의 `secondary`·`tertiary`).
32
+ 4. 의미를 `neutral`로 바꿉니다. `critical`·`warning`·`positive`·`informative`를 `neutral`로 바꿔야 한다면 구현을 멈추고 사용자에게 확인합니다.
25
33
 
26
- 기존 화면에서 다른 역할이 사용되고 있더라도 새 코드에서는 행동 의미에 맞는 공개 역할을 먼저 검토합니다. exact token이 없으면 `fg/bg/stroke` 역할, 상태, 행동 의미, `neutral` 순서로 가까운 공개 token을 선택합니다.
34
+ 버튼은 token을 조합하지 않고 EDS `Button`의 `role`·`variant`를 씁니다. 행동별 조합은 `QUICKSTART.md` 표와 `dist/components/Button/README.md` 「Role과 Variant」에 있습니다.
27
35
 
28
36
  ## Typography
29
37
 
30
- text style은 다섯 속성을 함께 적용하는 preset입니다. `fontFamily`, `fontWeight`, `fontSize`, `lineHeight`, `letterSpacing`을 각각 임의로 조합하지 않습니다.
38
+ text style은 `fontFamily`, `fontWeight`, `fontSize`, `lineHeight`, `letterSpacing`을 함께 적용하는 preset입니다. 한 속성만 떼어 쓰지 않고 preset 하나를 통째로 적용합니다. preset을 적용한 요소에는 `text-lg`(크기), `font-bold`(weight), `leading-*`, `tracking-*` 같은 typography utility를 덧붙이지 않고, 크기나 강조가 달라야 하면 다른 preset을 고릅니다.
31
39
 
32
- Tailwind utility는 `eds-typography-*` 패턴으로 사용하며, 설치된 manifest에 있는 preset 이름만 선택합니다. `npm run sync:eds`가 생성하는 `@theme inline`에는 `--font-sans: var(--eds-typography-body1-fontFamily);`가 포함되므로 Tailwind의 `font-sans`와 기본 sans font도 Pretendard가 됩니다. 이 font family는 `@spectrabrain/eds/fonts.css`가 선언합니다.
40
+ `src/styles/eds-tokens.css`가 있는 저장소에서는 `eds-typography-*` utility로, 그 밖의 저장소에서는 같은 preset의 `--eds-typography-<preset>-*` 변수 다섯 개로 적용하며, 설치된 manifest에 있는 preset 이름만 고릅니다. `npm run sync:eds`가 생성하는 `@theme inline`에는 `--font-sans: var(--eds-typography-body1-fontFamily);`가 포함되므로 Tailwind의 `font-sans`와 기본 sans font도 Pretendard가 됩니다. 이 font family는 `@spectrabrain/eds/fonts.css`가 선언합니다.
33
41
 
34
- | 순서 | class 패턴 | 권장 맥락 |
42
+ | 그룹 | preset | 권장 맥락 |
35
43
  | --- | --- | --- |
36
- | Display | `eds-typography-display1`, `eds-typography-display2` | 제품의 큰 메시지와 페이지 진입점입니다. |
37
- | Heading | `eds-typography-heading1` … `eds-typography-heading4` | 페이지·섹션·그룹의 구조를 나타냅니다. |
38
- | Title | `eds-typography-title1` … `eds-typography-title4` | 카드·행·대화상자의 핵심 제목과 control label입니다. |
39
- | Body | `eds-typography-body1` … `eds-typography-body4` | 설명, 입력 안내, 일반 본문입니다. |
40
- | Caption | `eds-typography-caption1` … `eds-typography-caption3` | 보조 설명, 메타데이터, 짧은 상태 안내입니다. |
44
+ | Display | `display1`, `display2` | 제품의 큰 메시지와 페이지 진입점입니다. |
45
+ | Heading | `heading1` … `heading4` | 페이지·섹션·그룹의 구조를 나타냅니다. |
46
+ | Title | `title1` … `title4` | 카드·행·대화상자의 핵심 제목과 control label입니다. |
47
+ | Body | `body1` … `body4` | 설명, 입력 안내, 일반 본문입니다. |
48
+ | Caption | `caption1` … `caption3` | 보조 설명, 메타데이터, 짧은 상태 안내입니다. |
41
49
 
42
- 한글과 영문이 함께 있는 화면에서도 실제 Pretendard preset을 그대로 사용합니다. 문장의 중요도와 정보 구조를 먼저 판단하고 글자 크기만 임의로 조정하지 않습니다.
50
+ 같은 그룹에서는 번호가 작을수록 글자가 크거나 같고, 크기가 같은 preset은 weight로 구분합니다. Title과 Body는 같은 번호끼리 크기가 같고 Title이 더 굵습니다.
43
51
 
44
- ## Tailwind className 예시
52
+ ## 예시
53
+
54
+ `src/styles/eds-tokens.css`가 있는 저장소에서는 `className`으로 조합합니다.
45
55
 
46
56
  ```tsx
47
- <section className="bg-eds-bg-neutral-primary text-eds-fg-neutral">
57
+ <section className="text-eds-fg-neutral">
48
58
  <h2 className="eds-typography-heading2 text-eds-fg-neutral">
49
59
  카메라 그룹
50
60
  </h2>
51
61
  <p className="eds-typography-body2 text-eds-fg-neutral-secondary">
52
62
  등록된 장치를 관리합니다.
53
63
  </p>
54
- <div className="border border-eds-stroke-neutral-secondary" />
64
+ <hr className="border-t border-eds-stroke-neutral-secondary" />
55
65
  </section>
56
66
  ```
57
67
 
58
- 새 UI는 위처럼 `className`으로 조합합니다. 컴포넌트별 규칙을 `index.css`에 추가하거나 공개 token의 값을 복사하지 않습니다.
68
+ divider의 stroke 단계는 `미결`이며, 예시는 Button `outline`의 경계와 같은 `neutral-secondary`를 씁니다.
69
+
70
+ Tailwind가 없는 저장소에서는 공개 CSS variable로 같은 조합을 씁니다.
71
+
72
+ ```css
73
+ .cameraGroupTitle {
74
+ color: var(--eds-color-fg-neutral);
75
+ font-family: var(--eds-typography-heading2-fontFamily);
76
+ font-weight: var(--eds-typography-heading2-fontWeight);
77
+ font-size: var(--eds-typography-heading2-fontSize);
78
+ line-height: var(--eds-typography-heading2-lineHeight);
79
+ letter-spacing: var(--eds-typography-heading2-letterSpacing);
80
+ }
81
+ ```
82
+
83
+ CSS-in-JS나 inline style에서는 `cssVar()`로 같은 이름을 씁니다. `cssVar()`는 CSS 변수 문자열만 반환하므로 앱 진입점에서 `@spectrabrain/eds/styles.css`를 한 번 import해 두어야 합니다.
84
+
85
+ ```tsx
86
+ import { cssVar } from "@spectrabrain/eds/tokens";
87
+
88
+ <p style={{ color: cssVar("color-fg-neutral-secondary") }}>…</p>; // var(--eds-color-fg-neutral-secondary)
89
+ ```
59
90
 
60
91
  ## Spacing과 radius
61
92
 
62
- 현재 공개 semantic token에는 소비처용 spacing·radius alias가 없습니다. 소비처 Tailwind의 기본 scale을 사용하고, 기존 scale로 표현할 수 없는 요구가 있을 때만 디자인 시스템 담당자에게 목적과 대체 가능성을 요청합니다.
93
+ 소비처 로컬 UI와 EDS component 밖의 배치에는 공개 spacing·radius token을 씁니다. 현재 scale 전체를 공개하며, 이름의 소수점은 유지합니다.
94
+
95
+ - spacing: `spacing-none`, `spacing-0.5`, `spacing-1`, `spacing-1.5`, `spacing-2`, `spacing-2.5`, `spacing-3`, `spacing-3.5`, `spacing-4`, `spacing-4.5`, `spacing-5`, `spacing-6`, `spacing-7`, `spacing-7.5`, `spacing-8`, `spacing-9`, `spacing-10`, `spacing-11`, `spacing-12`
96
+ - radius: `radius-none`, `radius-1`, `radius-2`, `radius-3`, `radius-4`, `radius-5`, `radius-6`, `radius-7`, `radius-8`, `radius-9`, `radius-10`
97
+
98
+ Tailwind에서는 CSS-safe alias를 사용합니다. `spacing-0.5`는 `p-eds-spacing-0-5`, `radius-1`은 `rounded-eds-radius-1`처럼 씁니다. `0.5`·`1.5`·`2.5`·`3.5`·`4.5`·`7.5`의 점은 alias에서 `-`로 바뀝니다.
99
+
100
+ Tailwind가 없으면 `@spectrabrain/eds/tokens`의 `SemanticTokenName` 자동완성과 `cssVar()`를 사용합니다. public 이름은 `spacing-0.5`로 전달하고, CSS reference에서만 점이 escape됩니다.
101
+
102
+ ```tsx
103
+ import { cssVar } from "@spectrabrain/eds/tokens";
104
+
105
+ <div style={{ padding: cssVar("spacing-0.5"), borderRadius: cssVar("radius-1") }}>…</div>;
106
+ // var(--eds-spacing-0\.5), var(--eds-radius-1)
107
+ ```
108
+
109
+ 직접 CSS를 쓸 때도 `tokens.json`의 `tokens.<name>.$extensions.eds.cssVariable` mapping을 따릅니다. CSS custom property 선언과 `var()` reference에서만 `.`을 escape하며, public token 이름은 바꾸지 않습니다.
63
110
 
64
111
  ## 확인 목록
65
112
 
66
- - `@spectrabrain/eds/styles.css`가 Tailwind root CSS에서 한 번만 import되어 있습니다. 개별 파일로 구성했다면 `@spectrabrain/eds/tokens.css`, `@spectrabrain/eds/components.css`, `@spectrabrain/eds/fonts.css`가 함께 import되어 있고 `@spectrabrain/eds/base.css`는 선택입니다. EDS text style이 참조하는 font family는 EDS `fonts.css`가 선언하므로 다른 출처의 Pretendard로 대신하지 않습니다.
67
- - 생성된 `eds-tokens.css`가 설치된 `dist/tokens.json`의 공개 이름만 참조합니다.
68
- - 색상은 `fg/bg/stroke` 역할과 상태를 설명할 수 있습니다.
69
- - typography preset은 다섯 속성을 함께 적용합니다.
70
- - 새 컴포넌트가 EDS component를 대체 구현하고 있지 않습니다.
71
- - raw 색상·typography·임의 CSS variable이 새 코드에 없습니다.
113
+ - 새로 쓴 CSS variable이 `tokens.json`의 `cssVariable` mapping과 일치하는지 확인합니다. dotted public name은 `var(--eds-spacing-0\.5)`처럼 CSS reference에서만 escape합니다. doctor는 Tailwind class를, typecheck는 `cssVar()` 인자를 검사합니다.
114
+ - typography는 preset 하나(`eds-typography-*` class 또는 같은 preset의 변수 다섯 개)로 지정합니다.
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "{{eds.srcDir}}/app/styles/index.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "@/shared/ui",
15
+ "utils": "@/shared/lib/utils",
16
+ "ui": "@/shared/ui",
17
+ "lib": "@/shared/lib",
18
+ "hooks": "@/shared/hooks"
19
+ },
20
+ "iconLibrary": "lucide"
21
+ }
@@ -0,0 +1 @@
1
+ VITE_API_MOCKING=true
@@ -0,0 +1,35 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import reactHooks from "eslint-plugin-react-hooks";
4
+ import reactRefresh from "eslint-plugin-react-refresh";
5
+ import tseslint from "typescript-eslint";
6
+ import { defineConfig, globalIgnores } from "eslint/config";
7
+
8
+ export default defineConfig([
9
+ // Build output, generated files and backend code are not linted by this frontend's config.
10
+ globalIgnores([{{eds.eslintIgnores}}]),
11
+ {
12
+ files: ["**/*.{ts,tsx}"],
13
+ extends: [
14
+ js.configs.recommended,
15
+ tseslint.configs.recommended,
16
+ // Includes the React Compiler rules.
17
+ reactHooks.configs.flat.recommended,
18
+ reactRefresh.configs.vite,
19
+ ],
20
+ rules: {
21
+ "@typescript-eslint/no-unused-vars": [
22
+ "error",
23
+ {
24
+ ignoreRestSiblings: true,
25
+ argsIgnorePattern: "^_",
26
+ varsIgnorePattern: "^_",
27
+ },
28
+ ],
29
+ },
30
+ languageOptions: {
31
+ ecmaVersion: 2020,
32
+ globals: globals.browser,
33
+ },
34
+ },
35
+ ]);
@@ -0,0 +1,10 @@
1
+ {
2
+ "dev": "vite",
3
+ "dev:mock": "vite --mode mock",
4
+ "build": "vite build",
5
+ "preview": "vite preview",
6
+ "lint": "eslint .",
7
+ "format": "prettier --write .",
8
+ "format:check": "prettier --check .",
9
+ "typecheck": "tsc --noEmit"
10
+ }
@@ -0,0 +1,2 @@
1
+ # Build output, generated files, Markdown and backend code are not formatted by this frontend's Prettier.
2
+ {{eds.prettierIgnores}}
@@ -0,0 +1,7 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": false,
4
+ "trailingComma": "all",
5
+ "printWidth": 80,
6
+ "tabWidth": 2
7
+ }
@@ -0,0 +1,16 @@
1
+ import { Toaster } from "sonner";
2
+ import Router from "./router";
3
+ import { ErrorHandlerProvider } from "./providers/ErrorHandler";
4
+
5
+ function App() {
6
+ return (
7
+ <ErrorHandlerProvider>
8
+ <main>
9
+ <Router />
10
+ <Toaster position="top-right" richColors />
11
+ </main>
12
+ </ErrorHandlerProvider>
13
+ );
14
+ }
15
+
16
+ export default App;
@@ -0,0 +1,27 @@
1
+ import "./styles/index.css";
2
+ import { StrictMode } from "react";
3
+ import { createRoot } from "react-dom/client";
4
+ import { BrowserRouter } from "react-router-dom";
5
+ import { QueryClientProvider } from "@tanstack/react-query";
6
+ import { queryClient } from "@/shared/api/queryClient";
7
+ import App from "./App.tsx";
8
+
9
+ async function main() {
10
+ // The dev:mock script loads .env.mock, which sets VITE_API_MOCKING=true.
11
+ if (import.meta.env.VITE_API_MOCKING === "true") {
12
+ const { worker } = await import("@/mocks/browser");
13
+ await worker.start({ onUnhandledRequest: "bypass" });
14
+ }
15
+
16
+ createRoot(document.getElementById("root")!).render(
17
+ <StrictMode>
18
+ <BrowserRouter>
19
+ <QueryClientProvider client={queryClient}>
20
+ <App />
21
+ </QueryClientProvider>
22
+ </BrowserRouter>
23
+ </StrictMode>,
24
+ );
25
+ }
26
+
27
+ main();