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 remarkEmoji from 'remark-emoji';
|
||||
import mdx from '@astrojs/mdx';
|
||||
import remarkRuby from './src/assets/ruby';
|
||||
import remarkRuby from './src/utils/ruby';
|
||||
import solid from '@astrojs/solid-js';
|
||||
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";
|
||||
|
||||
const html = await Astro.slots.render('default');
|
||||
|
@ -12,7 +13,7 @@ const cols = Object.keys(lyrics[0]);
|
|||
{lyrics.map(row =>
|
||||
<tr>{cols.map(col =>
|
||||
<td>
|
||||
{row[col].map(line => <span>{line}</span><br/>)}
|
||||
{row[col].map(line => <span><Ruby text={line}/></span><br/>)}
|
||||
</td>
|
||||
)}</tr>
|
||||
)}
|
||||
|
|
|
@ -11,11 +11,11 @@ Sadly, as far as I know CommonMark currently doesn't include anything about ruby
|
|||
|
||||
| Language | Example |
|
||||
| -------- | ------- |
|
||||
| Japanese | {日本語}(にほんご)の{文法}(ぶんぽう)は{難}(むずか)しい |
|
||||
| Chinese | {北}(Běi){京}(jīng)<br/>{北}(ㄅㄟˇ){京}(ㄐㄧㄥ) |
|
||||
| Korean | {韓}(한){國}(국) |
|
||||
| Vietnamese | {河}(Hà){內}(Nội) |
|
||||
| Other | I {love}(like) ruby! |
|
||||
| Japanese | [日本語]{にほんご}の[文法]{ぶんぽう}は[難]{むずか}しい |
|
||||
| Chinese | [北]{Běi}[京]{jīng}<br/>[北]{ㄅㄟˇ}[京]{ㄐㄧㄥ} |
|
||||
| Korean | [韓]{한}[國]{국} |
|
||||
| Vietnamese | [河]{Hà}[內]{Nội} |
|
||||
| Other | I [love]{like} ruby! |
|
||||
|
||||
|
||||
## Remark
|
||||
|
|
|
@ -13,11 +13,11 @@ album:
|
|||
|
||||
{% lyrics %}
|
||||
# Japanese
|
||||
- 瞬きをして 切り取る時間
|
||||
- 何気なくても 大切な今を
|
||||
- 忘れないで 居られるように
|
||||
- いつか 頭の中
|
||||
- 掻き消して しまっても
|
||||
- 瞬きをして 切り取る時間
|
||||
- 何気なくても 大切な今を
|
||||
- 忘れないで 居られるように
|
||||
- いつか 頭の中
|
||||
- 掻き消して しまっても
|
||||
# Romaji
|
||||
- Matataki wo shite kiritoru jikan
|
||||
- Nanigenakutemo taisetsuna ima wo
|
||||
|
@ -26,11 +26,11 @@ album:
|
|||
- Kakikeshite shimattemo
|
||||
---
|
||||
# Japanese
|
||||
- 瞬きをして 焼き付ける空
|
||||
- 永遠の折り 縁取らせたら
|
||||
- 綺麗なまま 残されてく
|
||||
- いつか 思い出して
|
||||
- 色褪せて しまっても
|
||||
- 瞬きをして 焼き付ける空
|
||||
- 永遠の折り 縁取らせたら
|
||||
- 綺麗なまま 残されてく
|
||||
- いつか 思い出して
|
||||
- 色褪せて しまっても
|
||||
# Romaji
|
||||
- Matataki wo shite yakitsukeru sora
|
||||
- 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": {
|
||||
"title": "Engaged Dancehall",
|
||||
"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