Compare commits

...

25 Commits
v1 ... master

Author SHA1 Message Date
851ae7a528
feat: add CV
All checks were successful
Build, check & Test / run (push) Successful in 4m13s
Signed-off-by: Avior <git@avior.me>
2024-10-18 11:58:57 +02:00
f671a21d2f Update Dockerfile.static
All checks were successful
Build, check & Test / run (push) Successful in 2m15s
2023-11-28 01:17:55 +00:00
3fc900a1e6 Update src/pages/index.astro (#1)
All checks were successful
Build, check & Test / run (push) Successful in 1m41s
Reviewed-on: #1
2023-11-25 22:50:55 +00:00
dc58e29760 Update .github/workflows/build_and_check.yml
All checks were successful
Build, check & Test / run (push) Successful in 1m54s
2023-11-25 22:37:00 +00:00
40d0d84619 Update .github/workflows/build_and_check.yml
All checks were successful
Build, check & Test / run (push) Successful in 1m59s
2023-11-25 22:33:30 +00:00
962ba24f7b Update .github/workflows/build_and_check.yml 2023-11-25 22:33:19 +00:00
e16134f15b Update .github/workflows/build_and_check.yml
All checks were successful
Build, check & Test / run (push) Successful in 1m55s
2023-11-25 22:27:51 +00:00
83d66eb440 Update .github/workflows/build_and_check.yml
All checks were successful
Build, check & Test / run (push) Successful in 1m54s
2023-11-25 22:23:56 +00:00
5c49bd2190 Update .github/workflows/build_and_check.yml 2023-11-25 22:22:09 +00:00
c4e702af67 Update .github/workflows/build_and_check.yml 2023-11-25 22:21:34 +00:00
30c0ac14a3 Update .github/workflows/build_and_check.yml
All checks were successful
Build, check & Test / run (push) Successful in 2m0s
2023-11-25 22:15:31 +00:00
a8ce0b4494 Update .github/workflows/build_and_check.yml
All checks were successful
Build, check & Test / run (push) Successful in 1m56s
2023-11-25 22:11:38 +00:00
45e79cf212 Update .github/workflows/build_and_check.yml
All checks were successful
Build, check & Test / run (push) Successful in 1m57s
2023-11-25 22:07:59 +00:00
fa8f946ff5 Update .github/workflows/build_and_check.yml
All checks were successful
Build, check & Test / run (push) Successful in 2m37s
2023-11-25 22:00:09 +00:00
9ffffcd927 Update Dockerfile.static
All checks were successful
Build, check & Test / run (push) Successful in 1m55s
2023-11-08 23:14:11 +00:00
9a96cb063a Update .github/workflows/build_and_check.yml
All checks were successful
Build, check & Test / run (push) Successful in 2m30s
2023-11-08 23:05:59 +00:00
4651debb38 Update .github/workflows/build_and_check.yml
All checks were successful
Build, check & Test / run (push) Successful in 2m40s
2023-11-08 22:56:37 +00:00
a641749d45 Update .github/workflows/build_and_check.yml
Some checks failed
Build, check & Test / run (push) Failing after 2m25s
2023-11-08 22:23:53 +00:00
898d5a241a Update .github/workflows/build_and_check.yml
Some checks failed
Build, check & Test / run (push) Failing after 2m16s
2023-11-08 22:12:25 +00:00
ca799e17b0 fix: README being compiled
Signed-off-by: Florian Bouillon <f.bouillon@aptatio.com>
2023-10-04 18:08:53 +02:00
0ff26c24b8 feat: Move posts to use the PIcture element
Signed-off-by: Florian Bouillon <f.bouillon@aptatio.com>
2023-10-04 18:00:27 +02:00
4a944f9e61 fix: Check errors
Signed-off-by: Florian Bouillon <f.bouillon@aptatio.com>
2023-10-04 17:23:54 +02:00
9a70042506 feat: Move to the Picture Component
Signed-off-by: Florian Bouillon <f.bouillon@aptatio.com>
2023-10-04 17:14:26 +02:00
0f1a3b7cc8 fix: breadcrumb
Signed-off-by: Florian Bouillon <f.bouillon@aptatio.com>
2023-10-02 17:41:47 +02:00
fb97ea4a9d fix: bugs
Signed-off-by: Florian Bouillon <f.bouillon@aptatio.com>
2023-10-02 12:31:38 +02:00
29 changed files with 1160 additions and 405 deletions

View File

@ -2,9 +2,13 @@ name: Build, check & Test
on:
push:
branches: [ "master" ]
branches:
- '*'
tags:
- v*
pull_request:
branches: [ "master" ]
branches:
- master
jobs:
run:
@ -13,23 +17,36 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Use Node.js 20
uses: actions/setup-node@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
node-version: 20
images: git.dzeio.com/avior/avior.me
tags: |
type=edge
type=ref,event=pr
type=ref,event=branch,prefix=branch-
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=semver,pattern=latest
- name: Install dependencies
run: npm ci
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: git.dzeio.com
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Build
run: npm run build
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Check
run: npm run check
- name: Prepare Tests
run: npm run install:test
- name: Test
run : npm run test
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
file: ./Dockerfile.static
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View File

@ -4,5 +4,8 @@
},
"tailwindCSS.includeLanguages": {
"astro": "html"
},
"files.associations": {
"*.mdx": "markdown"
}
}

