Files
multica/packages/views/editor/utils/preprocess.ts
Naiyuan Qing f41a0cf423 feat(views): extract packages/views — shared business UI + navigation adapter
- Create NavigationAdapter interface (push, replace, back, pathname, searchParams)
- Create AppLink component replacing next/link in 4 files
- Replace useRouter → useNavigation in 3 files (issue-detail, create-issue, create-workspace)
- Create WebNavigationProvider wrapping Next.js useRouter/usePathname/useSearchParams
- Move ~85 feature UI files (issues, editor, modals, my-issues, skills, runtimes) to packages/views/
- Add store singleton registration pattern (registerAuthStore, registerWorkspaceStore)
- Create data-aware wrappers in packages/views/common/ (ActorAvatar, Markdown)
- Update all app-layer imports to @multica/views/*
- Add @source directive for Tailwind to scan views package
- packages/views/ has zero next/* imports

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 11:49:55 +08:00

49 lines
1.9 KiB
TypeScript

import { preprocessLinks } from "@multica/ui/markdown";
import { preprocessMentionShortcodes } from "@multica/ui/markdown";
import { isFileCardUrl } from "../extensions/file-card";
/**
* Preprocess a markdown string before loading into Tiptap via contentType: 'markdown'.
*
* This is the ONLY transform applied before @tiptap/markdown parses the content.
* It does NOT convert to HTML — that was the old markdownToHtml.ts pipeline which
* was deleted in the April 2026 refactor.
*
* Three string→string transforms on raw Markdown:
* 1. Legacy mention shortcodes [@ id="..." label="..."] → [@Label](mention://member/id)
* (old serialization format in database, migrated on read)
* 2. Raw URLs → markdown links via linkify-it (so they render as clickable Link nodes)
* 3. CDN file links on their own line → HTML div for fileCard node parsing
*/
export function preprocessMarkdown(markdown: string): string {
if (!markdown) return "";
const step1 = preprocessMentionShortcodes(markdown);
const step2 = preprocessLinks(step1);
const step3 = preprocessFileCards(step2);
return step3;
}
/**
* Convert standalone `[name](cdnUrl)` lines into HTML that Tiptap's fileCard
* parseHTML can recognise. Only matches non-image CDN URLs on their own line.
*
* Input: `[report.pdf](https://multica-static.copilothub.ai/xxx.pdf)`
* Output: `<div data-type="fileCard" data-href="url" data-filename="report.pdf"></div>`
*/
const FILE_LINK_LINE = /^\[([^\]]+)\]\((https?:\/\/[^)]+)\)$/;
function preprocessFileCards(markdown: string): string {
return markdown
.split("\n")
.map((line) => {
const trimmed = line.trim();
const match = trimmed.match(FILE_LINK_LINE);
if (!match) return line;
const filename = match[1]!;
const url = match[2]!;
if (!isFileCardUrl(url)) return line;
return `<div data-type="fileCard" data-href="${url}" data-filename="${filename}"></div>`;
})
.join("\n");
}