From 7e297e4d4114ccac88fc272e2977b50c4a01c390 Mon Sep 17 00:00:00 2001 From: Aarni Halinen Date: Sat, 16 Jan 2021 21:44:14 +0200 Subject: [PATCH] Loader view & component --- src/components/AdminHeader.tsx | 12 +-- src/components/Loader.tsx | 46 ++++++++++ src/pages/events/[id].tsx | 3 +- src/views/EventPage/EventPageView.tsx | 3 +- src/views/SignUpPage/SignUpPageView.tsx | 9 +- src/views/common/AdminPageWrapper.tsx | 4 +- src/views/common/LoadingView.tsx | 106 ++++++++++++++++++++++++ 7 files changed, 173 insertions(+), 10 deletions(-) create mode 100644 src/components/Loader.tsx create mode 100644 src/views/common/LoadingView.tsx diff --git a/src/components/AdminHeader.tsx b/src/components/AdminHeader.tsx index 2596349..4886924 100644 --- a/src/components/AdminHeader.tsx +++ b/src/components/AdminHeader.tsx @@ -5,14 +5,16 @@ import { colors } from "@theme/colors"; const Header = styled.header` background-color: ${colors.darkBlue}; + display: flex; + flex-flow: row nowrap; + justify-content: center; a { + flex: 1 0 auto; + margin: 0.5rem auto; + max-width: 600px; + img { - display: block; - margin: 0.5rem auto; - padding: 2rem; - width: 100%; - max-width: 800px; fill: ${colors.white}; } } diff --git a/src/components/Loader.tsx b/src/components/Loader.tsx new file mode 100644 index 0000000..68f93fc --- /dev/null +++ b/src/components/Loader.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import styled from "styled-components"; +import { colors } from "@theme/colors"; + +const Loader = styled((props) => ( +
+
+
+
+
+))<{ $color?: typeof colors }>` + overflow: hidden; + font-size: 200px; + width: 1em; + height: 1em; + + @keyframes rotation { + 0% { transform: rotate(0deg) } + 50% { transform: rotate(180deg) } + 100% { transform: rotate(360deg) } + } + + & > div { + width: 100%; + height: 100%; + position: relative; + transform: translateZ(0) scale(1); + backface-visibility: hidden; + transform-origin: 0 0; + + & > div { + box-sizing: content-box; + position: absolute; + animation: rotation 1s linear infinite; + width: 80%; + height: 80%; + top: 10%; + left: 10%; + border-radius: 50%; + box-shadow: 0 0.02em 0 0 ${({ $color }) => $color || colors.white}; + transform-origin: 50% 51%; + } + } +`; + +export default Loader; diff --git a/src/pages/events/[id].tsx b/src/pages/events/[id].tsx index de73e56..9490c6f 100644 --- a/src/pages/events/[id].tsx +++ b/src/pages/events/[id].tsx @@ -7,6 +7,7 @@ import { } from "@models/Event"; import EventPageView from "@views/EventPage/EventPageView"; import PageWrapper from "@views/common/PageWrapper"; +import LoadingView from "@views/common/LoadingView"; interface InitialProps { initialEvent: Event; @@ -16,7 +17,7 @@ const EventPage: NextPage = ({ initialEvent }) => { const router = useRouter(); const { id } = router.query; const { data, error } = useFetchEvents({ initialData: initialEvent, id: id as string }); - if (!data) return
Loading
; + if (!data) return ; return ( <> diff --git a/src/views/EventPage/EventPageView.tsx b/src/views/EventPage/EventPageView.tsx index f2bf138..085ed27 100644 --- a/src/views/EventPage/EventPageView.tsx +++ b/src/views/EventPage/EventPageView.tsx @@ -8,6 +8,7 @@ import { Link, TextSection } from "@components/index"; import noop from "@utils/noop"; import MarkdownStyles from "@views/common/MarkdownStyles"; +import LoadingView from "@views/common/LoadingView"; interface EventPageViewProps { event?: Event; @@ -36,7 +37,7 @@ const Content = styled(MarkdownStyles)` `; const EventPageView: React.FC = ({ event }) => { - if (!event) return
Loading
; + if (!event) return ; return (

diff --git a/src/views/SignUpPage/SignUpPageView.tsx b/src/views/SignUpPage/SignUpPageView.tsx index e27e1fa..edbed0c 100644 --- a/src/views/SignUpPage/SignUpPageView.tsx +++ b/src/views/SignUpPage/SignUpPageView.tsx @@ -8,6 +8,7 @@ import RadioButtonWidget from "@components/Widgets/RadioButton/RadioButtonWidget import { TextSection } from "@components/index"; import { colors } from "@theme/colors"; import FormWrapper from "@views/common/FormWrapper"; +import Loader from "@components/Loader"; const customWidgets = { radio: RadioButtonWidget, @@ -52,6 +53,10 @@ const StyledSection = styled(TextSection)` color: ${colors.blue1}; } } + + ${Loader} { + margin: auto; + } `; const SignUpPageView: React.FC = ({ @@ -78,7 +83,9 @@ const SignUpPageView: React.FC = ({ ); }; - const form = signUpForm ? renderForm() : <>Loading...; + const form = signUpForm ? renderForm() : ( + + ); const signups = signUpForm && signUpForm.signups ? renderList(signUpForm) : null; return ( diff --git a/src/views/common/AdminPageWrapper.tsx b/src/views/common/AdminPageWrapper.tsx index b28e6d0..4396273 100644 --- a/src/views/common/AdminPageWrapper.tsx +++ b/src/views/common/AdminPageWrapper.tsx @@ -6,6 +6,7 @@ import AdminHeader from "@components/AdminHeader"; import AdminSidebar from "@components/AdminSidebar"; import { isAuthenticated } from "@utils/auth"; import { useRouter } from "next/router"; +import LoadingView from "./LoadingView"; const Main = styled.main` display: flex; @@ -70,9 +71,8 @@ const AdminPageWrapper: React.FC = ({ requiresAuthentication, childre router.push(loginURL); } - // TODO: Loading screen if (!completed) { - return <>Loading; + return ; } return ( diff --git a/src/views/common/LoadingView.tsx b/src/views/common/LoadingView.tsx new file mode 100644 index 0000000..59fdd2a --- /dev/null +++ b/src/views/common/LoadingView.tsx @@ -0,0 +1,106 @@ +import React from "react"; +import styled from "styled-components"; +import Loader from "@components/Loader"; +import colors from "@theme/colors"; + +const Main = styled.main` + display: flex; + flex-direction: column; + flex: 1 0 auto; + justify-content: center; + align-items: center; + color: ${colors.white}; + background-color: ${colors.darkBlue}; + + ${/* sc-selector */Loader} { + font-size: 10rem; + } +`; + +const DotPulse = styled.div` + @keyframes dotPulseBefore { + 0% { + box-shadow: 9984px 0 0 -5px ${colors.white}; + } + 30% { + box-shadow: 9984px 0 0 2px ${colors.white}; + } + 60%, 100% { + box-shadow: 9984px 0 0 -5px ${colors.white}; + } + } + + @keyframes dotPulse { + 0% { + box-shadow: 9999px 0 0 -5px ${colors.white}; + } + 30% { + box-shadow: 9999px 0 0 2px ${colors.white}; + } + 60%, 100% { + box-shadow: 9999px 0 0 -5px ${colors.white}; + } + } + + @keyframes dotPulseAfter { + 0% { + box-shadow: 10014px 0 0 -5px ${colors.white}; + } + 30% { + box-shadow: 10014px 0 0 2px ${colors.white}; + } + 60%, 100% { + box-shadow: 10014px 0 0 -5px ${colors.white}; + } + } + + display: inline-block; + margin-left: 1.5rem; + + position: relative; + left: -9999px; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: ${colors.white}; + color: ${colors.white}; + box-shadow: 9999px 0 0 -5px ${colors.white}; + animation: dotPulse 1.5s infinite linear; + animation-delay: .25s; + + &::before, &::after { + content: ''; + display: inline-block; + position: absolute; + top: 0; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: ${colors.white}; + color: ${colors.white}; + } + + &::before { + box-shadow: 9984px 0 0 -5px ${colors.white}; + animation: dotPulseBefore 1.5s infinite linear; + animation-delay: 0s; + } + + &::after { + box-shadow: 10014px 0 0 -5px ${colors.white}; + animation: dotPulseAfter 1.5s infinite linear; + animation-delay: .5s; + } +`; + +const LoadingView: React.FC = () => ( +
+ +

+ Loading + +

+
+); + +export default LoadingView;