mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-22 02:58:32 +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/state": "^6.2.0",
|
||||||
"@codemirror/view": "^6.7.3",
|
"@codemirror/view": "^6.7.3",
|
||||||
"@lezer/highlight": "^1.1.3",
|
"@lezer/highlight": "^1.1.3",
|
||||||
|
"@replit/codemirror-emacs": "^6.0.0",
|
||||||
"@replit/codemirror-vim": "^6.0.6",
|
"@replit/codemirror-vim": "^6.0.6",
|
||||||
"@strudel.cycles/core": "workspace:*",
|
"@strudel.cycles/core": "workspace:*",
|
||||||
"@strudel.cycles/transpiler": "workspace:*",
|
"@strudel.cycles/transpiler": "workspace:*",
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { useCallback } from 'react';
|
|||||||
import { autocompletion } from '@codemirror/autocomplete';
|
import { autocompletion } from '@codemirror/autocomplete';
|
||||||
import { strudelAutocomplete } from './Autocomplete';
|
import { strudelAutocomplete } from './Autocomplete';
|
||||||
import { vim } from '@replit/codemirror-vim';
|
import { vim } from '@replit/codemirror-vim';
|
||||||
|
import { emacs } from '@replit/codemirror-emacs';
|
||||||
|
|
||||||
export const setFlash = StateEffect.define();
|
export const setFlash = StateEffect.define();
|
||||||
const flashField = StateField.define({
|
const flashField = StateField.define({
|
||||||
@ -98,7 +99,8 @@ export default function CodeMirror({
|
|||||||
onViewChanged,
|
onViewChanged,
|
||||||
onSelectionChange,
|
onSelectionChange,
|
||||||
theme,
|
theme,
|
||||||
vimMode,
|
keybindings,
|
||||||
|
fontSize = 18,
|
||||||
options,
|
options,
|
||||||
editorDidMount,
|
editorDidMount,
|
||||||
}) {
|
}) {
|
||||||
@ -122,9 +124,18 @@ export default function CodeMirror({
|
|||||||
},
|
},
|
||||||
[onSelectionChange],
|
[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 (
|
return (
|
||||||
<>
|
<div style={{ fontSize }} className="w-full">
|
||||||
<_CodeMirror
|
<_CodeMirror
|
||||||
value={value}
|
value={value}
|
||||||
theme={theme || strudelTheme}
|
theme={theme || strudelTheme}
|
||||||
@ -133,7 +144,7 @@ export default function CodeMirror({
|
|||||||
onUpdate={handleOnUpdate}
|
onUpdate={handleOnUpdate}
|
||||||
extensions={extensions}
|
extensions={extensions}
|
||||||
/>
|
/>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: 11;
|
z-index: 11;
|
||||||
font-size: 18px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-theme {
|
.cm-theme {
|
||||||
|
|||||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@ -164,6 +164,7 @@ importers:
|
|||||||
'@codemirror/state': ^6.2.0
|
'@codemirror/state': ^6.2.0
|
||||||
'@codemirror/view': ^6.7.3
|
'@codemirror/view': ^6.7.3
|
||||||
'@lezer/highlight': ^1.1.3
|
'@lezer/highlight': ^1.1.3
|
||||||
|
'@replit/codemirror-emacs': ^6.0.0
|
||||||
'@replit/codemirror-vim': ^6.0.6
|
'@replit/codemirror-vim': ^6.0.6
|
||||||
'@strudel.cycles/core': workspace:*
|
'@strudel.cycles/core': workspace:*
|
||||||
'@strudel.cycles/transpiler': workspace:*
|
'@strudel.cycles/transpiler': workspace:*
|
||||||
@ -186,6 +187,7 @@ importers:
|
|||||||
'@codemirror/state': 6.2.0
|
'@codemirror/state': 6.2.0
|
||||||
'@codemirror/view': 6.7.3
|
'@codemirror/view': 6.7.3
|
||||||
'@lezer/highlight': 1.1.3
|
'@lezer/highlight': 1.1.3
|
||||||
|
'@replit/codemirror-emacs': 6.0.0_cgfc5aojxuwjajwhkrgidrzxoa
|
||||||
'@replit/codemirror-vim': 6.0.6_a4vbhepr4qhxm5cldqd4jpyase
|
'@replit/codemirror-vim': 6.0.6_a4vbhepr4qhxm5cldqd4jpyase
|
||||||
'@strudel.cycles/core': link:../core
|
'@strudel.cycles/core': link:../core
|
||||||
'@strudel.cycles/transpiler': link:../transpiler
|
'@strudel.cycles/transpiler': link:../transpiler
|
||||||
@ -3404,6 +3406,20 @@ packages:
|
|||||||
tsm: 2.3.0
|
tsm: 2.3.0
|
||||||
dev: false
|
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:
|
/@replit/codemirror-vim/6.0.6_a4vbhepr4qhxm5cldqd4jpyase:
|
||||||
resolution: {integrity: sha512-/Lc+5AmV+T5pTm5P+rWpL+gseNHNye7xaUWpULczHai5ZLVg/ZE3+MBwK3Ai+/SmZKR/mK2YuXgNKnTGToEGYg==}
|
resolution: {integrity: sha512-/Lc+5AmV+T5pTm5P+rWpL+gseNHNye7xaUWpULczHai5ZLVg/ZE3+MBwK3Ai+/SmZKR/mK2YuXgNKnTGToEGYg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|||||||
@ -1,7 +1,15 @@
|
|||||||
export const storeKey = 'strudel-settings';
|
export const storeKey = 'strudel-settings';
|
||||||
|
const defaults = {
|
||||||
|
keybindings: 'codemirror',
|
||||||
|
theme: 'strudelTheme',
|
||||||
|
fontSize: 18,
|
||||||
|
};
|
||||||
|
|
||||||
export function get(prop) {
|
export function get(prop) {
|
||||||
const state = JSON.parse(localStorage.getItem(storeKey));
|
let state = {
|
||||||
|
...defaults,
|
||||||
|
...JSON.parse(localStorage.getItem(storeKey) || '{}'),
|
||||||
|
};
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -206,34 +206,107 @@ function SamplesTab() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
function SettingsTab() {
|
|
||||||
const { state, update } = useStore();
|
function ButtonGroup({ value, onChange, items }) {
|
||||||
const { theme, vim } = state;
|
|
||||||
return (
|
return (
|
||||||
<div className="text-foreground grid space-y-4 p-2">
|
<div className="flex grow">
|
||||||
<label className="space-x-2">
|
{Object.entries(items).map(([key, label], i, arr) => (
|
||||||
<span>Theme</span>
|
<button
|
||||||
<select
|
key={key}
|
||||||
className="p-2 bg-background rounded-md text-foreground"
|
onClick={() => onChange(key)}
|
||||||
value={theme}
|
className={cx(
|
||||||
onChange={(e) => update((current) => ({ ...current, theme: e.target.value }))}
|
'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]) => (
|
{label}
|
||||||
<option key={k} className="bg-background">
|
</button>
|
||||||
{k}
|
))}
|
||||||
</option>
|
</div>
|
||||||
))}
|
);
|
||||||
</select>
|
}
|
||||||
</label>
|
|
||||||
<label className="space-x-2">
|
function SelectInput({ value, options, onChange }) {
|
||||||
<input
|
return (
|
||||||
className="bg-background w-5 h-5 rounded-md"
|
<select
|
||||||
type="checkbox"
|
className="p-2 bg-background rounded-md text-foreground"
|
||||||
checked={vim}
|
value={value}
|
||||||
onChange={(e) => update((current) => ({ ...current, vim: e.target.checked }))}
|
onChange={(e) => onChange(e.target.value)}
|
||||||
/>
|
>
|
||||||
<span>Vim Mode</span>
|
{Object.entries(options).map(([k, label]) => (
|
||||||
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -121,7 +121,7 @@ export function Repl({ embedded = false }) {
|
|||||||
|
|
||||||
const { theme, themeSettings } = useTheme();
|
const { theme, themeSettings } = useTheme();
|
||||||
const {
|
const {
|
||||||
state: { vim },
|
state: { keybindings, fontSize },
|
||||||
} = useStore();
|
} = 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 } =
|
||||||
@ -282,7 +282,8 @@ export function Repl({ embedded = false }) {
|
|||||||
<CodeMirror
|
<CodeMirror
|
||||||
theme={themes[theme] || themes.strudelTheme}
|
theme={themes[theme] || themes.strudelTheme}
|
||||||
value={code}
|
value={code}
|
||||||
vimMode={vim}
|
keybindings={keybindings}
|
||||||
|
fontSize={fontSize}
|
||||||
onChange={handleChangeCode}
|
onChange={handleChangeCode}
|
||||||
onViewChanged={setView}
|
onViewChanged={setView}
|
||||||
onSelectionChange={handleSelectionChange}
|
onSelectionChange={handleSelectionChange}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user