diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx
index 524c7db4..7ce47c74 100644
--- a/website/src/repl/Repl.jsx
+++ b/website/src/repl/Repl.jsx
@@ -17,7 +17,7 @@ import { prebake } from './prebake.mjs';
import * as tunes from './tunes.mjs';
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
import { themes } from './themes.mjs';
-import { settingsMap, useSettings, setLatestCode } from '../settings.mjs';
+import { settingsMap, useSettings, setLatestCode, updateUserPattern } from '../settings.mjs';
import Loader from './Loader';
import { settingPatterns } from '../settings.mjs';
import { code2hash, hash2code } from './helpers.mjs';
@@ -128,6 +128,7 @@ export function Repl({ embedded = false }) {
isLineWrappingEnabled,
panelPosition,
isZen,
+ activePattern,
} = useSettings();
const paintOptions = useMemo(() => ({ fontFamily }), [fontFamily]);
@@ -144,6 +145,7 @@ export function Repl({ embedded = false }) {
cleanupDraw();
},
afterEval: ({ code, meta }) => {
+ updateUserPattern(code);
setMiniLocations(meta.miniLocations);
setWidgets(meta.widgets);
setPending(false);
diff --git a/website/src/repl/panel/Panel.jsx b/website/src/repl/panel/Panel.jsx
index a38bdd24..711bd644 100644
--- a/website/src/repl/panel/Panel.jsx
+++ b/website/src/repl/panel/Panel.jsx
@@ -86,7 +86,7 @@ export function Panel({ context }) {
- {/* */}
+
{TAURI && }
@@ -101,7 +101,7 @@ export function Panel({ context }) {
{activeFooter === 'intro' &&
}
- {/* {activeFooter === 'patterns' &&
} */}
+ {activeFooter === 'patterns' &&
}
{activeFooter === 'console' &&
}
{activeFooter === 'sounds' &&
}
{activeFooter === 'reference' &&
}
diff --git a/website/src/repl/panel/PatternsTab.jsx b/website/src/repl/panel/PatternsTab.jsx
index 4a4a3930..60096bc8 100644
--- a/website/src/repl/panel/PatternsTab.jsx
+++ b/website/src/repl/panel/PatternsTab.jsx
@@ -1,24 +1,57 @@
import React from 'react';
import * as tunes from '../tunes.mjs';
-import { useSettings, clearUserPatterns, newUserPattern } from '../../settings.mjs';
+import {
+ useSettings,
+ clearUserPatterns,
+ newUserPattern,
+ setActivePattern,
+ deleteActivePattern,
+ duplicateActivePattern,
+ getUserPattern,
+} from '../../settings.mjs';
+
+function classNames(...classes) {
+ return classes.filter(Boolean).join(' ');
+}
export function PatternsTab({ context }) {
- const { userPatterns } = useSettings();
+ const { userPatterns, activePattern } = useSettings();
return (
My Patterns
-
-
+
+
+
+
{Object.entries(userPatterns).map(([key, up]) => (
{
const { code } = up;
- console.log('clikkk', code);
context.handleUpdate(code);
+ setActivePattern(key);
}}
>
{key}
@@ -28,9 +61,12 @@ export function PatternsTab({ context }) {
{Object.entries(tunes).map(([key, tune]) => (
{
- console.log('clikkk', tune);
+ setActivePattern(key);
context.handleUpdate(tune);
}}
>
diff --git a/website/src/settings.mjs b/website/src/settings.mjs
index 72ddace4..cb580eec 100644
--- a/website/src/settings.mjs
+++ b/website/src/settings.mjs
@@ -1,6 +1,7 @@
import { persistentMap } from '@nanostores/persistent';
import { useStore } from '@nanostores/react';
import { register } from '@strudel.cycles/core';
+import * as tunes from './repl/tunes.mjs';
export const defaultSettings = {
activeFooter: 'intro',
@@ -16,6 +17,7 @@ export const defaultSettings = {
soundsFilter: 'all',
panelPosition: 'bottom',
userPatterns: '{}',
+ activePattern: '',
};
export const settingsMap = persistentMap('strudel-settings', defaultSettings);
@@ -59,6 +61,10 @@ export const settingPatterns = { theme, fontFamily, fontSize };
function getUserPatterns() {
return JSON.parse(settingsMap.get().userPatterns);
}
+function getSetting(key) {
+ return settingsMap.get()[key];
+}
+
function setUserPatterns(obj) {
settingsMap.setKey('userPatterns', JSON.stringify(obj));
}
@@ -80,9 +86,68 @@ export function newUserPattern() {
const todays = Object.entries(userPatterns).filter(([name]) => name.startsWith(date));
const num = String(todays.length + 1).padStart(3, '0');
const defaultNewPattern = 's("hh")';
- addUserPattern(date + '_' + num, { code: defaultNewPattern });
+ const name = date + '_' + num;
+ addUserPattern(name, { code: defaultNewPattern });
+ setActivePattern(name);
+ return name;
}
export function clearUserPatterns() {
setUserPatterns({});
}
+
+export function getNextCloneName(key) {
+ const userPatterns = getUserPatterns();
+ const clones = Object.entries(userPatterns).filter(([name]) => name.startsWith(key));
+ const num = String(clones.length + 1).padStart(3, '0');
+ return key + '_' + num;
+}
+
+export function getUserPattern(key) {
+ const userPatterns = getUserPatterns();
+ return userPatterns[key];
+}
+
+export function updateUserPattern(code) {
+ const userPatterns = getUserPatterns();
+ let activePattern = getSetting('activePattern');
+ console.log('update', activePattern, code);
+ if (!activePattern) {
+ activePattern = newUserPattern();
+ setUserPatterns({ ...userPatterns, [activePattern]: { code } });
+ setActivePattern(activePattern);
+ } else if (!!tunes[activePattern] && code !== tunes[activePattern]) {
+ // is example / system pattern
+ activePattern = getNextCloneName(activePattern);
+ setUserPatterns({ ...userPatterns, [activePattern]: { code } });
+ setActivePattern(activePattern);
+ }
+}
+
+export function deleteActivePattern() {
+ let activePattern = getSetting('activePattern');
+ if (!activePattern) {
+ console.warn('cannot delete: no pattern selected');
+ return;
+ }
+ const userPatterns = getUserPatterns();
+ setUserPatterns(Object.fromEntries(Object.entries(userPatterns).filter(([key]) => key !== activePattern)));
+ setActivePattern('');
+}
+
+export function duplicateActivePattern() {
+ let activePattern = getSetting('activePattern');
+ let latestCode = getSetting('latestCode');
+ if (!activePattern) {
+ console.warn('cannot duplicate: no pattern selected');
+ return;
+ }
+ const userPatterns = getUserPatterns();
+ activePattern = getNextCloneName(activePattern);
+ setUserPatterns({ ...userPatterns, [activePattern]: { latestCode } });
+ setActivePattern(activePattern);
+}
+
+export function setActivePattern(key) {
+ settingsMap.setKey('activePattern', key);
+}