Skip to content

Commit

Permalink
Merge pull request #1163 from daslyfe/cross_orgin_check
Browse files Browse the repository at this point in the history
containerize/seperate out boolean checks for repl types/Repl logic into bespoke components.
  • Loading branch information
daslyfe authored Aug 15, 2024
2 parents 9d1674b + 053e4ee commit 3945abd
Show file tree
Hide file tree
Showing 7 changed files with 306 additions and 303 deletions.
30 changes: 11 additions & 19 deletions website/src/components/Udels/UdelsEditor.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { ReplContext } from '@src/repl/util.mjs';

import Loader from '@src/repl/components/Loader';
import { Panel } from '@src/repl/components/panel/Panel';
import { Code } from '@src/repl/components/Code';
Expand All @@ -8,27 +6,21 @@ import UserFacingErrorMessage from '@src/repl/components/UserFacingErrorMessage'

// type Props = {
// context: replcontext,
// containerRef: React.MutableRefObject<HTMLElement | null>,
// editorRef: React.MutableRefObject<HTMLElement | null>,
// error: Error
// init: () => void
// }

export default function UdelsEditor(Props) {
const { context, containerRef, editorRef, error, init } = Props;
const { pending, started, handleTogglePlay } = context;
const { context } = Props;
const { containerRef, editorRef, error, init, pending, started, handleTogglePlay } = context;

return (
<ReplContext.Provider value={context}>
<div className={'h-full flex w-full flex-col relative'}>
<Loader active={pending} />
{/* <Header context={context} /> */}
<BigPlayButton started={started} handleTogglePlay={handleTogglePlay} />
<div className="grow flex relative overflow-hidden">
<Code containerRef={containerRef} editorRef={editorRef} init={init} />
</div>
<UserFacingErrorMessage error={error} />
<Panel context={context} />
<div className={'h-full flex w-full flex-col relative'}>
<Loader active={pending} />
<BigPlayButton started={started} handleTogglePlay={handleTogglePlay} />
<div className="grow flex relative overflow-hidden">
<Code containerRef={containerRef} editorRef={editorRef} init={init} />
</div>
</ReplContext.Provider>
<UserFacingErrorMessage error={error} />
<Panel context={context} />
</div>
);
}
251 changes: 7 additions & 244 deletions website/src/repl/Repl.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,252 +4,15 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import { code2hash, logger, silence } from '@strudel/core';
import { getDrawContext } from '@strudel/draw';
import { transpiler } from '@strudel/transpiler';
import {
getAudioContext,
webaudioOutput,
resetGlobalEffects,
resetLoadedSounds,
initAudioOnFirstClick,
} from '@strudel/webaudio';
import { defaultAudioDeviceName } from '../settings.mjs';
import { getAudioDevices, setAudioDevice, setVersionDefaultsFrom } from './util.mjs';
import { StrudelMirror, defaultSettings } from '@strudel/codemirror';
import { clearHydra } from '@strudel/hydra';
import { useCallback, useEffect, useRef, useState } from 'react';
import { settingsMap, useSettings } from '../settings.mjs';
import {
setActivePattern,
setLatestCode,
createPatternID,
userPattern,
getViewingPatternData,
setViewingPatternData,
} from '../user_pattern_utils.mjs';
import { useStore } from '@nanostores/react';
import { prebake } from './prebake.mjs';
import { getRandomTune, initCode, loadModules, shareCode, ReplContext, isUdels } from './util.mjs';
import './Repl.css';
import { setInterval, clearInterval } from 'worker-timers';
import { getMetadata } from '../metadata_parser';
import { isIframe, isUdels } from './util.mjs';
import UdelsEditor from '@components/Udels/UdelsEditor';

import ReplEditor from './components/ReplEditor';

const { latestCode } = settingsMap.get();

let modulesLoading, presets, drawContext, clearCanvas, isIframe, audioReady;

