feat: publish initial manifest on startup and improve UI focus

- Publish the existing session manifest via the broker on startup
- Automatically focus the new session input field when it is shown
- Prevent event propagation when clicking to create a new session
This commit is contained in:
hypercross 2026-07-08 00:08:12 +08:00
parent 3eba8b3279
commit 57ffb35f2b
2 changed files with 35 additions and 3 deletions

View File

@ -150,6 +150,20 @@ export async function createJournalServer(
() => {},
);
// Publish the initial manifest on startup so clients see existing sessions
const initialManifest = loadManifest(root);
broker.publish(
{
topic: $SESSIONS,
payload: Buffer.from(JSON.stringify(initialManifest)),
qos: 1,
retain: true,
cmd: "publish" as const,
dup: false,
},
() => {},
);
console.log("[journal] persistence listener active");
console.log("[journal] broker available at ws://<host>:<port>");

View File

@ -5,7 +5,14 @@
* Auto-connects to ws://{current host}:{current port} — no URL input needed.
*/
import { Component, Show, createSignal, onMount, For } from "solid-js";
import {
Component,
Show,
createSignal,
onMount,
For,
createEffect,
} from "solid-js";
import {
connectStream,
hydrateFromServer,
@ -113,6 +120,7 @@ const JournalHeader: Component<JournalHeaderProps> = (props) => {
const [newSessionName, setNewSessionName] = createSignal("");
const [showNewInput, setShowNewInput] = createSignal(false);
let dropdownRef!: HTMLDivElement;
let newSessionInputRef!: HTMLInputElement;
const handleSessionSelect = async (id: string) => {
try {
@ -132,6 +140,13 @@ const JournalHeader: Component<JournalHeaderProps> = (props) => {
setShowNewInput(false);
};
// Focus the input when it appears
createEffect(() => {
if (showNewInput() && newSessionInputRef) {
newSessionInputRef.focus();
}
});
const handleDisconnect = () => disconnectStream();
// Close dropdown on outside click
@ -214,6 +229,7 @@ const JournalHeader: Component<JournalHeaderProps> = (props) => {
fallback={
<div class="px-3 py-1 flex gap-1">
<input
ref={newSessionInputRef}
type="text"
value={newSessionName()}
onInput={(e) =>
@ -221,7 +237,6 @@ const JournalHeader: Component<JournalHeaderProps> = (props) => {
}
placeholder="会话名称"
class="flex-1 border border-gray-300 rounded px-1.5 py-0.5 text-xs"
autofocus
onKeyDown={(e) => {
if (e.key === "Enter") handleCreate();
if (e.key === "Escape") setShowNewInput(false);
@ -237,7 +252,10 @@ const JournalHeader: Component<JournalHeaderProps> = (props) => {
}
>
<button
onClick={() => setShowNewInput(true)}
onClick={(e) => {
e.stopPropagation();
setShowNewInput(true);
}}
class="w-full text-left px-3 py-1 text-xs text-blue-600 hover:bg-gray-100"
>
+