@coze-arch/cli 0.0.1-alpha.f5dbe4 → 0.0.1-alpha.f62945
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/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +13 -12
- package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +9 -8
- package/lib/__templates__/expo/README.md +3 -5
- package/lib/__templates__/expo/client/app/+not-found.tsx +19 -4
- package/lib/__templates__/expo/client/app/_layout.tsx +17 -16
- package/lib/__templates__/expo/client/components/ThemedText.tsx +33 -0
- package/lib/__templates__/expo/client/components/ThemedView.tsx +37 -0
- package/lib/__templates__/expo/client/constants/theme.ts +177 -0
- package/lib/__templates__/expo/client/hooks/useColorScheme.tsx +48 -0
- package/lib/__templates__/expo/client/hooks/useTheme.ts +33 -0
- package/lib/__templates__/expo/client/metro.config.js +4 -8
- package/lib/__templates__/expo/client/package.json +29 -31
- package/lib/__templates__/expo/client/screens/demo/index.tsx +13 -7
- package/lib/__templates__/expo/package.json +1 -1
- package/lib/__templates__/expo/patches/{expo@54.0.32.patch → expo@54.0.33.patch} +3 -2
- package/lib/__templates__/expo/pnpm-lock.yaml +340 -1736
- package/lib/__templates__/expo/server/package.json +9 -7
- package/lib/__templates__/expo/server/src/index.ts +1 -0
- package/lib/__templates__/expo/template.config.js +56 -0
- package/lib/__templates__/native-static/.coze +11 -0
- package/lib/__templates__/native-static/index.html +33 -0
- package/lib/__templates__/native-static/styles/main.css +136 -0
- package/lib/__templates__/native-static/template.config.js +22 -0
- package/lib/__templates__/nextjs/package.json +3 -1
- package/lib/__templates__/nextjs/pnpm-lock.yaml +119 -106
- package/lib/__templates__/nextjs/src/app/page.tsx +18 -60
- package/lib/__templates__/nextjs/template.config.js +49 -14
- package/lib/__templates__/taro/.coze +14 -0
- package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.sh +19 -0
- package/lib/__templates__/taro/.cozeproj/scripts/deploy_run.sh +14 -0
- package/lib/__templates__/taro/.cozeproj/scripts/dev_build.sh +2 -0
- package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +151 -0
- package/lib/__templates__/taro/.cozeproj/scripts/init_env.sh +5 -0
- package/lib/__templates__/taro/.cozeproj/scripts/pack.sh +24 -0
- package/lib/__templates__/taro/README.md +751 -0
- package/lib/__templates__/taro/_gitignore +40 -0
- package/lib/__templates__/taro/_npmrc +18 -0
- package/lib/__templates__/taro/babel.config.js +12 -0
- package/lib/__templates__/taro/config/dev.ts +9 -0
- package/lib/__templates__/taro/config/index.ts +223 -0
- package/lib/__templates__/taro/config/prod.ts +34 -0
- package/lib/__templates__/taro/eslint.config.mjs +80 -0
- package/lib/__templates__/taro/key/private.appid.key +0 -0
- package/lib/__templates__/taro/package.json +107 -0
- package/lib/__templates__/taro/patches/@tarojs__plugin-mini-ci@4.1.9.patch +30 -0
- package/lib/__templates__/taro/pnpm-lock.yaml +23100 -0
- package/lib/__templates__/taro/pnpm-workspace.yaml +2 -0
- package/lib/__templates__/taro/project.config.json +15 -0
- package/lib/__templates__/taro/server/nest-cli.json +10 -0
- package/lib/__templates__/taro/server/package.json +40 -0
- package/lib/__templates__/taro/server/src/app.controller.ts +23 -0
- package/lib/__templates__/taro/server/src/app.module.ts +10 -0
- package/lib/__templates__/taro/server/src/app.service.ts +8 -0
- package/lib/__templates__/taro/server/src/interceptors/http-status.interceptor.ts +23 -0
- package/lib/__templates__/taro/server/src/main.ts +49 -0
- package/lib/__templates__/taro/server/tsconfig.json +24 -0
- package/lib/__templates__/taro/src/app.config.ts +11 -0
- package/lib/__templates__/taro/src/app.css +52 -0
- package/lib/__templates__/taro/src/app.tsx +9 -0
- package/lib/__templates__/taro/src/index.html +39 -0
- package/lib/__templates__/taro/src/network.ts +39 -0
- package/lib/__templates__/taro/src/pages/index/index.config.ts +3 -0
- package/lib/__templates__/taro/src/pages/index/index.css +1 -0
- package/lib/__templates__/taro/src/pages/index/index.tsx +33 -0
- package/lib/__templates__/taro/src/presets/dev-debug.ts +23 -0
- package/lib/__templates__/taro/src/presets/h5-container.tsx +15 -0
- package/lib/__templates__/taro/src/presets/h5-navbar.tsx +201 -0
- package/lib/__templates__/taro/src/presets/h5-styles.ts +142 -0
- package/lib/__templates__/taro/src/presets/index.tsx +18 -0
- package/lib/__templates__/taro/stylelint.config.mjs +4 -0
- package/lib/__templates__/taro/template.config.js +68 -0
- package/lib/__templates__/taro/tsconfig.json +29 -0
- package/lib/__templates__/taro/types/global.d.ts +32 -0
- package/lib/__templates__/templates.json +75 -0
- package/lib/__templates__/vite/package.json +5 -1
- package/lib/__templates__/vite/pnpm-lock.yaml +146 -1659
- package/lib/__templates__/vite/src/main.ts +17 -47
- package/lib/__templates__/vite/template.config.js +49 -14
- package/lib/__templates__/vite/vite.config.ts +1 -0
- package/lib/cli.js +62 -68
- package/package.json +2 -1
- package/lib/__templates__/expo/client/global.css +0 -76
- package/lib/__templates__/expo/client/uniwind-types.d.ts +0 -10
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
2
2
|
PREVIEW_DIR="${COZE_PREVIEW_DIR:-/source/preview}"
|
|
3
3
|
LOG_DIR="${COZE_LOG_DIR:-$ROOT_DIR/logs}"
|
|
4
|
-
|
|
4
|
+
LOG_CLIENT_FILE="$LOG_DIR/client.log"
|
|
5
5
|
mkdir -p "$LOG_DIR"
|
|
6
6
|
|
|
7
7
|
# ==================== 配置项 ====================
|
|
@@ -89,14 +89,17 @@ ensure_port() {
|
|
|
89
89
|
pipe_to_log() {
|
|
90
90
|
local source="${1:-CLIENT}"
|
|
91
91
|
local raw_log="${2:-}"
|
|
92
|
-
local line timestamp
|
|
92
|
+
local line clean_line timestamp
|
|
93
93
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
94
|
+
clean_line=$(printf '%s' "$line" | sed 's/\x1b\[[0-9;]*[mA-Za-z]//g')
|
|
95
|
+
if echo "$clean_line" | grep -qE '(^(Web|iOS|Android) node_modules/.*expo-router.*entry\.js.*%|^(Web|iOS|Android) Bundled [0-9]+ms node_modules/.*expo-router.*entry\.js|Logs will appear in the browser)'; then
|
|
96
|
+
continue
|
|
97
|
+
fi
|
|
94
98
|
if [ -n "$raw_log" ]; then
|
|
95
|
-
|
|
99
|
+
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
100
|
+
echo "[$timestamp] $clean_line" >> "$raw_log"
|
|
96
101
|
fi
|
|
97
|
-
|
|
98
|
-
msg="${line}"
|
|
99
|
-
echo "$msg"
|
|
102
|
+
printf '[%s] %s\n' "$source" "$clean_line"
|
|
100
103
|
done
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -116,10 +119,10 @@ start_expo() {
|
|
|
116
119
|
|
|
117
120
|
if [ "$offline" = "1" ]; then
|
|
118
121
|
( EXPO_OFFLINE=1 EXPO_NO_DEPENDENCY_VALIDATION=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" EXPO_PUBLIC_COZE_PROJECT_ID="$EXPO_PUBLIC_COZE_PROJECT_ID" \
|
|
119
|
-
nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$
|
|
122
|
+
nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$LOG_CLIENT_FILE" ) &
|
|
120
123
|
else
|
|
121
124
|
( EXPO_NO_DEPENDENCY_VALIDATION=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" EXPO_PUBLIC_COZE_PROJECT_ID="$EXPO_PUBLIC_COZE_PROJECT_ID" \
|
|
122
|
-
nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$
|
|
125
|
+
nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$LOG_CLIENT_FILE" ) &
|
|
123
126
|
fi
|
|
124
127
|
EXPO_PID=$!
|
|
125
128
|
disown $EXPO_PID 2>/dev/null || true
|
|
@@ -130,9 +133,9 @@ start_expo() {
|
|
|
130
133
|
detect_expo_fetch_failed() {
|
|
131
134
|
local timeout="${1:-8}"
|
|
132
135
|
local waited=0
|
|
133
|
-
local log_file="$
|
|
136
|
+
local log_file="$LOG_CLIENT_FILE"
|
|
134
137
|
while [ "$waited" -lt "$timeout" ]; do
|
|
135
|
-
if [ -f "$log_file" ] &&
|
|
138
|
+
if [ -f "$log_file" ] && tail -n 100 "$log_file" 2>/dev/null | grep -q "TypeError: fetch failed"; then
|
|
136
139
|
return 0
|
|
137
140
|
fi
|
|
138
141
|
sleep 1
|
|
@@ -166,8 +169,6 @@ check_command "pnpm"
|
|
|
166
169
|
check_command "lsof"
|
|
167
170
|
check_command "bash"
|
|
168
171
|
|
|
169
|
-
echo "准备日志目录:$ROOT_DIR/logs"
|
|
170
|
-
mkdir -p "$ROOT_DIR/logs"
|
|
171
172
|
# 端口占用预检查与处理
|
|
172
173
|
ensure_port SERVER_PORT "$SERVER_PORT"
|
|
173
174
|
ensure_port EXPO_PORT "$EXPO_PORT"
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
4
4
|
SERVER_DIR="$ROOT_DIR/server"
|
|
5
|
-
LOG_DIR="$ROOT_DIR/logs"
|
|
6
|
-
|
|
5
|
+
LOG_DIR="${COZE_LOG_DIR:-$ROOT_DIR/logs}"
|
|
6
|
+
LOG_SERVER_FILE="$LOG_DIR/server.log"
|
|
7
7
|
SERVER_PORT="${SERVER_PORT:-9091}"
|
|
8
8
|
|
|
9
9
|
mkdir -p "$LOG_DIR"
|
|
@@ -11,13 +11,14 @@ mkdir -p "$LOG_DIR"
|
|
|
11
11
|
pipe_to_log() {
|
|
12
12
|
local source="${1:-SERVER}"
|
|
13
13
|
local raw_log="${2:-}"
|
|
14
|
-
local line
|
|
14
|
+
local line clean_line timestamp
|
|
15
15
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
16
|
+
clean_line=$(printf '%s' "$line" | sed 's/\x1b\[[0-9;]*[mA-Za-z]//g')
|
|
16
17
|
if [ -n "$raw_log" ]; then
|
|
17
|
-
|
|
18
|
+
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
19
|
+
echo "[$timestamp] $clean_line" >> "$raw_log"
|
|
18
20
|
fi
|
|
19
|
-
|
|
20
|
-
echo "$line"
|
|
21
|
+
printf '[%s] %s\n' "$source" "$clean_line"
|
|
21
22
|
done
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -36,10 +37,10 @@ kill_old_server() {
|
|
|
36
37
|
echo "==================== Server Dev Run ===================="
|
|
37
38
|
echo "Server 目录:$SERVER_DIR"
|
|
38
39
|
echo "Server 端口:$SERVER_PORT"
|
|
39
|
-
echo "日志文件:$
|
|
40
|
+
echo "日志文件:$LOG_SERVER_FILE"
|
|
40
41
|
|
|
41
42
|
kill_old_server
|
|
42
43
|
|
|
43
44
|
echo "启动 server 服务..."
|
|
44
45
|
cd "$SERVER_DIR"
|
|
45
|
-
NODE_ENV=development PORT="$SERVER_PORT" npx tsx ./src/index.ts 2>&1 | pipe_to_log "SERVER" "$
|
|
46
|
+
NODE_ENV=development PORT="$SERVER_PORT" npx tsx watch ./src/index.ts 2>&1 | pipe_to_log "SERVER" "$LOG_SERVER_FILE"
|
|
@@ -20,11 +20,13 @@
|
|
|
20
20
|
│ │ └── index.tsx # re-export home.tsx
|
|
21
21
|
│ ├── screens/ # 页面实现目录(与 app/ 路由对应)
|
|
22
22
|
│ │ └── demo/ # demo 示例页面
|
|
23
|
-
│ │
|
|
23
|
+
│ │ ├── index.tsx # 页面组件实现
|
|
24
|
+
│ │ └── styles.ts # 页面样式
|
|
24
25
|
│ ├── components/ # 可复用组件
|
|
25
26
|
│ │ └── Screen.tsx # 页面容器组件(必用)
|
|
26
27
|
│ ├── hooks/ # 自定义 Hooks
|
|
27
28
|
│ ├── contexts/ # React Context 代码
|
|
29
|
+
│ ├── constants/ # 常量定义(如主题配置)
|
|
28
30
|
│ ├── utils/ # 工具函数
|
|
29
31
|
│ ├── assets/ # 静态资源
|
|
30
32
|
| └── package.json # Expo 应用 package.json
|
|
@@ -32,10 +34,6 @@
|
|
|
32
34
|
├── .cozeproj # 预置脚手架脚本(禁止修改)
|
|
33
35
|
└── .coze # 配置文件(禁止修改)
|
|
34
36
|
|
|
35
|
-
## 样式方案(TailwindCSS v4)
|
|
36
|
-
|
|
37
|
-
本项目通过 uniwind 实现了 react-native 对 TailwindCSS v4 的支持,在开始开发前,应先查看 client/global.css 了解必要的信息
|
|
38
|
-
|
|
39
37
|
## 安装依赖
|
|
40
38
|
|
|
41
39
|
### 命令
|
|
@@ -1,15 +1,30 @@
|
|
|
1
|
-
import { View, Text } from 'react-native';
|
|
1
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
2
2
|
import { Link } from 'expo-router';
|
|
3
|
+
import { useTheme } from '@/hooks/useTheme';
|
|
4
|
+
import { Spacing } from '@/constants/theme';
|
|
3
5
|
|
|
4
6
|
export default function NotFoundScreen() {
|
|
7
|
+
const { theme } = useTheme();
|
|
8
|
+
|
|
5
9
|
return (
|
|
6
|
-
<View
|
|
7
|
-
<Text
|
|
10
|
+
<View style={[styles.container, { backgroundColor: theme.backgroundRoot }]}>
|
|
11
|
+
<Text>
|
|
8
12
|
页面不存在
|
|
9
13
|
</Text>
|
|
10
|
-
<Link href="/"
|
|
14
|
+
<Link href="/" style={[styles.gohome]}>
|
|
11
15
|
返回首页
|
|
12
16
|
</Link>
|
|
13
17
|
</View>
|
|
14
18
|
);
|
|
15
19
|
}
|
|
20
|
+
|
|
21
|
+
const styles = StyleSheet.create({
|
|
22
|
+
container: {
|
|
23
|
+
flex: 1,
|
|
24
|
+
justifyContent: 'center',
|
|
25
|
+
alignItems: 'center',
|
|
26
|
+
},
|
|
27
|
+
gohome: {
|
|
28
|
+
marginTop: Spacing['2xl'],
|
|
29
|
+
},
|
|
30
|
+
});
|
|
@@ -5,8 +5,7 @@ import { StatusBar } from 'expo-status-bar';
|
|
|
5
5
|
import { LogBox } from 'react-native';
|
|
6
6
|
import Toast from 'react-native-toast-message';
|
|
7
7
|
import { AuthProvider } from "@/contexts/AuthContext";
|
|
8
|
-
|
|
9
|
-
import '../global.css';
|
|
8
|
+
import { ColorSchemeProvider } from '@/hooks/useColorScheme';
|
|
10
9
|
|
|
11
10
|
LogBox.ignoreLogs([
|
|
12
11
|
"TurboModuleRegistry.getEnforcing(...): 'RNMapsAirModule' could not be found",
|
|
@@ -16,20 +15,22 @@ LogBox.ignoreLogs([
|
|
|
16
15
|
export default function RootLayout() {
|
|
17
16
|
return (
|
|
18
17
|
<AuthProvider>
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
18
|
+
<ColorSchemeProvider>
|
|
19
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
20
|
+
<StatusBar style="dark"></StatusBar>
|
|
21
|
+
<Stack screenOptions={{
|
|
22
|
+
// 设置所有页面的切换动画为从右侧滑入,适用于iOS 和 Android
|
|
23
|
+
animation: 'slide_from_right',
|
|
24
|
+
gestureEnabled: true,
|
|
25
|
+
gestureDirection: 'horizontal',
|
|
26
|
+
// 隐藏自带的头部
|
|
27
|
+
headerShown: false
|
|
28
|
+
}}>
|
|
29
|
+
<Stack.Screen name="index" options={{ title: "" }} />
|
|
30
|
+
</Stack>
|
|
31
|
+
<Toast />
|
|
32
|
+
</GestureHandlerRootView>
|
|
33
|
+
</ColorSchemeProvider>
|
|
33
34
|
</AuthProvider>
|
|
34
35
|
);
|
|
35
36
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text, TextProps, TextStyle } from 'react-native';
|
|
3
|
+
import { useTheme } from '@/hooks/useTheme';
|
|
4
|
+
import { Typography } from '@/constants/theme';
|
|
5
|
+
|
|
6
|
+
type TypographyVariant = keyof typeof Typography;
|
|
7
|
+
|
|
8
|
+
interface ThemedTextProps extends TextProps {
|
|
9
|
+
variant?: TypographyVariant;
|
|
10
|
+
color?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function ThemedText({
|
|
14
|
+
variant = 'body',
|
|
15
|
+
color,
|
|
16
|
+
style,
|
|
17
|
+
children,
|
|
18
|
+
...props
|
|
19
|
+
}: ThemedTextProps) {
|
|
20
|
+
const { theme } = useTheme();
|
|
21
|
+
const typographyStyle = Typography[variant];
|
|
22
|
+
|
|
23
|
+
const textStyle: TextStyle = {
|
|
24
|
+
...typographyStyle,
|
|
25
|
+
color: color ?? theme.textPrimary,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Text style={[textStyle, style]} {...props}>
|
|
30
|
+
{children}
|
|
31
|
+
</Text>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, ViewProps, ViewStyle } from 'react-native';
|
|
3
|
+
import { useTheme } from '@/hooks/useTheme';
|
|
4
|
+
|
|
5
|
+
type BackgroundLevel = 'root' | 'default' | 'tertiary';
|
|
6
|
+
|
|
7
|
+
interface ThemedViewProps extends ViewProps {
|
|
8
|
+
level?: BackgroundLevel;
|
|
9
|
+
backgroundColor?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const backgroundMap: Record<BackgroundLevel, string> = {
|
|
13
|
+
root: 'backgroundRoot',
|
|
14
|
+
default: 'backgroundDefault',
|
|
15
|
+
tertiary: 'backgroundTertiary',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function ThemedView({
|
|
19
|
+
level = 'root',
|
|
20
|
+
backgroundColor,
|
|
21
|
+
style,
|
|
22
|
+
children,
|
|
23
|
+
...props
|
|
24
|
+
}: ThemedViewProps) {
|
|
25
|
+
const { theme } = useTheme();
|
|
26
|
+
const bgColor = backgroundColor ?? (theme as any)[backgroundMap[level]];
|
|
27
|
+
|
|
28
|
+
const viewStyle: ViewStyle = {
|
|
29
|
+
backgroundColor: bgColor,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<View style={[viewStyle, style]} {...props}>
|
|
34
|
+
{children}
|
|
35
|
+
</View>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
export const Colors = {
|
|
2
|
+
light: {
|
|
3
|
+
textPrimary: "#1C1917",
|
|
4
|
+
textSecondary: "#78716c",
|
|
5
|
+
textMuted: "#9CA3AF",
|
|
6
|
+
primary: "#4F46E5", // Indigo-600 - 品牌主色,代表科技与智能
|
|
7
|
+
accent: "#8B5CF6", // Violet-500 - 辅助色,代表创造力
|
|
8
|
+
success: "#10B981", // Emerald-500
|
|
9
|
+
error: "#EF4444",
|
|
10
|
+
backgroundRoot: "#FAFAFA",
|
|
11
|
+
backgroundDefault: "#FFFFFF",
|
|
12
|
+
backgroundTertiary: "#F9FAFB", // 更浅的背景色,用于去线留白
|
|
13
|
+
buttonPrimaryText: "#FFFFFF",
|
|
14
|
+
tabIconSelected: "#4F46E5",
|
|
15
|
+
border: "#E5E7EB",
|
|
16
|
+
borderLight: "#F3F4F6",
|
|
17
|
+
},
|
|
18
|
+
dark: {
|
|
19
|
+
textPrimary: "#FAFAF9",
|
|
20
|
+
textSecondary: "#A8A29E",
|
|
21
|
+
textMuted: "#6F767E",
|
|
22
|
+
primary: "#818CF8", // Indigo-400 - 暗色模式品牌主色
|
|
23
|
+
accent: "#A78BFA", // Violet-400
|
|
24
|
+
success: "#34D399",
|
|
25
|
+
error: "#F87171",
|
|
26
|
+
backgroundRoot: "#09090B", // 更深的背景色
|
|
27
|
+
backgroundDefault: "#1C1C1E",
|
|
28
|
+
backgroundTertiary: "#1F1F22", // 暗色模式去线留白背景
|
|
29
|
+
buttonPrimaryText: "#09090B",
|
|
30
|
+
tabIconSelected: "#818CF8",
|
|
31
|
+
border: "#3F3F46",
|
|
32
|
+
borderLight: "#27272A",
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const Spacing = {
|
|
37
|
+
xs: 4,
|
|
38
|
+
sm: 8,
|
|
39
|
+
md: 12,
|
|
40
|
+
lg: 16,
|
|
41
|
+
xl: 20,
|
|
42
|
+
"2xl": 24,
|
|
43
|
+
"3xl": 32,
|
|
44
|
+
"4xl": 40,
|
|
45
|
+
"5xl": 48,
|
|
46
|
+
"6xl": 64,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const BorderRadius = {
|
|
50
|
+
xs: 4,
|
|
51
|
+
sm: 8,
|
|
52
|
+
md: 12,
|
|
53
|
+
lg: 16,
|
|
54
|
+
xl: 20,
|
|
55
|
+
"2xl": 24,
|
|
56
|
+
"3xl": 28,
|
|
57
|
+
"4xl": 32,
|
|
58
|
+
full: 9999,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const Typography = {
|
|
62
|
+
display: {
|
|
63
|
+
fontSize: 112,
|
|
64
|
+
lineHeight: 112,
|
|
65
|
+
fontWeight: "200" as const,
|
|
66
|
+
letterSpacing: -4,
|
|
67
|
+
},
|
|
68
|
+
displayLarge: {
|
|
69
|
+
fontSize: 112,
|
|
70
|
+
lineHeight: 112,
|
|
71
|
+
fontWeight: "200" as const,
|
|
72
|
+
letterSpacing: -2,
|
|
73
|
+
},
|
|
74
|
+
displayMedium: {
|
|
75
|
+
fontSize: 48,
|
|
76
|
+
lineHeight: 56,
|
|
77
|
+
fontWeight: "200" as const,
|
|
78
|
+
},
|
|
79
|
+
h1: {
|
|
80
|
+
fontSize: 32,
|
|
81
|
+
lineHeight: 40,
|
|
82
|
+
fontWeight: "700" as const,
|
|
83
|
+
},
|
|
84
|
+
h2: {
|
|
85
|
+
fontSize: 28,
|
|
86
|
+
lineHeight: 36,
|
|
87
|
+
fontWeight: "700" as const,
|
|
88
|
+
},
|
|
89
|
+
h3: {
|
|
90
|
+
fontSize: 24,
|
|
91
|
+
lineHeight: 32,
|
|
92
|
+
fontWeight: "300" as const,
|
|
93
|
+
},
|
|
94
|
+
h4: {
|
|
95
|
+
fontSize: 20,
|
|
96
|
+
lineHeight: 28,
|
|
97
|
+
fontWeight: "600" as const,
|
|
98
|
+
},
|
|
99
|
+
title: {
|
|
100
|
+
fontSize: 18,
|
|
101
|
+
lineHeight: 24,
|
|
102
|
+
fontWeight: "700" as const,
|
|
103
|
+
},
|
|
104
|
+
body: {
|
|
105
|
+
fontSize: 16,
|
|
106
|
+
lineHeight: 24,
|
|
107
|
+
fontWeight: "400" as const,
|
|
108
|
+
},
|
|
109
|
+
bodyMedium: {
|
|
110
|
+
fontSize: 16,
|
|
111
|
+
lineHeight: 24,
|
|
112
|
+
fontWeight: "500" as const,
|
|
113
|
+
},
|
|
114
|
+
small: {
|
|
115
|
+
fontSize: 14,
|
|
116
|
+
lineHeight: 20,
|
|
117
|
+
fontWeight: "400" as const,
|
|
118
|
+
},
|
|
119
|
+
smallMedium: {
|
|
120
|
+
fontSize: 14,
|
|
121
|
+
lineHeight: 20,
|
|
122
|
+
fontWeight: "500" as const,
|
|
123
|
+
},
|
|
124
|
+
caption: {
|
|
125
|
+
fontSize: 12,
|
|
126
|
+
lineHeight: 16,
|
|
127
|
+
fontWeight: "400" as const,
|
|
128
|
+
},
|
|
129
|
+
captionMedium: {
|
|
130
|
+
fontSize: 12,
|
|
131
|
+
lineHeight: 16,
|
|
132
|
+
fontWeight: "500" as const,
|
|
133
|
+
},
|
|
134
|
+
label: {
|
|
135
|
+
fontSize: 14,
|
|
136
|
+
lineHeight: 20,
|
|
137
|
+
fontWeight: "500" as const,
|
|
138
|
+
letterSpacing: 2,
|
|
139
|
+
textTransform: "uppercase" as const,
|
|
140
|
+
},
|
|
141
|
+
labelSmall: {
|
|
142
|
+
fontSize: 12,
|
|
143
|
+
lineHeight: 16,
|
|
144
|
+
fontWeight: "500" as const,
|
|
145
|
+
letterSpacing: 1,
|
|
146
|
+
textTransform: "uppercase" as const,
|
|
147
|
+
},
|
|
148
|
+
labelTitle: {
|
|
149
|
+
fontSize: 14,
|
|
150
|
+
lineHeight: 20,
|
|
151
|
+
fontWeight: "700" as const,
|
|
152
|
+
letterSpacing: 2,
|
|
153
|
+
textTransform: "uppercase" as const,
|
|
154
|
+
},
|
|
155
|
+
link: {
|
|
156
|
+
fontSize: 16,
|
|
157
|
+
lineHeight: 24,
|
|
158
|
+
fontWeight: "400" as const,
|
|
159
|
+
},
|
|
160
|
+
stat: {
|
|
161
|
+
fontSize: 30,
|
|
162
|
+
lineHeight: 36,
|
|
163
|
+
fontWeight: "300" as const,
|
|
164
|
+
},
|
|
165
|
+
tiny: {
|
|
166
|
+
fontSize: 10,
|
|
167
|
+
lineHeight: 14,
|
|
168
|
+
fontWeight: "400" as const,
|
|
169
|
+
},
|
|
170
|
+
navLabel: {
|
|
171
|
+
fontSize: 10,
|
|
172
|
+
lineHeight: 14,
|
|
173
|
+
fontWeight: "500" as const,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
export type Theme = typeof Colors.light;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createContext, Dispatch, ReactNode, SetStateAction, useContext, useEffect, useState } from 'react';
|
|
2
|
+
import { ColorSchemeName, useColorScheme as useReactNativeColorScheme, Platform } from 'react-native';
|
|
3
|
+
|
|
4
|
+
const ColorSchemeContext = createContext<'light' | 'dark' | null | undefined>(null);
|
|
5
|
+
|
|
6
|
+
const ColorSchemeProvider = function ({ children }: { children?: ReactNode }) {
|
|
7
|
+
const systemColorScheme = useReactNativeColorScheme();
|
|
8
|
+
const [colorScheme, setColorScheme] = useState(systemColorScheme);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
setColorScheme(systemColorScheme);
|
|
12
|
+
}, [systemColorScheme]);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
function handleMessage(e: MessageEvent<{ event: string; colorScheme: ColorSchemeName; } | undefined>) {
|
|
16
|
+
if (e.data?.event === 'coze.workbench.colorScheme') {
|
|
17
|
+
const cs = e.data.colorScheme;
|
|
18
|
+
if (typeof cs === 'string' && typeof setColorScheme === 'function') {
|
|
19
|
+
setColorScheme(cs);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (Platform.OS === 'web') {
|
|
25
|
+
window.addEventListener('message', handleMessage, false);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return () => {
|
|
29
|
+
if (Platform.OS === 'web') {
|
|
30
|
+
window.removeEventListener('message', handleMessage, false);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, [setColorScheme]);
|
|
34
|
+
|
|
35
|
+
return <ColorSchemeContext.Provider value={colorScheme}>
|
|
36
|
+
{children}
|
|
37
|
+
</ColorSchemeContext.Provider>
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
function useColorScheme() {
|
|
41
|
+
const colorScheme = useContext(ColorSchemeContext);
|
|
42
|
+
return colorScheme;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
ColorSchemeProvider,
|
|
47
|
+
useColorScheme,
|
|
48
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Colors } from '@/constants/theme';
|
|
2
|
+
import { useColorScheme } from '@/hooks/useColorScheme';
|
|
3
|
+
|
|
4
|
+
enum COLOR_SCHEME_CHOICE {
|
|
5
|
+
FOLLOW_SYSTEM = 'follow-system', // 跟随系统自动变化
|
|
6
|
+
DARK = 'dark', // 固定为 dark 主题,不随系统变化
|
|
7
|
+
LIGHT = 'light', // 固定为 light 主题,不随系统变化
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const userPreferColorScheme: COLOR_SCHEME_CHOICE = COLOR_SCHEME_CHOICE.FOLLOW_SYSTEM;
|
|
11
|
+
|
|
12
|
+
function getTheme(colorScheme?: 'dark' | 'light' | null) {
|
|
13
|
+
const isDark = colorScheme === 'dark';
|
|
14
|
+
const theme = Colors[colorScheme ?? 'light'];
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
theme,
|
|
18
|
+
isDark,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function useTheme() {
|
|
23
|
+
const systemColorScheme = useColorScheme()
|
|
24
|
+
const colorScheme = userPreferColorScheme === COLOR_SCHEME_CHOICE.FOLLOW_SYSTEM ?
|
|
25
|
+
systemColorScheme :
|
|
26
|
+
userPreferColorScheme;
|
|
27
|
+
|
|
28
|
+
return getTheme(colorScheme);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
useTheme,
|
|
33
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const { getDefaultConfig } = require('expo/metro-config');
|
|
2
2
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
|
3
3
|
const connect = require('connect');
|
|
4
|
-
const { withUniwindConfig } = require('uniwind/metro');
|
|
5
4
|
|
|
6
5
|
const config = getDefaultConfig(__dirname);
|
|
7
6
|
|
|
@@ -27,6 +26,9 @@ config.resolver.blockList = [
|
|
|
27
26
|
// 4. 通用规则
|
|
28
27
|
/.*\/__tests__\/.*/, // 排除所有测试目录
|
|
29
28
|
/.*\.git\/.*/, // 排除 Git 目录
|
|
29
|
+
|
|
30
|
+
// 5. pnpm 临时目录(避免 ENOENT 错误)
|
|
31
|
+
/.*node_modules\/\.pnpm\/.*_tmp_\d+.*/,
|
|
30
32
|
];
|
|
31
33
|
|
|
32
34
|
const BACKEND_TARGET = 'http://localhost:9091';
|
|
@@ -119,10 +121,4 @@ config.server = {
|
|
|
119
121
|
},
|
|
120
122
|
};
|
|
121
123
|
|
|
122
|
-
module.exports =
|
|
123
|
-
// relative path to your global.css file (from previous step)
|
|
124
|
-
cssEntryFile: './global.css',
|
|
125
|
-
// (optional) path where we gonna auto-generate typings
|
|
126
|
-
// defaults to project's root
|
|
127
|
-
dtsFile: './uniwind-types.d.ts'
|
|
128
|
-
});
|
|
124
|
+
module.exports = config;
|
|
@@ -15,35 +15,35 @@
|
|
|
15
15
|
"preset": "jest-expo"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@expo/metro-runtime": "
|
|
19
|
-
"@expo/vector-icons": "^15.0.
|
|
20
|
-
"@react-native-async-storage/async-storage": "
|
|
21
|
-
"@react-native-community/datetimepicker": "
|
|
22
|
-
"@react-native-community/slider": "
|
|
23
|
-
"@react-native-masked-view/masked-view": "
|
|
24
|
-
"@react-native-picker/picker": "
|
|
18
|
+
"@expo/metro-runtime": "~6.1.2",
|
|
19
|
+
"@expo/vector-icons": "^15.0.3",
|
|
20
|
+
"@react-native-async-storage/async-storage": "2.2.0",
|
|
21
|
+
"@react-native-community/datetimepicker": "8.4.4",
|
|
22
|
+
"@react-native-community/slider": "5.0.1",
|
|
23
|
+
"@react-native-masked-view/masked-view": "0.3.2",
|
|
24
|
+
"@react-native-picker/picker": "2.11.1",
|
|
25
25
|
"@react-navigation/bottom-tabs": "^7.2.0",
|
|
26
26
|
"@react-navigation/native": "^7.0.14",
|
|
27
27
|
"dayjs": "^1.11.19",
|
|
28
|
-
"expo": "54.0.
|
|
29
|
-
"expo-auth-session": "
|
|
30
|
-
"expo-av": "~16.0.
|
|
31
|
-
"expo-blur": "~15.0.
|
|
28
|
+
"expo": "54.0.33",
|
|
29
|
+
"expo-auth-session": "~7.0.10",
|
|
30
|
+
"expo-av": "~16.0.8",
|
|
31
|
+
"expo-blur": "~15.0.8",
|
|
32
32
|
"expo-camera": "~17.0.10",
|
|
33
|
-
"expo-constants": "~18.0.
|
|
34
|
-
"expo-crypto": "
|
|
33
|
+
"expo-constants": "~18.0.13",
|
|
34
|
+
"expo-crypto": "~15.0.8",
|
|
35
35
|
"expo-file-system": "~19.0.21",
|
|
36
|
-
"expo-font": "~14.0.
|
|
37
|
-
"expo-haptics": "~15.0.
|
|
38
|
-
"expo-image": "
|
|
39
|
-
"expo-image-picker": "~17.0.
|
|
40
|
-
"expo-linear-gradient": "~15.0.
|
|
41
|
-
"expo-linking": "~8.0.
|
|
42
|
-
"expo-location": "~19.0.
|
|
43
|
-
"expo-router": "~6.0.
|
|
44
|
-
"expo-splash-screen": "~31.0.
|
|
45
|
-
"expo-status-bar": "~3.0.
|
|
46
|
-
"expo-symbols": "~1.0.
|
|
36
|
+
"expo-font": "~14.0.11",
|
|
37
|
+
"expo-haptics": "~15.0.8",
|
|
38
|
+
"expo-image": "~3.0.11",
|
|
39
|
+
"expo-image-picker": "~17.0.10",
|
|
40
|
+
"expo-linear-gradient": "~15.0.8",
|
|
41
|
+
"expo-linking": "~8.0.11",
|
|
42
|
+
"expo-location": "~19.0.8",
|
|
43
|
+
"expo-router": "~6.0.23",
|
|
44
|
+
"expo-splash-screen": "~31.0.13",
|
|
45
|
+
"expo-status-bar": "~3.0.9",
|
|
46
|
+
"expo-symbols": "~1.0.8",
|
|
47
47
|
"expo-system-ui": "~6.0.9",
|
|
48
48
|
"expo-web-browser": "~15.0.10",
|
|
49
49
|
"js-base64": "^3.7.7",
|
|
@@ -54,16 +54,14 @@
|
|
|
54
54
|
"react-native-gesture-handler": "~2.28.0",
|
|
55
55
|
"react-native-keyboard-aware-scroll-view": "^0.9.5",
|
|
56
56
|
"react-native-modal-datetime-picker": "18.0.0",
|
|
57
|
-
"react-native-reanimated": "~4.1.
|
|
57
|
+
"react-native-reanimated": "~4.1.1",
|
|
58
58
|
"react-native-safe-area-context": "~5.6.0",
|
|
59
59
|
"react-native-screens": "~4.16.0",
|
|
60
|
-
"react-native-svg": "15.
|
|
60
|
+
"react-native-svg": "15.12.1",
|
|
61
61
|
"react-native-toast-message": "^2.3.3",
|
|
62
|
-
"react-native-web": "
|
|
63
|
-
"react-native-webview": "
|
|
62
|
+
"react-native-web": "~0.21.0",
|
|
63
|
+
"react-native-webview": "13.15.0",
|
|
64
64
|
"react-native-worklets": "0.5.1",
|
|
65
|
-
"tailwindcss": "^4.1.18",
|
|
66
|
-
"uniwind": "^1.2.7",
|
|
67
65
|
"zod": "^4.2.1"
|
|
68
66
|
},
|
|
69
67
|
"devDependencies": {
|
|
@@ -88,7 +86,7 @@
|
|
|
88
86
|
"globals": "^16.1.0",
|
|
89
87
|
"http-proxy-middleware": "^3.0.5",
|
|
90
88
|
"jest": "^29.2.1",
|
|
91
|
-
"jest-expo": "~54.0.
|
|
89
|
+
"jest-expo": "~54.0.17",
|
|
92
90
|
"react-test-renderer": "19.1.0",
|
|
93
91
|
"tsx": "^4.21.0",
|
|
94
92
|
"typescript": "^5.8.3",
|