From 63ff7f83c56ab1319959f2baae97ebb9b1980bae Mon Sep 17 00:00:00 2001 From: Debbie Matthews Date: Sun, 7 Dec 2025 21:50:13 -0800 Subject: [PATCH 01/20] Fix code block copy button --- components/blocks/code.js | 49 ++++++++++++++++++++++++------- components/blocks/code.module.css | 10 ++++++- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/components/blocks/code.js b/components/blocks/code.js index a1b2780bf..db5595074 100644 --- a/components/blocks/code.js +++ b/components/blocks/code.js @@ -15,7 +15,14 @@ import styles from "./code.module.css"; // Initialize the cache for imported languages. const languageImports = new Map(); -const Code = ({ code, children, language, img, lines }) => { +const Code = ({ + code, + children, + language, + img, + lines, + hideCopyButton = false, +}) => { // Create a ref for the code element. const codeRef = useRef(null); @@ -49,9 +56,17 @@ const Code = ({ code, children, language, img, lines }) => { ); } } - // Only highlight the current code block. + // Highlight the code block and conditionally enable toolbar plugins (including copy button) if (codeRef.current) { + // First highlight the element Prism.highlightElement(codeRef.current); + // Then activate toolbar plugins on the parent container if copy button is not hidden + if (!hideCopyButton) { + const container = codeRef.current.closest(`.${styles.Container}`); + if (container) { + Prism.highlightAllUnder(container); + } + } } } } @@ -70,33 +85,45 @@ const Code = ({ code, children, language, img, lines }) => { if (img) { ConditionalRendering = ( -
+
-
+
           
             {customCode}
           
