Skip to content

Commit

Permalink
web: Loading indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
mmazzarolo committed Nov 7, 2020
1 parent 5eaebce commit 2b9b57c
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 108 deletions.
2 changes: 1 addition & 1 deletion config-overrides.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = override(
"process.env.NODE_ENV": JSON.stringify(
process.env.NODE_ENV || "development"
),
__DEV__: process.env.NODE_ENV === "production" || true,
__DEV__: process.env.NODE_ENV !== "production",
})
)
);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"android": "react-native run-android",
"ios": "react-native run-ios",
"web": "react-app-rewired start",
"web:build": "react-app-rewired build",
"web:build": "NODE_ENV=production react-app-rewired build",
"start": "react-native start",
"test": "jest",
"test:watch": "jest --watch",
Expand Down
71 changes: 68 additions & 3 deletions public/index.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
:root {
--color-background-root: #fbfaff;
--color-text: #161520;
--color-dot: #8f8c96;
--color-spinner: #8f8c96;
}

@media (prefers-color-scheme: dark) {
:root {
--color-background-root: #161520;
--color-text: #fbf8ff;
--color-spinner: #93bfec;
}
}

Expand Down Expand Up @@ -50,3 +49,69 @@ body,
flex: 1;
background: var(--color-background-root);
}

@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}

#splash {
opacity: 0;
position: absolute;
margin: 0;
padding: 0;
height: 100%;
width: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex: 1;
background: var(--color-background-root);
justify-content: flex-end;
align-items: flex-end;
animation: fade-in ease 0.5s forwards;
animation-delay: 300ms;
}

@keyframes splash-loading-rotate {
100% {
transform: rotate(360deg);
}
}

@keyframes splash-loading-dash {
0% {
stroke-dasharray: 1, 150;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -35;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -124;
}
}

#splash-loading {
animation: splash-loading-rotate 2s linear infinite;
z-index: 2;
position: absolute;
bottom: 24px;
right: 24px;
width: 50px;
height: 50px;
}

#splash-loading-path {
stroke: var(--color-spinner);
stroke-linecap: round;
animation: splash-loading-dash 1.5s ease-in-out infinite;
}
21 changes: 20 additions & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,36 @@
rel="preload"
href="%PUBLIC_URL%/fonts/Averta-Regular.woff2"
as="font"
crossorigin="anonymous"
/>
<link
rel="preload"
href="%PUBLIC_URL%/fonts/Averta-Bold.woff2"
as="font"
crossorigin="anonymous"
/>
<link rel="preload" href="%PUBLIC_URL%/fonts/Averta-Bold.woff2" as="font" />
<link
rel="preload"
href="%PUBLIC_URL%/fonts/Averta-Semibold.woff2"
as="font"
crossorigin="anonymous"
/>
</head>

<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div>
<div id="splash">
<svg id="splash-loading" viewBox="0 0 50 50">
<circle
id="splash-loading-path"
cx="25"
cy="25"
r="20"
fill="none"
stroke-width="5"
></circle>
</svg>
</div>
</body>
</html>
12 changes: 9 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ import { App } from "op-core";

AppRegistry.registerComponent("OrdinaryPuzzles", () => App);

