Skip to content
6 changes: 3 additions & 3 deletions components/blocks/autofunction.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
80 changes: 77 additions & 3 deletions components/blocks/code.js
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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 (
<a
href={playgroundUrl}
target="streamlit-playground"
className={styles.TryMeButton}
title="Try this code in Streamlit Playground"
>
<span className={styles.TryMeLabel}>Try it</span>
<i className={`material-icons-sharp ${styles.TryMeIcon}`}>
arrow_outward
</i>
</a>
);
};

// Initialize the cache for imported languages.
const languageImports = new Map();

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -127,14 +200,15 @@ 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 = (
<div className={classNames(styles.Header, "code-block-header")}>
{showLanguage && (
<span className={styles.Language}>{displayLanguage}</span>
)}
{filename && <span className={styles.Filename}>{filename}</span>}
{tryIt && <TryMeButton code={customCode} />}
</div>
);

Expand Down
47 changes: 38 additions & 9 deletions components/blocks/code.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 */
Expand All @@ -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;
}

Expand All @@ -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;
}
30 changes: 10 additions & 20 deletions content/develop/concepts/configuration/theming-fonts.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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]
Expand All @@ -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"
Expand Down Expand Up @@ -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

Expand All @@ -121,9 +119,7 @@ font="noto-sans"
codeFont="noto-mono"
```

Directory structure:

```none
```none filename="Directory structure"
project_directory/
├── .streamlit/
│ └── config.toml
Expand All @@ -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

Expand Down Expand Up @@ -178,9 +172,7 @@ weight=700
font="tuffy"
```

Directory structure:

```none
```none filename="Directory structure"
project_directory/
├── .streamlit/
│ └── config.toml
Expand All @@ -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"
Expand All @@ -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"
```
Expand Down
2 changes: 1 addition & 1 deletion content/get-started/fundamentals/main-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading