diff --git a/packages/moons/src/core/content/repository.mts b/packages/moons/src/core/content/repository.mts index 897f9f5b..8a88317b 100644 --- a/packages/moons/src/core/content/repository.mts +++ b/packages/moons/src/core/content/repository.mts @@ -1,6 +1,6 @@ import { getConfig } from '@withmoons/config' -import type { Content, ContentlayerDataExports, ContentlayerWebPageDocument, ContentlayerWebsite } from './types/index.mjs' +import type { Content, ContentlayerDataExports, ContentlayerWebPageDocument, ContentlayerWebPageElement, ContentlayerWebsite } from './types/index.mjs' import { computeDocuments } from './compute.mjs' import { homeIdentifier } from './consts.mjs' import { documentByIdentifierSelector, documentsByLanguagesSelector } from './selectors.mjs' @@ -23,6 +23,20 @@ const getGenerated = async (): Promise => { export const getWebsites = async (): Promise => (await getGenerated()).allWebsites +export type WebPageElementFilters = { + inLanguage?: string; +} +export const getWebPageElements = async (filters?: WebPageElementFilters): Promise => { + const elements = (await getGenerated()).allWebPageElements + + return filters?.inLanguage + ? documentsByLanguagesSelector(elements)([filters.inLanguage]) + : elements +} +export const getWebPageElementByType = async (type: ContentlayerWebPageElement['elementType'], filters?: WebPageElementFilters): Promise => + (await getWebPageElements(filters)).find(({ elementType: _t }) => _t === type) +export const getSiteNavigationElement = (filters?: WebPageElementFilters) => getWebPageElementByType('SiteNavigationElement', filters) + const getWebPageDocuments = async (): Promise => { if (Array.isArray(_documents)) { return _documents diff --git a/packages/moons/src/core/content/types/contentlayer.d.mts b/packages/moons/src/core/content/types/contentlayer.d.mts index 1b6831a7..b5e94df2 100644 --- a/packages/moons/src/core/content/types/contentlayer.d.mts +++ b/packages/moons/src/core/content/types/contentlayer.d.mts @@ -7,6 +7,7 @@ export { isType } from 'contentlayer/client' export type { Markdown, MDX, ImageFieldData, IsoDateTimeString } + /** Document types */ export type Article = { /** File path relative to `contentDirPath` */ @@ -117,6 +118,20 @@ export type Person = { collection: string } +export type WebPageElement = { + /** File path relative to `contentDirPath` */ + _id: string + _raw: Local.RawDocumentData + type: 'WebPageElement' + elementType?: 'SiteNavigationElement' | undefined + identifier: string + inLanguage?: string | undefined + name?: string | undefined + itemListElement: ItemListElement[] + /** MDX file body */ + body: MDX +} + export type Website = { /** File path relative to `contentDirPath` */ _id: string @@ -153,13 +168,24 @@ export type Id = { "@id": string } +export type ItemListElement = { + /** File path relative to `contentDirPath` */ + _id: string + _raw: Local.RawDocumentData + type: 'ItemListElement' + name: string + path?: string | undefined + url?: string | undefined + itemListElement?: ItemListElement[] | undefined +} + /** Helper types */ export type AllTypes = DocumentTypes | NestedTypes export type AllTypeNames = DocumentTypeNames | NestedTypeNames -export type DocumentTypes = Article | Organization | Page | Person | Website -export type DocumentTypeNames = 'Article' | 'Organization' | 'Page' | 'Person' | 'Website' +export type DocumentTypes = Article | Organization | Page | Person | WebPageElement | Website +export type DocumentTypeNames = 'Article' | 'Organization' | 'Page' | 'Person' | 'WebPageElement' | 'Website' export type NestedTypes = never export type NestedTypeNames = never @@ -171,4 +197,5 @@ export type DataExports = { allPages: Page[] allPeople: Person[] allWebsites: Website[] + allWebPageElements: WebPageElement[] } diff --git a/packages/moons/src/core/content/types/index.mts b/packages/moons/src/core/content/types/index.mts index f1135a38..aadf552a 100644 --- a/packages/moons/src/core/content/types/index.mts +++ b/packages/moons/src/core/content/types/index.mts @@ -16,6 +16,7 @@ export type { DataExports as ContentlayerDataExports, Person as ContentlayerPerson, Website as ContentlayerWebsite, + WebPageElement as ContentlayerWebPageElement, } from './contentlayer.mjs' export type * from './_schemas.mjs' export type ContentlayerWebPageDocument = ContentlayerArticle | ContentlayerPage diff --git a/packages/moons/src/core/contentlayer.mts b/packages/moons/src/core/contentlayer.mts index c3a48b21..3e9a8380 100644 --- a/packages/moons/src/core/contentlayer.mts +++ b/packages/moons/src/core/contentlayer.mts @@ -1,4 +1,4 @@ -import { defineNestedType, type FieldDefs } from 'contentlayer/source-files' +import { defineNestedType, type DocumentTypeDef, type FieldDefs, type NestedType } from 'contentlayer/source-files' import { collectionName } from './content/index.mjs' const moonsFields: FieldDefs = { @@ -15,6 +15,22 @@ const idDocumentType = defineNestedType(() => ({ fields: idFields, })) +const itemListElementFields: NestedType = defineNestedType(() => ({ + name: 'ItemListElement', + fields: { + name: { type: 'string', required: true }, + path: { type: 'string', required: false }, + url: { type: 'string', required: false }, + itemListElement: { type: 'list', required: false, of: itemListElementFields } + } +})) + +const itemListFields: FieldDefs = { + name: { type: 'string', required: false }, + identifier: { type: 'string', required: true }, + itemListElement: { type: 'list', required: true, of: itemListElementFields } +} + const thingsFields: FieldDefs = { name: { type: 'string', required: true }, description: { type: 'string', required: true }, @@ -38,7 +54,7 @@ const creativeWorkFields: FieldDefs = { keywords: { type: 'list', required: false, of: { type: 'string' } }, } -export const ContentLayerWebsiteFields = { +export const ContentLayerWebsiteFields: DocumentTypeDef = { name: 'Website', fields: { ...creativeWorkFields, @@ -46,7 +62,16 @@ export const ContentLayerWebsiteFields = { } } -export const ContentLayerArticleFields = { +export const ContentLayerWebPageElementFields: DocumentTypeDef = { + name: 'WebPageElement', + fields: { + elementType: { type: 'enum', options: ['SiteNavigationElement'], required: false }, // avoid collision with contentlayer type + inLanguage: { type: 'string', required: false }, + ...itemListFields + } +} + +export const ContentLayerArticleFields: DocumentTypeDef = { name: 'Article', fields: { ...moonsFields, @@ -57,7 +82,7 @@ export const ContentLayerArticleFields = { } } -export const ContentLayerPageFields = { +export const ContentLayerPageFields: DocumentTypeDef = { name: 'Page', fields: { ...moonsFields, @@ -68,7 +93,7 @@ export const ContentLayerPageFields = { } } -export const ContentLayerPersonFields = { +export const ContentLayerPersonFields: DocumentTypeDef = { name: 'Person', fields: { ...moonsFields, @@ -85,7 +110,7 @@ export const ContentLayerPersonFields = { } } -export const ContentLayerOrganizationFields = { +export const ContentLayerOrganizationFields: DocumentTypeDef = { name: 'Organization', fields: { ...moonsFields,