@coze-arch/cli 0.0.1-alpha.49a2d9 → 0.0.1-alpha.4c5c53
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/.coze +1 -1
- package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +19 -82
- package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +65 -84
- package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +2 -2
- package/lib/__templates__/expo/.cozeproj/scripts/prod_run.sh +2 -2
- package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +45 -0
- package/lib/__templates__/expo/README.md +24 -14
- package/lib/__templates__/expo/client/app/_layout.tsx +14 -14
- package/lib/__templates__/expo/client/app/index.tsx +1 -0
- package/lib/__templates__/expo/client/app.config.ts +65 -60
- package/lib/__templates__/expo/client/constants/theme.ts +22 -18
- package/lib/__templates__/expo/client/declarations.d.ts +5 -0
- package/lib/__templates__/expo/client/eslint.config.mjs +13 -10
- package/lib/__templates__/expo/client/hooks/useColorScheme.ts +34 -1
- package/lib/__templates__/expo/client/hooks/useTheme.ts +26 -6
- package/lib/__templates__/expo/client/package.json +1 -0
- package/lib/__templates__/expo/client/screens/demo/index.tsx +25 -0
- package/lib/__templates__/expo/client/screens/demo/styles.ts +28 -0
- package/lib/__templates__/expo/client/scripts/install-missing-deps.js +1 -0
- package/lib/__templates__/expo/client/utils/index.ts +22 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/names.js +2486 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/rule.js +155 -0
- package/lib/__templates__/expo/pnpm-lock.yaml +57 -5
- package/lib/__templates__/expo/server/build.js +21 -0
- package/lib/__templates__/expo/server/package.json +5 -3
- package/lib/__templates__/expo/server/src/index.ts +9 -2
- package/lib/__templates__/expo/template.config.js +1 -0
- package/lib/__templates__/nextjs/.coze +1 -0
- package/lib/__templates__/nextjs/_npmrc +1 -0
- package/lib/__templates__/nextjs/next.config.ts +11 -0
- package/lib/__templates__/nextjs/package.json +3 -2
- package/lib/__templates__/nextjs/pnpm-lock.yaml +13 -5
- package/lib/__templates__/nextjs/scripts/prepare.sh +9 -0
- package/lib/__templates__/nextjs/src/app/globals.css +10 -2
- package/lib/__templates__/nextjs/src/app/layout.tsx +1 -12
- package/lib/__templates__/nextjs/src/app/page.tsx +35 -23
- package/lib/__templates__/nextjs/src/components/ui/resizable.tsx +29 -22
- package/lib/__templates__/nextjs/src/components/ui/sidebar.tsx +228 -230
- package/lib/__templates__/nextjs/template.config.js +30 -0
- package/lib/__templates__/templates.json +61 -43
- package/lib/__templates__/vite/.coze +1 -0
- package/lib/__templates__/vite/_npmrc +1 -0
- package/lib/__templates__/vite/eslint.config.mjs +9 -0
- package/lib/__templates__/vite/package.json +5 -1
- package/lib/__templates__/vite/pnpm-lock.yaml +3481 -14
- package/lib/__templates__/vite/scripts/prepare.sh +9 -0
- package/lib/__templates__/vite/src/main.ts +1 -2
- package/lib/__templates__/vite/template.config.js +28 -4
- package/lib/cli.js +58 -27
- package/package.json +1 -1
- package/lib/__templates__/expo/client/app/index.ts +0 -1
- package/lib/__templates__/expo/client/screens/home/index.tsx +0 -50
- package/lib/__templates__/expo/client/screens/home/styles.ts +0 -60
- package/lib/__templates__/nextjs/.vscode/settings.json +0 -121
- package/lib/__templates__/vite/.vscode/settings.json +0 -7
|
@@ -1,71 +1,76 @@
|
|
|
1
1
|
import { ExpoConfig, ConfigContext } from 'expo/config';
|
|
2
2
|
|
|
3
|
+
const appName = process.env.EXPO_PUBLIC_COZE_PROJECT_NAME || '应用';
|
|
4
|
+
const projectId = process.env.EXPO_PUBLIC_COZE_PROJECT_ID;
|
|
5
|
+
const slugAppName = projectId ? `app${projectId}` : 'myapp';
|
|
6
|
+
|
|
3
7
|
export default ({ config }: ConfigContext): ExpoConfig => {
|
|
4
8
|
return {
|
|
5
9
|
...config,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
"name": appName,
|
|
11
|
+
"slug": slugAppName,
|
|
12
|
+
"version": "1.0.0",
|
|
13
|
+
"orientation": "portrait",
|
|
14
|
+
"icon": "./assets/images/icon.png",
|
|
15
|
+
"scheme": "myapp",
|
|
16
|
+
"userInterfaceStyle": "automatic",
|
|
17
|
+
"newArchEnabled": true,
|
|
18
|
+
"ios": {
|
|
19
|
+
"supportsTablet": true
|
|
20
|
+
},
|
|
21
|
+
"android": {
|
|
22
|
+
"adaptiveIcon": {
|
|
23
|
+
"foregroundImage": "./assets/images/adaptive-icon.png",
|
|
24
|
+
"backgroundColor": "#ffffff"
|
|
16
25
|
},
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
"package": `com.anonymous.x${projectId || '0'}`
|
|
27
|
+
},
|
|
28
|
+
"web": {
|
|
29
|
+
"bundler": "metro",
|
|
30
|
+
"output": "single",
|
|
31
|
+
"favicon": "./assets/images/favicon.png"
|
|
32
|
+
},
|
|
33
|
+
"plugins": [
|
|
34
|
+
process.env.EXPO_PUBLIC_BACKEND_BASE_URL ? [
|
|
35
|
+
"expo-router",
|
|
36
|
+
{
|
|
37
|
+
"origin": process.env.EXPO_PUBLIC_BACKEND_BASE_URL
|
|
38
|
+
}
|
|
39
|
+
] : 'expo-router',
|
|
40
|
+
[
|
|
41
|
+
"expo-splash-screen",
|
|
42
|
+
{
|
|
43
|
+
"image": "./assets/images/splash-icon.png",
|
|
44
|
+
"imageWidth": 200,
|
|
45
|
+
"resizeMode": "contain",
|
|
20
46
|
"backgroundColor": "#ffffff"
|
|
21
47
|
}
|
|
22
|
-
},
|
|
23
|
-
"web": {
|
|
24
|
-
"bundler": "metro",
|
|
25
|
-
"output": "single",
|
|
26
|
-
"favicon": "./assets/images/favicon.png"
|
|
27
|
-
},
|
|
28
|
-
"plugins": [
|
|
29
|
-
process.env.EXPO_PUBLIC_BACKEND_BASE_URL ? [
|
|
30
|
-
"expo-router",
|
|
31
|
-
{
|
|
32
|
-
"origin": process.env.EXPO_PUBLIC_BACKEND_BASE_URL
|
|
33
|
-
}
|
|
34
|
-
] : 'expo-router',
|
|
35
|
-
[
|
|
36
|
-
"expo-splash-screen",
|
|
37
|
-
{
|
|
38
|
-
"image": "./assets/images/splash-icon.png",
|
|
39
|
-
"imageWidth": 200,
|
|
40
|
-
"resizeMode": "contain",
|
|
41
|
-
"backgroundColor": "#ffffff"
|
|
42
|
-
}
|
|
43
|
-
],
|
|
44
|
-
[
|
|
45
|
-
"expo-image-picker",
|
|
46
|
-
{
|
|
47
|
-
"photosPermission": "允许${app_name}访问您的相册,以便您上传或保存图片。",
|
|
48
|
-
"cameraPermission": "允许${app_name}使用您的相机,以便您直接拍摄照片上传。",
|
|
49
|
-
"microphonePermission": "允许${app_name}访问您的麦克风,以便您拍摄带有声音的视频。"
|
|
50
|
-
}
|
|
51
|
-
],
|
|
52
|
-
[
|
|
53
|
-
"expo-location",
|
|
54
|
-
{
|
|
55
|
-
"locationWhenInUsePermission": "${app_name}需要访问您的位置以提供周边服务及导航功能。"
|
|
56
|
-
}
|
|
57
|
-
],
|
|
58
|
-
[
|
|
59
|
-
"expo-camera",
|
|
60
|
-
{
|
|
61
|
-
"cameraPermission": "${app_name}需要访问相机以拍摄照片和视频。",
|
|
62
|
-
"microphonePermission": "${app_name}需要访问麦克风以录制视频声音。",
|
|
63
|
-
"recordAudioAndroid": true
|
|
64
|
-
}
|
|
65
|
-
]
|
|
66
48
|
],
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
|
|
49
|
+
[
|
|
50
|
+
"expo-image-picker",
|
|
51
|
+
{
|
|
52
|
+
"photosPermission": `允许${appName}访问您的相册,以便您上传或保存图片。`,
|
|
53
|
+
"cameraPermission": `允许${appName}使用您的相机,以便您直接拍摄照片上传。`,
|
|
54
|
+
"microphonePermission": `允许${appName}访问您的麦克风,以便您拍摄带有声音的视频。`
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
[
|
|
58
|
+
"expo-location",
|
|
59
|
+
{
|
|
60
|
+
"locationWhenInUsePermission": `${appName}需要访问您的位置以提供周边服务及导航功能。`
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
[
|
|
64
|
+
"expo-camera",
|
|
65
|
+
{
|
|
66
|
+
"cameraPermission": `${appName}需要访问相机以拍摄照片和视频。`,
|
|
67
|
+
"microphonePermission": `${appName}需要访问麦克风以录制视频声音。`,
|
|
68
|
+
"recordAudioAndroid": true
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
],
|
|
72
|
+
"experiments": {
|
|
73
|
+
"typedRoutes": true
|
|
74
|
+
}
|
|
70
75
|
}
|
|
71
76
|
}
|
|
@@ -2,23 +2,21 @@ import { Platform, StyleSheet } from "react-native";
|
|
|
2
2
|
|
|
3
3
|
export const Colors = {
|
|
4
4
|
light: {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
textSecondary: "#374151",
|
|
5
|
+
textPrimary: "#1C1917",
|
|
6
|
+
textSecondary: "#78716c",
|
|
8
7
|
textMuted: "#9CA3AF",
|
|
9
8
|
textDisabled: "#D1D5DB",
|
|
10
9
|
placeholder: "#9CA3AF",
|
|
11
|
-
buttonText: "#FFFFFF",
|
|
12
10
|
tabIconDefault: "#9CA3AF",
|
|
13
|
-
tabIconSelected: "#
|
|
14
|
-
primary: "#
|
|
11
|
+
tabIconSelected: "#1C1917",
|
|
12
|
+
primary: "#1C1917",
|
|
15
13
|
accent: "#000000",
|
|
16
|
-
link: "#
|
|
14
|
+
link: "#1C1917",
|
|
17
15
|
success: "#16A34A",
|
|
18
16
|
warning: "#F59E0B",
|
|
19
17
|
error: "#DC2626",
|
|
20
18
|
info: "#2563EB",
|
|
21
|
-
backgroundRoot: "#
|
|
19
|
+
backgroundRoot: "#FFF",
|
|
22
20
|
backgroundDefault: "#F9FAFB",
|
|
23
21
|
backgroundSecondary: "#F3F4F6",
|
|
24
22
|
backgroundTertiary: "#E5E7EB",
|
|
@@ -27,25 +25,27 @@ export const Colors = {
|
|
|
27
25
|
divider: "#F3F4F6",
|
|
28
26
|
overlay: "rgba(0, 0, 0, 0.4)",
|
|
29
27
|
chartBackground: "rgba(249, 250, 251, 0.5)",
|
|
28
|
+
buttonPrimaryBackground: "#1C1917",
|
|
29
|
+
buttonPrimaryText: "#FFFFFF",
|
|
30
|
+
buttonSecondaryBackground: "#F3F4F6",
|
|
31
|
+
buttonSecondaryText: "#1C1917",
|
|
30
32
|
},
|
|
31
33
|
dark: {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
textSecondary: "#9BA1A6",
|
|
34
|
+
textPrimary: "#FAFAF9",
|
|
35
|
+
textSecondary: "#A8A29E",
|
|
35
36
|
textMuted: "#6F767E",
|
|
36
37
|
textDisabled: "#4A4D50",
|
|
37
38
|
placeholder: "#6F767E",
|
|
38
|
-
buttonText: "#FFFFFF",
|
|
39
39
|
tabIconDefault: "#6F767E",
|
|
40
|
-
tabIconSelected: "#
|
|
41
|
-
primary: "#
|
|
40
|
+
tabIconSelected: "#FAFAF9",
|
|
41
|
+
primary: "#FAFAF9",
|
|
42
42
|
accent: "#FFFFFF",
|
|
43
|
-
link: "#
|
|
43
|
+
link: "#FAFAF9",
|
|
44
44
|
success: "#30D158",
|
|
45
45
|
warning: "#FF9F0A",
|
|
46
46
|
error: "#FF453A",
|
|
47
47
|
info: "#64D2FF",
|
|
48
|
-
backgroundRoot: "#
|
|
48
|
+
backgroundRoot: "#0C0A09",
|
|
49
49
|
backgroundDefault: "#1C1C1E",
|
|
50
50
|
backgroundSecondary: "#2C2C2E",
|
|
51
51
|
backgroundTertiary: "#3A3A3C",
|
|
@@ -54,6 +54,10 @@ export const Colors = {
|
|
|
54
54
|
divider: "#2C2C2E",
|
|
55
55
|
overlay: "rgba(0, 0, 0, 0.6)",
|
|
56
56
|
chartBackground: "rgba(28, 28, 30, 0.5)",
|
|
57
|
+
buttonPrimaryBackground: "#FAFAF9",
|
|
58
|
+
buttonPrimaryText: "#0C0A09",
|
|
59
|
+
buttonSecondaryBackground: "#2C2C2E",
|
|
60
|
+
buttonSecondaryText: "#FAFAF9",
|
|
57
61
|
},
|
|
58
62
|
};
|
|
59
63
|
|
|
@@ -509,7 +513,7 @@ export const createThemedStyles = (theme: Theme) => {
|
|
|
509
513
|
...CommonStyles.scrollContent,
|
|
510
514
|
},
|
|
511
515
|
text: {
|
|
512
|
-
color: theme.
|
|
516
|
+
color: theme.textPrimary,
|
|
513
517
|
},
|
|
514
518
|
textPrimary: {
|
|
515
519
|
color: theme.textPrimary,
|
|
@@ -533,7 +537,7 @@ export const createThemedStyles = (theme: Theme) => {
|
|
|
533
537
|
color: theme.info,
|
|
534
538
|
},
|
|
535
539
|
textButton: {
|
|
536
|
-
color: theme.
|
|
540
|
+
color: theme.buttonPrimaryText,
|
|
537
541
|
},
|
|
538
542
|
avatar: {
|
|
539
543
|
...CommonStyles.avatar,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import js from
|
|
2
|
-
import globals from
|
|
3
|
-
import tseslint from
|
|
4
|
-
import pluginReact from
|
|
5
|
-
import reactHooks from
|
|
6
|
-
import regexp from
|
|
7
|
-
import pluginImport from
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
import tseslint from 'typescript-eslint';
|
|
4
|
+
import pluginReact from 'eslint-plugin-react';
|
|
5
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
6
|
+
import regexp from 'eslint-plugin-regexp';
|
|
7
|
+
import pluginImport from 'eslint-plugin-import';
|
|
8
|
+
import fontawesome6 from '../eslint-plugins/fontawesome6/index.js';
|
|
8
9
|
|
|
9
10
|
export default [
|
|
10
11
|
{
|
|
@@ -20,14 +21,14 @@ export default [
|
|
|
20
21
|
regexp.configs["flat/recommended"],
|
|
21
22
|
js.configs.recommended,
|
|
22
23
|
...tseslint.configs.recommended,
|
|
23
|
-
|
|
24
|
+
|
|
24
25
|
// React 的推荐配置
|
|
25
26
|
pluginReact.configs.flat.recommended,
|
|
26
27
|
pluginReact.configs.flat['jsx-runtime'],
|
|
27
28
|
reactHooks.configs.flat.recommended,
|
|
28
29
|
{
|
|
29
30
|
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
30
|
-
|
|
31
|
+
|
|
31
32
|
// 语言选项:设置全局变量
|
|
32
33
|
languageOptions: {
|
|
33
34
|
globals: {
|
|
@@ -52,6 +53,7 @@ export default [
|
|
|
52
53
|
|
|
53
54
|
plugins: {
|
|
54
55
|
import: pluginImport,
|
|
56
|
+
fontawesome6,
|
|
55
57
|
},
|
|
56
58
|
rules: {
|
|
57
59
|
// 关闭代码风格规则
|
|
@@ -70,6 +72,7 @@ export default [
|
|
|
70
72
|
'no-prototype-builtins': 'off',
|
|
71
73
|
'react/react-in-jsx-scope': 'off',
|
|
72
74
|
'react/jsx-uses-react': 'off',
|
|
75
|
+
'fontawesome6/valid-name': 'error',
|
|
73
76
|
},
|
|
74
77
|
},
|
|
75
78
|
|
|
@@ -91,7 +94,7 @@ export default [
|
|
|
91
94
|
// 在 .js 文件中关闭 TS 规则
|
|
92
95
|
'@typescript-eslint/no-require-imports': 'off',
|
|
93
96
|
// 在 Node.js 文件中允许 require
|
|
94
|
-
'@typescript-eslint/no-var-requires': 'off',
|
|
97
|
+
'@typescript-eslint/no-var-requires': 'off',
|
|
95
98
|
'no-undef': 'off',
|
|
96
99
|
},
|
|
97
100
|
},
|
|
@@ -1 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { ColorSchemeName, useColorScheme as useReactNativeColorScheme, Platform } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export function useColorScheme() {
|
|
5
|
+
const systemColorScheme = useReactNativeColorScheme();
|
|
6
|
+
const [colorScheme, setColorScheme] = useState<ColorSchemeName>(systemColorScheme);
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
setColorScheme(systemColorScheme);
|
|
10
|
+
}, [systemColorScheme])
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
function handleMessage(e: MessageEvent<{ event: string; colorScheme: ColorSchemeName; } | undefined>) {
|
|
14
|
+
if (e.data?.event === 'coze.workbench.colorScheme') {
|
|
15
|
+
const cs = e.data.colorScheme;
|
|
16
|
+
if (typeof cs === 'string') {
|
|
17
|
+
setColorScheme(cs);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (Platform.OS === 'web') {
|
|
23
|
+
window.addEventListener('message', handleMessage, false);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return () => {
|
|
27
|
+
if (Platform.OS === 'web') {
|
|
28
|
+
window.removeEventListener('message', handleMessage, false);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
return colorScheme;
|
|
34
|
+
}
|
|
@@ -1,13 +1,33 @@
|
|
|
1
|
-
import { Colors } from
|
|
2
|
-
import { useColorScheme } from
|
|
1
|
+
import { Colors } from '@/constants/theme';
|
|
2
|
+
import { useColorScheme } from '@/hooks/useColorScheme';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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'];
|
|
8
15
|
|
|
9
16
|
return {
|
|
10
17
|
theme,
|
|
11
18
|
isDark,
|
|
12
19
|
};
|
|
13
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
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { View, Text } from 'react-native';
|
|
2
|
+
import { Image } from 'expo-image';
|
|
3
|
+
|
|
4
|
+
import { useTheme } from '@/hooks/useTheme';
|
|
5
|
+
import { Screen } from '@/components/Screen';
|
|
6
|
+
import { styles } from './styles';
|
|
7
|
+
|
|
8
|
+
export default function DemoPage() {
|
|
9
|
+
const { theme, isDark } = useTheme();
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<Screen backgroundColor={theme.backgroundRoot} statusBarStyle={isDark ? 'light' : 'dark'}>
|
|
13
|
+
<View
|
|
14
|
+
style={styles.container}
|
|
15
|
+
>
|
|
16
|
+
<Image
|
|
17
|
+
style={styles.logo}
|
|
18
|
+
source="https://lf-coze-web-cdn.coze.cn/obj/eden-cn/lm-lgvj/ljhwZthlaukjlkulzlp/coze-coding/expo/coze-loading.gif"
|
|
19
|
+
></Image>
|
|
20
|
+
<Text style={{...styles.title, color: theme.textPrimary}}>APP 开发中</Text>
|
|
21
|
+
<Text style={{...styles.description, color: theme.textSecondary}}>即将为您呈现应用界面</Text>
|
|
22
|
+
</View>
|
|
23
|
+
</Screen>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Spacing } from '@/constants/theme';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export const styles = StyleSheet.create({
|
|
5
|
+
container: {
|
|
6
|
+
position: 'absolute',
|
|
7
|
+
top: 0,
|
|
8
|
+
left: 0,
|
|
9
|
+
width: '100%',
|
|
10
|
+
height: '100%',
|
|
11
|
+
display: 'flex',
|
|
12
|
+
flexDirection: 'column',
|
|
13
|
+
alignItems: 'center',
|
|
14
|
+
justifyContent: 'center',
|
|
15
|
+
},
|
|
16
|
+
logo: {
|
|
17
|
+
width: 130,
|
|
18
|
+
height: 109,
|
|
19
|
+
},
|
|
20
|
+
title: {
|
|
21
|
+
fontSize: 16,
|
|
22
|
+
fontWeight: 'bold',
|
|
23
|
+
},
|
|
24
|
+
description: {
|
|
25
|
+
fontSize: 14,
|
|
26
|
+
marginTop: Spacing.sm,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
@@ -1,9 +1,31 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
1
2
|
import dayjs from 'dayjs';
|
|
2
3
|
import utc from 'dayjs/plugin/utc';
|
|
3
4
|
dayjs.extend(utc);
|
|
4
5
|
|
|
5
6
|
const API_BASE = (process.env.EXPO_PUBLIC_API_BASE ?? '').replace(/\/$/, '');
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* 创建跨平台兼容的文件对象,用于 FormData.append()
|
|
10
|
+
* - Web 端返回 File 对象
|
|
11
|
+
* - 移动端返回 { uri, type, name } 对象(RN fetch 会自动处理)
|
|
12
|
+
* @param fileUri Expo 媒体库(如 expo-image-picker、expo-camera)返回的 uri
|
|
13
|
+
* @param fileName 上传时的文件名,如 'photo.jpg'
|
|
14
|
+
* @param mimeType 文件 MIME 类型,如 'image/jpeg'、'audio/mpeg'
|
|
15
|
+
*/
|
|
16
|
+
export async function createFormDataFile(
|
|
17
|
+
fileUri: string,
|
|
18
|
+
fileName: string,
|
|
19
|
+
mimeType: string
|
|
20
|
+
): Promise<File | { uri: string; type: string; name: string }> {
|
|
21
|
+
if (Platform.OS === 'web') {
|
|
22
|
+
const response = await fetch(fileUri);
|
|
23
|
+
const blob = await response.blob();
|
|
24
|
+
return new File([blob], fileName, { type: mimeType });
|
|
25
|
+
}
|
|
26
|
+
return { uri: fileUri, type: mimeType, name: fileName };
|
|
27
|
+
}
|
|
28
|
+
|
|
7
29
|
/**
|
|
8
30
|
* 构建文件或图片完整的URL
|
|
9
31
|
* @param url 相对或绝对路径
|