_includes/resources/tutorial/TutorialModels.ts (71 lines of code) (raw):

import { Static, Type } from "@sinclair/typebox"; import { getThumbnailPath, Resource, ResourceFrontmatter, ResourceMap, } from "../../../src/ResourceModels"; import { TUTORIAL_RESOURCE_TYPE } from "../../../src/resourceType"; import { EleventyPage } from "../../../src/models"; import { TutorialStep } from "./TutorialStepModels"; import { ThumbnailField, VideoBottomField } from "../commonModels"; import path from "upath"; export const TutorialFrontmatter = Type.Intersect([ ResourceFrontmatter, ThumbnailField, VideoBottomField, Type.Object({ tutorialItems: Type.Array( Type.String({ description: "Tutorial step(s) that are part of this tutorial", }) ), }), ]); export type TutorialFrontmatter = Static<typeof TutorialFrontmatter>; export class Tutorial extends Resource<TUTORIAL_RESOURCE_TYPE> implements TutorialFrontmatter { thumbnail: TutorialFrontmatter["thumbnail"]; tutorialItems: string[]; tutorialSteps: TutorialStep[]; videoBottom: boolean; static frontmatterSchema = TutorialFrontmatter; constructor({ data, page, }: { data: TutorialFrontmatter; page: EleventyPage; }) { super({ data, page }); this.tutorialItems = data.tutorialItems; this.tutorialSteps = []; this.videoBottom = !!data.videoBottom; this.thumbnail = getThumbnailPath(data.thumbnail, page.url); } resolve(allResources: ResourceMap) { super.resolve(allResources); // then call this this.tutorialItems.forEach((ti) => { const url = resolveChildPath(this.url, ti); const tutorialStep = allResources.get(url) as TutorialStep; if (tutorialStep) { tutorialStep.parentTutorial = this; this.tutorialSteps.push(tutorialStep); } else { throw new Error(`Tutorial step ${url} not found in ${this.url}`); } }); } getThumbnail(): string { return this.thumbnail; } } export function resolveChildPath( pathPrefix: string, tutorialItem: string ): string { let result = path.join(pathPrefix, tutorialItem); return !result.endsWith("/") ? result.concat("/") : result; }