Просмотр исходного кода

WIP: 固定 DOCX 正文 36px 内边距

[gstack-context]
Decisions: DOCX 外层画布边距保持 0px 且纯白;正文上下左右固定 36px;整页等比适配避免表格和图片裁切。
Remaining: 最终 Vitest、完整 Playwright 和独立复审。
Skill: /investigate
[/gstack-context]
samien 2 месяцев назад
Родитель
Сommit
9d6198afcf
2 измененных файлов с 5 добавлено и 5 удалено
  1. 1 1
      src/client/components/library/PreviewInspector.vue
  2. 4 4
      tests/e2e/workspace.spec.ts

+ 1 - 1
src/client/components/library/PreviewInspector.vue

@@ -149,7 +149,7 @@ onBeforeUnmount(() => officeResizeObserver?.disconnect())
 .preview-inspector { display: flex; height: 100%; min-height: 0; flex-direction: column; overflow: hidden; }
 header { display: flex; min-height: 56px; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--line); } header > strong { min-width: 0; flex: 1; overflow: hidden; font-size: 12px; font-weight: 630; text-overflow: ellipsis; white-space: nowrap; }.preview-header-actions { display: flex; flex: 0 0 auto; align-items: center; gap: 3px; }.preview-header-actions .icon-button { display: grid; width: 32px; height: 32px; place-items: center; padding: 0; border: 0; border-radius: 8px; background: transparent; color: var(--text-muted); cursor: pointer; text-decoration: none; }.preview-header-actions .icon-button:hover { background: var(--surface-soft); color: var(--text-primary); }
 .preview-stage { display: grid; min-height: 0; flex: 1 1 auto; place-items: center; overflow: hidden; background: var(--surface-soft); touch-action: pan-y; }.preview-stage img, .preview-stage video { display: block; width: auto; height: auto; max-width: 100%; max-height: 100%; object-fit: contain; }.preview-stage audio { width: calc(100% - 34px); }.preview-stage object { width: 100%; height: 100%; border: 0; }.preview-text { width: 100%; height: 100%; box-sizing: border-box; padding: 20px 28px 28px; overflow: auto; background: var(--surface-raised); }.preview-text pre { margin: 0; color: var(--text-secondary); font: 10px/1.65 var(--font-code); white-space: pre-wrap; overflow-wrap: anywhere; }
-.preview-office { width: 100%; height: 100%; overflow: auto; background: #fff; color: #111; }.preview-office :deep(.docx-wrapper) { width: 100%; min-width: 0; box-sizing: border-box; align-items: flex-start; padding: 0; background: #fff; }.preview-office :deep(.docx) { margin: 0 auto; zoom: var(--docx-preview-scale, 1); box-shadow: none; }.preview-office :deep(.docx > article) { padding: 0; }
+.preview-office { width: 100%; height: 100%; overflow: auto; background: #fff; color: #111; }.preview-office :deep(.docx-wrapper) { width: 100%; min-width: 0; box-sizing: border-box; align-items: flex-start; padding: 0; background: #fff; }.preview-office :deep(.docx) { margin: 0 auto; zoom: var(--docx-preview-scale, 1); box-shadow: none; }.preview-office :deep(.docx > article) { box-sizing: border-box; padding: 36px; }
 .preview-pdf { display: flex; width: 100%; height: 100%; box-sizing: border-box; align-items: center; flex-direction: column; gap: 12px; padding: 12px; overflow: auto; background: #dadad7; }.preview-pdf :deep(.pdf-page) { flex: 0 0 auto; overflow: hidden; background: #fff; box-shadow: 0 3px 14px rgba(0,0,0,.15); }.preview-pdf :deep(canvas) { display: block; }
 .preview-sheet { width: 100%; height: 100%; overflow: auto; background: var(--surface-raised); }.preview-sheet table { min-width: 100%; border-collapse: collapse; font-size: 9px; }.preview-sheet td { min-width: 72px; max-width: 240px; padding: 6px 8px; overflow: hidden; border: 1px solid var(--line); color: var(--text-secondary); text-overflow: ellipsis; white-space: nowrap; }.preview-sheet tr:first-child td { position: sticky; top: 0; background: var(--surface-soft); color: var(--text-primary); font-weight: 600; }
 .preview-link { display: flex; width: calc(100% - 34px); flex-direction: column; align-items: center; color: var(--text-secondary); text-decoration: none; text-align: center; }.preview-link > span, .preview-unavailable > span { display: grid; place-items: center; width: 52px; height: 52px; margin-bottom: 12px; border: 1px solid var(--line); border-radius: 16px; background: var(--surface-raised); }.preview-link strong { max-width: 100%; overflow: hidden; color: var(--text-primary); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }.preview-link small { margin-top: 5px; color: var(--text-muted); font-size: 9px; }

+ 4 - 4
tests/e2e/workspace.spec.ts

@@ -158,7 +158,7 @@ test('previews an octet-stream Markdown file from the file library', async ({ pa
   await expect(emptyDialog.locator('.preview-unavailable')).toHaveCount(0)
 })
 
-test('keeps DOCX content at zero inset without horizontal clipping', async ({ page }) => {
+test('keeps DOCX body at 36px inset with zero canvas margin', async ({ page }) => {
   await page.setViewportSize({ width: 620, height: 760 })
   await page.route('**/api/app/files**', async route => {
     const url = new URL(route.request().url())
@@ -234,9 +234,9 @@ test('keeps DOCX content at zero inset without horizontal clipping', async ({ pa
   expect(geometry.pageLeft).toBeGreaterThanOrEqual(geometry.officeLeft)
   expect(geometry.scrollWidth).toBeLessThanOrEqual(geometry.clientWidth + 1)
   expect(Math.abs(geometry.wrapperWidth - geometry.clientWidth)).toBeLessThan(1)
-  expect(geometry.articlePaddingTop).toBe(0)
-  expect(geometry.articlePaddingLeft).toBe(0)
-  expect(geometry.articlePaddingRight).toBe(0)
+  expect(geometry.articlePaddingTop).toBe(36)
+  expect(geometry.articlePaddingLeft).toBe(36)
+  expect(geometry.articlePaddingRight).toBe(36)
   expect(geometry.tableLeft).toBeGreaterThanOrEqual(geometry.pageLeft - 1)
   expect(geometry.tableRight).toBeLessThanOrEqual(geometry.pageLeft + geometry.pageWidth + 1)
   expect(geometry.officeBackground).toBe('rgb(255, 255, 255)')