Begin migrate to leptos

This commit is contained in:
Florian RICHER 2023-10-08 20:26:40 +02:00
parent 1060e12513
commit 79daad993e
45 changed files with 3202 additions and 1975 deletions

View file

@ -0,0 +1,11 @@
.link {
@apply flex gap-1 font-semibold italic;
& > i {
@apply flex items-center;
& > svg {
@apply scale-75;
}
}
}

View file

@ -0,0 +1,19 @@
import react, { ReactNode } from 'react';
import './Link.scss'
import { FaExternalLinkAlt } from 'react-icons/fa';
type LinkProps = {
children: ReactNode,
url: string
}
function Link({ children, url }: LinkProps) {
return (
<a className="link" href={url} target='_blank'>
{ children }
<i><FaExternalLinkAlt/></i>
</a>
)
}
export default Link

View file

@ -0,0 +1,422 @@
import react from 'react'
import Timeline from './timeline/Timeline'
import TimelineElement from './timeline/TimelineElement'
import TimelineLabel from './timeline/TimelineLabel'
import TimelineCard from './timeline/TimelineCard'
import TimelineCardSummary from './timeline/TimelineCardSummary'
import TimelineCardContent from './timeline/TimelineCardContent'
import Tag from './Tag'
import ProjectList from './project/ProjectList'
import ProjectElement from './project/ProjectElement'
import Link from './Link'
// Lang
const RUST_TAG = <Tag name="Rust" url="https://www.rust-lang.org/" />
const JAVA_TAG = <Tag name="Java" url="https://www.java.com/fr/" />
const CPP_TAG = <Tag name="C++" url="https://isocpp.org/" />
// Other
const REACT_TAG = <Tag name="React" url="https://fr.legacy.reactjs.org/" />
const SYMFONY_4_TAG = <Tag name="Symfony" url="https://symfony.com/" />
const FLUTTER_TAG = <Tag name="Flutter" url="https://flutter.dev/" />
const RUBY_ON_RAILS_TAG = <Tag name="Ruby on rails" url="https://rubyonrails.org/" />
const HOTWIRED_TAG = <Tag name="Hotwired" url="https://hotwired.dev/" />
const DOCKER_TAG = <Tag name="Docker" url="https://www.docker.com/" />
const STEAM_TAG = <Tag name="Steam API" url="https://partner.steamgames.com/doc/sdk/api/example" />
const GITLAB_CI_TAG = <Tag name="Gitlab CI" url="https://docs.gitlab.com/ee/ci/" />
const UNITY_TAG = <Tag name="Unity 3D" url="https://unity.com/fr" />
const WORDPRESS_TAG = <Tag name="Wordpress" url="https://wordpress.com/fr/" />
const CORDOVA_TAG = <Tag name="Cordova" url="https://cordova.apache.org/" />
const ELECTRON_TAG = <Tag name="Electron" url="https://www.electronjs.org/" />
const LWJGL_TAG = <Tag name="LWJGL" url="https://www.lwjgl.org/" />
const OPENGL_TAG = <Tag name="OpenGL" url="https://www.opengl.org/" />
const VULKAN_TAG = <Tag name="Vulkan" url="https://www.vulkan.org/" />
const MIDI_TAG = <Tag name="MIDI" url="https://fr.wikipedia.org/wiki/Musical_Instrument_Digital_Interface" />
const REQUIREJS_TAG = <Tag name="RequireJS" url="https://requirejs.org/" />
const WEBPACK_TAG = <Tag name="Webpack" url="https://webpack.js.org/" />
const VITE_TAG = <Tag name="Vite" url="https://vitejs.dev/" />
const MAVEN_TAG = <Tag name="Maven" url="https://maven.apache.org/" />
const GRADLE_TAG = <Tag name="Gradle" url="https://gradle.org/" />
const BABYLONJG_TAG = <Tag name="BabylonJS" url="https://www.babylonjs.com/" />
const ROCKET_RS_TAG = <Tag name="Rocket" url="https://rocket.rs/" />
const ACTIX_WEB_TAG = <Tag name="Actix Web" url="https://actix.rs/" />
function MonParcours() {
return (
<div>
<Timeline>
<TimelineElement>
<TimelineLabel>2019 - Aujourdhui</TimelineLabel>
<TimelineCard>
<TimelineCardSummary
tags={[
REACT_TAG, SYMFONY_4_TAG, FLUTTER_TAG, RUBY_ON_RAILS_TAG, HOTWIRED_TAG, RUST_TAG, WEBPACK_TAG, VITE_TAG, GRADLE_TAG
]}
>
Développeur dapplication Web, Mobile et Système (CDI)
</TimelineCardSummary>
<TimelineCardContent>
<p>Développement dapplication Symfony, React, Flutter, Rust et Ruby on rails (6 et 7) pour des clients.</p><br />
<p>Je développe surtout des applications Flutter et Ruby on rails avec laide de Hotwired.</p><br />
<i>Unova France</i><br />
<i>11 Septembre 2019 - Toujours en CDI</i>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
RUST_TAG, VULKAN_TAG
]}
>
Développement 3D (Perso)
</TimelineCardSummary>
<TimelineCardContent>
<p>Je développe un petit moteur 3D pour apprendre à utiliser Vulkan, mais aussi pour prendre en expérience en Rust</p><br/>
<ProjectList>
<ProjectElement
description="Projet pour apprendre"
url='https://github.com/mrdev023/RustGameMicroEngine'
/>
<ProjectElement
description="Le but, refaire mon vieux projet de voxel pour progresser en Rust et Vulkan"
url='https://github.com/mrdev023/voxel_rust_test'
/>
</ProjectList>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
RUST_TAG, ROCKET_RS_TAG, ACTIX_WEB_TAG
]}
>
Développement Web en Rust (Perso)
</TimelineCardSummary>
<TimelineCardContent>
<p>Je teste quelques technologies Web en Rust</p><br/>
<ProjectList>
<ProjectElement
description="Projet de test Rocket"
url='https://github.com/mrdev023/Rust-Rocket-Project'
/>
<ProjectElement
description="Projet de test actix"
url='https://github.com/mrdev023/rust-actix'
/>
</ProjectList>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
RUST_TAG
]}
>
Développement dun outil daccès serveur sécurisé en Rust (Perso)
</TimelineCardSummary>
<TimelineCardContent>
<p>Le but du projet était de proposer un programme en tant que shell et de vérifier la connexion entrante avec un Service dédié.</p><br/>
<p>Lensemble des sessions étaient enregistrées pour permettre à n'importe qui de savoir ce qui s'est passé.</p><br/>
<p>Les administrateurs pouvaient également gérer les connexions avec une ligne de commande.</p><br/>
<i>Le projet a é abandonné au profit de <Link url="https://github.com/ovh/the-bastion">The Bastion</Link></i>
<ProjectList>
<ProjectElement
description="Github du projet"
url='https://github.com/mrdev023/command_gateway'
/>
</ProjectList>
</TimelineCardContent>
</TimelineCard>
</TimelineElement>
<TimelineElement>
<TimelineLabel>2018 - 2019</TimelineLabel>
<TimelineCard>
<TimelineCardSummary
tags={[
UNITY_TAG, SYMFONY_4_TAG, GITLAB_CI_TAG, STEAM_TAG, DOCKER_TAG, MIDI_TAG
]}
>
Développeur Web et dapplication 2D (CDI)
</TimelineCardSummary>
<TimelineCardContent>
<p>Développement du Site en Symfony 4 (Changement graphique, ajout de fonctionnalité)</p><br />
<p>Intégration du déploiement continue de la nouvelle application Limouzik refaite sous Unity 3D sur Steam</p><br />
<i>Limouzik SAS</i><br />
<i>03 Septembre 2018 - 31 Juillet 2019 (Rupture pour raison économique)</i>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
UNITY_TAG
]}
>
Global Game Jam édition 2019 (Concours)
</TimelineCardSummary>
<TimelineCardContent>
<p>Participation au Global Gam Jam édition 2019.</p><br />
<p>Le but du concours est de developper un Jeu en 48h à partir dun thème donné au départ du concours.</p><br />
<i>3iL - Limoges</i><br />
<i>25 janvier - 27 janvier</i><br />
<i>Thème : What home means to you</i><br />
<i>Participants : Ezyrath, Fabien87, Flavien, MrDev023 (Moi), php4ever, spoutnik87</i><br />
<ProjectList>
<ProjectElement
image_src="https://github.com/mrdev023/Global-Game-Jam-2019/blob/master/ggj_2019_maison.png?raw=true"
description="Cauchemar en forêt"
url='https://github.com/mrdev023/Global-Game-Jam-2019'
/>
</ProjectList>
</TimelineCardContent>
</TimelineCard>
</TimelineElement>
<TimelineElement>
<TimelineLabel>2017 - 2018</TimelineLabel>
<TimelineCard>
<TimelineCardSummary>License Dev. Web et du Big Data</TimelineCardSummary>
<TimelineCardContent>
<p>Licence professionnelle en alternance de développeur dapplication web et du Big Data (LP DWBD).</p><br />
<p>Utilisation de docker, Mysql, PHP avancé, Symfony 3 et 4, AngularJS, NodeJS, Cassandra, MongoDB, </p><br />
<i>IUT du Limousin à Limoges</i>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
SYMFONY_4_TAG
]}
>
Développeur Web (Projet Tuteuré)
</TimelineCardSummary>
<TimelineCardContent>
<p>Développement du site sliz.me avec Symfony 4.</p><br />
<p>Ajout de QRCode sur l'ensemble des pages d'un fichier PDF pour que d'autres personnes puissent télécharger le PDF ou une page en question durant une conférence.</p><br />
<p>Il fallait également pouvoir générer des QrCode simple à scanner pour quun étudiant puisse le scanner à lautre bout de lamphi.</p><br />
<i>Onegate</i><br />
<i>Octobre 2017 - Février 2017</i>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
UNITY_TAG, SYMFONY_4_TAG, STEAM_TAG, REACT_TAG, WORDPRESS_TAG, CORDOVA_TAG, ELECTRON_TAG, MIDI_TAG, WEBPACK_TAG
]}
>
Développeur Web et dapplication 2D (Alternance)
</TimelineCardSummary>
<TimelineCardContent>
<p>Maintenance de la version du site en Wordpress + Refonte complète du site (Graphique et technique) avec Symfony 4.</p><br />
<p>Maintenance de la première version de lapplication React ainsi que la migration des modules RequireJS vers Webpack pour fortement améliorer le temps de chargement</p><br />
<p>Pour permettre lévolution future de lapplication (Intégration avec dautre boite de jeu VR + Gamification), lapplication a être refaite de A à Z en C# avec le moteur 3D Unity.</p><br />
<p>Ajout de lapplication Limouzik sur le Play Store (Android), AppStore (iOS) et sur Steam (PC) avec lintégration de SteamAPI</p><br />
<i>Lensemble du travail a é effectué par mes soins</i><br /><br />
<i>Limouzik SAS</i><br />
<i>04 Septembre 2017 - 24 Aout 2018</i>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
OPENGL_TAG, JAVA_TAG
]}
>
Global Game Jam édition 2017 (Concours)
</TimelineCardSummary>
<TimelineCardContent>
<p>Participation au Global Gam Jam édition 2017.</p><br />
<p>Le but du concours est de developper un Jeu en 48h à partir dun thème donné au départ du concours.</p><br />
<i>3iL - Limoges</i><br />
<i>20 janvier - 22 janvier</i><br />
<i>Thème : Waves</i><br />
<i>Participants : emiko, Fiesta87, MrDev023 (Moi), TheKitolex</i><br />
<ProjectList>
<ProjectElement
description="Beach Fighter"
url='https://github.com/mrdev023/Global-Gam-Jam-2017/'
/>
</ProjectList>
</TimelineCardContent>
</TimelineCard>
</TimelineElement>
<TimelineElement>
<TimelineLabel>2015 - 2017</TimelineLabel>
<TimelineCard>
<TimelineCardSummary>DUT Informatique</TimelineCardSummary>
<TimelineCardContent>
<p>Conception de programme en Java, C++, C, Android, PHP, NodeJS et lutilisation de Mysql. Apprentissage des bases scientifiques dans linformatique.</p><br />
<i>IUT du Limousin à Limoges</i>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
REACT_TAG, WORDPRESS_TAG, MIDI_TAG, REQUIREJS_TAG
]}
>
Développement dapplication Web + Site (Stage + CDD)
</TimelineCardSummary>
<TimelineCardContent>
<p>Développement dune application musicale en utilisant le protocole MIDI (+ Synthèse sonore).</p><br />
<p>La partie affichage a é développé avec React et RequireJS (Gestion de module).</p><br />
<p>Administration du Site en Wordpress avec les Plugins (Woocommerce et PaidMembership Pro) ainsi que le développement dun plugin propriétaire pour lintégration de lapplication dans Wordpress</p><br />
<i>Limouzik SAS</i><br />
<i>03 Avril 2017 - 30 Juin 2017 (Stage)</i><br />
<i>01 Juillet 2017 - 31 Juillet 2017 (CDD)</i>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
OPENGL_TAG, JAVA_TAG
]}
>
Global Game Jam édition 2016 (Concours)
</TimelineCardSummary>
<TimelineCardContent>
<p>Participation au Global Gam Jam édition 2016.</p><br />
<p>Le but du concours est de developper un Jeu en 48h à partir dun thème donné au départ du concours.</p><br />
<i>3iL - Limoges</i><br />
<i>29 janvier - 31 janvier</i><br />
<i>Thème : Ritual</i><br />
<i>Participants : Aliths, dikaios, Fiesta87, MrDev023 (Moi), TheKitolex</i><br />
<ProjectList>
<ProjectElement
image_src="https://github.com/mrdev023/Global-Game-Jam-2016/blob/master/ggj_into.png?raw=true"
description="Bifrost Saver's"
url='https://github.com/mrdev023/Global-Game-Jam-2016'
/>
</ProjectList>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
BABYLONJG_TAG
]}
>
Nuit de linfo édition 2016 (Concours)
</TimelineCardSummary>
<TimelineCardContent>
<p>Participation à la Nuit de linfo édition 2016.</p><br />
<p>Le but de ce concours était de développer un projet WebGL en 8h.</p><br />
<i>Bordeaux</i><br />
<i>1 Décembre 2016 - 2 Décembre 2016</i><br />
<i>Sujet : Venir en aide aux réfugiés</i><br />
<i>Nom de léquipe : echo "Avis de template"</i><br />
<i>Slogan : Qui sème le vent récolte le Template</i><br />
<Link url="https://www.nuitdelinfo.com/nuitinfo/defis2016:archives#defi12">WebGL : 1er</Link>
<Link url="https://www.nuitdelinfo.com/nuitinfo/defis2016:archives#defi38">Méthode agile : 1er</Link>
<ProjectList>
<ProjectElement
description="Github du projet"
url='https://github.com/mrdev023/NUIT_INFO_2_DECEMBRE_2016'
/>
</ProjectList>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
OPENGL_TAG, CPP_TAG
]}
>
Utilisation de lAPI graphique OpenGL (Perso)
</TimelineCardSummary>
<TimelineCardContent>
<p>Après avoir appris à faire de lOpenGL en Java , jai voulu tester en C++</p><br />
<ProjectList>
<ProjectElement
description='Petit projet OpenGL en C++'
url='https://github.com/mrdev023/MrDev023-Cpp-Engine'
/>
</ProjectList>
</TimelineCardContent>
</TimelineCard>
</TimelineElement>
<TimelineElement>
<TimelineLabel>2012 - 2015</TimelineLabel>
<TimelineCard>
<TimelineCardSummary>Bac STI2D spécialité SIN</TimelineCardSummary>
<TimelineCardContent>
<p>Passage du Bac sciences et technologies de lindustrie et du développement durable (STI2D).</p>
<p>Spécialité systèmes dinformation et numérique (SIN).</p><br />
<i>Lycée Jean Favard à Guéret</i>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
JAVA_TAG, MAVEN_TAG
]}
>
Développement en Java (Perso)
</TimelineCardSummary>
<TimelineCardContent>
<p>Apprentissage dans un premier temps du langage avec le site du zéro et les quelques vidéos sur Youtube.</p><br />
<p>Ensuite, j'ai commencé à développer des projets Perso (Plugin Minecraft, Mod Minecraft) dans un premier temps.</p><br />
<p>Puis, j'ai commencé à développer des petits jeux de A à Z (Petit moteur de physique + graphique + audio) et à m'entrainer avec des amis pour participer à des concours comme le Ludum dare et la Global Game Jam.</p>
</TimelineCardContent>
</TimelineCard>
<TimelineCard>
<TimelineCardSummary
tags={[
LWJGL_TAG, OPENGL_TAG, JAVA_TAG
]}
>
Utilisation de lAPI graphique OpenGL (Perso)
</TimelineCardSummary>
<TimelineCardContent>
<p>Après avoir développé quelques trucs sur Minecraft. Je me suis interessé à son fonctionnement et j'ai découvert la librairie LWJGL utilisé dans Minecraft.</p><br />
<p>J'ai très vite voulu développer mes propres Mini-Jeux en OpenGL avec cette librairie.</p>
<ProjectList>
<ProjectElement
image_src='https://camo.githubusercontent.com/5895992a1089b81b0730608a47ebe08d55f1e6c9bada7752f89f7304a743652d/68747470733a2f2f7062732e7477696d672e636f6d2f6d656469612f4363334475776e5749414949355a772e6a70673a6c61726765'
description='Test gestion de la lumière'
url='https://github.com/mrdev023/Java-Game-Engine-Light-Test'
/>
<ProjectElement
image_src='https://camo.githubusercontent.com/f2dbe8898987b638eaa4d5dbc72797a4ff9c4bcb0275591f7fb24e7f32da5dd3/68747470733a2f2f7062732e7477696d672e636f6d2f6d656469612f4373567138634657384141374279722e6a7067'
description='Test OpenGL 3.3+ et LWJGL 3'
url='https://github.com/mrdev023/Modern-Game-Engine'
/>
<ProjectElement
image_src='https://camo.githubusercontent.com/414745fd4066b03c789b3a54d798c6f76df05039d464e29c822653e4e1515c73/68747470733a2f2f7062732e7477696d672e636f6d2f6d656469612f4350576147763457734141585068552e706e673a6c61726765'
description='Petit jeu en Voxel (Minecraft like)'
url='https://github.com/mrdev023/Voxel-Test'
/>
</ProjectList>
</TimelineCardContent>
</TimelineCard>
</TimelineElement>
</Timeline>
</div>
)
}
export default MonParcours

