✨ feat(vscode): 代码阅读预览界面

Vite 加 code-reader.html 第二入口;代码块树(层级竖线、折叠、种类标签配色)、译文 / 源码按词性着色、块内直接编辑(防抖回写整行、Esc 回预览)、翻译下拉、解析失败提示;看板与代码阅读共用带类型的 acquireVsCodeApi 包装和 ErrorBoundary。
This commit is contained in:
cruldra committed 2026-09-24 21:01:34 +08:00
1 parent cab5ac0ebc
commit af56985d9a
16 files changed
+775 -74

No files matched your search

+3 -36
View File
@@ -1,39 +1,6 @@
/**
* Tiny typed bridge over the `acquireVsCodeApi()` postMessage channel.
*
* The webview gets exactly one chance to call `acquireVsCodeApi()` per
* lifetime, so we cache the handle module-side. When running outside the
* VS Code host (e.g. `vite dev`) we fall back to no-op stubs.
*/
/** 看板 webview 与扩展之间的收发。 */
import type { ExtensionToWebview, WebviewToExtension } from './messages'
import { createVsCodeBridge } from './vscodeBridge'
interface VsCodeApi {
postMessage: (msg: WebviewToExtension) => void
getState: <T = unknown>() => T | undefined
setState: <T = unknown>(state: T) => void
}
declare global {
interface Window {
acquireVsCodeApi?: () => VsCodeApi
}
}
const api: VsCodeApi = window.acquireVsCodeApi?.() ?? {
postMessage: () => {},
getState: () => undefined,
setState: () => {},
}
export function postMessage(msg: WebviewToExtension): void {
api.postMessage(msg)
}
export function onMessage(handler: (msg: ExtensionToWebview) => void): () => void {
const listener = (ev: MessageEvent): void => {
handler(ev.data as ExtensionToWebview)
}
window.addEventListener('message', listener)
return () => window.removeEventListener('message', listener)
}
export const { postMessage, onMessage } = createVsCodeBridge<ExtensionToWebview, WebviewToExtension>()
+45
View File
@@ -0,0 +1,45 @@
/**
* 对 `acquireVsCodeApi()` 的一层带类型包装:看板和代码阅读各自用自己的消息类型建一个。
*
* 每个 webview 一生只能调用一次 `acquireVsCodeApi()`,所以每个页面只建一个桥。
* 不在 VS Code 里跑(例如 `vite dev`)时退回空实现。
*/
interface VsCodeApi {
postMessage: (msg: unknown) => void
getState: () => unknown
setState: (state: unknown) => void
}
declare global {
interface Window {
acquireVsCodeApi?: () => VsCodeApi
}
}
export interface VsCodeBridge<In, Out, State> {
postMessage: (msg: Out) => void
onMessage: (handler: (msg: In) => void) => () => void
getState: () => State | undefined
setState: (state: State) => void
}
export function createVsCodeBridge<In, Out, State = never>(): VsCodeBridge<In, Out, State> {
const api: VsCodeApi = window.acquireVsCodeApi?.() ?? {
postMessage: () => {},
getState: () => undefined,
setState: () => {},
}
return {
postMessage: msg => api.postMessage(msg),
onMessage: (handler) => {
const listener = (ev: MessageEvent): void => {
handler(ev.data as In)
}
window.addEventListener('message', listener)
return () => window.removeEventListener('message', listener)
},
getState: () => api.getState() as State | undefined,
setState: state => api.setState(state),
}
}