Nest songs under circles
This commit is contained in:
parent
e8b653f8f3
commit
28bde28f46
|
@ -27,5 +27,5 @@ export default defineConfig({
|
||||||
integrations: [
|
integrations: [
|
||||||
mdx(),
|
mdx(),
|
||||||
solid(),
|
solid(),
|
||||||
],
|
]
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { defineMarkdocConfig } from '@astrojs/markdoc/config';
|
|
||||||
import Lyrics from './src/components/markdown/lyrics/Lyrics.astro';
|
|
||||||
|
|
||||||
|
|
||||||
export default defineMarkdocConfig({
|
|
||||||
tags: {
|
|
||||||
lyrics: {
|
|
||||||
render: Lyrics,
|
|
||||||
attributes: {
|
|
||||||
type: { type: String },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
15
src/components/markdown/Album.astro
Normal file
15
src/components/markdown/Album.astro
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
album: {
|
||||||
|
title: string;
|
||||||
|
cover: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { album } = Astro.props;
|
||||||
|
---
|
||||||
|
<a class="c-album" href={album.url}>
|
||||||
|
<img class="c-album__image" src={album.cover} alt=""/>
|
||||||
|
<div class="c-album__title">{album.title}</div>
|
||||||
|
</a>
|
|
@ -5,7 +5,7 @@ interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
cat: string;
|
cat: string;
|
||||||
track: number;
|
track: number;
|
||||||
circle: string;
|
name: string;
|
||||||
composer?: string;
|
composer?: string;
|
||||||
lyrics?: string;
|
lyrics?: string;
|
||||||
vocal?: string[];
|
vocal?: string[];
|
||||||
|
@ -33,7 +33,7 @@ const { metadata } = Astro.props;
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Circle</td>
|
<td>Circle</td>
|
||||||
<td>{metadata.circle}</td>
|
<td>{metadata.name}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Composer</td>
|
<td>Composer</td>
|
||||||
|
|
12
src/content/_templates/_song.md
Normal file
12
src/content/_templates/_song.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
title: Title
|
||||||
|
composer: Composer
|
||||||
|
lyrics: Lirycist
|
||||||
|
origin:
|
||||||
|
- Original title
|
||||||
|
album:
|
||||||
|
ARCD0051:
|
||||||
|
track: 7
|
||||||
|
vocal:
|
||||||
|
- Vocalist
|
||||||
|
---
|
13
src/content/songs/arcd0054/beautiful sky.md
Normal file
13
src/content/songs/arcd0054/beautiful sky.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
slug: beautiful-sky
|
||||||
|
title: Beautiful Sky
|
||||||
|
composer: Masayoshi Minoshima
|
||||||
|
lyrics: Mei Ayakura
|
||||||
|
origin:
|
||||||
|
- U.N.オーエンは彼女なのか?
|
||||||
|
album:
|
||||||
|
ARCD0054:
|
||||||
|
track: 2
|
||||||
|
vocal:
|
||||||
|
- nachi
|
||||||
|
---
|
|
@ -1,10 +1,13 @@
|
||||||
---
|
---
|
||||||
|
slug: dont-lose
|
||||||
title: "Don't lose"
|
title: "Don't lose"
|
||||||
origin:
|
origin:
|
||||||
- 亡き王女の為のセプテット
|
- 亡き王女の為のセプテット
|
||||||
album:
|
album:
|
||||||
ARCD0054:
|
ARCD0054:
|
||||||
track: 7
|
track: 7
|
||||||
|
vocal:
|
||||||
|
- nomico
|
||||||
---
|
---
|
||||||
|
|
||||||
# Japanese
|
# Japanese
|
|
@ -1,12 +1,22 @@
|
||||||
---
|
---
|
||||||
|
slug: dream-again
|
||||||
title: "Dream Again"
|
title: "Dream Again"
|
||||||
|
composer: Camellia
|
||||||
|
lyrics: Camellia
|
||||||
origin:
|
origin:
|
||||||
- the Last Judgment
|
- the Last Judgment
|
||||||
album:
|
album:
|
||||||
ARCD0054:
|
ARCD0054:
|
||||||
track: 5
|
track: 5
|
||||||
|
vocal:
|
||||||
|
- Mei Ayakura
|
||||||
---
|
---
|
||||||
|
|
||||||
# Japanese
|
# Japanese
|
||||||
|
- 秒針の音が響空間 狭くて安心するほど
|
||||||
|
- 割り込んだ感覚に目を閉じる 光がまた眩かしすぎて
|
||||||
|
|
||||||
- どこまでも続いていく階段 [降]{くだ}った途方もないほど
|
- どこまでも続いていく階段 [降]{くだ}った途方もないほど
|
||||||
- 行きたい場所はもう決まっている 幻想の声のする所
|
- 行きたい場所はもう決まっている 幻想の声のする所
|
||||||
|
|
||||||
|
- 夢溢れる海へ
|
|
@ -1,4 +1,5 @@
|
||||||
---
|
---
|
||||||
|
slug: black-eyes
|
||||||
title: Black Eyes
|
title: Black Eyes
|
||||||
composer: Kirin (EastNewSound)
|
composer: Kirin (EastNewSound)
|
||||||
lyrics: Mei Ayakura
|
lyrics: Mei Ayakura
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"Alstroemeria Records": {
|
"alstroemeria-records": {
|
||||||
|
"name": "Alstroemeria Records",
|
||||||
"albums": {
|
"albums": {
|
||||||
"ARCD0051": {
|
"ARCD0051": {
|
||||||
"title": "Engaged Dancehall",
|
"title": "Engaged Dancehall",
|
||||||
|
|
39
src/pages/songs/[circle].astro
Normal file
39
src/pages/songs/[circle].astro
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
import Base from "@layouts/Base.astro";
|
||||||
|
import Album from "@components/markdown/Album.astro";
|
||||||
|
import Header from "@components/headers/Base.astro";
|
||||||
|
import { CIRCLES } from "@utils/songs/data";
|
||||||
|
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
return Object.keys(CIRCLES)
|
||||||
|
.map(circle => ({
|
||||||
|
params: { circle },
|
||||||
|
props: { albums: CIRCLES[circle].albums }
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
albums: typeof CIRCLES[string]['albums'];
|
||||||
|
}
|
||||||
|
|
||||||
|
const circle = Astro.params.circle!;
|
||||||
|
const albums = Astro.props.albums;
|
||||||
|
const items = Object.keys(albums)
|
||||||
|
.map(slug => ({
|
||||||
|
title: albums[slug].title,
|
||||||
|
cover: albums[slug].cover,
|
||||||
|
url: `/songs/${circle}/${slug}/`
|
||||||
|
}))
|
||||||
|
---
|
||||||
|
|
||||||
|
<Base>
|
||||||
|
<main>
|
||||||
|
<article>
|
||||||
|
<Header title={CIRCLES[circle].name} />
|
||||||
|
<section class="l-album-grid">
|
||||||
|
{items.map(album => <Album album={album} />)}
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
</Base>
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
import Base from "../../layouts/Base.astro";
|
import Base from "@layouts/Base.astro";
|
||||||
import Header from '../../components/headers/Base.astro';
|
import Header from '@components/headers/Base.astro';
|
||||||
import { CollectionEntry, getCollection } from 'astro:content';
|
import { CollectionEntry, getCollection } from 'astro:content';
|
||||||
import { ALBUMS, getAllCats } from "../../utils/songs/data";
|
import { ALBUMS, getAllCats, order } from "@utils/songs/data";
|
||||||
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
|
@ -10,11 +10,15 @@ export async function getStaticPaths() {
|
||||||
const cats = getAllCats(songs);
|
const cats = getAllCats(songs);
|
||||||
|
|
||||||
return [...cats].map(cat => ({
|
return [...cats].map(cat => ({
|
||||||
params: {cat},
|
params: { circle: ALBUMS[cat].circle, cat },
|
||||||
props: {
|
props: {
|
||||||
songs: songs
|
songs: songs
|
||||||
.filter(entry => cat in entry.data.album)
|
.filter(entry => cat in entry.data.album)
|
||||||
.map(song => ({ frontmatter: song.data, slug: `/songs/${cat}/${song.slug}/` }))
|
.sort(order(cat))
|
||||||
|
.map(song => ({
|
||||||
|
frontmatter: song.data,
|
||||||
|
slug: `/songs/${ALBUMS[cat].circle}/${cat}/${song.slug}/`
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -34,7 +38,7 @@ const album = ALBUMS[cat!];
|
||||||
<Base>
|
<Base>
|
||||||
<main class="l-songs-cat">
|
<main class="l-songs-cat">
|
||||||
<article class="l-songs-cat__article">
|
<article class="l-songs-cat__article">
|
||||||
<Header title={`${cat} - ${album.title}`} />
|
<Header title={album.title} />
|
||||||
<div class="l-songs-cat__list">
|
<div class="l-songs-cat__list">
|
||||||
{songs.map(song => [
|
{songs.map(song => [
|
||||||
<span>{song.frontmatter.album[cat!].track}</span>
|
<span>{song.frontmatter.album[cat!].track}</span>
|
|
@ -1,15 +1,18 @@
|
||||||
---
|
---
|
||||||
import Base from "../../layouts/Base.astro";
|
import Base from "@layouts/Base.astro";
|
||||||
import Song from "../../components/markdown/Song.astro";
|
import Song from "@components/markdown/Song.astro";
|
||||||
import Lyrics from "../../components/markdown/Lyrics.astro";
|
import Lyrics from "@components/markdown/Lyrics.astro";
|
||||||
import { CollectionEntry, getCollection } from "astro:content";
|
import { CollectionEntry, getCollection } from "astro:content";
|
||||||
import { ALBUMS } from "../../utils/songs/data";
|
import { ALBUMS } from "@utils/songs/data";
|
||||||
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
return (await getCollection('songs'))
|
return (await getCollection('songs'))
|
||||||
.map(song => Object.keys(song.data.album)
|
.map(song => Object.keys(song.data.album)
|
||||||
.map(cat => ({ params: {slug: `${cat}/${song.slug}`}, props: {song, cat} })))
|
.map(cat => ({
|
||||||
|
params: { circle: ALBUMS[cat].circle, cat, song: song.slug},
|
||||||
|
props: { song, cat }
|
||||||
|
})))
|
||||||
.flat()
|
.flat()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
---
|
---
|
||||||
import List from "../../layouts/List.astro";
|
import List from "../../layouts/List.astro";
|
||||||
import { getCollection } from 'astro:content';
|
import { CIRCLES } from "../../utils/songs/data";
|
||||||
import { ALBUMS, getAllCats } from "../../utils/songs/data";
|
|
||||||
|
|
||||||
|
|
||||||
const pages = [...getAllCats(await getCollection('songs'))]
|
const pages = Object.keys(CIRCLES)
|
||||||
.sort((a, b) => a < b ? 1 : -1)
|
.map(slug => ({ title: CIRCLES[slug].name, slug: `/songs/${slug}/` }))
|
||||||
.map(catalog => ({
|
.sort((a, b) => a.title < b.title ? -1 : 1)
|
||||||
title: `${catalog} - ${ALBUMS[catalog].title}`,
|
|
||||||
slug: `/songs/${catalog}/`
|
|
||||||
}));
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<List title="Albums" pages={pages} />
|
<List title="Circles" pages={pages}/>
|
||||||
|
|
5
src/schema.d.ts
vendored
5
src/schema.d.ts
vendored
|
@ -1,9 +1,10 @@
|
||||||
/** @file src/data/circles.json */
|
/** @file src/data/circles.json */
|
||||||
interface CirclesSchema {
|
interface CirclesSchema {
|
||||||
/** Circle name */
|
/** slug */
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
|
name: string,
|
||||||
albums: {
|
albums: {
|
||||||
/** Catalog number */
|
/** catalog number */
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
title: string;
|
title: string;
|
||||||
cover: string;
|
cover: string;
|
||||||
|
|
16
src/styles/components/_album.scss
Normal file
16
src/styles/components/_album.scss
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
.c-album {
|
||||||
|
padding: 0.5em;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
box-shadow: var(--shadow-l);
|
||||||
|
transition: box-shadow ease-in-out 0.2s;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: var(--shadow-m);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__image {
|
||||||
|
width: 16em;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,14 @@
|
||||||
|
.l-album-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 2em;
|
||||||
|
|
||||||
|
&__item img {
|
||||||
|
width: 20em;
|
||||||
|
height: 20em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.l-songs-cat {
|
.l-songs-cat {
|
||||||
padding: 1.5em;
|
padding: 1.5em;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
@use 'components/tab';
|
@use 'components/tab';
|
||||||
@use 'components/lyrics';
|
@use 'components/lyrics';
|
||||||
@use 'components/song';
|
@use 'components/song';
|
||||||
|
@use 'components/album';
|
||||||
|
|
||||||
// Partials
|
// Partials
|
||||||
@use 'partials/nav';
|
@use 'partials/nav';
|
||||||
|
|
|
@ -6,8 +6,10 @@ type Song = CollectionEntry<'songs'>;
|
||||||
|
|
||||||
interface Metadata {
|
interface Metadata {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
|
/** Circle slug */
|
||||||
|
circle: string;
|
||||||
/** Circle name */
|
/** Circle name */
|
||||||
circle: string,
|
name: string,
|
||||||
/** Album title */
|
/** Album title */
|
||||||
title: string,
|
title: string,
|
||||||
/** Path to album cover image */
|
/** Path to album cover image */
|
||||||
|
@ -16,6 +18,10 @@ interface Metadata {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function order(cat: string) {
|
||||||
|
return (a: Song, b: Song) => a.data.album[cat].track < b.data.album[cat].track ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
export function getAllCats(songs: Song[]): Set<string> {
|
export function getAllCats(songs: Song[]): Set<string> {
|
||||||
return songs.reduce(
|
return songs.reduce(
|
||||||
(cats, next) => (
|
(cats, next) => (
|
||||||
|
@ -32,10 +38,10 @@ function createMetadata(circles: CirclesSchema): Metadata {
|
||||||
for (const circle of Object.keys(circles)) {
|
for (const circle of Object.keys(circles)) {
|
||||||
const data = circles[circle];
|
const data = circles[circle];
|
||||||
for (const cat of Object.keys(data.albums))
|
for (const cat of Object.keys(data.albums))
|
||||||
metadata[cat] = { circle, ...data.albums[cat] }
|
metadata[cat] = { circle, name: data.name, ...data.albums[cat] }
|
||||||
}
|
}
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const CIRCLES: CirclesSchema = circles;
|
||||||
export const ALBUMS: Metadata = createMetadata(circles);
|
export const ALBUMS: Metadata = createMetadata(circles);
|
||||||
|
|
|
@ -15,6 +15,7 @@ function increaseStack(data: Stack, lang: string) {
|
||||||
|
|
||||||
function fromMarkdown(markdown: string): Stack {
|
function fromMarkdown(markdown: string): Stack {
|
||||||
const stack: Stack = {};
|
const stack: Stack = {};
|
||||||
|
if (!markdown) return stack;
|
||||||
|
|
||||||
let space = true;
|
let space = true;
|
||||||
let lang = '';
|
let lang = '';
|
||||||
|
|
|
@ -3,6 +3,12 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"jsxImportSource": "solid-js"
|
"jsxImportSource": "solid-js",
|
||||||
|
"baseUrl": "src",
|
||||||
|
"paths": {
|
||||||
|
"@layouts/*": ["layouts/*"],
|
||||||
|
"@components/*": ["components/*"],
|
||||||
|
"@utils/*": ["utils/*"],
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}
|
}
|
Loading…
Reference in a new issue