chore: myriad fixes + artist pages
This commit is contained in:
parent
aec8471b06
commit
ff00020b70
53 changed files with 753 additions and 486 deletions
|
@ -1,4 +1,4 @@
|
|||
import { fetchGlobals } from "@utils/data/globals";
|
||||
import { fetchGlobals } from "@utils/data/globals.js";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
import Layout from '@layouts/Layout.astro';
|
||||
import BlockRenderer from '@components/blocks/BlockRenderer.astro';
|
||||
import { fetchPages } from '@utils/data/pages';
|
||||
import { fetchGlobalData } from '@utils/data/global/index.js';
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import BlockRenderer from "@components/blocks/BlockRenderer.astro";
|
||||
import { fetchPages } from "@utils/data/pages.js";
|
||||
import { fetchGlobalData } from "@utils/data/global/index.js";
|
||||
|
||||
export const prerender = true;
|
||||
|
||||
|
@ -26,7 +26,5 @@ const currentUrl = Astro.url.pathname;
|
|||
updated={page.updated}
|
||||
currentUrl={currentUrl}
|
||||
>
|
||||
{page.blocks.map((block) => (
|
||||
<BlockRenderer block={block} />
|
||||
))}
|
||||
{page.blocks.map((block) => <BlockRenderer block={block} />)}
|
||||
</Layout>
|
||||
|
|
|
@ -1,21 +1,28 @@
|
|||
---
|
||||
import Layout from '@layouts/Layout.astro';
|
||||
import { IconRss, IconJson, IconMailPlus, IconBrandMastodon } from "@tabler/icons-react";
|
||||
import { fetchBlogroll } from '@utils/data/blogroll.js';
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import {
|
||||
IconRss,
|
||||
IconJson,
|
||||
IconMailPlus,
|
||||
IconBrandMastodon,
|
||||
} from "@tabler/icons-react";
|
||||
import { fetchBlogroll } from "@utils/data/blogroll.js";
|
||||
|
||||
const blogroll = await fetchBlogroll();
|
||||
const currentUrl = Astro.url.pathname;
|
||||
const title = "Blogroll";
|
||||
const description = "These are awesome blogs that I enjoy and you may enjoy too.";
|
||||
const description =
|
||||
"These are awesome blogs that I enjoy and you may enjoy too.";
|
||||
---
|
||||
<Layout
|
||||
pageTitle={title}
|
||||
description={description}
|
||||
currentUrl={currentUrl}
|
||||
>
|
||||
|
||||
<Layout pageTitle={title} description={description} currentUrl={currentUrl}>
|
||||
<h2 class="page-title">{title}</h2>
|
||||
<p>
|
||||
You can <a href="/blogroll.opml" class="plausible-event-name=Blogroll+OPML+download">download an OPML file</a> containing all of these feeds and import them into your RSS reader.
|
||||
You can <a
|
||||
href="/blogroll.opml"
|
||||
class="plausible-event-name=Blogroll+OPML+download"
|
||||
>download an OPML file</a
|
||||
> containing all of these feeds and import them into your RSS reader.
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
|
@ -26,39 +33,60 @@ const description = "These are awesome blogs that I enjoy and you may enjoy too.
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{blogroll.map((blog) => (
|
||||
<tr>
|
||||
<td>{blog.name}</td>
|
||||
<td>
|
||||
<a href={blog.url}>{blog.url.replace("https://", "")}</a>
|
||||
</td>
|
||||
<td class="blog-roll-icons">
|
||||
{blog.rss_feed && (
|
||||
<a class="rss" href={blog.rss_feed} aria-label={`RSS feed for ${blog.name}`}>
|
||||
<IconRss size={16} />
|
||||
</a>
|
||||
)}
|
||||
{blog.json_feed && (
|
||||
<a class="json" href={blog.json_feed} aria-label={`JSON feed for ${blog.name}`}>
|
||||
<IconJson size={16} />
|
||||
</a>
|
||||
)}
|
||||
{blog.newsletter && (
|
||||
<a class="mail-plus" href={blog.newsletter} aria-label={`Subscribe to ${blog.name}'s newsletter`}>
|
||||
<IconMailPlus size={16} />
|
||||
</a>
|
||||
)}
|
||||
{blog.mastodon && (
|
||||
<a class="brand-mastodon" href={blog.mastodon} aria-label={`Follow ${blog.name} on Mastodon`}>
|
||||
<IconBrandMastodon size={16} />
|
||||
</a>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{
|
||||
blogroll.map((blog) => (
|
||||
<tr>
|
||||
<td>{blog.name}</td>
|
||||
<td>
|
||||
<a href={blog.url}>{blog.url.replace("https://", "")}</a>
|
||||
</td>
|
||||
<td class="blog-roll-icons">
|
||||
{blog.rss_feed && (
|
||||
<a
|
||||
class="rss"
|
||||
href={blog.rss_feed}
|
||||
aria-label={`RSS feed for ${blog.name}`}
|
||||
>
|
||||
<IconRss size={16} />
|
||||
</a>
|
||||
)}
|
||||
{blog.json_feed && (
|
||||
<a
|
||||
class="json"
|
||||
href={blog.json_feed}
|
||||
aria-label={`JSON feed for ${blog.name}`}
|
||||
>
|
||||
<IconJson size={16} />
|
||||
</a>
|
||||
)}
|
||||
{blog.newsletter && (
|
||||
<a
|
||||
class="mail-plus"
|
||||
href={blog.newsletter}
|
||||
aria-label={`Subscribe to ${blog.name}'s newsletter`}
|
||||
>
|
||||
<IconMailPlus size={16} />
|
||||
</a>
|
||||
)}
|
||||
{blog.mastodon && (
|
||||
<a
|
||||
class="brand-mastodon"
|
||||
href={blog.mastodon}
|
||||
aria-label={`Follow ${blog.name} on Mastodon`}
|
||||
>
|
||||
<IconBrandMastodon size={16} />
|
||||
</a>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
Head on over to <a href="https://blogroll.org">blogroll.org</a> to find more blogs to follow or search for feeds using <a href="https://feedle.world">feedle</a>.
|
||||
Head on over to <a href="https://blogroll.org">blogroll.org</a> to find more
|
||||
blogs to follow or search for feeds using <a href="https://feedle.world"
|
||||
>feedle</a
|
||||
>.
|
||||
</p>
|
||||
</Layout>
|
||||
</Layout>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { fetchBlogroll } from "@utils/data/blogroll";
|
||||
import { fetchGlobals } from "@utils/data/globals";
|
||||
import { fetchBlogroll } from "@utils/data/blogroll.js";
|
||||
import { fetchGlobals } from "@utils/data/global/index.js";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
|
|
|
@ -5,7 +5,7 @@ import AssociatedMedia from "@components/blocks/AssociatedMedia.astro";
|
|||
import ProgressBar from "@components/media/ProgressBar.astro";
|
||||
import { IconArrowLeft, IconHeart, IconNeedle } from "@tabler/icons-react";
|
||||
import { fetchBookByUrl } from "@utils/data/dynamic/bookByUrl.js";
|
||||
import { fetchGlobalData } from '@utils/data/global/index.js';
|
||||
import { fetchGlobalData } from "@utils/data/global/index.js";
|
||||
|
||||
const { isbn } = Astro.params;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import Layout from "@layouts/Layout.astro";
|
|||
import Rss from "@components/blocks/banners/Rss.astro";
|
||||
import ProgressBar from "@components/media/ProgressBar.astro";
|
||||
import { fetchBooks } from "@utils/data/books.js";
|
||||
import { fetchGlobalData } from '@utils/data/global/index.js';
|
||||
import { fetchGlobalData } from "@utils/data/global/index.js";
|
||||
import { md, htmlTruncate } from "@utils/helpers/general.js";
|
||||
|
||||
const books = await fetchBooks();
|
||||
|
@ -30,7 +30,6 @@ const bookYearLinks = (years) =>
|
|||
---
|
||||
|
||||
<Layout
|
||||
globals={globals}
|
||||
pageTitle={title}
|
||||
description={description}
|
||||
updated={updated}
|
||||
|
@ -43,7 +42,7 @@ const bookYearLinks = (years) =>
|
|||
>{currentBookCount} books</strong
|
||||
> this year.
|
||||
</p>
|
||||
<p set:html={bookYearLinks(books.years)}></p>
|
||||
<p set:html={bookYearLinks(books.years)} />
|
||||
<Rss
|
||||
url="/feeds/books"
|
||||
text="Subscribe to my books feed or follow along on this page"
|
||||
|
|
|
@ -2,8 +2,12 @@
|
|||
import Layout from "@layouts/Layout.astro";
|
||||
import Grid from "@components/media/Grid.astro";
|
||||
import { IconArrowLeft } from "@tabler/icons-react";
|
||||
import { filterBooksByStatus, findFavoriteBooks, mediaLinks } from "@utils/helpers/media.js";
|
||||
import { fetchGlobalData } from '@utils/data/global/index.js';
|
||||
import {
|
||||
filterBooksByStatus,
|
||||
findFavoriteBooks,
|
||||
mediaLinks,
|
||||
} from "@utils/helpers/media.js";
|
||||
import { fetchGlobalData } from "@utils/data/global/index.js";
|
||||
import { fetchBooks } from "@utils/data/books.js";
|
||||
import { DateTime } from "luxon";
|
||||
|
||||
|
@ -26,21 +30,30 @@ const description = isCurrentYear
|
|||
const intro = isCurrentYear
|
||||
? `
|
||||
I've finished <strong class="highlight-text">${bookData.length} books</strong> this year.
|
||||
${favoriteBooks ? ` Among my favorites are ${favoriteBooks}.` : ''}
|
||||
${favoriteBooks ? ` Among my favorites are ${favoriteBooks}.` : ""}
|
||||
`
|
||||
: `
|
||||
I finished <strong class="highlight-text">${bookData.length} books</strong> in
|
||||
<strong class="highlight-text">${year}</strong>.
|
||||
${favoriteBooks ? ` Among my favorites were ${favoriteBooks}.` : ''}
|
||||
${favoriteBooks ? ` Among my favorites were ${favoriteBooks}.` : ""}
|
||||
`;
|
||||
---
|
||||
|
||||
<Layout globals={globals} pageTitle={pageTitle} description={description} schema="books-year">
|
||||
<Layout
|
||||
pageTitle={pageTitle}
|
||||
description={description}
|
||||
schema="books-year"
|
||||
>
|
||||
<a href="/books" class="back-link">
|
||||
<IconArrowLeft size={18} /> Back to books
|
||||
</a>
|
||||
<h2 class="page-title">{year} / Books</h2>
|
||||
<div set:html={intro}></div>
|
||||
<div set:html={intro} />
|
||||
<hr />
|
||||
<Grid globals={globals} data={bookData} shape="vertical" count={200} loading="eager" />
|
||||
<Grid
|
||||
data={bookData}
|
||||
shape="vertical"
|
||||
count={200}
|
||||
loading="eager"
|
||||
/>
|
||||
</Layout>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { generateJsonFeed } from '@utils/generateJsonFeed';
|
||||
import { fetchGlobals } from '@utils/data/globals';
|
||||
import { fetchActivity } from '@utils/data/activity';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { generateJsonFeed } from "@utils/generateJsonFeed.js";
|
||||
import { fetchGlobals } from "@utils/data/globals.js";
|
||||
import { fetchActivity } from "@utils/data/activity.js";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const globals = await fetchGlobals();
|
||||
|
@ -15,7 +15,7 @@ export async function getStaticPaths() {
|
|||
data: activity,
|
||||
});
|
||||
|
||||
const filePath = path.resolve('public/feeds/all.json');
|
||||
const filePath = path.resolve("public/feeds/all.json");
|
||||
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
||||
await fs.writeFile(filePath, feed);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { generateRssFeed } from "@utils/generateRssFeed";
|
||||
import { fetchGlobals } from "@utils/data/globals";
|
||||
import { fetchActivity } from "@utils/data/activity";
|
||||
import { fetchGlobals } from "@utils/data/globals.js";
|
||||
import { fetchActivity } from "@utils/data/activity.js";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { generateJsonFeed } from "@utils/generateJsonFeed";
|
||||
import { fetchGlobals } from "@utils/data/globals";
|
||||
import { fetchBooks } from "@utils/data/books";
|
||||
import { generateJsonFeed } from "@utils/generateJsonFeed.js";
|
||||
import { fetchGlobals } from "@utils/data/globals.js";
|
||||
import { fetchBooks } from "@utils/data/books.js";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { generateRssFeed } from "@utils/generateRssFeed";
|
||||
import { fetchGlobals } from "@utils/data/globals";
|
||||
import { fetchBooks } from "@utils/data/books";
|
||||
import { fetchGlobals } from "@utils/data/globals.js";
|
||||
import { fetchBooks } from "@utils/data/books.js";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { generateJsonFeed } from "@utils/generateJsonFeed";
|
||||
import { fetchGlobals } from "@utils/data/globals";
|
||||
import { fetchLinks } from "@utils/data/links";
|
||||
import { generateJsonFeed } from "@utils/generateJsonFeed.js";
|
||||
import { fetchGlobals } from "@utils/data/globals.js";
|
||||
import { fetchLinks } from "@utils/data/links.js";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { generateRssFeed } from "@utils/generateRssFeed";
|
||||
import { fetchGlobals } from "@utils/data/globals";
|
||||
import { fetchGlobals } from "@utils/data/globals.js";
|
||||
import { fetchLinks } from "@utils/data/links";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { generateJsonFeed } from '@utils/generateJsonFeed';
|
||||
import { fetchGlobals } from '@utils/data/globals';
|
||||
import { generateJsonFeed } from '@utils/generateJsonFeed.js';
|
||||
import { fetchGlobals } from '@utils/data/globals.js';
|
||||
import { fetchMovies } from '@utils/data/movies';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { generateRssFeed } from "@utils/generateRssFeed";
|
||||
import { fetchGlobals } from "@utils/data/globals";
|
||||
import { fetchMovies } from "@utils/data/movies";
|
||||
import { fetchGlobals } from "@utils/data/globals.js";
|
||||
import { fetchMovies } from "@utils/data/movies.js";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { generateJsonFeed } from "@utils/generateJsonFeed";
|
||||
import { fetchGlobals } from "@utils/data/globals";
|
||||
import { fetchAllPosts } from "@utils/data/posts";
|
||||
import { generateJsonFeed } from "@utils/generateJsonFeed.js";
|
||||
import { fetchGlobals } from "@utils/data/globals.js";
|
||||
import { fetchAllPosts } from "@utils/data/posts.js";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { generateRssFeed } from "@utils/generateRssFeed";
|
||||
import { fetchGlobals } from "@utils/data/globals";
|
||||
import { fetchAllPosts } from "@utils/data/posts";
|
||||
import { fetchGlobals } from "@utils/data/globals.js";
|
||||
import { fetchAllPosts } from "@utils/data/posts.js";
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { fetchGlobals } from '@utils/data/globals';
|
||||
import { fetchGlobals } from '@utils/data/globals.js';
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
---
|
||||
import Layout from '@layouts/Layout.astro';
|
||||
import Intro from '@components/home/Intro.astro';
|
||||
import RecentActivity from '@components/home/RecentActivity.astro';
|
||||
import RecentPosts from '@components/home/RecentPosts.astro';
|
||||
import { fetchGlobalData } from '@utils/data/global/index.js';
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import Intro from "@components/home/Intro.astro";
|
||||
import RecentActivity from "@components/home/RecentActivity.astro";
|
||||
import RecentPosts from "@components/home/RecentPosts.astro";
|
||||
import { fetchGlobalData } from "@utils/data/global/index.js";
|
||||
|
||||
const { globals } = await fetchGlobalData(Astro);
|
||||
const schema = 'blog';
|
||||
const schema = "blog";
|
||||
const pageTitle = globals.site_name;
|
||||
const description = 'This is a blog post description';
|
||||
const description = "This is a blog post description";
|
||||
const ogImage = globals.cdn_url + globals.avatar;
|
||||
const fullUrl = globals.url + '/blog/my-post';
|
||||
const fullUrl = globals.url + "/blog/my-post";
|
||||
const themeColor = globals.theme_color;
|
||||
---
|
||||
|
||||
<Layout
|
||||
pageTitle={pageTitle}
|
||||
description={description}
|
||||
|
@ -24,4 +25,4 @@ const themeColor = globals.theme_color;
|
|||
<Intro intro={globals.intro} />
|
||||
<RecentActivity />
|
||||
<RecentPosts />
|
||||
</Layout>
|
||||
</Layout>
|
||||
|
|
|
@ -3,16 +3,20 @@ import Layout from "@layouts/Layout.astro";
|
|||
import Paginator from "@components/nav/Paginator.astro";
|
||||
import RssBanner from "@components/blocks/banners/Rss.astro";
|
||||
import { fetchLinks } from "@utils/data/links.js";
|
||||
import { fetchGlobalData } from '@utils/data/global/index.js';
|
||||
import { fetchGlobalData } from "@utils/data/global/index.js";
|
||||
|
||||
const { globals } = await fetchGlobalData(Astro);
|
||||
const links = await fetchLinks();
|
||||
const title = "Links";
|
||||
const description = "These are links I've liked or otherwise found interesting. They're all added manually, after having been read and, I suppose, properly considered.";
|
||||
const description =
|
||||
"These are links I've liked or otherwise found interesting. They're all added manually, after having been read and, I suppose, properly considered.";
|
||||
const pageSize = 30;
|
||||
const currentPage = parseInt(Astro.url.searchParams.get("page") || "1", 10);
|
||||
const totalPages = Math.ceil(links.length / pageSize);
|
||||
const paginatedLinks = links.slice((currentPage - 1) * pageSize, currentPage * pageSize);
|
||||
const paginatedLinks = links.slice(
|
||||
(currentPage - 1) * pageSize,
|
||||
currentPage * pageSize
|
||||
);
|
||||
|
||||
const pagination = {
|
||||
currentPage,
|
||||
|
@ -29,37 +33,40 @@ const pagination = {
|
|||
---
|
||||
|
||||
<Layout
|
||||
globals={globals}
|
||||
pageTitle={title}
|
||||
description={description}
|
||||
currentUrl={Astro.url.pathname}
|
||||
>
|
||||
{currentPage === 1 && (
|
||||
<>
|
||||
<h2 class="page-title">{title}</h2>
|
||||
<p>{description}</p>
|
||||
<RssBanner
|
||||
url="/feeds/links"
|
||||
text="Subscribe to my links feed or follow along on this page"
|
||||
/>
|
||||
<hr />
|
||||
</>
|
||||
)}
|
||||
{
|
||||
currentPage === 1 && (
|
||||
<>
|
||||
<h2 class="page-title">{title}</h2>
|
||||
<p>{description}</p>
|
||||
<RssBanner
|
||||
url="/feeds/links"
|
||||
text="Subscribe to my links feed or follow along on this page"
|
||||
/>
|
||||
<hr />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
<div class="link-grid">
|
||||
{paginatedLinks.map((link) => (
|
||||
<div class="link-box">
|
||||
<a href={link.link} title={link.title}>
|
||||
<strong>{link.title}</strong>
|
||||
</a>
|
||||
{link.author && (
|
||||
<>
|
||||
{" via "}
|
||||
<a href={link.author.url}>{link.author.name}</a>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{
|
||||
paginatedLinks.map((link) => (
|
||||
<div class="link-box">
|
||||
<a href={link.link} title={link.title}>
|
||||
<strong>{link.title}</strong>
|
||||
</a>
|
||||
{link.author && (
|
||||
<>
|
||||
{" via "}
|
||||
<a href={link.author.url}>{link.author.name}</a>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<Paginator pagination={pagination} />
|
||||
|
|
133
src/pages/music/artists/[slug].astro
Normal file
133
src/pages/music/artists/[slug].astro
Normal file
|
@ -0,0 +1,133 @@
|
|||
---
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import ToggleContent from "@components/utils/ToggleContent.astro";
|
||||
import AssociatedMedia from "@components/blocks/AssociatedMedia.astro";
|
||||
import { IconArrowLeft, IconHeart, IconNeedle, IconMapPin, IconDeviceSpeaker } from "@tabler/icons-react";
|
||||
import { fetchGlobalData } from "@utils/data/global/index.js";
|
||||
import { fetchArtistByUrl } from "@utils/data/dynamic/artistByUrl.js";
|
||||
|
||||
const { globals } = await fetchGlobalData(Astro);
|
||||
const artist = await fetchArtistByUrl(Astro.url.pathname);
|
||||
|
||||
if (!artist) return Astro.redirect("/404", 404);
|
||||
|
||||
const pageTitle = `${artist.name} / Music`;
|
||||
const description = artist.description || `Learn more about ${artist.name}`;
|
||||
const alt = `${artist.name} / ${artist.country}`;
|
||||
const playLabel = artist.total_plays === 1 ? "play" : "plays";
|
||||
---
|
||||
|
||||
<Layout pageTitle={pageTitle} description={description} schema="artist">
|
||||
<a href="/music" class="back-link">
|
||||
<IconArrowLeft size={18} /> Back to music
|
||||
</a>
|
||||
<article class="artist-focus">
|
||||
<div class="artist-display">
|
||||
<img
|
||||
srcset={`
|
||||
${globals.cdn_url}${artist.image}?class=w200&type=webp 200w,
|
||||
${globals.cdn_url}${artist.image}?class=w600&type=webp 400w,
|
||||
${globals.cdn_url}${artist.image}?class=w800&type=webp 800w
|
||||
`}
|
||||
sizes="(max-width: 450px) 200px,
|
||||
(max-width: 850px) 400px,
|
||||
800px"
|
||||
src={`${globals.cdn_url}${artist.image}?class=w200&type=webp`}
|
||||
alt={alt}
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
width="200"
|
||||
height="200"
|
||||
/>
|
||||
<div class="media-meta">
|
||||
<span class="title"><strong>{artist.name}</strong></span>
|
||||
<span class="sub-meta country">
|
||||
<IconMapPin size={18} /> {artist.country}
|
||||
</span>
|
||||
{artist.favorite && (
|
||||
<span class="sub-meta favorite">
|
||||
<IconHeart size={18} /> This is one of my favorite artists!
|
||||
</span>
|
||||
)}
|
||||
{artist.tattoo && (
|
||||
<span class="sub-meta tattoo">
|
||||
<IconNeedle size={18} /> I have a tattoo inspired by this artist!
|
||||
</span>
|
||||
)}
|
||||
{artist.total_plays > 0 && (
|
||||
<span class="sub-meta">
|
||||
<strong class="highlight-text">{artist.total_plays} {playLabel}</strong>
|
||||
</span>
|
||||
)}
|
||||
<span class="sub-meta">
|
||||
<a href={artist.genre.url} title={`Learn more about ${artist.genre.name}`}>
|
||||
{artist.genre.name}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AssociatedMedia
|
||||
artists={artist.related_artists}
|
||||
books={artist.books}
|
||||
genres={artist.genres}
|
||||
movies={artist.movies}
|
||||
posts={artist.posts}
|
||||
shows={artist.shows}
|
||||
/>
|
||||
|
||||
{artist.description && (
|
||||
<>
|
||||
<h2>Overview</h2>
|
||||
<ToggleContent content={artist.description} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{artist.concerts && (
|
||||
<>
|
||||
<p id="concerts" class="concerts">
|
||||
<IconDeviceSpeaker size={18} /> I've seen this artist live!
|
||||
</p>
|
||||
<ul>
|
||||
{artist.concerts.map((concert) => {
|
||||
const venue = concert.venue_latitude && concert.venue_longitude
|
||||
? `<a href="https://www.openstreetmap.org/?mlat=${concert.venue_latitude}&mlon=${concert.venue_longitude}#map=18/${concert.venue_latitude}/${concert.venue_longitude}">${concert.venue_name_short}</a>`
|
||||
: concert.venue_name_short;
|
||||
|
||||
return (
|
||||
<li>
|
||||
On <strong class="highlight-text">{concert.date.toLocaleString(DateTime.DATE_MED)}</strong>
|
||||
{venue && <> at {venue}</>}
|
||||
{concert.notes && (
|
||||
<span> — {concert.notes}</span>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
|
||||
{artist.albums && (
|
||||
<>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Album</th>
|
||||
<th>Plays</th>
|
||||
<th>Year</th>
|
||||
</tr>
|
||||
{artist.albums.map((album) => (
|
||||
<tr>
|
||||
<td>{album.name}</td>
|
||||
<td>{album.total_plays}</td>
|
||||
<td>{album.release_year}</td>
|
||||
</tr>
|
||||
))}
|
||||
</table>
|
||||
<p>
|
||||
<em>These are the albums by this artist that are in my collection, not necessarily a comprehensive discography.</em>
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</article>
|
||||
</Layout>
|
|
@ -1,23 +1,24 @@
|
|||
import { albumReleasesCalendar } from '@utils/albumReleasesCalendar';
|
||||
import { fetchAlbumReleases } from '@utils/data/albumReleases';
|
||||
import { albumReleasesCalendar } from "@utils/albumReleasesCalendar.js";
|
||||
import { fetchAlbumReleases } from "@utils/data/albumReleases.js";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const { all: albumReleases } = await fetchAlbumReleases();
|
||||
const icsContent = await albumReleasesCalendar(albumReleases);
|
||||
|
||||
if (!icsContent) return new Response('Error generating ICS file', { status: 500 });
|
||||
if (!icsContent)
|
||||
return new Response("Error generating ICS file", { status: 500 });
|
||||
|
||||
return new Response(icsContent, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'text/calendar',
|
||||
'Content-Disposition': 'attachment; filename="releases.ics"',
|
||||
"Content-Type": "text/calendar",
|
||||
"Content-Disposition": 'attachment; filename="releases.ics"',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error generating album releases ICS file:', error);
|
||||
return new Response('Error generating album releases ICS file', {
|
||||
console.error("Error generating album releases ICS file:", error);
|
||||
return new Response("Error generating album releases ICS file", {
|
||||
status: 500,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import { IconStar } from '@tabler/icons-react';
|
||||
import { getCollection } from "astro:content";
|
||||
import { IconStar } from "@tabler/icons-react";
|
||||
import { fetchAllPosts } from "@data/posts.js";
|
||||
import { fetchGlobalData } from '@utils/data/global/index.js';
|
||||
import { fetchGlobalData } from "@utils/data/global/index.js";
|
||||
import Layout from "@layouts/Layout.astro";
|
||||
import Paginator from '@components/nav/Paginator.astro';
|
||||
import { md } from '@utils/helpers/general.js';
|
||||
import { DateTime } from 'luxon';
|
||||
import Paginator from "@components/nav/Paginator.astro";
|
||||
import { md } from "@utils/helpers/general.js";
|
||||
import { DateTime } from "luxon";
|
||||
|
||||
const posts = await fetchAllPosts();
|
||||
const { page } = Astro.props;
|
||||
|
@ -35,25 +35,23 @@ const pagination = {
|
|||
};
|
||||
---
|
||||
|
||||
<Layout
|
||||
globals={globals}
|
||||
pageTitle="All posts"
|
||||
currentUrl={currentUrl}
|
||||
>
|
||||
{paginatedPosts.map((post) => (
|
||||
<article>
|
||||
<div class="post-meta">
|
||||
{post.featured && <IconStar size={16} />}
|
||||
<time datetime={post.date}>
|
||||
{DateTime.fromISO(post.date).toLocaleString(DateTime.DATE_FULL)}
|
||||
</time>
|
||||
</div>
|
||||
<h3>
|
||||
<a href={post.url}>{post.title}</a>
|
||||
</h3>
|
||||
<p set:html={md(post.description)}></p>
|
||||
</article>
|
||||
))}
|
||||
<Layout pageTitle="All posts" currentUrl={currentUrl}>
|
||||
{
|
||||
paginatedPosts.map((post) => (
|
||||
<article>
|
||||
<div class="post-meta">
|
||||
{post.featured && <IconStar size={16} />}
|
||||
<time datetime={post.date}>
|
||||
{DateTime.fromISO(post.date).toLocaleString(DateTime.DATE_FULL)}
|
||||
</time>
|
||||
</div>
|
||||
<h3>
|
||||
<a href={post.url}>{post.title}</a>
|
||||
</h3>
|
||||
<p set:html={md(post.description)} />
|
||||
</article>
|
||||
))
|
||||
}
|
||||
|
||||
<Paginator pagination={pagination} />
|
||||
</Layout>
|
||||
<Paginator pagination={pagination} />
|
||||
</Layout>
|
||||
|
|
|
@ -3,16 +3,16 @@ import { IconStar } from "@tabler/icons-react";
|
|||
import { fetchAllPosts } from "@data/posts.js";
|
||||
import { fetchAnalyticsData } from "@data/analytics.js";
|
||||
import { fetchLinks } from "@data/links.js";
|
||||
import { fetchGlobalData } from '@utils/data/global/index.js';
|
||||
import { md } from '@utils/helpers/general.js';
|
||||
import { getPopularPosts } from '@utils/getPopularPosts.js';
|
||||
import { fetchGlobalData } from "@utils/data/global/index.js";
|
||||
import { md } from "@utils/helpers/general.js";
|
||||
import { getPopularPosts } from "@utils/getPopularPosts.js";
|
||||
|
||||
const analytics = await fetchAnalyticsData();
|
||||
const links = await fetchLinks();
|
||||
const posts = await fetchAllPosts();
|
||||
const popularPosts = getPopularPosts(posts, analytics);
|
||||
|
||||
import AddonLinks from '@components/blocks/links/AddonLinks.astro';
|
||||
import AddonLinks from "@components/blocks/links/AddonLinks.astro";
|
||||
import AssociatedMedia from "@components/blocks/AssociatedMedia.astro";
|
||||
import BlockRenderer from "@components/blocks/BlockRenderer.astro";
|
||||
import Coffee from "@components/blocks/banners/Coffee.astro";
|
||||
|
|
Reference in a new issue