if (typeof window !== 'undefined') {
audioReady = initAudioOnFirstClick();
modulesLoading = loadModules();
presets = prebake();
drawContext = getDrawContext();
clearCanvas = () => drawContext.clearRect(0, 0, drawContext.canvas.height, drawContext.canvas.width);
isIframe = window.location !== window.parent.location;
}

async function getModule(name) {
if (!modulesLoading) {
return;
}
const modules = await modulesLoading;
return modules.find((m) => m.packageName === name);
}
import EmbeddedReplEditor from './components/EmbeddedReplEditor';
import { useReplContext } from './useReplContext';

export function Repl({ embedded = false }) {
const isEmbedded = embedded || isIframe;
const { panelPosition, isZen, isSyncEnabled } = useSettings();
const init = useCallback(() => {
const drawTime = [-2, 2];
const drawContext = getDrawContext();
const editor = new StrudelMirror({
sync: isSyncEnabled,
defaultOutput: webaudioOutput,
getTime: () => getAudioContext().currentTime,
setInterval,
clearInterval,
transpiler,
autodraw: false,
root: containerRef.current,
initialCode: '// LOADING',
pattern: silence,
drawTime,
drawContext,
prebake: async () => Promise.all([modulesLoading, presets]),
onUpdateState: (state) => {
setReplState({ ...state });
},
onToggle: (playing) => {
if (!playing) {
clearHydra();
}
},
beforeEval: () => audioReady,
afterEval: (all) => {
const { code } = all;
//post to iframe parent (like Udels) if it exists...
window.parent?.postMessage(code);

setLatestCode(code);
window.location.hash = '#' + code2hash(code);
setDocumentTitle(code);
const viewingPatternData = getViewingPatternData();
setVersionDefaultsFrom(code);
const data = { ...viewingPatternData, code };
let id = data.id;
const isExamplePattern = viewingPatternData.collection !== userPattern.collection;

if (isExamplePattern) {
const codeHasChanged = code !== viewingPatternData.code;
if (codeHasChanged) {
// fork example
const newPattern = userPattern.duplicate(data);
id = newPattern.id;
setViewingPatternData(newPattern.data);
}
} else {
id = userPattern.isValidID(id) ? id : createPatternID();
setViewingPatternData(userPattern.update(id, data).data);
}
setActivePattern(id);
},
bgFill: false,
});
window.strudelMirror = editor;

// init settings

initCode().then(async (decoded) => {
let code, msg;
if (decoded) {
code = decoded;
msg = `I have loaded the code from the URL.`;
} else if (latestCode) {
code = latestCode;
msg = `Your last session has been loaded!`;
} else {
const { code: randomTune, name } = await getRandomTune();
code = randomTune;
msg = `A random code snippet named "${name}" has been loaded!`;
}
editor.setCode(code);
setDocumentTitle(code);
logger(`Welcome to Strudel! ${msg} Press play or hit ctrl+enter to run it!`, 'highlight');
});

editorRef.current = editor;
}, []);

const [replState, setReplState] = useState({});
const { started, isDirty, error, activeCode, pending } = replState;
const editorRef = useRef();
const containerRef = useRef();

// this can be simplified once SettingsTab has been refactored to change codemirrorSettings directly!
// this will be the case when the main repl is being replaced
const _settings = useStore(settingsMap, { keys: Object.keys(defaultSettings) });
useEffect(() => {
let editorSettings = {};
Object.keys(defaultSettings).forEach((key) => {
if (_settings.hasOwnProperty(key)) {
editorSettings[key] = _settings[key];
}
});
editorRef.current?.updateSettings(editorSettings);
}, [_settings]);

// on first load, set stored audio device if possible
useEffect(() => {
const { audioDeviceName } = _settings;
if (audioDeviceName !== defaultAudioDeviceName) {
getAudioDevices().then((devices) => {
const deviceID = devices.get(audioDeviceName);
if (deviceID == null) {
return;
}
setAudioDevice(deviceID);
});
}
}, []);

//
// UI Actions
//

const setDocumentTitle = (code) => {
const meta = getMetadata(code);
document.title = (meta.title ? `${meta.title} - ` : '') + 'Strudel REPL';
};

const handleTogglePlay = async () => {
editorRef.current?.toggle();
};

const resetEditor = async () => {
(await getModule('@strudel/tonal'))?.resetVoicings();
resetGlobalEffects();
clearCanvas();
clearHydra();
resetLoadedSounds();
editorRef.current.repl.setCps(0.5);
await prebake(); // declare default samples
};

const handleUpdate = async (patternData, reset = false) => {
setViewingPatternData(patternData);
editorRef.current.setCode(patternData.code);
if (reset) {
await resetEditor();
handleEvaluate();
}
};

const handleEvaluate = () => {
editorRef.current.evaluate();
};
const handleShuffle = async () => {
const patternData = await getRandomTune();
const code = patternData.code;
logger(`[repl] ✨ loading random tune "${patternData.id}"`);
setActivePattern(patternData.id);
setViewingPatternData(patternData);
await resetEditor();
editorRef.current.setCode(code);
editorRef.current.repl.evaluate(code);
};

const handleShare = async () => shareCode(replState.code);
const context = {
embedded,
started,
pending,
isDirty,
activeCode,
handleTogglePlay,
handleUpdate,
handleShuffle,
handleShare,
handleEvaluate,
};

if (isUdels()) {
return (
<UdelsEditor context={context} error={error} init={init} editorRef={editorRef} containerRef={containerRef} />
);
}

return (
<ReplEditor
panelPosition={panelPosition}
isEmbedded={isEmbedded}
context={context}
error={error}
init={init}
editorRef={editorRef}
containerRef={containerRef}
/>
);
const isEmbedded = embedded || isIframe();
const Editor = isUdels() ? UdelsEditor : isEmbedded ? EmbeddedReplEditor : ReplEditor;
const context = useReplContext();
return <Editor context={context} />;
}
25 changes: 25 additions & 0 deletions website/src/repl/components/EmbeddedReplEditor.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Loader from '@src/repl/components/Loader';
import { Code } from '@src/repl/components/Code';
import BigPlayButton from '@src/repl/components/BigPlayButton';
import UserFacingErrorMessage from '@src/repl/components/UserFacingErrorMessage';
import { Header } from './Header';

