chore: concerts + fix modals
This commit is contained in:
parent
3345c170fc
commit
463a26defc
5 changed files with 144 additions and 27 deletions
|
@ -1,8 +1,25 @@
|
||||||
---
|
---
|
||||||
const { content } = Astro.props;
|
import { md } from "@utils/helpers/general.js";
|
||||||
---
|
import { IconCircleX, IconInfoCircle } from "@tabler/icons-react";
|
||||||
|
|
||||||
<div class="modal">
|
const { content, id } = Astro.props;
|
||||||
<button class="close">Close</button>
|
---
|
||||||
<div class="content">{content}</div>
|
<>
|
||||||
</div>
|
<input
|
||||||
|
class="modal-input"
|
||||||
|
id={id}
|
||||||
|
type="checkbox"
|
||||||
|
tabindex="0"
|
||||||
|
/>
|
||||||
|
<label class="modal-toggle" for={id}>
|
||||||
|
<IconInfoCircle size={24} />
|
||||||
|
</label>
|
||||||
|
<div class="modal-wrapper">
|
||||||
|
<div class="modal-body">
|
||||||
|
<label class="modal-close" for={id}>
|
||||||
|
<IconCircleX size={24} />
|
||||||
|
</label>
|
||||||
|
<div set:html={md(content)}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
---
|
---
|
||||||
|
import { DateTime } from "luxon";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
|
import Modal from "@components/blocks/Modal.astro";
|
||||||
import ToggleContent from "@components/utils/ToggleContent.astro";
|
import ToggleContent from "@components/utils/ToggleContent.astro";
|
||||||
import AssociatedMedia from "@components/blocks/AssociatedMedia.astro";
|
import AssociatedMedia from "@components/blocks/AssociatedMedia.astro";
|
||||||
import {
|
import {
|
||||||
|
@ -107,7 +109,6 @@ const playLabel = artist.total_plays === 1 ? "play" : "plays";
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
artist.concerts && (
|
artist.concerts && (
|
||||||
<>
|
<>
|
||||||
|
@ -115,28 +116,38 @@ const playLabel = artist.total_plays === 1 ? "play" : "plays";
|
||||||
<IconDeviceSpeaker size={18} /> I've seen this artist live!
|
<IconDeviceSpeaker size={18} /> I've seen this artist live!
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
{artist.concerts.map((concert) => {
|
{artist.concerts.map((concert, index) => (
|
||||||
const venue =
|
<li key={index}>
|
||||||
concert.venue_latitude && concert.venue_longitude
|
On{" "}
|
||||||
? `<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>`
|
<strong class="highlight-text">{DateTime.fromISO(concert.date).toLocaleString(DateTime.DATE_MED)}</strong>
|
||||||
: concert.venue_name_short;
|
{concert.venue_name_short && (
|
||||||
|
<>
|
||||||
return (
|
{" "}
|
||||||
<li>
|
at{" "}
|
||||||
On{" "}
|
{concert.venue_latitude && concert.venue_longitude ? (
|
||||||
<strong class="highlight-text">
|
<a
|
||||||
{concert.date.toLocaleString(DateTime.DATE_MED)}
|
href={`https://www.openstreetmap.org/?mlat=${concert.venue_latitude}&mlon=${concert.venue_longitude}#map=18/${concert.venue_latitude}/${concert.venue_longitude}`}
|
||||||
</strong>
|
>{concert.venue_name_short}</a>
|
||||||
{venue && <> at {venue}</>}
|
) : (
|
||||||
{concert.notes && <span> — {concert.notes}</span>}
|
<span>{concert.venue_name_short}</span>
|
||||||
</li>
|
)}
|
||||||
);
|
</>
|
||||||
})}
|
)}
|
||||||
|
{concert.notes && (
|
||||||
|
<>
|
||||||
|
{" "}
|
||||||
|
<Modal
|
||||||
|
id={`modal-${index}`}
|
||||||
|
content={`### Notes\n${concert.notes}`}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
artist.albums && (
|
artist.albums && (
|
||||||
<>
|
<>
|
||||||
|
|
87
src/pages/music/concerts.astro
Normal file
87
src/pages/music/concerts.astro
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
---
|
||||||
|
import Layout from "@layouts/Layout.astro";
|
||||||
|
import Paginator from "@components/nav/Paginator.astro";
|
||||||
|
import Modal from "@components/blocks/Modal.astro";
|
||||||
|
import { fetchConcerts } from "@utils/data/concerts.js";
|
||||||
|
import { fetchGlobalData } from "@utils/data/global/index.js";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
|
||||||
|
export const prerender = true;
|
||||||
|
|
||||||
|
const { globals } = await fetchGlobalData(Astro);
|
||||||
|
const concerts = await fetchConcerts();
|
||||||
|
const title = "Concerts";
|
||||||
|
const description =
|
||||||
|
"These are concerts I've attended (not all of them — just the ones I could remember or glean from emails, photo metadata et al). I've been to at least " +
|
||||||
|
concerts.length +
|
||||||
|
" shows.";
|
||||||
|
const pageSize = 30;
|
||||||
|
const currentPage = parseInt(Astro.url.searchParams.get("page") || "1", 10);
|
||||||
|
const totalPages = Math.ceil(concerts.length / pageSize);
|
||||||
|
const paginatedConcerts = concerts.slice(
|
||||||
|
(currentPage - 1) * pageSize,
|
||||||
|
currentPage * pageSize
|
||||||
|
);
|
||||||
|
|
||||||
|
const pagination = {
|
||||||
|
currentPage,
|
||||||
|
totalPages,
|
||||||
|
hasPrevious: currentPage > 1,
|
||||||
|
hasNext: currentPage < totalPages,
|
||||||
|
previousPage: currentPage > 1 ? `/concerts?page=${currentPage - 1}` : null,
|
||||||
|
nextPage: currentPage < totalPages ? `/concerts?page=${currentPage + 1}` : null,
|
||||||
|
pages: Array.from({ length: totalPages }, (_, index) => ({
|
||||||
|
number: index + 1,
|
||||||
|
href: `/concerts?page=${index + 1}`,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout
|
||||||
|
pageTitle={title}
|
||||||
|
description={description}
|
||||||
|
currentUrl={Astro.url.pathname}
|
||||||
|
>
|
||||||
|
{currentPage === 1 && (
|
||||||
|
<>
|
||||||
|
<h2 class="page-title">{title}</h2>
|
||||||
|
<p>These are concerts I've attended (not all of them — just the ones I could remember or glean from emails, photo metadata et al). I've been to at least <strong class="highlight-text">{concerts.length}</strong> shows.</p>
|
||||||
|
<hr />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<ul class="concert-list">
|
||||||
|
{paginatedConcerts.map((concert) => (
|
||||||
|
<li>
|
||||||
|
{concert.artist.url ? (
|
||||||
|
<a href={concert.artist.url}>{concert.artist.name}</a>
|
||||||
|
) : (
|
||||||
|
<span>{concert.artist.name}</span>
|
||||||
|
)}{" "}
|
||||||
|
on{" "}
|
||||||
|
<strong class="highlight-text">{DateTime.fromISO(concert.date).toLocaleString(DateTime.DATE_FULL)}</strong>
|
||||||
|
{concert.venue?.name && (
|
||||||
|
<>
|
||||||
|
{" at "}
|
||||||
|
{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 || concert.venue.name}</a>
|
||||||
|
) : (
|
||||||
|
<span>{concert.venue.name_short || concert.venue.name}</span>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{concert.notes && (
|
||||||
|
<Modal
|
||||||
|
id={`modal-${concert.id}`}
|
||||||
|
icon="info-circle"
|
||||||
|
content={`### Notes\n${concert.notes}`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<Paginator pagination={pagination} />
|
||||||
|
</Layout>
|
|
@ -435,12 +435,12 @@ td:first-of-type,
|
||||||
|
|
||||||
main {
|
main {
|
||||||
flex: 1 1 0%;
|
flex: 1 1 0%;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
main,
|
main,
|
||||||
footer {
|
footer {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
margin: var(--sizing-3xl) auto 0;
|
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
max-width: 768px;
|
max-width: 768px;
|
||||||
|
@ -448,6 +448,8 @@ footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
|
margin: var(--sizing-3xl) auto 0;
|
||||||
|
|
||||||
& nav {
|
& nav {
|
||||||
&.social,
|
&.social,
|
||||||
&.sub-pages {
|
&.sub-pages {
|
||||||
|
|
|
@ -6,7 +6,7 @@ const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
|
||||||
|
|
||||||
let cachedConcerts = null;
|
let cachedConcerts = null;
|
||||||
|
|
||||||
export async function fetchConcertsData() {
|
export async function fetchConcerts() {
|
||||||
if (import.meta.env.MODE === "development" && cachedConcerts)
|
if (import.meta.env.MODE === "development" && cachedConcerts)
|
||||||
return cachedConcerts;
|
return cachedConcerts;
|
||||||
|
|
||||||
|
|
Reference in a new issue