Font size
This commit is contained in:
@@ -47,10 +47,11 @@ interface EditorProps {
|
|||||||
initialValue?: string;
|
initialValue?: string;
|
||||||
onChange?: (editor: any, changes: any) => void;
|
onChange?: (editor: any, changes: any) => void;
|
||||||
onReady?: (editor: any) => void;
|
onReady?: (editor: any) => void;
|
||||||
|
fontSize?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Editor = forwardRef<any, EditorProps>(function Editor(
|
export const Editor = forwardRef<any, EditorProps>(function Editor(
|
||||||
{ initialValue = "", onChange, onReady },
|
{ initialValue = "", onChange, onReady, fontSize = 14 },
|
||||||
ref
|
ref
|
||||||
) {
|
) {
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
@@ -113,6 +114,17 @@ export const Editor = forwardRef<any, EditorProps>(function Editor(
|
|||||||
};
|
};
|
||||||
}, []); // DO NOT FILL ARRAY
|
}, []); // DO NOT FILL ARRAY
|
||||||
|
|
||||||
|
// Update font size when it changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (editorRef.current) {
|
||||||
|
const wrapper = editorRef.current.getWrapperElement();
|
||||||
|
if (wrapper) {
|
||||||
|
wrapper.style.fontSize = `${fontSize}px`;
|
||||||
|
editorRef.current.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [fontSize]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.editorContainer}>
|
<div className={styles.editorContainer}>
|
||||||
<textarea
|
<textarea
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { useState, useRef, useCallback, useEffect } from "react";
|
import { useState, useRef, useCallback, useEffect } from "react";
|
||||||
import { Button } from "@/components/ui/Button";
|
import { Button } from "@/components/ui/Button";
|
||||||
import { Dropdown } from "@/components/ui/Dropdown";
|
import { Dropdown } from "@/components/ui/Dropdown";
|
||||||
|
import { Slider } from "@/components/ui/Slider";
|
||||||
import { Editor } from "@/components/Editor";
|
import { Editor } from "@/components/Editor";
|
||||||
import { Terminal, TerminalRef } from "@/components/Terminal";
|
import { Terminal, TerminalRef } from "@/components/Terminal";
|
||||||
import {
|
import {
|
||||||
@@ -46,6 +47,7 @@ const exampleScriptList = [
|
|||||||
export default function Playground() {
|
export default function Playground() {
|
||||||
const [isScriptRunning, setIsScriptRunning] = useState(false);
|
const [isScriptRunning, setIsScriptRunning] = useState(false);
|
||||||
const [isEditorReady, setIsEditorReady] = useState(false);
|
const [isEditorReady, setIsEditorReady] = useState(false);
|
||||||
|
const [fontSize, setFontSize] = useState(14);
|
||||||
|
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
const resultRef = useRef<HTMLTextAreaElement>(null);
|
const resultRef = useRef<HTMLTextAreaElement>(null);
|
||||||
@@ -191,6 +193,24 @@ export default function Playground() {
|
|||||||
}))}
|
}))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Dropdown
|
||||||
|
trigger="Config"
|
||||||
|
align="right"
|
||||||
|
customContent={
|
||||||
|
<div className={styles.configPanel}>
|
||||||
|
<Slider
|
||||||
|
label="Font Size"
|
||||||
|
value={fontSize}
|
||||||
|
min={10}
|
||||||
|
max={24}
|
||||||
|
step={1}
|
||||||
|
onChange={setFontSize}
|
||||||
|
unit="px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<Dropdown
|
<Dropdown
|
||||||
triggerIcon="help-circle"
|
triggerIcon="help-circle"
|
||||||
align="right"
|
align="right"
|
||||||
@@ -246,6 +266,7 @@ export default function Playground() {
|
|||||||
initialValue={initialCode}
|
initialValue={initialCode}
|
||||||
onChange={() => {}}
|
onChange={() => {}}
|
||||||
onReady={() => setIsEditorReady(true)}
|
onReady={() => setIsEditorReady(true)}
|
||||||
|
fontSize={fontSize}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.rightPanel}>
|
<div className={styles.rightPanel}>
|
||||||
@@ -255,6 +276,7 @@ export default function Playground() {
|
|||||||
<Terminal
|
<Terminal
|
||||||
ref={terminalRef}
|
ref={terminalRef}
|
||||||
onData={sendDataToScript}
|
onData={sendDataToScript}
|
||||||
|
fontSize={fontSize}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -266,6 +288,7 @@ export default function Playground() {
|
|||||||
readOnly
|
readOnly
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
placeholder="Use print() to produce output"
|
placeholder="Use print() to produce output"
|
||||||
|
style={{ fontSize: `${fontSize}px` }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export const Terminal = forwardRef<
|
|||||||
TerminalRef,
|
TerminalRef,
|
||||||
{
|
{
|
||||||
onData: (data: String) => void;
|
onData: (data: String) => void;
|
||||||
|
fontSize?: number;
|
||||||
}
|
}
|
||||||
>(function Terminal(props, ref) {
|
>(function Terminal(props, ref) {
|
||||||
const terminalRef = useRef<HTMLDivElement>(null);
|
const terminalRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -54,7 +55,7 @@ export const Terminal = forwardRef<
|
|||||||
// - `init_term()` ccompletes, and we attempt to set `xtermRef.current`, causing issues
|
// - `init_term()` ccompletes, and we attempt to set `xtermRef.current`, causing issues
|
||||||
let mounted = true;
|
let mounted = true;
|
||||||
|
|
||||||
init_term(terminalRef, props.onData, () => mounted)
|
init_term(terminalRef, props.onData, () => mounted, props.fontSize)
|
||||||
.then((term) => {
|
.then((term) => {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
xtermRef.current = term;
|
xtermRef.current = term;
|
||||||
@@ -70,7 +71,14 @@ export const Terminal = forwardRef<
|
|||||||
xtermRef.current = null;
|
xtermRef.current = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [props.onData]);
|
}, [props.onData, props.fontSize]);
|
||||||
|
|
||||||
|
// Update font size when it changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (xtermRef.current && props.fontSize !== undefined) {
|
||||||
|
xtermRef.current.options.fontSize = props.fontSize;
|
||||||
|
}
|
||||||
|
}, [props.fontSize]);
|
||||||
|
|
||||||
return <div ref={terminalRef} style={{ height: "100%", width: "100%" }} />;
|
return <div ref={terminalRef} style={{ height: "100%", width: "100%" }} />;
|
||||||
});
|
});
|
||||||
@@ -80,7 +88,8 @@ async function init_term(
|
|||||||
|
|
||||||
// Called when the terminal receives data
|
// Called when the terminal receives data
|
||||||
onData: (data: String) => void,
|
onData: (data: String) => void,
|
||||||
isMounted: () => boolean
|
isMounted: () => boolean,
|
||||||
|
fontSize?: number
|
||||||
) {
|
) {
|
||||||
if (!ref.current) return;
|
if (!ref.current) return;
|
||||||
|
|
||||||
@@ -90,7 +99,7 @@ async function init_term(
|
|||||||
const term = new Terminal({
|
const term = new Terminal({
|
||||||
//"fontFamily": "Fantasque",
|
//"fontFamily": "Fantasque",
|
||||||
rows: 30,
|
rows: 30,
|
||||||
fontSize: 18,
|
fontSize: fontSize ?? 18,
|
||||||
tabStopWidth: 4,
|
tabStopWidth: 4,
|
||||||
cursorBlink: false,
|
cursorBlink: false,
|
||||||
cursorStyle: "block",
|
cursorStyle: "block",
|
||||||
|
|||||||
49
webui/src/components/ui/Slider.tsx
Normal file
49
webui/src/components/ui/Slider.tsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ChangeEvent } from "react";
|
||||||
|
import styles from "@/styles/Slider.module.css";
|
||||||
|
|
||||||
|
interface SliderProps {
|
||||||
|
label: string;
|
||||||
|
value: number;
|
||||||
|
min: number;
|
||||||
|
max: number;
|
||||||
|
step?: number;
|
||||||
|
onChange: (value: number) => void;
|
||||||
|
unit?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Slider({
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
step = 1,
|
||||||
|
onChange,
|
||||||
|
unit = "",
|
||||||
|
}: SliderProps) {
|
||||||
|
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
onChange(Number(e.target.value));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.sliderContainer}>
|
||||||
|
<div className={styles.sliderLabel}>
|
||||||
|
<span>{label}</span>
|
||||||
|
<span className={styles.sliderValue}>
|
||||||
|
{value}
|
||||||
|
{unit}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min={min}
|
||||||
|
max={max}
|
||||||
|
step={step}
|
||||||
|
value={value}
|
||||||
|
onChange={handleChange}
|
||||||
|
className={styles.slider}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
57
webui/src/styles/Slider.module.css
Normal file
57
webui/src/styles/Slider.module.css
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
.sliderContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sliderLabel {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sliderValue {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #3a3a3a;
|
||||||
|
outline: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #4fc3f7;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider::-webkit-slider-thumb:hover {
|
||||||
|
background: #6dd1ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider::-moz-range-thumb {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #4fc3f7;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider::-moz-range-thumb:hover {
|
||||||
|
background: #6dd1ff;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user