init elas atelier #1
@@ -6,6 +6,8 @@ const PAGE_SIZE = 9;
|
||||
interface CoverImage {
|
||||
url: string;
|
||||
alt: string;
|
||||
w?: number;
|
||||
h?: number;
|
||||
}
|
||||
|
||||
interface Post {
|
||||
@@ -135,7 +137,11 @@ export default function PostList({ posts: initialPosts, isAdmin = false }: Props
|
||||
<img
|
||||
src={post.cover_image!.url}
|
||||
alt={post.cover_image!.alt || displayTitle}
|
||||
width={post.cover_image!.w}
|
||||
height={post.cover_image!.h}
|
||||
loading={idx < 3 ? 'eager' : 'lazy'}
|
||||
decoding={idx === 0 ? 'sync' : 'async'}
|
||||
fetchPriority={idx === 0 ? 'high' : undefined}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
|
||||
@@ -79,8 +79,22 @@ const KATEX_TAGS = [
|
||||
'mpadded', 'menclose',
|
||||
];
|
||||
|
||||
export function renderMarkdown(src: string): string {
|
||||
const html = renderer.parse(src, { async: false }) as string;
|
||||
export interface ImageDim { w: number; h: number }
|
||||
export type ImageDims = Record<string, ImageDim>;
|
||||
|
||||
function injectDimensions(html: string, dims?: ImageDims): string {
|
||||
if (!dims) return html;
|
||||
return html.replace(/<img\s+src="([^"]+)"([^>]*?)\s*\/?>/g, (match, src, rest) => {
|
||||
const d = dims[src];
|
||||
if (!d) return match;
|
||||
if (/\swidth\s*=/.test(rest) || /\sheight\s*=/.test(rest)) return match;
|
||||
return `<img src="${src}" width="${d.w}" height="${d.h}"${rest} />`;
|
||||
});
|
||||
}
|
||||
|
||||
export function renderMarkdown(src: string, dims?: ImageDims): string {
|
||||
let html = renderer.parse(src, { async: false }) as string;
|
||||
html = injectDimensions(html, dims);
|
||||
return DOMPurify.sanitize(html, {
|
||||
ADD_TAGS: [...KATEX_TAGS, 'figure', 'figcaption'],
|
||||
ADD_ATTR: ['aria-hidden', 'style', 'id', 'class', 'encoding', 'mathvariant', 'displaystyle', 'scriptlevel', 'loading'],
|
||||
|
||||
@@ -9,6 +9,8 @@ const API_URL = process.env.PUBLIC_API_URL || 'http://localhost:3000';
|
||||
interface CoverImage {
|
||||
url: string;
|
||||
alt: string;
|
||||
w?: number;
|
||||
h?: number;
|
||||
}
|
||||
|
||||
interface Post {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { renderMarkdown } from '../../lib/markdown';
|
||||
const { slug } = Astro.params;
|
||||
const API_URL = (typeof process !== 'undefined' ? process.env.PUBLIC_API_URL : import.meta.env.PUBLIC_API_URL) || 'http://localhost:3000';
|
||||
|
||||
interface CoverImage { url: string; alt: string }
|
||||
interface CoverImage { url: string; alt: string; w?: number; h?: number }
|
||||
interface PostNeighbor {
|
||||
slug: string;
|
||||
title?: string;
|
||||
@@ -26,6 +26,7 @@ interface PostDetail {
|
||||
image_count: number;
|
||||
prev?: PostNeighbor;
|
||||
next?: PostNeighbor;
|
||||
dimensions?: Record<string, { w: number; h: number }>;
|
||||
}
|
||||
|
||||
function formatDate(d: string) {
|
||||
@@ -45,7 +46,7 @@ try {
|
||||
const postRes = await fetch(`${API_URL}/api/posts/${encodeURIComponent(slug ?? '')}`);
|
||||
if (postRes.ok) {
|
||||
post = await postRes.json();
|
||||
html = renderMarkdown(post!.content);
|
||||
html = renderMarkdown(post!.content, post!.dimensions);
|
||||
} else {
|
||||
error = 'Work not found in the catalogue';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user