madebydanny.uk written in html, css, and a lot of JavaScript I don't understand
madebydanny.uk
html
css
javascript
1// ── Photo data ────────────────────────────────────────────────────────────────
2
3const PHOTOS = [
4 {
5 src: 'https://imrs.madebydanny.uk/https://cloudflareisawesome.madebydanny.uk/photos-upload-1/20240622_235041500_iOS.jpg',
6 title: 'DSC_3811.jpg',
7 date: '2025-10-14'
8 },
9 {
10 src: 'https://imrs.madebydanny.uk/https://cloudflareisawesome.madebydanny.uk/photos-upload-1/DSC_3773.jpg',
11 title: 'DSC_3773.jpg',
12 date: '2025-10-14'
13 },
14 {
15 src: 'https://imrs.madebydanny.uk/https://cloudflareisawesome.madebydanny.uk/photos-upload-1/DSC_3766.jpg',
16 title: 'DSC_3766.jpg',
17 date: '2025-10-14'
18 },
19 {
20 src: 'https://imrs.madebydanny.uk/https://cloudflareisawesome.madebydanny.uk/photos-upload-1/DSC_3765.jpg',
21 title: 'DSC_3765.jpg',
22 date: '2025-10-14'
23 },
24 {
25 src: 'https://imrs.madebydanny.uk/https://cloudflareisawesome.madebydanny.uk/photos-upload-1/DSC_3704.jpg',
26 title: 'DSC_3704.jpg',
27 date: '2025-10-14'
28 },
29 {
30 src: 'https://imrs.madebydanny.uk/https://cloudflareisawesome.madebydanny.uk/photos-upload-1/DSC_3692.jpg',
31 title: 'DSC_3692.jpg',
32 date: '2025-10-14'
33 },
34 {
35 src: 'https://imrs.madebydanny.uk/https://cloudflareisawesome.madebydanny.uk/photos-upload-1/20240622_234015800_iOS.jpg',
36 title: 'DSC_3683.jpg',
37 date: '2025-10-14'
38 }
39];
40
41// ── Modal ─────────────────────────────────────────────────────────────────────
42
43function openPhotoModal(src, alt) {
44 const modal = document.getElementById('photo-modal');
45 const modalImg = document.getElementById('modal-photo');
46 if (!modal || !modalImg) return;
47 modalImg.src = src;
48 modalImg.alt = alt;
49 modal.classList.add('active');
50 document.body.style.overflow = 'hidden';
51}
52
53function closePhotoModal() {
54 const modal = document.getElementById('photo-modal');
55 if (!modal) return;
56 modal.classList.remove('active');
57 document.body.style.overflow = '';
58}
59
60// ── Home strip (4 most recent photos) ────────────────────────────────────────
61
62function renderHomePhotos() {
63 const strip = document.getElementById('home-photo-strip');
64 if (!strip) return;
65
66 const recent = PHOTOS.slice(0, 4);
67 strip.innerHTML = '';
68
69 recent.forEach(photo => {
70 const item = document.createElement('div');
71 item.className = 'photo-strip-item';
72 item.setAttribute('role', 'button');
73 item.setAttribute('tabindex', '0');
74 item.setAttribute('aria-label', `View photo: ${photo.title}`);
75
76 const img = document.createElement('img');
77 img.src = photo.src;
78 img.alt = photo.title;
79 img.loading = 'lazy';
80
81 item.appendChild(img);
82 item.addEventListener('click', () => openPhotoModal(photo.src, photo.title));
83 item.addEventListener('keydown', (e) => {
84 if (e.key === 'Enter' || e.key === ' ') openPhotoModal(photo.src, photo.title);
85 });
86
87 strip.appendChild(item);
88 });
89}
90
91// ── Full gallery (photos.html) ────────────────────────────────────────────────
92
93function renderPhotosGallery() {
94 const gallery = document.getElementById('photos-gallery');
95 const emptyState = document.getElementById('empty-photos');
96 if (!gallery) return;
97
98 gallery.innerHTML = '';
99
100 if (PHOTOS.length === 0) {
101 if (emptyState) emptyState.style.display = 'block';
102 return;
103 }
104 if (emptyState) emptyState.style.display = 'none';
105
106 PHOTOS.forEach(photo => {
107 const item = document.createElement('div');
108 item.className = 'photo-item';
109 item.setAttribute('role', 'button');
110 item.setAttribute('tabindex', '0');
111 item.setAttribute('aria-label', `View photo: ${photo.title}`);
112
113 const img = document.createElement('img');
114 img.src = photo.src;
115 img.alt = photo.title;
116 img.loading = 'lazy';
117
118 const info = document.createElement('div');
119 info.className = 'photo-info';
120
121 const title = document.createElement('h3');
122 title.className = 'photo-title';
123 title.textContent = photo.title;
124
125 const date = document.createElement('p');
126 date.className = 'photo-date';
127 date.textContent = new Date(photo.date).toLocaleDateString('en-GB', {
128 year: 'numeric', month: 'short', day: 'numeric'
129 });
130
131 info.appendChild(title);
132 info.appendChild(date);
133 item.appendChild(img);
134 item.appendChild(info);
135
136 item.addEventListener('click', () => openPhotoModal(photo.src, photo.title));
137 item.addEventListener('keydown', (e) => {
138 if (e.key === 'Enter' || e.key === ' ') openPhotoModal(photo.src, photo.title);
139 });
140
141 gallery.appendChild(item);
142 });
143}
144
145// ── Init ──────────────────────────────────────────────────────────────────────
146
147document.addEventListener('DOMContentLoaded', () => {
148 // Render whichever surface is present on this page
149 renderHomePhotos();
150 renderPhotosGallery();
151
152 // Modal wiring (used on both pages)
153 const modal = document.getElementById('photo-modal');
154 const closeBtn = document.getElementById('modal-close');
155
156 if (closeBtn) closeBtn.addEventListener('click', closePhotoModal);
157
158 if (modal) {
159 modal.addEventListener('click', e => { if (e.target === modal) closePhotoModal(); });
160 }
161
162 document.addEventListener('keydown', e => {
163 if (e.key === 'Escape') closePhotoModal();
164 });
165});