-        
+
); } else if (lines) { ConditionalRendering = ( -
-
+
+
           
             {customCode}
           
-        
+
); } else { ConditionalRendering = ( -
-
+
+
           
             {customCode}
           
-        
+
); } diff --git a/components/blocks/code.module.css b/components/blocks/code.module.css index ae115558e..c60a5d919 100644 --- a/components/blocks/code.module.css +++ b/components/blocks/code.module.css @@ -9,7 +9,11 @@ } .Pre { - @apply p-4 bg-gray-90 text-white font-medium rounded-md relative py-6 px-8 leading-relaxed; + @apply p-4 bg-gray-90 text-white font-medium rounded-md relative py-8 px-8 leading-relaxed; +} + +.Container pre { + @apply overflow-auto max-w-full whitespace-pre; } .Pre code { @@ -37,6 +41,10 @@ @apply opacity-100; } +.NoCopyButton button { + @apply hidden; +} + /* Code block adjustments */ .Pre code :global(.operator) { @apply text-yellow-50; From b92021531eba5908f60508adfc1835fc1acea3f5 Mon Sep 17 00:00:00 2001 From: Debbie Matthews Date: Mon, 8 Dec 2025 05:40:23 -0800 Subject: [PATCH 02/20] Add custom code style for RefCard --- components/blocks/refCard.module.css | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/components/blocks/refCard.module.css b/components/blocks/refCard.module.css index d82054611..70e4987b1 100644 --- a/components/blocks/refCard.module.css +++ b/components/blocks/refCard.module.css @@ -47,6 +47,10 @@ @apply p-4 pb-0 text-gray-90; } +.Container pre { + @apply px-1 pt-2.5 leading-loose; +} + :global(.dark) .Container { @apply border-gray-90; } @@ -150,12 +154,20 @@ } .Container section div { - @apply flex flex-col flex-1; - @apply m-0 rounded-none p-4 h-full text-sm tracking-tight; @apply bg-gray-10; @apply text-gray-80; } +.Container section div:not(:global(.toolbar)) { + @apply flex flex-col flex-1; + @apply m-0 rounded-none px-3 py-2 h-full text-sm tracking-tight; +} + +.Container section div:global(.toolbar), +.Container section div:global(.toolbar-item) { + @apply h-0 p-0; +} + /* Code block adjustments */ .Container section div code :global(.operator) { @apply text-yellow-90; From e64c19795e0516ee979dc329ae831341defa4476 Mon Sep 17 00:00:00 2001 From: Debbie Matthews Date: Mon, 8 Dec 2025 05:43:15 -0800 Subject: [PATCH 03/20] Change code blocks with theme --- components/blocks/autofunction.module.css | 14 ++++++++++++-- components/blocks/code.module.css | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/components/blocks/autofunction.module.css b/components/blocks/autofunction.module.css index f7b407c36..5ff6e96a6 100644 --- a/components/blocks/autofunction.module.css +++ b/components/blocks/autofunction.module.css @@ -64,7 +64,7 @@ } .CodeBlockContainer pre { - @apply p-4 bg-gray-90 text-white font-medium rounded-xl relative py-6 px-8 leading-relaxed; + @apply p-4 bg-gray-10 text-gray-80 font-medium rounded-xl relative leading-relaxed; } .CodeBlockContainer pre code { @@ -85,7 +85,7 @@ } .CodeBlockContainer button span { - @apply absolute right-10 text-white font-mono text-sm tracking-tight font-normal opacity-0; + @apply absolute right-10 text-gray-80 font-mono text-sm tracking-tight font-normal opacity-0; } .CodeBlockContainer button:hover span { @@ -175,3 +175,13 @@ :global(.dark) .Keyword::after { @apply bg-gray-80 text-gray-30; } + +/* Dark mode for code blocks */ +:global(.dark) .CodeBlockContainer pre { + @apply bg-gray-90 text-white; +} + +/* Dark mode button text */ +:global(.dark) .CodeBlockContainer button span { + @apply text-white; +} diff --git a/components/blocks/code.module.css b/components/blocks/code.module.css index c60a5d919..a32b00902 100644 --- a/components/blocks/code.module.css +++ b/components/blocks/code.module.css @@ -9,7 +9,7 @@ } .Pre { - @apply p-4 bg-gray-90 text-white font-medium rounded-md relative py-8 px-8 leading-relaxed; + @apply p-6 bg-gray-10 text-gray-80 font-medium rounded-md relative leading-relaxed; } .Container pre { @@ -34,7 +34,7 @@ } .Container button span { - @apply absolute right-10 text-white font-mono text-sm tracking-tight font-normal opacity-0; + @apply absolute right-10 text-gray-80 font-mono text-sm tracking-tight font-normal opacity-0; } .Container button:hover span { @@ -120,3 +120,13 @@ :global(.dark) .Pre code :global(.string) { @apply text-darkBlue-30; } + +/* Dark mode background and text for Pre */ +:global(.dark) .Pre { + @apply bg-gray-90 text-white; +} + +/* Dark mode button text */ +:global(.dark) .Container button span { + @apply text-white; +} From 426aba86909a612d46430c1a36cacf21256f03e3 Mon Sep 17 00:00:00 2001 From: Debbie Matthews Date: Mon, 8 Dec 2025 14:01:35 -0800 Subject: [PATCH 04/20] Unify syntax highlighting color; update light mode --- components/blocks/autofunction.module.css | 50 +--- components/blocks/code.module.css | 272 +------------------ components/blocks/codeTile.module.css | 32 +-- styles/main.scss | 1 + styles/syntax-highlighting.scss | 313 ++++++++++++++++++++++ 5 files changed, 317 insertions(+), 351 deletions(-) create mode 100644 styles/syntax-highlighting.scss diff --git a/components/blocks/autofunction.module.css b/components/blocks/autofunction.module.css index 5ff6e96a6..fcbec2131 100644 --- a/components/blocks/autofunction.module.css +++ b/components/blocks/autofunction.module.css @@ -92,55 +92,7 @@ @apply opacity-100; } -/* Code block adjustments */ -.CodeBlockContainer pre code :global(.decorator.annotation.punctuation) { - @apply text-red-50; -} - -.CodeBlockContainer pre code :global(.operator) { - @apply text-yellow-50; -} - -.CodeBlockContainer pre code :global(.decorator) { - @apply text-yellow-80; -} - -.CodeBlockContainer pre code :global(.keyword) { - @apply text-darkBlue-50; -} - -.CodeBlockContainer pre code :global(.builtin) { - @apply text-lightBlue-40; -} - -.CodeBlockContainer pre code :global(.string) { - @apply text-green-80; -} - -.CodeBlockContainer pre code :global(.number), -.CodeBlockContainer pre code :global(.boolean) { - @apply text-green-40; -} - -.CodeBlockContainer pre code :global(.function) { - @apply text-red-50; -} - -.CodeBlockContainer pre code :global(.punctuation) { - @apply text-gray-60; -} - -.CodeBlockContainer pre code :global(.comment) { - @apply text-gray-60 italic font-normal; -} - -.CodeBlockContainer pre code :global(.string) { - @apply text-darkBlue-30; -} - -.CodeBlockContainer pre code :global(.table) { - @apply inline; -} +/* Syntax highlighting is now handled globally via styles/syntax-highlighting.scss */ /* Styles for deprecation notice in param */ .DeprecatedContent { diff --git a/components/blocks/code.module.css b/components/blocks/code.module.css index 64c586b9e..213188c9b 100644 --- a/components/blocks/code.module.css +++ b/components/blocks/code.module.css @@ -54,274 +54,4 @@ @apply text-white; } -/* Code block adjustments */ -.Pre code :global(.operator) { - @apply text-yellow-50; -} - -.Pre code :global(.decorator.annotation.punctuation) { - @apply text-red-60; -} - -.Pre code :global(.string) { - @apply text-darkBlue-30; -} - -.Pre code :global(.keyword) { - @apply text-darkBlue-50; -} - -.Pre code :global(.builtin) { - @apply text-lightBlue-40; -} - -.Pre code :global(.number), -.Pre code :global(.boolean) { - @apply text-green-40; -} - -.Pre code :global(.punctuation) { - @apply text-gray-60; -} - -.Pre code :global(.comment) { - @apply text-gray-60 italic font-normal; -} - -.Pre code :global(.table) { - @apply inline; -} - -.Pre code :global(.deleted) { - @apply text-red-70 bg-red-70 bg-opacity-20; -} -.Pre code :global(.inserted) { - @apply text-green-70 bg-green-70 bg-opacity-20; -} - -/* Additional token types for HTML/markup, CSS, and other languages */ -.Pre code :global(.tag) { - @apply text-red-60; -} - -.Pre code :global(.attr-name) { - @apply text-lightBlue-40; -} - -.Pre code :global(.attr-value) { - @apply text-darkBlue-30; -} - -.Pre code :global(.entity) { - @apply text-green-40; -} - -.Pre code :global(.property) { - @apply text-lightBlue-40; -} - -.Pre code :global(.selector) { - @apply text-red-60; -} - -.Pre code :global(.rule) { - @apply text-darkBlue-50; -} - -.Pre code :global(.function) { - @apply text-red-60 font-semibold; -} - -.Pre code :global(.variable) { - @apply text-yellow-50; -} - -.Pre code :global(.class-name) { - @apply text-lightBlue-40; -} - -.Pre code :global(.constant) { - @apply text-green-40; -} - -.Pre code :global(.symbol) { - @apply text-yellow-50; -} - -.Pre code :global(.important) { - @apply text-red-60 font-bold; -} - -.Pre code :global(.atrule) { - @apply text-darkBlue-50; -} - -.Pre code :global(.url) { - @apply text-darkBlue-30; -} - -.Pre code :global(.regex) { - @apply text-green-40; -} - -.Pre code :global(.prolog), -.Pre code :global(.doctype), -.Pre code :global(.cdata) { - @apply text-gray-60 italic; -} - -/* Additional common token types */ -.Pre code :global(.namespace) { - @apply text-lightBlue-40; -} - -.Pre code :global(.char) { - @apply text-darkBlue-30; -} - -.Pre code :global(.interpolation) { - @apply text-yellow-50; -} - -.Pre code :global(.annotation) { - @apply text-red-60; -} - -.Pre code :global(.generic) { - @apply text-gray-60; -} - -.Pre code :global(.script) { - @apply text-gray-60; -} - -.Pre code :global(.plain-text) { - @apply text-white; -} - -/* Dark mode adjustments */ -:global(.dark) .Pre code :global(.operator), -:global(.dark) .Pre code :global(.decorator) { - @apply text-yellow-80; -} - -:global(.dark) .Pre code :global(.keyword) { - @apply text-darkBlue-50; -} - -:global(.dark) .Pre code :global(.builtin) { - @apply text-lightBlue-60; -} - -:global(.dark) .Pre code :global(.number), -:global(.dark) .Pre code :global(.boolean) { - @apply text-green-40; -} - -:global(.dark) .Pre code :global(.function) { - @apply text-red-60 font-semibold; -} - -:global(.dark) .Pre code :global(.comment) { - @apply text-gray-60; -} - -:global(.dark) .Pre code :global(.string) { - @apply text-darkBlue-30; -} - -/* Dark mode styles for additional token types */ -:global(.dark) .Pre code :global(.tag) { - @apply text-red-60; -} - -:global(.dark) .Pre code :global(.attr-name) { - @apply text-lightBlue-60; -} - -:global(.dark) .Pre code :global(.attr-value) { - @apply text-darkBlue-30; -} - -:global(.dark) .Pre code :global(.entity) { - @apply text-green-40; -} - -:global(.dark) .Pre code :global(.property) { - @apply text-lightBlue-60; -} - -:global(.dark) .Pre code :global(.selector) { - @apply text-red-60; -} - -:global(.dark) .Pre code :global(.rule) { - @apply text-darkBlue-50; -} - -:global(.dark) .Pre code :global(.variable) { - @apply text-yellow-80; -} - -:global(.dark) .Pre code :global(.class-name) { - @apply text-lightBlue-60; -} - -:global(.dark) .Pre code :global(.constant) { - @apply text-green-40; -} - -:global(.dark) .Pre code :global(.symbol) { - @apply text-yellow-80; -} - -:global(.dark) .Pre code :global(.important) { - @apply text-red-60 font-bold; -} - -:global(.dark) .Pre code :global(.atrule) { - @apply text-darkBlue-50; -} - -:global(.dark) .Pre code :global(.url) { - @apply text-darkBlue-30; -} - -:global(.dark) .Pre code :global(.regex) { - @apply text-green-40; -} - -:global(.dark) .Pre code :global(.prolog), -:global(.dark) .Pre code :global(.doctype), -:global(.dark) .Pre code :global(.cdata) { - @apply text-gray-60 italic; -} - -/* Dark mode for additional common token types */ -:global(.dark) .Pre code :global(.namespace) { - @apply text-lightBlue-60; -} - -:global(.dark) .Pre code :global(.char) { - @apply text-darkBlue-30; -} - -:global(.dark) .Pre code :global(.interpolation) { - @apply text-yellow-80; -} - -:global(.dark) .Pre code :global(.annotation) { - @apply text-red-60; -} - -:global(.dark) .Pre code :global(.generic) { - @apply text-gray-60; -} - -:global(.dark) .Pre code :global(.script) { - @apply text-gray-60; -} - -:global(.dark) .Pre code :global(.plain-text) { - @apply text-white; -} +/* Syntax highlighting is now handled globally via styles/syntax-highlighting.scss */ diff --git a/components/blocks/codeTile.module.css b/components/blocks/codeTile.module.css index e387ce5b9..299ac7cc0 100644 --- a/components/blocks/codeTile.module.css +++ b/components/blocks/codeTile.module.css @@ -56,34 +56,4 @@ @apply col-span-full md:col-span-3 lg:col-span-2; } -/* Code block adjustments */ -/* Code block adjustments */ -.Container pre code :global(.operator), -.Container pre code :global(.decorator) { - @apply text-yellow-80; -} - -.Container pre code :global(.keyword) { - @apply text-darkBlue-60; -} - -.Container pre code :global(.builtin) { - @apply text-lightBlue-70; -} - -.Container pre code :global(.string) { - @apply text-green-80; -} - -.Container pre code :global(.number), -.Container pre code :global(.boolean) { - @apply text-green-60; -} - -.Container pre code :global(.function) { - @apply text-red-60; -} - -.Container pre code :global(.punctuation) { - @apply text-gray-60; -} +/* Syntax highlighting is now handled globally via styles/syntax-highlighting.scss */ diff --git a/styles/main.scss b/styles/main.scss index 4badfab4e..fae621cd6 100644 --- a/styles/main.scss +++ b/styles/main.scss @@ -5,5 +5,6 @@ @import "./scrollbars.scss"; @import "./admonition.scss"; @import "./cookie-banner.scss"; +@import "./syntax-highlighting.scss"; @import "./print.scss"; diff --git a/styles/syntax-highlighting.scss b/styles/syntax-highlighting.scss new file mode 100644 index 000000000..86ee774ce --- /dev/null +++ b/styles/syntax-highlighting.scss @@ -0,0 +1,313 @@ +/* Syntax Highlighting Token Colors + * Centralized color definitions for all code blocks + */ + +/* Light mode syntax highlighting tokens */ +:root { + /* Primary syntax tokens */ + --syntax-operator: theme("colors.orange.80"); + --syntax-decorator: theme("colors.orange.80"); + --syntax-keyword: theme("colors.darkBlue.80"); + --syntax-builtin: theme("colors.lightBlue.80"); + --syntax-string: theme("colors.acqua.80"); + --syntax-number: theme("colors.green.70"); + --syntax-boolean: theme("colors.green.70"); + --syntax-function: theme("colors.red.70"); + --syntax-punctuation: theme("colors.gray.70"); + --syntax-comment: theme("colors.gray.70"); + + /* HTML/Markup tokens */ + --syntax-tag: theme("colors.red.70"); + --syntax-attr-name: theme("colors.lightBlue.80"); + --syntax-attr-value: theme("colors.green.80"); + --syntax-entity: theme("colors.green.70"); + + /* CSS tokens */ + --syntax-property: theme("colors.lightBlue.80"); + --syntax-selector: theme("colors.red.70"); + --syntax-rule: theme("colors.darkBlue.80"); + --syntax-atrule: theme("colors.darkBlue.80"); + --syntax-url: theme("colors.green.80"); + + /* Additional common tokens */ + --syntax-variable: theme("colors.orange.80"); + --syntax-class-name: theme("colors.lightBlue.80"); + --syntax-constant: theme("colors.green.70"); + --syntax-symbol: theme("colors.orange.80"); + --syntax-important: theme("colors.red.70"); + --syntax-regex: theme("colors.green.70"); + --syntax-namespace: theme("colors.lightBlue.80"); + --syntax-char: theme("colors.green.80"); + --syntax-interpolation: theme("colors.orange.80"); + --syntax-annotation: theme("colors.red.70"); + --syntax-generic: theme("colors.gray.70"); + --syntax-script: theme("colors.gray.70"); + --syntax-plain-text: theme("colors.gray.90"); + + /* Special tokens */ + --syntax-prolog: theme("colors.gray.70"); + --syntax-doctype: theme("colors.gray.70"); + --syntax-cdata: theme("colors.gray.70"); + --syntax-deleted: theme("colors.red.70"); + --syntax-inserted: theme("colors.green.70"); +} + +/* Dark mode syntax highlighting tokens */ +.dark { + /* Primary syntax tokens - keep existing dark mode colors */ + --syntax-operator: theme("colors.yellow.80"); + --syntax-decorator: theme("colors.yellow.80"); + --syntax-keyword: theme("colors.darkBlue.50"); + --syntax-builtin: theme("colors.lightBlue.60"); + --syntax-string: theme("colors.darkBlue.30"); + --syntax-number: theme("colors.green.40"); + --syntax-boolean: theme("colors.green.40"); + --syntax-function: theme("colors.red.60"); + --syntax-punctuation: theme("colors.gray.60"); + --syntax-comment: theme("colors.gray.60"); + + /* HTML/Markup tokens */ + --syntax-tag: theme("colors.red.60"); + --syntax-attr-name: theme("colors.lightBlue.60"); + --syntax-attr-value: theme("colors.darkBlue.30"); + --syntax-entity: theme("colors.green.40"); + + /* CSS tokens */ + --syntax-property: theme("colors.lightBlue.60"); + --syntax-selector: theme("colors.red.60"); + --syntax-rule: theme("colors.darkBlue.50"); + --syntax-atrule: theme("colors.darkBlue.50"); + --syntax-url: theme("colors.darkBlue.30"); + + /* Additional common tokens */ + --syntax-variable: theme("colors.yellow.80"); + --syntax-class-name: theme("colors.lightBlue.60"); + --syntax-constant: theme("colors.green.40"); + --syntax-symbol: theme("colors.yellow.80"); + --syntax-important: theme("colors.red.60"); + --syntax-regex: theme("colors.green.40"); + --syntax-namespace: theme("colors.lightBlue.60"); + --syntax-char: theme("colors.darkBlue.30"); + --syntax-interpolation: theme("colors.yellow.80"); + --syntax-annotation: theme("colors.red.60"); + --syntax-generic: theme("colors.gray.60"); + --syntax-script: theme("colors.gray.60"); + --syntax-plain-text: theme("colors.white"); + + /* Special tokens */ + --syntax-prolog: theme("colors.gray.60"); + --syntax-doctype: theme("colors.gray.60"); + --syntax-cdata: theme("colors.gray.60"); + --syntax-deleted: theme("colors.red.70"); + --syntax-inserted: theme("colors.green.70"); +} + +/* Global syntax highlighting classes using CSS custom properties */ +/* Target code elements within our specific containers */ +pre code .operator, +code .operator { + color: var(--syntax-operator) !important; +} + +pre code .decorator, +code .decorator { + color: var(--syntax-decorator) !important; +} + +pre code .decorator.annotation.punctuation, +code .decorator.annotation.punctuation { + color: var(--syntax-decorator) !important; +} + +pre code .keyword, +code .keyword { + color: var(--syntax-keyword) !important; +} + +pre code .builtin, +code .builtin { + color: var(--syntax-builtin) !important; +} + +pre code .string, +code .string { + color: var(--syntax-string) !important; +} + +pre code .number, +pre code .boolean, +code .number, +code .boolean { + color: var(--syntax-number) !important; +} + +pre code .function, +code .function { + color: var(--syntax-function) !important; + font-weight: 600 !important; +} + +pre code .punctuation, +code .punctuation { + color: var(--syntax-punctuation) !important; +} + +pre code .comment, +code .comment { + color: var(--syntax-comment) !important; + font-style: italic !important; + font-weight: normal !important; +} + +/* HTML/Markup tokens */ +pre code .tag, +code .tag { + color: var(--syntax-tag) !important; +} + +pre code .attr-name, +code .attr-name { + color: var(--syntax-attr-name) !important; +} + +pre code .attr-value, +code .attr-value { + color: var(--syntax-attr-value) !important; +} + +pre code .entity, +code .entity { + color: var(--syntax-entity) !important; +} + +/* CSS tokens */ +pre code .property, +code .property { + color: var(--syntax-property) !important; +} + +pre code .selector, +code .selector { + color: var(--syntax-selector) !important; +} + +pre code .rule, +code .rule { + color: var(--syntax-rule) !important; +} + +pre code .atrule, +code .atrule { + color: var(--syntax-atrule) !important; +} + +pre code .url, +code .url { + color: var(--syntax-url) !important; +} + +/* Additional common tokens */ +pre code .variable, +code .variable { + color: var(--syntax-variable) !important; +} + +pre code .class-name, +code .class-name { + color: var(--syntax-class-name) !important; +} + +pre code .constant, +code .constant { + color: var(--syntax-constant) !important; +} + +pre code .symbol, +code .symbol { + color: var(--syntax-symbol) !important; +} + +pre code .important, +code .important { + color: var(--syntax-important) !important; + font-weight: bold !important; +} + +pre code .regex, +code .regex { + color: var(--syntax-regex) !important; +} + +pre code .namespace, +code .namespace { + color: var(--syntax-namespace) !important; +} + +pre code .char, +code .char { + color: var(--syntax-char) !important; +} + +pre code .interpolation, +code .interpolation { + color: var(--syntax-interpolation) !important; +} + +pre code .annotation, +code .annotation { + color: var(--syntax-annotation) !important; +} + +pre code .generic, +code .generic { + color: var(--syntax-generic) !important; +} + +pre code .script, +code .script { + color: var(--syntax-script) !important; +} + +pre code .plain-text, +code .plain-text { + color: var(--syntax-plain-text) !important; +} + +/* Special tokens */ +pre code .prolog, +pre code .doctype, +pre code .cdata, +code .prolog, +code .doctype, +code .cdata { + color: var(--syntax-prolog) !important; + font-style: italic !important; +} + +pre code .deleted, +code .deleted { + color: var(--syntax-deleted) !important; + background-color: rgba( + 255, + 75, + 75, + 0.2 + ) !important; /* red-70 with 20% opacity */ +} + +pre code .inserted, +code .inserted { + color: var(--syntax-inserted) !important; + background-color: rgba( + 33, + 195, + 84, + 0.2 + ) !important; /* green-70 with 20% opacity */ +} + +/* Table token for inline display */ +pre code .table, +code .table { + display: inline !important; +} From ea1093b40b75b47651e17b96b8dcf8d0eaf898b8 Mon Sep 17 00:00:00 2001 From: Debbie Matthews Date: Fri, 19 Dec 2025 10:37:11 -0800 Subject: [PATCH 05/20] feature/code-block-language-header (#1389) * feature/code-block-language-header * Include none language * Debug none language * Hide language when none * Use right padding * Add header to Autofunctio code --- components/blocks/autofunction.js | 18 ++++++- components/blocks/autofunction.module.css | 25 +++++++-- components/blocks/code.js | 62 +++++++++++++++++++++-- components/blocks/code.module.css | 23 +++++++-- components/blocks/refCard.module.css | 4 ++ 5 files changed, 120 insertions(+), 12 deletions(-) diff --git a/components/blocks/autofunction.js b/components/blocks/autofunction.js index 05062a554..a3e1702db 100644 --- a/components/blocks/autofunction.js +++ b/components/blocks/autofunction.js @@ -85,16 +85,32 @@ const Autofunction = ({ ); pres.forEach((ele) => { + // Detect language based on pre element class + const isLiteralBlock = ele.classList.contains("literal-block"); + const language = isLiteralBlock ? "bash" : "python"; + const displayLanguage = isLiteralBlock ? "BASH" : "PYTHON"; + const codeText = ele.innerHTML; const preTag = ele.cloneNode(true); const codeWrap = document.createElement("div"); codeWrap.setAttribute("class", styles.CodeBlockContainer); + + // Create language header + const header = document.createElement("div"); + header.setAttribute("class", `${styles.Header} code-block-header`); + const langSpan = document.createElement("span"); + langSpan.setAttribute("class", styles.Language); + langSpan.textContent = displayLanguage; + header.appendChild(langSpan); + const codeTag = document.createElement("code"); - codeTag.setAttribute("class", "language-python"); + codeTag.setAttribute("class", `language-${language}`); preTag.classList.add("line-numbers"); codeTag.innerHTML = codeText; preTag.textContent = null; preTag.appendChild(codeTag); + + codeWrap.appendChild(header); codeWrap.appendChild(preTag); ele.replaceWith(codeWrap); }); diff --git a/components/blocks/autofunction.module.css b/components/blocks/autofunction.module.css index fcbec2131..fcc258988 100644 --- a/components/blocks/autofunction.module.css +++ b/components/blocks/autofunction.module.css @@ -2,6 +2,10 @@ @apply mt-6; } +.Container h4 { + @apply mb-4; +} + .HeaderContainer { @apply mb-6; } @@ -58,13 +62,26 @@ @apply mb-7 relative; } +.Header { + @apply flex items-center px-3 py-1 bg-gray-20 text-gray-70 text-xs font-medium tracking-wide rounded-t-xl border-b border-gray-30; + min-height: 2.5rem; +} + +:global(.dark) .Header { + @apply bg-gray-90 text-gray-50 border-gray-80; +} + +.Language { + @apply uppercase tracking-wider pr-4; +} + .CodeBlockContainer pre, .CodeBlockContainer code { @apply overflow-auto max-w-full whitespace-pre; } .CodeBlockContainer pre { - @apply p-4 bg-gray-10 text-gray-80 font-medium rounded-xl relative leading-relaxed; + @apply p-6 bg-gray-10 text-gray-80 font-medium rounded-b-xl relative leading-relaxed; } .CodeBlockContainer pre code { @@ -76,16 +93,16 @@ } .CodeBlockContainer button { - @apply absolute top-2 right-2 cursor-pointer h-8 w-8 mb-0 flex items-center; + @apply absolute top-2 right-1 cursor-pointer h-8 w-8 mb-0 flex items-center justify-center; } .CodeBlockContainer button::before { - @apply absolute top-2 right-2 z-10 transition-all duration-75 hover:opacity-40; + @apply z-10 transition-all duration-75 hover:opacity-40; content: url("/clipboard.svg"); } .CodeBlockContainer button span { - @apply absolute right-10 text-gray-80 font-mono text-sm tracking-tight font-normal opacity-0; + @apply absolute -top-0.5 right-10 text-gray-80 font-mono text-sm tracking-tight font-normal opacity-0; } .CodeBlockContainer button:hover span { diff --git a/components/blocks/code.js b/components/blocks/code.js index db5595074..b02f5ef2d 100644 --- a/components/blocks/code.js +++ b/components/blocks/code.js @@ -15,6 +15,44 @@ import styles from "./code.module.css"; // Initialize the cache for imported languages. const languageImports = new Map(); +// Map language identifiers to display-friendly names +const languageDisplayNames = { + python: "Python", + javascript: "JavaScript", + js: "JavaScript", + typescript: "TypeScript", + ts: "TypeScript", + bash: "Bash", + sh: "Bash", + shell: "Shell", + json: "JSON", + yaml: "YAML", + yml: "YAML", + html: "HTML", + css: "CSS", + sql: "SQL", + toml: "TOML", + markdown: "Markdown", + md: "Markdown", + jsx: "JSX", + tsx: "TSX", + go: "Go", + rust: "Rust", + ruby: "Ruby", + java: "Java", + c: "C", + cpp: "C++", + csharp: "C#", + php: "PHP", + swift: "Swift", + kotlin: "Kotlin", + scala: "Scala", + r: "R", + docker: "Docker", + dockerfile: "Dockerfile", + none: "", +}; + const Code = ({ code, children, @@ -29,7 +67,7 @@ const Code = ({ useEffect(() => { // Get the language from the className, if it exists. // Classname usually is `language-python`, `language-javascript`, `language-bash`, etc. - let importLanguage = children.props.className?.substring(9); + let importLanguage = children?.props?.className?.substring(9); // If no language, default to Phython if (importLanguage === undefined || importLanguage === "undefined") { @@ -83,6 +121,19 @@ const Code = ({ languageClass = children.props.className; } + // Extract language identifier for display + const langId = languageClass?.substring(9) || language || "python"; + const displayLanguage = languageDisplayNames[langId] || langId; + const showLanguage = langId.toLowerCase() !== "none"; + + const Header = ( +
+ {showLanguage && ( + {displayLanguage} + )} +
+ ); + if (img) { ConditionalRendering = (
+ {Header} -
+        
           
             {customCode}
           
@@ -105,7 +157,8 @@ const Code = ({
           [styles.NoCopyButton]: hideCopyButton,
         })}
       >
-        
+        {Header}
+        
           
             {customCode}
           
@@ -119,7 +172,8 @@ const Code = ({
           [styles.NoCopyButton]: hideCopyButton,
         })}
       >