View file

@ -0,0 +1,4 @@
.tag {
@apply rounded-lg px-3 py-1 font-normal text-sm;
@apply bg-primary dark:bg-dark_primary text-on_primary dark:text-dark_on_primary;
}

View file

@ -0,0 +1,16 @@
import './Tag.scss'
type TagProps = {
name: string,
url?: string
}
function Tag({ name, url }: TagProps) {
return (
<a className="tag" href={url} target='_blank'>
{name}
</a>
)
}
export default Tag

View file

@ -0,0 +1,32 @@
#top {
@apply min-h-screen w-full flex flex-col md:flex-row items-center gap-5 relative;
& > div {
@apply flex-1 p-10;
}
& > .top__image {
@apply flex justify-center items-center;
& > img {
@apply mx-auto rounded-lg;
}
}
& > .top__presentation {
@apply flex flex-col gap-3;
& > h1 {
@apply font-bold text-3xl;
}
& > h4 {
@apply font-semibold text-xl;
}
& > p {
@apply font-normal text-base;
}
}
}

View file

@ -0,0 +1,43 @@
import SocialLink from './social_link/SocialLink'
import SocialLinks from './social_link/SocialLinks'
import './TopComponent.scss'
import { FaEnvelope, FaGithub, FaLinkedin } from 'react-icons/fa'
function TopComponent() {
return (
<div id="top">
<div className='top__image'>
<img src="https://devemyhg.lycee-darchicourt.net/wp-content/uploads/2018/01/No-picture.png" alt="Ma photo" />
</div>
<div className='top__presentation'>
<h1>Florian RICHER</h1>
<h4>Développeur d´application Web et Mobile</h4>
<p>
Découvrez mon parcours en développement, ma passion précoce pour la programmation a débuté avec la
création d'applications 3D utilisant OpenGL et s'est étendue à la maîtrise de diverses technologies,
notamment le développement Web avec React, Ruby on Rails, Symfony, Tailwindcss et Bootstrap, la réalisation
d'applications mobiles avec Flutter et le développement système en Rust, toujours animé par mon désir
inépuisable d'apprendre et ma curiosité sans bornes.
</p>
<SocialLinks>
<SocialLink
icon={<FaGithub />}
name="Github"
url="https://github.com/mrdev023"
/>
<SocialLink
icon={<FaLinkedin />}
name="Linkedin"
url="https://www.linkedin.com/in/florian-richer-80960b129/"
/>
<SocialLink
icon={<FaEnvelope />}
name="Mail"
url="mailto:florian.richer@protonmail.com"
/>
</SocialLinks>
</div>
</div>
)
}
export default TopComponent

