feat(web): fold the search truncation total into the summary line

Replace the separate '已截断 · 共 N' pill with '显示 X / 共 N 处匹配 · K 个文件'
(and '显示 X / 共 N 个路径' for glob), mirroring the read card's '显示 X / Y 行',
so the retained count and the pre-cap total read as one clause instead of two
numbers that appear to disagree.
This commit is contained in:
Chinesezjc
2026-07-30 18:09:03 +08:00
parent 71adea8ba4
commit 2928c65ccd
3 changed files with 18 additions and 19 deletions

View File

@@ -37,11 +37,6 @@
color: var(--dsw-alias-label-secondary);
}
.truncated {
flex: none;
color: var(--dsw-alias-state-business-primary);
}
.copyButton {
flex: none;
background-color: transparent;

View File

@@ -10,7 +10,6 @@
import { useCallback, useMemo, useState, type ReactNode } from 'react'
import clsx from 'clsx'
import { writeClipboard } from './clipboard.ts'
import { Pill } from './Pill.tsx'
import css from './SearchBlock.module.css'
/**
@@ -109,17 +108,22 @@ function shownCount(props: SearchBlockProps): number {
}
/**
* The banner summary: the structural count of the retained result. The
* truncation pill beside it carries the capped-vs-complete signal, so this
* stays a plain count of what the card holds.
* The banner summary. When the search was capped it reads `显示 X / 共 N …` so
* the retained count and the pre-cap total sit in one clause (mirroring the read
* card's `显示 X / Y 行`); when it was not capped it is a plain count of what the
* card holds. The unit — `处匹配 · K 个文件` for grep, `个路径` for glob — trails
* the count either way.
* @param props - the card's props.
* @param shown - the retained result count from {@link shownCount}.
* @param truncated - whether the search was capped.
* @param total - the pre-cap total the truncation clause reports.
* @returns the summary text.
*/
function summaryText(props: SearchBlockProps, shown: number): string {
function summaryText(props: SearchBlockProps, shown: number, truncated: boolean, total: number): string {
const count = truncated ? `显示 ${shown} / 共 ${total}` : `${shown}`
return props.kind === 'paths'
? `${shown} 个路径`
: `${shown} 处匹配 · ${props.files.length} 个文件`
? `${count} 个路径`
: `${count} 处匹配 · ${props.files.length} 个文件`
}
/**
@@ -227,8 +231,7 @@ export function SearchBlock(props: SearchBlockProps) {
return (
<div className={clsx(css.block, className)} data-search={props.kind}>
<div className={css.header}>
<span className={css.summary}>{summaryText(props, shown)}</span>
{truncated && <Pill className={css.truncated}>{`已截断 · 共 ${total}`}</Pill>}
<span className={css.summary}>{summaryText(props, shown, truncated, total)}</span>
{!empty && (
<button type="button" className={css.copyButton} onClick={onCopy}>
{copied ? '复制成功' : '复制'}

View File

@@ -61,10 +61,10 @@ describe('SearchBlock matches kind', () => {
expect(lines(view.container)).toEqual(['1: x', '2: y'])
})
it('shows the truncation pill with the pre-cap total', () => {
it('folds the pre-cap total into the summary when truncated', () => {
const view = render(<SearchBlock kind="matches" truncated total={99} files={[group('a.ts', 2)]} />)
expect(view.getByText('已截断 · 共 99')).toBeTruthy()
expect(view.getByText('2 处匹配 · 1 个文件')).toBeTruthy()
expect(view.getByText('显示 2 / 共 99 处匹配 · 1 个文件')).toBeTruthy()
expect(view.queryByText(//u)).toBeNull()
})
})
@@ -77,9 +77,10 @@ describe('SearchBlock paths kind', () => {
expect(fileHeaders(view.container)).toEqual([])
})
it('shows the truncation pill with the pre-cap total', () => {
it('folds the pre-cap total into the paths summary when truncated', () => {
const view = render(<SearchBlock kind="paths" truncated total={50} paths={['a', 'b']} />)
expect(view.getByText('已截断 · 共 50')).toBeTruthy()
expect(view.getByText('显示 2 / 共 50 个路径')).toBeTruthy()
expect(view.queryByText(//u)).toBeNull()
})
})