Compare commits

...

4 commits

Author SHA1 Message Date
isUnknown
0b19589288 Tweak: ajustements style Portfolio
All checks were successful
Deploy / Deploy to Production (push) Successful in 20s
- Catchphrase en gradient-blue + Danzza Medium
- Titre en font-size-title-main + uppercase
- Description en font-size-subtitle
- Numéro nav après la vignette, align-items flex-start
- Vignette active scale(1.5) translateX(-20%)
- padding-right nav sidebar augmenté
- grid-area portfolio-text réduit d'une colonne

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:42:25 +01:00
isUnknown
88a5c78d7a Opti: images galerie portfolio en srcset webp
Kirby: preset 'gallery' + 'gallery-webp' (200→800px, qualité 80)
API: images_gallery retourne {src, srcset, webp} au lieu d'une simple URL
GalleryAnimation: <picture> + srcset, sizes 15vw desktop / 33vw mobile
decoding="async" ajouté

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:41:50 +01:00
isUnknown
88379fe073 Fix: fonts déplacées dans assets/fonts/ (chemin correct)
- Déplacement de assets/css/fonts/ → assets/fonts/
- Mise à jour des URLs dans fonts.css et le plugin Vite

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:22:47 +01:00
isUnknown
31ab9a1b69 Refactor: fonts — nouveaux fichiers otf/ttf dans assets/css/fonts/
- Chemins mis à jour vers /assets/css/fonts/
- Suppression des fichiers .woff inexistants
- Suppression de Danzza Light (fichier absent) → font-face-danzza-light pointe vers Regular
- Noms de fichiers avec espaces encodés en %20 dans le CSS source
- Plugin keepFontsInPlace : restaure les noms décodés dans le CSS buildé

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 16:19:19 +01:00
20 changed files with 69 additions and 37 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -84,13 +84,30 @@ return [
// Thumbs
'thumbs' => [
'quality' => 80,
'srcsets' => [
'default' => [
'300w' => ['width' => 300],
'600w' => ['width' => 600],
'900w' => ['width' => 900],
'1200w' => ['width' => 1200],
],
// Galerie portfolio — desktop ~15vw, mobile ~33vw (3 colonnes)
// Widths couvrent 1x et 2x retina pour les deux breakpoints
'gallery' => [
'200w' => ['width' => 200],
'300w' => ['width' => 300],
'400w' => ['width' => 400],
'600w' => ['width' => 600],
'900w' => ['width' => 900],
'1200w' => ['width' => 1200]
]
]
'800w' => ['width' => 800],
],
'gallery-webp' => [
'200w' => ['width' => 200, 'format' => 'webp'],
'300w' => ['width' => 300, 'format' => 'webp'],
'400w' => ['width' => 400, 'format' => 'webp'],
'600w' => ['width' => 600, 'format' => 'webp'],
'800w' => ['width' => 800, 'format' => 'webp'],
],
],
],
];

View file

