diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts
index 8ae32f08..41098f25 100644
--- a/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts
+++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts
@@ -761,4 +761,20 @@ test.describe('Doc Editor', () => {
await verifyDocName(page, docChild2);
});
+
+ test('it checks interlink shortcut @', async ({ page, browserName }) => {
+ const [randomDoc] = await createDoc(page, 'doc-interlink', browserName, 1);
+
+ await verifyDocName(page, randomDoc);
+
+ const editor = page.locator('.bn-block-outer').last();
+ await editor.click();
+ await page.keyboard.press('@');
+
+ await expect(
+ page.locator(
+ "span[data-inline-content-type='interlinkingSearchInline'] input",
+ ),
+ ).toBeVisible();
+ });
});
diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx
index 71b6c00d..6b7b77a4 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx
@@ -19,8 +19,13 @@ import { Box, TextErrors } from '@/components';
import { Doc, useIsCollaborativeEditable } from '@/docs/doc-management';
import { useAuth } from '@/features/auth';
-import { useHeadings, useUploadFile, useUploadStatus } from '../hook/';
-import useSaveDoc from '../hook/useSaveDoc';
+import {
+ useHeadings,
+ useSaveDoc,
+ useShortcuts,
+ useUploadFile,
+ useUploadStatus,
+} from '../hook';
import { useEditorStore } from '../stores';
import { cssEditor } from '../styles';
import { DocsBlockNoteEditor } from '../types';
@@ -153,6 +158,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
);
useHeadings(editor);
+ useShortcuts(editor);
useUploadStatus(editor);
useEffect(() => {
diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx
index d4a5acf1..94d56da6 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/InterlinkingSearchInlineContent.tsx
@@ -13,6 +13,10 @@ export const InterlinkingSearchInlineContent = createReactInlineContentSpec(
{
type: 'interlinkingSearchInline',
propSchema: {
+ trigger: {
+ default: '/',
+ values: ['/', '@'],
+ },
disabled: {
default: false,
values: [true, false],
@@ -26,7 +30,13 @@ export const InterlinkingSearchInlineContent = createReactInlineContentSpec(
return null;
}
- return ;
+ return (
+
+ );
},
},
);
@@ -45,6 +55,7 @@ export const getInterlinkinghMenuItems = (
type: 'interlinkingSearchInline',
props: {
disabled: false,
+ trigger: '/',
},
},
]);
diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx
index ce3953e8..4de6fd4c 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/SearchPage.tsx
@@ -44,6 +44,7 @@ const inputStyle = css`
`;
type SearchPageProps = {
+ trigger: string;
updateInlineContent: (
update: PartialCustomInlineContentFromConfig<
{
@@ -52,6 +53,9 @@ type SearchPageProps = {
disabled: {
default: boolean;
};
+ trigger: {
+ default: string;
+ };
};
content: 'styled';
},
@@ -63,6 +67,7 @@ type SearchPageProps = {
export const SearchPage = ({
contentRef,
+ trigger,
updateInlineContent,
}: SearchPageProps) => {
const { colorsTokens } = useCunninghamTheme();
@@ -106,7 +111,7 @@ export const SearchPage = ({
tabIndex={-1} // Ensure the span is focusable
>
{' '}
- /
+ {trigger}
({
useRouter: jest.fn(),
diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/index.ts b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/index.ts
index 3934dfa2..95a0804b 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/index.ts
+++ b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/index.ts
@@ -1,3 +1,4 @@
export * from './useHeadings';
export * from './useSaveDoc';
+export * from './useShortcuts';
export * from './useUploadFile';
diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx
index c6ca782e..57656a63 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx
@@ -10,7 +10,7 @@ import { toBase64 } from '../utils';
const SAVE_INTERVAL = 60000;
-const useSaveDoc = (
+export const useSaveDoc = (
docId: string,
yDoc: Y.Doc,
canSave: boolean,
@@ -105,5 +105,3 @@ const useSaveDoc = (
};
}, [router.events, saveDoc]);
};
-
-export default useSaveDoc;
diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useShortcuts.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useShortcuts.tsx
new file mode 100644
index 00000000..f2f3722f
--- /dev/null
+++ b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useShortcuts.tsx
@@ -0,0 +1,39 @@
+import { useEffect } from 'react';
+
+import { DocsBlockNoteEditor } from '../types';
+
+export const useShortcuts = (editor: DocsBlockNoteEditor) => {
+ useEffect(() => {
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key === '@' && editor?.isFocused()) {
+ const selection = window.getSelection();
+ const previousChar =
+ selection?.anchorNode?.textContent?.charAt(
+ selection.anchorOffset - 1,
+ ) || '';
+
+ if (![' ', ''].includes(previousChar)) {
+ return;
+ }
+
+ event.preventDefault();
+ editor.insertInlineContent([
+ {
+ type: 'interlinkingSearchInline',
+ props: {
+ disabled: false,
+ trigger: '@',
+ },
+ },
+ ]);
+ }
+ };
+
+ // Attach the event listener to the document instead of the window
+ document.addEventListener('keydown', handleKeyDown);
+
+ return () => {
+ document.removeEventListener('keydown', handleKeyDown);
+ };
+ }, [editor]);
+};