View file

@ -0,0 +1,20 @@
import react from 'react'
type ProjectElementProps = {
image_src?: string,
description: string,
url: string
}
function ProjectElement({ image_src, description, url }: ProjectElementProps) {
return (
<a href={url} target='_blank'>
{
image_src && <img src={image_src} />
}
<div><p>{description}</p></div>
</a>
)
}
export default ProjectElement

View file

@ -0,0 +1,22 @@
.project_list {
@apply grid grid-cols-1 gap-4 md:grid-cols-2 mt-3;
& > a {
@apply rounded-lg p-5 flex flex-col items-center gap-2;
@apply bg-primary/10 dark:bg-dark_primary/10;
@apply shadow-md shadow-primary/5 dark:shadow-dark_primary/5;
&:hover {
@apply bg-primary/20 dark:bg-dark_primary/20;
@apply shadow-md shadow-primary/10 dark:shadow-dark_primary/10;
}
& > img {
@apply h-1/2;
}
& > div {
@apply flex flex-col justify-center h-full;
}
}
}

View file

@ -0,0 +1,16 @@
import './ProjectList.scss'
import react from 'react'
type ProjectListProps = {
children: react.ReactElement<any, react.JSXElementConstructor<any>> | react.ReactElement<any, react.JSXElementConstructor<any>>[]
}
function ProjectList({ children } : ProjectListProps) {
return (
<div className="project_list">
{ children }
</div>
)
}
export default ProjectList

View file

@ -0,0 +1,18 @@
import react, { ReactNode } from 'react'
type SocialLinkProps = {
icon: ReactNode,
url: string,
name: string
}
function SocialLink({ icon, url, name }: SocialLinkProps) {
return (
<a className="social_link" href={url} target="_blank">
{icon}
<span>{name}</span>
</a>
)
}
export default SocialLink

View file

@ -0,0 +1,13 @@
.social_links {
@apply flex gap-5 justify-center flex-wrap my-5;
& > .social_link {
& > svg {
@apply mx-auto scale-150 mb-1;
}
& > span {
@apply text-sm;
}
}
}

View file

@ -0,0 +1,16 @@
import './SocialLinks.scss'
import react, { ReactNode } from 'react'
type SocialLinksProps = {
children: ReactNode
}
function SocialLinks({ children }: SocialLinksProps) {
return (
<div className='social_links'>
{children}
</div>
)
}
export default SocialLinks

View file

@ -0,0 +1,14 @@
.timeline {
@apply w-full px-5;
& > ul {
@apply list-none py-5 px-0 relative w-full max-w-5xl mx-auto;
// Draw center line
&:before {
@apply top-0 bottom-0 left-0 md:left-1/2 absolute content-[""] w-2;
@apply bg-primary/10 dark:bg-dark_primary/10;
@apply shadow-md shadow-primary/5 dark:shadow-dark_primary/5;
}
}
}

View file

@ -0,0 +1,19 @@
import './Timeline.scss'
import react, { ReactNode } from 'react'
type TimelapseProps = {
children: ReactNode
}
function Timeline({ children } : TimelapseProps) {
return (
<div className='timeline'>
<ul>
{ children }
</ul>
</div>
)
}
export default Timeline

View file

@ -0,0 +1,30 @@
import react, {Children, ReactNode} from 'react'
import TimelineCardSummary from './TimelineCardSummary'
import { FaCaretDown } from 'react-icons/fa'
type TimelineCardProps = {
children: react.ReactElement<any, react.JSXElementConstructor<any>>[]
}
function TimelineCard({ children } : TimelineCardProps) {
let titles : ReactNode[] = []
let childrens : ReactNode[] = []
Children.forEach(children, (c) => {
if (c.type === TimelineCardSummary) {
titles.push(c)
} else {
childrens.push(c)
}
});
return (
<details>
<summary>
{titles}
<i><FaCaretDown/></i>
</summary>
<div>{childrens}</div>
</details>
)
}
export default TimelineCard

View file

@ -0,0 +1,13 @@
import react, {ReactNode} from 'react'
type TimelineCardContentProps = {
children: ReactNode
}
function TimelineCardContent({ children } : TimelineCardContentProps) {
return (
<>{children}</>
)
}
export default TimelineCardContent

