Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions renderer/components/proofread/ProofreadEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export default function ProofreadEditor({
canRedo,
handleMergeSubtitles,
handleSplitSubtitle,
handleDeleteSubtitle,
handleTimeChange,
// 光标位置
handleCursorPositionChange,
Expand Down Expand Up @@ -222,6 +223,13 @@ export default function ProofreadEditor({
[handleSubtitleClick],
);

const handleDeleteClick = useCallback(
(index: number) => {
handleDeleteSubtitle(index);
},
[handleDeleteSubtitle],
);

// 重置触发器
const handleTriggerHandled = useCallback(() => {
setTriggerAiOptimize(false);
Expand Down Expand Up @@ -462,6 +470,7 @@ export default function ProofreadEditor({
onCursorPositionChange={handleCursorPositionChange}
onAiOptimizeClick={handleAiOptimizeClick}
onSplitClick={handleSplitClick}
onDeleteClick={handleDeleteClick}
onTimeChange={handleTimeChange}
retranslate={retranslate}
onMergeRange={handleMergeSubtitles}
Expand Down
38 changes: 38 additions & 0 deletions renderer/components/subtitle/SubtitleList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
Combine,
CircleStop,
X,
Trash2,
} from 'lucide-react';
import {
Tooltip,
Expand Down Expand Up @@ -51,6 +52,7 @@ interface SubtitleListProps {
onCursorPositionChange?: (position: number) => void;
onAiOptimizeClick?: (index: number) => void;
onSplitClick?: (index: number) => void;
onDeleteClick?: (index: number) => void;
/** 行内时间编辑提交;返回错误文案(不应用)或 null(已应用) */
onTimeChange?: (
index: number,
Expand All @@ -74,6 +76,7 @@ interface RowLabels {
translationFailedPlaceholder: string;
aiOptimize: string;
split: string;
deleteSubtitle: string;
timeInvalidFormat: string;
timeEditHint: string;
}
Expand Down Expand Up @@ -104,6 +107,7 @@ interface SubtitleRowProps {
fontScale: 's' | 'm' | 'l';
showAiOptimize: boolean;
showSplit: boolean;
showDelete: boolean;
labels: RowLabels;
onRowClick: (index: number, shiftKey: boolean) => void;
onFieldChange: (
Expand All @@ -122,6 +126,7 @@ interface SubtitleRowProps {
) => void;
onAiOptimize: (index: number) => void;
onSplit: (index: number) => void;
onDelete: (index: number) => void;
onTimeCommit: (
index: number,
startSec: number,
Expand All @@ -141,6 +146,7 @@ const SubtitleRow = memo(function SubtitleRow({
fontScale,
showAiOptimize,
showSplit,
showDelete,
labels,
onRowClick,
onFieldChange,
Expand All @@ -149,6 +155,7 @@ const SubtitleRow = memo(function SubtitleRow({
onTargetKeyDown,
onAiOptimize,
onSplit,
onDelete,
onTimeCommit,
}: SubtitleRowProps) {
// 失败行降噪:左缘红条 + ⚠,不再整行红底
Expand Down Expand Up @@ -269,6 +276,27 @@ const SubtitleRow = memo(function SubtitleRow({
<TooltipContent side="top">{labels.split}</TooltipContent>
</Tooltip>
)}
{showDelete && (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-5 w-5 text-muted-foreground hover:text-destructive"
aria-label={labels.deleteSubtitle}
onClick={(e) => {
e.stopPropagation();
onDelete(index);
}}
>
<Trash2 className="h-3 w-3" />
</Button>
</TooltipTrigger>
<TooltipContent side="top">
{labels.deleteSubtitle}
</TooltipContent>
</Tooltip>
)}
</div>
</TooltipProvider>
</div>
Expand Down Expand Up @@ -321,6 +349,7 @@ const SubtitleList: React.FC<SubtitleListProps> = ({
onCursorPositionChange,
onAiOptimizeClick,
onSplitClick,
onDeleteClick,
onTimeChange,
retranslate,
onMergeRange,
Expand Down Expand Up @@ -386,6 +415,7 @@ const SubtitleList: React.FC<SubtitleListProps> = ({
onCursorPositionChange,
onAiOptimizeClick,
onSplitClick,
onDeleteClick,
onTimeChange,
currentSubtitleIndex,
});
Expand All @@ -395,6 +425,7 @@ const SubtitleList: React.FC<SubtitleListProps> = ({
onCursorPositionChange,
onAiOptimizeClick,
onSplitClick,
onDeleteClick,
onTimeChange,
currentSubtitleIndex,
};
Expand Down Expand Up @@ -537,6 +568,10 @@ const SubtitleList: React.FC<SubtitleListProps> = ({
latestRef.current.onSplitClick?.(index);
}, []);

const onDelete = useCallback((index: number) => {
latestRef.current.onDeleteClick?.(index);
}, []);

const onTimeCommit = useCallback(
(index: number, startSec: number, endSec: number): string | null => {
return latestRef.current.onTimeChange?.(index, startSec, endSec) ?? null;
Expand All @@ -554,6 +589,7 @@ const SubtitleList: React.FC<SubtitleListProps> = ({
translationFailedPlaceholder: t('translationFailedPlaceholder'),
aiOptimize: t('aiOptimize'),
split: t('split'),
deleteSubtitle: t('deleteSubtitle'),
timeInvalidFormat: t('timeEditInvalidFormat'),
timeEditHint: t('timeEditHint'),
}),
Expand Down Expand Up @@ -773,6 +809,7 @@ const SubtitleList: React.FC<SubtitleListProps> = ({
fontScale={fontScale}
showAiOptimize={!!onAiOptimizeClick}
showSplit={!!onSplitClick}
showDelete={!!onDeleteClick}
labels={labels}
onRowClick={onRowClick}
onFieldChange={onFieldChange}
Expand All @@ -781,6 +818,7 @@ const SubtitleList: React.FC<SubtitleListProps> = ({
onTargetKeyDown={onTargetKeyDown}
onAiOptimize={onAiOptimize}
onSplit={onSplit}
onDelete={onDelete}
onTimeCommit={onTimeCommit}
/>
</div>
Expand Down
29 changes: 29 additions & 0 deletions renderer/hooks/useStandaloneSubtitles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,34 @@ export const useStandaloneSubtitles = (
[applySubtitles, flushPendingEdit, history.push, t],
);

// 删除字幕(区间命令:1 行 → 0 行;支持撤销恢复)
const handleDeleteSubtitle = useCallback(
(index: number) => {
const current = subtitlesRef.current;
if (index < 0 || index >= current.length) return;

flushPendingEdit();

const removed = current[index];
history.push({ start: index, removed: [removed], inserted: [] });

const next = current.slice();
next.splice(index, 1);
const normalized = renormalizeIds(next);
applySubtitles(normalized);

setCurrentSubtitleIndex((currentIndex) => {
if (normalized.length === 0) return -1;
if (currentIndex > index) return currentIndex - 1;
if (currentIndex >= normalized.length) return normalized.length - 1;
return currentIndex;
});
setIsDirty(true);
toast.success(t('deleteSubtitleSuccess'));
},
[applySubtitles, flushPendingEdit, history.push, t],
);

// 更新光标位置
const handleCursorPositionChange = useCallback((position: number) => {
cursorPositionRef.current = position;
Expand Down Expand Up @@ -767,6 +795,7 @@ export const useStandaloneSubtitles = (
canRedo,
handleMergeSubtitles,
handleSplitSubtitle,
handleDeleteSubtitle,
handleTimeChange,
// 光标位置
handleCursorPositionChange,
Expand Down
2 changes: 2 additions & 0 deletions renderer/public/locales/en/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,10 @@
"invalidMergeRange": "Invalid merge range",
"splitSubtitle": "Split Subtitle",
"split": "Split",
"deleteSubtitle": "Delete subtitle",
"mergeSuccess": "Subtitles merged",
"splitSuccess": "Subtitle split",
"deleteSubtitleSuccess": "Subtitle deleted",
"splitSubtitleDesc": "Choose text split position and time allocation",
"textSplitPosition": "Text split position",
"sourcePreview": "Source preview",
Expand Down
2 changes: 2 additions & 0 deletions renderer/public/locales/zh/home.json
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,10 @@
"invalidMergeRange": "无效的合并范围",
"splitSubtitle": "拆分字幕",
"split": "拆分",
"deleteSubtitle": "删除字幕",
"mergeSuccess": "字幕已合并",
"splitSuccess": "字幕已拆分",
"deleteSubtitleSuccess": "字幕已删除",
"splitSubtitleDesc": "选择文字拆分位置和时间分配",
"textSplitPosition": "文字拆分位置",
"sourcePreview": "原文预览",
Expand Down