From d39403c8f5063418797590ec9bc0372df3329814 Mon Sep 17 00:00:00 2001 From: murashit Date: Fri, 5 Jun 2026 09:31:11 +0900 Subject: [PATCH] Show runtime mode icons in status bar --- src/features/chat/ui/composer.tsx | 99 +++++++++++++++++-- src/features/chat/view-model.ts | 46 ++++++--- src/styles/33-chat-composer.css | 70 ++++++++++++- .../chat/chat-composer-controller.test.ts | 18 +++- .../chat/ui/renderers/composer.test.ts | 89 ++++++++++++++++- tests/features/chat/view-model.test.ts | 54 +++++++++- tests/styles.test.ts | 37 ++++++- 7 files changed, 380 insertions(+), 33 deletions(-) diff --git a/src/features/chat/ui/composer.tsx b/src/features/chat/ui/composer.tsx index 976af20a..5394b53a 100644 --- a/src/features/chat/ui/composer.tsx +++ b/src/features/chat/ui/composer.tsx @@ -3,7 +3,7 @@ import { useLayoutEffect, useRef } from "preact/hooks"; import type { ComposerSuggestion } from "../composer/suggestions"; import type { ComposerMetaViewModel } from "../view-model"; -import { IconButton } from "../../../shared/ui/components"; +import { IconButton, ObsidianIcon } from "../../../shared/ui/components"; import { renderUiRoot } from "../../../shared/ui/ui-root"; import { syncTextareaHeight } from "../../../shared/ui/textarea-autogrow"; @@ -27,9 +27,20 @@ type ButtonProps = ButtonHTMLAttributes & { const DEFAULT_COMPOSER_META: ComposerMetaViewModel = { fatal: null, - context: "ctx --%", + context: { + cells: [ + { text: "⣀", placeholder: true }, + { text: "⣀", placeholder: true }, + { text: "⣀", placeholder: true }, + { text: "⣀", placeholder: true }, + ], + percent: "--%", + }, model: "default", effort: null, + planActive: false, + autoReviewActive: false, + fastActive: false, }; export function renderComposerShell( @@ -154,6 +165,31 @@ function ComposerMeta({ sendMode: ComposerSendMode; onSendOrInterrupt: () => void; }): UiNode { + const statusRef = useRef(null); + useLayoutEffect(() => { + const status = statusRef.current; + if (!status) return; + const win = status.win; + let frame = 0; + const update = () => { + frame = 0; + updateComposerMetaStatusOverflow(status); + }; + const scheduleUpdate = () => { + if (frame) win.cancelAnimationFrame(frame); + frame = win.requestAnimationFrame(update); + }; + update(); + const ResizeObserverCtor = (win as Window & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver; + const observer = ResizeObserverCtor ? new ResizeObserverCtor(scheduleUpdate) : null; + observer?.observe(status); + win.addEventListener("resize", scheduleUpdate); + return () => { + if (frame) win.cancelAnimationFrame(frame); + observer?.disconnect(); + win.removeEventListener("resize", scheduleUpdate); + }; + }, [meta]); if (meta.fatal) { return (
@@ -164,15 +200,23 @@ function ComposerMeta({ } return (
-