View File

@ -1,4 +1,4 @@
# This Dockerfile allows you to run Astro in a static container (no server side)
# This Dockerfile allows you to run Astro in a static container using NGINX (no server side)
#########
# Build #
@ -36,3 +36,5 @@ ADD ./nginx.conf /etc/nginx/nginx.conf
# Copy dist fro mthe build image
COPY --from=BUILD_IMAGE /home/node/dist ./
EXPOSE 3000

View File

@ -1,44 +1,43 @@
import { defineConfig } from 'astro/config'
import tailwind from "@astrojs/tailwind"
import node from "@astrojs/node"
// const faviconHook = {
// name: 'Favicon',
// hooks: {
// "astro:build:setup": async () => {
// await Manifest.create('./src/assets/favicon.png', {
// name: 'Template'
// })
// }
// }
// }
// https://astro.build/config
export default defineConfig({
integrations: [tailwind()],
compressHTML: true,
build: {
assets: 'assets',
inlineStylesheets: 'auto'
},
server: {
host: true,
port: 3000
},
trailingSlash: 'never',
vite: {
server: {
watch: {
// support WSL strange things
usePolling: !!process.env.WSL_DISTRO_NAME
}
}
},
// Customizable depending on goal
output: 'static',
// adapter: node({
// mode: "standalone"
// }),
site: 'https://avior.me',
})
import { defineConfig } from 'astro/config'
import tailwind from "@astrojs/tailwind"
import mdx from "@astrojs/mdx"
// const faviconHook = {
// name: 'Favicon',
// hooks: {
// "astro:build:setup": async () => {
// await Manifest.create('./src/assets/favicon.png', {
// name: 'Template'
// })
// }
// }
// }
// https://astro.build/config
export default defineConfig({
integrations: [tailwind(), mdx()],
compressHTML: true,
build: {
assets: 'assets',
inlineStylesheets: 'auto'
},
server: {
host: true,
port: 3000
},
trailingSlash: 'never',
vite: {
server: {
watch: {
// support WSL strange things
usePolling: !!process.env.WSL_DISTRO_NAME
}
}
},
// Customizable depending on goal
output: 'static',
// adapter: node({
// mode: "standalone"
// }),
site: 'https://avior.me'
})

View File

