Created
December 3, 2025 06:30
-
-
Save Cozy228/2bb12c527e61c5344d864e2ade968f3d to your computer and use it in GitHub Desktop.
prompt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 你现在是一个前端/React/TypeScript 代码改造助手,目标很明确: | |
| 把“纯 `<pre>` 渲染的 ASCII 文本面板”改造成: | |
| 1)支持带颜色的数值变量, | |
| 2)仍然完全不破坏 ASCII 布局(边框不位移、对齐不乱), | |
| 3)数据和模板分离。 | |
| 请严格按下面步骤和约束修改代码。 | |
| -------------------- | |
| 【整体目标】 | |
| -------------------- | |
| - 现状:代码里用 `<pre>{ascii}</pre>` 直接渲染一整段 ASCII 字符串,其中包含边框、标签和“写死的数字”。 | |
| - 目标: | |
| 1. 把 ASCII 中的动态数值抽出来,变成 “模板 + 数据” 的形式; | |
| 2. 渲染时,模板中数值位置输出**固定宽度**的字符串,保证每一行长度恒定,ASCII 边框永远不会被撑歪; | |
| 3. 再把最终 ASCII 字符串拆成 `<span>` 网格,给数值字符上不同颜色,但不改变任何字符的位置。 | |
| -------------------- | |
| 【第 1 步:从纯 ASCII 变成“模板 + 数据”】 | |
| -------------------- | |
| 1. 找到当前类似下面的写法(示例): | |
| ```tsx | |
| const ascii = ` | |
| +--------------+ | |
| | CPU: 37 % | | |
| | MEM: 68 % | | |
| | RPS: 1024 | | |
| +--------------+ | |
| `.trimEnd() | |
| 2. 把“会变化的数字”改成占位符,采用如下语法: | |
| • [KEY:宽度] | |
| • KEY:数据字段名(大写字母/数字/下划线,方便正则解析,例如 CPU、MEM、RPS) | |
| • 宽度:这个位置允许显示的字符数,用于对齐,例如 CPU 是 3 位宽度,就写 :3 | |
| 示例改造: | |
| const template = ` | |
| +--------------+ | |
| | CPU: [CPU:3] %| | |
| | MEM: [MEM:3] %| | |
| | RPS: [RPS:5] | | |
| +--------------+ | |
| `.trimEnd() | |
| 3. 把真实数值放到一个 JS 对象里,不要写在模板里: | |
| const data = { | |
| CPU: 37, | |
| MEM: 68, | |
| RPS: 1024, | |
| } | |
| ⸻ | |
| 【第 2 步:实现 renderAscii(template, data) —— 固定宽度字符串】 | |
| 实现一个函数:输入模板字符串 + 数据对象,输出最终的纯 ASCII 字符串。核心要求:模板中的每一个 [KEY:宽度] 均被替换为 长度恰好等于 宽度 的字符串。 | |
| 规则: | |
| • 将 value 转为字符串; | |
| • 如果长度大于 宽度,只保留右边 宽度 位(slice(-width)),避免撑破; | |
| • 如果长度小于 宽度,用空格在左侧 padStart 填充到指定宽度; | |
| • 最终输出的字符串长度必须始终等于 宽度。 | |
| 示例实现(TypeScript/JS): | |
| function formatSlot(value: unknown, width: number) { | |
| const raw = String(value ?? '') | |
| const clipped = raw.slice(-width) // 只保留右侧 width 个字符 | |
| const padded = clipped.padStart(width, ' ')// 左侧填充空格 | |
| return padded | |
| } | |
| function renderAscii(template: string, data: Record<string, unknown>): string { | |
| return template.replace( | |
| /$begin:math:display$\(\[A\-Z0\-9\_\]\+\)\:\(\\d\+\)$end:math:display$/g, | |
| (_, key, widthStr) => { | |
| const width = parseInt(widthStr, 10) | |
| return formatSlot(data[key], width) | |
| }, | |
| ) | |
| } | |
| 使用方式: | |
| const ascii = renderAscii(template, data) | |
| 此时 ascii 是一个纯字符串,复制出来在任何等宽字体下都应保持完美对齐,边框不会错位。 | |
| ⸻ | |
| 【第 3 步:ColorAscii 组件——拆成字符网格,用 span 上色】 | |
| 现在要做的是:在不改变 ASCII 布局的前提下,对某些数字或位置进行着色。 | |
| 要求: | |
| • 保留 <pre> 或 white-space: pre,保证换行与空格原样输出; | |
| • 使用等宽字体(如 font-mono); | |
| • 将 ascii 拆分为「行数组 → 字符数组」; | |
| • 每个字符用 <span> 包裹,便于添加 className 来控制颜色; | |
| • 空格字符用 '\u00A0'(不换行空格)输出,防止因 HTML 的空格折叠导致视觉错位; | |
| • 推荐让 <span> display: inline-block,方便后续扩展(hover、tooltip 等)且更稳定。 | |
| 示例组件: | |
| type HighlightRule = (params: { | |
| ch: string | |
| x: number | |
| y: number | |
| }) => string | undefined // 返回 className | |
| function ColorAscii({ | |
| ascii, | |
| highlight, | |
| }: { | |
| ascii: string | |
| highlight?: HighlightRule | |
| }) { | |
| const lines = ascii.split('\n') | |
| return ( | |
| <pre className="font-mono whitespace-pre leading-none"> | |
| {lines.map((line, y) => ( | |
| <React.Fragment key={y}> | |
| {line.split('').map((ch, x) => { | |
| const cls = highlight?.({ ch, x, y }) | |
| return ( | |
| <span | |
| key={x} | |
| className={cls} | |
| style={{ display: 'inline-block' }} | |
| > | |
| {ch === ' ' ? '\u00A0' : ch} | |
| </span> | |
| ) | |
| })} | |
| {y < lines.length - 1 ? '\n' : null} | |
| </React.Fragment> | |
| ))} | |
| </pre> | |
| ) | |
| } | |
| 使用示例:根据字符是否是数字 + 数值大小上色(只是示例,实际逻辑可以更复杂,比如根据数据结构映射): | |
| function AsciiPanel() { | |
| const template = /* 如上定义的 template */ | |
| const data = /* 实际数据 */ | |
| const ascii = useMemo( | |
| () => renderAscii(template, data), | |
| [template, data], | |
| ) | |
| return ( | |
| <ColorAscii | |
| ascii={ascii} | |
| highlight={({ ch }) => { | |
| const n = Number(ch) | |
| if (!Number.isNaN(n) && n >= 7) return 'text-red-400' | |
| if (!Number.isNaN(n)) return 'text-sky-400' | |
| return 'text-slate-300' | |
| }} | |
| /> | |
| ) | |
| } | |
| 注意: | |
| • 不要在滚动/动画回调中不断 setState 触发此组件重渲染; | |
| • 动画(包括 GSAP auto scroll)只操作容器元素(例如 <pre> 外层)的 transform,不要让 React 每帧重算 ascii 或重新渲染整棵字符树。 | |
| ⸻ | |
| 【第 4 步:重点约束总结(你在修改代码时务必严格遵守)】 | |
| 1. 所有动态数值必须从 ASCII 字符串中剥离出来,改为 [KEY:宽度] 的模板占位符; | |
| 2. 模板渲染成最终 ASCII 时,每个占位符必须输出固定宽度字符串,超长截断、过短空格填充,行长度不能变化; | |
| 3. <pre> + 等宽字体 + white-space: pre 必须保留,以维持 ASCII 网格结构; | |
| 4. 每个最终字符用 <span> 包裹,空格用 '\u00A0' 输出,可以通过 className 控制颜色,但不能改动字符本身的位置; | |
| 5. 动画层(如 GSAP)只修改 DOM 的 transform 等样式,不通过 React 状态驱动逐帧重渲染; | |
| 6. 改造完成后,复制页面中这块 ASCII 文本到纯文本编辑器(等宽字体)时,边框和对齐必须与改造前一致,仅数值和颜色逻辑发生变化。 | |
| 请在重构代码时完全按照上述步骤和约束进行实现与修改。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment