Skip to content

Commit

Permalink
docs: add content types guide
Browse files Browse the repository at this point in the history
  • Loading branch information
David Featherston committed Jun 23, 2023
1 parent fde24a2 commit d2f1bb8
Showing 1 changed file with 158 additions and 3 deletions.
161 changes: 158 additions & 3 deletions docs/content/framework/3.guides/4.creating-content-types.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,166 @@
---
title: Creating content types
description: A guide to creating new content templates.
description: How to create new content types for the SDP platform
draft: true
layout: page
---

This is how you do that
> See [key concepts - content types](/framework/key-concepts/content-types) for an overview of what content types are and the core content types used within the SDP platform.
## Anatomy

Content types are comprised of three main parts:

- [A mapping object](#the-mapping-object) - maps API data to pass to a Vue component
- [A server plugin](#the-server-plugin) - registers the content type with `@dpc-sdp/ripple-tide-api`
- [And Vue components](#the-vue-component) - takes the mapped data and renders the content type

## Creating a content type

The Nuxt Ripple CLI provides a simple way to add new content types, to get started just run the following command:

```
npx @dpc-sdp/nuxt-ripple-cli add content-type [DIRECTORY] --name {NAME} --createTests --cypressPath {CYPRESSPATH}
```

Where `[DIRECTORY]` is the location to output the content type scaffolding, `{NAME}` is the name of the new content type, and `{CYPRESSPATH}` is the relative path to be used for the cypress tests folder.

> Using the CLI is the preferred way to create new content types as it will ensure the correct file structure and naming conventions are used. It will also scaffold the mapping object, server plugin, and Vue component for you.
## The mapping object

The mapping object is responsible for supplying the data mapping and includes.

- **Data mapping**: the data mapping is responsible for mapping the Tide API response data (i.e. Drupal JSON) into a clean format that can be used within the Vue component.
- **Includes**: the includes are an array of fields that need to be added to the API request so Drupal knows what referenced entities to include in the API response, for more on Drupal includes see [JSON API includes](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/includes).

Below is an example mapping object.

```ts
import type { IRplTideModuleMapping } from '@dpc-sdp/ripple-tide-api/types'
import { tidePageBaseMapping, tidePageBaseIncludes } from '@dpc-sdp/nuxt-ripple/mapping'
import { getField, getImageFromField } from '@dpc-sdp/ripple-tide-api'

const tideMyConentTypeModule: IRplTideModuleMapping = {
mapping: {
// The base mapping is used to add common fields
// See the tidePageBaseMapping function for details
...tidePageBaseMapping({ withTopicTags: true }),

content: 'field_my_content_type_content',

// Can be nested as needed
header: {
intro: 'field_landing_page_intro_text',
},

// Use a function to transform the data
files: (src) => getField(src, 'field_node_files').map((file) => ({
name: file.name,
url: file.field_media_file.url
})),

// Or when using helper functions
image: (src) => getImageFromField(src, 'field_featured_image.field_media_image')
},
includes: [
// The base includes are used to include common fields
// See the tidePageBaseIncludes function for details
...tidePageBaseIncludes({ withTopicTags: true }),

'field_featured_image',
'field_featured_image.field_media_image'
]
}

export default tideMyConentTypeModule
```

## The server plugin

The server plugin is responsible for registering the new content type with `@dpc-sdp/ripple-tide-api`, this file needs to live within the `server/plugins` directory of the content type.

The content type can then be registered by calling the `setContentType` method on the Tide page API. This method takes two arguments, the first is the name of the content type, and the second is the mapping object. If you have used the CLI to create the content type this will already be done for you.

```ts
import type { NitroApp } from 'nitropack'
import { defineNitroPlugin } from 'nitropack/dist/runtime/plugin'
import tideMyContentTypeModule from '../../mapping'

export default defineNitroPlugin(async (nitroApp: NitroApp) => {
nitroApp.tide?.pageApi.setContentType('my-content-type', tideMyContentTypeModule)
})
```

## The Vue component

A Vue component is needed to render the content type. This component will receive a `page` prop, it's this prop that contains the mapped data from the Tide API response.

> **Important note**: The component needs to be registered globally, this can be done by adding the component to a `/components/global` folder within the content type. Because this is global the name needs to be unique, it must also be prefixed with `Tide` i.e. `TideMyContentType`.
This component should use the `TideBaseLayout` component to render the shell of the site, from there slots are used to render the content types content in the right locations. If you're using the CLI it will take care of scaffolding a global component that uses `TideBaseLayout` for you.

Below is an example component using `TideBaseLayout`.

```vue
<template>
<TideBaseLayout
:site="site"
:page="page"
:siteSection="page.siteSection"
:pageTitle="page.title"
:pageLanguage="page.lang"
:updatedDate="page.changed || page.created"
:showContentRating="page.showContentRating"
>
<template #aboveHeader>
<slot name="aboveHeader"></slot>
</template>
<template #primaryNav>
<slot name="primaryNav"></slot>
</template>
<template #breadcrumbs>
<slot name="breadcrumbs"></slot>
</template>
<template #aboveBody>
<slot name="aboveBody"></slot>
</template>
<template #body>
<!-- Add content within the relevant slot -->
<TideMyContentTypeContent :content="page.content" />
</template>
<template #sidebar>
<slot name="sidebar"></slot>
</template>
<template #footer>
<slot name="footer"></slot>
</template>
</TideBaseLayout>
</template>
<script setup lang="ts">
import { TideSiteData } from '@dpc-sdp/ripple-tide-api/types'
import type { TideMediaPage } from '../../types'
interface Props {
site: TideSiteData
page: TideMediaPage
}
defineProps<Props>()
</script>
```

## Using the content type

Content types are actually [Nuxt layers](https://nuxt.com/docs/getting-started/layers) so these are added in the same way as any other layer through the extends property of the main applications `nuxt.config.ts` file.

```js
Some code
export default defineNuxtConfig({
extends: [
'@dpc-sdp/ripple-tide-news', // An npm installed package
'github:dpc-sdp/ripple-tide-news#1.0.0', // A tagged git repository
'./layers/tide-my-content-type', // A local layer
]
})
```

0 comments on commit d2f1bb8

Please sign in to comment.