Font size

This commit is contained in:
2025-11-01 11:18:34 -07:00
parent ccd4292ed2
commit e77db1f4c5
5 changed files with 155 additions and 5 deletions

View File

@@ -47,10 +47,11 @@ interface EditorProps {
initialValue?: string;
onChange?: (editor: any, changes: any) => void;
onReady?: (editor: any) => void;
fontSize?: number;
}
export const Editor = forwardRef<any, EditorProps>(function Editor(
{ initialValue = "", onChange, onReady },
{ initialValue = "", onChange, onReady, fontSize = 14 },
ref
) {
const textareaRef = useRef<HTMLTextAreaElement>(null);
@@ -113,6 +114,17 @@ export const Editor = forwardRef<any, EditorProps>(function Editor(
};
}, []); // 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 (
<div className={styles.editorContainer}>
<textarea

View File

@@ -3,6 +3,7 @@
import { useState, useRef, useCallback, useEffect } from "react";
import { Button } from "@/components/ui/Button";
import { Dropdown } from "@/components/ui/Dropdown";
import { Slider } from "@/components/ui/Slider";
import { Editor } from "@/components/Editor";
import { Terminal, TerminalRef } from "@/components/Terminal";
import {
@@ -46,6 +47,7 @@ const exampleScriptList = [
export default function Playground() {
const [isScriptRunning, setIsScriptRunning] = useState(false);
const [isEditorReady, setIsEditorReady] = useState(false);
const [fontSize, setFontSize] = useState(14);
const editorRef = useRef<any>(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
triggerIcon="help-circle"
align="right"
@@ -246,6 +266,7 @@ export default function Playground() {
initialValue={initialCode}
onChange={() => {}}
onReady={() => setIsEditorReady(true)}
fontSize={fontSize}
/>
</div>
<div className={styles.rightPanel}>
@@ -255,6 +276,7 @@ export default function Playground() {
<Terminal
ref={terminalRef}
onData={sendDataToScript}
fontSize={fontSize}
/>
</div>
</div>
@@ -266,6 +288,7 @@ export default function Playground() {
readOnly
autoComplete="off"
placeholder="Use print() to produce output"
style={{ fontSize: `${fontSize}px` }}
/>
</div>
</div>

View File

@@ -19,6 +19,7 @@ export const Terminal = forwardRef<
TerminalRef,
{
onData: (data: String) => void;
fontSize?: number;
}
>(function Terminal(props, ref) {
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
let mounted = true;
init_term(terminalRef, props.onData, () => mounted)
init_term(terminalRef, props.onData, () => mounted, props.fontSize)
.then((term) => {
if (!mounted) return;
xtermRef.current = term;
@@ -70,7 +71,14 @@ export const Terminal = forwardRef<
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%" }} />;
});
@@ -80,7 +88,8 @@ async function init_term(
// Called when the terminal receives data
onData: (data: String) => void,
isMounted: () => boolean
isMounted: () => boolean,
fontSize?: number
) {
if (!ref.current) return;
@@ -90,7 +99,7 @@ async function init_term(
const term = new Terminal({
//"fontFamily": "Fantasque",
rows: 30,
fontSize: 18,
fontSize: fontSize ?? 18,
tabStopWidth: 4,
cursorBlink: false,
cursorStyle: "block",

View 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>
);
}

View 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;
}