ContentReducer

This function is used to reduce the content to a certain limit. It is useful when you want to show only a certain number of items and hide the rest. It returns the content that can be shown and the remaining content that is hidden.

Installation

To use the ContentReducer component in your project, you can install it via npm.

npx rosalana-dev@latest add ContentReducer

API

The function accepts the following parameters:

  • content: An array of items that you want to reduce.
  • limit: The number of items that you want to show.
  • options: An object with the following properties:
    • firstAndLast: If true, the first and last items will always be visible.
    • renderRemainingCount: If true, it will render the number of remaining items.

The function returns an object with the following properties:

  • content: The items that can be shown.
  • remaining: The items that are hidden.
  • remainingCount: The number of hidden items.
  • cutIndex: The index where the content was cut.

Usage

Basic Cut

Example of the basic usage:

const someListofItems = [
  { id: 1, name: 'Item 1' },
  { id: 2, name: 'Item 2' },
  { id: 3, name: 'Item 3' },
  { id: 4, name: 'Item 4' },
  { id: 5, name: 'Item 5' },
  { id: 6, name: 'Item 6' },
  { id: 7, name: 'Item 7' },
  { id: 8, name: 'Item 8' },
  { id: 9, name: 'Item 9' },
  { id: 10, name: 'Item 10' },
]

const { content, remaining, remainingCount, cutIndex } = contentReducer(someListofItems, 5);

console.log(content)
// [
//   { id: 1, name: 'Item 1' },
//   { id: 2, name: 'Item 2' },
//   { id: 3, name: 'Item 3' },
//   { id: 4, name: 'Item 4' },
//   { id: 5, name: 'Item 5' },
// ]

console.log(remaining)
// [
//   { id: 6, name: 'Item 6' },
//   { id: 7, name: 'Item 7' },
//   { id: 8, name: 'Item 8' },
//   { id: 9, name: 'Item 9' },
//   { id: 10, name: 'Item 10' },
// ]

console.log(remainingCount)
// 5

console.log(cutIndex)
// 5

First and Last

Example of usage with firstAndLast option:

const { content, remaining, remainingCount, cutIndex } = contentReducer(someListofItems, 5, { firstAndLast: true });

console.log(content)
// [
//   { id: 1, name: 'Item 1' },
//   { id: 2, name: 'Item 2' },
//   { id: 3, name: 'Item 3' },
//   { id: 4, name: 'Item 4' },
//   { id: 10, name: 'Item 10' },
// ]

console.log(remaining)
// [
//   { id: 5, name: 'Item 5' },
//   { id: 6, name: 'Item 6' },
//   { id: 7, name: 'Item 7' },
//   { id: 8, name: 'Item 8' },
//   { id: 9, name: 'Item 9' },
// ]

console.log(remainingCount)
// 5

console.log(cutIndex)
// 4

Use cutIndex

When you get the cutIndex you can use it to show a "show more" button that will show the remaining items.

if (cutIndex !== undefined && remainingCount > 0) {
  content.splice(cutIndex, 0, {
    id: 'show-more',
    name: 'Show more',
    onClick: () => {
      // show the remaining items
    }
  });
}

Render Remaining Count (default option)

Use the renderRemainingCount option if you are cutting the content in the h function and want to show the number of remaining items.

const { content, remaining, remainingCount, cutIndex } = contentReducer(someListofItems, 5, { renderRemainingCount: true });

console.log(content)
// [
//   { id: 1, name: 'Item 1' },
//   { id: 2, name: 'Item 2' },
//   { id: 3, name: 'Item 3' },
//   { id: 4, name: 'Item 4' },
//   { id: 5, name: 'Item 5' },
//   h('span' , { class: 'text-gray-500 text-sm' }, `+5 more`)
// ]

Code

/**
 * Reduce content rendering to limit
 * @param content any[]
 * @param limit number
 * @param options { smartOffset?: boolean, renderRemainingCount?: boolean }
 * @returns { content: any[], remaining: any[], remainingCount: number }
 */
type ContentReducerOptions = {
  firstAndLast?: boolean,
  renderRemainingCount?: boolean
}

type ContentReducerReturn = {
  content: any[],
  remaining?: any[],
  remainingCount?: number
  cutIndex?: number
}

export function contentReducer(content: any[], limit: number = 5, options?: ContentReducerOptions): ContentReducerReturn {
  if (!Array.isArray(content)) {
    console.warn("contentReducer: input is not an array");
    return content;
  }

  if (content.length <= limit) {
    return { content };
  }

  let reducedContent = [];
  let remainingItems = [];
  let cutIndex = limit;

  // be ware thet first element and last element are always visible
  if (options?.firstAndLast) {
    const limitedLength = limit - 2;

    reducedContent = content.slice(1, limitedLength + 1); // get all items that can be shown except first and last
    reducedContent.unshift(content[0]); // add first item
    reducedContent.push(content[content.length - 1]); // add last item

    remainingItems = content.slice(limitedLength + 1, content.length - 1); // get all items that are not shown

    cutIndex = limitedLength + 1;

  } else {
    reducedContent = content.slice(0, limit); // get all items that can be shown
    remainingItems = content.slice(limit); // get all items that are not shown
  }

  const remainingCount = remainingItems.length;
  
  if (options?.renderRemainingCount && remainingCount > 0) {
    reducedContent.push(
      h('span' , { class: 'text-gray-500 text-sm' }, `+${remainingCount} more`)
    )
  }
  
  return {
    content: reducedContent,
    remaining: remainingItems,
    remainingCount,
    cutIndex
  }
}