Skip to content

Commit c682bce

Browse files
committed
📱(frontend) docs mobile friendly
We adapt the docs component to be mobile friendly.
1 parent 8dd7671 commit c682bce

File tree

26 files changed

+668
-322
lines changed

26 files changed

+668
-322
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to
1616
- ✨(frontend) Activate versions feature #240
1717
- ✨(frontend) one-click document creation #275
1818
- ✨(frontend) edit title inline #275
19+
- 📱(frontend) mobile responsive #304
1920
- 🌐(frontend) Update translation #308
2021

2122
## Changed

src/frontend/apps/e2e/__tests__/app-impress/common.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,14 @@ export const goToGridDoc = async (
113113
const header = page.locator('header').first();
114114
await header.locator('h2').getByText('Docs').click();
115115

116-
const datagrid = page
117-
.getByLabel('Datagrid of the documents page 1')
118-
.getByRole('table');
116+
const datagrid = page.getByLabel('Datagrid of the documents page 1');
117+
const datagridTable = datagrid.getByRole('table');
119118

120-
await expect(datagrid.getByLabel('Loading data')).toBeHidden();
119+
await expect(datagrid.getByLabel('Loading data')).toBeHidden({
120+
timeout: 10000,
121+
});
121122

122-
const rows = datagrid.getByRole('row');
123+
const rows = datagridTable.getByRole('row');
123124
const row = title
124125
? rows.filter({
125126
hasText: title,
@@ -132,7 +133,7 @@ export const goToGridDoc = async (
132133

133134
expect(docTitle).toBeDefined();
134135

135-
await docTitleCell.click();
136+
await row.getByRole('link').first().click();
136137

137138
return docTitle as string;
138139
};

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ test.describe('Doc Create', () => {
1818
const header = page.locator('header').first();
1919
await header.locator('h2').getByText('Docs').click();
2020

21-
const datagrid = page
22-
.getByLabel('Datagrid of the documents page 1')
23-
.getByRole('table');
21+
const datagrid = page.getByLabel('Datagrid of the documents page 1');
22+
const datagridTable = datagrid.getByRole('table');
2423

25-
await expect(datagrid.getByLabel('Loading data')).toBeHidden();
26-
await expect(datagrid.getByText(docTitle)).toBeVisible({
24+
await expect(datagrid.getByLabel('Loading data')).toBeHidden({
25+
timeout: 10000,
26+
});
27+
await expect(datagridTable.getByText(docTitle)).toBeVisible({
2728
timeout: 5000,
2829
});
2930
});

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

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ test.describe('Documents Grid', () => {
117117
.getByRole('cell')
118118
.nth(cellNumber);
119119

120-
await expect(datagrid.getByLabel('Loading data')).toBeHidden();
120+
await expect(datagrid.getByLabel('Loading data')).toBeHidden({
121+
timeout: 10000,
122+
});
121123

122124
// Initial state
123125
await expect(docNameRow1).toHaveText(/.*/);
@@ -134,7 +136,9 @@ test.describe('Documents Grid', () => {
134136
const responseOrderingAsc = await responsePromiseOrderingAsc;
135137
expect(responseOrderingAsc.ok()).toBeTruthy();
136138

137-
await expect(datagrid.getByLabel('Loading data')).toBeHidden();
139+
await expect(datagrid.getByLabel('Loading data')).toBeHidden({
140+
timeout: 10000,
141+
});
138142

139143
await expect(docNameRow1).toHaveText(/.*/);
140144
await expect(docNameRow2).toHaveText(/.*/);
@@ -155,7 +159,9 @@ test.describe('Documents Grid', () => {
155159
const responseOrderingDesc = await responsePromiseOrderingDesc;
156160
expect(responseOrderingDesc.ok()).toBeTruthy();
157161

158-
await expect(datagrid.getByLabel('Loading data')).toBeHidden();
162+
await expect(datagrid.getByLabel('Loading data')).toBeHidden({
163+
timeout: 10000,
164+
});
159165

160166
await expect(docNameRow1).toHaveText(/.*/);
161167
await expect(docNameRow2).toHaveText(/.*/);
@@ -244,3 +250,87 @@ test.describe('Documents Grid', () => {
244250
await expect(datagrid.getByText(docName!)).toBeHidden();
245251
});
246252
});
253+
254+
test.describe('Documents Grid mobile', () => {
255+
test.use({ viewport: { width: 500, height: 1200 } });
256+
257+
test.beforeEach(async ({ page }) => {
258+
await page.goto('/');
259+
});
260+
261+
test('it checks the grid when mobile', async ({ page }) => {
262+
await page.route('**/documents/**', async (route) => {
263+
const request = route.request();
264+
if (request.method().includes('GET') && request.url().includes('page=')) {
265+
await route.fulfill({
266+
json: {
267+
count: 1,
268+
next: null,
269+
previous: null,
270+
results: [
271+
{
272+
id: 'b7fd9d9b-0642-4b4f-8617-ce50f69519ed',
273+
title: 'My mocked document',
274+
accesses: [
275+
{
276+
id: '8c1e047a-24e7-4a80-942b-8e9c7ab43e1f',
277+
user: {
278+
id: '7380f42f-02eb-4ad5-b8f0-037a0e66066d',
279+
280+
full_name: 'John Doe',
281+
short_name: 'John',
282+
},
283+
team: '',
284+
role: 'owner',
285+
abilities: {
286+
destroy: false,
287+
update: false,
288+
partial_update: false,
289+
retrieve: true,
290+
set_role_to: [],
291+
},
292+
},
293+
],
294+
abilities: {
295+
attachment_upload: true,
296+
destroy: true,
297+
link_configuration: true,
298+
manage_accesses: true,
299+
partial_update: true,
300+
retrieve: true,
301+
update: true,
302+
versions_destroy: true,
303+
versions_list: true,
304+
versions_retrieve: true,
305+
},
306+
link_role: 'reader',
307+
link_reach: 'public',
308+
created_at: '2024-10-07T13:02:41.085298Z',
309+
updated_at: '2024-10-07T13:30:21.829690Z',
310+
},
311+
],
312+
},
313+
});
314+
} else {
315+
await route.continue();
316+
}
317+
});
318+
319+
await page.goto('/');
320+
321+
const datagrid = page.getByLabel('Datagrid of the documents page 1');
322+
const tableDatagrid = datagrid.getByRole('table');
323+
324+
await expect(datagrid.getByLabel('Loading data')).toBeHidden({
325+
timeout: 10000,
326+
});
327+
328+
const rows = tableDatagrid.getByRole('row');
329+
const row = rows.filter({
330+
hasText: 'My mocked document',
331+
});
332+
333+
await expect(row.getByRole('cell').nth(0)).toHaveText('My mocked document');
334+
await expect(row.getByRole('cell').nth(1)).toHaveText('Public');
335+
});
336+
});

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,3 +385,35 @@ test.describe('Doc Header', () => {
385385
).toBeHidden();
386386
});
387387
});
388+
389+
test.describe('Documents Header mobile', () => {
390+
test.use({ viewport: { width: 500, height: 1200 } });
391+
392+
test.beforeEach(async ({ page }) => {
393+
await page.goto('/');
394+
});
395+
396+
test('it checks the close button on Share modal', async ({ page }) => {
397+
await mockedDocument(page, {
398+
abilities: {
399+
destroy: true, // Means owner
400+
link_configuration: true,
401+
versions_destroy: true,
402+
versions_list: true,
403+
versions_retrieve: true,
404+
manage_accesses: true,
405+
update: true,
406+
partial_update: true,
407+
retrieve: true,
408+
},
409+
});
410+
411+
await goToGridDoc(page);
412+
413+
await page.getByRole('button', { name: 'Share' }).click();
414+
415+
await expect(page.getByLabel('Share modal')).toBeVisible();
416+
await page.getByRole('button', { name: 'close' }).click();
417+
await expect(page.getByLabel('Share modal')).toBeHidden();
418+
});
419+
});

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ test.beforeEach(async ({ page }) => {
88

99
test.describe('Doc Table Content', () => {
1010
test('it checks the doc table content', async ({ page, browserName }) => {
11+
test.setTimeout(60000);
12+
1113
const [randomDoc] = await createDoc(
1214
page,
1315
'doc-table-content',
@@ -37,7 +39,7 @@ test.describe('Doc Table Content', () => {
3739
await page.locator('.bn-block-outer').last().click();
3840

3941
// Create space to fill the viewport
40-
for (let i = 0; i < 5; i++) {
42+
for (let i = 0; i < 10; i++) {
4143
await page.keyboard.press('Enter');
4244
}
4345

@@ -48,7 +50,7 @@ test.describe('Doc Table Content', () => {
4850
await page.locator('.bn-block-outer').last().click();
4951

5052
// Create space to fill the viewport
51-
for (let i = 0; i < 5; i++) {
53+
for (let i = 0; i < 10; i++) {
5254
await page.keyboard.press('Enter');
5355
}
5456

@@ -61,11 +63,11 @@ test.describe('Doc Table Content', () => {
6163
const another = panel.getByText('Another World');
6264

6365
await expect(hello).toBeVisible();
64-
await expect(hello).toHaveCSS('font-size', /19/);
66+
await expect(hello).toHaveCSS('font-size', /17/);
6567
await expect(hello).toHaveAttribute('aria-selected', 'true');
6668

6769
await expect(superW).toBeVisible();
68-
await expect(superW).toHaveCSS('font-size', /16/);
70+
await expect(superW).toHaveCSS('font-size', /14/);
6971
await expect(superW).toHaveAttribute('aria-selected', 'false');
7072

7173
await expect(another).toBeVisible();

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ test.describe('Doc Visibility', () => {
2323
.getByLabel('Datagrid of the documents page 1')
2424
.getByRole('table');
2525

26-
await expect(datagrid.getByLabel('Loading data')).toBeHidden();
26+
await expect(datagrid.getByLabel('Loading data')).toBeHidden({
27+
timeout: 10000,
28+
});
2729

2830
await expect(datagrid.getByText(docTitle)).toBeVisible();
2931

src/frontend/apps/impress/src/cunningham/cunningham-style.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,23 @@ input:-webkit-autofill:focus {
507507
overflow-y: auto;
508508
}
509509

510+
@media screen and (width <= 420px) {
511+
.c__modal__scroller {
512+
padding: 0.7rem;
513+
}
514+
515+
.c__modal__title h2 {
516+
font-size: 1rem;
517+
}
518+
}
519+
520+
@media (width <= 576px) {
521+
.c__modal__footer--sided {
522+
gap: 0.5rem;
523+
flex-direction: column-reverse;
524+
}
525+
}
526+
510527
/**
511528
* Toast
512529
*/

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,14 @@ import { randomColor } from '../utils';
1818

1919
import { BlockNoteToolbar } from './BlockNoteToolbar';
2020

21-
const cssEditor = `
21+
const cssEditor = (readonly: boolean) => `
2222
&, & > .bn-container, & .ProseMirror {
2323
height:100%
2424
};
25+
& .bn-editor {
26+
padding-right: 30px;
27+
${readonly && `padding-left: 30px;`}
28+
};
2529
& .collaboration-cursor__caret.ProseMirror-widget{
2630
word-wrap: initial;
2731
}
@@ -30,6 +34,35 @@ const cssEditor = `
3034
padding: 2px;
3135
border-radius: 4px;
3236
}
37+
@media screen and (width <= 560px) {
38+
& .bn-editor {
39+
padding-left: 40px;
40+
padding-right: 10px;
41+
${readonly && `padding-left: 10px;`}
42+
};
43+
.bn-side-menu[data-block-type=heading][data-level="1"] {
44+
height: 46px;
45+
}
46+
.bn-side-menu[data-block-type=heading][data-level="2"] {
47+
height: 40px;
48+
}
49+
.bn-side-menu[data-block-type=heading][data-level="3"] {
50+
height: 40px;
51+
}
52+
& .bn-editor h1 {
53+
font-size: 1.6rem;
54+
}
55+
& .bn-editor h2 {
56+
font-size: 1.35rem;
57+
}
58+
& .bn-editor h3 {
59+
font-size: 1.2rem;
60+
}
61+
.bn-block-content[data-is-empty-and-focused][data-content-type="paragraph"]
62+
.bn-inline-content:has(> .ProseMirror-trailingBreak:only-child)::before {
63+
font-size: 14px;
64+
}
65+
}
3366
`;
3467

3568
interface BlockNoteEditorProps {
@@ -70,8 +103,9 @@ export const BlockNoteContent = ({
70103
const isVersion = doc.id !== storeId;
71104
const { userData } = useAuthStore();
72105
const { setStore, docsStore } = useDocStore();
73-
const canSave = doc.abilities.partial_update && !isVersion;
74-
useSaveDoc(doc.id, provider.document, canSave);
106+
107+
const readOnly = !doc.abilities.partial_update || isVersion;
108+
useSaveDoc(doc.id, provider.document, !readOnly);
75109
const storedEditor = docsStore?.[storeId]?.editor;
76110
const {
77111
mutateAsync: createDocAttachment,
@@ -130,7 +164,7 @@ export const BlockNoteContent = ({
130164
}, [editor, resetHeadings, setHeadings]);
131165

132166
return (
133-
<Box $css={cssEditor}>
167+
<Box $css={cssEditor(readOnly)}>
134168
{isErrorAttachment && (
135169
<Box $margin={{ bottom: 'big' }}>
136170
<TextErrors
@@ -144,7 +178,7 @@ export const BlockNoteContent = ({
144178
<BlockNoteView
145179
editor={editor}
146180
formattingToolbar={false}
147-
editable={doc.abilities.partial_update && !isVersion}
181+
editable={!readOnly}
148182
theme="light"
149183
>
150184
<BlockNoteToolbar />

0 commit comments

Comments
 (0)