add pattern filter behaves like sounds tab

This commit is contained in:
Jade (Rose) Rowland 2024-01-20 13:59:32 -05:00
parent b45fd5ce3a
commit 9dca7eb878
4 changed files with 104 additions and 86 deletions

View File

@ -1,8 +1,7 @@
import { DocumentDuplicateIcon, TrashIcon } from '@heroicons/react/20/solid';
import { useSettings } from '../../settings.mjs';
import { import {
exportPatterns, exportPatterns,
importPatterns, importPatterns,
patternFilterName,
useActivePattern, useActivePattern,
useViewingPatternData, useViewingPatternData,
userPattern, userPattern,
@ -11,6 +10,8 @@ import { useMemo } from 'react';
import { getMetadata } from '../../metadata_parser'; import { getMetadata } from '../../metadata_parser';
import { useExamplePatterns } from '../useExamplePatterns'; import { useExamplePatterns } from '../useExamplePatterns';
import { parseJSON } from '../util.mjs'; import { parseJSON } from '../util.mjs';
import { ButtonGroup } from './Forms.jsx';
import { settingsMap, useSettings } from '../../settings.mjs';
function classNames(...classes) { function classNames(...classes) {
return classes.filter(Boolean).join(' '); return classes.filter(Boolean).join(' ');
@ -18,14 +19,22 @@ function classNames(...classes) {
function PatternLabel({ pattern } /* : { pattern: Tables<'code'> } */) { function PatternLabel({ pattern } /* : { pattern: Tables<'code'> } */) {
const meta = useMemo(() => getMetadata(pattern.code), [pattern]); const meta = useMemo(() => getMetadata(pattern.code), [pattern]);
let title = meta.title;
if (title == null) {
title == pattern.hash;
}
if (title == null) {
const date = new Date(pattern.created_at);
if (isNaN(date)) {
return;
}
title = date.toLocaleDateString();
}
if (title == null) {
title = 'unnamed';
}
return ( return <>{`${pattern.id}: ${title} by ${Array.isArray(meta.by) ? meta.by.join(',') : 'Anonymous'}`}</>;
<>{`${pattern.id}: ${
meta.title ?? pattern.hash ?? pattern.created_at != null
? new Date(pattern.created_at).toLocaleDateString()
: 'unnamed'
} by ${Array.isArray(meta.by) ? meta.by.join(',') : 'Anonymous'}`}</>
);
} }
function PatternButton({ showOutline, onClick, pattern, showHiglight }) { function PatternButton({ showOutline, onClick, pattern, showHiglight }) {
@ -81,7 +90,7 @@ export function PatternsTab({ context }) {
const viewingPatternStore = useViewingPatternData(); const viewingPatternStore = useViewingPatternData();
const viewingPatternData = parseJSON(viewingPatternStore); const viewingPatternData = parseJSON(viewingPatternStore);
const { userPatterns } = useSettings(); const { userPatterns, patternFilter } = useSettings();
const examplePatterns = useExamplePatterns(); const examplePatterns = useExamplePatterns();
const collections = examplePatterns.collections; const collections = examplePatterns.collections;
@ -93,89 +102,91 @@ export function PatternsTab({ context }) {
const isUserPattern = userPatterns[viewingPatternID] != null; const isUserPattern = userPatterns[viewingPatternID] != null;
return ( return (
<div className="px-4 w-full dark:text-white text-stone-900 space-y-4 pb-4"> <div className="px-4 w-full dark:text-white text-stone-900 space-y-2 pb-4">
<ButtonGroup
value={patternFilter}
onChange={(value) => settingsMap.setKey('patternFilter', value)}
items={patternFilterName}
></ButtonGroup>
<section> <section>
{viewingIDIsValid && ( {patternFilter === patternFilterName.user && (
<div className="flex items-center mb-2 space-x-2 overflow-auto"> <div>
<h1 className="text-xl">{`${viewingPatternID}`}</h1> <div className="pr-4 space-x-4 border-b border-foreground mb-2 flex overflow-auto max-w-full items-center">
<div className="space-x-4 flex w-min">
<ActionButton <ActionButton
label="Duplicate" label="new"
onClick={() => {
const { data } = userPattern.createAndAddToDB();
updateCodeWindow(data);
}}
/>
<ActionButton
label="duplicate"
onClick={() => { onClick={() => {
const { data } = userPattern.duplicate(viewingPatternData); const { data } = userPattern.duplicate(viewingPatternData);
updateCodeWindow(data); updateCodeWindow(data);
}} }}
labelIsHidden />
> <ActionButton
<DocumentDuplicateIcon className="w-5 h-5" /> label="delete"
</ActionButton> onClick={() => {
{isUserPattern && ( const { data } = userPattern.delete(viewingPatternID);
<ActionButton updateCodeWindow({ ...data, collection: userPattern.collection });
label="Delete" }}
onClick={() => { />
const { data } = userPattern.delete(viewingPatternID); <label className="hover:opacity-50 cursor-pointer">
updateCodeWindow({ ...data, collection: userPattern.collection }); <input
}} style={{ display: 'none' }}
labelIsHidden type="file"
> multiple
<TrashIcon className="w-5 h-5" /> accept="text/plain,application/json"
</ActionButton> onChange={(e) => importPatterns(e.target.files)}
)} />
</div> import
</div> </label>
)} <ActionButton label="export" onClick={exportPatterns} />
<PatternButtons
onClick={(id) => updateCodeWindow({ ...userPatterns[id], collection: userPattern.collection }, false)}
patterns={userPatterns}
started={context.started}
activePattern={activePattern}
viewingPatternID={viewingPatternID}
/>
<div className="pr-4 space-x-4 border-b border-foreground mb-2 h-8 flex overflow-auto max-w-full items-center">
<ActionButton
label="new"
onClick={() => {
const { data } = userPattern.createAndAddToDB();
updateCodeWindow(data);
}}
/>
<ActionButton
label="clear"
onClick={() => {
const { data } = userPattern.clearAll();
updateCodeWindow(data);
}}
/>
<label className="hover:opacity-50 cursor-pointer"> <ActionButton
<input label="delete all"
style={{ display: 'none' }} onClick={() => {
type="file" const { data } = userPattern.clearAll();
multiple updateCodeWindow(data);
accept="text/plain,application/json" }}
onChange={(e) => importPatterns(e.target.files)}
/>
import
</label>
<ActionButton label="export" onClick={exportPatterns} />
</div>
</section>
{Array.from(collections.keys()).map((collection) => {
const patterns = collections.get(collection);
return (
<section key={collection}>
<h2 className="text-xl mb-2">{collection}</h2>
<div className="font-mono text-sm">
<PatternButtons
onClick={(id) => updateCodeWindow({ ...patterns[id], collection }, false)}
started={context.started}
patterns={patterns}
activePattern={activePattern}
/> />
</div> </div>
</section> {/* {viewingIDIsValid && (
); <div className="flex items-center mb-2 space-x-2 overflow-auto">
})} <h1 className="text-xl">{`${viewingPatternID}`}</h1>
</div>
)} */}
<PatternButtons
onClick={(id) => updateCodeWindow({ ...userPatterns[id], collection: userPattern.collection }, false)}
patterns={userPatterns}
started={context.started}
activePattern={activePattern}
viewingPatternID={viewingPatternID}
/>
</div>
)}
{patternFilter !== patternFilterName.user &&
Array.from(collections.keys()).map((collection) => {
const patterns = collections.get(collection);
return (
<section key={collection} className="py-2">
<h2 className="text-xl mb-2">{collection}</h2>
<div className="font-mono text-sm">
<PatternButtons
onClick={(id) => updateCodeWindow({ ...patterns[id], collection }, false)}
started={context.started}
patterns={patterns}
activePattern={activePattern}
/>
</div>
</section>
);
})}
</section>
</div> </div>
); );
} }

View File

@ -4,7 +4,7 @@ import { useMemo } from 'react';
import * as tunes from '../repl/tunes.mjs'; import * as tunes from '../repl/tunes.mjs';
export const stockPatterns = Object.fromEntries( export const stockPatterns = Object.fromEntries(
Object.entries(tunes).map(([key, code], i) => [i, { id: i, code, collection: collectionName.stock }]), Object.entries(tunes).map(([key, code], i) => [i, { id: i, code, collection: 'Stock Examples' }]),
); );
export const useExamplePatterns = () => { export const useExamplePatterns = () => {
@ -14,7 +14,7 @@ export const useExamplePatterns = () => {
const pats = new Map(); const pats = new Map();
pats.set(collectionName.featured, featuredPatterns); pats.set(collectionName.featured, featuredPatterns);
pats.set(collectionName.public, publicPatterns); pats.set(collectionName.public, publicPatterns);
pats.set(collectionName.stock, stockPatterns); // pats.set(collectionName.stock, stockPatterns);
return pats; return pats;
}, [featuredPatterns, publicPatterns]); }, [featuredPatterns, publicPatterns]);

View File

@ -1,6 +1,7 @@
import { persistentMap } from '@nanostores/persistent'; import { persistentMap } from '@nanostores/persistent';
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { register } from '@strudel/core'; import { register } from '@strudel/core';
import { patternFilterName } from './user_pattern_utils.mjs';
export const defaultAudioDeviceName = 'System Standard'; export const defaultAudioDeviceName = 'System Standard';
@ -20,6 +21,7 @@ export const defaultSettings = {
latestCode: '', latestCode: '',
isZen: false, isZen: false,
soundsFilter: 'all', soundsFilter: 'all',
patternFilter: patternFilterName.community,
panelPosition: 'right', panelPosition: 'right',
userPatterns: '{}', userPatterns: '{}',
audioDeviceName: defaultAudioDeviceName, audioDeviceName: defaultAudioDeviceName,

View File

@ -16,6 +16,11 @@ export const collectionName = {
featured: 'Featured', featured: 'Featured',
}; };
export const patternFilterName = {
community: 'community',
user: 'user',
};
export let $viewingPatternData = persistentAtom( export let $viewingPatternData = persistentAtom(
'viewingPatternData', 'viewingPatternData',
{ {