This commit is contained in:
parent
4b3aa3022e
commit
632543db4d
55 changed files with 432 additions and 117 deletions
|
|
@ -12,6 +12,7 @@ import tailwindcss from "@tailwindcss/vite";
|
|||
import remarkCallouts from "./src/remark/callouts.mjs";
|
||||
import remarkCodeFenceLanguages from "./src/remark/code-fence-languages.mjs";
|
||||
import remarkInlineFootnotes from "./src/remark/inline-footnotes.mjs";
|
||||
import remarkTypography from "./src/remark/typography.mjs";
|
||||
import { ACTIVE_BLOG_SITE } from "./src/blog-sites.js";
|
||||
|
||||
const remarkPlugins = [
|
||||
|
|
@ -19,6 +20,7 @@ const remarkPlugins = [
|
|||
remarkInlineFootnotes,
|
||||
remarkCodeFenceLanguages,
|
||||
remarkMath,
|
||||
remarkTypography,
|
||||
remarkCallouts,
|
||||
];
|
||||
const rehypePlugins = [rehypeKatex];
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
// all pages through the use of the <BaseHead /> component.
|
||||
import '../styles/global.css';
|
||||
import { SITE_TITLE, SITE_METADATA } from '../consts';
|
||||
import { typographicText } from '@/lib/typography';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
|
|
@ -13,8 +14,8 @@ interface Props {
|
|||
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
||||
|
||||
const { title, description, image } = Astro.props;
|
||||
const finalTitle = title || SITE_METADATA.title.default;
|
||||
const finalDescription = description || SITE_METADATA.description;
|
||||
const finalTitle = typographicText(title || SITE_METADATA.title.default);
|
||||
const finalDescription = typographicText(description || SITE_METADATA.description);
|
||||
const finalImage = image || SITE_METADATA.openGraph.images[0].url;
|
||||
const imageURL = new URL(finalImage, Astro.url);
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { ReactNode } from "react";
|
||||
import { format } from "date-fns";
|
||||
import { typographicText } from "@/lib/typography";
|
||||
|
||||
const getReadingTime = (body: string | undefined) => {
|
||||
const words = (body ?? "")
|
||||
|
|
@ -18,6 +19,7 @@ const BlogPost = ({
|
|||
children: ReactNode;
|
||||
}) => {
|
||||
const { title, image, pubDate } = post.data;
|
||||
const displayTitle = typographicText(title);
|
||||
const readingTime = getReadingTime(post.body);
|
||||
|
||||
return (
|
||||
|
|
@ -30,12 +32,12 @@ const BlogPost = ({
|
|||
</time>
|
||||
<span>{readingTime} min read</span>
|
||||
</div>
|
||||
<h1 className="blog-post-title">{title}</h1>
|
||||
<h1 className="blog-post-title">{displayTitle}</h1>
|
||||
</header>
|
||||
|
||||
{image ? (
|
||||
<figure className="blog-post-hero-image">
|
||||
<img src={image} alt={title} />
|
||||
<img src={image} alt={displayTitle} />
|
||||
</figure>
|
||||
) : null}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { Calendar, Clock, User } from "lucide-react";
|
||||
import { typographicText } from "@/lib/typography";
|
||||
import { PlusSigns } from "../icons/plus-signs";
|
||||
|
||||
const BlogPosts = ({
|
||||
|
|
@ -27,11 +28,13 @@ const BlogPosts = ({
|
|||
post: any;
|
||||
featured?: boolean;
|
||||
}) => {
|
||||
const displayTitle = typographicText(post.data.title);
|
||||
|
||||
if (post.data.image) {
|
||||
return (
|
||||
<img
|
||||
src={post.data.image}
|
||||
alt={post.data.title}
|
||||
alt={displayTitle}
|
||||
className="aspect-video w-full rounded-lg object-cover transition-transform group-hover:scale-[1.02]"
|
||||
/>
|
||||
);
|
||||
|
|
@ -44,7 +47,7 @@ const BlogPosts = ({
|
|||
featured ? "font-fraunces text-2xl" : "font-fraunces text-lg"
|
||||
}
|
||||
>
|
||||
{post.data.title}
|
||||
{displayTitle}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -82,10 +85,10 @@ const BlogPosts = ({
|
|||
Featured Post
|
||||
</Badge>
|
||||
<h2 className="blog-card-title-featured mb-3 group-hover:underline">
|
||||
{featuredPost.data.title}
|
||||
{typographicText(featuredPost.data.title)}
|
||||
</h2>
|
||||
<p className="text-muted-foreground mb-4 line-clamp-3 text-base">
|
||||
{featuredPost.data.description}
|
||||
{typographicText(featuredPost.data.description)}
|
||||
</p>
|
||||
|
||||
<div className="mb-6 flex gap-4">
|
||||
|
|
@ -128,10 +131,10 @@ const BlogPosts = ({
|
|||
</div>
|
||||
<div className="px-4 pb-5 pt-2">
|
||||
<h2 className="mb-2 text-xl font-semibold group-hover:underline">
|
||||
{post.data.title}
|
||||
{typographicText(post.data.title)}
|
||||
</h2>
|
||||
<p className="text-muted-foreground line-clamp-2 text-sm">
|
||||
{post.data.description}
|
||||
{typographicText(post.data.description)}
|
||||
</p>
|
||||
|
||||
<div className="text-muted-foreground mt-3 flex items-center gap-3 text-xs">
|
||||
|
|
|
|||
5
sites/research/src/lib/typography.ts
Normal file
5
sites/research/src/lib/typography.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
const EM_DASH_PATTERN = /---/g;
|
||||
|
||||
export function typographicText(value: string | null | undefined) {
|
||||
return (value ?? "").replace(EM_DASH_PATTERN, "—");
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import rss from "@astrojs/rss";
|
|||
import { getCollection } from "astro:content";
|
||||
import { SITE_TITLE, SITE_DESCRIPTION } from "../consts";
|
||||
import { ACTIVE_BLOG_SITE } from "../blog-sites.js";
|
||||
import { typographicText } from "@/lib/typography";
|
||||
|
||||
export async function GET(context) {
|
||||
const posts = (await getCollection(ACTIVE_BLOG_SITE.key)).sort(
|
||||
|
|
@ -10,10 +11,12 @@ export async function GET(context) {
|
|||
|
||||
return rss({
|
||||
title: SITE_TITLE,
|
||||
description: SITE_DESCRIPTION,
|
||||
description: typographicText(SITE_DESCRIPTION),
|
||||
site: context.site,
|
||||
items: posts.map((post) => ({
|
||||
...post.data,
|
||||
title: typographicText(post.data.title),
|
||||
description: typographicText(post.data.description),
|
||||
link: `/${post.id.replace(/\/index$/, "")}/`,
|
||||
})),
|
||||
});
|
||||
|
|
|
|||
22
sites/research/src/remark/typography.mjs
Normal file
22
sites/research/src/remark/typography.mjs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
const EM_DASH_PATTERN = /---/g;
|
||||
|
||||
function visitTextNodes(node) {
|
||||
if (!node || typeof node !== "object") return;
|
||||
|
||||
if (node.type === "text" && typeof node.value === "string") {
|
||||
node.value = node.value.replace(EM_DASH_PATTERN, "—");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Array.isArray(node.children)) return;
|
||||
|
||||
for (const child of node.children) {
|
||||
visitTextNodes(child);
|
||||
}
|
||||
}
|
||||
|
||||
export default function remarkTypography() {
|
||||
return (tree) => {
|
||||
visitTextNodes(tree);
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue