94 lines
4.0 KiB
TypeScript
94 lines
4.0 KiB
TypeScript
import type { ReactElement } from 'react'
|
|
import { Eye, GitBranch, MessageSquareText, Pencil, Sparkles } from 'lucide-react'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
/**
|
|
* 「重写注释」按钮的样子和动作:fresh 是块还没有注释、点了新写一段;正在重写时不能再点;
|
|
* reopen 是重写过、下面的重写记录收着,点了先展开它(好接着说),不重写。
|
|
*/
|
|
export interface RewriteTool {
|
|
fresh: boolean
|
|
rewriting: boolean
|
|
reopen: boolean
|
|
onRewrite: () => void
|
|
}
|
|
|
|
/**
|
|
* 块右上角的一排图标按钮(普通块、属性表、库规则的卡片共用):只放图标,名字写在悬停提示(data-tooltip)和读屏用的 aria-label 里。
|
|
* 「按注释规范重写」:用写注释的技能重写这块代码的注释并写回文件,块还没有注释时叫「按注释规范写注释」、新写一段;正在重写时不能再点。
|
|
* 重写过、记录收着时叫「展开重写记录」,点了只展开。图标是注释。
|
|
* 「问 AI」:点开 / 收起块下面的问答区,展开时带按下的底色。
|
|
* 「编辑 / 预览」切换:预览时是铅笔「编辑」,编辑时是眼睛「预览」、带按下的底色。
|
|
*/
|
|
export function BlockTools({ editing, onToggleEdit, asking, onToggleAsk, rewrite, callTree }: {
|
|
editing: boolean
|
|
onToggleEdit: () => void
|
|
/** 块下面的问答区展开着 */
|
|
asking?: boolean
|
|
/** 没给就不显示「问 AI」(问答没地方存) */
|
|
onToggleAsk?: () => void
|
|
/** 没给就不显示「按注释规范重写」(不能写注释的块、工作区外的库文件) */
|
|
rewrite?: RewriteTool
|
|
/** 没给就不显示调用树。count 是后台数出的棵数,大于 0 时按钮上带这个数字,是 0 时只有图标(还没数到、没有调用者,点开时会当场再问) */
|
|
callTree?: { anchor: string, count: number, open: boolean, onOpen: () => void }
|
|
}): ReactElement {
|
|
const label = editing ? '预览' : '编辑'
|
|
const Icon = editing ? Eye : Pencil
|
|
const rewriteLabel = rewrite?.reopen ? '展开重写记录' : rewrite?.fresh ? '按注释规范写注释' : '按注释规范重写'
|
|
return (
|
|
<div className="flex h-5 shrink-0 items-center gap-0.5" role="group" aria-label="块操作">
|
|
{rewrite && (
|
|
<button
|
|
type="button"
|
|
className="cr-tool flex h-5 w-6 items-center justify-center rounded"
|
|
data-tooltip={rewriteLabel}
|
|
aria-label={rewriteLabel}
|
|
aria-busy={rewrite.rewriting}
|
|
disabled={rewrite.rewriting}
|
|
onClick={rewrite.onRewrite}
|
|
>
|
|
<MessageSquareText size={14} strokeWidth={1.8} aria-hidden />
|
|
</button>
|
|
)}
|
|
{onToggleAsk && (
|
|
<button
|
|
type="button"
|
|
className="cr-tool flex h-5 w-6 items-center justify-center rounded"
|
|
data-active={asking ? '' : undefined}
|
|
data-tooltip="问 AI"
|
|
aria-label="问 AI"
|
|
aria-expanded={asking === true}
|
|
onClick={onToggleAsk}
|
|
>
|
|
<Sparkles size={14} strokeWidth={1.8} aria-hidden />
|
|
</button>
|
|
)}
|
|
<button
|
|
type="button"
|
|
className="cr-tool flex h-5 w-6 items-center justify-center rounded"
|
|
data-active={editing ? '' : undefined}
|
|
data-tooltip={label}
|
|
aria-label={label}
|
|
onClick={onToggleEdit}
|
|
>
|
|
<Icon size={14} strokeWidth={1.8} aria-hidden />
|
|
</button>
|
|
{callTree && (
|
|
<button
|
|
type="button"
|
|
className={cn('cr-tool flex h-5 items-center justify-center rounded', callTree.count > 0 ? 'gap-px px-1' : 'w-6')}
|
|
data-call-tree={callTree.anchor}
|
|
data-active={callTree.open ? '' : undefined}
|
|
data-tooltip="调用树"
|
|
aria-label="调用树"
|
|
aria-expanded={callTree.open}
|
|
onClick={callTree.onOpen}
|
|
>
|
|
<GitBranch size={14} strokeWidth={1.8} aria-hidden />
|
|
{callTree.count > 0 && <span className="cr-call-count">{callTree.count}</span>}
|
|
</button>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|