sh-ui-cli 0.22.2 → 0.23.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 +19 -2
- package/bin/sh-ui.mjs +7 -0
- package/data/changelog/versions.json +14 -0
- package/package.json +13 -2
- package/src/create/cli-args.js +63 -0
- package/src/create/generator.js +542 -0
- package/src/create/index.mjs +68 -0
- package/src/create/plugins/index.js +17 -0
- package/src/create/plugins/nextIntl.js +197 -0
- package/src/create/plugins/sentry.js +689 -0
- package/src/create/theme/decode.js +66 -0
- package/src/create/theme/inject.js +111 -0
- package/src/mcp.mjs +81 -27
- package/src/paths.mjs +5 -0
- package/templates/flutter-standalone/README.md +34 -0
- package/templates/flutter-standalone/analysis_options.yaml +1 -0
- package/templates/flutter-standalone/lib/main.dart +103 -0
- package/templates/flutter-standalone/lib/sh_ui/foundation/sh_ui_tokens.dart +389 -0
- package/templates/flutter-standalone/pubspec.yaml +20 -0
- package/templates/flutter-standalone/sh-ui.config.json +15 -0
- package/templates/monorepo/.dockerignore +7 -0
- package/templates/monorepo/.eslintrc.js +8 -0
- package/templates/monorepo/.prettierrc +17 -0
- package/templates/monorepo/README.md +103 -0
- package/templates/monorepo/package.json +24 -0
- package/templates/monorepo/packages/eslint-config/base.js +31 -0
- package/templates/monorepo/packages/eslint-config/fsd.js +119 -0
- package/templates/monorepo/packages/eslint-config/next.js +65 -0
- package/templates/monorepo/packages/eslint-config/package.json +31 -0
- package/templates/monorepo/packages/eslint-config/react-internal.js +36 -0
- package/templates/monorepo/packages/typescript-config/base.json +20 -0
- package/templates/monorepo/packages/typescript-config/nextjs.json +13 -0
- package/templates/monorepo/packages/typescript-config/package.json +5 -0
- package/templates/monorepo/packages/typescript-config/react-library.json +8 -0
- package/templates/monorepo/packages/ui/ui-apps/.gitkeep +0 -0
- package/templates/monorepo/packages/ui/ui-core/eslint.config.js +3 -0
- package/templates/monorepo/packages/ui/ui-core/package.json +23 -0
- package/templates/monorepo/packages/ui/ui-core/src/lib/utils.ts +6 -0
- package/templates/monorepo/packages/ui/ui-core/tsconfig.json +11 -0
- package/templates/monorepo/pnpm-workspace.yaml +5 -0
- package/templates/monorepo/tsconfig.json +3 -0
- package/templates/monorepo/turbo.json +26 -0
- package/templates/nextjs-app/.env.example +2 -0
- package/templates/nextjs-app/Dockerfile +11 -0
- package/templates/nextjs-app/README.md +64 -0
- package/templates/nextjs-app/app/layout.tsx +22 -0
- package/templates/nextjs-app/app/page.tsx +7 -0
- package/templates/nextjs-app/eslint.config.js +10 -0
- package/templates/nextjs-app/next.config.ts +12 -0
- package/templates/nextjs-app/package.json +45 -0
- package/templates/nextjs-app/postcss.config.mjs +1 -0
- package/templates/nextjs-app/src/app/layouts/.gitkeep +0 -0
- package/templates/nextjs-app/src/app/providers/GlobalProvider/index.tsx +23 -0
- package/templates/nextjs-app/src/app/providers/index.tsx +1 -0
- package/templates/nextjs-app/src/app/providers/tanstack/QueryClientProvider.tsx +27 -0
- package/templates/nextjs-app/src/app/providers/tanstack/TanstackDevtoolsProvider.tsx +13 -0
- package/templates/nextjs-app/src/app/providers/theme/ThemeProviders.tsx +12 -0
- package/templates/nextjs-app/src/entities/.gitkeep +0 -0
- package/templates/nextjs-app/src/features/.gitkeep +0 -0
- package/templates/nextjs-app/src/shared/api/.gitkeep +0 -0
- package/templates/nextjs-app/src/shared/config/.gitkeep +0 -0
- package/templates/nextjs-app/src/shared/hooks/.gitkeep +0 -0
- package/templates/nextjs-app/src/shared/lib/.gitkeep +0 -0
- package/templates/nextjs-app/src/shared/model/.gitkeep +0 -0
- package/templates/nextjs-app/src/shared/ui/.gitkeep +0 -0
- package/templates/nextjs-app/src/views/.gitkeep +0 -0
- package/templates/nextjs-app/src/widgets/.gitkeep +0 -0
- package/templates/nextjs-app/tsconfig.json +23 -0
- package/templates/nextjs-app/vitest.config.ts +15 -0
- package/templates/nextjs-app/vitest.setup.ts +1 -0
- package/templates/nextjs-standalone/.env.example +2 -0
- package/templates/nextjs-standalone/.prettierrc +17 -0
- package/templates/nextjs-standalone/README.md +77 -0
- package/templates/nextjs-standalone/app/globals.css +33 -0
- package/templates/nextjs-standalone/app/layout.tsx +22 -0
- package/templates/nextjs-standalone/app/page.tsx +7 -0
- package/templates/nextjs-standalone/eslint.config.js +162 -0
- package/templates/nextjs-standalone/next.config.ts +10 -0
- package/templates/nextjs-standalone/package.json +66 -0
- package/templates/nextjs-standalone/postcss.config.mjs +5 -0
- package/templates/nextjs-standalone/sh-ui.config.json +19 -0
- package/templates/nextjs-standalone/src/app/layouts/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/app/providers/GlobalProvider/index.tsx +23 -0
- package/templates/nextjs-standalone/src/app/providers/index.tsx +1 -0
- package/templates/nextjs-standalone/src/app/providers/tanstack/QueryClientProvider.tsx +27 -0
- package/templates/nextjs-standalone/src/app/providers/tanstack/TanstackDevtoolsProvider.tsx +13 -0
- package/templates/nextjs-standalone/src/app/providers/theme/ThemeProviders.tsx +12 -0
- package/templates/nextjs-standalone/src/entities/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/features/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/shared/api/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/shared/config/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/shared/hooks/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/shared/lib/utils.ts +6 -0
- package/templates/nextjs-standalone/src/shared/model/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/shared/styles/tokens.css +95 -0
- package/templates/nextjs-standalone/src/shared/ui/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/views/.gitkeep +0 -0
- package/templates/nextjs-standalone/src/widgets/.gitkeep +0 -0
- package/templates/nextjs-standalone/tsconfig.json +39 -0
- package/templates/nextjs-standalone/vitest.config.ts +15 -0
- package/templates/nextjs-standalone/vitest.setup.ts +1 -0
- package/templates/ui-app-template/eslint.config.js +3 -0
- package/templates/ui-app-template/package.json +38 -0
- package/templates/ui-app-template/postcss.config.mjs +5 -0
- package/templates/ui-app-template/sh-ui.config.json +14 -0
- package/templates/ui-app-template/src/components/.gitkeep +0 -0
- package/templates/ui-app-template/src/hooks/.gitkeep +0 -0
- package/templates/ui-app-template/src/lib/.gitkeep +0 -0
- package/templates/ui-app-template/src/styles/globals.css +37 -0
- package/templates/ui-app-template/src/styles/tokens.css +95 -0
- package/templates/ui-app-template/tsconfig.json +11 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import boundaries from "eslint-plugin-boundaries"
|
|
2
|
+
import importX from "eslint-plugin-import-x"
|
|
3
|
+
import checkFile from "eslint-plugin-check-file"
|
|
4
|
+
import { createTypeScriptImportResolver } from "eslint-import-resolver-typescript"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* FSD (Feature-Sliced Design) ESLint configuration.
|
|
8
|
+
* boundaries: layer import direction + public API enforcement
|
|
9
|
+
* import-x: import group ordering
|
|
10
|
+
* check-file: file/folder naming convention enforcement
|
|
11
|
+
*
|
|
12
|
+
* @type {import("eslint").Linter.Config[]}
|
|
13
|
+
*/
|
|
14
|
+
export const fsdConfig = [
|
|
15
|
+
// ── boundaries plugin ──
|
|
16
|
+
{
|
|
17
|
+
plugins: {
|
|
18
|
+
boundaries,
|
|
19
|
+
},
|
|
20
|
+
settings: {
|
|
21
|
+
"import/resolver": {
|
|
22
|
+
typescript: {
|
|
23
|
+
alwaysTryTypes: true,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
"boundaries/elements": [
|
|
27
|
+
{ type: "app", pattern: ["src/app"], mode: "folder" },
|
|
28
|
+
{ type: "shared", pattern: ["src/shared/*"], mode: "folder" },
|
|
29
|
+
{ type: "entity", pattern: ["src/entities/*"], mode: "folder" },
|
|
30
|
+
{ type: "feature", pattern: ["src/features/*"], mode: "folder" },
|
|
31
|
+
{ type: "widget", pattern: ["src/widgets/*"], mode: "folder" },
|
|
32
|
+
{ type: "view", pattern: ["src/views/*"], mode: "folder" },
|
|
33
|
+
],
|
|
34
|
+
"boundaries/ignore": ["**/*.test.*", "**/*.spec.*"],
|
|
35
|
+
},
|
|
36
|
+
rules: {
|
|
37
|
+
"boundaries/element-types": [
|
|
38
|
+
"warn",
|
|
39
|
+
{
|
|
40
|
+
default: "disallow",
|
|
41
|
+
rules: [
|
|
42
|
+
{ from: "app", allow: ["view", "widget", "feature", "entity", "shared"] },
|
|
43
|
+
{ from: "view", allow: ["widget", "feature", "entity", "shared"] },
|
|
44
|
+
{ from: "widget", allow: ["feature", "entity", "shared"] },
|
|
45
|
+
{ from: "feature", allow: ["entity", "shared"] },
|
|
46
|
+
{ from: "entity", allow: ["shared"] },
|
|
47
|
+
{ from: "shared", allow: ["shared"] },
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
"boundaries/entry-point": [
|
|
52
|
+
"warn",
|
|
53
|
+
{
|
|
54
|
+
default: "disallow",
|
|
55
|
+
rules: [
|
|
56
|
+
{ target: "shared", allow: "**" },
|
|
57
|
+
{ target: "app", allow: "**" },
|
|
58
|
+
{
|
|
59
|
+
target: ["entity", "widget", "view"],
|
|
60
|
+
allow: "index.{ts,tsx}",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
target: ["feature"],
|
|
64
|
+
allow: ["index.{ts,tsx}", "*/index.{ts,tsx}"],
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
// ── check-file plugin (naming conventions) ──
|
|
73
|
+
{
|
|
74
|
+
plugins: {
|
|
75
|
+
"check-file": checkFile,
|
|
76
|
+
},
|
|
77
|
+
rules: {
|
|
78
|
+
"check-file/filename-naming-convention": [
|
|
79
|
+
"error",
|
|
80
|
+
{
|
|
81
|
+
"**/src/**/*.tsx": "PASCAL_CASE",
|
|
82
|
+
"**/src/**/*.ts": "CAMEL_CASE",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
ignoreMiddleExtensions: true,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
files: [
|
|
92
|
+
"**/index.tsx", "**/index.ts",
|
|
93
|
+
"**/layout.tsx", "**/page.tsx",
|
|
94
|
+
"**/error.tsx", "**/not-found.tsx",
|
|
95
|
+
"**/routing.ts", "**/navigation.ts", "**/request.ts",
|
|
96
|
+
],
|
|
97
|
+
rules: {
|
|
98
|
+
"check-file/filename-naming-convention": "off",
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
// ── import-x plugin ──
|
|
103
|
+
{
|
|
104
|
+
plugins: {
|
|
105
|
+
"import-x": importX,
|
|
106
|
+
},
|
|
107
|
+
settings: {
|
|
108
|
+
"import-x/resolver-next": [
|
|
109
|
+
createTypeScriptImportResolver({
|
|
110
|
+
alwaysTryTypes: true,
|
|
111
|
+
}),
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
rules: {
|
|
115
|
+
"import-x/order": "off",
|
|
116
|
+
"import-x/no-unresolved": "off",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import js from "@eslint/js"
|
|
2
|
+
import pluginNext from "@next/eslint-plugin-next"
|
|
3
|
+
import checkFile from "eslint-plugin-check-file"
|
|
4
|
+
import eslintConfigPrettier from "eslint-config-prettier"
|
|
5
|
+
import pluginReact from "eslint-plugin-react"
|
|
6
|
+
import pluginReactHooks from "eslint-plugin-react-hooks"
|
|
7
|
+
import globals from "globals"
|
|
8
|
+
import tseslint from "typescript-eslint"
|
|
9
|
+
|
|
10
|
+
import { config as baseConfig } from "./base.js"
|
|
11
|
+
|
|
12
|
+
export const nextJsConfig = [
|
|
13
|
+
...baseConfig,
|
|
14
|
+
js.configs.recommended,
|
|
15
|
+
eslintConfigPrettier,
|
|
16
|
+
...tseslint.configs.recommended,
|
|
17
|
+
{
|
|
18
|
+
...pluginReact.configs.flat.recommended,
|
|
19
|
+
languageOptions: {
|
|
20
|
+
...pluginReact.configs.flat.recommended.languageOptions,
|
|
21
|
+
globals: {
|
|
22
|
+
...globals.serviceworker,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
plugins: {
|
|
28
|
+
"@next/next": pluginNext,
|
|
29
|
+
},
|
|
30
|
+
rules: {
|
|
31
|
+
...pluginNext.configs.recommended.rules,
|
|
32
|
+
...pluginNext.configs["core-web-vitals"].rules,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
plugins: {
|
|
37
|
+
"react-hooks": pluginReactHooks,
|
|
38
|
+
},
|
|
39
|
+
settings: { react: { version: "detect" } },
|
|
40
|
+
rules: {
|
|
41
|
+
...pluginReactHooks.configs.recommended.rules,
|
|
42
|
+
"react/react-in-jsx-scope": "off",
|
|
43
|
+
"react/prop-types": "off",
|
|
44
|
+
"react/function-component-definition": [
|
|
45
|
+
"warn",
|
|
46
|
+
{
|
|
47
|
+
namedComponents: "function-declaration",
|
|
48
|
+
unnamedComponents: "arrow-function",
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
plugins: {
|
|
55
|
+
"check-file": checkFile,
|
|
56
|
+
},
|
|
57
|
+
rules: {
|
|
58
|
+
"check-file/filename-naming-convention": [
|
|
59
|
+
"warn",
|
|
60
|
+
{ "src/**/*.{ts,tsx}": "CAMEL_CASE" },
|
|
61
|
+
{ ignoreMiddleExtensions: true },
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@workspace/eslint-config",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"private": true,
|
|
6
|
+
"exports": {
|
|
7
|
+
"./base": "./base.js",
|
|
8
|
+
"./next-js": "./next.js",
|
|
9
|
+
"./react-internal": "./react-internal.js",
|
|
10
|
+
"./fsd": "./fsd.js"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@eslint/js": "^9.39.2",
|
|
14
|
+
"@next/eslint-plugin-next": "^16.1.6",
|
|
15
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
16
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
17
|
+
"eslint": "^9.39.2",
|
|
18
|
+
"eslint-config-prettier": "^10.1.8",
|
|
19
|
+
"eslint-import-resolver-typescript": "^4.4.4",
|
|
20
|
+
"eslint-plugin-boundaries": "^5.4.0",
|
|
21
|
+
"eslint-plugin-check-file": "^3.3.1",
|
|
22
|
+
"eslint-plugin-import-x": "^4.16.1",
|
|
23
|
+
"eslint-plugin-only-warn": "^1.1.0",
|
|
24
|
+
"eslint-plugin-react": "^7.37.5",
|
|
25
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
26
|
+
"eslint-plugin-turbo": "^2.8.1",
|
|
27
|
+
"globals": "^17.2.0",
|
|
28
|
+
"typescript": "^5.9.3",
|
|
29
|
+
"typescript-eslint": "^8.54.0"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import js from "@eslint/js"
|
|
2
|
+
import eslintConfigPrettier from "eslint-config-prettier"
|
|
3
|
+
import pluginReact from "eslint-plugin-react"
|
|
4
|
+
import pluginReactHooks from "eslint-plugin-react-hooks"
|
|
5
|
+
import globals from "globals"
|
|
6
|
+
import tseslint from "typescript-eslint"
|
|
7
|
+
|
|
8
|
+
import { config as baseConfig } from "./base.js"
|
|
9
|
+
|
|
10
|
+
export const config = [
|
|
11
|
+
...baseConfig,
|
|
12
|
+
js.configs.recommended,
|
|
13
|
+
eslintConfigPrettier,
|
|
14
|
+
...tseslint.configs.recommended,
|
|
15
|
+
pluginReact.configs.flat.recommended,
|
|
16
|
+
{
|
|
17
|
+
languageOptions: {
|
|
18
|
+
...pluginReact.configs.flat.recommended.languageOptions,
|
|
19
|
+
globals: {
|
|
20
|
+
...globals.serviceworker,
|
|
21
|
+
...globals.browser,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
plugins: {
|
|
27
|
+
"react-hooks": pluginReactHooks,
|
|
28
|
+
},
|
|
29
|
+
settings: { react: { version: "detect" } },
|
|
30
|
+
rules: {
|
|
31
|
+
...pluginReactHooks.configs.recommended.rules,
|
|
32
|
+
"react/react-in-jsx-scope": "off",
|
|
33
|
+
"react/prop-types": "off",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"display": "Default",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"declarationMap": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"incremental": false,
|
|
9
|
+
"isolatedModules": true,
|
|
10
|
+
"lib": ["es2022", "DOM", "DOM.Iterable"],
|
|
11
|
+
"module": "NodeNext",
|
|
12
|
+
"moduleDetection": "force",
|
|
13
|
+
"moduleResolution": "NodeNext",
|
|
14
|
+
"noUncheckedIndexedAccess": true,
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"skipLibCheck": true,
|
|
17
|
+
"strict": true,
|
|
18
|
+
"target": "ES2022"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"display": "Next.js",
|
|
4
|
+
"extends": "./base.json",
|
|
5
|
+
"compilerOptions": {
|
|
6
|
+
"plugins": [{ "name": "next" }],
|
|
7
|
+
"module": "ESNext",
|
|
8
|
+
"moduleResolution": "Bundler",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"jsx": "preserve",
|
|
11
|
+
"noEmit": true
|
|
12
|
+
}
|
|
13
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@workspace/ui-core",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"private": true,
|
|
6
|
+
"scripts": {
|
|
7
|
+
"lint": "eslint . --max-warnings 0"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"class-variance-authority": "^0.7.1",
|
|
11
|
+
"clsx": "^2.1.1",
|
|
12
|
+
"tailwind-merge": "^3.5.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@workspace/eslint-config": "workspace:*",
|
|
16
|
+
"@workspace/typescript-config": "workspace:*",
|
|
17
|
+
"eslint": "^9.39.2",
|
|
18
|
+
"typescript": "^5.9.3"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
"./lib/*": "./src/lib/*.ts"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://turbo.build/schema.json",
|
|
3
|
+
"ui": "tui",
|
|
4
|
+
"globalEnv": [
|
|
5
|
+
"NODE_ENV",
|
|
6
|
+
"API_URL",
|
|
7
|
+
"CI"
|
|
8
|
+
],
|
|
9
|
+
"tasks": {
|
|
10
|
+
"build": {
|
|
11
|
+
"dependsOn": ["^build"],
|
|
12
|
+
"inputs": ["$TURBO_DEFAULT$", ".env*"],
|
|
13
|
+
"outputs": [".next/**", "!.next/cache/**"]
|
|
14
|
+
},
|
|
15
|
+
"lint": {
|
|
16
|
+
"dependsOn": ["^lint"]
|
|
17
|
+
},
|
|
18
|
+
"typecheck": {
|
|
19
|
+
"dependsOn": ["^typecheck"]
|
|
20
|
+
},
|
|
21
|
+
"dev": {
|
|
22
|
+
"cache": false,
|
|
23
|
+
"persistent": true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Next.js App Template (모노레포용)
|
|
2
|
+
|
|
3
|
+
모노레포 `apps/` 하위에 배치되는 Next.js 앱 템플릿.
|
|
4
|
+
UI 컴포넌트는 `@workspace/ui-{name}` 패키지를 참조하며, sh-ui 설정을 직접 갖지 않음.
|
|
5
|
+
|
|
6
|
+
## 기술 스택
|
|
7
|
+
|
|
8
|
+
- **Next.js 16** (App Router, React Compiler, standalone 출력)
|
|
9
|
+
- **React 19**
|
|
10
|
+
- **TypeScript 5.9**
|
|
11
|
+
- **@workspace/ui-{name}** (sh-ui 컴포넌트 패키지)
|
|
12
|
+
- **TanStack React Query** + **Axios**
|
|
13
|
+
- **Zustand**
|
|
14
|
+
- **next-themes** + **Sonner**
|
|
15
|
+
- **Zod**
|
|
16
|
+
- **Vitest** + **Testing Library**
|
|
17
|
+
- **Docker** 지원
|
|
18
|
+
|
|
19
|
+
## 프로젝트 구조
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
├── app/ # Next.js App Router
|
|
23
|
+
│ ├── layout.tsx # 루트 레이아웃 (@workspace/ui-{name}/globals.css import)
|
|
24
|
+
│ └── page.tsx
|
|
25
|
+
├── src/
|
|
26
|
+
│ ├── app/
|
|
27
|
+
│ │ └── providers/ # QueryClient, Theme, Toaster
|
|
28
|
+
│ ├── shared/ # FSD: 공유 유틸, 설정, 타입
|
|
29
|
+
│ ├── entities/
|
|
30
|
+
│ ├── features/
|
|
31
|
+
│ ├── views/
|
|
32
|
+
│ └── widgets/
|
|
33
|
+
├── eslint.config.js # @workspace/eslint-config 사용
|
|
34
|
+
├── tsconfig.json # @workspace/typescript-config 확장
|
|
35
|
+
├── postcss.config.mjs # @workspace/ui-{name}/postcss.config 재사용
|
|
36
|
+
├── next.config.ts
|
|
37
|
+
├── vitest.config.ts
|
|
38
|
+
├── Dockerfile
|
|
39
|
+
└── .env.example
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 워크스페이스 의존성
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
apps/{name}/
|
|
46
|
+
├── @workspace/ui-{name} → packages/ui/ui-apps/ui-{name} (sh-ui 컴포넌트 + 테마)
|
|
47
|
+
├── @workspace/ui-core → packages/ui/ui-core (cn 등 유틸)
|
|
48
|
+
├── @workspace/eslint-config → packages/eslint-config
|
|
49
|
+
└── @workspace/typescript-config → packages/typescript-config
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## sh-ui 컴포넌트 추가
|
|
53
|
+
|
|
54
|
+
모노레포 루트에서:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# 모든 ui 패키지에 추가 (대화형)
|
|
58
|
+
npx sh-ui-create add-component button
|
|
59
|
+
|
|
60
|
+
# 이 앱의 ui 패키지에만 추가
|
|
61
|
+
npx sh-ui-create add-component button --app {name}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
각 `ui-{app}/` 패키지의 `sh-ui.config.json` 경로 설정에 따라 `src/components/` 로 복사됨.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Metadata } from 'next';
|
|
2
|
+
import '@workspace/ui-app-name/globals.css';
|
|
3
|
+
import { GlobalProvider } from '@/src/app/providers';
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: 'App Name',
|
|
7
|
+
description: 'App Description',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function RootLayout({
|
|
11
|
+
children,
|
|
12
|
+
}: {
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}) {
|
|
15
|
+
return (
|
|
16
|
+
<html lang='ko' suppressHydrationWarning>
|
|
17
|
+
<body>
|
|
18
|
+
<GlobalProvider>{children}</GlobalProvider>
|
|
19
|
+
</body>
|
|
20
|
+
</html>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NextConfig } from 'next';
|
|
2
|
+
|
|
3
|
+
const nextConfig: NextConfig = {
|
|
4
|
+
reactCompiler: true,
|
|
5
|
+
transpilePackages: ['@workspace/ui'],
|
|
6
|
+
output: 'standalone',
|
|
7
|
+
images: {
|
|
8
|
+
unoptimized: process.env.NODE_ENV === 'development',
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default nextConfig;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "app-name",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"private": true,
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "next dev -p 3000 --turbopack",
|
|
8
|
+
"build": "next build",
|
|
9
|
+
"start": "next start",
|
|
10
|
+
"lint": "eslint .",
|
|
11
|
+
"lint:fix": "eslint . --fix",
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@tanstack/react-query": "^5.90.21",
|
|
18
|
+
"@workspace/ui-app-name": "workspace:*",
|
|
19
|
+
"axios": "^1.13.6",
|
|
20
|
+
"lucide-react": "^0.563.0",
|
|
21
|
+
"next": "16.1.6",
|
|
22
|
+
"next-themes": "^0.4.6",
|
|
23
|
+
"react": "^19.2.4",
|
|
24
|
+
"react-dom": "^19.2.4",
|
|
25
|
+
"server-only": "^0.0.1",
|
|
26
|
+
"sonner": "^2.0.7",
|
|
27
|
+
"zod": "^4.3.6",
|
|
28
|
+
"zustand": "^5.0.11"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@tailwindcss/postcss": "^4.1.18",
|
|
32
|
+
"@tanstack/react-query-devtools": "^5.91.3",
|
|
33
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
34
|
+
"@types/node": "^25.1.0",
|
|
35
|
+
"@types/react": "^19.2.10",
|
|
36
|
+
"@types/react-dom": "^19.2.3",
|
|
37
|
+
"@workspace/eslint-config": "workspace:^",
|
|
38
|
+
"@workspace/typescript-config": "workspace:*",
|
|
39
|
+
"babel-plugin-react-compiler": "^1.0.0",
|
|
40
|
+
"eslint": "^9.39.2",
|
|
41
|
+
"jsdom": "^29.0.0",
|
|
42
|
+
"typescript": "^5.9.3",
|
|
43
|
+
"vitest": "^4.1.0"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "@workspace/ui-app-name/postcss.config";
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { Toaster } from 'sonner';
|
|
3
|
+
|
|
4
|
+
import { QueryClientProvider } from '../tanstack/QueryClientProvider';
|
|
5
|
+
import { TanstackDevtoolsProvider } from '../tanstack/TanstackDevtoolsProvider';
|
|
6
|
+
import { ThemeProviders } from '../theme/ThemeProviders';
|
|
7
|
+
|
|
8
|
+
interface GlobalProviderProps {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function GlobalProvider({ children }: GlobalProviderProps) {
|
|
13
|
+
return (
|
|
14
|
+
<ThemeProviders>
|
|
15
|
+
<QueryClientProvider>
|
|
16
|
+
<TanstackDevtoolsProvider>
|
|
17
|
+
<Toaster />
|
|
18
|
+
{children}
|
|
19
|
+
</TanstackDevtoolsProvider>
|
|
20
|
+
</QueryClientProvider>
|
|
21
|
+
</ThemeProviders>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { GlobalProvider } from './GlobalProvider';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
QueryClient,
|
|
5
|
+
QueryClientProvider as TanstackQueryClientProvider,
|
|
6
|
+
} from '@tanstack/react-query';
|
|
7
|
+
import { useState, type ReactNode } from 'react';
|
|
8
|
+
|
|
9
|
+
export function QueryClientProvider({ children }: { children: ReactNode }) {
|
|
10
|
+
const [queryClient] = useState(
|
|
11
|
+
() =>
|
|
12
|
+
new QueryClient({
|
|
13
|
+
defaultOptions: {
|
|
14
|
+
queries: {
|
|
15
|
+
staleTime: 60 * 1000,
|
|
16
|
+
retry: 1,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<TanstackQueryClientProvider client={queryClient}>
|
|
24
|
+
{children}
|
|
25
|
+
</TanstackQueryClientProvider>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
|
4
|
+
import type { ReactNode } from 'react';
|
|
5
|
+
|
|
6
|
+
export function TanstackDevtoolsProvider({ children }: { children: ReactNode }) {
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
{children}
|
|
10
|
+
<ReactQueryDevtools initialIsOpen={false} />
|
|
11
|
+
</>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { ThemeProvider } from 'next-themes';
|
|
4
|
+
import type { ReactNode } from 'react';
|
|
5
|
+
|
|
6
|
+
export function ThemeProviders({ children }: { children: ReactNode }) {
|
|
7
|
+
return (
|
|
8
|
+
<ThemeProvider attribute='class' defaultTheme='system' enableSystem>
|
|
9
|
+
{children}
|
|
10
|
+
</ThemeProvider>
|
|
11
|
+
);
|
|
12
|
+
}
|