瀏覽代碼

style: 对齐夭夭文件库卡片尺寸

samien 2 月之前
父節點
當前提交
c8e89834dc
共有 2 個文件被更改,包括 17 次插入 和 10 次删除
  1. 9 10
      src/client/components/library/LibraryGrid.vue
  2. 8 0
      tests/e2e/workspace.spec.ts

+ 9 - 10
src/client/components/library/LibraryGrid.vue

@@ -60,7 +60,7 @@ function formatDate(value?: string | number | Date) {
         <div class="library-thumb" :class="`library-thumb--${item.kind}`">
           <img v-if="item.kind === 'image' && item.previewUrl" :src="item.previewUrl" :alt="item.name" loading="lazy" />
           <video v-else-if="item.kind === 'video' && item.previewUrl" :src="item.previewUrl" muted preload="metadata" />
-          <span v-else><AppIcon :name="iconFor(item)" :size="26" /><em>{{ item.name.split('.').at(-1)?.slice(0, 5).toUpperCase() }}</em></span>
+          <span v-else><AppIcon :name="iconFor(item)" :size="36" /><em>{{ item.name.split('.').at(-1)?.slice(0, 5).toUpperCase() }} · {{ item.kind }}</em></span>
           <div class="library-thumb__actions">
             <button type="button" title="加入输入框" aria-label="加入输入框" @click.stop="emit('addToComposer', item)"><AppIcon name="plus" :size="14" /></button>
             <button v-if="item.sourceSessionId" type="button" title="查看来源" aria-label="查看来源" @click.stop="emit('source', item)"><AppIcon name="external" :size="14" /></button>
@@ -77,18 +77,17 @@ function formatDate(value?: string | number | Date) {
 </template>
 
 <style scoped>
-.library-scroll { min-height: 0; flex: 1; overflow-y: auto; padding: 22px 24px 40px; }
-.library-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(164px, 1fr)); gap: 20px 14px; }
-article { min-width: 0; border-radius: 12px; cursor: pointer; outline: 0; } article:focus-visible .library-thumb, article.selected .library-thumb { border-color: var(--line-strong); box-shadow: 0 0 0 3px var(--focus-ring); }
-.library-thumb { position: relative; display: grid; aspect-ratio: 1.18; place-items: center; overflow: hidden; border: 1px solid var(--line); border-radius: 12px; background: var(--surface-raised); color: var(--text-muted); transition: border-color 140ms ease, transform 160ms var(--ease-out), box-shadow 140ms ease; }
-article:hover .library-thumb { border-color: var(--line-strong); transform: translateY(-2px); box-shadow: 0 12px 26px rgba(0,0,0,.07); }
+.library-scroll { min-height: 0; flex: 1; overflow-y: auto; padding: 20px clamp(18px, 3vw, 36px) 32px; }
+.library-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px 12px; }
+article { min-width: 0; overflow: hidden; border: 1px solid var(--line); border-radius: 11px; background: var(--surface); cursor: pointer; outline: 0; transition: border-color 140ms ease, box-shadow 140ms ease, transform 140ms ease; } article:focus-visible, article.selected { border-color: var(--line-strong); box-shadow: 0 0 0 2px var(--focus-ring); } article:hover { border-color: var(--line-strong); box-shadow: 0 8px 22px rgba(0,0,0,.07); transform: translateY(-1px); }
+.library-thumb { position: relative; display: grid; height: 154px; place-items: center; overflow: hidden; border: 0; border-bottom: 1px solid var(--line); border-radius: 0; background: var(--surface-soft); color: var(--text-muted); }
 .library-thumb img, .library-thumb video { width: 100%; height: 100%; object-fit: cover; }
