From b11de530f468e513f968920b580b43ffafd233b8 Mon Sep 17 00:00:00 2001 From: Chandler Abraham Date: Sat, 31 May 2025 14:31:13 -0700 Subject: [PATCH] First pass at save/upload --- website/src/repl/Repl.css | 30 +++++++++++ website/src/repl/components/Code.jsx | 10 ++-- .../src/repl/components/DownloadButton.jsx | 51 +++++++++++++++++++ website/src/repl/components/Header.jsx | 1 + website/src/repl/components/ReplEditor.jsx | 2 +- 5 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 website/src/repl/components/DownloadButton.jsx diff --git a/website/src/repl/Repl.css b/website/src/repl/Repl.css index 78740551d..2fda68308 100644 --- a/website/src/repl/Repl.css +++ b/website/src/repl/Repl.css @@ -76,3 +76,33 @@ outline-offset: -2px; background-color: rgba(76, 175, 80, 0.05) !important; } + +/* Download button styles */ +.download-button { + position: absolute; + top: 8px; + right: 8px; + z-index: 100; + background: rgba(0, 0, 0, 0.3); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 4px; + padding: 6px; + cursor: pointer; + color: rgba(255, 255, 255, 0.6); + transition: all 0.2s ease; + pointer-events: auto; +} + +.download-button:hover { + background: rgba(0, 0, 0, 0.5); + color: rgba(255, 255, 255, 0.9); + border-color: rgba(255, 255, 255, 0.2); +} + +.download-button:active { + transform: scale(0.95); +} + +.download-button svg { + display: block; +} diff --git a/website/src/repl/components/Code.jsx b/website/src/repl/components/Code.jsx index 8481cc272..e1c235348 100644 --- a/website/src/repl/components/Code.jsx +++ b/website/src/repl/components/Code.jsx @@ -1,14 +1,16 @@ +import DownloadButton from './DownloadButton'; + // type Props = { // containerRef: React.MutableRefObject, // editorRef: React.MutableRefObject, // init: () => void // } export function Code(Props) { - const { editorRef, containerRef, init } = Props; + const { editorRef, containerRef, init, context } = Props; return (
{ containerRef.current = el; @@ -16,6 +18,8 @@ export function Code(Props) { init(); } }} - >
+ > + {context && } + ); } diff --git a/website/src/repl/components/DownloadButton.jsx b/website/src/repl/components/DownloadButton.jsx new file mode 100644 index 000000000..adbcf6947 --- /dev/null +++ b/website/src/repl/components/DownloadButton.jsx @@ -0,0 +1,51 @@ +import { useCallback } from 'react'; + +export default function DownloadButton({ context }) { + const handleDownload = useCallback(() => { + // Get the current code from the editor + const code = context.code; + + // Create a blob with the code + const blob = new Blob([code], { type: 'text/javascript' }); + + // Create a temporary URL for the blob + const url = window.URL.createObjectURL(blob); + + // Create a temporary anchor element and trigger download + const a = document.createElement('a'); + a.href = url; + a.download = `strudel-pattern-${new Date().toISOString().slice(0, 10)}.js`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + + // Clean up the URL + window.URL.revokeObjectURL(url); + }, [context.code]); + + return ( + + ); +} \ No newline at end of file diff --git a/website/src/repl/components/Header.jsx b/website/src/repl/components/Header.jsx index 2963a5f97..2f5e46012 100644 --- a/website/src/repl/components/Header.jsx +++ b/website/src/repl/components/Header.jsx @@ -1,5 +1,6 @@ import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon'; import StopCircleIcon from '@heroicons/react/20/solid/StopCircleIcon'; +import ArrowDownTrayIcon from '@heroicons/react/20/solid/ArrowDownTrayIcon'; import cx from '@src/cx.mjs'; import { useSettings, setIsZen } from '../../settings.mjs'; import '../Repl.css'; diff --git a/website/src/repl/components/ReplEditor.jsx b/website/src/repl/components/ReplEditor.jsx index 23ceb122b..d2f52563f 100644 --- a/website/src/repl/components/ReplEditor.jsx +++ b/website/src/repl/components/ReplEditor.jsx @@ -20,7 +20,7 @@ export default function ReplEditor(Props) {
- + {!isZen && panelPosition === 'right' && }