Skip to content

feat(gui): add mobile bottom tab navigation (Phase 2-B of #572)#583

Merged
takaokouji merged 5 commits into
developfrom
fix/issue-572-phase-2b-bottom-tabs
Apr 29, 2026
Merged

feat(gui): add mobile bottom tab navigation (Phase 2-B of #572)#583
takaokouji merged 5 commits into
developfrom
fix/issue-572-phase-2b-bottom-tabs

Conversation

@takaokouji
Copy link
Copy Markdown

Summary

MobileGui に 5 つのボトムタブナビゲーションを追加 (issue #572 Phase 2-B)。

タブ:

  • 🧱 ブロック
  • 💻 Ruby
  • 🐱 スプライト
  • 🎨 コスチューム
  • 🔊 音

?mobile_gui=1 URL フラグ + 狭幅 viewport (< 768px) のときのみ表示されるオプトイン機能。

挙動

タブ クリック時の動作
ブロック upstream の editorTab Redux にディスパッチ (activateTab(BLOCKS_TAB_INDEX))。上部タブも同期する
Ruby 同上、RUBY_TAB_INDEX
スプライト placeholderbottom-tabs 内 active 状態のみ切替。upstream の editorTab は変更しない (実際の全画面スプライト UI は後続 PR で追加)
コスチューム upstream の editorTab にディスパッチ、COSTUMES_TAB_INDEX
同上、SOUNDS_TAB_INDEX

設計

  • 表示位置は position: fixed + visualViewport API で viewport 下端に追従 (Phase 1 のバナーと同じ仕組み)
  • スクロールバーは scrollbar-width: none / ::-webkit-scrollbar { display: none } で隠す
  • React Portal で document.body 直下にレンダリングし、<GUI> の祖先要素 (transform 等) の影響を受けない
  • Portal 経由で <GUI>IntlProvider context が届かないため、MobileGui で ConnectedIntlProvider を個別に包んで FormattedMessage を有効化

変更ファイル

新規 (Smalruby 固有)

  • src/components/mobile-bottom-tabs/{mobile-bottom-tabs.jsx,css,index.js} — タブ本体
  • test/unit/components/mobile-bottom-tabs.test.jsx — 8 ユニットテスト (タブ存在 / active 切替 / dispatch / sprite ローカル状態)

変更

  • src/components/mobile-gui/mobile-gui.jsx<MobileBottomTabs><ConnectedIntlProvider> で包んで追加
  • src/locales/{ja,ja-Hira,en}.js — 5 タブのラベル翻訳追加
  • .prettierignore / smalruby-prettier-files.md — 新規ファイルをホワイトリストに追加

upstream への影響

ゼロ。upstream のファイルには触れていない (Phase 2-A の render-gui.jsx 改修のみがこれまで唯一の upstream 変更)。

検証

ユニットテスト (jest, 8 件)

  • 5 タブが描画される
  • 初期状態で editorTab 由来の active 状態が反映される
  • ブロック / Ruby / コスチューム / 音 の各クリックで activateTab が正しい引数で呼ばれる
  • スプライトクリック時は activateTab が呼ばれず、ローカル active 状態だけ立つ
  • 別タブクリックでスプライトのローカル active 状態が解除される

Playwright (Chromium, viewport 390×844)

  • ?no_beforeunload=1&mobile_gui=1 で 5 タブが viewport 下端に表示
  • Ruby タブクリック → bottom-tabs data-active=true + upstream aria-selected=true 両方が Ruby に切替
  • Sprite タブクリック → bottom-tabs では active、upstream は前の選択 (ルビー) を維持
  • Phase 1 警告バナーも併存表示 (z-index でバナー優先)

Phase 2 進捗

Test plan

  • ユニットテスト 8/8 緑
  • ESLint / Prettier クリーン
  • Playwright で動作確認 (タブ表示、切替、Sprite 特殊挙動)
  • Phase 1 機能 (warning banner, overflow-y: clip 等) リグレッションなし
  • CI green (push 後)

Related

🤖 Generated with Claude Code

MobileGui に 5 つのボトムタブナビゲーションを追加:
ブロック / Ruby / スプライト / コスチューム / 音

挙動:
- ブロック / Ruby / コスチューム / 音 はクリックすると upstream の
  editorTab Redux にディスパッチして既存タブを切り替える
  (上部タブと下部タブが同期して動く)
- スプライトタブは mobile 固有の placeholder。クリックで bottom-tabs 内の
  active 状態だけ切り替わり、upstream の editorTab には影響しない。
  実際の全画面スプライト UI は後続 PR で追加する
- 表示位置は position: fixed + visualViewport API で viewport 下端に追従
  (Phase 1 のバナーと同じ仕組み)
- スクロールバーは非表示、タッチ・ホイールでスクロール自体は可能

upstream への影響:
- 一切なし。新規ファイル + 既存 Smalruby ファイル (mobile-gui.jsx, locales)
  のみ修正

実装メモ:
- MobileBottomTabs は createPortal で document.body 直下に出すため、
  GUI 内側の IntlProvider が見えない。MobileGui で
  ConnectedIntlProvider を別途包んで FormattedMessage を有効化した
- Sprite キーだけ tabIndex: null にしておき、handleClick で
  data-tab-key 属性から判定
- react/jsx-no-bind 回避のため、各ボタンの onClick は同一の
  useCallback にまとめ、data-tab-key で識別

検証 (Playwright, viewport 390x844):
- ?mobile_gui=1 で 5 タブが viewport 下部に表示
- Ruby タブクリック → bottom-tabs と upstream-tabs 両方が Ruby に切替
- Sprite タブクリック → bottom-tabs では active、upstream は前の選択を維持

Refs #572

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

Phase 2-B のボトムタブ (issue #572) と Phase 1 の警告バナーが両方
viewport 下端を占有して重なる問題を解消する。

narrow-screen-warning の visualViewport 位置決め JS で、DOM 上に
mobile-bottom-tabs がある場合はその高さ分だけ banner.top を上げる:
  top = vv.offsetTop + vv.height - bannerHeight - tabsHeight

これでバナーがタブの上に積み上がり、両方が同時に視認できる。
タブが存在しない (Phase 1 のみのケース) では tabsHeight=0 なので
従来どおり viewport 下端に貼り付く (リグレッションなし)。

Refs #572

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@takaokouji takaokouji force-pushed the fix/issue-572-phase-2b-bottom-tabs branch from 28964ae to 62565df Compare April 29, 2026 14:13
takaokouji and others added 3 commits April 29, 2026 23:23
タブ表示の調整 (issue #572 Phase 2-B フォローアップ):

1. 各タブのアイコンを upstream の SVG に統一
   - コード: components/gui/icon--code.svg (puzzle piece)
   - ルビー: components/gui/icon--ruby.svg (Smalruby diamond)
   - スプライト: components/action-menu/icon--sprite.svg (cat)
   - コスチューム: components/gui/icon--costumes.svg (paint brush)
   - 音: components/gui/icon--sounds.svg (speaker)

2. ラベルを upstream の翻訳キーに統一
   - 「ブロック」→「コード」(gui.gui.codeTab)
   - 「ルビー」(gui.smalruby3.gui.rubyTab)
   - 「コスチューム」(gui.gui.costumesTab)
   - 「音」(gui.gui.soundsTab)
   - スプライトのみ Smalruby 専用キー (gui.mobileBottomTabs.sprite)

3. data-testid を `mobile-bottom-tabs-block` → `mobile-bottom-tabs-code` に変更

4. ?mobile_gui=1 のときは Phase 1 警告バナーを非表示 (mobile UI で既に
   最適化されているため案内不要)

ロケールから不要になった 4 キー (block/ruby/costume/sound) を削除。
sprite キーのみ残す。

Refs #572

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
issue #572 Phase 2-B フォローアップ:

1. ボトムタブの順序を変更:
   旧: コード / ルビー / スプライト / コスチューム / 音
   新: スプライト / コード / コスチューム / 音 / ルビー
   (要望: スプライトを最左に、ルビーを最右に)

2. スプライトアイコンを PC 画面右下のスプライト追加 FAB と同じ見た目に
   - icon--sprite.svg (action-menu) を 26x26 紫円背景に白アイコンで配置
   - 他のタブアイコンよりやや目立つ FAB 風スタイル

3. スプライトタブの翻訳キーを upstream の `gui.SpriteInfo.sprite` に変更
   - 元々 sprite-info パネルのラベルとして存在していたキーを再利用
   - Smalruby 専用の `gui.mobileBottomTabs.sprite` をロケールから削除
   (3 言語 ja / ja-Hira / en)

4. data-testid `mobile-bottom-tabs-block` → `mobile-bottom-tabs-code` に追従

Refs #572

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rite tab

issue #572 Phase 2-B フォローアップ:

- 紫の丸い背景と "+" バッジを削除し、ネコ単体のアイコンに変更
- 他のタブアイコンと同じ purple (#855CD6) 単色塗りで統一感

実装:
- 新規 Smalruby SVG: components/mobile-bottom-tabs/icon--sprite-cat.svg
  upstream の icon--sprite.svg からネコ部分のパスのみ抽出、fill を白から紫へ
- mobile-bottom-tabs.jsx の `iconKind: 'sprite-fab'` 分岐を削除し、
  通常タブと同じ <img className={styles.icon}> でレンダリング
- mobile-bottom-tabs.css の sprite-fab-icon / sprite-fab-img クラスを削除

Refs #572

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@takaokouji takaokouji force-pushed the fix/issue-572-phase-2b-bottom-tabs branch from 18c3813 to 7745eee Compare April 29, 2026 14:40
@takaokouji takaokouji merged commit 91e45e5 into develop Apr 29, 2026
9 checks passed
@takaokouji takaokouji deleted the fix/issue-572-phase-2b-bottom-tabs branch April 29, 2026 14:45
github-actions Bot pushed a commit that referenced this pull request Apr 29, 2026
…-phase-2b-bottom-tabs

feat(gui): add mobile bottom tab navigation (Phase 2-B of #572)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant