2026-02-26 14:51:26 +08:00
|
|
|
|
import { Component, createSignal, createEffect, onCleanup, Show, createResource } from 'solid-js';
|
2026-02-26 09:24:26 +08:00
|
|
|
|
import { parseMarkdown } from '../markdown';
|
2026-02-26 14:24:48 +08:00
|
|
|
|
import { fetchData, extractSection } from '../data-loader';
|
2026-02-26 09:24:26 +08:00
|
|
|
|
|
|
|
|
|
|
export interface ArticleProps {
|
|
|
|
|
|
src: string;
|
2026-02-26 09:53:30 +08:00
|
|
|
|
section?: string; // 指定要显示的标题(不含 #)
|
2026-02-26 09:24:26 +08:00
|
|
|
|
onLoaded?: () => void;
|
|
|
|
|
|
onError?: (error: Error) => void;
|
2026-02-26 17:44:58 +08:00
|
|
|
|
class?: string; // 额外的 class 用于样式控制
|
2026-02-26 09:24:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-26 14:51:26 +08:00
|
|
|
|
async function fetchArticleContent(params: { src: string; section?: string }): Promise<string> {
|
|
|
|
|
|
const text = await fetchData(params.src);
|
|
|
|
|
|
// 如果指定了 section,提取对应内容
|
|
|
|
|
|
return params.section ? extractSection(text, params.section) : text;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-26 09:24:26 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* Article 组件
|
|
|
|
|
|
* 用于将特定 src 位置的 md 文件显示为 markdown 文章
|
|
|
|
|
|
*/
|
|
|
|
|
|
export const Article: Component<ArticleProps> = (props) => {
|
2026-02-26 14:51:26 +08:00
|
|
|
|
const [content, { refetch }] = createResource(
|
|
|
|
|
|
() => ({ src: props.src, section: props.section }),
|
|
|
|
|
|
fetchArticleContent
|
|
|
|
|
|
);
|
2026-02-26 09:24:26 +08:00
|
|
|
|
|
2026-02-26 14:51:26 +08:00
|
|
|
|
createEffect(() => {
|
|
|
|
|
|
const data = content();
|
|
|
|
|
|
if (data) {
|
2026-02-26 09:24:26 +08:00
|
|
|
|
props.onLoaded?.();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onCleanup(() => {
|
|
|
|
|
|
// 清理时清空内容,触发内部组件的销毁
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
2026-02-27 12:34:55 +08:00
|
|
|
|
<article class={`prose ${props.class || ''}`} data-src={props.src}>
|
2026-02-26 14:51:26 +08:00
|
|
|
|
<Show when={content.loading}>
|
2026-02-26 09:24:26 +08:00
|
|
|
|
<div class="text-gray-500">加载中...</div>
|
|
|
|
|
|
</Show>
|
2026-02-26 14:51:26 +08:00
|
|
|
|
<Show when={content.error}>
|
|
|
|
|
|
<div class="text-red-500">加载失败:{content.error?.message}</div>
|
2026-02-26 09:24:26 +08:00
|
|
|
|
</Show>
|
2026-02-26 14:51:26 +08:00
|
|
|
|
<Show when={!content.loading && !content.error && content()}>
|
2026-02-26 18:11:33 +08:00
|
|
|
|
<div class="relative" innerHTML={parseMarkdown(content()!)} />
|
2026-02-26 09:24:26 +08:00
|
|
|
|
</Show>
|
|
|
|
|
|
</article>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export default Article;
|