@coze-arch/cli 0.0.1-alpha.de5a13 → 0.0.1-alpha.deaedf

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 (143) hide show
  1. package/README.md +1 -0
  2. package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +1 -1
  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/metro.config.js +3 -0
  6. package/lib/__templates__/expo/client/scripts/install-missing-deps.js +10 -10
  7. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/index.js +9 -0
  8. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/rule.js +112 -0
  9. package/lib/__templates__/expo/eslint-plugins/forbid-emoji/tech.md +94 -0
  10. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/index.js +9 -0
  11. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/rule.js +120 -0
  12. package/lib/__templates__/expo/eslint-plugins/restrict-linear-gradient/tech.md +58 -0
  13. package/lib/__templates__/expo/pnpm-lock.yaml +8 -5
  14. package/lib/__templates__/expo/server/package.json +1 -1
  15. package/lib/__templates__/native-static/.coze +11 -0
  16. package/lib/__templates__/native-static/index.html +33 -0
  17. package/lib/__templates__/native-static/styles/main.css +136 -0
  18. package/lib/__templates__/native-static/template.config.js +22 -0
  19. package/lib/__templates__/nextjs/.babelrc +3 -0
  20. package/lib/__templates__/nextjs/README.md +5 -0
  21. package/lib/__templates__/nextjs/eslint.config.mjs +5 -0
  22. package/lib/__templates__/nextjs/next.config.ts +1 -2
  23. package/lib/__templates__/nextjs/package.json +3 -6
  24. package/lib/__templates__/nextjs/pnpm-lock.yaml +1036 -10
  25. package/lib/__templates__/nextjs/scripts/build.sh +4 -1
  26. package/lib/__templates__/nextjs/scripts/dev.sh +8 -2
  27. package/lib/__templates__/nextjs/scripts/start.sh +7 -1
  28. package/lib/__templates__/nextjs/src/app/layout.tsx +1 -1
  29. package/lib/__templates__/nextjs/src/app/page.tsx +1 -2
  30. package/lib/__templates__/nextjs/src/server.ts +35 -0
  31. package/lib/__templates__/nextjs/tsconfig.json +1 -1
  32. package/lib/__templates__/nuxt-vue/.coze +12 -0
  33. package/lib/__templates__/nuxt-vue/README.md +73 -0
  34. package/lib/__templates__/nuxt-vue/_gitignore +24 -0
  35. package/lib/__templates__/nuxt-vue/_npmrc +23 -0
  36. package/lib/__templates__/nuxt-vue/app/app.vue +6 -0
  37. package/lib/__templates__/nuxt-vue/app/pages/index.vue +23 -0
  38. package/lib/__templates__/nuxt-vue/assets/css/main.css +24 -0
  39. package/lib/__templates__/nuxt-vue/nuxt.config.ts +116 -0
  40. package/lib/__templates__/nuxt-vue/package.json +35 -0
  41. package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +8759 -0
  42. package/lib/__templates__/nuxt-vue/postcss.config.mjs +8 -0
  43. package/lib/__templates__/nuxt-vue/public/favicon.ico +0 -0
  44. package/lib/__templates__/nuxt-vue/public/robots.txt +2 -0
  45. package/lib/__templates__/nuxt-vue/scripts/build.sh +14 -0
  46. package/lib/__templates__/nuxt-vue/scripts/dev.sh +39 -0
  47. package/lib/__templates__/nuxt-vue/scripts/prepare.sh +14 -0
  48. package/lib/__templates__/nuxt-vue/scripts/start.sh +21 -0
  49. package/lib/__templates__/nuxt-vue/server/api/hello.ts +10 -0
  50. package/lib/__templates__/nuxt-vue/server/middleware/logger.ts +10 -0
  51. package/lib/__templates__/nuxt-vue/server/routes/health.ts +10 -0
  52. package/lib/__templates__/nuxt-vue/tailwind.config.js +13 -0
  53. package/lib/__templates__/nuxt-vue/template.config.js +87 -0
  54. package/lib/__templates__/nuxt-vue/tsconfig.json +18 -0
  55. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +107 -37
  56. package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +24 -1
  57. package/lib/__templates__/taro/README.md +138 -62
  58. package/lib/__templates__/taro/config/index.ts +105 -41
  59. package/lib/__templates__/taro/config/prod.ts +4 -5
  60. package/lib/__templates__/taro/eslint.config.mjs +82 -4
  61. package/lib/__templates__/taro/package.json +23 -7
  62. package/lib/__templates__/taro/patches/@tarojs__plugin-mini-ci@4.1.9.patch +30 -0
  63. package/lib/__templates__/taro/pnpm-lock.yaml +1198 -214
  64. package/lib/__templates__/taro/server/package.json +3 -1
  65. package/lib/__templates__/taro/src/app.css +140 -47
  66. package/lib/__templates__/taro/src/app.tsx +9 -0
  67. package/lib/__templates__/taro/src/components/ui/accordion.tsx +159 -0
  68. package/lib/__templates__/taro/src/components/ui/alert-dialog.tsx +260 -0
  69. package/lib/__templates__/taro/src/components/ui/alert.tsx +60 -0
  70. package/lib/__templates__/taro/src/components/ui/aspect-ratio.tsx +36 -0
  71. package/lib/__templates__/taro/src/components/ui/avatar.tsx +84 -0
  72. package/lib/__templates__/taro/src/components/ui/badge.tsx +37 -0
  73. package/lib/__templates__/taro/src/components/ui/breadcrumb.tsx +117 -0
  74. package/lib/__templates__/taro/src/components/ui/button-group.tsx +83 -0
  75. package/lib/__templates__/taro/src/components/ui/button.tsx +67 -0
  76. package/lib/__templates__/taro/src/components/ui/calendar.tsx +394 -0
  77. package/lib/__templates__/taro/src/components/ui/card.tsx +108 -0
  78. package/lib/__templates__/taro/src/components/ui/carousel.tsx +228 -0
  79. package/lib/__templates__/taro/src/components/ui/checkbox.tsx +58 -0
  80. package/lib/__templates__/taro/src/components/ui/code-block.tsx +169 -0
  81. package/lib/__templates__/taro/src/components/ui/collapsible.tsx +71 -0
  82. package/lib/__templates__/taro/src/components/ui/command.tsx +385 -0
  83. package/lib/__templates__/taro/src/components/ui/context-menu.tsx +614 -0
  84. package/lib/__templates__/taro/src/components/ui/dialog.tsx +256 -0
  85. package/lib/__templates__/taro/src/components/ui/drawer.tsx +192 -0
  86. package/lib/__templates__/taro/src/components/ui/dropdown-menu.tsx +561 -0
  87. package/lib/__templates__/taro/src/components/ui/field.tsx +228 -0
  88. package/lib/__templates__/taro/src/components/ui/hover-card.tsx +282 -0
  89. package/lib/__templates__/taro/src/components/ui/input-group.tsx +197 -0
  90. package/lib/__templates__/taro/src/components/ui/input-otp.tsx +136 -0
  91. package/lib/__templates__/taro/src/components/ui/input.tsx +56 -0
  92. package/lib/__templates__/taro/src/components/ui/label.tsx +24 -0
  93. package/lib/__templates__/taro/src/components/ui/menubar.tsx +595 -0
  94. package/lib/__templates__/taro/src/components/ui/navigation-menu.tsx +264 -0
  95. package/lib/__templates__/taro/src/components/ui/pagination.tsx +118 -0
  96. package/lib/__templates__/taro/src/components/ui/popover.tsx +291 -0
  97. package/lib/__templates__/taro/src/components/ui/portal.tsx +19 -0
  98. package/lib/__templates__/taro/src/components/ui/progress.tsx +28 -0
  99. package/lib/__templates__/taro/src/components/ui/radio-group.tsx +64 -0
  100. package/lib/__templates__/taro/src/components/ui/resizable.tsx +346 -0
  101. package/lib/__templates__/taro/src/components/ui/scroll-area.tsx +34 -0
  102. package/lib/__templates__/taro/src/components/ui/select.tsx +438 -0
  103. package/lib/__templates__/taro/src/components/ui/separator.tsx +30 -0
  104. package/lib/__templates__/taro/src/components/ui/sheet.tsx +262 -0
  105. package/lib/__templates__/taro/src/components/ui/skeleton.tsx +17 -0
  106. package/lib/__templates__/taro/src/components/ui/slider.tsx +203 -0
  107. package/lib/__templates__/taro/src/components/ui/sonner.tsx +1 -0
  108. package/lib/__templates__/taro/src/components/ui/switch.tsx +55 -0
  109. package/lib/__templates__/taro/src/components/ui/table.tsx +142 -0
  110. package/lib/__templates__/taro/src/components/ui/tabs.tsx +114 -0
  111. package/lib/__templates__/taro/src/components/ui/textarea.tsx +54 -0
  112. package/lib/__templates__/taro/src/components/ui/toast.tsx +517 -0
  113. package/lib/__templates__/taro/src/components/ui/toggle-group.tsx +120 -0
  114. package/lib/__templates__/taro/src/components/ui/toggle.tsx +77 -0
  115. package/lib/__templates__/taro/src/components/ui/tooltip.tsx +455 -0
  116. package/lib/__templates__/taro/src/lib/hooks/use-keyboard-offset.ts +37 -0
  117. package/lib/__templates__/taro/src/lib/measure.ts +115 -0
  118. package/lib/__templates__/taro/src/lib/platform.ts +12 -0
  119. package/lib/__templates__/taro/src/lib/utils.ts +6 -0
  120. package/lib/__templates__/taro/src/presets/dev-debug.ts +23 -0
  121. package/lib/__templates__/taro/src/presets/h5-container.tsx +15 -0
  122. package/lib/__templates__/taro/src/presets/h5-navbar.tsx +238 -0
  123. package/lib/__templates__/taro/src/presets/h5-styles.ts +220 -0
  124. package/lib/__templates__/taro/src/presets/index.tsx +18 -0
  125. package/lib/__templates__/templates.json +43 -0
  126. package/lib/__templates__/vite/README.md +190 -11
  127. package/lib/__templates__/vite/_gitignore +1 -0
  128. package/lib/__templates__/vite/eslint.config.mjs +6 -1
  129. package/lib/__templates__/vite/package.json +14 -5
  130. package/lib/__templates__/vite/pnpm-lock.yaml +768 -24
  131. package/lib/__templates__/vite/scripts/build.sh +4 -1
  132. package/lib/__templates__/vite/scripts/dev.sh +9 -2
  133. package/lib/__templates__/vite/scripts/start.sh +9 -3
  134. package/lib/__templates__/vite/server/routes/index.ts +31 -0
  135. package/lib/__templates__/vite/server/server.ts +65 -0
  136. package/lib/__templates__/vite/server/vite.ts +67 -0
  137. package/lib/__templates__/vite/tsconfig.json +4 -3
  138. package/lib/__templates__/vite/vite.config.ts +5 -0
  139. package/lib/cli.js +124 -103
  140. package/package.json +7 -3
  141. package/lib/__templates__/taro/src/app.ts +0 -14
  142. package/lib/__templates__/taro/src/utils/h5-styles.ts +0 -22
  143. package/lib/__templates__/taro/src/utils/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
