mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 23:04:52 +09:00
Merge pull request #939 from bbassie/feature/resizable-console
Make the Web UI console resizable
This commit is contained in:
2 files changed
+49
-4
No files matched your search
@@ -4,10 +4,14 @@ import { Select, Typography } from "antd";
|
||||
import * as lib from "@clusterio/lib";
|
||||
|
||||
import { useAccount } from "../model/account";
|
||||
import useLocalStorage from "../util/useLocalStorage";
|
||||
import ControlContext from "./ControlContext";
|
||||
|
||||
const { Paragraph } = Typography;
|
||||
|
||||
const consoleHeightKey = "instance-console-height";
|
||||
const defaultConsoleHeight = 300;
|
||||
|
||||
type Parsed = {
|
||||
format: string;
|
||||
type: string;
|
||||
@@ -99,6 +103,36 @@ export default function LogConsole(props: LogConsoleProps) {
|
||||
let anchor = useRef<any>();
|
||||
let [pastLines, setPastLines] = useState([<span key={0}>{"Loading past entries..."}<br/></span>]);
|
||||
let [lines, setLines] = useState<ReactElement[]>([]);
|
||||
const [consoleHeight, setConsoleHeight] = useLocalStorage(consoleHeightKey, defaultConsoleHeight);
|
||||
const consoleHeightRef = useRef(consoleHeight);
|
||||
consoleHeightRef.current = consoleHeight;
|
||||
|
||||
// The console is resized with the browser's native resize handle, which owns
|
||||
// the element's inline height. Driving the height from React would rewrite
|
||||
// that inline style on every re-render and fight the drag (locking the size),
|
||||
// so the height is only read here (on mount) and persisted (on resize), never
|
||||
// written back through React. The scroll container is the <code> element
|
||||
// wrapping the anchor.
|
||||
useEffect(() => {
|
||||
const element = anchor.current?.parentElement as HTMLElement | undefined;
|
||||
if (!element) {
|
||||
return undefined;
|
||||
}
|
||||
element.style.height = `${consoleHeightRef.current}px`;
|
||||
|
||||
if (typeof ResizeObserver === "undefined") {
|
||||
return undefined;
|
||||
}
|
||||
const observer = new ResizeObserver(() => {
|
||||
const next = Math.round(element.offsetHeight);
|
||||
if (next && next !== consoleHeightRef.current) {
|
||||
consoleHeightRef.current = next;
|
||||
setConsoleHeight(next);
|
||||
}
|
||||
});
|
||||
observer.observe(element);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
let logFilter = {
|
||||
@@ -164,6 +198,10 @@ export default function LogConsole(props: LogConsoleProps) {
|
||||
|
||||
return <>
|
||||
<Paragraph code className="instance-console">
|
||||
{/* Scrollable spacer (one console-height tall) that keeps short output
|
||||
pinned to the bottom and leaves room to scroll up. Unlike a
|
||||
padding-top it is scroll content, so it does not constrain resize. */}
|
||||
<div className="console-spacer" key="spacer" />
|
||||
{pastLines}
|
||||
{lines}
|
||||
<div className="scroll-anchor" key="anchor" ref={anchor} />
|
||||
|
||||
@@ -174,18 +174,25 @@ body {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
/* Scroll headroom above the output so short output sits at the bottom; it is
|
||||
scroll content, not box padding, so it does not block dragging smaller. */
|
||||
.instance-console code .console-spacer {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.instance-console code {
|
||||
display: block;
|
||||
margin: 0;
|
||||
background: #000;
|
||||
border-color: #252525;
|
||||
/* Drag-resizable (the native handle needs the scroll overflow); height is set
|
||||
imperatively in LogConsole, border-box keeps padding out of offsetHeight. */
|
||||
box-sizing: border-box;
|
||||
height: 300px;
|
||||
min-height: 100px;
|
||||
resize: vertical;
|
||||
overflow-y: scroll;
|
||||
white-space: pre-wrap;
|
||||
|
||||
/* Make sure there's at least one pixel of scroll space, this */
|
||||
/* is necessary for the view to stick on the scroll anchor. */
|
||||
padding-top: 300px;
|
||||
}
|
||||
|
||||
.instance-console .factorio-time {
|
||||
|
||||
Reference in new issue
Block a user