chore: middleware
This commit is contained in:
parent
45b6e113b5
commit
3ab6f77a69
18 changed files with 180 additions and 36 deletions
|
@ -6,6 +6,11 @@ export default defineConfig({
|
||||||
output: "server",
|
output: "server",
|
||||||
adapter: cloudflare(),
|
adapter: cloudflare(),
|
||||||
integrations: [react()],
|
integrations: [react()],
|
||||||
|
server: {
|
||||||
|
middleware: {
|
||||||
|
onRequest: "./src/middleware.js",
|
||||||
|
},
|
||||||
|
},
|
||||||
vite: {
|
vite: {
|
||||||
build: {
|
build: {
|
||||||
sourcemap: false,
|
sourcemap: false,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
---
|
---
|
||||||
import NavLink from '@components/nav/NavLink.astro';
|
import NavLink from '@components/nav/NavLink.astro';
|
||||||
|
|
||||||
const { nav, updated } = Astro.props;
|
const { updated } = Astro.props;
|
||||||
|
const { nav } = Astro.locals;
|
||||||
---
|
---
|
||||||
|
|
||||||
<footer style={updated ? undefined : 'margin-top: var(--spacing-3xl)'}>
|
<footer style={updated ? undefined : 'margin-top: var(--spacing-3xl)'}>
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
---
|
---
|
||||||
import Menu from '@components/nav/Menu.astro';
|
import Menu from '@components/nav/Menu.astro';
|
||||||
|
|
||||||
const { nav, siteName, url } = Astro.props;
|
const { siteName, url } = Astro.props;
|
||||||
|
const { nav } = Astro.locals;
|
||||||
const isHomePage = url === '/';
|
const isHomePage = url === '/';
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { escapeHtml } from "@utils/helpers.js";
|
||||||
|
|
||||||
const {
|
const {
|
||||||
schema = "page",
|
schema = "page",
|
||||||
globals,
|
|
||||||
pageTitle: titleOverride,
|
pageTitle: titleOverride,
|
||||||
description: descriptionOverride,
|
description: descriptionOverride,
|
||||||
ogImage: ogImageOverride,
|
ogImage: ogImageOverride,
|
||||||
|
@ -19,6 +18,7 @@ const {
|
||||||
genre,
|
genre,
|
||||||
year,
|
year,
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
const { globals} = Astro.locals;
|
||||||
|
|
||||||
let pageTitle = globals.site_name;
|
let pageTitle = globals.site_name;
|
||||||
let pageDescription = globals.site_description;
|
let pageDescription = globals.site_description;
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
---
|
---
|
||||||
import Paginator from '@components/nav/Paginator.astro';
|
import Paginator from '@components/nav/Paginator.astro';
|
||||||
|
|
||||||
const { data, globals, count, shape, pagination, loading = "lazy" } = Astro.props;
|
const { data, count, shape, pagination, loading = "lazy" } = Astro.props;
|
||||||
|
const { globals } = Astro.locals;
|
||||||
const pageCount = pagination?.pages?.length || 0;
|
const pageCount = pagination?.pages?.length || 0;
|
||||||
const hidePagination = pageCount <= 1;
|
const hidePagination = pageCount <= 1;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
---
|
---
|
||||||
const { data, globals } = Astro.props;
|
const { data } = Astro.props;
|
||||||
|
const { globals } = Astro.locals;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="music-chart">
|
<div class="music-chart">
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
---
|
---
|
||||||
import Hero from "@components/blocks/Hero.astro";
|
import Hero from "@components/blocks/Hero.astro";
|
||||||
|
|
||||||
const { movie, globals } = Astro.props;
|
const { movie } = Astro.props;
|
||||||
|
const { globals } = Astro.locals;
|
||||||
---
|
---
|
||||||
|
|
||||||
<a href={movie.url}>
|
<a href={movie.url}>
|
||||||
|
|
|
@ -9,15 +9,15 @@ const currentUrl = Astro.url.pathname;
|
||||||
const nav = await fetchNavigation();
|
const nav = await fetchNavigation();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
globals,
|
|
||||||
schema = "page",
|
schema = "page",
|
||||||
pageTitle,
|
pageTitle,
|
||||||
description,
|
description,
|
||||||
ogImage,
|
ogImage,
|
||||||
fullUrl,
|
fullUrl,
|
||||||
|
updated,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
const { globals} = Astro.locals;
|
||||||
const isProduction = import.meta.env.MODE === "production";
|
const isProduction = import.meta.env.MODE === "production";
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -42,18 +42,15 @@ const isProduction = import.meta.env.MODE === "production";
|
||||||
type="font/woff2"
|
type="font/woff2"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Metadata
|
<Metadata
|
||||||
schema={schema}
|
schema={schema}
|
||||||
globals={globals}
|
|
||||||
pageTitle={pageTitle}
|
pageTitle={pageTitle}
|
||||||
description={description}
|
description={description}
|
||||||
ogImage={ogImage}
|
ogImage={ogImage}
|
||||||
fullUrl={fullUrl}
|
fullUrl={fullUrl}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
/>
|
/>
|
||||||
|
<script defer src="/scripts/index.js" is:inline></script>
|
||||||
<script defer src="/scripts/index.js"></script>
|
|
||||||
{
|
{
|
||||||
isProduction && (
|
isProduction && (
|
||||||
<>
|
<>
|
||||||
|
@ -72,12 +69,12 @@ const isProduction = import.meta.env.MODE === "production";
|
||||||
<body>
|
<body>
|
||||||
<div class="main-wrapper">
|
<div class="main-wrapper">
|
||||||
<main>
|
<main>
|
||||||
<Header nav={nav} siteName={globals?.site_name} url={currentUrl} />
|
<Header siteName={globals?.site_name} url={currentUrl} />
|
||||||
<div class="default-wrapper">
|
<div class="default-wrapper">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<Footer nav={nav} />
|
<Footer updated={updated} />
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
19
src/middleware.js
Normal file
19
src/middleware.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { fetchGlobals } from "@utils/data/globals.js";
|
||||||
|
import { fetchNavigation } from "@utils/data/nav.js";
|
||||||
|
|
||||||
|
export async function onRequest(context, next) {
|
||||||
|
const { locals } = context;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const globals = await fetchGlobals();
|
||||||
|
const nav = await fetchNavigation();
|
||||||
|
|
||||||
|
locals.globals = globals;
|
||||||
|
locals.nav = nav;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in middleware fetching data:", error);
|
||||||
|
return new Response("Internal Server Error", { status: 500 });
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
import Layout from '@layouts/Layout.astro';
|
import Layout from '@layouts/Layout.astro';
|
||||||
import BlockRenderer from '@components/blocks/BlockRenderer.astro';
|
import BlockRenderer from '@components/blocks/BlockRenderer.astro';
|
||||||
import { fetchGlobals } from '@utils/data/globals.js';
|
|
||||||
import { fetchPages } from '@utils/data/pages';
|
import { fetchPages } from '@utils/data/pages';
|
||||||
|
|
||||||
export const prerender = true;
|
export const prerender = true;
|
||||||
|
@ -14,8 +13,8 @@ export async function getStaticPaths() {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const globals = await fetchGlobals();
|
|
||||||
const { page } = Astro.props;
|
const { page } = Astro.props;
|
||||||
|
const { globals } = Astro.locals;
|
||||||
const currentUrl = Astro.url.pathname;
|
const currentUrl = Astro.url.pathname;
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
---
|
---
|
||||||
import Layout from '@layouts/Layout.astro';
|
import Layout from '@layouts/Layout.astro';
|
||||||
import { IconRss, IconJson, IconMailPlus, IconBrandMastodon } from "@tabler/icons-react";
|
import { IconRss, IconJson, IconMailPlus, IconBrandMastodon } from "@tabler/icons-react";
|
||||||
import { fetchGlobals } from '@utils/data/globals.js';
|
|
||||||
import { fetchBlogroll } from '@utils/data/blogroll.js';
|
import { fetchBlogroll } from '@utils/data/blogroll.js';
|
||||||
|
|
||||||
const blogroll = await fetchBlogroll();
|
const blogroll = await fetchBlogroll();
|
||||||
const globals = await fetchGlobals();
|
|
||||||
|
|
||||||
const currentUrl = Astro.url.pathname;
|
const currentUrl = Astro.url.pathname;
|
||||||
|
|
||||||
const title = "Blogroll";
|
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
|
<Layout
|
||||||
globals={globals}
|
|
||||||
pageTitle={title}
|
pageTitle={title}
|
||||||
description={description}
|
description={description}
|
||||||
currentUrl={currentUrl}
|
currentUrl={currentUrl}
|
||||||
|
|
108
src/pages/books/[isbn].astro
Normal file
108
src/pages/books/[isbn].astro
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
---
|
||||||
|
import Layout from "@layouts/Layout.astro";
|
||||||
|
import Warning from "@components/blocks/banners/Warning.astro";
|
||||||
|
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/bookByUrl.js";
|
||||||
|
|
||||||
|
const { isbn } = Astro.params;
|
||||||
|
|
||||||
|
const book = await fetchBookByUrl(Astro.url.pathname);
|
||||||
|
if (!book) return Astro.redirect("/404", 404);
|
||||||
|
|
||||||
|
const alt = `${book.title}${book.author ? ` by ${book.author}` : ""}`;
|
||||||
|
const pageTitle = `Books / ${book.title}`;
|
||||||
|
const description = book.description || `Details about the book ${book.title}`;
|
||||||
|
const { globals } = Astro.locals;
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout pageTitle={pageTitle} description={description} schema="book">
|
||||||
|
<a class="back-link" href="/books" title="Go back to the books index page">
|
||||||
|
<IconArrowLeft size={18} /> Back to books
|
||||||
|
</a>
|
||||||
|
<article class="book-focus">
|
||||||
|
<div class="book-display">
|
||||||
|
<img
|
||||||
|
srcset={`
|
||||||
|
${globals.cdn_url}${book.image}?class=verticalsm&type=webp 200w,
|
||||||
|
${globals.cdn_url}${book.image}?class=verticalmd&type=webp 400w,
|
||||||
|
${globals.cdn_url}${book.image}?class=verticalbase&type=webp 800w
|
||||||
|
`}
|
||||||
|
sizes="(max-width: 450px) 203px,
|
||||||
|
(max-width: 850px) 406px,
|
||||||
|
(max-width: 1000px) 812px,
|
||||||
|
812px"
|
||||||
|
src={`${globals.cdn_url}${book.image}?class=verticalsm&type=webp`}
|
||||||
|
alt={alt}
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
width="200"
|
||||||
|
height="307"
|
||||||
|
/>
|
||||||
|
<div class="media-meta">
|
||||||
|
<span class="title"><strong>{book.title}</strong></span>
|
||||||
|
{book.rating && <span>{book.rating}</span>}
|
||||||
|
{book.author && <span class="sub-meta">By {book.author}</span>}
|
||||||
|
{
|
||||||
|
book.favorite && (
|
||||||
|
<span class="sub-meta favorite">
|
||||||
|
<IconHeart size={18} /> This is one of my favorite books!
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
book.tattoo && (
|
||||||
|
<span class="sub-meta tattoo">
|
||||||
|
<IconNeedle size={18} /> I have a tattoo inspired by this book!
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
book.status === "finished" && (
|
||||||
|
<span class="sub-meta">
|
||||||
|
Finished on:{" "}
|
||||||
|
<strong class="highlight-text">
|
||||||
|
{new Date(book.date_finished).toLocaleDateString("en-US", {
|
||||||
|
month: "long",
|
||||||
|
day: "numeric",
|
||||||
|
year: "numeric",
|
||||||
|
})}
|
||||||
|
</strong>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
book.status === "started" && (
|
||||||
|
<ProgressBar percentage={`${book.progress}%`} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
book.review && (
|
||||||
|
<>
|
||||||
|
<Warning text="There are probably spoilers after this banner — this is a warning about them." />
|
||||||
|
<h2>My thoughts</h2>
|
||||||
|
<div set:html={book.review} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<AssociatedMedia
|
||||||
|
artists={book.artists}
|
||||||
|
books={book.related_books}
|
||||||
|
genres={book.genres}
|
||||||
|
movies={book.movies}
|
||||||
|
posts={book.posts}
|
||||||
|
shows={book.shows}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
book.description && (
|
||||||
|
<>
|
||||||
|
<h2>Overview</h2>
|
||||||
|
<div set:html={book.description} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</article>
|
||||||
|
</Layout>
|
|
@ -2,18 +2,15 @@
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
import Rss from "@components/blocks/banners/Rss.astro";
|
import Rss from "@components/blocks/banners/Rss.astro";
|
||||||
import ProgressBar from "@components/media/ProgressBar.astro";
|
import ProgressBar from "@components/media/ProgressBar.astro";
|
||||||
import { fetchGlobals } from "@utils/data/globals.js";
|
|
||||||
import { fetchBooks } from "@utils/data/books.js";
|
import { fetchBooks } from "@utils/data/books.js";
|
||||||
import { md, htmlTruncate } from "@utils/helpers.js";
|
import { md, htmlTruncate } from "@utils/helpers.js";
|
||||||
|
|
||||||
const globals = await fetchGlobals();
|
|
||||||
const books = await fetchBooks();
|
const books = await fetchBooks();
|
||||||
|
const { globals } = Astro.locals;
|
||||||
const title = "Currently reading";
|
const title = "Currently reading";
|
||||||
const description = "Here's what I'm reading at the moment.";
|
const description = "Here's what I'm reading at the moment.";
|
||||||
const updated = new Date().toISOString();
|
const updated = new Date().toISOString();
|
||||||
const schema = "books";
|
const schema = "books";
|
||||||
|
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
const bookData = books.all
|
const bookData = books.all
|
||||||
.filter((book) => book.status === "started")
|
.filter((book) => book.status === "started")
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
---
|
---
|
||||||
import { fetchGlobals } from '@utils/data/globals';
|
|
||||||
import Layout from '@layouts/Layout.astro';
|
import Layout from '@layouts/Layout.astro';
|
||||||
import Intro from '@components/home/Intro.astro';
|
import Intro from '@components/home/Intro.astro';
|
||||||
import RecentActivity from '@components/home/RecentActivity.astro';
|
import RecentActivity from '@components/home/RecentActivity.astro';
|
||||||
import RecentPosts from '@components/home/RecentPosts.astro';
|
import RecentPosts from '@components/home/RecentPosts.astro';
|
||||||
|
|
||||||
const globals = await fetchGlobals();
|
const { globals } = Astro.locals;
|
||||||
const schema = 'blog';
|
const schema = 'blog';
|
||||||
const pageTitle = globals.site_name;
|
const pageTitle = globals.site_name;
|
||||||
const description = 'This is a blog post description';
|
const description = 'This is a blog post description';
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
import Paginator from "@components/nav/Paginator.astro";
|
import Paginator from "@components/nav/Paginator.astro";
|
||||||
import RssBanner from "@components/blocks/banners/Rss.astro";
|
import RssBanner from "@components/blocks/banners/Rss.astro";
|
||||||
import { fetchGlobals } from "@utils/data/globals.js";
|
|
||||||
import { fetchLinks } from "@utils/data/links.js";
|
import { fetchLinks } from "@utils/data/links.js";
|
||||||
|
|
||||||
const globals = await fetchGlobals();
|
const { globals } = Astro.locals;
|
||||||
const links = await fetchLinks();
|
const links = await fetchLinks();
|
||||||
|
|
||||||
const title = "Links";
|
const title = "Links";
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
---
|
---
|
||||||
import { getCollection } from 'astro:content';
|
import { getCollection } from 'astro:content';
|
||||||
import { IconStar } from '@tabler/icons-react';
|
import { IconStar } from '@tabler/icons-react';
|
||||||
import { fetchGlobals } from "@data/globals.js";
|
|
||||||
import { fetchAllPosts } from "@data/posts.js";
|
import { fetchAllPosts } from "@data/posts.js";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
import Paginator from '@components/nav/Paginator.astro';
|
import Paginator from '@components/nav/Paginator.astro';
|
||||||
import { md } from '@utils/helpers.js';
|
import { md } from '@utils/helpers.js';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
|
|
||||||
const globals = await fetchGlobals();
|
|
||||||
const posts = await fetchAllPosts();
|
const posts = await fetchAllPosts();
|
||||||
const { page } = Astro.props;
|
const { page } = Astro.props;
|
||||||
|
const { globals } = Astro.locals;
|
||||||
const currentUrl = Astro.url.pathname;
|
const currentUrl = Astro.url.pathname;
|
||||||
|
|
||||||
const currentPage = Astro.params.page ? parseInt(Astro.params.page, 10) : 1;
|
const currentPage = Astro.params.page ? parseInt(Astro.params.page, 10) : 1;
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
---
|
---
|
||||||
import { IconStar } from "@tabler/icons-react";
|
import { IconStar } from "@tabler/icons-react";
|
||||||
|
|
||||||
import { fetchAllPosts } from "@data/posts.js";
|
import { fetchAllPosts } from "@data/posts.js";
|
||||||
import { fetchAnalyticsData } from "@data/analytics.js";
|
import { fetchAnalyticsData } from "@data/analytics.js";
|
||||||
import { fetchGlobals } from "@data/globals.js";
|
|
||||||
import { fetchLinks } from "@data/links.js";
|
import { fetchLinks } from "@data/links.js";
|
||||||
|
|
||||||
import { md } from '@utils/helpers.js';
|
import { md } from '@utils/helpers.js';
|
||||||
import { getPopularPosts } from '@utils/getPopularPosts.js';
|
import { getPopularPosts } from '@utils/getPopularPosts.js';
|
||||||
|
|
||||||
|
@ -41,14 +38,13 @@ export async function getStaticPaths() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { post } = Astro.props;
|
const { post } = Astro.props;
|
||||||
|
const { globals } = Astro.locals;
|
||||||
const { year, title } = Astro.params;
|
const { year, title } = Astro.params;
|
||||||
const globals = await fetchGlobals();
|
|
||||||
const currentUrl = Astro.url.pathname;
|
const currentUrl = Astro.url.pathname;
|
||||||
const htmlContent = md(post.content);
|
const htmlContent = md(post.content);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout
|
<Layout
|
||||||
globals={globals}
|
|
||||||
pageTitle={post.title}
|
pageTitle={post.title}
|
||||||
description={post.description}
|
description={post.description}
|
||||||
ogImage={post.open_graph_image}
|
ogImage={post.open_graph_image}
|
||||||
|
|
26
src/utils/data/bookByUrl.js
Normal file
26
src/utils/data/bookByUrl.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { createClient } from "@supabase/supabase-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 bookCache = {};
|
||||||
|
|
||||||
|
export async function fetchBookByUrl(url) {
|
||||||
|
if (bookCache[url]) return bookCache[url];
|
||||||
|
|
||||||
|
const { data: book, error } = await supabase
|
||||||
|
.from("optimized_books")
|
||||||
|
.select("*")
|
||||||
|
.eq("url", url)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (error || !book) {
|
||||||
|
console.error(`Error fetching book with URL ${url}:`, error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bookCache[url] = book[0];
|
||||||
|
|
||||||
|
return book[0];
|
||||||
|
}
|
Reference in a new issue