View file

@ -0,0 +1,21 @@
import react, {ReactNode} from 'react'
type TimelineCardSummaryProps = {
children: ReactNode,
tags?: ReactNode[]
}
function TimelineCardSummary({ children, tags } : TimelineCardSummaryProps) {
return (
<>
{children}
{
tags && <div className='flex flex-wrap gap-2 mt-2'>
{ tags }
</div>
}
</>
)
}
export default TimelineCardSummary

View file

@ -0,0 +1,83 @@
.timeline-element {
@apply relative flex flex-col md:flex-row justify-between;
// Place point in center line
&:before {
@apply content-[""] w-6 h-6 rounded-[50%] absolute top-5 left-0 md:left-1/2 -ml-2 z-50;
@apply bg-primary/10 dark:bg-dark_primary/10;
@apply shadow-md shadow-primary/5 dark:shadow-dark_primary/5;
}
&:nth-child(even) {
@apply md:flex-row-reverse;
.timeline-element__category {
@apply md:flex-row-reverse;
}
}
.timeline-element__info, .timeline-element__category {
@apply relative w-4/5 md:w-2/5 left-[10%] md:left-0;
@apply text-on_surface dark:text-dark_on_surface;
}
.timeline-element__category {
@apply top-5 flex md:justify-end mb-12;
}
.timeline-element__info {
& > details {
@apply mb-12 rounded-xl overflow-hidden relative;
@apply bg-primary/10 dark:bg-dark_primary/10;
@apply shadow-md shadow-primary/5 dark:shadow-dark_primary/5;
& > summary, & > div {
@apply p-5;
}
& > summary {
@apply relative block select-none cursor-pointer outline-none p-5 pr-10 font-semibold;
&:hover {
@apply bg-primary/20 dark:bg-dark_primary/20;
}
i {
@apply absolute right-5 h-full top-0 flex items-center;
& > svg {
@apply scale-125;
transition: transform 300ms ease;
}
}
}
&[open] {
& > summary {
& > i > svg {
@apply -rotate-180;
}
& ~ * {
animation: toggle 0.4s ease-in-out;
}
}
}
}
}
}
@keyframes toggle {
0% {
font-size: 0;
opacity: 0;
}
90% {
font-size: 1rem;
opacity: 0;
}
100% {
font-size: 1rem;
opacity: 1;
}
}

View file

@ -0,0 +1,31 @@
import './TimelineElement.scss'
import react, {Children, ReactNode} from 'react'
import TimelineLabel from './TimelineLabel'
type TimelineElementProps = {
children: react.ReactElement<any, react.JSXElementConstructor<any>>[]
}
function TimelineElement({ children } : TimelineElementProps) {
let labels : ReactNode[] = []
let cards : ReactNode[] = []
Children.forEach(children, (c) => {
if (c.type === TimelineLabel) {
labels.push(c)
} else {
cards.push(c)
}
});
return (
<li className='timeline-element'>
<div className='timeline-element__category'>
{ labels }
</div>
<div className='timeline-element__info'>
{ cards }
</div>
</li>
)
}
export default TimelineElement

View file

@ -0,0 +1,13 @@
import react, {ReactNode} from 'react'
type TimelineLabelProps = {
children: ReactNode
}
function TimelineLabel({ children } : TimelineLabelProps) {
return (
<>{children}</>
)
}
export default TimelineLabel