@lark-apaas/coding-templates 0.1.43-alpha.8 → 0.1.43-beta.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/meta.json +2 -8
- package/package.json +1 -1
- package/template-apex/package.json +2 -2
- package/template-apex/tsconfig.app.json +1 -2
- package/template-html/_gitignore +2 -0
- package/template-html/index.html +20 -19
- package/template-html/package.json +2 -17
- package/template-html/routes.json +1 -0
- package/template-html/scripts/build.sh +16 -28
- package/template-vite-react/README.md +32 -55
- package/template-vite-react/{src → client/src}/hooks/use-mobile.ts +3 -4
- package/template-vite-react/{src → client/src}/index.tsx +2 -9
- package/template-vite-react/components.json +1 -1
- package/template-vite-react/package.json +6 -8
- package/template-vite-react/tsconfig.app.json +2 -3
- package/template-vite-react/tsconfig.json +1 -1
- package/template-vite-react/vite.config.ts +2 -1
- package/template-html/.spark_project +0 -17
- package/template-html/scripts/mock-health.cjs +0 -32
- package/template-html/src/main.js +0 -38
- package/template-html/src/styles.css +0 -1
- package/template-html/vite.config.ts +0 -70
- package/template-vite-react/.spark/meta.json +0 -8
- package/template-vite-react/.spark/meta.json.example +0 -8
- package/template-vite-react/.spark_project +0 -18
- package/template-vite-react/scripts/dev.cjs +0 -109
- package/template-vite-react/scripts/measure-boot.sh +0 -219
- package/template-vite-react/scripts/mock-health.cjs +0 -32
- package/template-vite-react/src/assets/logo.svg +0 -4
- /package/template-vite-react/{index.html → client/index.html} +0 -0
- /package/template-vite-react/{public → client/public}/favicon.svg +0 -0
- /package/template-vite-react/{public → client/public}/icons.svg +0 -0
- /package/template-vite-react/{src → client/src}/app.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/layout.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/accordion.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/alert-dialog.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/alert.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/aspect-ratio.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/avatar.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/badge.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/breadcrumb.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/button-group.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/button.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/calendar.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/card.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/carousel.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/chart.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/checkbox.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/collapsible.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/command.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/context-menu.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/dialog.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/drawer.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/dropdown-menu.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/empty.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/field.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/form.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/hover-card.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/image.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/input-group.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/input-otp.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/input.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/item.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/kbd.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/label.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/menubar.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/native-select.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/navigation-menu.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/pagination.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/popover.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/progress.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/radio-group.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/resizable.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/scroll-area.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/select.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/separator.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/sheet.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/sidebar.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/skeleton.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/slider.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/sonner.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/spinner.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/switch.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/table.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/tabs.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/textarea.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/toggle-group.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/toggle.tsx +0 -0
- /package/template-vite-react/{src → client/src}/components/ui/tooltip.tsx +0 -0
- /package/template-vite-react/{src → client/src}/index.css +0 -0
- /package/template-vite-react/{src → client/src}/pages/NotFoundPage/NotFoundPage.tsx +0 -0
package/meta.json
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"templates": [
|
|
3
|
-
{
|
|
4
|
-
"name": "vite-react",
|
|
5
|
-
"dir": "template-vite-react",
|
|
6
|
-
"description": "Vite + React 19 + shadcn — jsPage 主推(HMR / Inspector / Capability / OpenTel)",
|
|
7
|
-
"features": ["typescript", "vite", "hmr", "tailwind", "shadcn-ui", "inspector", "capability", "observable"]
|
|
8
|
-
},
|
|
9
3
|
{
|
|
10
4
|
"name": "html",
|
|
11
5
|
"dir": "template-html",
|
|
12
|
-
"description": "纯 HTML —
|
|
13
|
-
"features": ["
|
|
6
|
+
"description": "纯 HTML — 零依赖,原型验证",
|
|
7
|
+
"features": ["tailwind-cdn", "dark-mode"]
|
|
14
8
|
},
|
|
15
9
|
{
|
|
16
10
|
"name": "nextjs-static",
|
package/package.json
CHANGED
|
@@ -71,9 +71,9 @@
|
|
|
71
71
|
"react-day-picker": "^9.14.0",
|
|
72
72
|
"react-dom": "^19.2.4",
|
|
73
73
|
"react-hook-form": "^7.72.0",
|
|
74
|
-
"react-resizable-panels": "^
|
|
74
|
+
"react-resizable-panels": "^3.0.6",
|
|
75
75
|
"react-router-dom": "^7.13.2",
|
|
76
|
-
"recharts": "^
|
|
76
|
+
"recharts": "^2.15.4",
|
|
77
77
|
"sonner": "^2.0.7",
|
|
78
78
|
"tailwind-merge": "^3.5.0",
|
|
79
79
|
"tailwindcss": "^4.2.2",
|
package/template-html/index.html
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="zh-CN">
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>应用标题</title>
|
|
7
|
+
<link href="https://lf3-static.bytednsdoc.com/obj/eden-cn/ylcylz_fsph_ryhs/ljhwZthlaukjlkulzlp/feisuda/feisuda.svg" rel="shortcut icon"/>
|
|
8
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
9
|
+
<script>
|
|
10
|
+
// 可选:Tailwind 运行时配置
|
|
11
|
+
tailwind.config = {};
|
|
12
|
+
</script>
|
|
13
|
+
<style>
|
|
14
|
+
/* 必要的自定义样式(如画布容器尺寸、预览区边框等) */
|
|
15
|
+
</style>
|
|
16
|
+
</head>
|
|
17
|
+
<body class="bg-gray-50">
|
|
18
|
+
<!-- 画布布局容器 -->
|
|
19
|
+
<main id="canvas" class="mx-auto max-w-7xl p-6">
|
|
20
|
+
<!-- 页面内容(由 generate_design 生成的 HTML 片段插入此处) -->
|
|
21
|
+
</main>
|
|
22
|
+
</body>
|
|
22
23
|
</html>
|
|
@@ -5,24 +5,9 @@
|
|
|
5
5
|
"mclaw": {
|
|
6
6
|
"stack": "html",
|
|
7
7
|
"stackVersion": "0.1.0",
|
|
8
|
-
"features": [
|
|
9
|
-
"client"
|
|
10
|
-
]
|
|
8
|
+
"features": ["client"]
|
|
11
9
|
},
|
|
12
10
|
"scripts": {
|
|
13
|
-
"
|
|
14
|
-
"build": "bash scripts/build.sh",
|
|
15
|
-
"lint": "echo 'no lint for plain HTML'"
|
|
16
|
-
},
|
|
17
|
-
"dependencies": {
|
|
18
|
-
"@lark-apaas/client-toolkit-lite": "1.1.7-alpha.6",
|
|
19
|
-
"@lark-apaas/observable-web": "^1.0.6"
|
|
20
|
-
},
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"@lark-apaas/coding-vite-preset": "1.0.7-alpha.2",
|
|
23
|
-
"@tailwindcss/vite": "^4.0.0",
|
|
24
|
-
"concurrently": "^9",
|
|
25
|
-
"tailwindcss": "^4.0.0",
|
|
26
|
-
"vite": "^8"
|
|
11
|
+
"build": "bash scripts/build.sh"
|
|
27
12
|
}
|
|
28
13
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "version": 1, "type": "html", "fallback": "index.html" }
|
|
@@ -3,41 +3,29 @@ set -e
|
|
|
3
3
|
|
|
4
4
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
5
|
OUTPUT="$ROOT/dist/output"
|
|
6
|
-
OUTPUT_RESOURCE="$ROOT/dist/output_resource"
|
|
7
6
|
OUTPUT_STATIC="$ROOT/dist/output_static"
|
|
7
|
+
STATIC_PREFIX="${MCLAW_STATIC_PREFIX:-}"
|
|
8
8
|
|
|
9
|
-
#
|
|
10
|
-
export CLIENT_BASE_PATH="${MCLAW_APP_ID:+/app/$MCLAW_APP_ID}"
|
|
11
|
-
export ASSETS_CDN_PATH="${MCLAW_CDN_DOMAIN:-/}"
|
|
12
|
-
export NODE_ENV="${NODE_ENV:-production}"
|
|
13
|
-
|
|
9
|
+
# 清理
|
|
14
10
|
rm -rf "$ROOT/dist"
|
|
15
|
-
|
|
16
|
-
# 1. Vite 构建 → dist/client/
|
|
17
|
-
npx vite build --outDir "$ROOT/dist/client" --emptyOutDir
|
|
18
|
-
|
|
19
|
-
# 2. HTML → dist/output/
|
|
20
11
|
mkdir -p "$OUTPUT"
|
|
21
|
-
find "$ROOT/dist/client" -maxdepth 1 -name '*.html' -exec cp {} "$OUTPUT/" \;
|
|
22
12
|
|
|
23
|
-
#
|
|
24
|
-
|
|
13
|
+
# 1. 所有 .html 文件按目录结构复制到 dist/output/,并替换 $STATIC$ 为实际静态资源路径
|
|
14
|
+
cd "$ROOT"
|
|
15
|
+
find . -name '*.html' -not -path './dist/*' -not -path './node_modules/*' | while read -r file; do
|
|
16
|
+
dir=$(dirname "$file")
|
|
17
|
+
mkdir -p "$OUTPUT/$dir"
|
|
18
|
+
sed "s|\\\$STATIC\\\$|${STATIC_PREFIX}|g" "$file" > "$OUTPUT/$file"
|
|
19
|
+
done
|
|
25
20
|
|
|
26
|
-
#
|
|
27
|
-
|
|
28
|
-
mkdir -p "$OUTPUT_RESOURCE"
|
|
29
|
-
cp -r "$ROOT/dist/client/assets" "$OUTPUT_RESOURCE/"
|
|
30
|
-
fi
|
|
21
|
+
# 2. routes.json → dist/output/
|
|
22
|
+
cp "$ROOT/routes.json" "$OUTPUT/routes.json"
|
|
31
23
|
|
|
32
|
-
#
|
|
33
|
-
if [ -d "$ROOT/
|
|
34
|
-
|
|
35
|
-
rsync -a --exclude='*.ts' --exclude='*.tsx' --exclude='*.js' --exclude='*.jsx' "$ROOT/shared/static/" "$OUTPUT_STATIC/"
|
|
24
|
+
# 3. static/ → dist/output_static/(如果存在)
|
|
25
|
+
if [ -d "$ROOT/static" ]; then
|
|
26
|
+
cp -r "$ROOT/static" "$OUTPUT_STATIC"
|
|
36
27
|
fi
|
|
37
28
|
|
|
38
|
-
rm -rf "$ROOT/dist/client"
|
|
39
|
-
|
|
40
29
|
echo "Build complete"
|
|
41
|
-
echo " HTML
|
|
42
|
-
[ -d "$
|
|
43
|
-
[ -d "$OUTPUT_STATIC" ] && echo " Static → dist/output_static/" || true
|
|
30
|
+
echo " HTML → dist/output/"
|
|
31
|
+
[ -d "$OUTPUT_STATIC" ] && echo " Static → dist/output_static/" || true
|
|
@@ -15,47 +15,30 @@
|
|
|
15
15
|
## 目录结构
|
|
16
16
|
|
|
17
17
|
```
|
|
18
|
-
|
|
19
|
-
├── index.
|
|
20
|
-
├──
|
|
21
|
-
|
|
22
|
-
├──
|
|
23
|
-
│ ├──
|
|
24
|
-
│
|
|
25
|
-
|
|
26
|
-
│ ├──
|
|
27
|
-
│ │
|
|
28
|
-
│
|
|
29
|
-
│
|
|
30
|
-
│
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
│ └── lib/ # 工具函数(cn() 等)
|
|
39
|
-
└── shared/
|
|
40
|
-
└── static/ # 类别 ③:业务 CDN 私有资源
|
|
41
|
-
├── data/ # 数据文件(JSON)
|
|
42
|
-
└── images/ # 图片资源
|
|
18
|
+
client/src/
|
|
19
|
+
├── index.tsx # 入口(勿修改)
|
|
20
|
+
├── app.tsx # 路由配置(仅在 <Routes> 内增删 <Route>)
|
|
21
|
+
├── index.css # 全局样式 + 主题变量
|
|
22
|
+
├── components/ # 基础 UI 组件(禁止存放业务组件)
|
|
23
|
+
│ ├── layout.tsx # 全局布局容器(含 <Outlet />)
|
|
24
|
+
│ └── ui/ # shadcn/ui 内置组件(勿修改)
|
|
25
|
+
├── pages/ # 页面模块(每个页面一个目录)
|
|
26
|
+
│ ├── <PageName>/ # 页面目录示例
|
|
27
|
+
│ │ ├── PageName.tsx # 页面入口文件与目录同名
|
|
28
|
+
│ │ └── components/ # 页面专属组件
|
|
29
|
+
│ └── NotFoundPage/
|
|
30
|
+
│ └── NotFoundPage.tsx
|
|
31
|
+
├── hooks/ # 自定义 Hooks
|
|
32
|
+
└── lib/ # 工具函数(cn() 等)
|
|
33
|
+
|
|
34
|
+
shared/
|
|
35
|
+
└── static/ # 静态资源
|
|
36
|
+
├── data/ # 数据文件(JSON)
|
|
37
|
+
└── images/ # 图片资源
|
|
43
38
|
```
|
|
44
39
|
|
|
45
40
|
---
|
|
46
41
|
|
|
47
|
-
## 静态资源放哪里?三类不同位置
|
|
48
|
-
|
|
49
|
-
| 类别 | 位置 | 用法 | 谁处理 |
|
|
50
|
-
|------|------|------|--------|
|
|
51
|
-
| ① **代码 import 的资源**<br/>(小图标 / 按钮图)| `src/assets/` | `import logo from '@/assets/logo.svg'` | vite 打包:加 hash、压缩、可 inline base64 |
|
|
52
|
-
| ② **原样 serve 的资源**<br/>(favicon / robots.txt)| `public/` | `<link href="/favicon.svg" />`(URL 直接引)| vite dev/build 都原样输出,不进 bundle |
|
|
53
|
-
| ③ **业务 CDN 私有资源**<br/>(配置 json / 大图)| `shared/static/` | `import data from '@shared/static/foo.json'` | build.sh → `dist/output_static/` → 私有 tos(应用权限管控)|
|
|
54
|
-
|
|
55
|
-
> **为什么叫 `shared/`?** 沿用全栈模板时代的目录名(当时 `client/` ↔ `server/` 共享类型)。jsPage 没 server,但 `shared/static/` 这个目录被 preset 和 build.sh 认住了,改名要联动改下游链路,所以保留。语义上把它当作"CDN 私有静态目录"理解即可。
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
42
|
## 模板初始状态
|
|
60
43
|
|
|
61
44
|
- `app.tsx` 首页路由指向平台内置的 `<Welcome />` 组件
|
|
@@ -68,8 +51,8 @@
|
|
|
68
51
|
|
|
69
52
|
| 文件 | 原因 |
|
|
70
53
|
|------|------|
|
|
71
|
-
| `src/index.tsx` | Provider 层级 + 样式引入,由模板管理 |
|
|
72
|
-
| `src/components/ui/*` | shadcn/ui 内置组件,版本锁定 |
|
|
54
|
+
| `client/src/index.tsx` | Provider 层级 + 样式引入,由模板管理 |
|
|
55
|
+
| `client/src/components/ui/*` | shadcn/ui 内置组件,版本锁定 |
|
|
73
56
|
|
|
74
57
|
---
|
|
75
58
|
|
|
@@ -77,45 +60,39 @@
|
|
|
77
60
|
|
|
78
61
|
| 内容类型 | 放置位置 |
|
|
79
62
|
|---------|---------|
|
|
80
|
-
| 新页面 | `src/pages/<PageName>/PageName.tsx` |
|
|
81
|
-
| 页面专属组件 | `src/pages/<PageName>/components/` |
|
|
82
|
-
| 自定义 Hooks | `src/hooks/` |
|
|
83
|
-
| 工具函数 | `src/lib/` |
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
| 走业务 CDN 的私有静态 | `shared/static/`(`data/` JSON / `images/` 图片)|
|
|
87
|
-
| 共享类型定义 | `shared/types.ts` |
|
|
63
|
+
| 新页面 | `client/src/pages/<PageName>/PageName.tsx` |
|
|
64
|
+
| 页面专属组件 | `client/src/pages/<PageName>/components/` |
|
|
65
|
+
| 自定义 Hooks | `client/src/hooks/` |
|
|
66
|
+
| 工具函数 | `client/src/lib/` |
|
|
67
|
+
| 静态数据文件 | `shared/static/data/` |
|
|
68
|
+
| 静态图片 | `shared/static/images/` |
|
|
88
69
|
|
|
89
70
|
---
|
|
90
71
|
|
|
91
72
|
## 导入路径
|
|
92
73
|
|
|
93
74
|
```typescript
|
|
94
|
-
// @/ 别名 → src/
|
|
75
|
+
// @/ 别名 → client/src/
|
|
95
76
|
import { cn } from "@/lib/utils";
|
|
96
77
|
import { useIsMobile } from "@/hooks/use-mobile";
|
|
97
|
-
import logo from "@/assets/logo.svg";
|
|
98
78
|
|
|
99
|
-
// @shared/ 别名 → shared
|
|
79
|
+
// @shared/ 别名 → shared/
|
|
100
80
|
import heroImage from "@shared/static/images/hero.png";
|
|
101
81
|
import configData from "@shared/static/config.json";
|
|
102
|
-
|
|
103
|
-
// public/ 不能 import,只能 URL 直接引
|
|
104
|
-
// <link rel="icon" href="/favicon.svg" />
|
|
105
82
|
```
|
|
106
83
|
|
|
107
84
|
---
|
|
108
85
|
|
|
109
86
|
## 路由配置
|
|
110
87
|
|
|
111
|
-
- 新增页面需在 `src/app.tsx` 的 `<Routes>` 内注册 `<Route>`
|
|
88
|
+
- 新增页面需在 `client/src/app.tsx` 的 `<Routes>` 内注册 `<Route>`
|
|
112
89
|
- `BrowserRouter` 已在 `index.tsx` 中配置,`app.tsx` 中**禁止**再包裹 Router
|
|
113
90
|
|
|
114
91
|
---
|
|
115
92
|
|
|
116
93
|
## 主题变量
|
|
117
94
|
|
|
118
|
-
主题色定义在 `src/index.css`,通过 `:root` CSS 变量 + `@theme inline` 注册到 Tailwind。
|
|
95
|
+
主题色定义在 `client/src/index.css`,通过 `:root` CSS 变量 + `@theme inline` 注册到 Tailwind。
|
|
119
96
|
|
|
120
97
|
| 用途 | Tailwind 类 | CSS 变量 |
|
|
121
98
|
|------|------------|----------|
|
|
@@ -3,9 +3,7 @@ import * as React from "react"
|
|
|
3
3
|
const MOBILE_BREAKPOINT = 768
|
|
4
4
|
|
|
5
5
|
export function useIsMobile() {
|
|
6
|
-
const [isMobile, setIsMobile] = React.useState<boolean>(
|
|
7
|
-
typeof window !== "undefined" && window.innerWidth < MOBILE_BREAKPOINT,
|
|
8
|
-
)
|
|
6
|
+
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
|
|
9
7
|
|
|
10
8
|
React.useEffect(() => {
|
|
11
9
|
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
|
|
@@ -13,8 +11,9 @@ export function useIsMobile() {
|
|
|
13
11
|
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
|
14
12
|
}
|
|
15
13
|
mql.addEventListener("change", onChange)
|
|
14
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
|
|
16
15
|
return () => mql.removeEventListener("change", onChange)
|
|
17
16
|
}, [])
|
|
18
17
|
|
|
19
|
-
return isMobile
|
|
18
|
+
return !!isMobile
|
|
20
19
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { StrictMode } from "react";
|
|
2
2
|
import { createRoot } from "react-dom/client";
|
|
3
3
|
import { BrowserRouter } from "react-router-dom";
|
|
4
|
-
import {
|
|
5
|
-
import { AppContainer, ErrorRender } from "@lark-apaas/client-toolkit-lite";
|
|
4
|
+
import { AppContainer } from "@lark-apaas/client-toolkit-lite";
|
|
6
5
|
import App from "./app";
|
|
7
6
|
import "./index.css";
|
|
8
7
|
|
|
@@ -10,13 +9,7 @@ createRoot(document.getElementById("root")!).render(
|
|
|
10
9
|
<StrictMode>
|
|
11
10
|
<BrowserRouter basename={process.env.CLIENT_BASE_PATH || "/"}>
|
|
12
11
|
<AppContainer>
|
|
13
|
-
<
|
|
14
|
-
fallbackRender={({ error, resetErrorBoundary }) => (
|
|
15
|
-
<ErrorRender error={error} resetErrorBoundary={resetErrorBoundary} />
|
|
16
|
-
)}
|
|
17
|
-
>
|
|
18
|
-
<App />
|
|
19
|
-
</ErrorBoundary>
|
|
12
|
+
<App />
|
|
20
13
|
</AppContainer>
|
|
21
14
|
</BrowserRouter>
|
|
22
15
|
</StrictMode>,
|
|
@@ -10,11 +10,10 @@
|
|
|
10
10
|
]
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"dev": "node scripts/dev.cjs",
|
|
14
13
|
"build": "bash scripts/build.sh",
|
|
15
14
|
"typecheck": "tsc -p tsconfig.app.json",
|
|
16
|
-
"lint": "npm
|
|
17
|
-
"lint:eslint": "eslint src"
|
|
15
|
+
"lint": "concurrently npm:typecheck npm:lint:eslint",
|
|
16
|
+
"lint:eslint": "eslint client/src"
|
|
18
17
|
},
|
|
19
18
|
"dependencies": {
|
|
20
19
|
"@hookform/resolvers": "^5.2.2",
|
|
@@ -44,7 +43,7 @@
|
|
|
44
43
|
"@radix-ui/react-toggle": "^1.1.9",
|
|
45
44
|
"@radix-ui/react-toggle-group": "^1.1.10",
|
|
46
45
|
"@radix-ui/react-tooltip": "^1.1.18",
|
|
47
|
-
"@lark-apaas/client-toolkit-lite": "1.1.
|
|
46
|
+
"@lark-apaas/client-toolkit-lite": "^1.1.0",
|
|
48
47
|
"@formkit/auto-animate": "^0.9.0",
|
|
49
48
|
"@gsap/react": "^2.1.2",
|
|
50
49
|
"framer-motion": "^12.38.0",
|
|
@@ -62,11 +61,10 @@
|
|
|
62
61
|
"react": "^19.2.4",
|
|
63
62
|
"react-day-picker": "^9.14.0",
|
|
64
63
|
"react-dom": "^19.2.4",
|
|
65
|
-
"react-error-boundary": "^6.0.0",
|
|
66
64
|
"react-hook-form": "^7.72.0",
|
|
67
|
-
"react-resizable-panels": "^
|
|
65
|
+
"react-resizable-panels": "^3.0.6",
|
|
68
66
|
"react-router-dom": "^7.13.2",
|
|
69
|
-
"recharts": "^
|
|
67
|
+
"recharts": "^2.15.4",
|
|
70
68
|
"sonner": "^2.0.7",
|
|
71
69
|
"tailwind-merge": "^3.5.0",
|
|
72
70
|
"tailwindcss": "^4.2.2",
|
|
@@ -80,7 +78,7 @@
|
|
|
80
78
|
"@types/react": "^19",
|
|
81
79
|
"@types/react-dom": "^19",
|
|
82
80
|
"@lark-apaas/coding-presets": "^1.0.0",
|
|
83
|
-
"@lark-apaas/coding-vite-preset": "1.0.
|
|
81
|
+
"@lark-apaas/coding-vite-preset": "^1.0.0",
|
|
84
82
|
"concurrently": "^9",
|
|
85
83
|
"eslint": "^9",
|
|
86
84
|
"eslint-plugin-react-hooks": "^7",
|
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
5
5
|
"baseUrl": ".",
|
|
6
6
|
"paths": {
|
|
7
|
-
"@/*": ["./src/*"],
|
|
7
|
+
"@/*": ["./client/src/*"],
|
|
8
8
|
"@shared/*": ["./shared/*"]
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
|
-
"include": ["src", "shared"]
|
|
12
|
-
"exclude": ["src/components/ui"]
|
|
11
|
+
"include": ["client/src", "shared"]
|
|
13
12
|
}
|
|
@@ -2,9 +2,10 @@ import path from 'path'
|
|
|
2
2
|
import { defineConfig } from '@lark-apaas/coding-vite-preset'
|
|
3
3
|
|
|
4
4
|
export default defineConfig({
|
|
5
|
+
root: path.resolve(__dirname, 'client'),
|
|
5
6
|
resolve: {
|
|
6
7
|
alias: {
|
|
7
|
-
'@': path.resolve(__dirname, 'src'),
|
|
8
|
+
'@': path.resolve(__dirname, 'client/src'),
|
|
8
9
|
'@shared': path.resolve(__dirname, 'shared'),
|
|
9
10
|
},
|
|
10
11
|
},
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
run = ["npm", "run", "dev"]
|
|
2
|
-
lint = ["npm", "run", "lint"]
|
|
3
|
-
hidden = [".config", ".git", "scripts", "node_modules", "dist", ".spark", ".agent", ".agents", "tmp", ".spark_project", ".playwright-cli"]
|
|
4
|
-
|
|
5
|
-
[deployment]
|
|
6
|
-
build = ["npm", "run", "build"]
|
|
7
|
-
|
|
8
|
-
[files]
|
|
9
|
-
[files.restrict]
|
|
10
|
-
pathPatterns = ["package.json", ".spark_project", ".spark/meta.json", ".gitignore"]
|
|
11
|
-
[files.hidden]
|
|
12
|
-
pathPatterns = [".config", ".git", "scripts", "node_modules", "dist", ".spark", ".agent", ".agents", "tmp", ".spark_project", ".playwright-cli"]
|
|
13
|
-
|
|
14
|
-
[sandbox]
|
|
15
|
-
# 临时兼容老沙箱硬编码探测的 3000 / 8001 端口。
|
|
16
|
-
# 8001 由 vite dev server 真实占据;3000 由 scripts/mock-health.cjs 占位。
|
|
17
|
-
healthCheck = [8001, 3000]
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* 沙箱预览态健康检查兜底:在 3000 端口起 HTTP listener。
|
|
4
|
-
*
|
|
5
|
-
* 老沙箱硬编码探测 3000 + 8001 判定"应用启动了"。jsPage 没有真实 Node server,
|
|
6
|
-
* 8001 由 Vite dev server 真正占(预览流量也走 8001),3000 没有任何业务进程,
|
|
7
|
-
* 只能 mock 一个 listener 让健康检查过。
|
|
8
|
-
*
|
|
9
|
-
* 等沙箱链路切到新协议(读 .spark_project [sandbox].healthCheck)后可删除。
|
|
10
|
-
*/
|
|
11
|
-
const http = require('node:http');
|
|
12
|
-
|
|
13
|
-
const PORTS = [3000];
|
|
14
|
-
|
|
15
|
-
for (const port of PORTS) {
|
|
16
|
-
const server = http.createServer((_req, res) => {
|
|
17
|
-
res.writeHead(200, { 'content-type': 'text/plain' });
|
|
18
|
-
res.end('ok');
|
|
19
|
-
});
|
|
20
|
-
server.on('error', (err) => {
|
|
21
|
-
console.error(`[mock-health] :${port} listen error:`, err.message);
|
|
22
|
-
if (err.code === 'EADDRINUSE') {
|
|
23
|
-
// 端口已被占说明业务已起来,mock 退场即可
|
|
24
|
-
console.warn(`[mock-health] :${port} 已被占用,跳过 mock`);
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
process.exitCode = 1;
|
|
28
|
-
});
|
|
29
|
-
server.listen(port, '0.0.0.0', () => {
|
|
30
|
-
console.log(`[mock-health] listening on :${port}`);
|
|
31
|
-
});
|
|
32
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// 极薄入口:装平台 SDK。
|
|
2
|
-
// 业务代码写在 index.html 的 <script> 里,或者再 import './your-app.js'。
|
|
3
|
-
|
|
4
|
-
import './styles.css';
|
|
5
|
-
|
|
6
|
-
// 1) capability — 调插件能力
|
|
7
|
-
import { capabilityClient } from '@lark-apaas/client-toolkit-lite';
|
|
8
|
-
// 暴露到 window 让 index.html 内联 <script> 也能用
|
|
9
|
-
window.capability = capabilityClient;
|
|
10
|
-
|
|
11
|
-
// 2) observable — OpenTelemetry traces/logs/metrics
|
|
12
|
-
// lite 里的 initObservable() 绑了 React useEffect,纯 HTML 用不了;inline 一份等效逻辑。
|
|
13
|
-
import { observable, AppEnv } from '@lark-apaas/observable-web';
|
|
14
|
-
try {
|
|
15
|
-
const appId = window.appId;
|
|
16
|
-
const isNewPath =
|
|
17
|
-
typeof window.location !== 'undefined' &&
|
|
18
|
-
/^\/app\/[^/]/.test(window.location.pathname);
|
|
19
|
-
observable.start({
|
|
20
|
-
serviceName: 'app',
|
|
21
|
-
env: process.env.NODE_ENV === 'development' ? AppEnv.Dev : AppEnv.Prod,
|
|
22
|
-
collectorUrl: isNewPath
|
|
23
|
-
? {
|
|
24
|
-
log: `/app/${appId}/__runtime__/api/v1/observability/logs/collect`,
|
|
25
|
-
trace: `/app/${appId}/__runtime__/api/v1/observability/traces/collect`,
|
|
26
|
-
metric: `/app/${appId}/__runtime__/api/v1/observability/metrics/collect`,
|
|
27
|
-
time: `/app/${appId}/__runtime__/api/v1/observability/current_server_timestamp`,
|
|
28
|
-
}
|
|
29
|
-
: {
|
|
30
|
-
log: `/spark/app/${appId}/runtime/api/v1/observability/logs/collect`,
|
|
31
|
-
trace: `/spark/app/${appId}/runtime/api/v1/observability/traces/collect`,
|
|
32
|
-
metric: `/spark/app/${appId}/runtime/api/v1/observability/metrics/collect`,
|
|
33
|
-
time: `/spark/api/v1/observability/app/${appId}/current_server_timestamp`,
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
} catch (error) {
|
|
37
|
-
console.error('Failed to start WebObservableSdk:', error);
|
|
38
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@import "tailwindcss";
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import type { IncomingMessage, ServerResponse } from 'http'
|
|
3
|
-
import { defineConfig } from '@lark-apaas/coding-vite-preset'
|
|
4
|
-
import type { Plugin, ViteDevServer } from 'vite'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* dev 模式 base-path normalize 中间件(同 template-vite-react)
|
|
8
|
-
*
|
|
9
|
-
* 沙箱预览网关把流量原样转给 vite(保留 /app/:appId 前缀)。但浏览器首次访问的
|
|
10
|
-
* URL 是 `/app/app_xxx?sso_token=...`(pathname 缺末尾 /)。
|
|
11
|
-
*
|
|
12
|
-
* vite 8 的 baseMiddleware 对"缺末尾 /"的请求不再像 vite 5 那样自动 301,
|
|
13
|
-
* 而是直接返回 404 警告页 "The server is configured with a public base URL..."。
|
|
14
|
-
*
|
|
15
|
-
* 这里做 internal rewrite(不发 301,避免跟沙箱网关形成 round-trip 死循环):
|
|
16
|
-
* pathname === base 去尾 / → 改写 req.url 加上尾 /,下游继续 strip → SPA fallback。
|
|
17
|
-
*
|
|
18
|
-
* 必须 stack.unshift 而非 server.middlewares.use,否则排到内置 baseMiddleware
|
|
19
|
-
* 之后失效。
|
|
20
|
-
*
|
|
21
|
-
* TODO: coding-vite-preset 新版本已含同等逻辑,待依赖普及后可删此 plugin。
|
|
22
|
-
*/
|
|
23
|
-
const baseNormalizePlugin: Plugin = {
|
|
24
|
-
name: 'base-path-normalize',
|
|
25
|
-
configureServer(server: ViteDevServer) {
|
|
26
|
-
const base = (process.env.CLIENT_BASE_PATH || '').replace(/\/+$/, '')
|
|
27
|
-
if (!base) return
|
|
28
|
-
const stack = (
|
|
29
|
-
server.middlewares as unknown as {
|
|
30
|
-
stack: Array<{ route: string; handle: unknown }>
|
|
31
|
-
}
|
|
32
|
-
).stack
|
|
33
|
-
if (!Array.isArray(stack)) return
|
|
34
|
-
stack.unshift({
|
|
35
|
-
route: '',
|
|
36
|
-
handle: (req: IncomingMessage, _res: ServerResponse, next: () => void) => {
|
|
37
|
-
const url = req.url || ''
|
|
38
|
-
const qIdx = url.indexOf('?')
|
|
39
|
-
const pathname = qIdx >= 0 ? url.slice(0, qIdx) : url
|
|
40
|
-
const search = qIdx >= 0 ? url.slice(qIdx) : ''
|
|
41
|
-
if (pathname === base) {
|
|
42
|
-
req.url = base + '/' + search
|
|
43
|
-
}
|
|
44
|
-
next()
|
|
45
|
-
},
|
|
46
|
-
})
|
|
47
|
-
},
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export default defineConfig({
|
|
51
|
-
// 模板根目录就是 index.html 所在位置(跟 vite-react 不同,没有 client/ 子目录)
|
|
52
|
-
root: path.resolve(__dirname),
|
|
53
|
-
resolve: {
|
|
54
|
-
alias: {
|
|
55
|
-
'@shared': path.resolve(__dirname, 'shared'),
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
build: {
|
|
59
|
-
// coding-vite-preset 默认把 entry 设为 client/index.html(vite-react 用的布局),
|
|
60
|
-
// HTML 模板没有 client/ 子目录,override 成根目录的 index.html。
|
|
61
|
-
rollupOptions: {
|
|
62
|
-
input: path.resolve(__dirname, 'index.html'),
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
// 同步告诉 Vite dev 优化器 entry 在哪,避免"failed to resolve rolldownOptions.input"警告。
|
|
66
|
-
optimizeDeps: {
|
|
67
|
-
entries: [path.resolve(__dirname, 'index.html')],
|
|
68
|
-
},
|
|
69
|
-
plugins: [baseNormalizePlugin],
|
|
70
|
-
})
|