はじめに
記事にGitHubのコードを埋め込みたくなったので作りました。
以下のような感じになりました。
123456789101112131415
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"noEmit": true,
"strict": true,
"types": ["vite/client", "@cloudflare/workers-types", "@types/bun"],
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
}
}
ちなみに、リンクはこのサイトのtsconfig.json
へのリンクです。
Permalinkからコードを取得する
まずは、Permalinkからコードを取得してみます。
export async function fetchPermalink(permalink: string) {
const response = await fetch(permalink, {
headers: {
Accept: "application/json",
},
});
const { title, payload } = await response.json();
return {
title,
lines: payload.blob.rawLines,
language: payload.blob.language,
};
}
Acceptヘッダーにapplication/json
を指定してみたらJSON形式で取得できました。試してみるもんですね。
今回はタイトルとコードと言語が欲しいので、それだけ取り出しています。
コンポーネントを作る
次は、取得したコードを表示するコンポーネントを作ります。
参考までに、このサイトで使ってるコンポーネントを載せておきます。
2425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
export default async function GithubEmbed({ permalink }: Props) {
let { line, lineEnd } = parsePermalink(permalink);
const { title, language, lines } = await fetchPermalink(permalink);
if (!line) {
line = 1;
lineEnd = lines.length;
}
if (!lineEnd) {
lineEnd = line;
}
const selectedLines = lines.slice(line - 1, lineEnd);
const code = selectedLines.join("\n");
const lang = languageMap[language] ?? "plaintext";
const highlighter = await getHighlighter(lang);
const html = highlighter.codeToHtml(code, { lang, theme });
return (
<div class={css({ rounded: "md", overflow: "hidden" })}>
<div
class={css({
display: "grid",
gap: 2,
gridTemplateColumns: "auto 1fr",
alignItems: "center",
p: 2,
fontSize: "xs",
bg: "bg.emphasized",
fontFamily: "latin",
})}
>
<IconFa6BrandsGithub />
<a
class={css({
wordBreak: "break-word",
})}
href={permalink}
target="_blank"
rel="noopener noreferrer"
>
{title}
</a>
</div>
<div
class={css({
"& > pre": {
p: 4,
overflowX: "auto",
lineHeight: "normal",
},
})}
// biome-ignore lint/security/noDangerouslySetInnerHtml:
dangerouslySetInnerHTML={{ __html: html }}
/>
</div>
);
}
parsePermalink
はその名の通り、Permalinkをパースする関数です。
ここらへんはChatGPTにリンクの例を投げて書かせると良いでしょう。
その他この記事に登場しない部分は、リポジトリを見てみてください。
多分オープンにしてるはずなので。
おわりに
どうやって実装するか悩んでいたのですが、Acceptヘッダーに気づけた時点で9割くらい解決していました。
せっかく作ったブログ欄に何を載せるか悩んでいたので、軽めのネタが湧いてきて渡りに船でした。