import { persistentMap } from '@nanostores/persistent'; import { useStore } from '@nanostores/react'; import { register } from '@strudel/core'; import { isUdels } from './repl/util.mjs'; export const defaultAudioDeviceName = 'System Standard'; export const audioEngineTargets = { webaudio: 'webaudio', osc: 'osc', }; export const defaultSettings = { activeFooter: 'intro', keybindings: 'codemirror', isBracketMatchingEnabled: true, isBracketClosingEnabled: true, isLineNumbersDisplayed: true, isActiveLineHighlighted: true, isAutoCompletionEnabled: false, isTooltipEnabled: false, isFlashEnabled: true, isSyncEnabled: false, isLineWrappingEnabled: false, isPatternHighlightingEnabled: true, theme: 'strudelTheme', fontFamily: 'monospace', fontSize: 18, latestCode: '', isZen: false, soundsFilter: 'all', patternFilter: 'community', panelPosition: 'bottom', isPanelPinned: true, userPatterns: '{}', audioDeviceName: defaultAudioDeviceName, audioEngineTarget: audioEngineTargets.webaudio, }; let search = null; if (typeof window !== 'undefined') { search = new URLSearchParams(window.location.search); } // if running multiple instance in one window, it will use the settings for that instance. else default to normal const instance = parseInt(search?.get('instance') ?? '0'); const settings_key = `strudel-settings${instance > 0 ? instance : ''}`; export const settingsMap = persistentMap(settings_key, defaultSettings); const parseBoolean = (booleanlike) => ([true, 'true'].includes(booleanlike) ? true : false); 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; userPatterns[key] = data; }); return { ...state, isZen: parseBoolean(state.isZen), isPanelPinned: parseBoolean(state.isPanelPinned), isBracketMatchingEnabled: parseBoolean(state.isBracketMatchingEnabled), isBracketClosingEnabled: parseBoolean(state.isBracketClosingEnabled), isLineNumbersDisplayed: parseBoolean(state.isLineNumbersDisplayed), isActiveLineHighlighted: parseBoolean(state.isActiveLineHighlighted), isAutoCompletionEnabled: parseBoolean(state.isAutoCompletionEnabled), isPatternHighlightingEnabled: parseBoolean(state.isPatternHighlightingEnabled), isTooltipEnabled: parseBoolean(state.isTooltipEnabled), isLineWrappingEnabled: parseBoolean(state.isLineWrappingEnabled), isFlashEnabled: parseBoolean(state.isFlashEnabled), isSyncEnabled: isUdels() ? true : parseBoolean(state.isSyncEnabled), fontSize: Number(state.fontSize), panelPosition: state.activeFooter !== '' && !isUdels() ? state.panelPosition : 'bottom', // <-- keep this 'bottom' where it is! userPatterns: userPatterns, }; } export const setActiveFooter = (tab) => settingsMap.setKey('activeFooter', tab); export const setPanelPinned = (isPinned) => settingsMap.setKey('isPanelPinned', isPinned); export const setIsZen = (active) => settingsMap.setKey('isZen', !!active); const patternSetting = (key) => register(key, (value, pat) => pat.onTrigger(() => { value = Array.isArray(value) ? value.join(' ') : value; if (value !== settingsMap.get()[key]) { settingsMap.setKey(key, value); } return pat; }, false), ); export const theme = patternSetting('theme'); export const fontFamily = patternSetting('fontFamily'); export const fontSize = patternSetting('fontSize'); export const settingPatterns = { theme, fontFamily, fontSize };