diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx
index bf618b4d..a02893b3 100644
--- a/website/src/repl/Repl.jsx
+++ b/website/src/repl/Repl.jsx
@@ -80,6 +80,7 @@ export function Repl({ embedded = false }) {
const data = { code };
let id = getViewingPattern();
window.location.hash = '#' + code2hash(code);
+
const examplePatternData = examplePattern.getPatternData(id);
const isExamplePattern = examplePatternData != null;
diff --git a/website/src/repl/panel/PatternsTab.jsx b/website/src/repl/panel/PatternsTab.jsx
index e2d9cd1d..3276a16b 100644
--- a/website/src/repl/panel/PatternsTab.jsx
+++ b/website/src/repl/panel/PatternsTab.jsx
@@ -1,13 +1,8 @@
import { DocumentDuplicateIcon, PencilSquareIcon, TrashIcon } from '@heroicons/react/20/solid';
import {
-
$featuredPatterns,
$publicPatterns,
- clearUserPatterns,
- deleteActivePattern,
- duplicateActivePattern,
-
exportPatterns,
importPatterns,
useActivePattern,
@@ -23,72 +18,113 @@ import * as tunes from '../tunes.mjs';
import { useStore } from '@nanostores/react';
import { getMetadata } from '../../metadata_parser';
-
function classNames(...classes) {
return classes.filter(Boolean).join(' ');
}
-function PatternButton({ showOutline, onClick, label, showHiglight }) {
+function PatternLabel({ pattern } /* : { pattern: Tables<'code'> } */) {
+ const meta = useMemo(() => getMetadata(pattern.code), [pattern]);
+ return (
+ <>{`${pattern.id}: ${meta.title ?? pattern.hash ?? 'unnamed'} by ${
+ Array.isArray(meta.by) ? meta.by.join(',') : 'Anonymous'
+ }`}>
+ );
+}
+
+const getPatternLabel = (pattern) => {
+ return `${pattern.id}: ${meta.title ?? pattern.hash ?? 'unnamed'} by ${
+ Array.isArray(meta.by) ? meta.by.join(',') : 'Anonymous'
+ }`;
+};
+
+function PatternButton({ showOutline, onClick, pattern, showHiglight }) {
return (
- {label}
+
);
}
+// function ListButton() {
+// return (
+// {
+// setActivePattern(pattern.hash);
+// context.handleUpdate(pattern.code, true);
+// }}
+// >
+//
+//
+// );
+// }
+
function PatternButtons({ patterns, activePattern, onClick, viewingPattern, started }) {
return (
- {Object.entries(patterns).map(([id]) => (
-
onClick(id)}
- />
- ))}
+ {Object.values(patterns).map((pattern) => {
+ const id = pattern.id;
+ return (
+ onClick(id)}
+ />
+ );
+ })}
);
}
export function PatternsTab({ context }) {
const { userPatterns } = useSettings();
- const examplePatterns = useMemo(() => examplePattern.getAll(), []);
const activePattern = useActivePattern();
+ const featuredPatterns = useStore($featuredPatterns);
+ const publicPatterns = useStore($publicPatterns);
+
+ // const otherPatterns = [
+ // {source: 'Stock Examples', patterns: examplePatterns }
+ // ]
+
+ const otherPatterns = useMemo(() => {
+ const pats = new Map();
+ pats.set('Featured', featuredPatterns);
+ pats.set('Last Creations', publicPatterns);
+ pats.set('Stock Examples', examplePattern.getAll());
+ return pats;
+ }, [featuredPatterns, publicPatterns]);
+
const viewingPattern = useViewingPattern();
const updateCodeWindow = (id, code, reset = false) => {
context.handleUpdate(id, code, reset);
};
- const onPatternBtnClick = (id, isExample = false) => {
- const code = isExample ? examplePatterns[id].code : userPatterns[id].code;
- // display selected pattern code in the window
- updateCodeWindow(id, code, isExample);
- };
+ const isUserPattern = userPatterns[viewingPattern] != null;
- const isExample = examplePatterns[viewingPattern] != null;
-
- const featuredPatterns = useStore($featuredPatterns);
- const publicPatterns = useStore($publicPatterns);
- const isExample = useMemo(() => activePattern && !!tunes[activePattern], [activePattern]);
+ // const isExample = useMemo(() => activePattern && !!tunes[activePattern], [activePattern]);
return (
{viewingPattern && (
-
{viewingPattern}
+
{`${viewingPattern}`}
- {!isExample && (
+ {/* {!isExample && (
- )}
+ )} */}
- {!isExample && (
+ {isUserPattern && (
)}
updateCodeWindow(id, userPatterns[id]?.code, false)}
patterns={userPatterns}
started={context.started}
activePattern={activePattern}
@@ -166,90 +202,24 @@ export function PatternsTab({ context }) {
- {featuredPatterns && (
-
- )}
- {publicPatterns && (
-
- )}
-
+ {Array.from(otherPatterns.keys()).map((key) => {
+ const patterns = otherPatterns.get(key);
- Examples
- onPatternBtnClick(id, true)}
- started={context.started}
- patterns={examplePatterns}
- activePattern={activePattern}
- viewingPattern={viewingPattern}
- />
-
- Stock Examples
-
-
-
+ return (
+
+ {key}
+
+
updateCodeWindow(id, patterns[id]?.code, true)}
+ started={context.started}
+ patterns={patterns}
+ activePattern={activePattern}
+ viewingPattern={viewingPattern}
+ />
+
+
+ );
+ })}
);
}
-
-export function PatternLabel({ pattern } /* : { pattern: Tables<'code'> } */) {
- const meta = useMemo(() => getMetadata(pattern.code), [pattern]);
- return (
- <>
- {pattern.id}. {meta.title || pattern.hash} by {Array.isArray(meta.by) ? meta.by.join(',') : 'Anonymous'}
- >
- );
-}
diff --git a/website/src/repl/util.mjs b/website/src/repl/util.mjs
index 3405e93d..1da4fc65 100644
--- a/website/src/repl/util.mjs
+++ b/website/src/repl/util.mjs
@@ -29,8 +29,12 @@ async function loadDBPatterns() {
try {
const { data: publicPatterns } = await loadPublicPatterns();
const { data: featuredPatterns } = await loadFeaturedPatterns();
- $publicPatterns.set(publicPatterns);
- $featuredPatterns.set(featuredPatterns);
+ const featured = {};
+ const pub = {};
+ publicPatterns?.forEach((data, key) => (pub[data.id ?? key] = data));
+ featuredPatterns?.forEach((data, key) => (featured[data.id ?? key] = data));
+ $publicPatterns.set(pub);
+ $featuredPatterns.set(featured);
} catch (err) {
console.error('error loading patterns');
}
diff --git a/website/src/settings.mjs b/website/src/settings.mjs
index f500b92c..868a2ba8 100644
--- a/website/src/settings.mjs
+++ b/website/src/settings.mjs
@@ -4,7 +4,7 @@ import { useStore } from '@nanostores/react';
import { register } from '@strudel.cycles/core';
import * as tunes from './repl/tunes.mjs';
import { logger } from '@strudel.cycles/core';
-
+import { nanoid } from 'nanoid';
export let $publicPatterns = atom([]);
export let $featuredPatterns = atom([]);
@@ -70,6 +70,14 @@ export function initUserCode(code) {
export function useSettings() {
const state = useStore(settingsMap);
+
+ const userPatterns = JSON.parse(state.userPatterns);
+ Object.keys(userPatterns).forEach((key) => {
+ const data = userPatterns[key];
+ data.id = data.id ?? key;
+ data.date = data.date ?? 0;
+ userPatterns[key] = data;
+ });
return {
...state,
isZen: [true, 'true'].includes(state.isZen) ? true : false,
@@ -82,7 +90,7 @@ export function useSettings() {
isFlashEnabled: [true, 'true'].includes(state.isFlashEnabled) ? true : false,
fontSize: Number(state.fontSize),
panelPosition: state.activeFooter !== '' ? state.panelPosition : 'bottom', // <-- keep this 'bottom' where it is!
- userPatterns: JSON.parse(state.userPatterns),
+ userPatterns: userPatterns,
};
}
@@ -108,35 +116,23 @@ export const fontSize = patternSetting('fontSize');
export const settingPatterns = { theme, fontFamily, fontSize };
-export function getUserPatterns() {
+function getUserPatterns() {
return JSON.parse(settingsMap.get().userPatterns);
}
-function getSetting(key) {
- return settingsMap.get()[key];
-}
-export function setUserPatterns(obj) {
+function setUserPatterns(obj) {
return settingsMap.setKey('userPatterns', JSON.stringify(obj));
}
export const createPatternID = () => {
- const userPatterns = getUserPatterns();
- const date = new Date().toISOString().split('T')[0];
- const todays = Object.entries(userPatterns).filter(([name]) => name.startsWith(date));
- const num = String(todays.length + 1).padStart(3, '0');
- const id = date + '_' + num;
- return id;
+ return nanoid(12);
};
export const getNextCloneID = (id) => {
- const patterns = { ...userPattern.getAll(), ...examplePattern.getAll() };
- const clones = Object.entries(patterns).filter(([patID]) => patID.startsWith(id));
- const num = String(clones.length + 1).padStart(3, '0');
- const newID = id + '_' + num;
- return newID;
+ return createPatternID();
};
-const examplePatterns = Object.fromEntries(Object.entries(tunes).map(([id, code]) => [id, { code }]));
+const examplePatterns = Object.fromEntries(Object.entries(tunes).map(([key, code], i) => [i, { id: i, code }]));
export const examplePattern = {
getAll() {
@@ -154,7 +150,8 @@ export const examplePattern = {
// break
export const userPattern = {
getAll() {
- return JSON.parse(settingsMap.get().userPatterns);
+ const patterns = JSON.parse(settingsMap.get().userPatterns);
+ return patterns;
},
getPatternData(id) {
const userPatterns = this.getAll();
@@ -163,10 +160,13 @@ export const userPattern = {
exists(id) {
return this.getPatternData(id) != null;
},
+
create() {
const newID = createPatternID();
const code = defaultCode;
- const data = { code };
+
+ // const meta = getMetadata
+ const data = { code, created_at: Date.now(), id: newID };
this.update(newID, data);
return { id: newID, data };
},
@@ -221,44 +221,6 @@ export const userPattern = {
alert('Name already taken!');
return { id, data };
}
-// break
-export function updateUserCode(code) {
- const userPatterns = getUserPatterns();
- let activePattern = getActivePattern();
- // check if code is that of an example tune
- const [example] = Object.entries(tunes).find(([_, tune]) => tune === code) || [];
- if (example && (!activePattern || activePattern === example)) {
- // select example
- setActivePattern(example);
- return;
- }
- const publicPattern = $publicPatterns.get().find((pat) => pat.code === code);
- if (publicPattern) {
- setActivePattern(publicPattern.hash);
- return;
- }
- const featuredPattern = $featuredPatterns.get().find((pat) => pat.code === code);
- if (featuredPattern) {
- setActivePattern(featuredPattern.hash);
- return;
- }
- if (!activePattern) {
- // create new user pattern
- activePattern = newUserPattern();
- setActivePattern(activePattern);
- } else if (
- (!!tunes[activePattern] && code !== tunes[activePattern]) || // fork example tune?
- $publicPatterns.get().find((p) => p.hash === activePattern) || // fork public pattern?
- $featuredPatterns.get().find((p) => p.hash === activePattern) // fork featured pattern?
- ) {
- // fork example
- activePattern = getNextCloneName(activePattern);
- setActivePattern(activePattern);
- }
- setUserPatterns({ ...userPatterns, [activePattern]: { code } });
-}
-// break
-
userPatterns[newID] = data; // copy code
delete userPatterns[id];
@@ -270,6 +232,42 @@ export function updateUserCode(code) {
},
};
+// export function updateUserCode(code) {
+// const userPatterns = getUserPatterns();
+// let activePattern = getActivePattern();
+// // check if code is that of an example tune
+// const [example] = Object.entries(tunes).find(([_, tune]) => tune === code) || [];
+// if (example && (!activePattern || activePattern === example)) {
+// // select example
+// setActivePattern(example);
+// return;
+// }
+// const publicPattern = $publicPatterns.get().find((pat) => pat.code === code);
+// if (publicPattern) {
+// setActivePattern(publicPattern.hash);
+// return;
+// }
+// const featuredPattern = $featuredPatterns.get().find((pat) => pat.code === code);
+// if (featuredPattern) {
+// setActivePattern(featuredPattern.hash);
+// return;
+// }
+// if (!activePattern) {
+// // create new user pattern
+// activePattern = newUserPattern();
+// setActivePattern(activePattern);
+// } else if (
+// (!!tunes[activePattern] && code !== tunes[activePattern]) || // fork example tune?
+// $publicPatterns.get().find((p) => p.hash === activePattern) || // fork public pattern?
+// $featuredPatterns.get().find((p) => p.hash === activePattern) // fork featured pattern?
+// ) {
+// // fork example
+// activePattern = getNextCloneName(activePattern);
+// setActivePattern(activePattern);
+// }
+// setUserPatterns({ ...userPatterns, [activePattern]: { code } });
+// }
+
export async function importPatterns(fileList) {
const files = Array.from(fileList);
await Promise.all(