This commit is contained in:
oneao committed 2025-12-01 22:27:11 +08:00
1 parent 494f1ad01f
commit 0ab2796dd4
21 files changed
+1583 -472

No files matched your search

+2
View File
@@ -11,6 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@alova/adapter-axios": "^2.0.16", "@alova/adapter-axios": "^2.0.16",
"@expo/html-elements": "0.12.5",
"@gluestack-ui/core": "^3.0.12", "@gluestack-ui/core": "^3.0.12",
"@gluestack-ui/utils": "^3.0.11", "@gluestack-ui/utils": "^3.0.11",
"@gluestack/ui-next-adapter": "^3.0.3", "@gluestack/ui-next-adapter": "^3.0.3",
@@ -44,6 +45,7 @@
"react-native-modal": "14.0.0-rc.1", "react-native-modal": "14.0.0-rc.1",
"react-native-pager-view": "6.9.1", "react-native-pager-view": "6.9.1",
"react-native-popup-menu": "^0.18.0", "react-native-popup-menu": "^0.18.0",
"react-native-qrcode-svg": "^6.3.20",
"react-native-reanimated": "~4.1.3", "react-native-reanimated": "~4.1.3",
"react-native-safe-area-context": "~5.6.1", "react-native-safe-area-context": "~5.6.1",
"react-native-screens": "~4.16.0", "react-native-screens": "~4.16.0",
+127 -8
View File
@@ -11,6 +11,9 @@ importers:
'@alova/adapter-axios': '@alova/adapter-axios':
specifier: ^2.0.16 specifier: ^2.0.16
version: 2.0.16(alova@3.3.4)(axios@1.13.2) version: 2.0.16(alova@3.3.4)(axios@1.13.2)
'@expo/html-elements':
specifier: 0.12.5
version: 0.12.5
'@gluestack-ui/core': '@gluestack-ui/core':
specifier: ^3.0.12 specifier: ^3.0.12
version: 3.0.12(@gluestack-ui/utils@3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.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.2(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.1.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.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.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.2(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.1.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)
@@ -110,6 +113,9 @@ importers:
react-native-popup-menu: react-native-popup-menu:
specifier: ^0.18.0 specifier: ^0.18.0
version: 0.18.0 version: 0.18.0
react-native-qrcode-svg:
specifier: ^6.3.20
version: 6.3.20(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)
react-native-reanimated: react-native-reanimated:
specifier: ~4.1.3 specifier: ~4.1.3
version: 4.1.5(@babel/core@7.28.5)(react-native-worklets@0.5.1(@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) version: 4.1.5(@babel/core@7.28.5)(react-native-worklets@0.5.1(@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)
@@ -875,6 +881,9 @@ packages:
resolution: {integrity: sha512-8YPJpEYlmV171fi+t+cSLMX1nC5ngY9j2FiN70dHldLpd6Ct6ouGhk96svJ4BQZwsqwII2pokwzrDAwqo4Z0FQ==} resolution: {integrity: sha512-8YPJpEYlmV171fi+t+cSLMX1nC5ngY9j2FiN70dHldLpd6Ct6ouGhk96svJ4BQZwsqwII2pokwzrDAwqo4Z0FQ==}
hasBin: true hasBin: true
'@expo/html-elements@0.12.5':
resolution: {integrity: sha512-28KWO88YKykKU7ke5sEQs5TivFRMs1Aktz13xxgqAf5rTgb+lka0VKVt3W2fG7ksbUQ407rtUqz7SEAq298NvQ==}
'@expo/image-utils@0.8.7': '@expo/image-utils@0.8.7':
resolution: {integrity: sha512-SXOww4Wq3RVXLyOaXiCCuQFguCDh8mmaHBv54h/R29wGl4jRY8GEyQEx8SypV/iHt1FbzsU/X3Qbcd9afm2W2w==} resolution: {integrity: sha512-SXOww4Wq3RVXLyOaXiCCuQFguCDh8mmaHBv54h/R29wGl4jRY8GEyQEx8SypV/iHt1FbzsU/X3Qbcd9afm2W2w==}
@@ -2631,6 +2640,9 @@ packages:
client-only@0.0.1: client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
cliui@6.0.0:
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
cliui@8.0.1: cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -2814,6 +2826,10 @@ packages:
supports-color: supports-color:
optional: true optional: true
decamelize@1.2.0:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
decimal.js@10.6.0: decimal.js@10.6.0:
resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
@@ -2884,6 +2900,9 @@ packages:
resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
dijkstrajs@1.0.3:
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
dlv@1.1.3: dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
@@ -3911,56 +3930,48 @@ packages:
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-arm64-gnu@1.30.2: lightningcss-linux-arm64-gnu@1.30.2:
resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-arm64-musl@1.27.0: lightningcss-linux-arm64-musl@1.27.0:
resolution: {integrity: sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==} resolution: {integrity: sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-linux-arm64-musl@1.30.2: lightningcss-linux-arm64-musl@1.30.2:
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-linux-x64-gnu@1.27.0: lightningcss-linux-x64-gnu@1.27.0:
resolution: {integrity: sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==} resolution: {integrity: sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-x64-gnu@1.30.2: lightningcss-linux-x64-gnu@1.30.2:
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-x64-musl@1.27.0: lightningcss-linux-x64-musl@1.27.0:
resolution: {integrity: sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==} resolution: {integrity: sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-linux-x64-musl@1.30.2: lightningcss-linux-x64-musl@1.30.2:
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-win32-arm64-msvc@1.27.0: lightningcss-win32-arm64-msvc@1.27.0:
resolution: {integrity: sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==} resolution: {integrity: sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==}
@@ -4665,6 +4676,10 @@ packages:
resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==}
engines: {node: '>=4.0.0'} engines: {node: '>=4.0.0'}
pngjs@5.0.0:
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
engines: {node: '>=10.13.0'}
pnpm-workspace-yaml@1.3.0: pnpm-workspace-yaml@1.3.0:
resolution: {integrity: sha512-Krb5q8Totd5mVuLx7we+EFHq/AfxA75nbfTm25Q1pIf606+RlaKUG+PXH8SDihfe5b5k4H09gE+sL47L1t5lbw==} resolution: {integrity: sha512-Krb5q8Totd5mVuLx7we+EFHq/AfxA75nbfTm25Q1pIf606+RlaKUG+PXH8SDihfe5b5k4H09gE+sL47L1t5lbw==}
@@ -4763,6 +4778,11 @@ packages:
resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==} resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==}
hasBin: true hasBin: true
qrcode@1.5.4:
resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==}
engines: {node: '>=10.13.0'}
hasBin: true
quansync@0.2.11: quansync@0.2.11:
resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
@@ -4885,6 +4905,13 @@ packages:
react-native-popup-menu@0.18.0: react-native-popup-menu@0.18.0:
resolution: {integrity: sha512-XD3gyp/hwL5YWw2J034DerfvbJ6S2YHqAzvqAFRU+UGnFD4JyTqggfm4UyynBD26O1PDoRb45Loil+NZCGfCnA==} resolution: {integrity: sha512-XD3gyp/hwL5YWw2J034DerfvbJ6S2YHqAzvqAFRU+UGnFD4JyTqggfm4UyynBD26O1PDoRb45Loil+NZCGfCnA==}
react-native-qrcode-svg@6.3.20:
resolution: {integrity: sha512-GDP7T3DDEHUo53xmDyWWXXm3MhWRp0YayqVMum98JYfm0DW2rEbz1GIj+XLaA0QX443G0nURyzPnuQJeHjuvjA==}
peerDependencies:
react: '*'
react-native: '>=0.63.4'
react-native-svg: '>=14.0.0'
react-native-reanimated@4.1.5: react-native-reanimated@4.1.5:
resolution: {integrity: sha512-UA6VUbxwhRjEw2gSNrvhkusUq3upfD3Cv+AnB07V+kC8kpvwRVI+ivwY95ePbWNFkFpP+Y2Sdw1WHpHWEV+P2Q==} resolution: {integrity: sha512-UA6VUbxwhRjEw2gSNrvhkusUq3upfD3Cv+AnB07V+kC8kpvwRVI+ivwY95ePbWNFkFpP+Y2Sdw1WHpHWEV+P2Q==}
peerDependencies: peerDependencies:
@@ -5040,6 +5067,9 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
require-main-filename@2.0.0:
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
requireg@0.2.2: requireg@0.2.2:
resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==} resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==}
engines: {node: '>= 4.0.0'} engines: {node: '>= 4.0.0'}
@@ -5148,6 +5178,9 @@ packages:
server-only@0.0.1: server-only@0.0.1:
resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==}
set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
setimmediate@1.0.5: setimmediate@1.0.5:
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
@@ -5375,6 +5408,10 @@ packages:
resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
engines: {node: '>=8'} engines: {node: '>=8'}
text-encoding@0.7.0:
resolution: {integrity: sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==}
deprecated: no longer maintained
thenify-all@1.6.0: thenify-all@1.6.0:
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
engines: {node: '>=0.8'} engines: {node: '>=0.8'}
@@ -5609,6 +5646,9 @@ packages:
whatwg-url@5.0.0: whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
which-module@2.0.1:
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
which@2.0.2: which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@@ -5621,6 +5661,10 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
wrap-ansi@6.2.0:
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
engines: {node: '>=8'}
wrap-ansi@7.0.0: wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -5695,6 +5739,9 @@ packages:
resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
engines: {node: '>=8.0'} engines: {node: '>=8.0'}
y18n@4.0.3:
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
y18n@5.0.8: y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -5715,10 +5762,18 @@ packages:
engines: {node: '>= 14.6'} engines: {node: '>= 14.6'}
hasBin: true hasBin: true
yargs-parser@18.1.3:
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
engines: {node: '>=6'}
yargs-parser@21.1.1: yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'} engines: {node: '>=12'}
yargs@15.4.1:
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
engines: {node: '>=8'}
yargs@17.7.2: yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -6698,6 +6753,8 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@expo/html-elements@0.12.5': {}
'@expo/image-utils@0.8.7': '@expo/image-utils@0.8.7':
dependencies: dependencies:
'@expo/spawn-async': 1.7.2 '@expo/spawn-async': 1.7.2
@@ -9139,6 +9196,12 @@ snapshots:
client-only@0.0.1: {} client-only@0.0.1: {}
cliui@6.0.0:
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 6.2.0
cliui@8.0.1: cliui@8.0.1:
dependencies: dependencies:
string-width: 4.2.3 string-width: 4.2.3
@@ -9310,6 +9373,8 @@ snapshots:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
decamelize@1.2.0: {}
decimal.js@10.6.0: {} decimal.js@10.6.0: {}
decode-named-character-reference@1.2.0: decode-named-character-reference@1.2.0:
@@ -9358,6 +9423,8 @@ snapshots:
diff-sequences@27.5.1: {} diff-sequences@27.5.1: {}
dijkstrajs@1.0.3: {}
dlv@1.1.3: {} dlv@1.1.3: {}
dom-helpers@6.0.1: dom-helpers@6.0.1:
@@ -11581,6 +11648,8 @@ snapshots:
pngjs@3.4.0: {} pngjs@3.4.0: {}
pngjs@5.0.0: {}
pnpm-workspace-yaml@1.3.0: pnpm-workspace-yaml@1.3.0:
dependencies: dependencies:
yaml: 2.8.1 yaml: 2.8.1
@@ -11668,6 +11737,12 @@ snapshots:
qrcode-terminal@0.11.0: {} qrcode-terminal@0.11.0: {}
qrcode@1.5.4:
dependencies:
dijkstrajs: 1.0.3
pngjs: 5.0.0
yargs: 15.4.1
quansync@0.2.11: {} quansync@0.2.11: {}
query-string@7.1.3: query-string@7.1.3:
@@ -11841,6 +11916,15 @@ snapshots:
react-native-popup-menu@0.18.0: {} react-native-popup-menu@0.18.0: {}
react-native-qrcode-svg@6.3.20(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):
dependencies:
prop-types: 15.8.1
qrcode: 1.5.4
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)
text-encoding: 0.7.0
react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@0.5.1(@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-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@0.5.1(@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):
dependencies: dependencies:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
@@ -12080,6 +12164,8 @@ snapshots:
require-from-string@2.0.2: {} require-from-string@2.0.2: {}
require-main-filename@2.0.0: {}
requireg@0.2.2: requireg@0.2.2:
dependencies: dependencies:
nested-error-stacks: 2.0.1 nested-error-stacks: 2.0.1
@@ -12198,6 +12284,8 @@ snapshots:
server-only@0.0.1: {} server-only@0.0.1: {}
set-blocking@2.0.0: {}
setimmediate@1.0.5: {} setimmediate@1.0.5: {}
setprototypeof@1.2.0: {} setprototypeof@1.2.0: {}
@@ -12427,6 +12515,8 @@ snapshots:
glob: 7.2.3 glob: 7.2.3
minimatch: 3.1.2 minimatch: 3.1.2
text-encoding@0.7.0: {}
thenify-all@1.6.0: thenify-all@1.6.0:
dependencies: dependencies:
thenify: 3.3.1 thenify: 3.3.1
@@ -12629,6 +12719,8 @@ snapshots:
tr46: 0.0.3 tr46: 0.0.3
webidl-conversions: 3.0.1 webidl-conversions: 3.0.1
which-module@2.0.1: {}
which@2.0.2: which@2.0.2:
dependencies: dependencies:
isexe: 2.0.0 isexe: 2.0.0
@@ -12637,6 +12729,12 @@ snapshots:
word-wrap@1.2.5: {} word-wrap@1.2.5: {}
wrap-ansi@6.2.0:
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi@7.0.0: wrap-ansi@7.0.0:
dependencies: dependencies:
ansi-styles: 4.3.0 ansi-styles: 4.3.0
@@ -12685,6 +12783,8 @@ snapshots:
xmlbuilder@15.1.1: {} xmlbuilder@15.1.1: {}
y18n@4.0.3: {}
y18n@5.0.8: {} y18n@5.0.8: {}
yallist@3.1.1: {} yallist@3.1.1: {}
@@ -12698,8 +12798,27 @@ snapshots:
yaml@2.8.1: {} yaml@2.8.1: {}
yargs-parser@18.1.3:
dependencies:
camelcase: 5.3.1
decamelize: 1.2.0
yargs-parser@21.1.1: {} yargs-parser@21.1.1: {}
yargs@15.4.1:
dependencies:
cliui: 6.0.0
decamelize: 1.2.0
find-up: 4.1.0
get-caller-file: 2.0.5
require-directory: 2.1.1
require-main-filename: 2.0.0
set-blocking: 2.0.0
string-width: 4.2.3
which-module: 2.0.1
y18n: 4.0.3
yargs-parser: 18.1.3
yargs@17.7.2: yargs@17.7.2:
dependencies: dependencies:
cliui: 8.0.1 cliui: 8.0.1
@@ -1,6 +1,6 @@
import type { MoneyRecordGroup, MoneyRecordItem } from '@/types/money/record' import type { MoneyRecordGroup, MoneyRecordItem } from '@/types/money/record'
import React, { useCallback, useState } from 'react' import React, { useCallback, useState } from 'react'
import { RefreshControl, SectionList, Text, TouchableHighlight, View } from 'react-native' import { RefreshControl, SectionList, Text, TouchableHighlight, Vibration, View } from 'react-native'
import { import {
Menu, Menu,
MenuOption, MenuOption,
@@ -120,7 +120,6 @@ export default function StaticTransactions({
renderItem={({ item, index }) => { renderItem={({ item, index }) => {
const category = moneyCategoryStore.getCategoryById(item.category_id) const category = moneyCategoryStore.getCategoryById(item.category_id)
return ( return (
<Menu <Menu
renderer={renderers.Popover} renderer={renderers.Popover}
@@ -135,7 +134,12 @@ export default function StaticTransactions({
onOpen={() => setSelectedId(item.id)} onOpen={() => setSelectedId(item.id)}
onClose={() => setSelectedId(null)} onClose={() => setSelectedId(null)}
> >
<MenuTrigger triggerOnLongPress> <MenuTrigger
triggerOnLongPress
onPress={() => {
Vibration.vibrate(50)
}}
>
<View <View
className="flex-row items-center gap-4 py-2 px-5" className="flex-row items-center gap-4 py-2 px-5"
style={{ style={{
@@ -179,7 +183,6 @@ export default function StaticTransactions({
}, },
}} }}
> >
<MenuOption <MenuOption
customStyles={{ customStyles={{
OptionTouchableComponent: TouchableHighlight, OptionTouchableComponent: TouchableHighlight,
@@ -1,12 +1,34 @@
import type { AFormRef } from '@/components/common/ao' import type { AFormRef } from '@/components/common/ao'
import { SquareUserRound } from 'lucide-react-native'
import * as React from 'react' import * as React from 'react'
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { Text, View } from 'react-native' import { FlatList, Pressable, TouchableOpacity, View } from 'react-native'
import { AButton, AForm, AFormItem, AInput, ASegmentedTabs, ATab, LucideIcon } from '@/components/common/ao' import QRCode from 'react-native-qrcode-svg'
import { AButton, ADivider, AForm, AFormItem, AInput, LucideIcon } from '@/components/common/ao'
import CustomHeader from '@/components/custom/Header' import CustomHeader from '@/components/custom/Header'
import { Badge, BadgeIcon, BadgeText } from '@/components/ui/badge' import {
import { Divider } from '@/components/ui/divider' Accordion,
AccordionContent,
AccordionHeader,
AccordionIcon,
AccordionItem,
AccordionTitleText,
AccordionTrigger,
} from '@/components/ui/accordion'
import {
Avatar,
AvatarBadge,
AvatarFallbackText,
AvatarImage,
} from '@/components/ui/avatar'
import { Badge, BadgeText } from '@/components/ui/badge'
import { Heading } from '@/components/ui/heading'
import { HStack } from '@/components/ui/hstack'
import { ChevronDownIcon, ChevronUpIcon } from '@/components/ui/icon'
import { Link, LinkText } from '@/components/ui/link'
import { Menu, MenuItem, MenuItemLabel } from '@/components/ui/menu'
import { Text } from '@/components/ui/text'
import { VStack } from '@/components/ui/vstack'
export default function PagerWithTab() { export default function PagerWithTab() {
const formRef = useRef<AFormRef>(null) const formRef = useRef<AFormRef>(null)
@@ -14,9 +36,11 @@ export default function PagerWithTab() {
code: '', code: '',
}) })
const [accordion, setAccordion] = useState(['a'])
function EnterSapce() { function EnterSapce() {
return ( return (
<View> <View className="px-4 items-center">
<AForm ref={formRef} form={form}> <AForm ref={formRef} form={form}>
<AFormItem <AFormItem
name="username" name="username"
@@ -26,7 +50,7 @@ export default function PagerWithTab() {
</AFormItem> </AFormItem>
</AForm> </AForm>
<AButton>加入空间</AButton> <AButton className="w-full">加入空间</AButton>
<View <View
className="flex-row items-center w-full" className="flex-row items-center w-full"
style={{ style={{
@@ -35,19 +59,27 @@ export default function PagerWithTab() {
}} }}
> >
<View className="flex-1"> <View className="flex-1">
<Divider /> <ADivider />
</View> </View>
<Text className="mx-3 text-gray-500 text-sm">或</Text> <Text className="mx-3 text-gray-500 text-sm">或</Text>
<View className="flex-1"> <View className="flex-1">
<Divider /> <ADivider />
</View> </View>
</View> </View>
<AButton variant="outline">扫码加入</AButton> <AButton variant="outline" className="w-full">扫码加入</AButton>
<Link className="mt-4">
<LinkText>返回</LinkText>
</Link>
</View> </View>
) )
} }
const members = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' },
]
return ( return (
<View className="flex-1"> <View className="flex-1">
@@ -79,24 +111,65 @@ export default function PagerWithTab() {
<AButton variant="outline">加入已有空间</AButton> <AButton variant="outline">加入已有空间</AButton>
</View> */} </View> */}
<View className="p-4"> {/* <View className="px-4 flex-1">
<View> <Accordion
<View className="flex flex-row items-center justify-between"> size="md"
<Text className="font-semibold text-lg">邀请好友加入</Text> variant="unfilled"
</View> type="multiple"
isCollapsible={true}
<View isDisabled={false}
className="flex-row items-center justify-between px-2 py-2 mt-4 border-round" value={accordion}
style={{ onValueChange={(value) => {
backgroundColor: '#f8f9fa', setAccordion(value)
}}
>
<AccordionItem value="a">
<AccordionHeader>
<AccordionTrigger
style={{
paddingLeft: 0,
paddingRight: 0,
}}
>
{({ isExpanded }: { isExpanded: boolean }) => {
return (
<>
<AccordionTitleText className="font-semibold text-lg">
我的邀请码
</AccordionTitleText>
{isExpanded
? (
<AccordionIcon as={ChevronUpIcon} className="ml-3" />
)
: (
<AccordionIcon as={ChevronDownIcon} className="ml-3" />
)}
</>
)
}}
</AccordionTrigger>
</AccordionHeader>
<AccordionContent style={{
marginBottom: 0,
paddingBottom: 0,
}} }}
> >
<Text>123456</Text> <TouchableOpacity className="flex-row items-center justify-center ">
<AButton size="xs">复制代码</AButton> <Text className="font-bold text-3xl tracking-[4px] mr-3">123456</Text>
</View> <LucideIcon icon="Copy" size={16} color="blue" clickable={false} />
</View> </TouchableOpacity>
<View className="mt-8"> <View className="items-center justify-center">
<ADivider direction="horizontal" text="扫描二维码" />
<QRCode
size={120}
value="http://awesome.link.qr"
/>
</View>
</AccordionContent>
</AccordionItem>
</Accordion>
<View className="mt-4 flex-1">
<View className="flex flex-row items-center justify-between"> <View className="flex flex-row items-center justify-between">
<Text className="font-semibold text-lg">空间成员</Text> <Text className="font-semibold text-lg">空间成员</Text>
<Badge size="lg" variant="solid" action="muted"> <Badge size="lg" variant="solid" action="muted">
@@ -104,12 +177,65 @@ export default function PagerWithTab() {
</Badge> </Badge>
</View> </View>
<View className="mt-2"> <View>
<Text>列表</Text> <FlatList
data={members}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => (
<TouchableOpacity>
<HStack space="md" className="my-2 items-center">
<Avatar className="bg-indigo-600">
<AvatarFallbackText className="text-white text-lg">
{item.name}
</AvatarFallbackText>
<AvatarBadge />
</Avatar>
<VStack>
<HStack space="sm">
<Heading size="sm">{item.name}</Heading>
<Badge size="sm" variant="solid" action="muted">
<BadgeText>管理员</BadgeText>
</Badge>
</HStack>
<Text size="sm">Marketing Coordinator</Text>
</VStack>
<View className="ml-auto">
<Menu
placement="top"
offset={5}
trigger={triggerProps => (
<Pressable
{...triggerProps}
style={{
padding: 8,
justifyContent: 'center',
alignItems: 'center',
}}
>
<LucideIcon icon="EllipsisVertical" size={20} clickable={false} />
</Pressable>
)}
>
<MenuItem key="Add account" textValue="Add account">
<MenuItemLabel size="sm">添加为管理员</MenuItemLabel>
</MenuItem>
<MenuItem key="Community" textValue="Community">
<MenuItemLabel size="sm">移出空间</MenuItemLabel>
</MenuItem>
</Menu>
</View>
</HStack>
</TouchableOpacity>
)}
/>
</View> </View>
<AButton size="sm" className="mb-8 mt-4">退出该空间</AButton>
</View> </View>
</View> </View> */}
<EnterSapce />
</View> </View>
</View> </View>
) )
@@ -0,0 +1,74 @@
import type { ViewStyle } from 'react-native'
import React from 'react'
import { Text, View } from 'react-native'
interface DividerProps {
direction?: 'horizontal' | 'vertical'
text?: string | React.ReactNode
textPosition?: 'left' | 'center' | 'right'
style?: ViewStyle
className?: string
}
export default function Divider({
direction = 'horizontal',
text,
textPosition = 'center',
style,
className,
}: DividerProps) {
const isString = typeof text === 'string'
// 垂直分割线
if (direction === 'vertical') {
return (
<View
style={style}
className={`w-px bg-gray-300 mx-2 h-4 ${className ?? ''}`}
/>
)
}
// 水平,无文字
if (!text) {
return (
<View
style={style}
className={`h-px bg-gray-300 my-2 w-full ${className ?? ''}`}
/>
)
}
// 水平 + 文本
return (
<View
style={style}
className={`flex-row items-center my-2 ${className ?? ''}`}
>
{/* 左线 */}
<View
className={`h-px bg-gray-300 ${
textPosition === 'left' ? 'w-2' : 'flex-1'
}`}
/>
{/* 文本(字符串 → 自动包裹 Text;node → 直接渲染) */}
<View className="mx-3">
{isString
? (
<Text className="text-gray-500 text-sm">{text}</Text>
)
: (
text
)}
</View>
{/* 右线 */}
<View
className={`h-px bg-gray-300 ${
textPosition === 'right' ? 'w-2' : 'flex-1'
}`}
/>
</View>
)
}
@@ -2,6 +2,7 @@ import Button from './Button'
import { Cell, CellGroup } from './Cell' import { Cell, CellGroup } from './Cell'
import Checkbox from './Checkbox' import Checkbox from './Checkbox'
import DatePicker from './DatePicker' import DatePicker from './DatePicker'
import Divider from './Divider'
import Form, { FormRef } from './Form' import Form, { FormRef } from './Form'
import FormItem from './FormItem' import FormItem from './FormItem'
import Input from './Input' import Input from './Input'
@@ -16,6 +17,7 @@ export {
CellGroup as ACellGroup, CellGroup as ACellGroup,
Checkbox as ACheckbox, Checkbox as ACheckbox,
DatePicker as ADatePicker, DatePicker as ADatePicker,
Divider as ADivider,
Form as AForm, Form as AForm,
FormItem as AFormItem, FormItem as AFormItem,
FormRef as AFormRef, FormRef as AFormRef,
@@ -0,0 +1,331 @@
'use client';
import React from 'react';
import { createAccordion } from '@gluestack-ui/core/accordion/creator';
import { View, Pressable, Text, Platform, TextProps } from 'react-native';
import { tva } from '@gluestack-ui/utils/nativewind-utils';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import {
withStyleContext,
useStyleContext,
} from '@gluestack-ui/utils/nativewind-utils';
import { H3 } from '@expo/html-elements';
import { cssInterop } from 'nativewind';
import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator';
const SCOPE = 'ACCORDION';
/** Styles */
const accordionStyle = tva({
base: 'w-full',
variants: {
variant: {
filled: 'bg-white shadow-hard-2',
unfilled: '',
},
size: {
sm: '',
md: '',
lg: '',
},
},
});
const accordionItemStyle = tva({
base: '',
parentVariants: {
variant: {
filled: 'bg-background-0',
unfilled: 'bg-transparent',
},
},
});
const accordionTitleTextStyle = tva({
base: 'text-typography-900 font-bold flex-1 text-left',
parentVariants: {
size: {
sm: 'text-sm',
md: 'text-base',
lg: 'text-lg',
},
},
});
const accordionIconStyle = tva({
base: 'text-typography-900 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 accordionContentTextStyle = tva({
base: 'text-typography-700 font-normal',
parentVariants: {
size: {
sm: 'text-sm',
md: 'text-base',
lg: 'text-lg',
},
},
});
const accordionHeaderStyle = tva({
base: 'mx-0 my-0',
});
const accordionContentStyle = tva({
base: 'pt-1 pb-3 px-4',
});
const accordionTriggerStyle = tva({
base: 'w-full flex-row justify-between items-center web:outline-none focus:outline-none data-[disabled=true]:opacity-40 data-[disabled=true]:cursor-not-allowed data-[focus-visible=true]:bg-background-50 py-3 px-4',
});
const Root = withStyleContext(View, SCOPE);
const Header = (
Platform.OS === 'web' ? H3 : View
) as React.ComponentType<TextProps>;
/** Creator */
const UIAccordion = createAccordion({
Root: Root,
Item: View,
Header: Header,
Trigger: Pressable,
Icon: UIIcon,
TitleText: Text,
ContentText: Text,
Content: View,
});
cssInterop(PrimitiveIcon, {
className: {
target: 'style',
nativeStyleToProp: {
height: true,
width: true,
fill: true,
color: 'classNameColor',
stroke: true,
},
},
});
cssInterop(H3, {
className: {
target: 'style',
},
});
type IAccordionProps = React.ComponentPropsWithoutRef<typeof UIAccordion> &
VariantProps<typeof accordionStyle>;
type IAccordionItemProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.Item
> &
VariantProps<typeof accordionItemStyle>;
type IAccordionContentProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.Content
> &
VariantProps<typeof accordionContentStyle>;
type IAccordionContentTextProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.ContentText
> &
VariantProps<typeof accordionContentTextStyle>;
type IAccordionIconProps = VariantProps<typeof accordionIconStyle> &
React.ComponentPropsWithoutRef<typeof UIAccordion.Icon> & {
as?: React.ElementType;
height?: number;
width?: number;
};
type IAccordionHeaderProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.Header
> &
VariantProps<typeof accordionHeaderStyle>;
type IAccordionTriggerProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.Trigger
> &
VariantProps<typeof accordionTriggerStyle>;
type IAccordionTitleTextProps = React.ComponentPropsWithoutRef<
typeof UIAccordion.TitleText
> &
VariantProps<typeof accordionTitleTextStyle>;
/** Components */
const Accordion = React.forwardRef<
React.ComponentRef<typeof UIAccordion>,
IAccordionProps
>(({ className, variant = 'filled', size = 'md', ...props }, ref) => {
return (
<UIAccordion
ref={ref}
{...props}
className={accordionStyle({ variant, class: className })}
context={{ variant, size }}
/>
);
});
const AccordionItem = React.forwardRef<
React.ComponentRef<typeof UIAccordion.Item>,
IAccordionItemProps
>(({ className, ...props }, ref) => {
const { variant } = useStyleContext(SCOPE);
return (
<UIAccordion.Item
ref={ref}
{...props}
className={accordionItemStyle({
parentVariants: { variant },
class: className,
})}
/>
);
});
const AccordionContent = React.forwardRef<
React.ComponentRef<typeof UIAccordion.Content>,
IAccordionContentProps
>(function AccordionContent({ className, ...props }, ref) {
return (
<UIAccordion.Content
ref={ref}
{...props}
className={accordionContentStyle({
class: className,
})}
/>
);
});
const AccordionContentText = React.forwardRef<
React.ComponentRef<typeof UIAccordion.ContentText>,
IAccordionContentTextProps
>(function AccordionContentText({ className, ...props }, ref) {
const { size } = useStyleContext(SCOPE);
return (
<UIAccordion.ContentText
ref={ref}
{...props}
className={accordionContentTextStyle({
parentVariants: { size },
class: className,
})}
/>
);
});
const AccordionIcon = React.forwardRef<
React.ComponentRef<typeof UIAccordion.Icon>,
IAccordionIconProps
>(function AccordionIcon({ size, className, ...props }, ref) {
const { size: parentSize } = useStyleContext(SCOPE);
if (typeof size === 'number') {
return (
<UIAccordion.Icon
ref={ref}
{...props}
className={accordionIconStyle({ class: className })}
size={size}
/>
);
} else if (
(props.height !== undefined || props.width !== undefined) &&
size === undefined
) {
return (
<UIAccordion.Icon
ref={ref}
{...props}
className={accordionIconStyle({ class: className })}
/>
);
}
return (
<UIAccordion.Icon
ref={ref}
{...props}
className={accordionIconStyle({
size,
class: className,
parentVariants: { size: parentSize },
})}
/>
);
});
const AccordionHeader = React.forwardRef<
React.ComponentRef<typeof UIAccordion.Header>,
IAccordionHeaderProps
>(function AccordionHeader({ className, ...props }, ref) {
return (
<UIAccordion.Header
ref={ref}
{...props}
className={accordionHeaderStyle({
class: className,
})}
/>
);
});
const AccordionTrigger = React.forwardRef<
React.ComponentRef<typeof UIAccordion.Trigger>,
IAccordionTriggerProps
>(function AccordionTrigger({ className, ...props }, ref) {
return (
<UIAccordion.Trigger
ref={ref}
{...props}
className={accordionTriggerStyle({
class: className,
})}
/>
);
});
const AccordionTitleText = React.forwardRef<
React.ComponentRef<typeof UIAccordion.TitleText>,
IAccordionTitleTextProps
>(function AccordionTitleText({ className, ...props }, ref) {
const { size } = useStyleContext(SCOPE);
return (
<UIAccordion.TitleText
ref={ref}
{...props}
className={accordionTitleTextStyle({
parentVariants: { size },
class: className,
})}
/>
);
});
Accordion.displayName = 'Accordion';
AccordionItem.displayName = 'AccordionItem';
AccordionHeader.displayName = 'AccordionHeader';
AccordionTrigger.displayName = 'AccordionTrigger';
AccordionTitleText.displayName = 'AccordionTitleText';
AccordionContentText.displayName = 'AccordionContentText';
AccordionIcon.displayName = 'AccordionIcon';
AccordionContent.displayName = 'AccordionContent';
export {
Accordion,
AccordionItem,
AccordionHeader,
AccordionTrigger,
AccordionTitleText,
AccordionContentText,
AccordionIcon,
AccordionContent,
};
@@ -0,0 +1,220 @@
import React, { forwardRef, memo } from 'react';
import { H1, H2, H3, H4, H5, H6 } from '@expo/html-elements';
import { headingStyle } from './styles';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { cssInterop } from 'nativewind';
type IHeadingProps = VariantProps<typeof headingStyle> &
React.ComponentPropsWithoutRef<typeof H1> & {
as?: React.ElementType;
};
cssInterop(H1, { className: 'style' });
cssInterop(H2, { className: 'style' });
cssInterop(H3, { className: 'style' });
cssInterop(H4, { className: 'style' });
cssInterop(H5, { className: 'style' });
cssInterop(H6, { className: 'style' });
const MappedHeading = memo(
forwardRef<React.ComponentRef<typeof H1>, IHeadingProps>(
function MappedHeading(
{
size,
className,
isTruncated,
bold,
underline,
strikeThrough,
sub,
italic,
highlight,
...props
},
ref
) {
switch (size) {
case '5xl':
case '4xl':
case '3xl':
return (
<H1
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
case '2xl':
return (
<H2
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
case 'xl':
return (
<H3
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
case 'lg':
return (
<H4
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
case 'md':
return (
<H5
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
case 'sm':
case 'xs':
return (
<H6
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
default:
return (
<H4
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
// @ts-expect-error : type issue
ref={ref}
/>
);
}
}
)
);
const Heading = memo(
forwardRef<React.ComponentRef<typeof H1>, IHeadingProps>(function Heading(
{ className, size = 'lg', as: AsComp, ...props },
ref
) {
const {
isTruncated,
bold,
underline,
strikeThrough,
sub,
italic,
highlight,
} = props;
if (AsComp) {
return (
<AsComp
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
/>
);
}
return (
<MappedHeading className={className} size={size} ref={ref} {...props} />
);
})
);
Heading.displayName = 'Heading';
export { Heading };
@@ -0,0 +1,202 @@
import React, { forwardRef, memo } from 'react';
import { headingStyle } from './styles';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
type IHeadingProps = VariantProps<typeof headingStyle> &
React.ComponentPropsWithoutRef<'h1'> & {
as?: React.ElementType;
};
const MappedHeading = memo(
forwardRef<HTMLHeadingElement, IHeadingProps>(function MappedHeading(
{
size,
className,
isTruncated,
bold,
underline,
strikeThrough,
sub,
italic,
highlight,
...props
},
ref
) {
switch (size) {
case '5xl':
case '4xl':
case '3xl':
return (
<h1
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
case '2xl':
return (
<h2
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
case 'xl':
return (
<h3
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
case 'lg':
return (
<h4
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
case 'md':
return (
<h5
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
case 'sm':
case 'xs':
return (
<h6
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
default:
return (
<h4
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
})
);
const Heading = memo(
forwardRef<HTMLHeadingElement, IHeadingProps>(function Heading(
{ className, size = 'lg', as: AsComp, ...props },
ref
) {
const {
isTruncated,
bold,
underline,
strikeThrough,
sub,
italic,
highlight,
} = props;
if (AsComp) {
return (
<AsComp
className={headingStyle({
size,
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
return (
<MappedHeading className={className} size={size} ref={ref} {...props} />
);
})
);
Heading.displayName = 'Heading';
export { Heading };
@@ -0,0 +1,43 @@
import { tva } from '@gluestack-ui/utils/nativewind-utils';
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'font-sans tracking-sm bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word'
: '';
export const headingStyle = tva({
base: `text-typography-900 font-bold font-heading tracking-sm my-0 ${baseStyle}`,
variants: {
isTruncated: {
true: 'truncate',
},
bold: {
true: 'font-bold',
},
underline: {
true: 'underline',
},
strikeThrough: {
true: 'line-through',
},
sub: {
true: 'text-xs',
},
italic: {
true: 'italic',
},
highlight: {
true: 'bg-yellow-500',
},
size: {
'5xl': 'text-6xl',
'4xl': 'text-5xl',
'3xl': 'text-4xl',
'2xl': 'text-3xl',
'xl': 'text-2xl',
'lg': 'text-xl',
'md': 'text-lg',
'sm': 'text-base',
'xs': 'text-sm',
},
},
});
@@ -0,0 +1,27 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { View } from 'react-native';
import type { ViewProps } from 'react-native';
import { hstackStyle } from './styles';
type IHStackProps = ViewProps & VariantProps<typeof hstackStyle>;
const HStack = React.forwardRef<React.ComponentRef<typeof View>, IHStackProps>(
function HStack({ className, space, reversed, ...props }, ref) {
return (
<View
className={hstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
HStack.displayName = 'HStack';
export { HStack };
@@ -0,0 +1,26 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { hstackStyle } from './styles';
type IHStackProps = React.ComponentPropsWithoutRef<'div'> &
VariantProps<typeof hstackStyle>;
const HStack = React.forwardRef<React.ComponentRef<'div'>, IHStackProps>(
function HStack({ className, space, reversed, ...props }, ref) {
return (
<div
className={hstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
HStack.displayName = 'HStack';
export { HStack };
@@ -0,0 +1,25 @@
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
import { tva } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'flex relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none'
: '';
export const hstackStyle = tva({
base: `flex-row ${baseStyle}`,
variants: {
space: {
'xs': 'gap-1',
'sm': 'gap-2',
'md': 'gap-3',
'lg': 'gap-4',
'xl': 'gap-5',
'2xl': 'gap-6',
'3xl': 'gap-7',
'4xl': 'gap-8',
},
reversed: {
true: 'flex-row-reverse',
},
},
});
@@ -0,0 +1,48 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { Text as RNText } from 'react-native';
import { textStyle } from './styles';
type ITextProps = React.ComponentProps<typeof RNText> &
VariantProps<typeof textStyle>;
const Text = React.forwardRef<React.ComponentRef<typeof RNText>, ITextProps>(
function Text(
{
className,
isTruncated,
bold,
underline,
strikeThrough,
size = 'md',
sub,
italic,
highlight,
...props
},
ref
) {
return (
<RNText
className={textStyle({
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
size,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
Text.displayName = 'Text';
export { Text };
@@ -0,0 +1,45 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { textStyle } from './styles';
type ITextProps = React.ComponentProps<'span'> & VariantProps<typeof textStyle>;
const Text = React.forwardRef<React.ComponentRef<'span'>, ITextProps>(
function Text(
{
className,
isTruncated,
bold,
underline,
strikeThrough,
size = 'md',
sub,
italic,
highlight,
...props
}: { className?: string } & ITextProps,
ref
) {
return (
<span
className={textStyle({
isTruncated: isTruncated as boolean,
bold: bold as boolean,
underline: underline as boolean,
strikeThrough: strikeThrough as boolean,
size,
sub: sub as boolean,
italic: italic as boolean,
highlight: highlight as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
Text.displayName = 'Text';
export { Text };
@@ -0,0 +1,47 @@
import { tva } from '@gluestack-ui/utils/nativewind-utils';
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'font-sans tracking-sm my-0 bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word'
: '';
export const textStyle = tva({
base: `text-typography-700 font-body ${baseStyle}`,
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',
},
},
});
@@ -0,0 +1,28 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { View } from 'react-native';
import { vstackStyle } from './styles';
type IVStackProps = React.ComponentProps<typeof View> &
VariantProps<typeof vstackStyle>;
const VStack = React.forwardRef<React.ComponentRef<typeof View>, IVStackProps>(
function VStack({ className, space, reversed, ...props }, ref) {
return (
<View
className={vstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
VStack.displayName = 'VStack';
export { VStack };
@@ -0,0 +1,27 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { vstackStyle } from './styles';
type IVStackProps = React.ComponentProps<'div'> &
VariantProps<typeof vstackStyle>;
const VStack = React.forwardRef<React.ComponentRef<'div'>, IVStackProps>(
function VStack({ className, space, reversed, ...props }, ref) {
return (
<div
className={vstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
VStack.displayName = 'VStack';
export { VStack };
@@ -0,0 +1,25 @@
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
import { tva } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'flex flex-col relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none'
: '';
export const vstackStyle = tva({
base: `flex-col ${baseStyle}`,
variants: {
space: {
'xs': 'gap-1',
'sm': 'gap-2',
'md': 'gap-3',
'lg': 'gap-4',
'xl': 'gap-5',
'2xl': 'gap-6',
'3xl': 'gap-7',
'4xl': 'gap-8',
},
reversed: {
true: 'flex-col-reverse',
},
},
});
@@ -32,8 +32,8 @@ function isWhiteListed(url: string) {
} }
const alovaInstance = createAlova({ const alovaInstance = createAlova({
// baseURL: 'http://192.168.5.6:8086/app', baseURL: 'http://192.168.5.6:8086/app',
baseURL: 'http://192.168.1.136:8086/app', // baseURL: 'http://192.168.1.136:8086/app',
requestAdapter: axiosRequestAdapter(), requestAdapter: axiosRequestAdapter(),
timeout: 5000, timeout: 5000,
cacheFor: null, cacheFor: null,
+120 -429
View File
@@ -1,457 +1,148 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="zh-CN"> <html lang="zh">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>高级邀请页面</title>
<title>查询进度步骤条 - 精确对齐版本</title> <style>
<style> body {
* { margin: 0;
margin: 0; font-family: "Inter", sans-serif;
padding: 0; background: #f3f4f7;
box-sizing: border-box; }
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
padding: 40px 20px;
}
.g3-main-content-indicator{
display: block;
}
.g3-main-content-indicator-title { /* 顶部渐变 Header */
font-size: 22px; .header {
font-weight: 600; width: 100%;
margin-bottom: 15px; padding: 40px 24px;
color: #1a2980; background: linear-gradient(135deg, #4d8dff, #6fa5ff);
} color: white;
font-size: 26px;
font-weight: 600;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.progress-steps { /* 内容卡片 */
display: flex; .container {
justify-content: space-between; margin-top: -32px;
position: relative; padding: 0 24px 40px;
margin: 60px 0px; }
counter-reset: step;
}
.step { .card {
position: relative; background: white;
z-index: 3; padding: 24px;
display: flex; border-radius: 20px;
flex-direction: column; box-shadow: 0 6px 20px rgba(0,0,0,0.06);
align-items: center; margin-bottom: 24px;
flex: 1; }
}
.step-connector { .title-row {
position: absolute; display: flex;
top: 28px; align-items: center;
height: 4px; justify-content: space-between;
background-color: #e0e0e0; }
z-index: 1;
}
.step-progress { .title {
position: absolute; font-size: 20px;
top: 0; font-weight: 600;
left: 0; }
height: 100%;
width: 0;
background: #4b6cb7;
transition: width 0.8s ease, background-color 0.8s ease;
z-index: 2;
}
.step-progress.success { .invite-code {
background: linear-gradient(to right, #4CAF50, #2E7D32); font-size: 40px;
} font-weight: 700;
letter-spacing: 4px;
color: #333;
text-align: center;
margin-top: 12px;
}
.step-progress.failed { .copy-btn {
background: linear-gradient(to right, #f44336, #c62828); display: flex;
} justify-content: center;
margin-top: 8px;
font-size: 14px;
color: #4d8dff;
cursor: pointer;
}
.step-icon { /* 二维码卡片设计 */
width: 50px; .qr-card {
height: 50px; background: white;
border-radius: 50%; padding: 20px;
background: #e0e0e0; border-radius: 20px;
display: flex; text-align: center;
justify-content: center; box-shadow: 0 4px 14px rgba(0,0,0,0.05);
align-items: center; margin-bottom: 24px;
color: #999; }
font-weight: bold;
border: 4px solid white;
box-shadow: 0 0 0 3px #e0e0e0;
transition: all 0.5s ease;
position: relative;
z-index: 4;
font-size: 24px;
}
.step.active .step-icon { .qr-img {
background: #4b6cb7; width: 190px;
color: white; height: 190px;
box-shadow: 0 0 0 3px #b8c6f0; border-radius: 12px;
animation: pulse 1.5s infinite; border: 1px solid #eee;
} }
.step.completed .step-icon { .badge {
background: #4CAF50; background: #eef1ff;
color: white; padding: 6px 14px;
box-shadow: 0 0 0 3px #a5d6a7; border-radius: 14px;
} font-size: 14px;
color: #4d5bff;
}
.step.failed .step-icon { .member-item {
background: #f44336; padding: 14px 0;
color: white; border-bottom: 1px solid #f0f0f0;
box-shadow: 0 0 0 3px #ffcdd2; font-size: 16px;
} }
.step.completed .step-icon::after { .member-item:last-child {
content: '✓'; border-bottom: none;
font-size: 24px; }
} </style>
.step.failed .step-icon::after {
content: '✕';
font-size: 24px;
}
.step-label {
margin-top: 10px;
text-align: center;
font-size: 14px;
color: #666;
font-weight: 500;
max-width: 100px;
}
.step.active .step-label {
color: #4b6cb7;
font-weight: 600;
}
.step.completed .step-label {
color: #4CAF50;
}
.step.failed .step-label {
color: #f44336;
font-weight: 600;
}
.progress-info {
background: #f8f9fa;
border-radius: 8px;
padding: 20px;
margin-top: 20px;
text-align: center;
border-left: 4px solid #4b6cb7;
display: flex;
flex-direction: column;
justify-content: center;
}
.progress-info.failed {
border-left-color: #f44336;
}
.progress-info.success {
border-left-color: #4CAF50;
}
.progress-status {
font-size: 16px;
color: #333;
margin-bottom: 10px;
}
.progress-details {
font-size: 18px;
line-height: 1.5;
}
.progress-time {
display: inline-block;
background: #e3f2fd;
padding: 3px 8px;
border-radius: 4px;
font-size: 16px;
color: #1565c0;
margin-top: 5px;
}
</style>
</head> </head>
<body> <body>
<div id="statusIndicator" class="g3-main-content-indicator">
<div class="g3-main-content-indicator-title">查询状态</div>
<div class="progress-steps">
<!-- 步骤1 -->
<div class="step active" id="step1">
<div class="step-icon">1</div>
<div class="step-label">验证查询条件</div>
</div>
<!-- 步骤2 --> <!-- Header -->
<div class="step" id="step2"> <div class="header">邀请好友加入空间</div>
<div class="step-icon">2</div>
<div class="step-label">发出请求</div>
</div>
<!-- 步骤3 --> <!-- 内容 -->
<div class="step" id="step3"> <div class="container">
<div class="step-icon">3</div>
<div class="step-label">等待响应</div>
</div>
<!-- 步骤4 --> <!-- 邀请码卡片 -->
<div class="step" id="step4"> <div class="card">
<div class="step-icon">4</div> <div class="title-row">
<div class="step-label">查询成功</div> <div class="title">我的邀请码</div>
</div>
<!-- 连接线1-2 -->
<div class="step-connector" id="connector1" style="left: 12.5%; width: 25%;">
<div class="step-progress" id="progress1"></div>
</div>
<!-- 连接线2-3 -->
<div class="step-connector" id="connector2" style="left: 37.5%; width: 25%;">
<div class="step-progress" id="progress2"></div>
</div>
<!-- 连接线3-4 -->
<div class="step-connector" id="connector3" style="left: 62.5%; width: 25%;">
<div class="step-progress" id="progress3"></div>
</div>
</div>
<div class="progress-info" id="progressInfo">
<div class="progress-details" id="progressDetails">
检查查询参数的有效性,确保数据请求符合系统要求。
<div class="progress-time">已用时间: <span id="timeElapsed">0分00秒</span></div>
</div>
</div>
</div> </div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const steps = document.querySelectorAll('.step');
const stepProgresses = document.querySelectorAll('.step-progress');
const connectors = document.querySelectorAll('.step-connector');
const progressInfoElement = document.getElementById('progressInfo');
const progressDetails = document.getElementById('progressDetails');
const timeElapsed = document.getElementById('timeElapsed');
let currentStep = 1; <div class="invite-code">123456</div>
let isRunning = false; <div class="copy-btn">点击复制邀请码</div>
let hasFailed = false; </div>
let timerInterval;
let seconds = 0;
let stepStatus = [null, 'active', null, null, null];
<!-- 二维码卡片 -->
<div class="qr-card">
<img
src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=demo"
class="qr-img"
alt="二维码"
/>
<p style="margin-top: 12px; color: #666; font-size: 14px;">
扫码加入我的共享空间
</p>
</div>
// 计算连接线位置 <!-- 成员卡片 -->
function calculateConnectorPositions() { <div class="card">
const stepWidth = 100 / steps.length; // 每个步骤占据的宽度百分比 <div class="title-row">
<div class="title">空间成员</div>
<div class="badge">3 人</div>
</div>
connectors.forEach((connector, index) => { <div class="member-item">成员 A</div>
// 计算连接线的起始位置和宽度 <div class="member-item">成员 B</div>
const left = (index + 0.5) * stepWidth; // 从第一个步骤的中心开始 <div class="member-item">成员 C</div>
const width = stepWidth; // 连接线宽度等于步骤宽度 </div>
connector.style.left = left + `%`; </div>
connector.style.width = width + `%`;
});
}
// 更新步骤状态
function updateSteps() {
steps.forEach((step, index) => {
step.classList.remove('active', 'completed', 'failed');
if (index + 1 < currentStep) {
step.classList.add('completed');
} else if (index + 1 === currentStep) {
if (currentStep > steps.length) {
// 如果所有步骤已完成,最后一个步骤显示为完成状态
step.classList.add('completed');
} else {
step.classList.add('active');
}
}
});
}
// 更新进度条
function updateProgressBars() {
// 重置所有进度条
stepProgresses.forEach((progress, index) => {
progress.style.width = '0';
progress.classList.remove('success', 'failed');
});
// 设置已完成的进度条
for (let i = 1; i < currentStep; i++) {
if (i <= stepProgresses.length) {
const progress = document.getElementById(`progress` + i);
if (progress) {
progress.style.width = '100%';
// 根据步骤状态设置颜色
if (stepStatus[i] === 'completed') {
progress.classList.add('success');
} else if (stepStatus[i] === 'failed') {
progress.classList.add('failed');
}
}
}
}
}
// 标记步骤失败
function markStepFailed(stepIndex, error) {
stepStatus[stepIndex] = 'failed';
hasFailed = true;
steps[stepIndex - 1].classList.remove('active', 'completed');
steps[stepIndex - 1].classList.add('failed');
// 标记前一个连接线为失败
if (stepIndex > 1) {
const prevProgress = document.getElementById("progress" + (stepIndex - 1));
if (prevProgress) {
prevProgress.classList.add('failed');
}
}
progressInfoElement.classList.add('failed');
isRunning = false;
stopTimer();
updateProgressBars();
}
// 标记步骤成功
function markStepCompleted(stepIndex) {
stepStatus[stepIndex] = 'completed';
updateSteps();
// 标记前一个连接线为成功
if (stepIndex > 1) {
const prevProgress = document.getElementById("progress" + (stepIndex - 1));
if (prevProgress) {
prevProgress.classList.add('success');
}
}
updateProgressBars();
}
// 标记所有步骤完成
function markAllStepsCompleted() {
for (let i = 1; i <= steps.length; i++) {
stepStatus[i] = 'completed';
}
updateSteps();
updateProgressBars();
}
// 更新状态信息
function updateStatus() {
const statusTexts = [
'',
'正在验证查询条件...',
'正在向服务器发出请求...',
'正在等待服务器响应...',
'查询成功,正在处理结果...'
];
const detailTexts = [
'',
'检查查询参数的有效性,确保数据请求符合系统要求。',
'将查询请求发送到远程服务器,建立数据连接。',
'等待服务器处理查询请求并返回结果。',
'处理查询结果并准备返回,即将完成整个过程。'
];
progressDetails.innerHTML = detailTexts[currentStep] +
'<div class="progress-time">已用时间: <span id="timeElapsed">'
+ formatTime(seconds) +
'</span></div>';
progressInfoElement.classList.remove('failed');
}
// 格式化时间显示
function formatTime(totalSeconds) {
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return minutes + "分" + seconds.toString().padStart(2, "0") + "秒";
}
// 开始计时器
function startTimer() {
seconds = 0;
timerInterval = setInterval(() => {
seconds++;
timeElapsed.textContent = formatTime(seconds);
}, 1000);
}
// 停止计时器
function stopTimer() {
clearInterval(timerInterval);
}
// 初始化
updateSteps();
updateProgressBars();
updateStatus();
function runStep() {
if (currentStep > steps.length) {
// 查询完成
isRunning = false;
stopTimer();
markAllStepsCompleted();
progressDetails.innerHTML =
'数据查询已成功完成,结果已准备就绪。' +
'<div class="progress-time">总用时: <span id="timeElapsed">'
+ formatTime(seconds) +
'</span></div>';
return;
}
updateStatus();
updateSteps();
updateProgressBars();
const stepWillFail = Math.random() < 0.2;
const duration = [0,1000,1000,1000,1000][currentStep];
setTimeout(() => {
if (stepWillFail && !hasFailed) {
markStepFailed(currentStep, "模拟失败");
hasFailed = true;
return;
}
markStepCompleted(currentStep);
currentStep++;
runStep(); // ✅ 递归调用下一步
}, duration);
}
runStep();
})
</script>
</body> </body>
</html> </html>