mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-25 19:26:31 -05:00
Add new loading animation
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
85eff24be1
commit
bd58bca39c
7 changed files with 242 additions and 72 deletions
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import LogoColor from '../../../common/hedge-doc-logo/logo_color.svg'
|
||||
import styles from './animations.module.scss'
|
||||
|
||||
export interface HedgeDocLogoProps {
|
||||
animation: AnimationType
|
||||
}
|
||||
|
||||
export enum AnimationType {
|
||||
JUMP = 'animation-jump',
|
||||
SHAKE = 'animation-shake'
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an animated hedgedoc logo.
|
||||
*
|
||||
* @param animation The name of the animation
|
||||
*/
|
||||
export const AnimatedHedgeDocLogo: React.FC<HedgeDocLogoProps> = ({ animation }) => {
|
||||
return (
|
||||
<LogoColor
|
||||
className={`w-auto ${styles[animation]}`}
|
||||
title={'HedgeDoc logo'}
|
||||
alt={'HedgeDoc logo'}
|
||||
height={256}
|
||||
width={256}
|
||||
/>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*!
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
@import "keyframes";
|
||||
|
||||
.rows {
|
||||
transition: opacity 0.2s;
|
||||
|
||||
.row {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.particle {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
position: absolute;
|
||||
font-size: 1.3em !important;
|
||||
top: calc(50% - 12px);
|
||||
left: calc(50% - 12px);
|
||||
animation: particle 3s infinite;
|
||||
}
|
||||
|
||||
@for $i from 1 through 12 {
|
||||
.row:nth-child(#{$i}) {
|
||||
transform: rotateZ(30deg * ($i - 1));
|
||||
|
||||
@for $j from 1 through 10 {
|
||||
& .particle:nth-child(#{$j}) {
|
||||
opacity: 0;
|
||||
animation-timing-function: ease-out;
|
||||
animation-delay: -$i * 830ms - $j * 600ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
z-index: 1000;
|
||||
position: relative;
|
||||
font-size: 3em;
|
||||
height: 240px;
|
||||
width: 203px;
|
||||
color: #ffffff;
|
||||
text-shadow: 4px 4px 0 #3b4045;
|
||||
|
||||
.overlay {
|
||||
color: rgb(181, 31, 8);
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
animation: fill 6s infinite;
|
||||
width: 100%;
|
||||
|
||||
&, :global(.fa) {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pulse {
|
||||
animation: 3s pulse infinite;
|
||||
box-shadow: #404040 0 0 200px 100px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border-radius: 100%;
|
||||
margin: auto;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.error {
|
||||
.channels {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.pulse {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.logo {
|
||||
.overlay {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
color: rgb(181, 31, 8);
|
||||
animation: 1s shake;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react'
|
||||
import { createNumberRangeArray } from '../../common/number-range/number-range'
|
||||
import { RandomIcon } from './random-icon'
|
||||
import styles from './animations.module.scss'
|
||||
|
||||
/**
|
||||
* Shows a number of {@link RandomIcon random icons in a row}.
|
||||
*/
|
||||
export const IconRow: React.FC = () => {
|
||||
const children = useMemo(() => createNumberRangeArray(5).map((index) => <RandomIcon key={index}></RandomIcon>), [])
|
||||
|
||||
return <div className={styles.row}>{children}</div>
|
||||
}
|
|
@ -1,34 +1,10 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
/*!
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@keyframes animation-jump {
|
||||
0% {
|
||||
transform: scale(1, 1) translateY(0);
|
||||
}
|
||||
10% {
|
||||
transform: scale(1.1, .9) translateY(0);
|
||||
}
|
||||
30% {
|
||||
transform: scale(.9, 1.1) translateY(-100px);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05, .95) translateY(0);
|
||||
}
|
||||
57% {
|
||||
transform: scale(1, 1) translateY(-7px);
|
||||
}
|
||||
64% {
|
||||
transform: scale(1, 1) translateY(0);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1, 1) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation-shake {
|
||||
@keyframes shake {
|
||||
0% {
|
||||
transform: translate(1px, 1px) rotate(0deg);
|
||||
}
|
||||
|
@ -64,14 +40,54 @@
|
|||
}
|
||||
}
|
||||
|
||||
.animation-jump {
|
||||
transform-origin: bottom;
|
||||
animation-duration: 2s;
|
||||
animation-iteration-count: infinite;
|
||||
animation-name: animation-jump;
|
||||
animation-timing-function: cubic-bezier(0.280, 0.840, 0.420, 1);
|
||||
@keyframes particle {
|
||||
0% {
|
||||
opacity: 0.3;
|
||||
transform: translate(300px, 300px) rotateZ(360deg);
|
||||
border-radius: 0;
|
||||
color: #ffffff;
|
||||
}
|
||||
20% {
|
||||
border-radius: 0;
|
||||
}
|
||||
70% {
|
||||
opacity: 1;
|
||||
transform: translate(120px, 120px) rotateZ(180deg);
|
||||
border-radius: 10px;
|
||||
}
|
||||
90% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translate(0px, 0px) rotateZ(0deg);
|
||||
color: rgb(181, 31, 8);
|
||||
}
|
||||
}
|
||||
|
||||
.animation-shake {
|
||||
animation: animation-shake 0.3s ease-in-out;
|
||||
@keyframes fill {
|
||||
0% {
|
||||
height: 0%;
|
||||
}
|
||||
|
||||
50% {
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
100%{
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: #ffffff00 0 0 200px 100px;
|
||||
}
|
||||
|
||||
30% {
|
||||
box-shadow: #ffffff33 0 0 200px 100px;
|
||||
}
|
||||
|
||||
100% {
|
||||
box-shadow: #ffffff00 0 0 200px 100px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react'
|
||||
import styles from './animations.module.scss'
|
||||
import { ForkAwesomeIcon } from '../../common/fork-awesome/fork-awesome-icon'
|
||||
import { IconRow } from './icon-row'
|
||||
import { createNumberRangeArray } from '../../common/number-range/number-range'
|
||||
|
||||
export interface HedgeDocLogoProps {
|
||||
error: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a loading animation.
|
||||
*
|
||||
* @param error Defines if the error animation should be shown instead
|
||||
*/
|
||||
export const LoadingAnimation: React.FC<HedgeDocLogoProps> = ({ error }) => {
|
||||
const iconRows = useMemo(() => createNumberRangeArray(12).map((index) => <IconRow key={index} />), [])
|
||||
|
||||
return (
|
||||
<div className={`position-relative ${error ? styles.error : ''}`}>
|
||||
<div className={styles.logo}>
|
||||
<div>
|
||||
<ForkAwesomeIcon icon={'pencil'} className={styles.background} size={'5x'}></ForkAwesomeIcon>
|
||||
</div>
|
||||
<div className={`${styles.overlay}`}>
|
||||
<ForkAwesomeIcon icon={'pencil'} size={'5x'}></ForkAwesomeIcon>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.pulse}></div>
|
||||
<div className={styles.rows}>{iconRows}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import React from 'react'
|
||||
import { Alert } from 'react-bootstrap'
|
||||
import { AnimatedHedgeDocLogo, AnimationType } from './animated-hedge-doc-logo/animated-hedge-doc-logo'
|
||||
import { LoadingAnimation } from './loading-animation'
|
||||
import { ShowIf } from '../../common/show-if/show-if'
|
||||
import styles from '../application-loader.module.scss'
|
||||
|
||||
|
@ -24,7 +24,7 @@ export const LoadingScreen: React.FC<LoadingScreenProps> = ({ failedTaskName })
|
|||
<div className={`${styles.loader} ${styles.middle} text-light overflow-hidden`}>
|
||||
<div className='mb-3 text-light'>
|
||||
<span className={`d-block`}>
|
||||
<AnimatedHedgeDocLogo animation={failedTaskName ? AnimationType.SHAKE : AnimationType.JUMP} />
|
||||
<LoadingAnimation error={!!failedTaskName} />
|
||||
</span>
|
||||
</div>
|
||||
<ShowIf condition={!!failedTaskName}>
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react'
|
||||
import type { IconName } from '../../common/fork-awesome/types'
|
||||
import { ForkAwesomeIcon } from '../../common/fork-awesome/fork-awesome-icon'
|
||||
import styles from './animations.module.scss'
|
||||
|
||||
const elements: IconName[] = [
|
||||
'file-text',
|
||||
'markdown',
|
||||
'pencil',
|
||||
'bold',
|
||||
'italic',
|
||||
'align-justify',
|
||||
'tag',
|
||||
'user',
|
||||
'file',
|
||||
'keyboard-o',
|
||||
'cog',
|
||||
'font'
|
||||
]
|
||||
|
||||
/**
|
||||
* Chooses a random fork awesome icon from a predefined set and renders it.
|
||||
*/
|
||||
export const RandomIcon: React.FC = () => {
|
||||
const icon = useMemo(() => elements[Math.floor(Math.random() * elements.length)], [])
|
||||
|
||||
return <ForkAwesomeIcon icon={icon} className={styles.particle}></ForkAwesomeIcon>
|
||||
}
|
Loading…
Reference in a new issue