-.library-thumb > span { display: flex; flex-direction: column; align-items: center; gap: 9px; }.library-thumb > span em { max-width: 74px; overflow: hidden; color: var(--text-muted); font-size: 8px; font-style: normal; letter-spacing: .1em; text-overflow: ellipsis; }
+.library-thumb > span { display: flex; flex-direction: column; align-items: center; gap: 7px; }.library-thumb > span em { max-width: 150px; overflow: hidden; color: var(--text-muted); font-size: 11px; font-style: normal; letter-spacing: .02em; text-overflow: ellipsis; text-transform: capitalize; }
 .library-thumb--code, .library-thumb--text { background: linear-gradient(135deg, var(--surface-soft), var(--surface-raised)); }.library-thumb--link { border-style: dashed; }
 .library-thumb__actions { position: absolute; top: 6px; right: 6px; display: flex; gap: 4px; opacity: 0; transform: translateY(-3px); transition: opacity 120ms ease, transform 140ms var(--ease-out); }.library-thumb:hover .library-thumb__actions, article:focus-within .library-thumb__actions { opacity: 1; transform: translateY(0); }.library-thumb__actions button { display: grid; place-items: center; width: 28px; height: 28px; padding: 0; border: 1px solid rgba(255,255,255,.32); border-radius: 8px; background: rgba(25,25,24,.72); color: #fff; cursor: pointer; backdrop-filter: blur(8px); }
-.library-copy { padding: 8px 3px 0; }.library-copy strong { display: block; overflow: hidden; font-size: 11px; font-weight: 580; text-overflow: ellipsis; white-space: nowrap; }.library-copy > span { display: flex; margin-top: 4px; justify-content: space-between; gap: 7px; color: var(--text-muted); font-size: 9px; }.library-copy small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }.library-copy time { flex: 0 0 auto; }
+.library-copy { padding: 10px 12px 9px; }.library-copy strong { display: block; overflow: hidden; font-size: 13px; font-weight: 550; text-overflow: ellipsis; white-space: nowrap; }.library-copy > span { display: flex; margin-top: 5px; justify-content: space-between; gap: 8px; color: var(--text-muted); font-size: 11px; line-height: 1.4; }.library-copy small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }.library-copy time { flex: 0 0 auto; }
 .load-more { display: block; margin: 28px auto 0; padding: 7px 12px; border: 1px solid var(--line); border-radius: 9px; background: transparent; color: var(--text-secondary); cursor: pointer; font-size: 10px; }.load-more:hover { background: var(--surface-hover); }
-.library-skeleton { display: grid; grid-template-columns: repeat(auto-fill, minmax(164px, 1fr)); gap: 20px 14px; }.library-skeleton i { aspect-ratio: 1.18; border-radius: 12px; background: linear-gradient(90deg, var(--surface-soft), var(--surface-hover), var(--surface-soft)); background-size: 200% 100%; animation: shimmer 1.5s linear infinite; }
+.library-skeleton { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px 12px; }.library-skeleton i { height: 208px; border-radius: 11px; background: linear-gradient(90deg, var(--surface-soft), var(--surface-hover), var(--surface-soft)); background-size: 200% 100%; animation: shimmer 1.5s linear infinite; }
 @keyframes shimmer { to { background-position: -200% 0; } }
-@media (max-width: 600px) { .library-scroll { padding: 16px 12px 30px; }.library-grid, .library-skeleton { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 10px; }.library-thumb__actions { opacity: 1; transform: none; }.library-copy strong { font-size: 10px; } }
+@media (max-width: 600px) { .library-scroll { padding: 16px 12px 30px; }.library-grid, .library-skeleton { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 9px; }.library-thumb { height: 122px; }.library-thumb__actions { opacity: 1; transform: none; }.library-copy { padding: 8px 9px; }.library-copy strong { font-size: 11px; }.library-copy > span { font-size: 9px; } }
 </style>

+ 8 - 0
tests/e2e/workspace.spec.ts

@@ -30,6 +30,14 @@ test('navigates every 9119 workspace without blank transitions', async ({ page }
   await page.goto('/files')
   await expect(page.getByRole('heading', { name: '文件库', exact: true }).last()).toBeVisible()
   await expect(page.getByText('demo-report.pdf')).toBeVisible()
+  const firstFileCard = page.locator('.library-grid article').first()
+  const cardGeometry = await firstFileCard.evaluate(element => {
+    const card = element.getBoundingClientRect()
+    const preview = element.querySelector('.library-thumb')?.getBoundingClientRect()
+    return { width: card.width, previewHeight: preview?.height || 0 }
+  })
+  expect(cardGeometry.width).toBeGreaterThanOrEqual(220)
+  expect(cardGeometry.previewHeight).toBe(154)
   await page.getByText('demo-report.pdf').click()
   await expect(page.getByRole('dialog', { name: /预览 demo-report.pdf/ })).toBeVisible()
   await expect(page.locator('.preview-meta')).toHaveCount(0)