mirror of
https://github.com/eliasstepanik/strudel.git
synced 2026-01-11 05:38:35 +00:00
add emacs mode + fontSize slider
This commit is contained in:
parent
014555fe5d
commit
ceb3aa0627
@ -37,6 +37,7 @@
|
||||
"@codemirror/state": "^6.2.0",
|
||||
"@codemirror/view": "^6.7.3",
|
||||
"@lezer/highlight": "^1.1.3",
|
||||
"@replit/codemirror-emacs": "^6.0.0",
|
||||
"@replit/codemirror-vim": "^6.0.6",
|
||||
"@strudel.cycles/core": "workspace:*",
|
||||
"@strudel.cycles/transpiler": "workspace:*",
|
||||
|
||||
@ -9,6 +9,7 @@ import { useCallback } from 'react';
|
||||
import { autocompletion } from '@codemirror/autocomplete';
|
||||
import { strudelAutocomplete } from './Autocomplete';
|
||||
import { vim } from '@replit/codemirror-vim';
|
||||
import { emacs } from '@replit/codemirror-emacs';
|
||||
|
||||
export const setFlash = StateEffect.define();
|
||||
const flashField = StateField.define({
|
||||
@ -98,7 +99,8 @@ export default function CodeMirror({
|
||||
onViewChanged,
|
||||
onSelectionChange,
|
||||
theme,
|
||||
vimMode,
|
||||
keybindings,
|
||||
fontSize = 18,
|
||||
options,
|
||||
editorDidMount,
|
||||
}) {
|
||||
@ -122,9 +124,18 @@ export default function CodeMirror({
|
||||
},
|
||||
[onSelectionChange],
|
||||
);
|
||||
const extensions = useMemo(() => [...staticExtensions, ...(vimMode ? [vim()] : [])], [vimMode]);
|
||||
const extensions = useMemo(() => {
|
||||
let bindings = {
|
||||
vim,
|
||||
emacs,
|
||||
};
|
||||
if (bindings[keybindings]) {
|
||||
return [...staticExtensions, bindings[keybindings]()];
|
||||
}
|
||||
return staticExtensions;
|
||||
}, [keybindings]);
|
||||
return (
|
||||
<>
|
||||
<div style={{ fontSize }} className="w-full">
|
||||
<_CodeMirror
|
||||
value={value}
|
||||
theme={theme || strudelTheme}
|
||||
@ -133,7 +144,7 @@ export default function CodeMirror({
|
||||
onUpdate={handleOnUpdate}
|
||||
extensions={extensions}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
background-color: transparent !important;
|
||||
height: 100%;
|
||||
z-index: 11;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.cm-theme {
|
||||
|
||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@ -164,6 +164,7 @@ importers:
|
||||
'@codemirror/state': ^6.2.0
|
||||
'@codemirror/view': ^6.7.3
|
||||
'@lezer/highlight': ^1.1.3
|
||||
'@replit/codemirror-emacs': ^6.0.0
|
||||
'@replit/codemirror-vim': ^6.0.6
|
||||
'@strudel.cycles/core': workspace:*
|
||||
'@strudel.cycles/transpiler': workspace:*
|
||||
@ -186,6 +187,7 @@ importers:
|
||||
'@codemirror/state': 6.2.0
|
||||
'@codemirror/view': 6.7.3
|
||||
'@lezer/highlight': 1.1.3
|
||||
'@replit/codemirror-emacs': 6.0.0_cgfc5aojxuwjajwhkrgidrzxoa
|
||||
'@replit/codemirror-vim': 6.0.6_a4vbhepr4qhxm5cldqd4jpyase
|
||||
'@strudel.cycles/core': link:../core
|
||||
'@strudel.cycles/transpiler': link:../transpiler
|
||||
@ -3404,6 +3406,20 @@ packages:
|
||||
tsm: 2.3.0
|
||||
dev: false
|
||||
|
||||
/@replit/codemirror-emacs/6.0.0_cgfc5aojxuwjajwhkrgidrzxoa:
|
||||
resolution: {integrity: sha512-zxSDg3UKm7811hjqNtgvK9G0IBtCWf82Idb9nZQo0ldmGl4d9SV7oCSuXQ58NmOG4AV7coD7kgFSZhEqHhyQhA==}
|
||||
peerDependencies:
|
||||
'@codemirror/autocomplete': ^6.0.2
|
||||
'@codemirror/commands': ^6.0.0
|
||||
'@codemirror/search': ^6.0.0
|
||||
'@codemirror/state': ^6.0.1
|
||||
'@codemirror/view': ^6.0.2
|
||||
dependencies:
|
||||
'@codemirror/autocomplete': 6.4.0_a4vbhepr4qhxm5cldqd4jpyase
|
||||
'@codemirror/state': 6.2.0
|
||||
'@codemirror/view': 6.7.3
|
||||
dev: false
|
||||
|
||||
/@replit/codemirror-vim/6.0.6_a4vbhepr4qhxm5cldqd4jpyase:
|
||||
resolution: {integrity: sha512-/Lc+5AmV+T5pTm5P+rWpL+gseNHNye7xaUWpULczHai5ZLVg/ZE3+MBwK3Ai+/SmZKR/mK2YuXgNKnTGToEGYg==}
|
||||
peerDependencies:
|
||||
|
||||
@ -1,7 +1,15 @@
|
||||
export const storeKey = 'strudel-settings';
|
||||
const defaults = {
|
||||
keybindings: 'codemirror',
|
||||
theme: 'strudelTheme',
|
||||
fontSize: 18,
|
||||
};
|
||||
|
||||
export function get(prop) {
|
||||
const state = JSON.parse(localStorage.getItem(storeKey));
|
||||
let state = {
|
||||
...defaults,
|
||||
...JSON.parse(localStorage.getItem(storeKey) || '{}'),
|
||||
};
|
||||
if (!prop) {
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -206,34 +206,107 @@ function SamplesTab() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
function SettingsTab() {
|
||||
const { state, update } = useStore();
|
||||
const { theme, vim } = state;
|
||||
|
||||
function ButtonGroup({ value, onChange, items }) {
|
||||
return (
|
||||
<div className="text-foreground grid space-y-4 p-2">
|
||||
<label className="space-x-2">
|
||||
<span>Theme</span>
|
||||
<select
|
||||
className="p-2 bg-background rounded-md text-foreground"
|
||||
value={theme}
|
||||
onChange={(e) => update((current) => ({ ...current, theme: e.target.value }))}
|
||||
<div className="flex grow">
|
||||
{Object.entries(items).map(([key, label], i, arr) => (
|
||||
<button
|
||||
key={key}
|
||||
onClick={() => onChange(key)}
|
||||
className={cx(
|
||||
'p-2 grow',
|
||||
i === 0 && 'rounded-l-md',
|
||||
i === arr.length - 1 && 'rounded-r-md',
|
||||
value === key ? 'bg-background' : 'bg-lineHighlight',
|
||||
)}
|
||||
>
|
||||
{Object.entries(themes).map(([k, t]) => (
|
||||
<option key={k} className="bg-background">
|
||||
{k}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label className="space-x-2">
|
||||
<input
|
||||
className="bg-background w-5 h-5 rounded-md"
|
||||
type="checkbox"
|
||||
checked={vim}
|
||||
onChange={(e) => update((current) => ({ ...current, vim: e.target.checked }))}
|
||||
/>
|
||||
<span>Vim Mode</span>
|
||||
</label>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function SelectInput({ value, options, onChange }) {
|
||||
return (
|
||||
<select
|
||||
className="p-2 bg-background rounded-md text-foreground"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
>
|
||||
{Object.entries(options).map(([k, label]) => (
|
||||
<option key={k} className="bg-background" value={k}>
|
||||
{label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
|
||||
function NumberSlider({ value, onChange, step = 1, ...rest }) {
|
||||
return (
|
||||
<div className="flex space-x-2 gap-1">
|
||||
<input
|
||||
className="p-2 grow"
|
||||
type="range"
|
||||
value={value}
|
||||
step={step}
|
||||
onChange={(e) => onChange(Number(e.target.value))}
|
||||
{...rest}
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
value={value}
|
||||
step={step}
|
||||
className="w-16 bg-background rounded-md"
|
||||
onChange={(e) => onChange(Number(e.target.value))}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function FormItem({ label, children }) {
|
||||
return (
|
||||
<div className="grid gap-2">
|
||||
<label>{label}</label>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const themeOptions = Object.fromEntries(Object.keys(themes).map((k) => [k, k]));
|
||||
|
||||
function SettingsTab() {
|
||||
const { state, update } = useStore();
|
||||
const { theme, keybindings, fontSize } = state;
|
||||
return (
|
||||
<div className="text-foreground p-4 space-y-4">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<FormItem label="Theme">
|
||||
<SelectInput
|
||||
options={themeOptions}
|
||||
value={theme}
|
||||
onChange={(theme) => update((current) => ({ ...current, theme }))}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="Font Size">
|
||||
<NumberSlider
|
||||
value={fontSize}
|
||||
onChange={(fontSize) => update((current) => ({ ...current, fontSize }))}
|
||||
min={10}
|
||||
max={40}
|
||||
step={2}
|
||||
/>
|
||||
</FormItem>
|
||||
</div>
|
||||
<FormItem label="Keybindings">
|
||||
<ButtonGroup
|
||||
value={keybindings}
|
||||
onChange={(keybindings) => update((current) => ({ ...current, keybindings }))}
|
||||
items={{ codemirror: 'Codemirror', vim: 'Vim', emacs: 'Emacs' }}
|
||||
></ButtonGroup>
|
||||
</FormItem>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ export function Repl({ embedded = false }) {
|
||||
|
||||
const { theme, themeSettings } = useTheme();
|
||||
const {
|
||||
state: { vim },
|
||||
state: { keybindings, fontSize },
|
||||
} = useStore();
|
||||
|
||||
const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } =
|
||||
@ -282,7 +282,8 @@ export function Repl({ embedded = false }) {
|
||||
<CodeMirror
|
||||
theme={themes[theme] || themes.strudelTheme}
|
||||
value={code}
|
||||
vimMode={vim}
|
||||
keybindings={keybindings}
|
||||
fontSize={fontSize}
|
||||
onChange={handleChangeCode}
|
||||
onViewChanged={setView}
|
||||
onSelectionChange={handleSelectionChange}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user