This commit is contained in:
oneao committed 2025-10-27 22:25:58 +08:00
1 parent b9744acdc0
commit 2f021ec51f
13 files changed
+277 -73

No files matched your search

@@ -0,0 +1,23 @@
import FontAwesome from '@expo/vector-icons/FontAwesome'
import { Tabs } from 'expo-router'
export default function TabLayout() {
return (
<Tabs screenOptions={{ tabBarActiveTintColor: 'blue', tabBarShowLabel: false }}>
<Tabs.Screen
name="index"
options={{
headerShown: false,
tabBarIcon: ({ color }) => <FontAwesome size={28} name="home" color={color} />,
}}
/>
<Tabs.Screen
name="settings"
options={{
headerShown: false,
tabBarIcon: ({ color }) => <FontAwesome size={28} name="cog" color={color} />,
}}
/>
</Tabs>
)
}
@@ -0,0 +1,26 @@
import { Ionicons } from '@expo/vector-icons'
import { router } from 'expo-router'
import { StyleSheet, Text, View } from 'react-native'
import { Button, ButtonIcon, ButtonText } from '@/components/ui/button'
export default function Tab() {
const to404 = () => {
router.navigate('/abc')
}
return (
<View style={styles.container}>
<Button onPress={to404} className="flex items-center justify-center">
<ButtonText size="sm">测试</ButtonText>
</Button>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
})
@@ -0,0 +1,17 @@
import { StyleSheet, Text, View } from 'react-native'
export default function Tab() {
return (
<View style={styles.container}>
<Text>Tab [Settings]</Text>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
})
+20 -4
View File
@@ -1,9 +1,25 @@
import { Text, View } from 'react-native'
import { router, Stack } from 'expo-router'
import LottieView from 'lottie-react-native'
import { ArrowLeft } from 'lucide-react-native'
import { View } from 'react-native'
import { Button, ButtonIcon, ButtonText } from '@/components/ui/button'
export default function NotFound() {
return (
<View>
<Text>404</Text>
</View>
<>
<Stack.Screen options={{ headerShown: false }} />
<View className="flex-1 justify-center items-center bg-white">
<LottieView
source={require('@/static/lottie/404.json')}
style={{ width: 300, height: 300 }}
autoPlay
loop
/>
<Button onPress={() => router.replace('/')}>
<ButtonIcon as={ArrowLeft} />
<ButtonText>返回应用首页</ButtonText>
</Button>
</View>
</>
)
}
+38 -3
View File
@@ -1,14 +1,49 @@
import type { ErrorBoundaryProps } from 'expo-router'
import { useFonts } from 'expo-font'
import { Stack } from 'expo-router'
import * as SplashScreen from 'expo-splash-screen'
import { StatusBar } from 'expo-status-bar'
import { useEffect } from 'react'
import { Text, View } from 'react-native'
import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider'
import '@/styles/global.css'
SplashScreen.preventAutoHideAsync()
export function ErrorBoundary({ error, retry }: ErrorBoundaryProps) {
return (
<View style={{ flex: 1 }}>
<Text>{error.message}</Text>
<Text onPress={retry}>Try Again?</Text>
</View>
)
}
export default function Layout() {
const [loaded, error] = useFonts({
SpaceMono: require('@/static/fonts/SpaceMono-Regular.ttf'),
})
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync()
}
}, [loaded])
// 模拟错误,100%发生
throw new Error('模拟错误测试 ErrorBoundary!')
return (
<GluestackUIProvider>
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="modal" options={{ presentation: 'modal', title: 'Modal' }} />
<Stack
screenOptions={{
headerTitleAlign: 'center',
animation: 'slide_from_right',
}}
>
<Stack.Screen
name="(tabs)"
options={{ headerShown: false }}
/>
</Stack>
<StatusBar style="auto" />
</GluestackUIProvider>
@@ -1,27 +1,28 @@
'use client';
import React from 'react';
import { createButton } from '@gluestack-ui/core/button/creator';
'use client'
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'
import { createButton } from '@gluestack-ui/core/button/creator'
import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'
import {
tva,
withStyleContext,
useStyleContext,
type VariantProps,
} from '@gluestack-ui/utils/nativewind-utils';
import { cssInterop } from 'nativewind';
import { ActivityIndicator, Pressable, Text, View } from 'react-native';
import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator';
const SCOPE = 'BUTTON';
withStyleContext,
} from '@gluestack-ui/utils/nativewind-utils'
import { cssInterop } from 'nativewind'
import React from 'react'
import { ActivityIndicator, Pressable, Text, View } from 'react-native'
const Root = withStyleContext(Pressable, SCOPE);
const SCOPE = 'BUTTON'
const Root = withStyleContext(Pressable, SCOPE)
const UIButton = createButton({
Root: Root,
Root,
Text,
Group: View,
Spinner: ActivityIndicator,
Icon: UIIcon,
});
})
cssInterop(PrimitiveIcon, {
className: {
@@ -34,7 +35,7 @@ cssInterop(PrimitiveIcon, {
stroke: true,
},
},
});
})
const buttonStyle = tva({
base: 'group/button rounded bg-primary-500 flex-row items-center justify-center data-[focus-visible=true]:web:outline-none data-[focus-visible=true]:web:ring-2 data-[disabled=true]:opacity-40 gap-2',
@@ -116,7 +117,7 @@ const buttonStyle = tva({
'bg-transparent data-[hover=true]:bg-background-50 data-[active=true]:bg-transparent',
},
],
});
})
const buttonTextStyle = tva({
base: 'text-typography-0 font-semibold web:select-none',
@@ -195,7 +196,7 @@ const buttonTextStyle = tva({
'text-primary-500 data-[hover=true]:text-primary-500 data-[active=true]:text-primary-500',
},
],
});
})
const buttonIconStyle = tva({
base: 'fill-none',
@@ -251,7 +252,7 @@ const buttonIconStyle = tva({
'text-typography-0 data-[hover=true]:text-typography-0 data-[active=true]:text-typography-0',
},
],
});
})
const buttonGroupStyle = tva({
base: '',
@@ -276,13 +277,13 @@ const buttonGroupStyle = tva({
'column-reverse': 'flex-col-reverse',
},
},
});
})
type IButtonProps = Omit<
React.ComponentPropsWithoutRef<typeof UIButton>,
'context'
> &
VariantProps<typeof buttonStyle> & { className?: string };
>
& VariantProps<typeof buttonStyle> & { className?: string }
const Button = React.forwardRef<
React.ElementRef<typeof UIButton>,
@@ -290,7 +291,7 @@ const Button = React.forwardRef<
>(
(
{ className, variant = 'solid', size = 'md', action = 'primary', ...props },
ref
ref,
) => {
return (
<UIButton
@@ -299,12 +300,12 @@ const Button = React.forwardRef<
className={buttonStyle({ variant, size, action, class: className })}
context={{ variant, size, action }}
/>
);
}
);
)
},
)
type IButtonTextProps = React.ComponentPropsWithoutRef<typeof UIButton.Text> &
VariantProps<typeof buttonTextStyle> & { className?: string };
type IButtonTextProps = React.ComponentPropsWithoutRef<typeof UIButton.Text>
& VariantProps<typeof buttonTextStyle> & { className?: string }
const ButtonText = React.forwardRef<
React.ElementRef<typeof UIButton.Text>,
@@ -314,7 +315,7 @@ const ButtonText = React.forwardRef<
variant: parentVariant,
size: parentSize,
action: parentAction,
} = useStyleContext(SCOPE);
} = useStyleContext(SCOPE)
return (
<UIButton.Text
@@ -332,18 +333,18 @@ const ButtonText = React.forwardRef<
class: className,
})}
/>
);
});
)
})
const ButtonSpinner = UIButton.Spinner;
const ButtonSpinner = UIButton.Spinner
type IButtonIcon = React.ComponentPropsWithoutRef<typeof UIButton.Icon> &
VariantProps<typeof buttonIconStyle> & {
className?: string | undefined;
as?: React.ElementType;
height?: number;
width?: number;
};
type IButtonIcon = React.ComponentPropsWithoutRef<typeof UIButton.Icon>
& VariantProps<typeof buttonIconStyle> & {
className?: string | undefined
as?: React.ElementType
height?: number
width?: number
}
const ButtonIcon = React.forwardRef<
React.ElementRef<typeof UIButton.Icon>,
@@ -353,7 +354,7 @@ const ButtonIcon = React.forwardRef<
variant: parentVariant,
size: parentSize,
action: parentAction,
} = useStyleContext(SCOPE);
} = useStyleContext(SCOPE)
if (typeof size === 'number') {
return (
@@ -363,10 +364,11 @@ const ButtonIcon = React.forwardRef<
className={buttonIconStyle({ class: className })}
size={size}
/>
);
} else if (
(props.height !== undefined || props.width !== undefined) &&
size === undefined
)
}
else if (
(props.height !== undefined || props.width !== undefined)
&& size === undefined
) {
return (
<UIButton.Icon
@@ -374,7 +376,7 @@ const ButtonIcon = React.forwardRef<
{...props}
className={buttonIconStyle({ class: className })}
/>
);
)
}
return (
<UIButton.Icon
@@ -390,11 +392,11 @@ const ButtonIcon = React.forwardRef<
})}
ref={ref}
/>
);
});
)
})
type IButtonGroupProps = React.ComponentPropsWithoutRef<typeof UIButton.Group> &
VariantProps<typeof buttonGroupStyle>;
type IButtonGroupProps = React.ComponentPropsWithoutRef<typeof UIButton.Group>
& VariantProps<typeof buttonGroupStyle>
const ButtonGroup = React.forwardRef<
React.ElementRef<typeof UIButton.Group>,
@@ -408,7 +410,7 @@ const ButtonGroup = React.forwardRef<
flexDirection = 'column',
...props
},
ref
ref,
) => {
return (
<UIButton.Group
@@ -421,14 +423,14 @@ const ButtonGroup = React.forwardRef<
{...props}
ref={ref}
/>
);
}
);
)
},
)
Button.displayName = 'Button';
ButtonText.displayName = 'ButtonText';
ButtonSpinner.displayName = 'ButtonSpinner';
ButtonIcon.displayName = 'ButtonIcon';
ButtonGroup.displayName = 'ButtonGroup';
Button.displayName = 'Button'
ButtonText.displayName = 'ButtonText'
ButtonSpinner.displayName = 'ButtonSpinner'
ButtonIcon.displayName = 'ButtonIcon'
ButtonGroup.displayName = 'ButtonGroup'
export { Button, ButtonText, ButtonSpinner, ButtonIcon, ButtonGroup };
export { Button, ButtonGroup, ButtonIcon, ButtonSpinner, ButtonText }
@@ -0,0 +1 @@
{"v":"5.0.3","fr":60,"ip":0,"op":481,"w":1920,"h":1080,"nm":"08 - 404 Page-2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"astronaut","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":0,"s":[0],"e":[6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":240,"s":[6],"e":[0]},{"t":480}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":0,"s":[1053.917,479.903,0],"e":[1004.917,482.903,0],"to":[-8.16666698455811,0.5,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":240,"s":[1004.917,482.903,0],"e":[1053.917,479.903,0],"to":[0,0,0],"ti":[-8.16666698455811,0.5,0]},{"t":480}],"ix":2},"a":{"a":0,"k":[238.431,194.157,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.695,-0.123],[0.208,-1.775],[-8.528,-22.143],[-16.702,-14.602],[-1.408,1.101],[11.447,29.719],[28.36,-0.002]],"o":[[-1.783,0.13],[-2.59,22.033],[8.528,22.142],[1.345,1.177],[23.868,-18.628],[-10.804,-28.052],[-1.688,0]],"v":[[-38.22,-63.515],[-41.631,-60.213],[-33.12,6.934],[5.611,62.44],[10.354,62.6],[32.773,-18.445],[-33.138,-63.699]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":1,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"g":{"p":3,"k":{"a":0,"k":[0,1,0.4431,0,0.5,0.1972,0.3055,0.3828,1,0.0306,0.0999,0.1494,0,1,0.5,0.995,1,0.99],"ix":9}},"s":{"a":0,"k":[80,-37],"ix":5},"e":{"a":0,"k":[-23.5,9],"ix":6},"t":1,"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[322.001,69.707],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"visor","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-13.398,-34.788],[34.788,-13.398],[13.4,34.788],[-34.788,13.399]],"o":[[13.399,34.788],[-34.788,13.399],[-13.398,-34.788],[34.788,-13.399]],"v":[[62.989,-24.261],[24.261,62.989],[-62.99,24.261],[-24.261,-62.989]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[288.878,76.638],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"helmet","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[264.015,127.254],"ix":2},"a":{"a":0,"k":[264.015,127.254],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[-6]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":240,"s":[-6],"e":[0]},{"t":480}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"helmet","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p833_1_0p167_0p167","t":0,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-2.649,9.747],[8.886,-1.547]],"c":false}],"e":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.153,4.911],[6.153,-4.911]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":60,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.153,4.911],[6.153,-4.911]],"c":false}],"e":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0.097,13.536],[11.028,1.089]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":180,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0.097,13.536],[11.028,1.089]],"c":false}],"e":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.153,4.911],[6.153,-4.911]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":300,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-6.153,4.911],[6.153,-4.911]],"c":false}],"e":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0.097,13.536],[11.028,1.089]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":420,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0.097,13.536],[11.028,1.089]],"c":false}],"e":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,Line truncated