mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-23 03:27:05 -04:00
fix: Move content into to frontend directory
Doing this BEFORE the merge prevents a lot of merge conflicts. Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
4e18ce38f3
commit
762a0a850e
1051 changed files with 0 additions and 35 deletions
|
@ -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>
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*!
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@keyframes shake {
|
||||
0% {
|
||||
transform: translate(1px, 1px) rotate(0deg);
|
||||
}
|
||||
10% {
|
||||
transform: translate(-1px, -2px) rotate(-1deg);
|
||||
}
|
||||
20% {
|
||||
transform: translate(-3px, 0px) rotate(1deg);
|
||||
}
|
||||
30% {
|
||||
transform: translate(3px, 2px) rotate(0deg);
|
||||
}
|
||||
40% {
|
||||
transform: translate(1px, -1px) rotate(1deg);
|
||||
}
|
||||
50% {
|
||||
transform: translate(-1px, 2px) rotate(-1deg);
|
||||
}
|
||||
60% {
|
||||
transform: translate(-3px, 1px) rotate(0deg);
|
||||
}
|
||||
70% {
|
||||
transform: translate(3px, 1px) rotate(-1deg);
|
||||
}
|
||||
80% {
|
||||
transform: translate(-1px, -1px) rotate(1deg);
|
||||
}
|
||||
90% {
|
||||
transform: translate(1px, 2px) rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: translate(1px, -2px) rotate(-1deg);
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
@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>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { ReactElement } from 'react'
|
||||
import React from 'react'
|
||||
import { Alert } from 'react-bootstrap'
|
||||
import { LoadingAnimation } from './loading-animation'
|
||||
import { ShowIf } from '../../common/show-if/show-if'
|
||||
import styles from '../application-loader.module.scss'
|
||||
|
||||
export interface LoadingScreenProps {
|
||||
errorMessage?: string | ReactElement
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a loading animation.
|
||||
*
|
||||
* @param failedTaskName Should be set if a task failed to load. The name will be shown on screen.
|
||||
*/
|
||||
export const LoadingScreen: React.FC<LoadingScreenProps> = ({ errorMessage }) => {
|
||||
return (
|
||||
<div className={`${styles.loader} ${styles.middle} text-light overflow-hidden`}>
|
||||
<div className='mb-3 text-light'>
|
||||
<span className={`d-block`}>
|
||||
<LoadingAnimation error={!!errorMessage} />
|
||||
</span>
|
||||
</div>
|
||||
<ShowIf condition={!!errorMessage}>
|
||||
<Alert variant={'danger'}>{errorMessage}</Alert>
|
||||
</ShowIf>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import React, { useEffect, useState } 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.
|
||||
*
|
||||
* The component uses a static icon in the first rendering and will choose the random icon after that.
|
||||
* This is done because if the loading screen is prepared using SSR and then hydrated in the client, the rendered css class isn't the expected one from the SSR. (It's random. d'uh).
|
||||
* To avoid this problem the icon will be chosen in an effect because SSR won't run effects.
|
||||
*
|
||||
* See https://nextjs.org/docs/messages/react-hydration-error
|
||||
*/
|
||||
export const RandomIcon: React.FC = () => {
|
||||
const [icon, setIcon] = useState<number | undefined>()
|
||||
|
||||
useEffect(() => {
|
||||
setIcon(Math.floor(Math.random() * elements.length))
|
||||
}, [])
|
||||
|
||||
return icon === undefined ? null : (
|
||||
<ForkAwesomeIcon icon={elements[icon]} className={styles.particle}></ForkAwesomeIcon>
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue