Skip to content

Commit 8d189a6

Browse files
leifericfclaude
andcommitted
Add landing page: random hero images, lightbox, alpha banner
- Randomize hero images from all 62 examples on each page load - Fix inline script HTML escaping (angle brackets in JS) - Hero images clickable with lightbox - Early alpha disclaimer banner Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f5a6aa4 commit 8d189a6

2 files changed

Lines changed: 48 additions & 13 deletions

File tree

examples/site/render.clj

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@
1717
(def highlight-clj-js
1818
"function highlightClj(code) {
1919
// HTML-escape first
20-
code = code.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
20+
code = code.replace(/&/g, '&amp;').replace(/\\x3c/g, '&lt;').replace(/>/g, '&gt;');
2121
// Extract comments and strings into placeholders so they don't interfere
2222
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'; });
2525
// 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>');
2929
// Restore placeholders
3030
code = code.replace(/\\x00T(\\d+)T\\x00/g, function(_, i) { return tokens[parseInt(i)]; });
3131
return code;
@@ -173,15 +173,17 @@
173173
(defn generate-landing-html
174174
"Generates the landing page HTML."
175175
[examples-by-category]
176-
(let [hero-images (pages/hero-images)]
176+
(let [all-images (->> examples-by-category
177+
(mapcat :examples)
178+
(mapv :output))]
177179
(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."]
178182
[:section.hero
179183
[:h1.hero-title "Eido"]
180184
[: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]
185187
[:div.hero-links
186188
[:a.hero-link.hero-link--primary {:href "./gallery/index.html"} "Browse Gallery"]
187189
[:a.hero-link.hero-link--secondary {:href "./docs/index.html"} "Read the Docs"]]]
@@ -202,7 +204,32 @@
202204
document.querySelectorAll('pre code').forEach(function(el) {
203205
el.innerHTML = highlightClj(el.textContent);
204206
});
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]])))
206233

207234
;; --- Gallery page ---
208235

examples/site/styles.clj

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,15 @@
7979
:border-top (str "1px solid " (:border colors))
8080
:text-align "center"
8181
:color (:text-muted colors)
82-
:font-size "0.85rem"}]])
82+
:font-size "0.85rem"}]
83+
[:.alpha-banner {:text-align "center"
84+
:font-size "0.8rem"
85+
:color "#b0a070"
86+
:background "rgba(180, 160, 80, 0.08)"
87+
:border "1px solid rgba(180, 160, 80, 0.2)"
88+
:border-radius "6px"
89+
:padding "0.5rem 1rem"
90+
:margin-top "1rem"}]])
8391

8492
;; --- Hero (landing page) ---
8593

0 commit comments

Comments
 (0)