ttrpg-tools/src/components/Article.tsx

58 lines
1.5 KiB
TypeScript
Raw Normal View History

2026-02-26 09:24:26 +08:00
import { Component, createSignal, onMount, onCleanup, Show } from 'solid-js';
import { parseMarkdown } from '../markdown';
import { fetchData } from '../data-loader';
export interface ArticleProps {
src: string;
onLoaded?: () => void;
onError?: (error: Error) => void;
}
/**
* Article
* src md markdown
*/
export const Article: Component<ArticleProps> = (props) => {
const [content, setContent] = createSignal('');
const [loading, setLoading] = createSignal(true);
const [error, setError] = createSignal<Error | null>(null);
let articleRef: HTMLArticleElement | undefined;
onMount(async () => {
setLoading(true);
try {
const text = await fetchData(props.src);
setContent(text);
setLoading(false);
props.onLoaded?.();
} catch (err) {
const errorObj = err instanceof Error ? err : new Error(String(err));
setError(errorObj);
setLoading(false);
props.onError?.(errorObj);
}
});
onCleanup(() => {
// 清理时清空内容,触发内部组件的销毁
setContent('');
});
return (
2026-02-26 09:47:21 +08:00
<article ref={articleRef} class="prose" data-src={props.src}>
2026-02-26 09:24:26 +08:00
<Show when={loading()}>
<div class="text-gray-500">...</div>
</Show>
<Show when={error()}>
<div class="text-red-500">{error()?.message}</div>
</Show>
<Show when={!loading() && !error()}>
<div innerHTML={parseMarkdown(content())} />
</Show>
</article>
);
};
export default Article;