Skip to content

Commit 5831b33

Browse files
committed
Load content collections from json files.
1 parent db5ad69 commit 5831b33

File tree

5 files changed

+121
-3
lines changed

5 files changed

+121
-3
lines changed

astro.config.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ export default defineConfig({
7878
},
7979
image: {
8080
experimentalLayout: "responsive",
81+
remotePatterns: [{ protocol: "https" }],
82+
domains: ["programme.europython.eu", "placehold.co"],
83+
service: {
84+
entrypoint: "src/image.service.ts",
85+
},
8186
},
8287
experimental: {
8388
responsiveImages: true,

src/assets/placeholder.png

5.35 KB
Loading

src/assets/placeholder.svg

Lines changed: 1 addition & 0 deletions
Loading

src/image.service.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import type { LocalImageService, ImageTransform, AstroConfig } from "astro";
2+
3+
type OutputFormat = "avif" | "jpeg" | "jpg" | "png" | "webp";
4+
5+
const service: LocalImageService = {
6+
getURL(options: ImageTransform, imageConfig: AstroConfig["image"]) {
7+
const searchParams = new URLSearchParams();
8+
searchParams.append(
9+
"href",
10+
typeof options.src === "string" ? options.src : options.src.src
11+
);
12+
if (options.width) searchParams.append("w", options.width.toString());
13+
if (options.height) searchParams.append("h", options.height.toString());
14+
if (options.quality) searchParams.append("q", options.quality.toString());
15+
if (options.format) searchParams.append("f", options.format);
16+
return `/_image/?${searchParams.toString()}`;
17+
},
18+
19+
parseURL(url: URL, imageConfig) {
20+
const params = url.searchParams;
21+
return {
22+
src: params.get("href")!,
23+
width: params.has("w") ? parseInt(params.get("w")!) : undefined,
24+
height: params.has("h") ? parseInt(params.get("h")!) : undefined,
25+
quality: params.has("q") ? parseInt(params.get("q")!) : undefined,
26+
format: params.get("f") as OutputFormat | undefined,
27+
};
28+
},
29+
30+
async transform(
31+
inputBuffer: Uint8Array,
32+
transform: {
33+
src: string;
34+
width?: number;
35+
height?: number;
36+
quality?: number;
37+
format?: OutputFormat;
38+
},
39+
imageConfig
40+
) {
41+
let buffer = inputBuffer;
42+
43+
if (/^https?:\/\//.test(transform.src)) {
44+
const response = await fetch(transform.src);
45+
if (!response.ok) {
46+
throw new Error(`Failed to fetch image from ${transform.src}`);
47+
}
48+
buffer = new Uint8Array(await response.arrayBuffer());
49+
}
50+
51+
const sharp = (await import("sharp")).default;
52+
let image = sharp(buffer);
53+
54+
if (transform.width || transform.height) {
55+
image = image.resize(transform.width, transform.height);
56+
}
57+
58+
if (transform.format) {
59+
image = image.toFormat(transform.format, {
60+
quality: transform.quality,
61+
});
62+
}
63+
64+
const outputBuffer = await image.toBuffer();
65+
66+
return {
67+
data: outputBuffer,
68+
format: transform.format ?? "webp",
69+
};
70+
},
71+
72+
getHTMLAttributes(options, imageConfig) {
73+
let targetWidth = options.width;
74+
let targetHeight = options.height;
75+
76+
if (typeof options.src === "object") {
77+
const aspectRatio = options.src.width / options.src.height;
78+
if (targetHeight && !targetWidth) {
79+
targetWidth = Math.round(targetHeight * aspectRatio);
80+
} else if (targetWidth && !targetHeight) {
81+
targetHeight = Math.round(targetWidth / aspectRatio);
82+
}
83+
}
84+
85+
const { src, width, height, format, quality, ...attributes } = options;
86+
87+
return {
88+
...attributes,
89+
width: targetWidth,
90+
height: targetHeight,
91+
loading: attributes.loading ?? "lazy",
92+
decoding: attributes.decoding ?? "async",
93+
};
94+
},
95+
96+
propertiesToHash: ["src", "width", "height", "format", "quality"],
97+
};
98+
99+
export default service;

src/pages/speaker/[slug].astro

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
import { getCollection, getEntries } from "astro:content";
33
import Layout from "../../layouts/Layout.astro";
44
import Prose from "../../components/prose/prose.astro";
5-
import { Picture } from "astro:assets";
6-
import { getEntry, render } from 'astro:content';
5+
import { Picture, getImage } from "astro:assets";
76
import Markdown from "@ui/Markdown.astro";
87
import Headline from "@ui/Headline.astro";
8+
import Placeholder from "@assets/placeholder.png";
99
1010
export async function getStaticPaths() {
1111
const entries = await getCollection("speakers");
@@ -18,6 +18,19 @@ export async function getStaticPaths() {
1818
const {entry} = Astro.props;
1919
console.log(entry.data.avatar);
2020
21+
let avatar: any;
22+
23+
try {
24+
25+
avatar = getImage({ src: entry.data.avatar , width:'600', htight: '400', alt: 'User avatar' });
26+
} catch (e) {
27+
//TODO: improve placeholders and offline
28+
//avatar = await getImage({ src: 'https://placehold.co/600x400?text=x', width: '600', height:'400', alt: 'Default avatar' });
29+
//avatar = await getImage({ src: '@assets/prague.png', width: '600', height:'400', alt: 'Default avatar' });
30+
avatar = Placeholder;
31+
}
32+
33+
2134
const sessions = await getEntries(entry.data.submissions);
2235
2336
// Get @username from Twitter URL
@@ -75,7 +88,7 @@ function ensureHttps(str: string): string {
7588
(entry.data.avatar &&
7689
<div class="border-4 border-white rounded-lg shadow-lg inline-block mb-10">
7790
<Picture
78-
src={entry.data.avatar}
91+
src={avatar}
7992
alt={entry.data.name}
8093
inferSize={true}
8194
widths={[400, 800, 1200]}

0 commit comments

Comments
 (0)