Skip to content

Commit

Permalink
refactor: centralize keyboard shortcuts and fix bold shortcut conflic…
Browse files Browse the repository at this point in the history
…ts (#8467)

- Move keyboard shortcuts (Cmd+B for navigation, Cmd+/ for new conversation) to centralized hook
- Disable default Cmd+B shortcut from Tiptap's Bold extension
- Add custom Bold extension to prevent shortcut conflicts
- Update Navigation component to receive isNavigationBarOpen state from parent

Co-authored-by: Henry Fontanier <[email protected]>
  • Loading branch information
fontanierh and Henry Fontanier authored Nov 6, 2024
1 parent cf63e56 commit fbc10c8
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Bold from "@tiptap/extension-bold";
import { MentionPluginKey } from "@tiptap/extension-mention";
import Placeholder from "@tiptap/extension-placeholder";
import type { Editor, JSONContent } from "@tiptap/react";
Expand Down Expand Up @@ -156,6 +157,14 @@ export interface CustomEditorProps {
disableAutoFocus: boolean;
}

const CustomBold = Bold.extend({
addKeyboardShortcuts() {
return {
"Mod-b": () => false,
};
},
});

const useCustomEditor = ({
onEnterKeyDown,
resetEditorContainerSize,
Expand All @@ -171,7 +180,10 @@ const useCustomEditor = ({
heading: false,
// Disable the paragraph extension to handle Enter key press manually.
paragraph: false,
// Disable the default Bold extension from StarterKit
bold: false,
}),
CustomBold,
ParagraphExtension,
MentionStorage,
MentionWithPaste.configure({
Expand Down
19 changes: 5 additions & 14 deletions front/components/navigation/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { XMarkIcon } from "@dust-tt/sparkle";
import type { SubscriptionType, WorkspaceType } from "@dust-tt/types";
import { Dialog, Transition } from "@headlessui/react";
import { Bars3Icon } from "@heroicons/react/20/solid";
import React, { Fragment, useContext, useEffect, useState } from "react";
import React, { Fragment, useContext } from "react";

import type { SidebarNavigation } from "@app/components/navigation/config";
import {
Expand All @@ -18,6 +18,8 @@ interface NavigationProps {
subscription: SubscriptionType;
navChildren?: React.ReactNode;
subNavigation?: SidebarNavigation[] | null;
isNavigationBarOpen: boolean;
setNavigationBarOpen: (isOpen: boolean) => void;
}

export function Navigation({
Expand All @@ -26,21 +28,10 @@ export function Navigation({
subscription,
navChildren,
subNavigation,
isNavigationBarOpen,
setNavigationBarOpen,
}: NavigationProps) {
const { sidebarOpen, setSidebarOpen } = useContext(SidebarContext);
const [isNavigationBarOpen, setNavigationBarOpen] = useState(true);

useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e?.key?.toLowerCase() === "b" && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setNavigationBarOpen(!isNavigationBarOpen);
}
};

document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [isNavigationBarOpen, setSidebarOpen, sidebarOpen]);

if (hideSidebar) {
return null;
Expand Down
6 changes: 6 additions & 0 deletions front/components/sparkle/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { HelpAndQuickGuideWrapper } from "@app/components/assistant/conversation
import { CONVERSATION_PARENT_SCROLL_DIV_ID } from "@app/components/assistant/conversation/lib";
import type { SidebarNavigation } from "@app/components/navigation/config";
import { Navigation } from "@app/components/navigation/Navigation";
import { useAppKeyboardShortcuts } from "@app/hooks/useAppKeyboardShortcuts";
import { useUser } from "@app/lib/swr/user";
import { classNames } from "@app/lib/utils";

Expand Down Expand Up @@ -54,6 +55,9 @@ export default function AppLayout({
const [loaded, setLoaded] = useState(false);
const user = useUser();

const { isNavigationBarOpen, setIsNavigationBarOpen } =
useAppKeyboardShortcuts(owner);

useEffect(() => {
setLoaded(true);
}, []);
Expand Down Expand Up @@ -115,6 +119,8 @@ export default function AppLayout({
<div className="light flex h-full flex-row">
<Navigation
hideSidebar={hideSidebar}
isNavigationBarOpen={isNavigationBarOpen}
setNavigationBarOpen={setIsNavigationBarOpen}
owner={owner}
subscription={subscription}
navChildren={navChildren}
Expand Down
34 changes: 34 additions & 0 deletions front/hooks/useAppKeyboardShortcuts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { LightWorkspaceType } from "@dust-tt/types";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";

export function useAppKeyboardShortcuts(owner: LightWorkspaceType) {
const [isNavigationBarOpen, setIsNavigationBarOpen] = useState(true);
const router = useRouter();

useEffect(() => {
function handleKeyboardShortcuts(event: KeyboardEvent) {
// Check for Command/Control key
const isModifier = event.metaKey || event.ctrlKey;

if (isModifier) {
switch (event.key) {
case "b":
event.preventDefault();
setIsNavigationBarOpen((prev) => !prev);
break;

case "/":
event.preventDefault();
void router.push(`/w/${owner.sId}/assistant/new`);
break;
}
}
}

window.addEventListener("keydown", handleKeyboardShortcuts);
return () => window.removeEventListener("keydown", handleKeyboardShortcuts);
}, [owner.sId, router]);

return { isNavigationBarOpen, setIsNavigationBarOpen };
}
15 changes: 0 additions & 15 deletions front/pages/w/[wId]/assistant/[cId]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,21 +100,6 @@ export default function AssistantConversation({
}
}, [cId, assistant, setConversationKey, initialConversationId]);

useEffect(() => {
function handleNewConvoShortcut(event: KeyboardEvent) {
// Check for Command on Mac or Ctrl on others
const isModifier = event.metaKey || event.ctrlKey;
if (isModifier && event.key === "/") {
void router.push(`/w/${owner.sId}/assistant/new`);
}
}

window.addEventListener("keydown", handleNewConvoShortcut);
return () => {
window.removeEventListener("keydown", handleNewConvoShortcut);
};
}, [owner.sId, router]);

return (
<ConversationContainer
// Key ensures the component re-renders when conversation changes except for shallow browse.
Expand Down

0 comments on commit fbc10c8

Please sign in to comment.