diff options
| -rw-r--r-- | nix/hashes.json | 2 | ||||
| -rw-r--r-- | packages/opencode/src/cli/cmd/tui/routes/session/index.tsx | 33 | ||||
| -rw-r--r-- | packages/opencode/src/util/locale.ts | 24 |
3 files changed, 54 insertions, 5 deletions
diff --git a/nix/hashes.json b/nix/hashes.json index c91afa86e..7f089c7e0 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,3 +1,3 @@ { - "nodeModules": "sha256-krj85tYW0P/YOnsXnO1cD5XkLtfWZzdXzj7CTNvsPPk=" + "nodeModules": "sha256-N33FQyKF6IgGIRZ8NFd9o1/sjHMwbQ6KQcnMFyN0WmI=" } diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 43b8cc9de..f5224b2f9 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -79,6 +79,7 @@ const context = createContext<{ width: number conceal: () => boolean showThinking: () => boolean + showTimestamps: () => boolean }>() function use() { @@ -109,6 +110,7 @@ export function Session() { const [sidebar, setSidebar] = createSignal<"show" | "hide" | "auto">(kv.get("sidebar", "auto")) const [conceal, setConceal] = createSignal(true) const [showThinking, setShowThinking] = createSignal(true) + const [showTimestamps, setShowTimestamps] = createSignal(kv.get("timestamps", "hide") === "show") const wide = createMemo(() => dimensions().width > 120) const sidebarVisible = createMemo(() => sidebar() === "show" || (sidebar() === "auto" && wide())) @@ -404,6 +406,19 @@ export function Session() { }, }, { + title: "Toggle timestamps", + value: "session.toggle.timestamps", + category: "Session", + onSelect: (dialog) => { + setShowTimestamps((prev) => { + const next = !prev + kv.set("timestamps", next ? "show" : "hide") + return next + }) + dialog.clear() + }, + }, + { title: "Toggle thinking blocks", value: "session.toggle.thinking", category: "Session", @@ -712,6 +727,7 @@ export function Session() { }, conceal, showThinking, + showTimestamps, }} > <box flexDirection="row" paddingBottom={1} paddingTop={1} paddingLeft={2} paddingRight={2} gap={2}> @@ -891,6 +907,7 @@ function UserMessage(props: { index: number pending?: string }) { + const ctx = use() const text = createMemo(() => props.parts.flatMap((x) => (x.type === "text" && !x.synthetic ? [x] : []))[0]) const files = createMemo(() => props.parts.flatMap((x) => (x.type === "file" ? [x] : []))) const sync = useSync() @@ -949,7 +966,13 @@ function UserMessage(props: { {sync.data.config.username ?? "You"}{" "} <Show when={queued()} - fallback={<span style={{ fg: theme.textMuted }}>{Locale.time(props.message.time.created)}</span>} + fallback={ + <span style={{ fg: theme.textMuted }}> + {ctx.showTimestamps() + ? `· ${Locale.todayTimeOrDateTime(props.message.time.created)}` + : `· ${Locale.time(props.message.time.created)}`} + </span> + } > <span style={{ bg: theme.accent, fg: theme.backgroundPanel, bold: true }}> QUEUED </span> </Show> @@ -973,6 +996,7 @@ function UserMessage(props: { function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; last: boolean }) { const local = useLocal() const { theme } = useTheme() + const ctx = use() return ( <> <For each={props.parts}> @@ -1015,7 +1039,12 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; las <box paddingLeft={3}> <text marginTop={1}> <span style={{ fg: local.agent.color(props.message.mode) }}>{Locale.titlecase(props.message.mode)}</span>{" "} - <span style={{ fg: theme.textMuted }}>{props.message.modelID}</span> + <span style={{ fg: theme.textMuted }}> + {props.message.modelID} + {ctx.showTimestamps() && + props.message.time.completed && + ` · ${Locale.todayTimeOrDateTime(props.message.time.completed)}`} + </span> </text> </box> </Match> diff --git a/packages/opencode/src/util/locale.ts b/packages/opencode/src/util/locale.ts index ab2623271..e567d5763 100644 --- a/packages/opencode/src/util/locale.ts +++ b/packages/opencode/src/util/locale.ts @@ -3,9 +3,29 @@ export namespace Locale { return str.replace(/\b\w/g, (c) => c.toUpperCase()) } - export function time(input: number) { + export function time(input: number): string { const date = new Date(input) - return date.toLocaleTimeString() + return date.toLocaleTimeString(undefined, { timeStyle: "short" }) + } + + export function datetime(input: number): string { + const date = new Date(input) + const localTime = time(input) + const localDate = date.toLocaleDateString() + return `${localTime} · ${localDate}` + } + + export function todayTimeOrDateTime(input: number): string { + const date = new Date(input) + const now = new Date() + const isToday = + date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate() + + if (isToday) { + return time(input) + } else { + return datetime(input) + } } export function number(num: number): string { |
