feat(ui): add clear action to prompt input
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Suspense, createEffect, createSignal, lazy, on, onCleanup, Show } from "solid-js"
|
||||
import { ArrowBigUp, ArrowBigDown, Loader2, Mic } from "lucide-solid"
|
||||
import { ArrowBigUp, ArrowBigDown, Loader2, Mic, X } from "lucide-solid"
|
||||
import ExpandButton from "./expand-button"
|
||||
import { clearAttachments, removeAttachment } from "../stores/attachments"
|
||||
import { resolvePastedPlaceholders } from "../lib/prompt-placeholders"
|
||||
@@ -351,6 +351,19 @@ export default function PromptInput(props: PromptInputProps) {
|
||||
textareaRef?.focus()
|
||||
}
|
||||
|
||||
function handleClearPrompt() {
|
||||
clearPrompt()
|
||||
clearHistoryDraft()
|
||||
resetHistoryNavigation()
|
||||
setShowPicker(false)
|
||||
setPickerMode("mention")
|
||||
setAtPosition(null)
|
||||
setSearchQuery("")
|
||||
setIgnoredAtPositions(new Set<number>())
|
||||
syncAttachmentCounters("")
|
||||
textareaRef?.focus()
|
||||
}
|
||||
|
||||
function insertBlockContent(block: string) {
|
||||
const textarea = textareaRef
|
||||
const current = prompt()
|
||||
@@ -422,6 +435,8 @@ export default function PromptInput(props: PromptInputProps) {
|
||||
return hasText || attachments().length > 0
|
||||
}
|
||||
|
||||
const canClearPrompt = () => prompt().length > 0
|
||||
|
||||
const shellHint = () =>
|
||||
mode() === "shell"
|
||||
? { key: "Esc", text: t("promptInput.hints.shell.exit") }
|
||||
@@ -543,7 +558,7 @@ export default function PromptInput(props: PromptInputProps) {
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div class="prompt-nav-buttons">
|
||||
<div class="prompt-nav-top-row">
|
||||
<div class="prompt-nav-column prompt-nav-column-left">
|
||||
<Show when={showVoiceInput()}>
|
||||
<button
|
||||
type="button"
|
||||
@@ -586,43 +601,55 @@ export default function PromptInput(props: PromptInputProps) {
|
||||
</Show>
|
||||
</button>
|
||||
</Show>
|
||||
<button
|
||||
type="button"
|
||||
class="prompt-clear-button"
|
||||
onClick={handleClearPrompt}
|
||||
disabled={!canClearPrompt()}
|
||||
aria-label={t("promptInput.clear.ariaLabel")}
|
||||
title={t("promptInput.clear.title")}
|
||||
>
|
||||
<X class="h-4 w-4" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="prompt-nav-column prompt-nav-column-right">
|
||||
<ExpandButton
|
||||
expandState={expandState}
|
||||
onToggleExpand={handleExpandToggle}
|
||||
/>
|
||||
<Show when={hasHistory()}>
|
||||
<button
|
||||
type="button"
|
||||
class="prompt-history-button"
|
||||
onClick={() =>
|
||||
selectPreviousHistory({
|
||||
force: true,
|
||||
isPickerOpen: showPicker(),
|
||||
getTextarea: () => textareaRef,
|
||||
})
|
||||
}
|
||||
disabled={!canHistoryGoPrevious()}
|
||||
aria-label={t("promptInput.history.previousAriaLabel")}
|
||||
>
|
||||
<ArrowBigUp class="h-5 w-5" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="prompt-history-button"
|
||||
onClick={() =>
|
||||
selectNextHistory({
|
||||
force: true,
|
||||
isPickerOpen: showPicker(),
|
||||
getTextarea: () => textareaRef,
|
||||
})
|
||||
}
|
||||
disabled={!canHistoryGoNext()}
|
||||
aria-label={t("promptInput.history.nextAriaLabel")}
|
||||
>
|
||||
<ArrowBigDown class="h-5 w-5" aria-hidden="true" />
|
||||
</button>
|
||||
</Show>
|
||||
</div>
|
||||
<Show when={hasHistory()}>
|
||||
<button
|
||||
type="button"
|
||||
class="prompt-history-button"
|
||||
onClick={() =>
|
||||
selectPreviousHistory({
|
||||
force: true,
|
||||
isPickerOpen: showPicker(),
|
||||
getTextarea: () => textareaRef,
|
||||
})
|
||||
}
|
||||
disabled={!canHistoryGoPrevious()}
|
||||
aria-label={t("promptInput.history.previousAriaLabel")}
|
||||
>
|
||||
<ArrowBigUp class="h-5 w-5" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="prompt-history-button"
|
||||
onClick={() =>
|
||||
selectNextHistory({
|
||||
force: true,
|
||||
isPickerOpen: showPicker(),
|
||||
getTextarea: () => textareaRef,
|
||||
})
|
||||
}
|
||||
disabled={!canHistoryGoNext()}
|
||||
aria-label={t("promptInput.history.nextAriaLabel")}
|
||||
>
|
||||
<ArrowBigDown class="h-5 w-5" aria-hidden="true" />
|
||||
</button>
|
||||
</Show>
|
||||
</div>
|
||||
<Show when={shouldShowOverlay()}>
|
||||
<div class={`prompt-input-overlay keyboard-hints ${mode() === "shell" ? "shell-mode" : ""}`}>
|
||||
|
||||
@@ -142,6 +142,8 @@ export const messagingMessages = {
|
||||
"promptInput.overlay.againToAbort": "again to abort session",
|
||||
"promptInput.stopSession.ariaLabel": "Stop session",
|
||||
"promptInput.stopSession.title": "Stop session",
|
||||
"promptInput.clear.ariaLabel": "Clear prompt text",
|
||||
"promptInput.clear.title": "Clear prompt text",
|
||||
"promptInput.send.ariaLabel": "Send message",
|
||||
"promptInput.send.errorFallback": "Failed to send message",
|
||||
"promptInput.send.errorTitle": "Send failed",
|
||||
|
||||
@@ -144,6 +144,8 @@ export const messagingMessages = {
|
||||
"promptInput.overlay.againToAbort": "otra vez para abortar la sesión",
|
||||
"promptInput.stopSession.ariaLabel": "Detener sesión",
|
||||
"promptInput.stopSession.title": "Detener sesión",
|
||||
"promptInput.clear.ariaLabel": "Borrar el texto del prompt",
|
||||
"promptInput.clear.title": "Borrar el texto del prompt",
|
||||
"promptInput.send.ariaLabel": "Enviar mensaje",
|
||||
"promptInput.send.errorFallback": "No se pudo enviar el mensaje",
|
||||
"promptInput.send.errorTitle": "Error al enviar",
|
||||
|
||||
@@ -144,6 +144,8 @@ export const messagingMessages = {
|
||||
"promptInput.overlay.againToAbort": "à nouveau pour interrompre la session",
|
||||
"promptInput.stopSession.ariaLabel": "Arrêter la session",
|
||||
"promptInput.stopSession.title": "Arrêter la session",
|
||||
"promptInput.clear.ariaLabel": "Effacer le texte du prompt",
|
||||
"promptInput.clear.title": "Effacer le texte du prompt",
|
||||
"promptInput.send.ariaLabel": "Envoyer le message",
|
||||
"promptInput.send.errorFallback": "Impossible d'envoyer le message",
|
||||
"promptInput.send.errorTitle": "Échec de l'envoi",
|
||||
|
||||
@@ -142,6 +142,8 @@ export const messagingMessages = {
|
||||
"promptInput.overlay.againToAbort": "שוב כדי לבטל את הסשן",
|
||||
"promptInput.stopSession.ariaLabel": "עצור סשן",
|
||||
"promptInput.stopSession.title": "עצור סשן",
|
||||
"promptInput.clear.ariaLabel": "נקה את טקסט הפרומפט",
|
||||
"promptInput.clear.title": "נקה את טקסט הפרומפט",
|
||||
"promptInput.send.ariaLabel": "שלח הודעה",
|
||||
"promptInput.send.errorFallback": "שליחת ההודעה נכשלה",
|
||||
"promptInput.send.errorTitle": "השליחה נכשלה",
|
||||
|
||||
@@ -144,6 +144,8 @@ export const messagingMessages = {
|
||||
"promptInput.overlay.againToAbort": "もう一度押すとセッションを中断",
|
||||
"promptInput.stopSession.ariaLabel": "セッションを停止",
|
||||
"promptInput.stopSession.title": "セッションを停止",
|
||||
"promptInput.clear.ariaLabel": "プロンプトのテキストをクリア",
|
||||
"promptInput.clear.title": "プロンプトのテキストをクリア",
|
||||
"promptInput.send.ariaLabel": "メッセージを送信",
|
||||
"promptInput.send.errorFallback": "メッセージの送信に失敗しました",
|
||||
"promptInput.send.errorTitle": "送信に失敗",
|
||||
|
||||
@@ -144,6 +144,8 @@ export const messagingMessages = {
|
||||
"promptInput.overlay.againToAbort": "еще раз, чтобы прервать сессию",
|
||||
"promptInput.stopSession.ariaLabel": "Остановить сессию",
|
||||
"promptInput.stopSession.title": "Остановить сессию",
|
||||
"promptInput.clear.ariaLabel": "Очистить текст prompt",
|
||||
"promptInput.clear.title": "Очистить текст prompt",
|
||||
"promptInput.send.ariaLabel": "Отправить сообщение",
|
||||
"promptInput.send.errorFallback": "Не удалось отправить сообщение",
|
||||
"promptInput.send.errorTitle": "Не удалось отправить",
|
||||
|
||||
@@ -144,6 +144,8 @@ export const messagingMessages = {
|
||||
"promptInput.overlay.againToAbort": "再次按下以中止会话",
|
||||
"promptInput.stopSession.ariaLabel": "停止会话",
|
||||
"promptInput.stopSession.title": "停止会话",
|
||||
"promptInput.clear.ariaLabel": "清除输入框文本",
|
||||
"promptInput.clear.title": "清除输入框文本",
|
||||
"promptInput.send.ariaLabel": "发送消息",
|
||||
"promptInput.send.errorFallback": "发送消息失败",
|
||||
"promptInput.send.errorTitle": "发送失败",
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
.prompt-input {
|
||||
@apply w-full pt-2.5 border text-sm resize-none outline-none transition-colors;
|
||||
padding-inline-start: 0.75rem;
|
||||
padding-inline-end: 5.5rem;
|
||||
padding-inline-end: 7.5rem;
|
||||
font-family: inherit;
|
||||
background-color: var(--surface-base);
|
||||
color: var(--text-primary);
|
||||
@@ -90,22 +90,32 @@
|
||||
inset-inline-end: 0.25rem;
|
||||
bottom: 0.25rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-start;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-end;
|
||||
gap: 0.125rem;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.prompt-nav-top-row {
|
||||
.prompt-nav-column {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-start;
|
||||
gap: 0.125rem;
|
||||
}
|
||||
|
||||
.prompt-nav-column-left {
|
||||
min-width: 1.75rem;
|
||||
}
|
||||
|
||||
.prompt-nav-column-right {
|
||||
min-width: 1.75rem;
|
||||
}
|
||||
|
||||
.prompt-expand-button,
|
||||
.prompt-history-button {
|
||||
.prompt-history-button,
|
||||
.prompt-clear-button {
|
||||
@apply w-7 h-7 flex items-center justify-center rounded-md;
|
||||
color: var(--text-muted);
|
||||
background-color: var(--control-ghost-bg);
|
||||
@@ -115,7 +125,8 @@
|
||||
}
|
||||
|
||||
.prompt-expand-button:hover:not(:disabled),
|
||||
.prompt-history-button:hover:not(:disabled) {
|
||||
.prompt-history-button:hover:not(:disabled),
|
||||
.prompt-clear-button:hover:not(:disabled) {
|
||||
background-color: var(--surface-secondary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
@@ -127,7 +138,8 @@
|
||||
}
|
||||
|
||||
.prompt-expand-button:disabled,
|
||||
.prompt-history-button:disabled {
|
||||
.prompt-history-button:disabled,
|
||||
.prompt-clear-button:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@@ -397,7 +409,7 @@
|
||||
.prompt-input {
|
||||
min-height: 0;
|
||||
padding: 0.5rem 0.75rem;
|
||||
padding-inline-end: 5.5rem;
|
||||
padding-inline-end: 7.5rem;
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user