diff --git a/code/base-project/base-app/iconfont.json b/code/base-project/base-app/iconfont.json new file mode 100644 index 00000000..92f6b047 --- /dev/null +++ b/code/base-project/base-app/iconfont.json @@ -0,0 +1,8 @@ +{ + "symbol_url": "//at.alicdn.com/t/c/font_5056764_6s6rld1vyq.js", + "use_typescript": true, + "save_dir": "./src/components/iconfont", + "trim_icon_prefix": "icon", + "default_icon_size": 18, + "local_svgs": "" +} diff --git a/code/base-project/base-app/package.json b/code/base-project/base-app/package.json index fd31d590..cc8046e7 100644 --- a/code/base-project/base-app/package.json +++ b/code/base-project/base-app/package.json @@ -22,7 +22,7 @@ "expo-router": "~6.0.14", "expo-splash-screen": "~31.0.10", "expo-status-bar": "~3.0.8", - "lucide-react-native": "^0.552.0", + "lucide-react-native": "^0.510.0", "nativewind": "^4.2.1", "react": "19.1.0", "react-native": "0.81.5", @@ -30,13 +30,14 @@ "react-native-reanimated": "~4.1.3", "react-native-safe-area-context": "~5.6.1", "react-native-screens": "~4.16.0", - "react-native-svg": "15.12.1", + "react-native-svg": "15.12.0", "zustand": "^5.0.8" }, "devDependencies": { "@antfu/eslint-config": "^6.2.0", "@types/react": "~19.1.0", "eslint": "^9.38.0", + "react-native-iconfont-cli": "^2.2.4", "tailwindcss": "^3.4.17", "typescript": "~5.9.2" } diff --git a/code/base-project/base-app/pnpm-lock.yaml b/code/base-project/base-app/pnpm-lock.yaml index 1fdf003c..b87c6e84 100644 --- a/code/base-project/base-app/pnpm-lock.yaml +++ b/code/base-project/base-app/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: dependencies: '@gluestack-ui/core': specifier: ^3.0.12 - version: 3.0.12(@gluestack-ui/utils@3.0.11(react-dom@19.2.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + version: 3.0.12(@gluestack-ui/utils@3.0.11(react-dom@19.2.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) '@gluestack-ui/utils': specifier: ^3.0.11 version: 3.0.11(react-dom@19.2.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)) @@ -19,7 +19,7 @@ importers: version: 3.0.3 '@legendapp/motion': specifier: ^2.4.0 - version: 2.4.0(nativewind@4.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + version: 2.4.0(nativewind@4.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) '@react-native-async-storage/async-storage': specifier: 2.2.0 version: 2.2.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)) @@ -45,11 +45,11 @@ importers: specifier: ~3.0.8 version: 3.0.8(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) lucide-react-native: - specifier: ^0.552.0 - version: 0.552.0(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + specifier: ^0.510.0 + version: 0.510.0(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) nativewind: specifier: ^4.2.1 - version: 4.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)) + version: 4.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)) react: specifier: 19.1.0 version: 19.1.0 @@ -69,8 +69,8 @@ importers: specifier: ~4.16.0 version: 4.16.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-svg: - specifier: 15.12.1 - version: 15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + specifier: 15.12.0 + version: 15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) zustand: specifier: ^5.0.8 version: 5.0.8(@types/react@19.1.17)(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0)) @@ -84,6 +84,9 @@ importers: eslint: specifier: ^9.38.0 version: 9.39.0(jiti@1.21.7) + react-native-iconfont-cli: + specifier: ^2.2.4 + version: 2.2.4(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) tailwindcss: specifier: ^3.4.17 version: 3.4.18(yaml@2.8.1) @@ -2202,6 +2205,10 @@ packages: async-limiter@1.0.1: resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} + axios@0.19.2: + resolution: {integrity: sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==} + deprecated: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410 + babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2448,6 +2455,10 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + colors@1.4.0: + resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} + engines: {node: '>=0.1.90'} + commander@12.1.0: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} @@ -2542,6 +2553,14 @@ packages: supports-color: optional: true + debug@3.1.0: + resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -3124,6 +3143,10 @@ packages: flow-enums-runtime@0.0.6: resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + follow-redirects@1.5.10: + resolution: {integrity: sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==} + engines: {node: '>=4.0'} + fontfaceobserver@2.3.0: resolution: {integrity: sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==} @@ -3270,6 +3293,9 @@ packages: hyphenate-style-name@1.1.0: resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} + iconfont-parser@1.0.0: + resolution: {integrity: sha512-3RJceYHEjaqYyeDdfSAb1vP1x1Eb7ZtC9Xwetj+axm85sBlJU7HMvdNLVpwm/3g5eghYOdkQK+epUITZGAIqKQ==} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -3551,48 +3577,56 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-gnu@1.30.2: resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.27.0: resolution: {integrity: sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.27.0: resolution: {integrity: sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.27.0: resolution: {integrity: sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.27.0: resolution: {integrity: sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==} @@ -3674,10 +3708,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react-native@0.552.0: - resolution: {integrity: sha512-PWTUYyljcpHNql46wbaFk5lm0fdKg+2TnfsN/1KyuWw9McNNWZKkEqhz1k2n7wO/ZWB7jkM8QJCkZZT/SuQykw==} + lucide-react-native@0.510.0: + resolution: {integrity: sha512-Ggy6NyWNcb/Wp9I0Kguwab5FRjr3GYsxNi0Nmy+skur1yj9TKiF2vcXPL7zWkkcgqk8WWKiIvmN3CntWvaDR1w==} peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^16.5.1 || ^17.0.0 || ^18.0.0 react-native: '*' react-native-svg: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 @@ -3995,6 +4029,10 @@ packages: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} @@ -4406,6 +4444,14 @@ packages: react: '*' react-native: '*' + react-native-iconfont-cli@2.2.4: + resolution: {integrity: sha512-qTjfHG2f/sc3/YKWZJvIJk/SwiTu8C9/SvtoLxRX+GM/6pvOJq0ge6rcV3vTh4s3QJDuNDOD6+a4hGD6vv2vSg==} + hasBin: true + peerDependencies: + react: '*' + react-native: '*' + react-native-svg: '>=9.7.0' + react-native-is-edge-to-edge@1.2.1: resolution: {integrity: sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q==} peerDependencies: @@ -4432,8 +4478,8 @@ packages: react: '*' react-native: '*' - react-native-svg@15.12.1: - resolution: {integrity: sha512-vCuZJDf8a5aNC2dlMovEv4Z0jjEUET53lm/iILFnFewa15b4atjVxU6Wirm6O9y6dEsdjDZVD7Q3QM4T1wlI8g==} + react-native-svg@15.12.0: + resolution: {integrity: sha512-iE25PxIJ6V0C6krReLquVw6R0QTsRTmEQc4K2Co3P6zsimU/jltcDBKYDy1h/5j9S/fqmMeXnpM+9LEWKJKI6A==} peerDependencies: react: '*' react-native: '*' @@ -4927,6 +4973,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -5174,6 +5223,10 @@ packages: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} + xml2js@0.4.23: + resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} + engines: {node: '>=4.0.0'} + xml2js@0.6.0: resolution: {integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==} engines: {node: '>=4.0.0'} @@ -6360,13 +6413,13 @@ snapshots: dependencies: tslib: 2.8.1 - '@gluestack-ui/core@3.0.12(@gluestack-ui/utils@3.0.11(react-dom@19.2.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': + '@gluestack-ui/core@3.0.12(@gluestack-ui/utils@3.0.11(react-dom@19.2.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': dependencies: '@gluestack-ui/utils': 3.0.11(react-dom@19.2.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)) react: 19.1.0 react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) react-native-safe-area-context: 5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) - react-native-svg: 15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + react-native-svg: 15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-web: 0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0) '@gluestack-ui/utils@3.0.11(react-dom@19.2.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1))': @@ -6517,10 +6570,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@legendapp/motion@2.4.0(nativewind@4.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': + '@legendapp/motion@2.4.0(nativewind@4.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': dependencies: '@legendapp/tools': 2.0.1(react@19.1.0) - nativewind: 4.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)) + nativewind: 4.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)) react: 19.1.0 react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) @@ -8212,6 +8265,12 @@ snapshots: async-limiter@1.0.1: {} + axios@0.19.2: + dependencies: + follow-redirects: 1.5.10 + transitivePeerDependencies: + - supports-color + babel-jest@29.7.0(@babel/core@7.28.5): dependencies: '@babel/core': 7.28.5 @@ -8516,6 +8575,8 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + colors@1.4.0: {} + commander@12.1.0: {} commander@2.20.3: {} @@ -8612,6 +8673,10 @@ snapshots: dependencies: ms: 2.0.0 + debug@3.1.0: + dependencies: + ms: 2.0.0 + debug@3.2.7: dependencies: ms: 2.1.3 @@ -9271,6 +9336,12 @@ snapshots: flow-enums-runtime@0.0.6: {} + follow-redirects@1.5.10: + dependencies: + debug: 3.1.0 + transitivePeerDependencies: + - supports-color + fontfaceobserver@2.3.0: {} foreground-child@3.3.1: @@ -9402,6 +9473,15 @@ snapshots: hyphenate-style-name@1.1.0: {} + iconfont-parser@1.0.0: + dependencies: + axios: 0.19.2 + colors: 1.4.0 + tslib: 1.14.1 + xml2js: 0.4.23 + transitivePeerDependencies: + - supports-color + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -9773,11 +9853,11 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react-native@0.552.0(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): + lucide-react-native@0.510.0(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: react: 19.1.0 react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) - react-native-svg: 15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + react-native-svg: 15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) magic-string@0.30.21: dependencies: @@ -10499,6 +10579,10 @@ snapshots: dependencies: minipass: 7.1.2 + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + mkdirp@1.0.4: {} mlly@1.8.0: @@ -10520,11 +10604,11 @@ snapshots: nanoid@3.3.11: {} - nativewind@4.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)): + nativewind@4.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)): dependencies: comment-json: 4.4.1 debug: 4.4.3 - react-native-css-interop: 0.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)) + react-native-css-interop: 0.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)) tailwindcss: 3.4.18(yaml@2.8.1) transitivePeerDependencies: - react @@ -10894,7 +10978,7 @@ snapshots: react-is@19.2.0: {} - react-native-css-interop@0.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)): + react-native-css-interop@0.2.1(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)): dependencies: '@babel/helper-module-imports': 7.27.1 '@babel/traverse': 7.28.5 @@ -10908,7 +10992,7 @@ snapshots: tailwindcss: 3.4.18(yaml@2.8.1) optionalDependencies: react-native-safe-area-context: 5.6.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) - react-native-svg: 15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + react-native-svg: 15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) transitivePeerDependencies: - supports-color @@ -10920,6 +11004,21 @@ snapshots: react: 19.1.0 react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) + react-native-iconfont-cli@2.2.4(react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): + dependencies: + colors: 1.4.0 + glob: 7.2.3 + iconfont-parser: 1.0.0 + lodash: 4.17.21 + minimist: 1.2.8 + mkdirp: 0.5.6 + react: 19.1.0 + react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) + react-native-svg: 15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + tslib: 1.14.1 + transitivePeerDependencies: + - supports-color + react-native-is-edge-to-edge@1.2.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: react: 19.1.0 @@ -10947,7 +11046,7 @@ snapshots: react-native-is-edge-to-edge: 1.2.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) warn-once: 0.1.1 - react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): + react-native-svg@15.12.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: css-select: 5.2.2 css-tree: 1.1.3 @@ -11518,6 +11617,8 @@ snapshots: ts-interface-checker@0.1.13: {} + tslib@1.14.1: {} + tslib@2.8.1: {} type-check@0.4.0: @@ -11713,6 +11814,11 @@ snapshots: xml-name-validator@4.0.0: {} + xml2js@0.4.23: + dependencies: + sax: 1.4.1 + xmlbuilder: 11.0.1 + xml2js@0.6.0: dependencies: sax: 1.4.1 diff --git a/code/base-project/base-app/src/app/(tabs)/_layout.tsx b/code/base-project/base-app/src/app/(tabs)/_layout.tsx index d48dbc44..759ce90d 100644 --- a/code/base-project/base-app/src/app/(tabs)/_layout.tsx +++ b/code/base-project/base-app/src/app/(tabs)/_layout.tsx @@ -1,5 +1,5 @@ -import type { TabbarItem } from '@/components/custom/tabbar' -import CustomTabbar from '@/components/custom/tabbar' +import type { TabbarItem } from '@/components/custom/Tabbar' +import CustomTabbar from '@/components/custom/Tabbar' import { useToast } from '@/utils/toast' export default function TabsLayout() { diff --git a/code/base-project/base-app/src/app/+not-found.tsx b/code/base-project/base-app/src/app/+not-found.tsx index e99a3c70..1a0539f1 100644 --- a/code/base-project/base-app/src/app/+not-found.tsx +++ b/code/base-project/base-app/src/app/+not-found.tsx @@ -1,6 +1,6 @@ import { router, Stack } from 'expo-router' import { ArrowLeft } from 'lucide-react-native' -import { EmptyState } from '@/components/common/empty-status' +import { EmptyState } from '@/components/common/EmptyStatus' export default function NotFound() { return ( diff --git a/code/base-project/base-app/src/app/_layout.tsx b/code/base-project/base-app/src/app/_layout.tsx index 7b26423f..a9eb8566 100644 --- a/code/base-project/base-app/src/app/_layout.tsx +++ b/code/base-project/base-app/src/app/_layout.tsx @@ -6,7 +6,7 @@ import * as SplashScreen from 'expo-splash-screen' import { StatusBar } from 'expo-status-bar' import { RefreshCw } from 'lucide-react-native' import { useEffect, useState } from 'react' -import { EmptyState } from '@/components/common/empty-status' +import EmptyState from '@/components/common/EmptyStatus' import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider' import { useUserStore } from '@/store/user' import { ToastProviderWrapper } from '@/utils/toast' @@ -56,7 +56,7 @@ export default function RootLayout() { // 如果没有 token,则跳转登录页 if (token === null) { - // router.replace('/auth/login') + router.replace('/auth') } } }, [fontsLoaded, storeLoaded, token]) @@ -81,7 +81,7 @@ export default function RootLayout() { options={{ headerShown: false }} /> + + + ) +} diff --git a/code/base-project/base-app/src/app/auth/index.tsx b/code/base-project/base-app/src/app/auth/index.tsx new file mode 100644 index 00000000..b63cf3e8 --- /dev/null +++ b/code/base-project/base-app/src/app/auth/index.tsx @@ -0,0 +1,42 @@ +import { useRouter } from 'expo-router' +import { Image, Text, View } from 'react-native' +import { Button, ButtonText } from '@/components/ui/button' + +export default function AuthIndex() { + const router = useRouter() + + function toPath(url: string) { + router.push(url) + } + + return ( + + + + + + + ONEAO + + + + + + + + + ) +} diff --git a/code/base-project/base-app/src/app/auth/login.tsx b/code/base-project/base-app/src/app/auth/login.tsx index 987313e3..3d2fef7e 100644 --- a/code/base-project/base-app/src/app/auth/login.tsx +++ b/code/base-project/base-app/src/app/auth/login.tsx @@ -1,12 +1,141 @@ -import { Text, View } from 'react-native' -import CustomLayout from '@/components/custom/layout' +import { Lock, UserRound } from 'lucide-react-native' +import { useState } from 'react' +import { Image, Text, View } from 'react-native' +import { IconQq, IconWeixin, IconZhiwen } from '@/components/iconfont' +import { Button, ButtonText } from '@/components/ui/button' +import { + Checkbox, + CheckboxIcon, + CheckboxIndicator, + CheckboxLabel, +} from '@/components/ui/checkbox' +import { Divider } from '@/components/ui/divider' +import { + FormControl, + FormControlLabel, + FormControlLabelText, +} from '@/components/ui/form-control' +import { CheckIcon, EyeIcon, EyeOffIcon } from '@/components/ui/icon' +import { Input, InputField, InputIcon, InputSlot } from '@/components/ui/input' +import { useToast } from '@/utils/toast' + +interface LoginForm { + username: string + password: string + rememberMe?: boolean + socialType?: 'qq' | 'weixin' | 'fingerprint' +} export default function AuthLogin() { + const toast = useToast() + + const [showPassword, setShowPassword] = useState(false) + const [form, setForm] = useState({ + username: '', + password: '', + rememberMe: true, + }) + + const defaultLogin = () => { + if (form.username === '') { + toast.show({ + title: '账号不能为空!', + action: 'error', + }) + return + } + if (form.password === '') { + toast.show({ + title: '密码不能为空!', + action: 'error', + }) + } + // + } + return ( - - - 登录 + + + + + + + 账号 + + + + + + setForm(prev => ({ ...prev, username: text }))} + /> + + + + + + 密码 + + + + + + setForm(prev => ({ ...prev, password: text }))} + /> + setShowPassword(prev => !prev)}> + + + + + + + + setForm(prev => ({ ...prev, rememberMe: checked }))} + > + + + + 记住我 + + + + 忘记密码? + - + + + + + + + + + 社交账号 + + + + + + + + + + + + + ) } diff --git a/code/base-project/base-app/src/app/auth/register.tsx b/code/base-project/base-app/src/app/auth/register.tsx new file mode 100644 index 00000000..bc864bfa --- /dev/null +++ b/code/base-project/base-app/src/app/auth/register.tsx @@ -0,0 +1,10 @@ +import { Text, View } from 'react-native' + +export default function Register() { + return ( + + 测试内容 + + + ) +} diff --git a/code/base-project/base-app/src/components/common/empty-status.tsx b/code/base-project/base-app/src/components/common/EmptyStatus.tsx similarity index 96% rename from code/base-project/base-app/src/components/common/empty-status.tsx rename to code/base-project/base-app/src/components/common/EmptyStatus.tsx index 707633ce..dfedd3e7 100644 --- a/code/base-project/base-app/src/components/common/empty-status.tsx +++ b/code/base-project/base-app/src/components/common/EmptyStatus.tsx @@ -10,7 +10,7 @@ interface EmptyStateProps { onButtonPress: () => void } -export function EmptyState({ +export default function EmptyState({ image, title, description, diff --git a/code/base-project/base-app/src/components/custom/StepLayout.tsx b/code/base-project/base-app/src/components/custom/StepLayout.tsx new file mode 100644 index 00000000..7883d388 --- /dev/null +++ b/code/base-project/base-app/src/components/custom/StepLayout.tsx @@ -0,0 +1,79 @@ +import { Ionicons } from '@expo/vector-icons' +import { usePathname, useRouter } from 'expo-router' +import { Image, Pressable, ScrollView, Text, View } from 'react-native' +import Animated, { SlideInRight } from 'react-native-reanimated' +import { SafeAreaView } from 'react-native-safe-area-context' + +export interface StepLayoutItem { + path: string // 步骤路径 + title?: string // 步骤标题 + onBack?: () => void // 可选的返回按钮回调 + showHearder?: boolean // 是否显示 header,单独放在每个步骤中 + headerRight?: React.ReactNode +} + +interface StepLayoutProps { + steps: StepLayoutItem[] // 步骤列表 + children: React.ReactNode // 子内容 + showHearder?: boolean // 控制整体 header 是否显示 +} + +export default function StepLayout({ steps, children, showHearder = true }: StepLayoutProps) { + const router = useRouter() + const pathname = usePathname() + + // 是否能返回 + const canGoBack = router.canGoBack() + + // 当前步骤 + const currentStep = steps.find(step => step.path === pathname) ?? steps[0] + + // 是否显示header + const headerVisible = showHearder !== false && currentStep.showHearder !== false + + return ( + + + {headerVisible && ( + + router.back())) : undefined} + style={{ opacity: canGoBack ? 1 : 0 }} + > + + + + + {currentStep.title} + + + + {currentStep.headerRight ?? ( + + )} + + + )} + + + {children} + + + + + ) +} diff --git a/code/base-project/base-app/src/components/custom/layout.tsx b/code/base-project/base-app/src/components/custom/layout.tsx deleted file mode 100644 index 4c007115..00000000 --- a/code/base-project/base-app/src/components/custom/layout.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { useRouter } from 'expo-router' -// components/Layout.tsx -import { Pressable, Text, View } from 'react-native' -import { SafeAreaView } from 'react-native-safe-area-context' - -interface LayoutProps { - title: string - children: React.ReactNode - showBack?: boolean - right?: React.ReactNode -} - -export default function CustomLayout({ title, children, showBack = true, right }: LayoutProps) { - const router = useRouter() - - return ( - - {children} - - ) -} diff --git a/code/base-project/base-app/src/components/custom/tabbar.tsx b/code/base-project/base-app/src/components/custom/tabbar.tsx index 313a8e21..e189fe36 100644 --- a/code/base-project/base-app/src/components/custom/tabbar.tsx +++ b/code/base-project/base-app/src/components/custom/tabbar.tsx @@ -4,7 +4,7 @@ import { icons } from 'lucide-react-native' import { useEffect, useState } from 'react' import { Pressable, View } from 'react-native' import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler' -import Animated, { SlideInLeft, SlideInRight, SlideOutLeft, SlideOutRight, useAnimatedStyle, useSharedValue, withSequence, withTiming } from 'react-native-reanimated' +import Animated, { SlideInLeft, SlideInRight, useAnimatedStyle, useSharedValue, withSequence, withTiming } from 'react-native-reanimated' import { scheduleOnRN } from 'react-native-worklets' interface AppTabbarProps { diff --git a/code/base-project/base-app/src/components/iconfont/IconQq.tsx b/code/base-project/base-app/src/components/iconfont/IconQq.tsx new file mode 100644 index 00000000..9ddae151 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconQq.tsx @@ -0,0 +1,69 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +// ✅ 关键改动:排除 GProps.color +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconQq: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + + + + + + + + + + ); +}; + +export default React.memo(IconQq); diff --git a/code/base-project/base-app/src/components/iconfont/IconWeixin.tsx b/code/base-project/base-app/src/components/iconfont/IconWeixin.tsx new file mode 100644 index 00000000..c5ad2318 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconWeixin.tsx @@ -0,0 +1,37 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +// ✅ 关键改动:排除 GProps.color +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconWeixin: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + + ); +}; + +export default React.memo(IconWeixin); diff --git a/code/base-project/base-app/src/components/iconfont/IconZhiwen.tsx b/code/base-project/base-app/src/components/iconfont/IconZhiwen.tsx new file mode 100644 index 00000000..6a47ab8a --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconZhiwen.tsx @@ -0,0 +1,45 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +// ✅ 关键改动:排除 GProps.color +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconZhiwen: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + + + + ); +}; + +export default React.memo(IconZhiwen); diff --git a/code/base-project/base-app/src/components/iconfont/helper.ts b/code/base-project/base-app/src/components/iconfont/helper.ts new file mode 100644 index 00000000..60d6d713 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/helper.ts @@ -0,0 +1,12 @@ +/* tslint:disable */ +/* eslint-disable */ + +export const getIconColor = (color: string | string[] | undefined, index: number, defaultColor: string) => { + return color + ? ( + typeof color === 'string' + ? color + : color[index] || defaultColor + ) + : defaultColor; +}; diff --git a/code/base-project/base-app/src/components/iconfont/index.tsx b/code/base-project/base-app/src/components/iconfont/index.tsx new file mode 100644 index 00000000..e3452bdc --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/index.tsx @@ -0,0 +1,37 @@ +/* tslint:disable */ +/* eslint-disable */ + +import React, { FunctionComponent } from 'react'; +import { ViewProps } from 'react-native'; +import { GProps } from 'react-native-svg'; +import IconWeixin from './IconWeixin'; +import IconZhiwen from './IconZhiwen'; +import IconQq from './IconQq'; +export { default as IconWeixin } from './IconWeixin'; +export { default as IconZhiwen } from './IconZhiwen'; +export { default as IconQq } from './IconQq'; + +export type IconNames = 'weixin' | 'zhiwen' | 'QQ'; + +interface Props extends GProps, ViewProps { + name: IconNames; + size?: number; + color?: string | string[]; +} + +let IconFont: FunctionComponent = ({ name, ...rest }) => { + switch (name) { + case 'weixin': + return ; + case 'zhiwen': + return ; + case 'QQ': + return ; + } + + return null; +}; + +IconFont = React.memo ? React.memo(IconFont) : IconFont; + +export default IconFont; diff --git a/code/base-project/base-app/src/components/ui/checkbox/index.tsx b/code/base-project/base-app/src/components/ui/checkbox/index.tsx new file mode 100644 index 00000000..a6bbcab8 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/checkbox/index.tsx @@ -0,0 +1,242 @@ +'use client'; +import React from 'react'; +import { createCheckbox } from '@gluestack-ui/core/checkbox/creator'; +import { View, Pressable, Text, Platform } from 'react-native'; +import type { TextProps, ViewProps } from 'react-native'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { + PrimitiveIcon, + IPrimitiveIcon, + UIIcon, +} from '@gluestack-ui/core/icon/creator'; +import { + withStyleContext, + useStyleContext, +} from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; + +const IndicatorWrapper = React.forwardRef< + React.ComponentRef, + ViewProps +>(function IndicatorWrapper({ ...props }, ref) { + return ; +}); + +const LabelWrapper = React.forwardRef< + React.ComponentRef, + TextProps +>(function LabelWrapper({ ...props }, ref) { + return ; +}); + +const IconWrapper = React.forwardRef< + React.ComponentRef, + IPrimitiveIcon +>(function IconWrapper({ ...props }, ref) { + return ; +}); + +const SCOPE = 'CHECKBOX'; +const UICheckbox = createCheckbox({ + // @ts-expect-error : internal implementation for r-19/react-native-web + Root: + Platform.OS === 'web' + ? withStyleContext(View, SCOPE) + : withStyleContext(Pressable, SCOPE), + Group: View, + Icon: IconWrapper, + Label: LabelWrapper, + Indicator: IndicatorWrapper, +}); + +cssInterop(PrimitiveIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: 'classNameColor', + stroke: true, + }, + }, +}); + +const checkboxStyle = tva({ + base: 'group/checkbox flex-row items-center justify-start web:cursor-pointer data-[disabled=true]:cursor-not-allowed', + variants: { + size: { + lg: 'gap-2', + md: 'gap-2', + sm: 'gap-1.5', + }, + }, +}); + +const checkboxIndicatorStyle = tva({ + base: 'justify-center items-center border-outline-400 bg-transparent rounded web:data-[focus-visible=true]:outline-none web:data-[focus-visible=true]:ring-2 web:data-[focus-visible=true]:ring-indicator-primary data-[checked=true]:bg-primary-600 data-[checked=true]:border-primary-600 data-[hover=true]:data-[checked=false]:border-outline-500 data-[hover=true]:bg-transparent data-[hover=true]:data-[invalid=true]:border-error-700 data-[hover=true]:data-[checked=true]:bg-primary-700 data-[hover=true]:data-[checked=true]:border-primary-700 data-[hover=true]:data-[checked=true]:data-[disabled=true]:border-primary-600 data-[hover=true]:data-[checked=true]:data-[disabled=true]:bg-primary-600 data-[hover=true]:data-[checked=true]:data-[disabled=true]:opacity-40 data-[hover=true]:data-[checked=true]:data-[disabled=true]:data-[invalid=true]:border-error-700 data-[hover=true]:data-[disabled=true]:border-outline-400 data-[hover=true]:data-[disabled=true]:data-[invalid=true]:border-error-700 data-[active=true]:data-[checked=true]:bg-primary-800 data-[active=true]:data-[checked=true]:border-primary-800 data-[invalid=true]:border-error-700 data-[disabled=true]:opacity-40', + parentVariants: { + size: { + lg: 'w-6 h-6 border-[3px]', + md: 'w-5 h-5 border-2', + sm: 'w-4 h-4 border-2', + }, + }, +}); + +const checkboxLabelStyle = tva({ + base: 'text-typography-600 data-[checked=true]:text-typography-900 data-[hover=true]:text-typography-900 data-[hover=true]:data-[checked=true]:text-typography-900 data-[hover=true]:data-[checked=true]:data-[disabled=true]:text-typography-900 data-[hover=true]:data-[disabled=true]:text-typography-400 data-[active=true]:text-typography-900 data-[active=true]:data-[checked=true]:text-typography-900 data-[disabled=true]:opacity-40 web:select-none', + parentVariants: { + size: { + lg: 'text-lg', + md: 'text-base', + sm: 'text-sm', + }, + }, +}); + +const checkboxIconStyle = tva({ + base: 'text-typography-50 fill-none', + + parentVariants: { + size: { + sm: 'h-3 w-3', + md: 'h-4 w-4', + lg: 'h-5 w-5', + }, + }, +}); + +const CheckboxGroup = UICheckbox.Group; + +type ICheckboxProps = React.ComponentPropsWithoutRef & + VariantProps; + +const Checkbox = React.forwardRef< + React.ComponentRef, + ICheckboxProps +>(function Checkbox({ className, size = 'md', ...props }, ref) { + return ( + + ); +}); + +type ICheckboxIndicatorProps = React.ComponentPropsWithoutRef< + typeof UICheckbox.Indicator +> & + VariantProps; + +const CheckboxIndicator = React.forwardRef< + React.ComponentRef, + ICheckboxIndicatorProps +>(function CheckboxIndicator({ className, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + return ( + + ); +}); + +type ICheckboxLabelProps = React.ComponentPropsWithoutRef< + typeof UICheckbox.Label +> & + VariantProps; +const CheckboxLabel = React.forwardRef< + React.ComponentRef, + ICheckboxLabelProps +>(function CheckboxLabel({ className, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + return ( + + ); +}); + +type ICheckboxIconProps = React.ComponentPropsWithoutRef< + typeof UICheckbox.Icon +> & + VariantProps; + +const CheckboxIcon = React.forwardRef< + React.ComponentRef, + ICheckboxIconProps +>(function CheckboxIcon({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + + return ( + + ); +}); + +Checkbox.displayName = 'Checkbox'; +CheckboxIndicator.displayName = 'CheckboxIndicator'; +CheckboxLabel.displayName = 'CheckboxLabel'; +CheckboxIcon.displayName = 'CheckboxIcon'; + +export { + Checkbox, + CheckboxIndicator, + CheckboxLabel, + CheckboxIcon, + CheckboxGroup, +}; diff --git a/code/base-project/base-app/src/components/ui/divider/index.tsx b/code/base-project/base-app/src/components/ui/divider/index.tsx new file mode 100644 index 00000000..f8a73063 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/divider/index.tsx @@ -0,0 +1,40 @@ +'use client'; +import React from 'react'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { Platform, View } from 'react-native'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; + +const dividerStyle = tva({ + base: 'bg-background-200', + variants: { + orientation: { + vertical: 'w-px h-full', + horizontal: 'h-px w-full', + }, + }, +}); + +type IUIDividerProps = React.ComponentPropsWithoutRef & + VariantProps; + +const Divider = React.forwardRef< + React.ComponentRef, + IUIDividerProps +>(function Divider({ className, orientation = 'horizontal', ...props }, ref) { + return ( + + ); +}); + +Divider.displayName = 'Divider'; + +export { Divider }; diff --git a/code/base-project/base-app/src/components/ui/form-control/index.tsx b/code/base-project/base-app/src/components/ui/form-control/index.tsx new file mode 100644 index 00000000..a9056b55 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/form-control/index.tsx @@ -0,0 +1,468 @@ +'use client'; +import { Text, View } from 'react-native'; +import React from 'react'; +import { createFormControl } from '@gluestack-ui/core/form-control/creator'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { + withStyleContext, + useStyleContext, +} from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'; + +const SCOPE = 'FORM_CONTROL'; + +const formControlStyle = tva({ + base: 'flex flex-col', + variants: { + size: { + sm: '', + md: '', + lg: '', + }, + }, +}); + +const formControlErrorIconStyle = tva({ + base: 'text-error-700 fill-none', + variants: { + size: { + '2xs': 'h-3 w-3', + 'xs': 'h-3.5 w-3.5', + 'sm': 'h-4 w-4', + 'md': 'h-[18px] w-[18px]', + 'lg': 'h-5 w-5', + 'xl': 'h-6 w-6', + }, + }, +}); + +const formControlErrorStyle = tva({ + base: 'flex flex-row justify-start items-center mt-1 gap-1', +}); + +const formControlErrorTextStyle = tva({ + base: 'text-error-700', + variants: { + isTruncated: { + true: 'web:truncate', + }, + bold: { + true: 'font-bold', + }, + underline: { + true: 'underline', + }, + strikeThrough: { + true: 'line-through', + }, + size: { + '2xs': 'text-2xs', + 'xs': 'text-xs', + 'sm': 'text-sm', + 'md': 'text-base', + 'lg': 'text-lg', + 'xl': 'text-xl', + '2xl': 'text-2xl', + '3xl': 'text-3xl', + '4xl': 'text-4xl', + '5xl': 'text-5xl', + '6xl': 'text-6xl', + }, + sub: { + true: 'text-xs', + }, + italic: { + true: 'italic', + }, + highlight: { + true: 'bg-yellow-500', + }, + }, +}); + +const formControlHelperStyle = tva({ + base: 'flex flex-row justify-start items-center mt-1', +}); + +const formControlHelperTextStyle = tva({ + base: 'text-typography-500', + variants: { + isTruncated: { + true: 'web:truncate', + }, + bold: { + true: 'font-bold', + }, + underline: { + true: 'underline', + }, + strikeThrough: { + true: 'line-through', + }, + size: { + '2xs': 'text-2xs', + 'xs': 'text-xs', + 'sm': 'text-xs', + 'md': 'text-sm', + 'lg': 'text-base', + 'xl': 'text-xl', + '2xl': 'text-2xl', + '3xl': 'text-3xl', + '4xl': 'text-4xl', + '5xl': 'text-5xl', + '6xl': 'text-6xl', + }, + sub: { + true: 'text-xs', + }, + italic: { + true: 'italic', + }, + highlight: { + true: 'bg-yellow-500', + }, + }, +}); + +const formControlLabelStyle = tva({ + base: 'flex flex-row justify-start items-center mb-1', +}); + +const formControlLabelTextStyle = tva({ + base: 'font-medium text-typography-900', + variants: { + isTruncated: { + true: 'web:truncate', + }, + bold: { + true: 'font-bold', + }, + underline: { + true: 'underline', + }, + strikeThrough: { + true: 'line-through', + }, + size: { + '2xs': 'text-2xs', + 'xs': 'text-xs', + 'sm': 'text-sm', + 'md': 'text-base', + 'lg': 'text-lg', + 'xl': 'text-xl', + '2xl': 'text-2xl', + '3xl': 'text-3xl', + '4xl': 'text-4xl', + '5xl': 'text-5xl', + '6xl': 'text-6xl', + }, + sub: { + true: 'text-xs', + }, + italic: { + true: 'italic', + }, + highlight: { + true: 'bg-yellow-500', + }, + }, +}); + +const formControlLabelAstrickStyle = tva({ + base: 'font-medium text-typography-900', + variants: { + isTruncated: { + true: 'web:truncate', + }, + bold: { + true: 'font-bold', + }, + underline: { + true: 'underline', + }, + strikeThrough: { + true: 'line-through', + }, + size: { + '2xs': 'text-2xs', + 'xs': 'text-xs', + 'sm': 'text-sm', + 'md': 'text-base', + 'lg': 'text-lg', + 'xl': 'text-xl', + '2xl': 'text-2xl', + '3xl': 'text-3xl', + '4xl': 'text-4xl', + '5xl': 'text-5xl', + '6xl': 'text-6xl', + }, + sub: { + true: 'text-xs', + }, + italic: { + true: 'italic', + }, + highlight: { + true: 'bg-yellow-500', + }, + }, +}); + +type IFormControlLabelAstrickProps = React.ComponentPropsWithoutRef< + typeof Text +> & + VariantProps; + +const FormControlLabelAstrick = React.forwardRef< + React.ComponentRef, + IFormControlLabelAstrickProps +>(function FormControlLabelAstrick({ className, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + return ( + + ); +}); + +export const UIFormControl = createFormControl({ + Root: withStyleContext(View, SCOPE), + Error: View, + ErrorText: Text, + ErrorIcon: UIIcon, + Label: View, + LabelText: Text, + LabelAstrick: FormControlLabelAstrick, + Helper: View, + HelperText: Text, +}); + +cssInterop(PrimitiveIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: true, + stroke: true, + }, + }, +}); + +type IFormControlProps = React.ComponentProps & + VariantProps; + +const FormControl = React.forwardRef< + React.ComponentRef, + IFormControlProps +>(function FormControl({ className, size = 'md', ...props }, ref) { + return ( + + ); +}); + +type IFormControlErrorProps = React.ComponentProps & + VariantProps; + +const FormControlError = React.forwardRef< + React.ComponentRef, + IFormControlErrorProps +>(function FormControlError({ className, ...props }, ref) { + return ( + + ); +}); + +type IFormControlErrorTextProps = React.ComponentProps< + typeof UIFormControl.Error.Text +> & + VariantProps; + +const FormControlErrorText = React.forwardRef< + React.ComponentRef, + IFormControlErrorTextProps +>(function FormControlErrorText({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + return ( + + ); +}); + +type IFormControlErrorIconProps = React.ComponentProps< + typeof UIFormControl.Error.Icon +> & + VariantProps & { + height?: number; + width?: number; + }; + +const FormControlErrorIcon = React.forwardRef< + React.ComponentRef, + IFormControlErrorIconProps +>(function FormControlErrorIcon({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + return ( + + ); +}); + +type IFormControlLabelProps = React.ComponentProps & + VariantProps; + +const FormControlLabel = React.forwardRef< + React.ComponentRef, + IFormControlLabelProps +>(function FormControlLabel({ className, ...props }, ref) { + return ( + + ); +}); + +type IFormControlLabelTextProps = React.ComponentProps< + typeof UIFormControl.Label.Text +> & + VariantProps; + +const FormControlLabelText = React.forwardRef< + React.ComponentRef, + IFormControlLabelTextProps +>(function FormControlLabelText({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + return ( + + ); +}); + +type IFormControlHelperProps = React.ComponentProps< + typeof UIFormControl.Helper +> & + VariantProps; + +const FormControlHelper = React.forwardRef< + React.ComponentRef, + IFormControlHelperProps +>(function FormControlHelper({ className, ...props }, ref) { + return ( + + ); +}); + +type IFormControlHelperTextProps = React.ComponentProps< + typeof UIFormControl.Helper.Text +> & + VariantProps; + +const FormControlHelperText = React.forwardRef< + React.ComponentRef, + IFormControlHelperTextProps +>(function FormControlHelperText({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + return ( + + ); +}); + +FormControl.displayName = 'FormControl'; +FormControlError.displayName = 'FormControlError'; +FormControlErrorText.displayName = 'FormControlErrorText'; +FormControlErrorIcon.displayName = 'FormControlErrorIcon'; +FormControlLabel.displayName = 'FormControlLabel'; +FormControlLabelText.displayName = 'FormControlLabelText'; +FormControlLabelAstrick.displayName = 'FormControlLabelAstrick'; +FormControlHelper.displayName = 'FormControlHelper'; +FormControlHelperText.displayName = 'FormControlHelperText'; + +export { + FormControl, + FormControlError, + FormControlErrorText, + FormControlErrorIcon, + FormControlLabel, + FormControlLabelText, + FormControlLabelAstrick, + FormControlHelper, + FormControlHelperText, +}; \ No newline at end of file diff --git a/code/base-project/base-app/src/components/ui/icon/index.tsx b/code/base-project/base-app/src/components/ui/icon/index.tsx new file mode 100644 index 00000000..d94bfc87 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/icon/index.tsx @@ -0,0 +1,1588 @@ +import React from 'react'; +import { createIcon } from '@gluestack-ui/core/icon/creator'; +import { Path } from 'react-native-svg'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; +import { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { + PrimitiveIcon, + IPrimitiveIcon, + Svg, +} from '@gluestack-ui/core/icon/creator'; + +export const UIIcon = createIcon({ + Root: PrimitiveIcon, +}) as React.ForwardRefExoticComponent< + React.ComponentPropsWithoutRef & + React.RefAttributes> +>; + +const iconStyle = tva({ + base: 'text-typography-950 fill-none pointer-events-none', + variants: { + size: { + '2xs': 'h-3 w-3', + 'xs': 'h-3.5 w-3.5', + 'sm': 'h-4 w-4', + 'md': 'h-[18px] w-[18px]', + 'lg': 'h-5 w-5', + 'xl': 'h-6 w-6', + }, + }, +}); + +cssInterop(UIIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: 'classNameColor', + stroke: true, + }, + }, +}); + +type IIConProps = IPrimitiveIcon & + VariantProps & + React.ComponentPropsWithoutRef; + +const Icon = React.forwardRef, IIConProps>( + function Icon({ size = 'md', className, ...props }, ref) { + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + return ( + + ); + } +); + +export { Icon }; + +type ParameterTypes = Omit[0], 'Root'>; + +const createIconUI = ({ ...props }: ParameterTypes) => { + const UIIconCreateIcon = createIcon({ + Root: Svg, + ...props, + }) as React.ForwardRefExoticComponent< + React.ComponentPropsWithoutRef & + React.RefAttributes> + >; + + return React.forwardRef>(function UIIcon( + { + className, + size, + ...inComingProps + }: VariantProps & + React.ComponentPropsWithoutRef, + ref + ) { + return ( + + ); + }); +}; +export { createIconUI as createIcon }; +// All Icons +const AddIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +AddIcon.displayName = 'AddIcon'; +export { AddIcon }; + +const AlertCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +AlertCircleIcon.displayName = 'AlertCircleIcon'; +export { AlertCircleIcon }; + +const ArrowUpIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowDownIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowLeftIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ArrowUpIcon.displayName = 'ArrowUpIcon'; +ArrowDownIcon.displayName = 'ArrowDownIcon'; +ArrowRightIcon.displayName = 'ArrowRightIcon'; +ArrowLeftIcon.displayName = 'ArrowLeftIcon'; + +export { ArrowUpIcon, ArrowDownIcon, ArrowRightIcon, ArrowLeftIcon }; + +const AtSignIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + <> + + + + + ), +}); + +AtSignIcon.displayName = 'AtSignIcon'; + +export { AtSignIcon }; + +const BellIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +BellIcon.displayName = 'BellIcon'; + +export { BellIcon }; + +const CalendarDaysIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + + + + + ), +}); + +CalendarDaysIcon.displayName = 'CalendarDaysIcon'; + +export { CalendarDaysIcon }; + +const CheckIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const CheckCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +CheckIcon.displayName = 'CheckIcon'; +CheckCircleIcon.displayName = 'CheckCircleIcon'; + +export { CheckIcon, CheckCircleIcon }; + +const ChevronUpIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + d: 'M12 10L8 6L4 10', + path: ( + <> + + + ), +}); + +const ChevronDownIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronLeftIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronsLeftIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ChevronsRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ChevronsUpDownIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ChevronUpIcon.displayName = 'ChevronUpIcon'; +ChevronDownIcon.displayName = 'ChevronDownIcon'; +ChevronLeftIcon.displayName = 'ChevronLeftIcon'; +ChevronRightIcon.displayName = 'ChevronRightIcon'; +ChevronsLeftIcon.displayName = 'ChevronsLeftIcon'; +ChevronsRightIcon.displayName = 'ChevronsRightIcon'; +ChevronsUpDownIcon.displayName = 'ChevronsUpDownIcon'; + +export { + ChevronUpIcon, + ChevronDownIcon, + ChevronLeftIcon, + ChevronRightIcon, + ChevronsLeftIcon, + ChevronsRightIcon, + ChevronsUpDownIcon, +}; + +const CircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +CircleIcon.displayName = 'CircleIcon'; + +export { CircleIcon }; + +const ClockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ClockIcon.displayName = 'ClockIcon'; + +export { ClockIcon }; + +const CloseIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const CloseCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +CloseIcon.displayName = 'CloseIcon'; +CloseCircleIcon.displayName = 'CloseCircleIcon'; + +export { CloseIcon, CloseCircleIcon }; + +const CopyIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +CopyIcon.displayName = 'CopyIcon'; + +export { CopyIcon }; + +const DownloadIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +DownloadIcon.displayName = 'DownloadIcon'; +export { DownloadIcon }; + +const EditIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +EditIcon.displayName = 'EditIcon'; +export { EditIcon }; + +const EyeIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +EyeIcon.displayName = 'EyeIcon'; + +const EyeOffIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + ), +}); + +EyeOffIcon.displayName = 'EyeOffIcon'; +export { EyeIcon, EyeOffIcon }; + +const FavouriteIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +FavouriteIcon.displayName = 'FavouriteIcon'; +export { FavouriteIcon }; + +const GlobeIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +GlobeIcon.displayName = 'GlobeIcon'; +export { GlobeIcon }; + +const GripVerticalIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + ), +}); + +GripVerticalIcon.displayName = 'GripVerticalIcon'; +export { GripVerticalIcon }; + +const HelpCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +HelpCircleIcon.displayName = 'HelpCircleIcon'; +export { HelpCircleIcon }; + +const InfoIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +InfoIcon.displayName = 'InfoIcon'; +export { InfoIcon }; + +const LinkIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +LinkIcon.displayName = 'LinkIcon'; + +const ExternalLinkIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +ExternalLinkIcon.displayName = 'ExternalLinkIcon'; +export { LinkIcon, ExternalLinkIcon }; + +const LoaderIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +LoaderIcon.displayName = 'LoaderIcon'; +export { LoaderIcon }; + +const LockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +LockIcon.displayName = 'LockIcon'; +export { LockIcon }; + +const MailIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +MailIcon.displayName = 'MailIcon'; +export { MailIcon }; + +const MenuIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +MenuIcon.displayName = 'MenuIcon'; +export { MenuIcon }; + +const MessageCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +MessageCircleIcon.displayName = 'MessageCircleIcon'; + +export { MessageCircleIcon }; + +const MoonIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +MoonIcon.displayName = 'MoonIcon'; +export { MoonIcon }; + +const PaperclipIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +PaperclipIcon.displayName = 'PaperclipIcon'; +export { PaperclipIcon }; + +const PhoneIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +PhoneIcon.displayName = 'PhoneIcon'; +export { PhoneIcon }; + +const PlayIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +PlayIcon.displayName = 'PlayIcon'; +export { PlayIcon }; + +const RemoveIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +RemoveIcon.displayName = 'RemoveIcon'; +export { RemoveIcon }; + +const RepeatIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + ), +}); + +RepeatIcon.displayName = 'RepeatIcon'; + +const Repeat1Icon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + ), +}); + +Repeat1Icon.displayName = 'Repeat1Icon'; +export { RepeatIcon, Repeat1Icon }; + +const SearchIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SearchIcon.displayName = 'SearchIcon'; +export { SearchIcon }; + +const SettingsIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SettingsIcon.displayName = 'SettingsIcon'; +export { SettingsIcon }; + +const ShareIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + ), +}); + +ShareIcon.displayName = 'ShareIcon'; +export { ShareIcon }; + +const SlashIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SlashIcon.displayName = 'SlashIcon'; +export { SlashIcon }; + +const StarIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +StarIcon.displayName = 'StarIcon'; +export { StarIcon }; + +const SunIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + + + + ), +}); + +SunIcon.displayName = 'SunIcon'; +export { SunIcon }; + +const ThreeDotsIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +ThreeDotsIcon.displayName = 'ThreeDotsIcon'; +export { ThreeDotsIcon }; + +const TrashIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +TrashIcon.displayName = 'TrashIcon'; +export { TrashIcon }; + +const UnlockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +UnlockIcon.displayName = 'UnlockIcon'; +export { UnlockIcon }; \ No newline at end of file diff --git a/code/base-project/base-app/src/components/ui/icon/index.web.tsx b/code/base-project/base-app/src/components/ui/icon/index.web.tsx new file mode 100644 index 00000000..f5bef8b5 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/icon/index.web.tsx @@ -0,0 +1,1573 @@ +import React from 'react'; +import { createIcon } from '@gluestack-ui/core/icon/creator'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { PrimitiveIcon, Svg } from '@gluestack-ui/core/icon/creator'; + +export const UIIcon = createIcon({ + Root: PrimitiveIcon, +}); + +const iconStyle = tva({ + base: 'text-typography-950 fill-none pointer-events-none', + variants: { + size: { + '2xs': 'h-3 w-3', + 'xs': 'h-3.5 w-3.5', + 'sm': 'h-4 w-4', + 'md': 'h-[18px] w-[18px]', + 'lg': 'h-5 w-5', + 'xl': 'h-6 w-6', + }, + }, +}); + +export const Icon = React.forwardRef< + React.ComponentRef, + React.ComponentPropsWithoutRef & + VariantProps & { + height?: number | string; + width?: number | string; + } +>(function Icon({ size = 'md', className, ...props }, ref) { + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + return ( + + ); +}); + +type ParameterTypes = Omit[0], 'Root'>; + +const accessClassName = (style: any) => { + const styleObject = Array.isArray(style) ? style[0] : style; + const keys = Object.keys(styleObject); + return styleObject[keys[1]]; +}; + +const createIconUI = ({ ...props }: ParameterTypes) => { + const NewUIIcon = createIcon({ Root: Svg, ...props }); + return React.forwardRef< + React.ComponentRef, + React.ComponentPropsWithoutRef & + VariantProps & { + height?: number | string; + width?: number | string; + } + >(function UIIcon({ className, ...inComingprops }, ref) { + const calculateClassName = React.useMemo(() => { + return className === undefined + ? accessClassName(inComingprops?.style) + : className; + }, [className, inComingprops?.style]); + return ( + + ); + }); +}; + +export { createIconUI as createIcon }; + +// All Icons +const AddIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +AddIcon.displayName = 'AddIcon'; +export { AddIcon }; + +const AlertCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +AlertCircleIcon.displayName = 'AlertCircleIcon'; +export { AlertCircleIcon }; + +const ArrowUpIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowDownIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ArrowLeftIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ArrowUpIcon.displayName = 'ArrowUpIcon'; +ArrowDownIcon.displayName = 'ArrowDownIcon'; +ArrowRightIcon.displayName = 'ArrowRightIcon'; +ArrowLeftIcon.displayName = 'ArrowLeftIcon'; + +export { ArrowUpIcon, ArrowDownIcon, ArrowRightIcon, ArrowLeftIcon }; + +const AtSignIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + <> + + + + + ), +}); + +AtSignIcon.displayName = 'AtSignIcon'; + +export { AtSignIcon }; + +const BellIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +BellIcon.displayName = 'BellIcon'; + +export { BellIcon }; + +const CalendarDaysIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + + + + + ), +}); + +CalendarDaysIcon.displayName = 'CalendarDaysIcon'; + +export { CalendarDaysIcon }; + +const CheckIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const CheckCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +CheckIcon.displayName = 'CheckIcon'; +CheckCircleIcon.displayName = 'CheckCircleIcon'; + +export { CheckIcon, CheckCircleIcon }; + +const ChevronUpIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + d: 'M12 10L8 6L4 10', + path: ( + <> + + + ), +}); + +const ChevronDownIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronLeftIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +const ChevronsLeftIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ChevronsRightIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const ChevronsUpDownIcon = createIcon({ + Root: Svg, + + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ChevronUpIcon.displayName = 'ChevronUpIcon'; +ChevronDownIcon.displayName = 'ChevronDownIcon'; +ChevronLeftIcon.displayName = 'ChevronLeftIcon'; +ChevronRightIcon.displayName = 'ChevronRightIcon'; +ChevronsLeftIcon.displayName = 'ChevronsLeftIcon'; +ChevronsRightIcon.displayName = 'ChevronsRightIcon'; +ChevronsUpDownIcon.displayName = 'ChevronsUpDownIcon'; + +export { + ChevronUpIcon, + ChevronDownIcon, + ChevronLeftIcon, + ChevronRightIcon, + ChevronsLeftIcon, + ChevronsRightIcon, + ChevronsUpDownIcon, +}; + +const CircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +CircleIcon.displayName = 'CircleIcon'; +export { CircleIcon }; + +const ClockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +ClockIcon.displayName = 'ClockIcon'; + +export { ClockIcon }; + +const CloseIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +const CloseCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +CloseIcon.displayName = 'CloseIcon'; +CloseCircleIcon.displayName = 'CloseCircleIcon'; + +export { CloseIcon, CloseCircleIcon }; + +const CopyIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +CopyIcon.displayName = 'CopyIcon'; + +export { CopyIcon }; + +const DownloadIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +DownloadIcon.displayName = 'DownloadIcon'; +export { DownloadIcon }; + +const EditIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +EditIcon.displayName = 'EditIcon'; +export { EditIcon }; + +const EyeIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +EyeIcon.displayName = 'EyeIcon'; + +const EyeOffIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + ), +}); + +EyeOffIcon.displayName = 'EyeOffIcon'; +export { EyeIcon, EyeOffIcon }; + +const FavouriteIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +FavouriteIcon.displayName = 'FavouriteIcon'; +export { FavouriteIcon }; + +const GlobeIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +GlobeIcon.displayName = 'GlobeIcon'; +export { GlobeIcon }; + +const GripVerticalIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + ), +}); + +GripVerticalIcon.displayName = 'GripVerticalIcon'; +export { GripVerticalIcon }; + +const HelpCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +HelpCircleIcon.displayName = 'HelpCircleIcon'; +export { HelpCircleIcon }; + +const InfoIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +InfoIcon.displayName = 'InfoIcon'; +export { InfoIcon }; + +const LinkIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +LinkIcon.displayName = 'LinkIcon'; + +const ExternalLinkIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +ExternalLinkIcon.displayName = 'ExternalLinkIcon'; +export { LinkIcon, ExternalLinkIcon }; + +const LoaderIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +LoaderIcon.displayName = 'LoaderIcon'; +export { LoaderIcon }; + +const LockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +LockIcon.displayName = 'LockIcon'; +export { LockIcon }; + +const MailIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +MailIcon.displayName = 'MailIcon'; +export { MailIcon }; + +const MenuIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +MenuIcon.displayName = 'MenuIcon'; +export { MenuIcon }; + +const MessageCircleIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +MessageCircleIcon.displayName = 'MessageCircleIcon'; + +export { MessageCircleIcon }; + +const MoonIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +MoonIcon.displayName = 'MoonIcon'; +export { MoonIcon }; + +const PaperclipIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +PaperclipIcon.displayName = 'PaperclipIcon'; +export { PaperclipIcon }; + +const PhoneIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +PhoneIcon.displayName = 'PhoneIcon'; +export { PhoneIcon }; + +const PlayIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +PlayIcon.displayName = 'PlayIcon'; +export { PlayIcon }; + +const RemoveIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +RemoveIcon.displayName = 'RemoveIcon'; +export { RemoveIcon }; + +const RepeatIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + ), +}); + +RepeatIcon.displayName = 'RepeatIcon'; + +const Repeat1Icon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + ), +}); + +Repeat1Icon.displayName = 'Repeat1Icon'; +export { RepeatIcon, Repeat1Icon }; + +const SearchIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SearchIcon.displayName = 'SearchIcon'; +export { SearchIcon }; + +const SettingsIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SettingsIcon.displayName = 'SettingsIcon'; +export { SettingsIcon }; + +const ShareIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + ), +}); + +ShareIcon.displayName = 'ShareIcon'; +export { ShareIcon }; + +const SlashIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +SlashIcon.displayName = 'SlashIcon'; +export { SlashIcon }; + +const StarIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + ), +}); + +StarIcon.displayName = 'StarIcon'; +export { StarIcon }; + +const SunIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + + + + + + + ), +}); + +SunIcon.displayName = 'SunIcon'; +export { SunIcon }; + +const ThreeDotsIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +ThreeDotsIcon.displayName = 'ThreeDotsIcon'; +export { ThreeDotsIcon }; + +const TrashIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + + ), +}); + +TrashIcon.displayName = 'TrashIcon'; +export { TrashIcon }; + +const UnlockIcon = createIcon({ + Root: Svg, + viewBox: '0 0 24 24', + path: ( + <> + + + + ), +}); + +UnlockIcon.displayName = 'UnlockIcon'; +export { UnlockIcon }; \ No newline at end of file diff --git a/code/base-project/base-app/src/components/ui/input/index.tsx b/code/base-project/base-app/src/components/ui/input/index.tsx new file mode 100644 index 00000000..03d46eb2 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/input/index.tsx @@ -0,0 +1,217 @@ +'use client'; +import React from 'react'; +import { createInput } from '@gluestack-ui/core/input/creator'; +import { View, Pressable, TextInput } from 'react-native'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { + withStyleContext, + useStyleContext, +} from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'; + +const SCOPE = 'INPUT'; + +const UIInput = createInput({ + Root: withStyleContext(View, SCOPE), + Icon: UIIcon, + Slot: Pressable, + Input: TextInput, +}); + +cssInterop(PrimitiveIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: 'classNameColor', + stroke: true, + }, + }, +}); + +const inputStyle = tva({ + base: 'border-background-300 flex-row overflow-hidden content-center data-[hover=true]:border-outline-400 data-[focus=true]:border-primary-700 data-[focus=true]:hover:border-primary-700 data-[disabled=true]:opacity-40 data-[disabled=true]:hover:border-background-300 items-center', + + variants: { + size: { + xl: 'h-12', + lg: 'h-11', + md: 'h-10', + sm: 'h-9', + }, + + variant: { + underlined: + 'rounded-none border-b data-[invalid=true]:border-b-2 data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700', + + outline: + 'rounded border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 data-[focus=true]:web:ring-1 data-[focus=true]:web:ring-inset data-[focus=true]:web:ring-indicator-primary data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-indicator-error data-[invalid=true]:data-[focus=true]:hover:web:ring-1 data-[invalid=true]:data-[focus=true]:hover:web:ring-inset data-[invalid=true]:data-[focus=true]:hover:web:ring-indicator-error data-[invalid=true]:data-[disabled=true]:hover:web:ring-1 data-[invalid=true]:data-[disabled=true]:hover:web:ring-inset data-[invalid=true]:data-[disabled=true]:hover:web:ring-indicator-error', + + rounded: + 'rounded-full border data-[invalid=true]:border-error-700 data-[invalid=true]:hover:border-error-700 data-[invalid=true]:data-[focus=true]:border-error-700 data-[invalid=true]:data-[focus=true]:hover:border-error-700 data-[invalid=true]:data-[disabled=true]:hover:border-error-700 data-[focus=true]:web:ring-1 data-[focus=true]:web:ring-inset data-[focus=true]:web:ring-indicator-primary data-[invalid=true]:web:ring-1 data-[invalid=true]:web:ring-inset data-[invalid=true]:web:ring-indicator-error data-[invalid=true]:data-[focus=true]:hover:web:ring-1 data-[invalid=true]:data-[focus=true]:hover:web:ring-inset data-[invalid=true]:data-[focus=true]:hover:web:ring-indicator-error data-[invalid=true]:data-[disabled=true]:hover:web:ring-1 data-[invalid=true]:data-[disabled=true]:hover:web:ring-inset data-[invalid=true]:data-[disabled=true]:hover:web:ring-indicator-error', + }, + }, +}); + +const inputIconStyle = tva({ + base: 'justify-center items-center text-typography-400 fill-none', + parentVariants: { + size: { + '2xs': 'h-3 w-3', + 'xs': 'h-3.5 w-3.5', + 'sm': 'h-4 w-4', + 'md': 'h-[18px] w-[18px]', + 'lg': 'h-5 w-5', + 'xl': 'h-6 w-6', + }, + }, +}); + +const inputSlotStyle = tva({ + base: 'justify-center items-center web:disabled:cursor-not-allowed', +}); + +const inputFieldStyle = tva({ + base: 'flex-1 text-typography-900 py-0 px-3 placeholder:text-typography-500 h-full ios:leading-[0px] web:cursor-text web:data-[disabled=true]:cursor-not-allowed', + + parentVariants: { + variant: { + underlined: 'web:outline-0 web:outline-none px-0', + outline: 'web:outline-0 web:outline-none', + rounded: 'web:outline-0 web:outline-none px-4', + }, + + size: { + '2xs': 'text-2xs', + 'xs': 'text-xs', + 'sm': 'text-sm', + 'md': 'text-base', + 'lg': 'text-lg', + 'xl': 'text-xl', + '2xl': 'text-2xl', + '3xl': 'text-3xl', + '4xl': 'text-4xl', + '5xl': 'text-5xl', + '6xl': 'text-6xl', + }, + }, +}); + +type IInputProps = React.ComponentProps & + VariantProps & { className?: string }; +const Input = React.forwardRef, IInputProps>( + function Input( + { className, variant = 'outline', size = 'md', ...props }, + ref + ) { + return ( + + ); + } +); + +type IInputIconProps = React.ComponentProps & + VariantProps & { + className?: string; + height?: number; + width?: number; + }; + +const InputIcon = React.forwardRef< + React.ComponentRef, + IInputIconProps +>(function InputIcon({ className, size, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + return ( + + ); +}); + +type IInputSlotProps = React.ComponentProps & + VariantProps & { className?: string }; + +const InputSlot = React.forwardRef< + React.ComponentRef, + IInputSlotProps +>(function InputSlot({ className, ...props }, ref) { + return ( + + ); +}); + +type IInputFieldProps = React.ComponentProps & + VariantProps & { className?: string }; + +const InputField = React.forwardRef< + React.ComponentRef, + IInputFieldProps +>(function InputField({ className, ...props }, ref) { + const { variant: parentVariant, size: parentSize } = useStyleContext(SCOPE); + + return ( + + ); +}); + +Input.displayName = 'Input'; +InputIcon.displayName = 'InputIcon'; +InputSlot.displayName = 'InputSlot'; +InputField.displayName = 'InputField'; + +export { Input, InputField, InputIcon, InputSlot }; diff --git a/code/base-project/base-app/src/components/ui/link/index.tsx b/code/base-project/base-app/src/components/ui/link/index.tsx new file mode 100644 index 00000000..1254d990 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/link/index.tsx @@ -0,0 +1,102 @@ +'use client'; +import { createLink } from '@gluestack-ui/core/link/creator'; +import { Pressable } from 'react-native'; +import { Text } from 'react-native'; + +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { withStyleContext } from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; + +import React from 'react'; +export const UILink = createLink({ + Root: withStyleContext(Pressable), + Text: Text, +}); + +cssInterop(UILink, { className: 'style' }); +cssInterop(UILink.Text, { className: 'style' }); + +const linkStyle = tva({ + base: 'group/link web:outline-0 data-[disabled=true]:web:cursor-not-allowed data-[focus-visible=true]:web:ring-2 data-[focus-visible=true]:web:ring-indicator-primary data-[focus-visible=true]:web:outline-0 data-[disabled=true]:opacity-4 ', +}); + +const linkTextStyle = tva({ + base: 'underline text-info-700 data-[hover=true]:text-info-600 data-[hover=true]:no-underline data-[active=true]:text-info-700 font-normal font-body web:font-sans web:tracking-sm web:my-0 web:bg-transparent web:border-0 web:box-border web:display-inline web:list-none web:margin-0 web:padding-0 web:position-relative web:text-start web:whitespace-pre-wrap web:word-wrap-break-word', + + variants: { + isTruncated: { + true: 'web:truncate', + }, + bold: { + true: 'font-bold', + }, + underline: { + true: 'underline', + }, + strikeThrough: { + true: 'line-through', + }, + size: { + '2xs': 'text-2xs', + 'xs': 'text-xs', + 'sm': 'text-sm', + 'md': 'text-base', + 'lg': 'text-lg', + 'xl': 'text-xl', + '2xl': 'text-2xl', + '3xl': 'text-3xl', + '4xl': 'text-4xl', + '5xl': 'text-5xl', + '6xl': 'text-6xl', + }, + sub: { + true: 'text-xs', + }, + italic: { + true: 'italic', + }, + highlight: { + true: 'bg-yellow-500', + }, + }, +}); + +type ILinkProps = React.ComponentProps & + VariantProps & { className?: string }; + +const Link = React.forwardRef, ILinkProps>( + function Link({ className, ...props }, ref) { + return ( + + ); + } +); + +type ILinkTextProps = React.ComponentProps & + VariantProps & { className?: string }; + +const LinkText = React.forwardRef< + React.ComponentRef, + ILinkTextProps +>(function LinkText({ className, size = 'md', ...props }, ref) { + return ( + + ); +}); + +Link.displayName = 'Link'; +LinkText.displayName = 'LinkText'; + +export { Link, LinkText }; diff --git a/code/base-project/base-app/src/static/images/logo.png b/code/base-project/base-app/src/static/images/logo.png new file mode 100644 index 00000000..0fd90bc0 Binary files /dev/null and b/code/base-project/base-app/src/static/images/logo.png differ diff --git a/code/base-project/base-app/src/static/images/work.png b/code/base-project/base-app/src/static/images/work.png new file mode 100644 index 00000000..539d6d80 Binary files /dev/null and b/code/base-project/base-app/src/static/images/work.png differ diff --git a/code/base-project/base-go-v2/cmd/app/main.go b/code/base-project/base-go-v2/cmd/app/main.go index fc9edb80..e151acb7 100644 --- a/code/base-project/base-go-v2/cmd/app/main.go +++ b/code/base-project/base-go-v2/cmd/app/main.go @@ -3,7 +3,7 @@ package main import ( "base-go-v2/internal/api" "base-go-v2/internal/config" - "base-go-v2/internal/database" + "base-go-v2/internal/db" "base-go-v2/internal/logx" "fmt" "github.com/valyala/fasthttp" @@ -17,7 +17,7 @@ func main() { } // 初始化数据库 - if err := database.InitDb(); err != nil { + if err := db.InitDb(); err != nil { log.Fatalf("加载数据库配置失败: %v", err) } diff --git a/code/base-project/base-go-v2/go.mod b/code/base-project/base-go-v2/go.mod index 72048674..aaf2ffdb 100644 --- a/code/base-project/base-go-v2/go.mod +++ b/code/base-project/base-go-v2/go.mod @@ -13,6 +13,7 @@ require ( github.com/andybalholm/brotli v1.2.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect github.com/klauspost/compress v1.18.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect diff --git a/code/base-project/base-go-v2/go.sum b/code/base-project/base-go-v2/go.sum index 82fd7216..54a58b43 100644 --- a/code/base-project/base-go-v2/go.sum +++ b/code/base-project/base-go-v2/go.sum @@ -1,15 +1,20 @@ +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= diff --git a/code/base-project/base-go-v2/internal/api/auth/index.go b/code/base-project/base-go-v2/internal/api/auth/index.go index eaf3abd8..b87d2261 100644 --- a/code/base-project/base-go-v2/internal/api/auth/index.go +++ b/code/base-project/base-go-v2/internal/api/auth/index.go @@ -1,5 +1,27 @@ package auth -func InitAuthRouter() { +import ( + response "base-go-v2/internal/reponse" + "base-go-v2/internal/router" +) +func InitAuthRouter(r *router.Router) { + group := r.Group("auth") + group.POST("/login/default", loginDefault) +} + +// 默认登录 +func loginDefault(c *router.Context) error { + return response.Success(c).Send() +} + +// 注册 +func registerDefault(c *router.Context) error { + var req struct { + Email string `json:"email"` + Password string `json:"password"` + } + + if err := c.BindJSON(&req); err != nil { + } } diff --git a/code/base-project/base-go-v2/internal/database/db.go b/code/base-project/base-go-v2/internal/db/db.go similarity index 92% rename from code/base-project/base-go-v2/internal/database/db.go rename to code/base-project/base-go-v2/internal/db/db.go index 3c452e2b..6f2bc0af 100644 --- a/code/base-project/base-go-v2/internal/database/db.go +++ b/code/base-project/base-go-v2/internal/db/db.go @@ -1,15 +1,15 @@ -package database +package db import ( "base-go-v2/internal/config" - "database/sql" "fmt" "time" + "github.com/jmoiron/sqlx" _ "github.com/lib/pq" ) -var DB *sql.DB +var DB *sqlx.DB var defaultPoolConfig = struct { MaxOpenConns int @@ -28,7 +28,7 @@ func InitDb() error { dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", d.Host, d.Port, d.User, d.Password, d.Dbname) - db, err := sql.Open("postgres", dsn) + db, err := sqlx.Connect("postgres", dsn) if err != nil { return fmt.Errorf("打开数据库失败: %w", err) } @@ -60,5 +60,6 @@ func InitDb() error { fmt.Printf("✅ 数据库连接成功:%s:%d/%s\n", d.Host, d.Port, d.Dbname) DB = db + return nil } diff --git a/code/base-project/base-go-v2/internal/db/delete.go b/code/base-project/base-go-v2/internal/db/delete.go new file mode 100644 index 00000000..70e5db13 --- /dev/null +++ b/code/base-project/base-go-v2/internal/db/delete.go @@ -0,0 +1,61 @@ +package db + +import ( + "fmt" +) + +// DeleteOne 根据主键删除单条记录 +func DeleteOne(table string, pkColumn string, pkValue interface{}) (int64, error) { + tx, err := DB.Beginx() + if err != nil { + return 0, err + } + + query := fmt.Sprintf("DELETE FROM %s WHERE %s=$1", table, pkColumn) + res, err := tx.Exec(query, pkValue) + if err != nil { + tx.Rollback() + return 0, err + } + + if err := tx.Commit(); err != nil { + return 0, err + } + + return res.RowsAffected() +} + +// DeleteBatch 根据主键批量删除记录 +func DeleteBatch(table string, pkColumn string, pkValues []interface{}) (int64, error) { + if len(pkValues) == 0 { + return 0, nil + } + + tx, err := DB.Beginx() + if err != nil { + return 0, err + } + + total := int64(0) + for _, pk := range pkValues { + query := fmt.Sprintf("DELETE FROM %s WHERE %s=$1", table, pkColumn) + res, err := tx.Exec(query, pk) + if err != nil { + tx.Rollback() + return 0, err + } + + rows, err := res.RowsAffected() + if err != nil { + tx.Rollback() + return 0, err + } + total += rows + } + + if err := tx.Commit(); err != nil { + return 0, err + } + + return total, nil +} diff --git a/code/base-project/base-go-v2/internal/db/insert.go b/code/base-project/base-go-v2/internal/db/insert.go new file mode 100644 index 00000000..c1409f01 --- /dev/null +++ b/code/base-project/base-go-v2/internal/db/insert.go @@ -0,0 +1,146 @@ +package db + +import ( + "fmt" + "strings" +) + +// ---------------- 内部辅助函数 ---------------- + +// buildInsertSQL 构建插入 SQL 和参数 +func buildInsertSQL(table string, data map[string]interface{}, returning string) (string, []interface{}) { + columns := make([]string, 0, len(data)) + placeholders := make([]string, 0, len(data)) + values := make([]interface{}, 0, len(data)) + + i := 1 + for k, v := range data { + columns = append(columns, k) + placeholders = append(placeholders, fmt.Sprintf("$%d", i)) + values = append(values, v) + i++ + } + + sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", table, + strings.Join(columns, ","), strings.Join(placeholders, ",")) + + if returning != "" { + sql += " RETURNING " + returning + } + + return sql, values +} + +// ---------------- 公共方法 ---------------- + +// InsertOne 插入单条记录,返回受影响行数 +func InsertOne(table string, data map[string]interface{}) (int64, error) { + tx, err := DB.Beginx() + if err != nil { + return 0, err + } + + sql, values := buildInsertSQL(table, data, "") + res, err := tx.Exec(sql, values...) + if err != nil { + tx.Rollback() + return 0, err + } + + if err := tx.Commit(); err != nil { + return 0, err + } + + return res.RowsAffected() +} + +// InsertBatch 批量插入,返回总受影响行数 +func InsertBatch(table string, dataList []map[string]interface{}) (int64, error) { + if len(dataList) == 0 { + return 0, nil + } + + tx, err := DB.Beginx() + if err != nil { + return 0, err + } + + total := int64(0) + + for _, data := range dataList { + sql, values := buildInsertSQL(table, data, "") + res, err := tx.Exec(sql, values...) + if err != nil { + tx.Rollback() + return 0, err + } + rows, err := res.RowsAffected() + if err != nil { + tx.Rollback() + return 0, err + } + total += rows + } + + if err := tx.Commit(); err != nil { + return 0, err + } + + return total, nil +} + +// InsertOneReturnPK 插入单条记录,返回主键值 +func InsertOneReturnPK(table string, pkColumn string, data map[string]interface{}) (int64, error) { + tx, err := DB.Beginx() + if err != nil { + return 0, err + } + + sql, values := buildInsertSQL(table, data, pkColumn) + + var pk int64 + err = tx.Get(&pk, sql, values...) + if err != nil { + tx.Rollback() + return 0, err + } + + if err := tx.Commit(); err != nil { + return 0, err + } + + return pk, nil +} + +// InsertBatchReturnPK 批量插入多条记录,返回主键数组 +func InsertBatchReturnPK(table string, pkColumn string, dataList []map[string]interface{}) ([]int64, error) { + if len(dataList) == 0 { + return nil, nil + } + + tx, err := DB.Beginx() + if err != nil { + return nil, err + } + + var pkList []int64 + + for _, data := range dataList { + sql, values := buildInsertSQL(table, data, pkColumn) + + var pk int64 + err := tx.Get(&pk, sql, values...) + if err != nil { + tx.Rollback() + return nil, err + } + + pkList = append(pkList, pk) + } + + if err := tx.Commit(); err != nil { + return nil, err + } + + return pkList, nil +} diff --git a/code/base-project/base-go-v2/internal/db/query.go b/code/base-project/base-go-v2/internal/db/query.go new file mode 100644 index 00000000..0701ff6b --- /dev/null +++ b/code/base-project/base-go-v2/internal/db/query.go @@ -0,0 +1,96 @@ +package db + +import ( + "fmt" + "strings" +) + +// ---------------- 通用查询方法 ---------------- + +// GetOne 根据主键查询单条记录,返回 map[string]interface{} +func GetOne(table string, pkColumn string, pkValue interface{}) (map[string]interface{}, error) { + query := fmt.Sprintf("SELECT * FROM %s WHERE %s=$1", table, pkColumn) + + row := make(map[string]interface{}) + err := DB.Get(&row, query, pkValue) + if err != nil { + return nil, err + } + return row, nil +} + +// GetBatch 根据主键批量查询,返回 []map[string]interface{} +func GetBatch(table string, pkColumn string, pkValues []interface{}) ([]map[string]interface{}, error) { + if len(pkValues) == 0 { + return nil, nil + } + + var rows []map[string]interface{} + + // 构建 IN 占位符 + placeholders := make([]string, len(pkValues)) + for i := range pkValues { + placeholders[i] = fmt.Sprintf("$%d", i+1) + } + + query := fmt.Sprintf("SELECT * FROM %s WHERE %s IN (%s)", table, pkColumn, strings.Join(placeholders, ",")) + err := DB.Select(&rows, query, pkValues...) + if err != nil { + return nil, err + } + + return rows, nil +} + +// Find 根据条件查询多条记录,可选排序 +// conditions: map[column]value, 将以 AND 拼接 +// orderBy: 可选排序字段,如 "created_at ASC",为空默认 "b_id DESC" +func Find(table string, conditions map[string]interface{}, orderBy ...string) ([]map[string]interface{}, error) { + if len(conditions) == 0 { + return nil, fmt.Errorf("查询条件不能为空") + } + + var whereParts []string + var values []interface{} + i := 1 + for k, v := range conditions { + whereParts = append(whereParts, fmt.Sprintf("%s=$%d", k, i)) + values = append(values, v) + i++ + } + + query := fmt.Sprintf("SELECT * FROM %s WHERE %s", table, strings.Join(whereParts, " AND ")) + + order := "b_id DESC" + if len(orderBy) > 0 && orderBy[0] != "" { + order = orderBy[0] + } + query += " ORDER BY " + order + + var rows []map[string]interface{} + err := DB.Select(&rows, query, values...) + if err != nil { + return nil, err + } + + return rows, nil +} + +// FindAll 查询整个表,可选排序 +func FindAll(table string, orderBy ...string) ([]map[string]interface{}, error) { + query := fmt.Sprintf("SELECT * FROM %s", table) + + order := "b_id DESC" + if len(orderBy) > 0 && orderBy[0] != "" { + order = orderBy[0] + } + query += " ORDER BY " + order + + var rows []map[string]interface{} + err := DB.Select(&rows, query) + if err != nil { + return nil, err + } + + return rows, nil +} diff --git a/code/base-project/base-go-v2/internal/db/update.go b/code/base-project/base-go-v2/internal/db/update.go new file mode 100644 index 00000000..49081ab0 --- /dev/null +++ b/code/base-project/base-go-v2/internal/db/update.go @@ -0,0 +1,103 @@ +package db + +import ( + "fmt" + "strings" +) + +// ---------------- 内部辅助函数 ---------------- + +// buildUpdateSQL 构建 UPDATE SQL 和参数 +// idColumn: 主键列名 +func buildUpdateSQL(table string, data map[string]interface{}, idColumn string) (string, []interface{}) { + var setParts []string + var values []interface{} + i := 1 + for k, v := range data { + setParts = append(setParts, fmt.Sprintf("%s=$%d", k, i)) + values = append(values, v) + i++ + } + // WHERE id = $n + sql := fmt.Sprintf("UPDATE %s SET %s WHERE %s=$%d", + table, + strings.Join(setParts, ", "), + idColumn, + i, + ) + return sql, values +} + +// ---------------- 公共方法 ---------------- + +// UpdateOne 更新单条记录,按主键 idColumn +func UpdateOne(table string, idColumn string, id interface{}, data map[string]interface{}) (int64, error) { + tx, err := DB.Beginx() + if err != nil { + return 0, err + } + + sql, values := buildUpdateSQL(table, data, idColumn) + values = append(values, id) // 最后一个参数是 id + + res, err := tx.Exec(sql, values...) + if err != nil { + err := tx.Rollback() + if err != nil { + return 0, err + } + return 0, err + } + + if err := tx.Commit(); err != nil { + return 0, err + } + + return res.RowsAffected() +} + +// UpdateBatch 批量更新,dataList 中每个 map 必须包含主键 idColumn +func UpdateBatch(table string, idColumn string, dataList []map[string]interface{}) (int64, error) { + if len(dataList) == 0 { + return 0, nil + } + + tx, err := DB.Beginx() + if err != nil { + return 0, err + } + + total := int64(0) + for _, data := range dataList { + idValue, ok := data[idColumn] + if !ok { + tx.Rollback() + return 0, fmt.Errorf("缺少主键列 %s", idColumn) + } + + // 移除主键列,否则会重复在 SET 中出现 + delete(data, idColumn) + + sql, values := buildUpdateSQL(table, data, idColumn) + values = append(values, idValue) + + res, err := tx.Exec(sql, values...) + if err != nil { + tx.Rollback() + + return 0, err + } + rows, err := res.RowsAffected() + if err != nil { + tx.Rollback() + return 0, err + } + total += rows + } + + if err := tx.Commit(); err != nil { + return 0, err + } + + return total, nil +} diff --git a/code/base-project/base-go-v2/logs/error/error-2025-11-04.log b/code/base-project/base-go-v2/logs/error/error-2025-11-04.log new file mode 100644 index 00000000..e69de29b diff --git a/code/base-project/base-go-v2/logs/info/info-2025-11-04.log b/code/base-project/base-go-v2/logs/info/info-2025-11-04.log new file mode 100644 index 00000000..e69de29b diff --git a/code/base-project/base-go-v2/logs/warn/warn-2025-11-04.log b/code/base-project/base-go-v2/logs/warn/warn-2025-11-04.log new file mode 100644 index 00000000..e69de29b diff --git a/notes/前端开发/react-native/expo.md b/notes/前端开发/react-native/expo.md index ebf247b8..67fcf227 100644 --- a/notes/前端开发/react-native/expo.md +++ b/notes/前端开发/react-native/expo.md @@ -816,6 +816,46 @@ import 'react-native-gesture-handler' +## 集成[react-native-iconfont-cli](https://github.com/iconfont-cli/react-native-iconfont-cli) + +安装: + +```bash +pnpm add react-native-iconfont-cli -D +``` + +BUG位置:https://github.com/iconfont-cli/react-native-iconfont-cli/issues/42 + +解决fang'an修改模板 `node_modules/react-native-iconfont-cli/templates/SingleIcon.tsx.template`: + +```tsx +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +#svgComponents# +#helper# + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const #componentName#: FunctionComponent = ({ + size = #size#, + color, + ...rest +}) => { + return ( + #iconContent# + ); +}; + +export default React.memo(#componentName#); +``` + ## 配置深度链接