add key short in edit inline

This commit is contained in:
duanfuxiang 2025-02-18 12:31:04 +08:00
parent d15681b0d5
commit 76a5799067
3 changed files with 82 additions and 15 deletions

View File

@ -1,7 +1,7 @@
import { Change, diffLines } from 'diff'
import { CheckIcon, X } from 'lucide-react'
import { getIcon } from 'obsidian'
import { useState } from 'react'
import { Platform, getIcon } from 'obsidian'
import { useEffect, useState } from 'react'
import { ApplyViewState } from '../../ApplyView'
import { useApp } from '../../contexts/AppContext'
@ -17,6 +17,14 @@ export default function ApplyViewRoot({
const rejectIcon = getIcon('x')
const excludeIcon = getIcon('x')
const getShortcutText = (shortcut: 'accept' | 'reject') => {
const isMac = Platform.isMacOS
if (shortcut === 'accept') {
return isMac ? '(⌘⏎)' : '(Ctrl+⏎)'
}
return isMac ? '(⌘⌫)' : '(Ctrl+⌫)'
}
const app = useApp()
const [diff, setDiff] = useState<Change[]>(
@ -64,6 +72,30 @@ export default function ApplyViewRoot({
})
}
const handleKeyDown = (event: KeyboardEvent) => {
const modifierKey = Platform.isMacOS ? event.metaKey : event.ctrlKey;
if (modifierKey) {
if (event.key === 'Enter') {
event.preventDefault();
event.stopPropagation();
handleAccept();
} else if (event.key === 'Backspace') {
event.preventDefault();
event.stopPropagation();
handleReject();
}
}
}
// 在组件挂载时添加事件监听器,在卸载时移除
useEffect(() => {
const handler = (e: KeyboardEvent) => handleKeyDown(e);
window.addEventListener('keydown', handler, true);
return () => {
window.removeEventListener('keydown', handler, true);
}
}, [handleAccept, handleReject]) // 添加handleAccept和handleReject作为依赖项
return (
<div id="infio-apply-view">
<div className="view-header">
@ -81,7 +113,7 @@ export default function ApplyViewRoot({
onClick={handleAccept}
>
{acceptIcon && <CheckIcon size={14} />}
Accept
Accept {getShortcutText('accept')}
</button>
<button
className="clickable-icon view-action infio-reject-button"
@ -89,7 +121,7 @@ export default function ApplyViewRoot({
onClick={handleReject}
>
{rejectIcon && <X size={14} />}
Reject
Reject {getShortcutText('reject')}
</button>
</div>
</div>

View File

@ -1,6 +1,6 @@
import { MarkdownView, Plugin } from 'obsidian';
import { MarkdownView, Plugin, Platform } from 'obsidian';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { CornerDownLeft } from 'lucide-react';
import { APPLY_VIEW_TYPE } from '../../constants';
import LLMManager from '../../core/llm/manager';
import { InfioSettings } from '../../types/settings';
@ -20,24 +20,41 @@ type InlineEditProps = {
type InputAreaProps = {
value: string;
onChange: (value: string) => void;
handleSubmit: () => void;
handleClose: () => void;
}
const InputArea: React.FC<InputAreaProps> = ({ value, onChange }) => {
const InputArea: React.FC<InputAreaProps> = ({ value, onChange, handleSubmit, handleClose }) => {
const textareaRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
// 组件挂载后自动聚焦到 textarea
textareaRef.current?.focus();
}, []);
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === 'Enter') {
if (e.shiftKey) {
// Shift + Enter: 允许换行,使用默认行为
return;
}
// 普通 Enter: 阻止默认行为并触发提交
e.preventDefault();
handleSubmit();
} else if (e.key === 'Escape') {
// 当按下 Esc 键时关闭编辑器
handleClose();
}
};
return (
<div className="infio-ai-block-input-wrapper">
<textarea
ref={textareaRef}
className="infio-ai-block-content"
placeholder="Enter instruction"
placeholder="Input instruction, Enter to submit, Esc to close"
value={value}
onChange={(e) => onChange(e.target.value)}
onKeyDown={handleKeyDown}
/>
</div>
);
@ -91,7 +108,12 @@ const ControlArea: React.FC<ControlAreaProps> = ({
onClick={onSubmit}
disabled={isSubmitting}
>
{isSubmitting ? "Submitting..." : "Submit"}
{isSubmitting ? "submitting..." : (
<>
submit
<CornerDownLeft size={11} className="infio-ai-block-submit-icon" />
</>
)}
</button>
</div>);
};
@ -251,9 +273,8 @@ export const InlineEdit: React.FC<InlineEditProps> = ({
return (
<div className="infio-ai-block-container"
id="infio-ai-block-container"
style={{ backgroundColor: 'var(--background-secondary)' }}
>
<InputArea value={instruction} onChange={setInstruction} />
<InputArea value={instruction} onChange={setInstruction} handleSubmit={handleSubmit} handleClose={handleClose} />
<button className="infio-ai-block-close-button" onClick={handleClose}>
<svg
width="14"

View File

@ -1431,7 +1431,7 @@ input[type='text'].infio-chat-list-dropdown-item-title-input {
}
.infio-ai-block-container {
background: var(--background-secondary-alt);
background: var(--background-secondary);
border-radius: 4px;
padding: 0px;
border: 1px solid var(--background-modifier-border);
@ -1443,11 +1443,11 @@ input[type='text'].infio-chat-list-dropdown-item-title-input {
}
.infio-ai-block-content {
width: 80%;
width: 100%;
background: transparent;
border: none !important;
padding: 8px;
padding-right: 40px;
padding-right: 20px;
height: 60px;
resize: none;
color: var(--text-normal);
@ -1462,6 +1462,10 @@ input[type='text'].infio-chat-list-dropdown-item-title-input {
}
}
.infio-ai-block-content::-webkit-scrollbar {
display: none;
}
.infio-ai-block-close-button {
position: absolute;
top: 8px;
@ -1655,6 +1659,14 @@ select.infio-ai-block-model-select::-ms-expand {
}
}
.infio-approve-button {
background: rgba(var(--color-green-rgb), 0.7);
}
.infio-reject-button {
background: rgba(var(--color-red-rgb), 0.7);
}
.infio-accept {
background: rgba(var(--color-green-rgb), 0.7);
box-shadow: inset 0 0 0 1000px rgba(0, 0, 0, 0.1);
@ -1673,10 +1685,12 @@ select.infio-ai-block-model-select::-ms-expand {
}
.view-actions {
gap: 2px;
button {
color: var(--text-normal);
font-weight: var(--font-medium);
gap: 2px;
border-radius: 0.5;
}
}
}