From 9a13c58583ed3084ee9f631aea55a4fe51676448 Mon Sep 17 00:00:00 2001 From: "Jade (Rose) Rowland" Date: Fri, 19 Jan 2024 00:14:08 -0500 Subject: [PATCH] cleaning up --- website/src/repl/Repl.jsx | 27 ++++----- website/src/repl/panel/PatternsTab.jsx | 74 ++++++++++++----------- website/src/repl/useExamplePatterns.jsx | 13 ++-- website/src/repl/util.mjs | 14 +++-- website/src/user_pattern_utils.mjs | 80 +++++++++++++------------ 5 files changed, 113 insertions(+), 95 deletions(-) diff --git a/website/src/repl/Repl.jsx b/website/src/repl/Repl.jsx index 8ec9feb2..ce4561b8 100644 --- a/website/src/repl/Repl.jsx +++ b/website/src/repl/Repl.jsx @@ -17,7 +17,6 @@ import { initUserCode, setActivePattern, setLatestCode, - setViewingPattern, createPatternID, userPattern, getViewingPatternData, @@ -77,7 +76,6 @@ export function Repl({ embedded = false }) { setLatestCode(code); window.location.hash = '#' + code2hash(code); const viewingPatternData = getViewingPatternData(); - const data = { ...viewingPatternData, code }; let id = data.id; const isExamplePattern = viewingPatternData.collection !== userPattern.collection; @@ -86,13 +84,12 @@ export function Repl({ embedded = false }) { const codeHasChanged = code !== viewingPatternData.code; if (codeHasChanged) { // fork example - id = createPatternID(); - setViewingPattern(id); - setViewingPatternData(userPattern.update(id, data).data); + const newPattern = userPattern.duplicate(data); + id = newPattern.id; + setViewingPatternData(newPattern.data); } } else { - id = id == null ? createPatternID() : id; - setViewingPattern(id); + id = userPattern.isValidID(id) ? id : createPatternID(); setViewingPatternData(userPattern.update(id, data).data); } setActivePattern(id); @@ -169,23 +166,23 @@ export function Repl({ embedded = false }) { await prebake(); // declare default samples }; - const handleUpdate = async (id, data, reset = false) => { - setViewingPatternData(data); + const handleUpdate = async (patternData, reset = false) => { if (reset) { await resetEditor(); } - setViewingPattern(id); - editorRef.current.setCode(data.code); + setViewingPatternData(patternData); + editorRef.current.setCode(patternData.code); }; const handleEvaluate = () => { editorRef.current.evaluate(); }; const handleShuffle = async () => { - const { code, name } = getRandomTune(); - logger(`[repl] ✨ loading random tune "${name}"`); - setActivePattern(name); - setViewingPattern(name); + const patternData = getRandomTune(); + const code = patternData.code; + logger(`[repl] ✨ loading random tune "${patternData.id}"`); + setActivePattern(patternData.id); + setViewingPatternData(patternData); clearCanvas(); resetLoadedSounds(); await prebake(); // declare default samples diff --git a/website/src/repl/panel/PatternsTab.jsx b/website/src/repl/panel/PatternsTab.jsx index a950d754..8c66d2ea 100644 --- a/website/src/repl/panel/PatternsTab.jsx +++ b/website/src/repl/panel/PatternsTab.jsx @@ -4,7 +4,7 @@ import { exportPatterns, importPatterns, useActivePattern, - useViewingPattern, + useViewingPatternData, userPattern, } from '../../user_pattern_utils.mjs'; import { useMemo } from 'react'; @@ -40,21 +40,26 @@ function PatternButton({ showOutline, onClick, pattern, showHiglight }) { ); } -function PatternButtons({ patterns, activePattern, onClick, viewingPattern, started }) { +function PatternButtons({ patterns, activePattern, onClick, started }) { + const viewingPatternStore = useViewingPatternData(); + const viewingPatternData = JSON.parse(viewingPatternStore); + const viewingPatternID = viewingPatternData.id; return (
- {Object.values(patterns).map((pattern) => { - const id = pattern.id; - return ( - onClick(id)} - /> - ); - })} + {Object.values(patterns) + .reverse() + .map((pattern) => { + const id = pattern.id; + return ( + onClick(id)} + /> + ); + })}
); } @@ -70,30 +75,32 @@ function ActionButton({ children, onClick, label, labelIsHidden }) { export function PatternsTab({ context }) { const activePattern = useActivePattern(); - const viewingPattern = useViewingPattern(); + const viewingPatternStore = useViewingPatternData(); + const viewingPatternData = JSON.parse(viewingPatternStore); + const { userPatterns } = useSettings(); const examplePatterns = useExamplePatterns(); const collections = examplePatterns.collections; - const updateCodeWindow = (id, data, reset = false) => { - context.handleUpdate(id, data, reset); + const updateCodeWindow = (patternData, reset = false) => { + context.handleUpdate(patternData, reset); }; - const isUserPattern = userPatterns[viewingPattern] != null; + const viewingPatternID = viewingPatternData?.id; + const viewingIDIsValid = userPattern.isValidID(viewingPatternID); + const isUserPattern = userPatterns[viewingPatternID] != null; return (
- {viewingPattern && ( + {viewingIDIsValid && (
-

{`${viewingPattern}`}

+

{`${viewingPatternID}`}

{ - const { id, data } = userPattern.duplicate( - userPattern.getPatternData(id) ?? examplePatterns.patterns[id], - ); - updateCodeWindow(id, data); + const { data } = userPattern.duplicate(viewingPatternData); + updateCodeWindow(data); }} labelIsHidden > @@ -103,8 +110,8 @@ export function PatternsTab({ context }) { { - const { id, data } = userPattern.delete(viewingPattern); - updateCodeWindow(id, { ...data, collection: userPattern.collection }); + const { data } = userPattern.delete(viewingPatternID); + updateCodeWindow({ ...data, collection: userPattern.collection }); }} labelIsHidden > @@ -115,25 +122,25 @@ export function PatternsTab({ context }) {
)} updateCodeWindow(id, { ...userPatterns[id], collection: userPattern.collection }, false)} + onClick={(id) => updateCodeWindow({ ...userPatterns[id], collection: userPattern.collection }, false)} patterns={userPatterns} started={context.started} activePattern={activePattern} - viewingPattern={viewingPattern} + viewingPatternID={viewingPatternID} />
{ - const { id, data } = userPattern.createAndAddToDB(); - updateCodeWindow(id, data); + const { data } = userPattern.createAndAddToDB(); + updateCodeWindow(data); }} /> { - const { id, data } = userPattern.clearAll(); - updateCodeWindow(id, data); + const { data } = userPattern.clearAll(); + updateCodeWindow(data); }} /> @@ -157,11 +164,10 @@ export function PatternsTab({ context }) {

{collection}

updateCodeWindow(id, { ...patterns[id], collection }, true)} + onClick={(id) => updateCodeWindow({ ...patterns[id], collection }, true)} started={context.started} patterns={patterns} activePattern={activePattern} - viewingPattern={viewingPattern} />
diff --git a/website/src/repl/useExamplePatterns.jsx b/website/src/repl/useExamplePatterns.jsx index 65d94583..92874db6 100644 --- a/website/src/repl/useExamplePatterns.jsx +++ b/website/src/repl/useExamplePatterns.jsx @@ -1,17 +1,20 @@ -import { $featuredPatterns, $publicPatterns } from '../user_pattern_utils.mjs'; +import { $featuredPatterns, $publicPatterns, collectionName } from '../user_pattern_utils.mjs'; import { useStore } from '@nanostores/react'; import { useMemo } from 'react'; import * as tunes from '../repl/tunes.mjs'; +export const stockPatterns = Object.fromEntries( + Object.entries(tunes).map(([key, code], i) => [i, { id: i, code, collection: collectionName.stock }]), +); + export const useExamplePatterns = () => { const featuredPatterns = useStore($featuredPatterns); const publicPatterns = useStore($publicPatterns); const collections = useMemo(() => { - const stockPatterns = Object.fromEntries(Object.entries(tunes).map(([key, code], i) => [i, { id: i, code }])); const pats = new Map(); - pats.set('Featured', featuredPatterns); - pats.set('Last Creations', publicPatterns); - pats.set('Stock Examples', stockPatterns); + pats.set(collectionName.featured, featuredPatterns); + pats.set(collectionName.public, publicPatterns); + pats.set(collectionName.stock, stockPatterns); return pats; }, [featuredPatterns, publicPatterns]); diff --git a/website/src/repl/util.mjs b/website/src/repl/util.mjs index 19afdabb..8bfcf8ce 100644 --- a/website/src/repl/util.mjs +++ b/website/src/repl/util.mjs @@ -4,11 +4,13 @@ import { getAudioContext, initializeAudioOutput, setDefaultAudioContext } from ' import { isTauri } from '../tauri.mjs'; import './Repl.css'; -import * as tunes from './tunes.mjs'; + import { createClient } from '@supabase/supabase-js'; import { nanoid } from 'nanoid'; import { writeText } from '@tauri-apps/api/clipboard'; import { createContext } from 'react'; +import { stockPatterns } from './useExamplePatterns'; +import { loadDBPatterns } from '@src/user_pattern_utils.mjs'; // Create a single supabase client for interacting with your database export const supabase = createClient( @@ -16,6 +18,10 @@ export const supabase = createClient( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBpZHhkc3hwaGxoempuem1pZnRoIiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTYyMzA1NTYsImV4cCI6MTk3MTgwNjU1Nn0.bqlw7802fsWRnqU5BLYtmXk_k-D1VFmbkHMywWc15NM', ); +if (typeof window !== 'undefined') { + loadDBPatterns(); +} + export async function initCode() { // load code from url hash (either short hash from database or decode long hash) try { @@ -47,10 +53,10 @@ export async function initCode() { } export function getRandomTune() { - const allTunes = Object.entries(tunes); + const allTunes = Object.entries(stockPatterns); const randomItem = (arr) => arr[Math.floor(Math.random() * arr.length)]; - const [name, code] = randomItem(allTunes); - return { name, code }; + const [id, data] = randomItem(allTunes); + return data; } export function loadModules() { diff --git a/website/src/user_pattern_utils.mjs b/website/src/user_pattern_utils.mjs index 7419a5a7..cddaa57c 100644 --- a/website/src/user_pattern_utils.mjs +++ b/website/src/user_pattern_utils.mjs @@ -9,21 +9,30 @@ import { supabase } from './repl/util.mjs'; export let $publicPatterns = atom([]); export let $featuredPatterns = atom([]); -const userPatternCollectionName = 'user'; + +export const collectionName = { + user: 'user', + public: 'Last Creations', + stock: 'Stock Examples', + featured: 'Featured', +}; + export let $viewingPatternData = persistentAtom( 'viewingPatternData', { id: '', code: '', - collection: userPatternCollectionName, + collection: collectionName.user, created_at: Date.now(), }, { listen: false }, ); export const getViewingPatternData = () => { - console.log(JSON.parse($viewingPatternData.get())); - return $viewingPatternData.get(); + return JSON.parse($viewingPatternData.get()); +}; +export const useViewingPatternData = () => { + return useStore($viewingPatternData); }; export const setViewingPatternData = (data) => { @@ -38,37 +47,34 @@ export function loadFeaturedPatterns() { return supabase.from('code').select().eq('featured', true).limit(20).order('id', { ascending: false }); } -async function loadDBPatterns() { +export async function loadDBPatterns() { try { const { data: publicPatterns } = await loadPublicPatterns(); const { data: featuredPatterns } = await loadFeaturedPatterns(); 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'); + console.error('error loading patterns', err); } } -if (typeof window !== 'undefined') { - loadDBPatterns(); -} - //pattern that the use is currently viewing in the window -const $viewingPattern = persistentAtom('viewingPattern', '', { listen: false }); -export function setViewingPattern(key) { - $viewingPattern.set(key); -} -export function getViewingPattern() { - return $viewingPattern.get(); -} +// const $viewingPattern = persistentAtom('viewingPattern', '', { listen: false }); +// export function setViewingPattern(key) { +// $viewingPattern.set(key); +// } +// export function getViewingPattern() { +// return $viewingPattern.get(); +// } -export function useViewingPattern() { - return useStore($viewingPattern); -} +// export function useViewingPattern() { +// return useStore($viewingPattern); +// } // active pattern is separate, because it shouldn't sync state across tabs // reason: https://github.com/tidalcycles/strudel/issues/857 const $activePattern = persistentAtom('activePattern', '', { listen: false }); @@ -83,20 +89,20 @@ export function useActivePattern() { return useStore($activePattern); } export function initUserCode(code) { - const patterns = { ...userPattern.getAll() }; - const match = Object.entries(patterns).find(([_, pat]) => pat.code === code); - const id = match?.[0]; - if (id != null) { - setActivePattern(id); - setViewingPattern(id); - } + // const patterns = { ...userPattern.getAll() }; + // const match = Object.entries(patterns).find(([_, pat]) => pat.code === code); + // const id = match?.[0]; + // if (id != null) { + // setActivePattern(id); + // setViewingPattern(id); + // } } export const setLatestCode = (code) => settingsMap.setKey('latestCode', code); const defaultCode = ''; export const userPattern = { - collection: userPatternCollectionName, + collection: collectionName.user, getAll() { const patterns = JSON.parse(settingsMap.get().userPatterns); return patterns ?? {}; @@ -108,6 +114,9 @@ export const userPattern = { exists(id) { return this.getPatternData(id) != null; }, + isValidID(id) { + return id != null && id.length > 0; + }, create() { const newID = createPatternID(); @@ -127,8 +136,8 @@ export const userPattern = { return { id, data }; }, duplicate(data) { - const newID = createPatternID(); - return this.update(newID, data); + const newPattern = this.create(); + return this.update(newPattern.id, { ...newPattern.data, code: data.code }); }, clearAll() { if (!confirm(`This will delete all your patterns. Are you really sure?`)) { @@ -150,11 +159,12 @@ export const userPattern = { setActivePattern(null); } setUserPatterns(userPatterns); - const viewingPattern = getViewingPattern(); - if (viewingPattern === id) { + const viewingPatternData = getViewingPatternData(); + const viewingID = viewingPatternData?.id; + if (viewingID === id) { return { id: null, data: { code: defaultCode } }; } - return { id: viewingPattern, data: userPatterns[viewingPattern] }; + return { id: viewingID, data: userPatterns[viewingID] }; }, }; @@ -166,10 +176,6 @@ export const createPatternID = () => { return nanoid(12); }; -export const getNextCloneID = (id) => { - return createPatternID(); -}; - export async function importPatterns(fileList) { const files = Array.from(fileList); await Promise.all(