@lmy54321/design-system 1.1.3 → 1.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.
- package/{rules → .codebuddy/rules}/design-system.mdc +28 -0
- package/.codebuddy/rules/init-project.mdc +127 -0
- package/package.json +6 -3
- package/template/index.html +18 -0
- package/template/public/manifest.json +9 -0
- package/template/src/App.tsx +55 -0
- package/template/src/index.css +4 -0
- package/template/src/main.tsx +28 -0
- package/template/src/pages/CommuteFoodPage.tsx +547 -0
- package/template/src/pages/ComponentLibrary.tsx +1049 -0
- package/template/src/pages/DeployPage.tsx +290 -0
- package/template/src/pages/DevPortal.tsx +161 -0
- package/template/src/pages/ExplorePage.tsx +1013 -0
- package/template/src/pages/MapHome.tsx +388 -0
- package/template/src/pages/MapSearchPage.tsx +529 -0
- package/template/src/pages/MePage.tsx +196 -0
- package/template/src/pages/POIRecommendPage.tsx +676 -0
- package/template/src/pages/PlanDetailPage.tsx +345 -0
- package/template/src/pages/PlanPage.tsx +602 -0
- package/template/src/pages/RouteDetailPage.tsx +276 -0
- package/template/src/pages/SearchFlowDemo.tsx +954 -0
- package/template/src/pages/SyncTool.tsx +688 -0
- package/template/src/pages/TeamTripPage.tsx +697 -0
- package/template/src/pages/TemplateDetailPage.tsx +287 -0
- package/template/tsconfig.json +23 -0
- package/template/vite.config.ts +18 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { useNavigate } from "react-router-dom";
|
|
3
|
+
import { Btn, IconFont, cn } from "@lmy54321/design-system";
|
|
4
|
+
import { motion, AnimatePresence } from "motion/react";
|
|
5
|
+
|
|
6
|
+
type DeployStatus = "idle" | "building" | "uploading" | "done" | "error";
|
|
7
|
+
|
|
8
|
+
const STEPS = [
|
|
9
|
+
{ key: "building", label: "打包项目", icon: "system-components" },
|
|
10
|
+
{ key: "uploading", label: "上传资源", icon: "cloud-upload" },
|
|
11
|
+
{ key: "done", label: "部署完成", icon: "check-circle" },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export function DeployPage() {
|
|
15
|
+
const navigate = useNavigate();
|
|
16
|
+
const [status, setStatus] = useState<DeployStatus>("idle");
|
|
17
|
+
const [progress, setProgress] = useState(0);
|
|
18
|
+
|
|
19
|
+
const handleDeploy = async () => {
|
|
20
|
+
setStatus("building");
|
|
21
|
+
setProgress(0);
|
|
22
|
+
|
|
23
|
+
// 模拟打包
|
|
24
|
+
for (let i = 0; i <= 40; i += 5) {
|
|
25
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
26
|
+
setProgress(i);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 模拟上传
|
|
30
|
+
setStatus("uploading");
|
|
31
|
+
for (let i = 40; i <= 90; i += 5) {
|
|
32
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
33
|
+
setProgress(i);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 完成
|
|
37
|
+
setProgress(100);
|
|
38
|
+
setStatus("done");
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const isDeploying = status === "building" || status === "uploading";
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className="min-h-[100dvh] bg-background">
|
|
45
|
+
{/* Header */}
|
|
46
|
+
<div className="border-b border-border bg-card px-[32px] py-[24px]">
|
|
47
|
+
<div className="max-w-[800px] mx-auto">
|
|
48
|
+
<div className="flex items-center gap-[12px] mb-[8px]">
|
|
49
|
+
<button
|
|
50
|
+
onClick={() => navigate("/dev")}
|
|
51
|
+
className="size-[36px] rounded-full bg-black/[0.04] flex items-center justify-center active:bg-black/[0.08]"
|
|
52
|
+
>
|
|
53
|
+
<IconFont name="chevron-left" size="20px" />
|
|
54
|
+
</button>
|
|
55
|
+
<h1 className="text-[24px] font-bold text-foreground">部署预览</h1>
|
|
56
|
+
</div>
|
|
57
|
+
<p className="text-[14px] text-muted-foreground ml-[48px]">
|
|
58
|
+
一键打包并部署 Demo,生成手机可扫描的预览链接
|
|
59
|
+
</p>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
{/* Content */}
|
|
64
|
+
<div className="max-w-[800px] mx-auto p-[32px]">
|
|
65
|
+
{/* 部署说明 */}
|
|
66
|
+
<div className="bg-black/[0.02] rounded-[20px] p-[24px] mb-[32px]">
|
|
67
|
+
<h3 className="text-[15px] font-medium text-foreground mb-[12px]">
|
|
68
|
+
部署说明
|
|
69
|
+
</h3>
|
|
70
|
+
<ul className="space-y-[8px]">
|
|
71
|
+
<li className="flex items-start gap-[8px] text-[13px] text-muted-foreground">
|
|
72
|
+
<IconFont
|
|
73
|
+
name="check-circle"
|
|
74
|
+
size="16px"
|
|
75
|
+
className="text-[#22C55E] shrink-0 mt-[1px]"
|
|
76
|
+
/>
|
|
77
|
+
只会部署 Demo 演示页面(<code className="px-[4px] py-[1px] bg-black/[0.04] rounded text-[12px]">/</code> 路径),开发工具页不会出现
|
|
78
|
+
</li>
|
|
79
|
+
<li className="flex items-start gap-[8px] text-[13px] text-muted-foreground">
|
|
80
|
+
<IconFont
|
|
81
|
+
name="check-circle"
|
|
82
|
+
size="16px"
|
|
83
|
+
className="text-[#22C55E] shrink-0 mt-[1px]"
|
|
84
|
+
/>
|
|
85
|
+
部署后会生成一个链接和二维码,手机扫码即可预览
|
|
86
|
+
</li>
|
|
87
|
+
<li className="flex items-start gap-[8px] text-[13px] text-muted-foreground">
|
|
88
|
+
<IconFont
|
|
89
|
+
name="check-circle"
|
|
90
|
+
size="16px"
|
|
91
|
+
className="text-[#22C55E] shrink-0 mt-[1px]"
|
|
92
|
+
/>
|
|
93
|
+
每次部署会覆盖上一次的内容,链接保持不变
|
|
94
|
+
</li>
|
|
95
|
+
</ul>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
{/* 部署进度 */}
|
|
99
|
+
<AnimatePresence mode="wait">
|
|
100
|
+
{status === "idle" && (
|
|
101
|
+
<motion.div
|
|
102
|
+
key="idle"
|
|
103
|
+
initial={{ opacity: 0 }}
|
|
104
|
+
animate={{ opacity: 1 }}
|
|
105
|
+
exit={{ opacity: 0 }}
|
|
106
|
+
className="text-center py-[48px]"
|
|
107
|
+
>
|
|
108
|
+
<div className="size-[80px] rounded-[24px] bg-primary/10 flex items-center justify-center mx-auto mb-[20px]">
|
|
109
|
+
<IconFont
|
|
110
|
+
name="cloud-upload"
|
|
111
|
+
size="40px"
|
|
112
|
+
className="text-primary"
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
<h3 className="text-[18px] font-medium text-foreground mb-[8px]">
|
|
116
|
+
准备就绪
|
|
117
|
+
</h3>
|
|
118
|
+
<p className="text-[14px] text-muted-foreground mb-[32px]">
|
|
119
|
+
点击下方按钮开始部署
|
|
120
|
+
</p>
|
|
121
|
+
<Btn
|
|
122
|
+
variant="primary"
|
|
123
|
+
size="large"
|
|
124
|
+
label="开始部署"
|
|
125
|
+
icon={<IconFont name="cloud-upload" size="18px" />}
|
|
126
|
+
onClick={handleDeploy}
|
|
127
|
+
/>
|
|
128
|
+
</motion.div>
|
|
129
|
+
)}
|
|
130
|
+
|
|
131
|
+
{isDeploying && (
|
|
132
|
+
<motion.div
|
|
133
|
+
key="deploying"
|
|
134
|
+
initial={{ opacity: 0 }}
|
|
135
|
+
animate={{ opacity: 1 }}
|
|
136
|
+
exit={{ opacity: 0 }}
|
|
137
|
+
className="py-[32px]"
|
|
138
|
+
>
|
|
139
|
+
{/* 步骤指示器 */}
|
|
140
|
+
<div className="flex items-center justify-center gap-[24px] mb-[40px]">
|
|
141
|
+
{STEPS.map((step, idx) => {
|
|
142
|
+
const isActive =
|
|
143
|
+
(step.key === "building" && status === "building") ||
|
|
144
|
+
(step.key === "uploading" && status === "uploading") ||
|
|
145
|
+
step.key === "done";
|
|
146
|
+
const isDone =
|
|
147
|
+
(step.key === "building" &&
|
|
148
|
+
(status === "uploading" || status === "done")) ||
|
|
149
|
+
(step.key === "uploading" && status === "done");
|
|
150
|
+
return (
|
|
151
|
+
<div
|
|
152
|
+
key={step.key}
|
|
153
|
+
className="flex items-center gap-[8px]"
|
|
154
|
+
>
|
|
155
|
+
{idx > 0 && (
|
|
156
|
+
<div
|
|
157
|
+
className={cn(
|
|
158
|
+
"w-[32px] h-[2px] rounded-full",
|
|
159
|
+
isDone ? "bg-primary" : "bg-border"
|
|
160
|
+
)}
|
|
161
|
+
/>
|
|
162
|
+
)}
|
|
163
|
+
<div
|
|
164
|
+
className={cn(
|
|
165
|
+
"size-[36px] rounded-full flex items-center justify-center transition-colors",
|
|
166
|
+
isDone
|
|
167
|
+
? "bg-primary"
|
|
168
|
+
: isActive && status === step.key
|
|
169
|
+
? "bg-primary/20"
|
|
170
|
+
: "bg-black/[0.04]"
|
|
171
|
+
)}
|
|
172
|
+
>
|
|
173
|
+
<IconFont
|
|
174
|
+
name={step.icon}
|
|
175
|
+
size="18px"
|
|
176
|
+
className={cn(
|
|
177
|
+
isDone
|
|
178
|
+
? "text-white"
|
|
179
|
+
: isActive && status === step.key
|
|
180
|
+
? "text-primary"
|
|
181
|
+
: "text-muted-foreground"
|
|
182
|
+
)}
|
|
183
|
+
/>
|
|
184
|
+
</div>
|
|
185
|
+
<span
|
|
186
|
+
className={cn(
|
|
187
|
+
"text-[13px]",
|
|
188
|
+
isDone || (isActive && status === step.key)
|
|
189
|
+
? "text-foreground font-medium"
|
|
190
|
+
: "text-muted-foreground"
|
|
191
|
+
)}
|
|
192
|
+
>
|
|
193
|
+
{step.label}
|
|
194
|
+
</span>
|
|
195
|
+
</div>
|
|
196
|
+
);
|
|
197
|
+
})}
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
{/* 进度条 */}
|
|
201
|
+
<div className="max-w-[400px] mx-auto">
|
|
202
|
+
<div className="h-[6px] bg-black/[0.06] rounded-full overflow-hidden">
|
|
203
|
+
<motion.div
|
|
204
|
+
className="h-full bg-primary rounded-full"
|
|
205
|
+
initial={{ width: 0 }}
|
|
206
|
+
animate={{ width: `${progress}%` }}
|
|
207
|
+
transition={{ ease: "easeOut" }}
|
|
208
|
+
/>
|
|
209
|
+
</div>
|
|
210
|
+
<p className="text-center text-[13px] text-muted-foreground mt-[12px]">
|
|
211
|
+
{status === "building" ? "正在打包..." : "正在上传..."}
|
|
212
|
+
{progress}%
|
|
213
|
+
</p>
|
|
214
|
+
</div>
|
|
215
|
+
</motion.div>
|
|
216
|
+
)}
|
|
217
|
+
|
|
218
|
+
{status === "done" && (
|
|
219
|
+
<motion.div
|
|
220
|
+
key="done"
|
|
221
|
+
initial={{ opacity: 0, scale: 0.95 }}
|
|
222
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
223
|
+
className="text-center py-[32px]"
|
|
224
|
+
>
|
|
225
|
+
<div className="size-[64px] rounded-full bg-[#22C55E]/10 flex items-center justify-center mx-auto mb-[16px]">
|
|
226
|
+
<IconFont
|
|
227
|
+
name="check"
|
|
228
|
+
size="32px"
|
|
229
|
+
className="text-[#22C55E]"
|
|
230
|
+
/>
|
|
231
|
+
</div>
|
|
232
|
+
<h3 className="text-[20px] font-semibold text-foreground mb-[8px]">
|
|
233
|
+
部署成功
|
|
234
|
+
</h3>
|
|
235
|
+
<p className="text-[14px] text-muted-foreground mb-[24px]">
|
|
236
|
+
手机扫描下方二维码即可预览
|
|
237
|
+
</p>
|
|
238
|
+
|
|
239
|
+
{/* 二维码区域(占位) */}
|
|
240
|
+
<div className="inline-block bg-white p-[16px] rounded-[20px] shadow-lg mb-[24px]">
|
|
241
|
+
<div className="size-[180px] bg-black/[0.04] rounded-[12px] flex items-center justify-center">
|
|
242
|
+
<div className="text-center">
|
|
243
|
+
<IconFont
|
|
244
|
+
name="qrcode"
|
|
245
|
+
size="48px"
|
|
246
|
+
className="text-muted-foreground mb-[8px]"
|
|
247
|
+
/>
|
|
248
|
+
<p className="text-[11px] text-muted-foreground">
|
|
249
|
+
二维码预览
|
|
250
|
+
</p>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
{/* 链接 */}
|
|
256
|
+
<div className="bg-black/[0.02] rounded-[12px] p-[12px] max-w-[400px] mx-auto mb-[24px]">
|
|
257
|
+
<p className="text-[12px] text-muted-foreground mb-[4px]">
|
|
258
|
+
预览链接
|
|
259
|
+
</p>
|
|
260
|
+
<p className="text-[13px] text-accent font-mono break-all">
|
|
261
|
+
https://your-project.cloudstudio.app
|
|
262
|
+
</p>
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
<div className="flex items-center justify-center gap-[12px]">
|
|
266
|
+
<Btn
|
|
267
|
+
variant="ghost"
|
|
268
|
+
size="middle"
|
|
269
|
+
label="返回入口"
|
|
270
|
+
icon={null}
|
|
271
|
+
onClick={() => navigate("/dev")}
|
|
272
|
+
/>
|
|
273
|
+
<Btn
|
|
274
|
+
variant="primary"
|
|
275
|
+
size="middle"
|
|
276
|
+
label="重新部署"
|
|
277
|
+
icon={<IconFont name="refresh" size="16px" />}
|
|
278
|
+
onClick={() => {
|
|
279
|
+
setStatus("idle");
|
|
280
|
+
setProgress(0);
|
|
281
|
+
}}
|
|
282
|
+
/>
|
|
283
|
+
</div>
|
|
284
|
+
</motion.div>
|
|
285
|
+
)}
|
|
286
|
+
</AnimatePresence>
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
);
|
|
290
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { useNavigate } from "react-router-dom";
|
|
2
|
+
import { Btn, IconFont, cn } from "@lmy54321/design-system";
|
|
3
|
+
import { motion } from "motion/react";
|
|
4
|
+
|
|
5
|
+
interface PortalCard {
|
|
6
|
+
id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
icon: string;
|
|
10
|
+
route: string;
|
|
11
|
+
colorClass: string;
|
|
12
|
+
badge?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const PORTAL_CARDS: PortalCard[] = [
|
|
16
|
+
{
|
|
17
|
+
id: "demo",
|
|
18
|
+
title: "Demo 演示",
|
|
19
|
+
description: "查看当前项目的业务 Demo,这也是手机预览看到的内容",
|
|
20
|
+
icon: "mobile",
|
|
21
|
+
route: "/",
|
|
22
|
+
colorClass: "bg-[#22C55E]",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "components",
|
|
26
|
+
title: "组件库",
|
|
27
|
+
description: "浏览所有可用组件的效果和配置项,开发时随时查阅",
|
|
28
|
+
icon: "component",
|
|
29
|
+
route: "/components",
|
|
30
|
+
colorClass: "bg-[#367BF6]",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "sync",
|
|
34
|
+
title: "规范同步",
|
|
35
|
+
description: "检查设计规范是否有更新,可视化对比后选择性合并",
|
|
36
|
+
icon: "refresh",
|
|
37
|
+
route: "/sync",
|
|
38
|
+
colorClass: "bg-[#FFB800]",
|
|
39
|
+
badge: "有更新",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "deploy",
|
|
43
|
+
title: "部署预览",
|
|
44
|
+
description: "一键打包并部署到手机端,扫码即可预览效果",
|
|
45
|
+
icon: "cloud-upload",
|
|
46
|
+
route: "/deploy",
|
|
47
|
+
colorClass: "bg-[#FF293B]",
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
export function DevPortal() {
|
|
52
|
+
const navigate = useNavigate();
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div className="min-h-[100dvh] bg-background px-[32px] py-[48px]">
|
|
56
|
+
{/* Header */}
|
|
57
|
+
<div className="max-w-[800px] mx-auto mb-[48px]">
|
|
58
|
+
<motion.h1
|
|
59
|
+
initial={{ opacity: 0, y: -12 }}
|
|
60
|
+
animate={{ opacity: 1, y: 0 }}
|
|
61
|
+
className="text-[32px] font-bold text-foreground mb-[8px]"
|
|
62
|
+
>
|
|
63
|
+
开发者入口
|
|
64
|
+
</motion.h1>
|
|
65
|
+
<motion.p
|
|
66
|
+
initial={{ opacity: 0, y: -8 }}
|
|
67
|
+
animate={{ opacity: 1, y: 0 }}
|
|
68
|
+
transition={{ delay: 0.1 }}
|
|
69
|
+
className="text-[16px] text-muted-foreground"
|
|
70
|
+
>
|
|
71
|
+
选择你要进行的操作,所有功能都可以通过点击完成
|
|
72
|
+
</motion.p>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
{/* Cards Grid */}
|
|
76
|
+
<div className="max-w-[800px] mx-auto grid grid-cols-2 gap-[20px]">
|
|
77
|
+
{PORTAL_CARDS.map((card, idx) => (
|
|
78
|
+
<motion.button
|
|
79
|
+
key={card.id}
|
|
80
|
+
initial={{ opacity: 0, y: 16 }}
|
|
81
|
+
animate={{ opacity: 1, y: 0 }}
|
|
82
|
+
transition={{ delay: 0.15 + idx * 0.08 }}
|
|
83
|
+
whileHover={{ y: -4 }}
|
|
84
|
+
whileTap={{ scale: 0.98 }}
|
|
85
|
+
onClick={() => navigate(card.route)}
|
|
86
|
+
className="group relative bg-card rounded-[24px] p-[24px] text-left border border-border hover:border-primary/30 hover:shadow-lg transition-shadow"
|
|
87
|
+
>
|
|
88
|
+
{/* Badge */}
|
|
89
|
+
{card.badge && (
|
|
90
|
+
<span className="absolute top-[16px] right-[16px] px-[8px] py-[3px] rounded-full bg-destructive text-white text-[11px] font-medium">
|
|
91
|
+
{card.badge}
|
|
92
|
+
</span>
|
|
93
|
+
)}
|
|
94
|
+
|
|
95
|
+
{/* Icon */}
|
|
96
|
+
<div
|
|
97
|
+
className={cn(
|
|
98
|
+
"size-[48px] rounded-[16px] flex items-center justify-center mb-[16px]",
|
|
99
|
+
card.colorClass
|
|
100
|
+
)}
|
|
101
|
+
>
|
|
102
|
+
<IconFont name={card.icon} size="24px" className="text-white" />
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
{/* Content */}
|
|
106
|
+
<h3 className="text-[18px] font-semibold text-foreground mb-[8px] group-hover:text-primary transition-colors">
|
|
107
|
+
{card.title}
|
|
108
|
+
</h3>
|
|
109
|
+
<p className="text-[14px] text-muted-foreground leading-relaxed">
|
|
110
|
+
{card.description}
|
|
111
|
+
</p>
|
|
112
|
+
|
|
113
|
+
{/* Arrow */}
|
|
114
|
+
<div className="absolute bottom-[24px] right-[24px] size-[32px] rounded-full bg-black/[0.04] flex items-center justify-center group-hover:bg-primary/10 transition-colors">
|
|
115
|
+
<IconFont
|
|
116
|
+
name="chevron-right"
|
|
117
|
+
size="16px"
|
|
118
|
+
className="text-muted-foreground group-hover:text-primary transition-colors"
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
</motion.button>
|
|
122
|
+
))}
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
{/* Quick Links */}
|
|
126
|
+
<motion.div
|
|
127
|
+
initial={{ opacity: 0 }}
|
|
128
|
+
animate={{ opacity: 1 }}
|
|
129
|
+
transition={{ delay: 0.6 }}
|
|
130
|
+
className="max-w-[800px] mx-auto mt-[48px] p-[24px] bg-black/[0.02] rounded-[16px]"
|
|
131
|
+
>
|
|
132
|
+
<h3 className="text-[14px] font-medium text-foreground mb-[12px]">
|
|
133
|
+
快速链接
|
|
134
|
+
</h3>
|
|
135
|
+
<div className="flex gap-[16px] flex-wrap items-center">
|
|
136
|
+
<a
|
|
137
|
+
href="https://gist.github.com/lmy910510/a630f17c0141e076f7f669d1f663bae6"
|
|
138
|
+
target="_blank"
|
|
139
|
+
rel="noreferrer"
|
|
140
|
+
className="text-[13px] text-accent hover:underline flex items-center gap-[4px]"
|
|
141
|
+
>
|
|
142
|
+
<IconFont name="file" size="14px" />
|
|
143
|
+
规范文档
|
|
144
|
+
</a>
|
|
145
|
+
<a
|
|
146
|
+
href="https://www.npmjs.com/package/@lmy54321/design-system"
|
|
147
|
+
target="_blank"
|
|
148
|
+
rel="noreferrer"
|
|
149
|
+
className="text-[13px] text-accent hover:underline flex items-center gap-[4px]"
|
|
150
|
+
>
|
|
151
|
+
<IconFont name="system-components" size="14px" />
|
|
152
|
+
npm 包
|
|
153
|
+
</a>
|
|
154
|
+
<span className="text-[13px] text-muted-foreground">
|
|
155
|
+
当前版本: v1.2.0
|
|
156
|
+
</span>
|
|
157
|
+
</div>
|
|
158
|
+
</motion.div>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
}
|