Moved to Nuxt
pipeline / build-and-push-images (push) Successful in 3m12s

NuxtJS, Vue, real web app

Nuxt content: blog

Better mobile/responsive design and practices

Better practices overall
This commit is contained in:
2025-11-18 20:59:23 +01:00
parent 93a4e124ff
commit 99a943eb36
57 changed files with 19126 additions and 718 deletions
+97
View File
@@ -0,0 +1,97 @@
<script setup lang="ts">
const route = useRoute()
const slug = route.params.slug
const { data } = await useAsyncData(() => queryCollection('blog').path("/blog/" + slug).first())
const title = (data.value == undefined ? 'Blog' : data.value!.title);
useSeoMeta({
title: data.value?.title,
description: data.value?.description
})
defineOgImageComponent('BlogPost', {
title: title,
description: data.value?.description
})
</script>
<template>
<HeaderCompact :title="title" previous-link="/blog" />
<div class="flex xl:flex-row flex-col-reverse xl:mt-20 sm:mt-10 mt-5 xl:mb-20 mb-5 m-auto">
<ContentRenderer v-if="data" :value="data" class="max-w-4xl w-[90%] xl:mr-10 m-auto content" />
<div v-if="data?.body.toc != undefined" class="xl:visible collapse xl:mt-0 mt-5 xl:ml-10 ml-5 mb-10 m-auto max-w-60 xl:sticky xl:top-16">
<ul>
<BlogTocLink v-for="link of data.body.toc.links" :link="link" />
</ul>
</div>
</div>
</template>
<style>
.content h2 {
font-size: 30px;
margin-top: 10px;
margin-bottom: 10px;
}
.content h3 {
font-size: 26px;
margin-top: 10px;
margin-bottom: 10px;
}
.content h4 {
font-size: 23px;
margin-top: 10px;
margin-bottom: 10px;
}
.content h5 {
font-size: 21px;
margin-top: 10px;
margin-bottom: 10px;
}
.content p {
font-size: 20px;
margin-bottom: 20px;
}
.content ul {
list-style-type: disc;
list-style-position: inside;
font-size: 20px;
margin-bottom: 20px;
}
.content li {
list-style-type: disc;
list-style-position: inside;
}
.content a {
color: initial;
}
.content a:link {
color: initial;
}
.content a:visited {
color: initial;
}
.content a:hover {
color: initial;
}
.content a:active {
color: initial;
}
.content p a {
text-decoration: underline;
}
ul {
list-style: none;
}
li {
list-style: none;
}
</style>
+40
View File
@@ -0,0 +1,40 @@
<script setup lang="ts">
defineOgImageComponent('Site', {
title: 'Blog'
})
const content = await queryCollection('blog').order('date', 'DESC').all()
function formatDateString(dateString: string) : string {
let date = new Date(Date.parse(dateString))
return new Intl.DateTimeFormat("en-US", {
dateStyle: "long",
timeZone: "Europe/Paris",
}).format(date)
}
</script>
<template>
<HeaderCompact title="Blog" previous-link="/" class="mb-20" />
<div class="m-auto lg:w-[56rem] w-[90%]" v-for="article in content">
<h1 class="text-2xl" v-if="article">{{ article.title }}</h1>
<h3 class="text-xl" v-if="article">
{{ formatDateString(article.date) }}
</h3>
<div class="flex">
<h4 v-for="tag in article.tags"
class="p-1 bg-slate-100 mr-3 hover:cursor-pointer">
{{ tag }}
</h4>
</div>
<h4 class="text-xl mt-2" v-if="article">{{ article.description }}</h4>
<a :href="article.path">
<h2 class="text-xl text-right">[ Read more ]</h2>
</a>
</div>
</template>
+223
View File
@@ -0,0 +1,223 @@
<script setup lang="ts">
defineOgImageComponent('Site', {
title: 'CV'
})
</script>
<template>
<HeaderBig />
<!-- CV -->
<div class="sm:mt-[100px] sm:mb-[200px] flex flex-col w-fit m-auto">
<!-- Professional experience -->
<div class="sm:mt-[50px] mt-8">
<h2 style="margin-bottom: 20px;">Professional experience</h2>
<div class="grid-flow-col section">
<p class="date">2025 - Now</p>
<p style="max-width: 1015px;"><strong>Sofware engineer</strong>, Canonical, Ubuntu engineering</p>
<p class="subtext" style="max-width: 1015px;">Working on Ubuntu support for RISC-V architecture</p>
<div class="entry-sep" />
<p class="date">2025</p>
<p style="max-width: 1015px;"><strong>Master's internship</strong>, ONERA, “Probabilistic analysis of execution time on multi/manycore heterogeneous boards for optimal task mapping”</p>
<p class="subtext" style="max-width: 1015px;">Real-time multicore optimal task mapping using a solver that automatically measures a pWCET for a solution on target platform</p>
<div class="entry-sep" />
<p class="date">Summer 2023</p>
<p style="max-width: 1015px;"><strong>Master's internship</strong>, Huawei Research Zurich, Improving performances of virtualized servers by removing the guest kernel/user isolation layer</p>
<p class="subtext">Working on a Linux kernel patch to allow programs to run in kernel mode</p>
<div class="entry-sep" />
<p class="date">2022 - 2023</p>
<p style="max-width: 1015px;"><strong>Master's research project</strong>, IRISA (Rennes), “Transparent use of node-local storage for asynchronous I/O on supercomputers”</p>
<p class="subtext">Library replacing MPI-IO calls, caching data locally, with neighbour communication</p>
<div class="entry-sep" />
<p class="date">Summer 2022</p>
<p style="max-width: 1015px;"><strong>Bachelor's internship</strong>, IRIT (Toulouse), Reducing traffic in data centers by avoiding the transition of data through intermediate servers</p>
<p class="subtext">Library replacing read/write, using memory protection to provide data on-demand</p>
<div class="entry-sep" />
</div>
</div>
<!-- Education -->
<div>
<h2 style="margin-bottom: 20px;">Education</h2>
<div class="section">
<p class="date">2024 - 2025</p>
<p><strong>M2 SIF</strong>, ENS Rennes, Second year of CS Master's Degree (Research)</p>
<div class="entry-sep" />
<p class="date">2023 - 2024</p>
<p><strong>Agrégation</strong>, ENS Rennes, Preparation for national competitive exam</p>
<p class="subtext">'Agrégé' in computer science, rank 14/22</p>
<div class="entry-sep" />
<p class="date">2022 - 2023</p>
<p><strong>M1 SIF</strong>, ENS Rennes, First year of CS Master's Degree (Research)</p>
<div class="entry-sep" />
<p class="date">2021 - 2022</p>
<p><strong>L3 SIF</strong>, ENS Rennes, Last year of CS Bachelor's Degree</p>
<div class="entry-sep" />
<p class="date">2018 - 2021</p>
<p style="max-width: 1015px;"><strong>Prépa</strong>, Lycée Bellevue Toulouse, two-year intensive program preparing
for the national competitive exams for entry to engineering schools.</p>
<p class="subtext">Prépa MPSI/MP, entry to ENS Rennes</p>
<div class="entry-sep" />
</div>
</div>
<!-- Personal projects -->
<div class="sm:mt-12 mt-5">
<h2 style="margin-bottom: 20px;">Personal projects</h2>
<div class="section">
<p class="date">2023 - 2024</p>
<p style="max-width: 1015px;"><a href="https://git.vhaudiquet.fr/vhaudiquet/vriscv/" target="_blank" rel="noopener noreferrer"><strong>RISC-V simulator</strong></a></p>
<p class="subtext">Basic RISC-V processor simulator, capable of running BBL and booting Linux</p>
<div class="entry-sep" />
<p class="date">2022 - 2023</p>
<p style="max-width: 1015px;"><strong>Java Virtual Machine implementation</strong>, school project</p>
<p class="subtext">Basic C JVM for GNU/Linux, Java 8 specs, using OpenJRE runtime</p>
<div class="entry-sep" />
<p class="date">2018 - Now?</p>
<p style="max-width: 1015px;"><a href="https://github.com/vhaudiquet/BladePlayer/" target="_blank" rel="noopener noreferrer"><strong>Blade Player</strong></a>, Android multi-source music player</p>
<p class="subtext">Maintaining for 100+ users this Android application that plays music from Spotify or Deezer</p>
<div class="entry-sep" />
<p class="date">2018 - 2020</p>
<p style="max-width: 1015px;"><a href="https://github.com/vhaudiquet/vk/" target="_blank" rel="noopener noreferrer"><strong>Operating system kernel development</strong></a>,x86 architecture</p>
<p class="subtext">Basic operating system kernel, with drivers, filesystem, Newlib ported, dash shell</p>
<div class="entry-sep" />
</div>
</div>
<!-- Skills -->
<div class="sm:mt-12 mt-5">
<h2 style="margin-bottom: 20px;">Skills</h2>
<div class="section">
<p style="margin-left: 10px; font-weight: 500; grid-column: 1;">Programming languages</p>
<p class="sm:col-start-2 col-start-1" style="max-width: 900px;">C, Assembly (x86, RISC-V, ARM), Java, TypeScript/JavaScript, Kotlin, Python, OCaml</p>
<p style="margin-left: 10px; font-weight: 500;">DevOps / Workflow</p>
<p>Linux, Bash, Git, CI/CD, Docker, Kubernetes, virtual machines</p>
<p style="margin-left: 10px; font-weight: 500;">Presentation tools</p>
<p>LaTeX, Figma, HTML/CSS, Inkscape, Gimp</p>
<p style="margin-left: 10px; font-weight: 500;">Spoken languages</p>
<p>French (native), English (fluent), Spanish (basic)</p>
</div>
</div>
<!-- Contact -->
<div class="sm:mt-12 mt-5 sm:mb-0 mb-8">
<h2 style="margin-bottom: 20px;">Contact</h2>
<div class="section">
<p style="margin-left: 10px; font-weight: 500; grid-column: 1;">E-Mail</p>
<a href="mailto:valentin.haudiquet@ens-rennes.fr" style="grid-column: 2;"><p style="grid-column: 2;">valentin.haudiquet@ens-rennes.fr</p></a>
<p style="margin-left: 10px; font-weight: 500;">Website</p>
<a href="https://vhaudiquet.fr" target="_blank" rel="noopener noreferrer"><p>https://vhaudiquet.fr</p></a>
<p style="margin-left: 10px; font-weight: 500;">Phone number</p>
<p>+33 7 87 18 09 65</p>
<p style="margin-left: 10px; font-weight: 500;">Street address</p>
<p>30 rue Achille Viadieu, 31400 Toulouse, France</p>
<p style="margin-left: 10px; font-weight: 500;">GitHub</p>
<a href="https://github.com/vhaudiquet/" target="_blank" rel="noopener noreferrer"><p>vhaudiquet</p></a>
</div>
</div>
</div>
</template>
<style lang="css" scoped>
.section {
display: grid;
grid-auto-flow: row;
column-gap: 50px;
width: fit-content;
}
.date {
margin-left: 10px;
font-style: italic;
}
.subtext {
font-weight: 200;
font-size: 26px;
grid-column: 2;
}
h2 {
font-size: 40px;
margin-top: 5px;
margin-bottom: 5px;
}
p {
font-size: 30px;
margin-top: 5px;
margin-bottom: 5px;
}
.entry-sep {
grid-column: 2;
}
@media only screen and (max-width: 450px) {
h2 {
font-size: 30px;
margin-top: 2px;
margin-bottom: 2px;
margin-left: 5px;
}
p {
font-size: 20px;
margin-left: 10px;
margin-top: 0px;
margin-bottom: 0px;
}
.subtext {
grid-column: 1;
font-size: 18px;
margin-left: 10px;
}
.entry-sep {
grid-column: 1;
margin-top: 20px;
margin-top: 20px;
}
}
</style>
+113
View File
@@ -0,0 +1,113 @@
<script setup lang="ts">
defineOgImageComponent('Site', {
title: 'vhaudiquet.fr'
})
</script>
<template>
<HeaderBig />
<div class="content-holder">
<!-- Links -->
<div id="links-div" style="grid-column: 1;">
<a href="/blog/" style="grid-column: 1;">
<img src="~/assets/img/post-outline.svg"
class="sm:w-[150px] w-[70px] h-auto m-auto" />
<p class="text-center sm:text-3xl text-xl">Blog</p>
</a>
<a href="/projects">
<img src="~/assets/img/material-symbols--list-alt-outline.svg"
class="sm:w-[150px] w-[70px] h-auto m-auto" />
<p class="text-center sm:text-3xl text-xl">Projects</p>
</a>
<a href="/cv/">
<img src="~/assets/img/icon-park-solid_people.svg"
class="sm:w-[150px] w-[70px] h-auto pb-4 p-3 m-auto" />
<p class="text-center sm:text-3xl text-xl">CV</p>
</a>
</div>
<div class="lg:w-[350px] w-0 col-2" />
<div id="contact-div" class="mt-12 mb-12">
<h4 class="sm:text-4xl text-3xl text-left pb-4">Find me on...</h4>
<a href="https://github.com/vhaudiquet" class="flex">
<img src="~/assets/img/github-mark.png" class="contact-image"/>
<p class="contact-text sm:text-3xl text-xl mt-1 mb-1">GitHub</p>
</a>
<a href="https://git.vhaudiquet.fr/vhaudiquet/" class="flex">
<img src="~/assets/img/logo_black.svg" class="contact-image"/>
<p class="contact-text sm:text-3xl text-xl mt-1 mb-1">Gitea (personal)</p>
</a>
<a href="https://launchpad.net/~vhaudiquet" class="flex">
<img src="~/assets/img/launchpad-white-black.png" class="contact-image"/>
<p class="contact-text sm:text-3xl text-xl mt-1 mb-1">Launchpad</p>
</a>
<a href="mailto:valentin.haudiquet@ens-rennes.fr" class="flex">
<img src="~/assets/img/arobase.svg" class="contact-image"/>
<p class="contact-text sm:text-3xl text-xl mt-1 mb-1">Mail</p>
</a>
</div>
</div>
</template>
<style lang="css" scoped>
.content-holder {
display: grid;
width: fit-content;
margin: auto;
grid-auto-flow: column;
}
.contact-image {
width: 48px;
height: 48px;
}
.contact-text {
text-align: right;
padding-left: 10px;
font-size: 28px;
}
#links-div {
display: grid;
column-gap: 40px;
grid-auto-flow: column;
width: fit-content;
margin: auto;
margin-top: 100px;
}
@media only screen and (max-width: 1000px) {
#links-div {
display: grid;
column-gap: 40px;
row-gap: 40px;
width: fit-content;
margin: auto;
margin-top: 100px;
}
.content-holder {
grid-auto-flow: row;
}
}
@media only screen and (max-width: 450px) {
#header-div {
margin-top: 30px;
}
#links-div {
margin-top: 40px;
}
}
</style>
+148
View File
@@ -0,0 +1,148 @@
<script setup lang="ts">
defineOgImageComponent('Site', {
title: 'Projects'
})
</script>
<template>
<HeaderBig />
<!-- Projects -->
<div id="projects-div">
<!-- BuildPath -->
<a href="https://buildpath.win">
<div class="project-div">
<h2 class="project-title">BuildPath</h2>
<img class="project-img" src="https://buildpath.win/favicon.svg"/>
<h3 class="project-link">https://buildpath.win</h3>
<p class="project-desc">a tool for League of Legends champions runes and build paths</p>
</div>
</a>
<!-- homeprod -->
<a href="https://github.com/vhaudiquet/homeprod">
<div class="project-div">
<h2 class="project-title">homeprod</h2>
<img class="project-img" src="https://vhaudiquet.fr/public/github_assets/homeprod/p330_sff.png"/>
<h3 class="project-link" style="display: flex;">
<img src="~/assets/img/github-mark.png" width="16px" style="margin: auto; display: block; margin-right: 4px;"/>
vhaudiquet/homeprod
</h3>
<p class="project-desc">personal home production environment</p>
</div>
</a>
<!-- BladePlayer -->
<a href="https://github.com/vhaudiquet/BladePlayer">
<div class="project-div">
<h2 class="project-title">Blade Player</h2>
<img class="project-img" src="~/assets/img/blade-icon.png"/>
<h3 class="project-link" style="display: flex;">
<img src="~/assets/img/github-mark.png" width="16px" style="margin: auto; display: block; margin-right: 4px;"/>
vhaudiquet/BladePlayer
</h3>
<p class="project-desc">android music player that plays from multiple sources</p>
</div>
</a>
<!-- vhaudiquet.fr -->
<a href="https://vhaudiquet.fr">
<div class="project-div">
<h2 class="project-title">vhaudiquet.fr</h2>
<img class="project-img" src="~/assets/img/favicon.ico_256x256.png"/>
<h3 class="project-link" style="display: flex;">
https://vhaudiquet.fr
</h3>
<p class="project-desc">this website: my personal website with information, CV, projects</p>
</div>
</a>
</div>
</template>
<style lang="css" scoped>
#projects-div {
display: grid;
grid-auto-flow: column;
width: fit-content;
margin: auto;
margin-top: 100px;
column-gap: 40px;
}
.project-div {
max-width: 280px;
width: 280px;
height: 350px;
background-color: #FEFEFE;
border-radius: 12px;
border: 1px solid #E0E0E0;
box-shadow: 5px 2px 2px #E0E0E0;
padding: 10px;
}
.project-div:hover {
background-color: #EEEEEE;
}
.project-title {
width: fit-content;
margin: auto;
font-weight: 400;
font-size: 30px;
color: black;
}
.project-img {
max-width: 140px;
max-height: 140px;
/* width: fit-content; */
margin: auto;
display: block;
margin-top: 10px;
}
.project-link {
font-size: 12px;
width: fit-content;
font-weight: 400;
margin: auto;
margin-top: 8px;
color: black;
}
.project-desc {
font-size: 16px;
margin-left: 5px;
margin-top: 30px;
font-weight: 300;
color: black;
text-align: center;
}
@media only screen and (max-width: 1000px) {
#projects-div {
grid-auto-flow: row;
row-gap: 40px;
grid-template-columns: repeat(2, 270px);
}
}
@media only screen and (max-width: 650px) {
#projects-div {
margin-top: 50px;
grid-template-columns: repeat(1, 270px);
}
}
</style>