feat: pass source path to markdown parser for icon resolution
Pass the file's base path through the markdown parsing pipeline to allow the icon directive to resolve relative asset paths correctly using an absolute fallback chain.
This commit is contained in:
parent
2dba19e1f8
commit
6ab6b76978
|
|
@ -135,7 +135,7 @@ export const Article: Component<ArticleProps & ParentProps> = (props) => {
|
|||
<div
|
||||
class="relative"
|
||||
ref={setContentDom}
|
||||
innerHTML={parseMarkdown(content()!)}
|
||||
innerHTML={parseMarkdown(content()!, props.src)}
|
||||
/>
|
||||
{props.children}
|
||||
</ArticleDomCtx.Provider>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export function CardLayer(props: CardLayerProps) {
|
|||
function renderLayerContent(content: string) {
|
||||
return parseMarkdown(
|
||||
processVariables(content, props.cardData, props.store.state.cards),
|
||||
props.store.state.cards.sourcePath,
|
||||
) as string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,10 @@ customElement("md-embed", { headingBase: 0 }, (props, { element }) => {
|
|||
</Show>
|
||||
<Show when={!content.loading && !content.error && content()}>
|
||||
{/* biome-ignore lint/security/noDangerouslySetInnerHtml: markdown render */}
|
||||
<div class="prose" innerHTML={parseMarkdown(content()!)} />
|
||||
<div
|
||||
class="prose"
|
||||
innerHTML={parseMarkdown(content()!, resolvedPath)}
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,25 +1,41 @@
|
|||
/**
|
||||
* marked-directive 扩展:支持 :[icon] 和 :[icon.ext] 行内图标语法
|
||||
*
|
||||
* 生成的 CSS 包含从当前目录向上查找的 fallback 链:
|
||||
* url('./assets/icon.png'),
|
||||
* url('../assets/icon.png'),
|
||||
* url('../../assets/icon.png'),
|
||||
* ...
|
||||
* 生成的 CSS 包含从文件所在目录向上查找的 fallback 链:
|
||||
* url('/pages/sub/deep/assets/icon.png'),
|
||||
* url('/pages/sub/assets/icon.png'),
|
||||
* url('/pages/assets/icon.png'),
|
||||
* url('/assets/icon.png')
|
||||
*
|
||||
* 支持的扩展名:.svg, .png, .gif, .jpg, .jpeg, .webp(默认 .png)
|
||||
*/
|
||||
|
||||
const SUPPORTED_EXTENSIONS = ["svg", "png", "gif", "jpg", "jpeg", "webp"];
|
||||
|
||||
/** 生成多层 fallback 路径,向上查找最多 10 级 */
|
||||
function buildIconSrc(iconName: string, extension: string): string {
|
||||
const levels = 10;
|
||||
const urls: string[] = [];
|
||||
for (let i = 0; i < levels; i++) {
|
||||
const prefix = i === 0 ? "./" : "../".repeat(i);
|
||||
urls.push(`url('${prefix}assets/${iconName}.${extension}')`);
|
||||
let globalBasePath: string | undefined;
|
||||
|
||||
/** 设置当前 markdown 文件路径,用于解析 ./assets */
|
||||
export function setIconBase(basePath: string | undefined) {
|
||||
globalBasePath = basePath;
|
||||
}
|
||||
|
||||
/** 生成多层 fallback 路径,从文件所在目录向上查找 */
|
||||
function buildIconSrc(iconName: string, extension: string): string {
|
||||
if (!globalBasePath) return "";
|
||||
|
||||
// 取文件所在目录,如 /pages/sub/deep/file.md → /pages/sub/deep
|
||||
const dir =
|
||||
globalBasePath.substring(0, globalBasePath.lastIndexOf("/")) || "/";
|
||||
const parts = dir.split("/").filter(Boolean);
|
||||
|
||||
const urls: string[] = [];
|
||||
// 从当前目录开始,逐级向上
|
||||
for (let i = parts.length; i >= 0; i--) {
|
||||
const prefix = "/" + parts.slice(0, i).join("/");
|
||||
const base = prefix === "/" ? "/assets" : `${prefix}/assets`;
|
||||
urls.push(`url('${base}/${iconName}.${extension}')`);
|
||||
}
|
||||
|
||||
return urls.join(", ");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import markedTable from "./table";
|
|||
import { gfmHeadingId } from "marked-gfm-heading-id";
|
||||
import markedColumns from "./columns";
|
||||
import markedCodeBlockYamlTag from "./code-block-yaml-tag";
|
||||
import { iconDirective } from "./icon";
|
||||
import { iconDirective, setIconBase } from "./icon";
|
||||
|
||||
// 使用 marked-directive 来支持指令语法
|
||||
const marked = new Marked()
|
||||
|
|
@ -33,7 +33,8 @@ const marked = new Marked()
|
|||
},
|
||||
);
|
||||
|
||||
export function parseMarkdown(content: string): string {
|
||||
export function parseMarkdown(content: string, basePath?: string): string {
|
||||
setIconBase(basePath);
|
||||
return marked.parse(content.trimStart()) as string;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue