diff --git a/.gitignore b/.gitignore index 13fb01a..f622d69 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,7 @@ x86-ubuntu-gpu-ml-isca.gz build/ *.DS_Store + +# node_modules +node_modules/ +package-lock.json diff --git a/marp-custom-engine.js b/marp-custom-engine.js new file mode 100644 index 0000000..c0dcc97 --- /dev/null +++ b/marp-custom-engine.js @@ -0,0 +1,35 @@ +const { Marp } = require('@marp-team/marp-core'); + +// Define your variables here +const variables = { + BOOTCAMP_WEBSITE: "https://gem5bootcamp.gem5.org/", + BOOTCAMP_ARCHIVE: "https://gem5bootcamp.github.io/2024", + GITHUB_REPO: "https://github.com/gem5bootcamp/2024", + GITHUB_CLASSROOM: "https://classroom.github.com/a/gCcXlgBs", + GEM5_CODE: "https://github.com/gem5/gem5", + GEM5_WEBSITE: "https://www.gem5.org/", + GEM5_YOUTUBE: "https://youtube.com/@gem5", + GEM5_SLACK: "https://gem5-workspace.slack.com/join/shared_invite/zt-2e2nfln38-xsIkN1aRmofRlAHOIkZaEA" +}; + +// Function to replace placeholders with actual values in the markdown content +function replaceVariables(content) { + let updatedContent = content.toString(); // Ensure content is a string + for (const [key, value] of Object.entries(variables)) { + const placeholder = `{{${key}}}`; + const regex = new RegExp(placeholder, 'g'); + updatedContent = updatedContent.replace(regex, value); + } + return updatedContent; +} + +// Custom Marp engine class +class CustomMarpEngine extends Marp { + // Override the render method to preprocess Markdown content + render(markdown, options = {}) { + const processedMarkdown = replaceVariables(markdown); // Replace placeholders + return super.render(processedMarkdown, options); // Call Marp's render method + } +} + +module.exports = CustomMarpEngine; diff --git a/package.json b/package.json new file mode 100644 index 0000000..d265396 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "@marp-team/marp-cli": "^4.0.3", + "fs": "^0.0.1-security" + } +} diff --git a/slides/01-Introduction/00-introduction-to-bootcamp.md b/slides/01-Introduction/00-introduction-to-bootcamp.md index 4a8b217..a28e270 100644 --- a/slides/01-Introduction/00-introduction-to-bootcamp.md +++ b/slides/01-Introduction/00-introduction-to-bootcamp.md @@ -14,9 +14,9 @@ author: Jason Lowe-Power ## About the overall structure of the bootcamp -These slides and are available at for you to follow along. +These slides and are available at {{BOOTCAMP_WEBSITE}} for you to follow along. -(Note: They will be archived at ) +(Note: They will be archived at {{GITHUB_REPO}}) The source for the slides, and what you'll be using throughout the bootcamp can be found on github at diff --git a/web/app.js b/web/app.js index 8fac595..96a0404 100644 --- a/web/app.js +++ b/web/app.js @@ -5,6 +5,10 @@ const pdf_url_base = './pdf/' const pdf_url_ext = '.pdf' const slide_link_height = 25; +/* Button Names variables */ +SHOW_SOLUTION_BUTTON_TEXT = "Show Solution"; +HIDE_SOLUTION_BUTTON_TEXT = "Hide Solution"; + /* Global references and variables */ let slide_list = []; let slide_id = -1; @@ -119,6 +123,138 @@ function sidebar_category_onclick(e) { slides.style.height = `${height}px`; } +/* ========================================================================= * + * Copy functionality + * ========================================================================= */ +function addCopyButtonsInIframe() { + let frame = document.querySelector('#slideFrame'); + if (!frame) { + console.error("Error: #slideFrame element not found."); + return; + } + + // Function to insert copy buttons in blocks inside the iframe + const insertCopyButtons = () => { + const frame = document.querySelector('#slideFrame'); + const codeBlocks = frame.contentDocument.querySelectorAll('marp-pre code'); + + codeBlocks.forEach((block) => { + if (block.parentElement.querySelector('.copy-button')) return; // Avoid duplicates + + // Create the copy button element + let copyButton = document.createElement('button'); + copyButton.classList.add('copy-button'); + copyButton.innerHTML = ` + + + `; + + // Set the CSS position directly with JavaScript + copyButton.style.position = 'absolute'; + copyButton.style.top = '2px'; + copyButton.style.right = '2px'; + copyButton.style.background = 'none'; + copyButton.style.border = 'none'; + copyButton.style.padding = '4px'; + copyButton.style.cursor = 'pointer'; + copyButton.style.opacity = '0.7'; + + // Apply position to the container + block.parentElement.style.position = 'relative'; + + // Insert the copy button at the beginning of each element + block.parentElement.insertBefore(copyButton, block); + + // Add the copy functionality + copyButton.addEventListener('click', () => { + navigator.clipboard.writeText(block.innerText); + }); + }); + }; + + + // MutationObserver to detect changes within the iframe's content + const observer = new MutationObserver(insertCopyButtons); + + // Listen for when the iframe content loads + frame.addEventListener('load', () => { + // Observe the iframe's document for added blocks + observer.observe(frame.contentDocument.body, { childList: true, subtree: true }); + insertCopyButtons(); // Initial call for existing code blocks + }); +} + +// Run addCopyButtonsInIframe after the main DOM is fully loaded +document.addEventListener('DOMContentLoaded', addCopyButtonsInIframe); + +/* ========================================================================= * + * Hidden slides logic handeling + * ========================================================================= */ +function setupToggleButtons() { + const frame = document.querySelector('#slideFrame'); + + // Check if iframe exists and load content + if (frame) { + frame.addEventListener('load', () => { + const contentDoc = frame.contentDocument || frame.contentWindow.document; + + // Select all toggle buttons and toggle-content sections in the iframe + const toggleButtons = contentDoc.querySelectorAll('.toggle-button'); + const toggleContents = contentDoc.querySelectorAll('.toggle-content'); + + // Force initial hidden state for all toggle-content elements + toggleContents.forEach(content => { + content.style.display = 'none'; // Ensure they are hidden at the start + }); + + // Initialize each button's text to "Show Content" and add inline styles + toggleButtons.forEach(button => { + button.textContent = SHOW_SOLUTION_BUTTON_TEXT; + + // Apply inline styles to the toggle button + button.style.cursor = 'pointer'; + button.style.backgroundColor = '#007bff'; // Blue color + button.style.color = 'white'; + button.style.padding = '10px'; + button.style.border = 'none'; + button.style.borderRadius = '5px'; + button.style.fontSize = '16px'; + button.style.marginTop = '10px'; + + // Hover effect + button.addEventListener('mouseover', () => { + button.style.backgroundColor = '#0056b3'; // Darker blue on hover + }); + button.addEventListener('mouseout', () => { + button.style.backgroundColor = '#007bff'; // Original blue + }); + }); + + // Add click event listener to each toggle button + toggleButtons.forEach((button, index) => { + button.addEventListener('click', () => { + const content = toggleContents[index]; + if (content) { + // Toggle the display of the content + if (content.style.display === 'none') { + content.style.display = 'block'; + button.textContent = HIDE_SOLUTION_BUTTON_TEXT; + } else { + content.style.display = 'none'; + button.textContent = SHOW_SOLUTION_BUTTON_TEXT; + } + } + }); + }); + }); + } else { + console.error("Error: #slideFrame element not found."); + } +} + +// Run setupToggleButtons after the main DOM is fully loaded +document.addEventListener('DOMContentLoaded', setupToggleButtons); + /* ========================================================================= * * Relative Link to Git Translation !!TEMPORARY!! * ========================================================================= */