1import { persistentMap } from '@nanostores/persistent'; 2import { useStore } from '@nanostores/react'; 3import { register } from '@strudel/core'; 4import { isUdels } from './repl/util.mjs'; 5import { computed } from 'nanostores'; 6 7export const audioEngineTargets = { 8 webaudio: 'webaudio', 9 osc: 'osc', 10}; 11 12export const soundFilterType = { 13 USER: 'user', 14 DRUMS: 'drums', 15 SAMPLES: 'samples', 16 SYNTHS: 'synths', 17 WAVETABLES: 'wavetables', 18 ALL: 'all', 19}; 20 21const initialPrebakeScript = `// Prebake script 22// 23// This is code that is loaded before your pattern is run. 24// You can use it to define custom functions to use in any pattern. 25// 26// This is an initial example script. You can edit it to add 27// your own funtions. 28// 29// To use a script shared by some other user you can use 30// the import-button or paste the script in this editor. 31 32const ratchet = register('ratchet', (pat) => pat.sometimes(ply(2))) 33`; 34 35export const defaultSettings = { 36 activeFooter: 'intro', 37 keybindings: 'codemirror', 38 isBracketMatchingEnabled: true, 39 isBracketClosingEnabled: true, 40 isLineNumbersDisplayed: true, 41 isActiveLineHighlighted: true, 42 isAutoCompletionEnabled: false, 43 isTooltipEnabled: false, 44 isFlashEnabled: true, 45 isSyncEnabled: false, 46 isLineWrappingEnabled: false, 47 // jevstrudel: the minimap, with the playing lines on it 48 isMinimapEnabled: true, 49 isPatternHighlightingEnabled: true, 50 isTabIndentationEnabled: false, 51 isMultiCursorEnabled: false, 52 isBlockBasedEvalEnabled: false, 53 theme: 'strudelTheme', 54 fontFamily: 'monospace', 55 fontSize: 18, 56 latestCode: '', 57 isZen: false, 58 soundsFilter: soundFilterType.ALL, 59 referenceTag: 'all', 60 patternFilter: 'community', 61 // panelPosition: window.innerWidth > 1000 ? 'right' : 'bottom', //FIX: does not work on astro 62 panelPosition: 'right', 63 isPanelPinned: false, 64 // jevstrudel: a first visit opens the jev panel (the songs) and leaves the editor room 65 isPanelOpen: false, 66 // jevstrudel: the left panel, Jev's (songs and who is listening), and its tab 67 isJevPanelOpen: true, 68 jevTab: 'songs', 69 userPatterns: '{}', 70 prebakeScript: initialPrebakeScript, 71 audioEngineTarget: audioEngineTargets.webaudio, 72 isButtonRowHidden: false, 73 isCSSAnimationDisabled: false, 74 maxPolyphony: 128, 75 multiChannelOrbits: false, 76 includePrebakeScriptInShare: true, 77 settingsTab: 'settings', 78}; 79 80let search = null; 81if (typeof window !== 'undefined') { 82 search = new URLSearchParams(window.location.search); 83}
if running multiple instance in one window, it will use the settings for that instance. else default to normal
88export const settingsMap = persistentMap(settings_key, defaultSettings); 89 90export const $settings = computed(settingsMap, (state) => { 91 const userPatterns = JSON.parse(state.userPatterns); 92 Object.keys(userPatterns).forEach((key) => { 93 const data = userPatterns[key]; 94 data.id = data.id ?? key; 95 userPatterns[key] = data; 96 }); 97 return { 98 ...state, 99 isZen: parseBoolean(state.isZen), 100 isBracketMatchingEnabled: parseBoolean(state.isBracketMatchingEnabled), 101 isBracketClosingEnabled: parseBoolean(state.isBracketClosingEnabled), 102 isLineNumbersDisplayed: parseBoolean(state.isLineNumbersDisplayed), 103 isActiveLineHighlighted: parseBoolean(state.isActiveLineHighlighted), 104 isAutoCompletionEnabled: parseBoolean(state.isAutoCompletionEnabled), 105 isPatternHighlightingEnabled: parseBoolean(state.isPatternHighlightingEnabled), 106 isButtonRowHidden: parseBoolean(state.isButtonRowHidden), 107 isCSSAnimationDisabled: parseBoolean(state.isCSSAnimationDisabled), 108 isTooltipEnabled: parseBoolean(state.isTooltipEnabled), 109 isLineWrappingEnabled: parseBoolean(state.isLineWrappingEnabled), 110 isMinimapEnabled: parseBoolean(state.isMinimapEnabled), 111 isFlashEnabled: parseBoolean(state.isFlashEnabled), 112 isSyncEnabled: isUdels() ? true : parseBoolean(state.isSyncEnabled), 113 isTabIndentationEnabled: parseBoolean(state.isTabIndentationEnabled), 114 isMultiCursorEnabled: parseBoolean(state.isMultiCursorEnabled), 115 isBlockBasedEvalEnabled: parseBoolean(state.isBlockBasedEvalEnabled), 116 fontSize: Number(state.fontSize), 117 panelPosition: state.activeFooter !== '' && !isUdels() ? state.panelPosition : 'bottom', // <-- keep this 'bottom' where it is! 118 isPanelPinned: parseBoolean(state.isPanelPinned), 119 isPanelOpen: parseBoolean(state.isPanelOpen), 120 isJevPanelOpen: parseBoolean(state.isJevPanelOpen), 121 userPatterns: userPatterns, 122 multiChannelOrbits: parseBoolean(state.multiChannelOrbits), 123 includePrebakeScriptInShare: parseBoolean(state.includePrebakeScriptInShare), 124 patternAutoStart: isUdels() 125 ? false 126 : state.patternAutoStart === undefined 127 ? true 128 : parseBoolean(state.patternAutoStart), 129 }; 130}); 131 132export const parseBoolean = (booleanlike) => ([true, 'true'].includes(booleanlike) ? true : false); 133 134export function useSettings() { 135 return useStore($settings); 136} 137 138export const setActiveFooter = (tab) => settingsMap.setKey('activeFooter', tab); 139export const setPanelPinned = (bool) => settingsMap.setKey('isPanelPinned', bool); 140export const setIsPanelOpened = (bool) => settingsMap.setKey('isPanelOpen', bool); 141export const setIsJevPanelOpened = (bool) => settingsMap.setKey('isJevPanelOpen', bool); 142export const setJevTab = (tab) => settingsMap.setKey('jevTab', tab); 143export const setSettingsTab = (tab) => settingsMap.setKey('settingsTab', tab); 144 145export const storePrebakeScript = (script) => settingsMap.setKey('prebakeScript', script); 146 147export const setIsZen = (active) => settingsMap.setKey('isZen', !!active); 148 149const patternSetting = (key) => 150 register(key, (value, pat) => 151 pat.onTrigger(() => { 152 value = Array.isArray(value) ? value.join(' ') : value; 153 if (value !== settingsMap.get()[key]) { 154 settingsMap.setKey(key, value); 155 } 156 return pat; 157 }, false), 158 ); 159 160export const theme = patternSetting('theme'); 161export const fontFamily = patternSetting('fontFamily'); 162export const fontSize = patternSetting('fontSize'); 163 164export const settingPatterns = { theme, fontFamily, fontSize };