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

Compare commits

..

11 Commits

49 changed files with 1416 additions and 2429 deletions

View File

@ -1,5 +1,5 @@
{
"name": "Divlo",
"name": "theoludwig",
"dockerComposeFile": "./docker-compose.yml",
"service": "workspace",
"workspaceFolder": "/workspace",

View File

@ -1,2 +1,2 @@
COMPOSE_PROJECT_NAME=divlo
COMPOSE_PROJECT_NAME=theoludwig
PORT=3000

View File

@ -4,12 +4,7 @@
"parserOptions": {
"project": "./tsconfig.json"
},
"env": {
"node": true,
"browser": true
},
"rules": {
"prettier/prettier": "error",
"@next/next/no-img-element": "off"
"prettier/prettier": "error"
}
}

View File

@ -60,7 +60,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
<contact@divlo.fr>.
<contact@theoludwig.fr>.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the

View File

@ -1,10 +1,10 @@
# 💡 Contributing
Thanks a lot for your interest in contributing to **divlo.fr**! 🎉
Thanks a lot for your interest in contributing to **theoludwig.fr**! 🎉
## Code of Conduct
**divlo.fr** adopted the [Contributor Covenant](https://www.contributor-covenant.org/) as its Code of Conduct, and we expect project participants to adhere to it. Please read [the full text](./CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated.
**theoludwig.fr** adopted the [Contributor Covenant](https://www.contributor-covenant.org/) as its Code of Conduct, and we expect project participants to adhere to it. Please read [the full text](./CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated.
## Types of contributions
@ -21,7 +21,7 @@ Thanks a lot for your interest in contributing to **divlo.fr**! 🎉
- Make sure your **code passes the tests**.
If you're adding new features to **divlo.fr**, please include tests.
If you're adding new features to **theoludwig.fr**, please include tests.
## Commits
@ -68,4 +68,4 @@ docker compose up --build
### Services started
- website: `http://127.0.0.1:3000`
- `website`: <http://127.0.0.1:3000>

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) Divlo
Copyright (c) Théo LUDWIG
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,4 +1,4 @@
<h1 align="center"><a href="https://divlo.fr/">Divlo</a></h1>
<h1 align="center"><a href="https://theoludwig.fr/">Théo LUDWIG</a></h1>
<p align="center">
<strong>Developer Full Stack • Open-Source enthusiast</strong>
@ -11,8 +11,8 @@
<a href="https://twitter.com/Divlo_FR"><img alt="Twitter" src="https://img.shields.io/badge/-Twitter-1ca0f1?style=flat&labelColor=1ca0f1&logo=twitter&logoColor=white"/></a>
<a href="https://www.youtube.com/channel/UCfEKQzI3c8vmZOrsTOi5spA"><img alt="YouTube" src="https://img.shields.io/badge/-YouTube-c4302b?style=flat&labelColor=c4302b&logo=youtube&logoColor=white"/></a>
<a href="https://www.twitch.tv/divlo"><img alt="Twitch" src="https://img.shields.io/badge/-Twitch-9147FF?style=flat&labelColor=9147FF&logo=twitch&logoColor=white"/></a>
<a href="https://www.divlo.fr"><img alt="Website" src="https://img.shields.io/badge/-Website-181818?style=flat&labelColor=181818&logo=Google-Chrome&logoColor=white"/></a>
<a href="mailto:contact@divlo.fr"><img alt="Email" src="https://img.shields.io/badge/-contact@divlo.fr-2F7EBE?style=flat&labelColor=2F7EBE&logo=minutemailer&logoColor=white"/></a>
<a href="https://theoludwig.fr/"><img alt="Website" src="https://img.shields.io/badge/-Website-181818?style=flat&labelColor=181818&logo=Google-Chrome&logoColor=white"/></a>
<a href="mailto:contact@theoludwig.fr"><img alt="Email" src="https://img.shields.io/badge/-contact@theoludwig.fr-2F7EBE?style=flat&labelColor=2F7EBE&logo=minutemailer&logoColor=white"/></a>
</p>
<hr />
@ -21,15 +21,15 @@
```json
{
"name": "Divlo",
"name": "Théo LUDWIG",
"pronouns": "He/Him",
"birthDate": "31/03/2003",
"nationality": "Alsace, France",
"interests": ["Open-Source enthusiast", "Passionate about High-Tech"],
"skills": {
"programmingLanguages": ["JavaScript/TypeScript", "Python", "C/C++", "PHP"],
"frontEnd": ["HTML", "CSS", "Tailwind CSS", "React.js/Next.js"],
"backEnd": ["Laravel", "Node.js", "Fastify", "PostgreSQL"],
"frontend": ["HTML", "CSS", "Tailwind CSS", "React.js/Next.js"],
"backend": ["Laravel", "Node.js", "Fastify", "PostgreSQL"],
"tools": ["GNU/Linux", "Ubuntu", "Visual Studio Code", "Git", "Docker"]
}
}

View File

@ -21,7 +21,7 @@ export const Footer: React.FC<FooterProps> = (props) => {
href='/'
className='text-yellow hover:underline dark:text-yellow-dark'
>
Divlo
Théo LUDWIG
</Link>{' '}
| {t('common:all-rights-reserved')}
</p>

View File

@ -9,10 +9,10 @@ interface HeadProps {
export const Head: React.FC<HeadProps> = (props) => {
const {
title = 'Divlo',
image = 'https://divlo.fr/images/icons/icon-96x96.png',
description = 'Divlo - Developer Full Stack • Passionate about High-Tech',
url = 'https://divlo.fr/'
title = 'Théo LUDWIG',
image = 'https://theoludwig.fr/images/icon-96x96.png',
description = 'Théo LUDWIG - Developer Full Stack • Passionate about High-Tech',
url = 'https://theoludwig.fr/'
} = props
return (
@ -23,7 +23,7 @@ export const Head: React.FC<HeadProps> = (props) => {
{/* Meta Tag */}
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
<meta name='description' content={description} />
<meta name='Language' content='fr, en' />
<meta name='Language' content='fr-FR, en-US' />
<meta name='theme-color' content='#ffd800' />
{/* Open Graph Metadata */}
@ -32,7 +32,7 @@ export const Head: React.FC<HeadProps> = (props) => {
<meta property='og:url' content={url} />
<meta property='og:image' content={image} />
<meta property='og:description' content={description} />
<meta property='og:locale' content='fr_FR, en_US' />
<meta property='og:locale' content='fr-FR, en-US' />
<meta property='og:site_name' content={title} />
{/* Twitter card Metadata */}
@ -46,12 +46,6 @@ export const Head: React.FC<HeadProps> = (props) => {
name='google-site-verification'
content='j9CQEbSuYydXytr6gdkTfam_xX_pU97NSpVH3Bq-6f4'
/>
{/* PWA Data */}
<link rel='manifest' href='/manifest.json' />
<meta name='apple-mobile-web-app-capable' content='yes' />
<meta name='mobile-web-app-capable' content='yes' />
<link rel='apple-touch-icon' href={image} />
</NextHead>
)
}

View File

@ -20,10 +20,11 @@ export const Header: React.FC<HeaderProps> = (props) => {
width={60}
height={60}
src='/images/divlo_icon_small.png'
alt='Divlo'
alt='Théo LUDWIG'
priority
/>
<strong className='ml-1 hidden font-headline font-semibold text-yellow dark:text-yellow-dark xs:block'>
Divlo
Théo LUDWIG
</strong>
</div>
</Link>
@ -37,7 +38,7 @@ export const Header: React.FC<HeaderProps> = (props) => {
Blog
</Link>
</div>
{showLanguage && <Language />}
{showLanguage ? <Language /> : null}
<SwitchTheme />
</div>
</header>

View File

@ -6,7 +6,7 @@ export const ProfileDescriptionBottom: React.FC = () => {
return (
<p className='mb-8 mt-8 text-base font-normal text-gray dark:text-gray-dark'>
{t('home:about.description-bottom')}
{lang === 'fr' && (
{lang === 'fr' ? (
<>
<br />
<br />
@ -17,7 +17,7 @@ export const ProfileDescriptionBottom: React.FC = () => {
Curriculum vitæ
</a>
</>
)}
) : null}
</p>
)
}

View File

@ -5,11 +5,8 @@ export const ProfileInformation: React.FC = () => {
return (
<div className='mb-6 border-b-2 border-gray-600 pb-2 font-headline dark:border-gray-400'>
<h1 className='mb-2 text-4xl'>
{t('home:about.i-am')}{' '}
<strong className='font-semibold text-yellow dark:text-yellow-dark'>
Divlo
</strong>
<h1 className='mb-2 text-4xl font-semibold text-yellow dark:text-yellow-dark'>
Théo LUDWIG
</h1>
<h2 className='mb-3 text-base'>{t('home:about.description')}</h2>
</div>

View File

@ -1,7 +1,7 @@
import useTranslation from 'next-translate/useTranslation'
import { useMemo } from 'react'
import { DIVLO_BIRTHDAY, DIVLO_BIRTHDAY_DATE, getAge } from 'utils/getAge'
import { BIRTH_DATE, BIRTH_DATE_STRING, getAge } from 'utils/getAge'
import { ProfileItem } from './ProfileItem'
@ -9,21 +9,24 @@ export const ProfileList: React.FC = () => {
const { t } = useTranslation('home')
const age = useMemo(() => {
return getAge(DIVLO_BIRTHDAY)
return getAge(BIRTH_DATE)
}, [])
return (
<ul className='m-0 list-none p-0'>
<ProfileItem title={t('home:about.full-name')} value='Théo LUDWIG' />
<ProfileItem
title={t('home:about.pronouns')}
value={t('home:about.pronouns-value')}
/>
<ProfileItem
title={t('home:about.birth-date')}
value={`${DIVLO_BIRTHDAY_DATE} (${age} ${t('home:about.years-old')})`}
value={`${BIRTH_DATE_STRING} (${age} ${t('home:about.years-old')})`}
/>
<ProfileItem title={t('home:about.nationality')} value='Alsace, France' />
<ProfileItem
title='Email'
value='contact@divlo.fr'
link='mailto:contact@divlo.fr'
value='contact@theoludwig.fr'
link='mailto:contact@theoludwig.fr'
/>
</ul>
)

View File

@ -1,11 +1,11 @@
import Image from 'next/image'
import DivloLogo from 'public/images/divlo_logo.png'
import Logo from 'public/images/divlo_logo.png'
export const ProfileLogo: React.FC = () => {
return (
<div className='max-h-[370px] max-w-[370px] px-2 py-6'>
<Image quality={100} src={DivloLogo} alt='Divlo' priority />
<Image quality={100} src={Logo} alt='Théo LUDWIG' priority />
</div>
)
}

View File

@ -31,7 +31,7 @@ export const SocialMediaList: React.FC = () => {
<SocialMediaItem link='https://www.twitch.tv/divlo' ariaLabel='Twitch'>
<TwitchIcon />
</SocialMediaItem>
<SocialMediaItem link='mailto:contact@divlo.fr' ariaLabel='Email'>
<SocialMediaItem link='mailto:contact@theoludwig.fr' ariaLabel='Email'>
<EmailIcon />
</SocialMediaItem>
</ul>

View File

@ -16,14 +16,14 @@ export const Skills: React.FC = () => {
<SkillComponent skill='PHP' />
</SkillsSection>
<SkillsSection title='Front-end'>
<SkillsSection title='Frontend'>
<SkillComponent skill='HTML' />
<SkillComponent skill='CSS' />
<SkillComponent skill='Tailwind CSS' />
<SkillComponent skill='React.js (+ Next.js)' />
</SkillsSection>
<SkillsSection title='Back-end'>
<SkillsSection title='Backend'>
<SkillComponent skill='Laravel' />
<SkillComponent skill='Node.js' />
<SkillComponent skill='Fastify' />

View File

@ -88,16 +88,12 @@ export const skills = {
},
'Visual Studio Code': {
link: 'https://code.visualstudio.com/',
image: '/images/skills/Visual_Studio_Code.png'
image: '/images/skills/VisualStudioCode.png'
},
Git: {
link: 'https://git-scm.com/',
image: '/images/skills/Git.png'
},
Hyper: {
link: 'https://hyper.is/',
image: '/images/skills/Hyper.svg'
},
Ubuntu: {
link: 'https://ubuntu.com/',
image: '/images/skills/Ubuntu.png'

View File

@ -23,7 +23,9 @@ export const Section: React.FC<SectionProps> = (props) => {
<div className='w-full px-3'>
<ShadowContainer style={{ marginTop: 50 }}>
<section {...rest}>
{heading != null && <SectionHeading>{heading}</SectionHeading>}
{heading != null ? (
<SectionHeading>{heading}</SectionHeading>
) : null}
<div className='w-full px-3'>{children}</div>
</section>
</ShadowContainer>
@ -34,7 +36,7 @@ export const Section: React.FC<SectionProps> = (props) => {
if (withoutShadowContainer) {
return (
<section {...rest}>
{heading != null && <SectionHeading>{heading}</SectionHeading>}
{heading != null ? <SectionHeading>{heading}</SectionHeading> : null}
<div className='w-full px-3'>{children}</div>
</section>
)
@ -42,16 +44,18 @@ export const Section: React.FC<SectionProps> = (props) => {
return (
<section {...rest}>
{heading != null && (
<SectionHeading style={{ ...(description != null && { margin: 0 }) }}>
{heading != null ? (
<SectionHeading
style={{ ...(description != null ? { margin: 0 } : {}) }}
>
{heading}
</SectionHeading>
)}
{description != null && (
) : null}
{description != null ? (
<p style={{ marginTop: 7 }} className='text-center'>
{description}
</p>
)}
) : null}
<div className='w-full px-3'>
<ShadowContainer>
<div className='w-full px-16 py-4 leading-8'>{children}</div>

View File

@ -4,7 +4,7 @@ describe('<Footer />', () => {
it('should render with appropriate link tag version', () => {
const version = '1.0.0'
cy.mount(<Footer version={version} />)
cy.contains('Divlo')
cy.contains('Théo LUDWIG')
.get('[data-cy=version-link]')
.should('have.text', version)
.should(

View File

@ -38,7 +38,7 @@ describe('Common > Header', () => {
describe('Switch Language', () => {
it('should switch language from EN (default) to FR', () => {
cy.get('h1').contains('I am Divlo')
cy.get('h1').contains('Théo LUDWIG')
cy.get('[data-cy=language-flag-text]').contains('EN')
cy.get('[data-cy=languages-list]').should('not.be.visible')
cy.get('[data-cy=language-click]').click()
@ -46,7 +46,7 @@ describe('Common > Header', () => {
cy.get('[data-cy=languages-list] > li:first-child').contains('FR').click()
cy.get('[data-cy=languages-list]').should('not.be.visible')
cy.get('[data-cy=language-flag-text]').contains('FR')
cy.get('h1').contains('Je suis Divlo')
cy.get('h1').contains('Théo LUDWIG')
})
it('should close the language list menu when clicking outside', () => {

View File

@ -1,7 +1,7 @@
services:
divlo:
theoludwig:
container_name: ${COMPOSE_PROJECT_NAME}
image: 'divlo'
image: 'theoludwig'
build:
context: './'
ports:

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="fr">
<html lang="fr-FR">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

View File

@ -12,9 +12,9 @@
"modern-normalize": "2.0.0"
},
"devDependencies": {
"@types/node": "20.2.1",
"@types/node": "20.2.5",
"date-and-time": "3.0.0",
"vite": "4.3.8",
"vite": "4.3.9",
"vite-plugin-html": "3.2.0"
}
},
@ -483,9 +483,9 @@
}
},
"node_modules/@types/node": {
"version": "20.2.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.1.tgz",
"integrity": "sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==",
"version": "20.2.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz",
"integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==",
"dev": true
},
"node_modules/acorn": {
@ -1020,9 +1020,9 @@
}
},
"node_modules/jake": {
"version": "10.8.6",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.6.tgz",
"integrity": "sha512-G43Ub9IYEFfu72sua6rzooi8V8Gz2lkfk48rW20vEWCGizeaEPlKB1Kh8JIA84yQbiAEfqlPmSpGgCKKxH3rDA==",
"version": "10.8.7",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
"integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==",
"dev": true,
"dependencies": {
"async": "^3.2.3",
@ -1203,9 +1203,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
"version": "8.4.24",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
"integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
"dev": true,
"funding": [
{
@ -1270,9 +1270,9 @@
}
},
"node_modules/rollup": {
"version": "3.22.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.22.0.tgz",
"integrity": "sha512-imsigcWor5Y/dC0rz2q0bBt9PabcL3TORry2hAa6O6BuMvY71bqHyfReAz5qyAqiQATD1m70qdntqBfBQjVWpQ==",
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz",
"integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
@ -1349,9 +1349,9 @@
}
},
"node_modules/terser": {
"version": "5.17.4",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.17.4.tgz",
"integrity": "sha512-jcEKZw6UPrgugz/0Tuk/PVyLAPfMBJf5clnGueo45wTweoV8yh7Q7PEkhkJ5uuUbC7zAxEcG3tqNr1bstkQ8nw==",
"version": "5.17.6",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.17.6.tgz",
"integrity": "sha512-V8QHcs8YuyLkLHsJO5ucyff1ykrLVsR4dNnS//L5Y3NiSXpbK1J+WMVUs67eI0KTxs9JtHhgEQpXQVHlHI92DQ==",
"dev": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.2",
@ -1400,9 +1400,9 @@
}
},
"node_modules/vite": {
"version": "4.3.8",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz",
"integrity": "sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==",
"version": "4.3.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
"integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
"dev": true,
"dependencies": {
"esbuild": "^0.17.5",

View File

@ -13,9 +13,9 @@
"modern-normalize": "2.0.0"
},
"devDependencies": {
"@types/node": "20.2.1",
"@types/node": "20.2.5",
"date-and-time": "3.0.0",
"vite": "4.3.8",
"vite": "4.3.9",
"vite-plugin-html": "3.2.0"
}
}

View File

@ -1,5 +1,5 @@
import { DIVLO_BIRTHDAY, getAge } from '../../utils/getAge.ts'
import { BIRTH_DATE, getAge } from '../../utils/getAge.ts'
const yearOld = document.getElementById('year-old')
yearOld.textContent = getAge(DIVLO_BIRTHDAY).toString()
yearOld.textContent = getAge(BIRTH_DATE).toString()

View File

@ -1,8 +1,8 @@
{
"about": {
"i-am": "I am",
"description": "Developer Full Stack • Open-Source enthusiast",
"full-name": "Full name",
"pronouns": "Pronouns",
"pronouns-value": "He/Him",
"birth-date": "Birth date",
"years-old": "years old",
"nationality": "Nationality",

View File

@ -1,8 +1,8 @@
{
"about": {
"i-am": "Je suis",
"description": "Développeur Full Stack • Enthousiaste de l'Open-Source",
"full-name": "Prénom NOM",
"pronouns": "Pronoms",
"pronouns-value": "Il/Lui",
"birth-date": "Date de naissance",
"years-old": "ans",
"nationality": "Nationalité",

View File

@ -1,7 +1,3 @@
const nextPWA = require('next-pwa')({
disable: process.env.NODE_ENV !== 'production',
dest: 'public'
})
const nextTranslate = require('next-translate-plugin')
/** @type {import("next").NextConfig} */
@ -10,4 +6,4 @@ const nextConfig = {
output: 'standalone'
}
module.exports = nextTranslate(nextPWA(nextConfig))
module.exports = nextTranslate(nextConfig)

3427
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "divlo",
"version": "2.7.0",
"name": "theoludwig",
"version": "2.8.0",
"private": true,
"repository": {
"type": "git",
@ -30,7 +30,7 @@
"postinstall": "husky install"
},
"dependencies": {
"@fontsource/montserrat": "5.0.0",
"@fontsource/montserrat": "5.0.1",
"@fortawesome/fontawesome-svg-core": "6.4.0",
"@fortawesome/free-brands-svg-icons": "6.4.0",
"@fortawesome/free-solid-svg-icons": "6.4.0",
@ -41,9 +41,8 @@
"gray-matter": "4.0.3",
"html-react-parser": "3.0.16",
"katex": "0.16.7",
"next": "13.4.3",
"next": "13.4.4",
"next-mdx-remote": "4.4.1",
"next-pwa": "5.6.0",
"next-themes": "0.2.1",
"next-translate": "2.0.5",
"react": "18.2.0",
@ -67,16 +66,16 @@
"@semantic-release/git": "10.0.1",
"@tailwindcss/typography": "0.5.9",
"@tsconfig/strictest": "2.0.1",
"@types/node": "20.2.1",
"@types/react": "18.2.6",
"@types/node": "20.2.5",
"@types/react": "18.2.7",
"@types/unist": "2.0.6",
"@typescript-eslint/eslint-plugin": "5.59.6",
"@typescript-eslint/eslint-plugin": "5.59.7",
"autoprefixer": "10.4.14",
"cypress": "12.12.0",
"cypress": "12.13.0",
"editorconfig-checker": "5.0.1",
"eslint": "8.41.0",
"eslint-config-conventions": "9.0.0",
"eslint-config-next": "13.4.3",
"eslint-config-next": "13.4.4",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-prettier": "4.2.1",
@ -89,13 +88,13 @@
"markdownlint-cli2": "0.7.1",
"markdownlint-rule-relative-links": "1.2.0",
"next-translate-plugin": "2.0.5",
"postcss": "8.4.23",
"postcss": "8.4.24",
"prettier": "2.8.8",
"prettier-plugin-tailwindcss": "0.3.0",
"semantic-release": "21.0.2",
"start-server-and-test": "2.0.0",
"tailwindcss": "3.3.2",
"typescript": "5.0.4",
"vercel": "29.3.6"
"vercel": "30.0.0"
}
}

View File

@ -13,7 +13,7 @@ const Error404: NextPage<Error404Props> = (props) => {
return (
<>
<Head title='404 | Divlo' />
<Head title='404 | Théo LUDWIG' />
<ErrorPage
statusCode={404}
message={t('errors:not-found')}

View File

@ -13,7 +13,7 @@ const Error500: NextPage<Error500Props> = (props) => {
return (
<>
<Head title='500 | Divlo' />
<Head title='500 | Théo LUDWIG' />
<ErrorPage
statusCode={500}
message={t('errors:server-error')}

View File

@ -1,4 +1,5 @@
import type { GetStaticProps, GetStaticPaths, NextPage } from 'next'
import Image from 'next/image'
import { MDXRemote } from 'next-mdx-remote'
import date from 'date-and-time'
import Giscus from '@giscus/react'
@ -24,56 +25,63 @@ const BlogPostPage: NextPage<BlogPostPageProps> = (props) => {
return (
<>
<Head
title={`${post.frontmatter.title} | Divlo`}
title={`${post.frontmatter.title} | Théo LUDWIG`}
description={post.frontmatter.description}
/>
<Header />
<main className='flex flex-1 flex-col flex-wrap items-center'>
<div className='my-10 flex flex-col items-center'>
<main className='break-wrap-words flex flex-1 flex-col flex-wrap items-center'>
<div className='my-10 flex flex-col items-center text-center'>
<h1 className='text-3xl font-semibold'>{post.frontmatter.title}</h1>
<p className='mt-2' data-cy='blog-post-date'>
{date.format(new Date(post.frontmatter.publishedOn), 'DD/MM/YYYY')}
</p>
</div>
<div className='prose mb-10 px-8'>
<MDXRemote
{...post.source}
components={{
img: (properties) => {
const { src, alt, ...props } = properties
let source = src
source = src?.replace('../public/', '/')
return (
<span className='flex flex-col items-center justify-center'>
<img src={source} alt={alt} {...props} />
</span>
)
},
a: (props) => {
if (props.href?.startsWith('#') ?? false) {
return <a {...props} />
<div className='prose mb-10'>
<div className='px-8'>
<MDXRemote
{...post.source}
components={{
img: (properties) => {
const { src = '', alt = 'Blog Image' } = properties
const source = src.replace('../public/', '/')
return (
<span className='flex flex-col items-center justify-center'>
<Image
src={source}
alt={alt}
width={1000}
height={1000}
className='h-auto w-auto'
/>
</span>
)
},
a: (props) => {
if (props.href?.startsWith('#') ?? false) {
return <a {...props} />
}
return (
<a target='_blank' rel='noopener noreferrer' {...props} />
)
}
return (
<a target='_blank' rel='noopener noreferrer' {...props} />
)
}
}}
/>
<Giscus
id='comments'
repo='Divlo/Divlo'
repoId='MDEwOlJlcG9zaXRvcnkzNTg5NDg1NDQ='
category='General'
categoryId='DIC_kwDOFWUewM4CQ_WK'
mapping='pathname'
reactionsEnabled='1'
emitMetadata='0'
inputPosition='top'
theme={theme}
lang='en'
loading='lazy'
/>
}}
/>
<Giscus
id='comments'
repo='Divlo/Divlo'
repoId='MDEwOlJlcG9zaXRvcnkzNTg5NDg1NDQ='
category='General'
categoryId='DIC_kwDOFWUewM4CQ_WK'
mapping='pathname'
reactionsEnabled='1'
emitMetadata='0'
inputPosition='top'
theme={theme}
lang='en'
loading='lazy'
/>
</div>
</div>
</main>
<Footer version={version} />

View File

@ -21,7 +21,7 @@ const BlogPage: NextPage<BlogPageProps> = (props) => {
return (
<>
<Head title='Blog | Divlo' description={blogDescription} />
<Head title='Blog | Théo LUDWIG' description={blogDescription} />
<Header />
<main className='flex flex-1 flex-col flex-wrap items-center'>

View File

@ -7,13 +7,13 @@ publishedOn: '2022-04-11T10:24:55.206Z'
Hello! 👋
After months of hard work, [Thream v1.0.0](https://www.thream.divlo.fr/) has been released! 🎉
After months of hard work, [Thream v1.0.0](https://thream.divlo.fr/) has been released! 🎉
[**Thream**](https://www.thream.divlo.fr/) is your open-source platform to stay close with your friends and communities, talk, chat, collaborate, share and have fun.
[**Thream**](https://thream.divlo.fr/) is your open-source platform to stay close with your friends and communities, talk, chat, collaborate, share and have fun.
## Presentation
[**Thream**](https://www.thream.divlo.fr/) is a social network to stay close with your friends and communities to talk, chat, collaborate and share.
[**Thream**](https://thream.divlo.fr/) is a social network to stay close with your friends and communities to talk, chat, collaborate and share.
The project is largely inspired by [Discord](https://discord.com), a proprietary instant messaging service, but differentiates itself by its **non-profit open source philosophy** and will integrate special features.
@ -23,11 +23,11 @@ The idea is that a user can create an account to authenticate with an email addr
![The Thream app on a community page](../public/images/posts/thream-v1-0-0/thream-ui.png)
[**Thream**](https://www.thream.divlo.fr/) is a website that works on any recent browser, accessible on [thream.divlo.fr](https://www.thream.divlo.fr/).
[**Thream**](https://thream.divlo.fr/) is a website that works on any recent browser, accessible on [thream.divlo.fr](https://thream.divlo.fr/).
## History
The idea for the project has existed since May 13, 2020, symbolized by a [publication on Twitter](https://twitter.com/Divlo_FR/status/1260638175246135296) by the creator: Divlo.
The idea for the project has existed since May 13, 2020, symbolized by a [publication on Twitter](https://twitter.com/Divlo_FR/status/1260638175246135296) by the creator: Théo LUDWIG.
The main goal is to put into **practice knowledge in web development** and computer science in general on a concrete project that can **easily evolve over time** where you can add many features.
@ -116,4 +116,4 @@ The other interest of the project is that it is completely **open-source**, and
Feel free to give feebacks and suggestions to improve the project, and to report any bug you find.
**Thream** is available: [**thream.divlo.fr**](https://www.thream.divlo.fr/).
**Thream** is available: [**thream.divlo.fr**](https://thream.divlo.fr/).

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,51 +0,0 @@
{
"name": "Divlo",
"short_name": "Divlo",
"icons": [
{
"src": "images/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "images/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "images/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "images/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "images/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "images/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "images/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffd800",
"background_color": "#181818",
"start_url": "/",
"display": "standalone"
}

View File

@ -6,14 +6,14 @@
"basics": {
"name": "Théo LUDWIG",
"label": "Développeur Full Stack • Étudiant",
"image": "https://divlo.fr/images/logo_orange.png",
"email": "contact@divlo.fr",
"image": "https://theoludwig.fr/images/logo_orange.png",
"email": "contact@theoludwig.fr",
"age": "31/03/2003",
"location": {
"address": "Alsace, France"
},
"url": "https://divlo.fr",
"summary": "Je suis étudiant à l'université suivant la formation \"BUT Informatique\" et me forme en autodidacte dans l'informatique en suivant des formations en ligne. <br/> Je mets en pratique tout ce que j'apprends et réalise de nombreux projets (disponible sur <a href=\"https://divlo.fr\">divlo.fr</a>)."
"url": "https://theoludwig.fr",
"summary": "Je suis étudiant à l'université suivant la formation \"BUT Informatique\" et me forme en autodidacte dans l'informatique en suivant des formations en ligne. <br/> Je mets en pratique tout ce que j'apprends et réalise de nombreux projets (disponible sur <a href=\"https://theoludwig.fr\">theoludwig.fr</a>)."
},
"education": [
{

View File

@ -2,8 +2,13 @@
@tailwind components;
@tailwind utilities;
.break-wrap-words {
word-wrap: break-word;
word-break: break-word;
}
.prose {
@apply !max-w-4xl text-gray dark:text-gray-300;
@apply !max-w-5xl text-gray dark:text-gray-300;
}
.prose a,
@ -28,8 +33,6 @@
}
.shiki {
white-space: pre-wrap !important;
word-break: normal !important;
word-wrap: normal;
}
code {
counter-reset: step;
@ -43,4 +46,12 @@ code .line::before {
display: inline-block;
text-align: right;
color: rgba(133, 133, 133, 0.8);
word-wrap: normal;
word-break: normal;
}
.katex .base {
display: inline !important;
white-space: normal !important;
width: 100% !important;
}

View File

@ -1,11 +1,11 @@
export const DIVLO_BIRTHDAY_DAY = '31' as const
export const DIVLO_BIRTHDAY_MONTH = '03' as const
export const DIVLO_BIRTHDAY_YEAR = '2003' as const
export const DIVLO_BIRTHDAY_DATE =
`${DIVLO_BIRTHDAY_DAY}/${DIVLO_BIRTHDAY_MONTH}/${DIVLO_BIRTHDAY_YEAR}` as const
export const DIVLO_BIRTHDAY_DATE_ISO_8061 =
`${DIVLO_BIRTHDAY_YEAR}-${DIVLO_BIRTHDAY_MONTH}-${DIVLO_BIRTHDAY_DAY}` as const
export const DIVLO_BIRTHDAY = new Date(DIVLO_BIRTHDAY_DATE_ISO_8061)
export const BIRTH_DATE_DAY = '31' as const
export const BIRTH_DATE_MONTH = '03' as const
export const BIRTH_DATE_YEAR = '2003' as const
export const BIRTH_DATE_STRING =
`${BIRTH_DATE_DAY}/${BIRTH_DATE_MONTH}/${BIRTH_DATE_YEAR}` as const
export const BIRTH_DATE_ISO_8601 =
`${BIRTH_DATE_YEAR}-${BIRTH_DATE_MONTH}-${BIRTH_DATE_DAY}` as const
export const BIRTH_DATE = new Date(BIRTH_DATE_ISO_8601)
/**
* Calculates the age of a person based on their birth date