@ -9,6 +9,16 @@ http {
listen 3000;
listen [::]:3000;
# Redirect from non-www to www
# if ($host ~ ^(?!www\.)(?<domain>.+)$) {
# return 301 $scheme://www.$domain$request_uri;
# }
# Redirect from www to non-www
if ($host ~ ^www\.(?<domain>.+)$) {
return 301 $scheme://$domain$request_uri;
}
server_name _;
root /usr/share/nginx/html;
@ -18,13 +28,23 @@ http {
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/html text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
error_page 404 /404.html;
error_page 500 502 503 504 /500.html;
error_page 500 502 503 504 /50x.html;
# Security headers (note: temporaly unvailable "prefetch-src 'self'; ")
add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'none'; form-action 'self'; manifest-src 'self'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src data: 'self' https://img.shields.io; font-src 'self'; connect-src 'self'; base-uri 'self';";
add_header X-Frame-Options "DENY";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
add_header Referrer-Policy "no-referrer";
add_header Permissions-Policy "geolocation=(), microphone=(), interest-cohort=()";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Download-Options "noopen";
location / {
try_files $uri $uri.html $uri/index.html /$uri /$uri/index.html /index.html;
try_files $uri $uri.html $uri/index.html /$uri /$uri/index.html =404;
}
# Plausible script

799
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,12 +15,12 @@
"install:test": "playwright install --with-deps"
},
"dependencies": {
"@astrojs/node": "^6",
"@astrojs/mdx": "^1.1.0",
"@astrojs/tailwind": "^5",
"@dzeio/logger": "^3",
"@dzeio/object-util": "^1",
"@dzeio/url-manager": "^1",
"@fontsource-variable/lexend": "^5.0.12",
"@fontsource-variable/lexend": "^5.1.1",
"@tailwindcss/typography": "^0.5.10",
"astro": "^3",
"astro-seo": "^0.8.0",

5
public/robots.txt Normal file
View File

@ -0,0 +1,5 @@
User-Agent: *
Disallow:
Disallow: /cv
Sitemap: https://avior.me/sitemap.xml

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

BIN
src/assets/pages/cv/me.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@ -0,0 +1,89 @@
---
import { getImage } from 'astro:assets'
import AstroUtils from '../libs/AstroUtils'
import { objectOmit } from '@dzeio/object-util'
const formats = [
'avif',
'webp'
]
export interface Props extends Omit<astroHTML.JSX.ImgHTMLAttributes, 'src'> {
src: ImageMetadata | string
srcDark?: ImageMetadata | string
width?: number
height?: number
innerClass?: string
}
type PictureResult = {
format: 'new'
formats: Array<{format: string, img: Awaited<ReturnType<typeof getImage>>}>
src: Awaited<ReturnType<typeof getImage>>
} | {
format: 'raw'
src: string
}
interface Result {
light: PictureResult
dark?: PictureResult | undefined
}
async function resolvePicture(image: ImageMetadata | string): Promise<PictureResult> {
const ext = typeof image === 'string' ? image.substring(image.lastIndexOf('.')) : image.format
if (ext === 'svg') {
return {
format: 'raw',
src: typeof image === 'string' ? image : image.src
}
}
const imageFormats: Array<{format: string, img: Awaited<ReturnType<typeof getImage>>}> = await Promise.all(
formats.map(async (it) => ({
img: await getImage({src: Astro.props.src, format: it, width: Astro.props.width, height: Astro.props.height}),
format: it
}))
)
const orig = await getImage({src: Astro.props.src, format: ext, width: Astro.props.width, height: Astro.props.height})
return {
format: 'new',
formats: imageFormats,
src: orig
}
}
const res = await AstroUtils.wrap<Result>(async () => {
return {
light: await resolvePicture(Astro.props.src),
dark: Astro.props.srcDark ? await resolvePicture(Astro.props.srcDark) : undefined
}
})
const props = objectOmit(Astro.props, 'src', 'srcDark', 'class')
---
{res.light.format === 'new' && (
<picture {...props} {...res.light.src.attributes} class:list={[res.light.src.attributes.class, Astro.props.class, {'dark:hidden': res.dark}]}>
{res.light.formats.map((it) => (
<source srcset={it.img.src} type={`image/${it.format}`} />
))}
<img src={res.light.src.src} class={Astro.props.innerClass} />
</picture>
) || (
<img {...props} class:list={[Astro.props.class, {'dark:hidden': res.dark}]} src={res.light.src as string} />
)}
{res.dark && res.dark.format === 'new' && (
<picture {...props} {...res.dark.src.attributes} class:list={[res.dark.src.attributes.class, Astro.props.class, 'hidden', 'dark:block']}>
{res.dark.formats.map((it) => (
<source srcset={it.img.src} type={`image/${it.format}`} />
))}
<img src={res.dark.src.src} class={Astro.props.innerClass} />
</picture>
) || (res.dark && (
<img {...props} class:list={[Astro.props.class, 'hidden', 'dark:block']} src={res.dark.src as string} />
))}

View File

@ -1,42 +0,0 @@
---
import { LocalImageProps, RemoteImageProps, getImage } from 'astro:assets'
import AstroUtils from '../libs/AstroUtils'
type ImageProps = LocalImageProps | RemoteImageProps
export type Props = ImageProps
const res = await AstroUtils.wrap(async () => {
const image = Astro.props.src
const ext = typeof image === 'string' ? image.substring(image.lastIndexOf('.')) : image.format
if (ext === 'svg') {
return {
format: 'raw',
props: {
...Astro.props,
src: typeof image === 'string' ? image : image.src
}
}
}
const avif = await getImage({src: Astro.props.src, format: 'avif'})
const webp = await getImage({src: Astro.props.src, format: 'webp'})
const orig = await getImage({src: Astro.props.src, format: ext})
return {
format: 'new',
avif,
webp,
orig
}
})
---
{res.format === 'new' && (
<picture class:list={[res.orig!.attributes.class, Astro.props.class]}>
<source srcset={res.avif!.src} type="image/avif" />
<source srcset={res.webp!.src} type="image/webp" />
<img src={res.orig!.src} class="" {...res.orig!.attributes} />
</picture>
) || (
<img {...res.props} />
)}

View File

@ -2,20 +2,20 @@
interface Props {
items: Array<{
text: string
href?: string
href?: string | undefined
}>
}
---
<nav>
<ol vocab="https://schema.org/" typeof="BreadcrumbList">
<ol vocab="https://schema.org/" typeof="BreadcrumbList" class="inline-flex items-center flex-wrap px-0 mb-4">
{Astro.props.items.map((el, index) => (
<li property="itemListElement" typeof="ListItem">
<li property="itemListElement" typeof="ListItem" class="inline-block px-0">
{index > 0 && (
<span class="text-slate-900 dark:text-slate-100 mx-4">/</span>
<span class="text-gray-900 dark:text-gray-100 mx-4">/</span>
)}
{el.href ? (
<a class="text-slate-900 dark:text-slate-100" href={el.href} property="item" typeof="WebPage">
<a class="text-gray-900 dark:text-gray-100 font-normal" href={el.href} property="item" typeof="WebPage">
<span property="name">{el.text}</span>
</a>
) : (
@ -26,15 +26,3 @@ interface Props {
))}
</ol>
</nav>
<style>
ol {
@apply inline-flex items-center flex-wrap px-0 mb-4
}
li {
@apply inline-block px-0
}
a {
@apply font-normal
}
</style>

View File

@ -1,18 +1,12 @@
---
import Logo from 'assets/logo.svg'
import LogoDark from 'assets/logo.dark.svg'
import { Image } from 'astro:assets'
import Picture from 'components/Picture.astro'
---
<header class="bg-white/1 flex justify-center sm:justify-normal">
<header class="bg-white/1 z-10 justify-center sm:justify-normal transition-opacity
fixed w-full h-20 flex items-center border-b border-slate-900/10 backdrop-blur-md">
<a href="/">
<Image src={Logo} alt="Avior.me Logo" class="h-9 dark:hidden" />
<Image src={LogoDark} alt="Avior.me Logo" class="h-9 hidden dark:block" />
<Picture src={Logo} srcDark={LogoDark} alt="Avior.me Logo" class="h-9" />
</a>
</header>
<style>
header {
@apply transition-opacity fixed w-full h-20 flex items-center border-b border-slate-900/10 backdrop-blur-md
}
</style>

View File

@ -11,11 +11,13 @@ const projectsCollection = defineCollection({
link: z.object({
href: z.string(),
rel: z.string().optional(),
text: z.string().optional()
text: z.string().optional(),
target: z.string().optional()
}).optional(),
disabled: z.string().optional(),
created: z.date().optional(),
updated: z.date().optional()
updated: z.date().optional(),
techs: z.string().array().optional()
})
})
const blogCollection = defineCollection({

View File

@ -7,6 +7,13 @@ link:
image: ./og.png
created: 2022-09-03
updated: 2023-07-02
techs:
- NextJS
- Typescript
- Appwrite
- Scrapping
- Docker
- Stylus
---
![Logo de FI3D](./logo.svg)
@ -49,21 +56,21 @@ FI3D propose également des fonctionnalités pratiques telles que le thème somb
Que l'on travaille sur des prototypes, des maquettes, des objets décoratifs ou des pièces fonctionnelles, FI3D offre un monde de possibilités. Découvrez la polyvalence de l'impression 3D en explorant les différents types de filaments disponibles, des PLA aux ABS en passant par le PETG et bien d'autres.
<!-- ![Image d'objets imprimés en 3D](lien_de_l_image_8.jpg)
*Image 7 : Objets imprimés en 3D avec différents filaments* -->
{/* ![Image d'objets imprimés en 3D](lien_de_l_image_8.jpg)
*Image 7 : Objets imprimés en 3D avec différents filaments* */}
**Notez et Partagez Vos Expériences**
Il est encouragé de partager ses expériences et ses avis sur les filaments. Si l'on a utilisé un filament particulier et que l'on souhaite aider d'autres membres de la communauté FI3D, il suffit de laisser une note et un commentaire.
<!-- ![Image d'une personne écrivant une critique](lien_de_l_image_9.jpg)
*Image 8 : Utilisateur laissant une critique sur un filament* -->
{/* ![Image d'une personne écrivant une critique](lien_de_l_image_9.jpg)
*Image 8 : Utilisateur laissant une critique sur un filament* */}
**Inscrivez-vous dès aujourd'hui sur FI3D**
Pour profiter pleinement de toutes les fonctionnalités de FI3D, il est possible de s'inscrire gratuitement sur la plateforme. On pourra ainsi ajouter des filaments à sa liste de favoris, suivre les dernières tendances en matière d'impression 3D et participer à une communauté dynamique de passionnés d'impression 3D.
<!-- ![Image d'une personne s'inscrivant sur FI3D](lien_de_l_image_10.jpg)
*Image 9: Processus d'inscription sur FI3D* -->
{/* ![Image d'une personne s'inscrivant sur FI3D](lien_de_l_image_10.jpg)
*Image 9: Processus d'inscription sur FI3D* */}
Que l'on soit un professionnel de l'industrie, un bricoleur ou simplement curieux de découvrir le monde de l'impression 3D, FI3D est l'outil idéal pour trouver le filament qui répond à ses besoins.

View File

@ -6,6 +6,14 @@ link:
image: ./og.png
created: 2018-09-10
updated: 2021-04-29
techs:
- NextJS
- Typescript
- MongoDB
- Firebase
- Symphony
- Docker
- Stylus
---
![Logo de Studiomoto](./logo.svg)

View File

@ -7,14 +7,14 @@ import Breadcrumb from 'components/global/Breadcrumb.astro'
export interface Props extends BaseProps {
link?: {
href: string
rel?: string
text?: string
target?: string
}
disabled?: string
rel?: string | undefined
text?: string | undefined
target?: string | undefined
} | undefined
disabled?: string | undefined
breadcrumb: Array<{
text: string
href?: string
href?: string | undefined
}>
}
---

View File

@ -1,6 +1,8 @@
---
import Head, { type Props as HeadProps } from './Head.astro'
import '@fontsource-variable/lexend'
export interface Props extends HeadProps {}
---
@ -13,3 +15,9 @@ export interface Props extends HeadProps {}
<slot />
</body>
</html>
<style is:global>
html {
font-weight: 350;
}
</style>

View File

@ -5,23 +5,23 @@ import IconPNG from '../assets/layouts/Base/favicon.png'
import '@fontsource-variable/lexend'
export interface Props {
siteName?: string
title?: string
description?: string
canonical?: string
image?: Array<typeof IconPNG>
siteName?: string | undefined
title?: string | undefined
description?: string | undefined
canonical?: string | undefined
image?: Array<typeof IconPNG> | undefined
twitter?: {
title?: string
card?: "summary" | "summary_large_image" | "app" | "player"
site?: string
creator?: string
}
title?: string | undefined
card?: "summary" | "summary_large_image" | "app" | "player" | undefined
site?: string | undefined
creator?: string | undefined
} | undefined
og?: {
title?: string
type?: string
description?: string
url?: string
}
title?: string | undefined
type?: string | undefined
description?: string | undefined
url?: string | undefined
} | undefined
}
const props = Astro.props

25
src/pages/404.astro Normal file
View File

@ -0,0 +1,25 @@
---
import Layout from 'layouts/Layout.astro'
import I404 from 'assets/pages/404/404.svg'
import I404Light from 'assets/pages/404/404.light.svg'
import Button from 'components/global/Button.astro'
import ButtonLink from 'components/global/ButtonLink.astro'
import Picture from 'components/Picture.astro'
---
<Layout>
<main class="container flex flex-col gap-24 justify-center items-center md:mt-6">
<h1 class="text-6xl text-center font-bold">404 La page recherché n'existe pas :(</h1>
<Picture src={I404Light} srcDark={I404} alt="404 error image" />
<div class="flex gap-6">
<ButtonLink href="/">Retour à la page d'accueil</ButtonLink>
<Button id="back_button">Retour à la page précédente</Button>
</div>
</main>
</Layout>
<script>
(document.querySelector('button.back_button') as HTMLButtonElement).addEventListener('click', () => {
history.back()
})
</script>

158
src/pages/cv.astro Normal file
View File

@ -0,0 +1,158 @@
---
import Base from 'layouts/Base.astro'
import Picture from 'components/Picture.astro'
import Me from 'assets/pages/cv/me.jpg'
import { objectMap } from '@dzeio/object-util'
const skills = {
'Langages': 'Typescript/JavaScript, Web (HTML/CSS), Kotlin, C++',
'Frameworks': 'Astro, NextJS, Android (MVVM), PlatformIO',
'Softwares': 'Git, VSCode, Zed',
'Tertiaire': 'Gestion de projet, Encadrement de collaborateurs'
} as const
const skillColor: Record<keyof typeof skills, string> = {
'Langages': 'amber',
'Frameworks': 'sky',
'Softwares': 'teal',
'Tertiaire': 'gray'
}
const passions: Array<string> = [
'Pokémon',
'Tennis',
'Programation'
]
const jobs: Array<{
company: string
start: string
end?: string
projects: Array<{
name: string
client?: string
description: string
technics?: Array<string>
}>
}> = [{
company: 'Aptatio',
start: '2019-09-30',
projects: [{
name: 'Ifremer LOOP',
client: 'Ifremer',
description: 'Développement dune application de gestion des réponses des appels à données et participations aux groupes internationaux',
technics: [
'Gestion de projet',
'Conception de logiciel',
'Développement de logiciel Web (Framework Astro & Typescript)'
]
}, {
name: 'Gwaleen',
client: 'Ifremer & Aptatio',
description: 'Développement de plusieurs modules logiciel des Ichtyomètre éléctronique Gwaleen',
technics: [
'Création et maintenance d\'un Logiciel Android de Gestion de donnée provenant d\'Ichtyomètres Connecté (Kotlin)',
'Conception et Création d\'un protocol de communication entre 2 appareil Android en bluetooth pour de la donnée Vidéo (Kotlin)',
'Gestion et création du code embarqué dans les Ichtyomètres Gwaleen (C++)'
]
}, {
name: 'ImmerCité',
client: 'La cité des congrès de Nantes',
description: 'Création d\'ImmerCité, un logiciel immersif pour la présentation d\'événements, primé au concours international des Cités des Congrès et lauréat du 1er prix Innovation Award à la conférence annuelle de l\'AIPC au Costa Rica.',
technics: [
'Conception de logiciel',
'Développement de logiciel Web (Framework NextJS & Typescript)',
'Création d\'un engine de gestion 2D pour le placement et l\'automatisation des objets dans les salles de la cité',
'Gestion de la communication et synchronisation entre plusieurs ordinateurs (WebSocket & ExpressJS)',
'Programation de la 3D dans Unity puis Godot (C#, GDScript)'
]
}, {
name: 'Gestion de l\'infrastructure',
description: 'Gestion de l\'infrastructure Réseau de l\'entreprise',
technics: [
'mise en place d\'un SSO (Single sign-on)',
'Gestion de la donnée utilisateur/client',
'Mise en ligne des logiciels Client',
'Maintenance Préventive des serveurs'
]
}]
}, {
company: 'Auto-Entreprise',
start: '2019-04-01',
projects: [{
name: 'TCGdex',
description: 'Développement de TCGdex, une API open source multilingue (14 langues) pour le jeu de cartes Pokémon JCC, offrant des fonctionnalités avancées aux développeurs et amateurs du jeu.',
technics: [
'Récupération des données depuis une multitude de sources',
'Création et maintenance d\'une API avec + de 4 Millions de requettes par mois',
'Mise en place d\'outillages pour simplifier l\'usage de l\'API aux développeurs',
'Maintenance et gestion d\'une communauté autour du jeux de carte Pokémon'
]
}]
}]
---
<Base>
<main class="container py-8">
<div class="flex gap-4">
<div class="w-1/4 flex flex-col gap-4">
<Picture src={Me} innerClass="rounded-xl" />
<h1 class="font-bold text-5xl text-center">Florian Bouillon</h1>
<div>
<p>Compétences :</p>
<div class="hidden bg-amber-300 bg-sky-300 bg-teal-300"></div>
<ul class="pl-6 list-disc">
{objectMap(skills, (it, key) => (
<li>{key}: {it.split(',').map((it) => <span class:list={[`bg-${skillColor[key]}-300`, "inline-block px-2 py-1 m-1 text-black rounded-xl"]}>{it}</span>)}</li>
))}
</ul>
</div>
<div>
<p>Passions :</p>
<ul class="pl-2 list-disc">
{passions.map((it) => (
<li>{it}</li>
))}
</ul>
</div>
</div>
<div class="w-3/4">
<div class="">
<h2 class="text-4xl font-bold">Expérience professionnel</h2>
{jobs.map((company) => (
<div class="mt-6">
<div class="flex justify-between items-center">
<h2 class="text-2xl font-semibold">{company.company}</h2>
<div class="italic">{company.start} - {company.end ?? 'Aujourd\'hui'}</div>
</div>
<div class="pl-2">
{company.projects.map((it, idx) => (
<div>
{idx > 0 && (
<hr class="my-2 border-t-2 border-gray-500" />
)}
<div class="flex justify-between items-center">
<p class="text-xl font-[550]">- {it.name}</p>
{it.client && (
<p>{it.client}</p>
)}
</div>
<p class="mt-2 pl-4">{it.description}</p>
{it.technics && (
<div class="pl-4 mt-2">
<p>Tâches:</p>
<ul class="list-disc pl-6">
{it.technics?.map((tech) => <li>{tech}</li>)}
</ul>
</div>
)}
</div>
))}
</div>
</div>
))}
</div>
</div>
</div>
</main>
</Layout>

View File

@ -1,60 +1,60 @@
---
import { getCollection } from 'astro:content'
import { Image } from 'astro:assets'
import Layout from 'layouts/Layout.astro'
const projects = await getCollection('projects')
const clients = await Promise.all((await getCollection('clients')).map(async (it) => ({...it, obj: await it.render()})))
---
<Layout title="Avior.me - Developpement de solutions selon vos besoins">
<main class="container">
<div class="flex justify-center items-center h-64">
<h1 class="text-4xl font-bold">Développement de solutions selon vos besoins</h1>
</div>
<h2 class="text-center md:text-left text-2xl font-semibold mb-4">Projets</h2>
<div class="md:grid grid-cols-3 gap-4">
{projects.map((it) => (
<a href={`/projets/${it.slug}`} class="flex flex-col gap-4 mb-6 md:mb-0">
{it.data.image && (
<Image src={it.data.image} alt="" />
)}
<p>{it.data.title}</p>
</a>
))}
</div>
<h2 class="text-center md:text-left text-2xl font-semibold my-8">Clients</h2>
<div class="flex flex-col gap-4">
<div class="grid grid-cols-2 items-center">
<div></div>
<div class="prose dark:prose-invert max-w-none">
<p class="font-semibold">Tâches :</p>
</div>
</div>
{clients.map((client, index) => {
const { Content } = client.obj
client.data.logo
return (
<>
{index > 0 && (
<div class="hidden md:block w-10/12 mx-auto h-0.5 bg-gray-300 dark:bg-gray-700"></div>
)}
<div class="mt-6 md:mt-0 md:grid grid-cols-2 items-center">
<a href={client.data.site} target="_blank" rel="noreferrer nofollow" class="flex flex-col gap-4">
{client.data.logo && (
<Image class:list={{'mx-auto': true, 'md:mx-0': true, 'dark:invert': client.data.logo.invert}} src={client.data.logo.src} height={48} alt="" />
) || (
<div>{client.data.title}</div>
)}
</a>
<div class="prose dark:prose-invert max-w-none">
<Content />
</div>
</div>
</>
)
})}
</div>
</main>
</Layout>
---
import { getCollection } from 'astro:content'
import Layout from 'layouts/Layout.astro'
import Picture from 'components/Picture.astro'
const projects = await getCollection('projects')
const clients = await Promise.all((await getCollection('clients')).map(async (it) => ({...it, obj: await it.render()})))
---
<Layout title="Avior.me - Developpement de solutions selon vos besoins">
<main class="container">
<div class="flex justify-center items-center h-64">
<h1 class="text-4xl font-bold">Développement de solutions selon vos besoins</h1>
</div>
<h2 class="text-center md:text-left text-2xl font-semibold mb-4">Projets</h2>
<div class="md:grid grid-cols-3 gap-4">
{projects.map((it) => (
<a href={`/projets/${it.slug}`} class="flex flex-col gap-4 mb-6 md:mb-0">
{it.data.image && (
<Picture src={it.data.image} alt="" />
)}
<p>{it.data.title}</p>
</a>
))}
</div>
<h2 class="text-center md:text-left text-2xl font-semibold my-8">Clients</h2>
<div class="flex flex-col gap-4">
<div class="grid grid-cols-2 items-center">
<div></div>
<div class="prose dark:prose-invert max-w-none">
<p class="font-semibold">Tâches :</p>
</div>
</div>
{clients.map((client, index) => {
const { Content } = client.obj
client.data.logo
return (
<>
{index > 0 && (
<div class="hidden md:block w-10/12 mx-auto h-0.5 bg-gray-300 dark:bg-gray-700"></div>
)}
<div class="mt-6 md:mt-0 md:grid grid-cols-2 items-center">
<a href={client.data.site} target="_blank" rel="noreferrer nofollow" class="flex flex-col gap-4">
{client.data.logo && (
<Picture class:list={{'mx-auto': true, 'md:mx-0': true, 'dark:invert': client.data.logo.invert}} src={client.data.logo.src} height={48} alt="" />
) || (
<div>{client.data.title}</div>
)}
</a>
<div class="prose dark:prose-invert max-w-none">
<Content />
</div>
</div>
</>
)
})}
</div>
</main>
</Layout>

View File

@ -1,5 +1,6 @@
---
import { getCollection } from 'astro:content';
import Picture from 'components/Picture.astro'
import Article from 'layouts/Article.astro'
export const prerender = true
@ -11,16 +12,28 @@ export async function getStaticPaths() {
}))
}
// 2. For your template, you can get the entry directly from the prop
const { entry } = Astro.props;
const { entry } = Astro.props as Awaited<ReturnType<typeof getStaticPaths>>[0]['props'];
const { Content } = await entry.render();
---
<Article title={entry.data.title} image={[entry.data.image]} description={entry.data.description} link={entry.data.link} breadcrumb={[{text: 'Accueil', href: '/'}, {text: 'Projets', href: '/projets'}, {text: entry.data.title}]}>
<Article
title={entry.data.title}
image={entry.data.image ? [entry.data.image] : undefined}
description={entry.data.description}
link={entry.data.link}
breadcrumb={[
{text: 'Accueil', href: '/'},
{text: 'Projets', href: '/projets'},
{text: entry.data.title}
]}
>
<h1>{entry.data.title}</h1>
<p class="flex justify-end font-lights my-0">
<span>Sortie initial le {entry.data.created.toLocaleDateString('fr')}</span>
{entry.data.created && (
<span>Sortie initial le {entry.data.created.toLocaleDateString('fr')}</span>
)}
<!-- <p>Software updated: {entry.data.updated.toLocaleDateString()}</p> -->
</p>
<Content />
<Content components={{img: Picture }}/>
</Article>

View File

@ -13,11 +13,11 @@ export const ALL: APIRoute = async () => {
sitemap.addEntry('/', {
priority: 1
})
sitemap.addEntry('/projets/', {
sitemap.addEntry('/projects/', {
priority: 0.5
})
for (const project of projects) {
sitemap.addEntry('/projets/' + project.slug, {
sitemap.addEntry('/projects/' + project.slug, {
priority: 0.7
})
}

View File

@ -15,9 +15,7 @@ module.exports = {
}
},
fontFamily: {
fontFamily: {
sans: ["Lexend Variable", "Lexend", ...defaultTheme.fontFamily.sans],
},
sans: ["Lexend Variable", "Lexend", ...defaultTheme.fontFamily.sans],
},
extend: {
},