diff --git a/package-lock.json b/package-lock.json index 875827e..bd3eec5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@tabler/icons-react": "^3.22.0", "astro": "^4.16.13", "luxon": "^3.5.0", + "minisearch": "7.1.0", "rehype-prism-plus": "2.0.0", "rehype-stringify": "10.0.1", "remark": "15.0.1", @@ -5832,6 +5833,12 @@ "node": ">=16.13" } }, + "node_modules/minisearch": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.1.0.tgz", + "integrity": "sha512-tv7c/uefWdEhcu6hvrfTihflgeEi2tN6VV7HJnCjK6VxM75QQJh4t9FwJCsA2EsRS8LCnu3W87CuGPWMocOLCA==", + "license": "MIT" + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", diff --git a/package.json b/package.json index 5f08242..f6bb2ab 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@tabler/icons-react": "^3.22.0", "astro": "^4.16.13", "luxon": "^3.5.0", + "minisearch": "7.1.0", "rehype-prism-plus": "2.0.0", "rehype-stringify": "10.0.1", "remark": "15.0.1", diff --git a/src/components/blocks/BlockRenderer.astro b/src/components/blocks/BlockRenderer.astro index 2ac4255..6f445bb 100644 --- a/src/components/blocks/BlockRenderer.astro +++ b/src/components/blocks/BlockRenderer.astro @@ -15,33 +15,65 @@ import YouTubePlayer from "@components/blocks//YouTubePlayer.astro"; 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 [analytics, links, posts] = await Promise.all([ + fetchAnalyticsData(), + fetchLinks(), + fetchAllPosts(), +]); const popularPosts = getPopularPosts(posts, analytics); -const { block } = Astro.props; +const { blocks } = Astro.props; +const processedBlocks = await Promise.all( + blocks.map(async (block) => { + if (block.type === "markdown") { + return { + ...block, + html: await md(block.text), + }; + } + if (block.type === "divider") { + return { + ...block, + html: await md(block.markup), + }; + } + return block; + }) +); + --- -{ - block.type === "addon_links" && ( - - ) -} +
+ { + processedBlocks.map((block) => ( + <> + {block.type === "addon_links" && ( + + )} -{block.type === "associated_media" && } + {block.type === "associated_media" && ( + + )} -{block.type === "divider" &&
} + {block.type === "divider" &&
} -{block.type === "github_banner" && } + {block.type === "github_banner" && } -{block.type === "hero" && } + {block.type === "hero" && } -{block.type === "markdown" &&
} + {block.type === "markdown" &&
} -{block.type === "npm_banner" && } + {block.type === "npm_banner" && ( + + )} -{block.type === "modal" && } + {block.type === "modal" && } -{block.type === "rss_banner" && } + {block.type === "rss_banner" && ( + + )} -{block.type === "youtube_player" && } + {block.type === "youtube_player" && } + + )) + } +
diff --git a/src/components/home/RecentActivity.astro b/src/components/home/RecentActivity.astro index 0884455..c9b873c 100644 --- a/src/components/home/RecentActivity.astro +++ b/src/components/home/RecentActivity.astro @@ -8,12 +8,13 @@ import { IconActivity } from "@tabler/icons-react"; import Rss from "@components/blocks/banners/Rss.astro"; -const music = await fetchMusicData(); -const tv = await fetchShows(); -const movies = await fetchMovies(); -const books = await fetchBooks(); -const links = await fetchLinks(); - +const [music, tv, movies, books, links] = await Promise.all([ + fetchMusicData(), + fetchShows(), + fetchMovies(), + fetchBooks(), + fetchLinks(), +]); const track = music.week?.tracks[0]; const show = tv.recentlyWatched[0]; const movie = movies.recentlyWatched[0]; @@ -34,7 +35,8 @@ const link = links[0];
  • Last episode watched: {show.formatted_episode} of {show.title} + href={show.url}>{show.title}
  • Last movie watched: diff --git a/src/middleware.js b/src/middleware.js index 4e70472..6c7e532 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -5,8 +5,10 @@ export async function onRequest(context, next) { const { locals } = context; try { - const globals = await fetchGlobals(); - const nav = await fetchNavigation(); + const [globals, nav] = await Promise.all([ + fetchGlobals(), + fetchNavigation(), + ]); locals.globals = globals; locals.nav = nav; diff --git a/src/pages/[permalink].astro b/src/pages/[permalink].astro index 9b89620..22b14f5 100644 --- a/src/pages/[permalink].astro +++ b/src/pages/[permalink].astro @@ -4,7 +4,6 @@ import BlockRenderer from "@components/blocks/BlockRenderer.astro"; import { fetchPages } from "@utils/data/pages.js"; export const prerender = true; - export async function getStaticPaths() { const pages = await fetchPages(); return pages.map((page) => ({ @@ -23,5 +22,5 @@ const currentUrl = Astro.url.pathname; ogImage={page.open_graph_image} currentUrl={currentUrl} > - {page.blocks.map((block) => )} + diff --git a/src/pages/books/index.astro b/src/pages/books/index.astro index acf4226..d15c435 100644 --- a/src/pages/books/index.astro +++ b/src/pages/books/index.astro @@ -5,29 +5,30 @@ import ProgressBar from "@components/media/ProgressBar.astro"; import { fetchBooks } from "@utils/data/books.js"; import { fetchGlobalData } from "@utils/data/global/index.js"; import { md, htmlTruncate } from "@utils/helpers/general.js"; +import { bookYearLinks } from "@utils/helpers/media.js"; export const prerender = true; const books = await fetchBooks(); +const currentBookCount = books.currentYear.length; +const bookData = books.all + .filter((book) => book.status === "started") + .reverse(); +const processedBooks = await Promise.all( + bookData.map(async (book) => { + const descriptionHtml = await md(book.description); + const truncatedHtml = htmlTruncate(descriptionHtml, 50); + return { + ...book, + truncatedDescription: truncatedHtml, + }; + }) +); const { globals } = await fetchGlobalData(Astro); const title = "Currently reading"; const description = "Here's what I'm reading at the moment."; const updated = new Date().toISOString(); const currentYear = new Date().getFullYear(); -const bookData = books.all - .filter((book) => book.status === "started") - .reverse(); -const currentBookCount = books.currentYear.length; -const bookYearLinks = (years) => - years - .sort((a, b) => b.value - a.value) - .map( - (year, index) => - `${year.value}${ - index < years.length - 1 ? " / " : "" - }` - ) - .join(""); --- />
    { - bookData.map((book) => ( + processedBooks.map((book) => (
    {book.description && (
    )}
    diff --git a/src/pages/feeds/all.json.js b/src/pages/feeds/all.json.js index 2c00506..60223bb 100644 --- a/src/pages/feeds/all.json.js +++ b/src/pages/feeds/all.json.js @@ -3,9 +3,10 @@ import { fetchGlobals } from "@utils/data/globals.js"; import { fetchActivity } from "@utils/data/activity.js"; export async function GET() { - const globals = await fetchGlobals(); - const activity = await fetchActivity(); - + const [globals, activity] = await Promise.all([ + fetchGlobals(), + fetchActivity(), + ]); const feed = generateJsonFeed({ permalink: "/feeds/all.json", title: "All activity / Cory Dransfeldt", diff --git a/src/pages/feeds/all.xml.js b/src/pages/feeds/all.xml.js index 261eb49..dfde329 100644 --- a/src/pages/feeds/all.xml.js +++ b/src/pages/feeds/all.xml.js @@ -3,9 +3,10 @@ import { fetchGlobals } from "@utils/data/globals.js"; import { fetchActivity } from "@utils/data/activity.js"; export async function GET() { - const globals = await fetchGlobals(); - const activity = await fetchActivity(); - + const [globals, activity] = await Promise.all([ + fetchGlobals(), + fetchActivity(), + ]); const rss = generateRssFeed({ permalink: "/feeds/all.xml", title: "All activity feed", diff --git a/src/pages/feeds/books.json.js b/src/pages/feeds/books.json.js index ffe4d4f..7d4dfb3 100644 --- a/src/pages/feeds/books.json.js +++ b/src/pages/feeds/books.json.js @@ -3,9 +3,10 @@ import { fetchGlobals } from "@utils/data/globals.js"; import { fetchBooks } from "@utils/data/books.js"; export async function GET() { - const globals = await fetchGlobals(); - const books = await fetchBooks(); - + const [globals, books] = await Promise.all([ + fetchGlobals(), + fetchBooks(), + ]); const feed = generateJsonFeed({ permalink: "/feeds/books.json", title: "Books / Cory Dransfeldt", diff --git a/src/pages/feeds/books.xml.js b/src/pages/feeds/books.xml.js index 41ca1ae..f215351 100644 --- a/src/pages/feeds/books.xml.js +++ b/src/pages/feeds/books.xml.js @@ -3,9 +3,10 @@ import { fetchGlobals } from "@utils/data/globals.js"; import { fetchBooks } from "@utils/data/books.js"; export async function GET() { - const globals = await fetchGlobals(); - const books = await fetchBooks(); - + const [globals, books] = await Promise.all([ + fetchGlobals(), + fetchBooks(), + ]); const rss = generateRssFeed({ permalink: "/feeds/books.xml", title: "Books feed", diff --git a/src/pages/feeds/links.json.js b/src/pages/feeds/links.json.js index 80d03a9..bb43a95 100644 --- a/src/pages/feeds/links.json.js +++ b/src/pages/feeds/links.json.js @@ -3,9 +3,10 @@ import { fetchGlobals } from "@utils/data/globals.js"; import { fetchLinks } from "@utils/data/links.js"; export async function GET() { - const globals = await fetchGlobals(); - const links = await fetchLinks(); - + const [globals, links] = await Promise.all([ + fetchGlobals(), + fetchLinks(), + ]); const feed = generateJsonFeed({ permalink: "/feeds/links.json", title: "Links / Cory Dransfeldt", diff --git a/src/pages/feeds/links.xml.js b/src/pages/feeds/links.xml.js index a6d235f..f455308 100644 --- a/src/pages/feeds/links.xml.js +++ b/src/pages/feeds/links.xml.js @@ -3,9 +3,10 @@ import { fetchGlobals } from "@utils/data/globals.js"; import { fetchLinks } from "@utils/data/links"; export async function GET() { - const globals = await fetchGlobals(); - const links = await fetchLinks(); - + const [globals, links] = await Promise.all([ + fetchGlobals(), + fetchLinks(), + ]); const rss = generateRssFeed({ permalink: "/feeds/links.xml", title: "Links feed", diff --git a/src/pages/feeds/movies.json.js b/src/pages/feeds/movies.json.js index 9416343..9487b1e 100644 --- a/src/pages/feeds/movies.json.js +++ b/src/pages/feeds/movies.json.js @@ -3,9 +3,10 @@ import { fetchGlobals } from '@utils/data/globals.js'; import { fetchMovies } from '@utils/data/movies'; export async function GET() { - const globals = await fetchGlobals(); - const movies = await fetchMovies(); - + const [globals, movies] = await Promise.all([ + fetchGlobals(), + fetchMovies(), + ]); const feed = generateJsonFeed({ permalink: "/feeds/movies.json", title: "Movies / Cory Dransfeldt", diff --git a/src/pages/feeds/movies.xml.js b/src/pages/feeds/movies.xml.js index b5e6417..32928e6 100644 --- a/src/pages/feeds/movies.xml.js +++ b/src/pages/feeds/movies.xml.js @@ -3,9 +3,10 @@ import { fetchGlobals } from "@utils/data/globals.js"; import { fetchMovies } from "@utils/data/movies.js"; export async function GET() { - const globals = await fetchGlobals(); - const movies = await fetchMovies(); - + const [globals, movies] = await Promise.all([ + fetchGlobals(), + fetchMovies(), + ]); const rss = generateRssFeed({ permalink: "/feeds/movies.xml", title: "Movies feed", diff --git a/src/pages/feeds/posts.json.js b/src/pages/feeds/posts.json.js index 1ab8b66..2fd2ddb 100644 --- a/src/pages/feeds/posts.json.js +++ b/src/pages/feeds/posts.json.js @@ -3,9 +3,10 @@ import { fetchGlobals } from "@utils/data/globals.js"; import { fetchAllPosts } from "@utils/data/posts.js"; export async function GET() { - const globals = await fetchGlobals(); - const posts = await fetchAllPosts(); - + const [globals, posts] = await Promise.all([ + fetchGlobals(), + fetchAllPosts(), + ]); const feed = generateJsonFeed({ permalink: "/feeds/posts.json", title: "Posts / Cory Dransfeldt", diff --git a/src/pages/feeds/posts.xml.js b/src/pages/feeds/posts.xml.js index fda623b..3db012a 100644 --- a/src/pages/feeds/posts.xml.js +++ b/src/pages/feeds/posts.xml.js @@ -3,9 +3,10 @@ import { fetchGlobals } from "@utils/data/globals.js"; import { fetchAllPosts } from "@utils/data/posts.js"; export async function GET() { - const globals = await fetchGlobals(); - const posts = await fetchAllPosts(); - + const [globals, posts] = await Promise.all([ + fetchGlobals(), + fetchAllPosts(), + ]); const rss = generateRssFeed({ permalink: "/feeds/posts.xml", title: "Posts feed", diff --git a/src/pages/feeds/syndication.xml.js b/src/pages/feeds/syndication.xml.js index 345ff8d..5ab6c3a 100644 --- a/src/pages/feeds/syndication.xml.js +++ b/src/pages/feeds/syndication.xml.js @@ -45,9 +45,10 @@ const generateSyndicationRSS = async (globals, entries) => { export async function GET() { try { - const globals = await fetchGlobals(); - const entries = await fetchSyndication(); - + const [globals, entries] = await Promise.all([ + fetchGlobals(), + fetchSyndication(), + ]); const rss = await generateSyndicationRSS(globals, entries); return new Response(rss, { diff --git a/src/pages/links.astro b/src/pages/links/[...page].astro similarity index 56% rename from src/pages/links.astro rename to src/pages/links/[...page].astro index 6d52bf1..9e4eb74 100644 --- a/src/pages/links.astro +++ b/src/pages/links/[...page].astro @@ -1,48 +1,53 @@ --- import Layout from "@layouts/Layout.astro"; import Paginator from "@components/nav/Paginator.astro"; -import RssBanner from "@components/blocks/banners/Rss.astro"; +import Rss from "@components/blocks/banners/Rss.astro"; import { fetchLinks } from "@utils/data/links.js"; export const prerender = true; -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 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 -); +export const getStaticPaths = async ({ paginate }) => { + const links = await fetchLinks(); + return paginate(links, { + pageSize: 30, + }); +}; +const { page } = Astro.props; + +const paginatedLinks = page.data; const pagination = { - currentPage, - totalPages, - hasPrevious: currentPage > 1, - hasNext: currentPage < totalPages, - previousPage: currentPage > 1 ? `/links?page=${currentPage - 1}` : null, - nextPage: currentPage < totalPages ? `/links?page=${currentPage + 1}` : null, - pages: Array.from({ length: totalPages }, (_, index) => ({ - number: index + 1, - href: `/links?page=${index + 1}`, + currentPage: page.currentPage, + totalPages: page.lastPage, + hasPrevious: page.currentPage > 1, + hasNext: page.currentPage < page.lastPage, + previousPage: page.url.prev || null, + nextPage: page.url.next || null, + pages: Array.from({ length: page.lastPage }, (_, i) => ({ + number: i + 1, + href: i === 0 ? `/links` : `/links/${i + 1}`, })), }; + +const pageTitle = + pagination.currentPage === 1 + ? "Linls" + : `Links / page ${pagination.currentPage}`; +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."; --- { - currentPage === 1 && ( + pagination.currentPage === 1 && ( <> -

    {title}

    +

    {pageTitle}

    {description}

    - @@ -50,7 +55,6 @@ const pagination = { ) } - -
    diff --git a/src/pages/music/index.astro b/src/pages/music/index.astro index 3e92c67..7d3e8c8 100644 --- a/src/pages/music/index.astro +++ b/src/pages/music/index.astro @@ -19,8 +19,10 @@ import { mediaLinks } from "@utils/helpers/media.js"; export const prerender = true; const { globals } = await fetchGlobalData(Astro); -const music = await fetchMusicData(); -const albumReleases = await fetchAlbumReleases(); +const [music, albumReleases ] = await Promise.all([ + fetchMusicData(), + fetchAlbumReleases(), +]); const title = "Music"; const description = diff --git a/src/pages/posts/[...page].astro b/src/pages/posts/[...page].astro index f0940d0..d57052c 100644 --- a/src/pages/posts/[...page].astro +++ b/src/pages/posts/[...page].astro @@ -5,46 +5,45 @@ 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 type { GetStaticPaths, Page } from "astro"; export const prerender = true; - -export async function getStaticPaths() { - const pageSize = 15; // Declare inside this function +export const getStaticPaths = async ({ paginate }) => { const posts = await fetchAllPosts(); + const sortedPosts = posts.sort((a, b) => new Date(b.date) - new Date(a.date)); - const totalPages = Math.ceil(posts.length / pageSize); - const paths = Array.from({ length: totalPages }, (_, i) => ({ - params: { page: (i + 1).toString() }, - })); - - return paths; -} - -const pageSize = 15; -const currentUrl = Astro.url.pathname; -const currentPage = Astro.params.page ? parseInt(Astro.params.page, 10) : 1; -const posts = await fetchAllPosts(); -const totalPosts = posts.length; -const totalPages = Math.ceil(totalPosts / pageSize); -const start = (currentPage - 1) * pageSize; -const end = start + pageSize; -const paginatedPosts = posts.slice(start, end); + return paginate(sortedPosts, { + pageSize: 15, + }); +}; +const { page } = Astro.props; +const paginatedPosts = page.data; const pagination = { - currentPage, - totalPages, - hasPrevious: currentPage > 1, - hasNext: currentPage < totalPages, - previousPage: currentPage > 1 ? `/posts/${currentPage - 1}` : null, - nextPage: currentPage < totalPages ? `/posts/${currentPage + 1}` : null, - pages: Array.from({ length: totalPages }, (_, i) => ({ + currentPage: page.currentPage, + totalPages: page.lastPage, + hasPrevious: page.currentPage > 1, + hasNext: page.currentPage < page.lastPage, + previousPage: page.url.prev || null, + nextPage: page.url.next || null, + pages: Array.from({ length: page.lastPage }, (_, i) => ({ number: i + 1, - href: `/posts/${i + 1}`, + href: i === 0 ? `/posts` : `/posts/${i + 1}`, })), }; +const pageTitle = + pagination.currentPage === 1 + ? "Posts" + : `Posts / page ${pagination.currentPage}`; +const description = + "These are posts I've written. They're all added manually, after having been written and, I suppose, properly considered."; --- - + { paginatedPosts.map((post) => (
    @@ -61,6 +60,5 @@ const pagination = {
    )) } -
    diff --git a/src/pages/posts/[year]/[title].astro b/src/pages/posts/[year]/[title].astro index 7dd78cc..d843e13 100644 --- a/src/pages/posts/[year]/[title].astro +++ b/src/pages/posts/[year]/[title].astro @@ -7,9 +7,11 @@ 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 [analytics, links, posts] = await Promise.all([ + fetchAnalyticsData(), + fetchLinks(), + fetchAllPosts(), +]); const popularPosts = getPopularPosts(posts, analytics); import AddonLinks from "@components/blocks/links/AddonLinks.astro"; @@ -91,10 +93,7 @@ const htmlContent = md(post.content); ) }
    - { - post.blocks && - post.blocks.map((block) => ) - } + {post.blocks && } {post.mastodon_url && } +

    Search

    +

    + You can find posts, links, artists, genres, movies, shows and books via the field below (though it only surfaces + movies and shows I've watched and books I've written something about). +

    + +
    + +
    + Filter by type +
    + + + + + + + +
    +
    + +
    +
      + + + diff --git a/src/pages/watching/favorite-movies.astro b/src/pages/watching/favorite-movies.astro new file mode 100644 index 0000000..c5be19f --- /dev/null +++ b/src/pages/watching/favorite-movies.astro @@ -0,0 +1,60 @@ +--- +import Layout from "@layouts/Layout.astro"; +import Grid from "@components/media/Grid.astro"; +import { IconArrowLeft } from "@tabler/icons-react"; +import { fetchMovies } from "@utils/data/movies.js"; +import { fetchGlobalData } from "@utils/data/global/index.js"; +import { shuffleArray } from "@utils/helpers/general.js"; + +const { globals } = await fetchGlobalData(Astro); +const movies = await fetchMovies(); +const favoriteMovies = movies.favorites; +const pageSize = 24; +const currentPage = Astro.params.page ? parseInt(Astro.params.page, 10) : 1; +const totalMovies = favoriteMovies.length; +const totalPages = Math.ceil(totalMovies / pageSize); +const start = (currentPage - 1) * pageSize; +const end = start + pageSize; +const paginatedMovies = favoriteMovies.slice(start, end); + +const pagination = { + currentPage, + totalPages, + hasPrevious: currentPage > 1, + hasNext: currentPage < totalPages, + previousPage: currentPage > 1 ? `/watching/favorite-movies/${currentPage - 1}` : null, + nextPage: currentPage < totalPages ? `/watching/favorite-movies/${currentPage + 1}` : null, + pages: Array.from({ length: totalPages }, (_, i) => ({ + number: i + 1, + href: `/watching/favorite-movies/${i + 1}`, + })), +}; + +const pageTitle = currentPage === 1 ? "Favorite Movies" : `Favorite Movies - Page ${currentPage}`; +const description = "These are my favorite movies. There are many like them, but these are mine."; +--- + + + + Back to watching + + {currentPage === 1 && ( + <> +

      Favorite Movies

      +

      These are my favorite movies. There are many like them, but these are mine.

      +
      + + )} + +
      \ No newline at end of file diff --git a/src/pages/watching/favorite-shows.astro b/src/pages/watching/favorite-shows.astro new file mode 100644 index 0000000..01fd0c4 --- /dev/null +++ b/src/pages/watching/favorite-shows.astro @@ -0,0 +1,60 @@ +--- +import Layout from "@layouts/Layout.astro"; +import Grid from "@components/media/Grid.astro"; +import { IconArrowLeft } from "@tabler/icons-react"; +import { fetchShows } from "@utils/data/tv.js"; +import { fetchGlobalData } from "@utils/data/global/index.js"; +import { shuffleArray } from "@utils/helpers/general.js"; + +const { globals } = await fetchGlobalData(Astro); +const shows = await fetchShows(); +const favoriteShows = shows.favorites; +const pageSize = 24; +const currentPage = Astro.params.page ? parseInt(Astro.params.page, 10) : 1; +const totalTvShows = favoriteShows.length; +const totalPages = Math.ceil(totalTvShows / pageSize); +const start = (currentPage - 1) * pageSize; +const end = start + pageSize; +const paginatedTvShows = favoriteShows.slice(start, end); + +const pagination = { + currentPage, + totalPages, + hasPrevious: currentPage > 1, + hasNext: currentPage < totalPages, + previousPage: currentPage > 1 ? `/watching/favorite-shows/${currentPage - 1}` : null, + nextPage: currentPage < totalPages ? `/watching/favorite-shows/${currentPage + 1}` : null, + pages: Array.from({ length: totalPages }, (_, i) => ({ + number: i + 1, + href: `/watching/favorite-shows/${i + 1}`, + })), +}; + +const pageTitle = currentPage === 1 ? "Favorite Shows" : `Favorite shows / page ${currentPage}`; +const description = "These are my favorite TV shows. There are many like them, but these are mine."; +--- + + + + Back to watching + + {currentPage === 1 && ( + <> +

      Favorite Shows

      +

      These are my favorite TV shows. There are many like them, but these are mine.

      +
      + + )} + +
      diff --git a/src/pages/watching/movies/[slug].astro b/src/pages/watching/movies/[slug].astro new file mode 100644 index 0000000..5110ab5 --- /dev/null +++ b/src/pages/watching/movies/[slug].astro @@ -0,0 +1,120 @@ +--- +import { DateTime } from "luxon"; +import Layout from "@layouts/Layout.astro"; +import AssociatedMedia from "@components/blocks/AssociatedMedia.astro"; +import Warning from "@components/blocks/banners/Warning.astro"; +import { + IconArrowLeft, + IconHeart, + IconNeedle, + IconCircleCheck, +} from "@tabler/icons-react"; +import { fetchGlobalData } from "@utils/data/global/index.js"; +import { fetchMovieByUrl } from "@utils/data/dynamic/movieByUrl.js"; + +const { globals } = await fetchGlobalData(Astro); +const movie = await fetchMovieByUrl(Astro.url.pathname); + +if (!movie) return Astro.redirect("/404", 404); + +const pageTitle = `${movie.title} / Movies`; +const description = movie.description || `Details about ${movie.title}.`; +const alt = `${movie.title} / ${movie.year}${movie.rating ? ` (${movie.rating})` : ""}`; +--- + + + + Back to watching + +
      + {alt} +
      + + {movie.title} + {movie.year && !movie.rating && ` (${movie.year})`} + + { + movie.rating && ( + + {movie.rating} + {movie.year && ` (${movie.year})`} + + ) + } + { + movie.favorite && ( + + This is one of my favorite movies! + + ) + } + { + movie.tattoo && ( + + I have a tattoo inspired by this movie! + + ) + } + { + movie.collected && ( + + This movie is in my collection! + + ) + } + { + movie.lastWatched && ( + + Last watched on{" "} + {DateTime.fromISO(movie.lastWatched).toLocaleString(DateTime.DATE_FULL)}. + + ) + } +
      + + {movie.review && ( + <> +

      My thoughts

      + +
      + + )} + + + + {movie.description && ( + <> +

      Overview

      +
      + + )} +
      +
      diff --git a/src/pages/watching/shows/[slug].astro b/src/pages/watching/shows/[slug].astro new file mode 100644 index 0000000..52dd288 --- /dev/null +++ b/src/pages/watching/shows/[slug].astro @@ -0,0 +1,113 @@ +--- +import { DateTime } from "luxon"; +import Layout from "@layouts/Layout.astro"; +import AssociatedMedia from "@components/blocks/AssociatedMedia.astro"; +import Warning from "@components/blocks/banners/Warning.astro"; +import { + IconArrowLeft, + IconHeart, + IconNeedle, + IconCircleCheck, +} from "@tabler/icons-react"; +import { fetchGlobalData } from "@utils/data/global/index.js"; +import { fetchTvByUrl } from "@utils/data/dynamic/tvByUrl.js"; + +const { globals } = await fetchGlobalData(Astro); +const show = await fetchTvByUrl(Astro.url.pathname); + +if (!show) return Astro.redirect("/404", 404); + +const pageTitle = `${show.title} / TV`; +const description = show.description || `Details about ${show.title}.`; +const alt = `${show.title} / ${show.year}`; +--- + + + + Back to watching + +
      + {alt} +
      + + {show.title} + {show.year && ` (${show.year})`} + + { + show.favorite && ( + + This is one of my favorite shows! + + ) + } + { + show.tattoo && ( + + I have a tattoo inspired by this show! + + ) + } + { + show.collected && ( + + This show is in my collection! + + ) + } + { + show.episode?.formatted_episode && ( + + I last watched{" "} + {show.episode.formatted_episode}{" "} + on {DateTime.fromISO(show.episode.last_watched_at).toLocaleString(DateTime.DATE_FULL)}. + + ) + } +
      + + {show.review && ( + <> +

      My thoughts

      + +
      + + )} + + + + {show.description && ( + <> +

      Overview

      +
      + + )} +
      +
      diff --git a/src/utils/data/dynamic/movieByUrl.js b/src/utils/data/dynamic/movieByUrl.js new file mode 100644 index 0000000..feecd0b --- /dev/null +++ b/src/utils/data/dynamic/movieByUrl.js @@ -0,0 +1,25 @@ +import { createClient } from "@supabase/supabase-js"; +import { removeTrailingSlash } from "@utils/helpers/general.js"; + +const SUPABASE_URL = import.meta.env.SUPABASE_URL; +const SUPABASE_KEY = import.meta.env.SUPABASE_KEY; +const supabase = createClient(SUPABASE_URL, SUPABASE_KEY); + +const movieCache = {}; + +export async function fetchMovieByUrl(url) { + if (import.meta.env.MODE === "development" && movieCache[url]) return movieCache[url]; + + const { data: movie, error } = await supabase + .from("optimized_movies") + .select("*") + .eq("url", removeTrailingSlash(url)) + .limit(1); + if (error) { + console.error("Error fetching movie:", error); + return null; + } + if (import.meta.env.MODE === "development") movieCache[url] = movie[0]; + + return movie[0]; +} diff --git a/src/utils/data/dynamic/tvByUrl.js b/src/utils/data/dynamic/tvByUrl.js new file mode 100644 index 0000000..9b03737 --- /dev/null +++ b/src/utils/data/dynamic/tvByUrl.js @@ -0,0 +1,25 @@ +import { createClient } from "@supabase/supabase-js"; +import { removeTrailingSlash } from "@utils/helpers/general.js"; + +const SUPABASE_URL = import.meta.env.SUPABASE_URL; +const SUPABASE_KEY = import.meta.env.SUPABASE_KEY; +const supabase = createClient(SUPABASE_URL, SUPABASE_KEY); + +const tvCache = {}; + +export async function fetchTvByUrl(url) { + if (import.meta.env.MODE === "development" && tvCache[url]) return tvCache[url]; + + const { data: tv, error } = await supabase + .from("optimized_shows") + .select("*") + .eq("url", removeTrailingSlash(url)) + .limit(1); + if (error) { + console.error("Error fetching tv:", error); + return null; + } + if (import.meta.env.MODE === "development") tvCache[url] = tv[0]; + + return tv[0]; +} diff --git a/src/utils/helpers/general.js b/src/utils/helpers/general.js index cf8adfb..d8e6382 100644 --- a/src/utils/helpers/general.js +++ b/src/utils/helpers/general.js @@ -71,7 +71,7 @@ export const escapeHtml = (str) => // urls export const encodeAmp = (url) => url.replace(/&/g, "&"); -export const removeTrailingSlash = (url) => url.replace(/\/$/, ''); +export const removeTrailingSlash = (url) => url.replace(/\/$/, ""); // dates export const dateToRFC822 = (date) =>