Skip to main content

New Commit: Switch reader to scroll mode with page markers Replaces the old single-page/page-flip reader engine with a new continuous-scroll marker script that estimates pages by word count and tracks the active page while scrolling. Updates the reader template to default to `mode-scroll`, removes page-flip mode controls and related footer UI, and switches script loading from `read-single.js` to `read-scroll-markers.js`. Also adds CSS for inline page markers and a utility script to apply the template updates.

Repository: Hestenb62/_legacy_backup

Author: Hesten Berger

Commit Message: Switch reader to scroll mode with page markers Replaces the old single-page/page-flip reader engine with a new continuous-scroll marker script that estimates pages by word count and tracks the active page while scrolling. Updates the reader template to default to , removes page-flip mode controls and related footer UI, and switches script loading from to . Also adds CSS for inline page markers and a utility script to apply the template updates.

URL: https://github.com/Hestenb62/_legacy_backup/commit/45612163a0e1b29ed38f54628e87ead2627f420f

Code Changes:

diff --git a/assets/css/reader-main.css b/assets/css/reader-main.css
index a4e57e8..4bfc6cc 100644
--- a/assets/css/reader-main.css
+++ b/assets/css/reader-main.css
@@ -12,4 +12,33 @@
 @import url('./reader/read-reader-academic-citation-modal.css');
 @import url('./reader/read-book-sourcing-information-moda.css');
 @import url('./reader/read-responsive-breakpoints-for-rea.css');
