Feat/file tree row menu - #648
Open
mrytsr wants to merge 4 commits into
Open
Conversation
added 4 commits
September 3, 2026 21:43
Add an on-screen virtual key bar for the terminal panel so mobile users
can send escape / tab / control / arrow / page keys without a hardware
keyboard. The bar mirrors the pios implementation: two rows of 14 buttons
(ESC / / — HOME ↑ END PGUP | TAB CTRL ALT ← ↓ → PGDN) with a CTRL/ALT
latch that wraps the next soft-keyboard input as a control byte or ESC
prefix respectively.
Pure encoding lives in lib/terminal/keybar.ts — 12 keys + termKeySeq +
applyTermMods + kbdLiftPx — covered by 18 unit tests. The new
<TermKeybar /> component is purely presentational and uses shadcn Button
+ Tailwind utilities, so there is no raw CSS.
Wiring:
- terminal-panel.tsx adds useMediaQuery('(max-width: 768px)') and a
localStorage-backed collapse flag (codeg:term-keybar) shared across
all tabs, then forwards keybarVisible down.
- terminal-tab-bar.tsx gains a ⌨ toggle button (mobile-only, with
tooltip + active highlight) that flips the flag.
- terminal-view.tsx exposes writeQueueRef so the key bar's bytes feed
the existing ordered single-flight write pump (without this the key
bar would bypass the queue and scramble with onData on slow transport).
onData is wrapped with applyTermMods to honor the latch. The
visualViewport observer drives a kbdLift max-height on the outer flex
column so the bar lifts above the soft keyboard and xterm auto-refits
via the existing ResizeObserver.
- workspace/layout.tsx bumps the mobile Drawer from 70vh to 95vh to
give the new bar enough room when folded in.
i18n: 16 new keys under Folder.terminal.keybar across all 10 locales
(symbols are language-neutral; show/hide/label are translated for
zh-CN/zh-TW/ja/ko/es/de/fr/pt/ar). English fallbacks keep the type
contract aligned.
Desktop path is untouched: useMediaQuery stays false, the toggle and
the bar never render, and the writeQueueRef sits at null.
The three ContextMenuTrigger wrappers around FileTreeFile, FileTreeFolder, and the RootDropFolder root-drop menu rendered as bare <span> elements. HTML parser rules disallow <span> from containing <div> children, so the row div ended up as the span's sibling and Radix's pointerdown / contextmenu handlers — and its WebkitTouchCallout: none style — never reached the actual row. Effect on touch: * iOS Safari showed its native long-press callout (Copy / Share / Save Image), eating the gesture before Radix's 700ms long-press timer could open the menu. * Android Chrome and desktop touchscreens likewise had no path to open the per-row menu. Desktop right-click worked because onContextMenu propagates by capture and bubble independently of the parent-child DOM relationship. Fix: pass asChild to each of the three ContextMenuTrigger instances so Radix's Slot mechanism merges the trigger props onto the row's own div. This matches every other ContextMenuTrigger usage in the codebase (tabs/tab-item, automations-page, settings/skills-settings, settings/mcp-settings, conversations/sidebar-conversation-list, etc.).
Bring the mobile virtual key bar for the terminal into main.
Touch devices don't get a free way to open the file-tree context menu now that the long-press gesture is reserved for drag. Add a small horizontal three-dots button (MoreHorizontal) on the right of every file, folder, and workspace-root row. Clicking it dispatches a synthetic contextmenu MouseEvent on the row so Radix's existing ContextMenuTrigger opens the same menu the right-click and long-press paths open — no menu items duplicated. - FileTreeFile / FileTreeFolder gain an optional actions?: ReactNode prop rendered inside the existing FileTreeActions wrapper (which already stops click bubbling). - RowMoreButton (new component) walks up to the nearest [data-tree-row-path] ancestor and dispatches the contextmenu event. - Folder.fileTreeTab.moreActions added to all 10 locales. - useLongPressToOpenMenu is kept (and its tests restored) for reuse elsewhere; the file tree now relies on the more button + native right-click instead of the long-press hook.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
文件树在桌面端可以右键打开菜单,触屏端之前依赖长按。长按接下来要留给拖拽用,所以触屏端需要另一条入口。
改动
每个文件/文件夹/工作区根目录行的右侧加一个横向三点的
RowMoreButton。点击时阻止冒泡,向最近的[data-tree-row-path]祖先派发一个合成的contextmenuMouseEvent。Radix 已有的ContextMenuTrigger(asChild包裹整行)收到这个事件就打开和右键、长按完全同一个菜单——零菜单项重复。FileTreeFile/FileTreeFolder新增actions?: ReactNode,渲染在已有的FileTreeActions包裹里(自动stopPropagation)。RowMoreButton(新组件 + 3 个单测)处理按钮的渲染和派发逻辑。Folder.fileTreeTab.moreActions文案 10 个语言全量新增。useLongPressToOpenMenu保留(测试一起恢复)备用,文件树不再依赖它。验证
eslint .→ exit 0vitest run→ 5786 个测试通过(406 个文件;比之前 +13:恢复的 10 个 hook 测试 + 新增的 3 个RowMoreButton测试)next build→ 成功