feat: inline md-table
This commit is contained in:
parent
3d9617f06c
commit
6b411c2f24
|
|
@ -1,8 +1,8 @@
|
|||
import { customElement, noShadowDOM } from 'solid-element';
|
||||
import { createSignal, For, Show, createEffect, createMemo, createResource } from 'solid-js';
|
||||
import { marked } from '../markdown';
|
||||
import { loadCSV, CSV, processVariables, isCSV } from './utils/csv-loader';
|
||||
import { resolvePath } from './utils/path';
|
||||
import {loadCSV, CSV, processVariables} from './utils/csv-loader';
|
||||
|
||||
export interface TableProps {
|
||||
roll?: boolean;
|
||||
|
|
@ -23,8 +23,8 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
|
|||
const [bodyHtml, setBodyHtml] = createSignal('');
|
||||
let tabsContainer: HTMLDivElement | undefined;
|
||||
|
||||
// 从 element 的 textContent 获取 CSV 路径
|
||||
const src = element?.textContent?.trim() || '';
|
||||
// 从 element 的 textContent 获取 CSV 路径或 inline CSV 数据
|
||||
const rawContent = element?.textContent?.trim() || '';
|
||||
|
||||
// 隐藏原始文本内容
|
||||
if (element) {
|
||||
|
|
@ -35,11 +35,11 @@ customElement('md-table', { roll: false, remix: false }, (props, { element }) =>
|
|||
const articleEl = element?.closest('article[data-src]');
|
||||
const articlePath = articleEl?.getAttribute('data-src') || '';
|
||||
|
||||
// 解析相对路径
|
||||
const resolvedSrc = resolvePath(articlePath, src);
|
||||
// 如果是 inline CSV,直接使用;否则解析相对路径
|
||||
const contentOrPath = isCSV(rawContent) ? rawContent : resolvePath(articlePath, rawContent);
|
||||
|
||||
// 使用 createResource 加载 CSV,自动响应路径变化并避免重复加载
|
||||
const [csvData] = createResource(() => resolvedSrc, loadCSV);
|
||||
const [csvData] = createResource(() => contentOrPath, loadCSV);
|
||||
|
||||
// 当数据加载完成后更新 rows
|
||||
createEffect(() => {
|
||||
|
|
|
|||
|
|
@ -31,13 +31,87 @@ function parseFrontMatter(content: string): { frontmatter?: JSONObject; remainin
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测字符串是否是 CSV 格式
|
||||
* @param str 待检测的字符串
|
||||
* @returns 如果是 CSV 格式返回 true
|
||||
*/
|
||||
export function isCSV(str: string): boolean {
|
||||
const trimmed = str.trim();
|
||||
|
||||
// 检查是否以 YAML front matter 开头
|
||||
if (trimmed.startsWith('---\n') || trimmed.startsWith('---\r\n')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查是否包含 CSV 特征:多行且有分隔符
|
||||
const lines = trimmed.split(/\r?\n/).filter(line => line.trim() !== '');
|
||||
if (lines.length < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检测常见 CSV 分隔符
|
||||
const separators = [',', '\t', ';', '|'];
|
||||
const firstLine = lines[0];
|
||||
|
||||
for (const sep of separators) {
|
||||
if (firstLine.includes(sep)) {
|
||||
// 检查其他行是否也有相同的分隔符
|
||||
const hasSeparatorInOtherLines = lines.slice(1).some(line => line.includes(sep));
|
||||
if (hasSeparatorInOtherLines) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 CSV 字符串
|
||||
* @template T 返回数据的类型,默认为 Record<string, string>
|
||||
* @param csvString CSV 字符串内容
|
||||
* @param sourcePath 源路径标识(用于标记数据来源)
|
||||
* @returns 解析后的 CSV 数据
|
||||
*/
|
||||
export function parseCSVString<T = Record<string, string>>(csvString: string, sourcePath: string = 'inline'): CSV<T> {
|
||||
// 解析 front matter
|
||||
const { frontmatter, remainingContent } = parseFrontMatter(csvString);
|
||||
|
||||
const records = parse(remainingContent, {
|
||||
columns: true,
|
||||
comment: '#',
|
||||
trim: true,
|
||||
skipEmptyLines: true
|
||||
});
|
||||
|
||||
const result = records as Record<string, string>[];
|
||||
// 添加 front matter 到结果中
|
||||
const csvResult = result as CSV<T>;
|
||||
if (frontmatter) {
|
||||
csvResult.frontmatter = frontmatter;
|
||||
for(const each of result){
|
||||
Object.assign(each, frontmatter);
|
||||
}
|
||||
}
|
||||
csvResult.sourcePath = sourcePath;
|
||||
return csvResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载 CSV 文件
|
||||
* @template T 返回数据的类型,默认为 Record<string, string>
|
||||
* @param pathOrContent 文件路径或 inline CSV 字符串
|
||||
* @returns 解析后的 CSV 数据
|
||||
*/
|
||||
export async function loadCSV<T = Record<string, string>>(path: string): Promise<CSV<T>> {
|
||||
// 尝试从索引获取
|
||||
const content = await getIndexedData(path);
|
||||
export async function loadCSV<T = Record<string, string>>(pathOrContent: string): Promise<CSV<T>> {
|
||||
// 检测是否是 inline CSV 数据
|
||||
if (isCSV(pathOrContent)) {
|
||||
return parseCSVString<T>(pathOrContent, 'inline');
|
||||
}
|
||||
|
||||
// 从索引获取文件内容
|
||||
const content = await getIndexedData(pathOrContent);
|
||||
|
||||
// 解析 front matter
|
||||
const { frontmatter, remainingContent } = parseFrontMatter(content);
|
||||
|
|
@ -58,7 +132,7 @@ export async function loadCSV<T = Record<string, string>>(path: string): Promise
|
|||
Object.assign(each, frontmatter);
|
||||
}
|
||||
}
|
||||
csvResult.sourcePath = path;
|
||||
csvResult.sourcePath = pathOrContent;
|
||||
return csvResult;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue