add settings form to codemirror example

This commit is contained in:
Felix Roos 2023-12-14 11:29:33 +01:00
parent 9474ed7d85
commit 72d1f129cf
4 changed files with 160 additions and 24 deletions

View File

@ -19,6 +19,7 @@ const extensions = {
theme, theme,
isAutoCompletionEnabled, isAutoCompletionEnabled,
isPatternHighlightingEnabled, isPatternHighlightingEnabled,
isActiveLineHighlighted: (on) => (on ? [highlightActiveLine(), highlightActiveLineGutter()] : []),
isFlashEnabled, isFlashEnabled,
keybindings, keybindings,
}; };
@ -40,8 +41,6 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, set
// indentOnInput(), // works without. already brought with javascript extension? // indentOnInput(), // works without. already brought with javascript extension?
// bracketMatching(), // does not do anything // bracketMatching(), // does not do anything
closeBrackets(), closeBrackets(),
highlightActiveLineGutter(),
highlightActiveLine(),
syntaxHighlighting(defaultHighlightStyle), syntaxHighlighting(defaultHighlightStyle),
history(), history(),
EditorView.updateListener.of((v) => onChange(v)), EditorView.updateListener.of((v) => onChange(v)),

View File

@ -7,6 +7,80 @@
<title>StrudelMirror Example</title> <title>StrudelMirror Example</title>
</head> </head>
<body> <body>
<div class="settings">
<form name="settings">
<label
>theme
<select name="theme">
<option>strudelTheme</option>
<option>bluescreen</option>
<option>blackscreen</option>
<option>whitescreen</option>
<option>teletext</option>
<option>algoboy</option>
<option>terminal</option>
<option>abcdef</option>
<option>androidstudio</option>
<option>atomone</option>
<option>aura</option>
<option>bespin</option>
<option>darcula</option>
<option>dracula</option>
<option>duotoneDark</option>
<option>eclipse</option>
<option>githubDark</option>
<option>gruvboxDark</option>
<option>materialDark</option>
<option>nord</option>
<option>okaidia</option>
<option>solarizedDark</option>
<option>sublime</option>
<option>tokyoNight</option>
<option>tokyoNightStorm</option>
<option>vscodeDark</option>
<option>xcodeDark</option>
<option>bbedit</option>
<option>duotoneLight</option>
<option>githubLight</option>
<option>gruvboxLight</option>
<option>materialLight</option>
<option>noctisLilac</option>
<option>solarizedLight</option>
<option>tokyoNightDay</option>
<option>xcodeLight</option>
</select> </label
><br />
<label
>keybindings
<select name="keybindings">
<option>codemirror</option>
<option>vim</option>
<option>emacs</option>
<option>vscode</option>
</select> </label
><br />
<label
>fontFamily
<select name="fontFamily">
<option>monospace</option>
<option>helvetica</option>
</select> </label
><br />
<label>fontSize <input type="number" name="fontSize" /></label>
<br />
<label><input type="checkbox" name="isLineNumbersDisplayed" />isLineNumbersDisplayed</label>
<br />
<label><input type="checkbox" name="isActiveLineHighlighted" />isActiveLineHighlighted</label>
<br />
<label><input type="checkbox" name="isPatternHighlightingEnabled" />isPatternHighlightingEnabled</label>
<br />
<label><input type="checkbox" name="isFlashEnabled" />isFlashEnabled</label>
<br />
<label><input type="checkbox" name="isLineWrappingEnabled" />isLineWrappingEnabled</label>
<!-- <label><input type="checkbox" name="isAutoCompletionEnabled" />isAutoCompletionEnabled</label> -->
<!-- <label><input type="checkbox" name="isTooltipEnabled" />isTooltipEnabled</label> -->
</form>
</div>
<div id="code"></div> <div id="code"></div>
<script type="module" src="/main.js"></script> <script type="module" src="/main.js"></script>
</body> </body>

View File

