[MM-58726] Add a loading screen to initial load of the web app (#27740)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
eafe056bea
Коммит
5d7aa17a27
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {InitialLoadingScreenClass} from './initial_loading_screen_class';
|
||||
|
||||
const InitialLoadingScreen = new InitialLoadingScreenClass();
|
||||
|
||||
export default InitialLoadingScreen;
|
||||
@@ -0,0 +1,359 @@
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.LoadingScreen.disabled {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.LoadingScreen {
|
||||
--background-color: #f4f4f6;
|
||||
--background-color-highlight: #ffffff;
|
||||
--stipple-color: #1e325c;
|
||||
--stipple-opacity: 0.08;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 1;
|
||||
transition: opacity 150ms 0ms ease-out, visibility 150ms 0ms step-start;
|
||||
vertical-align: middle;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.LoadingScreen--darkMode {
|
||||
--background-color-highlight: #28427b;
|
||||
--background-color: #1e325c;
|
||||
--stipple-color: #14213e;
|
||||
--stipple-opacity: 0.8;
|
||||
}
|
||||
|
||||
.LoadingScreen__background,
|
||||
.LoadingScreen__background > svg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.LoadingScreen__background {
|
||||
background: var(--background-color);
|
||||
}
|
||||
|
||||
.LoadingScreen .Pill__stipple {
|
||||
fill: var(--stipple-color);
|
||||
fill-opacity: var(--stipple-opacity);
|
||||
}
|
||||
|
||||
.LoadingScreen .Pill__gradient {
|
||||
stop-color: var(--background-color);
|
||||
}
|
||||
|
||||
.LoadingScreen .Pill__gradientHighlight {
|
||||
stop-color: var(--background-color-highlight);
|
||||
}
|
||||
|
||||
.LoadingScreen--loaded {
|
||||
opacity: 0;
|
||||
transition: opacity 150ms 0ms ease-in, visibility 150ms 0ms step-end;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.LoadingAnimation {
|
||||
--fade-duration: 150ms;
|
||||
--colour: #1E325C;
|
||||
--animation-initial-delay: 750ms;
|
||||
--animation-start-duration: 750ms;
|
||||
--animation-end-duration: 600ms;
|
||||
--animation-spinner-speed: 500ms;
|
||||
--animation-spinner-mask-stroke-length: 169.6;
|
||||
--ease-in-cubic: cubic-bezier(0.32, 0, 0.67, 0);
|
||||
--ease-in: var(--ease-in-cubic);
|
||||
--ease-in-out-cubic: cubic-bezier(0.65, 0, 0.35, 1);
|
||||
--ease-in-out: var(--ease-in-out-cubic);
|
||||
--ease-in-out-compass-shrink: cubic-bezier(0.1, 0.25, 0.3, 1);
|
||||
|
||||
opacity: 1;
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
.LoadingAnimation--darkMode {
|
||||
--colour: white;
|
||||
}
|
||||
|
||||
.LoadingAnimation g,
|
||||
.LoadingAnimation rect,
|
||||
.LoadingAnimation path,
|
||||
.LoadingAnimation circle {
|
||||
transform-origin: center center;
|
||||
}
|
||||
.LoadingAnimation svg {
|
||||
color: var(--colour);
|
||||
}
|
||||
.LoadingAnimation .LoadingAnimation__spinner-gradient-color {
|
||||
stop-color: var(--colour);
|
||||
}
|
||||
.LoadingAnimation .LoadingAnimation__spinner-container {
|
||||
opacity: 0;
|
||||
transform: scale3D(2.08, 2.08, 1) rotate3d(0, 0, 1, -10deg);
|
||||
}
|
||||
.LoadingAnimation .LoadingAnimation__spinner-mask-container {
|
||||
transform: rotate3d(0, 0, 1, -86deg);
|
||||
}
|
||||
.LoadingAnimation .LoadingAnimation__spinner-mask {
|
||||
stroke-dasharray: var(--animation-spinner-mask-stroke-length);
|
||||
stroke-dashoffset: var(--animation-spinner-mask-stroke-length);
|
||||
transform: scale3d(1.03, 1.03, 1);
|
||||
}
|
||||
.LoadingAnimation .LoadingAnimation__compass {
|
||||
opacity: 1;
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
.LoadingAnimation .LoadingAnimation__compass-needle-container {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
.LoadingAnimation .LoadingAnimation__compass-needle,
|
||||
.LoadingAnimation .LoadingAnimation__compass-needle-front-mask,
|
||||
.LoadingAnimation .LoadingAnimation__compass-needle-behind-mask {
|
||||
transform: rotate3d(0, 0, 1, 0deg);
|
||||
transform-origin: 54px 46px;
|
||||
}
|
||||
.LoadingAnimation .LoadingAnimation__compass-base-mask-container {
|
||||
transform: rotate3d(0, 0, 1, -86deg);
|
||||
}
|
||||
.LoadingAnimation .LoadingAnimation__compass-base-mask {
|
||||
stroke-dasharray: var(--animation-spinner-mask-stroke-length);
|
||||
stroke-dashoffset: var(--animation-spinner-mask-stroke-length);
|
||||
}
|
||||
|
||||
.LoadingAnimation--loading {
|
||||
--fade-in-duration: 150ms;
|
||||
--fade-in-delay: 0ms;
|
||||
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
|
||||
.LoadingAnimation.LoadingAnimation--loading .LoadingAnimation__spinner-container {
|
||||
--shrink-duration: calc(var(--animation-end-duration) * 0.5);
|
||||
--shrink-delay: calc( ( var(--animation-start-duration) + var(--animation-end-duration) ) * 0.91 + var(--animation-initial-delay));
|
||||
--fade-in-duration: calc(var(--animation-end-duration) * 0.25);
|
||||
--fade-in-delay: calc( var(--animation-start-duration) + var(--animation-end-duration) * 0.24 + var(--animation-initial-delay));
|
||||
|
||||
animation: LoadingAnimation__spinner-shrink var(--shrink-duration) var(--shrink-delay) var(--ease-in-out-compass-shrink) forwards, LoadingAnimation__fade-in var(--fade-in-duration) var(--fade-in-delay) var(--ease-in) forwards;
|
||||
}
|
||||
.LoadingAnimation.LoadingAnimation--loading .LoadingAnimation__spinner-mask {
|
||||
--reveal-duration: var(--animation-end-duration);
|
||||
--reveal-delay: calc(var(--animation-start-duration) + var(--animation-initial-delay));
|
||||
|
||||
animation: LoadingAnimation__spinner-reveal var(--reveal-duration) var(--reveal-delay) var(--ease-in) forwards;
|
||||
}
|
||||
.LoadingAnimation.LoadingAnimation--loading .LoadingAnimation__compass {
|
||||
--shrink-duration: calc(var(--animation-end-duration) * 0.5);
|
||||
--shrink-delay: calc( ( var(--animation-start-duration) + var(--animation-end-duration) ) * 0.91 + var(--animation-initial-delay));
|
||||
|
||||
animation: LoadingAnimation__compass-shrink var(--shrink-duration) var(--shrink-delay) var(--ease-in-out-compass-shrink) forwards;
|
||||
}
|
||||
.LoadingAnimation.LoadingAnimation--loading .LoadingAnimation__compass-needle-container {
|
||||
--shrink-duration: calc(var(--animation-end-duration) * 0.25);
|
||||
--shrink-delay: calc( var(--animation-start-duration) + var(--animation-end-duration) - var(--animation-end-duration) * 0.25 + var(--animation-initial-delay));
|
||||
|
||||
animation: LoadingAnimation__needle-shrink var(--shrink-duration) var(--shrink-delay) var(--ease-in) forwards;
|
||||
}
|
||||
.LoadingAnimation.LoadingAnimation--loading .LoadingAnimation__compass-needle {
|
||||
--spin-left-duration: var(--animation-start-duration);
|
||||
--spin-left-delay: var(--animation-initial-delay);
|
||||
--spin-right-duration: var(--animation-end-duration);
|
||||
--spin-right-delay: calc(var(--animation-start-duration) + var(--animation-initial-delay));
|
||||
--fade-out-duration: calc(var(--animation-end-duration) * 0.25);
|
||||
--fade-out-delay: calc( var(--animation-start-duration) + var(--animation-end-duration) - var(--animation-end-duration) * 0.25 + var(--animation-initial-delay));
|
||||
|
||||
animation:
|
||||
LoadingAnimation__needle-spin-left var(--spin-left-duration) var(--spin-left-delay) var(--ease-in-out) forwards,
|
||||
LoadingAnimation__needle-spin-right var(--spin-right-duration) var(--spin-right-delay) var(--ease-in) forwards,
|
||||
LoadingAnimation__fade-out var(--fade-out-duration) var(--fade-out-delay) var(--ease-in) forwards;
|
||||
}
|
||||
.LoadingAnimation.LoadingAnimation--loading .LoadingAnimation__compass-needle-behind-mask {
|
||||
--spin-left-duration: var(--animation-start-duration);
|
||||
--spin-left-delay: var(--animation-initial-delay);
|
||||
--spin-right-duration: calc(var(--animation-end-duration) * 0.3666);
|
||||
--spin-right-delay: calc(var(--animation-start-duration) + var(--animation-initial-delay));
|
||||
|
||||
animation: LoadingAnimation__needle-mask-spin-left var(--spin-left-duration) var(--spin-left-delay) var(--ease-in-out) forwards, LoadingAnimation__needle-mask-spin-right var(--spin-right-duration) var(--spin-right-delay) var(--ease-in) forwards;
|
||||
}
|
||||
.LoadingAnimation.LoadingAnimation--loading .LoadingAnimation__compass-needle-front-mask {
|
||||
--spin-left-duration: var(--animation-start-duration);
|
||||
--spin-left-delay: var(--animation-initial-delay);
|
||||
--spin-right-duration: var(--animation-end-duration);
|
||||
--spin-right-delay: calc(var(--animation-start-duration) + var(--animation-initial-delay));
|
||||
|
||||
animation: LoadingAnimation__needle-spin-left var(--spin-left-duration) var(--spin-left-delay) var(--ease-in-out) forwards, LoadingAnimation__needle-spin-right var(--spin-right-duration) var(--spin-right-delay) var(--ease-in) forwards;
|
||||
}
|
||||
.LoadingAnimation.LoadingAnimation--loading .LoadingAnimation__compass-base-mask {
|
||||
--conceal-duration: var(--animation-end-duration);
|
||||
--conceal-delay: calc(var(--animation-start-duration) + var(--animation-initial-delay));
|
||||
|
||||
animation: LoadingAnimation__compass-base-conceal var(--conceal-duration) var(--conceal-delay) var(--ease-in) forwards;
|
||||
}
|
||||
.LoadingAnimation.LoadingAnimation--spinning .LoadingAnimation__spinner {
|
||||
--spin-duration: var(--animation-spinner-speed);
|
||||
--spin-delay: calc( ( var(--animation-start-duration) + var(--animation-end-duration) ) * 0.95 + var(--animation-initial-delay));
|
||||
|
||||
animation: LoadingAnimation__spinner-spin var(--spin-duration) var(--spin-delay) linear infinite;
|
||||
}
|
||||
|
||||
.LoadingAnimation--loaded {
|
||||
--duration: 150ms;
|
||||
--delay: 0ms;
|
||||
|
||||
animation: LoadingAnimation__fade-out var(--duration) var(--delay) var(--ease-in) forwards, LoadingAnimation__shrink var(--duration) var(--delay) var(--ease-in) forwards;
|
||||
}
|
||||
|
||||
.LoadingAnimation--loaded .LoadingAnimation__spinner-container {
|
||||
opacity: 1;
|
||||
transform: scale3D(1, 1, 1) rotate3d(0, 0, 1, -10deg);
|
||||
}
|
||||
.LoadingAnimation--loaded .LoadingAnimation__spinner-mask {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
.LoadingAnimation--loaded .LoadingAnimation__compass {
|
||||
transform: scale3D(0.4166666667, 0.4166666667, 1);
|
||||
}
|
||||
.LoadingAnimation--loaded .LoadingAnimation__compass-needle-container {
|
||||
transform: scale3d(0.35, 0.35, 1);
|
||||
}
|
||||
.LoadingAnimation--loaded .LoadingAnimation__compass-needle {
|
||||
opacity: 0;
|
||||
transform: rotate3d(0, 0, 1, 405deg);
|
||||
}
|
||||
.LoadingAnimation--loaded .LoadingAnimation__compass-needle-behind-mask {
|
||||
transform: rotate3d(0, 0, 1, 0deg);
|
||||
}
|
||||
.LoadingAnimation--loaded .LoadingAnimation__compass-needle-front-mask {
|
||||
transform: rotate3d(0, 0, 1, 405deg);
|
||||
}
|
||||
.LoadingAnimation--loaded .LoadingAnimation__compass-base-mask {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__fade-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__shrink {
|
||||
0% {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
100% {
|
||||
transform: scale3d(0.35, 0.35, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__spinner-shrink {
|
||||
0% {
|
||||
transform: scale3D(2.08, 2.08, 1) rotate3d(0, 0, 1, -10deg);
|
||||
}
|
||||
100% {
|
||||
transform: scale3D(1, 1, 1) rotate3d(0, 0, 1, -10deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__spinner-spin {
|
||||
from {
|
||||
transform: rotate3d(0, 0, 1, 0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate3d(0, 0, 1, 359deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__spinner-reveal {
|
||||
0%, 5% {
|
||||
stroke-dashoffset: var(--animation-spinner-mask-stroke-length);
|
||||
}
|
||||
95%, 100% {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__needle-spin-left {
|
||||
0% {
|
||||
transform: rotate3d(0, 0, 1, 0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate3d(0, 0, 1, -20deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__needle-spin-right {
|
||||
0% {
|
||||
transform: rotate3d(0, 0, 1, -20deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate3d(0, 0, 1, 405deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__needle-mask-spin-left {
|
||||
0% {
|
||||
transform: rotate3d(0, 0, 1, 0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate3d(0, 0, 1, -20deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__needle-mask-spin-right {
|
||||
0% {
|
||||
transform: rotate3d(0, 0, 1, -20deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate3d(0, 0, 1, 0deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__needle-shrink {
|
||||
0% {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
100% {
|
||||
transform: scale3d(0.35, 0.35, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__compass-shrink {
|
||||
0% {
|
||||
transform: scale3D(1, 1, 1);
|
||||
}
|
||||
100% {
|
||||
transform: scale3D(0.4166666667, 0.4166666667, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes LoadingAnimation__compass-base-conceal {
|
||||
0%, 5% {
|
||||
stroke-dashoffset: var(--animation-spinner-mask-stroke-length);
|
||||
}
|
||||
95%, 100% {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {isDesktopApp} from 'utils/user_agent';
|
||||
|
||||
const ANIMATION_CLASS_FOR_MATTERMOST_LOGO_HIDE = 'LoadingAnimation__compass-shrink';
|
||||
const ANIMATION_CLASS_FOR_COMPLETE_LOADER_HIDE = 'LoadingAnimation__shrink';
|
||||
|
||||
const LOADING_CLASS_FOR_SCREEN = 'LoadingScreen LoadingScreen--darkMode';
|
||||
const LOADING_COMPLETE_CLASS_FOR_SCREEN = 'LoadingScreen LoadingScreen--darkMode LoadingScreen--loaded';
|
||||
|
||||
const STATIC_CLASS_FOR_ANIMATION = 'LoadingAnimation LoadingAnimation--darkMode';
|
||||
const LOADING_CLASS_FOR_ANIMATION = STATIC_CLASS_FOR_ANIMATION + ' LoadingAnimation--spinning LoadingAnimation--loading';
|
||||
const LOADING_COMPLETE_CLASS_FOR_ANIMATION = STATIC_CLASS_FOR_ANIMATION + ' LoadingAnimation--spinning LoadingAnimation--loaded';
|
||||
|
||||
const DESTROY_DELAY_AFTER_ANIMATION_END = 1000;
|
||||
|
||||
export class InitialLoadingScreenClass {
|
||||
private isLoading: boolean | null = true;
|
||||
|
||||
private loadingScreenElement: HTMLElement | null;
|
||||
private loadingAnimationElement: HTMLElement | null;
|
||||
|
||||
private initialLoadingScreenCSS: HTMLLinkElement | null;
|
||||
|
||||
constructor() {
|
||||
this.loadingScreenElement = document.getElementById('initialPageLoadingScreen');
|
||||
this.loadingAnimationElement = document.getElementById('initialPageLoadingAnimation');
|
||||
|
||||
this.initialLoadingScreenCSS = document.getElementById('initialLoadingScreenCSS') as HTMLLinkElement | null;
|
||||
|
||||
this.handleAnimationEndEvent = this.handleAnimationEndEvent.bind(this);
|
||||
}
|
||||
|
||||
private handleAnimationEndEvent(event: AnimationEvent) {
|
||||
if (!this.loadingAnimationElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.animationName === ANIMATION_CLASS_FOR_MATTERMOST_LOGO_HIDE || event.animationName === ANIMATION_CLASS_FOR_COMPLETE_LOADER_HIDE) {
|
||||
if (!this.isLoading) {
|
||||
this.loadingAnimationElement.className = STATIC_CLASS_FOR_ANIMATION;
|
||||
|
||||
// Automatically destroy the loading screen after the animation has finished.
|
||||
// Should be changed if we want to loading animation to start again.
|
||||
setTimeout(() => {
|
||||
this.destroy();
|
||||
}, DESTROY_DELAY_AFTER_ANIMATION_END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private addAnimationEndListener() {
|
||||
if (this.loadingAnimationElement) {
|
||||
this.loadingAnimationElement.addEventListener('animationend', this.handleAnimationEndEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private removeAnimationEndListener() {
|
||||
if (this.loadingAnimationElement) {
|
||||
this.loadingAnimationElement.removeEventListener('animationend', this.handleAnimationEndEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private destroy() {
|
||||
this.removeAnimationEndListener();
|
||||
|
||||
if (this.loadingScreenElement) {
|
||||
this.loadingScreenElement.remove();
|
||||
this.loadingScreenElement = null;
|
||||
}
|
||||
|
||||
if (this.initialLoadingScreenCSS) {
|
||||
this.initialLoadingScreenCSS.remove();
|
||||
this.initialLoadingScreenCSS = null;
|
||||
}
|
||||
|
||||
if (this.loadingAnimationElement) {
|
||||
this.loadingAnimationElement = null;
|
||||
}
|
||||
|
||||
this.isLoading = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The loading animations are always started as soon as the loading indicator is shown in the screen for the first time.
|
||||
* But we still want to have this start method incase we need to start the loading animations manually any time.
|
||||
* If we do want to do that then we should remove the set timeout destroy call doing above.
|
||||
*/
|
||||
public start() {
|
||||
if (isDesktopApp()) {
|
||||
// Let Mattermost desktop handle the loading screen
|
||||
this.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
this.addAnimationEndListener();
|
||||
|
||||
if (!this.loadingScreenElement || !this.loadingAnimationElement) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('InitialLoadingScreen: No loading screen or animation element found');
|
||||
return;
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
|
||||
this.loadingScreenElement.className = LOADING_CLASS_FOR_SCREEN;
|
||||
this.loadingAnimationElement.className = LOADING_CLASS_FOR_ANIMATION;
|
||||
}
|
||||
|
||||
public stop() {
|
||||
if (!this.loadingScreenElement || !this.loadingAnimationElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isLoading = false;
|
||||
|
||||
this.loadingScreenElement.className = LOADING_COMPLETE_CLASS_FOR_SCREEN;
|
||||
this.loadingAnimationElement.className = LOADING_COMPLETE_CLASS_FOR_ANIMATION;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
<div
|
||||
id="initialPageLoadingScreen"
|
||||
class="LoadingScreen LoadingScreen--darkMode"
|
||||
>
|
||||
<div class="LoadingScreen__background">
|
||||
<svg
|
||||
viewBox="0 0 1366 728"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
preserveAspectRatio="xMidYMid slice"
|
||||
>
|
||||
<g style="transform: translate(676px, -200px)">
|
||||
<g
|
||||
style="
|
||||
transform-origin: 450px 267.5px;
|
||||
transform: rotate(45deg);
|
||||
"
|
||||
>
|
||||
<use href="#pill" />
|
||||
</g>
|
||||
</g>
|
||||
<g style="transform: translate(125px, 0px)">
|
||||
<g
|
||||
style="
|
||||
transform-origin: 450px 267.5px;
|
||||
transform: rotate(-135deg);
|
||||
"
|
||||
>
|
||||
<use href="#pill" />
|
||||
</g>
|
||||
</g>
|
||||
<g style="transform: translate(700px, 330px)">
|
||||
<g
|
||||
style="
|
||||
transform-origin: 450px 267.5px;
|
||||
transform: rotate(-135deg);
|
||||
"
|
||||
>
|
||||
<use href="#pill" />
|
||||
</g>
|
||||
</g>
|
||||
<g style="transform: translate(-280px, 190px)">
|
||||
<g
|
||||
style="
|
||||
transform-origin: 450px 267.5px;
|
||||
transform: rotate(45deg);
|
||||
"
|
||||
>
|
||||
<use href="#pill" />
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<mask id="stippleMask">
|
||||
<image width="900" height="535" />
|
||||
</mask>
|
||||
<g id="pill" class="Pill">
|
||||
<rect
|
||||
class="Pill__stipple"
|
||||
x="0"
|
||||
y="0"
|
||||
width="900"
|
||||
height="535"
|
||||
mask="url(#stippleMask)"
|
||||
/>
|
||||
<path
|
||||
class="Pill__shape"
|
||||
d="M600 40H0V490H600C724.264 490 825 389.264 825 265C825 140.736 724.264 40 600 40Z"
|
||||
fill="url(#pillGradient)"
|
||||
/>
|
||||
</g>
|
||||
<linearGradient id="pillGradient">
|
||||
<stop
|
||||
class="Pill__gradient"
|
||||
offset="20%"
|
||||
stop-opacity="1"
|
||||
/>
|
||||
<stop
|
||||
class="Pill__gradientHighlight"
|
||||
offset="95%"
|
||||
stop-opacity="1"
|
||||
/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
id="initialPageLoadingAnimation"
|
||||
class="LoadingAnimation LoadingAnimation--darkMode LoadingAnimation--spinning LoadingAnimation--loading"
|
||||
>
|
||||
<svg
|
||||
width="104"
|
||||
height="104"
|
||||
viewBox="0 0 104 104"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="LoadingAnimation__spinner-gradient"
|
||||
x1="0%"
|
||||
y1="72px"
|
||||
x2="0%"
|
||||
y2="32px"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop
|
||||
offset="0"
|
||||
class="LoadingAnimation__spinner-gradient-color"
|
||||
stop-opacity="1"
|
||||
/>
|
||||
<stop
|
||||
offset="1"
|
||||
class="LoadingAnimation__spinner-gradient-color"
|
||||
stop-opacity="0"
|
||||
/>
|
||||
</linearGradient>
|
||||
<mask id="LoadingAnimation__base-wipe-mask">
|
||||
<rect x="0" y="0" width="104" height="104" fill="white" />
|
||||
<g class="LoadingAnimation__compass-base-mask-container">
|
||||
<circle
|
||||
class="LoadingAnimation__compass-base-mask"
|
||||
r="27"
|
||||
cx="52"
|
||||
cy="52"
|
||||
fill="white"
|
||||
stroke="black"
|
||||
stroke-width="54"
|
||||
/>
|
||||
</g>
|
||||
</mask>
|
||||
<mask id="LoadingAnimation__base-mask">
|
||||
<rect x="0" y="0" width="104" height="104" fill="white" />
|
||||
<circle r="37" cx="54" cy="46" fill="black" />
|
||||
<g class="LoadingAnimation__compass-needle-behind-mask">
|
||||
<g transform="translate(54,46)">
|
||||
<g transform="translate(-29, -61.3)">
|
||||
<path
|
||||
d="M38.5984 0C45.476 1.07762 51.9794 3.28918 57.9108 6.43722V61.1566C57.9108 77.1373 44.9364 90.1119 28.9554 90.1119C12.9744 90.1119 0 77.1373 0 61.1566C0 55.3848 1.69443 50.0063 4.60763 45.4861L38.5984 0Z"
|
||||
fill="black"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g class="LoadingAnimation__compass-needle-front-mask">
|
||||
<g transform="translate(54,46)">
|
||||
<g transform="translate(-29,-61.3)">
|
||||
<path
|
||||
d="M38.5984 0C45.476 1.07762 51.9794 3.28918 57.9108 6.43722V61.1566C57.9108 77.1373 44.9364 90.1119 28.9554 90.1119C12.9744 90.1119 0 77.1373 0 61.1566C0 55.3848 1.69443 50.0063 4.60763 45.4861L38.5984 0Z"
|
||||
fill="black"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</mask>
|
||||
<mask id="LoadingAnimation__spinner-left-half-mask">
|
||||
<rect x="0" y="0" width="52" height="104" fill="white" />
|
||||
<circle
|
||||
class="LoadingAnimation__spinner-mask"
|
||||
r="20"
|
||||
cx="52"
|
||||
cy="52"
|
||||
fill="black"
|
||||
/>
|
||||
</mask>
|
||||
<mask id="LoadingAnimation__spinner-right-half-mask">
|
||||
<rect x="52" y="0" width="52" height="104" fill="white" />
|
||||
<circle
|
||||
class="LoadingAnimation__spinner-mask"
|
||||
r="20"
|
||||
cx="52"
|
||||
cy="52"
|
||||
fill="black"
|
||||
/>
|
||||
</mask>
|
||||
</defs>
|
||||
<g class="LoadingAnimation__spinner-container">
|
||||
<g class="LoadingAnimation__spinner">
|
||||
<circle
|
||||
r="25"
|
||||
cx="52"
|
||||
cy="52"
|
||||
fill="currentColor"
|
||||
mask="url(#LoadingAnimation__spinner-left-half-mask)"
|
||||
/>
|
||||
<circle
|
||||
r="25"
|
||||
cx="52"
|
||||
cy="52"
|
||||
fill="url(#LoadingAnimation__spinner-gradient)"
|
||||
mask="url(#LoadingAnimation__spinner-right-half-mask)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<g class="LoadingAnimation__compass">
|
||||
<g
|
||||
class="LoadingAnimation__compass-base-container"
|
||||
mask="url(#LoadingAnimation__base-wipe-mask)"
|
||||
>
|
||||
<circle
|
||||
class="LoadingAnimation__compass-base"
|
||||
r="52"
|
||||
cx="52"
|
||||
cy="52"
|
||||
fill="currentColor"
|
||||
mask="url(#LoadingAnimation__base-mask)"
|
||||
/>
|
||||
</g>
|
||||
<g class="LoadingAnimation__compass-needle-container">
|
||||
<g class="LoadingAnimation__compass-needle">
|
||||
<g transform="translate(54,46)">
|
||||
<g transform="translate(-15,-42)">
|
||||
<path
|
||||
d="M29.9539 1.4977C29.9539 0.670968 29.2827 0 28.4562 0C27.9597 0 27.5192 0.242028 27.2468 0.614415C27.216 0.656555 27.1873 0.700359 27.1609 0.745666L3.66519 32.1191C1.38202 34.7479 0 38.1803 0 41.9355C0 50.207 6.70541 56.9124 14.977 56.9124C23.2485 56.9124 29.9539 50.207 29.9539 41.9355L29.9539 41.9013V1.50252C29.9539 1.50091 29.9539 1.49931 29.9539 1.4977Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
Ссылка в новой задаче
Block a user