✨ feat(vscode): 代码阅读函数、导入、常量、变量块预览改成属性表

This commit is contained in:
cruldra committed 2026-09-25 04:56:22 +08:00
1 parent 0c4c9b0fba
commit dd9b39ac5d
19 files changed
+1458 -213

No files matched your search

+14 -6
View File
@@ -4,6 +4,7 @@ import { ChevronDown, ChevronRight, Eye, Pencil } from 'lucide-react'
import { Fragment } from 'react'
import { cn } from '@/lib/utils'
import { CodeEditor } from './CodeEditor'
import { PropertyGrid } from './PropertyGrid'
import { SegmentText } from './SegmentText'
const KIND_LABEL: Record<BlockKind, string> = {
@@ -60,7 +61,18 @@ export function BlockLevel({ blocks, kind, tree }: { blocks: BlockView[], kind?:
)
}
/** 一块:折叠箭头、种类标签、译文或源码、右边的「编辑 / 预览」切换。 */
/** 预览状态的内容:函数、导入、常量、变量块是属性表,其余是一行译文。 */
function BlockPreview({ block }: { block: BlockView }): ReactElement {
if ('properties' in block)
return <PropertyGrid rows={block.properties} />
return (
<p className="cr-code">
<SegmentText segments={block.translation} />
</p>
)
}
/** 一块:折叠箭头、种类标签、预览内容或源码、右边的「编辑 / 预览」切换。 */
function BlockCard({ block, tree }: { block: BlockView, tree: BlockTreeState }): ReactElement {
const editing = tree.editing.has(block.id)
const collapsed = tree.collapsed.has(block.id)
@@ -100,11 +112,7 @@ function BlockCard({ block, tree }: { block: BlockView, tree: BlockTreeState }):
onExit={() => tree.onToggleEdit(block.id)}
/>
)
: (
<p className="cr-code">
<SegmentText segments={block.translation} />
</p>
)}
: <BlockPreview block={block} />}
</div>
<button
type="button"
@@ -0,0 +1,58 @@
import type { ReactElement } from 'react'
import type { PropertyItem, PropertyRow } from './types'
import { ChevronDown } from 'lucide-react'
import { Fragment } from 'react'
import { SegmentText } from './SegmentText'
/** 子行里除最后一列以外各列的宽度(参数的名称、类型),最后一列占满剩下的;编辑区窄时按比例收,不把最后一列挤没 */
const CELL_WIDTHS = ['min(150px, 28%)', 'min(220px, 38%)']
function columns(count: number): string {
const fixed = Array.from({ length: count - 1 }, (_, i) => CELL_WIDTHS[i] ?? CELL_WIDTHS[CELL_WIDTHS.length - 1])
return [...fixed, 'minmax(0, 1fr)'].join(' ')
}
/** 展开在一行下面的子行:左边一条竖线,每个子行几列对齐。 */
function PropertyItems({ items }: { items: PropertyItem[] }): ReactElement {
return (
<div className="flex gap-2.5 pl-[5px]">
<div className="cr-guide w-px shrink-0" />
<div className="flex min-w-0 flex-1 flex-col gap-0.5">
{items.map((item, index) => (
<div key={index} className="grid gap-x-3" style={{ gridTemplateColumns: columns(item.cells.length) }}>
{item.cells.map((cell, i) => (
<p key={i} className="cr-code min-w-0">
<SegmentText segments={cell} />
</p>
))}
</div>
))}
</div>
</div>
)
}
/** 函数、导入、常量、变量块的预览:属性名一列对齐,值按词性着色;输入参数、导入项下面展开子行。 */
export function PropertyGrid({ rows }: { rows: PropertyRow[] }): ReactElement {
return (
<div className="flex flex-col gap-[3px]">
{rows.map((row, index) => {
const items = row.items ?? []
return (
<Fragment key={index}>
<div className="flex gap-3">
<span className="cr-prop-label flex h-5 w-[76px] shrink-0 items-center gap-1">
{items.length > 0 && <ChevronDown size={12} strokeWidth={1.8} className="shrink-0" />}
{row.label}
</span>
<p className="cr-code min-w-0 flex-1">
<SegmentText segments={row.value} />
</p>
</div>
{items.length > 0 && <PropertyItems items={items} />}
</Fragment>
)
})}
</div>
)
}
@@ -132,6 +132,15 @@ body.vscode-high-contrast-light {
.cr-role-number,
.cr-role-literal { color: var(--cr-number); }
.cr-role-comment { color: var(--cr-comment); }
.cr-role-hint { color: var(--vscode-descriptionForeground); }
/* 属性表的属性名:界面字体,和值一样的行高,两边逐行对齐 */
.cr-prop-label {
font-size: 12.5px;
line-height: 20px;
color: var(--vscode-descriptionForeground);
white-space: nowrap;
}
/* 编辑:透明输入框垫在底下接收输入和选区,着色层盖在上面只负责显示,高度由着色层撑开 */
.cr-editor {
+16 -3
View File
@@ -10,12 +10,23 @@ export type BlockKind
export type TokenRole
= | 'keyword' // 流程关键字:import from export if else for return try catch await …
| 'storage' // 声明关键字与字面量关键字:const function async class interface new true false null …
| 'operator' // 被翻成文字的运算符:全等 与 或 非
| 'operator' // 被翻成文字的运算符:全等 并且 或者 非
| 'hint' // 属性表里的说明词:未标注 无 N 个 默认导出 …
| 'variable' | 'function' | 'type' | 'string' | 'number' | 'literal' | 'comment' | 'plain'
export interface Segment { text: string, role: TokenRole }
export interface BlockView {
/** 属性表里展开的一个子行:几列对齐的格子,例如参数的名称 / 类型 / 默认值 */
export interface PropertyItem { cells: Segment[][] }
/** 属性表的一行:左列属性名,右列着色的值;items 是展开在这一行下面的子行(输入参数、导入项) */
export interface PropertyRow {
label: string
value: Segment[]
items?: PropertyItem[]
}
interface BlockViewBase {
/** 在树里的位置,例如 '6.1.0' */
id: string
kind: BlockKind
@@ -26,10 +37,12 @@ export interface BlockView {
code: string
/** 源码着色(拼起来等于 code) */
codeTokens: Segment[]
translation: Segment[]
children: BlockView[]
}
/** 函数、导入、常量、变量块预览时是属性表,其余是一行译文 */
export type BlockView = BlockViewBase & ({ translation: Segment[] } | { properties: PropertyRow[] })
export interface TranslatorOption { id: string, label: string }
export interface DocumentMessage {