@ -8,7 +8,11 @@ $specificData = [
'catchphrase' => $project->catchphrase()->value(),
'description' => $project->description()->value(),
'thumbnail' => $project->thumbnail()->toFile()?->url(),
'images_gallery' => $project->images_gallery()->toFiles()->map(fn($f) => $f->url())->values(),
'images_gallery' => $project->images_gallery()->toFiles()->map(fn($f) => [
'src' => $f->url(),
'srcset' => $f->srcset('gallery'),
'webp' => $f->srcset('gallery-webp'),
])->values(),
'mockup' => $project->mockup()->toFile()?->url(),
'keywords' => $project->keywords()->toStructure()->map(fn($i) => [
'label' => $i->label()->value(),

View file

@ -1,8 +1,8 @@
<script>
/**
* GalleryAnimation — animation CSS de galerie en 3 colonnes défilantes.
* @prop {string[]} images — URLs des images
* @prop {number} secondsPerImage — durée par image (défaut: 8s)
* @prop {Array<{src: string, srcset: string, webp: string}>} images
* @prop {number} secondsPerImage — durée par image (défaut: 8s)
*/
let { images = [], secondsPerImage = 8 } = $props()
@ -38,11 +38,22 @@
style="animation-delay: -{col.delay}s"
>
<!-- Images × 2 pour le défilement infini -->
{#each col.images as src}
<img class="gallery-animation__image" {src} alt="" aria-hidden="true" loading="lazy" />
{/each}
{#each col.images as src}
<img class="gallery-animation__image" {src} alt="" aria-hidden="true" loading="lazy" />
{#each [col.images, col.images] as set}
{#each set as img}
<picture>
<source type="image/webp" srcset={img.webp} sizes="(max-width: 700px) 33vw, 15vw" />
<img
class="gallery-animation__image"
src={img.src}
srcset={img.srcset}
sizes="(max-width: 700px) 33vw, 15vw"
alt=""
aria-hidden="true"
loading="lazy"
decoding="async"
/>
</picture>
{/each}
{/each}
</div>
</div>

View file

@ -9,32 +9,21 @@
@font-face {
font-family: "Danzza";
src: local("Danzza Regular"),
url("/assets/fonts/Danzza-Regular.woff") format("woff"),
url("/assets/fonts/Danzza-Regular.otf") format("opentype");
font-display: swap;
}
@font-face {
font-family: "Danzza Light";
src: local("Danzza Light"),
url("/assets/fonts/Danzza-Light.woff") format("woff"),
url("/assets/fonts/Danzza-Light.otf") format("opentype");
url("/assets/fonts/Danzza%20Regular.otf") format("opentype");
font-display: swap;
}
@font-face {
font-family: "Danzza Medium";
src: local("Danzza Medium"),
url("/assets/fonts/Danzza-Medium.woff") format("woff"),
url("/assets/fonts/Danzza-Medium.otf") format("opentype");
url("/assets/fonts/Danzza%20Medium.otf") format("opentype");
font-display: swap;
}
@font-face {
font-family: "Danzza Bold";
src: local("Danzza Bold"),
url("/assets/fonts/Danzza-Bold.woff") format("woff"),
url("/assets/fonts/Danzza-Bold.otf") format("opentype");
url("/assets/fonts/Danzza%20Bold.otf") format("opentype");
font-display: swap;
}
@ -47,8 +36,9 @@
font-family: "Danzza";
}
/* Danzza Light n'existe pas — pointe vers Regular */
.font-face-danzza-light {
font-family: "Danzza Light";
font-family: "Danzza";
}
.font-face-danzza-medium {
@ -62,3 +52,10 @@
.green {
color: var(--color-primary);
}
.gradient-blue {
-webkit-text-fill-color: transparent;
background: linear-gradient(90deg, #2c85f3 0, #68e0cf 50%);
background-clip: text;
-webkit-background-clip: text;
}

View file

@ -105,7 +105,7 @@
<!-- Infos projet (droite) -->
<div class="portfolio-text" aria-live="polite">
<h2>{currentProject.title}</h2>
<h3 class="portfolio-catchphrase">{@html currentProject.catchphrase}</h3>
<h3 class="portfolio-catchphrase gradient-blue">{@html currentProject.catchphrase}</h3>
<div class="portfolio-description">{@html currentProject.description}</div>
<div class="portfolio-keywords">
{#each currentProject.keywords as kw}
@ -128,8 +128,8 @@
class:active={i === currentIndex}
onclick={() => { currentIndex = i; setAnchor(i) }}
>
<span class="portfolio-nav-number">{String(i + 1).padStart(2, '0')}</span>
<img src={project.thumbnail} alt={project.title} />
<span class="portfolio-nav-number">{String(i + 1).padStart(2, '0')}</span>
</button>
{/each}
</nav>
@ -170,7 +170,7 @@
}
.portfolio-text {
grid-area: 7/11 / span 6 / span 6;
grid-area: 7/11 / span 6 / span 5;
z-index: var(--z-content);
text-align: left;
display: flex;
@ -181,18 +181,20 @@
}
.portfolio-text h2 {
font-size: var(--font-size-title-section);
font-size: var(--font-size-title-main);
text-transform: uppercase;
line-height: 1.1;
}
.portfolio-catchphrase {
font-family: "Danzza Medium", sans-serif;
font-size: var(--font-size-subtitle);
font-weight: 600;
color: var(--color-primary);
font-weight: normal;
}
.portfolio-description {
font-size: var(--font-size-paragraph-small);
font-size: var(--font-size-subtitle);
line-height: 1.5;
opacity: 0.8;
}
@ -215,6 +217,7 @@
/* Sidebar navigation */
.portfolio-nav {
grid-area: 4/17 / span 14 / span 4;
padding-right: 8rem;
z-index: var(--z-content);
display: flex;
flex-direction: column;
@ -225,7 +228,7 @@
.portfolio-nav-item {
display: flex;
align-items: center;
align-items: flex-start;
gap: 0.5rem;
background: none;
border: none;
@ -236,13 +239,13 @@
}
.portfolio-nav-item.active {
transform: scale(1.25) translateX(-50%);
transform: scale(1.5) translateX(-20%);
opacity: 1;
}
.portfolio-nav-number {
color: var(--color-text);
font-size: var(--font-size-caption);
font-size: .5rem;
}
.portfolio-nav-item img {

View file

@ -21,7 +21,7 @@ function keepFontsInPlace() {
if (chunk.type === 'asset' && chunk.fileName.endsWith('.css')) {
chunk.source = chunk.source.replace(
/url\((['"]?)([^'")\s]*\.(woff2?|ttf|otf))\1\)/gi,
(_, _q, p) => `url("/assets/fonts/${p.split('/').pop()}")`
(_, _q, p) => `url("/assets/fonts/${decodeURIComponent(p.split('/').pop())}")`
)
}
}