diff --git a/CHANGELOG.md b/CHANGELOG.md index 91a8e0aad..e85e8de6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to - ♻️(backend) allow global search in sub documents - ✨(backend) add a breadcrumb in the search response +- ♻️(frontend) move doc action buttons to fix toolbar #2360 ### Fixed diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts index 71fb3dccd..dcc8afc3d 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts @@ -7,6 +7,7 @@ import { PDFParse } from 'pdf-parse'; import { TestLanguage, + clickInEditorMenu, createDoc, verifyDocName, waitForLanguageSwitch, @@ -24,11 +25,7 @@ test.describe('Doc Export', () => { browserName, }) => { await createDoc(page, 'doc-editor', browserName, 1); - await page - .getByRole('button', { - name: 'Export the document', - }) - .click(); + await clickInEditorMenu(page, 'Download'); await expect(page.getByTestId('modal-export-title')).toBeVisible(); await expect( @@ -54,11 +51,7 @@ test.describe('Doc Export', () => { test('it exports the doc to docx', async ({ page, browserName }) => { const randomDoc = await overrideDocContent({ page, browserName }); - await page - .getByRole('button', { - name: 'Export the document', - }) - .click(); + await clickInEditorMenu(page, 'Download'); await page.getByRole('combobox', { name: 'Format' }).click(); await page.getByRole('option', { name: 'Docx' }).click(); @@ -84,11 +77,7 @@ test.describe('Doc Export', () => { test('it exports the doc to odt', async ({ page, browserName }) => { const randomDoc = await overrideDocContent({ page, browserName }); - await page - .getByRole('button', { - name: 'Export the document', - }) - .click(); + await clickInEditorMenu(page, 'Download'); await page.getByRole('combobox', { name: 'Format' }).click(); await page.getByRole('option', { name: 'Odt' }).click(); @@ -139,11 +128,7 @@ test.describe('Doc Export', () => { // Give some time for the image to be fully processed await page.waitForTimeout(1000); - await page - .getByRole('button', { - name: 'Export the document', - }) - .click(); + await clickInEditorMenu(page, 'Download'); await page.getByRole('combobox', { name: 'Format' }).click(); await page.getByRole('option', { name: 'HTML' }).click(); @@ -231,11 +216,7 @@ test.describe('Doc Export', () => { .fill('https://docs.numerique.gouv.fr/assets/logo-gouv.png'); await page.getByText('Embed image').click(); - await page - .getByRole('button', { - name: 'Export the document', - }) - .click(); + await clickInEditorMenu(page, 'Download'); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -322,11 +303,7 @@ test.describe('Doc Export', () => { await overrideDocContent({ page, browserName }); - await page - .getByRole('button', { - name: 'Export the document', - }) - .click(); + await clickInEditorMenu(page, 'Download'); await page.getByRole('combobox', { name: 'Format' }).click(); await page.getByRole('option', { name: 'Print' }).click(); @@ -375,11 +352,7 @@ test.describe('Doc Export', () => { const randomDoc = await overrideDocContent({ page, browserName }); - await page - .getByRole('button', { - name: 'Export the document', - }) - .click(); + await clickInEditorMenu(page, 'Download'); const downloadPromise = page.waitForEvent('download', (download) => { return download.suggestedFilename().includes(`${randomDoc}.pdf`); diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts index 20c2bd155..5c5e91a6d 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts @@ -1,6 +1,7 @@ import { expect, test } from '@playwright/test'; import { + clickInEditorMenu, clickInEditorShareButton, createDoc, getGridRow, @@ -83,15 +84,14 @@ test.describe('Doc Header', () => { await page.getByRole('button', { name: 'close' }).first().click(); - await expect(card.getByText('Public document')).toBeVisible(); - + await expect(card.getByText('Public ·')).toBeVisible(); await expect(card.getByText('Owner ·')).toBeVisible(); await expect(page.getByRole('button', { name: 'Share' })).toBeVisible(); + await page + .getByRole('button', { name: 'Open the document options' }) + .click(); await expect( - page.getByRole('button', { name: 'Export the document' }), - ).toBeVisible(); - await expect( - page.getByRole('button', { name: 'Open the document options' }), + page.getByRole('menuitem', { name: 'Download' }), ).toBeVisible(); }); @@ -186,17 +186,15 @@ test.describe('Doc Header', () => { await createDoc(page, 'doc-update-emoji', browserName, 1); const emojiPicker = page.locator('.--docs--doc-title').getByRole('button'); - const optionMenu = page.getByLabel('Open the document options'); - const addEmojiMenuItem = page.getByRole('menuitem', { name: 'Add emoji' }); - const removeEmojiMenuItem = page.getByRole('menuitem', { - name: 'Remove emoji', + const addEmoji = page.getByRole('button', { name: 'Add icon' }); + const removeEmoji = page.getByRole('button', { + name: 'Remove icon', }); // Top parent should not have emoji picker await expect(emojiPicker).toBeHidden(); - await optionMenu.click(); - await expect(addEmojiMenuItem).toBeHidden(); - await expect(removeEmojiMenuItem).toBeHidden(); + await expect(addEmoji).toBeHidden(); + await expect(removeEmoji).toBeHidden(); await page.keyboard.press('Escape'); const { name: docChild } = await createRootSubPage( @@ -211,9 +209,8 @@ test.describe('Doc Header', () => { await expect(emojiPicker).toBeHidden(); // Add emoji - await optionMenu.click(); - await expect(removeEmojiMenuItem).toBeHidden(); - await addEmojiMenuItem.click(); + await expect(removeEmoji).toBeHidden(); + await addEmoji.click(); // The 1 April the emoji is a fish await expect(emojiPicker).toHaveText(/📄|🐟/); @@ -235,17 +232,15 @@ test.describe('Doc Header', () => { await expect(row.getByText('😀')).toBeVisible(); // Remove emoji - await optionMenu.click(); - await expect(addEmojiMenuItem).toBeHidden(); - await removeEmojiMenuItem.click(); + await expect(addEmoji).toBeHidden(); + await removeEmoji.click(); await expect(emojiPicker).toBeHidden(); }); test('it deletes the doc', async ({ page, browserName }) => { const [randomDoc] = await createDoc(page, 'doc-delete', browserName, 1); - await page.getByLabel('Open the document options').click(); - await page.getByRole('menuitem', { name: 'Delete document' }).click(); + await clickInEditorMenu(page, 'Delete'); await expect( page.getByRole('heading', { name: 'Delete a doc' }), @@ -301,15 +296,12 @@ test.describe('Doc Header', () => { page.getByRole('textbox', { name: 'Document title' }), ).toContainText('Mocked document'); - await expect( - page.getByRole('button', { name: 'Export the document' }), - ).toBeVisible(); - await page.getByLabel('Open the document options').click(); await expect( - page.getByRole('menuitem', { name: 'Delete document' }), - ).toBeDisabled(); + page.getByRole('menuitem', { name: 'Download' }), + ).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Delete' })).toBeHidden(); // Click somewhere else to close the options await page.locator('body').click({ position: { x: 0, y: 0 } }); @@ -381,14 +373,12 @@ test.describe('Doc Header', () => { page.getByRole('textbox', { name: 'Document title' }), ).toContainText('Mocked document'); - await expect( - page.getByRole('button', { name: 'Export the document' }), - ).toBeVisible(); await page.getByLabel('Open the document options').click(); await expect( - page.getByRole('menuitem', { name: 'Delete document' }), - ).toBeDisabled(); + page.getByRole('menuitem', { name: 'Download' }), + ).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Delete' })).toBeHidden(); // Click somewhere else to close the options await page.locator('body').click({ position: { x: 0, y: 0 } }); @@ -453,14 +443,12 @@ test.describe('Doc Header', () => { page.getByRole('heading', { name: 'Mocked document' }), ).toBeVisible(); - await expect( - page.getByRole('button', { name: 'Export the document' }), - ).toBeVisible(); await page.getByLabel('Open the document options').click(); await expect( - page.getByRole('menuitem', { name: 'Delete document' }), - ).toBeDisabled(); + page.getByRole('menuitem', { name: 'Download' }), + ).toBeVisible(); + await expect(page.getByRole('menuitem', { name: 'Delete' })).toBeHidden(); // Click somewhere else to close the options await page.locator('body').click({ position: { x: 0, y: 0 } }); @@ -707,13 +695,18 @@ test.describe('Documents Header mobile', () => { await goToGridDoc(page); - await expect(page.getByRole('button', { name: 'Copy link' })).toBeHidden(); await page.getByLabel('Open the document options').click(); await expect( page.getByRole('menuitem', { name: 'Copy link' }), ).toBeVisible(); - await page.getByRole('menuitem', { name: 'Share' }).click(); - await expect(page.getByRole('button', { name: 'Copy link' })).toBeVisible(); + await page.keyboard.press('Escape'); + await page.getByRole('button', { name: 'Share' }).click(); + const shareModal = page.getByRole('dialog', { + name: 'Share the document', + }); + await expect( + shareModal.getByRole('button', { name: 'Copy link' }), + ).toBeVisible(); }); test('it checks the close button on Share modal', async ({ page }) => { diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-version.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-version.spec.ts index 7294a52b2..7a698b027 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/doc-version.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-version.spec.ts @@ -116,7 +116,7 @@ test.describe('Doc Version', () => { await page.getByLabel('Open the document options').click(); await expect( page.getByRole('menuitem', { name: 'Version history' }), - ).toBeDisabled(); + ).toBeHidden(); }); test('it restores the doc version', async ({ page, browserName }) => { diff --git a/src/frontend/apps/impress/src/cunningham/cunningham-style.css b/src/frontend/apps/impress/src/cunningham/cunningham-style.css index 9c3074223..673c0668c 100644 --- a/src/frontend/apps/impress/src/cunningham/cunningham-style.css +++ b/src/frontend/apps/impress/src/cunningham/cunningham-style.css @@ -93,7 +93,7 @@ * Tooltip */ .c__tooltip { - padding: var(--c--globals--font--sizes--sm) var(--c--globals--spacings--xxs); + padding: var(--c--globals--font--sizes--t) var(--c--globals--spacings--xxs); } .c__tooltip .react-aria-OverlayArrow svg { diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocHeaderEmoji.spec.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocHeaderEmoji.spec.tsx new file mode 100644 index 000000000..caa82a8da --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocHeaderEmoji.spec.tsx @@ -0,0 +1,61 @@ +import { fireEvent, render, screen } from '@testing-library/react'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; + +import { AppWrapper } from '@/tests/utils'; + +const mockUpdateDocEmoji = vi.fn(); + +vi.mock('@/docs/doc-management', async () => { + const actual = await vi.importActual('@/docs/doc-management'); + return { + ...actual, + useDocTitleUpdate: () => ({ updateDocEmoji: mockUpdateDocEmoji }), + }; +}); + +import { DocHeader } from '../components/DocHeader'; + +const doc = { + id: 'doc-1', + title: 'My document', + is_favorite: false, + nb_accesses_direct: 1, + abilities: { + versions_list: true, + destroy: true, + partial_update: true, + duplicate: true, + accesses_view: true, + }, +} as any; + +describe('DocHeader - Add emoji (April Fools easter egg)', () => { + beforeEach(() => { + vi.useFakeTimers(); + mockUpdateDocEmoji.mockClear(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + [ + { emoji: '🐟', date: '2026-04-01' }, + { emoji: '📄', date: '2026-03-30' }, + { emoji: '📄', date: '2026-04-02' }, + ].forEach(({ emoji, date }) => { + test(`uses ${emoji} emoji on ${date}`, () => { + vi.setSystemTime(new Date(date)); + + render(, { wrapper: AppWrapper }); + + fireEvent.click(screen.getByRole('button', { name: 'Add icon' })); + + expect(mockUpdateDocEmoji).toHaveBeenCalledWith( + 'doc-1', + 'My document', + emoji, + ); + }); + }); +}); diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxEmoji.spec.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxEmoji.spec.tsx deleted file mode 100644 index 5e0024cce..000000000 --- a/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxEmoji.spec.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { render } from '@testing-library/react'; -import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; - -import { DropdownMenuOption } from '@/components'; -import { AppWrapper } from '@/tests/utils'; - -const mockUpdateDocEmoji = vi.fn(); -let capturedOptions: DropdownMenuOption[] = []; - -vi.mock('@/components', async () => { - const actual = await vi.importActual('@/components'); - return { - ...actual, - DropdownMenu: ({ options }: { options: DropdownMenuOption[] }) => { - capturedOptions = options; - return null; - }, - }; -}); - -vi.mock('next/router', async () => ({ - ...(await vi.importActual('next/router')), - useRouter: () => ({ push: vi.fn() }), -})); - -vi.mock('@/docs/doc-management', async () => { - const actual = await vi.importActual('@/docs/doc-management'); - return { - ...actual, - useDocTitleUpdate: () => ({ updateDocEmoji: mockUpdateDocEmoji }), - useDocUtils: () => ({ isChild: true, isTopRoot: false }), - useCopyDocLink: () => vi.fn(), - useCreateFavoriteDoc: () => ({ mutate: vi.fn() }), - useDeleteFavoriteDoc: () => ({ mutate: vi.fn() }), - useDuplicateDoc: () => ({ mutate: vi.fn() }), - }; -}); - -vi.mock('@/stores', () => ({ - useFocusStore: (selector?: (state: any) => any) => { - const state = { addLastFocus: vi.fn(), restoreFocus: vi.fn() }; - return selector ? selector(state) : state; - }, - useResponsiveStore: () => ({ - isSmallMobile: false, - isMobile: false, - isDesktop: true, - }), -})); - -vi.mock('../hooks/useCopyCurrentEditorToClipboard', () => ({ - useCopyCurrentEditorToClipboard: () => vi.fn(), -})); - -import { DocToolBox } from '../components/DocToolBox'; - -const doc = { - id: 'doc-1', - title: 'My document', - is_favorite: false, - nb_accesses_direct: 1, - abilities: { - versions_list: true, - destroy: true, - partial_update: true, - duplicate: true, - accesses_view: true, - }, -} as any; - -describe('DocToolBox - Add emoji (April Fools easter egg)', () => { - beforeEach(() => { - vi.useFakeTimers(); - mockUpdateDocEmoji.mockClear(); - }); - - afterEach(() => { - vi.useRealTimers(); - }); - - [ - { emoji: '🐟', date: '2026-04-01' }, - { emoji: '📄', date: '2026-03-30' }, - { emoji: '📄', date: '2026-04-02' }, - ].forEach(({ emoji, date }) => { - test(`uses ${emoji} emoji on ${date}`, () => { - vi.setSystemTime(new Date(date)); - - render(, { wrapper: AppWrapper }); - - const addEmojiOption = capturedOptions.find( - (o) => o.label === 'Add emoji', - ); - void addEmojiOption?.callback?.(); - - expect(mockUpdateDocEmoji).toHaveBeenCalledWith( - 'doc-1', - 'My document', - emoji, - ); - }); - }); -}); diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxLicence.spec.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxLicence.spec.tsx index e0e693d31..087940fa0 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxLicence.spec.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/__tests__/DocToolBoxLicence.spec.tsx @@ -9,9 +9,33 @@ vi.mock('next/router', async () => ({ ...(await vi.importActual('next/router')), useRouter: () => ({ push: vi.fn(), + pathname: '/docs/doc-1', }), })); +vi.mock('@gouvfr-lasuite/ui-kit', async () => { + const actual = await vi.importActual('@gouvfr-lasuite/ui-kit'); + return { + ...actual, + DropdownMenu: ({ options, children }: any) => ( + <> + {children} +
    + {options + .filter((o: any) => !o.isHidden) + .map((o: any) => ( +
  • {o.label}
  • + ))} +
