diff --git a/src/components/MemoryGraphBlock/index.js b/src/components/MemoryGraphBlock/index.js index 5723ab6..29fdb15 100644 --- a/src/components/MemoryGraphBlock/index.js +++ b/src/components/MemoryGraphBlock/index.js @@ -1,48 +1,24 @@ -import React, { useMemo } from 'react'; +import React from 'react'; import MDXComponents from '@theme-original/MDXComponents'; +import MemoryGraphHeader from '@site/src/components/MemoryGraphHeader'; import styles from './styles.module.css'; -const MEMORY_GRAPH_BASE_URL = 'https://memory-graph.com/'; - /** - * Wraps a ```lang debug code block with a header bar linking out to - * Bas Terwijn's Memory Graph web debugger (memory-graph.com), so students - * can step through the exact snippet from the lesson and watch variables/ - * references change line by line. - * - * Unlike InteractivePython, this doesn't replace the block with an editor — - * the theme's normal
still renders (syntax highlighting, copy button,
- * line numbers all keep working). We just read the raw code to build a
- * deep link and drop a button above it.
+ * Wraps a ```lang debug (debug-only) code block: a flush MemoryGraphHeader
+ * sitting directly on top of the theme's normal , so syntax
+ * highlighting and the built-in copy button keep working.
*
- * Memory Graph reads code from a URL *fragment* (`#code=...`), not a query
- * string — that's deliberate on their end, it means the code never gets
- * sent to their server, it's only ever interpreted client-side once the
- * page loads. Don't "fix" this to `?code=`.
+ * For ```lang interactive debug (both keywords), MDXComponents renders
+ * MemoryGraphHeader directly above InteractivePython instead, skipping
+ * this component entirely — see src/theme/MDXComponents.js.
*/
export default function MemoryGraphBlock(props) {
- const { children } = props;
- const rawCode = children?.props?.children?.trim() || '';
-
- const memoryGraphUrl = useMemo(
- () => `${MEMORY_GRAPH_BASE_URL}#code=${encodeURIComponent(rawCode)}`,
- [rawCode]
- );
+ const rawCode = props.children?.props?.children || '';
return (
);
-}
\ No newline at end of file
+}
diff --git a/src/components/MemoryGraphBlock/styles.module.css b/src/components/MemoryGraphBlock/styles.module.css
index 2e00a02..9963a66 100644
--- a/src/components/MemoryGraphBlock/styles.module.css
+++ b/src/components/MemoryGraphBlock/styles.module.css
@@ -1,64 +1,7 @@
-/* ==========================================================================
- Reuses the site's existing purple accent (see .alert--explore in
- custom.css) so "debug" blocks read as their own category, distinct
- from the blue InteractivePython header.
- ========================================================================== */
.wrapper {
margin: 1.5rem 0;
}
-.header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- flex-wrap: wrap;
- gap: 12px;
- padding: 10px 16px;
- background-color: rgba(124, 58, 237, 0.08);
- border: 1px solid rgba(124, 58, 237, 0.35);
- border-bottom: none;
- border-radius: var(--ifm-global-radius) var(--ifm-global-radius) 0 0;
-}
-
-[data-theme='dark'] .header {
- background-color: rgba(168, 85, 247, 0.15);
- border-color: rgba(216, 180, 254, 0.3);
-}
-
-.headerText {
- font-family: var(--ifm-font-family-base, sans-serif);
- font-weight: 600;
- font-size: 0.85rem;
- letter-spacing: 0.05rem;
- text-transform: uppercase;
- color: #7c3aed;
-}
-
-[data-theme='dark'] .headerText {
- color: #e9d5ff;
-}
-
-.openButton {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- padding: 6px 14px;
- border-radius: 6px;
- background-color: #7c3aed;
- color: #ffffff !important; /* override Docusaurus's default link color */
- font-family: var(--ifm-font-family-base, sans-serif);
- font-weight: 600;
- font-size: 0.85rem;
- text-decoration: none !important;
- white-space: nowrap;
- transition: background-color 0.15s ease;
-}
-
-.openButton:hover {
- background-color: #6d28d9;
- color: #ffffff !important;
-}
-
/* Butt the code block directly against the header — no gap, no double border */
.wrapper :global(.theme-code-block) {
margin-top: 0 !important;
@@ -66,10 +9,3 @@
border-top-right-radius: 0 !important;
border-top: none !important;
}
-
-@media (max-width: 480px) {
- .header {
- justify-content: center;
- text-align: center;
- }
-}
\ No newline at end of file
diff --git a/src/components/MemoryGraphHeader/index.js b/src/components/MemoryGraphHeader/index.js
new file mode 100644
index 0000000..c89e92f
--- /dev/null
+++ b/src/components/MemoryGraphHeader/index.js
@@ -0,0 +1,37 @@
+import React, { useMemo } from 'react';
+import styles from './styles.module.css';
+
+const MEMORY_GRAPH_BASE_URL = 'https://memory-graph.com/';
+
+/**
+ * Purple header bar linking a code snippet out to Bas Terwijn's Memory
+ * Graph web debugger (memory-graph.com). This is just the bar + link —
+ * it doesn't render the code itself, so it can sit above either a plain
+ * (```lang debug, via MemoryGraphBlock) or InteractivePython's
+ * editable sandbox (```lang interactive debug, via MDXComponents).
+ *
+ * `code` is the raw (untrimmed is fine) source string; `flush` squares
+ * off the bottom edge and drops the outer margin so it butts directly
+ * against whatever renders right beneath it, instead of floating as its
+ * own rounded pill.
+ */
+export default function MemoryGraphHeader({ code, flush = false }) {
+ const memoryGraphUrl = useMemo(
+ () => `${MEMORY_GRAPH_BASE_URL}#code=${encodeURIComponent((code || '').trim())}`,
+ [code]
+ );
+
+ return (
+
+ Debug Mode
+
+ View on Memory Graph ↗
+
+
+ );
+}
diff --git a/src/components/MemoryGraphHeader/styles.module.css b/src/components/MemoryGraphHeader/styles.module.css
new file mode 100644
index 0000000..d99077b
--- /dev/null
+++ b/src/components/MemoryGraphHeader/styles.module.css
@@ -0,0 +1,72 @@
+/* ==========================================================================
+ Reuses the site's existing purple accent (see .alert--explore in
+ custom.css) so "debug" blocks read as their own category, distinct
+ from the blue InteractivePython header.
+ ========================================================================== */
+.header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ gap: 12px;
+ margin: 1.5rem 0 0.5rem;
+ padding: 10px 16px;
+ background-color: rgba(124, 58, 237, 0.08);
+ border: 1px solid rgba(124, 58, 237, 0.35);
+ border-radius: var(--ifm-global-radius);
+}
+
+[data-theme='dark'] .header {
+ background-color: rgba(168, 85, 247, 0.15);
+ border-color: rgba(216, 180, 254, 0.3);
+}
+
+/* Flush mode: sits directly on top of a following block (a plain
+ via MemoryGraphBlock) — squared-off bottom, no gap beneath it. The
+ parent wrapper supplies the outer margin instead. */
+.header.flush {
+ margin: 0;
+ border-bottom: none;
+ border-radius: var(--ifm-global-radius) var(--ifm-global-radius) 0 0;
+}
+
+.headerText {
+ font-family: var(--ifm-font-family-base, sans-serif);
+ font-weight: 600;
+ font-size: 0.85rem;
+ letter-spacing: 0.05rem;
+ text-transform: uppercase;
+ color: #7c3aed;
+}
+
+[data-theme='dark'] .headerText {
+ color: #e9d5ff;
+}
+
+.openButton {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 6px 14px;
+ border-radius: 6px;
+ background-color: #7c3aed;
+ color: #ffffff !important; /* override Docusaurus's default link color */
+ font-family: var(--ifm-font-family-base, sans-serif);
+ font-weight: 600;
+ font-size: 0.85rem;
+ text-decoration: none !important;
+ white-space: nowrap;
+ transition: background-color 0.15s ease;
+}
+
+.openButton:hover {
+ background-color: #6d28d9;
+ color: #ffffff !important;
+}
+
+@media (max-width: 480px) {
+ .header {
+ justify-content: center;
+ text-align: center;
+ }
+}
diff --git a/src/theme/MDXComponents.js b/src/theme/MDXComponents.js
index 7e13a98..ee3698f 100644
--- a/src/theme/MDXComponents.js
+++ b/src/theme/MDXComponents.js
@@ -1,17 +1,29 @@
import MDXComponents from '@theme-original/MDXComponents';
import InteractivePython from '@site/src/components/InteractivePython';
import MemoryGraphBlock from '@site/src/components/MemoryGraphBlock';
+import MemoryGraphHeader from '@site/src/components/MemoryGraphHeader';
export default {
...MDXComponents,
// We wrap the standard 'pre' tag (which wraps code blocks)
pre: (props) => {
const metastring = props.children?.props?.metastring || '';
+ const isInteractive = metastring.includes('interactive');
+ const isDebug = metastring.includes('debug');
- if (metastring.includes('interactive')) {
+ if (isInteractive && isDebug) {
+ const rawCode = props.children?.props?.children || '';
+ return (
+ <>
+
+
+ >
+ );
+ }
+ if (isInteractive) {
return ;
}
- if (metastring.includes('debug')) {
+ if (isDebug) {
return ;
}
return ;