@coze-arch/cli 0.0.1-alpha.db1c06 → 0.0.1-alpha.dcc485

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.
Files changed (132) hide show
  1. package/README.md +1 -0
  2. package/lib/__templates__/expo/_npmrc +1 -0
  3. package/lib/__templates__/expo/client/components/Screen.tsx +2 -2
  4. package/lib/__templates__/expo/client/eslint.config.mjs +7 -0
  5. package/lib/__templates__/expo/client/scripts/install-missing-deps.js +10 -10
  6. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/index.js +9 -0
  7. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/rule.js +112 -0
  8. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/tech.md +94 -0
  9. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/index.js +9 -0
  10. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/rule.js +120 -0
  11. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/tech.md +58 -0
  12. package/lib/__templates__/nextjs/AGENTS.md +54 -0
  13. package/lib/__templates__/nextjs/README.md +5 -0
  14. package/lib/__templates__/nextjs/eslint.config.mjs +5 -0
  15. package/lib/__templates__/nextjs/next.config.ts +1 -2
  16. package/lib/__templates__/nextjs/package.json +2 -5
  17. package/lib/__templates__/nextjs/pnpm-lock.yaml +1028 -5
  18. package/lib/__templates__/nextjs/scripts/build.sh +4 -1
  19. package/lib/__templates__/nextjs/scripts/dev.sh +8 -2
  20. package/lib/__templates__/nextjs/scripts/start.sh +7 -1
  21. package/lib/__templates__/nextjs/src/app/layout.tsx +1 -1
  22. package/lib/__templates__/nextjs/src/app/page.tsx +1 -2
  23. package/lib/__templates__/nextjs/src/server.ts +35 -0
  24. package/lib/__templates__/nextjs/tsconfig.json +1 -1
  25. package/lib/__templates__/nuxt-vue/.coze +12 -0
  26. package/lib/__templates__/nuxt-vue/AGENTS.md +42 -0
  27. package/lib/__templates__/nuxt-vue/README.md +73 -0
  28. package/lib/__templates__/nuxt-vue/_gitignore +24 -0
  29. package/lib/__templates__/nuxt-vue/_npmrc +23 -0
  30. package/lib/__templates__/nuxt-vue/app/app.vue +6 -0
  31. package/lib/__templates__/nuxt-vue/app/pages/index.vue +23 -0
  32. package/lib/__templates__/nuxt-vue/assets/css/main.css +24 -0
  33. package/lib/__templates__/nuxt-vue/nuxt.config.ts +116 -0
  34. package/lib/__templates__/nuxt-vue/package.json +35 -0
  35. package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +8759 -0
  36. package/lib/__templates__/nuxt-vue/postcss.config.mjs +8 -0
  37. package/lib/__templates__/nuxt-vue/public/favicon.ico +0 -0
  38. package/lib/__templates__/nuxt-vue/public/robots.txt +2 -0
  39. package/lib/__templates__/nuxt-vue/scripts/build.sh +14 -0
  40. package/lib/__templates__/nuxt-vue/scripts/dev.sh +39 -0
  41. package/lib/__templates__/nuxt-vue/scripts/prepare.sh +14 -0
  42. package/lib/__templates__/nuxt-vue/scripts/start.sh +21 -0
  43. package/lib/__templates__/nuxt-vue/server/api/hello.ts +10 -0
  44. package/lib/__templates__/nuxt-vue/server/middleware/logger.ts +10 -0
  45. package/lib/__templates__/nuxt-vue/server/routes/health.ts +10 -0
  46. package/lib/__templates__/nuxt-vue/tailwind.config.js +13 -0
  47. package/lib/__templates__/nuxt-vue/template.config.js +87 -0
  48. package/lib/__templates__/nuxt-vue/tsconfig.json +18 -0
  49. package/lib/__templates__/taro/README.md +57 -45
  50. package/lib/__templates__/taro/config/index.ts +106 -41
  51. package/lib/__templates__/taro/config/prod.ts +4 -5
  52. package/lib/__templates__/taro/eslint.config.mjs +62 -6
  53. package/lib/__templates__/taro/package.json +19 -4
  54. package/lib/__templates__/taro/patches/@tarojs__plugin-mini-ci@4.1.9.patch +30 -0
  55. package/lib/__templates__/taro/pnpm-lock.yaml +912 -206
  56. package/lib/__templates__/taro/src/app.css +140 -36
  57. package/lib/__templates__/taro/src/components/ui/accordion.tsx +159 -0
  58. package/lib/__templates__/taro/src/components/ui/alert-dialog.tsx +260 -0
  59. package/lib/__templates__/taro/src/components/ui/alert.tsx +60 -0
  60. package/lib/__templates__/taro/src/components/ui/aspect-ratio.tsx +36 -0
  61. package/lib/__templates__/taro/src/components/ui/avatar.tsx +84 -0
  62. package/lib/__templates__/taro/src/components/ui/badge.tsx +37 -0
  63. package/lib/__templates__/taro/src/components/ui/breadcrumb.tsx +117 -0
  64. package/lib/__templates__/taro/src/components/ui/button-group.tsx +83 -0
  65. package/lib/__templates__/taro/src/components/ui/button.tsx +67 -0
  66. package/lib/__templates__/taro/src/components/ui/calendar.tsx +394 -0
  67. package/lib/__templates__/taro/src/components/ui/card.tsx +108 -0
  68. package/lib/__templates__/taro/src/components/ui/carousel.tsx +228 -0
  69. package/lib/__templates__/taro/src/components/ui/checkbox.tsx +58 -0
  70. package/lib/__templates__/taro/src/components/ui/code-block.tsx +169 -0
  71. package/lib/__templates__/taro/src/components/ui/collapsible.tsx +71 -0
  72. package/lib/__templates__/taro/src/components/ui/command.tsx +385 -0
  73. package/lib/__templates__/taro/src/components/ui/context-menu.tsx +614 -0
  74. package/lib/__templates__/taro/src/components/ui/dialog.tsx +256 -0
  75. package/lib/__templates__/taro/src/components/ui/drawer.tsx +192 -0
  76. package/lib/__templates__/taro/src/components/ui/dropdown-menu.tsx +561 -0
  77. package/lib/__templates__/taro/src/components/ui/field.tsx +228 -0
  78. package/lib/__templates__/taro/src/components/ui/hover-card.tsx +282 -0
  79. package/lib/__templates__/taro/src/components/ui/input-group.tsx +197 -0
  80. package/lib/__templates__/taro/src/components/ui/input-otp.tsx +136 -0
  81. package/lib/__templates__/taro/src/components/ui/input.tsx +56 -0
  82. package/lib/__templates__/taro/src/components/ui/label.tsx +24 -0
  83. package/lib/__templates__/taro/src/components/ui/menubar.tsx +595 -0
  84. package/lib/__templates__/taro/src/components/ui/navigation-menu.tsx +264 -0
  85. package/lib/__templates__/taro/src/components/ui/pagination.tsx +118 -0
  86. package/lib/__templates__/taro/src/components/ui/popover.tsx +291 -0
  87. package/lib/__templates__/taro/src/components/ui/portal.tsx +19 -0
  88. package/lib/__templates__/taro/src/components/ui/progress.tsx +28 -0
  89. package/lib/__templates__/taro/src/components/ui/radio-group.tsx +64 -0
  90. package/lib/__templates__/taro/src/components/ui/resizable.tsx +346 -0
  91. package/lib/__templates__/taro/src/components/ui/scroll-area.tsx +34 -0
  92. package/lib/__templates__/taro/src/components/ui/select.tsx +438 -0
  93. package/lib/__templates__/taro/src/components/ui/separator.tsx +30 -0
  94. package/lib/__templates__/taro/src/components/ui/sheet.tsx +262 -0
  95. package/lib/__templates__/taro/src/components/ui/skeleton.tsx +17 -0
  96. package/lib/__templates__/taro/src/components/ui/slider.tsx +203 -0
  97. package/lib/__templates__/taro/src/components/ui/sonner.tsx +1 -0
  98. package/lib/__templates__/taro/src/components/ui/switch.tsx +55 -0
  99. package/lib/__templates__/taro/src/components/ui/table.tsx +142 -0
  100. package/lib/__templates__/taro/src/components/ui/tabs.tsx +114 -0
  101. package/lib/__templates__/taro/src/components/ui/textarea.tsx +54 -0
  102. package/lib/__templates__/taro/src/components/ui/toast.tsx +517 -0
  103. package/lib/__templates__/taro/src/components/ui/toggle-group.tsx +120 -0
  104. package/lib/__templates__/taro/src/components/ui/toggle.tsx +77 -0
  105. package/lib/__templates__/taro/src/components/ui/tooltip.tsx +455 -0
  106. package/lib/__templates__/taro/src/lib/hooks/use-keyboard-offset.ts +37 -0
  107. package/lib/__templates__/taro/src/lib/measure.ts +115 -0
  108. package/lib/__templates__/taro/src/lib/platform.ts +12 -0
  109. package/lib/__templates__/taro/src/lib/utils.ts +6 -0
  110. package/lib/__templates__/taro/src/presets/dev-debug.ts +23 -0
  111. package/lib/__templates__/taro/src/presets/h5-container.tsx +15 -0
  112. package/lib/__templates__/taro/src/presets/h5-navbar.tsx +97 -30
  113. package/lib/__templates__/taro/src/presets/h5-styles.ts +192 -5
  114. package/lib/__templates__/taro/src/presets/index.tsx +4 -4
  115. package/lib/__templates__/templates.json +32 -0
  116. package/lib/__templates__/vite/AGENTS.md +41 -0
  117. package/lib/__templates__/vite/README.md +190 -11
  118. package/lib/__templates__/vite/_gitignore +1 -0
  119. package/lib/__templates__/vite/eslint.config.mjs +6 -1
  120. package/lib/__templates__/vite/package.json +10 -3
  121. package/lib/__templates__/vite/pnpm-lock.yaml +755 -15
  122. package/lib/__templates__/vite/scripts/build.sh +4 -1
  123. package/lib/__templates__/vite/scripts/dev.sh +9 -2
  124. package/lib/__templates__/vite/scripts/start.sh +9 -3
  125. package/lib/__templates__/vite/server/routes/index.ts +31 -0
  126. package/lib/__templates__/vite/server/server.ts +65 -0
  127. package/lib/__templates__/vite/server/vite.ts +67 -0
  128. package/lib/__templates__/vite/tsconfig.json +4 -3
  129. package/lib/__templates__/vite/vite.config.ts +4 -0
  130. package/lib/cli.js +99 -92
  131. package/package.json +6 -3
  132. package/lib/__templates__/taro/src/presets/wx-debug.ts +0 -23
