Basic lyrics transform

This commit is contained in:
Maciej Jur 2023-04-26 00:26:45 +02:00
parent d423a4cffc
commit 9a8d9c3e28
8 changed files with 225 additions and 0 deletions

1
.gitignore vendored
View file

@ -27,3 +27,4 @@ public/**/*.webp
# obsidian
.obsidian/
.stfolder/

View file

@ -17,6 +17,7 @@
"leaflet": "^1.9.3",
"leaflet.markercluster": "^1.5.3",
"lunr": "^2.3.9",
"node-html-parser": "^6.1.5",
"rehype-katex": "^6.0.3",
"rehype-raw": "^6.1.1",
"rehype-stringify": "^9.0.3",

View file

@ -22,6 +22,9 @@ dependencies:
lunr:
specifier: ^2.3.9
version: 2.3.9
node-html-parser:
specifier: ^6.1.5
version: 6.1.5
rehype-katex:
specifier: ^6.0.3
version: 6.0.3
@ -1113,6 +1116,10 @@ packages:
readable-stream: 3.6.2
dev: false
/boolbase@1.0.0:
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
dev: false
/boxen@6.2.1:
resolution: {integrity: sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@ -1302,6 +1309,21 @@ packages:
which: 2.0.2
dev: false
/css-select@5.1.0:
resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
dependencies:
boolbase: 1.0.0
css-what: 6.1.0
domhandler: 5.0.3
domutils: 3.0.1
nth-check: 2.1.1
dev: false
/css-what@6.1.0:
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
engines: {node: '>= 6'}
dev: false
/csstype@3.1.2:
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
dev: false
@ -1362,6 +1384,33 @@ packages:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
dev: false
/dom-serializer@2.0.0:
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
dependencies:
domelementtype: 2.3.0
domhandler: 5.0.3
entities: 4.5.0
dev: false
/domelementtype@2.3.0:
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
dev: false
/domhandler@5.0.3:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
dependencies:
domelementtype: 2.3.0
dev: false
/domutils@3.0.1:
resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==}
dependencies:
dom-serializer: 2.0.0
domelementtype: 2.3.0
domhandler: 5.0.3
dev: false
/dset@3.1.2:
resolution: {integrity: sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==}
engines: {node: '>=4'}
@ -1808,6 +1857,11 @@ packages:
space-separated-tokens: 2.0.2
dev: false
/he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
dev: false
/html-entities@2.3.3:
resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
dev: false
@ -2707,6 +2761,13 @@ packages:
lodash: 4.17.21
dev: false
/node-html-parser@6.1.5:
resolution: {integrity: sha512-fAaM511feX++/Chnhe475a0NHD8M7AxDInsqQpz6x63GRF7xYNdS8Vo5dKsIVPgsOvG7eioRRTZQnWBrhDHBSg==}
dependencies:
css-select: 5.1.0
he: 1.2.0
dev: false
/node-releases@2.0.10:
resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==}
dev: false
@ -2722,6 +2783,12 @@ packages:
path-key: 4.0.0
dev: false
/nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
dependencies:
boolbase: 1.0.0
dev: false
/onetime@5.1.2:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
engines: {node: '>=6'}

View file

@ -0,0 +1,8 @@
---
import { transform } from "./transform";
const html = await Astro.slots.render('default');
const lyrics = transform(html);
---
<section class="lyrics" set:html={lyrics}></section>

View file

@ -0,0 +1,87 @@
import { Node, HTMLElement, parse } from 'node-html-parser';
interface Stack {
[key: string]: string[][];
}
interface Verse {
[key: string]: string[];
}
function extractLines(nodes: Node[]): string[] {
return nodes
.map(node => node.text)
.filter(text => text != '\n');
}
function createVerse(data: Stack, lang: string) {
(lang in data)
? data[lang].push([])
: data[lang] = [[]];
}
function toStack(html: string): Stack {
const root = parse(html);
const stack: Stack = {};
const nodes = root.childNodes as HTMLElement[];
nodes.reduce((lang, node) => {
switch (node.rawTagName) {
case 'h1': {
const lang: string = node.id.replace(/-.+/, '');
createVerse(stack, lang);
return lang;
}
case 'ul': {
const lines = extractLines(node.childNodes);
stack[lang].at(-1)!.push(...lines);
return lang;
}
}
return lang;
}, '');
return stack;
}
function reduceStack(stack: Stack): Verse[] {
const langs = Object.keys(stack);
const length = langs.map(lang => stack[lang].length).reduce((a, b) => Math.max(a, b));
const verses: Verse[] = [];
for (const _ of Array(length)) {
const verse: Verse = {};
for (const lang of langs) {
const lines = stack[lang].pop();
verse[lang] = lines ? lines : [];
}
verses.push(verse);
}
return verses.reverse();
}
function toHtml(verses: Verse[]): string {
const keys = Object.keys(verses[0]);
const head = keys.map(lang => `<th>${lang}</th>`);
const rows = verses.map(verse =>
`<tr>${keys.map(lang =>
`<td>${verse[lang].map(line =>
`<span>${line}</span><br/>`).join('')}
</td>`).join('')}
</tr>`
)
.join('');
return [
"<table>",
`<tr>${head.join('')}</tr>`,
rows,
"</table>",
].join('');
}
export function transform(html: string) {
return toHtml(reduceStack(toStack(html)));
}

View file

@ -0,0 +1,33 @@
---
title: Black Eyes
date: 2023-04-25
---
import Lyrics from '../../components/lyrics/Lyrics.astro';
<Lyrics>
# Japanese
- 瞬きをして 切り取る時間
- 何気なくても 大切な今を
- 忘れないで 居られるように
- いつか 頭の中
- 掻き消して しまっても
# Romaji
- fddsfsaf
- fdsfadsf
- test
- test
---
# Japanese
- 瞬きをして 切り取る時間ff
- 何気なくても 大切な今を
- 忘れないで 居られるように
- いつか 頭の中
- 掻き消して しまっても
# Romaji
- fddsfsaf
- fdsfadsf
- test
- test
</Lyrics>

12
src/layouts/Lyrics.astro Normal file
View file

@ -0,0 +1,12 @@
---
import Base from "./Base.astro";
---
<Base>
<main class="l_pages">
<article class="l_pages__list">
<slot/>
</article>
</main>
</Base>

View file

@ -0,0 +1,16 @@
---
import Lyrics from "../../layouts/Lyrics.astro";
import { getCollection } from "astro:content";
export async function getStaticPaths() {
return (await getCollection('lyrics'))
.map(entry => ({params: {slug: entry.slug}, props: {entry}}));
}
const { entry } = Astro.props;
const { Content } = await entry.render();
---
<Lyrics>
<Content />
</Lyrics>