diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..0902d1b --- /dev/null +++ b/.prettierignore @@ -0,0 +1,17 @@ +dist +node_modules +.yarn +build +coverage +.docusaurus +.github +.drone.yml + +docs +static + +*.md +*.json +*.js +*.compose.yml +i18n \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 77f4562..f2a72ff 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,9 +1,10 @@ { - "arrowParens": "always", - "bracketSpacing": false, - "bracketSameLine": true, - "printWidth": 80, - "proseWrap": "never", - "singleQuote": true, - "trailingComma": "all" -} \ No newline at end of file + "arrowParens": "always", + "bracketSpacing": true, + "bracketSameLine": false, + "printWidth": 110, + "proseWrap": "never", + "singleQuote": true, + "trailingComma": "none", + "tabWidth": 4 +} diff --git a/src/index.ts b/src/index.ts index 13f5aa7..c2c4c2d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,16 +5,15 @@ * LICENSE file in the root directory of this source tree. */ - /** * Notes * - how to add static files: https://github.com/facebook/docusaurus/discussions/6907 * ---> sitemap plugin: https://github.com/facebook/docusaurus/blob/main/packages/docusaurus-plugin-sitemap/src/index.ts * - call brython with arguments: https://github.com/brython-dev/brython/issues/2421 - * + * */ -import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations'; +import { readDefaultCodeTranslationMessages } from '@docusaurus/theme-translations'; import type { HtmlTags, LoadContext, Plugin } from '@docusaurus/types'; // eslint-disable-next-line import/no-extraneous-dependencies, import/order import logger from '@docusaurus/logger'; @@ -39,15 +38,12 @@ const extractImports = (script: string): string[] => { return imports.push(importImport[1]); } }); - return imports -} + return imports; +}; -const theme: Plugin<{ remoteHeadTags: HtmlTags[] }> = ( - context: LoadContext, - options: ThemeOptions, -) => { +const theme: Plugin<{ remoteHeadTags: HtmlTags[] }> = (context: LoadContext, options: ThemeOptions) => { const { - i18n: {currentLocale}, + i18n: { currentLocale } } = context; const libDir = options.libDir || DEFAULT_LIB_DIR; const isRemote = /https?:\/\//.test(libDir); @@ -57,7 +53,7 @@ const theme: Plugin<{ remoteHeadTags: HtmlTags[] }> = ( async loadContent() { const staticDir = path.join(context.siteDir, context.siteConfig.staticDirectories[0], libDir); let assets: string[] = []; - const bryModules: {name: string, content: string}[] = []; + const bryModules: { name: string; content: string }[] = []; if (!options.skipCopyAssetsToLibDir && !isRemote) { await fs.ensureDir(staticDir); if (process.env.NODE_ENV !== 'production') { @@ -72,7 +68,7 @@ const theme: Plugin<{ remoteHeadTags: HtmlTags[] }> = ( } if (isHashRouter && !isRemote) { const libs = await fs.readdir(staticDir); - const libraries: {[key: string]: string} = {}; + const libraries: { [key: string]: string } = {}; for (const lib of libs) { const libPath = path.join(staticDir, lib); if (libPath.endsWith('.py')) { @@ -84,32 +80,38 @@ const theme: Plugin<{ remoteHeadTags: HtmlTags[] }> = ( for (const libName of libNames) { const libContent = libraries[libName]; const imports = extractImports(libContent); - const injectAt = Math.max(...bryModules.map((lib, idx) => imports.includes(lib.name) ? idx : -1), -1); + const injectAt = Math.max( + ...bryModules.map((lib, idx) => (imports.includes(lib.name) ? idx : -1)), + -1 + ); if (injectAt < 0) { - bryModules.splice(0, 0, {name: libName, content: libContent}); + bryModules.splice(0, 0, { name: libName, content: libContent }); } else if (injectAt + 1 < bryModules.length) { - bryModules.splice(injectAt + 1, 0, {name: libName, content: libContent}); + bryModules.splice(injectAt + 1, 0, { + name: libName, + content: libContent + }); } else { - bryModules.push({name: libName, content: libContent}); + bryModules.push({ name: libName, content: libContent }); } } } return { assets: assets, bryModules: bryModules - } + }; }, getDefaultCodeTranslationMessages() { - return readDefaultCodeTranslationMessages({ - locale: currentLocale, - name: NAME, - }); + return readDefaultCodeTranslationMessages({ + locale: currentLocale, + name: NAME + }); }, async contentLoaded({ content, actions }) { const { setGlobalData } = actions; const libUrl = isRemote ? libDir : path.join(context.baseUrl, libDir, '/'); - setGlobalData({ - libDir: libUrl, + setGlobalData({ + libDir: libUrl, syncMaxOnceEvery: options.syncMaxOnceEvery || DEFAULT_OPTIONS.syncMaxOnceEvery }); }, @@ -120,9 +122,9 @@ const theme: Plugin<{ remoteHeadTags: HtmlTags[] }> = ( { test: /\.raw\.*/, type: 'asset/source' - }, - ], - }, + } + ] + } }; }, getThemePath() { @@ -131,27 +133,27 @@ const theme: Plugin<{ remoteHeadTags: HtmlTags[] }> = ( getTypeScriptThemePath() { return '../src/theme'; }, - injectHtmlTags({content}: {content: {bryModules: {name: string, content: string}[]}}) { + injectHtmlTags({ content }: { content: { bryModules: { name: string; content: string }[] } }) { return { headTags: [ { tagName: 'script', attributes: { src: options.brythonSrc || DEFAULT_OPTIONS.brythonSrc, - crossorigin: "anonymous", - referrerpolicy: "no-referrer", + crossorigin: 'anonymous', + referrerpolicy: 'no-referrer', defer: 'defer' - }, + } }, { tagName: 'script', attributes: { src: options.brythonStdlibSrc || DEFAULT_OPTIONS.brythonStdlibSrc, - crossorigin: "anonymous", - referrerpolicy: "no-referrer", + crossorigin: 'anonymous', + referrerpolicy: 'no-referrer', defer: 'defer' - }, - }, + } + } ], postBodyTags: content.bryModules.map((module) => { return { @@ -161,7 +163,7 @@ const theme: Plugin<{ remoteHeadTags: HtmlTags[] }> = ( type: 'text/python' }, innerHTML: module.content - } + }; }) }; }, @@ -169,8 +171,8 @@ const theme: Plugin<{ remoteHeadTags: HtmlTags[] }> = ( return []; } } as Plugin; -} +}; export default theme; -export {validateThemeConfig} from './options'; -export {ThemeOptions, Options}; \ No newline at end of file +export { validateThemeConfig } from './options'; +export { ThemeOptions, Options }; diff --git a/src/options.ts b/src/options.ts index c250658..623607d 100644 --- a/src/options.ts +++ b/src/options.ts @@ -5,9 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -import {Joi} from '@docusaurus/utils-validation'; +import { Joi } from '@docusaurus/utils-validation'; -import type {ThemeConfigValidationContext} from '@docusaurus/types'; +import type { ThemeConfigValidationContext } from '@docusaurus/types'; export type ThemeOptions = { /** @@ -42,8 +42,7 @@ export type ThemeOptions = { * @default 1000 */ syncMaxOnceEvery: number; -} - +}; export type Options = Partial; @@ -63,9 +62,10 @@ const ThemeOptionSchema = Joi.object({ syncMaxOnceEvery: Joi.number().default(DEFAULT_OPTIONS.syncMaxOnceEvery) }); -export function validateThemeConfig( - {themeConfig, validate}: ThemeConfigValidationContext -): ThemeOptions { - const validatedConfig = validate(ThemeOptionSchema, themeConfig); - return validatedConfig; -} \ No newline at end of file +export function validateThemeConfig({ + themeConfig, + validate +}: ThemeConfigValidationContext): ThemeOptions { + const validatedConfig = validate(ThemeOptionSchema, themeConfig); + return validatedConfig; +} diff --git a/src/theme/CodeBlock/index.tsx b/src/theme/CodeBlock/index.tsx index 46be594..5ac25d9 100644 --- a/src/theme/CodeBlock/index.tsx +++ b/src/theme/CodeBlock/index.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import CodeBlock, {type Props as CodeBlockType} from '@theme-init/CodeBlock'; +import CodeBlock, { type Props as CodeBlockType } from '@theme-init/CodeBlock'; import type { WrapperProps } from '@docusaurus/types'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import CodeEditor, { type MetaProps } from '@theme/CodeEditor'; @@ -7,33 +7,43 @@ import CodeEditor, { type MetaProps } from '@theme/CodeEditor'; import ScriptContext from '@theme/CodeEditor/WithScript/ScriptContext'; import ContextEditor from '@theme/CodeEditor/ContextEditor'; - type Props = WrapperProps; - const sanitizedTitle = (id: string) => { if (!id) { return; } - return id.replace(/--/g, '<>').replace(/__/g, '<>').replace(/[-_]/g, ' ').replace(/<>/g, '_').replace(/<>/g, '-') -} + return id + .replace(/--/g, '<>') + .replace(/__/g, '<>') + .replace(/[-_]/g, ' ') + .replace(/<>/g, '_') + .replace(/<>/g, '-'); +}; -const extractMetaProps = (props: {metastring?: string}): MetaProps => { +const extractMetaProps = (props: { metastring?: string }): MetaProps => { const metaString = (props?.metastring || '').replace(/\s*=\s*/g, '='); // remove spaces around = const metaRaw = metaString.split(/\s+/).map((s) => s.trim().split('=')); - return metaRaw.reduce((acc, [key, value]) => { - if (!key) { + return metaRaw.reduce( + (acc, [key, value]) => { + if (!key) { + return acc; + } + /** casts to booleans and numbers. When no value was provided, true is used */ + const val = + value === 'true' + ? true + : value === 'false' + ? false + : !Number.isNaN(Number(value)) + ? Number(value) + : value || true; + acc[key] = val; return acc; - } - /** casts to booleans and numbers. When no value was provided, true is used */ - const val = value === 'true' ? true - : value === 'false' ? false - : !Number.isNaN(Number(value)) ? Number(value) - : value || true; - acc[key] = val; - return acc; - }, {} as {[key: string]: number | string | boolean}); -} + }, + {} as { [key: string]: number | string | boolean } + ); +}; export default function CodeBlockWrapper(props: Props): JSX.Element { const metaProps = extractMetaProps(props); @@ -48,19 +58,13 @@ export default function CodeBlockWrapper(props: Props): JSX.Element { if (metaProps.live_py && ExecutionEnvironment.canUseDOM) { const title = props.title || metaProps.title; - const rawcode: string = (props.children as string || '').replace(/\s*\n$/, ''); + const rawcode: string = ((props.children as string) || '').replace(/\s*\n$/, ''); let code = rawcode; return ( - + {props.children} ); } - return ( - - ); -} \ No newline at end of file + return ; +} diff --git a/src/theme/CodeEditor/Actions/DownloadCode.tsx b/src/theme/CodeEditor/Actions/DownloadCode.tsx index d38aca4..d0884da 100644 --- a/src/theme/CodeEditor/Actions/DownloadCode.tsx +++ b/src/theme/CodeEditor/Actions/DownloadCode.tsx @@ -3,36 +3,37 @@ import { useStore, useScript } from '@theme/CodeEditor/hooks'; import Button, { Color } from '@theme/CodeEditor/Button'; import { translate } from '@docusaurus/Translate'; - -const DownloadCode = (props: {title: string}) => { +const DownloadCode = (props: { title: string }) => { const store = useStore(); const code = useScript(store, 'code'); const lang = useScript(store, 'lang'); const id = useScript(store, 'id'); return ( - ) -} + ); +}; -export default Button; \ No newline at end of file +export default Button; diff --git a/src/theme/CodeEditor/Button/styles.module.css b/src/theme/CodeEditor/Button/styles.module.css index 1595750..cbc0bb9 100644 --- a/src/theme/CodeEditor/Button/styles.module.css +++ b/src/theme/CodeEditor/Button/styles.module.css @@ -6,4 +6,4 @@ cursor: pointer; margin: 0px 2px; padding: 4px 10px; -} \ No newline at end of file +} diff --git a/src/theme/CodeEditor/CodeHistory/index.tsx b/src/theme/CodeEditor/CodeHistory/index.tsx index 585885f..9093aeb 100644 --- a/src/theme/CodeEditor/CodeHistory/index.tsx +++ b/src/theme/CodeEditor/CodeHistory/index.tsx @@ -17,7 +17,7 @@ const highlightSyntax = (str: string) => { return ( ); @@ -40,16 +40,26 @@ const CodeHistory = () => {
- { - versionsLoaded - ? translate({message: '{n} Versions', id: 'CodeHistory.nVersions.text'}, {n: versions.length}) - : translate({message: 'Load Versions', id: 'CodeHistory.LoadVersions.text'}) - } + {versionsLoaded + ? translate( + { + message: '{n} Versions', + id: 'CodeHistory.nVersions.text' + }, + { n: versions.length } + ) + : translate({ + message: 'Load Versions', + id: 'CodeHistory.LoadVersions.text' + })}
{versions.length > 1 && ( @@ -95,7 +103,9 @@ const CodeHistory = () => { {`V${version}`} {versions[version].pasted && ( - Pasted + + Pasted + )}
@@ -105,7 +115,9 @@ const CodeHistory = () => { {`V${version}`} {versions[version].pasted && ( - Pasted + + Pasted + )} diff --git a/src/theme/CodeEditor/CodeHistory/styles.module.css b/src/theme/CodeEditor/CodeHistory/styles.module.css index 6b35e60..3432084 100644 --- a/src/theme/CodeEditor/CodeHistory/styles.module.css +++ b/src/theme/CodeEditor/CodeHistory/styles.module.css @@ -1,54 +1,54 @@ -.codeHistory>.historyDetails { - cursor: pointer; - margin-bottom: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; +.codeHistory > .historyDetails { + cursor: pointer; + margin-bottom: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; } .summary { - display: flex; - align-items: center; + display: flex; + align-items: center; } .spacer { - flex-grow: 1; - flex-shrink: 1; - flex-basis: 0; -} + flex-grow: 1; + flex-shrink: 1; + flex-basis: 0; +} .versionControl { - padding: 1em 2em; - box-shadow: var(--ifm-global-shadow-lw); - border-radius: var(--ifm-global-radius); + padding: 1em 2em; + box-shadow: var(--ifm-global-shadow-lw); + border-radius: var(--ifm-global-radius); } .faButton { - margin-left: 1em; + margin-left: 1em; } .faButton:hover { - transform: scale(1.2); + transform: scale(1.2); } .diffViewer { - --ifm-pre-background: rgba(255, 255, 255, 0); - --ifm-alert-background-color: rgba(255, 255, 255, 0); - --ifm-alert-background-color-highlight: rgba(255, 255, 255, 0); - --ifm-table-stripe-background: rgba(255, 255, 255, 0); - font-family: monospace; - overflow: auto; + --ifm-pre-background: rgba(255, 255, 255, 0); + --ifm-alert-background-color: rgba(255, 255, 255, 0); + --ifm-alert-background-color-highlight: rgba(255, 255, 255, 0); + --ifm-table-stripe-background: rgba(255, 255, 255, 0); + font-family: monospace; + overflow: auto; } .diffViewer table tbody tr td { - padding-top: 0; - padding-bottom: 0; + padding-top: 0; + padding-bottom: 0; } .diffViewer table tbody tr td pre { - white-space: nowrap; - padding-top: 0; - padding-bottom: 0; - line-height: 18px; + white-space: nowrap; + padding-top: 0; + padding-bottom: 0; + line-height: 18px; } .diffHeader { - display: flex; - justify-content: space-between; -} \ No newline at end of file + display: flex; + justify-content: space-between; +} diff --git a/src/theme/CodeEditor/ContextEditor/index.tsx b/src/theme/CodeEditor/ContextEditor/index.tsx index f23d204..4e299e3 100644 --- a/src/theme/CodeEditor/ContextEditor/index.tsx +++ b/src/theme/CodeEditor/ContextEditor/index.tsx @@ -12,13 +12,13 @@ interface Props extends MetaProps { const SPLIT_CODE_REGEX = /^(?:(?
.*?)\n###\s*PRE\s*)?(?.*?)(?:\n###\s*POST\s*(?.*))?$/s;
 const splitCode = (rawCode: string) => {
-    const {pre, code, post} = rawCode.replace(/\s*\n$/, '').match(SPLIT_CODE_REGEX).groups || {};
+    const { pre, code, post } = rawCode.replace(/\s*\n$/, '').match(SPLIT_CODE_REGEX).groups || {};
     return {
         pre: pre || '',
         code: code || '',
         post: post || ''
     };
-}
+};
 
 /**
  * Use this component when you want a working CodeEditor.
@@ -34,7 +34,7 @@ const ContextEditor = (props: Props) => {
     }
     if (ExecutionEnvironment.canUseDOM) {
         const title = props.title || lang;
-        const {pre, code, post} = splitCode(props.children as string || '');
+        const { pre, code, post } = splitCode((props.children as string) || '');
         return (
              {
             
         );
     }
-    return (
-        
-    );
-}
+    return ;
+};
 
-export default ContextEditor;
\ No newline at end of file
+export default ContextEditor;
diff --git a/src/theme/CodeEditor/Editor/EditorAce.tsx b/src/theme/CodeEditor/Editor/EditorAce.tsx
index d8a2d8b..0aa3a80 100644
--- a/src/theme/CodeEditor/Editor/EditorAce.tsx
+++ b/src/theme/CodeEditor/Editor/EditorAce.tsx
@@ -21,8 +21,8 @@ export interface Props {
 }
 
 const ALIAS_LANG_MAP_ACE = {
-    mpy: 'python',
-}
+    mpy: 'python'
+};
 
 const EditorAce = (props: Props) => {
     const eRef = React.useRef(null);
@@ -41,7 +41,7 @@ const EditorAce = (props: Props) => {
                     // commands is array of key bindings.
                     name: 'execute',
                     bindKey: { win: 'Ctrl-Enter', mac: 'Command-Enter' },
-                    exec: () => store.execScript(),
+                    exec: () => store.execScript()
                 });
             }
             node.editor.commands.addCommand({
@@ -50,7 +50,7 @@ const EditorAce = (props: Props) => {
                 bindKey: { win: 'Ctrl-s', mac: 'Command-s' },
                 exec: () => {
                     store.saveNow();
-                },
+                }
             });
             return () => {
                 if (node && node.editor) {
@@ -92,7 +92,7 @@ const EditorAce = (props: Props) => {
                 ref={eRef}
                 mode={ALIAS_LANG_MAP_ACE[lang as keyof typeof ALIAS_LANG_MAP_ACE] ?? lang}
                 theme="dracula"
-                onChange={(value: string, e: {action: 'insert' | 'remove'}) => {
+                onChange={(value: string, e: { action: 'insert' | 'remove' }) => {
                     store.setCode(value, e.action);
                 }}
                 readOnly={showRaw}
@@ -103,7 +103,7 @@ const EditorAce = (props: Props) => {
                 setOptions={{
                     displayIndentGuides: true,
                     vScrollBarAlwaysVisible: false,
-                    highlightGutterLine: false,
+                    highlightGutterLine: false
                 }}
                 showPrintMargin={false}
                 highlightActiveLine={false}
diff --git a/src/theme/CodeEditor/Editor/Header/index.tsx b/src/theme/CodeEditor/Editor/Header/index.tsx
index 1382677..dde87a2 100644
--- a/src/theme/CodeEditor/Editor/Header/index.tsx
+++ b/src/theme/CodeEditor/Editor/Header/index.tsx
@@ -27,15 +27,9 @@ const Header = (props: Props) => {
                 
                     
{props.title}
- {hasEdits && props.resettable && ( - - )} - {props.download && ( - - )} - {hasEdits && !props.noCompare && ( - - )} + {hasEdits && props.resettable && } + {props.download && } + {hasEdits && !props.noCompare && }
)} {lang === 'python' && } diff --git a/src/theme/CodeEditor/Editor/Header/styles.module.css b/src/theme/CodeEditor/Editor/Header/styles.module.css index 0cbabdf..d1d6650 100644 --- a/src/theme/CodeEditor/Editor/Header/styles.module.css +++ b/src/theme/CodeEditor/Editor/Header/styles.module.css @@ -3,7 +3,7 @@ display: flex; align-items: center; letter-spacing: 0.08em; - + z-index: calc(var(--ifm-z-index-fixed) - 2); padding: 0.2em; padding-left: 0.5em; @@ -15,13 +15,13 @@ } .controls > .title { - flex-shrink: 1; - flex-grow: 1; - overflow-x: hidden; - text-overflow: ellipsis; - white-space: nowrap; + flex-shrink: 1; + flex-grow: 1; + overflow-x: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .controls.slim { padding: 0; -} \ No newline at end of file +} diff --git a/src/theme/CodeEditor/Editor/HiddenCode/index.tsx b/src/theme/CodeEditor/Editor/HiddenCode/index.tsx index 37aed45..e3ce50e 100644 --- a/src/theme/CodeEditor/Editor/HiddenCode/index.tsx +++ b/src/theme/CodeEditor/Editor/HiddenCode/index.tsx @@ -12,7 +12,7 @@ interface Props { const HiddenCode = (props: Props) => { const [show, setShow] = React.useState(false); - const {code} = props; + const { code } = props; if (code.length === 0) { return null; } @@ -20,7 +20,11 @@ const HiddenCode = (props: Props) => {
{show && (
- + {code}
@@ -28,9 +32,15 @@ const HiddenCode = (props: Props) => {
); diff --git a/src/theme/CodeEditor/Editor/HiddenCode/styles.module.css b/src/theme/CodeEditor/Editor/HiddenCode/styles.module.css index ce923b8..efeb606 100644 --- a/src/theme/CodeEditor/Editor/HiddenCode/styles.module.css +++ b/src/theme/CodeEditor/Editor/HiddenCode/styles.module.css @@ -20,7 +20,7 @@ top: unset; bottom: 0px; } -.toggleButton>svg { +.toggleButton > svg { transition: all 0.1s ease; /* Adjust timing as needed */ } @@ -47,8 +47,6 @@ top: 0; } - - html[data-theme='dark'] .hiddenCode pre > code { background-color: var(--ifm-card-background-color); -} \ No newline at end of file +} diff --git a/src/theme/CodeEditor/Editor/Result/Graphics/Canvas.tsx b/src/theme/CodeEditor/Editor/Result/Graphics/Canvas.tsx index 0b7c677..629cd47 100644 --- a/src/theme/CodeEditor/Editor/Result/Graphics/Canvas.tsx +++ b/src/theme/CodeEditor/Editor/Result/Graphics/Canvas.tsx @@ -13,17 +13,20 @@ const downloadCanvas = (canvasId: string) => { var dt = canvas.toDataURL('image/png'); /* Change MIME type to trick the browser to downlaod the file instead of displaying it */ dt = dt.replace(/^data:image\/[^;]*/, 'data:application/octet-stream'); - + /* In addition to 's "download" attribute, you can define HTTP-style headers */ - dt = dt.replace(/^data:application\/octet-stream/, 'data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=Canvas.png'); - - var downloadLink = document.createElement("a"); + dt = dt.replace( + /^data:application\/octet-stream/, + 'data:application/octet-stream;headers=Content-Disposition%3A%20attachment%3B%20filename=Canvas.png' + ); + + var downloadLink = document.createElement('a'); downloadLink.href = dt; downloadLink.download = `${canvasId}.png`; document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); - }; +}; const Canvas = () => { const store = useStore(); @@ -33,28 +36,29 @@ const Canvas = () => { { - downloadCanvas(DOM_ELEMENT_IDS.canvasContainer(codeId)) + downloadCanvas(DOM_ELEMENT_IDS.canvasContainer(codeId)); }} title="Download SVG" className={styles.slimStrippedButton} /> } main={ - + }} + > } /> - ) + ); }; -export default Canvas; \ No newline at end of file +export default Canvas; diff --git a/src/theme/CodeEditor/Editor/Result/Graphics/Turtle.tsx b/src/theme/CodeEditor/Editor/Result/Graphics/Turtle.tsx index e3c42c6..6680680 100644 --- a/src/theme/CodeEditor/Editor/Result/Graphics/Turtle.tsx +++ b/src/theme/CodeEditor/Editor/Result/Graphics/Turtle.tsx @@ -16,24 +16,28 @@ const Turtle = () => { controls={