1- import React , { useEffect , useRef } from "react" ;
1+ import React , { useEffect , useRef , useState } from "react" ;
22import classNames from "classnames" ;
33import Prism from "prismjs" ;
44import "prismjs/plugins/line-numbers/prism-line-numbers" ;
@@ -12,6 +12,87 @@ import Image from "./image";
1212
1313import styles from "./code.module.css" ;
1414
15+ // Compress code with gzip and encode as base64 for Streamlit Playground
16+ async function compressCodeForPlayground ( code ) {
17+ const encoder = new TextEncoder ( ) ;
18+ const data = encoder . encode ( code ) ;
19+
20+ const cs = new CompressionStream ( "gzip" ) ;
21+ const writer = cs . writable . getWriter ( ) ;
22+ writer . write ( data ) ;
23+ writer . close ( ) ;
24+
25+ const compressedChunks = [ ] ;
26+ const reader = cs . readable . getReader ( ) ;
27+
28+ while ( true ) {
29+ const { done, value } = await reader . read ( ) ;
30+ if ( done ) break ;
31+ compressedChunks . push ( value ) ;
32+ }
33+
34+ // Combine all chunks into a single Uint8Array
35+ const totalLength = compressedChunks . reduce (
36+ ( acc , chunk ) => acc + chunk . length ,
37+ 0 ,
38+ ) ;
39+ const compressed = new Uint8Array ( totalLength ) ;
40+ let offset = 0 ;
41+ for ( const chunk of compressedChunks ) {
42+ compressed . set ( chunk , offset ) ;
43+ offset += chunk . length ;
44+ }
45+
46+ // Convert to URL-safe base64 (uses - and _ instead of + and /)
47+ let binary = "" ;
48+ for ( let i = 0 ; i < compressed . length ; i ++ ) {
49+ binary += String . fromCharCode ( compressed [ i ] ) ;
50+ }
51+ return btoa ( binary ) . replace ( / \+ / g, "-" ) . replace ( / \/ / g, "_" ) ;
52+ }
53+
54+ // TryMeButton component
55+ const TryMeButton = ( { code } ) => {
56+ const [ playgroundUrl , setPlaygroundUrl ] = useState ( null ) ;
57+
58+ useEffect ( ( ) => {
59+ async function generateUrl ( ) {
60+ if ( code ) {
61+ const encoded = await compressCodeForPlayground ( code . trim ( ) ) ;
62+ setPlaygroundUrl (
63+ `https://streamlit.io/playground?example=blank&code=${ encoded } ` ,
64+ ) ;
65+ }
66+ }
67+ generateUrl ( ) ;
68+ } , [ code ] ) ;
69+
70+ if ( ! playgroundUrl ) return null ;
71+
72+ return (
73+ < a
74+ href = { playgroundUrl }
75+ target = "_blank"
76+ rel = "noopener noreferrer"
77+ className = { styles . TryMeButton }
78+ title = "Try this code in Streamlit Playground"
79+ >
80+ < span className = { styles . TryMeLabel } > Try it!</ span >
81+ < svg
82+ className = { styles . TryMeIcon }
83+ viewBox = "0 0 24 24"
84+ fill = "none"
85+ stroke = "currentColor"
86+ strokeWidth = "2"
87+ strokeLinecap = "round"
88+ strokeLinejoin = "round"
89+ >
90+ < polygon points = "5 3 19 12 5 21 5 3" />
91+ </ svg >
92+ </ a >
93+ ) ;
94+ } ;
95+
1596// Initialize the cache for imported languages.
1697const languageImports = new Map ( ) ;
1798
@@ -62,6 +143,7 @@ const Code = ({
62143 hideCopyButton = false ,
63144 filename,
64145 filenameOnly = true ,
146+ try : tryIt = false ,
65147} ) => {
66148 // Create a ref for the code element.
67149 const codeRef = useRef ( null ) ;
@@ -135,6 +217,7 @@ const Code = ({
135217 < span className = { styles . Language } > { displayLanguage } </ span >
136218 ) }
137219 { filename && < span className = { styles . Filename } > { filename } </ span > }
220+ { tryIt && < TryMeButton code = { customCode } /> }
138221 </ div >
139222 ) ;
140223
0 commit comments