fix(app-expo): use brand splash icon on logout replay overlay
Replace Expo template logo and blue gradient with splash-icon.png and Co-authored-by: Cursor <cursoragent@cursor.com> #E6F4FE so post-logout splash matches the native cold-start screen.
This commit is contained in:
@@ -1,6 +0,0 @@
|
|||||||
.expoLogoBackground {
|
|
||||||
background-image: linear-gradient(180deg, #3c9ffe, #0274df);
|
|
||||||
border-radius: 40px;
|
|
||||||
width: 128px;
|
|
||||||
height: 128px;
|
|
||||||
}
|
|
||||||
@@ -8,9 +8,11 @@ import { completeSplashReplay } from '@/core/splash-replay';
|
|||||||
|
|
||||||
const INITIAL_SCALE_FACTOR = Dimensions.get('screen').height / 90;
|
const INITIAL_SCALE_FACTOR = Dimensions.get('screen').height / 90;
|
||||||
const DURATION = 600;
|
const DURATION = 600;
|
||||||
|
/** Matches expo-splash-screen `imageWidth` in app.config.ts */
|
||||||
|
const SPLASH_LOGO_SIZE = 200;
|
||||||
|
|
||||||
/** Brand gate background (matches native splash / overlay). */
|
/** Brand gate background — matches native splash / adaptiveIcon (#E6F4FE). */
|
||||||
export const BRAND_BOOTSTRAP_BG = '#208AEF';
|
export const BRAND_BOOTSTRAP_BG = '#E6F4FE';
|
||||||
|
|
||||||
export function AnimatedSplashOverlay() {
|
export function AnimatedSplashOverlay() {
|
||||||
const [visible, setVisible] = useState(true);
|
const [visible, setVisible] = useState(true);
|
||||||
@@ -61,100 +63,41 @@ export function BrandBootstrapLoading() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyframe = new Keyframe({
|
|
||||||
0: {
|
|
||||||
transform: [{ scale: INITIAL_SCALE_FACTOR }],
|
|
||||||
},
|
|
||||||
100: {
|
|
||||||
transform: [{ scale: 1 }],
|
|
||||||
easing: Easing.elastic(0.7),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const logoKeyframe = new Keyframe({
|
const logoKeyframe = new Keyframe({
|
||||||
0: {
|
0: {
|
||||||
transform: [{ scale: 1.3 }],
|
transform: [{ scale: 0.92 }],
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
},
|
},
|
||||||
40: {
|
|
||||||
transform: [{ scale: 1.3 }],
|
|
||||||
opacity: 0,
|
|
||||||
easing: Easing.elastic(0.7),
|
|
||||||
},
|
|
||||||
100: {
|
100: {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
transform: [{ scale: 1 }],
|
transform: [{ scale: 1 }],
|
||||||
easing: Easing.elastic(0.7),
|
easing: Easing.out(Easing.cubic),
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const glowKeyframe = new Keyframe({
|
|
||||||
0: {
|
|
||||||
transform: [{ rotateZ: '0deg' }],
|
|
||||||
},
|
|
||||||
100: {
|
|
||||||
transform: [{ rotateZ: '7200deg' }],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function AnimatedIcon() {
|
export function AnimatedIcon() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.iconContainer}>
|
<Animated.View
|
||||||
<Animated.View
|
style={styles.logoContainer}
|
||||||
entering={glowKeyframe.duration(60 * 1000 * 4)}
|
entering={logoKeyframe.duration(DURATION)}
|
||||||
style={styles.glow}
|
>
|
||||||
>
|
<Image
|
||||||
<Image
|
style={styles.splashLogo}
|
||||||
style={styles.glow}
|
source={require('@/assets/images/splash-icon.png')}
|
||||||
source={require('@/assets/images/logo-glow.png')}
|
contentFit="contain"
|
||||||
/>
|
|
||||||
</Animated.View>
|
|
||||||
|
|
||||||
<Animated.View
|
|
||||||
entering={keyframe.duration(DURATION)}
|
|
||||||
style={styles.background}
|
|
||||||
/>
|
/>
|
||||||
<Animated.View
|
</Animated.View>
|
||||||
style={styles.imageContainer}
|
|
||||||
entering={logoKeyframe.duration(DURATION)}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
style={styles.image}
|
|
||||||
source={require('@/assets/images/expo-logo.png')}
|
|
||||||
/>
|
|
||||||
</Animated.View>
|
|
||||||
</View>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
imageContainer: {
|
logoContainer: {
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
glow: {
|
splashLogo: {
|
||||||
width: 201,
|
width: SPLASH_LOGO_SIZE,
|
||||||
height: 201,
|
height: SPLASH_LOGO_SIZE,
|
||||||
position: 'absolute',
|
|
||||||
},
|
|
||||||
iconContainer: {
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
width: 128,
|
|
||||||
height: 128,
|
|
||||||
zIndex: 100,
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
position: 'absolute',
|
|
||||||
width: 76,
|
|
||||||
height: 71,
|
|
||||||
},
|
|
||||||
background: {
|
|
||||||
borderRadius: 40,
|
|
||||||
experimental_backgroundImage: `linear-gradient(180deg, #3C9FFE, #0274DF)`,
|
|
||||||
width: 128,
|
|
||||||
height: 128,
|
|
||||||
position: 'absolute',
|
|
||||||
},
|
},
|
||||||
backgroundSolidColor: {
|
backgroundSolidColor: {
|
||||||
...StyleSheet.absoluteFillObject,
|
...StyleSheet.absoluteFillObject,
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { Image } from 'expo-image';
|
import { Image } from 'expo-image';
|
||||||
import { StyleSheet, View } from 'react-native';
|
import { StyleSheet, View } from 'react-native';
|
||||||
import Animated, { Keyframe, Easing } from 'react-native-reanimated';
|
import Animated, { Easing, Keyframe } from 'react-native-reanimated';
|
||||||
|
|
||||||
import classes from './animated-icon.module.css';
|
/** Matches expo-splash-screen `imageWidth` in app.config.ts */
|
||||||
|
const SPLASH_LOGO_SIZE = 200;
|
||||||
const DURATION = 300;
|
const DURATION = 300;
|
||||||
|
|
||||||
/** Brand gate background (matches native splash / overlay). */
|
/** Brand gate background — matches native splash / adaptiveIcon (#E6F4FE). */
|
||||||
export const BRAND_BOOTSTRAP_BG = '#208AEF';
|
export const BRAND_BOOTSTRAP_BG = '#E6F4FE';
|
||||||
|
|
||||||
export function AnimatedSplashOverlay() {
|
export function AnimatedSplashOverlay() {
|
||||||
return null;
|
return null;
|
||||||
@@ -21,81 +22,30 @@ export function BrandBootstrapLoading() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyframe = new Keyframe({
|
|
||||||
0: {
|
|
||||||
transform: [{ scale: 0 }],
|
|
||||||
},
|
|
||||||
60: {
|
|
||||||
transform: [{ scale: 1.2 }],
|
|
||||||
easing: Easing.elastic(1.2),
|
|
||||||
},
|
|
||||||
100: {
|
|
||||||
transform: [{ scale: 1 }],
|
|
||||||
easing: Easing.elastic(1.2),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const logoKeyframe = new Keyframe({
|
const logoKeyframe = new Keyframe({
|
||||||
0: {
|
0: {
|
||||||
|
transform: [{ scale: 0.92 }],
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
},
|
},
|
||||||
60: {
|
|
||||||
transform: [{ scale: 1.2 }],
|
|
||||||
opacity: 0,
|
|
||||||
easing: Easing.elastic(1.2),
|
|
||||||
},
|
|
||||||
100: {
|
100: {
|
||||||
transform: [{ scale: 1 }],
|
transform: [{ scale: 1 }],
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
easing: Easing.elastic(1.2),
|
easing: Easing.out(Easing.cubic),
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const glowKeyframe = new Keyframe({
|
|
||||||
0: {
|
|
||||||
transform: [{ rotateZ: '-180deg' }, { scale: 0.8 }],
|
|
||||||
opacity: 0,
|
|
||||||
},
|
|
||||||
[DURATION / 1000]: {
|
|
||||||
transform: [{ rotateZ: '0deg' }, { scale: 1 }],
|
|
||||||
opacity: 1,
|
|
||||||
easing: Easing.elastic(0.7),
|
|
||||||
},
|
|
||||||
100: {
|
|
||||||
transform: [{ rotateZ: '7200deg' }],
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function AnimatedIcon() {
|
export function AnimatedIcon() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.iconContainer}>
|
<Animated.View
|
||||||
<Animated.View
|
style={styles.logoContainer}
|
||||||
entering={glowKeyframe.duration(60 * 1000 * 4)}
|
entering={logoKeyframe.duration(DURATION)}
|
||||||
style={styles.glow}
|
>
|
||||||
>
|
<Image
|
||||||
<Image
|
style={styles.splashLogo}
|
||||||
style={styles.glow}
|
source={require('@/assets/images/splash-icon.png')}
|
||||||
source={require('@/assets/images/logo-glow.png')}
|
contentFit="contain"
|
||||||
/>
|
/>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|
||||||
<Animated.View
|
|
||||||
style={styles.background}
|
|
||||||
entering={keyframe.duration(DURATION)}
|
|
||||||
>
|
|
||||||
<div className={classes.expoLogoBackground} />
|
|
||||||
</Animated.View>
|
|
||||||
|
|
||||||
<Animated.View
|
|
||||||
style={styles.imageContainer}
|
|
||||||
entering={logoKeyframe.duration(DURATION)}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
style={styles.image}
|
|
||||||
source={require('@/assets/images/expo-logo.png')}
|
|
||||||
/>
|
|
||||||
</Animated.View>
|
|
||||||
</View>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,36 +56,12 @@ const styles = StyleSheet.create({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
container: {
|
logoContainer: {
|
||||||
alignItems: 'center',
|
|
||||||
width: '100%',
|
|
||||||
zIndex: 1000,
|
|
||||||
position: 'absolute',
|
|
||||||
top: 128 / 2 + 138,
|
|
||||||
},
|
|
||||||
imageContainer: {
|
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
glow: {
|
splashLogo: {
|
||||||
width: 201,
|
width: SPLASH_LOGO_SIZE,
|
||||||
height: 201,
|
height: SPLASH_LOGO_SIZE,
|
||||||
position: 'absolute',
|
|
||||||
},
|
|
||||||
iconContainer: {
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
width: 128,
|
|
||||||
height: 128,
|
|
||||||
},
|
|
||||||
image: {
|
|
||||||
position: 'absolute',
|
|
||||||
width: 76,
|
|
||||||
height: 71,
|
|
||||||
},
|
|
||||||
background: {
|
|
||||||
width: 128,
|
|
||||||
height: 128,
|
|
||||||
position: 'absolute',
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user