Refactor ruby support
This commit is contained in:
parent
15d32a6dab
commit
c717cc6280
|
@ -3,7 +3,7 @@ import rehypeKatex from 'rehype-katex';
|
||||||
import remarkMath from 'remark-math';
|
import remarkMath from 'remark-math';
|
||||||
import remarkEmoji from 'remark-emoji';
|
import remarkEmoji from 'remark-emoji';
|
||||||
import mdx from '@astrojs/mdx';
|
import mdx from '@astrojs/mdx';
|
||||||
import remarkRuby from './src/assets/ruby';
|
import remarkRuby from './src/utils/ruby';
|
||||||
import solid from '@astrojs/solid-js';
|
import solid from '@astrojs/solid-js';
|
||||||
import markdoc from '@astrojs/markdoc';
|
import markdoc from '@astrojs/markdoc';
|
||||||
|
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
import type { Node, Parent } from 'unist';
|
|
||||||
import { visit } from "unist-util-visit";
|
|
||||||
|
|
||||||
|
|
||||||
interface RubyNode extends Node {
|
|
||||||
type: 'html';
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const regex = /\{.+?\}\(.+?\)/g;
|
|
||||||
const group = /^\{(.+?)\}\((.+?)\)$/;
|
|
||||||
const template = "<ruby>$1<rp>(</rp><rt>$2</rt><rp>)</rp></ruby>";
|
|
||||||
|
|
||||||
function toRuby(ruby: string): RubyNode {
|
|
||||||
return {
|
|
||||||
type: "html",
|
|
||||||
value: ruby.replace(group, template),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function transformRuby(node: {value: string}, index: number, parent: Parent) {
|
|
||||||
if (!regex.test(node.value)) return;
|
|
||||||
|
|
||||||
const text = node.value.split(regex).map(value => ({ type: "text", value}));
|
|
||||||
const ruby = node.value.match(regex)!.map(toRuby);
|
|
||||||
|
|
||||||
const merged = [];
|
|
||||||
for (let i = 0; i < text.length; i++) {
|
|
||||||
text[i] && merged.push(text[i]);
|
|
||||||
ruby[i] && merged.push(ruby[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.children.splice(index, 1, ...merged);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ruby() {
|
|
||||||
return (tree: Node, _: any) => {
|
|
||||||
visit(tree, "text", transformRuby);
|
|
||||||
}
|
|
||||||
}
|
|
14
src/components/markdown/Ruby.astro
Normal file
14
src/components/markdown/Ruby.astro
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
import { transform } from '../../utils/ruby';
|
||||||
|
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = transform(Astro.props.text);
|
||||||
|
---
|
||||||
|
{text.map(annotated => typeof annotated === 'object'
|
||||||
|
? <ruby>{annotated.text}<rp>(</rp><rt>{annotated.ruby}</rt><rp>)</rp></ruby>
|
||||||
|
: annotated
|
||||||
|
)}
|
|
@ -1,4 +1,5 @@
|
||||||
---
|
---
|
||||||
|
import Ruby from "../Ruby.astro";
|
||||||
import { transform } from "./transform";
|
import { transform } from "./transform";
|
||||||
|
|
||||||
const html = await Astro.slots.render('default');
|
const html = await Astro.slots.render('default');
|
||||||
|
@ -12,7 +13,7 @@ const cols = Object.keys(lyrics[0]);
|
||||||
{lyrics.map(row =>
|
{lyrics.map(row =>
|
||||||
<tr>{cols.map(col =>
|
<tr>{cols.map(col =>
|
||||||
<td>
|
<td>
|
||||||
{row[col].map(line => <span>{line}</span><br/>)}
|
{row[col].map(line => <span><Ruby text={line}/></span><br/>)}
|
||||||
</td>
|
</td>
|
||||||
)}</tr>
|
)}</tr>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -11,11 +11,11 @@ Sadly, as far as I know CommonMark currently doesn't include anything about ruby
|
||||||
|
|
||||||
| Language | Example |
|
| Language | Example |
|
||||||
| -------- | ------- |
|
| -------- | ------- |
|
||||||
| Japanese | {日本語}(にほんご)の{文法}(ぶんぽう)は{難}(むずか)しい |
|
| Japanese | [日本語]{にほんご}の[文法]{ぶんぽう}は[難]{むずか}しい |
|
||||||
| Chinese | {北}(Běi){京}(jīng)<br/>{北}(ㄅㄟˇ){京}(ㄐㄧㄥ) |
|
| Chinese | [北]{Běi}[京]{jīng}<br/>[北]{ㄅㄟˇ}[京]{ㄐㄧㄥ} |
|
||||||
| Korean | {韓}(한){國}(국) |
|
| Korean | [韓]{한}[國]{국} |
|
||||||
| Vietnamese | {河}(Hà){內}(Nội) |
|
| Vietnamese | [河]{Hà}[內]{Nội} |
|
||||||
| Other | I {love}(like) ruby! |
|
| Other | I [love]{like} ruby! |
|
||||||
|
|
||||||
|
|
||||||
## Remark
|
## Remark
|
||||||
|
|
|
@ -13,11 +13,11 @@ album:
|
||||||
|
|
||||||
{% lyrics %}
|
{% lyrics %}
|
||||||
# Japanese
|
# Japanese
|
||||||
- 瞬きをして 切り取る時間
|
- 瞬きをして 切り取る時間
|
||||||
- 何気なくても 大切な今を
|
- 何気なくても 大切な今を
|
||||||
- 忘れないで 居られるように
|
- 忘れないで 居られるように
|
||||||
- いつか 頭の中
|
- いつか 頭の中
|
||||||
- 掻き消して しまっても
|
- 掻き消して しまっても
|
||||||
# Romaji
|
# Romaji
|
||||||
- Matataki wo shite kiritoru jikan
|
- Matataki wo shite kiritoru jikan
|
||||||
- Nanigenakutemo taisetsuna ima wo
|
- Nanigenakutemo taisetsuna ima wo
|
||||||
|
@ -26,11 +26,11 @@ album:
|
||||||
- Kakikeshite shimattemo
|
- Kakikeshite shimattemo
|
||||||
---
|
---
|
||||||
# Japanese
|
# Japanese
|
||||||
- 瞬きをして 焼き付ける空
|
- 瞬きをして 焼き付ける空
|
||||||
- 永遠の折り 縁取らせたら
|
- 永遠の折り 縁取らせたら
|
||||||
- 綺麗なまま 残されてく
|
- 綺麗なまま 残されてく
|
||||||
- いつか 思い出して
|
- いつか 思い出して
|
||||||
- 色褪せて しまっても
|
- 色褪せて しまっても
|
||||||
# Romaji
|
# Romaji
|
||||||
- Matataki wo shite yakitsukeru sora
|
- Matataki wo shite yakitsukeru sora
|
||||||
- Eien no ori fuchidorasetara
|
- Eien no ori fuchidorasetara
|
||||||
|
|
28
src/content/songs/dont-lose.mdoc
Normal file
28
src/content/songs/dont-lose.mdoc
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
title: "Don't lose"
|
||||||
|
origin:
|
||||||
|
- 亡き王女の為のセプテット
|
||||||
|
album:
|
||||||
|
ARCD0054:
|
||||||
|
track: 7
|
||||||
|
---
|
||||||
|
|
||||||
|
{% lyrics %}
|
||||||
|
# Japanese
|
||||||
|
- こんなにも 綺麗な月は
|
||||||
|
- どうしても 届かないけど
|
||||||
|
- どんなにも 赤さは
|
||||||
|
- いつまでも
|
||||||
|
- あんなにも
|
||||||
|
- なんどでも
|
||||||
|
- そんなにも
|
||||||
|
- なにもかも
|
||||||
|
---
|
||||||
|
- 飲み込んだ 暗闇の奥
|
||||||
|
|
||||||
|
---
|
||||||
|
- 愛してた 閉じ込めるほどに
|
||||||
|
- todo
|
||||||
|
- 「I」してた 閉じ込めるほどに
|
||||||
|
- だけどもう違うから
|
||||||
|
{% /lyrics %}
|
14
src/content/songs/dream-again.mdoc
Normal file
14
src/content/songs/dream-again.mdoc
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
title: "Dream Again"
|
||||||
|
origin:
|
||||||
|
- the Last Judgment
|
||||||
|
album:
|
||||||
|
ARCD0054:
|
||||||
|
track: 5
|
||||||
|
---
|
||||||
|
|
||||||
|
{% lyrics %}
|
||||||
|
# Japanese
|
||||||
|
- どこまでも続いていく階段 [降]{くだ}った途方もないほど
|
||||||
|
- 行きたい場所はもう決まっている 幻想の声のする所
|
||||||
|
{% /lyrics %}
|
|
@ -4,6 +4,10 @@
|
||||||
"ARCD0051": {
|
"ARCD0051": {
|
||||||
"title": "Engaged Dancehall",
|
"title": "Engaged Dancehall",
|
||||||
"cover": "/static/albums/ARCD0051.jpg"
|
"cover": "/static/albums/ARCD0051.jpg"
|
||||||
|
},
|
||||||
|
"ARCD0054": {
|
||||||
|
"title": "Ignition Dancehall",
|
||||||
|
"cover": "/static/albums/ARCD0054.jpg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
53
src/utils/ruby.ts
Normal file
53
src/utils/ruby.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import type { Node, Parent } from 'unist';
|
||||||
|
import { visit } from "unist-util-visit";
|
||||||
|
|
||||||
|
|
||||||
|
const regex = /\[([^\]]+)\]\{([^}]+)\}/g;
|
||||||
|
|
||||||
|
interface Ruby {
|
||||||
|
text: string;
|
||||||
|
ruby: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Annotated =
|
||||||
|
| string
|
||||||
|
| Ruby;
|
||||||
|
|
||||||
|
|
||||||
|
export function transform(input: string): Annotated[] {
|
||||||
|
const parts: Annotated[] = [];
|
||||||
|
let lastIndex = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const match = regex.exec(input);
|
||||||
|
if (!match) break;
|
||||||
|
|
||||||
|
const [full, text, ruby] = match;
|
||||||
|
|
||||||
|
if (match.index > lastIndex)
|
||||||
|
parts.push(input.slice(lastIndex, match.index));
|
||||||
|
|
||||||
|
parts.push({ text: text, ruby: ruby });
|
||||||
|
lastIndex = regex.lastIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastIndex < input.length)
|
||||||
|
parts.push(input.slice(lastIndex));
|
||||||
|
|
||||||
|
regex.lastIndex = 0;
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ruby() {
|
||||||
|
return (tree: Node, _: any) => {
|
||||||
|
visit(tree, "text", (node: { value: string }, index: number, parent: Parent) => {
|
||||||
|
const items = transform(node.value)
|
||||||
|
.map(a => typeof a === 'object'
|
||||||
|
? ({ type: 'html', value: `<ruby>${a.text}<rp>(</rp><rt>${a.ruby}</rt><rp>)</rp></ruby>` })
|
||||||
|
: ({ type: 'text', value: a })
|
||||||
|
);
|
||||||
|
|
||||||
|
parent.children.splice(index, 1, ...items);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue