Refactor ruby support

This commit is contained in:
Maciej Jur 2023-04-29 15:29:07 +02:00
parent 15d32a6dab
commit c717cc6280
10 changed files with 131 additions and 57 deletions

View file

@ -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';

View file

@ -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);
}
}

View 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
)}

View file

@ -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>
)} )}

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,28 @@
---
title: "Don't lose"
origin:
- 亡き王女の為のセプテット
album:
ARCD0054:
track: 7
---
{% lyrics %}
# Japanese
- こんなにも 綺麗な月は
- どうしても 届かないけど
- どんなにも 赤さは
- いつまでも
- あんなにも
- なんどでも
- そんなにも
- なにもかも
---
- 飲み込んだ 暗闇の奥
---
- 愛してた 閉じ込めるほどに
- todo
- 「I」してた 閉じ込めるほどに
- だけどもう違うから
{% /lyrics %}

View file

@ -0,0 +1,14 @@
---
title: "Dream Again"
origin:
- the Last Judgment
album:
ARCD0054:
track: 5
---
{% lyrics %}
# Japanese
- どこまでも続いていく階段 [降]{くだ}った途方もないほど
- 行きたい場所はもう決まっている 幻想の声のする所
{% /lyrics %}

View file

@ -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
View 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);
});
}
}