Compare commits
7 commits
d82e51c4c9
...
261323b4ce
| Author | SHA1 | Date | |
|---|---|---|---|
| 261323b4ce | |||
| 90e673901e | |||
| 835519a0c2 | |||
| 37339f4ebe | |||
| d01d42fbfb | |||
| c3cc6915db | |||
| 3566488a0a |
50 changed files with 186 additions and 135 deletions
|
|
@ -4,6 +4,7 @@ import tailwind from "@astrojs/tailwind";
|
|||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
devToolbar: { enabled: false },
|
||||
integrations: [tailwind()],
|
||||
i18n: {
|
||||
defaultLocale: "fr",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ const categories = sortedCategories.map(cat => ({ id: cat.id, title: cat.data.ti
|
|||
<HomeIcon size={16} />
|
||||
<span class="site-name">Jalil Arfaoui</span>
|
||||
</a>
|
||||
<span class="nav-separator"></span>
|
||||
<a href="/photo" class="nav-link">Photo</a>
|
||||
</div>
|
||||
|
||||
<!-- Bouton hamburger (mobile) -->
|
||||
|
|
@ -69,6 +71,13 @@ const categories = sortedCategories.map(cat => ({ id: cat.id, title: cat.data.ti
|
|||
height: 53px;
|
||||
}
|
||||
|
||||
.site-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.site-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -84,6 +93,11 @@ const categories = sortedCategories.map(cat => ({ id: cat.id, title: cat.data.ti
|
|||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.site-title .nav-link {
|
||||
padding-bottom: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.hamburger {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
|
|
@ -193,14 +207,14 @@ const categories = sortedCategories.map(cat => ({ id: cat.id, title: cat.data.ti
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
.nav-menu .nav-link {
|
||||
display: block;
|
||||
padding: 15px 20px;
|
||||
font-size: 18px;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
.nav-menu .nav-link.active {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
|
@ -220,7 +234,8 @@ const categories = sortedCategories.map(cat => ({ id: cat.id, title: cat.data.ti
|
|||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.site-name {
|
||||
.site-name,
|
||||
.site-title .nav-separator {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
63
src/components/photo/PhotoFooter.astro
Normal file
63
src/components/photo/PhotoFooter.astro
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<footer class="photo-footer">
|
||||
<div class="photo-footer-inner">
|
||||
<div class="photo-footer-links">
|
||||
<a href="/a-propos">À propos</a>
|
||||
<a href="mailto:jalil@arfaoui.net">Contact</a>
|
||||
<a href="https://instagram.com/l.i.l.a.j" target="_blank" rel="noopener noreferrer">Instagram</a>
|
||||
</div>
|
||||
<div class="photo-footer-copy">
|
||||
© Jalil Arfaoui <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener noreferrer">Creative Commons CC-BY-NC 4.0</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
.photo-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 40;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
backdrop-filter: blur(8px);
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.photo-footer-inner {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
height: 54px;
|
||||
font-size: 16px;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.photo-footer-links {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.photo-footer-links a,
|
||||
.photo-footer-copy,
|
||||
.photo-footer-copy a {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.photo-footer-links a:hover,
|
||||
.photo-footer-copy a:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.photo-footer-inner {
|
||||
flex-direction: column;
|
||||
height: auto;
|
||||
padding: 10px 20px;
|
||||
gap: 4px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
.prev-btn,
|
||||
.next-btn {
|
||||
top: auto;
|
||||
bottom: 2rem;
|
||||
bottom: 5rem;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,11 +67,11 @@ const talksCollection = defineCollection({
|
|||
|
||||
const photoBlogPostsCollection = defineCollection({
|
||||
type: "content",
|
||||
schema: ({ image }) => z.object({
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
date: z.date(),
|
||||
coverImage: image(),
|
||||
coverImage: z.string(),
|
||||
tags: z.array(z.string()).optional(),
|
||||
featured: z.boolean().default(false),
|
||||
draft: z.boolean().default(false),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
title: "تصوير إيرول"
|
||||
description: "أراد إيرول صورًا له لإعداد كتاب أعمال. عملنا طوال اليوم لتنويع الأجواء..."
|
||||
date: 2011-10-02
|
||||
coverImage: "../../assets/images/photos/blog/eroll/18-Eroll-Shooting-1-19.jpg"
|
||||
coverImage: "18-Eroll-Shooting-1-19.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Shooting Eroll"
|
||||
description: "Eroll wanted some photos of him in order to have a modeling book. We worked all day in order to have some ambiance variations..."
|
||||
date: 2011-10-02
|
||||
coverImage: "../../assets/images/photos/blog/eroll/18-Eroll-Shooting-1-19.jpg"
|
||||
coverImage: "18-Eroll-Shooting-1-19.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Shooting Eroll"
|
||||
description: "Eroll voulait des photos de lui pour constituer un book. On a travaillé toute la journée pour varier les ambiances..."
|
||||
date: 2011-10-02
|
||||
coverImage: "../../assets/images/photos/blog/eroll/18-Eroll-Shooting-1-19.jpg"
|
||||
coverImage: "18-Eroll-Shooting-1-19.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Inox Park Paris 2011"
|
||||
description: "بعد نجاحه في 2010، يعود مهرجان Inox Park Paris إلى جزيرة شاتو في نسخته الثانية. ثلاث مسارح، 15 دي جي، 12 ساعة من الحفل في الهواء الطلق: Tiësto، Joachim Garraud، Sven Väth، Steve Aoki..."
|
||||
date: 2011-09-10
|
||||
coverImage: "../../assets/images/photos/blog/inox-park-2011/01-Inox-Park-Paris-Chatou-2011.jpg"
|
||||
coverImage: "01-Inox-Park-Paris-Chatou-2011.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Inox Park Paris 2011"
|
||||
description: "After its 2010 success, the Inox Park Paris Electro Festival is back to the island of Chatou for its second edition. Three stages, 15 DJs, 12 hours of outdoor party: Tiësto, Joachim Garraud, Sven Väth, Steve Aoki..."
|
||||
date: 2011-09-10
|
||||
coverImage: "../../assets/images/photos/blog/inox-park-2011/01-Inox-Park-Paris-Chatou-2011.jpg"
|
||||
coverImage: "01-Inox-Park-Paris-Chatou-2011.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Inox Park Paris 2011"
|
||||
description: "Après son succès de 2010, le festival Inox Park Paris revient sur l'île de Chatou pour sa deuxième édition. Trois scènes, 15 DJs, 12 heures de fête en plein air : Tiësto, Joachim Garraud, Sven Väth, Steve Aoki..."
|
||||
date: 2011-09-10
|
||||
coverImage: "../../assets/images/photos/blog/inox-park-2011/10-Inox-Park-Paris-Chatou-2011-7.jpg"
|
||||
coverImage: "10-Inox-Park-Paris-Chatou-2011-7.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "عملية المحفظة 2012"
|
||||
description: "توزيع محافظ مدرسية مجانية في مدارس محرومة من طرف جمعية محلية (JCI)، طنجة، المغرب."
|
||||
date: 2012-09-30
|
||||
coverImage: "../../assets/images/photos/blog/schoolbag-operation-2012/35-Moroccan-Schoolgirls.jpg"
|
||||
coverImage: "35-Moroccan-Schoolgirls.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Schoolbag Operation 2012"
|
||||
description: "During a distribution of free schoolbags in poor schools by a local association (JCI), Tangier, Morocco."
|
||||
date: 2012-09-30
|
||||
coverImage: "../../assets/images/photos/blog/schoolbag-operation-2012/35-Moroccan-Schoolgirls.jpg"
|
||||
coverImage: "35-Moroccan-Schoolgirls.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Opération Cartable 2012"
|
||||
description: "Distribution gratuite de cartables dans des écoles défavorisées par une association locale (JCI), Tanger, Maroc."
|
||||
date: 2012-09-30
|
||||
coverImage: "../../assets/images/photos/blog/schoolbag-operation-2012/35-Moroccan-Schoolgirls.jpg"
|
||||
coverImage: "35-Moroccan-Schoolgirls.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "جولة في طنجة"
|
||||
description: "جولة فوتوغرافية في شوارع طنجة."
|
||||
date: 2012-05-26
|
||||
coverImage: "../../assets/images/photos/blog/tangier-walk/01-Observer-le-changement.jpg"
|
||||
coverImage: "01-Observer-le-changement.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Tangier Walk"
|
||||
description: "A photographic walk through the streets of Tangier."
|
||||
date: 2012-05-26
|
||||
coverImage: "../../assets/images/photos/blog/tangier-walk/01-Observer-le-changement.jpg"
|
||||
coverImage: "01-Observer-le-changement.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Balade à Tanger"
|
||||
description: "Promenade photographique dans les rues de Tanger"
|
||||
date: 2012-05-26
|
||||
coverImage: "../../assets/images/photos/blog/tangier-walk/01-Observer-le-changement.jpg"
|
||||
coverImage: "01-Observer-le-changement.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "هلسنكي"
|
||||
description: "اختفى الثلج من هلسنكي وسرعان ما أفسح المجال للربيع..."
|
||||
date: 2013-05-15
|
||||
coverImage: "../../assets/images/photos/blog/helsinki/01-Library-of-University-of-Helsinki.jpg"
|
||||
coverImage: "01-Library-of-University-of-Helsinki.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Helsinki"
|
||||
description: "The snow has disappeared from Helsinki and quickly gave way to spring..."
|
||||
date: 2013-05-15
|
||||
coverImage: "../../assets/images/photos/blog/helsinki/01-Library-of-University-of-Helsinki.jpg"
|
||||
coverImage: "01-Library-of-University-of-Helsinki.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Helsinki"
|
||||
description: "La neige a disparu d'Helsinki et a vite laissé place au printemps..."
|
||||
date: 2013-05-15
|
||||
coverImage: "../../assets/images/photos/blog/helsinki/01-Library-of-University-of-Helsinki.jpg"
|
||||
coverImage: "01-Library-of-University-of-Helsinki.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "نزهة في إفران"
|
||||
description: "نزهة شتوية في جبال الأطلس المتوسط."
|
||||
date: 2013-01-13
|
||||
coverImage: "../../assets/images/photos/blog/ifrane-hike/03-3.jpg"
|
||||
coverImage: "03-3.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Ifrane Hike"
|
||||
description: "Winter hike in the Middle Atlas mountains."
|
||||
date: 2013-01-13
|
||||
coverImage: "../../assets/images/photos/blog/ifrane-hike/03-3.jpg"
|
||||
coverImage: "03-3.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Randonnée à Ifrane"
|
||||
description: "Randonnée hivernale dans les montagnes du Moyen Atlas"
|
||||
date: 2013-01-13
|
||||
coverImage: "../../assets/images/photos/blog/ifrane-hike/03-3.jpg"
|
||||
coverImage: "03-3.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "London Calling"
|
||||
description: "عطلة نهاية أسبوع فوتوغرافية في لندن."
|
||||
date: 2014-07-15
|
||||
coverImage: "../../assets/images/photos/blog/london-calling/01-The-sky-inside.jpg"
|
||||
coverImage: "01-The-sky-inside.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "London Calling"
|
||||
description: "A photographic weekend in London."
|
||||
date: 2014-07-15
|
||||
coverImage: "../../assets/images/photos/blog/london-calling/01-The-sky-inside.jpg"
|
||||
coverImage: "01-The-sky-inside.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "London Calling"
|
||||
description: "Week-end photographique à Londres"
|
||||
date: 2014-07-15
|
||||
coverImage: "../../assets/images/photos/blog/london-calling/01-The-sky-inside.jpg"
|
||||
coverImage: "01-The-sky-inside.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "أحد سيكواني"
|
||||
description: "نزهة يوم أحد على ضفاف نهر السين."
|
||||
date: 2014-05-18
|
||||
coverImage: "../../assets/images/photos/blog/sequanian-sunday/04-La-Defense-seen-from-Pont-de-Suresnes-2.jpg"
|
||||
coverImage: "04-La-Defense-seen-from-Pont-de-Suresnes-2.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Sequanian Sunday"
|
||||
description: "A sunday walk near the Seine."
|
||||
date: 2014-05-18
|
||||
coverImage: "../../assets/images/photos/blog/sequanian-sunday/04-La-Defense-seen-from-Pont-de-Suresnes-2.jpg"
|
||||
coverImage: "04-La-Defense-seen-from-Pont-de-Suresnes-2.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Dimanche Séquanais"
|
||||
description: "Balade dominicale au bord de la Seine."
|
||||
date: 2014-05-18
|
||||
coverImage: "../../assets/images/photos/blog/sequanian-sunday/04-La-Defense-seen-from-Pont-de-Suresnes-2.jpg"
|
||||
coverImage: "04-La-Defense-seen-from-Pont-de-Suresnes-2.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "تجوال في مدينة طنجة القديمة"
|
||||
description: "أثناء التجوال في أزقة طنجة القديمة، صادفت ساعاتيًا، ونجّارًا، وقمرًا عملاقًا..."
|
||||
date: 2014-08-10
|
||||
coverImage: "../../assets/images/photos/blog/wandering-tangier-medina/01-The-watchmaker.jpg"
|
||||
coverImage: "01-The-watchmaker.jpg"
|
||||
tags: []
|
||||
featured: true
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Wandering Tangier Medina"
|
||||
description: "Walking in the streets of the old Tangier, met a watchmaker, a carpenter and a super-moon..."
|
||||
date: 2014-08-10
|
||||
coverImage: "../../assets/images/photos/blog/wandering-tangier-medina/01-The-watchmaker.jpg"
|
||||
coverImage: "01-The-watchmaker.jpg"
|
||||
tags: []
|
||||
featured: true
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Dans la médina de Tanger"
|
||||
description: "En marchant dans les rues du vieux Tanger, j'ai croisé un horloger, un menuisier et une super-lune..."
|
||||
date: 2014-08-10
|
||||
coverImage: "../../assets/images/photos/blog/wandering-tangier-medina/01-The-watchmaker.jpg"
|
||||
coverImage: "01-The-watchmaker.jpg"
|
||||
tags: []
|
||||
featured: true
|
||||
draft: false
|
||||
|
|
@ -5,7 +5,7 @@ description: |
|
|||
|
||||
تغطية.
|
||||
date: 2015-04-25
|
||||
coverImage: "../../assets/images/photos/blog/enigma/01-Enigma-v1.jpg"
|
||||
coverImage: "01-Enigma-v1.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -5,7 +5,7 @@ description: |
|
|||
|
||||
Recap.
|
||||
date: 2015-04-25
|
||||
coverImage: "../../assets/images/photos/blog/enigma/01-Enigma-v1.jpg"
|
||||
coverImage: "01-Enigma-v1.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -5,7 +5,7 @@ description: |
|
|||
|
||||
Récap.
|
||||
date: 2015-04-25
|
||||
coverImage: "../../assets/images/photos/blog/enigma/11-Enigma-v1-11.jpg"
|
||||
coverImage: "11-Enigma-v1-11.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Field of Stones"
|
||||
description: "كواليس تصوير غلاف ألبوم ماركو وولتر. أراد أن تُلتقط الصورة في سينماتيك طنجة. لا وقت، لا إضاءة، لكن لا خيار. حاولنا تقديم أفضل ما لدينا..."
|
||||
date: 2015-04-02
|
||||
coverImage: "../../assets/images/photos/blog/field-of-stones/01-Marco-Wolter-Field-of-Stones-2.jpg"
|
||||
coverImage: "01-Marco-Wolter-Field-of-Stones-2.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Field of Stones"
|
||||
description: "Making of the album cover for Marco Wolter. He wanted it to be shot in the Cinémathèque of Tangier. We had no time, no light, but no choice. We tried to make the best of it..."
|
||||
date: 2015-04-02
|
||||
coverImage: "../../assets/images/photos/blog/field-of-stones/01-Marco-Wolter-Field-of-Stones-2.jpg"
|
||||
coverImage: "01-Marco-Wolter-Field-of-Stones-2.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Field of Stones"
|
||||
description: "Making of de la pochette de l'album de Marco Wolter. Il voulait que la photo soit prise à la Cinémathèque de Tanger. Pas de temps, pas de lumière, mais pas le choix. On a fait au mieux..."
|
||||
date: 2015-04-02
|
||||
coverImage: "../../assets/images/photos/blog/field-of-stones/01-Marco-Wolter-Field-of-Stones-2.jpg"
|
||||
coverImage: "01-Marco-Wolter-Field-of-Stones-2.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "لا رياح في لاس كويفاس"
|
||||
description: "كان من المفترض أن يكون يومًا مثاليًا لتطيير طائرتنا الورقية: مشمس وعاصف. مشمس كان، لكن الرياح لم تأتِ أبدًا."
|
||||
date: 2015-01-10
|
||||
coverImage: "../../assets/images/photos/blog/no-wind-las-cuevas/13-No-wind-at-Las-Cuevas.jpg"
|
||||
coverImage: "13-No-wind-at-Las-Cuevas.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "No Wind at Las Cuevas"
|
||||
description: "It was supposed to be a perfect day for flying our kite: sunny and windy. Sunny it was, but the wind never came."
|
||||
date: 2015-01-10
|
||||
coverImage: "../../assets/images/photos/blog/no-wind-las-cuevas/13-No-wind-at-Las-Cuevas.jpg"
|
||||
coverImage: "13-No-wind-at-Las-Cuevas.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Pas de vent à Las Cuevas"
|
||||
description: "Ça devait être une journée parfaite pour faire voler notre cerf-volant : ensoleillée et venteuse. Ensoleillée, oui. Mais le vent n'est jamais venu."
|
||||
date: 2015-01-10
|
||||
coverImage: "../../assets/images/photos/blog/no-wind-las-cuevas/13-No-wind-at-Las-Cuevas.jpg"
|
||||
coverImage: "13-No-wind-at-Las-Cuevas.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "زفاف أورور وتوما"
|
||||
description: "كان لي شرف ومتعة أن أكون شاهد توما في زفافه الجميل مع أورور. ليس سهلًا التصوير في نفس الوقت، لكن كل الصور مليئة بالحب."
|
||||
date: 2015-09-26
|
||||
coverImage: "../../assets/images/photos/blog/wedding-aurore-thomas/10-Mariage-Aurore-Thomas-10.jpg"
|
||||
coverImage: "10-Mariage-Aurore-Thomas-10.jpg"
|
||||
tags: []
|
||||
featured: true
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Wedding Aurore & Thomas"
|
||||
description: "I had the honor and pleasure to be Thomas' best man for his beautiful wedding with Aurore. Not easy to shoot pictures though, but all of them are filled with love."
|
||||
date: 2015-09-26
|
||||
coverImage: "../../assets/images/photos/blog/wedding-aurore-thomas/10-Mariage-Aurore-Thomas-10.jpg"
|
||||
coverImage: "10-Mariage-Aurore-Thomas-10.jpg"
|
||||
tags: []
|
||||
featured: true
|
||||
draft: false
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Mariage Aurore & Thomas"
|
||||
description: "J'ai eu l'honneur et le plaisir d'être le témoin de Thomas pour son beau mariage avec Aurore. Pas facile de shooter en même temps, mais toutes les photos sont remplies d'amour."
|
||||
date: 2015-09-26
|
||||
coverImage: "../../assets/images/photos/blog/wedding-aurore-thomas/10-Mariage-Aurore-Thomas-10.jpg"
|
||||
coverImage: "10-Mariage-Aurore-Thomas-10.jpg"
|
||||
tags: []
|
||||
featured: true
|
||||
draft: false
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
title: "في انتظار العروس"
|
||||
description: "تحضيرات زفاف."
|
||||
date: 2014-10-25
|
||||
coverImage: "../../assets/images/photos/blog/waiting-for-the-bride/01-.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
lang: ar
|
||||
---
|
||||
|
||||
تحضيرات زفاف.
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
title: "Waiting for the Bride"
|
||||
description: "Wedding preparations."
|
||||
date: 2014-10-25
|
||||
coverImage: "../../assets/images/photos/blog/waiting-for-the-bride/01-.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
lang: en
|
||||
---
|
||||
|
||||
Wedding preparations.
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
title: "En attendant la mariée"
|
||||
description: "Préparatifs d'un mariage"
|
||||
date: 2014-10-25
|
||||
coverImage: "../../assets/images/photos/blog/waiting-for-the-bride/01-.jpg"
|
||||
tags: []
|
||||
featured: false
|
||||
draft: false
|
||||
---
|
||||
|
||||
Préparatifs d'un mariage.
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
---
|
||||
import PhotoFooter from '../components/photo/PhotoFooter.astro';
|
||||
|
||||
const { title = "Galerie Photo - Jalil Arfaoui", enableScroll = false } = Astro.props;
|
||||
---
|
||||
|
||||
|
|
@ -25,19 +27,7 @@ const { title = "Galerie Photo - Jalil Arfaoui", enableScroll = false } = Astro.
|
|||
<body class={`antialiased bg-black text-white ${enableScroll ? '' : 'overflow-hidden'}`} style="font-family: 'Karla', 'Helvetica Neue', Helvetica, Arial, sans-serif;">
|
||||
<slot />
|
||||
|
||||
<!-- Footer bandeau -->
|
||||
<footer class="fixed bottom-0 left-0 right-0 z-40 bg-black/30 backdrop-blur-sm transition-transform duration-300">
|
||||
<div class="flex justify-between items-center w-full" style="padding-left: 20px; padding-right: 20px; height: 54px; line-height: 54px;">
|
||||
<div class="footer-left flex items-center text-white/70" style="font-size: 16px; font-weight: normal;">
|
||||
<a href="/a-propos" class="hover:text-white transition-colors" style="margin-right: 15px;">À propos</a>
|
||||
<a href="mailto:jalil@arfaoui.net" class="hover:text-white transition-colors" style="margin-right: 15px;">Contact</a>
|
||||
<a href="https://instagram.com/l.i.l.a.j" target="_blank" rel="noopener noreferrer" class="hover:text-white transition-colors">Instagram</a>
|
||||
</div>
|
||||
<div class="footer-right text-white/70" style="font-size: 16px; font-weight: normal;">
|
||||
© Jalil Arfaoui Creative Commons CC-BY-NC 4.0
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<PhotoFooter />
|
||||
|
||||
<Fragment set:html={import.meta.env.FOOTER_INJECT} />
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import PhotoLayout from '../../../layouts/PhotoLayout.astro';
|
||||
import CategoryNav from '../../../components/photo/CategoryNav.astro';
|
||||
import AlbumHeader from '../../../components/photo/AlbumHeader.astro';
|
||||
import MasonryGallery from '../../../components/photo/MasonryGallery.astro';
|
||||
import Lightbox from '../../../components/photo/Lightbox.astro';
|
||||
import PhotoLayout from '../../../../layouts/PhotoLayout.astro';
|
||||
import CategoryNav from '../../../../components/photo/CategoryNav.astro';
|
||||
import AlbumHeader from '../../../../components/photo/AlbumHeader.astro';
|
||||
import MasonryGallery from '../../../../components/photo/MasonryGallery.astro';
|
||||
import Lightbox from '../../../../components/photo/Lightbox.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
// Importer toutes les images du dossier photos
|
||||
|
|
@ -11,27 +11,37 @@ const allImages = import.meta.glob<{ default: ImageMetadata }>('/src/assets/imag
|
|||
|
||||
export async function getStaticPaths() {
|
||||
const allPhotoBlogPosts = await getCollection('photoBlogPosts');
|
||||
return allPhotoBlogPosts.map(post => ({
|
||||
params: { slug: post.slug },
|
||||
props: { post },
|
||||
}));
|
||||
return allPhotoBlogPosts.map(post => {
|
||||
// Le slug Astro inclut le préfixe d'année (ex: "2015/enigma.en")
|
||||
const slug = post.slug.replace(/^\d{4}\//, '');
|
||||
return {
|
||||
params: {
|
||||
year: String(post.data.date.getFullYear()),
|
||||
slug,
|
||||
},
|
||||
props: { post },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const { post } = Astro.props;
|
||||
const { Content } = await post.render();
|
||||
|
||||
// coverImage est déjà un ImageMetadata grâce au schema image() dans config.ts
|
||||
const coverImage = post.data.coverImage;
|
||||
// Slug de base sans préfixe d'année ni suffixe de langue (2015/enigma.en → enigma)
|
||||
const baseSlug = post.slug.replace(/^\d{4}\//, '').replace(/\.(en|ar)$/, '');
|
||||
|
||||
// Slug de base sans suffixe de langue (enigma.en → enigma)
|
||||
const baseSlug = post.slug.replace(/\.(en|ar)$/, '');
|
||||
|
||||
// Charger toutes les images du dossier correspondant au slug
|
||||
const albumPath = `/src/assets/images/photos/blog/${baseSlug}/`;
|
||||
// Construire le chemin de l'album avec l'année
|
||||
const year = post.data.date.getFullYear();
|
||||
const albumPath = `/src/assets/images/photos/blog/${year}/${baseSlug}/`;
|
||||
const albumImages = Object.keys(allImages)
|
||||
.filter(path => path.startsWith(albumPath))
|
||||
.sort();
|
||||
|
||||
// Résoudre la cover image depuis le glob
|
||||
const coverPath = `/src/assets/images/photos/blog/${year}/${baseSlug}/${post.data.coverImage}`;
|
||||
const coverImageLoader = allImages[coverPath];
|
||||
const coverImage = coverImageLoader ? (await coverImageLoader()).default : undefined;
|
||||
|
||||
// Résoudre les images de la galerie
|
||||
const galleryImages = await Promise.all(
|
||||
albumImages.map(async (imagePath) => {
|
||||
|
|
@ -115,4 +125,4 @@ const lightboxImages = galleryImages.map(img => ({
|
|||
border-radius: 8px;
|
||||
margin: 2em 0;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -4,6 +4,11 @@ import CategoryNav from '../../../components/photo/CategoryNav.astro';
|
|||
import { getCollection } from 'astro:content';
|
||||
import { Picture } from 'astro:assets';
|
||||
|
||||
// Importer toutes les images pour résoudre les cover images
|
||||
const allImages = import.meta.glob<{ default: ImageMetadata }>(
|
||||
'/src/assets/images/photos/blog/**/*.{jpg,jpeg,png,webp}'
|
||||
);
|
||||
|
||||
// Récupération des posts photo (langue par défaut : FR)
|
||||
const allPhotoBlogPosts = (await getCollection('photoBlogPosts'))
|
||||
.filter(post => (post.data.lang ?? 'fr') === 'fr');
|
||||
|
|
@ -13,10 +18,14 @@ const sortedPosts = allPhotoBlogPosts.sort((a, b) =>
|
|||
new Date(b.data.date).getTime() - new Date(a.data.date).getTime()
|
||||
);
|
||||
|
||||
// coverImage est déjà un ImageMetadata grâce au schema image() dans config.ts
|
||||
const postsWithImages = sortedPosts.map((post) => ({
|
||||
...post,
|
||||
resolvedCoverImage: post.data.coverImage
|
||||
// Résoudre les cover images via le glob
|
||||
const postsWithImages = await Promise.all(sortedPosts.map(async (post) => {
|
||||
const year = post.data.date.getFullYear();
|
||||
const baseSlug = post.slug.replace(/^\d{4}\//, '').replace(/\.(en|ar)$/, '');
|
||||
const coverPath = `/src/assets/images/photos/blog/${year}/${baseSlug}/${post.data.coverImage}`;
|
||||
const loader = allImages[coverPath];
|
||||
const resolvedCoverImage = loader ? (await loader()).default : undefined;
|
||||
return { ...post, resolvedCoverImage };
|
||||
}));
|
||||
|
||||
// Séparer les posts à la une des autres
|
||||
|
|
@ -41,7 +50,6 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
<div class="post-content">
|
||||
<span class="post-badge">À la une</span>
|
||||
<h2 class="post-title">{post.data.title}</h2>
|
||||
<p class="post-description">{post.data.description}</p>
|
||||
<time class="post-date">
|
||||
{new Date(post.data.date).toLocaleDateString('fr-FR', {
|
||||
year: 'numeric',
|
||||
|
|
@ -69,7 +77,6 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
<div class="post-overlay">
|
||||
<div class="overlay-content">
|
||||
<h3 class="post-title">{post.data.title}</h3>
|
||||
<p class="post-subtitle">{post.data.description}</p>
|
||||
<time class="post-date">
|
||||
{new Date(post.data.date).toLocaleDateString('fr-FR', {
|
||||
year: 'numeric',
|
||||
|
|
@ -96,15 +103,13 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
|
||||
/* Section à la une */
|
||||
.featured-section {
|
||||
padding: 40px 20px 60px;
|
||||
max-width: 1600px;
|
||||
margin: 0 auto;
|
||||
padding: 16px 16px 0;
|
||||
}
|
||||
|
||||
.featured-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
|
||||
gap: 20px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.featured-post {
|
||||
|
|
@ -141,13 +146,10 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 40px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.featured-post .post-content {
|
||||
color: white;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.post-badge {
|
||||
|
|
@ -165,7 +167,7 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
.featured-post .post-title {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 12px 0;
|
||||
margin: 0 0 4px 0;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
|
|
@ -182,21 +184,20 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
}
|
||||
|
||||
.featured-post .post-date {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Grille des posts */
|
||||
.posts-grid {
|
||||
padding: 0 20px 100px;
|
||||
max-width: 1600px;
|
||||
margin: 0 auto;
|
||||
padding: 16px 16px 100px;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.post-item {
|
||||
|
|
@ -211,6 +212,11 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
aspect-ratio: 3/2;
|
||||
}
|
||||
|
||||
.featured-post .post-link {
|
||||
aspect-ratio: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.post-link img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
@ -221,18 +227,19 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
|
||||
.post-item .post-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0) 100%);
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.5) 25%, rgba(0,0,0,0) 50%);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 20px;
|
||||
padding: 12px 16px;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
.post-item:hover .post-overlay {
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.2) 100%);
|
||||
background: linear-gradient(to top, rgba(0,0,0,0.95) 0%, rgba(0,0,0,0.7) 25%, rgba(0,0,0,0) 50%);
|
||||
}
|
||||
|
||||
.post-item:hover img {
|
||||
|
|
@ -246,7 +253,7 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
.post-item .post-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 4px 0;
|
||||
margin: 0 0 2px 0;
|
||||
line-height: 1.3;
|
||||
text-shadow: 0 1px 3px rgba(0,0,0,0.8);
|
||||
}
|
||||
|
|
@ -279,7 +286,7 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
@media (max-width: 768px) {
|
||||
.featured-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 20px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.featured-post {
|
||||
|
|
@ -309,11 +316,11 @@ const regularPosts = postsWithImages.filter(post => !post.data.featured);
|
|||
}
|
||||
|
||||
.featured-section {
|
||||
padding: 20px 15px 40px;
|
||||
padding: 12px 12px 0;
|
||||
}
|
||||
|
||||
.posts-grid {
|
||||
padding: 0 15px 80px;
|
||||
padding: 12px 12px 80px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Reference in a new issue