Skip to content

Commit 7c26cb2

Browse files
authored
improvement: enhance multi-cell action toolbar with new shortcuts and actions (#5655)
1 parent 21edaaa commit 7c26cb2

File tree

1 file changed

+76
-5
lines changed

1 file changed

+76
-5
lines changed

frontend/src/components/editor/navigation/multi-cell-action-toolbar.tsx

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import type { EditorView } from "@codemirror/view";
44
import { useAtomValue } from "jotai";
55
import {
66
ChevronDownIcon,
7+
ChevronsDownIcon,
8+
ChevronsUpIcon,
79
ChevronUpIcon,
810
Code2Icon,
911
EyeIcon,
@@ -17,6 +19,7 @@ import {
1719
} from "lucide-react";
1820
import React from "react";
1921
import useEvent from "react-use-event-hook";
22+
import { MinimalShortcut } from "@/components/shortcuts/renderShortcut";
2023
import { Button } from "@/components/ui/button";
2124
import {
2225
DropdownMenu,
@@ -33,6 +36,7 @@ import {
3336
} from "@/core/cells/cells";
3437
import type { CellId } from "@/core/cells/ids";
3538
import { formatEditorViews } from "@/core/codemirror/format";
39+
import type { HotkeyAction } from "@/core/hotkeys/hotkeys";
3640
import { saveCellConfig } from "@/core/network/requests";
3741
import type { CellConfig } from "@/core/network/types";
3842
import { store } from "@/core/state/jotai";
@@ -44,6 +48,7 @@ import { useCellSelectionActions, useCellSelectionState } from "./selection";
4448

4549
interface MultiCellActionButton extends Omit<ActionButton, "handle"> {
4650
handle: (selectedCells: CellId[]) => void;
51+
hotkey?: HotkeyAction;
4752
}
4853

4954
const CellStateDropdown: React.FC<{
@@ -71,9 +76,19 @@ const CellStateDropdown: React.FC<{
7176
onSelect={() => action.handle(cellIds)}
7277
className="flex items-center gap-2"
7378
>
74-
<div className="flex items-center gap-2">
75-
{action.icon}
76-
<span className="text-xs">{action.label}</span>
79+
<div className="flex items-center flex-1">
80+
{action.icon && (
81+
<div className="mr-2 w-5 text-muted-foreground">
82+
{action.icon}
83+
</div>
84+
)}
85+
<div className="flex-1">{action.label}</div>
86+
{action.hotkey && (
87+
<MinimalShortcut
88+
shortcut={action.hotkey}
89+
className="ml-4"
90+
/>
91+
)}
7792
</div>
7893
</DropdownMenuItem>
7994
);
@@ -91,7 +106,13 @@ const CellStateDropdown: React.FC<{
91106
};
92107

93108
export function useMultiCellActionButtons(cellIds: CellId[]) {
94-
const { updateCellConfig, moveCell, clearCellOutput } = useCellActions();
109+
const {
110+
updateCellConfig,
111+
moveCell,
112+
clearCellOutput,
113+
sendToTop,
114+
sendToBottom,
115+
} = useCellActions();
95116
const deleteCell = useDeleteManyCellsCallback();
96117
const hasOnlyOneCell = useAtomValue(hasOnlyOneCellAtom);
97118
const selectionActions = useCellSelectionActions();
@@ -138,6 +159,19 @@ export function useMultiCellActionButtons(cellIds: CellId[]) {
138159
},
139160
);
140161

162+
const sendSelectedCellsToTop = useEvent((cellIds: CellId[]) => {
163+
// Send in reverse order to maintain relative positions
164+
[...cellIds].reverse().forEach((cellId) => {
165+
sendToTop({ cellId });
166+
});
167+
});
168+
169+
const sendSelectedCellsToBottom = useEvent((cellIds: CellId[]) => {
170+
cellIds.forEach((cellId) => {
171+
sendToBottom({ cellId });
172+
});
173+
});
174+
141175
const formatSelectedCells = useEvent((cellIds: CellId[]) => {
142176
const editorViews: Record<CellId, EditorView> = {};
143177
cellIds.forEach((cellId) => {
@@ -176,18 +210,21 @@ export function useMultiCellActionButtons(cellIds: CellId[]) {
176210
icon: <PlayIcon size={13} strokeWidth={1.5} />,
177211
label: "Run cells",
178212
handle: (cellIds) => runCells(cellIds),
213+
hotkey: "cell.run",
179214
},
180215
],
181216
[
182217
{
183218
icon: <ChevronUpIcon size={13} strokeWidth={1.5} />,
184219
label: "Move up",
185220
handle: (cellIds) => moveSelectedCells(cellIds, "up"),
221+
hotkey: "cell.moveUp",
186222
},
187223
{
188224
icon: <ChevronDownIcon size={13} strokeWidth={1.5} />,
189225
label: "Move down",
190226
handle: (cellIds) => moveSelectedCells(cellIds, "down"),
227+
hotkey: "cell.moveDown",
191228
},
192229
],
193230
[
@@ -207,6 +244,7 @@ export function useMultiCellActionButtons(cellIds: CellId[]) {
207244
icon: <Code2Icon size={13} strokeWidth={1.5} />,
208245
label: "Format cells",
209246
handle: formatSelectedCells,
247+
hotkey: "cell.format",
210248
},
211249
{
212250
icon: <XCircleIcon size={13} strokeWidth={1.5} />,
@@ -220,12 +258,40 @@ export function useMultiCellActionButtons(cellIds: CellId[]) {
220258
label: "Hide code",
221259
handle: (cellIds) =>
222260
toggleSelectedCellsProperty(cellIds, "hide_code", true),
261+
hotkey: "cell.hideCode",
223262
},
224263
{
225264
icon: <EyeIcon size={13} strokeWidth={1.5} />,
226265
label: "Show code",
227266
handle: (cellIds) =>
228267
toggleSelectedCellsProperty(cellIds, "hide_code", false),
268+
hotkey: "cell.hideCode",
269+
},
270+
],
271+
[
272+
{
273+
icon: <ChevronUpIcon size={13} strokeWidth={1.5} />,
274+
label: "Move up",
275+
handle: (cellIds) => moveSelectedCells(cellIds, "up"),
276+
hotkey: "cell.moveUp",
277+
},
278+
{
279+
icon: <ChevronDownIcon size={13} strokeWidth={1.5} />,
280+
label: "Move down",
281+
handle: (cellIds) => moveSelectedCells(cellIds, "down"),
282+
hotkey: "cell.moveDown",
283+
},
284+
{
285+
icon: <ChevronsUpIcon size={13} strokeWidth={1.5} />,
286+
label: "Send to top",
287+
handle: sendSelectedCellsToTop,
288+
hotkey: "cell.sendToTop",
289+
},
290+
{
291+
icon: <ChevronsDownIcon size={13} strokeWidth={1.5} />,
292+
label: "Send to bottom",
293+
handle: sendSelectedCellsToBottom,
294+
hotkey: "cell.sendToBottom",
229295
},
230296
],
231297
[
@@ -317,11 +383,16 @@ const MultiCellActionToolbarInternal = ({ cellIds }: { cellIds: CellId[] }) => {
317383
}
318384
size="sm"
319385
onClick={() => action.handle(cellIds)}
320-
className="h-8 px-2 gap-1 flex-shrink-0"
386+
className="h-8 px-2 gap-1 flex-shrink-0 flex items-center"
321387
title={action.label}
322388
>
323389
{action.icon}
324390
<span className="text-xs">{action.label}</span>
391+
{action.hotkey && (
392+
<div className="ml-1 border bg-muted rounded-md px-1">
393+
<MinimalShortcut shortcut={action.hotkey} />
394+
</div>
395+
)}
325396
</Button>
326397
))}
327398
{groupIndex < actions.length - 1 && <Separator />}

0 commit comments

Comments
 (0)