ac1f92d816
refactor(core): 迁移 post-content 到 yggdrasil-core,删除 public/js
...
逐行 TypeScript 化(逻辑不变),改走 window.__initPostContent 全局入口。
post-content.js 已迁移进 libs/yggdrasil-core/,public/js/ 目录随之删除。
2026-06-26 13:57:48 +08:00
afabdf4655
chore(core): 搭建 yggdrasil-core 子工程骨架
...
照搬 lightbox 的 Vite IIFE 工程结构,作为核心 JS 统一归处。
此 commit 仅打通构建管线,业务逻辑后续 task 填入。
同时把 public/yggdrasil-core 加入根 .gitignore。
2026-06-26 13:51:39 +08:00
2f861d3e6a
chore(lightbox): update package-lock.json
CI / check (push) Failing after 5m8s
CI / build (push) Has been skipped
2026-06-24 15:57:47 +08:00
25eacc1c3c
refactor(lightbox): modernize to const/let, template literals, drop IIFE
...
纯现代化重构,行为不变(23 个回归测试全绿作证):
- var → const/let(state、gotoIndex 的 newIndex 用 let,其余 const)
- 循环 for+var+IIFE包装 → for..of/forEach + const(天然捕获迭代变量,
消除旧 var 循环闭包必须立即执行函数固定变量的写法)
- 字符串拼接 → 模板字面量(counter 文本、transform、width/height)
- 事件处理 function() → 箭头函数(无 this 依赖场景)
- 拆掉外层 (function(){'use strict'; ... })():ES module 作用域已封装,
IIFE 是历史遗留;辅助函数仍用 function 声明(openLightbox↔closeLightbox
互递归依赖提升)
几何纯函数(fitCentered/transformFor/originalUrl)已在 geometry.ts,
本文件只剩 DOM 胶水 + state 单例。
2026-06-24 11:44:06 +08:00
aadfed2595
test(lightbox): add happy-dom behavior regression tests for refactor
...
为现代化重构(var→const、拆 IIFE、for→for..of)补行为回归防线。
黑盒驱动 window.__initLightbox,覆盖高风险路径:
- 循环闭包捕获 idx(点第 1/2/3 张 counter 显示正确序号)
- 点击打开(overlay 创建、origSrc 去 query、caption、单张 counter 隐藏)
- 关闭(Esc / 点背景;点图片本身不关)
- 图集 gotoIndex 循环边界(首末衔接 + originNode 更新后焦点归还)
- 单张图不参与切换
happy-dom 20.10.6 作 devDep,vitest 默认环境改 happy-dom;
geometry.test.ts 用 // @vitest-environment node 指令保持纯函数在 node 跑。
23 tests (12 geometry + 11 behavior) 全绿。
2026-06-24 11:40:36 +08:00
507d271a2b
fix(lightbox): prevent page scroll on close via focus({ preventScroll: true })
...
关闭灯箱时 removeOverlay() 调用 .focus() 归还焦点给原图,浏览器的 focus()
默认会 scrollIntoView,导致页面自动滚动把原图完整纳入视口。用户向下滚动后
只点露出的下半截图、再 Esc 关闭时,页面会向上跳到整图可见——非预期行为。
focus({ preventScroll: true }) 抑制该滚动(Chrome68+/FF68+/Safari15.4+ 支持),
焦点归还的无障碍语义不变。
2026-06-24 11:27:15 +08:00
b4ef906141
refactor(lightbox): move .lightbox-* CSS into lightbox project, wire import
2026-06-24 11:02:44 +08:00
5f57d375ea
feat(lightbox): migrate DOM logic to TypeScript index.ts with self-start contract
2026-06-24 10:57:23 +08:00
44fc641aaa
feat(lightbox): extract geometry pure fns with vitest coverage
2026-06-24 10:52:48 +08:00
c5af4457e2
feat(lightbox): scaffold libs/lightbox TS project (vite + tsc + vitest)
2026-06-24 10:49:58 +08:00
fb31ecb5ae
fix(tiptap): expose EditorOptions as runtime class for wasm-bindgen
...
EditorOptions was a TS interface (erased at runtime), but the Rust
wasm-bindgen extern uses #[wasm_bindgen(constructor)] which generates
'new EditorOptions()' — requiring a global constructor.
Vite 5/Rollup accidentally leaked the name into IIFE global scope,
masking this. Vite 8/Rolldown strictly erases interfaces, exposing it
as 'EditorOptions is not defined'.
Fix: make EditorOptions a class (retains runtime constructor) and mount
it on window, since the IIFE bundle name is taken by TiptapEditor.
2026-06-24 10:27:07 +08:00
08c2539dfc
test(tiptap): add isValidUrl tests covering scheme validation edge cases
2026-06-24 10:10:39 +08:00
90cff2d0cc
test(tiptap): add UploadImageNodeView tests for rendering/update/callbacks/destroy
2026-06-24 10:09:36 +08:00
f7042d3ab4
test(tiptap): add UploadCoordinator tests for counts/lifecycle/emit/idempotency
2026-06-24 10:07:43 +08:00
8ff051689f
refactor(tiptap): export isValidUrl and UploadImageNodeView for testability
2026-06-24 10:04:59 +08:00
19532670d3
build(tiptap): add vitest config with happy-dom environment
2026-06-24 10:04:23 +08:00
21c0359f5e
build(tiptap): upgrade to vite 8/vitest 4/typescript 6/tiptap 3.27, migrate to rolldownOptions
2026-06-24 10:03:47 +08:00
939e0de171
build(tiptap): run tsc --noEmit before vite build
2026-06-23 18:45:17 +08:00
6ffcd55c94
fix(tiptap): correct link command order + validate URL scheme in slash commands
2026-06-23 18:42:57 +08:00
e580c3ab18
refactor(tiptap): narrow updateNodeAttrs type, extract findImageNodeByUploadId helper
2026-06-23 18:42:05 +08:00
d099db4140
refactor(tiptap): move coordinator to editor.storage, drop dead Markdown html option
2026-06-23 18:39:38 +08:00
6b44a9c036
fix(tiptap): clean up pending upload on NodeView.destroy to prevent blob leak
2026-06-23 18:36:47 +08:00
2e239908a4
fix(tiptap): revoke blob on node destroy + maintain upload counts internally
2026-06-23 18:36:07 +08:00
71df6abe5d
refactor(tiptap): drop redundant single-arg mergeAttributes call
2026-06-23 18:35:05 +08:00
18ae6a915e
refactor(tiptap): type coordinatorRef via Pick<UploadCoordinator> instead of duck typing
2026-06-23 18:34:37 +08:00
558191e922
refactor(tiptap): type CommandItem.editor as Editor, explicit SlashPopup return type
2026-06-23 18:33:59 +08:00
073f6936e3
build(tiptap): add tsconfig + typecheck script
2026-06-23 18:32:26 +08:00
a3896c24a5
refactor(write): replace all js_sys::eval with tiptap_bridge bindings
...
write.rs changes (Tasks 7-11):
- use_drop: EditorHandle::drop replaces eval destroy + global reset (#1 )
- init use_effect: closure-driven bridge.create replaces eval initEditor
script + 100ms ready polling (#2/#3/#4/#5)
- getMarkdown: read via EditorHandle instead of eval (#8 )
- delete upload polling use_future: driven by onUploadEvent closure (#6/#7)
- removeUploadByUploadId: call via EditorHandle instead of eval (#9 )
Bridge fixes during integration:
- UploadCountsJs: drop Copy derive (wasm_bindgen types can't be Copy)
- split module: shared types compile on both targets, wasm externs gated
- add WritableExt/Readable/Writable trait imports for .write()/.set()
- use FnMut closures (Signal write/set take &mut self)
- consume_upload_event takes &mut Signal params
Also: remove stale window.__tiptap_content in index.ts source-mode handler.
2026-06-23 11:25:06 +08:00
92cfda7d5a
refactor(tiptap): EditorOptions onReady/onUploadEvent callbacks replace polling
2026-06-23 10:52:30 +08:00
b09216ef29
refactor(tiptap): UploadCoordinator emit callback replaces window global
2026-06-23 10:52:20 +08:00
876cb55e91
style(editor): smooth blur/grayscale transition on placeholder image
...
给 img 加 transition: filter 0.2s ease,blur 出现和消失(上传中→成功/
失败)平滑过渡,而非瞬间切换。transition 写在基础 img 规则上,
确保 is-uploading class 移除时过渡也能触发。
2026-06-22 16:27:02 +08:00
6e04940edc
style(editor): blur uploading placeholder image, keep overlay text sharp
...
上传中占位符图片加高斯模糊,遮罩文字保持清晰。
- .is-uploading img 加 filter: blur(8px)
- container.is-uploading 加 overflow: hidden 防止 blur 边缘渗出
- overlay 文字(spinner/"上传中…")不受影响:overlay 是 img 的兄弟元素
而非后代,CSS filter 只作用于目标元素本身,不波及兄弟
2026-06-22 16:24:02 +08:00
cee4f3f3ef
fix(upload): address code review findings
...
final code review 后的修复:
1. blob 检查收紧(Important): md.contains("blob:") 误伤合法讨论 blob URL
的代码块/正文,改为检测 markdown 图片语法 ](blob: 才算占位符泄漏
2. 重试错误原地更新(Minor): seen_error_ids 去重逻辑导致重试后再失败时
顶部提示停留在旧错误文案;改为已存在 id 时原地更新 message
3. destroy 清理 coordinatorRef(Minor): destroy() 调 setUploadCoordinator(null),
避免 NodeView 指向已销毁的 coordinator(防御性)
4. 删除 NodeView 未用的 editor 字段(Nit): 死代码清理
验证: cargo test (384 passed) / clippy (本次零警告) / dx check / tiptap build 全过
2026-06-22 15:49:23 +08:00
8ffb4451b1
style(editor): add upload placeholder NodeView styles (overlay/spinner/error)
2026-06-22 15:32:32 +08:00
34c8b47436
feat(editor): route slash-command image upload through coordinator
...
- slash-command.ts: SlashCommandOptions 加 onInsertUploading option
- slash-command.ts: 上传图片命令优先走 onInsertUploading(coordinator 占位符+上传),
退回 uploadFn 直接上传(无占位符)
- index.ts: SlashCommand.configure 注入 onInsertUploading,
闭包延迟读取 this.coordinator(在 editor 创建后才实例化)
2026-06-22 15:30:39 +08:00
5d527778a5
feat(editor): wire UploadCoordinator and custom Image in TiptapEditorInstance
...
- index.ts: 替换 Image.configure 为 UploadImage(自定义扩展+NodeView)
- index.ts: editor 创建后实例化 UploadCoordinator 并注入 NodeView
- index.ts: FileHandler onPaste/onDrop 改走 coordinator.insertUploading
- index.ts: 暴露 removeUploadByUploadId 供 Rust ×关闭调用
- index.ts: destroy 清理 coordinator
- upload-image.ts: 修正 import 来源(Image 来自 extension-image, mergeAttributes 来自 core)
2026-06-22 15:28:40 +08:00
57bea05aa3
feat(editor): add custom Image extension with upload-state NodeView
2026-06-22 15:25:25 +08:00
8ce9c58997
feat(editor): maintain window.__tiptap_uploads for Rust polling
2026-06-22 15:24:37 +08:00
6506931c1d
feat(editor): add runUpload and retryUpload to UploadCoordinator
2026-06-22 15:23:57 +08:00
e06667f792
feat(editor): add UploadCoordinator skeleton with pending map and node removal
2026-06-22 15:22:42 +08:00
6ff37322b2
feat(editor): add image upload to slash command and build tiptap in make dev
...
斜杠命令图片上传 + Makefile dev 构建修复
1. 斜杠命令接入图片上传管线
- slash-command.ts: SlashCommand 扩展改为 Extension.create<Options>,
新增 onImageUpload 选项;原单一"图片"命令拆成两个:
· "上传图片"(📤 ): 仅在 onImageUpload 可用时出现,触发原生文件选择器
(accept 限定 jpeg/png/gif/webp,与 upload 端点 MIME 一致),
上传成功后 setImage 插入,失败 console.error(与 FileHandler 一致)
· "图片链接"(🖼): 保留原 window.prompt URL 方式
- index.ts: SlashCommand.configure({ onImageUpload }) 透传宿主回调,
复用 write.rs 已注入的 /api/upload 管线,无需 Rust 端改动
2. Makefile: make dev 不再忽略 tiptap 构建
- 根因: 原 dev target 只起 tailwindcss watch + dx serve,从不构建
tiptap 编辑器,导致 dev server 始终 serve 上次 make build 残留的
旧 editor.js(本次新增的"上传图片"命令在 dev 下永远不生效)
- 新增 build-editor-incremental target (跳过 npm ci,直接 vite build,~1s)
- dev 现在依赖 build-editor-incremental,启动前先增量构建编辑器
3. Makefile: clean 不再删 public/tiptap
- public/tiptap 是跨子项目(npm)构建产物,删除后必须重跑 make build-editor
(含 npm ci) 才能恢复;原 clean 会删它是陷阱(make clean && make dev
会导致编辑器直接消失)。现在 clean 只清 Rust 产物和缓存
2026-06-22 14:18:05 +08:00
6ce8915e6c
fix(editor): 修复 focus() 把源码视图滚动到底部
...
切换到源码模式时 sourceTextarea.focus() 会触发浏览器将光标
所在行滚动进可视区域,光标默认在内容末尾,导致 textarea 被
拉到底部覆盖已设的滚动位置。改为 focus 后立即恢复 scrollTop。
同时移除调试日志。
2026-06-16 16:13:46 +08:00
ae6d80c9cc
fix(editor): 修复滚动比例同步失效导致切换到底部
...
原 syncScrollRatio 封装在 display:'none' 之后重复读取源容器
scrollTop,此时浏览器已将其归零,导致比例计算为 0。改为提前
读取比例并直接应用,移除二次封装与调试日志。
2026-06-16 15:58:50 +08:00
914f168551
fix(editor): 切换视图时按滚动比例同步位置
...
修复切回富文本时编辑器滚动到底部的问题:移除 commands.focus()
(会强制滚动到光标位置),改用滚动比例跨模式同步,富文本与源码
视图按相同比例定位,保持视觉位置一致。
2026-06-16 15:53:28 +08:00
480aa92bb4
feat(editor): 新增 Markdown 源码视图切换
...
在 Tiptap 编辑器右上角增加 </> 悬浮按钮,支持在富文本与
Markdown 源码视图间双向切换,内容自动同步。getMarkdown() 在
源码模式下返回 textarea 内容,使 Rust 端提交逻辑无需改动。
2026-06-16 15:50:09 +08:00
012704d0a5
chore(tiptap-editor): update package-lock.json
2026-06-08 15:54:27 +08:00
72ba8ea9ec
chore(tiptap-editor): update package-lock.json
2026-06-06 00:29:53 +08:00
078e9b1da1
fix(tiptap-editor): configure link via StarterKit to avoid duplicate extension warning
2026-06-05 18:19:24 +08:00
ad208a4603
fix(tiptap-editor): correct setContent call signature for markdown parsing
2026-06-05 18:05:47 +08:00
26eb62c2ae
fix(upload): disable default body limit and fix error object serialization
2026-06-05 16:52:52 +08:00