feat: implement icon directive with relative path fallback
Refactor icon rendering to use a custom `marked-directive` instead of a global icon prefix. This allows icons to use a CSS-based fallback chain (searching up to 10 directory levels for an `assets/` folder), making icon paths more robust and removing the need to pass path prefixes through the component tree.
This commit is contained in:
@@ -7,20 +7,17 @@ import {
|
||||
onCleanup,
|
||||
Show,
|
||||
createResource,
|
||||
createMemo,
|
||||
createSignal,
|
||||
} from "solid-js";
|
||||
import { parseMarkdown } from "../markdown";
|
||||
import { extractSection } from "../data-loader";
|
||||
import mermaid from "mermaid";
|
||||
import { getIndexedData } from "../data-loader/file-index";
|
||||
import { resolvePath } from "./utils/path";
|
||||
import { useNavigateWithParams } from "./useNavigateWithParams";
|
||||
|
||||
export interface ArticleProps {
|
||||
src: string;
|
||||
section?: string; // 指定要显示的标题(不含 #)
|
||||
iconPath?: string; // 图标路径前缀,默认为 "./assets",空字符串表示禁用
|
||||
onLoaded?: () => void;
|
||||
onError?: (error: Error) => void;
|
||||
class?: string; // 额外的 class 用于样式控制
|
||||
@@ -83,12 +80,6 @@ export const Article: Component<ArticleProps & ParentProps> = (props) => {
|
||||
);
|
||||
const [contentDom, setContentDom] = createSignal<HTMLDivElement>();
|
||||
|
||||
// 解析 iconPath,默认为 "./assets",空字符串表示禁用
|
||||
const iconPrefix = createMemo(() => {
|
||||
if (props.iconPath === "") return undefined; // 空字符串禁用图标前缀
|
||||
return resolvePath(props.src, props.iconPath ?? "./assets");
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
const data = content();
|
||||
if (data) {
|
||||
@@ -144,7 +135,7 @@ export const Article: Component<ArticleProps & ParentProps> = (props) => {
|
||||
<div
|
||||
class="relative"
|
||||
ref={setContentDom}
|
||||
innerHTML={parseMarkdown(content()!, iconPrefix())}
|
||||
innerHTML={parseMarkdown(content()!)}
|
||||
/>
|
||||
{props.children}
|
||||
</ArticleDomCtx.Provider>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { getLayerStyle } from "./hooks/dimensions";
|
||||
import type { CardData, CardSide, LayerConfig } from "./types";
|
||||
import { DeckStore } from "./hooks/deckStore";
|
||||
import { processVariables } from "../utils/csv-loader";
|
||||
import { resolvePath } from "../utils/path";
|
||||
import type { LayerInteractionHandlers } from "./hooks/useLayerInteraction";
|
||||
|
||||
export interface CardLayerProps {
|
||||
@@ -26,13 +25,8 @@ export function CardLayer(props: CardLayerProps) {
|
||||
const draggingState = () => props.store.state.draggingState;
|
||||
|
||||
function renderLayerContent(content: string) {
|
||||
const iconPath = resolvePath(
|
||||
props.store.state.cards.sourcePath,
|
||||
props.cardData.iconPath ?? "./assets",
|
||||
);
|
||||
return parseMarkdown(
|
||||
processVariables(content, props.cardData, props.store.state.cards),
|
||||
iconPath,
|
||||
) as string;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { customElement, noShadowDOM } from "solid-element";
|
||||
import { createResource, Show, createMemo, createEffect } from "solid-js";
|
||||
import { createResource, Show, createEffect } from "solid-js";
|
||||
import { getIndexedData } from "../data-loader/file-index";
|
||||
import { extractSection } from "../data-loader";
|
||||
import { parseMarkdown } from "../markdown";
|
||||
@@ -27,9 +27,6 @@ customElement("md-embed", { headingBase: 0 }, (props, { element }) => {
|
||||
const articlePath = articleEl?.getAttribute("data-src") || "";
|
||||
const resolvedPath = resolvePath(articlePath, filePath);
|
||||
|
||||
// 计算嵌入文件的 iconPrefix,用 createMemo 包装避免每个 embed 都重新计算
|
||||
const iconPrefix = createMemo(() => resolvePath(resolvedPath, "./assets"));
|
||||
|
||||
const [content] = createResource(
|
||||
() => ({ path: resolvedPath, section }),
|
||||
async ({ path, section }) => {
|
||||
@@ -56,10 +53,7 @@ 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()!, iconPrefix())}
|
||||
/>
|
||||
<div class="prose" innerHTML={parseMarkdown(content()!)} />
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user