List Teasers

List Teasers are based on Includes and use paramsSchema to define the UI.

This guide assumes that you are familiar with the possibilities to register an Include Service and how to use it in a Component.

Include Service

{
  name: 'my-teaser-list-service',
  paramsSchema: [
    {
      handle: 'list',
      type: 'li-list-reference',
      preload: true, // Populate referenced article data
      config: {
        enableCount: true,      // enable UI configuration of number of articles (default: false)
        defaultCount: 3,        // number of articles shown by default (default: 3)
        minCount: 2,            // minimum number of articles
        maxCount: 6,            // maximum number of articles
        enableListEditing: true // allow to create/edit list inline (default: false)
      }
    }
  ],
  rendering: {
    type: 'function',
    async render (params, context) {
      // The "list" property is from the "handle" above
      // The "reference.id" is defined by the "li-list-reference" schema
      // "params.list.$ref" would contain the type, in this case "document"
      if (!params.list?.reference?.id) {
        // No list selected
        return {doNotRender: true}
      }
      // Using "preload" in "paramsSchema" will populate the documents in the "values" property.
      // It will automatically remove duplicates between lists displayed on the same page.
      if (!params.list?.values?.length) {
        // Empty list
        return {content: []}
      }

      // Return an array of Livingdocs components for the content property,
      // or a HTML string for the html property.
      return {
        // Render multiple "teaser" components
        content: params.list.values.map(({metadata, systemdata}) => ({
          id: `list-teaser-${systemdata.documentId}`,
          component: 'my-teaser-component', // The component is defined below
          content: {
            // Provide the necessary properties for the component
            image: metadata.teaserImage,
            title: metadata.title,
            showLead: true,
            lead: 'lead from include',
            showByline: true,
            byline: 'byline from include',
            link: 'https://example.com'
          }
        }))
      }
    }
  }
}

Components

// Register a teaser list component which will be used to show multiple teaser components
{
  name: 'my-list-teaser-component',
  label: 'Teaser List', // Displayed in the editor UI as the component name
  iconUrl: 'https://www.example.com/my/icon.svg', // Provide a URL to an SVG icon
  directives: [
    {
      name: 'my-teaser-list-directive',
      type: 'include',
      service: 'my-teaser-list-service'
    }
  ],
  // The "Select a List" placeholder element is displayed when
  // `{doNotRender: true}` is returned by the service
  html: `
    <div doc-include="my-teaser-list-directive">
      <div>Select a List</div>
    </div>
  `
}

// Register a teaser component which will be used to show individual article teasers
{
  name: 'my-teaser-component',
  label: 'Teaser',
  directives: [
    {
      name: 'image',
      type: 'image',
      allowOriginalRatio: true,
      imageRatios: ['16:9', '1:1', '4:3', '3:4']
    },
    {
      type: 'editable',
      name: 'title',
      maxLength: 10
    },
    {
      type: 'toggle',
      name: 'showLead',
      label: 'show lead',
      default: false
    },
    {
      type: 'toggle',
      name: 'showByline',
      label: 'show byline',
      default: true
    }
  ],
  html: `
    <a class="teaser" doc-link="link">
      <img class="responsive-img" doc-image="image">
      <h3 doc-editable="title">Title</h3>
      <p class="text" doc-editable="lead" doc-toggle="showLead">
        Lead
      </p>
      <p class="text" doc-editable="byline" doc-toggle="showByline">
        Byline
      </p>
    </a>
  `
}

References