diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts index c1c25d0a..28ff84b7 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-create.spec.ts @@ -29,6 +29,28 @@ test.describe('Doc Create', () => { await expect(page.getByTestId('grid-loader')).toBeHidden(); await expect(docsGrid.getByText(docTitle)).toBeVisible(); }); + + test('it creates a sub doc from slash menu editor', async ({ + page, + browserName, + }) => { + const [title] = await createDoc(page, 'my-new-slash-doc', browserName, 1); + + await verifyDocName(page, title); + + await page.locator('.bn-block-outer').last().fill('/'); + await page + .getByText('New sub-doc', { + exact: true, + }) + .click(); + + const input = page.getByRole('textbox', { name: 'doc title input' }); + await expect(input).toHaveText(''); + await expect( + page.locator('.c__tree-view--row-content').getByText('Untitled document'), + ).toBeVisible(); + }); }); test.describe('Doc Create: Not logged', () => { diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts index 6f8eb7c6..189dbc1e 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-routing.spec.ts @@ -16,18 +16,11 @@ test.describe('Doc Routing', () => { await page.goto('/'); }); - test('Check the presence of the meta tag noindex', async ({ page }) => { - const buttonCreateHomepage = page.getByRole('button', { - name: 'New doc', - }); - - await expect(buttonCreateHomepage).toBeVisible(); - await buttonCreateHomepage.click(); - await expect( - page.getByRole('button', { - name: 'Share', - }), - ).toBeVisible(); + test('Check the presence of the meta tag noindex', async ({ + page, + browserName, + }) => { + await createDoc(page, 'doc-routing-test', browserName, 1); const metaDescription = page.locator('meta[name="robots"]'); await expect(metaDescription).toHaveAttribute('content', 'noindex'); }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-plus.svg b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-plus.svg new file mode 100644 index 00000000..219f8f17 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/assets/doc-plus.svg @@ -0,0 +1,30 @@ + + + + + + + diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx index 9284e81f..450a3f52 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx @@ -9,28 +9,49 @@ import { import React, { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { DocsBlockSchema } from '../types'; +import { + DocsBlockSchema, + DocsInlineContentSchema, + DocsStyleSchema, +} from '../types'; import { getCalloutReactSlashMenuItems, getDividerReactSlashMenuItems, } from './custom-blocks'; +import { useGetInterlinkingMenuItems } from './custom-inline-content'; import XLMultiColumn from './xl-multi-column'; const getMultiColumnSlashMenuItems = XLMultiColumn?.getMultiColumnSlashMenuItems; export const BlockNoteSuggestionMenu = () => { - const editor = useBlockNoteEditor(); + const editor = useBlockNoteEditor< + DocsBlockSchema, + DocsInlineContentSchema, + DocsStyleSchema + >(); const { t } = useTranslation(); const basicBlocksName = useDictionary().slash_menu.page_break.group; + const getInterlinkingMenuItems = useGetInterlinkingMenuItems(); const getSlashMenuItems = useMemo(() => { + // We insert it after the "Code Block" item to have the interlinking block displayed after the basic blocks + const defaultMenu = getDefaultReactSlashMenuItems(editor); + const index = defaultMenu.findIndex( + (item) => item.aliases?.includes('code') && item.aliases?.includes('pre'), + ); + const newSlashMenuItems = [ + ...defaultMenu.slice(0, index + 1), + ...getInterlinkingMenuItems(t), + ...defaultMenu.slice(index + 1), + ]; + return async (query: string) => Promise.resolve( filterSuggestionItems( combineByGroup( - getDefaultReactSlashMenuItems(editor), + newSlashMenuItems, getCalloutReactSlashMenuItems(editor, t, basicBlocksName), getMultiColumnSlashMenuItems?.(editor) || [], getPageBreakReactSlashMenuItems(editor), @@ -39,7 +60,7 @@ export const BlockNoteSuggestionMenu = () => { query, ), ); - }, [basicBlocksName, editor, t]); + }, [basicBlocksName, editor, getInterlinkingMenuItems, t]); return ( , + group: string, + createPage: () => void, +) => [ + { + title: t('New sub-doc'), + onItemClick: createPage, + aliases: ['new sub-doc'], + group, + icon: , + subtext: t('Create a new sub-doc'), + }, +]; + +export const useGetInterlinkingMenuItems = () => { + const treeContext = useTreeContext(); + const router = useRouter(); + const { currentDoc } = useDocStore(); + + const { mutate: createChildDoc } = useCreateChildDoc({ + onSuccess: (createdDoc) => { + const newDoc = { + ...createdDoc, + children: [], + childrenCount: 0, + parentId: currentDoc?.id ?? undefined, + }; + treeContext?.treeData.addChild(currentDoc?.id || null, newDoc); + + router.push(`/docs/${newDoc.id}`); + treeContext?.treeData.setSelectedNode(createdDoc); + }, + }); + + return useCallback( + (t: TFunction<'translation', undefined>) => + getInterlinkingMenuItems( + t, + t('Links'), + () => + currentDoc?.id && + createChildDoc({ + parentId: currentDoc.id, + }), + ), + [createChildDoc, currentDoc?.id], + ); +}; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts new file mode 100644 index 00000000..b1a3b448 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/Interlinking/index.ts @@ -0,0 +1 @@ +export * from './InterlinkingSearchInlineContent'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/index.ts b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/index.ts new file mode 100644 index 00000000..fa505a9e --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/custom-inline-content/index.ts @@ -0,0 +1 @@ +export * from './Interlinking';