mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-24 03:58:53 +00:00
refactor settings to nanostores
This commit is contained in:
parent
ff99dbcd22
commit
b67b049802
@ -136,7 +136,7 @@ export default function CodeMirror({
|
|||||||
return staticExtensions;
|
return staticExtensions;
|
||||||
}, [keybindings]);
|
}, [keybindings]);
|
||||||
return (
|
return (
|
||||||
<div style={{ fontSize, fontFamily }} className="w-full">
|
<div style={{ fontSize: parseInt(fontSize), fontFamily }} className="w-full">
|
||||||
<_CodeMirror
|
<_CodeMirror
|
||||||
value={value}
|
value={value}
|
||||||
theme={theme || strudelTheme}
|
theme={theme || strudelTheme}
|
||||||
|
|||||||
40
pnpm-lock.yaml
generated
40
pnpm-lock.yaml
generated
@ -362,6 +362,8 @@ importers:
|
|||||||
'@docsearch/react': ^3.1.0
|
'@docsearch/react': ^3.1.0
|
||||||
'@headlessui/react': ^1.7.7
|
'@headlessui/react': ^1.7.7
|
||||||
'@heroicons/react': ^2.0.13
|
'@heroicons/react': ^2.0.13
|
||||||
|
'@nanostores/persistent': ^0.7.0
|
||||||
|
'@nanostores/react': ^0.4.1
|
||||||
'@strudel.cycles/core': workspace:*
|
'@strudel.cycles/core': workspace:*
|
||||||
'@strudel.cycles/csound': workspace:*
|
'@strudel.cycles/csound': workspace:*
|
||||||
'@strudel.cycles/midi': workspace:*
|
'@strudel.cycles/midi': workspace:*
|
||||||
@ -387,6 +389,7 @@ importers:
|
|||||||
fraction.js: ^4.2.0
|
fraction.js: ^4.2.0
|
||||||
html-escaper: ^3.0.3
|
html-escaper: ^3.0.3
|
||||||
nanoid: ^4.0.0
|
nanoid: ^4.0.0
|
||||||
|
nanostores: ^0.7.4
|
||||||
preact: ^10.7.3
|
preact: ^10.7.3
|
||||||
react: ^18.2.0
|
react: ^18.2.0
|
||||||
react-dom: ^18.2.0
|
react-dom: ^18.2.0
|
||||||
@ -407,6 +410,8 @@ importers:
|
|||||||
'@docsearch/react': 3.3.2_y6lbs4o5th67cuzjdmtw5eqh7a
|
'@docsearch/react': 3.3.2_y6lbs4o5th67cuzjdmtw5eqh7a
|
||||||
'@headlessui/react': 1.7.8_biqbaboplfbrettd7655fr4n2y
|
'@headlessui/react': 1.7.8_biqbaboplfbrettd7655fr4n2y
|
||||||
'@heroicons/react': 2.0.14_react@18.2.0
|
'@heroicons/react': 2.0.14_react@18.2.0
|
||||||
|
'@nanostores/persistent': 0.7.0_nanostores@0.7.4
|
||||||
|
'@nanostores/react': 0.4.1_nkfnbc2tpc77iht7asm3uqwau4
|
||||||
'@strudel.cycles/core': link:../packages/core
|
'@strudel.cycles/core': link:../packages/core
|
||||||
'@strudel.cycles/csound': link:../packages/csound
|
'@strudel.cycles/csound': link:../packages/csound
|
||||||
'@strudel.cycles/midi': link:../packages/midi
|
'@strudel.cycles/midi': link:../packages/midi
|
||||||
@ -430,6 +435,7 @@ importers:
|
|||||||
canvas: 2.11.0
|
canvas: 2.11.0
|
||||||
fraction.js: 4.2.0
|
fraction.js: 4.2.0
|
||||||
nanoid: 4.0.0
|
nanoid: 4.0.0
|
||||||
|
nanostores: 0.7.4
|
||||||
preact: 10.11.3
|
preact: 10.11.3
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0_react@18.2.0
|
react-dom: 18.2.0_react@18.2.0
|
||||||
@ -3170,6 +3176,27 @@ packages:
|
|||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@nanostores/persistent/0.7.0_nanostores@0.7.4:
|
||||||
|
resolution: {integrity: sha512-4PAInL/T1hbftZUJ0cmgdFHBMalUoq7BUXFBy7QfyMv/8X3LPTYNh/yxspL7+J+XM3UNvVI7IFRMMs6FBasjhQ==}
|
||||||
|
engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
nanostores: ^0.7.0
|
||||||
|
dependencies:
|
||||||
|
nanostores: 0.7.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@nanostores/react/0.4.1_nkfnbc2tpc77iht7asm3uqwau4:
|
||||||
|
resolution: {integrity: sha512-lsv0CYrMxczbXtoV/mxFVEoL/uVjEjseoP89srO/5yNAOkJka+dSFS7LYyWEbuvCPO7EgbtkvRpO5V+OztKQOw==}
|
||||||
|
engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
nanostores: ^0.7.0
|
||||||
|
react: '>=18.0.0'
|
||||||
|
dependencies:
|
||||||
|
nanostores: 0.7.4
|
||||||
|
react: 18.2.0
|
||||||
|
use-sync-external-store: 1.2.0_react@18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@nodelib/fs.scandir/2.1.5:
|
/@nodelib/fs.scandir/2.1.5:
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@ -9646,6 +9673,11 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/nanostores/0.7.4:
|
||||||
|
resolution: {integrity: sha512-MBeUVt7NBcXqh7AGT+KSr3O0X/995CZsvcP2QEMP+PXFwb07qv3Vjyq+EX0yS8f12Vv3Tn2g/BvK/OZoMhJlOQ==}
|
||||||
|
engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/napi-build-utils/1.0.2:
|
/napi-build-utils/1.0.2:
|
||||||
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
||||||
dev: true
|
dev: true
|
||||||
@ -12851,6 +12883,14 @@ packages:
|
|||||||
punycode: 2.3.0
|
punycode: 2.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/use-sync-external-store/1.2.0_react@18.2.0:
|
||||||
|
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/utf-8-validate/5.0.10:
|
/utf-8-validate/5.0.10:
|
||||||
resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==}
|
resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==}
|
||||||
engines: {node: '>=6.14.2'}
|
engines: {node: '>=6.14.2'}
|
||||||
|
|||||||
@ -21,6 +21,8 @@
|
|||||||
"@docsearch/react": "^3.1.0",
|
"@docsearch/react": "^3.1.0",
|
||||||
"@headlessui/react": "^1.7.7",
|
"@headlessui/react": "^1.7.7",
|
||||||
"@heroicons/react": "^2.0.13",
|
"@heroicons/react": "^2.0.13",
|
||||||
|
"@nanostores/persistent": "^0.7.0",
|
||||||
|
"@nanostores/react": "^0.4.1",
|
||||||
"@strudel.cycles/core": "workspace:*",
|
"@strudel.cycles/core": "workspace:*",
|
||||||
"@strudel.cycles/csound": "workspace:*",
|
"@strudel.cycles/csound": "workspace:*",
|
||||||
"@strudel.cycles/midi": "workspace:*",
|
"@strudel.cycles/midi": "workspace:*",
|
||||||
@ -44,6 +46,7 @@
|
|||||||
"canvas": "^2.11.0",
|
"canvas": "^2.11.0",
|
||||||
"fraction.js": "^4.2.0",
|
"fraction.js": "^4.2.0",
|
||||||
"nanoid": "^4.0.0",
|
"nanoid": "^4.0.0",
|
||||||
|
"nanostores": "^0.7.4",
|
||||||
"preact": "^10.7.3",
|
"preact": "^10.7.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
|||||||
@ -47,37 +47,34 @@ const base = BASE_URL;
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { settings } from '../repl/themes.mjs';
|
import { settings } from '../repl/themes.mjs';
|
||||||
import { watch, get } from '../store.mjs';
|
import { settingsMap } from '../settings.mjs';
|
||||||
|
import { listenKeys } from 'nanostores';
|
||||||
const themeStyle = document.createElement('style');
|
const themeStyle = document.createElement('style');
|
||||||
themeStyle.id = 'strudel-theme';
|
themeStyle.id = 'strudel-theme';
|
||||||
document.head.append(themeStyle);
|
document.head.append(themeStyle);
|
||||||
function getTheme(name) {
|
function activateTheme(name) {
|
||||||
if (!settings[name]) {
|
if (!settings[name]) {
|
||||||
console.warn('theme', name, 'has no settings');
|
console.warn('theme', name, 'has no settings.. defaulting to strudelTheme settings');
|
||||||
}
|
}
|
||||||
return {
|
const themeSettings = settings[name] || settings.strudelTheme;
|
||||||
name,
|
|
||||||
settings: settings[name] || settings.strudelTheme,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function setTheme(name) {
|
|
||||||
const { settings } = getTheme(name);
|
|
||||||
// set css variables
|
// set css variables
|
||||||
themeStyle.innerHTML = `:root {
|
themeStyle.innerHTML = `:root {
|
||||||
${Object.entries(settings)
|
${Object.entries(themeSettings)
|
||||||
// important to override fallback
|
// important to override fallback
|
||||||
.map(([key, value]) => `--${key}: ${value} !important;`)
|
.map(([key, value]) => `--${key}: ${value} !important;`)
|
||||||
.join('\n')}
|
.join('\n')}
|
||||||
}`;
|
}`;
|
||||||
// tailwind dark mode
|
// tailwind dark mode
|
||||||
if (settings.light) {
|
if (themeSettings.light) {
|
||||||
document.documentElement.classList.remove('dark');
|
document.documentElement.classList.remove('dark');
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.add('dark');
|
document.documentElement.classList.add('dark');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setTheme(get().theme);
|
|
||||||
watch(setTheme, 'theme');
|
activateTheme(settingsMap.get().theme);
|
||||||
|
listenKeys(settingsMap, ['theme'], ({ theme }) => activateTheme(theme));
|
||||||
|
|
||||||
// https://medium.com/quick-code/100vh-problem-with-ios-safari-92ab23c852a8
|
// https://medium.com/quick-code/100vh-problem-with-ios-safari-92ab23c852a8
|
||||||
const appHeight = () => {
|
const appHeight = () => {
|
||||||
const doc = document.documentElement;
|
const doc = document.documentElement;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { prebake } from '../repl/prebake';
|
import { prebake } from '../repl/prebake';
|
||||||
import { themes, settings } from '../repl/themes.mjs';
|
import { themes, settings } from '../repl/themes.mjs';
|
||||||
import './MiniRepl.css';
|
import './MiniRepl.css';
|
||||||
import useStore from '../useStore.mjs';
|
import { useSettings } from '../settings.mjs';
|
||||||
|
|
||||||
let modules;
|
let modules;
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
@ -28,9 +28,7 @@ if (typeof window !== 'undefined') {
|
|||||||
|
|
||||||
export function MiniRepl({ tune, drawTime, punchcard, canvasHeight = 100 }) {
|
export function MiniRepl({ tune, drawTime, punchcard, canvasHeight = 100 }) {
|
||||||
const [Repl, setRepl] = useState();
|
const [Repl, setRepl] = useState();
|
||||||
const {
|
const { theme } = useSettings();
|
||||||
state: { theme },
|
|
||||||
} = useStore();
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// we have to load this package on the client
|
// we have to load this package on the client
|
||||||
// because codemirror throws an error on the server
|
// because codemirror throws an error on the server
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
|||||||
import { loadedSamples } from './Repl';
|
import { loadedSamples } from './Repl';
|
||||||
import { Reference } from './Reference';
|
import { Reference } from './Reference';
|
||||||
import { themes } from './themes.mjs';
|
import { themes } from './themes.mjs';
|
||||||
import useStore from '../useStore.mjs';
|
import { useSettings, settingsMap } from '../settings.mjs';
|
||||||
|
|
||||||
export function Footer({ context }) {
|
export function Footer({ context }) {
|
||||||
// const [activeFooter, setActiveFooter] = useState('console');
|
// const [activeFooter, setActiveFooter] = useState('console');
|
||||||
@ -287,29 +287,24 @@ const fontFamilyOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function SettingsTab() {
|
function SettingsTab() {
|
||||||
const { state, update, reset } = useStore();
|
const { theme, keybindings, fontSize, fontFamily } = useSettings();
|
||||||
const { theme, keybindings, fontSize, fontFamily } = state;
|
|
||||||
return (
|
return (
|
||||||
<div className="text-foreground p-4 space-y-4">
|
<div className="text-foreground p-4 space-y-4">
|
||||||
<FormItem label="Theme">
|
<FormItem label="Theme">
|
||||||
<SelectInput
|
<SelectInput options={themeOptions} value={theme} onChange={(theme) => settingsMap.setKey('theme', theme)} />
|
||||||
options={themeOptions}
|
|
||||||
value={theme}
|
|
||||||
onChange={(theme) => update((current) => ({ ...current, theme }))}
|
|
||||||
/>
|
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<FormItem label="Font Family">
|
<FormItem label="Font Family">
|
||||||
<SelectInput
|
<SelectInput
|
||||||
options={fontFamilyOptions}
|
options={fontFamilyOptions}
|
||||||
value={fontFamily}
|
value={fontFamily}
|
||||||
onChange={(fontFamily) => update((current) => ({ ...current, fontFamily }))}
|
onChange={(fontFamily) => settingsMap.setKey('fontFamily', fontFamily)}
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem label="Font Size">
|
<FormItem label="Font Size">
|
||||||
<NumberSlider
|
<NumberSlider
|
||||||
value={fontSize}
|
value={fontSize}
|
||||||
onChange={(fontSize) => update((current) => ({ ...current, fontSize }))}
|
onChange={(fontSize) => settingsMap.setKey('fontSize', fontSize)}
|
||||||
min={10}
|
min={10}
|
||||||
max={40}
|
max={40}
|
||||||
step={2}
|
step={2}
|
||||||
@ -319,7 +314,7 @@ function SettingsTab() {
|
|||||||
<FormItem label="Keybindings">
|
<FormItem label="Keybindings">
|
||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
value={keybindings}
|
value={keybindings}
|
||||||
onChange={(keybindings) => update((current) => ({ ...current, keybindings }))}
|
onChange={(keybindings) => settingsMap.setKey('keybindings', keybindings)}
|
||||||
items={{ codemirror: 'Codemirror', vim: 'Vim', emacs: 'Emacs' }}
|
items={{ codemirror: 'Codemirror', vim: 'Vim', emacs: 'Emacs' }}
|
||||||
></ButtonGroup>
|
></ButtonGroup>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
@ -328,7 +323,7 @@ function SettingsTab() {
|
|||||||
className="bg-background p-2 max-w-[300px] rounded-md hover:opacity-50"
|
className="bg-background p-2 max-w-[300px] rounded-md hover:opacity-50"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (confirm('Sure?')) {
|
if (confirm('Sure?')) {
|
||||||
reset();
|
settingsMap.setKey(defaultSettings);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -23,8 +23,7 @@ import { prebake } from './prebake.mjs';
|
|||||||
import * as tunes from './tunes.mjs';
|
import * as tunes from './tunes.mjs';
|
||||||
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
|
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
|
||||||
import { themes } from './themes.mjs';
|
import { themes } from './themes.mjs';
|
||||||
import useTheme from '../useTheme';
|
import { useSettings } from '../settings.mjs';
|
||||||
import useStore from '../useStore.mjs';
|
|
||||||
|
|
||||||
const initialTheme = localStorage.getItem('strudel-theme') || 'strudelTheme';
|
const initialTheme = localStorage.getItem('strudel-theme') || 'strudelTheme';
|
||||||
|
|
||||||
@ -119,10 +118,7 @@ export function Repl({ embedded = false }) {
|
|||||||
const [isZen, setIsZen] = useState(false);
|
const [isZen, setIsZen] = useState(false);
|
||||||
const [pending, setPending] = useState(false);
|
const [pending, setPending] = useState(false);
|
||||||
|
|
||||||
const { theme, themeSettings } = useTheme();
|
const { theme, keybindings, fontSize, fontFamily } = useSettings();
|
||||||
const {
|
|
||||||
state: { keybindings, fontSize, fontFamily },
|
|
||||||
} = useStore();
|
|
||||||
|
|
||||||
const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } =
|
const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } =
|
||||||
useStrudel({
|
useStrudel({
|
||||||
|
|||||||
15
website/src/settings.mjs
Normal file
15
website/src/settings.mjs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { persistentMap } from '@nanostores/persistent';
|
||||||
|
import { useStore } from '@nanostores/react';
|
||||||
|
|
||||||
|
export const defaultSettings = {
|
||||||
|
keybindings: 'codemirror',
|
||||||
|
theme: 'strudelTheme',
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
fontSize: 18,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const settingsMap = persistentMap('strudel-settings', defaultSettings);
|
||||||
|
|
||||||
|
export function useSettings() {
|
||||||
|
return useStore(settingsMap);
|
||||||
|
}
|
||||||
@ -1,49 +0,0 @@
|
|||||||
export const storeKey = 'strudel-settings';
|
|
||||||
const defaults = {
|
|
||||||
keybindings: 'codemirror',
|
|
||||||
theme: 'strudelTheme',
|
|
||||||
fontFamily: 'monospace',
|
|
||||||
fontSize: 18,
|
|
||||||
};
|
|
||||||
|
|
||||||
export function get(prop) {
|
|
||||||
let state = {
|
|
||||||
...defaults,
|
|
||||||
...JSON.parse(localStorage.getItem(storeKey) || '{}'),
|
|
||||||
};
|
|
||||||
if (!prop) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
return state[prop];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function set(next) {
|
|
||||||
localStorage.setItem(storeKey, JSON.stringify(next));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function update(func) {
|
|
||||||
const prev = get();
|
|
||||||
const next = func(prev);
|
|
||||||
set(next);
|
|
||||||
document.dispatchEvent(
|
|
||||||
new CustomEvent(storeKey, {
|
|
||||||
detail: { next, prev },
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reset() {
|
|
||||||
update(() => defaults);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function watch(func, prop) {
|
|
||||||
document.addEventListener(storeKey, (e) => {
|
|
||||||
const { prev, next } = e.detail;
|
|
||||||
const hasPropChanged = (p) => next[p] !== prev[p];
|
|
||||||
if (!prop) {
|
|
||||||
func(next);
|
|
||||||
} else if (hasPropChanged(prop)) {
|
|
||||||
func(next[prop]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
// import { useEvent } from '@strudel.cycles/react';
|
|
||||||
import * as Store from './store.mjs';
|
|
||||||
import {} from 'react';
|
|
||||||
|
|
||||||
function useStore() {
|
|
||||||
const [state, setState] = useState(Store.get());
|
|
||||||
useEvent(Store.storeKey, (e) => setState(e.detail.next));
|
|
||||||
return { state, ...Store };
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: dedupe
|
|
||||||
function useEvent(name, onTrigger, useCapture = false) {
|
|
||||||
useEffect(() => {
|
|
||||||
document.addEventListener(name, onTrigger, useCapture);
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener(name, onTrigger, useCapture);
|
|
||||||
};
|
|
||||||
}, [onTrigger]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useStore;
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import { settings } from './repl/themes.mjs';
|
|
||||||
import useStore from './useStore.mjs';
|
|
||||||
|
|
||||||
function useTheme() {
|
|
||||||
const { state } = useStore();
|
|
||||||
const theme = state.theme || 'strudelTheme';
|
|
||||||
const themeSettings = settings[theme];
|
|
||||||
return {
|
|
||||||
theme: state.theme,
|
|
||||||
themeSettings,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useTheme;
|
|
||||||
Loading…
x
Reference in New Issue
Block a user