Skip to content

Commit 7700686

Browse files
committed
fix(content): schema validation and use entry.id
1 parent cb81f53 commit 7700686

File tree

12 files changed

+141
-115
lines changed

12 files changed

+141
-115
lines changed

src/components/project-card.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import {GrLinkNext} from "react-icons/gr";
21
import {stringToKebabCase} from "../lib/utils.ts";
32

43
export default function ProjectCard({project, title, children, href = "#"}) {

src/components/services-list.astro

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
---
2+
import { idToSlug } from "../lib/utils";
23
const { services } = Astro.props;
4+
console.log(services);
35
---
46

57
<div class="overflow-hidden rounded-md mt-8" data-tags-container="1">
68
<ul role="list">
79
{services.map((service) => (
810
<li class={`overflow-clip bg-light-surface dark:bg-dark-surface shadow-2xl relative px-6 py-6 flex animate__animated animate__fadeIn`}
911
data-tags={`${service.tags?.join(",")}`}>
10-
<a href={`/services/${service.slug}`}>
12+
<a href={`/services/${idToSlug(service.id)}`}>
1113
{service.tags.includes("service") && (
1214
<span class="absolute shadow top-0 z-10 text-xs right-0 text-white bg-brand-primary px-1.5 py-0.5 rounded-bl opacity-75">
1315
Node Service

src/content/config.ts

Lines changed: 108 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,133 @@
1-
import { defineCollection, z } from 'astro:content';
1+
import {defineCollection, z} from 'astro:content';
22

3-
const news = defineCollection({
4-
type: 'content',
5-
schema: z.object({
6-
title: z.string(),
7-
date: z.string(),
8-
summary: z.string(),
9-
cover: z.object({
10-
source: z.string(),
11-
}).optional(),
12-
layout: z.string().optional(),
13-
variant: z.string().optional(),
14-
}),
3+
const about = defineCollection({
4+
type: 'content',
5+
schema: z.object({
6+
title: z.string().optional(),
7+
layout: z.string().optional(),
8+
variant: z.string().optional(),
9+
cover: z.object({
10+
source: z.string(),
11+
}).optional(),
12+
}),
1513
});
1614

17-
const services = defineCollection({
18-
type: 'content',
19-
schema: z.object({
20-
title: z.string(),
21-
summary: z.string(),
22-
logo: z.string().optional(),
23-
tags: z.array(z.string()).optional(),
24-
layout: z.string().optional(),
25-
variant: z.string().optional(),
26-
}),
15+
const accessibility = defineCollection({
16+
type: 'content',
17+
schema: z.object({
18+
title: z.string().optional(),
19+
layout: z.string().optional(),
20+
variant: z.string().optional(),
21+
}),
2722
});
2823

29-
const events = defineCollection({
30-
type: 'content',
31-
schema: z.object({
32-
title: z.string(),
33-
date: z.string(),
34-
summary: z.string(),
35-
cover: z.object({
36-
source: z.string(),
37-
}).optional(),
38-
layout: z.string().optional(),
39-
variant: z.string().optional(),
40-
}),
24+
const banner = defineCollection({
25+
type: 'content',
26+
schema: z.object({
27+
title: z.string().optional(),
28+
summary: z.string().optional(),
29+
}),
4130
});
4231

43-
const about = defineCollection({
44-
type: 'content',
45-
schema: z.object({
46-
title: z.string().optional(),
47-
summary: z.string().optional(),
48-
logo: z.string().optional(),
49-
layout: z.string().optional(),
50-
variant: z.string().optional(),
51-
}),
32+
const events = defineCollection({
33+
type: 'content',
34+
schema: z.object({
35+
layout: z.string().optional(),
36+
variant: z.string().optional(),
37+
title: z.string(),
38+
date: z.string(),
39+
cover: z.object({
40+
source: z.string(),
41+
}).optional(),
42+
summary: z.string(),
43+
}),
5244
});
5345

5446
const fundingAndProjects = defineCollection({
55-
type: 'content',
56-
schema: z.object({
57-
title: z.string(),
58-
summary: z.string().optional(),
59-
date: z.string().optional(),
60-
cover: z.object({
61-
source: z.string(),
62-
}).optional(),
63-
layout: z.string().optional(),
64-
variant: z.string().optional(),
65-
}),
47+
type: 'content',
48+
schema: z.object({
49+
layout: z.string().optional(),
50+
variant: z.string().optional(),
51+
title: z.string(),
52+
summary: z.string().optional(),
53+
status: z.string().optional(),
54+
category: z.string().optional(),
55+
funder: z.object({
56+
name: z.string().or(z.null()),
57+
link: z.string().or(z.null()),
58+
}).optional(),
59+
project_number: z.object({
60+
grant_agreement_id: z.string().or(z.number()).or(z.null()),
61+
link: z.string().or(z.null()),
62+
}).optional(),
63+
period: z.string().optional(),
64+
external_link: z.string().optional().or(z.null()),
65+
keywords: z.array(z.string()).optional(),
66+
draft: z.boolean().optional(),
67+
}),
6668
});
6769

68-
const accessibility = defineCollection({
69-
type: 'content',
70-
schema: z.object({
71-
title: z.string().optional(),
72-
layout: z.string().optional(),
73-
variant: z.string().optional(),
74-
}),
70+
const landing = defineCollection({
71+
type: 'content',
72+
schema: z.object({
73+
layout: z.string().optional(),
74+
variant: z.string().optional(),
75+
}),
7576
});
7677

77-
const banner = defineCollection({
78-
type: 'content',
79-
schema: z.object({
80-
title: z.string().optional(),
81-
layout: z.string().optional(),
82-
variant: z.string().optional(),
83-
}),
78+
const news = defineCollection({
79+
type: 'content',
80+
schema: z.object({
81+
layout: z.string().optional(),
82+
variant: z.string().optional(),
83+
title: z.string(),
84+
date: z.string(),
85+
cover: z.object({
86+
source: z.string(),
87+
}).optional(),
88+
summary: z.string(),
89+
}),
8490
});
8591

86-
const landing = defineCollection({
87-
type: 'content',
88-
schema: z.object({
89-
title: z.string().optional(),
90-
layout: z.string().optional(),
91-
variant: z.string().optional(),
92-
}),
92+
const researchSupport = defineCollection({
93+
type: 'content',
94+
schema: z.object({
95+
title: z.string().optional(),
96+
layout: z.string().optional(),
97+
variant: z.string().optional(),
98+
}),
9399
});
94100

95-
const researchSupport = defineCollection({
96-
type: 'content',
97-
schema: z.object({
98-
title: z.string().optional(),
99-
summary: z.string().optional(),
100-
layout: z.string().optional(),
101-
variant: z.string().optional(),
102-
}),
101+
const services = defineCollection({
102+
type: 'content',
103+
schema: z.object({
104+
layout: z.string().optional(),
105+
variant: z.string().optional(),
106+
title: z.string(),
107+
logo: z.string().optional(),
108+
summary: z.string(),
109+
tags: z.array(z.string()).optional(),
110+
}),
103111
});
104112

105113
const training = defineCollection({
106-
type: 'content',
107-
schema: z.object({
108-
title: z.string().optional(),
109-
summary: z.string().optional(),
110-
date: z.string().optional(),
111-
layout: z.string().optional(),
112-
variant: z.string().optional(),
113-
}),
114+
type: 'content',
115+
schema: z.object({
116+
layout: z.string().optional(),
117+
variant: z.string().optional(),
118+
title: z.string().optional(),
119+
}),
114120
});
115121

116122
export const collections = {
117-
news,
118-
services,
119-
events,
120-
about,
121-
'funding-and-projects': fundingAndProjects,
122-
accessibility,
123-
banner,
124-
landing,
125-
'research-support': researchSupport,
126-
training,
123+
news,
124+
services,
125+
events,
126+
about,
127+
'funding-and-projects': fundingAndProjects,
128+
accessibility,
129+
banner,
130+
landing,
131+
'research-support': researchSupport,
132+
training,
127133
};

src/lib/utils.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,16 @@ export const truncateStringToLength = (string: string, length: number) => {
2525
? `${string.substring(0, length).trim()}...`
2626
: string
2727
};
28+
29+
/**
30+
* Converts Astro v5 content id to URL-safe slug
31+
* Strips .mdx/.md extension and extracts filename
32+
*
33+
* Examples:
34+
* - "news/article.mdx" → "article"
35+
* - "services/galaxy.mdx" → "galaxy"
36+
* - "about/index.mdx" → "index"
37+
*/
38+
export const idToSlug = (id: string): string => {
39+
return id.replace(/\.(mdx|md)$/, '').split('/').pop() || id;
40+
};

src/pages/about/[...organization].astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
---
22
import { getCollection, render } from "astro:content";
33
import { components } from "../../components/elements";
4+
import { idToSlug } from "../../lib/utils";
45
56
export const prerender = true;
67
78
export async function getStaticPaths() {
89
const organizations = await getCollection("about");
910
return organizations.map((entry) => {
10-
console.log(entry)
1111
return ({
1212
params: {
13-
organization: entry.slug,
13+
organization: idToSlug(entry.id),
1414
},
1515
props: {
1616
entry,

src/pages/events/[...events].astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
import { getCollection, render } from "astro:content";
33
import { components } from "../../components/elements";
4+
import { idToSlug } from "../../lib/utils";
45
56
export const prerender = true;
67
@@ -9,7 +10,7 @@ export async function getStaticPaths() {
910
return events.map((entry) => {
1011
return {
1112
params: {
12-
events: entry.slug,
13+
events: idToSlug(entry.id),
1314
},
1415
props: {
1516
entry,

src/pages/events/index.astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import Page from "../../layouts/page.astro";
33
import { getCollection } from "astro:content";
44
import CardV2 from "../../components/card.v2";
5+
import { idToSlug } from "../../lib/utils";
56
67
// Function to normalize the date
78
function parseDate(dateString: string): number {
@@ -26,7 +27,7 @@ events.sort((a, b) => parseDate(b.data.date) - parseDate(a.data.date));
2627
events.map((entry) => {
2728
return (
2829
<CardV2
29-
link={`/events/${entry.slug}`}
30+
link={`/events/${idToSlug(entry.id)}`}
3031
title={entry.data.title}
3132
summary={entry.data.summary}
3233
cover={entry.data?.cover?.source}

src/pages/funding-and-projects/[...project].astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
---
22
import { getCollection, render } from "astro:content";
33
import { components } from "../../components/elements";
4+
import { idToSlug } from "../../lib/utils";
45
56
export const prerender = true;
67
78
export async function getStaticPaths() {
89
const projects = await getCollection("funding-and-projects");
910
return projects.map((entry) => ({
1011
params: {
11-
project: entry.slug,
12+
project: idToSlug(entry.id),
1213
},
1314
props: {
1415
entry,

src/pages/funding-and-projects/index.astro

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
import ProjectCard from "../../components/project-card";
33
import {getCollection} from 'astro:content';
4-
import {slugToTitleCase, sortStringsByLength} from "../../lib/utils";
4+
import {slugToTitleCase, sortStringsByLength, idToSlug} from "../../lib/utils";
55
import Page from "../../layouts/page.astro";
66
import MetadataFilter from "../../components/metadata-filter";
77
@@ -60,7 +60,7 @@ const projects =
6060
.filter((item: any) => !item.data.draft);
6161
6262
const _projects = projects.map(
63-
({slug, id, data}) => ({slug, id, ...data})
63+
({id, data}) => ({id, ...data})
6464
);
6565
6666
const _filters = [
@@ -169,7 +169,7 @@ const _filters = [
169169
{_projects.map((project) => {
170170
return (
171171
<ProjectCard project={project} title={project.title}
172-
href={`/funding-and-projects/${project.slug}`}>
172+
href={`/funding-and-projects/${idToSlug(project.id)}`}>
173173
{project.summary}
174174
</ProjectCard>
175175
);

src/pages/news/[...news].astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { getCollection, render } from "astro:content";
33
import type { CollectionEntry } from "astro:content";
44
import { components } from "../../components/elements";
5+
import { idToSlug } from "../../lib/utils";
56
67
export const prerender = true;
78
@@ -14,7 +15,7 @@ export async function getStaticPaths() {
1415
];
1516
return {
1617
params: {
17-
news: entry.slug,
18+
news: idToSlug(entry.id),
1819
},
1920
props: {
2021
entry,

0 commit comments

Comments
 (0)