@@ -0,0 +1,115 @@
1
+ import Taro from '@tarojs/taro'
2
+ import { canUseDOM, isH5 } from './platform'
3
+
4
+ export type Rect = { left: number; top: number; width: number; height: number }
5
+
6
+ const toNumber = (v: unknown) => {
7
+ if (typeof v === 'number') return v
8
+ if (typeof v === 'string') {
9
+ const n = parseFloat(v)
10
+ return Number.isFinite(n) ? n : 0
11
+ }
12
+ return 0
13
+ }
14
+
15
+ const normalizeRect = (r: any): Rect | null => {
16
+ if (!r) return null
17
+ return {
18
+ left: toNumber(r.left),
19
+ top: toNumber(r.top),
20
+ width: toNumber(r.width),
21
+ height: toNumber(r.height),
22
+ }
23
+ }
24
+
25
+ export const getViewport = () => {
26
+ if (isH5() && canUseDOM()) {
27
+ return { width: window.innerWidth, height: window.innerHeight }
28
+ }
29
+ try {
30
+ const info = Taro.getSystemInfoSync()
31
+ return {
32
+ width: toNumber(info.windowWidth),
33
+ height: toNumber(info.windowHeight),
34
+ }
35
+ } catch {
36
+ return { width: 375, height: 667 }
37
+ }
38
+ }
39
+
40
+ const getRectH5 = (id: string): Rect | null => {
41
+ if (!isH5() || !canUseDOM()) return null
42
+ const el = document.getElementById(id)
43
+ if (!el) return null
44
+ const r = el.getBoundingClientRect()
45
+ return normalizeRect(r)
46
+ }
47
+
48
+ export const getRectById = (id: string): Promise<Rect | null> => {
49
+ const h5Rect = getRectH5(id)
50
+ if (h5Rect) return Promise.resolve(h5Rect)
51
+ return new Promise(resolve => {
52
+ const query = Taro.createSelectorQuery()
53
+ query
54
+ .select(`#${id}`)
55
+ .boundingClientRect(res => {
56
+ const rect = Array.isArray(res) ? res[0] : res
57
+ resolve(normalizeRect(rect))
58
+ })
59
+ .exec()
60
+ })
61
+ }
62
+
63
+ export const computePosition = (params: {
64
+ triggerRect: Rect
65
+ contentRect: Rect
66
+ align: 'start' | 'center' | 'end'
67
+ side: 'top' | 'bottom' | 'left' | 'right'
68
+ sideOffset: number
69
+ }) => {
70
+ const { triggerRect, contentRect, align, side, sideOffset } = params
71
+ const { width: vw, height: vh } = getViewport()
72
+ const margin = 8
73
+
74
+ const crossStart =
75
+ side === 'left' || side === 'right' ? triggerRect.top : triggerRect.left
76
+ const crossSize =
77
+ side === 'left' || side === 'right'
78
+ ? triggerRect.height
79
+ : triggerRect.width
80
+ const contentCrossSize =
81
+ side === 'left' || side === 'right'
82
+ ? contentRect.height
83
+ : contentRect.width
84
+
85
+ const cross = (() => {
86
+ if (align === 'start') return crossStart
87
+ if (align === 'end') return crossStart + crossSize - contentCrossSize
88
+ return crossStart + crossSize / 2 - contentCrossSize / 2
89
+ })()
90
+
91
+ let left = 0
92
+ let top = 0
93
+
94
+ if (side === 'bottom' || side === 'top') {
95
+ left = cross
96
+ top =
97
+ side === 'bottom'
98
+ ? triggerRect.top + triggerRect.height + sideOffset
99
+ : triggerRect.top - contentRect.height - sideOffset
100
+ } else {
101
+ top = cross
102
+ left =
103
+ side === 'right'
104
+ ? triggerRect.left + triggerRect.width + sideOffset
105
+ : triggerRect.left - contentRect.width - sideOffset
106
+ }
107
+
108
+ const maxLeft = Math.max(margin, vw - contentRect.width - margin)
109
+ const maxTop = Math.max(margin, vh - contentRect.height - margin)
110
+
111
+ left = Math.min(Math.max(left, margin), maxLeft)
112
+ top = Math.min(Math.max(top, margin), maxTop)
113
+
114
+ return { left, top }
115
+ }
@@ -0,0 +1,12 @@
1
+ import Taro from "@tarojs/taro"
2
+
3
+ export const canUseDOM = () => typeof window !== "undefined" && typeof document !== "undefined"
4
+
5
+ export const isH5 = () => {
6
+ try {
7
+ return Taro.getEnv() === Taro.ENV_TYPE.WEB
8
+ } catch {
9
+ return canUseDOM()
10
+ }
11
+ }
12
+
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,23 @@
1
+ import Taro from '@tarojs/taro';
2
+
3
+ /**
4
+ * 小程序调试工具
5
+ * 在开发版/体验版自动开启调试模式
6
+ * 支持微信小程序和抖音小程序
7
+ */
8
+ export function devDebug() {
9
+ const env = Taro.getEnv();
10
+ if (env === Taro.ENV_TYPE.WEAPP || env === Taro.ENV_TYPE.TT) {
11
+ try {
12
+ const accountInfo = Taro.getAccountInfoSync();
13
+ const envVersion = accountInfo.miniProgram.envVersion;
14
+ console.log('[Debug] envVersion:', envVersion);
15
+
16
+ if (envVersion !== 'release') {
17
+ Taro.setEnableDebug({ enableDebug: true });
18
+ }
19
+ } catch (error) {
20
+ console.error('[Debug] 开启调试模式失败:', error);
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,15 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { H5NavBar } from './h5-navbar';
3
+
4
+ export const H5Container = ({ children }: PropsWithChildren) => {
5
+ if (TARO_ENV !== 'h5') {
6
+ return <>{children}</>;
7
+ }
8
+
9
+ return (
10
+ <>
11
+ <H5NavBar />
12
+ {children}
13
+ </>
14
+ );
15
+ };
@@ -1,6 +1,6 @@
1
1
  import { View, Text } from '@tarojs/components';
2
2
  import Taro, { useDidShow, usePageScroll } from '@tarojs/taro';
3
- import { useState, useEffect, PropsWithChildren, useCallback } from 'react';
3
+ import { useState, useEffect, useCallback } from 'react';
4
4
  import { ChevronLeft, House } from 'lucide-react-taro';
5
5
 
6
6
  interface NavConfig {
@@ -37,6 +37,11 @@ const DEFAULT_NAV_STATE: NavState = {
37
37
  leftIcon: LeftIcon.None,
38
38
  };
39
39
 
40
+ const getGlobalWindowConfig = (): Partial<NavConfig> => {
41
+ const app = Taro.getApp();
42
+ return app?.config?.window || {};
43
+ };
44
+
40
45
  const getTabBarPages = (): Set<string> => {
41
46
  const tabBar = Taro.getApp()?.config?.tabBar;
42
47
  return new Set(
@@ -44,16 +49,26 @@ const getTabBarPages = (): Set<string> => {
44
49
  );
45
50
  };
46
51
 
52
+ const getHomePage = (): string => {
53
+ const app = Taro.getApp();
54
+ return app?.config?.pages?.[0] || 'pages/index/index';
55
+ };
56
+
57
+ const cleanPath = (path: string): string => path.replace(/^\//, '');
58
+
47
59
  const computeLeftIcon = (
48
60
  route: string,
49
61
  tabBarPages: Set<string>,
50
62
  historyLength: number,
63
+ homePage: string,
51
64
  ): LeftIcon => {
52
65
  if (!route) return LeftIcon.None;
53
66
 
54
- const isHomePage =
55
- route === 'pages/index/index' || route === '/pages/index/index';
56
- const isTabBarPage = tabBarPages.has(route);
67
+ const cleanRoute = cleanPath(route);
68
+ const cleanHomePage = cleanPath(homePage);
69
+ const isHomePage = cleanRoute === cleanHomePage;
70
+ const isTabBarPage =
71
+ tabBarPages.has(cleanRoute) || tabBarPages.has(`/${cleanRoute}`);
57
72
  const hasHistory = historyLength > 1;
58
73
 
59
74
  if (isTabBarPage || isHomePage) return LeftIcon.None;
@@ -61,29 +76,60 @@ const computeLeftIcon = (
61
76
  return LeftIcon.Home;
62
77
  };
63
78
 
64
- export const H5NavBar = ({ children }: PropsWithChildren) => {
79
+ export const H5NavBar = () => {
65
80
  const [navState, setNavState] = useState<NavState>(DEFAULT_NAV_STATE);
66
81
  const [scrollOpacity, setScrollOpacity] = useState(0);
67
82
 
68
83
  const updateNavState = useCallback(() => {
69
84
  const pages = Taro.getCurrentPages();
85
+ if (pages.length === 0) {
86
+ setNavState(prev => ({ ...prev, visible: false }));
87
+ return;
88
+ }
89
+
70
90
  const currentPage = pages[pages.length - 1];
71
91
  const route = currentPage?.route || '';
72
- const config: NavConfig = (currentPage as any)?.config || {};
92
+ if (!route) return;
93
+
94
+ const pageConfig: NavConfig = (currentPage as any)?.config || {};
95
+ const globalConfig = getGlobalWindowConfig();
73
96
  const tabBarPages = getTabBarPages();
97
+ const homePage = getHomePage();
98
+
99
+ const cleanRoute = cleanPath(route);
100
+ const cleanHomePage = cleanPath(homePage);
101
+
102
+ const isHomePage = cleanRoute === cleanHomePage;
103
+ const isTabBarPage =
104
+ tabBarPages.has(cleanRoute) || tabBarPages.has(`/${cleanRoute}`);
74
105
 
75
- const isSinglePageApp = tabBarPages.size <= 1 && pages.length <= 1;
106
+ const shouldHideNav =
107
+ tabBarPages.size <= 1 &&
108
+ pages.length <= 1 &&
109
+ (isHomePage || isTabBarPage);
76
110
 
77
111
  setNavState({
78
- visible: !isSinglePageApp,
79
- title: config.navigationBarTitleText || '',
80
- bgColor: config.navigationBarBackgroundColor || '#ffffff',
81
- textStyle: config.navigationBarTextStyle || 'black',
82
- navStyle: config.navigationStyle || 'default',
83
- transparent: config.transparentTitle || 'none',
84
- leftIcon: isSinglePageApp
112
+ visible: !shouldHideNav,
113
+ title:
114
+ document.title ||
115
+ pageConfig.navigationBarTitleText ||
116
+ globalConfig.navigationBarTitleText ||
117
+ '',
118
+ bgColor:
119
+ pageConfig.navigationBarBackgroundColor ||
120
+ globalConfig.navigationBarBackgroundColor ||
121
+ '#ffffff',
122
+ textStyle:
123
+ pageConfig.navigationBarTextStyle ||
124
+ globalConfig.navigationBarTextStyle ||
125
+ 'black',
126
+ navStyle:
127
+ pageConfig.navigationStyle || globalConfig.navigationStyle || 'default',
128
+ transparent:
129
+ pageConfig.transparentTitle || globalConfig.transparentTitle || 'none',
130
+ leftIcon: shouldHideNav
85
131
  ? LeftIcon.None
86
- : computeLeftIcon(route, tabBarPages, pages.length),
132
+ : computeLeftIcon(cleanRoute, tabBarPages, pages.length, cleanHomePage),
87
133
  });
88
134
  }, []);
89
135
 
@@ -100,23 +146,42 @@ export const H5NavBar = ({ children }: PropsWithChildren) => {
100
146
  useEffect(() => {
101
147
  if (TARO_ENV !== 'h5') return;
102
148
 
103
- const titleEl = document.querySelector('title') || document.head;
104
- const observer = new MutationObserver(() => updateNavState());
105
- observer.observe(titleEl, {
149
+ let timer: NodeJS.Timeout | null = null;
150
+ const observer = new MutationObserver(() => {
151
+ if (timer) clearTimeout(timer);
152
+ timer = setTimeout(() => {
153
+ updateNavState();
154
+ }, 50);
155
+ });
156
+
157
+ observer.observe(document.head, {
106
158
  subtree: true,
107
159
  childList: true,
108
160
  characterData: true,
109
161
  });
110
162
 
111
- return () => observer.disconnect();
163
+ updateNavState();
164
+
165
+ return () => {
166
+ observer.disconnect();
167
+ if (timer) clearTimeout(timer);
168
+ };
112
169
  }, [updateNavState]);
113
170
 
114
- if (
115
- TARO_ENV !== 'h5' ||
116
- navState.navStyle === 'custom' ||
117
- !navState.visible
118
- ) {
119
- return <>{children}</>;
171
+ const shouldRender =
172
+ TARO_ENV === 'h5' && navState.visible && navState.navStyle !== 'custom';
173
+
174
+ useEffect(() => {
175
+ if (TARO_ENV !== 'h5') return;
176
+ if (shouldRender) {
177
+ document.body.classList.add('h5-navbar-visible');
178
+ } else {
179
+ document.body.classList.remove('h5-navbar-visible');
180
+ }
181
+ }, [shouldRender]);
182
+
183
+ if (!shouldRender) {
184
+ return <></>;
120
185
  }
121
186
 
122
187
  const iconColor = navState.textStyle === 'white' ? '#fff' : '#333';
@@ -134,12 +199,15 @@ export const H5NavBar = ({ children }: PropsWithChildren) => {
134
199
  };
135
200
 
136
201
  const handleBack = () => Taro.navigateBack();
137
- const handleGoHome = () => Taro.switchTab({ url: '/pages/index/index' });
202
+ const handleGoHome = () => {
203
+ const homePage = getHomePage();
204
+ Taro.reLaunch({ url: `/${homePage}` });
205
+ };
138
206
 
139
207
  return (
140
- <View className="flex flex-col h-full">
208
+ <>
141
209
  <View
142
- className={`fixed top-0 left-0 right-0 h-11 flex items-center justify-center z-1000 ${navState.transparent === 'none' ? 'border-b border-gray-200' : ''}`}
210
+ className="fixed top-0 left-0 right-0 h-11 flex items-center justify-center z-1000"
143
211
  style={getBgStyle()}
144
212
  >
145
213
  {navState.leftIcon === LeftIcon.Back && (
@@ -165,7 +233,6 @@ export const H5NavBar = ({ children }: PropsWithChildren) => {
165
233
  </Text>
166
234
  </View>
167
235
  <View className="h-11 shrink-0" />
168
- <View className="pb-11 h-full">{children}</View>
169
- </View>
236
+ </>
170
237
  );
171
238
  };
@@ -2,11 +2,8 @@
2
2
  * H5 端特殊样式注入
3
3
  * 如无必要,请勿修改本文件
4
4
  */
5
- export function injectH5Styles() {
6
- if (TARO_ENV !== 'h5') return;
7
5
 
8
- const style = document.createElement('style');
9
- style.innerHTML = `
6
+ const H5_BASE_STYLES = `
10
7
  /* H5 端隐藏 TabBar 空图标(只隐藏没有 src 的图标) */
11
8
  .weui-tabbar__icon:not([src]),
12
9
  .weui-tabbar__icon[src=''] {
@@ -28,6 +25,196 @@ vite-error-overlay::part(window) {
28
25
  max-width: 90vw;
29
26
  padding: 10px;
30
27
  }
31
- `;
28
+
29
+ .taro_page {
30
+ overflow: auto;
31
+ }
32
+
33
+ ::-webkit-scrollbar {
34
+ width: 4px;
35
+ height: 4px;
36
+ }
37
+
38
+ ::-webkit-scrollbar-track {
39
+ background: transparent;
40
+ }
41
+
42
+ ::-webkit-scrollbar-thumb {
43
+ background: rgba(0, 0, 0, 0.2);
44
+ border-radius: 2px;
45
+ }
46
+
47
+ ::-webkit-scrollbar-thumb:hover {
48
+ background: rgba(0, 0, 0, 0.3);
49
+ }
50
+
51
+ /* H5 导航栏页面自动添加顶部间距 */
52
+ body.h5-navbar-visible .taro_page {
53
+ padding-top: 44px;
54
+ }
55
+
56
+ body.h5-navbar-visible .toaster[data-position^="top"] {
57
+ top: 44px !important;
58
+ }
59
+
60
+ /* Sheet 组件在 H5 导航栏下的位置修正 */
61
+ body.h5-navbar-visible .sheet-content:not([data-side="bottom"]) {
62
+ top: 44px !important;
63
+ }
64
+
65
+ /*
66
+ * H5 端 rem 适配:与小程序 rpx 缩放一致
67
+ * 375px 屏幕:1rem = 16px,小程序 32rpx = 16px
68
+ */
69
+ html {
70
+ font-size: 4vw !important;
71
+ }
72
+
73
+ /* H5 端组件默认样式修复 */
74
+ taro-view-core {
75
+ display: block;
76
+ }
77
+
78
+ taro-text-core {
79
+ display: inline;
80
+ }
81
+
82
+ taro-input-core {
83
+ display: block;
84
+ width: 100%;
85
+ }
86
+
87
+ taro-input-core input {
88
+ width: 100%;
89
+ background: transparent;
90
+ border: none;
91
+ outline: none;
92
+ }
93
+
94
+ taro-input-core.taro-otp-hidden-input input {
95
+ color: transparent;
96
+ caret-color: transparent;
97
+ -webkit-text-fill-color: transparent;
98
+ }
99
+
100
+ /* 全局按钮样式重置 */
101
+ taro-button-core,
102
+ button {
103
+ margin: 0 !important;
104
+ padding: 0 !important;
105
+ line-height: inherit;
106
+ display: flex;
107
+ align-items: center;
108
+ justify-content: center;
109
+ }
110
+
111
+ taro-button-core::after,
112
+ button::after {
113
+ border: none;
114
+ }
115
+
116
+ taro-textarea-core > textarea,
117
+ .taro-textarea,
118
+ textarea.taro-textarea {
119
+ resize: none !important;
120
+ }
121
+ `;
122
+
123
+ const PC_WIDESCREEN_STYLES = `
124
+ /* PC 宽屏适配 - 基础布局 */
125
+ @media (min-width: 769px) {
126
+ html {
127
+ font-size: 15px !important;
128
+ }
129
+
130
+ body {
131
+ background-color: #f3f4f6 !important;
132
+ display: flex !important;
133
+ justify-content: center !important;
134
+ align-items: center !important;
135
+ min-height: 100vh !important;
136
+ }
137
+ }
138
+ `;
139
+
140
+ const PC_WIDESCREEN_PHONE_FRAME = `
141
+ /* PC 宽屏适配 - 手机框样式(有 TabBar 页面) */
142
+ @media (min-width: 769px) {
143
+ .taro-tabbar__container {
144
+ width: 375px !important;
145
+ max-width: 375px !important;
146
+ height: calc(100vh - 40px) !important;
147
+ max-height: 900px !important;
148
+ background-color: #fff !important;
149
+ transform: translateX(0) !important;
150
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.1) !important;
151
+ border-radius: 20px !important;
152
+ overflow: hidden !important;
153
+ position: relative !important;
154
+ }
155
+
156
+ .taro-tabbar__panel {
157
+ height: 100% !important;
158
+ overflow: auto !important;
159
+ }
160
+ }
161
+
162
+ /* PC 宽屏适配 - Toast 定位到手机框范围内 */
163
+ @media (min-width: 769px) {
164
+ body .toaster {
165
+ left: 50% !important;
166
+ right: auto !important;
167
+ width: 375px !important;
168
+ max-width: 375px !important;
169
+ transform: translateX(-50%) !important;
170
+ box-sizing: border-box !important;
171
+ }
172
+ }
173
+
174
+ /* PC 宽屏适配 - 手机框样式(无 TabBar 页面,通过 JS 添加 no-tabbar 类) */
175
+ @media (min-width: 769px) {
176
+ body.no-tabbar #app {
177
+ width: 375px !important;
178
+ max-width: 375px !important;
179
+ height: calc(100vh - 40px) !important;
180
+ max-height: 900px !important;
181
+ background-color: #fff !important;
182
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.1) !important;
183
+ border-radius: 20px !important;
184
+ overflow: hidden !important;
185
+ position: relative !important;
186
+ transform: translateX(0) !important;
187
+ }
188
+
189
+ body.no-tabbar #app .taro_router {
190
+ height: 100% !important;
191
+ overflow: auto !important;
192
+ }
193
+ }
194
+ `;
195
+
196
+ function injectStyles() {
197
+ const style = document.createElement('style');
198
+ style.innerHTML =
199
+ H5_BASE_STYLES + PC_WIDESCREEN_STYLES + PC_WIDESCREEN_PHONE_FRAME;
32
200
  document.head.appendChild(style);
33
201
  }
202
+
203
+ function setupTabbarDetection() {
204
+ const checkTabbar = () => {
205
+ const hasTabbar = !!document.querySelector('.taro-tabbar__container');
206
+ document.body.classList.toggle('no-tabbar', !hasTabbar);
207
+ };
208
+
209
+ checkTabbar();
210
+
211
+ const observer = new MutationObserver(checkTabbar);
212
+ observer.observe(document.body, { childList: true, subtree: true });
213
+ }
214
+
215
+ export function injectH5Styles() {
216
+ if (TARO_ENV !== 'h5') return;
217
+
218
+ injectStyles();
219
+ setupTabbarDetection();
220
+ }
@@ -1,17 +1,17 @@
1
1
  import { useLaunch } from '@tarojs/taro';
2
2
  import { PropsWithChildren } from 'react';
3
- import { H5NavBar } from './h5-navbar';
4
3
  import { injectH5Styles } from './h5-styles';
5
- import { enableWxDebugIfNeeded } from './wx-debug';
4
+ import { devDebug } from './dev-debug';
5
+ import { H5Container } from './h5-container';
6
6
 
7
7
  export const Preset = ({ children }: PropsWithChildren) => {
8
8
  useLaunch(() => {
9
- enableWxDebugIfNeeded();
9
+ devDebug();
10
10
  injectH5Styles();
11
11
  });
12
12
 
13
13
  if (TARO_ENV === 'h5') {
14
- return <H5NavBar>{children}</H5NavBar>;
14
+ return <H5Container>{children}</H5Container>;
15
15
  }
16
16
 
17
17
  return <>{children}</>;
@@ -62,6 +62,38 @@
62
62
  "additionalProperties": false
63
63
  }
64
64
  },
65
+ {
66
+ "name": "nuxt-vue",
67
+ "description": "Nuxt.js(服务端 + Vue):`coze init ${COZE_WORKSPACE_PATH} --template nuxt-vue`\n- 适用:全栈应用、需要服务端接口能力的 Vue 项目\n- 特点:\n - **服务端能力**:内置服务端 API 路由,可直接创建后端接口\n - **Vue 3**:基于最新的 Vue 3 Composition API\n - **Vite**:使用 Vite 作为构建工具,开发体验极佳\n - **TypeScript**:完整的 TypeScript 支持\n - **文件路由**:基于文件系统的自动路由\n - **项目理解加速**:可依赖项目下 `package.json` 和 `nuxt.config.ts` 理解项目配置",
68
+ "location": "./nuxt-vue",
69
+ "paramsSchema": {
70
+ "type": "object",
71
+ "properties": {
72
+ "appName": {
73
+ "type": "string",
74
+ "minLength": 1,
75
+ "pattern": "^[a-z0-9-]+$",
76
+ "description": "Application name (lowercase, alphanumeric and hyphens only)"
77
+ },
78
+ "port": {
79
+ "type": "number",
80
+ "default": 5000,
81
+ "minimum": 1024,
82
+ "maximum": 65535,
83
+ "description": "Development server port (for Nuxt dev server)"
84
+ },
85
+ "hmrPort": {
86
+ "type": "number",
87
+ "default": 6000,
88
+ "minimum": 1024,
89
+ "maximum": 65535,
90
+ "description": "Hot Module Replacement (HMR) port"
91
+ }
92
+ },
93
+ "required": [],
94
+ "additionalProperties": false
95
+ }
96
+ },
65
97
  {
66
98
  "name": "taro",
67
99
  "description": "Taro(小程序 + H5):`coze init ${COZE_WORKSPACE_PATH} --template taro`\n- 适用:微信小程序、H5 跨端应用\n- 前后端分离架构:Taro 4 + NestJS\n- 支持微信小程序和 H5 双端构建\n- 使用 TailwindCSS + weapp-tailwindcss 实现跨端样式",
@@ -0,0 +1,41 @@
1
+ # 项目上下文
2
+
3
+ ## 技术栈
4
+
5
+ - **核心**: Vite 7, TypeScript, Express
6
+ - **UI**: Tailwind CSS
7
+
8
+ ## 目录结构
9
+
10
+ ```
11
+ ├── scripts/ # 构建与启动脚本
12
+ │ ├── build.sh # 构建脚本
13
+ │ ├── dev.sh # 开发环境启动脚本
14
+ │ ├── prepare.sh # 预处理脚本
15
+ │ └── start.sh # 生产环境启动脚本
16
+ ├── server/ # 服务端逻辑
17
+ │ ├── routes/ # API 路由
18
+ │ ├── server.ts # Express 服务入口
19
+ │ └── vite.ts # Vite 中间件集成
20
+ ├── src/ # 前端源码
21
+ │ ├── index.css # 全局样式
22
+ │ ├── index.ts # 客户端入口
23
+ │ └── main.ts # 主逻辑
24
+ ├── index.html # 入口 HTML
25
+ ├── package.json # 项目依赖管理
26
+ ├── tsconfig.json # TypeScript 配置
27
+ └── vite.config.ts # Vite 配置
28
+ ```
29
+
30
+ ## 包管理规范
31
+
32
+ **仅允许使用 pnpm** 作为包管理器,**严禁使用 npm 或 yarn**。
33
+ **常用命令**:
34
+ - 安装依赖:`pnpm add <package>`
35
+ - 安装开发依赖:`pnpm add -D <package>`
36
+ - 安装所有依赖:`pnpm install`
37
+ - 移除依赖:`pnpm remove <package>`
38
+
39
+ ## 开发规范
40
+
41
+ - 使用 Tailwind CSS 进行样式开发