// type Props = {
// context: replcontext,
// }

export default function EmbeddedReplEditor(Props) {
const { context } = Props;
const { pending, started, handleTogglePlay, containerRef, editorRef, error, init } = context;
return (
<div className="h-full flex flex-col relative">
<Loader active={pending} />
<Header context={context} embedded={true} />
<BigPlayButton started={started} handleTogglePlay={handleTogglePlay} />
<div className="grow flex relative overflow-hidden">
<Code containerRef={containerRef} editorRef={editorRef} init={init} />
</div>
<UserFacingErrorMessage error={error} />
</div>
);
}
17 changes: 4 additions & 13 deletions website/src/repl/components/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,14 @@ import SparklesIcon from '@heroicons/react/20/solid/SparklesIcon';
import StopCircleIcon from '@heroicons/react/20/solid/StopCircleIcon';
import cx from '@src/cx.mjs';
import { useSettings, setIsZen } from '../../settings.mjs';
// import { ReplContext } from './Repl';
import '../Repl.css';

const { BASE_URL } = import.meta.env;
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;

export function Header({ context }) {
const {
embedded,
started,
pending,
isDirty,
activeCode,
handleTogglePlay,
handleEvaluate,
handleShuffle,
handleShare,
} = context;
export function Header({ context, embedded = false }) {
const { started, pending, isDirty, activeCode, handleTogglePlay, handleEvaluate, handleShuffle, handleShare } =
context;
const isEmbedded = typeof window !== 'undefined' && (embedded || window.location !== window.parent.location);
const { isZen } = useSettings();

Expand Down
Loading

0 comments on commit 3945abd

Please sign in to comment.