Merge pull request #333 from tidalcycles/embed-route

Embed mode improvements
This commit is contained in:
Felix Roos 2022-12-29 21:11:15 +01:00 committed by GitHub
commit 8ef1ae5202
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 33 deletions

View File

@ -8127,10 +8127,10 @@ exports[`renders tunes > tune: loungeSponge 1`] = `
exports[`renders tunes > tune: meltingsubmarine 1`] = ` exports[`renders tunes > tune: meltingsubmarine 1`] = `
[ [
"[ (0/1 → 1/1) ⇝ 3/2 | s:bd speed:0.7519542165100574 ]", "[ (0/1 → 1/1) ⇝ 3/2 | s:bd:5 speed:0.7519542165100574 ]",
"[ (3/4 → 1/1) ⇝ 3/2 | s:sd speed:0.7931522866332671 ]", "[ (3/4 → 1/1) ⇝ 3/2 | s:sd:1 speed:0.7931522866332671 ]",
"[ 3/8 → 3/4 | s:hh speed:0.7285963821098448 ]", "[ 3/8 → 3/4 | s:hh27 speed:0.7285963821098448 ]",
"[ (3/4 → 1/1) ⇝ 9/8 | s:hh speed:0.77531205091027 ]", "[ (3/4 → 1/1) ⇝ 9/8 | s:hh27 speed:0.77531205091027 ]",
"[ (0/1 → 1/1) ⇝ 3/2 | n:33.129885541275144 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]", "[ (0/1 → 1/1) ⇝ 3/2 | n:33.129885541275144 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]",
"[ (0/1 → 1/1) ⇝ 3/2 | n:33.17988554127514 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]", "[ (0/1 → 1/1) ⇝ 3/2 | n:33.17988554127514 decay:0.15 sustain:0 s:sawtooth gain:0.4 cutoff:3669.6267869262615 ]",
"[ (0/1 → 1/1) ⇝ 3/2 | n:55.129885541275144 s:sawtooth gain:0.16 cutoff:500 attack:1 ]", "[ (0/1 → 1/1) ⇝ 3/2 | n:55.129885541275144 s:sawtooth gain:0.16 cutoff:500 attack:1 ]",

View File

@ -0,0 +1,14 @@
---
import HeadCommon from '../components/HeadCommon.astro';
import { Repl } from '../repl/Repl.jsx';
---
<html>
<head>
<HeadCommon />
<title>Strudel REPL</title>
</head>
<body>
<Repl client:only="react" embedded />
</body>
</html>

View File

@ -1,5 +1,5 @@
import AcademicCapIcon from '@heroicons/react/20/solid/AcademicCapIcon'; import AcademicCapIcon from '@heroicons/react/20/solid/AcademicCapIcon';
import CommandLineIcon from '@heroicons/react/20/solid/CommandLineIcon'; import ArrowPathIcon from '@heroicons/react/20/solid/ArrowPathIcon';
import LinkIcon from '@heroicons/react/20/solid/LinkIcon'; import LinkIcon from '@heroicons/react/20/solid/LinkIcon';
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon'; import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
import SparklesIcon from '@heroicons/react/20/solid/SparklesIcon'; import SparklesIcon from '@heroicons/react/20/solid/SparklesIcon';
@ -9,10 +9,9 @@ import React, { useContext } from 'react';
// import { ReplContext } from './Repl'; // import { ReplContext } from './Repl';
import './Repl.css'; import './Repl.css';
const isEmbedded = window.location !== window.parent.location;
export function Header({ context }) { export function Header({ context }) {
const { const {
embedded,
started, started,
pending, pending,
isDirty, isDirty,
@ -25,32 +24,37 @@ export function Header({ context }) {
isZen, isZen,
setIsZen, setIsZen,
} = context; } = context;
const isEmbedded = embedded || window.location !== window.parent.location;
// useContext(ReplContext) // useContext(ReplContext)
return ( return (
<header <header
id="header" id="header"
className={cx( className={cx(
'py-1 flex-none w-full md:flex text-black justify-between z-[100] text-lg select-none sticky top-0', 'py-1 flex-none w-full text-black justify-between z-[100] text-lg select-none sticky top-0',
!isZen && 'bg-header', !isZen && !isEmbedded && 'bg-header',
isEmbedded ? 'flex' : 'md:flex',
)} )}
> >
<div className="px-4 flex space-x-2 pt-2 md:pt-0 select-none"> <div className="px-4 flex space-x-2 md:pt-0 select-none">
{/* <img {/* <img
src={logo} src={logo}
className={cx('Tidal-logo', isEmbedded ? 'w-8 h-8' : 'w-10 h-10', started && 'animate-pulse')} // 'bg-[#ffffff80] rounded-full' className={cx('Tidal-logo', isEmbedded ? 'w-8 h-8' : 'w-10 h-10', started && 'animate-pulse')} // 'bg-[#ffffff80] rounded-full'
alt="logo" alt="logo"
/> */} /> */}
<h1 <h1
onClick={() => {
if (isEmbedded) window.open(window.location.href.replace('embed', ''));
}}
className={cx( className={cx(
isEmbedded ? 'text-l' : 'text-xl', isEmbedded ? 'text-l cursor-pointer' : 'text-xl',
// 'bg-clip-text bg-gradient-to-r from-primary to-secondary text-transparent font-bold', // 'bg-clip-text bg-gradient-to-r from-primary to-secondary text-transparent font-bold',
'text-white font-bold flex space-x-2 items-center', 'text-white font-bold flex space-x-2 items-center',
)} )}
> >
<div <div
className={cx('mt-[1px]', started && 'animate-spin', 'cursor-pointer')} className={cx('mt-[1px]', started && 'animate-spin', 'cursor-pointer')}
onClick={() => setIsZen((z) => !z)} onClick={() => !isEmbedded && setIsZen((z) => !z)}
> >
🌀 🌀
</div> </div>
@ -65,12 +69,13 @@ export function Header({ context }) {
<div className="flex max-w-full overflow-auto text-white "> <div className="flex max-w-full overflow-auto text-white ">
<button <button
onClick={handleTogglePlay} onClick={handleTogglePlay}
title={started ? 'stop' : 'play'}
className={cx(!isEmbedded ? 'p-2' : 'px-2', 'hover:text-tertiary', !started && 'animate-pulse')} className={cx(!isEmbedded ? 'p-2' : 'px-2', 'hover:text-tertiary', !started && 'animate-pulse')}
> >
{!pending ? ( {!pending ? (
<span className={cx('flex items-center space-x-1', isEmbedded ? 'w-16' : 'w-16')}> <span className={cx('flex items-center space-x-1', isEmbedded ? '' : 'w-16')}>
{started ? <StopCircleIcon className="w-5 h-5" /> : <PlayCircleIcon className="w-5 h-5" />} {started ? <StopCircleIcon className="w-6 h-6" /> : <PlayCircleIcon className="w-6 h-6" />}
<span>{started ? 'stop' : 'play'}</span> {!isEmbedded && <span>{started ? 'stop' : 'play'}</span>}
</span> </span>
) : ( ) : (
<>loading...</> <>loading...</>
@ -78,46 +83,54 @@ export function Header({ context }) {
</button> </button>
<button <button
onClick={handleUpdate} onClick={handleUpdate}
title="update"
className={cx( className={cx(
'flex items-center space-x-1', 'flex items-center space-x-1',
!isEmbedded ? 'p-2' : 'px-2', !isEmbedded ? 'p-2' : 'px-2',
!isDirty || !activeCode ? 'opacity-50' : 'hover:text-tertiary', !isDirty || !activeCode ? 'opacity-50' : 'hover:text-tertiary',
)} )}
> >
<CommandLineIcon className="w-5 h-5" /> {/* <CommandLineIcon className="w-6 h-6" /> */}
<span>update</span> <ArrowPathIcon className="w-6 h-6" />
{!isEmbedded && <span>update</span>}
</button> </button>
{!isEmbedded && ( {!isEmbedded && (
<button className="hover:text-tertiary p-2 flex items-center space-x-1" onClick={handleShuffle}> <button
<SparklesIcon className="w-5 h-5" /> title="shuffle"
className="hover:text-tertiary p-2 flex items-center space-x-1"
onClick={handleShuffle}
>
<SparklesIcon className="w-6 h-6" />
<span> shuffle</span> <span> shuffle</span>
</button> </button>
)} )}
{!isEmbedded && ( {!isEmbedded && (
<button <button
title="share"
className={cx( className={cx(
'cursor-pointer hover:text-tertiary flex items-center space-x-1', 'cursor-pointer hover:text-tertiary flex items-center space-x-1',
!isEmbedded ? 'p-2' : 'px-2', !isEmbedded ? 'p-2' : 'px-2',
)} )}
onClick={handleShare} onClick={handleShare}
> >
<LinkIcon className="w-5 h-5" /> <LinkIcon className="w-6 h-6" />
<span>share{lastShared && lastShared === (activeCode || code) ? 'd!' : ''}</span> <span>share{lastShared && lastShared === (activeCode || code) ? 'd!' : ''}</span>
</button> </button>
)} )}
{!isEmbedded && ( {!isEmbedded && (
<a <a
title="learn"
href="./learn/getting-started" href="./learn/getting-started"
className={cx('hover:text-tertiary flex items-center space-x-1', !isEmbedded ? 'p-2' : 'px-2')} className={cx('hover:text-tertiary flex items-center space-x-1', !isEmbedded ? 'p-2' : 'px-2')}
> >
<AcademicCapIcon className="w-5 h-5" /> <AcademicCapIcon className="w-6 h-6" />
<span>learn</span> <span>learn</span>
</a> </a>
)} )}
{isEmbedded && ( {/* {isEmbedded && (
<button className={cx('hover:text-tertiary px-2')}> <button className={cx('hover:text-tertiary px-2')}>
<a href={window.location.href} target="_blank" rel="noopener noreferrer" title="Open in REPL"> <a href={window.location.href} target="_blank" rel="noopener noreferrer" title="Open in REPL">
🚀 open 🚀
</a> </a>
</button> </button>
)} )}
@ -130,10 +143,10 @@ export function Header({ context }) {
}} }}
title="Reset" title="Reset"
> >
💔 reset 💔
</a> </a>
</button> </button>
)} )} */}
</div> </div>
)} )}
</header> </header>

View File

@ -22,6 +22,7 @@ import { Footer } from './Footer';
import { Header } from './Header'; import { Header } from './Header';
import { prebake } from './prebake.mjs'; import { prebake } from './prebake.mjs';
import * as tunes from './tunes.mjs'; import * as tunes from './tunes.mjs';
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
initAudioOnFirstClick(); initAudioOnFirstClick();
@ -101,7 +102,8 @@ const { code: randomTune, name } = getRandomTune();
export const ReplContext = createContext(null); export const ReplContext = createContext(null);
export function Repl() { export function Repl({ embedded = false }) {
const isEmbedded = embedded || window.location !== window.parent.location;
const [view, setView] = useState(); // codemirror view const [view, setView] = useState(); // codemirror view
const [lastShared, setLastShared] = useState(); const [lastShared, setLastShared] = useState();
const [activeFooter, setActiveFooter] = useState(''); const [activeFooter, setActiveFooter] = useState('');
@ -232,6 +234,7 @@ export function Repl() {
} }
}; };
const context = { const context = {
embedded,
started, started,
pending, pending,
isDirty, isDirty,
@ -269,7 +272,16 @@ export function Repl() {
{error && ( {error && (
<div className="text-red-500 p-4 bg-lineblack animate-pulse">{error.message || 'Unknown Error :-/'}</div> <div className="text-red-500 p-4 bg-lineblack animate-pulse">{error.message || 'Unknown Error :-/'}</div>
)} )}
<Footer context={context} /> {isEmbedded && !started && (
<button
onClick={() => handleTogglePlay()}
className="text-white text-2xl fixed left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] z-[1000] m-auto p-4 bg-black rounded-md flex items-center space-x-2"
>
<PlayCircleIcon className="w-6 h-6" />
<span>play</span>
</button>
)}
{!isEmbedded && <Footer context={context} />}
</div> </div>
</ReplContext.Provider> </ReplContext.Provider>
); );

View File

@ -518,13 +518,9 @@ export const festivalOfFingers3 = `// licensed with CC BY-NC-SA 4.0 https://crea
export const meltingsubmarine = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ export const meltingsubmarine = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos // by Felix Roos
samples({ await samples('github:tidalcycles/Dirt-Samples/master/')
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav','bd/BT0A0DA.wav','bd/BT0A0D3.wav','bd/BT0A0D0.wav','bd/BT0A0A7.wav'],
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
}, 'github:tidalcycles/Dirt-Samples/master/');
stack( stack(
s("bd,[~ <sd!3 sd(3,4,2)>],hh(3,4)") // drums s("bd:5,[~ <sd:1!3 sd:1(3,4,2)>],hh27(3,4)") // drums
.speed(perlin.range(.7,.9)) // random sample speed variation .speed(perlin.range(.7,.9)) // random sample speed variation
//.hush() //.hush()
,"<a1 b1*2 a1(3,8) e2>" // bassline ,"<a1 b1*2 a1(3,8) e2>" // bassline