Add AI documentary photo gallery — 13 Gemini-generated images

Gallery page with:
- 13 photorealistic documentary photos matching Lolo field photo DNA
- Pillar-based filtering (Water/Food/Livelihoods/Education)
- Lightbox with keyboard navigation
- Masonry-style grid layout
- All images optimized to JPG (~130KB each, 1.7MB total)

Images: fish ponds aerial, borehole water, fish harvest, solar panels,
classroom, market, sunset water tank, pond construction, woman carrying
water, community meeting, hands with seedling, catfish basin, camp overview
This commit is contained in:
2026-03-09 00:34:40 +08:00
parent 5979def72f
commit 9a1cd05471
20 changed files with 731 additions and 10 deletions
+413
View File
@@ -0,0 +1,413 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gallery — Taawunu</title>
<meta name="description" content="Documentary photography from the Lolo community development project — fish ponds, water infrastructure, education, and community life.">
<link rel="icon" type="image/svg+xml" href="/images/favicon.svg">
<link rel="stylesheet" href="/css/style.css">
<style>
.gallery-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
}
.gallery-item {
position: relative;
overflow: hidden;
cursor: pointer;
aspect-ratio: 4/3;
}
.gallery-item.tall { grid-row: span 2; aspect-ratio: auto; }
.gallery-item.wide { grid-column: span 2; }
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.gallery-item:hover img { transform: scale(1.05); }
.gallery-item .overlay {
position: absolute;
inset: 0;
background: linear-gradient(to top, rgba(61,31,21,0.8) 0%, transparent 50%);
opacity: 0;
transition: opacity 0.3s;
display: flex;
flex-direction: column;
justify-content: flex-end;
padding: 20px;
}
.gallery-item:hover .overlay { opacity: 1; }
.overlay .pillar-tag {
display: inline-block;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.1em;
padding: 3px 8px;
border-radius: 2px;
margin-bottom: 6px;
width: fit-content;
}
.overlay .caption-title {
font-family: var(--font-display);
font-weight: 700;
font-size: 16px;
color: var(--cream);
margin-bottom: 4px;
}
.overlay .caption-desc {
font-size: 12px;
color: rgba(245,239,224,0.7);
line-height: 1.4;
}
.tag-water { background: rgba(37,120,161,0.8); color: white; }
.tag-food { background: rgba(45,106,79,0.8); color: white; }
.tag-livelihoods { background: rgba(107,58,42,0.8); color: white; }
.tag-education { background: rgba(201,168,76,0.8); color: var(--deep); }
/* Lightbox */
.lightbox {
display: none;
position: fixed;
inset: 0;
z-index: 1000;
background: rgba(0,0,0,0.95);
align-items: center;
justify-content: center;
padding: 40px;
}
.lightbox.open { display: flex; }
.lightbox img {
max-width: 90vw;
max-height: 85vh;
object-fit: contain;
border-radius: 4px;
}
.lightbox-close {
position: absolute;
top: 20px;
right: 24px;
color: white;
font-size: 28px;
cursor: pointer;
background: none;
border: none;
opacity: 0.7;
transition: opacity 0.2s;
}
.lightbox-close:hover { opacity: 1; }
.lightbox-caption {
position: absolute;
bottom: 20px;
left: 40px;
right: 40px;
text-align: center;
color: rgba(255,255,255,0.7);
font-size: 14px;
}
.lightbox-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
color: white;
font-size: 36px;
cursor: pointer;
background: none;
border: none;
opacity: 0.5;
transition: opacity 0.2s;
padding: 20px;
}
.lightbox-nav:hover { opacity: 1; }
.lightbox-prev { left: 10px; }
.lightbox-next { right: 10px; }
@media (max-width: 768px) {
.gallery-grid { grid-template-columns: repeat(2, 1fr); }
.gallery-item.wide { grid-column: span 1; }
.gallery-item.tall { grid-row: span 1; aspect-ratio: 4/3; }
}
@media (max-width: 480px) {
.gallery-grid { grid-template-columns: 1fr; gap: 4px; }
}
</style>
</head>
<body>
<nav class="nav" id="nav">
<div class="nav-inner">
<a href="/" class="nav-brand">
<svg class="mark" viewBox="0 0 64 64" width="32" height="32"><path d="M32 4 C32 4, 56 28, 56 40 C56 53.25 45.25 60 32 60 C18.75 60 8 53.25 8 40 C8 28 32 4 32 4Z" fill="#C9A84C"/><path d="M32 14 C32 14, 50 31, 50 40 C50 49.5 41.75 55 32 55 C22.25 55 14 49.5 14 40 C14 31 32 14 32 14Z" fill="#6B3A2A"/><path d="M32 22 C32 22, 44 34, 44 40 C44 46.6 38.6 50 32 50 C25.4 50 20 46.6 20 40 C20 34 32 22 32 22Z" fill="#2D6A4F"/><path d="M32 30 C32 30, 38 36, 38 40 C38 43.3 35.3 45 32 45 C28.7 45 26 43.3 26 40 C26 36 32 30 32 30Z" fill="#2578A1"/></svg>
<span class="wordmark">TAAWUNU</span>
</a>
<button class="nav-toggle" id="navToggle" aria-label="Menu"><span></span><span></span><span></span></button>
<ul class="nav-links" id="navLinks">
<li><a href="/">Home</a></li>
<li><a href="/approach/">Our Approach</a></li>
<li><a href="/projects/">Projects</a></li>
<li><a href="/about/">About</a></li>
<li><a href="/support/" class="nav-cta">Support a Project</a></li>
</ul>
</div>
</nav>
<section class="page-hero">
<div class="container">
<div class="label fade-up">Gallery</div>
<h1 class="fade-up">The work. The land.<br>The people. The proof.</h1>
<p class="fade-up">Documentary photography from the Lolo community development project — every pillar of the journey from aid to self-sufficiency.</p>
</div>
</section>
<!-- Pillar filter -->
<section style="padding: 24px 0; border-bottom: 1px solid rgba(156,148,136,0.15);">
<div class="container" style="display:flex; gap:12px; flex-wrap:wrap;">
<button class="filter-btn active" data-filter="all" style="font-family:var(--font-body); font-size:13px; font-weight:600; padding:6px 16px; border-radius:3px; border:1.5px solid var(--earth); background:var(--earth); color:white; cursor:pointer; transition:all 0.2s;">All</button>
<button class="filter-btn" data-filter="water" style="font-family:var(--font-body); font-size:13px; font-weight:600; padding:6px 16px; border-radius:3px; border:1.5px solid var(--water); background:transparent; color:var(--water); cursor:pointer; transition:all 0.2s;">💧 Water</button>
<button class="filter-btn" data-filter="food" style="font-family:var(--font-body); font-size:13px; font-weight:600; padding:6px 16px; border-radius:3px; border:1.5px solid var(--green); background:transparent; color:var(--green); cursor:pointer; transition:all 0.2s;">🌾 Food</button>
<button class="filter-btn" data-filter="livelihoods" style="font-family:var(--font-body); font-size:13px; font-weight:600; padding:6px 16px; border-radius:3px; border:1.5px solid var(--earth); background:transparent; color:var(--earth); cursor:pointer; transition:all 0.2s;">💼 Livelihoods</button>
<button class="filter-btn" data-filter="education" style="font-family:var(--font-body); font-size:13px; font-weight:600; padding:6px 16px; border-radius:3px; border:1.5px solid var(--gold); background:transparent; color:var(--gold); cursor:pointer; transition:all 0.2s;">📚 Education</button>
</div>
</section>
<section class="section" style="padding-top:32px;">
<div class="container">
<div class="gallery-grid">
<!-- Row 1: Hero wide + tall -->
<div class="gallery-item wide" data-pillar="food" data-index="0">
<img src="/images/gallery/fish-ponds-aerial.jpg" alt="Aerial view of 10 fish ponds carved into red laterite earth" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-food">🌾 Food</span>
<div class="caption-title">The Fish Farm — Aerial View</div>
<div class="caption-desc">10 earthen ponds carved into the red laterite soil, filled with water and ready for stocking. The foundation of community self-sufficiency.</div>
</div>
</div>
<div class="gallery-item tall" data-pillar="water" data-index="1">
<img src="/images/gallery/borehole-water-flowing.jpg" alt="Solar-powered borehole pumping clean water" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-water">💧 Water</span>
<div class="caption-title">Clean Water Flows</div>
<div class="caption-desc">Solar-powered borehole pumping 10,000 litres daily. Elevated storage tank and solar panels visible. The first pillar — complete.</div>
</div>
</div>
<!-- Row 2 -->
<div class="gallery-item" data-pillar="food" data-index="2">
<img src="/images/gallery/fish-harvest-community.jpg" alt="Community members harvesting catfish from pond" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-food">🌾 Food</span>
<div class="caption-title">First Harvest</div>
<div class="caption-desc">Community members wade into the drained pond with nets. Women and children sort the catch on the embankment above.</div>
</div>
</div>
<div class="gallery-item" data-pillar="food" data-index="3">
<img src="/images/gallery/pond-construction-workers.jpg" alt="Workers digging fish ponds by hand" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-food">🌾 Food</span>
<div class="caption-title">Building the Ponds</div>
<div class="caption-desc">Community members dig fish ponds by hand — the scale of manual labour is staggering. Real work, real progress.</div>
</div>
</div>
<!-- Row 3 -->
<div class="gallery-item" data-pillar="water" data-index="4">
<img src="/images/gallery/water-tank-sunset.jpg" alt="Water storage tank silhouetted against sunset" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-water">💧 Water</span>
<div class="caption-title">Permanence at Sunset</div>
<div class="caption-desc">The elevated water tank silhouetted against the African sunset. This infrastructure will be here long after the project team has gone home.</div>
</div>
</div>
<div class="gallery-item wide" data-pillar="education" data-index="5">
<img src="/images/gallery/children-classroom-light.jpg" alt="Children studying in community classroom" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-education">📚 Education</span>
<div class="caption-title">The Classroom</div>
<div class="caption-desc">Natural light streams through open windows. A teacher instructs children at wooden desks. Basic but functional — and funded by the fish farm.</div>
</div>
</div>
<!-- Row 4 -->
<div class="gallery-item" data-pillar="livelihoods" data-index="6">
<img src="/images/gallery/market-fish-sales.jpg" alt="Woman selling catfish at local market" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-livelihoods">💼 Livelihoods</span>
<div class="caption-title">Market Day</div>
<div class="caption-desc">Fresh catfish for sale at the local market. Surplus fish create income, jobs, and an economy that doesn't depend on outside funding.</div>
</div>
</div>
<div class="gallery-item" data-pillar="livelihoods" data-index="7">
<img src="/images/gallery/catfish-closeup-basin.jpg" alt="Freshly harvested catfish in metal basin" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-livelihoods">💼 Livelihoods</span>
<div class="caption-title">The Harvest — Up Close</div>
<div class="caption-desc">Freshly harvested catfish packed in a basin. These fish grew in the ponds, fed by the water system. The model works.</div>
</div>
</div>
<div class="gallery-item" data-pillar="water" data-index="8">
<img src="/images/gallery/solar-panels-installation.jpg" alt="Installing solar panels for water pump" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-water">💧 Water</span>
<div class="caption-title">Solar Power Installation</div>
<div class="caption-desc">Workers install solar panels to power the borehole pump. No fuel costs, no moving parts — clean energy for clean water.</div>
</div>
</div>
<!-- Row 5 -->
<div class="gallery-item" data-pillar="water" data-index="9">
<img src="/images/gallery/woman-carrying-water.jpg" alt="Woman carrying water along red laterite path" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-water">💧 Water</span>
<div class="caption-title">Water For Home</div>
<div class="caption-desc">Clean water carried home along the red laterite paths of the camp. Before the borehole, this walk was kilometres longer.</div>
</div>
</div>
<div class="gallery-item" data-pillar="food" data-index="10">
<img src="/images/gallery/hands-soil-seedling.jpg" alt="Hands cupping red earth with a seedling" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-food">🌾 Food</span>
<div class="caption-title">From the Ground Up</div>
<div class="caption-desc">Working hands hold red Cameroon earth and a tiny seedling. The core metaphor of everything we do.</div>
</div>
</div>
<div class="gallery-item" data-pillar="livelihoods" data-index="11">
<img src="/images/gallery/community-meeting-shelter.jpg" alt="Community meeting under open shelter" loading="lazy">
<div class="overlay">
<span class="pillar-tag tag-livelihoods">💼 Livelihoods</span>
<div class="caption-title">Community Governance</div>
<div class="caption-desc">Decisions are made together. The community management committee meets to plan operations, allocate resources, and solve problems collectively.</div>
</div>
</div>
<!-- Final: full-width hero -->
<div class="gallery-item wide" data-pillar="food" data-index="12" style="grid-column: span 3;">
<img src="/images/gallery/drone-camp-overview.jpg" alt="Aerial overview of the camp and fish ponds" loading="lazy" style="aspect-ratio:21/9; object-position: center 40%;">
<div class="overlay">
<span class="pillar-tag tag-food">🌾 Full Ecosystem</span>
<div class="caption-title">The Full Picture</div>
<div class="caption-desc">Fish ponds, water infrastructure, community, forest — all interconnected. From aid to independence, one community at a time.</div>
</div>
</div>
</div>
</div>
</section>
<!-- CTA -->
<section class="cta-banner fade-up">
<h2>See the model. Support the mission.</h2>
<p>Every image tells a story of progress. Every project is designed to make itself unnecessary.</p>
<div class="cta-buttons">
<a href="/support/" class="btn btn-primary">Support a Project</a>
<a href="/projects/" class="btn btn-outline">View Project Details</a>
</div>
</section>
<!-- Lightbox -->
<div class="lightbox" id="lightbox">
<button class="lightbox-close" id="lightboxClose">&times;</button>
<button class="lightbox-nav lightbox-prev" id="lightboxPrev">&#8249;</button>
<button class="lightbox-nav lightbox-next" id="lightboxNext">&#8250;</button>
<img id="lightboxImg" src="" alt="">
<div class="lightbox-caption" id="lightboxCaption"></div>
</div>
<footer class="footer">
<div class="container">
<div class="footer-grid">
<div class="footer-brand"><div class="footer-arabic">تَعَاوُنُوا</div><div class="footer-wordmark">TAAWUNU</div><p>A social impact studio designing permanent self-sufficiency for marginalized communities.</p></div>
<div><h4>Explore</h4><ul><li><a href="/approach/">Our Approach</a></li><li><a href="/projects/">Projects</a></li><li><a href="/gallery/">Gallery</a></li><li><a href="/about/">About Us</a></li><li><a href="/support/">Support</a></li></ul></div>
<div><h4>Projects</h4><ul><li><a href="/projects/#aquaculture">Lolo Aquaculture</a></li><li><a href="/projects/#water">Solar Water Well</a></li></ul></div>
<div><h4>Connect</h4><ul><li><a href="mailto:hello@taawunu.org">hello@taawunu.org</a></li><li><a href="https://linkedin.com/company/taawunu" target="_blank" rel="noopener">LinkedIn</a></li><li><a href="https://instagram.com/taawunu" target="_blank" rel="noopener">Instagram</a></li></ul></div>
</div>
<div class="footer-bottom">
<p>&copy; 2026 Taawunu. From the ground up.</p>
<p class="footer-legal">Taawunu is a social impact studio. Charitable donations are processed by our registered charity partners. Taawunu does not solicit or receive charitable donations directly.</p>
</div>
</div>
</footer>
<script>
// Nav
const nav = document.getElementById('nav');
window.addEventListener('scroll', () => nav.classList.toggle('scrolled', window.scrollY > 20));
document.getElementById('navToggle').addEventListener('click', () => document.getElementById('navLinks').classList.toggle('open'));
// Filter
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.filter-btn').forEach(b => {
b.style.background = 'transparent';
b.classList.remove('active');
});
btn.style.background = btn.dataset.filter === 'all' ? 'var(--earth)' :
btn.dataset.filter === 'water' ? 'var(--water)' :
btn.dataset.filter === 'food' ? 'var(--green)' :
btn.dataset.filter === 'livelihoods' ? 'var(--earth)' : 'var(--gold)';
btn.style.color = 'white';
btn.classList.add('active');
const filter = btn.dataset.filter;
document.querySelectorAll('.gallery-item').forEach(item => {
if (filter === 'all' || item.dataset.pillar === filter) {
item.style.display = '';
} else {
item.style.display = 'none';
}
});
});
});
// Lightbox
const items = document.querySelectorAll('.gallery-item');
const lightbox = document.getElementById('lightbox');
const lightboxImg = document.getElementById('lightboxImg');
const lightboxCaption = document.getElementById('lightboxCaption');
let currentIndex = 0;
function openLightbox(index) {
currentIndex = index;
const item = items[index];
const img = item.querySelector('img');
const title = item.querySelector('.caption-title');
const desc = item.querySelector('.caption-desc');
lightboxImg.src = img.src;
lightboxCaption.textContent = (title?.textContent || '') + ' — ' + (desc?.textContent || '');
lightbox.classList.add('open');
document.body.style.overflow = 'hidden';
}
function closeLightbox() {
lightbox.classList.remove('open');
document.body.style.overflow = '';
}
function navigate(dir) {
const visible = [...items].filter(i => i.style.display !== 'none');
const visibleIndex = visible.indexOf(items[currentIndex]);
const nextVisibleIndex = (visibleIndex + dir + visible.length) % visible.length;
const nextItem = visible[nextVisibleIndex];
const newIndex = [...items].indexOf(nextItem);
openLightbox(newIndex);
}
items.forEach((item, i) => item.addEventListener('click', () => openLightbox(i)));
document.getElementById('lightboxClose').addEventListener('click', closeLightbox);
document.getElementById('lightboxPrev').addEventListener('click', () => navigate(-1));
document.getElementById('lightboxNext').addEventListener('click', () => navigate(1));
lightbox.addEventListener('click', (e) => { if (e.target === lightbox) closeLightbox(); });
document.addEventListener('keydown', (e) => {
if (!lightbox.classList.contains('open')) return;
if (e.key === 'Escape') closeLightbox();
if (e.key === 'ArrowLeft') navigate(-1);
if (e.key === 'ArrowRight') navigate(1);
});
// Fade-up
const observer = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('visible'); }); }, { threshold: 0.1 });
document.querySelectorAll('.fade-up').forEach(el => observer.observe(el));
</script>
</body>
</html>