create-yoya-ui 0.1.1 → 0.1.2

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 CHANGED
@@ -7,14 +7,17 @@
7
7
  ```bash
8
8
  npx create-yoya-ui@latest my-app # basic 模板(SPA)
9
9
  npx create-yoya-ui@latest my-app --template ssr # SSR 模板
10
+ npx create-yoya-ui@latest my-app --template admin # 后台管理模板
10
11
  cd my-app
11
12
  npm install
12
13
  ```
13
14
 
14
15
  - **basic**:默认模板,`npm run dev` 启动 Vite 开发服务器
15
16
  - **ssr**:服务端渲染模板,`npm run build && npm start`(renderPage 整页渲染 + hydrateOrMount 客户端接入)
17
+ - **admin**:标准后台管理模板(顶部导航 + 可折叠侧栏 + RouterViews 内容区)
16
18
 
17
19
  ## 模板内容
18
20
 
19
21
  - `templates/basic`:页面壳、按钮事件、表单收集校验、主题切换
20
22
  - `templates/ssr`:home-page.js(页面组件 + 词典)、server.mjs(node:http + renderPage)、client.js(hydrateOrMount)
23
+ - `templates/admin`:管理后台壳(logo/系统名、顶级导航、用户头像、可折叠菜单、带标题内容区)
@@ -13,7 +13,7 @@ const templateName =
13
13
  const templateRoot = resolve(fileURLToPath(new URL(`../templates/${templateName}`, import.meta.url)));
14
14
 
15
15
  if (!existsSync(templateRoot)) {
16
- console.error(`未知模板:${templateName}(可用:basic、ssr)`);
16
+ console.error(`未知模板:${templateName}(可用:basic、ssr、admin)`);
17
17
  process.exit(1);
18
18
  }
19
19
 
@@ -40,7 +40,9 @@ if (templateName === 'ssr') {
40
40
  console.log('\nSSR 模板:renderPage 整页渲染 + hydrateOrMount 客户端接入。\n');
41
41
  } else {
42
42
  console.log(' npm run dev');
43
- console.log('\n更多:npm run build 构建,npm run preview 预览产物。\n');
43
+ console.log(
44
+ `\n${templateName === 'admin' ? '管理后台模板:顶部导航 + 可折叠侧栏 + RouterViews 内容区。' : ''}更多:npm run build 构建,npm run preview 预览产物。\n`
45
+ );
44
46
  }
45
47
 
46
48
  function sanitizeName(name) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-yoya-ui",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Scaffold a new yoya-ui project with Vite: basic template (SPA) or SSR template (renderPage + hydrateOrMount).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,25 @@
