migrate stage build to native elc; chat restores from localStorage on return
Build pipeline - build-stage.sh replaces the old in-Dockerfile bootstrap.py path. Host pre-compiles src/*.el into dist/main.c via the canonical native elc at foundation/el/dist/platform/elc and applies the stub-decl sed before docker buildx runs. - Dockerfile.stage drops bootstrap.py + python3 from the builder stage and just runs cc on the host-supplied dist/main.c. - Pre-rendered HTML shells under /srv/landing/ are now chowned to the landing user so the El page-builder's fs_write at startup can rewrite them — without that, post-COPY edits never reach the served HTML and the served page stays as the stale build-time fallback. Chat restore - session.verified + session.verifiedAt persist through localStorage so a return visit within 24h skips the Turnstile gate and lands directly in the restored conversation. - restoreOrGreet() is the single source of truth for what shows up in the message pane after the gate clears: replays prior messages with skipSave, else drops the canned hello once and remembers it. - applyVerifiedDom() hides the gate / reveals the chat row, called both from the verified-on-load path (DOMContentLoaded if loading, else immediate) and from the Turnstile callback. - neuronDemoReset clears verified + verifiedAt so the gate returns next open. Extracted JS assets (src/assets/js/*.js + manifest.json) and the extract-js.py helper land here too — they match what the new build-stage flow produces and removes the inline <script> blobs from the served HTML.
This commit is contained in:
+1
-77
@@ -185,83 +185,7 @@ body::before {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
// Nav scroll effect
|
||||
var nav = document.getElementById('nav');
|
||||
if (nav) window.addEventListener('scroll', function() {
|
||||
nav.classList.toggle('scrolled', window.scrollY > 10);
|
||||
}, { passive: true });
|
||||
|
||||
// Hamburger
|
||||
var btn = document.getElementById('nav-hamburger');
|
||||
var menu = document.getElementById('nav-mobile');
|
||||
if (btn && menu) {
|
||||
function navClose() { menu.classList.remove('open'); btn.setAttribute('aria-expanded','false'); }
|
||||
function navOpen() { menu.classList.add('open'); btn.setAttribute('aria-expanded','true'); }
|
||||
btn.addEventListener('click', function(e) { e.stopPropagation(); menu.classList.contains('open') ? navClose() : navOpen(); });
|
||||
menu.querySelectorAll('a').forEach(function(a) { a.addEventListener('click', navClose); });
|
||||
document.addEventListener('click', function(e) { if (!nav.contains(e.target)) navClose(); });
|
||||
document.addEventListener('keydown', function(e) { if (e.key === 'Escape') navClose(); });
|
||||
window.addEventListener('resize', function() { if (window.innerWidth > 1060) navClose(); });
|
||||
}
|
||||
|
||||
// Dropdown - Mission
|
||||
var ddBtn = document.querySelector('.nav-dropdown-btn');
|
||||
var dd = document.querySelector('.nav-dropdown');
|
||||
if (ddBtn && dd) {
|
||||
ddBtn.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
var isOpen = dd.classList.contains('open');
|
||||
dd.classList.toggle('open');
|
||||
ddBtn.setAttribute('aria-expanded', isOpen ? 'false' : 'true');
|
||||
});
|
||||
dd.querySelectorAll('.nav-dropdown-item').forEach(function(a) { a.addEventListener('click', function() { dd.classList.remove('open'); }); });
|
||||
document.addEventListener('click', function() { dd.classList.remove('open'); });
|
||||
}
|
||||
|
||||
// Search
|
||||
var searchEl = document.getElementById('gal-search');
|
||||
var grid = document.getElementById('gallery-grid');
|
||||
var noResults = document.getElementById('no-results');
|
||||
|
||||
function filterCards() {
|
||||
var q = (searchEl.value || '').toLowerCase().trim();
|
||||
var cards = grid.querySelectorAll('.gal-card');
|
||||
var visible = 0;
|
||||
cards.forEach(function(c) {
|
||||
var text = c.textContent.toLowerCase();
|
||||
var match = !q || text.indexOf(q) !== -1;
|
||||
c.classList.toggle('hidden', !match);
|
||||
if (match) visible++;
|
||||
});
|
||||
noResults.style.display = visible === 0 && q ? 'block' : 'none';
|
||||
}
|
||||
|
||||
if (searchEl) searchEl.addEventListener('input', filterCards);
|
||||
|
||||
// Sort
|
||||
var currentSort = 'top';
|
||||
window.setSort = function(mode, btn) {
|
||||
document.querySelectorAll('.sort-btn').forEach(function(b){ b.classList.remove('active'); });
|
||||
btn.classList.add('active');
|
||||
currentSort = mode;
|
||||
var cards = Array.from(grid.querySelectorAll('.gal-card'));
|
||||
cards.sort(function(a, b) {
|
||||
if (mode === 'top') {
|
||||
var aV = parseInt(a.getAttribute('data-score') || '0');
|
||||
var bV = parseInt(b.getAttribute('data-score') || '0');
|
||||
return bV - aV;
|
||||
} else {
|
||||
var aT = parseInt(a.getAttribute('data-ts') || '0');
|
||||
var bT = parseInt(b.getAttribute('data-ts') || '0');
|
||||
return bT - aT;
|
||||
}
|
||||
});
|
||||
cards.forEach(function(c){ grid.appendChild(c); });
|
||||
};
|
||||
})();
|
||||
</script>
|
||||
<script src=\"/assets/js/cd30551e3c3b.js\" defer></script>
|
||||
</body>
|
||||
</html>"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user