🏷️

YAMLタグをHTML bodyに入れるプラグイン【SSG-PJ-04】

2024/10/26に公開

これまでの流れ

Markdown→HTMLのSSGを作りたい!

Markdown→HTMLのSSGを作ってみた!

タイトルを抽出するプラグインを作ってみた!

アウトプットイメージ

自分はObsidianのタグ機能は使わず、自作のtopicaltagsをYAML内で使っています。topicaltagsはタグ自体が他のメモへのリンクなので、HTMLに変換後もリンクとして扱う必要があります。イメージはこんな感じです:

---
topicaltags:
	- [[tag1]]
	- [[tag2]]
---

# HEADER 1 

content content content 
<html>
	<head>
		<title>HEADER 1</title>
	</head>
	<body>
		<h1>HEADER 1</h1>
		<p><a href="tag1.html">tag1</a>, <a href="tag2.html">tag2</a></p>
		<p>content content content</p>
	</body>
</html>

parseMarkdown.jsにプラグインを追加

下記のコードを初期設定後かつMarkdownをHTMLに変換する関数の前に入れてください。

parseMarkdown.js
// タグの中身を取り出す関数
function extractTagsFromBrackets(tags) {
	return tags
	.map(tag => tag.toString().replace(/\[\[(.*?)\]\]/, '$1').trim()) 
	.filter(Boolean); 
}

// YAMLタグをH1の後に追加するプラグイン
md.use(function(md) {
	md.core.ruler.push('insert_topicaltags', function(state) {
		if (!state.tokens || !Array.isArray(state.tokens)) {
			return; // Early exit if there are no tokens
		}
		if (state.env.topicaltags && state.env.topicaltags.length > 0) {
			const rawTags = Array.isArray(state.env.topicaltags) ? state.env.topicaltags : [state.env.topicaltags];
			const tags = extractTagsFromBrackets(rawTags);
			if (tags.length > 0) {
				const paragraphOpen = new state.Token('paragraph_open', 'p', 1);
				const paragraphContent = new state.Token('inline', '', 0);
				const links = tags.map(tag => `<a href="${tag}.html">${tag}</a>`);	
				paragraphContent.content = links.join(', ');
				paragraphContent.children = [];
				tags.forEach((tag, index) => {
					const linkToken = new state.Token('link_open', 'a', 1);
					linkToken.attrs = [['href', `${tag}`]]; 
					const linkContentToken = new state.Token('text', '', 0);
					linkContentToken.content = tag; 
					const linkCloseToken = new state.Token('link_close', 'a', -1); 
					paragraphContent.children.push(linkToken, linkContentToken, linkCloseToken);
					if (index < tags.length - 1) {
						const separator = new state.Token('text', '', 0);
						separator.content = ', '; 
						paragraphContent.children.push(separator);
					}
				});
				const paragraphClose = new state.Token('paragraph_close', 'p', -1);
				const h1Index = state.tokens.findIndex(token => token.type === 'heading_open' && token.tag === 'h1');
				if (h1Index !== -1) {
					state.tokens.splice(h1Index + 3, 0, paragraphOpen, paragraphContent, paragraphClose);
				} else {
					console.warn("No H1 tag found to insert topical tags after.");
				}
			}
		}
	});
});

parseMarkdown.js内の関数をアップデート

parseMarkdown.js
// MarkdownをHTMLに変換する関数
function processMarkdown(content) {
	const { body, attributes } = frontMatter(content);
	const env = {
+		topicaltags: attributes.topicaltags || []
	};
	const html = md.render(body, env);
	if (!attributes.title && env.title) {
		attributes.title = env.title;
	}
	return { html, metadata: attributes };
}
GitHubで編集を提案

Discussion