astro-theme-popular 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/index.mjs +32 -20
- package/package.json +1 -1
- package/src/components/EventRow.astro +3 -3
- package/src/components/PostCard.astro +2 -2
- package/src/lib/collections.ts +14 -0
- package/src/pages/[slug].astro +5 -4
- package/src/pages/authors/[slug].astro +4 -3
- package/src/pages/blog/[...page].astro +2 -2
- package/src/pages/blog/[slug].astro +4 -3
- package/src/pages/events/[...page].astro +2 -2
- package/src/pages/events/[slug].astro +5 -4
- package/src/pages/index.astro +5 -5
- package/src/pages/organizers/[...page].astro +2 -2
- package/src/pages/rss.xml.js +3 -3
- package/src/pages/speakers/[slug].astro +4 -3
- package/src/pages/tags/[tag]/[...page].astro +2 -2
- package/src/pages/venues/[slug].astro +4 -3
package/README.md
CHANGED
|
@@ -21,6 +21,13 @@ export default defineConfig({
|
|
|
21
21
|
});
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
Disable any injected route group when your site replaces it (also the
|
|
25
|
+
answer when you provide your own `/` or `/rss.xml`):
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
popular({ routes: { speakers: false, venues: false } })
|
|
29
|
+
```
|
|
30
|
+
|
|
24
31
|
Your site keeps its own content (`src/content/`) and one typed config file
|
|
25
32
|
(`popular.config.ts`); the theme injects the routes, layouts, styles and
|
|
26
33
|
behavior. Adopt the content model in one line:
|
package/index.mjs
CHANGED
|
@@ -14,20 +14,29 @@
|
|
|
14
14
|
import path from 'node:path';
|
|
15
15
|
import { fileURLToPath } from 'node:url';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
['/
|
|
24
|
-
['/
|
|
25
|
-
['/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
/* Injected routes, grouped by opt-out key: popular({ routes: { speakers:
|
|
18
|
+
false } }) skips a group. Disabling is also the durable answer when your
|
|
19
|
+
site provides its own page at a theme path (`/`, `/rss.xml`): Astro is
|
|
20
|
+
deprecating silent route collisions. Slug routes use rest params so
|
|
21
|
+
folder-organized content ids (2019-pycon-us/cooper-lees) resolve. */
|
|
22
|
+
const ROUTES = {
|
|
23
|
+
home: [['/', 'index.astro']],
|
|
24
|
+
pages: [['/[...slug]', '[slug].astro']],
|
|
25
|
+
authors: [['/authors/[...slug]', 'authors/[slug].astro']],
|
|
26
|
+
blog: [
|
|
27
|
+
['/blog/[...page]', 'blog/[...page].astro'],
|
|
28
|
+
['/blog/[...slug]', 'blog/[slug].astro'],
|
|
29
|
+
],
|
|
30
|
+
events: [
|
|
31
|
+
['/events/[...page]', 'events/[...page].astro'],
|
|
32
|
+
['/events/[...slug]', 'events/[slug].astro'],
|
|
33
|
+
],
|
|
34
|
+
organizers: [['/organizers/[...page]', 'organizers/[...page].astro']],
|
|
35
|
+
speakers: [['/speakers/[...slug]', 'speakers/[slug].astro']],
|
|
36
|
+
venues: [['/venues/[...slug]', 'venues/[slug].astro']],
|
|
37
|
+
tags: [['/tags/[tag]/[...page]', 'tags/[tag]/[...page].astro']],
|
|
38
|
+
rss: [['/rss.xml', 'rss.xml.js']],
|
|
39
|
+
};
|
|
31
40
|
|
|
32
41
|
export default function popular(options = {}) {
|
|
33
42
|
const configFile = options.configFile ?? './popular.config.ts';
|
|
@@ -68,12 +77,15 @@ export default function popular(options = {}) {
|
|
|
68
77
|
'copy-code',
|
|
69
78
|
].map((s) => `import 'astro-theme-popular/scripts/${s}.js';`).join('\n'),
|
|
70
79
|
);
|
|
71
|
-
for (const [
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
for (const [key, routes] of Object.entries(ROUTES)) {
|
|
81
|
+
if (options.routes?.[key] === false) continue;
|
|
82
|
+
for (const [pattern, entry] of routes) {
|
|
83
|
+
injectRoute({
|
|
84
|
+
pattern,
|
|
85
|
+
entrypoint: `astro-theme-popular/pages/${entry}`,
|
|
86
|
+
prerender: true,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
77
89
|
}
|
|
78
90
|
},
|
|
79
91
|
},
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { SITE, STRINGS } from 'popular:config';
|
|
3
3
|
import type { CollectionEntry } from 'astro:content';
|
|
4
|
-
import {
|
|
4
|
+
import { safeCollection } from '../lib/collections';
|
|
5
5
|
|
|
6
6
|
interface Props { event: CollectionEntry<'events'> }
|
|
7
7
|
const { event } = Astro.props;
|
|
8
8
|
const d = event.data;
|
|
9
9
|
|
|
10
10
|
/* Venue: a venueRef to the venues collection wins over the flat fields. */
|
|
11
|
-
const venuePage = d.venueRef ? (await
|
|
11
|
+
const venuePage = d.venueRef ? (await safeCollection('venues')).find((v) => v.id === d.venueRef) : undefined;
|
|
12
12
|
if (d.venueRef && !venuePage) console.warn(`events/${event.id}: venueRef "${d.venueRef}" matches no venue page`);
|
|
13
13
|
const venueName = venuePage?.data.title ?? d.venue;
|
|
14
14
|
const venueAddress = venuePage?.data.address ?? (venuePage ? undefined : d.address);
|
|
15
15
|
const tbd = d.venueWanted || !venueName;
|
|
16
16
|
|
|
17
17
|
/* Speaker line: resolved speaker-profile names, falling back to the string. */
|
|
18
|
-
const allSpeakers = d.speakers.length ? await
|
|
18
|
+
const allSpeakers = d.speakers.length ? await safeCollection('speakers') : [];
|
|
19
19
|
const names = d.speakers.map((slug) => {
|
|
20
20
|
const found = allSpeakers.find((s) => s.id === slug);
|
|
21
21
|
if (!found) console.warn(`events/${event.id}: speaker "${slug}" matches no speaker page`);
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { SITE } from 'popular:config';
|
|
3
3
|
import { tagSlug } from '../lib/slugs';
|
|
4
4
|
import type { CollectionEntry } from 'astro:content';
|
|
5
|
-
import {
|
|
5
|
+
import { safeCollection } from '../lib/collections';
|
|
6
6
|
|
|
7
7
|
interface Props { post: CollectionEntry<'blog'> }
|
|
8
8
|
const { post } = Astro.props;
|
|
9
9
|
const d = post.data;
|
|
10
10
|
const href = `/blog/${post.id}/`;
|
|
11
11
|
const month = d.date.toLocaleDateString(SITE.locale, { month: 'short', year: 'numeric' });
|
|
12
|
-
const allAuthors = await
|
|
12
|
+
const allAuthors = await safeCollection('authors');
|
|
13
13
|
const names = [
|
|
14
14
|
...d.authors.map((slug) => allAuthors.find((a) => a.id === slug)?.data.title ?? slug),
|
|
15
15
|
...d.guestAuthors.map((g) => g.name),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getCollection } from 'astro:content';
|
|
2
|
+
|
|
3
|
+
/* Collection access that tolerates an adopter who never defined (or has no
|
|
4
|
+
entries in) a collection: returns [] instead of undefined. Sites that
|
|
5
|
+
replace part of the content model should also disable the matching
|
|
6
|
+
injected route (popular({ routes: { venues: false } })), which silences
|
|
7
|
+
Astro's missing-collection warning entirely. */
|
|
8
|
+
export async function safeCollection(name: string): Promise<any[]> {
|
|
9
|
+
try {
|
|
10
|
+
return ((await getCollection(name as any)) as any[]) ?? [];
|
|
11
|
+
} catch {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
}
|
package/src/pages/[slug].astro
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
import { STRINGS } from 'popular:config';
|
|
3
3
|
/** Root-level content pages: prose pages (about, code-of-conduct, get-involved)
|
|
4
4
|
* and docs pages (handbook, runbooks, rendered with a scroll-spy TOC). */
|
|
5
|
-
import {
|
|
5
|
+
import { render } from 'astro:content';
|
|
6
|
+
import { safeCollection } from '../lib/collections';
|
|
6
7
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
|
7
8
|
import PageHero from '../components/PageHero.astro';
|
|
8
9
|
|
|
9
10
|
export async function getStaticPaths() {
|
|
10
|
-
const pages = await
|
|
11
|
-
const docs = await
|
|
11
|
+
const pages = await safeCollection('pages');
|
|
12
|
+
const docs = await safeCollection('docs');
|
|
12
13
|
return [
|
|
13
14
|
...pages.map((entry) => ({ params: { slug: entry.id }, props: { entry, kind: 'page' } })),
|
|
14
15
|
...docs.map((entry) => ({ params: { slug: entry.id }, props: { entry, kind: 'doc' } })),
|
|
@@ -21,7 +22,7 @@ const { Content, headings } = await render(entry);
|
|
|
21
22
|
/* Current page's h2/h3 links nest under its sidebar entry, in document
|
|
22
23
|
order, mirroring the Hugo theme's docs/single.html. */
|
|
23
24
|
const sections = headings.filter((h) => h.depth === 2 || h.depth === 3);
|
|
24
|
-
const allDocs = (await
|
|
25
|
+
const allDocs = (await safeCollection('docs')).sort(
|
|
25
26
|
(a, b) => (a.data.weight ?? 100) - (b.data.weight ?? 100)
|
|
26
27
|
);
|
|
27
28
|
---
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { STRINGS } from 'popular:config';
|
|
3
|
-
import {
|
|
3
|
+
import { render } from 'astro:content';
|
|
4
|
+
import { safeCollection } from '../../lib/collections';
|
|
4
5
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
5
6
|
import PageHero from '../../components/PageHero.astro';
|
|
6
7
|
import AuthorBox from '../../components/AuthorBox.astro';
|
|
7
8
|
import PostCard from '../../components/PostCard.astro';
|
|
8
9
|
|
|
9
10
|
export async function getStaticPaths() {
|
|
10
|
-
const authors = await
|
|
11
|
+
const authors = await safeCollection('authors');
|
|
11
12
|
return authors.map((entry) => ({ params: { slug: entry.id }, props: { entry } }));
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const { entry } = Astro.props;
|
|
15
16
|
const { Content } = await render(entry);
|
|
16
|
-
const posts = (await
|
|
17
|
+
const posts = (await safeCollection('blog'))
|
|
17
18
|
.filter((p) => !p.data.draft && p.data.authors.includes(entry.id))
|
|
18
19
|
.sort((a, b) => +b.data.date - +a.data.date);
|
|
19
20
|
---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { safeCollection } from '../../lib/collections';
|
|
3
3
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
4
4
|
import PageHero from '../../components/PageHero.astro';
|
|
5
5
|
import PostCard from '../../components/PostCard.astro';
|
|
@@ -10,7 +10,7 @@ import { SECTIONS, STRINGS, PAGINATION } from 'popular:config';
|
|
|
10
10
|
paginator URLs. /blog/<slug> still goes to [slug].astro: named params
|
|
11
11
|
take priority over rest params. */
|
|
12
12
|
export async function getStaticPaths() {
|
|
13
|
-
const posts = (await
|
|
13
|
+
const posts = (await safeCollection('blog')).filter((p) => !p.data.draft).sort((a, b) => +b.data.date - +a.data.date);
|
|
14
14
|
const size = PAGINATION.pageSize;
|
|
15
15
|
const total = Math.max(1, Math.ceil(posts.length / size));
|
|
16
16
|
const tags = [...new Set(posts.flatMap((p) => p.data.tags))];
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { render } from 'astro:content';
|
|
3
|
+
import { safeCollection } from '../../lib/collections';
|
|
3
4
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
4
5
|
import AuthorBox from '../../components/AuthorBox.astro';
|
|
5
6
|
import { SUPPORT, SITE, STRINGS } from 'popular:config';
|
|
6
7
|
import { tagSlug } from '../../lib/slugs';
|
|
7
8
|
|
|
8
9
|
export async function getStaticPaths() {
|
|
9
|
-
const posts = (await
|
|
10
|
+
const posts = (await safeCollection('blog')).filter((p) => !p.data.draft);
|
|
10
11
|
/* PARITY.md pins the ordering: date desc, then title, then id, matching
|
|
11
12
|
Hugo's section order (posts must not set weight). next = newer. */
|
|
12
13
|
const cmp = (x: string, y: string) => (x < y ? -1 : x > y ? 1 : 0);
|
|
@@ -24,7 +25,7 @@ const d = post.data;
|
|
|
24
25
|
const { Content } = await render(post);
|
|
25
26
|
const dateStr = d.date.toLocaleDateString(SITE.locale, { month: 'short', day: 'numeric', year: 'numeric' });
|
|
26
27
|
|
|
27
|
-
const allAuthors = await
|
|
28
|
+
const allAuthors = await safeCollection('authors');
|
|
28
29
|
const resolved = d.authors.map((slug) => allAuthors.find((a) => a.id === slug)).filter(Boolean);
|
|
29
30
|
const bylineNames = [
|
|
30
31
|
...d.authors.map((slug) => allAuthors.find((a) => a.id === slug)?.data.title ?? slug),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { safeCollection } from '../../lib/collections';
|
|
3
3
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
4
4
|
import PageHero from '../../components/PageHero.astro';
|
|
5
5
|
import EventRow from '../../components/EventRow.astro';
|
|
@@ -11,7 +11,7 @@ import { SECTIONS, STRINGS, PAGINATION } from 'popular:config';
|
|
|
11
11
|
full, mirroring layouts/events/list.html on the Hugo side. */
|
|
12
12
|
export async function getStaticPaths() {
|
|
13
13
|
const now = new Date();
|
|
14
|
-
const all = (await
|
|
14
|
+
const all = (await safeCollection('events')).filter((e) => !e.data.draft);
|
|
15
15
|
const upcoming = all.filter((e) => e.data.date >= now).sort((a, b) => +a.data.date - +b.data.date);
|
|
16
16
|
const past = all.filter((e) => e.data.date < now).sort((a, b) => +b.data.date - +a.data.date);
|
|
17
17
|
const size = PAGINATION.pageSize;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { SITE, STRINGS } from 'popular:config';
|
|
3
|
-
import {
|
|
3
|
+
import { render } from 'astro:content';
|
|
4
|
+
import { safeCollection } from '../../lib/collections';
|
|
4
5
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
5
6
|
import AuthorBox from '../../components/AuthorBox.astro';
|
|
6
7
|
|
|
7
8
|
export async function getStaticPaths() {
|
|
8
|
-
const events = (await
|
|
9
|
+
const events = (await safeCollection('events')).filter((e) => !e.data.draft);
|
|
9
10
|
return events.map((event) => ({ params: { slug: event.id }, props: { event } }));
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -16,12 +17,12 @@ const dateStr = d.date.toLocaleDateString(SITE.locale, { weekday: 'long', month:
|
|
|
16
17
|
|
|
17
18
|
/* Venue: a venueRef to the venues collection wins over the flat fields;
|
|
18
19
|
its arrival notes are inherited unless the event sets venueNotes. */
|
|
19
|
-
const venuePage = d.venueRef ? (await
|
|
20
|
+
const venuePage = d.venueRef ? (await safeCollection('venues')).find((v) => v.id === d.venueRef) : undefined;
|
|
20
21
|
if (d.venueRef && !venuePage) throw new Error(`events/${event.id}: venueRef "${d.venueRef}" matches no venue page`);
|
|
21
22
|
const venueNotes = d.venueNotes ?? venuePage?.data.notes;
|
|
22
23
|
|
|
23
24
|
/* Speaker profile cards, resolved from the speakers collection. */
|
|
24
|
-
const allSpeakers = await
|
|
25
|
+
const allSpeakers = await safeCollection('speakers');
|
|
25
26
|
const speakerEntries = d.speakers.map((slug) => {
|
|
26
27
|
const entry = allSpeakers.find((s) => s.id === slug);
|
|
27
28
|
if (!entry) throw new Error(`events/${event.id}: speaker "${slug}" matches no speaker page`);
|
package/src/pages/index.astro
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { safeCollection } from '../lib/collections';
|
|
3
3
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
|
4
4
|
import PostCard from '../components/PostCard.astro';
|
|
5
5
|
import OrganizerCard from '../components/OrganizerCard.astro';
|
|
6
6
|
import { HOME, SITE, STRINGS } from 'popular:config';
|
|
7
7
|
|
|
8
8
|
const now = new Date();
|
|
9
|
-
const events = (await
|
|
9
|
+
const events = (await safeCollection('events')).filter((e) => !e.data.draft);
|
|
10
10
|
const upcoming = events.filter((e) => e.data.date >= now).sort((a, b) => +a.data.date - +b.data.date);
|
|
11
11
|
const next = upcoming[0];
|
|
12
12
|
|
|
13
|
-
const posts = (await
|
|
13
|
+
const posts = (await safeCollection('blog')).filter((p) => !p.data.draft).sort((a, b) => +b.data.date - +a.data.date).slice(0, 3);
|
|
14
14
|
/* value = "@pastEventCount" renders the live number of past events,
|
|
15
15
|
rounded down to a "70+" style once there are ten or more (Hugo parity). */
|
|
16
16
|
const pastCount = events.filter((e) => e.data.date < now).length;
|
|
17
17
|
const statValue = (v: string) =>
|
|
18
18
|
v === '@pastEventCount' ? (pastCount >= 10 ? `${Math.floor(pastCount / 10) * 10}+` : String(pastCount)) : v;
|
|
19
|
-
const nextVenue = next?.data.venueRef ? (await
|
|
20
|
-
const organizers = (await
|
|
19
|
+
const nextVenue = next?.data.venueRef ? (await safeCollection('venues')).find((v) => v.id === next.data.venueRef)?.data.title : undefined;
|
|
20
|
+
const organizers = (await safeCollection('organizers')).sort((a, b) => a.data.weight - b.data.weight);
|
|
21
21
|
|
|
22
22
|
const h = HOME;
|
|
23
23
|
---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { safeCollection } from '../../lib/collections';
|
|
3
3
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
4
4
|
import PageHero from '../../components/PageHero.astro';
|
|
5
5
|
import OrganizerCard from '../../components/OrganizerCard.astro';
|
|
@@ -9,7 +9,7 @@ import { SECTIONS, PAGINATION } from 'popular:config';
|
|
|
9
9
|
/* One route serves /organizers/ and /organizers/page/N/, matching the Hugo
|
|
10
10
|
theme's paginator URLs. */
|
|
11
11
|
export async function getStaticPaths() {
|
|
12
|
-
const organizers = (await
|
|
12
|
+
const organizers = (await safeCollection('organizers')).sort((a, b) => a.data.weight - b.data.weight);
|
|
13
13
|
const size = PAGINATION.pageSize;
|
|
14
14
|
const total = Math.max(1, Math.ceil(organizers.length / size));
|
|
15
15
|
return Array.from({ length: total }, (_, i) => ({
|
package/src/pages/rss.xml.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import rss from '@astrojs/rss';
|
|
2
|
-
import {
|
|
2
|
+
import { safeCollection } from '../lib/collections';
|
|
3
3
|
import { SITE } from 'popular:config';
|
|
4
4
|
|
|
5
5
|
const escapeXml = (s) => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
6
6
|
|
|
7
7
|
export async function GET(context) {
|
|
8
|
-
const posts = (await
|
|
8
|
+
const posts = (await safeCollection('blog'))
|
|
9
9
|
.filter((p) => !p.data.draft)
|
|
10
10
|
.sort((a, b) => +b.data.date - +a.data.date);
|
|
11
|
-
const allAuthors = await
|
|
11
|
+
const allAuthors = await safeCollection('authors');
|
|
12
12
|
return rss({
|
|
13
13
|
title: SITE.title,
|
|
14
14
|
description: SITE.description,
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { STRINGS } from 'popular:config';
|
|
3
|
-
import {
|
|
3
|
+
import { render } from 'astro:content';
|
|
4
|
+
import { safeCollection } from '../../lib/collections';
|
|
4
5
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
5
6
|
import PageHero from '../../components/PageHero.astro';
|
|
6
7
|
import AuthorBox from '../../components/AuthorBox.astro';
|
|
7
8
|
import EventRow from '../../components/EventRow.astro';
|
|
8
9
|
|
|
9
10
|
export async function getStaticPaths() {
|
|
10
|
-
const speakers = await
|
|
11
|
+
const speakers = await safeCollection('speakers');
|
|
11
12
|
return speakers.map((entry) => ({ params: { slug: entry.id }, props: { entry } }));
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
const { entry } = Astro.props;
|
|
15
16
|
const { Content } = await render(entry);
|
|
16
|
-
const events = (await
|
|
17
|
+
const events = (await safeCollection('events'))
|
|
17
18
|
.filter((e) => !e.data.draft && e.data.speakers.includes(entry.id))
|
|
18
19
|
.sort((a, b) => +b.data.date - +a.data.date);
|
|
19
20
|
---
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { STRINGS, PAGINATION } from 'popular:config';
|
|
3
3
|
import { tagSlug } from '../../../lib/slugs';
|
|
4
|
-
import {
|
|
4
|
+
import { safeCollection } from '../../../lib/collections';
|
|
5
5
|
import BaseLayout from '../../../layouts/BaseLayout.astro';
|
|
6
6
|
import PageHero from '../../../components/PageHero.astro';
|
|
7
7
|
import PostCard from '../../../components/PostCard.astro';
|
|
@@ -11,7 +11,7 @@ import Pagination from '../../../components/Pagination.astro';
|
|
|
11
11
|
theme's paginated term pages. URLs use the Hugo-compatible slug; the page
|
|
12
12
|
displays the tag's first-seen spelling. */
|
|
13
13
|
export async function getStaticPaths() {
|
|
14
|
-
const posts = (await
|
|
14
|
+
const posts = (await safeCollection('blog')).filter((p) => !p.data.draft);
|
|
15
15
|
const labels = new Map(); // slug -> first-seen tag spelling
|
|
16
16
|
for (const p of posts) for (const t of p.data.tags) {
|
|
17
17
|
const slug = tagSlug(t);
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { STRINGS } from 'popular:config';
|
|
3
|
-
import {
|
|
3
|
+
import { render } from 'astro:content';
|
|
4
|
+
import { safeCollection } from '../../lib/collections';
|
|
4
5
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
|
5
6
|
import PageHero from '../../components/PageHero.astro';
|
|
6
7
|
import EventRow from '../../components/EventRow.astro';
|
|
7
8
|
|
|
8
9
|
export async function getStaticPaths() {
|
|
9
|
-
const venues = await
|
|
10
|
+
const venues = await safeCollection('venues');
|
|
10
11
|
return venues.map((entry) => ({ params: { slug: entry.id }, props: { entry } }));
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
const { entry } = Astro.props;
|
|
14
15
|
const d = entry.data;
|
|
15
16
|
const { Content } = await render(entry);
|
|
16
|
-
const events = (await
|
|
17
|
+
const events = (await safeCollection('events'))
|
|
17
18
|
.filter((e) => !e.data.draft && e.data.venueRef === entry.id)
|
|
18
19
|
.sort((a, b) => +b.data.date - +a.data.date);
|
|
19
20
|
---
|