feat: improve header to set locale + remove setup page
@ -4,7 +4,7 @@
|
||||
"startServerCommand": "npm run start",
|
||||
"startServerReadyPattern": "ready on",
|
||||
"startServerReadyTimeout": 20000,
|
||||
"url": ["http://localhost:3000/", "http://localhost:3000/setup"],
|
||||
"url": ["http://localhost:3000/"],
|
||||
"numberOfRuns": 3
|
||||
},
|
||||
"assert": {
|
||||
|
@ -77,7 +77,7 @@ export const Contact: React.FC = () => {
|
||||
required
|
||||
/>
|
||||
|
||||
<div className='text-center'>
|
||||
<div className='text-center' style={{ marginBottom: 20 }}>
|
||||
<Button type='submit'>{t('home:contact.sendEmail')}</Button>
|
||||
</div>
|
||||
</Form>
|
||||
|
@ -1,29 +0,0 @@
|
||||
import setLanguage from 'next-translate/setLanguage'
|
||||
|
||||
interface LanguageButtonProps {
|
||||
lang: string
|
||||
}
|
||||
|
||||
export const LanguageButton: React.FC<LanguageButtonProps> = (props) => {
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
onClick={async () => await setLanguage(props.lang)}
|
||||
className='important'
|
||||
>
|
||||
{props.children}
|
||||
</span>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
span {
|
||||
cursor: pointer;
|
||||
}
|
||||
span:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import { Tooltip } from 'components/design/Tooltip'
|
||||
import { LanguageButton } from './LanguageButton'
|
||||
|
||||
interface LanguageFlagProps {
|
||||
imageLink: string
|
||||
title: string
|
||||
lang: string
|
||||
}
|
||||
|
||||
export const LanguageFlag: React.FC<LanguageFlagProps> = (props) => {
|
||||
const { lang, title, imageLink } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='LanguageFlag'>
|
||||
<LanguageButton lang={lang}>
|
||||
<Tooltip title={title}>
|
||||
<Image alt={title} src={imageLink} width={31} height={31} />
|
||||
</Tooltip>
|
||||
</LanguageButton>
|
||||
</div>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.LanguageFlag {
|
||||
margin-right: 7px;
|
||||
}
|
||||
@media (max-width: 700px) {
|
||||
.LanguageFlag {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,36 +1,16 @@
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
|
||||
import { LanguageButton } from './LanguageButton'
|
||||
import { LanguageFlag } from './LanguageFlag'
|
||||
|
||||
export const Footer: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<footer className='Footer text-center'>
|
||||
<p className='Footer__text'>
|
||||
<p>
|
||||
<span className='important'>Divlo</span> | {t('common:allRightsReserved')}
|
||||
</p>
|
||||
<p className='Footer__lang'>
|
||||
<LanguageButton lang='en'>{t('common:english')}</LanguageButton> |{' '}
|
||||
<LanguageButton lang='fr'>{t('common:french')}</LanguageButton>
|
||||
</p>
|
||||
</footer>
|
||||
|
||||
<div className='Footer__flags'>
|
||||
<LanguageFlag
|
||||
lang='en'
|
||||
imageLink='/images/flags/english_flag.png'
|
||||
title={t('common:english')}
|
||||
/>
|
||||
<LanguageFlag
|
||||
lang='fr'
|
||||
imageLink='/images/flags/french_flag.png'
|
||||
title={t('common:french')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.Footer {
|
||||
@ -39,19 +19,7 @@ export const Footer: React.FC = () => {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.Footer__text {
|
||||
margin: 20px 0 10px 0;
|
||||
}
|
||||
.Footer__lang {
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
.Footer__flags {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
bottom: 28px;
|
||||
left: 32px;
|
||||
z-index: 10;
|
||||
padding: 10px;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
@ -1,38 +0,0 @@
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
|
||||
export const BrandLogo: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<Link href='/'>
|
||||
<a className='Header__brand-link'>
|
||||
<Image
|
||||
width={65}
|
||||
height={65}
|
||||
src='/images/divlo_icon_small.png'
|
||||
alt="Divlo's Logo"
|
||||
/>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.Header__brand-link {
|
||||
display: inline-block;
|
||||
padding-top: 0.3125rem;
|
||||
padding-bottom: 0.3125rem;
|
||||
margin-right: 1rem;
|
||||
font-size: 1.25rem;
|
||||
line-height: inherit;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@media (min-width: 993px) {
|
||||
.Header__brand-link {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
type HamburgerIconComponent = React.FC<{
|
||||
isActive: boolean
|
||||
handleToggleNavbar: () => void
|
||||
}>
|
||||
|
||||
export const HamburgerIcon: HamburgerIconComponent = props => {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
onClick={props.handleToggleNavbar}
|
||||
className={classNames('Header__hamburger', {
|
||||
'Header__hamburger-active': props.isActive
|
||||
})}
|
||||
>
|
||||
<span />
|
||||
</div>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.Header__hamburger {
|
||||
display: none;
|
||||
width: 56px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 0.25rem;
|
||||
position: relative;
|
||||
}
|
||||
.Header__hamburger > span,
|
||||
.Header__hamburger > span::before,
|
||||
.Header__hamburger > span::after {
|
||||
position: absolute;
|
||||
width: 22px;
|
||||
height: 1.3px;
|
||||
background-color: rgba(255, 255, 255);
|
||||
}
|
||||
.Header__hamburger > span {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: background-color 0.3s ease-in-out;
|
||||
}
|
||||
.Header__hamburger > span::before,
|
||||
.Header__hamburger > span::after {
|
||||
content: '';
|
||||
transition: transform 0.3s ease-in-out;
|
||||
}
|
||||
.Header__hamburger > span::before {
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
.Header__hamburger > span::after {
|
||||
transform: translateY(8px);
|
||||
}
|
||||
.Header__hamburger-active span {
|
||||
background-color: transparent;
|
||||
}
|
||||
.Header__hamburger-active > span::before {
|
||||
transform: translateY(0px) rotateZ(45deg);
|
||||
}
|
||||
.Header__hamburger-active > span::after {
|
||||
transform: translateY(0px) rotateZ(-45deg);
|
||||
}
|
||||
/* Hamburger icon on Mobile */
|
||||
@media (max-width: 992px) {
|
||||
.Header__hamburger {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
16
components/Header/Language/Arrow.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
export const Arrow: React.FC = () => {
|
||||
return (
|
||||
<svg
|
||||
width='12'
|
||||
height='8'
|
||||
viewBox='0 0 12 8'
|
||||
fill='none'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
>
|
||||
<path
|
||||
d='M9.8024 0.292969L5.61855 4.58597L1.43469 0.292969L0.0566406 1.70697L5.61855 7.41397L11.1805 1.70697L9.8024 0.292969Z'
|
||||
fill='#fff'
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
31
components/Header/Language/LanguageFlag.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
export interface LanguageFlagProps {
|
||||
language: string
|
||||
}
|
||||
|
||||
export const LanguageFlag: React.FC<LanguageFlagProps> = (props) => {
|
||||
const { language } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<Image
|
||||
width={35}
|
||||
height={35}
|
||||
src={`/images/languages/${language}.svg`}
|
||||
alt={language}
|
||||
/>
|
||||
<p className='language-title'>{language.toUpperCase()}</p>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.language-title {
|
||||
margin: 0 8px 0 10px;
|
||||
font-size: 16px;
|
||||
font-family: 'Arial', 'sans-serif';
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
105
components/Header/Language/index.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
import setLanguage from 'next-translate/setLanguage'
|
||||
|
||||
import { Arrow } from './Arrow'
|
||||
import { LanguageFlag } from './LanguageFlag'
|
||||
import { locales } from 'i18n.json'
|
||||
|
||||
export const Language: React.FC = () => {
|
||||
const { lang: currentLanguage } = useTranslation()
|
||||
const [hiddenMenu, setHiddenMenu] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
if (!hiddenMenu) {
|
||||
window.document.addEventListener('click', handleHiddenMenu)
|
||||
} else {
|
||||
window.document.removeEventListener('click', handleHiddenMenu)
|
||||
}
|
||||
|
||||
return () => {
|
||||
window.document.removeEventListener('click', handleHiddenMenu)
|
||||
}
|
||||
}, [hiddenMenu])
|
||||
|
||||
const handleLanguage = async (language: string): Promise<void> => {
|
||||
await setLanguage(language)
|
||||
handleHiddenMenu()
|
||||
}
|
||||
|
||||
const handleHiddenMenu = (): void => {
|
||||
setHiddenMenu(!hiddenMenu)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='language-menu'>
|
||||
<div className='selected-language' onClick={handleHiddenMenu}>
|
||||
<LanguageFlag language={currentLanguage} />
|
||||
<Arrow />
|
||||
</div>
|
||||
{!hiddenMenu && (
|
||||
<ul>
|
||||
{locales.map((language, index) => {
|
||||
if (language === currentLanguage) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<li
|
||||
key={index}
|
||||
onClick={async () => await handleLanguage(language)}
|
||||
>
|
||||
<LanguageFlag language={language} />
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.language-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.selected-language {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 15px;
|
||||
}
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
width: 100px;
|
||||
padding: 10px;
|
||||
margin: 10px 15px 0 0px;
|
||||
border-radius: 15%;
|
||||
padding: 0;
|
||||
box-shadow: 0px 1px 10px var(--color-shadow);
|
||||
background-color: var(--color-background-primary);
|
||||
z-index: 10;
|
||||
}
|
||||
ul > li {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
}
|
||||
ul > li:hover {
|
||||
background-color: rgba(79, 84, 92, 0.16);
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import classNames from 'classnames'
|
||||
|
||||
type NavigationLinkComponent = React.FC<{ path: string }>
|
||||
|
||||
export const NavigationLink: NavigationLinkComponent = props => {
|
||||
const { pathname } = useRouter()
|
||||
const isCurrentPage = pathname === props.path
|
||||
|
||||
return (
|
||||
<>
|
||||
<li className='navbar-item'>
|
||||
<Link href={props.path}>
|
||||
<a
|
||||
className={classNames('navbar-link', {
|
||||
'navbar-link-active': isCurrentPage
|
||||
})}
|
||||
>
|
||||
{props.children}
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.navbar-link {
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
.navbar-link:hover {
|
||||
text-decoration: none;
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
.navbar-link,
|
||||
.navbar-link-active {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.navbar-link-active,
|
||||
.navbar-link-active:hover {
|
||||
color: var(--text-color);
|
||||
}
|
||||
.navbar-item {
|
||||
list-style: none;
|
||||
}
|
||||
.navbar-link {
|
||||
font-size: 16px;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
import classNames from 'classnames'
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
|
||||
import { NavigationLink } from './NavigationLink'
|
||||
|
||||
type NavigationComponent = React.FC<{ isActive: boolean }>
|
||||
|
||||
export const Navigation: NavigationComponent = props => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<nav className='Header__navbar'>
|
||||
<ul
|
||||
className={classNames('navbar__list', {
|
||||
'navbar__list-active': props.isActive
|
||||
})}
|
||||
>
|
||||
<NavigationLink path='/'>{t('common:home')}</NavigationLink>
|
||||
<NavigationLink path='/setup'>Setup</NavigationLink>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
@media (min-width: 992px) {
|
||||
.Header__navbar {
|
||||
display: flex;
|
||||
flex-basis: auto;
|
||||
}
|
||||
}
|
||||
.Header__navbar {
|
||||
flex-basis: 100%;
|
||||
flex-grow: 1;
|
||||
align-items: center;
|
||||
}
|
||||
.navbar__list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-left: auto;
|
||||
}
|
||||
.navbar__list.navbar__list-active {
|
||||
margin: 0 !important;
|
||||
display: flex;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.navbar__list {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,65 +1,84 @@
|
||||
import { useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
|
||||
import { HamburgerIcon } from './HamburgerIcon'
|
||||
import { BrandLogo } from './BrandLogo'
|
||||
import { Navigation } from './Navigation'
|
||||
import { Language } from './Language'
|
||||
|
||||
export const Header: React.FC = () => {
|
||||
const [isActive, setIsActive] = useState(false)
|
||||
|
||||
const handleToggleNavbar = (): void => {
|
||||
setIsActive(!isActive)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className='Header'>
|
||||
<header className='header'>
|
||||
<div className='container'>
|
||||
<BrandLogo />
|
||||
<HamburgerIcon
|
||||
isActive={isActive}
|
||||
handleToggleNavbar={handleToggleNavbar}
|
||||
/>
|
||||
<Navigation isActive={isActive} />
|
||||
<nav className='navbar navbar-fixed-top'>
|
||||
<Link href='/'>
|
||||
<a className='navbar__brand-link'>
|
||||
<div className='navbar__brand'>
|
||||
<Image
|
||||
width={60}
|
||||
height={60}
|
||||
src='/images/divlo_icon_small.png'
|
||||
alt='Divlo'
|
||||
/>
|
||||
<strong className='navbar__brand-title'>Divlo</strong>
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
<div className='navbar__buttons'>
|
||||
<Language />
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<style jsx>
|
||||
{`
|
||||
.Header {
|
||||
.header {
|
||||
background-color: var(--color-background);
|
||||
border-bottom: var(--border-header-footer);
|
||||
padding: 0.5rem 1rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
|
||||
height: var(--header-height);
|
||||
}
|
||||
.container {
|
||||
max-width: 1280px;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
.navbar {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 1rem;
|
||||
|
||||
border-bottom: var(--border-header-footer);
|
||||
background-color: var(--color-background);
|
||||
align-items: center;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.Header {
|
||||
display: flex;
|
||||
flex-basis: auto;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.navbar-fixed-top {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 200;
|
||||
}
|
||||
.Header > .container {
|
||||
.navbar__brand-link {
|
||||
color: var(--color-text-1);
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
.navbar__brand {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.Header > .container {
|
||||
flex-wrap: nowrap;
|
||||
.navbar__brand-title {
|
||||
font-weight: 600;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.navbar__buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
@media (max-width: 320px) {
|
||||
.navbar__brand-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`}
|
||||
|
@ -1,14 +1,11 @@
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
import Translation from 'next-translate/Trans'
|
||||
|
||||
export const ProfileDescriptionBottom: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className='profile-description-bottom'>
|
||||
<Translation
|
||||
i18nKey={t('home:about.descriptionBottom')}
|
||||
i18nKey='home:about.descriptionBottom'
|
||||
components={[<br key='break' />]}
|
||||
/>
|
||||
</p>
|
||||
|
@ -1,50 +0,0 @@
|
||||
export interface TableRow {
|
||||
title: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface TableProps {
|
||||
rows: TableRow[]
|
||||
}
|
||||
|
||||
export const Table: React.FC<TableProps> = props => {
|
||||
const { rows } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='col-24 table-column text-center'>
|
||||
<table>
|
||||
<tbody>
|
||||
{rows.map((row, index) => {
|
||||
return (
|
||||
<tr key={index}>
|
||||
<th className='table-row'>{row.title}</th>
|
||||
<td className='table-row'>{row.value}</td>
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style jsx>{`
|
||||
.table-column {
|
||||
display: grid;
|
||||
}
|
||||
.table,
|
||||
th,
|
||||
td {
|
||||
border: 1px solid var(--color-text-1);
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.table-row {
|
||||
padding: 15px;
|
||||
}
|
||||
.image-setup {
|
||||
width: 85%;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
export const TableTitle: React.FC = props => {
|
||||
const { children } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='col-24'>
|
||||
<p className='text-center title-table'>
|
||||
<strong className='important'>{children}</strong>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<style jsx>{`
|
||||
.title-table {
|
||||
font-size: 24px;
|
||||
margin: 40px 0 20px 0;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
import Image from 'next/image'
|
||||
|
||||
import { Table, TableRow } from './Table'
|
||||
import { TableTitle } from './TableTitle'
|
||||
|
||||
export const Setup: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const rowsConfigPC: TableRow[] = [
|
||||
{
|
||||
title: t('setup:configPC.motherboard'),
|
||||
value: 'MSI Z87-G45 GAMING'
|
||||
},
|
||||
{
|
||||
title: t('setup:configPC.processor'),
|
||||
value: 'Intel Core i5-4690k'
|
||||
},
|
||||
{
|
||||
title: t('setup:configPC.graphicCard'),
|
||||
value: 'Zotac GeForce GTX 970'
|
||||
},
|
||||
{
|
||||
title: t('setup:configPC.ramMemory'),
|
||||
value: '16 GB (2 x 8Go) Kingston HyperX'
|
||||
},
|
||||
{
|
||||
title: t('setup:configPC.hardDrive'),
|
||||
value: '256 GB SSD Crucial & 2 TB Seagate'
|
||||
}
|
||||
]
|
||||
|
||||
const rowsPeripherals: TableRow[] = [
|
||||
{
|
||||
title: t('setup:peripheral.keyboard'),
|
||||
value: 'Corsair K95 RGB'
|
||||
},
|
||||
{
|
||||
title: t('setup:peripheral.mouse'),
|
||||
value: 'SteelSeries Rival 310'
|
||||
},
|
||||
{
|
||||
title: t('setup:peripheral.headset'),
|
||||
value: 'SteelSeries ARCTIS PRO + GAMEDAC'
|
||||
},
|
||||
{
|
||||
title: t('setup:peripheral.mainScreen'),
|
||||
value: 'IIyama PL2480H'
|
||||
},
|
||||
{
|
||||
title: t('setup:peripheral.secondScreen'),
|
||||
value: 'Samsung SyncMaster 2220LM'
|
||||
}
|
||||
]
|
||||
|
||||
const rowsOffice: TableRow[] = [
|
||||
{
|
||||
title: t('setup:officeOther.mousepad'),
|
||||
value: 'SteelSeries QCK Heavy (Grand) as string'
|
||||
},
|
||||
{
|
||||
title: 'Mouse Bungee',
|
||||
value: 'BenQ ZOWIE Camade'
|
||||
},
|
||||
{
|
||||
title: t('setup:officeOther.usb'),
|
||||
value: 'Kingston 128GB'
|
||||
},
|
||||
{
|
||||
title: 'Smartphone',
|
||||
value: 'Samsung Galaxy A5 (2017)'
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableTitle>{t('setup:configPC.title')}</TableTitle>
|
||||
<Table rows={rowsConfigPC} />
|
||||
|
||||
<TableTitle>{t('setup:peripheral.title')}</TableTitle>
|
||||
<Table rows={rowsPeripherals} />
|
||||
|
||||
<TableTitle>{t('setup:officeOther.title')}</TableTitle>
|
||||
<Table rows={rowsOffice} />
|
||||
|
||||
<div
|
||||
className='row row-padding justify-content-center'
|
||||
style={{ marginTop: 50 }}
|
||||
>
|
||||
<Image
|
||||
src='/images/setup/setup2019.png'
|
||||
alt='Setup Divlo'
|
||||
width={856.8}
|
||||
height={672.58}
|
||||
className='Setup__image'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='row row-padding justify-content-center'>
|
||||
<Image
|
||||
src='/images/setup/setup2019-lights.jpg'
|
||||
alt='Setup Divlo'
|
||||
width={856.8}
|
||||
height={672.58}
|
||||
className='Setup__image'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='row row-padding'>
|
||||
<TableTitle>{t('setup:connexion')}</TableTitle>
|
||||
<div style={{ marginBottom: 25 }} className='col-24 text-center'>
|
||||
<a
|
||||
href='https://www.speedtest.net/result/8533865940'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
aria-label='Speedtest link'
|
||||
>
|
||||
<Image
|
||||
src='/images/setup/speedtest-result.png'
|
||||
alt='Speedtest Result'
|
||||
width={308}
|
||||
height={165}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style jsx global>
|
||||
{`
|
||||
.Setup__image {
|
||||
width: 85% !important;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
@ -4,7 +4,6 @@
|
||||
"pages": {
|
||||
"*": ["common"],
|
||||
"/": ["home"],
|
||||
"/setup": ["setup"],
|
||||
"/404": ["errors"],
|
||||
"/500": ["errors"]
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
},
|
||||
{
|
||||
"title": "Open-Source enthusiast :",
|
||||
"description": "For me, everyone should work, solve problems, build things and think together. Long live open source, whenever you can share your work, do it! <br/> The website is open-source on <a href='https://github.com/Divlo/divlo.fr' target='_blank' rel='noopener noreferrer'>github</a>."
|
||||
"description": "For me, everyone should work, solve problems, build things and think together. Long live open source, whenever you can share your work, do it! <br/> The website is open-source on <a href='https://github.com/Divlo/Divlo' target='_blank' rel='noopener noreferrer'>github</a>."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1,26 +0,0 @@
|
||||
{
|
||||
"title": "Setup of Divlo",
|
||||
"description": "The list of all the computer equipment that Divlo has.",
|
||||
"configPC": {
|
||||
"title": "Hardware PC Configuration",
|
||||
"motherboard": "Motherboard",
|
||||
"processor": "Processor",
|
||||
"graphicCard": "Graphic card",
|
||||
"ramMemory": "Ram Memory",
|
||||
"hardDrive": "Hard Drive"
|
||||
},
|
||||
"peripheral": {
|
||||
"title": "Computer Peripheral ",
|
||||
"keyboard": "Keyboard",
|
||||
"mouse": "Mouse",
|
||||
"headset": "Micro Headset",
|
||||
"mainScreen": "Main Screen",
|
||||
"secondScreen": "2nd screen"
|
||||
},
|
||||
"officeOther": {
|
||||
"title": "Office / Other",
|
||||
"mousepad": "Mousepad",
|
||||
"usb": "USB Key"
|
||||
},
|
||||
"connexion": "My internet connection"
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
"description": "Développeur Full Stack Junior • Passionné de High-Tech",
|
||||
"birthDate": "Date de naissance",
|
||||
"nationality": "Nationalité",
|
||||
"descriptionBottom": "J'apprends en ligne l'informatique et les langages de programmation pour m'améliorer dans ma passion. <br/> <br/> J'ai conçu ma charte graphique et mon site internet."
|
||||
"descriptionBottom": "J'apprends en ligne l'informatique et les langages de programmation pour m'améliorer dans ma passion. <0/> <0/> J'ai conçu ma charte graphique et mon site internet."
|
||||
},
|
||||
"interests": {
|
||||
"title": "Mes intérêts",
|
||||
@ -19,7 +19,7 @@
|
||||
},
|
||||
{
|
||||
"title": "Enthousiaste de l'Open-Source :",
|
||||
"description": "Pour moi, tout le monde devrait travailler, résoudre des problèmes, construire des choses et réfléchir ensemble. Longue vie à l'open-source, chaque fois que vous pouvez partagez votre travail, faites-le! <br/> Le site est open-source sur <a href='https://github.com/Divlo/divlo.fr' target='_blank' rel='noopener noreferrer'>github</a>."
|
||||
"description": "Pour moi, tout le monde devrait travailler, résoudre des problèmes, construire des choses et réfléchir ensemble. Longue vie à l'open-source, chaque fois que vous pouvez partagez votre travail, faites-le! <br/> Le site est open-source sur <a href='https://github.com/Divlo/Divlo' target='_blank' rel='noopener noreferrer'>github</a>."
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1,26 +0,0 @@
|
||||
{
|
||||
"title": "Setup de Divlo",
|
||||
"description": "La liste de tout le matériel informatique dont dispose Divlo.",
|
||||
"configPC": {
|
||||
"title": "Configuration matérielle du PC",
|
||||
"motherboard": "Carte mère",
|
||||
"processor": "Processeur",
|
||||
"graphicCard": "Carte graphique",
|
||||
"ramMemory": "Mémoires Ram",
|
||||
"hardDrive": "Disques Dur"
|
||||
},
|
||||
"peripheral": {
|
||||
"title": "Périphériques",
|
||||
"keyboard": "Clavier",
|
||||
"mouse": "Souris",
|
||||
"headset": "Casque Micro",
|
||||
"mainScreen": "Écran Principal",
|
||||
"secondScreen": "2ème écran"
|
||||
},
|
||||
"officeOther": {
|
||||
"title": "Bureautique / Autre",
|
||||
"mousepad": "Tapis de souris",
|
||||
"usb": "Clé USB"
|
||||
},
|
||||
"connexion": "Ma connection internet"
|
||||
}
|
26
package-lock.json
generated
@ -18,7 +18,7 @@
|
||||
"classnames": "2.3.1",
|
||||
"html-react-parser": "1.2.5",
|
||||
"next": "10.1.3",
|
||||
"next-pwa": "5.2.10",
|
||||
"next-pwa": "5.2.12",
|
||||
"next-translate": "1.0.6",
|
||||
"nodemailer": "6.5.0",
|
||||
"normalize.css": "8.0.1",
|
||||
@ -9802,9 +9802,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/next-pwa": {
|
||||
"version": "5.2.10",
|
||||
"resolved": "https://registry.npmjs.org/next-pwa/-/next-pwa-5.2.10.tgz",
|
||||
"integrity": "sha512-0WIEIEqAy9q5YGA/gYwXVWHStGtoIqJRAZusO3PlRHo3HDr5CWs1RCJ/2faCL/UIyZ9msrUxl0+GR9oxlest0A==",
|
||||
"version": "5.2.12",
|
||||
"resolved": "https://registry.npmjs.org/next-pwa/-/next-pwa-5.2.12.tgz",
|
||||
"integrity": "sha512-MWVpV5sq0eQnJnp79o0DQlMOIpmEoBLpeakKqrAXlhyLLKRF+94UmeLaBLtWvj2yadBGfpa59EbiTTGv+cfySw==",
|
||||
"dependencies": {
|
||||
"babel-loader": "^8.2.2",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
@ -10623,9 +10623,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.1.tgz",
|
||||
"integrity": "sha512-WQUIkCSDPWm5ing/PTUkLr2KaOXX2uV/vz1hLGW2XbZ/RDUmtgcsOyEqA1ox0rkyNx9mJX4kxX+YWceje3pmag==",
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.2.tgz",
|
||||
"integrity": "sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@ -22853,9 +22853,9 @@
|
||||
}
|
||||
},
|
||||
"next-pwa": {
|
||||
"version": "5.2.10",
|
||||
"resolved": "https://registry.npmjs.org/next-pwa/-/next-pwa-5.2.10.tgz",
|
||||
"integrity": "sha512-0WIEIEqAy9q5YGA/gYwXVWHStGtoIqJRAZusO3PlRHo3HDr5CWs1RCJ/2faCL/UIyZ9msrUxl0+GR9oxlest0A==",
|
||||
"version": "5.2.12",
|
||||
"resolved": "https://registry.npmjs.org/next-pwa/-/next-pwa-5.2.12.tgz",
|
||||
"integrity": "sha512-MWVpV5sq0eQnJnp79o0DQlMOIpmEoBLpeakKqrAXlhyLLKRF+94UmeLaBLtWvj2yadBGfpa59EbiTTGv+cfySw==",
|
||||
"requires": {
|
||||
"babel-loader": "^8.2.2",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
@ -23421,9 +23421,9 @@
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"object-inspect": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.1.tgz",
|
||||
"integrity": "sha512-WQUIkCSDPWm5ing/PTUkLr2KaOXX2uV/vz1hLGW2XbZ/RDUmtgcsOyEqA1ox0rkyNx9mJX4kxX+YWceje3pmag=="
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.2.tgz",
|
||||
"integrity": "sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA=="
|
||||
},
|
||||
"object-is": {
|
||||
"version": "1.1.5",
|
||||
|
@ -40,7 +40,7 @@
|
||||
"classnames": "2.3.1",
|
||||
"html-react-parser": "1.2.5",
|
||||
"next": "10.1.3",
|
||||
"next-pwa": "5.2.10",
|
||||
"next-pwa": "5.2.12",
|
||||
"next-translate": "1.0.6",
|
||||
"nodemailer": "6.5.0",
|
||||
"normalize.css": "8.0.1",
|
||||
|
@ -18,14 +18,14 @@ const emailTransporter = nodemailer.createTransport({
|
||||
})
|
||||
|
||||
export default async (
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
request: NextApiRequest,
|
||||
response: NextApiResponse
|
||||
): Promise<any> => {
|
||||
if (req.method !== 'POST') {
|
||||
return res.redirect('/404')
|
||||
if (request.method !== 'POST') {
|
||||
return response.redirect('/404')
|
||||
}
|
||||
|
||||
let { name, email, subject, message } = req.body as {
|
||||
let { name, email, subject, message } = request.body as {
|
||||
name: string
|
||||
email: string
|
||||
subject: string
|
||||
@ -38,11 +38,11 @@ export default async (
|
||||
validator.isEmpty(subject) ||
|
||||
validator.isEmpty(message)
|
||||
) {
|
||||
return res.status(400).json({ type: 'requiredFields' })
|
||||
return response.status(400).json({ type: 'requiredFields' })
|
||||
}
|
||||
|
||||
if (!validator.isEmail(email)) {
|
||||
return res.status(400).json({ type: 'invalidEmail' })
|
||||
return response.status(400).json({ type: 'invalidEmail' })
|
||||
}
|
||||
|
||||
email = validator.normalizeEmail(email) as string
|
||||
@ -62,8 +62,8 @@ export default async (
|
||||
<b>Message:</b> ${message}
|
||||
`
|
||||
})
|
||||
return res.status(201).json({ type: 'success' })
|
||||
return response.status(201).json({ type: 'success' })
|
||||
} catch {
|
||||
return res.status(500).json({ type: 'serverError' })
|
||||
return response.status(500).json({ type: 'serverError' })
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
import { GetStaticProps } from 'next'
|
||||
import useTranslation from 'next-translate/useTranslation'
|
||||
|
||||
import { Section } from 'components/design/Section'
|
||||
import Head from 'components/Head'
|
||||
import { Setup } from 'components/Setup'
|
||||
|
||||
const SetupPage: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head title={t('setup:title')} description={t('setup:description')} />
|
||||
|
||||
<Section
|
||||
id='setup'
|
||||
style={{ marginTop: 60 }}
|
||||
description={t('setup:description')}
|
||||
heading={t('setup:title')}
|
||||
>
|
||||
<Setup />
|
||||
</Section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const getStaticProps: GetStaticProps = async () => {
|
||||
return { props: {} }
|
||||
}
|
||||
|
||||
export default SetupPage
|
Before Width: | Height: | Size: 525 B |
Before Width: | Height: | Size: 127 B |
30
public/images/languages/en.svg
Normal file
@ -0,0 +1,30 @@
|
||||
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M46 4.6C41.3 1.7 35.9 0 30 0V4.6H46Z" fill="#ED4C5C"/>
|
||||
<path d="M30 9.2H51.6C49.9 7.5 48 5.9 46 4.6H30V9.2Z" fill="white"/>
|
||||
<path d="M30 13.8H55.3C54.2 12.1 53 10.6 51.7 9.2H30V13.8Z" fill="#ED4C5C"/>
|
||||
<path d="M30 18.4H57.7C57 16.8 56.2 15.2 55.3 13.8H30V18.4Z" fill="white"/>
|
||||
<path d="M30 23H59.2C58.8 21.4 58.3 19.9 57.7 18.4H30V23Z" fill="#ED4C5C"/>
|
||||
<path d="M30 27.7H59.9C59.8 26.1 59.5 24.6 59.2 23.1H30V27.7Z" fill="white"/>
|
||||
<path d="M59.9 27.7H30V30H0C0 30.8 -9.68575e-08 31.5 0.0999999 32.3H59.9C60 31.5 60 30.8 60 30C60 29.2 60 28.4 59.9 27.7Z" fill="#ED4C5C"/>
|
||||
<path d="M0.800006 36.9H59.2C59.6 35.4 59.8 33.9 59.9 32.3H0.100006C0.200006 33.8 0.400006 35.4 0.800006 36.9Z" fill="white"/>
|
||||
<path d="M2.3 41.5H57.7C58.3 40 58.8 38.5 59.2 36.9H0.800003C1.2 38.5 1.7 40 2.3 41.5Z" fill="#ED4C5C"/>
|
||||
<path d="M4.7 46.1H55.3C56.2 44.6 57 43.1 57.7 41.5H2.3C3 43.1 3.8 44.6 4.7 46.1Z" fill="white"/>
|
||||
<path d="M8.3 50.7H51.7C53 49.3 54.3 47.7 55.3 46.1H4.7C5.7 47.8 7 49.3 8.3 50.7Z" fill="#ED4C5C"/>
|
||||
<path d="M13.9 55.3H46.1C48.2 54 50 52.4 51.7 50.7H8.3C10 52.5 11.9 54 13.9 55.3Z" fill="white"/>
|
||||
<path d="M30 60C35.9 60 41.4 58.3 46.1 55.3H13.9C18.6 58.3 24.1 60 30 60Z" fill="#ED4C5C"/>
|
||||
<path d="M14 4.6C11.9 5.9 10 7.5 8.3 9.2C6.9 10.6 5.7 12.2 4.7 13.8C3.8 15.3 2.9 16.8 2.3 18.4C1.7 19.9 1.2 21.4 0.8 23C0.4 24.5 0.2 26 0.0999999 27.6C-9.68575e-08 28.4 0 29.2 0 30H30V0C24.1 0 18.7 1.7 14 4.6Z" fill="#428BC1"/>
|
||||
<path d="M23 1L23.5 2.5H25L23.8 3.5L24.2 5L23 4.1L21.8 5L22.2 3.5L21 2.5H22.5L23 1Z" fill="white"/>
|
||||
<path d="M27 7L27.5 8.5H29L27.8 9.5L28.2 11L27 10.1L25.8 11L26.2 9.5L25 8.5H26.5L27 7Z" fill="white"/>
|
||||
<path d="M19 7L19.5 8.5H21L19.8 9.5L20.2 11L19 10.1L17.8 11L18.2 9.5L17 8.5H18.5L19 7Z" fill="white"/>
|
||||
<path d="M23 13L23.5 14.5H25L23.8 15.5L24.2 17L23 16.1L21.8 17L22.2 15.5L21 14.5H22.5L23 13Z" fill="white"/>
|
||||
<path d="M15 13L15.5 14.5H17L15.8 15.5L16.2 17L15 16.1L13.8 17L14.2 15.5L13 14.5H14.5L15 13Z" fill="white"/>
|
||||
<path d="M7 13L7.5 14.5H9L7.8 15.5L8.2 17L7 16.1L5.8 17L6.2 15.5L5 14.5H6.5L7 13Z" fill="white"/>
|
||||
<path d="M27 19L27.5 20.5H29L27.8 21.5L28.2 23L27 22.1L25.8 23L26.2 21.5L25 20.5H26.5L27 19Z" fill="white"/>
|
||||
<path d="M19 19L19.5 20.5H21L19.8 21.5L20.2 23L19 22.1L17.8 23L18.2 21.5L17 20.5H18.5L19 19Z" fill="white"/>
|
||||
<path d="M11 19L11.5 20.5H13L11.8 21.5L12.2 23L11 22.1L9.8 23L10.2 21.5L9 20.5H10.5L11 19Z" fill="white"/>
|
||||
<path d="M23 25L23.5 26.5H25L23.8 27.5L24.2 29L23 28.1L21.8 29L22.2 27.5L21 26.5H22.5L23 25Z" fill="white"/>
|
||||
<path d="M15 25L15.5 26.5H17L15.8 27.5L16.2 29L15 28.1L13.8 29L14.2 27.5L13 26.5H14.5L15 25Z" fill="white"/>
|
||||
<path d="M7 25L7.5 26.5H9L7.8 27.5L8.2 29L7 28.1L5.8 29L6.2 27.5L5 26.5H6.5L7 25Z" fill="white"/>
|
||||
<path d="M9.79999 11L11 10.1L12.2 11L11.7 9.5L12.9 8.5H11.4L11 7L10.5 8.5H9.09999L10.3 9.4L9.79999 11Z" fill="white"/>
|
||||
<path d="M1.79999 23L2.99999 22.1L4.19999 23L3.69999 21.5L4.89999 20.5H3.49999L2.99999 19L2.49999 20.5H1.49999C1.49999 20.6 1.39999 20.7 1.39999 20.8L2.19999 21.4L1.79999 23Z" fill="white"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.0 KiB |
12
public/images/languages/fr.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<svg width="35" height="35" viewBox="0 0 35 35" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path d="M0 17.5C0 25.1417 4.9 31.6167 11.6667 34.0084V0.991699C4.9 3.38337 0 9.85837 0 17.5Z" fill="#428BC1"/>
|
||||
<path d="M35 17.5C35 9.85837 30.1584 3.38337 23.3334 0.991699V34.0084C30.1584 31.6167 35 25.1417 35 17.5Z" fill="#ED4C5C"/>
|
||||
<path d="M11.6666 34.0083C13.475 34.65 15.4583 35 17.5 35C19.5416 35 21.525 34.65 23.3333 34.0083V0.991667C21.525 0.35 19.6 0 17.5 0C15.4 0 13.475 0.35 11.6666 0.991667V34.0083Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="35" height="35" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 659 B |
Before Width: | Height: | Size: 216 KiB |
Before Width: | Height: | Size: 651 KiB |
Before Width: | Height: | Size: 49 KiB |
@ -4,7 +4,8 @@
|
||||
--color-text-1: rgb(222, 222, 222);
|
||||
--color-text-2: #b2bac2;
|
||||
--color-background: #181818;
|
||||
--header-height: 99px;
|
||||
--color-shadow: rgba(255, 255, 255, 0.2);
|
||||
--header-height: 79px;
|
||||
}
|
||||
*,
|
||||
*::before,
|
||||
|