@ -10,42 +10,38 @@ import {
} from '@strudel.cycles/webaudio'; } from '@strudel.cycles/webaudio';
import './style.css'; import './style.css';
let editor;
const initialSettings = {
keybindings: 'codemirror',
isLineNumbersDisplayed: true,
isActiveLineHighlighted: true,
isAutoCompletionEnabled: false,
isPatternHighlightingEnabled: true,
isFlashEnabled: true,
isTooltipEnabled: false,
isLineWrappingEnabled: false,
theme: 'teletext',
fontFamily: 'monospace',
fontSize: 18,
};
async function run() { async function run() {
const container = document.getElementById('code'); const container = document.getElementById('code');
if (!container) { if (!container) {
console.warn('could not init: no container found'); console.warn('could not init: no container found');
return; return;
} }
const settings = {
activeFooter: 'intro',
keybindings: 'codemirror',
isLineNumbersDisplayed: true,
isActiveLineHighlighted: true,
isAutoCompletionEnabled: false,
isPatternHighlightingEnabled: true,
isFlashEnabled: true,
isTooltipEnabled: false,
isLineWrappingEnabled: false,
theme: 'teletext',
fontFamily: 'monospace',
fontSize: 18,
latestCode: '',
isZen: false,
soundsFilter: 'all',
panelPosition: 'bottom',
userPatterns: '{}',
};
const drawContext = getDrawContext(); const drawContext = getDrawContext();
const drawTime = [-2, 2]; const drawTime = [-2, 2];
const editor = new StrudelMirror({ editor = new StrudelMirror({
defaultOutput: webaudioOutput, defaultOutput: webaudioOutput,
getTime: () => getAudioContext().currentTime, getTime: () => getAudioContext().currentTime,
transpiler, transpiler,
root: container, root: container,
initialCode: '// LOADING', initialCode: '// LOADING',
pattern: silence, pattern: silence,
settings, settings: initialSettings,
drawTime, drawTime,
onDraw: (haps, time, frame, painters) => { onDraw: (haps, time, frame, painters) => {
painters.length && drawContext.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2); painters.length && drawContext.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2);
@ -90,7 +86,7 @@ async function run() {
}); });
// init settings // init settings
editor.updateSettings(settings); editor.updateSettings(initialSettings);
logger(`Welcome to Strudel! Click into the editor and then hit ctrl+enter to run the code!`, 'highlight'); logger(`Welcome to Strudel! Click into the editor and then hit ctrl+enter to run the code!`, 'highlight');
const codeParam = window.location.href.split('#')[1] || ''; const codeParam = window.location.href.split('#')[1] || '';
@ -154,3 +150,50 @@ function onEvent(key, callback) {
window.addEventListener('message', listener); window.addEventListener('message', listener);
return () => window.removeEventListener('message', listener); return () => window.removeEventListener('message', listener);
} }
// settings form
function getInput(form, name) {
return form.querySelector(`input[name=${name}]`) || form.querySelector(`select[name=${name}]`);
}
function getFormValues(form, initial) {
const entries = Object.entries(initial).map(([key, initialValue]) => {
const input = getInput(form, key);
if (!input) {
return [key, initialValue]; // fallback
}
if (input.type === 'checkbox') {
return [key, input.checked];
}
if (input.type === 'number') {
return [key, Number(input.value)];
}
if (input.tagName === 'SELECT') {
return [key, input.value];
}
return [key, input.value];
});
return Object.fromEntries(entries);
}
function setFormValues(form, values) {
Object.entries(values).forEach(([key, value]) => {
const input = getInput(form, key);
if (!input) {
return;
}
if (input.type === 'checkbox') {
input.checked = !!value;
} else if (input.type === 'number') {
input.value = value;
} else if (input.tagName) {
input.value = value;
}
});
}
const form = document.querySelector('form[name=settings]');
setFormValues(form, initialSettings);
form.addEventListener('change', () => {
const values = getFormValues(form, initialSettings);
// console.log('values', values);
editor.updateSettings(values);
});

View File

@ -2,6 +2,13 @@
--foreground: white; --foreground: white;
} }
body,
input {
font-family: monospace;
background: black;
color: white;
}
html, html,
body, body,
#code, #code,
@ -11,3 +18,16 @@ body,
margin: 0; margin: 0;
height: 100%; height: 100%;
} }
.settings {
position: fixed;
right: 0;
top: 0;
z-index: 1000;
display: flex-col;
padding: 10px;
}
.settings > form > * + * {
margin-top: 10px;
}