Skip to content

Commit 24c220a

Browse files
committed
✨(frontend) add "Add Emoji" button to doc options menu
- Add "Add Emoji" button to doc options menu - Remove default emoji when none selected - Improve doc options styling
1 parent d7d468f commit 24c220a

File tree

4 files changed

+102
-70
lines changed

4 files changed

+102
-70
lines changed

src/frontend/apps/e2e/__tests__/app-impress/doc-header.spec.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,18 @@ test.describe('Doc Header', () => {
6868
await createDoc(page, 'doc-update-emoji', browserName, 1);
6969

7070
const emojiPicker = page.locator('.--docs--doc-title').getByRole('button');
71+
const optionMenu = page.getByLabel('Open the document options');
72+
const addEmojiMenuItem = page.getByRole('menuitem', { name: 'Add emoji' });
73+
const removeEmojiMenuItem = page.getByRole('menuitem', {
74+
name: 'Remove emoji',
75+
});
7176

7277
// Top parent should not have emoji picker
7378
await expect(emojiPicker).toBeHidden();
79+
await optionMenu.click();
80+
await expect(addEmojiMenuItem).toBeHidden();
81+
await expect(removeEmojiMenuItem).toBeHidden();
82+
await page.keyboard.press('Escape');
7483

7584
const { name: docChild } = await createRootSubPage(
7685
page,
@@ -80,13 +89,23 @@ test.describe('Doc Header', () => {
8089

8190
await verifyDocName(page, docChild);
8291

83-
await expect(emojiPicker).toBeVisible();
92+
// Emoji picker should be hidden initially
93+
await expect(emojiPicker).toBeHidden();
94+
95+
// Add emoji
96+
await optionMenu.click();
97+
await expect(removeEmojiMenuItem).toBeHidden();
98+
await addEmojiMenuItem.click();
99+
await expect(emojiPicker).toHaveText('📄');
100+
101+
// Change emoji
84102
await emojiPicker.click({
85103
delay: 100,
86104
});
87105
await page.getByRole('button', { name: '😀' }).first().click();
88106
await expect(emojiPicker).toHaveText('😀');
89107

108+
// Update title
90109
const docTitle = page.getByRole('textbox', { name: 'Document title' });
91110
await docTitle.fill('Hello Emoji World');
92111
await docTitle.blur();
@@ -95,6 +114,12 @@ test.describe('Doc Header', () => {
95114
// Check the tree
96115
const row = await getTreeRow(page, 'Hello Emoji World');
97116
await expect(row.getByText('😀')).toBeVisible();
117+
118+
// Remove emoji
119+
await optionMenu.click();
120+
await expect(addEmojiMenuItem).toBeHidden();
121+
await removeEmojiMenuItem.click();
122+
await expect(emojiPicker).toBeHidden();
98123
});
99124

100125
test('it deletes the doc', async ({ page, browserName }) => {

src/frontend/apps/e2e/__tests__/app-impress/doc-tree.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ test.describe('Doc Tree', () => {
352352
await page.getByRole('menuitem', { name: 'Remove emoji' }).click();
353353

354354
await expect(row.getByText('😀')).toBeHidden();
355-
await expect(titleEmojiPicker).not.toHaveText('😀');
355+
await expect(titleEmojiPicker).toBeHidden();
356356
});
357357
});
358358

src/frontend/apps/impress/src/features/docs/doc-header/components/DocTitle.tsx

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,16 @@ const DocTitleEmojiPicker = ({ doc }: DocTitleProps) => {
5555
const { colorsTokens } = useCunninghamTheme();
5656
const { emoji } = getEmojiAndTitle(doc.title ?? '');
5757

58+
if (!emoji) {
59+
return null;
60+
}
61+
5862
return (
59-
<Tooltip content={t('Document emoji')} aria-hidden={true} placement="top">
63+
<Tooltip
64+
content={t('Edit document emoji')}
65+
aria-hidden={true}
66+
placement="top"
67+
>
6068
<Box
6169
$css={css`
6270
padding: 4px;
@@ -70,11 +78,17 @@ const DocTitleEmojiPicker = ({ doc }: DocTitleProps) => {
7078
`}
7179
>
7280
<DocIcon
81+
buttonProps={{
82+
$width: '32px',
83+
$height: '32px',
84+
$justify: 'space-between',
85+
$align: 'center',
86+
}}
7387
withEmojiPicker={doc.abilities.partial_update}
7488
docId={doc.id}
7589
title={doc.title}
7690
emoji={emoji}
77-
$size="25px"
91+
$size="23px"
7892
defaultIcon={
7993
<SimpleFileIcon
8094
width="25px"
@@ -94,7 +108,6 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
94108
const { isDesktop } = useResponsiveStore();
95109
const { t } = useTranslation();
96110
const { colorsTokens } = useCunninghamTheme();
97-
const { spacingsTokens } = useCunninghamTheme();
98111
const { isTopRoot } = useDocUtils(doc);
99112
const { untitledDocument } = useTrans();
100113
const { emoji, titleWithoutEmoji } = getEmojiAndTitle(doc.title ?? '');
@@ -139,19 +152,9 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
139152
className="--docs--doc-title"
140153
$direction="row"
141154
$align="center"
142-
$gap={spacingsTokens['xs']}
155+
$gap="4px"
143156
$minHeight="40px"
144157
>
145-
{isTopRoot && (
146-
<SimpleFileIcon
147-
width="25px"
148-
height="25px"
149-
aria-hidden="true"
150-
aria-label={t('Simple document icon')}
151-
color={colorsTokens['primary-500']}
152-
style={{ flexShrink: '0' }}
153-
/>
154-
)}
155158
{!isTopRoot && <DocTitleEmojiPicker doc={doc} />}
156159

157160
<Tooltip content={t('Rename')} aria-hidden={true} placement="top">

src/frontend/apps/impress/src/features/docs/doc-header/components/DocToolBox.tsx

Lines changed: 58 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
6060
const selectHistoryModal = useModal();
6161
const modalShare = useModal();
6262

63-
const { isSmallMobile, isDesktop } = useResponsiveStore();
63+
const { isSmallMobile, isMobile } = useResponsiveStore();
6464
const copyDocLink = useCopyDocLink(doc.id);
6565
const { mutate: duplicateDoc } = useDuplicateDoc({
6666
onSuccess: (data) => {
@@ -90,28 +90,20 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
9090
const { updateDocEmoji } = useDocTitleUpdate();
9191

9292
const options: DropdownMenuOption[] = [
93-
...(isSmallMobile
94-
? [
95-
{
96-
label: t('Share'),
97-
icon: 'group',
98-
callback: modalShare.open,
99-
},
100-
{
101-
label: t('Export'),
102-
icon: 'download',
103-
callback: () => {
104-
setIsModalExportOpen(true);
105-
},
106-
show: !!ModalExport,
107-
},
108-
{
109-
label: t('Copy link'),
110-
icon: 'add_link',
111-
callback: copyDocLink,
112-
},
113-
]
114-
: []),
93+
{
94+
label: t('Share'),
95+
icon: 'group',
96+
callback: modalShare.open,
97+
show: isSmallMobile,
98+
},
99+
{
100+
label: t('Export'),
101+
icon: 'download',
102+
callback: () => {
103+
setIsModalExportOpen(true);
104+
},
105+
show: !!ModalExport && isSmallMobile,
106+
},
115107
{
116108
label: doc.is_favorite ? t('Unpin') : t('Pin'),
117109
icon: 'push_pin',
@@ -124,25 +116,38 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
124116
},
125117
testId: `docs-actions-${doc.is_favorite ? 'unpin' : 'pin'}-${doc.id}`,
126118
},
127-
...(emoji && doc.abilities.partial_update && !isTopRoot
128-
? [
129-
{
130-
label: t('Remove emoji'),
131-
icon: 'emoji_emotions',
132-
callback: () => {
133-
updateDocEmoji(doc.id, doc.title ?? '', '');
134-
},
135-
},
136-
]
137-
: []),
138119
{
139120
label: t('Version history'),
140121
icon: 'history',
141122
disabled: !doc.abilities.versions_list,
142123
callback: () => {
143124
selectHistoryModal.open();
144125
},
145-
show: isDesktop,
126+
show: !isMobile,
127+
showSeparator: isTopRoot ? true : false,
128+
},
129+
{
130+
label: t('Remove emoji'),
131+
icon: 'emoji_emotions',
132+
callback: () => {
133+
updateDocEmoji(doc.id, doc.title ?? '', '');
134+
},
135+
showSeparator: true,
136+
show: !!emoji && doc.abilities.partial_update && !isTopRoot,
137+
},
138+
{
139+
label: t('Add emoji'),
140+
icon: 'emoji_emotions',
141+
callback: () => {
142+
updateDocEmoji(doc.id, doc.title ?? '', '📄');
143+
},
144+
showSeparator: true,
145+
show: !emoji && doc.abilities.partial_update && !isTopRoot,
146+
},
147+
{
148+
label: t('Copy link'),
149+
icon: 'add_link',
150+
callback: copyDocLink,
146151
},
147152
{
148153
label: t('Copy as {{format}}', { format: 'Markdown' }),
@@ -158,6 +163,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
158163
void copyCurrentEditorToClipboard('html');
159164
},
160165
show: isFeatureFlagActivated('CopyAsHTML'),
166+
showSeparator: true,
161167
},
162168
{
163169
label: t('Duplicate'),
@@ -170,6 +176,7 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
170176
canSave: doc.abilities.partial_update,
171177
});
172178
},
179+
showSeparator: true,
173180
},
174181
{
175182
label: isChild ? t('Delete sub-document') : t('Delete document'),
@@ -224,25 +231,22 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
224231
aria-label={t('Export the document')}
225232
/>
226233
)}
227-
<DropdownMenu options={options} label={t('Open the document options')}>
228-
<IconOptions
229-
aria-hidden="true"
230-
isHorizontal
231-
$theme="primary"
232-
$padding={{ all: 'xs' }}
233-
$css={css`
234-
border-radius: 4px;
235-
&:hover {
236-
background-color: ${colorsTokens['greyscale-100']};
237-
}
238-
${isSmallMobile
239-
? css`
240-
padding: 10px;
241-
border: 1px solid ${colorsTokens['greyscale-300']};
242-
`
243-
: ''}
244-
`}
245-
/>
234+
<DropdownMenu
235+
options={options}
236+
label={t('Open the document options')}
237+
buttonCss={css`
238+
padding: ${spacingsTokens['xs']};
239+
&:hover {
240+
background-color: ${colorsTokens['greyscale-100']};
241+
}
242+
${isSmallMobile
243+
? css`
244+
border: 1px solid ${colorsTokens['greyscale-300']};
245+
`
246+
: ''}
247+
`}
248+
>
249+
<IconOptions aria-hidden="true" isHorizontal $theme="primary" />
246250
</DropdownMenu>
247251
</Box>
248252

0 commit comments

Comments
 (0)