1
1
mirror of https://github.com/theoludwig/theoludwig.git synced 2025-05-29 22:37:44 +02:00

feat: improve header to set locale + remove setup page

This commit is contained in:
divlo
2021-04-18 18:02:55 +02:00
parent a1608b25b6
commit e68fdb132e
34 changed files with 283 additions and 691 deletions

View File

@ -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>

View File

@ -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>
</>
)
}

View File

@ -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>
</>
)
}

View File

@ -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>

View File

@ -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>
</>
)
}

View File

@ -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>
</>
)
}

View 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>
)
}

View 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>
</>
)
}

View 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>
</>
)
}

View File

@ -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>
</>
)
}

View File

@ -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>
</>
)
}

View File

@ -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;
}
}
`}

View File

@ -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>

View File

@ -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>
</>
)
}

View File

@ -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>
</>
)
}

View File

@ -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>
</>
)
}