frontend: Preloader & 404 Error page
This commit is contained in:
parent
3debd85a70
commit
fd7fc44fe7
@ -1,6 +1,6 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useState, forwardRef } from 'react';
|
import { useState, forwardRef } from 'react';
|
||||||
import Loader from '../Loader/Loader';
|
import Loader from '../Loader';
|
||||||
import './FunctionCard.css';
|
import './FunctionCard.css';
|
||||||
|
|
||||||
const FunctionCard = forwardRef((props, ref) => {
|
const FunctionCard = forwardRef((props, ref) => {
|
||||||
|
@ -1,33 +1,36 @@
|
|||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
|
|
||||||
const HeadTag = (props) => (
|
const HeadTag = ({ title, image, description }) => (
|
||||||
<Head>
|
<Head>
|
||||||
<title>{props.title}</title>
|
<title>{title}</title>
|
||||||
<link rel="icon" type="image/png" href={props.image} />
|
<link rel="icon" type="image/png" href={image} />
|
||||||
|
|
||||||
{/* Meta Tag */}
|
{/* Meta Tag */}
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="description" content={props.description} />
|
<meta name="description" content={description} />
|
||||||
<link rel="canonical" href="function.divlo.fr"/>
|
<link rel="canonical" href="function.divlo.fr"/>
|
||||||
<meta name="Language" content="fr" />
|
<meta name="Language" content="fr" />
|
||||||
<meta name="theme-color" content="#ffd800" />
|
<meta name="theme-color" content="#ffd800" />
|
||||||
|
|
||||||
{/* Open Graph Metadata */}
|
{/* Open Graph Metadata */}
|
||||||
<meta property="og:title" content={props.title} />
|
<meta property="og:title" content={title} />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:url" content="https://function.divlo.fr/" />
|
<meta property="og:url" content="https://function.divlo.fr/" />
|
||||||
<meta property="og:image" content={props.image} />
|
<meta property="og:image" content={image} />
|
||||||
<meta property="og:description" content={props.description} />
|
<meta property="og:description" content={description} />
|
||||||
<meta property="og:locale" content="fr_FR" />
|
<meta property="og:locale" content="fr_FR" />
|
||||||
<meta property="og:site_name" content="FunctionProject" />
|
<meta property="og:site_name" content="FunctionProject" />
|
||||||
|
|
||||||
{/* Twitter card Metadata */}
|
{/* Twitter card Metadata */}
|
||||||
<meta name="twitter:card" content="summary" />
|
<meta name="twitter:card" content="summary" />
|
||||||
<meta name="twitter:description" content={props.description} />
|
<meta name="twitter:description" content={description} />
|
||||||
<meta name="twitter:title" content={props.title} />
|
<meta name="twitter:title" content={title} />
|
||||||
<meta name="twitter:site" content="@Divlo_FR" />
|
<meta name="twitter:site" content="@Divlo_FR" />
|
||||||
<meta name="twitter:image:src" content={props.image} />
|
<meta name="twitter:image:src" content={image} />
|
||||||
<meta name="twitter:creator" content="@Divlo_FR" />
|
<meta name="twitter:creator" content="@Divlo_FR" />
|
||||||
|
|
||||||
|
{/* Preloader script */}
|
||||||
|
<script src="/js/preloader.js"></script>
|
||||||
</Head>
|
</Head>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
15
frontend/components/Loader.js
Normal file
15
frontend/components/Loader.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const Loader = ({ width, height, speed }) => (
|
||||||
|
<svg width={width} height={height} viewBox="0 0 100 100">
|
||||||
|
<g transform="translate(50 50) rotate(0) scale(1 1) translate(-50 -50)">
|
||||||
|
<image style={{transformOrigin: "50% 50%", animation: `${speed} linear 0s infinite normal forwards running Loader__spin`}} x="0" y="0" width="100" height="100" href="/images/FunctionProject_icon.png"></image>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
Loader.defaultProps = {
|
||||||
|
width: "100px",
|
||||||
|
height: "100px",
|
||||||
|
speed: ".9s"
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Loader;
|
@ -1,13 +0,0 @@
|
|||||||
.Loader {
|
|
||||||
transform-origin: 50% 50%; animation: .9s linear 0s infinite normal forwards running Loader__spin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes Loader__spin {
|
|
||||||
0% {
|
|
||||||
animation-timing-function: cubic-bezier(0.5856,0.0703,0.4143,0.9297);
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import './Loader.css';
|
|
||||||
|
|
||||||
const Loader = ({ width, height }) => (
|
|
||||||
<svg width={width} height={height} viewBox="0 0 100 100">
|
|
||||||
<g transform="translate(50 50) rotate(0) scale(1 1) translate(-50 -50)">
|
|
||||||
<image className="Loader" x="0" y="0" width="100" height="100" href="/images/FunctionProject_icon.png"></image>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default Loader;
|
|
29
frontend/pages/404.js
Normal file
29
frontend/pages/404.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Fragment } from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import HeadTag from '../components/HeadTag';
|
||||||
|
import '../public/css/pages/404.css';
|
||||||
|
|
||||||
|
const Error404 = () => (
|
||||||
|
<Fragment>
|
||||||
|
<HeadTag
|
||||||
|
title="Erreur 404"
|
||||||
|
description="Cette page n'existe pas!"
|
||||||
|
image="/images/error404.png"
|
||||||
|
/>
|
||||||
|
<div className="Error404__container">
|
||||||
|
<h1>Erreur <span className="important">404</span></h1>
|
||||||
|
<p className="text-center">
|
||||||
|
Cette page n'existe pas! <Link href={"/"}><a>Revenir à la page d'accueil ?</a></Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
{`
|
||||||
|
#__next {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Error404;
|
@ -1,4 +1,5 @@
|
|||||||
import Document, { Html, Head, Main, NextScript } from "next/document";
|
import Document, { Html, Head, Main, NextScript } from "next/document";
|
||||||
|
import Loader from '../components/Loader';
|
||||||
|
|
||||||
class MyDocument extends Document {
|
class MyDocument extends Document {
|
||||||
static async getInitialProps(ctx) {
|
static async getInitialProps(ctx) {
|
||||||
@ -11,7 +12,12 @@ class MyDocument extends Document {
|
|||||||
<Html lang="fr">
|
<Html lang="fr">
|
||||||
<Head />
|
<Head />
|
||||||
<body>
|
<body>
|
||||||
<Main />
|
<div id="preloader">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
<div className="isLoading">
|
||||||
|
<Main />
|
||||||
|
</div>
|
||||||
<NextScript />
|
<NextScript />
|
||||||
</body>
|
</body>
|
||||||
</Html>
|
</Html>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Fragment, useState, useEffect, useRef, useCallback } from 'react';
|
import { Fragment, useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import HeadTag from '../components/HeadTag';
|
import HeadTag from '../components/HeadTag';
|
||||||
import FunctionCard from '../components/FunctionCard/FunctionCard';
|
import FunctionCard from '../components/FunctionCard/FunctionCard';
|
||||||
import Loader from '../components/Loader/Loader';
|
import Loader from '../components/Loader';
|
||||||
import '../public/css/pages/functions.css';
|
import '../public/css/pages/functions.css';
|
||||||
import { API_URL } from '../config/config';
|
import { API_URL } from '../config/config';
|
||||||
import api from '../config/api';
|
import api from '../config/api';
|
||||||
@ -91,7 +91,7 @@ const Functions = () => {
|
|||||||
return <FunctionCard key={f.id} slug={f.slug} image={API_URL + f.image} title={f.title} description={f.description} category={f.categorie} publicationDate={new Date(f.createdAt).toLocaleDateString('fr-FR')} />;
|
return <FunctionCard key={f.id} slug={f.slug} image={API_URL + f.image} title={f.title} description={f.description} category={f.categorie} publicationDate={new Date(f.createdAt).toLocaleDateString('fr-FR')} />;
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
{isLoadingFunctions && <Loader width="100px" height="100px" />}
|
{isLoadingFunctions && <Loader />}
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
@ -45,6 +45,26 @@ a:hover {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* LOADING */
|
||||||
|
.isLoading {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#preloader {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
@keyframes Loader__spin {
|
||||||
|
0% {
|
||||||
|
animation-timing-function: cubic-bezier(0.5856, 0.0703, 0.4143, 0.9297);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* UTILITIES */
|
/* UTILITIES */
|
||||||
.text-center {
|
.text-center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
7
frontend/public/css/pages/404.css
Normal file
7
frontend/public/css/pages/404.css
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.Error404__container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
BIN
frontend/public/images/error404.png
Normal file
BIN
frontend/public/images/error404.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 168 KiB |
4
frontend/public/js/preloader.js
Normal file
4
frontend/public/js/preloader.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
window.addEventListener('load', () => {
|
||||||
|
document.querySelector('.isLoading').classList.remove('isLoading');
|
||||||
|
document.getElementById('preloader').remove();
|
||||||
|
});
|
Reference in New Issue
Block a user