mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-11 13:48:34 +00:00
better repl init + a bit of ssr for main repl
This commit is contained in:
parent
b0bdd09032
commit
9974311344
@ -1,4 +1,4 @@
|
|||||||
import { useState, useRef, useCallback, useMemo, useEffect, useLayoutEffect } from 'react';
|
import { useState, useRef, useCallback, useMemo, useEffect } from 'react';
|
||||||
import { Icon } from './Icon';
|
import { Icon } from './Icon';
|
||||||
import { silence, getPunchcardPainter, noteToMidi } from '@strudel.cycles/core';
|
import { silence, getPunchcardPainter, noteToMidi } from '@strudel.cycles/core';
|
||||||
import { transpiler } from '@strudel.cycles/transpiler';
|
import { transpiler } from '@strudel.cycles/transpiler';
|
||||||
@ -8,9 +8,7 @@ import { StrudelMirror } from '@strudel/codemirror';
|
|||||||
import { prebake } from '../repl/prebake.mjs';
|
import { prebake } from '../repl/prebake.mjs';
|
||||||
import { loadModules } from '../repl/util.mjs';
|
import { loadModules } from '../repl/util.mjs';
|
||||||
import Claviature from '@components/Claviature';
|
import Claviature from '@components/Claviature';
|
||||||
|
import useClient from '@src/useClient.mjs';
|
||||||
// https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85
|
|
||||||
export const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
|
||||||
|
|
||||||
let prebaked, modulesLoading;
|
let prebaked, modulesLoading;
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
@ -91,19 +89,7 @@ export function MiniRepl({
|
|||||||
const { started, isDirty, error } = replState;
|
const { started, isDirty, error } = replState;
|
||||||
const editorRef = useRef();
|
const editorRef = useRef();
|
||||||
const containerRef = useRef();
|
const containerRef = useRef();
|
||||||
const [client, setClient] = useState(false);
|
const client = useClient();
|
||||||
|
|
||||||
useIsomorphicLayoutEffect(() => {
|
|
||||||
setClient(true);
|
|
||||||
if (!editorRef.current) {
|
|
||||||
setTimeout(() => {
|
|
||||||
init({ code, shouldDraw });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return () => {
|
|
||||||
editorRef.current?.clear();
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (!client) {
|
if (!client) {
|
||||||
return <pre>{code}</pre>;
|
return <pre>{code}</pre>;
|
||||||
@ -136,7 +122,14 @@ export function MiniRepl({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="overflow-auto relative p-1">
|
<div className="overflow-auto relative p-1">
|
||||||
<div ref={containerRef}></div>
|
<div
|
||||||
|
ref={(el) => {
|
||||||
|
if (!editorRef.current) {
|
||||||
|
containerRef.current = el;
|
||||||
|
init({ code, shouldDraw });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
{error && <div className="text-right p-1 text-md text-red-200">{error.message}</div>}
|
{error && <div className="text-right p-1 text-md text-red-200">{error.message}</div>}
|
||||||
</div>
|
</div>
|
||||||
{shouldShowCanvas && (
|
{shouldShowCanvas && (
|
||||||
|
|||||||
@ -9,6 +9,6 @@ import { Repl } from '../repl/Repl';
|
|||||||
<title>Strudel REPL</title>
|
<title>Strudel REPL</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="h-app-height bg-background">
|
<body class="h-app-height bg-background">
|
||||||
<Repl client:only="react" />
|
<Repl client:load />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export function Header({ context }) {
|
|||||||
handleShuffle,
|
handleShuffle,
|
||||||
handleShare,
|
handleShare,
|
||||||
} = context;
|
} = context;
|
||||||
const isEmbedded = embedded || window.location !== window.parent.location;
|
const isEmbedded = typeof window !== 'undefined' && (embedded || window.location !== window.parent.location);
|
||||||
const { isZen } = useSettings();
|
const { isZen } = useSettings();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -35,19 +35,15 @@ export const ReplContext = createContext(null);
|
|||||||
|
|
||||||
const { latestCode } = settingsMap.get();
|
const { latestCode } = settingsMap.get();
|
||||||
|
|
||||||
initAudioOnFirstClick();
|
let modulesLoading, presets, drawContext, clearCanvas;
|
||||||
|
|
||||||
const modulesLoading = loadModules();
|
|
||||||
const presets = prebake();
|
|
||||||
|
|
||||||
let drawContext, clearCanvas;
|
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
|
initAudioOnFirstClick();
|
||||||
|
modulesLoading = loadModules();
|
||||||
|
presets = prebake();
|
||||||
drawContext = getDrawContext();
|
drawContext = getDrawContext();
|
||||||
clearCanvas = () => drawContext.clearRect(0, 0, drawContext.canvas.height, drawContext.canvas.width);
|
clearCanvas = () => drawContext.clearRect(0, 0, drawContext.canvas.height, drawContext.canvas.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const getTime = () => getAudioContext().currentTime;
|
|
||||||
|
|
||||||
export function Repl({ embedded = false }) {
|
export function Repl({ embedded = false }) {
|
||||||
//const isEmbedded = embedded || window.location !== window.parent.location;
|
//const isEmbedded = embedded || window.location !== window.parent.location;
|
||||||
const isEmbedded = false;
|
const isEmbedded = false;
|
||||||
@ -116,19 +112,6 @@ export function Repl({ embedded = false }) {
|
|||||||
const { started, isDirty, error, activeCode } = replState;
|
const { started, isDirty, error, activeCode } = replState;
|
||||||
const editorRef = useRef();
|
const editorRef = useRef();
|
||||||
const containerRef = useRef();
|
const containerRef = useRef();
|
||||||
const [client, setClient] = useState(false);
|
|
||||||
useEffect(() => {
|
|
||||||
setClient(true);
|
|
||||||
if (!editorRef.current) {
|
|
||||||
setTimeout(() => {
|
|
||||||
init({ shouldDraw });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return () => {
|
|
||||||
editorRef.current?.clear();
|
|
||||||
delete editorRef.current;
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// this can be simplified once SettingsTab has been refactored to change codemirrorSettings directly!
|
// 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
|
// this will be the case when the main repl is being replaced
|
||||||
@ -217,7 +200,12 @@ export function Repl({ embedded = false }) {
|
|||||||
<section
|
<section
|
||||||
className={'text-gray-100 cursor-text pb-0 overflow-auto grow' + (isZen ? ' px-10' : '')}
|
className={'text-gray-100 cursor-text pb-0 overflow-auto grow' + (isZen ? ' px-10' : '')}
|
||||||
id="code"
|
id="code"
|
||||||
ref={containerRef}
|
ref={(el) => {
|
||||||
|
containerRef.current = el;
|
||||||
|
if (!editorRef.current) {
|
||||||
|
init({ shouldDraw });
|
||||||
|
}
|
||||||
|
}}
|
||||||
></section>
|
></section>
|
||||||
{panelPosition === 'right' && !isEmbedded && <Panel context={context} />}
|
{panelPosition === 'right' && !isEmbedded && <Panel context={context} />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { logger } from '@strudel.cycles/core';
|
|||||||
import useEvent from '@src/useEvent.mjs';
|
import useEvent from '@src/useEvent.mjs';
|
||||||
import cx from '@src/cx.mjs';
|
import cx from '@src/cx.mjs';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
import { useCallback, useLayoutEffect, useEffect, useRef, useState } from 'react';
|
||||||
import { setActiveFooter, useSettings } from '../../settings.mjs';
|
import { setActiveFooter, useSettings } from '../../settings.mjs';
|
||||||
import { ConsoleTab } from './ConsoleTab';
|
import { ConsoleTab } from './ConsoleTab';
|
||||||
import { FilesTab } from './FilesTab';
|
import { FilesTab } from './FilesTab';
|
||||||
@ -12,21 +12,25 @@ import { SettingsTab } from './SettingsTab';
|
|||||||
import { SoundsTab } from './SoundsTab';
|
import { SoundsTab } from './SoundsTab';
|
||||||
import { WelcomeTab } from './WelcomeTab';
|
import { WelcomeTab } from './WelcomeTab';
|
||||||
import { PatternsTab } from './PatternsTab';
|
import { PatternsTab } from './PatternsTab';
|
||||||
|
import useClient from '@src/useClient.mjs';
|
||||||
|
|
||||||
const TAURI = window.__TAURI__;
|
// https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85
|
||||||
|
export const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
||||||
|
|
||||||
|
const TAURI = typeof window !== 'undefined' && window.__TAURI__;
|
||||||
|
|
||||||
export function Panel({ context }) {
|
export function Panel({ context }) {
|
||||||
const footerContent = useRef();
|
const footerContent = useRef();
|
||||||
const [log, setLog] = useState([]);
|
const [log, setLog] = useState([]);
|
||||||
const { activeFooter, isZen, panelPosition } = useSettings();
|
const { activeFooter, isZen, panelPosition } = useSettings();
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
if (footerContent.current && activeFooter === 'console') {
|
if (footerContent.current && activeFooter === 'console') {
|
||||||
// scroll log box to bottom when log changes
|
// scroll log box to bottom when log changes
|
||||||
footerContent.current.scrollTop = footerContent.current?.scrollHeight;
|
footerContent.current.scrollTop = footerContent.current?.scrollHeight;
|
||||||
}
|
}
|
||||||
}, [log, activeFooter]);
|
}, [log, activeFooter]);
|
||||||
useLayoutEffect(() => {
|
useIsomorphicLayoutEffect(() => {
|
||||||
if (!footerContent.current) {
|
if (!footerContent.current) {
|
||||||
} else if (activeFooter === 'console') {
|
} else if (activeFooter === 'console') {
|
||||||
footerContent.current.scrollTop = footerContent.current?.scrollHeight;
|
footerContent.current.scrollTop = footerContent.current?.scrollHeight;
|
||||||
@ -80,6 +84,10 @@ export function Panel({ context }) {
|
|||||||
right: cx('max-w-full flex-grow-0 flex-none overflow-hidden', isActive ? 'w-[600px] h-full' : 'absolute right-0'),
|
right: cx('max-w-full flex-grow-0 flex-none overflow-hidden', isActive ? 'w-[600px] h-full' : 'absolute right-0'),
|
||||||
bottom: cx('relative', isActive ? 'h-[360px] min-h-[360px]' : ''),
|
bottom: cx('relative', isActive ? 'h-[360px] min-h-[360px]' : ''),
|
||||||
};
|
};
|
||||||
|
const client = useClient();
|
||||||
|
if (!client) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<nav className={cx('bg-lineHighlight z-[10] flex flex-col', positions[panelPosition])}>
|
<nav className={cx('bg-lineHighlight z-[10] flex flex-col', positions[panelPosition])}>
|
||||||
<div className="flex justify-between px-2">
|
<div className="flex justify-between px-2">
|
||||||
|
|||||||
9
website/src/useClient.mjs
Normal file
9
website/src/useClient.mjs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export default function useClient() {
|
||||||
|
const [client, setClient] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
setClient(true);
|
||||||
|
}, []);
|
||||||
|
return client;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user