Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions src/components/ResourcesBySelector.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,43 @@ import { z } from "astro:schema";
import { getCollection, type CollectionEntry } from "astro:content";
import ResourcesBySelectorReact from "./ResourcesBySelector";

type Props = z.infer<typeof props>;
type Frontmatter = keyof CollectionEntry<"docs">["data"];
type Props = z.input<typeof props>;

type DocsData = keyof CollectionEntry<"docs">["data"];
type VideosData = keyof CollectionEntry<"stream">["data"];

type ResourcesData = DocsData | VideosData;

const props = z.object({
tags: z.string().array().optional(),
types: z.string().array(),
products: z.string().array().optional(),
directory: z.string().optional(),
filterables: z.custom<Frontmatter>().array().optional(),
filterables: z.custom<ResourcesData>().array().optional(),
columns: z.union([z.literal(2), z.literal(3)]).default(2),
});

const { tags, types, products, directory, filterables } = props.parse(
const { tags, types, products, directory, filterables, columns } = props.parse(
Astro.props,
);

const resources = await getCollection("docs", ({ id, data }) => {
const docs = await getCollection("docs");
const videos = await getCollection("stream");

const resources: Array<CollectionEntry<"docs"> | CollectionEntry<"stream">> = [
...docs,
...videos,
].filter(({ id, collection, data }) => {
const type = "pcx_content_type" in data ? data.pcx_content_type : collection;
return (
types.includes(data.pcx_content_type ?? "") &&
types.includes(type ?? "") &&
(directory ? id.startsWith(directory) : true) &&
(tags ? data.tags?.some((v: string) => tags.includes(v)) : true) &&
(products ? data.products?.some((v: string) => products.includes(v)) : true)
(products
? data.products?.some((v) =>
products.includes(typeof v === "object" ? v.id : v),
)
: true)
);
});

Expand All @@ -32,7 +48,7 @@ const facets = resources.reduce(
if (!filterables) return acc;

for (const filter of filterables) {
const val = page.data[filter];
const val = page.data[filter as keyof typeof page.data];
if (val) {
if (Array.isArray(val) && val.every((v) => typeof v === "string")) {
acc[filter] = [...new Set([...(acc[filter] || []), ...val])];
Expand All @@ -53,6 +69,7 @@ const facets = resources.reduce(
resources={resources}
facets={facets}
filters={filterables}
columns={columns}
client:load
/>
</div>
52 changes: 33 additions & 19 deletions src/components/ResourcesBySelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@ import { useEffect, useState } from "react";
import ReactSelect from "./ReactSelect";
import type { CollectionEntry } from "astro:content";

type Frontmatter = keyof CollectionEntry<"docs">["data"];
type DocsData = keyof CollectionEntry<"docs">["data"];
type VideosData = keyof CollectionEntry<"stream">["data"];

type ResourcesData = DocsData | VideosData;

interface Props {
resources: CollectionEntry<"docs">[];
resources: Array<CollectionEntry<"docs"> | CollectionEntry<"stream">>;
facets: Record<string, string[]>;
filters?: Frontmatter[];
filters?: ResourcesData[];
columns: number;
}

export default function ResourcesBySelector({
resources,
facets,
filters,
columns,
}: Props) {
const [selectedFilter, setSelectedFilter] = useState<string | null>(null);

Expand All @@ -34,7 +39,7 @@ export default function ResourcesBySelector({

const filterableValues: string[] = [];
for (const filter of filters) {
const val = resource.data[filter];
const val = resource.data[filter as keyof typeof resource.data];
if (val) {
if (Array.isArray(val) && val.every((v) => typeof v === "string")) {
filterableValues.push(...val);
Expand Down Expand Up @@ -75,21 +80,30 @@ export default function ResourcesBySelector({
</div>
)}

<div className="grid grid-cols-2 gap-4">
{visibleResources.map((page) => (
<a
key={page.id}
href={`/${page.id}/`}
className="flex flex-col gap-2 rounded-sm border border-solid border-gray-200 p-6 text-black no-underline hover:bg-gray-50 dark:border-gray-700 dark:hover:bg-gray-800"
>
<p className="decoration-accent underline decoration-2 underline-offset-4">
{page.data.title}
</p>
<span className="line-clamp-3" title={page.data.description}>
{page.data.description}
</span>
</a>
))}
<div
className={`grid ${columns === 2 ? "grid-cols-2" : "grid-cols-3"} gap-4`}
>
{visibleResources.map((page) => {
const href =
page.collection === "stream"
? `/videos/${page.data.url}/`
: `/${page.id}/`;

return (
<a
key={page.id}
href={href}
className="flex flex-col gap-2 rounded-sm border border-solid border-gray-200 p-6 text-black no-underline hover:bg-gray-50 dark:border-gray-700 dark:hover:bg-gray-800"
>
<p className="decoration-accent underline decoration-2 underline-offset-4">
{page.data.title}
</p>
<span className="line-clamp-3" title={page.data.description}>
{page.data.description}
</span>
</a>
);
})}
</div>
</div>
);
Expand Down
13 changes: 0 additions & 13 deletions src/content/stream/example-video/index.yaml

This file was deleted.

40 changes: 0 additions & 40 deletions src/content/stream/example-video/transcript.vtt

This file was deleted.

42 changes: 42 additions & 0 deletions src/pages/videos/[...slug].astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
import type { GetStaticPaths } from "astro";
import { getCollection } from "astro:content";
import StarlightPage, {
type StarlightPageProps,
} from "@astrojs/starlight/components/StarlightPage.astro";

import { Stream, Width } from "~/components";

export const getStaticPaths = (async () => {
const entries = await getCollection("stream");

return entries.map(({ data }) => {
return {
params: {
slug: data.url,
},
props: {
entry: data,
},
};
});
}) satisfies GetStaticPaths;

const { entry } = Astro.props;

const props = {
frontmatter: {
title: entry.title,
description: entry.description,
template: "splash",
noindex: true,
},
hideBreadcrumbs: true,
} as StarlightPageProps;
---

<StarlightPage {...props}>
<Width size="large" center={true}>
<Stream id={entry.id} title={entry.title} chapters={entry.chapters} />
</Width>
</StarlightPage>
20 changes: 20 additions & 0 deletions src/pages/videos/index.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
import StarlightPage, {
type StarlightPageProps,
} from "@astrojs/starlight/components/StarlightPage.astro";

import { ResourcesBySelector } from "~/components";

const props = {
frontmatter: {
title: "Videos",
template: "splash",
noindex: true,
},
hideBreadcrumbs: true,
} as StarlightPageProps;
---

<StarlightPage {...props}>
<ResourcesBySelector types={["stream"]} columns={3} />
</StarlightPage>
Loading