From c717cc6280db5504cf08d753e65212b764cf27c9 Mon Sep 17 00:00:00 2001 From: Maciej Jur Date: Sat, 29 Apr 2023 15:29:07 +0200 Subject: [PATCH] Refactor ruby support --- astro.config.ts | 2 +- src/assets/ruby.ts | 40 ---------------- src/components/markdown/Ruby.astro | 14 ++++++ src/components/markdown/lyrics/Lyrics.astro | 3 +- src/content/posts/ruby-in-markdown.md | 10 ++-- src/content/songs/black-eyes.mdoc | 20 ++++---- src/content/songs/dont-lose.mdoc | 28 +++++++++++ src/content/songs/dream-again.mdoc | 14 ++++++ src/data/circles.json | 4 ++ src/utils/ruby.ts | 53 +++++++++++++++++++++ 10 files changed, 131 insertions(+), 57 deletions(-) delete mode 100644 src/assets/ruby.ts create mode 100644 src/components/markdown/Ruby.astro create mode 100644 src/content/songs/dont-lose.mdoc create mode 100644 src/content/songs/dream-again.mdoc create mode 100644 src/utils/ruby.ts diff --git a/astro.config.ts b/astro.config.ts index 9cae606..5496c4f 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -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'; diff --git a/src/assets/ruby.ts b/src/assets/ruby.ts deleted file mode 100644 index eb41815..0000000 --- a/src/assets/ruby.ts +++ /dev/null @@ -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 = "$1($2)"; - -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); - } -} diff --git a/src/components/markdown/Ruby.astro b/src/components/markdown/Ruby.astro new file mode 100644 index 0000000..02f4157 --- /dev/null +++ b/src/components/markdown/Ruby.astro @@ -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' + ? {annotated.text}({annotated.ruby}) + : annotated +)} diff --git a/src/components/markdown/lyrics/Lyrics.astro b/src/components/markdown/lyrics/Lyrics.astro index 9379530..c5c57d3 100644 --- a/src/components/markdown/lyrics/Lyrics.astro +++ b/src/components/markdown/lyrics/Lyrics.astro @@ -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 => {cols.map(col => - {row[col].map(line => {line}
)} + {row[col].map(line =>
)} )} )} diff --git a/src/content/posts/ruby-in-markdown.md b/src/content/posts/ruby-in-markdown.md index d7bfd8b..9c278e6 100644 --- a/src/content/posts/ruby-in-markdown.md +++ b/src/content/posts/ruby-in-markdown.md @@ -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)
{北}(ㄅㄟˇ){京}(ㄐㄧㄥ) | -| Korean | {韓}(한){國}(국) | -| Vietnamese | {河}(Hà){內}(Nội) | -| Other | I {love}(like) ruby! | +| Japanese | [日本語]{にほんご}の[文法]{ぶんぽう}は[難]{むずか}しい | +| Chinese | [北]{Běi}[京]{jīng}
[北]{ㄅㄟˇ}[京]{ㄐㄧㄥ} | +| Korean | [韓]{한}[國]{국} | +| Vietnamese | [河]{Hà}[內]{Nội} | +| Other | I [love]{like} ruby! | ## Remark diff --git a/src/content/songs/black-eyes.mdoc b/src/content/songs/black-eyes.mdoc index d554b73..c55ab00 100644 --- a/src/content/songs/black-eyes.mdoc +++ b/src/content/songs/black-eyes.mdoc @@ -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 diff --git a/src/content/songs/dont-lose.mdoc b/src/content/songs/dont-lose.mdoc new file mode 100644 index 0000000..cbbf135 --- /dev/null +++ b/src/content/songs/dont-lose.mdoc @@ -0,0 +1,28 @@ +--- +title: "Don't lose" +origin: + - 亡き王女の為のセプテット +album: + ARCD0054: + track: 7 +--- + +{% lyrics %} +# Japanese +- こんなにも 綺麗な月は +- どうしても 届かないけど +- どんなにも 赤さは +- いつまでも +- あんなにも +- なんどでも +- そんなにも +- なにもかも +--- +- 飲み込んだ 暗闇の奥 + +--- +- 愛してた 閉じ込めるほどに +- todo +- 「I」してた 閉じ込めるほどに +- だけどもう違うから +{% /lyrics %} diff --git a/src/content/songs/dream-again.mdoc b/src/content/songs/dream-again.mdoc new file mode 100644 index 0000000..d5cd695 --- /dev/null +++ b/src/content/songs/dream-again.mdoc @@ -0,0 +1,14 @@ +--- +title: "Dream Again" +origin: + - the Last Judgment +album: + ARCD0054: + track: 5 +--- + +{% lyrics %} +# Japanese +- どこまでも続いていく階段 [降]{くだ}った途方もないほど +- 行きたい場所はもう決まっている 幻想の声のする所 +{% /lyrics %} diff --git a/src/data/circles.json b/src/data/circles.json index dd33f12..dd3cd29 100644 --- a/src/data/circles.json +++ b/src/data/circles.json @@ -4,6 +4,10 @@ "ARCD0051": { "title": "Engaged Dancehall", "cover": "/static/albums/ARCD0051.jpg" + }, + "ARCD0054": { + "title": "Ignition Dancehall", + "cover": "/static/albums/ARCD0054.jpg" } } } diff --git a/src/utils/ruby.ts b/src/utils/ruby.ts new file mode 100644 index 0000000..59b8fc5 --- /dev/null +++ b/src/utils/ruby.ts @@ -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: `${a.text}(${a.ruby})` }) + : ({ type: 'text', value: a }) + ); + + parent.children.splice(index, 1, ...items); + }); + } +}