diff --git a/_brand/scripts/subscribe-modal.js b/_brand/scripts/subscribe-modal.js new file mode 100644 index 000000000..0749fcc45 --- /dev/null +++ b/_brand/scripts/subscribe-modal.js @@ -0,0 +1,587 @@ +/** + * Subscribe Modal Component + * Elegant popup subscription form for ML Systems Textbook + */ + +(function() { + 'use strict'; + + // Create modal HTML structure + function createModalHTML() { + return ` +
+ `; + } + + // Create modal CSS + function createModalCSS() { + const style = document.createElement('style'); + style.textContent = ` + /* Modal Overlay and Container */ + .modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(15, 23, 42, 0.6); + backdrop-filter: blur(4px); + z-index: 10001; + align-items: center; + justify-content: center; + padding: 1rem; + animation: fadeIn 0.2s ease; + } + + @keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } + } + + @keyframes slideUp { + from { + opacity: 0; + transform: translateY(20px) scale(0.98); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } + } + + .modal-container { + background: white; + border-radius: 16px; + max-width: 440px; + width: 100%; + max-height: 90vh; + overflow-y: auto; + position: relative; + box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1), 0 0 0 1px rgba(0,0,0,0.05); + animation: slideUp 0.3s ease; + margin: auto; + } + + .modal-close { + position: absolute; + top: 1rem; + right: 1rem; + width: 36px; + height: 36px; + border: none; + background: #f8fafc; + border-radius: 50%; + font-size: 1.5rem; + color: #64748b; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + z-index: 10; + line-height: 1; + } + + .modal-close:hover { + background: white; + color: #0f172a; + transform: scale(1.05); + } + + .modal-content { + padding: 2rem 2.5rem 2.5rem 2.5rem; + } + + .modal-header { + text-align: center; + margin-bottom: 1.5rem; + display: flex; + flex-direction: column; + align-items: center; + } + + .modal-brand-row { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + margin-bottom: 1rem; + } + + .modal-brand-item { + font-size: 0.8rem; + font-weight: 600; + color: #374151; + background: #f3f4f6; + padding: 0.3rem 0.6rem; + border-radius: 5px; + white-space: nowrap; + } + + .modal-brand-plus { + font-size: 0.9rem; + font-weight: 300; + color: #9ca3af; + } + + .modal-title { + font-size: 1.5rem; + font-weight: 700; + color: #0f172a; + margin: 0 0 0.4rem 0; + line-height: 1.2; + width: 100%; + } + + .modal-subtitle { + font-size: 0.9rem; + color: #64748b; + margin: 0; + line-height: 1.5; + max-width: 320px; + } + + /* Form Styles */ + .subscribe-form { + display: flex; + flex-direction: column; + gap: 1.25rem; + } + + .form-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.75rem; + } + + .form-row .form-group { + min-width: 0; + } + + .form-row .form-group input { + width: 100%; + box-sizing: border-box; + } + + .form-group { + display: flex; + flex-direction: column; + gap: 0.5rem; + } + + .form-group label { + font-size: 0.9rem; + font-weight: 600; + color: #0f172a; + } + + .optional-label { + font-weight: 400; + color: #64748b; + } + + .form-group input[type="text"], + .form-group input[type="email"], + .form-group textarea { + padding: 0.875rem 1rem; + border: 1px solid #cbd5e1; + border-radius: 8px; + font-size: 1rem; + transition: all 0.2s ease; + background: #f8fafc; + font-family: inherit; + } + + .form-group textarea { + resize: vertical; + min-height: 60px; + } + + .form-group input[type="text"]:focus, + .form-group input[type="email"]:focus, + .form-group textarea:focus { + outline: none; + border-color: #3b82f6; + background: white; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); + } + + .form-group input::placeholder, + .form-group textarea::placeholder { + color: #94a3b8; + } + + /* Role Options - compact style */ + .role-options { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.75rem; + } + + .role-options-three-compact { + grid-template-columns: repeat(3, 1fr); + } + + .role-option { + cursor: pointer; + } + + .role-option input[type="radio"] { + position: absolute; + opacity: 0; + width: 0; + height: 0; + } + + .role-label { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.75rem 1rem; + border: 2px solid #e2e8f0; + border-radius: 8px; + font-size: 0.9rem; + font-weight: 500; + color: #475569; + transition: all 0.2s ease; + background: #f8fafc; + } + + .role-options-three-compact .role-label { + padding: 0.625rem 0.5rem; + font-size: 0.8rem; + text-align: center; + } + + .role-option input[type="radio"]:checked + .role-label { + border-color: #3b82f6; + background: rgba(59, 130, 246, 0.08); + color: #3b82f6; + } + + .role-option:hover .role-label { + border-color: #cbd5e1; + background: white; + } + + /* Button Styles */ + .btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.75rem 1.5rem; + border-radius: 8px; + text-decoration: none; + font-weight: 600; + font-size: 0.95rem; + transition: all 0.2s ease; + border: none; + cursor: pointer; + font-family: inherit; + } + + .btn-primary { + background: #3b82f6; + color: white; + } + + .btn-primary:hover { + background: #1e3a8a; + transform: translateY(-1px); + box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); + } + + .subscribe-btn { + width: 100%; + padding: 1rem; + font-size: 1rem; + margin-top: 0.5rem; + } + + .form-note { + text-align: center; + font-size: 0.85rem; + color: #64748b; + margin: 0; + } + + /* Success Message */ + .subscribe-success { + text-align: center; + padding: 2rem 1rem; + } + + .success-icon { + font-size: 3rem; + margin-bottom: 1rem; + } + + .subscribe-success h3 { + font-size: 1.5rem; + font-weight: 600; + color: #0f172a; + margin-bottom: 0.5rem; + } + + .subscribe-success p { + color: #475569; + font-size: 1rem; + } + + /* Dark mode support */ + body.quarto-dark .modal-container { + background: #1e293b; + } + + body.quarto-dark .modal-close { + background: #0f172a; + color: #94a3b8; + } + + body.quarto-dark .modal-close:hover { + background: #334155; + color: #f1f5f9; + } + + body.quarto-dark .modal-brand-item { + background: #334155; + color: #e2e8f0; + } + + body.quarto-dark .modal-brand-plus { + color: #64748b; + } + + body.quarto-dark .modal-title, + body.quarto-dark .form-group label, + body.quarto-dark .subscribe-success h3 { + color: #f1f5f9; + } + + body.quarto-dark .modal-subtitle, + body.quarto-dark .subscribe-success p { + color: #cbd5e1; + } + + body.quarto-dark .form-group input[type="text"], + body.quarto-dark .form-group input[type="email"], + body.quarto-dark .form-group textarea { + background: #0f172a; + border-color: #334155; + color: #f1f5f9; + } + + body.quarto-dark .role-label { + background: #0f172a; + border-color: #334155; + color: #cbd5e1; + } + + body.quarto-dark .role-option input[type="radio"]:checked + .role-label { + border-color: #3b82f6; + background: rgba(59, 130, 246, 0.15); + color: #60a5fa; + } + + /* Responsive */ + @media (max-width: 640px) { + .modal-content { + padding: 2rem 1.5rem; + } + + .form-row { + grid-template-columns: 1fr; + } + + .role-options-three-compact { + grid-template-columns: repeat(3, 1fr); + } + } + `; + return style; + } + + // Initialize modal + function initModal() { + // Add CSS + document.head.appendChild(createModalCSS()); + + // Add HTML + const modalDiv = document.createElement('div'); + modalDiv.innerHTML = createModalHTML(); + document.body.appendChild(modalDiv.firstElementChild); + + const modal = document.getElementById('subscribe-modal'); + const form = document.getElementById('subscribe-modal-form'); + const success = document.getElementById('modal-subscribe-success'); + + // Open modal function + window.openModal = function() { + modal.style.display = 'flex'; + document.body.style.overflow = 'hidden'; + + // Focus first input + setTimeout(() => { + const firstInput = document.getElementById('modal-first-name'); + if (firstInput) firstInput.focus(); + }, 100); + }; + + // Close modal function + window.closeModal = function() { + modal.style.display = 'none'; + document.body.style.overflow = ''; + + // Reset form after closing + setTimeout(() => { + form.style.display = 'flex'; + form.reset(); + success.style.display = 'none'; + }, 300); + }; + + // Close on overlay click + modal.addEventListener('click', (e) => { + if (e.target === modal) { + closeModal(); + } + }); + + // Close button click + const closeBtn = modal.querySelector('[data-close-modal]'); + if (closeBtn) { + closeBtn.addEventListener('click', closeModal); + } + + // Close on Escape key + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && modal.style.display === 'flex') { + closeModal(); + } + }); + + // Handle form submission + form.addEventListener('submit', function() { + // Let the form submit to Buttondown + setTimeout(() => { + form.style.display = 'none'; + success.style.display = 'block'; + + // Close modal after 5 seconds + setTimeout(closeModal, 5000); + }, 100); + }); + + // Check if URL has #subscribe hash on page load - auto-open modal + if (window.location.hash === '#subscribe') { + // Small delay to ensure page is fully loaded + setTimeout(() => { + openModal(); + }, 300); + } + + // Also listen for hash changes (e.g., user clicks back/forward) + window.addEventListener('hashchange', function() { + if (window.location.hash === '#subscribe') { + openModal(); + } + }); + + // Intercept navbar subscribe link + setTimeout(() => { + // Look for subscribe links in navbar + const subscribeSelectors = [ + 'a[href*="buttondown.email/mlsysbook"]', + 'a[href="#subscribe"]', + 'a[href*="subscribe"]', + '#navbar-subscribe-btn', + '.subscribe-link' + ]; + + subscribeSelectors.forEach(selector => { + try { + const links = document.querySelectorAll(selector); + links.forEach(link => { + link.addEventListener('click', function(e) { + e.preventDefault(); + openModal(); + }); + }); + } catch (err) { + // Selector not supported, continue + } + }); + }, 1000); + } + + // Initialize when DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initModal); + } else { + initModal(); + } +})(); diff --git a/_brand/site.webmanifest b/_brand/site.webmanifest new file mode 100644 index 000000000..eb53da963 --- /dev/null +++ b/_brand/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Machine Learning Systems", + "short_name": "MLSysBook", + "description": "A comprehensive textbook on machine learning systems, covering hardware, software, and deployment.", + "start_url": "/book/", + "scope": "/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#A51C30", + "icons": [ + { + "src": "/assets/images/favicon.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any maskable" + } + ], + "categories": ["education", "books", "technology"] +} diff --git a/book/quarto/config/_quarto-html.yml b/book/quarto/config/_quarto-html.yml index b1b189791..96cca223c 100644 --- a/book/quarto/config/_quarto-html.yml +++ b/book/quarto/config/_quarto-html.yml @@ -543,6 +543,9 @@ format: + + + diff --git a/book/quarto/site.webmanifest b/book/quarto/site.webmanifest new file mode 100644 index 000000000..93a7fb8b6 --- /dev/null +++ b/book/quarto/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Machine Learning Systems Textbook", + "short_name": "MLSysBook", + "description": "A comprehensive textbook on machine learning systems, covering hardware, software, and deployment.", + "start_url": "/book/", + "scope": "/book/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#A51C30", + "icons": [ + { + "src": "assets/images/icons/favicon.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any maskable" + } + ], + "categories": ["education", "books", "technology"] +} diff --git a/collabs/404.qmd b/collabs/404.qmd new file mode 100644 index 000000000..3709eb2e5 --- /dev/null +++ b/collabs/404.qmd @@ -0,0 +1,31 @@ +--- +title: "Page Not Found" +--- + +# ๐ก Oops! Simulation Error 404 + +The page you're looking for seems to have drifted into an unexplored region of the parameter space... + +## ๐งญ **Navigation Help** + +**Quick Links:** + +- [๐ Return Home](/) +- [๐ Main Textbook](../book/) +- [๐ง Hardware Kits](../kits/) +- [๐ฅ TinyTorch](../tinytorch/) + +## ๐ **Search the Site** + +Use the search box in the navbar to find what you're looking for! + +## ๐ **Still Lost?** + +If you believe this is an error: + +- [๐ Report this issue](https://github.com/harvard-edge/cs249r_book/issues) on GitHub +- [๐ฌ Start a discussion](https://github.com/harvard-edge/cs249r_book/discussions) with the community + +--- + +*"In collaborative learning, getting lost is just the first step toward discovery!"* ๐งช diff --git a/collabs/assets/images/covers/cover-hardcover-book.png b/collabs/assets/images/covers/cover-hardcover-book.png new file mode 100644 index 000000000..e2adeb056 Binary files /dev/null and b/collabs/assets/images/covers/cover-hardcover-book.png differ diff --git a/collabs/config/_quarto-html.yml b/collabs/config/_quarto-html.yml index 81a19e6a6..adabafb04 100644 --- a/collabs/config/_quarto-html.yml +++ b/collabs/config/_quarto-html.yml @@ -19,12 +19,12 @@ website: open-graph: locale: en_US site-name: "Machine Learning Systems" - image: assets/images/favicon.png - image-width: 512 - image-height: 512 + image: assets/images/covers/cover-hardcover-book.png + image-width: 1200 + image-height: 630 twitter-card: - card-style: summary - image: assets/images/favicon.png + card-style: summary_large_image + image: assets/images/covers/cover-hardcover-book.png page-navigation: true reader-mode: false @@ -118,7 +118,8 @@ format: - assets/styles/style.scss - assets/styles/dark-mode.scss respect-user-color-scheme: true - toc: false + toc: true + toc-depth: 3 number-sections: false code-copy: true code-overflow: wrap @@ -131,6 +132,9 @@ format: + + + include-after-body: - text: | diff --git a/collabs/site.webmanifest b/collabs/site.webmanifest new file mode 100644 index 000000000..bb520ecdb --- /dev/null +++ b/collabs/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Co-Labs - ML Systems", + "short_name": "Co-Labs", + "description": "Interactive ML simulations and collaborative labs for exploring machine learning systems.", + "start_url": "/collabs/", + "scope": "/collabs/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#7D3C98", + "icons": [ + { + "src": "assets/images/favicon.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any maskable" + } + ], + "categories": ["education", "technology", "simulation"] +} diff --git a/kits/404.qmd b/kits/404.qmd new file mode 100644 index 000000000..d9844e354 --- /dev/null +++ b/kits/404.qmd @@ -0,0 +1,33 @@ +--- +title: "Page Not Found" +--- + +# ๐ง Oops! Hardware Error 404 + +The page you're looking for seems to have escaped the breadboard and is hiding somewhere in the circuit... + +## ๐งญ **Navigation Help** + +**Quick Links:** + +- [๐ Return Home](/) +- [๐ Getting Started](/contents/getting-started.html) +- [๐ฌ Arduino Nicla Vision](/contents/arduino/nicla_vision/nicla_vision.html) +- [๐ฑ Seeed XIAO ESP32S3](/contents/seeed/xiao_esp32s3/xiao_esp32s3.html) +- [๐๏ธ Grove Vision AI V2](/contents/seeed/grove_vision_ai_v2/grove_vision_ai_v2.html) +- [๐ Raspberry Pi](/contents/raspi/raspi.html) + +## ๐ **Search the Site** + +Use the search box in the sidebar or navbar to find what you're looking for! + +## ๐ **Still Lost?** + +If you believe this is an error: + +- [๐ Report this issue](https://github.com/harvard-edge/cs249r_book/issues) on GitHub +- [๐ฌ Start a discussion](https://github.com/harvard-edge/cs249r_book/discussions) with the community + +--- + +*"In hardware, there are no bugs, only unexpected features waiting to be debugged!"* ๐ diff --git a/kits/assets/images/covers/cover-hardcover-book.png b/kits/assets/images/covers/cover-hardcover-book.png new file mode 100644 index 000000000..e2adeb056 Binary files /dev/null and b/kits/assets/images/covers/cover-hardcover-book.png differ diff --git a/kits/config/_quarto-html.yml b/kits/config/_quarto-html.yml index 06beddc46..5cfa2ce96 100644 --- a/kits/config/_quarto-html.yml +++ b/kits/config/_quarto-html.yml @@ -19,12 +19,12 @@ website: open-graph: locale: en_US site-name: "Machine Learning Systems" - image: assets/images/favicon.png - image-width: 512 - image-height: 512 + image: assets/images/covers/cover-hardcover-book.png + image-width: 1200 + image-height: 630 twitter-card: - card-style: summary - image: assets/images/favicon.png + card-style: summary_large_image + image: assets/images/covers/cover-hardcover-book.png page-navigation: true reader-mode: false @@ -201,6 +201,9 @@ format: + + + include-after-body: - text: | diff --git a/kits/site.webmanifest b/kits/site.webmanifest new file mode 100644 index 000000000..62de2e5de --- /dev/null +++ b/kits/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Hardware Kits - ML Systems", + "short_name": "HW Kits", + "description": "Hands-on hardware labs and kits for machine learning systems education.", + "start_url": "/kits/", + "scope": "/kits/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#148F77", + "icons": [ + { + "src": "assets/images/favicon.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any maskable" + } + ], + "categories": ["education", "technology", "hardware"] +} diff --git a/tinytorch/site/404.md b/tinytorch/site/404.md new file mode 100644 index 000000000..21f5cd606 --- /dev/null +++ b/tinytorch/site/404.md @@ -0,0 +1,28 @@ +# ๐ฅ Oops! Torch Error 404 + +The page you're looking for seems to have vanished into the gradient descent and got stuck in a local minimum... + +## ๐งญ Navigation Help + +**Quick Links:** + +- [๐ Return Home](intro) +- [๐ Module 1: Foundations](modules/1_ABOUT) +- [๐๏ธ Module 2: Architecture](modules/2_ABOUT) +- [โก Module 3: Performance](modules/3_ABOUT) +- [๐ Main Textbook](../book/) + +## ๐ Search the Site + +Use the search box in the sidebar to find what you're looking for! + +## ๐ Still Lost? + +If you believe this is an error: + +- [๐ Report this issue](https://github.com/harvard-edge/cs249r_book/issues) on GitHub +- [๐ฌ Start a discussion](https://github.com/harvard-edge/cs249r_book/discussions) with the community + +--- + +*"In deep learning, every error is just a gradient pointing toward the right answer!"* ๐ง