mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-14 03:56:55 +03:00
fix(tui): anchor diff file menus to the screen (#47147)
This commit is contained in:
committed by
GitHub
Unverified
parent
90cd910f52
commit
8ff1ef1a62
@@ -0,0 +1,87 @@
|
||||
/** @jsxImportSource @opentui/solid */
|
||||
import type { Plugin } from "@opencode-ai/plugin/tui"
|
||||
import { BoxRenderable, MouseButton } from "@opentui/core"
|
||||
import { Portal, useTerminalDimensions } from "@opentui/solid"
|
||||
import { createSignal, onCleanup } from "solid-js"
|
||||
|
||||
export function DiffFileMenu(props: {
|
||||
context: Plugin.Context
|
||||
state: { fileIndex: number; x: number; y: number }
|
||||
reviewed: boolean
|
||||
onToggle: () => void
|
||||
onClose: () => void
|
||||
}) {
|
||||
const dimensions = useTerminalDimensions()
|
||||
const theme = props.context.theme.contextual.overlay
|
||||
const [hovered, setHovered] = createSignal(false)
|
||||
const label = () => (props.reviewed ? "Mark incomplete" : "Mark complete")
|
||||
const width = () => Math.min(19, dimensions().width)
|
||||
const run = () => {
|
||||
props.onClose()
|
||||
props.onToggle()
|
||||
}
|
||||
onCleanup(props.context.keymap.mode.push("menu"))
|
||||
props.context.keymap.layer(() => ({
|
||||
mode: "menu",
|
||||
commands: [
|
||||
{ bind: "escape,ctrl+c", title: "Close file menu", group: "Diff", run: props.onClose },
|
||||
{ bind: "return", title: label(), group: "Diff", run },
|
||||
],
|
||||
}))
|
||||
|
||||
return (
|
||||
<Portal
|
||||
ref={(container) => {
|
||||
if (!(container instanceof BoxRenderable)) return
|
||||
// Portal's wrapper must also escape root flow, not follow the full-height app.
|
||||
container.position = "absolute"
|
||||
container.left = 0
|
||||
container.top = 0
|
||||
container.zIndex = 2600
|
||||
}}
|
||||
>
|
||||
<box
|
||||
id="diff-file-menu-overlay"
|
||||
position="absolute"
|
||||
left={0}
|
||||
top={0}
|
||||
width={dimensions().width}
|
||||
height={dimensions().height}
|
||||
zIndex={2600}
|
||||
onMouseDown={(event) => {
|
||||
props.onClose()
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<box
|
||||
id="diff-file-menu"
|
||||
position="absolute"
|
||||
left={Math.max(0, Math.min(props.state.x, dimensions().width - width()))}
|
||||
top={Math.max(0, Math.min(props.state.y + 1, dimensions().height - 1))}
|
||||
width={width()}
|
||||
height={1}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={hovered() ? theme.background.action.primary.hovered : theme.background.default}
|
||||
onMouseOver={() => setHovered(true)}
|
||||
onMouseOut={() => setHovered(false)}
|
||||
onMouseDown={(event) => {
|
||||
if (event.button === MouseButton.RIGHT) props.onClose()
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}}
|
||||
onMouseUp={(event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
if (event.button === MouseButton.LEFT) run()
|
||||
}}
|
||||
>
|
||||
<text fg={theme.text.default} selectable={false} wrapMode="none" truncate>
|
||||
{label()}
|
||||
</text>
|
||||
</box>
|
||||
</box>
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import { filetype } from "../../util/filetype"
|
||||
import { useRenderer, useTerminalDimensions } from "@opentui/solid"
|
||||
import { createEffect, createMemo, createResource, createSignal, For, Match, onCleanup, Show, Switch } from "solid-js"
|
||||
import { DiffViewerFileTree } from "./diff-viewer-file-tree"
|
||||
import { DiffFileMenu } from "./diff-viewer-file-menu"
|
||||
import { DiffViewerImage, isDiffImageFile } from "./diff-viewer-image"
|
||||
import { DialogSelect } from "../../ui/dialog-select"
|
||||
import { EmptyBorder } from "../../ui/border"
|
||||
@@ -1076,76 +1077,6 @@ export function DiffViewerContent(props: {
|
||||
)
|
||||
}
|
||||
|
||||
function DiffFileMenu(props: {
|
||||
context: Plugin.Context
|
||||
state: FileMenuState
|
||||
reviewed: boolean
|
||||
onToggle: () => void
|
||||
onClose: () => void
|
||||
}) {
|
||||
const dimensions = useTerminalDimensions()
|
||||
const theme = props.context.theme.contextual.overlay
|
||||
const [hovered, setHovered] = createSignal(false)
|
||||
const label = () => (props.reviewed ? "Mark incomplete" : "Mark complete")
|
||||
const run = () => {
|
||||
props.onClose()
|
||||
props.onToggle()
|
||||
}
|
||||
onCleanup(props.context.keymap.mode.push("menu"))
|
||||
props.context.keymap.layer(() => ({
|
||||
mode: "menu",
|
||||
commands: [
|
||||
{ bind: "escape,ctrl+c", title: "Close file menu", group: "Diff", run: props.onClose },
|
||||
{ bind: "return", title: label(), group: "Diff", run },
|
||||
],
|
||||
}))
|
||||
|
||||
return (
|
||||
<box
|
||||
id="diff-file-menu-overlay"
|
||||
position="absolute"
|
||||
left={0}
|
||||
top={0}
|
||||
width={dimensions().width}
|
||||
height={dimensions().height}
|
||||
zIndex={2600}
|
||||
onMouseDown={(event) => {
|
||||
props.onClose()
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<box
|
||||
id="diff-file-menu"
|
||||
position="absolute"
|
||||
left={Math.max(0, Math.min(props.state.x, dimensions().width - 19))}
|
||||
top={Math.max(0, Math.min(props.state.y + 1, dimensions().height - 1))}
|
||||
width={19}
|
||||
height={1}
|
||||
paddingLeft={1}
|
||||
paddingRight={1}
|
||||
backgroundColor={hovered() ? theme.background.action.primary.hovered : theme.background.default}
|
||||
onMouseOver={() => setHovered(true)}
|
||||
onMouseOut={() => setHovered(false)}
|
||||
onMouseDown={(event) => {
|
||||
if (event.button === MouseButton.RIGHT) props.onClose()
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}}
|
||||
onMouseUp={(event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
if (event.button === MouseButton.LEFT) run()
|
||||
}}
|
||||
>
|
||||
<text fg={theme.text.default} selectable={false}>
|
||||
{label()}
|
||||
</text>
|
||||
</box>
|
||||
</box>
|
||||
)
|
||||
}
|
||||
|
||||
function DiffViewerHelpDialog(props: { context: Plugin.Context; single: boolean }) {
|
||||
const dimensions = useTerminalDimensions()
|
||||
const theme = props.context.theme.contextual.elevated
|
||||
|
||||
Reference in New Issue
Block a user