-@import url('./reader/read-realistic-single.css');
\ No newline at end of file
+@import url('./reader/read-realistic-single.css');
+/* Inline Page Markers for Scroll Mode */
+.inline-page-marker {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin: 3rem 0;
+    opacity: 0.7;
+    user-select: none;
+}
+
+.inline-page-marker .marker-line {
+    flex-grow: 1;
+    border: none;
+    border-top: 1px solid var(--color-border);
+    margin: 0;
+}
+
+.inline-page-marker .marker-pill {
+    margin: 0 1rem;
+    font-size: 0.8rem;
+    text-transform: uppercase;
+    letter-spacing: 2px;
+    color: var(--color-text-muted);
+    background: var(--color-bg-surface);
+    padding: 0.25rem 1rem;
+    border-radius: 1rem;
+    border: 1px solid var(--color-border);
+}
+
diff --git a/assets/js/reader/read-scroll-markers.js b/assets/js/reader/read-scroll-markers.js
new file mode 100644
index 0000000..722d342
--- /dev/null
+++ b/assets/js/reader/read-scroll-markers.js
@@ -0,0 +1,72 @@
+/**
+ * assets/js/reader/read-scroll-markers.js
+ * Continuous scroll mode engine with inline page markers.
+ */
+document.addEventListener("DOMContentLoaded", () => {
+    const bookContent = document.getElementById("book-content");
+    if (!bookContent) return;
+
+    const WORDS_PER_PAGE = 250;
+    let wordTally = 0;
+    let currentPage = 1;
+
+    // Traverse the content to inject markers
+    // We only want to inject markers BETWEEN block-level elements (paragraphs, blockquotes, etc)
+    const blockElements = Array.from(bookContent.children);
+    
+    // We start at page 1 implicitly, so we don't need a marker at the very top.
+    
+    blockElements.forEach(element => {
+        // Count words in this block
+        const text = element.innerText || element.textContent || '';
+        const words = text.trim().split(/\s+/).filter(w => w.length > 0).length;
+        
+        wordTally += words;
+
+        // If this element pushed us over the word threshold for a page, inject a marker BEFORE it.
+        if (wordTally >= WORDS_PER_PAGE) {
+            currentPage++;
+            wordTally = 0; // Reset tally for the next page
+
+            const marker = document.createElement("div");
+            marker.className = "inline-page-marker";
+            marker.dataset.page = currentPage;
+            marker.innerHTML = `
+                <hr class="marker-line">
+                <span class="marker-pill">Page ${currentPage}</span>
+                <hr class="marker-line">
+            `;
+            
+            // Insert the marker before the current element
+            bookContent.insertBefore(marker, element);
+        }
+    });
+
+    window.TOTAL_READER_PAGES = currentPage;
+    window.CURRENT_READER_PAGE = 1; // Default to 1
+
+    // Setup IntersectionObserver to update CURRENT_READER_PAGE as user scrolls
+    const markers = document.querySelectorAll(".inline-page-marker");
+    if (markers.length > 0) {
+        const observer = new IntersectionObserver((entries) => {
+            // We want to know the highest page number that is currently above or crossing the viewport
+            // Actually, a simpler way is: find the last marker whose bounding client rect top is < window.innerHeight / 2
+            // IntersectionObserver is good, but tracking the "active" page might be easier with a scroll listener.
+        }, { threshold: 0 });
+        
+        // Use scroll event for more precise "current page" tracking
+        window.addEventListener("scroll", () => {
+            let activePage = 1;
+            const thresholdY = window.innerHeight / 3; // Top third of screen
+
+            markers.forEach(marker => {
+                const rect = marker.getBoundingClientRect();
+                if (rect.top <= thresholdY) {
+                    activePage = parseInt(marker.dataset.page, 10);
+                }
+            });
+            
+            window.CURRENT_READER_PAGE = activePage;
+        }, { passive: true });
+    }
+});
diff --git a/assets/js/reader/read-single.js b/assets/js/reader/read-single.js
deleted file mode 100644
index f7065da..0000000
--- a/assets/js/reader/read-single.js
+++ /dev/null
@@ -1,299 +0,0 @@
-    /* ==========================================================================
-       8. Single-Page Realistic Book Mode & Page-Flip Engine
-       ========================================================================== */
-    function initSinglePageBookMode(meta, prefsKey) {
-        const bookStage = document.getElementById("book-stage");
-        const bookFrame = document.getElementById("book-frame");
-        const bookViewport = document.getElementById("book-page-viewport");
-        const bookContent = document.getElementById("book-content");
-        const prevPageBtn = document.getElementById("book-page-prev-btn");
-        const nextPageBtn = document.getElementById("book-page-next-btn");
-        const pageIndicator = document.getElementById("book-page-indicator");
-        const readingTimePill = document.getElementById("book-reading-time-pill");
-        const scrubberTrack = document.getElementById("book-scrubber-track");
-        const scrubberFill = document.getElementById("book-scrubber-fill");
-        const toggleViewModeBtn = document.getElementById("toggle-view-mode-btn");
-
-        if (!bookContent || !bookViewport) return;
-
-        const VIEW_MODE_KEY = 'hesten_reader_view_mode';
-        let currentViewMode = 'book';
-        try {
-            const savedMode = localStorage.getItem(VIEW_MODE_KEY);
-            if (savedMode === 'scroll' || savedMode === 'book') {
-                currentViewMode = savedMode;
-            }
-        } catch (e) {}
-
-        let currentPage = 1;
-        let totalPages = 1;
-        let columnStride = 0;
-        let totalWordCount = 0;
-
-        // Standard Educational Grade-Level WPM Benchmark Mapper
-        function getGradeLevelWpm(gradeStr) {
-            if (!gradeStr) return 225;
-            const str = String(gradeStr).toLowerCase();
-            if (str.includes('k') || str.includes('1') || str.includes('2')) return 100;
-            if (str.includes('3') || str.includes('4')) return 135;
-            if (str.includes('5') || str.includes('6')) return 165;
-            if (str.includes('7') || str.includes('8')) return 195;
-            if (str.includes('9') || str.includes('10') || str.includes('11') || str.includes('12') || str.includes('high')) return 225;
-            if (str.includes('college') || str.includes('adult') || str.includes('advanced')) return 260;
-            return 225;
-        }
-
-        const gradeWpm = getGradeLevelWpm(meta.grade || 'Grades 9-12');
-
-        // Count words in chapter
-        function countWords() {
-            const text = bookContent.innerText || bookContent.textContent || '';
-            const words = text.trim().split(/\s+/).filter(w => w.length > 0);
-            totalWordCount = Math.max(1, words.length);
-        }
-        countWords();
-
-        function setViewMode(mode) {
-            currentViewMode = mode;
-            try {
-                localStorage.setItem(VIEW_MODE_KEY, mode);
-            } catch (e) {}
-
-            document.body.classList.remove('mode-book', 'mode-scroll');
-            document.body.classList.add(`mode-${mode}`);
-
-            if (toggleViewModeBtn) {
-                toggleViewModeBtn.innerHTML = mode === 'book' ? '<i class="fas fa-book-open"></i>' : '<i class="fas fa-scroll"></i>';
-                toggleViewModeBtn.title = mode === 'book' ? 'Switch to Continuous Scroll View' : 'Switch to Realistic Book Page-Flip View';
-            }
-
-            document.querySelectorAll('.settings-mode').forEach(btn => {
-                btn.classList.toggle('active', btn.dataset.mode === mode);
-            });
-
-            if (mode === 'book') {
-                recalculatePagination();
-                handleUrlHash();
-            } else {
-                bookContent.style.transform = '';
-                bookContent.style.columnWidth = '';
-                bookContent.style.columnGap = '';
-            }
-        }
-
-        function recalculatePagination() {
-            if (currentViewMode !== 'book') return;
-
-            const viewportWidth = bookViewport.clientWidth;
-            const viewportHeight = bookViewport.clientHeight;
-            if (viewportWidth <= 0 || viewportHeight <= 0) return;
-
-            const columnGap = 64; // matching CSS column-gap (4rem)
-            bookContent.style.columnWidth = `${viewportWidth}px`;
-            bookContent.style.columnGap = `${columnGap}px`;
-
-            const contentScrollWidth = bookContent.scrollWidth;
-            columnStride = viewportWidth + columnGap;
-            totalPages = Math.max(1, Math.ceil((contentScrollWidth + (columnGap / 2)) / columnStride));
-
-            if (currentPage > totalPages) {
-                currentPage = totalPages;
-            } else if (currentPage < 1) {
-                currentPage = 1;
-            }
-
-            window.CURRENT_READER_PAGE = currentPage;
-            window.TOTAL_READER_PAGES = totalPages;
-
-            updatePageDisplay(false);
-        }
-
-        function updatePageDisplay(animate = false, direction = 'forward') {
-            if (currentViewMode !== 'book') return;
-
-            const offset = (currentPage - 1) * columnStride;
-            bookContent.style.transform = `translateX(-${offset}px)`;
-
-            if (pageIndicator) {
-                pageIndicator.innerHTML = `<i class="fas fa-file-alt"></i> Page ${currentPage} of ${totalPages}`;
-            }
-
-            if (readingTimePill) {
-                const wordsRemaining = Math.max(0, Math.round(totalWordCount * ((totalPages - currentPage) / totalPages)));
-                const minutesRemaining = Math.ceil(wordsRemaining / gradeWpm);
-                const timeText = minutesRemaining <= 1 ? '< 1 min left' : `~${minutesRemaining} min left`;
-                readingTimePill.innerHTML = `<i class="fas fa-clock"></i> ${timeText}`;
-                readingTimePill.title = `Estimated time remaining at ${gradeWpm} WPM (${meta.grade || 'Grades 9-12'} pace)`;
-            }
-
-            if (scrubberFill) {
-                const pct = totalPages > 1 ? Math.round(((currentPage - 1) / (totalPages - 1)) * 100) : 100;
-                scrubberFill.style.width = `${pct}%`;
-            }
-
-            if (prevPageBtn) {
-                prevPageBtn.disabled = currentPage <= 1;
-                prevPageBtn.classList.toggle('disabled', currentPage <= 1);
-            }
-            if (nextPageBtn) {
-                nextPageBtn.disabled = currentPage >= totalPages;
-                nextPageBtn.classList.toggle('disabled', currentPage >= totalPages);
-            }
-
-            if (animate && bookFrame) {
-                const animClass = direction === 'forward' ? 'flip-forward' : 'flip-backward';
-                bookFrame.classList.remove('flip-forward', 'flip-backward');
-                void bookFrame.offsetWidth;
-                bookFrame.classList.add(animClass);
-                setTimeout(() => {
-                    bookFrame.classList.remove(animClass);
-                }, 420);
-            }
-        }
-
-        function goToPage(targetPage, updateHash = true, animate = true, direction = null) {
-            const clamped = Math.max(1, Math.min(targetPage, totalPages));
-            if (clamped === currentPage && !animate) return;
-
-            const dir = direction || (clamped >= currentPage ? 'forward' : 'backward');
-            currentPage = clamped;
-            window.CURRENT_READER_PAGE = currentPage;
-
-            updatePageDisplay(animate, dir);
-
-            if (updateHash) {
-                const targetHash = `#page-${currentPage}`;
-                if (window.location.hash !== targetHash) {
-                    history.pushState(null, '', targetHash);
-                }
-            }
-        }
-
-        function handleUrlHash() {
-            const hash = window.location.hash;
-            if (hash && /^#page-\d+$/i.test(hash)) {
-                const pageNum = parseInt(hash.replace('#page-', ''), 10);
-                if (!isNaN(pageNum) && pageNum >= 1) {

Popular Posts

New Commit: fixed theme issues

Repository: Hestenb62/_legacy_backup Author: Hesten Berger Commit Message: fixed theme issues URL: https://github.com/Hestenb62/_legacy_backup/commit/498741f8c633ecaf6e7e594bb0aed02c47e69b39 Code Changes: diff --git a/assessment/index.php b/assessment/index.php index 822865b..5e8b706 100644 --- a/assessment/index.php +++ b/assessment/index.php @@ -264,7 +264,7 @@ include '../src/header.php'; </div> <!-- Hint Modal (Inline) --> - <div id="hintText" class="hint-box" style="display: none;"> + <div id="hintText" class="hint-box hidden"> <strong>Hint:</strong> <span id="hint-content"></span> </div> </div> diff --git a/assets/css/pages/assessment.css b/assets/css/pages/assessment.css index b57e964..7eb0d74 100644 --- a/assets/c...

New Commit: added arura mesh

Repository: Hestenb62/_legacy_backup Author: Hesten Berger Commit Message: added arura mesh URL: https://github.com/Hestenb62/_legacy_backup/commit/d8a9c63f2df943f6e40651985fb1c273c5809dd4 Code Changes: diff --git a/assets/css/level-style.css b/assets/css/level-style.css index ed8b60b..49cddf7 100644 --- a/assets/css/level-style.css +++ b/assets/css/level-style.css @@ -100,6 +100,8 @@ h1, h2, h3, h4 { padding: 4rem 1rem 3rem 1rem; background: linear-gradient(180deg, var(--bg-secondary) 0%, var(--bg-primary) 100%); border-bottom: 1px solid var(--glass-border); + position: relative; + overflow: hidden; } .hero-inner { @@ -111,6 +113,78 @@ h1, h2, h3, h4 { flex-wrap: wrap; gap: 1.5rem; animation: fadeUp 0.6s ease-out; + position: relative; + z-index: 2; +} + +/* Aurora Mesh Background for Level Hero */ +.level-aurora-bg { + position: absolute; + inset: 0; + overflow: hidden; + pointer-events: none; + z-index: 1; +} + +....

New Commit: Add JSON lesson migration and renderer scaffold Introduces a first-pass migration pipeline from PHP lesson files to structured JSON with `migrate_lessons.php`, and adds a generated `assets/data/lessons.json` catalog containing extracted metadata plus manual-migration placeholders for complex interactive content. Adds a new universal `src/lesson_renderer.php` to render lessons from JSON, along with initial component templates (`interactive-ladder` and `teacher-concepts`) for modular block rendering. Also includes `audit_report.html` documenting current security, accessibility, and architecture findings that motivated the move toward a template-driven lesson system.

Repository: Hestenb62/_legacy_backup Author: Hesten Berger Commit Message: Add JSON lesson migration and renderer scaffold Introduces a first-pass migration pipeline from PHP lesson files to structured JSON with , and adds a generated catalog containing extracted metadata plus manual-migration placeholders for complex interactive content. Adds a new universal to render lessons from JSON, along with initial component templates ( and ) for modular block rendering. Also includes documenting current security, accessibility, and architecture findings that motivated the move toward a template-driven lesson system. URL: https://github.com/Hestenb62/_legacy_backup/commit/f0c974b613ed65b7edcb712abb88bfae61ef0df5 Code Changes: diff --git a/assets/data/lessons.json b/assets/data/lessons.json new file mode 100644 index 0000000..0389666 --- /dev/null +++ b/assets/data/lessons.json @@ -0,0 +1,2835 @@ +{ + "lessons": { + "k-ela-m1-a-1": { + ...