diff --git a/src/components/VideoHeader.astro b/src/components/VideoHeader.astro index 321908983..2cfae98f5 100644 --- a/src/components/VideoHeader.astro +++ b/src/components/VideoHeader.astro @@ -6,7 +6,7 @@ export interface Props { } const { video } = Astro.props; -const { frontmatter, author } = video; +const { data: frontmatter, author } = video; ---
diff --git a/src/components/VideoListItem.astro b/src/components/VideoListItem.astro index a95bf4905..6c7aafa8a 100644 --- a/src/components/VideoListItem.astro +++ b/src/components/VideoListItem.astro @@ -6,21 +6,21 @@ export interface Props { } const { video } = Astro.props; -const { frontmatter, id } = video; +const { data: frontmatter, slug: id } = video; --- - + {frontmatter.title} { frontmatter.isNew && ( - + New - diff --git a/src/content/config.ts b/src/content/config.ts index 3f4e01b12..cc4d4b9db 100644 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -2,10 +2,12 @@ import { authorCollection } from './author'; import { guideCollection } from './guide'; import { projectCollection } from './project'; import { questionGroupCollection } from './question-group'; +import { videoCollection } from './video'; export const collections = { authors: authorCollection, guides: guideCollection, 'question-groups': questionGroupCollection, projects: projectCollection, + videos: videoCollection, }; diff --git a/src/content/video.ts b/src/content/video.ts new file mode 100644 index 000000000..1768f0d2c --- /dev/null +++ b/src/content/video.ts @@ -0,0 +1,24 @@ +import { defineCollection, z } from 'astro:content'; + +export const videoCollection = defineCollection({ + type: 'content', + schema: z.object({ + title: z.string(), + description: z.string(), + authorId: z.string(), + seo: z + .object({ + title: z.string().optional(), + description: z.string().optional(), + }) + .optional(), + isNew: z.boolean(), + duration: z.string(), + date: z.date(), + sitemap: z.object({ + priority: z.number(), + changefreq: z.enum(['daily', 'weekly', 'monthly', 'yearly']), + }), + tags: z.array(z.string()), + }), +}); diff --git a/src/data/videos/acid-explained.md b/src/content/videos/acid-explained.md similarity index 100% rename from src/data/videos/acid-explained.md rename to src/content/videos/acid-explained.md diff --git a/src/data/videos/all-about-http-caching.md b/src/content/videos/all-about-http-caching.md similarity index 100% rename from src/data/videos/all-about-http-caching.md rename to src/content/videos/all-about-http-caching.md diff --git a/src/data/videos/array-structure.md b/src/content/videos/array-structure.md similarity index 100% rename from src/data/videos/array-structure.md rename to src/content/videos/array-structure.md diff --git a/src/data/videos/arrays-and-objects-in-javascript.md b/src/content/videos/arrays-and-objects-in-javascript.md similarity index 100% rename from src/data/videos/arrays-and-objects-in-javascript.md rename to src/content/videos/arrays-and-objects-in-javascript.md diff --git a/src/data/videos/async-javascript.md b/src/content/videos/async-javascript.md similarity index 100% rename from src/data/videos/async-javascript.md rename to src/content/videos/async-javascript.md diff --git a/src/data/videos/basic-authentication.md b/src/content/videos/basic-authentication.md similarity index 100% rename from src/data/videos/basic-authentication.md rename to src/content/videos/basic-authentication.md diff --git a/src/data/videos/basics-of-authentication.md b/src/content/videos/basics-of-authentication.md similarity index 100% rename from src/data/videos/basics-of-authentication.md rename to src/content/videos/basics-of-authentication.md diff --git a/src/data/videos/big-o-notation.md b/src/content/videos/big-o-notation.md similarity index 100% rename from src/data/videos/big-o-notation.md rename to src/content/videos/big-o-notation.md diff --git a/src/data/videos/content-delivery-networks.md b/src/content/videos/content-delivery-networks.md similarity index 100% rename from src/data/videos/content-delivery-networks.md rename to src/content/videos/content-delivery-networks.md diff --git a/src/data/videos/dns-explained.md b/src/content/videos/dns-explained.md similarity index 100% rename from src/data/videos/dns-explained.md rename to src/content/videos/dns-explained.md diff --git a/src/data/videos/dns-records.md b/src/content/videos/dns-records.md similarity index 100% rename from src/data/videos/dns-records.md rename to src/content/videos/dns-records.md diff --git a/src/data/videos/floating-point-arithmetic.md b/src/content/videos/floating-point-arithmetic.md similarity index 100% rename from src/data/videos/floating-point-arithmetic.md rename to src/content/videos/floating-point-arithmetic.md diff --git a/src/data/videos/freeze-and-seal-objects-in-javascript.md b/src/content/videos/freeze-and-seal-objects-in-javascript.md similarity index 100% rename from src/data/videos/freeze-and-seal-objects-in-javascript.md rename to src/content/videos/freeze-and-seal-objects-in-javascript.md diff --git a/src/data/videos/graph-data-structure.md b/src/content/videos/graph-data-structure.md similarity index 100% rename from src/data/videos/graph-data-structure.md rename to src/content/videos/graph-data-structure.md diff --git a/src/data/videos/hash-table-data-structure.md b/src/content/videos/hash-table-data-structure.md similarity index 100% rename from src/data/videos/hash-table-data-structure.md rename to src/content/videos/hash-table-data-structure.md diff --git a/src/data/videos/heap-data-structure.md b/src/content/videos/heap-data-structure.md similarity index 100% rename from src/data/videos/heap-data-structure.md rename to src/content/videos/heap-data-structure.md diff --git a/src/data/videos/how-to-use-css-variables.md b/src/content/videos/how-to-use-css-variables.md similarity index 100% rename from src/data/videos/how-to-use-css-variables.md rename to src/content/videos/how-to-use-css-variables.md diff --git a/src/data/videos/how-to-use-github-actions.md b/src/content/videos/how-to-use-github-actions.md similarity index 100% rename from src/data/videos/how-to-use-github-actions.md rename to src/content/videos/how-to-use-github-actions.md diff --git a/src/data/videos/javascript-fetch-api.md b/src/content/videos/javascript-fetch-api.md similarity index 100% rename from src/data/videos/javascript-fetch-api.md rename to src/content/videos/javascript-fetch-api.md diff --git a/src/data/videos/linked-list-data-structure.md b/src/content/videos/linked-list-data-structure.md similarity index 100% rename from src/data/videos/linked-list-data-structure.md rename to src/content/videos/linked-list-data-structure.md diff --git a/src/data/videos/load-balancers-101.md b/src/content/videos/load-balancers-101.md similarity index 100% rename from src/data/videos/load-balancers-101.md rename to src/content/videos/load-balancers-101.md diff --git a/src/data/videos/osi-model.md b/src/content/videos/osi-model.md similarity index 100% rename from src/data/videos/osi-model.md rename to src/content/videos/osi-model.md diff --git a/src/data/videos/practical-intro-to-react.md b/src/content/videos/practical-intro-to-react.md similarity index 100% rename from src/data/videos/practical-intro-to-react.md rename to src/content/videos/practical-intro-to-react.md diff --git a/src/data/videos/promises-in-javascript.md b/src/content/videos/promises-in-javascript.md similarity index 100% rename from src/data/videos/promises-in-javascript.md rename to src/content/videos/promises-in-javascript.md diff --git a/src/data/videos/queue-data-structure.md b/src/content/videos/queue-data-structure.md similarity index 100% rename from src/data/videos/queue-data-structure.md rename to src/content/videos/queue-data-structure.md diff --git a/src/data/videos/random-number-generators.md b/src/content/videos/random-number-generators.md similarity index 100% rename from src/data/videos/random-number-generators.md rename to src/content/videos/random-number-generators.md diff --git a/src/data/videos/scaling-the-unscalable.md b/src/content/videos/scaling-the-unscalable.md similarity index 100% rename from src/data/videos/scaling-the-unscalable.md rename to src/content/videos/scaling-the-unscalable.md diff --git a/src/data/videos/session-based-authentication.md b/src/content/videos/session-based-authentication.md similarity index 100% rename from src/data/videos/session-based-authentication.md rename to src/content/videos/session-based-authentication.md diff --git a/src/data/videos/ssh-ssl-tls.md b/src/content/videos/ssh-ssl-tls.md similarity index 100% rename from src/data/videos/ssh-ssl-tls.md rename to src/content/videos/ssh-ssl-tls.md diff --git a/src/data/videos/stack-data-structure.md b/src/content/videos/stack-data-structure.md similarity index 100% rename from src/data/videos/stack-data-structure.md rename to src/content/videos/stack-data-structure.md diff --git a/src/data/videos/system-design-101.md b/src/content/videos/system-design-101.md similarity index 100% rename from src/data/videos/system-design-101.md rename to src/content/videos/system-design-101.md diff --git a/src/data/videos/tcp-ip-model.md b/src/content/videos/tcp-ip-model.md similarity index 100% rename from src/data/videos/tcp-ip-model.md rename to src/content/videos/tcp-ip-model.md diff --git a/src/data/videos/transport-protocols-tcp-vs-udp.md b/src/content/videos/transport-protocols-tcp-vs-udp.md similarity index 100% rename from src/data/videos/transport-protocols-tcp-vs-udp.md rename to src/content/videos/transport-protocols-tcp-vs-udp.md diff --git a/src/data/videos/tree-data-structure.md b/src/content/videos/tree-data-structure.md similarity index 100% rename from src/data/videos/tree-data-structure.md rename to src/content/videos/tree-data-structure.md diff --git a/src/data/videos/what-are-data-structures.md b/src/content/videos/what-are-data-structures.md similarity index 100% rename from src/data/videos/what-are-data-structures.md rename to src/content/videos/what-are-data-structures.md diff --git a/src/data/videos/what-is-cap-theorem.md b/src/content/videos/what-is-cap-theorem.md similarity index 100% rename from src/data/videos/what-is-cap-theorem.md rename to src/content/videos/what-is-cap-theorem.md diff --git a/src/data/videos/what-is-dependency-injection.md b/src/content/videos/what-is-dependency-injection.md similarity index 100% rename from src/data/videos/what-is-dependency-injection.md rename to src/content/videos/what-is-dependency-injection.md diff --git a/src/data/videos/what-is-dom-shadow-dom-virtual-dom.md b/src/content/videos/what-is-dom-shadow-dom-virtual-dom.md similarity index 100% rename from src/data/videos/what-is-dom-shadow-dom-virtual-dom.md rename to src/content/videos/what-is-dom-shadow-dom-virtual-dom.md diff --git a/src/data/videos/what-is-eventual-consistency.md b/src/content/videos/what-is-eventual-consistency.md similarity index 100% rename from src/data/videos/what-is-eventual-consistency.md rename to src/content/videos/what-is-eventual-consistency.md diff --git a/src/data/videos/yaml-in-depth.md b/src/content/videos/yaml-in-depth.md similarity index 100% rename from src/data/videos/yaml-in-depth.md rename to src/content/videos/yaml-in-depth.md diff --git a/src/lib/video.ts b/src/lib/video.ts index e0bba39e1..0d4907c7e 100644 --- a/src/lib/video.ts +++ b/src/lib/video.ts @@ -1,44 +1,12 @@ import type { MarkdownFileType } from './file'; import type { AuthorFileType } from './author.ts'; import { getAllAuthors } from './author.ts'; -import type { GuideFileType } from './guide.ts'; -import { getAllGuides } from './guide.ts'; +import { getCollection, type CollectionEntry } from 'astro:content'; -export interface VideoFrontmatter { - title: string; - description: string; - authorId: string; - seo: { - title: string; - description: string; - }; - isNew: boolean; - duration: string; - date: string; - sitemap: { - priority: number; - changefreq: 'daily' | 'weekly' | 'monthly' | 'yearly'; - }; - tags: string[]; -} - -export type VideoFileType = MarkdownFileType & { - id: string; +export type VideoFileType = CollectionEntry<'videos'> & { author: AuthorFileType; }; -/** - * Generates id from the given video file - * @param filePath Markdown file path - * - * @returns unique video identifier - */ -function videoPathToId(filePath: string): string { - const fileName = filePath.split('/').pop() || ''; - - return fileName.replace('.md', ''); -} - export async function getVideosByAuthor( authorId: string, ): Promise { @@ -52,43 +20,38 @@ export async function getVideosByAuthor( * @returns Promisifed video files */ export async function getAllVideos(): Promise { - const videos = import.meta.glob('/src/data/videos/*.md', { - eager: true, - }); - + const videoEntries = await getCollection('videos'); const allAuthors = await getAllAuthors(); - const videoFiles = Object.values(videos); - const enrichedVideos = videoFiles.map((videoFile) => ({ - ...videoFile, - id: videoPathToId(videoFile.file), - author: allAuthors.find( - (author) => author.slug === videoFile.frontmatter.authorId, - )!, - })); + const enrichedVideos = videoEntries.map((videoFile) => { + const author = allAuthors.find( + (author) => author.slug === videoFile.data.authorId, + ); + + if (!author) { + throw new Error( + `Author with ID ${videoFile.data.authorId} not found for video ${videoFile.data.title}`, + ); + } + + return { + ...videoFile, + author, + }; + }); return enrichedVideos.sort( - (a, b) => - new Date(b.frontmatter.date).valueOf() - - new Date(a.frontmatter.date).valueOf(), + (a, b) => new Date(b.data.date).valueOf() - new Date(a.data.date).valueOf(), ); } export async function getVideoById(id: string): Promise { - const videoFilesMap: Record = - import.meta.glob('../data/videos/*.md', { - eager: true, - }); + const allVideos = await getAllVideos(); + const videoFile = allVideos.find((video) => video.slug === id); - const videoFile = Object.values(videoFilesMap).find((videoFile) => { - return videoPathToId(videoFile.file) === id; - }); if (!videoFile) { throw new Error(`Video with ID ${id} not found`); } - return { - ...videoFile, - id: videoPathToId(videoFile.file), - }; + return videoFile; } diff --git a/src/pages/pages.json.ts b/src/pages/pages.json.ts index 2996e7ea3..456258f0d 100644 --- a/src/pages/pages.json.ts +++ b/src/pages/pages.json.ts @@ -50,9 +50,9 @@ export async function GET() { group: 'Guides', })), ...videos.map((video) => ({ - id: video.id, - url: `/videos/${video.id}`, - title: video.frontmatter.title, + id: video.slug, + url: `/videos/${video.slug}`, + title: video.data.title, group: 'Videos', })), ...projects.map((project) => ({ diff --git a/src/pages/videos/[videoId].astro b/src/pages/videos/[videoId].astro index 096e230a0..bd7058872 100644 --- a/src/pages/videos/[videoId].astro +++ b/src/pages/videos/[videoId].astro @@ -1,7 +1,7 @@ --- import VideoHeader from '../../components/VideoHeader.astro'; import BaseLayout from '../../layouts/BaseLayout.astro'; -import { getAllVideos, VideoFileType } from '../../lib/video'; +import { getAllVideos, type VideoFileType } from '../../lib/video'; export interface Props { video: VideoFileType; @@ -11,18 +11,19 @@ export async function getStaticPaths() { const videos = await getAllVideos(); return videos.map((video) => ({ - params: { videoId: video.id }, + params: { videoId: video.slug }, props: { video }, })); } const { videoId } = Astro.params; const { video } = Astro.props; +const { Content } = await video.render(); --- @@ -31,7 +32,7 @@ const { video } = Astro.props;
- +