1
+ # yoya-ui 后台管理模板
2
+
3
+ 标准管理后台布局:
4
+
5
+ - 左上角:logo + 系统名
6
+ - 中间:顶级导航
7
+ - 右上角:用户头像
8
+ - 下方:左侧可折叠菜单 + 右侧带标题的 RouterViews 内容区
9
+ - 点击顶级导航切换左侧菜单与内容路由
10
+
11
+ ## 启动
12
+
13
+ ```bash
14
+ npm install
15
+ npm run dev
16
+ ```
17
+
18
+ ## 结构
19
+
20
+ ```text
21
+ src/
22
+ main.js 管理台壳:模块配置、路由、顶部导航、侧栏切换、内容区
23
+ ```
24
+
25
+ 扩展新模块:在 `main.js` 的 `modules` 数组里加一组 `{ key, label, icon, routes }` 即可。
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>yoya-ui 管理台</title>
7
+ </head>
8
+ <body>
9
+ <main id="app"></main>
10
+ <script type="module" src="/src/main.js"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "yoya-ui-admin-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@yoyaflow/yoya-ui": "^0.2.0"
13
+ },
14
+ "devDependencies": {
15
+ "vite": "^8.2.0"
16
+ }
17
+ }
@@ -0,0 +1,166 @@
1
+ import {
2
+ createRouter,
3
+ toast,
4
+ vBody,
5
+ vNavbar,
6
+ vRouterViews,
7
+ vSidebar,
8
+ vstack
9
+ } from '@yoyaflow/yoya-ui';
10
+ import '@yoyaflow/yoya-ui/ui.css';
11
+
12
+ // ---------- 页面视图 ----------
13
+
14
+ function pageView(title, text) {
15
+ return vstack({ gap: '16px' }, (stack) => {
16
+ stack.h2(title);
17
+ stack.vCard((card) => {
18
+ card.vCardHeader(title);
19
+ card.vCardBody((body) => {
20
+ body.p(text);
21
+ body.vButton('操作', (btn) => {
22
+ btn.variant('primary');
23
+ btn.on('click', () => toast.success(`${title} 操作成功`));
24
+ });
25
+ });
26
+ });
27
+ });
28
+ }
29
+
30
+ // ---------- 模块配置:顶级导航 → 左侧菜单 → 路由 ----------
31
+
32
+ const modules = [
33
+ {
34
+ key: 'dashboard',
35
+ label: '工作台',
36
+ icon: 'D',
37
+ routes: [
38
+ { path: '/dashboard/overview', title: '数据概览', text: '关键指标、趋势与告警一览。' },
39
+ { path: '/dashboard/todos', title: '待办审批', text: '待处理审批与任务。' }
40
+ ]
41
+ },
42
+ {
43
+ key: 'ops',
44
+ label: '运维',
45
+ icon: 'O',
46
+ routes: [
47
+ { path: '/ops/services', title: '服务清单', text: '服务列表与健康状态。' },
48
+ { path: '/ops/deploys', title: '部署任务', text: '发布记录与执行状态。' }
49
+ ]
50
+ },
51
+ {
52
+ key: 'system',
53
+ label: '系统',
54
+ icon: 'S',
55
+ routes: [
56
+ { path: '/system/users', title: '成员管理', text: '成员列表与角色分配。' },
57
+ { path: '/system/roles', title: '权限策略', text: '角色与权限规则。' }
58
+ ]
59
+ }
60
+ ];
61
+
62
+ // ---------- 路由与内容区 ----------
63
+
64
+ const appRouter = createRouter((r) => {
65
+ modules.forEach((module) => {
66
+ module.routes.forEach((route) => {
67
+ r.route(route.path, { title: route.title, view: () => pageView(route.title, route.text) });
68
+ });
69
+ });
70
+ r.notFound(() => pageView('未找到', '该页面不存在。'));
71
+ });
72
+
73
+ // ---------- 左侧菜单:随顶级导航切换 ----------
74
+
75
+ let activeTopItem = null;
76
+
77
+ function renderSidebarMenu(module) {
78
+ sidebar.menuContent((menu) => {
79
+ menu.vMenuGroup((group) => {
80
+ group.label(module.label);
81
+ module.routes.forEach((route) => {
82
+ group.vMenuItem((item) => {
83
+ item.icon(module.icon);
84
+ item.text(route.title);
85
+ item.on('click', () => appRouter.navigate(route.path));
86
+ });
87
+ });
88
+ });
89
+ });
90
+ }
91
+
92
+ function switchModule(module, topItem) {
93
+ if (activeTopItem) {
94
+ activeTopItem.active(false);
95
+ }
96
+ activeTopItem = topItem;
97
+ topItem.active(true);
98
+ renderSidebarMenu(module);
99
+ appRouter.navigate(module.routes[0].path);
100
+ }
101
+
102
+ const sidebar = vSidebar((side) => {
103
+ side.ariaLabel('左侧菜单');
104
+ side.title('导航');
105
+ });
106
+ renderSidebarMenu(modules[0]);
107
+
108
+ // ---------- 顶部导航:logo + 系统名 / 顶级导航 / 用户头像 ----------
109
+
110
+ const navbar = vNavbar((nav) => {
111
+ nav.sticky(true);
112
+ nav.brand((brand) => {
113
+ brand.hstack({ gap: '8px' }, (row) => {
114
+ row.style('alignItems', 'center');
115
+ row.span((logo) => {
116
+ logo.style({
117
+ color: 'var(--yoya-color-primary, #2563eb)',
118
+ fontSize: '18px',
119
+ fontWeight: '700'
120
+ });
121
+ logo.text('◆');
122
+ });
123
+ row.strong('yoya 管理台');
124
+ });
125
+ });
126
+ nav.menuContent((menu) => {
127
+ modules.forEach((module) => {
128
+ menu.vMenuItem((item) => {
129
+ item.text(module.label);
130
+ item.on('click', () => switchModule(module, item));
131
+ });
132
+ });
133
+ });
134
+ nav.actions((actions) => {
135
+ actions.vAvatar({ color: '#2563eb', size: 'small', text: '管' });
136
+ });
137
+ });
138
+
139
+ // ---------- 页面壳:上方导航,下方左菜单右内容 ----------
140
+
141
+ const page = vBody((shell) => {
142
+ shell.gap(0);
143
+ shell.maxWidth('100%');
144
+ shell.padding(0);
145
+ shell.vContainer((frame) => {
146
+ frame.style('minHeight', '100vh');
147
+ frame.vHeader({ height: 56 }, (header) => {
148
+ header.style('padding', '0');
149
+ header.child(navbar);
150
+ });
151
+ frame.vContainer((body) => {
152
+ body.vAside({ width: 220 }, (aside) => {
153
+ aside.style('padding', '12px');
154
+ aside.child(sidebar);
155
+ });
156
+ body.vMain((main) => {
157
+ main.style('padding', '16px');
158
+ main.child(vRouterViews(appRouter, { lockTitle: true, title: '内容区' }));
159
+ });
160
+ });
161
+ });
162
+ });
163
+
164
+ page.bindTo('#app');
165
+ appRouter.start();
166
+ appRouter.navigate(modules[0].routes[0].path, { replace: true }); // 进入默认模块首页
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite';
2
+
3
+ export default defineConfig({
4
+ server: {
5
+ port: 5173
6
+ }
7
+ });
@@ -34,7 +34,6 @@ createServer((req, res) => {
34
34
  });
35
35
  page.body((body) => {
36
36
  body.vBody((shell) => {
37
- shell.h1('SSR 示例'.s('title'));
38
37
  shell.child(HomePage(state)); // state = { lang, path, mode }
39
38
  });
40
39
  });