diff --git a/web/e2e/smoke.spec.js b/web/e2e/smoke.spec.js index ebe855d..3fa8591 100644 --- a/web/e2e/smoke.spec.js +++ b/web/e2e/smoke.spec.js @@ -2440,7 +2440,8 @@ test('en note kan deles med et projekts folk, og tages tilbage igen', async ({ p await page.keyboard.type('Fælles aftale om leveringen'); await page.getByRole('textbox', { name: 'Notens tekst' }).blur(); - // Shared by being filed in a project. Not an access list of its own. + // Filing it in a project — the controls live in the Del popover in the footer. + await page.locator('.sharewrap > button').click(); await page.getByLabel('Læg i projekt').selectOption({ label: 'Delenoter' }); await expect(page.getByText('delt med projektets folk')).toBeVisible(); @@ -2451,6 +2452,7 @@ test('en note kan deles med et projekts folk, og tages tilbage igen', async ({ p // Taken back out, it is the author's alone again. await sidebar.getByRole('link', { name: 'Noter', exact: true }).click(); await page.getByRole('button', { name: /Fælles aftale/ }).click(); + await page.locator('.sharewrap > button').click(); await page.getByLabel('Læg i projekt').selectOption({ label: 'Intet projekt' }); await expect(page.getByText('din igen')).toBeVisible(); @@ -2487,10 +2489,12 @@ test('en note kan deles med en person direkte, og dukker op hos dem', async ({ b await page.keyboard.type('Ferieplan for hele holdet'); await page.getByRole('textbox', { name: 'Notens tekst' }).blur(); - const share = page.locator('.people-share'); + // Sharing lives in a popover behind the Del button in the footer. + await page.locator('.sharewrap > button').click(); + const share = page.locator('.sharepanel'); await expect(share).toBeVisible(); await share.locator('.addshare select').first().selectOption({ label: 'Sofie' }); - await page.getByRole('button', { name: 'Del', exact: true }).click(); + await share.getByRole('button', { name: 'Tilføj' }).click(); // She is on the note now, with the role she was given. const row = share.locator('.sharelist li').filter({ hasText: 'Sofie' }); @@ -2981,7 +2985,8 @@ test('en note kan oprettes inde fra et projekt og hører til det med det samme', await page.waitForTimeout(1200); // Den hører til projektet med det samme: "Læg i projekt" står på projektet, - // uden at nogen har valgt det bagefter. + // uden at nogen har valgt det bagefter. Kontrollen ligger i Del-popoveren. + await page.locator('.sharewrap > button').click(); await expect(page.getByLabel('Læg i projekt')).toHaveValue(/.+/); const shared = await page.getByLabel('Læg i projekt').evaluate((el) => el.selectedOptions[0].textContent); expect(shared).toContain('Tagprojekt'); diff --git a/web/src/lib/locales/da.js b/web/src/lib/locales/da.js index f1028ac..f24da7f 100644 --- a/web/src/lib/locales/da.js +++ b/web/src/lib/locales/da.js @@ -25,7 +25,8 @@ export const da = { 'notes.sharedBy': 'Delt af {name}', 'notes.sharePeople': 'Del med personer', 'notes.sharePick': 'Vælg en person …', - 'notes.shareAdd': 'Del', + 'notes.shareButton': 'Del', + 'notes.shareAdd': 'Tilføj', 'notes.shareRoleViewer': 'Kan læse', 'notes.shareRoleEditor': 'Kan rette', 'notes.shareRemove': 'Fjern adgang', diff --git a/web/src/lib/locales/en.js b/web/src/lib/locales/en.js index d4bc226..87b932a 100644 --- a/web/src/lib/locales/en.js +++ b/web/src/lib/locales/en.js @@ -21,7 +21,8 @@ export const en = { 'notes.sharedBy': 'Shared by {name}', 'notes.sharePeople': 'Share with people', 'notes.sharePick': 'Choose someone …', - 'notes.shareAdd': 'Share', + 'notes.shareButton': 'Share', + 'notes.shareAdd': 'Add', 'notes.shareRoleViewer': 'Can view', 'notes.shareRoleEditor': 'Can edit', 'notes.shareRemove': 'Remove access', diff --git a/web/src/routes/noter/+page.svelte b/web/src/routes/noter/+page.svelte index 6e24c6f..dade9b4 100644 --- a/web/src/routes/noter/+page.svelte +++ b/web/src/routes/noter/+page.svelte @@ -193,6 +193,26 @@ let shareBusy = $state(false); const ownsSelected = $derived(!!selected && selected.created_by === app.user?.id); + // The whole of sharing — a project and named people — lives in a popover behind + // one button, so the note's footer stays a status and three buttons rather than + // a row that runs off its own width. + let shareOpen = $state(false); + let shareWrap = $state(null); + // Closing on a switch of note, and only then: the panel belongs to the note it + // was opened on. Tracked by id rather than by the object, so a save that returns + // a fresh copy of the same note does not slam the panel shut mid-use. + let sharePanelFor = $state(null); + $effect(() => { + const id = selected?.id ?? null; + if (id !== sharePanelFor) { + shareOpen = false; + sharePanelFor = id; + } + }); + function onShareOutside(event) { + if (shareOpen && shareWrap && !shareWrap.contains(event.target)) shareOpen = false; + } + $effect(() => { const id = selected?.id; // Nulstil ved hvert skift, så den forrige notes folk ikke står et øjeblik @@ -638,6 +658,13 @@ {t('notes.title')} · verdande + { + if (e.key === 'Escape' && shareOpen) shareOpen = false; + }} +/> +