|
17 | 17 | (def highlight-clj-js |
18 | 18 | "function highlightClj(code) { |
19 | 19 | // HTML-escape first |
20 | | - code = code.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); |
| 20 | + code = code.replace(/&/g, '&').replace(/\\x3c/g, '<').replace(/>/g, '>'); |
21 | 21 | // Extract comments and strings into placeholders so they don't interfere |
22 | 22 | var tokens = []; |
23 | | - code = code.replace(/(;;[^\\n]*)/g, function(m) { tokens.push('<span class=\"clj-comment\">' + m + '</span>'); return '\\x00T' + (tokens.length-1) + 'T\\x00'; }); |
24 | | - code = code.replace(/(\"(?:[^\"\\\\]|\\\\.)*\")/g, function(m) { tokens.push('<span class=\"clj-string\">' + m + '</span>'); return '\\x00T' + (tokens.length-1) + 'T\\x00'; }); |
| 23 | + code = code.replace(/(;;[^\\n]*)/g, function(m) { tokens.push('\\x3cspan class=\"clj-comment\">' + m + '\\x3c/span>'); return '\\x00T' + (tokens.length-1) + 'T\\x00'; }); |
| 24 | + code = code.replace(/(\"(?:[^\"\\\\]|\\\\.)*\")/g, function(m) { tokens.push('\\x3cspan class=\"clj-string\">' + m + '\\x3c/span>'); return '\\x00T' + (tokens.length-1) + 'T\\x00'; }); |
25 | 25 | // Highlight remaining tokens |
26 | | - code = code.replace(/(:[a-zA-Z][a-zA-Z0-9_\\-.*+!?\\/<>]*)/g, '<span class=\"clj-keyword\">$1</span>'); |
27 | | - code = code.replace(/\\b(\\d+\\.?\\d*)\\b/g, '<span class=\"clj-number\">$1</span>'); |
28 | | - code = code.replace(/(?<=\\()\\b(defn-?|def|let|fn|if|when|cond|do|loop|recur|for|doseq|mapv|map|filter|reduce|into|concat|vec|assoc|merge|require|ns)\\b/g, '<span class=\"clj-special\">$1</span>'); |
| 26 | + code = code.replace(/(:[a-zA-Z][a-zA-Z0-9_\\-.*+!?\\/<>]*)/g, '\\x3cspan class=\"clj-keyword\">$1\\x3c/span>'); |
| 27 | + code = code.replace(/\\b(\\d+\\.?\\d*)\\b/g, '\\x3cspan class=\"clj-number\">$1\\x3c/span>'); |
| 28 | + code = code.replace(/(?<=\\()\\b(defn-?|def|let|fn|if|when|cond|do|loop|recur|for|doseq|mapv|map|filter|reduce|into|concat|vec|assoc|merge|require|ns)\\b/g, '\\x3cspan class=\"clj-special\">$1\\x3c/span>'); |
29 | 29 | // Restore placeholders |
30 | 30 | code = code.replace(/\\x00T(\\d+)T\\x00/g, function(_, i) { return tokens[parseInt(i)]; }); |
31 | 31 | return code; |
|
173 | 173 | (defn generate-landing-html |
174 | 174 | "Generates the landing page HTML." |
175 | 175 | [examples-by-category] |
176 | | - (let [hero-images (pages/hero-images)] |
| 176 | + (let [all-images (->> examples-by-category |
| 177 | + (mapcat :examples) |
| 178 | + (mapv :output))] |
177 | 179 | (html-page {:title "Eido" :active-page :home :depth 0} |
| 180 | + [:div.alpha-banner |
| 181 | + "Early alpha — under heavy development. Expect some breaking changes between releases."] |
178 | 182 | [:section.hero |
179 | 183 | [:h1.hero-title "Eido"] |
180 | 184 | [:p.hero-tagline "Describe what you see as plain data"] |
181 | | - [:p {:style "color: #6a6a7a; font-size: 0.85rem; margin-top: 0.3rem; font-style: italic;"} "From Greek " [:em "eido"] " — \"I see\""] |
182 | | - [:div.hero-images |
183 | | - (for [img hero-images] |
184 | | - [:img {:src (str "./images/" img) :alt "" :loading "lazy"}])] |
| 185 | + [:p {:style "color: #6a6a7a; font-size: 0.85rem; margin-top: 0.3rem; font-style: italic;"} "From Greek " [:em "eido"] " \u2014 \"I see\""] |
| 186 | + [:div#hero-images.hero-images] |
185 | 187 | [:div.hero-links |
186 | 188 | [:a.hero-link.hero-link--primary {:href "./gallery/index.html"} "Browse Gallery"] |
187 | 189 | [:a.hero-link.hero-link--secondary {:href "./docs/index.html"} "Read the Docs"]]] |
|
202 | 204 | document.querySelectorAll('pre code').forEach(function(el) { |
203 | 205 | el.innerHTML = highlightClj(el.textContent); |
204 | 206 | }); |
205 | | -"))]))) |
| 207 | +var allImages = [" (str/join ", " (map #(str "\"" % "\"") all-images)) "]; |
| 208 | +var shuffled = allImages.sort(function() { return 0.5 - Math.random(); }); |
| 209 | +var container = document.getElementById('hero-images'); |
| 210 | +shuffled.slice(0, 6).forEach(function(img) { |
| 211 | + var el = document.createElement('img'); |
| 212 | + el.src = './images/' + img; |
| 213 | + el.alt = ''; |
| 214 | + el.loading = 'lazy'; |
| 215 | + el.style.cursor = 'pointer'; |
| 216 | + el.onclick = function() { openLightbox(this.src, this.alt); }; |
| 217 | + container.appendChild(el); |
| 218 | +}); |
| 219 | +function openLightbox(src, alt) { |
| 220 | + var lb = document.getElementById('lightbox'); |
| 221 | + document.getElementById('lightbox-img').src = src; |
| 222 | + lb.classList.add('active'); |
| 223 | + document.body.style.overflow = 'hidden'; |
| 224 | +} |
| 225 | +function closeLightbox() { |
| 226 | + document.getElementById('lightbox').classList.remove('active'); |
| 227 | + document.body.style.overflow = ''; |
| 228 | +} |
| 229 | +document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeLightbox(); }); |
| 230 | +"))] |
| 231 | + [:div#lightbox {:onclick "closeLightbox()"} |
| 232 | + [:img#lightbox-img]]))) |
206 | 233 |
|
207 | 234 | ;; --- Gallery page --- |
208 | 235 |
|
|
0 commit comments