Merge pull request #164 from tidalcycles/talk-fixes

Talk fixes
This commit is contained in:
Felix Roos 2022-08-02 23:43:07 +02:00 committed by GitHub
commit 688a3d29fd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 406 additions and 291 deletions

1
.gitignore vendored
View file

@ -35,3 +35,4 @@ tutorial.rendered.mdx
doc.json doc.json
talk/public/EmuSP12 talk/public/EmuSP12
talk/public/samples talk/public/samples
server/samples/old

View file

@ -1046,6 +1046,22 @@ export class Pattern {
onTrigger(onTrigger) { onTrigger(onTrigger) {
return this._withHap((hap) => hap.setContext({ ...hap.context, onTrigger })); return this._withHap((hap) => hap.setContext({ ...hap.context, onTrigger }));
} }
log(func = id) {
return this._withHap((hap) =>
hap.setContext({
...hap.context,
onTrigger: (...args) => {
if (hap.context.onTrigger) {
hap.context.onTrigger(...args);
}
console.log(func(...args));
},
}),
);
}
logValues(func = id) {
return this.log((_, hap) => func(hap.value));
}
} }
// TODO - adopt value.mjs fully.. // TODO - adopt value.mjs fully..

View file

@ -31,6 +31,19 @@ export const fromMidi = (n) => {
return Math.pow(2, (n - 69) / 12) * 440; return Math.pow(2, (n - 69) / 12) * 440;
}; };
export const getFreq = (noteOrMidi) => {
if (typeof noteOrMidi === 'number') {
return fromMidi(noteOrMidi);
}
return fromMidi(toMidi(noteOrMidi));
};
export const midi2note = (n) => {
const oct = Math.floor(n / 12) - 1;
const pc = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'][n % 12];
return pc + oct;
};
// modulo that works with negative numbers e.g. mod(-1, 3) = 2 // modulo that works with negative numbers e.g. mod(-1, 3) = 2
// const mod = (n: number, m: number): number => (n < 0 ? mod(n + m, m) : n % m); // const mod = (n: number, m: number): number => (n < 0 ? mod(n + m, m) : n % m);
export const mod = (n, m) => ((n % m) + m) % m; export const mod = (n, m) => ((n % m) + m) % m;

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react'; import React, { useState, useEffect, useCallback, useMemo, useRef, useLayoutEffect } from 'react';
import { CodeMirror as CodeMirror$1 } from 'react-codemirror6'; import { CodeMirror as CodeMirror$1 } from 'react-codemirror6';
import { EditorView, Decoration } from '@codemirror/view'; import { EditorView, Decoration } from '@codemirror/view';
import { StateEffect, StateField } from '@codemirror/state'; import { StateEffect, StateField } from '@codemirror/state';
@ -46,7 +46,13 @@ const materialPalenightTheme = EditorView.theme(
lineHeight: '22px', lineHeight: '22px',
}, },
'.cm-line': { '.cm-line': {
background: '#2C323699', // background: '#2C323699',
background: 'transparent',
},
'.cm-line > *': {
// background: '#2C323699',
background: '#00000090',
// background: 'transparent',
}, },
// done // done
'&.cm-focused .cm-cursor': { '&.cm-focused .cm-cursor': {
@ -71,7 +77,8 @@ const materialPalenightTheme = EditorView.theme(
backgroundColor: '#6199ff2f', backgroundColor: '#6199ff2f',
}, },
'.cm-activeLine': { backgroundColor: highlightBackground }, // commented out because it looks bad in mini repl one liners
//'.cm-activeLine': { backgroundColor: cursor + '50' },
'.cm-selectionMatch': { backgroundColor: '#aafe661a' }, '.cm-selectionMatch': { backgroundColor: '#aafe661a' },
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': { '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
@ -193,7 +200,7 @@ const highlightField = StateField.define({
if (from > l || to > l) { if (from > l || to > l) {
return; return;
} }
const mark = Decoration.mark({ attributes: { style: `outline: 1px solid ${color}` } }); const mark = Decoration.mark({ attributes: { style: `outline: 1.5px solid ${color};` } });
return mark.range(from, to); return mark.range(from, to);
})).filter(Boolean), true); })).filter(Boolean), true);
} }
@ -351,6 +358,8 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP
} }
}, [activeCode, onDrawProp]); }, [activeCode, onDrawProp]);
const hideHeader = useMemo(() => activeCode && activeCode.includes('strudel hide-header'), [activeCode]);
const hideConsole = useMemo(() => activeCode && activeCode.includes('strudel hide-console'), [activeCode]);
// cycle hook to control scheduling // cycle hook to control scheduling
const cycle = useCycle({ const cycle = useCycle({
onDraw, onDraw,
@ -449,6 +458,8 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP
}; };
return { return {
hideHeader,
hideConsole,
pending, pending,
code, code,
setCode, setCode,
@ -521,13 +532,13 @@ var tailwind = '';
var style = ''; var style = '';
const container = "_container_10e1g_1"; const container = "_container_xpa19_1";
const header = "_header_10e1g_5"; const header = "_header_xpa19_5";
const buttons = "_buttons_10e1g_9"; const buttons = "_buttons_xpa19_9";
const button = "_button_10e1g_9"; const button = "_button_xpa19_9";
const buttonDisabled = "_buttonDisabled_10e1g_17"; const buttonDisabled = "_buttonDisabled_xpa19_17";
const error = "_error_10e1g_21"; const error = "_error_xpa19_21";
const body = "_body_10e1g_25"; const body = "_body_xpa19_25";
var styles = { var styles = {
container: container, container: container,
header: header, header: header,
@ -563,12 +574,16 @@ function Icon({ type }) {
}[type]); }[type]);
} }
function MiniRepl({ tune, defaultSynth, hideOutsideView = false }) { function MiniRepl({ tune, defaultSynth, hideOutsideView = false, theme, init, onEvent, enableKeyboard }) {
const { code, setCode, pattern, activateCode, error, cycle, dirty, togglePlay } = useRepl({ const { code, setCode, pattern, activeCode, activateCode, evaluateOnly, error, cycle, dirty, togglePlay, stop } = useRepl({
tune, tune,
defaultSynth, defaultSynth,
autolink: false autolink: false,
onEvent
}); });
useEffect(() => {
init && evaluateOnly();
}, [tune, init]);
const [view, setView] = useState(); const [view, setView] = useState();
const [ref, isVisible] = useInView({ const [ref, isVisible] = useInView({
threshold: 0.01 threshold: 0.01
@ -580,7 +595,25 @@ function MiniRepl({ tune, defaultSynth, hideOutsideView = false }) {
} }
return isVisible || wasVisible.current; return isVisible || wasVisible.current;
}, [isVisible, hideOutsideView]); }, [isVisible, hideOutsideView]);
useHighlighting({ view, pattern, active: cycle.started }); useHighlighting({ view, pattern, active: cycle.started && !activeCode?.includes("strudel disable-highlighting") });
useLayoutEffect(() => {
if (enableKeyboard) {
const handleKeyPress = async (e) => {
if (e.ctrlKey || e.altKey) {
if (e.code === "Enter") {
e.preventDefault();
flash(view);
await activateCode();
} else if (e.code === "Period") {
cycle.stop();
e.preventDefault();
}
}
};
window.addEventListener("keydown", handleKeyPress, true);
return () => window.removeEventListener("keydown", handleKeyPress, true);
}
}, [enableKeyboard, pattern, code, activateCode, cycle, view]);
return /* @__PURE__ */ React.createElement("div", { return /* @__PURE__ */ React.createElement("div", {
className: styles.container, className: styles.container,
ref ref

View file

@ -1 +1 @@
*,:before,:after{--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sc-h-5{height:1.25rem}.sc-w-5{width:1.25rem}@keyframes sc-pulse{50%{opacity:.5}}.sc-animate-pulse{animation:sc-pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cm-editor{background-color:transparent!important}._container_10e1g_1{overflow:hidden;border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(68 76 87 / var(--tw-bg-opacity))}._header_10e1g_5{display:flex;justify-content:space-between;border-top-width:1px;--tw-border-opacity: 1;border-color:rgb(100 116 139 / var(--tw-border-opacity));--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}._buttons_10e1g_9{display:flex}._button_10e1g_9{display:flex;width:4rem;cursor:pointer;align-items:center;justify-content:center;border-right-width:1px;--tw-border-opacity: 1;border-color:rgb(100 116 139 / var(--tw-border-opacity));--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity));padding:.25rem;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}._button_10e1g_9:hover{--tw-bg-opacity: 1;background-color:rgb(71 85 105 / var(--tw-bg-opacity))}._buttonDisabled_10e1g_17{display:flex;width:4rem;cursor:pointer;cursor:not-allowed;align-items:center;justify-content:center;--tw-bg-opacity: 1;background-color:rgb(71 85 105 / var(--tw-bg-opacity));padding:.25rem;--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}._error_10e1g_21{padding:.25rem;text-align:right;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(254 202 202 / var(--tw-text-opacity))}._body_10e1g_25{position:relative;overflow:auto} *,:before,:after{--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sc-h-5{height:1.25rem}.sc-w-5{width:1.25rem}@keyframes sc-pulse{50%{opacity:.5}}.sc-animate-pulse{animation:sc-pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cm-editor{background-color:transparent!important}._container_xpa19_1{overflow:hidden;border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(17 17 17 / var(--tw-bg-opacity))}._header_xpa19_5{display:flex;justify-content:space-between;border-top-width:1px;--tw-border-opacity: 1;border-color:rgb(100 116 139 / var(--tw-border-opacity));--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}._buttons_xpa19_9{display:flex}._button_xpa19_9{display:flex;width:4rem;cursor:pointer;align-items:center;justify-content:center;border-right-width:1px;--tw-border-opacity: 1;border-color:rgb(100 116 139 / var(--tw-border-opacity));--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity));padding:.25rem;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}._button_xpa19_9:hover{--tw-bg-opacity: 1;background-color:rgb(71 85 105 / var(--tw-bg-opacity))}._buttonDisabled_xpa19_17{display:flex;width:4rem;cursor:pointer;cursor:not-allowed;align-items:center;justify-content:center;--tw-bg-opacity: 1;background-color:rgb(71 85 105 / var(--tw-bg-opacity));padding:.25rem;--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}._error_xpa19_21{padding:.25rem;text-align:right;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(254 202 202 / var(--tw-text-opacity))}._body_xpa19_25{position:relative;overflow:auto}

View file

@ -60,7 +60,8 @@ const highlightField = StateField.define({
if (from > l || to > l) { if (from > l || to > l) {
return; // dont mark outside of range, as it will throw an error return; // dont mark outside of range, as it will throw an error
} }
const mark = Decoration.mark({ attributes: { style: `outline: 1px solid ${color}` } }); // const mark = Decoration.mark({ attributes: { style: `outline: 1px solid ${color}` } });
const mark = Decoration.mark({ attributes: { style: `outline: 1.5px solid ${color};` } });
return mark.range(from, to); return mark.range(from, to);
}), }),
) )

View file

@ -1,20 +1,25 @@
import React, { useState, useMemo, useRef } from 'react'; import React, { useState, useMemo, useRef, useEffect, useLayoutEffect } from 'react';
import { useInView } from 'react-hook-inview'; import { useInView } from 'react-hook-inview';
import useRepl from '../hooks/useRepl.mjs'; import useRepl from '../hooks/useRepl.mjs';
import cx from '../cx'; import cx from '../cx';
import useHighlighting from '../hooks/useHighlighting.mjs'; import useHighlighting from '../hooks/useHighlighting.mjs';
import CodeMirror6 from './CodeMirror6'; import CodeMirror6, { flash } from './CodeMirror6';
import 'tailwindcss/tailwind.css'; import 'tailwindcss/tailwind.css';
import './style.css'; import './style.css';
import styles from './MiniRepl.module.css'; import styles from './MiniRepl.module.css';
import { Icon } from './Icon'; import { Icon } from './Icon';
export function MiniRepl({ tune, defaultSynth, hideOutsideView = false }) { export function MiniRepl({ tune, defaultSynth, hideOutsideView = false, theme, init, onEvent, enableKeyboard }) {
const { code, setCode, pattern, activateCode, error, cycle, dirty, togglePlay } = useRepl({ const { code, setCode, pattern, activeCode, activateCode, evaluateOnly, error, cycle, dirty, togglePlay, stop } =
useRepl({
tune, tune,
defaultSynth, defaultSynth,
autolink: false, autolink: false,
onEvent,
}); });
useEffect(() => {
init && evaluateOnly();
}, [tune, init]);
const [view, setView] = useState(); const [view, setView] = useState();
const [ref, isVisible] = useInView({ const [ref, isVisible] = useInView({
threshold: 0.01, threshold: 0.01,
@ -26,7 +31,28 @@ export function MiniRepl({ tune, defaultSynth, hideOutsideView = false }) {
} }
return isVisible || wasVisible.current; return isVisible || wasVisible.current;
}, [isVisible, hideOutsideView]); }, [isVisible, hideOutsideView]);
useHighlighting({ view, pattern, active: cycle.started }); useHighlighting({ view, pattern, active: cycle.started && !activeCode?.includes('strudel disable-highlighting') });
// set active pattern on ctrl+enter
useLayoutEffect(() => {
if (enableKeyboard) {
const handleKeyPress = async (e) => {
if (e.ctrlKey || e.altKey) {
if (e.code === 'Enter') {
e.preventDefault();
flash(view);
await activateCode();
} else if (e.code === 'Period') {
cycle.stop();
e.preventDefault();
}
}
};
window.addEventListener('keydown', handleKeyPress, true);
return () => window.removeEventListener('keydown', handleKeyPress, true);
}
}, [enableKeyboard, pattern, code, activateCode, cycle, view]);
return ( return (
<div className={styles.container} ref={ref}> <div className={styles.container} ref={ref}>
<div className={styles.header}> <div className={styles.header}>
@ -40,7 +66,7 @@ export function MiniRepl({ tune, defaultSynth, hideOutsideView = false }) {
</div> </div>
{error && <div className={styles.error}>{error.message}</div>} {error && <div className={styles.error}>{error.message}</div>}
</div> </div>
<div className={styles.body} > <div className={styles.body}>
{show && <CodeMirror6 value={code} onChange={setCode} onViewChanged={setView} />} {show && <CodeMirror6 value={code} onChange={setCode} onViewChanged={setView} />}
</div> </div>
</div> </div>

View file

@ -1,5 +1,5 @@
.container { .container {
@apply sc-rounded-md sc-overflow-hidden sc-bg-[#444C57]; @apply sc-rounded-md sc-overflow-hidden sc-bg-[#111111];
} }
.header { .header {

View file

@ -36,6 +36,8 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP
} }
}, [activeCode, onDrawProp]); }, [activeCode, onDrawProp]);
const hideHeader = useMemo(() => activeCode && activeCode.includes('strudel hide-header'), [activeCode]);
const hideConsole = useMemo(() => activeCode && activeCode.includes('strudel hide-console'), [activeCode]);
// cycle hook to control scheduling // cycle hook to control scheduling
const cycle = useCycle({ const cycle = useCycle({
onDraw, onDraw,
@ -136,6 +138,8 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP
}; };
return { return {
hideHeader,
hideConsole,
pending, pending,
code, code,
setCode, setCode,

View file

@ -36,7 +36,13 @@ export const materialPalenightTheme = EditorView.theme(
lineHeight: '22px', lineHeight: '22px',
}, },
'.cm-line': { '.cm-line': {
background: '#2C323699', // background: '#2C323699',
background: 'transparent',
},
'.cm-line > *': {
// background: '#2C323699',
background: '#00000090',
// background: 'transparent',
}, },
// done // done
'&.cm-focused .cm-cursor': { '&.cm-focused .cm-cursor': {
@ -61,7 +67,8 @@ export const materialPalenightTheme = EditorView.theme(
backgroundColor: '#6199ff2f', backgroundColor: '#6199ff2f',
}, },
'.cm-activeLine': { backgroundColor: highlightBackground }, // commented out because it looks bad in mini repl one liners
//'.cm-activeLine': { backgroundColor: cursor + '50' },
'.cm-selectionMatch': { backgroundColor: '#aafe661a' }, '.cm-selectionMatch': { backgroundColor: '#aafe661a' },
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': { '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {

View file

@ -126,6 +126,7 @@ const splitSN = (s, n) => {
Pattern.prototype.out = function () { Pattern.prototype.out = function () {
return this.onTrigger(async (t, hap, ct) => { return this.onTrigger(async (t, hap, ct) => {
try {
const ac = getAudioContext(); const ac = getAudioContext();
// calculate correct time (tone.js workaround) // calculate correct time (tone.js workaround)
t = ac.currentTime + t - ct; t = ac.currentTime + t - ct;
@ -267,5 +268,8 @@ Pattern.prototype.out = function () {
chain.push(ac.destination); chain.push(ac.destination);
// connect chain elements together // connect chain elements together
chain.slice(1).reduce((last, current) => last.connect(current), chain[0]); chain.slice(1).reduce((last, current) => last.connect(current), chain[0]);
} catch (e) {
console.warn('.out error:', e);
}
}); });
}; };

1
repl/.gitignore vendored
View file

@ -24,3 +24,4 @@ dist-ssr
*.sw? *.sw?
oldtunes.mjs oldtunes.mjs
public/samples/EMU World/

View file

@ -3,7 +3,7 @@
@tailwind utilities; @tailwind utilities;
body { body {
background-color: #2a3236; background-color: #111;
} }
.react-codemirror2, .react-codemirror2,
@ -15,12 +15,12 @@ body {
} }
.CodeMirror-line > span { .CodeMirror-line > span {
background-color: #2a323699; background-color: #11111190;
} }
.darken::before { .darken::before {
content: ' '; content: ' ';
position: absolute; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100vw; width: 100vw;

View file

@ -108,6 +108,8 @@ function App() {
pattern, pattern,
pushLog, pushLog,
pending, pending,
hideHeader,
hideConsole,
} = useRepl({ } = useRepl({
tune: '// LOADING...', tune: '// LOADING...',
defaultSynth, defaultSynth,
@ -167,6 +169,7 @@ function App() {
return ( return (
<div className="min-h-screen flex flex-col"> <div className="min-h-screen flex flex-col">
{!hideHeader && (
<header <header
id="header" id="header"
className={cx( className={cx(
@ -289,20 +292,26 @@ function App() {
)} )}
</div> </div>
</header> </header>
)}
<section className="grow flex flex-col text-gray-100"> <section className="grow flex flex-col text-gray-100">
<div className="grow relative flex overflow-auto" id="code"> <div className="grow relative flex overflow-auto pb-8 cursor-text" id="code">
{/* onCursor={markParens} */} {/* onCursor={markParens} */}
<CodeMirror value={code} onChange={setCode} onViewChanged={setView} /> <CodeMirror value={code} onChange={setCode} onViewChanged={setView} />
<span className="z-[20] py-1 px-2 absolute top-0 right-0 text-xs whitespace-pre text-right pointer-events-none"> <span className="z-[20] bg-black rounded-t-md py-1 px-2 fixed bottom-0 right-1 text-xs whitespace-pre text-right pointer-events-none">
{!cycle.started ? `press ctrl+enter to play\n` : dirty ? `ctrl+enter to update\n` : 'no changes\n'} {!cycle.started ? `press ctrl+enter to play\n` : dirty ? `ctrl+enter to update\n` : 'no changes\n'}
</span> </span>
{error && ( {error && (
<div className={cx('absolute right-2 bottom-2 px-2', 'text-red-500')}> <div
className={cx(
'rounded-md fixed pointer-events-none left-2 bottom-1 text-xs bg-black px-2 z-[20]',
'text-red-500',
)}
>
{error?.message || 'unknown error'} {error?.message || 'unknown error'}
</div> </div>
)} )}
</div> </div>
{!isEmbedded && ( {!isEmbedded && !hideConsole && (
<textarea <textarea
className="z-[10] h-16 border-0 text-xs bg-[transparent] border-t border-slate-600 resize-none" className="z-[10] h-16 border-0 text-xs bg-[transparent] border-t border-slate-600 resize-none"
value={log} value={log}