From dccca92928675cfb60139a95d2ffc75a95f9768a Mon Sep 17 00:00:00 2001 From: Dream Hunter Date: Sat, 22 Aug 2026 19:31:54 +0800 Subject: [PATCH] fix: align send mail fields and editor caret (#1121) fix(frontend): align send mail fields and editor caret --- CHANGELOG.md | 1 + CHANGELOG_EN.md | 1 + e2e/tests/browser/send-mail-compose.spec.ts | 60 ++++++++++++++++++++- frontend/src/views/admin/SendMail.vue | 4 +- frontend/src/views/index/SendMail.vue | 16 +++--- 5 files changed, 70 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49cba70..736c48e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Bug Fixes - fix: |Admin| 修复切换一级标签页时二级标签页偶发无选中项、内容不显示及指示条偏移的问题 +- fix: |发信页面| 统一邮箱与名称字段顺序,并修复空正文输入框的光标与占位文字错位 ### Improvements diff --git a/CHANGELOG_EN.md b/CHANGELOG_EN.md index 5bf0c42..de558f7 100644 --- a/CHANGELOG_EN.md +++ b/CHANGELOG_EN.md @@ -15,6 +15,7 @@ ### Bug Fixes - fix: |Admin| Fix secondary tabs occasionally losing their active item, hiding content, and leaving the indicator offset after switching primary tabs +- fix: |Send Mail| Use a consistent address/name field order and align the empty content editor caret with its placeholder ### Improvements diff --git a/e2e/tests/browser/send-mail-compose.spec.ts b/e2e/tests/browser/send-mail-compose.spec.ts index 89430f4..5a0753c 100644 --- a/e2e/tests/browser/send-mail-compose.spec.ts +++ b/e2e/tests/browser/send-mail-compose.spec.ts @@ -1,4 +1,4 @@ -import { test, expect, request as apiRequest } from '@playwright/test'; +import { test, expect, request as apiRequest, type Page } from '@playwright/test'; import { FRONTEND_URL, createTestAddress, @@ -6,6 +6,27 @@ import { requestSendAccess, } from '../../fixtures/test-helpers'; +const expectEditorOriginsToAlign = async (page: Page) => { + const editorOriginDelta = await page.locator('.compose-textarea').evaluate((editor) => { + const textareaElement = editor.querySelector('textarea'); + const placeholder = editor.querySelector('.n-input__placeholder'); + if (!textareaElement) throw new Error('compose textarea element not found'); + if (!placeholder) throw new Error('compose placeholder element not found'); + const textareaBox = textareaElement.getBoundingClientRect(); + const placeholderBox = placeholder.getBoundingClientRect(); + const textareaStyle = getComputedStyle(textareaElement); + const placeholderStyle = getComputedStyle(placeholder); + return { + x: textareaBox.x + parseFloat(textareaStyle.paddingLeft) + - placeholderBox.x - parseFloat(placeholderStyle.paddingLeft), + y: textareaBox.y + parseFloat(textareaStyle.paddingTop) + - placeholderBox.y - parseFloat(placeholderStyle.paddingTop), + }; + }); + expect(Math.abs(editorOriginDelta.x)).toBeLessThan(1); + expect(Math.abs(editorOriginDelta.y)).toBeLessThan(1); +}; + test.describe('Send mail composer', () => { test('edits a draft, changes format, and previews HTML', async ({ page }) => { const api = await apiRequest.newContext(); @@ -22,6 +43,20 @@ test.describe('Send mail composer', () => { await expect(page.getByRole('heading', { name: 'Compose email', exact: true })).toBeVisible(); await expect(page.locator('.composer-title')).toContainText(created.address); + const expectedFieldOrder = [ + 'send-mail-sender-address', + 'send-mail-sender-name', + 'send-mail-recipient-address', + 'send-mail-recipient-name', + ]; + const fieldIds = await page.locator('.composer-form .n-grid input').evaluateAll( + (inputs) => inputs.map((input) => input.id) + ); + expect(fieldIds.filter((id) => expectedFieldOrder.includes(id))).toEqual(expectedFieldOrder); + + const textarea = page.locator('.compose-textarea textarea'); + await expectEditorOriginsToAlign(page); + const recipient = page.getByRole('textbox', { name: /^Recipient address/ }); const subject = page.getByRole('textbox', { name: /^Subject/ }); await recipient.fill('recipient@test.example.com'); @@ -32,7 +67,6 @@ test.describe('Send mail composer', () => { '

Preview heading

Preview body

', '', ].join(''); - const textarea = page.locator('.compose-textarea textarea'); let previewDialogAppeared = false; page.on('dialog', async (dialog) => { previewDialogAppeared = true; @@ -75,4 +109,26 @@ test.describe('Send mail composer', () => { } } }); + + test('keeps the Admin field order and editor placeholder aligned', async ({ page }) => { + await page.addInitScript(() => { + localStorage.setItem('adminAuth', 'e2e-admin-pass'); + sessionStorage.setItem('adminTab', 'mails'); + }); + await page.goto(`${FRONTEND_URL}/en/admin`); + await page.getByText('Send Mail', { exact: true }).click(); + + await expect(page.getByRole('heading', { name: 'Compose email', exact: true })).toBeVisible(); + const expectedFieldOrder = [ + 'admin-send-mail-sender-address', + 'admin-send-mail-sender-name', + 'admin-send-mail-recipient-address', + 'admin-send-mail-recipient-name', + ]; + const fieldIds = await page.locator('.composer-form .n-grid input').evaluateAll( + (inputs) => inputs.map((input) => input.id) + ); + expect(fieldIds.filter((id) => expectedFieldOrder.includes(id))).toEqual(expectedFieldOrder); + await expectEditorOriginsToAlign(page); + }); }); diff --git a/frontend/src/views/admin/SendMail.vue b/frontend/src/views/admin/SendMail.vue index b621213..01990a8 100644 --- a/frontend/src/views/admin/SendMail.vue +++ b/frontend/src/views/admin/SendMail.vue @@ -332,8 +332,8 @@ const handleCreated = (editor) => { min-height: 360px; } -.compose-textarea :deep(.n-input__textarea-el) { - padding: 18px; +.compose-textarea :deep(.n-input__textarea-el), +.compose-textarea :deep(.n-input__placeholder) { line-height: 1.7; text-align: left; } diff --git a/frontend/src/views/index/SendMail.vue b/frontend/src/views/index/SendMail.vue index bbd2d5f..7acdb87 100644 --- a/frontend/src/views/index/SendMail.vue +++ b/frontend/src/views/index/SendMail.vue @@ -199,18 +199,18 @@ onMounted(async () => {