mirror of
https://github.com/theoludwig/theoludwig.git
synced 2025-05-29 22:37:44 +02:00
feat: rewrite to Next.js v13 app directory
Improvements: - Hide switch theme input (ugly little white square) - i18n without subpath (e.g: /fr or /en), same url whatever the locale used
This commit is contained in:
16
components/Header/Locales/Arrow.tsx
Normal file
16
components/Header/Locales/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
|
||||
className='fill-current text-black dark:text-white'
|
||||
d='M9.8024 0.292969L5.61855 4.58597L1.43469 0.292969L0.0566406 1.70697L5.61855 7.41397L11.1805 1.70697L9.8024 0.292969Z'
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
30
components/Header/Locales/LocaleFlag.tsx
Normal file
30
components/Header/Locales/LocaleFlag.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import Image from 'next/image'
|
||||
|
||||
import type { CookiesStore } from '@/i18n/i18n.client'
|
||||
import { useI18n } from '@/i18n/i18n.client'
|
||||
|
||||
export interface LocaleFlagProps {
|
||||
locale: string
|
||||
cookiesStore: CookiesStore
|
||||
}
|
||||
|
||||
export const LocaleFlag: React.FC<LocaleFlagProps> = (props) => {
|
||||
const { locale, cookiesStore } = props
|
||||
|
||||
const i18n = useI18n(cookiesStore)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Image
|
||||
quality={100}
|
||||
width={35}
|
||||
height={35}
|
||||
src={`/images/locales/${locale}.svg`}
|
||||
alt={locale}
|
||||
/>
|
||||
<p data-cy='locale-flag-text' className='mx-2 text-base'>
|
||||
{i18n.translate(`common.${locale}`)}
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
94
components/Header/Locales/index.tsx
Normal file
94
components/Header/Locales/index.tsx
Normal file
@ -0,0 +1,94 @@
|
||||
'use client'
|
||||
|
||||
import { useCallback, useEffect, useState, useRef } from 'react'
|
||||
import classNames from 'clsx'
|
||||
|
||||
import { AVAILABLE_LOCALES } from '@/utils/constants'
|
||||
import type { CookiesStore } from '@/i18n/i18n.client'
|
||||
|
||||
import { Arrow } from './Arrow'
|
||||
import { LocaleFlag } from './LocaleFlag'
|
||||
|
||||
export interface LocalesProps {
|
||||
currentLocale: string
|
||||
cookiesStore: CookiesStore
|
||||
}
|
||||
|
||||
export const Locales = (props: LocalesProps): JSX.Element => {
|
||||
const { currentLocale, cookiesStore } = props
|
||||
|
||||
const [hiddenMenu, setHiddenMenu] = useState(true)
|
||||
const languageClickRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
const handleHiddenMenu = useCallback(() => {
|
||||
setHiddenMenu((oldHiddenMenu) => {
|
||||
return !oldHiddenMenu
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickEvent = (event: MouseEvent): void => {
|
||||
if (languageClickRef.current == null || event.target == null) {
|
||||
return
|
||||
}
|
||||
if (!languageClickRef.current.contains(event.target as Node)) {
|
||||
setHiddenMenu(true)
|
||||
}
|
||||
}
|
||||
|
||||
window.document.addEventListener('click', handleClickEvent)
|
||||
|
||||
return () => {
|
||||
return window.removeEventListener('click', handleClickEvent)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleLocale = async (locale: string): Promise<void> => {
|
||||
const { setLocale } = await import('@/i18n/i18n.server')
|
||||
setLocale(locale)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex cursor-pointer flex-col items-center justify-center'>
|
||||
<div
|
||||
ref={languageClickRef}
|
||||
data-cy='locale-click'
|
||||
className='mr-5 flex items-center'
|
||||
onClick={handleHiddenMenu}
|
||||
>
|
||||
<LocaleFlag
|
||||
locale={currentLocale}
|
||||
cookiesStore={cookiesStore?.toString()}
|
||||
/>
|
||||
<Arrow />
|
||||
</div>
|
||||
|
||||
<ul
|
||||
data-cy='locales-list'
|
||||
className={classNames(
|
||||
'absolute top-14 z-10 mr-4 mt-3 flex w-32 list-none flex-col items-center justify-center rounded-lg bg-white p-0 shadow-lightFlag dark:bg-black dark:shadow-darkFlag',
|
||||
{ hidden: hiddenMenu }
|
||||
)}
|
||||
>
|
||||
{AVAILABLE_LOCALES.filter((locale) => {
|
||||
return locale !== currentLocale
|
||||
}).map((locale) => {
|
||||
return (
|
||||
<li
|
||||
key={locale}
|
||||
className='flex h-12 w-full items-center justify-center hover:bg-[#4f545c] hover:bg-opacity-20'
|
||||
onClick={async () => {
|
||||
return await handleLocale(locale)
|
||||
}}
|
||||
>
|
||||
<LocaleFlag
|
||||
locale={locale}
|
||||
cookiesStore={cookiesStore?.toString()}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user