atomsystem 0.1.39 → 0.1.41

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/cli/init.js DELETED
@@ -1,276 +0,0 @@
1
- #!/usr/bin/env node
2
- import inquirer from "inquirer";
3
- import ora from "ora";
4
- import { exec } from "child_process";
5
- import fs, { copyFileSync, mkdirSync, readdirSync } from "fs";
6
- import path from "path";
7
- import { fileURLToPath } from "url";
8
- import { promisify } from "util";
9
-
10
- const execPromise = promisify(exec);
11
-
12
- // 현재 실행중인 CLI 파일의 디렉토리 찾기
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = path.dirname(__filename);
15
-
16
- // 패키지 내부 경로 설정
17
- const packageRoot = path.join(__dirname, "..");
18
- const tokenFile = path.join(packageRoot, "tokens", "tokens.json");
19
- const buildFile = path.join(packageRoot, "build", "build-tokens.js");
20
- const textCssFile = path.join(packageRoot, "css", "text.css");
21
-
22
- // 프로젝트 루트 경로 (사용자가 실행한 곳)
23
- const projectRoot = process.cwd();
24
- const targetTokenDir = path.join(projectRoot, "tokens");
25
- const targetTokenFile = path.join(targetTokenDir, "tokens.json");
26
- const targetBuildDir = path.join(projectRoot, "build");
27
- const targetBuildFile = path.join(targetBuildDir, "build-tokens.js");
28
- const targetCssDir = path.join(projectRoot, "css");
29
- const targetTextCssFile = path.join(targetCssDir, "text.css");
30
-
31
- // 파일 복사 헬퍼: 대상 디렉토리 생성 → 파일 복사 → 로그 출력
32
- function copyTo(src, dest, label) {
33
- const dir = path.dirname(dest);
34
- if (!fs.existsSync(dir)) mkdirSync(dir, { recursive: true });
35
- copyFileSync(src, dest);
36
- console.log(`✅ Copied: ${label} -> ${dest}`);
37
- }
38
-
39
- // 사용자 프로젝트에 package.json이 존재하는지 먼저 확인 (안전장치)
40
- const packageJsonPath = path.join(projectRoot, "package.json");
41
- if (!fs.existsSync(packageJsonPath)) {
42
- console.error("❌ Error: package.json not found in the current directory.");
43
- console.error("Please run 'npm init' or 'npm init -y' before running atomsystem-init.");
44
- process.exit(1);
45
- }
46
-
47
- // 사용자에게 Next.js 설치 여부 질문
48
- inquirer
49
- .prompt([
50
- {
51
- type: "confirm",
52
- name: "installPackages",
53
- message: "Do you want to install Next.js and React?",
54
- default: true,
55
- },
56
- ])
57
- .then(async (answers) => {
58
- if (answers.installPackages) {
59
- const pkgSpinner = ora("Installing Next.js and React...").start();
60
-
61
- try {
62
- await execPromise(
63
- "npm install next@latest react@latest react-dom@latest tailwindcss @tailwindcss/postcss postcss clsx react-modal typescript @types/react @types/node @types/react-dom @types/react-modal"
64
- );
65
- pkgSpinner.succeed("Next.js and React installation complete!");
66
- } catch (err) {
67
- pkgSpinner.fail("Error during Next.js/React installation");
68
- console.error(err);
69
- return;
70
- }
71
-
72
- const sdSpinner = ora("Installing style-dictionary for atom design tokens...").start();
73
- try {
74
- await execPromise("npm install style-dictionary -D");
75
- sdSpinner.succeed("style-dictionary installation complete!");
76
- } catch (err) {
77
- sdSpinner.fail("Error during style-dictionary installation");
78
- console.error(err);
79
- return;
80
- }
81
-
82
- // package.json 업데이트
83
- const packageJsonPath = path.join(projectRoot, "package.json");
84
- try {
85
- const packageJson = JSON.parse(
86
- fs.readFileSync(packageJsonPath, "utf8")
87
- );
88
-
89
- packageJson.type = "module";
90
- packageJson.scripts = {
91
- ...packageJson.scripts,
92
- "dev": "node build/build-tokens.js && next dev",
93
- "build": "next build",
94
- "start": "next start",
95
- "lint": "next lint",
96
- "token-build": "node build/build-tokens.js",
97
- };
98
-
99
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
100
- console.log("✅ Updated package.json with scripts.");
101
- } catch (err) {
102
- console.error("❌ Error updating package.json:", err);
103
- return;
104
- }
105
-
106
- // app 디렉토리 생성 및 파일 추가
107
- const appDir = path.join(projectRoot, "app");
108
- if (!fs.existsSync(appDir)) mkdirSync(appDir);
109
-
110
- // components 및 Theme 디렉토리 생성은 add.js 가 알아서 처리하므로 여기서는 page.tsx 와 layout.tsx, globals.css 만 생성합니다.
111
- const files = [
112
- {
113
- path: path.join(appDir, "layout.tsx"),
114
- content: `import { ThemeProvider } from "./components/Theme/Theme";
115
- import "./globals.css";
116
-
117
- export default function RootLayout({ children }: { children: React.ReactNode }) {
118
- return (
119
- <html lang="en" suppressHydrationWarning>
120
- <body>
121
- <ThemeProvider />
122
- {children}
123
- <div id="modal-root"></div>
124
- </body>
125
- </html>
126
- )
127
- }`,
128
- },
129
- {
130
- path: path.join(appDir, "globals.css"),
131
- content: `@import "tailwindcss";
132
- @import "../build/css/_variables.css";
133
- @import "../css/text.css";`,
134
- },
135
- {
136
- path: path.join(appDir, "page.tsx"),
137
- content: `import { ThemeSelector } from "./components/Theme/Theme";
138
- import { Button } from "./components/Button/Button";
139
- import { Card, CardHeader, CardContent, CardFooter } from "./components/Card/Card";
140
-
141
- export default function Page() {
142
- return (
143
- <main style={{ padding: "40px", minHeight: "100vh", background: "var(--color-bg-wrapper)", transition: "background 0.3s ease" }}>
144
- <div style={{ maxWidth: "800px", margin: "0 auto", display: "flex", flexDirection: "column", gap: "24px" }}>
145
- <h1 style={{ fontSize: "var(--font-sizes-h2)", color: "var(--color-text-standard)", margin: 0 }}>Hello, atomsystem!</h1>
146
- <p style={{ fontSize: "var(--font-sizes-body)", margin: 0 }}>
147
- 이 화면은 디자인 토큰이 적용된 샘플 화면입니다. 아래 테마를 변경해보세요.
148
- </p>
149
-
150
- <ThemeSelector />
151
-
152
- <Card>
153
- <CardHeader>
154
- <h2 style={{ fontSize: "var(--font-sizes-h3)", margin: 0 }}>Sample Card Components</h2>
155
- </CardHeader>
156
- <CardContent>
157
- <p style={{ margin: 0, color: "var(--color-text-disabled)" }}>
158
- 이 카드는 테마 변경 시 배경색, 텍스트 색상, 테두리 색상이 자동으로 변경됩니다.
159
- 여기 있는 버튼들은 제공된 Button 컴포넌트로 구성되었습니다.
160
- </p>
161
- </CardContent>
162
- <CardFooter>
163
- <div style={{ display: "flex", gap: "12px" }}>
164
- <Button type="primary">Primary Button</Button>
165
- <Button type="secondary">Secondary Button</Button>
166
- <Button type="gray">Gray Button</Button>
167
- </div>
168
- </CardFooter>
169
- </Card>
170
- </div>
171
- </main>
172
- )
173
- }`,
174
- },
175
- // ✅ tsconfig.json: "@/*" 경로 별칭 설정 (예: @/build/typescript/theme)
176
- {
177
- path: path.join(projectRoot, "tsconfig.json"),
178
- content: JSON.stringify({
179
- compilerOptions: {
180
- target: "ES2017",
181
- lib: ["dom", "dom.iterable", "esnext"],
182
- allowJs: true,
183
- skipLibCheck: true,
184
- strict: true,
185
- noEmit: true,
186
- esModuleInterop: true,
187
- module: "esnext",
188
- moduleResolution: "bundler",
189
- resolveJsonModule: true,
190
- isolatedModules: true,
191
- jsx: "preserve",
192
- incremental: true,
193
- plugins: [{ name: "next" }],
194
- paths: {
195
- "@/*": ["./*"]
196
- }
197
- },
198
- include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
199
- exclude: ["node_modules"]
200
- }, null, 2),
201
- },
202
- // ✅ next.config.ts: Next.js 기본 설정
203
- {
204
- path: path.join(projectRoot, "next.config.ts"),
205
- content: `import type { NextConfig } from "next";
206
-
207
- const nextConfig: NextConfig = {
208
- reactStrictMode: false,
209
- };
210
-
211
- export default nextConfig;`,
212
- },
213
- // ✅ postcss.config.mjs: Tailwind CSS v4 PostCSS 플러그인 등록 (@theme, @import "tailwindcss" 인식)
214
- {
215
- path: path.join(projectRoot, "postcss.config.mjs"),
216
- content: `/** @type {import('postcss-load-config').Config} */
217
- const config = {
218
- plugins: {
219
- "@tailwindcss/postcss": {},
220
- },
221
- };
222
-
223
- export default config;`,
224
- },
225
- ];
226
-
227
- files.forEach(({ path, content }) => {
228
- fs.writeFileSync(path, content);
229
- console.log(`✅ Created ${path}`);
230
- });
231
-
232
- // ✅ 토큰 빌드 먼저 실행: Theme.tsx가 @/build/typescript/theme를 import하므로
233
- // 컴포넌트 복사 전에 build-tokens.js를 실행해 theme.ts를 미리 생성해야 합니다.
234
- const buildTokensPath = path.join(projectRoot, "build", "build-tokens.js");
235
- if (fs.existsSync(buildTokensPath)) {
236
- const tokenBuildSpinner = ora("Building design tokens (generating build/typescript/theme.ts)...").start();
237
- try {
238
- await execPromise(`node "${buildTokensPath}"`, { cwd: projectRoot });
239
- tokenBuildSpinner.succeed("Design tokens built successfully!");
240
- } catch (err) {
241
- tokenBuildSpinner.fail("Error during token build");
242
- console.error(err);
243
- return;
244
- }
245
- } else {
246
- console.warn("⚠️ build-tokens.js not found, skipping token build.");
247
- }
248
-
249
- // add.js를 실행하여 Theme, Card 컴포넌트 및 하위 의존성을 복사합니다.
250
- const addScriptPath = path.join(__dirname, "add.js");
251
- if (fs.existsSync(addScriptPath)) {
252
- console.log("⏳ Adding default components via add.js...");
253
- try {
254
- // Theme 설치 (Theme 내부에 Button 등이 포함되어 있음)
255
- await execPromise(`node "${addScriptPath}" Theme`, { cwd: projectRoot });
256
- // Card 설치
257
- await execPromise(`node "${addScriptPath}" Card`, { cwd: projectRoot });
258
- console.log("✅ Default components (Theme, Card, Button 등) added successfully.");
259
- } catch (err) {
260
- console.error("❌ Failed to add components:", err);
261
- }
262
- }
263
- } else {
264
- console.log("🚀 Installation skipped.");
265
- }
266
-
267
- // ✅ 필수 파일 복사 (Next.js 설치 여부와 관계없이 실행)
268
- copyTo(tokenFile, targetTokenFile, "tokens/tokens.json");
269
- copyTo(buildFile, targetBuildFile, "build/build-tokens.js");
270
- copyTo(textCssFile, targetTextCssFile, "css/text.css");
271
-
272
- console.log("🚀 Token setup complete!");
273
- })
274
- .catch((error) => {
275
- console.error("❌ Error:", error);
276
- });