// @ts-ignore
document.fonts.ready.then(() => {
// Load the app only when all the fonts are loaded
// Load the app only when all the fonts are loaded
Promise.all([
// @ts-ignore
document.fonts.load("12px Averta-Bold"),
// @ts-ignore
document.fonts.load("12px Averta-Semibold"),
// @ts-ignore
document.fonts.load("12px Averta-Regular"),
]).then((f) => {
AppRegistry.runApplication("OrdinaryPuzzles", {
rootTag: document.getElementById("root"),
});
Expand Down
2 changes: 1 addition & 1 deletion src/op-config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const simulateProduction = false;
const _enableMobxLogging = true;

// Don't show the splash screen
const _skipSplashScreen = true;
const _skipSplashScreen = false;

// Clean the local-storage
const _simulateFirstLoad = false;
Expand Down
109 changes: 109 additions & 0 deletions src/op-splash/Splash.native.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React, { FC, useRef } from "react";
import { StyleSheet, Animated, TouchableWithoutFeedback } from "react-native";
import { Text } from "op-common";
import { useAnimation, useOnMount, scale, delay } from "op-utils";
import { animations, metrics, colors } from "op-design";
import { credits } from "op-config";

const asyncAnimationStart = (anim: Animated.CompositeAnimation) =>
new Promise((resolve) => anim.start(resolve));

interface SplashProps {
onHide: () => void;
}

export const Splash: FC<SplashProps> = function ({ onHide }) {
const skippingEnabledRef = useRef(true);
const hasSkippedRef = useRef(false);

// Animations setup
const fadeCreditsAnimDuration = 200;
const fadeCreditsStaggerDuration = 100;
const backgroundColorAnimDuration = 200;
// We can use hooks in loops in this case because "credits" is a constant
// eslint-disable-next-line react-hooks/rules-of-hooks
const fadeCreditsAnims = credits.map(() => useAnimation());
const backgroundColorAnim = useAnimation();
const splashDuration = 2000;
const showAnim = Animated.stagger(
fadeCreditsStaggerDuration,
fadeCreditsAnims.map((anim) =>
anim.setup({ duration: fadeCreditsAnimDuration })
)
);

const hideAnim = Animated.sequence([
Animated.stagger(
fadeCreditsStaggerDuration,
fadeCreditsAnims.map((anim) =>
anim.setup({ duration: fadeCreditsAnimDuration, toValue: 0 })
)
),
backgroundColorAnim.setup({
duration: backgroundColorAnimDuration,
useNativeDriver: false,
}),
]);

const animate = async () => {
await asyncAnimationStart(showAnim);
await delay(splashDuration);
skippingEnabledRef.current = false;
if (!hasSkippedRef.current) {
await asyncAnimationStart(hideAnim);
onHide();
}
};

useOnMount(() => {
animate();
});

const rootAnimStyle = {
backgroundColor: backgroundColorAnim.value.interpolate({
inputRange: [0, 1],
outputRange: [colors.splash, colors.primary[9]],
}),
};

// If the user touches the screen, end the animation early
const handlePress = () => {
if (!skippingEnabledRef.current || hasSkippedRef.current) return;
hasSkippedRef.current = true;
hideAnim.start(onHide);
};

return (
<TouchableWithoutFeedback onPress={handlePress}>
<Animated.View style={[styles.root, rootAnimStyle]}>
{credits.map((credit, index) => (
<Text
key={credit}
weight="bold"
style={[
styles.credit,
animations.fadeSlideBottom(fadeCreditsAnims[index].value),
]}
>
{credit}
</Text>
))}
</Animated.View>
</TouchableWithoutFeedback>
);
};

const styles = StyleSheet.create({
root: {
padding: metrics.screenMargin,
flex: 1,
flexDirection: "column",
justifyContent: "center",
backgroundColor: colors.splash,
},
credit: {
color: "white",
fontSize: scale(28),
marginVertical: scale(12),
},
});
104 changes: 6 additions & 98 deletions src/op-splash/Splash.tsx
Original file line number Diff line number Diff line change
@@ -1,109 +1,17 @@
import React, { FC, useRef } from "react";
import { StyleSheet, Animated, TouchableWithoutFeedback } from "react-native";
import { Text } from "op-common";
import { useAnimation, useOnMount, scale, delay } from "op-utils";
import { animations, metrics, colors } from "op-design";
import { credits } from "op-config";

const asyncAnimationStart = (anim: Animated.CompositeAnimation) =>
new Promise((resolve) => anim.start(resolve));
import { FC } from "react";
import { useOnMount } from "op-utils";

interface SplashProps {
onHide: () => void;
}

export const Splash: FC<SplashProps> = function ({ onHide }) {
const skippingEnabledRef = useRef(true);
const hasSkippedRef = useRef(false);

// Animations setup
const fadeCreditsAnimDuration = 200;
const fadeCreditsStaggerDuration = 100;
const backgroundColorAnimDuration = 200;
// We can use hooks in loops in this case because "credits" is a constant
// eslint-disable-next-line react-hooks/rules-of-hooks
const fadeCreditsAnims = credits.map(() => useAnimation());
const backgroundColorAnim = useAnimation();
const splashDuration = 2000;
const showAnim = Animated.stagger(
fadeCreditsStaggerDuration,
fadeCreditsAnims.map((anim) =>
anim.setup({ duration: fadeCreditsAnimDuration })
)
);

const hideAnim = Animated.sequence([
Animated.stagger(
fadeCreditsStaggerDuration,
fadeCreditsAnims.map((anim) =>
anim.setup({ duration: fadeCreditsAnimDuration, toValue: 0 })
)
),
backgroundColorAnim.setup({
duration: backgroundColorAnimDuration,
useNativeDriver: false,
}),
]);

const animate = async () => {
await asyncAnimationStart(showAnim);
await delay(splashDuration);
skippingEnabledRef.current = false;
if (!hasSkippedRef.current) {
await asyncAnimationStart(hideAnim);
onHide();
}
};
// @ts-ignore
document.getElementById("splash").style.display = "none";

useOnMount(() => {
animate();
onHide();
});

const rootAnimStyle = {
backgroundColor: backgroundColorAnim.value.interpolate({
inputRange: [0, 1],
outputRange: [colors.splash, colors.primary[9]],
}),
};

// If the user touches the screen, end the animation early
const handlePress = () => {
if (!skippingEnabledRef.current || hasSkippedRef.current) return;
hasSkippedRef.current = true;
hideAnim.start(onHide);
};

return (
<TouchableWithoutFeedback onPress={handlePress}>
<Animated.View style={[styles.root, rootAnimStyle]}>
{credits.map((credit, index) => (
<Text
key={credit}
weight="bold"
style={[
styles.credit,
animations.fadeSlideBottom(fadeCreditsAnims[index].value),
]}
>
{credit}
</Text>
))}
</Animated.View>
</TouchableWithoutFeedback>
);
return null;
};

const styles = StyleSheet.create({
root: {
padding: metrics.screenMargin,
flex: 1,
flexDirection: "column",
justifyContent: "center",
backgroundColor: colors.splash,
},
credit: {
color: "white",
fontSize: scale(28),
marginVertical: scale(12),
},
});

0 comments on commit 2b9b57c

Please sign in to comment.