sh-ui-cli 0.23.0 → 0.24.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/README.md +0 -2
- package/data/changelog/versions.json +24 -0
- package/package.json +1 -1
- package/src/create/index.mjs +2 -3
- package/src/create/plugins/nextIntl.js +36 -20
- package/src/mcp.mjs +1 -1
- package/templates/nextjs-app/app/layout.tsx +5 -11
- package/templates/nextjs-app/src/app/layouts/RootLayout.tsx +11 -0
- package/templates/nextjs-standalone/app/layout.tsx +5 -11
- package/templates/nextjs-standalone/src/app/layouts/RootLayout.tsx +11 -0
- package/templates/nextjs-app/src/app/layouts/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/app/layouts/.gitkeep +0 -0
package/README.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$description": "sh-ui 릴리즈 노트 단일 소스. docs(React)와 showcase(Flutter)가 함께 읽는다. 새 릴리즈마다 맨 앞에 추가.",
|
|
4
4
|
"versions": [
|
|
5
|
+
{
|
|
6
|
+
"version": "0.24.0",
|
|
7
|
+
"date": "2026-04-28",
|
|
8
|
+
"title": "Next.js 템플릿 RootLayout 분리 — app/layout.tsx 는 thin wrapper",
|
|
9
|
+
"type": "minor",
|
|
10
|
+
"highlights": [
|
|
11
|
+
"nextjs-standalone / nextjs-app 모두 src/app/layouts/RootLayout.tsx 로 layout 본체 분리, app/layout.tsx 는 metadata + thin wrapper 만 유지",
|
|
12
|
+
"next-intl 플러그인 적용 시에도 동일 패턴 — RootLayout 이 locale 검증·hasLocale·notFound 까지 담당하고 app/[locale]/layout.tsx 는 params forward 만",
|
|
13
|
+
"사용자가 layout 로직을 확장할 때 entrypoint(layout.tsx) 와 컴포넌트(RootLayout) 책임이 분리돼 FSD 관습에 맞게 정렬"
|
|
14
|
+
],
|
|
15
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.24.0"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"version": "0.23.1",
|
|
19
|
+
"date": "2026-04-28",
|
|
20
|
+
"title": "sh-ui-create 패키지 완전 삭제 — 단일 sh-ui-cli",
|
|
21
|
+
"type": "patch",
|
|
22
|
+
"highlights": [
|
|
23
|
+
"베타 단계라 sh-ui-create 사용자가 없으므로 deprecate shim 도 폐기 — packages/create 디렉토리 + npm 의 sh-ui-create 패키지 둘 다 정리",
|
|
24
|
+
"publish workflow 매트릭스에서 create 제거 — 앞으로 sh-ui-cli 만 발행",
|
|
25
|
+
"문서 일괄 갱신: README, getting-started, CLI 레퍼런스, 플레이그라운드 명령 컴포저 모두 `npx sh-ui-cli create` 로 통일"
|
|
26
|
+
],
|
|
27
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.23.1"
|
|
28
|
+
},
|
|
5
29
|
{
|
|
6
30
|
"version": "0.23.0",
|
|
7
31
|
"date": "2026-04-28",
|
package/package.json
CHANGED
package/src/create/index.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
// sh-ui create — 프로젝트 스캐폴드 진입점.
|
|
2
|
-
// bin/sh-ui.mjs 의 `create` 서브커맨드와 sh-ui-create 호환 shim 양쪽에서 호출된다.
|
|
1
|
+
// sh-ui create — 프로젝트 스캐폴드 진입점. bin/sh-ui.mjs 의 `create` 서브커맨드에서 호출.
|
|
3
2
|
|
|
4
3
|
import { parseArgs } from './cli-args.js';
|
|
5
4
|
import { createProject, addApp, addComponent } from './generator.js';
|
|
@@ -37,7 +36,7 @@ export async function runCreate(rest) {
|
|
|
37
36
|
// parseArgs 가 process.argv 형태(앞 두 개는 스킵)를 기대하므로 더미 두 개를 prepend.
|
|
38
37
|
let parsed;
|
|
39
38
|
try {
|
|
40
|
-
parsed = parseArgs(['node', 'sh-ui
|
|
39
|
+
parsed = parseArgs(['node', 'sh-ui', ...rest]);
|
|
41
40
|
} catch (e) {
|
|
42
41
|
console.error(`❌ ${e.message}`);
|
|
43
42
|
console.error(`\n도움말: sh-ui create --help`);
|
|
@@ -47,6 +47,37 @@ export const nextIntlPlugin = {
|
|
|
47
47
|
}) {
|
|
48
48
|
return children;
|
|
49
49
|
}
|
|
50
|
+
`,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'replace',
|
|
54
|
+
path: 'src/app/layouts/RootLayout.tsx',
|
|
55
|
+
content: `import { hasLocale } from 'next-intl';
|
|
56
|
+
import { notFound } from 'next/navigation';
|
|
57
|
+
import { GlobalProvider } from '@/src/app/providers';
|
|
58
|
+
import { routing } from '@/src/shared/config/i18n/routing';
|
|
59
|
+
|
|
60
|
+
export async function RootLayout({
|
|
61
|
+
children,
|
|
62
|
+
params,
|
|
63
|
+
}: {
|
|
64
|
+
children: React.ReactNode;
|
|
65
|
+
params: Promise<{ locale: string }>;
|
|
66
|
+
}) {
|
|
67
|
+
const { locale } = await params;
|
|
68
|
+
|
|
69
|
+
if (!hasLocale(routing.locales, locale)) {
|
|
70
|
+
notFound();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<html lang={locale} suppressHydrationWarning>
|
|
75
|
+
<body>
|
|
76
|
+
<GlobalProvider>{children}</GlobalProvider>
|
|
77
|
+
</body>
|
|
78
|
+
</html>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
50
81
|
`,
|
|
51
82
|
},
|
|
52
83
|
],
|
|
@@ -149,36 +180,21 @@ export const { Link, redirect, usePathname, useRouter, getPathname } =
|
|
|
149
180
|
`,
|
|
150
181
|
|
|
151
182
|
'app/[locale]/layout.tsx': `import type { Metadata } from 'next';
|
|
152
|
-
import {
|
|
153
|
-
import { notFound } from 'next/navigation';
|
|
154
|
-
import { GlobalProvider } from '@/src/app/providers';
|
|
155
|
-
import { routing } from '@/src/shared/config/i18n/routing';
|
|
183
|
+
import { RootLayout } from '@/src/app/layouts/RootLayout';
|
|
156
184
|
|
|
157
185
|
export const metadata: Metadata = {
|
|
158
186
|
title: 'My App',
|
|
159
187
|
description: 'My App Description',
|
|
160
188
|
};
|
|
161
189
|
|
|
162
|
-
export default
|
|
190
|
+
export default function Layout({
|
|
163
191
|
children,
|
|
164
192
|
params,
|
|
165
|
-
}: {
|
|
193
|
+
}: Readonly<{
|
|
166
194
|
children: React.ReactNode;
|
|
167
195
|
params: Promise<{ locale: string }>;
|
|
168
|
-
}) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (!hasLocale(routing.locales, locale)) {
|
|
172
|
-
notFound();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return (
|
|
176
|
-
<html lang={locale} suppressHydrationWarning>
|
|
177
|
-
<body>
|
|
178
|
-
<GlobalProvider>{children}</GlobalProvider>
|
|
179
|
-
</body>
|
|
180
|
-
</html>
|
|
181
|
-
);
|
|
196
|
+
}>) {
|
|
197
|
+
return <RootLayout params={params}>{children}</RootLayout>;
|
|
182
198
|
}
|
|
183
199
|
`,
|
|
184
200
|
|
package/src/mcp.mjs
CHANGED
|
@@ -135,7 +135,7 @@ const SERVER_INSTRUCTIONS = `sh-ui — Base UI 위에 빌드된 React/Flutter
|
|
|
135
135
|
|
|
136
136
|
export async function startMcpServer() {
|
|
137
137
|
const server = new McpServer(
|
|
138
|
-
{ name: "sh-ui", version: "0.23.
|
|
138
|
+
{ name: "sh-ui", version: "0.23.1" }, // sh-ui-cli 와 동기화
|
|
139
139
|
{
|
|
140
140
|
capabilities: { tools: {} },
|
|
141
141
|
instructions: SERVER_INSTRUCTIONS,
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import type { Metadata } from 'next';
|
|
2
2
|
import '@workspace/ui-app-name/globals.css';
|
|
3
|
-
import {
|
|
3
|
+
import { RootLayout } from '@/src/app/layouts/RootLayout';
|
|
4
4
|
|
|
5
5
|
export const metadata: Metadata = {
|
|
6
6
|
title: 'App Name',
|
|
7
7
|
description: 'App Description',
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export default function
|
|
10
|
+
export default function Layout({
|
|
11
11
|
children,
|
|
12
|
-
}: {
|
|
12
|
+
}: Readonly<{
|
|
13
13
|
children: React.ReactNode;
|
|
14
|
-
}) {
|
|
15
|
-
return
|
|
16
|
-
<html lang='ko' suppressHydrationWarning>
|
|
17
|
-
<body>
|
|
18
|
-
<GlobalProvider>{children}</GlobalProvider>
|
|
19
|
-
</body>
|
|
20
|
-
</html>
|
|
21
|
-
);
|
|
14
|
+
}>) {
|
|
15
|
+
return <RootLayout>{children}</RootLayout>;
|
|
22
16
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GlobalProvider } from '@/src/app/providers';
|
|
2
|
+
|
|
3
|
+
export function RootLayout({ children }: { children: React.ReactNode }) {
|
|
4
|
+
return (
|
|
5
|
+
<html lang='ko' suppressHydrationWarning>
|
|
6
|
+
<body>
|
|
7
|
+
<GlobalProvider>{children}</GlobalProvider>
|
|
8
|
+
</body>
|
|
9
|
+
</html>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Metadata } from 'next';
|
|
2
|
-
import {
|
|
2
|
+
import { RootLayout } from '@/src/app/layouts/RootLayout';
|
|
3
3
|
import './globals.css';
|
|
4
4
|
|
|
5
5
|
export const metadata: Metadata = {
|
|
@@ -7,16 +7,10 @@ export const metadata: Metadata = {
|
|
|
7
7
|
description: 'My App Description',
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
export default function
|
|
10
|
+
export default function Layout({
|
|
11
11
|
children,
|
|
12
|
-
}: {
|
|
12
|
+
}: Readonly<{
|
|
13
13
|
children: React.ReactNode;
|
|
14
|
-
}) {
|
|
15
|
-
return
|
|
16
|
-
<html lang='ko' suppressHydrationWarning>
|
|
17
|
-
<body>
|
|
18
|
-
<GlobalProvider>{children}</GlobalProvider>
|
|
19
|
-
</body>
|
|
20
|
-
</html>
|
|
21
|
-
);
|
|
14
|
+
}>) {
|
|
15
|
+
return <RootLayout>{children}</RootLayout>;
|
|
22
16
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GlobalProvider } from '@/src/app/providers';
|
|
2
|
+
|
|
3
|
+
export function RootLayout({ children }: { children: React.ReactNode }) {
|
|
4
|
+
return (
|
|
5
|
+
<html lang='ko' suppressHydrationWarning>
|
|
6
|
+
<body>
|
|
7
|
+
<GlobalProvider>{children}</GlobalProvider>
|
|
8
|
+
</body>
|
|
9
|
+
</html>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
File without changes
|
|
File without changes
|