diff --git a/src/components/journal/ComposePanel.tsx b/src/components/journal/ComposePanel.tsx index c638523..2489bf7 100644 --- a/src/components/journal/ComposePanel.tsx +++ b/src/components/journal/ComposePanel.tsx @@ -4,12 +4,7 @@ import { Component, createSignal, For, Show, createMemo } from "solid-js"; import { registeredTypes, canEmit } from "./registry"; -import { - sendMessage, - revertLatest, - canRevert, - useJournalStream, -} from "../stores/journalStream"; +import { sendMessage, useJournalStream } from "../stores/journalStream"; import type { MessageTypeDef } from "./registry"; import { DynamicForm } from "./DynamicForm"; @@ -20,7 +15,7 @@ export const ComposePanel: Component = () => { const [error, setError] = createSignal(null); const [sending, setSending] = createSignal(false); - const role = () => stream.myName; + const role = () => stream.myRole; // Available types filtered by role const availableTypes = createMemo(() => { @@ -51,12 +46,6 @@ export const ComposePanel: Component = () => { setSending(false); }; - const handleRevert = () => { - revertLatest(); - }; - - const showRevert = () => canRevert() && stream.myName === "gm"; - return (
{/* Type picker */} @@ -81,16 +70,6 @@ export const ComposePanel: Component = () => { > {sending() ? "..." : "Send"} - - - -
{/* Dynamic form */} diff --git a/src/components/journal/JournalInput.tsx b/src/components/journal/JournalInput.tsx index de9622f..b39825a 100644 --- a/src/components/journal/JournalInput.tsx +++ b/src/components/journal/JournalInput.tsx @@ -21,11 +21,7 @@ import { Match, } from "solid-js"; import { sendMessage, useJournalStream } from "../stores/journalStream"; -import { - useJournalCompletions, - ensureCompletions, - type CompletionsState, -} from "./completions"; +import { useJournalCompletions, ensureCompletions } from "./completions"; // ---- Helpers ---- @@ -78,6 +74,10 @@ export const JournalInput: Component = () => { const stream = useJournalStream(); const comp = useJournalCompletions(); + const isObserver = () => stream.myRole === "observer"; + const isPlayer = () => stream.myRole === "player"; + const isGm = () => stream.myRole === "gm"; + const [text, setText] = createSignal(""); const [error, setError] = createSignal(null); const [sending, setSending] = createSignal(false); @@ -98,6 +98,18 @@ export const JournalInput: Component = () => { const raw = text().trim(); if (!raw) return; + // Players can't use commands — everything is narrative + if (isPlayer() || isObserver()) { + const result = sendMessage("narrative", { text: raw }); + if (!result.success) { + setError(result.error); + } else { + setText(""); + } + textareaRef?.focus(); + return; + } + const parsed = parseInput(raw); if (parsed.error) { setError(parsed.error); @@ -132,6 +144,8 @@ export const JournalInput: Component = () => { function buildCompletions(): CompletionItem[] { const raw = text().trim(); + // Only GM gets completions + if (!isGm()) return []; const data = comp.data; const commands = [ { label: "/roll", kind: "command" as const, insertText: "/roll " }, @@ -235,9 +249,9 @@ export const JournalInput: Component = () => { } return; } - // If not open and starts with /, open completions + // If not open and starts with /, open completions (GM only) const raw = text(); - if (raw.startsWith("/")) { + if (isGm() && raw.startsWith("/")) { e.preventDefault(); setShowCompletions(true); setSelectedIdx(0); @@ -280,8 +294,8 @@ export const JournalInput: Component = () => { const raw = input.value; setText(raw); - // Completions visibility — keep open while user types any / - if (raw.startsWith("/")) { + // Completions visibility — keep open while user types any / (GM only) + if (isGm() && raw.startsWith("/")) { setShowCompletions(true); setSelectedIdx(0); } else { @@ -386,35 +400,49 @@ export const JournalInput: Component = () => { {/* Textarea + actions */}
-