+ };
@@ -0,0 +1,238 @@
1
+ import { View, Text } from '@tarojs/components';
2
+ import Taro, { useDidShow, usePageScroll } from '@tarojs/taro';
3
+ import { useState, useEffect, useCallback } from 'react';
4
+ import { ChevronLeft, House } from 'lucide-react-taro';
5
+
6
+ interface NavConfig {
7
+ navigationBarTitleText?: string;
8
+ navigationBarBackgroundColor?: string;
9
+ navigationBarTextStyle?: 'black' | 'white';
10
+ navigationStyle?: 'default' | 'custom';
11
+ transparentTitle?: 'none' | 'always' | 'auto';
12
+ }
13
+
14
+ enum LeftIcon {
15
+ Back = 'back',
16
+ Home = 'home',
17
+ None = 'none',
18
+ }
19
+
20
+ interface NavState {
21
+ visible: boolean;
22
+ title: string;
23
+ bgColor: string;
24
+ textStyle: 'black' | 'white';
25
+ navStyle: 'default' | 'custom';
26
+ transparent: 'none' | 'always' | 'auto';
27
+ leftIcon: LeftIcon;
28
+ }
29
+
30
+ const DEFAULT_NAV_STATE: NavState = {
31
+ visible: false,
32
+ title: '',
33
+ bgColor: '#ffffff',
34
+ textStyle: 'black',
35
+ navStyle: 'default',
36
+ transparent: 'none',
37
+ leftIcon: LeftIcon.None,
38
+ };
39
+
40
+ const getGlobalWindowConfig = (): Partial<NavConfig> => {
41
+ const app = Taro.getApp();
42
+ return app?.config?.window || {};
43
+ };
44
+
45
+ const getTabBarPages = (): Set<string> => {
46
+ const tabBar = Taro.getApp()?.config?.tabBar;
47
+ return new Set(
48
+ tabBar?.list?.map((item: { pagePath: string }) => item.pagePath) || [],
49
+ );
50
+ };
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
+
59
+ const computeLeftIcon = (
60
+ route: string,
61
+ tabBarPages: Set<string>,
62
+ historyLength: number,
63
+ homePage: string,
64
+ ): LeftIcon => {
65
+ if (!route) return LeftIcon.None;
66
+
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}`);
72
+ const hasHistory = historyLength > 1;
73
+
74
+ if (isTabBarPage || isHomePage) return LeftIcon.None;
75
+ if (hasHistory) return LeftIcon.Back;
76
+ return LeftIcon.Home;
77
+ };
78
+
79
+ export const H5NavBar = () => {
80
+ const [navState, setNavState] = useState<NavState>(DEFAULT_NAV_STATE);
81
+ const [scrollOpacity, setScrollOpacity] = useState(0);
82
+
83
+ const updateNavState = useCallback(() => {
84
+ const pages = Taro.getCurrentPages();
85
+ if (pages.length === 0) {
86
+ setNavState(prev => ({ ...prev, visible: false }));
87
+ return;
88
+ }
89
+
90
+ const currentPage = pages[pages.length - 1];
91
+ const route = currentPage?.route || '';
92
+ if (!route) return;
93
+
94
+ const pageConfig: NavConfig = (currentPage as any)?.config || {};
95
+ const globalConfig = getGlobalWindowConfig();
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}`);
105
+
106
+ const shouldHideNav =
107
+ tabBarPages.size <= 1 &&
108
+ pages.length <= 1 &&
109
+ (isHomePage || isTabBarPage);
110
+
111
+ setNavState({
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
131
+ ? LeftIcon.None
132
+ : computeLeftIcon(cleanRoute, tabBarPages, pages.length, cleanHomePage),
133
+ });
134
+ }, []);
135
+
136
+ useDidShow(() => {
137
+ updateNavState();
138
+ });
139
+
140
+ usePageScroll(({ scrollTop }) => {
141
+ if (navState.transparent === 'auto') {
142
+ setScrollOpacity(Math.min(scrollTop / 100, 1));
143
+ }
144
+ });
145
+
146
+ useEffect(() => {
147
+ if (TARO_ENV !== 'h5') return;
148
+
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, {
158
+ subtree: true,
159
+ childList: true,
160
+ characterData: true,
161
+ });
162
+
163
+ updateNavState();
164
+
165
+ return () => {
166
+ observer.disconnect();
167
+ if (timer) clearTimeout(timer);
168
+ };
169
+ }, [updateNavState]);
170
+
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 <></>;
185
+ }
186
+
187
+ const iconColor = navState.textStyle === 'white' ? '#fff' : '#333';
188
+ const textColorClass =
189
+ navState.textStyle === 'white' ? 'text-white' : 'text-gray-800';
190
+
191
+ const getBgStyle = () => {
192
+ if (navState.transparent === 'always') {
193
+ return { backgroundColor: 'transparent' };
194
+ }
195
+ if (navState.transparent === 'auto') {
196
+ return { backgroundColor: navState.bgColor, opacity: scrollOpacity };
197
+ }
198
+ return { backgroundColor: navState.bgColor };
199
+ };
200
+
201
+ const handleBack = () => Taro.navigateBack();
202
+ const handleGoHome = () => {
203
+ const homePage = getHomePage();
204
+ Taro.reLaunch({ url: `/${homePage}` });
205
+ };
206
+
207
+ return (
208
+ <>
209
+ <View
210
+ className="fixed top-0 left-0 right-0 h-11 flex items-center justify-center z-1000"
211
+ style={getBgStyle()}
212
+ >
213
+ {navState.leftIcon === LeftIcon.Back && (
214
+ <View
215
+ className="absolute left-2 top-1/2 -translate-y-1/2 p-1 flex items-center justify-center"
216
+ onClick={handleBack}
217
+ >
218
+ <ChevronLeft size={24} color={iconColor} />
219
+ </View>
220
+ )}
221
+ {navState.leftIcon === LeftIcon.Home && (
222
+ <View
223
+ className="absolute left-2 top-1/2 -translate-y-1/2 p-1 flex items-center justify-center"
224
+ onClick={handleGoHome}
225
+ >
226
+ <House size={22} color={iconColor} />
227
+ </View>
228
+ )}
229
+ <Text
230
+ className={`text-base font-medium max-w-3/5 truncate ${textColorClass}`}
231
+ >
232
+ {navState.title}
233
+ </Text>
234
+ </View>
235
+ <View className="h-11 shrink-0" />
236
+ </>
237
+ );
238
+ };
@@ -0,0 +1,220 @@
1
+ /**
2
+ * H5 端特殊样式注入
3
+ * 如无必要,请勿修改本文件
4
+ */
5
+
6
+ const H5_BASE_STYLES = `
7
+ /* H5 端隐藏 TabBar 空图标(只隐藏没有 src 的图标) */
8
+ .weui-tabbar__icon:not([src]),
9
+ .weui-tabbar__icon[src=''] {
10
+ display: none !important;
11
+ }
12
+
13
+ .weui-tabbar__item:has(.weui-tabbar__icon:not([src])) .weui-tabbar__label,
14
+ .weui-tabbar__item:has(.weui-tabbar__icon[src='']) .weui-tabbar__label {
15
+ margin-top: 0 !important;
16
+ }
17
+
18
+ /* Vite 错误覆盖层无法选择文本的问题 */
19
+ vite-error-overlay {
20
+ /* stylelint-disable-next-line property-no-vendor-prefix */
21
+ -webkit-user-select: text !important;
22
+ }
23
+
24
+ vite-error-overlay::part(window) {
25
+ max-width: 90vw;
26
+ padding: 10px;
27
+ }
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;
200
+ document.head.appendChild(style);
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
+ }
@@ -0,0 +1,18 @@
1
+ import { useLaunch } from '@tarojs/taro';
2
+ import { PropsWithChildren } from 'react';
3
+ import { injectH5Styles } from './h5-styles';
4
+ import { devDebug } from './dev-debug';
5
+ import { H5Container } from './h5-container';
6
+
7
+ export const Preset = ({ children }: PropsWithChildren) => {
8
+ useLaunch(() => {
9
+ devDebug();
10
+ injectH5Styles();
11
+ });
12
+
13
+ if (TARO_ENV === 'h5') {
14
+ return <H5Container>{children}</H5Container>;
15
+ }
16
+
17
+ return <>{children}</>;
18
+ };