Compare commits
3 Commits
dev
...
nxl/shell-
| Author | SHA1 | Date |
|---|---|---|
|
|
01d80f37dd | |
|
|
f714300e9a | |
|
|
30c4ccbfee |
|
|
@ -19,6 +19,7 @@ import { useSDK } from "@/context/sdk"
|
|||
import { useSync } from "@/context/sync"
|
||||
import { useComments } from "@/context/comments"
|
||||
import { Button } from "@opencode-ai/ui/button"
|
||||
import { ButtonShortcut } from "@opencode-ai/ui/button-shortcut"
|
||||
import { DockShellForm, DockTray } from "@opencode-ai/ui/dock-surface"
|
||||
import { Icon } from "@opencode-ai/ui/icon"
|
||||
import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
|
||||
|
|
@ -1450,17 +1451,17 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||
<Show when={store.mode === "normal" || store.mode === "shell"}>
|
||||
<DockTray attach="top">
|
||||
<div class="px-1.75 pt-5.5 pb-2 flex items-center gap-2 min-w-0">
|
||||
<div class="flex items-center gap-1.5 min-w-0 flex-1 relative">
|
||||
<div class="flex h-7 items-center gap-1.5 min-w-0 flex-1 relative">
|
||||
<div
|
||||
class="h-7 flex items-center gap-1.5 max-w-[160px] min-w-0 absolute inset-y-0 left-0"
|
||||
class="flex items-center max-w-[160px] min-w-0 absolute inset-y-0 left-0"
|
||||
style={{
|
||||
padding: "0 4px 0 8px",
|
||||
padding: "0 8px",
|
||||
...shell(),
|
||||
}}
|
||||
>
|
||||
<span class="truncate text-13-medium text-text-strong">{language.t("prompt.mode.shell")}</span>
|
||||
<div class="size-4 shrink-0" />
|
||||
<span class="truncate text-13-regular text-text-strong">{language.t("prompt.mode.shell")}</span>
|
||||
</div>
|
||||
<Show when={store.mode !== "shell"}>
|
||||
<div class="flex items-center gap-1.5 min-w-0 flex-1">
|
||||
<div data-component="prompt-agent-control">
|
||||
<TooltipKeybind
|
||||
|
|
@ -1485,7 +1486,6 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||
/>
|
||||
</TooltipKeybind>
|
||||
</div>
|
||||
<Show when={store.mode !== "shell"}>
|
||||
<div data-component="prompt-model-control">
|
||||
<Show
|
||||
when={providers.paid().length > 0}
|
||||
|
|
@ -1581,7 +1581,22 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
|
|||
/>
|
||||
</TooltipKeybind>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
<div class="absolute inset-y-0 right-0 flex items-center" style={shell()}>
|
||||
<ButtonShortcut
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="small"
|
||||
shortcut="Esc"
|
||||
shortcutAria="Escape"
|
||||
class="h-6 gap-2 rounded-[6px] border-none px-0 py-0 pl-3 pr-0.75 text-13-medium text-text-base shadow-none"
|
||||
tabIndex={store.mode === "shell" ? undefined : -1}
|
||||
onClick={() => setMode("normal")}
|
||||
aria-label={language.t("common.cancel")}
|
||||
>
|
||||
{language.t("common.cancel")}
|
||||
</ButtonShortcut>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
[data-component="button"][data-button-shortcut] {
|
||||
[data-slot="button-shortcut-label"] {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
[data-slot="button-shortcut-key"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
[data-slot="button-shortcut-key"] [data-component="keybind"] {
|
||||
box-shadow: none;
|
||||
background: var(--surface-raised-base);
|
||||
color: var(--text-weak);
|
||||
font-family: var(--font-family-sans);
|
||||
font-weight: var(--font-weight-regular);
|
||||
}
|
||||
|
||||
&[data-size="small"] [data-slot="button-shortcut-key"] [data-component="keybind"],
|
||||
&[data-size="normal"] [data-slot="button-shortcut-key"] [data-component="keybind"] {
|
||||
height: 18px;
|
||||
padding: 0 4px;
|
||||
border-radius: 3px;
|
||||
font-size: var(--font-size-small);
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
&[data-size="large"] [data-slot="button-shortcut-key"] [data-component="keybind"] {
|
||||
height: 20px;
|
||||
padding: 0 6px;
|
||||
border-radius: 4px;
|
||||
font-size: var(--font-size-small);
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// @ts-nocheck
|
||||
import { ButtonShortcut } from "./button-shortcut"
|
||||
|
||||
const docs = `### Overview
|
||||
Button with a trailing shortcut keycap.
|
||||
|
||||
Use this when the action label and shortcut should be taught together at the control level.
|
||||
|
||||
### API
|
||||
- Inherits Button props.
|
||||
- \`shortcut\`: visible keycap text.
|
||||
- \`shortcutAria\`: semantic shortcut string for \`aria-keyshortcuts\`.
|
||||
- \`shortcutClass\`: optional class override for the keycap.
|
||||
|
||||
### Variants and states
|
||||
- Uses the same \`variant\` and \`size\` options as \`Button\`.
|
||||
- Supports disabled state.
|
||||
|
||||
### Accessibility
|
||||
- Keep the visible shortcut concise.
|
||||
- Use \`shortcutAria\` for the canonical key sequence when it differs from the visible label.
|
||||
|
||||
### Theming/tokens
|
||||
- Extends \`Button\` and composes \`Keybind\`.
|
||||
|
||||
`
|
||||
|
||||
export default {
|
||||
title: "UI/ButtonShortcut",
|
||||
id: "components-button-shortcut",
|
||||
component: ButtonShortcut,
|
||||
tags: ["autodocs"],
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
component: docs,
|
||||
},
|
||||
},
|
||||
},
|
||||
args: {
|
||||
children: "Cancel",
|
||||
shortcut: "Esc",
|
||||
shortcutAria: "Escape",
|
||||
variant: "ghost",
|
||||
size: "small",
|
||||
},
|
||||
argTypes: {
|
||||
variant: {
|
||||
control: "select",
|
||||
options: ["primary", "secondary", "ghost"],
|
||||
},
|
||||
size: {
|
||||
control: "select",
|
||||
options: ["small", "normal", "large"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const Basic = {}
|
||||
|
||||
export const Sizes = {
|
||||
render: () => (
|
||||
<div style={{ display: "flex", gap: "12px", "align-items": "center" }}>
|
||||
<ButtonShortcut size="small" variant="ghost" shortcut="Esc" shortcutAria="Escape">
|
||||
Cancel
|
||||
</ButtonShortcut>
|
||||
<ButtonShortcut size="normal" variant="secondary" shortcut="Tab" shortcutAria="Tab">
|
||||
Focus
|
||||
</ButtonShortcut>
|
||||
<ButtonShortcut size="large" variant="primary" shortcut="Enter" shortcutAria="Enter">
|
||||
Submit
|
||||
</ButtonShortcut>
|
||||
</div>
|
||||
),
|
||||
}
|
||||
|
||||
export const Shell = {
|
||||
args: {
|
||||
children: "Cancel",
|
||||
shortcut: "Esc",
|
||||
shortcutAria: "Escape",
|
||||
variant: "ghost",
|
||||
size: "small",
|
||||
class: "h-6 gap-2 rounded-[6px] border-none px-0 py-0 pl-3 pr-0.75 text-13-medium text-text-base shadow-none",
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import { type ComponentProps, Show, splitProps } from "solid-js"
|
||||
import { Button, type ButtonProps } from "./button"
|
||||
import { Keybind } from "./keybind"
|
||||
|
||||
export interface ButtonShortcutProps extends ButtonProps {
|
||||
shortcut?: string
|
||||
shortcutAria?: string
|
||||
shortcutClass?: string
|
||||
shortcutClassList?: ComponentProps<"span">["classList"]
|
||||
}
|
||||
|
||||
export function ButtonShortcut(props: ButtonShortcutProps) {
|
||||
const [split, rest] = splitProps(props, [
|
||||
"children",
|
||||
"shortcut",
|
||||
"shortcutAria",
|
||||
"shortcutClass",
|
||||
"shortcutClassList",
|
||||
])
|
||||
|
||||
return (
|
||||
<Button {...rest} aria-keyshortcuts={split.shortcutAria} data-button-shortcut={split.shortcut ? "true" : undefined}>
|
||||
<span data-slot="button-shortcut-label">{split.children}</span>
|
||||
<Show when={split.shortcut}>
|
||||
<span data-slot="button-shortcut-key">
|
||||
<Keybind class={split.shortcutClass} classList={split.shortcutClassList}>
|
||||
{split.shortcut}
|
||||
</Keybind>
|
||||
</span>
|
||||
</Show>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
@import "../components/avatar.css" layer(components);
|
||||
@import "../components/basic-tool.css" layer(components);
|
||||
@import "../components/button.css" layer(components);
|
||||
@import "../components/button-shortcut.css" layer(components);
|
||||
@import "../components/card.css" layer(components);
|
||||
@import "../components/tool-error-card.css" layer(components);
|
||||
@import "../components/checkbox.css" layer(components);
|
||||
|
|
|
|||
Loading…
Reference in New Issue