39 lines
1.1 KiB
TypeScript
39 lines
1.1 KiB
TypeScript
|
|
import { useEffect, useRef } from "preact/hooks";
|
||
|
|
import type { LogLine } from "../types";
|
||
|
|
|
||
|
|
interface Props {
|
||
|
|
lines: LogLine[];
|
||
|
|
}
|
||
|
|
|
||
|
|
export function LogPanel({ lines }: Props) {
|
||
|
|
const innerRef = useRef<HTMLDivElement>(null);
|
||
|
|
|
||
|
|
// Scroll to top (newest line — column-reverse layout) after each update
|
||
|
|
useEffect(() => {
|
||
|
|
const el = innerRef.current?.parentElement;
|
||
|
|
if (el) el.scrollTop = 0;
|
||
|
|
}, [lines]);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div id="log">
|
||
|
|
<div id="log-inner" ref={innerRef}>
|
||
|
|
{lines.map((line) => {
|
||
|
|
const time = line.timestamp ? new Date(line.timestamp).toLocaleTimeString() : "";
|
||
|
|
const role = line.role.trim().toLowerCase();
|
||
|
|
let text: string;
|
||
|
|
if (role === "nanobot") {
|
||
|
|
text = `[${time}] ${line.text.replace(/^(?:nanobot|napbot)\b\s*[:>-]?\s*/i, "")}`;
|
||
|
|
} else {
|
||
|
|
text = `[${time}] ${line.role}: ${line.text}`;
|
||
|
|
}
|
||
|
|
return (
|
||
|
|
<div key={line.id} class={`line ${line.role}`}>
|
||
|
|
{text}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
})}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|