-        
+        {Header}
+        
           
             {customCode}
           
diff --git a/components/blocks/code.module.css b/components/blocks/code.module.css
index 213188c9b..ee9119bce 100644
--- a/components/blocks/code.module.css
+++ b/components/blocks/code.module.css
@@ -3,6 +3,23 @@
   @apply relative !important;
 }
 
+.Header {
+  @apply flex items-center px-3 py-1 bg-gray-20 text-gray-70 text-xs font-medium tracking-wide rounded-t-md border-b border-gray-30;
+  min-height: 2.5rem;
+}
+
+:global(.dark) .Header {
+  @apply bg-gray-90 text-gray-50 border-gray-80;
+}
+
+.Language {
+  @apply uppercase tracking-wider pr-4;
+}
+
+.HasHeader {
+  @apply rounded-t-none !important;
+}
+
 .Pre,
 .Container code {
   @apply overflow-auto max-w-full whitespace-pre;
@@ -29,16 +46,16 @@
   @apply bg-gray-80 opacity-30 z-0;
 }
 .Container button {
-  @apply absolute top-2 right-2 cursor-pointer h-8 w-8 mb-0 flex items-center;
+  @apply absolute top-2 right-1 cursor-pointer h-8 w-8 mb-0 flex items-center justify-center;
 }
 
 .Container button::before {
-  @apply absolute top-2 right-2 z-10 transition-all duration-75 hover:opacity-40;
+  @apply z-10 transition-all duration-75 hover:opacity-40;
   content: url("/clipboard.svg");
 }
 
 .Container button span {
-  @apply absolute right-10 text-gray-80 font-mono text-sm tracking-tight font-normal opacity-0;
+  @apply absolute -top-0.5 right-10 text-gray-80 font-mono text-sm tracking-tight font-normal opacity-0;
 }
 
 .Container button:hover span {
diff --git a/components/blocks/refCard.module.css b/components/blocks/refCard.module.css
index 70e4987b1..931cb50a4 100644
--- a/components/blocks/refCard.module.css
+++ b/components/blocks/refCard.module.css
@@ -153,6 +153,10 @@
   @apply hidden;
 }
 
+.Container section :global(.code-block-header) {
+  @apply hidden !important;
+}
+
 .Container section div {
   @apply bg-gray-10;
   @apply text-gray-80;

From 8248257883187d20db329a2df66e376c01b448ff Mon Sep 17 00:00:00 2001
From: Debbie Matthews 
Date: Fri, 19 Dec 2025 11:05:30 -0800
Subject: [PATCH 06/20] feature/code-block-description (#1390)

* feature/code-block-description

* Filename color

* Replace language with filename; optionally both

* Revert content changes

* Revert more content changes
---
 components/blocks/code.js         | 6 +++++-
 components/blocks/code.module.css | 4 ++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/components/blocks/code.js b/components/blocks/code.js
index b02f5ef2d..e8efad6f7 100644
--- a/components/blocks/code.js
+++ b/components/blocks/code.js
@@ -60,6 +60,8 @@ const Code = ({
   img,
   lines,
   hideCopyButton = false,
+  filename,
+  filenameOnly = true,
 }) => {
   // Create a ref for the code element.
   const codeRef = useRef(null);
@@ -124,13 +126,15 @@ const Code = ({
   // Extract language identifier for display
   const langId = languageClass?.substring(9) || language || "python";
   const displayLanguage = languageDisplayNames[langId] || langId;
-  const showLanguage = langId.toLowerCase() !== "none";
+  const showLanguage =
+    langId.toLowerCase() !== "none" && !(filenameOnly && filename);
 
   const Header = (
     
{showLanguage && ( {displayLanguage} )} + {filename && {filename}}
); diff --git a/components/blocks/code.module.css b/components/blocks/code.module.css index ee9119bce..6f00a5e47 100644 --- a/components/blocks/code.module.css +++ b/components/blocks/code.module.css @@ -16,6 +16,10 @@ @apply uppercase tracking-wider pr-4; } +.Filename { + @apply font-mono text-sm leading-6 pr-4; +} + .HasHeader { @apply rounded-t-none !important; } From 2ae788907d3ab2efe094445d0b0619f627a48353 Mon Sep 17 00:00:00 2001 From: Debbie Matthews Date: Fri, 19 Dec 2025 14:26:53 -0800 Subject: [PATCH 07/20] feature/try-it-code-block-button (#1391) * feature/code-block-description * Filename color * Replace language with filename; optionally both * Revert content changes * Revert more content changes * feature/try-it-code-block-button * Use named target * Design edits * Fix gray code header in dark mode * Remove filename * Design tweaks * Update Autofunction code block to match --- components/blocks/autofunction.module.css | 6 +- components/blocks/code.js | 80 ++++++++++++++++++- components/blocks/code.module.css | 47 ++++++++--- .../concepts/configuration/theming-fonts.md | 30 +++---- .../get-started/fundamentals/main-concepts.md | 2 +- pages/[...slug].js | 57 ++++++++++++- styles/syntax-highlighting.scss | 4 +- tailwind.config.js | 2 +- 8 files changed, 187 insertions(+), 41 deletions(-) diff --git a/components/blocks/autofunction.module.css b/components/blocks/autofunction.module.css index fcc258988..155ac3f70 100644 --- a/components/blocks/autofunction.module.css +++ b/components/blocks/autofunction.module.css @@ -63,16 +63,16 @@ } .Header { - @apply flex items-center px-3 py-1 bg-gray-20 text-gray-70 text-xs font-medium tracking-wide rounded-t-xl border-b border-gray-30; + @apply flex items-center px-3 py-1 bg-gray-10 text-gray-70 text-sm font-mono font-medium tracking-wide rounded-t-xl border-b border-gray-30; min-height: 2.5rem; } :global(.dark) .Header { - @apply bg-gray-90 text-gray-50 border-gray-80; + @apply bg-gray-90 text-gray-60 border-gray-80; } .Language { - @apply uppercase tracking-wider pr-4; + @apply uppercase pr-4 font-mono; } .CodeBlockContainer pre, diff --git a/components/blocks/code.js b/components/blocks/code.js index e8efad6f7..a5038c395 100644 --- a/components/blocks/code.js +++ b/components/blocks/code.js @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from "react"; +import React, { useEffect, useRef, useState } from "react"; import classNames from "classnames"; import Prism from "prismjs"; import "prismjs/plugins/line-numbers/prism-line-numbers"; @@ -12,6 +12,78 @@ import Image from "./image"; import styles from "./code.module.css"; +// Compress code with gzip and encode as base64 for Streamlit Playground +async function compressCodeForPlayground(code) { + const encoder = new TextEncoder(); + const data = encoder.encode(code); + + const cs = new CompressionStream("gzip"); + const writer = cs.writable.getWriter(); + writer.write(data); + writer.close(); + + const compressedChunks = []; + const reader = cs.readable.getReader(); + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + compressedChunks.push(value); + } + + // Combine all chunks into a single Uint8Array + const totalLength = compressedChunks.reduce( + (acc, chunk) => acc + chunk.length, + 0, + ); + const compressed = new Uint8Array(totalLength); + let offset = 0; + for (const chunk of compressedChunks) { + compressed.set(chunk, offset); + offset += chunk.length; + } + + // Convert to URL-safe base64 (uses - and _ instead of + and /) + let binary = ""; + for (let i = 0; i < compressed.length; i++) { + binary += String.fromCharCode(compressed[i]); + } + return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_"); +} + +// TryMeButton component +const TryMeButton = ({ code }) => { + const [playgroundUrl, setPlaygroundUrl] = useState(null); + + useEffect(() => { + async function generateUrl() { + if (code) { + const encoded = await compressCodeForPlayground(code.trim()); + setPlaygroundUrl( + `https://streamlit.io/playground?example=blank&code=${encoded}`, + ); + } + } + generateUrl(); + }, [code]); + + if (!playgroundUrl) return null; + + return ( + + Try it + + arrow_outward + + + ); +}; + // Initialize the cache for imported languages. const languageImports = new Map(); @@ -61,7 +133,8 @@ const Code = ({ lines, hideCopyButton = false, filename, - filenameOnly = true, + showAll = false, + try: tryIt = false, }) => { // Create a ref for the code element. const codeRef = useRef(null); @@ -127,7 +200,7 @@ const Code = ({ const langId = languageClass?.substring(9) || language || "python"; const displayLanguage = languageDisplayNames[langId] || langId; const showLanguage = - langId.toLowerCase() !== "none" && !(filenameOnly && filename); + langId.toLowerCase() !== "none" && (showAll || !filename); const Header = (
@@ -135,6 +208,7 @@ const Code = ({ {displayLanguage} )} {filename && {filename}} + {tryIt && }
); diff --git a/components/blocks/code.module.css b/components/blocks/code.module.css index 6f00a5e47..97b9716ed 100644 --- a/components/blocks/code.module.css +++ b/components/blocks/code.module.css @@ -4,20 +4,20 @@ } .Header { - @apply flex items-center px-3 py-1 bg-gray-20 text-gray-70 text-xs font-medium tracking-wide rounded-t-md border-b border-gray-30; + @apply flex items-center px-3 py-1 bg-gray-10 text-gray-70 text-sm font-mono font-medium tracking-wide rounded-t-xl border-b border-gray-30; min-height: 2.5rem; } :global(.dark) .Header { - @apply bg-gray-90 text-gray-50 border-gray-80; + @apply bg-gray-90 text-gray-60 border-gray-80; } .Language { - @apply uppercase tracking-wider pr-4; + @apply uppercase pr-4 font-mono; } .Filename { - @apply font-mono text-sm leading-6 pr-4; + @apply leading-6 pr-4; } .HasHeader { @@ -30,7 +30,7 @@ } .Pre { - @apply p-6 bg-gray-10 text-gray-80 font-medium rounded-md relative leading-relaxed; + @apply p-6 bg-gray-10 text-gray-80 font-medium rounded-xl relative leading-relaxed; } /* Dark mode background and text for Pre */ @@ -54,15 +54,25 @@ } .Container button::before { - @apply z-10 transition-all duration-75 hover:opacity-40; + @apply z-10 transition-all duration-75 hover:opacity-60; content: url("/clipboard.svg"); } .Container button span { - @apply absolute -top-0.5 right-10 text-gray-80 font-mono text-sm tracking-tight font-normal opacity-0; + @apply absolute -top-0.5 right-10 text-gray-70 font-mono text-sm tracking-tight font-normal opacity-0; } -.Container button:hover span { +:global(.dark) .Container button span { + @apply text-gray-70 !important; +} + +/* Hide "Copy" text completely */ +.Container button[data-copy-state="copy"] span { + @apply hidden; +} + +/* Show "Copied!" text */ +.Container button[data-copy-state="copy-success"] span { @apply opacity-100; } @@ -72,7 +82,26 @@ /* Dark mode button text */ :global(.dark) .Container button span { - @apply text-white; + @apply text-gray-40; } /* Syntax highlighting is now handled globally via styles/syntax-highlighting.scss */ + +/* Try Me Button */ +.TryMeButton { + @apply flex items-center text-gray-90 gap-1 pr-4 rounded text-sm font-medium transition-all duration-150; + @apply hover:opacity-60; + text-decoration: none !important; +} + +:global(.dark) .TryMeButton { + @apply text-white; +} + +.TryMeIcon { + @apply text-lg leading-none; +} + +.TryMeLabel { + @apply hidden sm:inline tracking-tight; +} diff --git a/content/develop/concepts/configuration/theming-fonts.md b/content/develop/concepts/configuration/theming-fonts.md index edcd6ed7e..5d5abbf63 100644 --- a/content/develop/concepts/configuration/theming-fonts.md +++ b/content/develop/concepts/configuration/theming-fonts.md @@ -15,7 +15,7 @@ Streamlit comes with [Source Sans](https://fonts.adobe.com/fonts/source-sans), [ To use these default faults, you can set each of the following configuration options to `"sans-serif"` (Source Sans), `"serif"` (Source Serif), or `"monospace"` (Source Code) in `config.toml`: -```toml +```toml filename=".streamlit/config.toml" [theme] font = "sans-serif" headingFont = "sans-serif" @@ -45,7 +45,7 @@ When fonts are not declared in `[theme.sidebar]`, Streamlit will inherit each op In the following `config.toml` example, Streamlit uses Source Serif in the main body of the app and Source Sans in the sidebar. -```toml +```toml filename=".streamlit/config.toml" [theme] font = "serif" [theme.sidebar] @@ -56,7 +56,7 @@ font = "sans-serif" If you use a font service like Google Fonts or Adobe Fonts, you can use those fonts directly by encoding their font family (name) and CSS URL into a single string of the form `{font_name}:{css_url}`. If your font family includes a space, use inner quotes on the font family. In the following `config.toml` example, Streamlit uses Nunito font for all text except code, which is Space Mono instead. Space Mono has inner quotes because it has a space. -```toml +```toml filename=".streamlit/config.toml" [theme] font = "Nunito:https://fonts.googleapis.com/css2?family=Nunito&display=swap" codeFont = "'Space Mono':https://fonts.googleapis.com/css2?family=Space+Mono&display=swap" @@ -98,9 +98,7 @@ The following example uses static file serving to host Google's [Noto Sans](http A line-by-line explanation of this example is available in a [tutorial](/develop/tutorials/configuration-and-theming/variable-fonts). -`.streamlit/config.toml`: - -```toml +```toml filename=".streamlit/config.toml" [server] enableStaticServing = true @@ -121,9 +119,7 @@ font="noto-sans" codeFont="noto-mono" ``` -Directory structure: - -```none +```none filename="Directory structure" project_directory/ ├── .streamlit/ │ └── config.toml @@ -147,9 +143,7 @@ If your app uses a font without a matching weight-style definition, the user's b A line-by-line explanation of this example is available in a [tutorial](/develop/tutorials/configuration-and-theming/static-fonts). -`.streamlit/config.toml`: - -```toml +```toml filename=".streamlit/config.toml" [server] enableStaticServing = true @@ -178,9 +172,7 @@ weight=700 font="tuffy" ``` -Directory structure: - -```none +```none filename="Directory structure" project_directory/ ├── .streamlit/ │ └── config.toml @@ -204,9 +196,7 @@ You can always include one of Streamlit's default fonts as a final fallback. The A line-by-line explanation of this example is available in a [tutorial](/develop/tutorials/configuration-and-theming/external-fonts). -`.streamlit/config.toml`: - -```toml +```toml filename=".streamlit/config.toml" [theme] font="Nunito:https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000, sans-serif" codeFont="'Space Mono':https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap, monospace" @@ -222,14 +212,14 @@ If any of your font family names contain spaces and you are declaring a fallback You can set the base font size for your app in pixels. You must specify the base font size as an integer. The following configuration is equivalent to the default base font size of 16 pixels: -```toml +```toml filename=".streamlit/config.toml" [theme] baseFontSize=16 ``` Additionally, you can set the font size for code blocks. The font size can be declared in pixels or rem. The following configuration is equivalent to the default code font size of 0.875rem. -```toml +```toml filename=".streamlit/config.toml" [theme] codeFontSize="0.875rem" ``` diff --git a/content/get-started/fundamentals/main-concepts.md b/content/get-started/fundamentals/main-concepts.md index 8d30bd826..e826b501e 100644 --- a/content/get-started/fundamentals/main-concepts.md +++ b/content/get-started/fundamentals/main-concepts.md @@ -113,7 +113,7 @@ You can also write to your app without calling any Streamlit methods. Streamlit supports "[magic commands](/develop/api-reference/write-magic/magic)," which means you don't have to use [`st.write()`](/develop/api-reference/write-magic/st.write) at all! To see this in action try this snippet: -```python +```python try """ # My first app Here's our first attempt at using data to create a table: diff --git a/pages/[...slug].js b/pages/[...slug].js index 37d30cb6c..22664ecb1 100644 --- a/pages/[...slug].js +++ b/pages/[...slug].js @@ -14,6 +14,29 @@ import { useRouter } from "next/router"; import rehypeSlug from "rehype-slug"; import rehypeAutolinkHeadings from "rehype-autolink-headings"; import getConfig from "next/config"; + +// Custom remark plugin to pass code fence metadata through to the HTML +// e.g., ```python try filename="app.py"``` adds data-meta attribute +function remarkCodeMeta() { + // Simple recursive tree walker (avoids ESM import issues with unist-util-visit) + function walkTree(node, callback) { + callback(node); + if (node.children) { + node.children.forEach((child) => walkTree(child, callback)); + } + } + + return (tree) => { + walkTree(tree, (node) => { + if (node.type === "code" && node.meta) { + // Store meta in data.hProperties which remark-rehype passes to the element + node.data = node.data || {}; + node.data.hProperties = node.data.hProperties || {}; + node.data.hProperties["data-meta"] = node.meta; + } + }); + }; +} const { serverRuntimeConfig, publicRuntimeConfig } = getConfig(); // Site Components @@ -167,7 +190,37 @@ export default function Article({ goToLatest={goToLatest} /> ), - pre: (props) => , + pre: (props) => { + // Extract metadata from code fence (e.g., ```python try filename="app.py" showAll) + // The metadata is passed via data-meta attribute from our remark plugin + const codeElement = props.children; + const metaString = codeElement?.props?.["data-meta"] || ""; + + // Parse metadata into props + const codeProps = {}; + + if (metaString) { + // Supported boolean flags (standalone words) + const booleanFlags = ["try", "showAll", "hideCopyButton"]; + + // Extract key="value" pairs (e.g., filename="app.py") + const keyValueRegex = /(\w+)=["']([^"']+)["']/g; + let match; + while ((match = keyValueRegex.exec(metaString)) !== null) { + codeProps[match[1]] = match[2]; + } + + // Check for boolean flags (standalone words like `try` or `showAll`) + const cleanedMeta = metaString.replace(keyValueRegex, ""); + booleanFlags.forEach((flag) => { + if (new RegExp(`\\b${flag}\\b`).test(cleanedMeta)) { + codeProps[flag] = true; + } + }); + } + + return ; + }, h1: H1, h2: H2, h3: H3, @@ -410,7 +463,7 @@ export async function getStaticProps(context) { scope: data, mdxOptions: { rehypePlugins: [rehypeSlug, rehypeAutolinkHeadings], - remarkPlugins: [remarkUnwrapImages, remarkGfm], + remarkPlugins: [remarkUnwrapImages, remarkGfm, remarkCodeMeta], }, }); diff --git a/styles/syntax-highlighting.scss b/styles/syntax-highlighting.scss index 86ee774ce..3f50992b3 100644 --- a/styles/syntax-highlighting.scss +++ b/styles/syntax-highlighting.scss @@ -9,7 +9,7 @@ --syntax-decorator: theme("colors.orange.80"); --syntax-keyword: theme("colors.darkBlue.80"); --syntax-builtin: theme("colors.lightBlue.80"); - --syntax-string: theme("colors.acqua.80"); + --syntax-string: theme("colors.indigo.80"); --syntax-number: theme("colors.green.70"); --syntax-boolean: theme("colors.green.70"); --syntax-function: theme("colors.red.70"); @@ -59,7 +59,7 @@ --syntax-decorator: theme("colors.yellow.80"); --syntax-keyword: theme("colors.darkBlue.50"); --syntax-builtin: theme("colors.lightBlue.60"); - --syntax-string: theme("colors.darkBlue.30"); + --syntax-string: theme("colors.indigo.30"); --syntax-number: theme("colors.green.40"); --syntax-boolean: theme("colors.green.40"); --syntax-function: theme("colors.red.60"); diff --git a/tailwind.config.js b/tailwind.config.js index a47b6c9fe..2dd96ee75 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -156,7 +156,7 @@ module.exports = { 100: "#3f3163", }, gray: { - 10: "#fafafa", + 10: "#F5F7F9", 20: "#f0f2f6", 30: "#e6eaf1", 40: "#d5dae5", From b561e1a3e34a9a246a60bc7dbcab302f60fae79d Mon Sep 17 00:00:00 2001 From: Thiago Teixeira Date: Fri, 19 Dec 2025 23:47:27 -0300 Subject: [PATCH 08/20] Fix the font-family used in inline code. --- styles/text.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/styles/text.scss b/styles/text.scss index 1b0161807..84701a59b 100644 --- a/styles/text.scss +++ b/styles/text.scss @@ -116,6 +116,7 @@ tt.docutils.literal { @apply text-green-80 bg-green-80/5; @apply dark:text-green-50 dark:bg-green-50/10; @apply text-base; + @apply font-mono; line-height: inherit; } From d6a8f6d26ece5ed289dc425860238137f0408ca8 Mon Sep 17 00:00:00 2001 From: Thiago Teixeira Date: Sat, 20 Dec 2025 00:18:01 -0300 Subject: [PATCH 09/20] Update styling for code blocks. --- components/blocks/componentCard.js | 7 ++++++- components/blocks/refCard.js | 5 ++++- components/blocks/refCard.module.css | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/components/blocks/componentCard.js b/components/blocks/componentCard.js index e84254273..530b689e9 100644 --- a/components/blocks/componentCard.js +++ b/components/blocks/componentCard.js @@ -6,7 +6,12 @@ import customStyles from "./componentCard.module.css"; const ComponentCard = ({ children, href }) => { return ( { : styles.Third; return ( - + {deprecated === true ? (
Date: Sat, 20 Dec 2025 00:18:29 -0300 Subject: [PATCH 10/20] Unrelated but make radius of Kapa dialog nicer. --- components/utilities/kapa.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/utilities/kapa.js b/components/utilities/kapa.js index 16593137e..f18edf996 100644 --- a/components/utilities/kapa.js +++ b/components/utilities/kapa.js @@ -51,7 +51,7 @@ const Kapa = () => { data-button-hide="true" data-modal-override-open-id="kapa-ai" data-modal-lock-scroll="false" - data-modal-border-radius="6px" + data-modal-border-radius="12px" data-modal-image-height="18px" data-answer-feedback-button-active-border="1px solid #808495" data-user-analytics-cookie-enabled="false" From a76fc7d2375dd2b84a01d14d9a4ff2afaf014b37 Mon Sep 17 00:00:00 2001 From: Thiago Teixeira Date: Sat, 20 Dec 2025 00:19:07 -0300 Subject: [PATCH 11/20] Unrelated but fix arrows and padding in component slider. --- components/blocks/componentSlider.js | 2 +- components/blocks/componentSlider.module.css | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/components/blocks/componentSlider.js b/components/blocks/componentSlider.js index 371935529..ea536e784 100644 --- a/components/blocks/componentSlider.js +++ b/components/blocks/componentSlider.js @@ -10,7 +10,7 @@ import styles from "./componentSlider.module.css"; const Arrow = ({ onClick, type }) => { return ( ); }; diff --git a/components/blocks/componentSlider.module.css b/components/blocks/componentSlider.module.css index e37e7a5a4..62376fe9b 100644 --- a/components/blocks/componentSlider.module.css +++ b/components/blocks/componentSlider.module.css @@ -1,5 +1,5 @@ .SectionContainer { - @apply relative; + @apply relative mt-8; } /* Styles to align the slider with the API reference grid above and below */ @@ -79,15 +79,19 @@ /* Slider arrow styles */ .ArrowsContainer { - @apply flex list-none m-0; + @apply flex list-none m-0 gap-2; } .ArrowsContainer li { - @apply m-0 ml-2; + @apply flex p-0 m-0; } .ArrowsContainer li button { - @apply transition ease-in-out duration-100 hover:text-gray-50 text-gray-60; + @apply transition ease-in-out duration-100 hover:text-gray-50 text-gray-60 flex; +} + +.ArrowsContainer li button i { + @apply w-4 text-base; } /* Hide the default arrows */ From 86f1e8814ebff086ff8140712f490edb04732944 Mon Sep 17 00:00:00 2001 From: Thiago Teixeira Date: Sat, 20 Dec 2025 00:46:07 -0300 Subject: [PATCH 12/20] Refactor and add nicer timeout for copy button --- components/blocks/autofunction.js | 8 +- components/blocks/code.js | 160 ++++++++++++++---------------- 2 files changed, 80 insertions(+), 88 deletions(-) diff --git a/components/blocks/autofunction.js b/components/blocks/autofunction.js index a3e1702db..264c95863 100644 --- a/components/blocks/autofunction.js +++ b/components/blocks/autofunction.js @@ -84,6 +84,7 @@ const Autofunction = ({ blockRef.current.getElementsByTagName("pre"), ); + // Important: keep this in sync with components/block/code.js pres.forEach((ele) => { // Detect language based on pre element class const isLiteralBlock = ele.classList.contains("literal-block"); @@ -552,7 +553,12 @@ const Autofunction = ({ ); return ( -
+
{header} {body}
diff --git a/components/blocks/code.js b/components/blocks/code.js index a5038c395..5e1e4736b 100644 --- a/components/blocks/code.js +++ b/components/blocks/code.js @@ -130,14 +130,17 @@ const Code = ({ children, language, img, + // Lines to highlight. For example: "1, 5-7, 9" lines, hideCopyButton = false, + hideHeader = false, filename, showAll = false, try: tryIt = false, }) => { // Create a ref for the code element. const codeRef = useRef(null); + hideCopyButton |= hideHeader; useEffect(() => { // Get the language from the className, if it exists. @@ -155,39 +158,14 @@ const Code = ({ importLanguage = "javascript"; } - // After we have the values, let's import just the necessary languages - async function highlight() { - if (typeof window !== "undefined") { - // Only import the language if it hasn't been imported before. - if (!languageImports.has(importLanguage)) { - try { - await import(`prismjs/components/prism-${importLanguage}`); - languageImports.set(importLanguage, true); - } catch (error) { - console.error( - `Prism doesn't support this language: ${importLanguage}`, - ); - } - } - // Highlight the code block and conditionally enable toolbar plugins (including copy button) - if (codeRef.current) { - // First highlight the element - Prism.highlightElement(codeRef.current); - // Then activate toolbar plugins on the parent container if copy button is not hidden - if (!hideCopyButton) { - const container = codeRef.current.closest(`.${styles.Container}`); - if (container) { - Prism.highlightAllUnder(container); - } - } - } - } - } - - highlight(); + highlightElement( + importLanguage, + languageImports, + codeRef.current, + hideCopyButton, + ); }, [children]); - let ConditionalRendering; let customCode = code !== undefined ? code : children; let languageClass = `language-${language}`; @@ -202,65 +180,73 @@ const Code = ({ const showLanguage = langId.toLowerCase() !== "none" && (showAll || !filename); - const Header = ( -
- {showLanguage && ( - {displayLanguage} + // Important: keep this in sync with components/block/autofunction.js + return ( +
+ {!hideHeader && ( +
+ {showLanguage && ( + {displayLanguage} + )} + {filename && {filename}} + {tryIt && } +
)} - {filename && {filename}} - {tryIt && } -
- ); - if (img) { - ConditionalRendering = ( -
- {Header} - -
-          
-            {customCode}
-          
-        
-
- ); - } else if (lines) { - ConditionalRendering = ( -
- {Header} -
-          
-            {customCode}
-          
-        
-
- ); - } else { - ConditionalRendering = ( -
- {Header} -
-          
-            {customCode}
-          
-        
-
- ); - } + {img && } - return ConditionalRendering; +
+        
+          {customCode}
+        
+      
+
+ ); }; +async function highlightElement( + importLanguage, + languageImports, + codeElement, + hideCopyButton, +) { + if (typeof window !== "undefined") { + // Only import the language if it hasn't been imported before. + if (!languageImports.has(importLanguage)) { + try { + await import(`prismjs/components/prism-${importLanguage}`); + languageImports.set(importLanguage, true); + } catch (error) { + console.error(`Prism doesn't support this language: ${importLanguage}`); + } + } + + // Highlight the code block and conditionally enable toolbar plugins (including copy button) + if (codeElement) { + // First highlight the element + Prism.highlightElement(codeElement); + + // Then activate toolbar plugins on the parent container if copy button is not hidden + if (!hideCopyButton) { + const container = codeElement.closest(`.${styles.Container}`); + if (container) { + Prism.highlightAllUnder(container); + } + } + } + } +} + export default Code; From 87ad5afe32c052bf063902b925f0d62403fbfbdf Mon Sep 17 00:00:00 2001 From: Thiago Teixeira Date: Sat, 20 Dec 2025 00:20:10 -0300 Subject: [PATCH 13/20] Add example of code block without header. --- content/get-started/fundamentals/advanced-concepts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/get-started/fundamentals/advanced-concepts.md b/content/get-started/fundamentals/advanced-concepts.md index a1c8c80eb..c20ba6fd1 100644 --- a/content/get-started/fundamentals/advanced-concepts.md +++ b/content/get-started/fundamentals/advanced-concepts.md @@ -107,12 +107,12 @@ st.dataframe(df) Of course, you may be wondering where your username and password go. Streamlit has a convenient mechanism for [Secrets management](/develop/concepts/connections/secrets-management). For now, let's just see how `st.connection` works very nicely with secrets. In your local project directory, you can save a `.streamlit/secrets.toml` file. You save your secrets in the toml file and `st.connection` just uses them! For example, if you have an app file `streamlit_app.py` your project directory may look like this: -```bash + your-LOCAL-repository/ ├── .streamlit/ │ └── secrets.toml # Make sure to gitignore this! └── streamlit_app.py -``` + For the above SQL example, your `secrets.toml` file might look like the following: From 499c92d3714fc9d49fd7c9ba793482cbda8f2542 Mon Sep 17 00:00:00 2001 From: Thiago Teixeira Date: Sat, 20 Dec 2025 00:38:41 -0300 Subject: [PATCH 14/20] Fix hydration errors. --- components/blocks/code.js | 4 ++-- components/blocks/componentCard.js | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/components/blocks/code.js b/components/blocks/code.js index 5e1e4736b..173a59d02 100644 --- a/components/blocks/code.js +++ b/components/blocks/code.js @@ -200,7 +200,7 @@ const Code = ({ {img && } -
@@ -211,7 +211,7 @@ const Code = ({
         >
           {customCode}
         
-      
+
); }; diff --git a/components/blocks/componentCard.js b/components/blocks/componentCard.js index 530b689e9..cf1e9e95f 100644 --- a/components/blocks/componentCard.js +++ b/components/blocks/componentCard.js @@ -2,22 +2,25 @@ import classNames from "classnames"; import genericStyles from "./refCard.module.css"; import customStyles from "./componentCard.module.css"; +import { useCallback } from "react"; const ComponentCard = ({ children, href }) => { + const onClick = useCallback(() => { + window.open(href, "_blank", "noopener,noreferrer"); + }, [href]); + return ( - {children} - + ); }; From d3536031b6d6c2b27921a2892e7d894dcd4a341a Mon Sep 17 00:00:00 2001 From: Thiago Teixeira Date: Sat, 20 Dec 2025 00:40:39 -0300 Subject: [PATCH 15/20] Rename Bash->Terminal in code blocks. --- components/blocks/code.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/blocks/code.js b/components/blocks/code.js index 173a59d02..9fbe23976 100644 --- a/components/blocks/code.js +++ b/components/blocks/code.js @@ -94,8 +94,10 @@ const languageDisplayNames = { js: "JavaScript", typescript: "TypeScript", ts: "TypeScript", - bash: "Bash", - sh: "Bash", + // Rename Bash to Terminal since Windows doesn't use Bash, and most of the commands we + // mark as Bash here would actually work in any terminal. + bash: "Terminal", + sh: "Sh", shell: "Shell", json: "JSON", yaml: "YAML", From 033d6092304babc9303642515064774d37b774c0 Mon Sep 17 00:00:00 2001 From: Thiago Teixeira Date: Sat, 20 Dec 2025 02:01:20 -0300 Subject: [PATCH 16/20] Fix rebase errors and improve design of `try it` button --- components/blocks/autofunction.module.css | 90 +++++++++----- components/blocks/code.js | 30 ++--- components/blocks/code.module.css | 136 +++++++++++++--------- styles/syntax-highlighting.scss | 104 ++++++++--------- 4 files changed, 199 insertions(+), 161 deletions(-) diff --git a/components/blocks/autofunction.module.css b/components/blocks/autofunction.module.css index 155ac3f70..c3517e741 100644 --- a/components/blocks/autofunction.module.css +++ b/components/blocks/autofunction.module.css @@ -59,54 +59,96 @@ } .CodeBlockContainer { - @apply mb-7 relative; + @apply mb-7 relative bg-gray-90 rounded-xl; } +/* Keep in sync with components/blocks/code.module.css */ .Header { - @apply flex items-center px-3 py-1 bg-gray-10 text-gray-70 text-sm font-mono font-medium tracking-wide rounded-t-xl border-b border-gray-30; - min-height: 2.5rem; + @apply flex items-center + min-h-10 px-3 + border-b border-gray-80 + text-gray-50 text-xs font-medium tracking-wide; } -:global(.dark) .Header { - @apply bg-gray-90 text-gray-60 border-gray-80; +/* Keep in sync with components/blocks/code.module.css */ +.Language { + @apply uppercase tracking-wider leading-none; } -.Language { - @apply uppercase pr-4 font-mono; +/* Keep in sync with components/blocks/code.module.css */ +.CodeBlockContainer pre { + @apply p-6 text-white font-medium relative leading-relaxed; } +/* Keep in sync with components/blocks/code.module.css */ .CodeBlockContainer pre, .CodeBlockContainer code { @apply overflow-auto max-w-full whitespace-pre; } -.CodeBlockContainer pre { - @apply p-6 bg-gray-10 text-gray-80 font-medium rounded-b-xl relative leading-relaxed; -} - +/* Keep in sync with components/blocks/autofunction.module.css */ .CodeBlockContainer pre code { @apply z-10 relative; } +/* Keep in sync with components/blocks/code.module.css */ .LineHighlight { @apply bg-gray-80 opacity-30 z-0; } -.CodeBlockContainer button { - @apply absolute top-2 right-1 cursor-pointer h-8 w-8 mb-0 flex items-center justify-center; +/* Keep in sync with components/blocks/code.module.css */ +.Container :global(.toolbar) { + @apply absolute top-0 right-0 + flex items-center justify-end + px-3 h-10 + text-gray-80 text-xs font-medium tracking-wide; +} + +/* Keep in sync with components/blocks/code.module.css */ +.Container :global(.toolbar-item) { + @apply flex items-center justify-end; } -.CodeBlockContainer button::before { - @apply z-10 transition-all duration-75 hover:opacity-40; - content: url("/clipboard.svg"); +/* Keep in sync with components/blocks/code.module.css */ +.CodeBlockContainer button { + @apply flex flex-row gap-1 + h-full + text-xs leading-none + text-gray-50 hover:text-white; } +/* Keep in sync with components/blocks/code.module.css */ .CodeBlockContainer button span { - @apply absolute -top-0.5 right-10 text-gray-80 font-mono text-sm tracking-tight font-normal opacity-0; + @apply flex items-center justify-start + tracking-wide font-medium; +} + +/* Keep in sync with components/blocks/code.module.css */ +.CodeBlockContainer :global(.copy-to-clipboard-button) { + &::after { + @apply block text-gray-50 hover:text-white h-3 w-3 cursor-pointer; + content: ""; + background-color: currentColor; + -webkit-mask-image: url("/clipboard.svg"); + mask-image: url("/clipboard.svg"); + mask-size: contain; + -webkit-mask-size: contain; + mask-repeat: no-repeat; + } + + & span { + @apply text-white + opacity-0 translate-x-2 transition-transform + pointer-events-none; + } + + &:hover span { + @apply opacity-100 translate-x-0; + } } -.CodeBlockContainer button:hover span { - @apply opacity-100; +.NoCopyButton :global(.copy-to-clipboard-button) { + @apply hidden; } /* Syntax highlighting is now handled globally via styles/syntax-highlighting.scss */ @@ -144,13 +186,3 @@ :global(.dark) .Keyword::after { @apply bg-gray-80 text-gray-30; } - -/* Dark mode for code blocks */ -:global(.dark) .CodeBlockContainer pre { - @apply bg-gray-90 text-white; -} - -/* Dark mode button text */ -:global(.dark) .CodeBlockContainer button span { - @apply text-white; -} diff --git a/components/blocks/code.js b/components/blocks/code.js index 9fbe23976..a48e08c78 100644 --- a/components/blocks/code.js +++ b/components/blocks/code.js @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import classNames from "classnames"; import Prism from "prismjs"; import "prismjs/plugins/line-numbers/prism-line-numbers"; @@ -51,36 +51,20 @@ async function compressCodeForPlayground(code) { return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_"); } -// TryMeButton component const TryMeButton = ({ code }) => { - const [playgroundUrl, setPlaygroundUrl] = useState(null); - - useEffect(() => { - async function generateUrl() { - if (code) { - const encoded = await compressCodeForPlayground(code.trim()); - setPlaygroundUrl( - `https://streamlit.io/playground?example=blank&code=${encoded}`, - ); - } - } - generateUrl(); + const onClick = useCallback(async () => { + const encoded = await compressCodeForPlayground(code.trim()); + const url = `https://streamlit.io/playground?example=blank&code=${encoded}`; + window.open(url, "_blank", "noopener,noreferrer"); }, [code]); - if (!playgroundUrl) return null; - return ( - + ); }; diff --git a/components/blocks/code.module.css b/components/blocks/code.module.css index 97b9716ed..4fecd27e9 100644 --- a/components/blocks/code.module.css +++ b/components/blocks/code.module.css @@ -1,107 +1,129 @@ .Container { - @apply w-full my-7 mx-auto overflow-x-auto; + @apply w-full my-7 mx-auto overflow-x-auto bg-gray-90 rounded-xl; + @apply relative !important; } +/* Keep in sync with components/blocks/autofunction.module.css */ .Header { - @apply flex items-center px-3 py-1 bg-gray-10 text-gray-70 text-sm font-mono font-medium tracking-wide rounded-t-xl border-b border-gray-30; - min-height: 2.5rem; -} - -:global(.dark) .Header { - @apply bg-gray-90 text-gray-60 border-gray-80; + @apply flex items-center gap-2 + min-h-10 px-3 + border-b border-gray-80 + text-gray-50 text-xs font-medium tracking-wide; } +/* Keep in sync with components/blocks/autofunction.module.css */ .Language { - @apply uppercase pr-4 font-mono; + @apply uppercase tracking-wider; } .Filename { - @apply leading-6 pr-4; + @apply font-mono tracking-wider; } -.HasHeader { - @apply rounded-t-none !important; +/* Keep in sync with components/blocks/autofunction.module.css */ +.Pre { + @apply p-6 text-white font-medium relative leading-relaxed; } +/* Keep in sync with components/blocks/autofunction.module.css */ .Pre, .Container code { @apply overflow-auto max-w-full whitespace-pre; } -.Pre { - @apply p-6 bg-gray-10 text-gray-80 font-medium rounded-xl relative leading-relaxed; -} - -/* Dark mode background and text for Pre */ -:global(.dark) .Pre { - @apply bg-gray-90 text-white; -} - -.Container pre { - @apply overflow-auto max-w-full whitespace-pre; -} - +/* Keep in sync with components/blocks/autofunction.module.css */ .Pre code { @apply z-10 relative; } +/* Keep in sync with components/blocks/autofunction.module.css */ .LineHighlight { @apply bg-gray-80 opacity-30 z-0; } -.Container button { - @apply absolute top-2 right-1 cursor-pointer h-8 w-8 mb-0 flex items-center justify-center; -} -.Container button::before { - @apply z-10 transition-all duration-75 hover:opacity-60; - content: url("/clipboard.svg"); +/* Keep in sync with components/blocks/autofunction.module.css */ +.Container :global(.toolbar) { + @apply absolute top-0 right-0 + flex items-center justify-end + px-3 h-10 + text-gray-80 text-xs font-medium tracking-wide; } -.Container button span { - @apply absolute -top-0.5 right-10 text-gray-70 font-mono text-sm tracking-tight font-normal opacity-0; +/* Keep in sync with components/blocks/autofunction.module.css */ +.Container :global(.toolbar-item) { + @apply flex items-center justify-end; } -:global(.dark) .Container button span { - @apply text-gray-70 !important; +/* Keep in sync with components/blocks/autofunction.module.css */ +.Container button { + @apply flex flex-row gap-1 + h-full + text-xs leading-none + text-gray-50 hover:text-white; } -/* Hide "Copy" text completely */ -.Container button[data-copy-state="copy"] span { - @apply hidden; +/* Keep in sync with components/blocks/autofunction.module.css */ +.Container button span { + @apply flex items-center justify-start + tracking-wide font-medium; } -/* Show "Copied!" text */ -.Container button[data-copy-state="copy-success"] span { - @apply opacity-100; +.Container button i { + @apply flex text-xs leading-none; } -.NoCopyButton button { +.TryMeButton { + @apply px-2 py-1 rounded-md + border border-gray-80 hover:border-white; +} + +/* Keep in sync with components/blocks/autofunction.module.css */ +.Container :global(.copy-to-clipboard-button) { + &::after { + @apply block text-gray-50 hover:text-white h-3 w-3 cursor-pointer; + content: ""; + background-color: currentColor; + -webkit-mask-image: url("/clipboard.svg"); + mask-image: url("/clipboard.svg"); + mask-size: contain; + -webkit-mask-size: contain; + mask-repeat: no-repeat; + } + + & span { + @apply text-white + opacity-0 translate-x-2 transition-transform + pointer-events-none; + } + + &:hover span { + @apply opacity-100 translate-x-0; + } +} + +.NoCopyButton :global(.copy-to-clipboard-button) { @apply hidden; } -/* Dark mode button text */ -:global(.dark) .Container button span { - @apply text-gray-40; +.TryMeButton { + @apply h-3 flex flex-row gap-1; } -/* Syntax highlighting is now handled globally via styles/syntax-highlighting.scss */ - -/* Try Me Button */ -.TryMeButton { - @apply flex items-center text-gray-90 gap-1 pr-4 rounded text-sm font-medium transition-all duration-150; - @apply hover:opacity-60; - text-decoration: none !important; +:global(.refcard) .Container { + @apply rounded-none bg-transparent; } -:global(.dark) .TryMeButton { - @apply text-white; +:global(.refcard) .Container .Pre { + @apply p-0 text-gray-80; } -.TryMeIcon { - @apply text-lg leading-none; +:global(.refcard) .Container code { + @apply h-full p-4; } -.TryMeLabel { - @apply hidden sm:inline tracking-tight; +:global(.refcard) .Container :global(.code-toolbar) { + @apply px-0 py-0; } + +/* Syntax highlighting is now handled globally via styles/syntax-highlighting.scss */ diff --git a/styles/syntax-highlighting.scss b/styles/syntax-highlighting.scss index 3f50992b3..72f69bd94 100644 --- a/styles/syntax-highlighting.scss +++ b/styles/syntax-highlighting.scss @@ -2,64 +2,14 @@ * Centralized color definitions for all code blocks */ -/* Light mode syntax highlighting tokens */ -:root { - /* Primary syntax tokens */ - --syntax-operator: theme("colors.orange.80"); - --syntax-decorator: theme("colors.orange.80"); - --syntax-keyword: theme("colors.darkBlue.80"); - --syntax-builtin: theme("colors.lightBlue.80"); - --syntax-string: theme("colors.indigo.80"); - --syntax-number: theme("colors.green.70"); - --syntax-boolean: theme("colors.green.70"); - --syntax-function: theme("colors.red.70"); - --syntax-punctuation: theme("colors.gray.70"); - --syntax-comment: theme("colors.gray.70"); - - /* HTML/Markup tokens */ - --syntax-tag: theme("colors.red.70"); - --syntax-attr-name: theme("colors.lightBlue.80"); - --syntax-attr-value: theme("colors.green.80"); - --syntax-entity: theme("colors.green.70"); - - /* CSS tokens */ - --syntax-property: theme("colors.lightBlue.80"); - --syntax-selector: theme("colors.red.70"); - --syntax-rule: theme("colors.darkBlue.80"); - --syntax-atrule: theme("colors.darkBlue.80"); - --syntax-url: theme("colors.green.80"); - - /* Additional common tokens */ - --syntax-variable: theme("colors.orange.80"); - --syntax-class-name: theme("colors.lightBlue.80"); - --syntax-constant: theme("colors.green.70"); - --syntax-symbol: theme("colors.orange.80"); - --syntax-important: theme("colors.red.70"); - --syntax-regex: theme("colors.green.70"); - --syntax-namespace: theme("colors.lightBlue.80"); - --syntax-char: theme("colors.green.80"); - --syntax-interpolation: theme("colors.orange.80"); - --syntax-annotation: theme("colors.red.70"); - --syntax-generic: theme("colors.gray.70"); - --syntax-script: theme("colors.gray.70"); - --syntax-plain-text: theme("colors.gray.90"); - - /* Special tokens */ - --syntax-prolog: theme("colors.gray.70"); - --syntax-doctype: theme("colors.gray.70"); - --syntax-cdata: theme("colors.gray.70"); - --syntax-deleted: theme("colors.red.70"); - --syntax-inserted: theme("colors.green.70"); -} - /* Dark mode syntax highlighting tokens */ -.dark { +:root { /* Primary syntax tokens - keep existing dark mode colors */ --syntax-operator: theme("colors.yellow.80"); --syntax-decorator: theme("colors.yellow.80"); --syntax-keyword: theme("colors.darkBlue.50"); --syntax-builtin: theme("colors.lightBlue.60"); - --syntax-string: theme("colors.indigo.30"); + --syntax-string: theme("colors.darkBlue.30"); --syntax-number: theme("colors.green.40"); --syntax-boolean: theme("colors.green.40"); --syntax-function: theme("colors.red.60"); @@ -102,6 +52,56 @@ --syntax-inserted: theme("colors.green.70"); } +/* Light mode syntax highlighting tokens */ +.code-light { + /* Primary syntax tokens */ + --syntax-operator: theme("colors.yellow.90"); + --syntax-decorator: theme("colors.yellow.100"); + --syntax-keyword: theme("colors.darkBlue.70"); + --syntax-builtin: theme("colors.lightBlue.80"); + --syntax-string: theme("colors.green.80"); + --syntax-number: theme("colors.red.90"); + --syntax-boolean: theme("colors.green.60"); + --syntax-function: theme("colors.red.60"); + --syntax-punctuation: theme("colors.gray.60"); + --syntax-comment: theme("colors.gray.60"); + + /* HTML/Markup tokens */ + --syntax-tag: theme("colors.red.70"); + --syntax-attr-name: theme("colors.lightBlue.80"); + --syntax-attr-value: theme("colors.green.80"); + --syntax-entity: theme("colors.green.70"); + + /* CSS tokens */ + --syntax-property: theme("colors.lightBlue.80"); + --syntax-selector: theme("colors.red.70"); + --syntax-rule: theme("colors.darkBlue.80"); + --syntax-atrule: theme("colors.darkBlue.80"); + --syntax-url: theme("colors.green.80"); + + /* Additional common tokens */ + --syntax-variable: theme("colors.orange.80"); + --syntax-class-name: theme("colors.lightBlue.80"); + --syntax-constant: theme("colors.green.70"); + --syntax-symbol: theme("colors.orange.80"); + --syntax-important: theme("colors.red.70"); + --syntax-regex: theme("colors.green.70"); + --syntax-namespace: theme("colors.lightBlue.80"); + --syntax-char: theme("colors.green.80"); + --syntax-interpolation: theme("colors.orange.80"); + --syntax-annotation: theme("colors.red.70"); + --syntax-generic: theme("colors.gray.70"); + --syntax-script: theme("colors.gray.70"); + --syntax-plain-text: theme("colors.gray.90"); + + /* Special tokens */ + --syntax-prolog: theme("colors.gray.70"); + --syntax-doctype: theme("colors.gray.70"); + --syntax-cdata: theme("colors.gray.70"); + --syntax-deleted: theme("colors.red.70"); + --syntax-inserted: theme("colors.green.70"); +} + /* Global syntax highlighting classes using CSS custom properties */ /* Target code elements within our specific containers */ pre code .operator, From f0b658dbeb8eac508826ff035e1c0383a41d7ea3 Mon Sep 17 00:00:00 2001 From: Thiago Teixeira Date: Sat, 20 Dec 2025 02:13:29 -0300 Subject: [PATCH 17/20] Fix bug where copy button wasn't showing. This will lead to hydration errors, though --- components/blocks/code.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/blocks/code.js b/components/blocks/code.js index a48e08c78..565c55ad8 100644 --- a/components/blocks/code.js +++ b/components/blocks/code.js @@ -186,7 +186,7 @@ const Code = ({ {img && } -
@@ -197,7 +197,7 @@ const Code = ({ > {customCode} -
+
); }; From 771dda2c3adcfd390422159da5db9e5b0243105f Mon Sep 17 00:00:00 2001 From: Thiago Teixeira Date: Sat, 20 Dec 2025 02:16:29 -0300 Subject: [PATCH 18/20] Add comment. --- components/blocks/code.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/blocks/code.js b/components/blocks/code.js index 565c55ad8..39540dd01 100644 --- a/components/blocks/code.js +++ b/components/blocks/code.js @@ -186,6 +186,11 @@ const Code = ({ {img && } + {/* + The copy-to-clipboard feature requires
, but this leads to
+      hydration errors because sometimes there's already a 
 around this
+      entire component.
+      */}
       
Date: Sat, 20 Dec 2025 02:23:47 -0300
Subject: [PATCH 19/20] Fix ref cards

---
 components/blocks/code.module.css | 8 ++++++--
 styles/syntax-highlighting.scss   | 2 +-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/components/blocks/code.module.css b/components/blocks/code.module.css
index 4fecd27e9..acb68926b 100644
--- a/components/blocks/code.module.css
+++ b/components/blocks/code.module.css
@@ -115,11 +115,15 @@
 }
 
 :global(.refcard) .Container .Pre {
-  @apply p-0 text-gray-80;
+  @apply p-0 text-gray-80 h-full;
+
+  html:global(.dark) & {
+    @apply text-white;
+  }
 }
 
 :global(.refcard) .Container code {
-  @apply h-full p-4;
+  @apply block p-4 h-full;
 }
 
 :global(.refcard) .Container :global(.code-toolbar) {
diff --git a/styles/syntax-highlighting.scss b/styles/syntax-highlighting.scss
index 72f69bd94..b78b9ff94 100644
--- a/styles/syntax-highlighting.scss
+++ b/styles/syntax-highlighting.scss
@@ -53,7 +53,7 @@
 }
 
 /* Light mode syntax highlighting tokens */
-.code-light {
+html.light .code-light {
   /* Primary syntax tokens */
   --syntax-operator: theme("colors.yellow.90");
   --syntax-decorator: theme("colors.yellow.100");

From c7ad2ed1acf01bde15c5fbd3f34f03c07306cb38 Mon Sep 17 00:00:00 2001
From: Debbie Matthews 
Date: Sat, 20 Dec 2025 11:06:45 -0800
Subject: [PATCH 20/20] Add hideHeader boolean flag

---
 content/get-started/fundamentals/advanced-concepts.md | 4 ++--
 pages/[...slug].js                                    | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/content/get-started/fundamentals/advanced-concepts.md b/content/get-started/fundamentals/advanced-concepts.md
index c20ba6fd1..d99bbbacf 100644
--- a/content/get-started/fundamentals/advanced-concepts.md
+++ b/content/get-started/fundamentals/advanced-concepts.md
@@ -107,12 +107,12 @@ st.dataframe(df)
 
 Of course, you may be wondering where your username and password go. Streamlit has a convenient mechanism for [Secrets management](/develop/concepts/connections/secrets-management). For now, let's just see how `st.connection` works very nicely with secrets. In your local project directory, you can save a `.streamlit/secrets.toml` file. You save your secrets in the toml file and `st.connection` just uses them! For example, if you have an app file `streamlit_app.py` your project directory may look like this:
 
-
+```none hideHeader
 your-LOCAL-repository/
 ├── .streamlit/
 │   └── secrets.toml # Make sure to gitignore this!
 └── streamlit_app.py
-
+```
 
 For the above SQL example, your `secrets.toml` file might look like the following:
 
diff --git a/pages/[...slug].js b/pages/[...slug].js
index 22664ecb1..60271d9b1 100644
--- a/pages/[...slug].js
+++ b/pages/[...slug].js
@@ -201,7 +201,7 @@ export default function Article({
 
       if (metaString) {
         // Supported boolean flags (standalone words)
-        const booleanFlags = ["try", "showAll", "hideCopyButton"];
+        const booleanFlags = ["try", "showAll", "hideCopyButton", "hideHeader"];
 
         // Extract key="value" pairs (e.g., filename="app.py")
         const keyValueRegex = /(\w+)=["']([^"']+)["']/g;