+ + ), + }; +}); + +vi.mock('../hooks/useCopyCurrentEditorToClipboard', () => ({ + useCopyCurrentEditorToClipboard: () => vi.fn(), +})); + const doc = { nb_accesses: 1, abilities: { @@ -39,9 +63,7 @@ describe('DocToolBox - Licence', () => { wrapper: AppWrapper, }); - expect( - await screen.findByLabelText('Export the document'), - ).toBeInTheDocument(); + expect(await screen.findByText('Download')).toBeInTheDocument(); }, 15000); test('The export button is not rendered when MIT version is activated', async () => { @@ -53,12 +75,6 @@ describe('DocToolBox - Licence', () => { wrapper: AppWrapper, }); - expect( - screen.getByLabelText('Open the document options'), - ).toBeInTheDocument(); - - expect( - screen.queryByLabelText('Export the document'), - ).not.toBeInTheDocument(); + expect(screen.queryByText('Download')).not.toBeInTheDocument(); }, 15000); }); diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx index 43c4a7eab..2a71202ed 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeader.tsx @@ -1,62 +1,90 @@ +import { Button } from '@gouvfr-lasuite/cunningham-react'; import { useTranslation } from 'react-i18next'; +import RemoveEmojiSVG from '@/assets/icons/ui-kit/face-remove.svg'; +import AddEmojiSVG from '@/assets/icons/ui-kit/face.svg'; import { Box, HorizontalSeparator } from '@/components'; -import { useCunninghamTheme } from '@/cunningham'; -import { Doc, useIsCollaborativeEditable } from '@/docs/doc-management'; -import { useResponsiveStore } from '@/stores'; +import { + Doc, + getEmojiAndTitle, + useDocTitleUpdate, + useDocUtils, + useIsCollaborativeEditable, +} from '@/docs/doc-management'; import { AlertNetwork } from './AlertNetwork'; import { AlertRestore } from './AlertRestore'; import { DocHeaderInfo } from './DocHeaderInfo'; import { DocTitle } from './DocTitle'; -import { DocToolBox } from './DocToolBox'; interface DocHeaderProps { doc: Doc; } export const DocHeader = ({ doc }: DocHeaderProps) => { - const { spacingsTokens } = useCunninghamTheme(); - const { isDesktop } = useResponsiveStore(); const { t } = useTranslation(); const { isEditable } = useIsCollaborativeEditable(doc); const isDeletedDoc = !!doc.deleted_at; + // Emoji Management + const { emoji } = getEmojiAndTitle(doc.title ?? ''); + const { updateDocEmoji } = useDocTitleUpdate(); + const { isTopRoot } = useDocUtils(doc); + const displayEmojiButton = doc.abilities.partial_update && !isTopRoot; return ( <> - {isDeletedDoc && } - {!isEditable && } - - - - - - - - {!isDeletedDoc && } - + {isDeletedDoc && } + {!isEditable && } - + + + {displayEmojiButton && ( + + )} + + + + + ); diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeaderInfo.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeaderInfo.tsx index 273c15c89..8de22bd4a 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeaderInfo.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocHeaderInfo.tsx @@ -2,7 +2,7 @@ import { t } from 'i18next'; import PublicSVG from '@/assets/icons/ui-kit/public.svg'; import ProtedtedSVG from '@/assets/icons/ui-kit/vpn_lock.svg'; -import { Text } from '@/components'; +import { Box, Text } from '@/components'; import { useConfig } from '@/core'; import { Doc, @@ -40,7 +40,7 @@ export const DocHeaderInfo = ({ doc }: DocHeaderInfoProps) => { } return ( - <> + { {dateToDisplay} - + ); }; diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx index 7a3ce2ea2..7c87ac542 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx @@ -42,11 +42,7 @@ export const DocTitleText = () => { return ( - + {currentDoc?.title || untitledDocument} @@ -110,7 +106,7 @@ const DocTitleEmojiPicker = ({ doc }: DocTitleProps) => { }; const DocTitleInput = ({ doc }: DocTitleProps) => { - const { isLargeScreen } = useResponsiveStore(); + const { isSmallMobile } = useResponsiveStore(); const { t } = useTranslation(); const { isTopRoot } = useDocUtils(doc); const { untitledDocument } = useTrans(); @@ -200,7 +196,6 @@ const DocTitleInput = ({ doc }: DocTitleProps) => { $minHeight="40px" > {!isTopRoot && } - { } onPasteCapture={handlePaste} onDropCapture={handleDrop} - $padding={{ right: 'big' }} $css={css` &[contenteditable='true']:empty:not(:focus):before { content: '${untitledDocument}'; @@ -227,11 +221,12 @@ const DocTitleInput = ({ doc }: DocTitleProps) => { pointer-events: none; font-style: italic; } - font-size: ${isLargeScreen - ? 'var(--c--globals--font--sizes--h2)' - : 'var(--c--globals--font--sizes--sm)'}; + font-size: ${isSmallMobile + ? 'var(--c--globals--font--sizes--h4)' + : 'var(--c--globals--font--sizes--h2)'}; font-weight: 700; outline: none; + width: 100%; `} > {titleDisplay} diff --git a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx index 7d2f749e0..78380ca3d 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx @@ -1,42 +1,36 @@ import { Button, useModal } from '@gouvfr-lasuite/cunningham-react'; -import { useTreeContext } from '@gouvfr-lasuite/ui-kit'; +import { + DropdownMenu, + DropdownMenuOption, + useTreeContext, +} from '@gouvfr-lasuite/ui-kit'; import dynamic from 'next/dynamic'; import { useRouter } from 'next/router'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { css } from 'styled-components'; import AddLinkSVG from '@/assets/icons/ui-kit/add_link.svg'; import ContentCopySVG from '@/assets/icons/ui-kit/content_copy.svg'; import DeleteSVG from '@/assets/icons/ui-kit/delete.svg'; import DownloadSVG from '@/assets/icons/ui-kit/download.svg'; -import RemoveEmojiSVG from '@/assets/icons/ui-kit/face-remove.svg'; -import AddEmojiSVG from '@/assets/icons/ui-kit/face.svg'; +import SharedSVG from '@/assets/icons/ui-kit/group.svg'; import HistorySVG from '@/assets/icons/ui-kit/history.svg'; import KeepSVG from '@/assets/icons/ui-kit/keep.svg'; import KeepOffSVG from '@/assets/icons/ui-kit/keep_off.svg'; import MarkdownCopySVG from '@/assets/icons/ui-kit/markdown_copy.svg'; -import { - Box, - DropdownMenu, - DropdownMenuOption, - Icon, - IconOptions, -} from '@/components'; -import { useCunninghamTheme } from '@/cunningham'; +import MoreSVG from '@/assets/icons/ui-kit/more_horiz.svg'; import { Doc, KEY_DOC, KEY_LIST_DOC, KEY_LIST_FAVORITE_DOC, - getEmojiAndTitle, useCopyDocLink, useCreateFavoriteDoc, useDeleteFavoriteDoc, - useDocTitleUpdate, useDocUtils, useDuplicateDoc, } from '@/docs/doc-management'; +import { useAuth } from '@/features/auth'; import { useFocusStore, useResponsiveStore } from '@/stores'; import { useCopyCurrentEditorToClipboard } from '../hooks/useCopyCurrentEditorToClipboard'; @@ -57,6 +51,14 @@ const ModalSelectVersion = dynamic( { ssr: false }, ); +const DocShareModal = dynamic( + () => + import('@/docs/doc-share/components/DocShareModal').then((mod) => ({ + default: mod.DocShareModal, + })), + { ssr: false }, +); + const ModalExport = process.env.NEXT_PUBLIC_PUBLISH_AS_MIT === 'false' ? dynamic( @@ -76,16 +78,18 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { const { t } = useTranslation(); const treeContext = useTreeContext(); const router = useRouter(); - const { isChild, isTopRoot } = useDocUtils(doc); - - const { spacingsTokens, colorsTokens } = useCunninghamTheme(); + const { isTopRoot } = useDocUtils(doc); + const { authenticated } = useAuth(); + const copyCurrentEditorToClipboard = useCopyCurrentEditorToClipboard(); + const [openDropdown, setOpenDropdown] = useState(false); const [isModalRemoveOpen, setIsModalRemoveOpen] = useState(false); const [isModalExportOpen, setIsModalExportOpen] = useState(false); + const shareModal = useModal(); const selectHistoryModal = useModal(); - const { addLastFocus, restoreFocus } = useFocusStore(); - const { isSmallMobile, isMobile } = useResponsiveStore(); + const { restoreFocus } = useFocusStore(); + const { isMobile } = useResponsiveStore(); const copyDocLink = useCopyDocLink(doc.id); const { mutate: duplicateDoc } = useDuplicateDoc({ onSuccess: (data) => { @@ -99,19 +103,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => { listInvalidQueries: [KEY_LIST_DOC, KEY_DOC, KEY_LIST_FAVORITE_DOC], }); - // Emoji Management - const { emoji } = getEmojiAndTitle(doc.title ?? ''); - const { updateDocEmoji } = useDocTitleUpdate(); - const options: DropdownMenuOption[] = [ - { - label: t('Export'), - icon: