Skip to content

feat(ui): give the terminal pane a header with tabs, close and size #68

Description

@smileygames

目的

診断面の端末を、独立した窓として扱えるようにする。上部にヘッダを持ち、そこにタブ・閉じる・寸法の操作を載せる。角を丸くする。

Master の発言(2026-08-24):

このターミナルみたいにタブと閉じるボタンを端末ウィンドウにつけたいんだよ。あとウィンドウも角を丸く表示させて。でそのトップヘッダーにサイズ変更機能も付ければ完璧じゃない?
タブは並列起動しているCLI用って感じね?

前提

いまの形

端末は #diagnosticsheight: 50vhaside)の中の #terminal 一枠で、走っているアカウントごとに端末を作り、選ばれた一つ以外を hidden にしている(#57)。ヘッダは持たない。

  • 切り替え = 参加者パネルの行。行を押すと showView(accountId) が走る。
  • 面の開閉 = ヘッダの 診断 ボタン(#diagnostics.hidden の反転)。
  • セッションの終了 = 行の 終了。取り消せないため 2 クリック(feat(account): give each account its own terminal and a way to end it #57)。
  • 角丸 = #terminalborder-radius: 4px が既にある。

決まったこと(Master、2026-08-24)

  • 閉じるボタンは面をたたむ。 セッションは生きたまま。行の 終了 は移さない。
  • 切り替えはタブと行の両方から。連動する。 どちらを押しても同じ端末が出る。
  • ヘッダのサイズ変更は端末自身の寸法。 xterm の fontSize を動かす。UI 全体の寸法(feat(ui): let the whole UI be scaled from a global setting #66)ではない。

三つめにより寸法の軸が三本に確定した — 会話面(#60、実装済み)、端末(この issue)、UI 全体(#66)。いずれも独立しており、互いに相対で乗らない。

受け入れた重複

タブと行の連動は、同じ選択を二つの面が持つ形である。#59 は「一つの名簿を二つ描くのは、一面多い」としてヘッダの名簿を落としており、その判断とは逆を向く。Master は重複を承知の上で両方を選んだ。ここでは決着済みとして扱い、実装時に蒸し返さない。

実装の形

未決であった五点を、着手前に次のとおり決めた。

  • 診断 は残す。外から開き、中から閉じる。 面をたたむ意味は同じだが、たためた状態から開く手が × には無い。二つは同じ操作の入口と出口であり、重なっているのは意味であって役割ではない。
  • 角丸は面全体(#diagnostics)が持つ。 #terminal は上側の角を手放す。値は 4px より大きくし、ヘッダの上端と面の下端で揃える。
  • 端末の寸法は localStorage の梯子で持つ。 feat(ui): let the chat text size be changed #60 の会話面と同じ形にする。値を変えるたびに fit を呼び、桁数と行数を計算し直す。上下限も feat(ui): let the chat text size be changed #60 に倣って梯子の両端で止める。
  • タブの表示はアカウント名。 起動コマンドは行の title#account-dialog で既に読める。走っていないアカウントはタブを持たない(端末そのものが無いため)。
  • 終了したセッションのタブには × を持たせる(Master、2026-08-24)。終了した端末は押されるまでタブに残り、× を押した時点で捨てる。

「読んだ」の合図が移る

src/main.tsshowView は、終了した端末を「別のアカウントが選ばれた」時点で捨てている。コメントがその理由を書いている——

choosing another account is the person saying they have read it (#57)

タブに × が付くと、この合図は暗黙の選択から明示の操作へ移る。showView 冒頭の終了ビュー破棄(if (view.ended !== null && view.accountId !== accountId) discardView(view))は落ち、discardView はタブの × から呼ばれる。合図そのものは失われない——置き場所が変わる。

代償は、閉じられるまで終了済みの端末が views に残ること。scrollback を抱えたまま生き続けるため、放置されたタブの分だけメモリを持つ。#57 は「読んだら消える」ことでこれを避けていた。Master は明示の操作を選んだ上でこれを受け入れている。決着済みとして扱い、実装時に蒸し返さない。

× は終了したタブにだけ出す

走っているセッションのタブは × を持たない。持たせると「セッションの終了」と読まれ、制約(行の 終了 を端末側へ移さない)を破る。走っているセッションを終わらせる手は行の ❌(#71)のままである。

実機を見ての追加指示(Master、2026-08-24)

ヘッダが出た状態の実機を見ての指示。同じ PR で扱う。

端末ウィンドウのヘッダーの色分けなしで。ウィンドウタイトルに端末ってのが欲しいかも。
あと、端末ウィンドウ枠の余白をもっと少なくしてもらえる

  • ヘッダに色を敷かない。 面の他の部分と同じ地のままにする。ヘッダであることは位置と中身が言うのであって、色を変えて言う必要はない。
  • ヘッダに「端末」を出す。 窓の名前として左に置く。タブはその後ろに並ぶ。
    タブが並ぶのは走っているセッションがあるときだけであり、起動直後のヘッダにはタブが無い。名前が効くのはその状態である。一方でアプリのヘッダ右上の 端末 ボタンが既に同じ名前を言っており、タブが並んでいる間は一面多いとも読める(feat(account): one participant list, and a dialog to make an account in #59 の判断の筋)。まず残す形で出し、実機を見てから落とすかを決める(Master、2026-08-24)。落とす判断になった場合は別 issue で扱う。
  • 枠の余白を詰める。 端末の外側(#diagnostics#terminal の間)に入っている余白を今より小さくする。端末は桁数と行数をその寸法から計算するため、余白を削った分は端末が使える面積になる。

制約

対象ファイル

  • index.html — 端末ヘッダとタブ
  • src/styles.css — ヘッダ、角丸、#diagnostics / #terminal の枠
  • src/main.ts — タブの描画と連動、面の開閉、xterm の寸法と fit
  • docs/0-requirements.md

関連

Metadata

Metadata

Assignees

Labels

enhancement新機能・改善要望ready本文が実装開始できる形まで収束している状態。ただし更新は継続可能

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions