Для Справочника по климатическим технологиям, проекта с открытым исходным кодом, в котором я участвовал последние несколько месяцев, мне нужно было создать повторно используемый компонент реагирования под названием ImageCards для создания карточек в файлах уценки с использованием Докузавр.

Docusaurus — это генератор статических сайтов, такой как Nextra.js (Next. js Static Site Generator framework), который позволяет авторам контента использовать простые файлы уценки. с помощью программного обеспечения, такого как notion, но также принимает mdx, который позволяет нам использовать повторно используемые компоненты реагирования в этих файлах.

Благодаря этому мы можем создавать статические сайты с реагирующими компонентами, как показано ниже:

Действующий сайт здесь *
Github Repo здесь
* усечение еще не опубликовано на сайте, но вы можете увидеть там ImageCards.

Это не ограничивается файлами .mdx, но когда компонент используется несколько раз на одной странице или на нескольких страницах, трудно сохранить все красиво и чисто. Например, в приведенном выше примере карточки используются для перечисления климатических решений для каждого сектора. Проблема здесь в том, что количество слов/символов в описании каждого изображения различается.

Для вышеуказанного компонента ImageCards у меня изначально был машинописный код, приведенный ниже:

import React from 'react'
import styles from "./ImageCard.module.css";
import clsx from "clsx";
import Link from "@docusaurus/Link";
import { AiOutlineArrowRight } from 'react-icons/ai';
import { useHistory } from 'react-router-dom';

    interface CardProps {
        title: string;
        description: string;
        imageUrl: string;
        linkUrl: string;
    }

    const ImageCard: React.FC<CardProps> = ({
        title,
        description,
        imageUrl,
        linkUrl,
    }) => {

    const history = useHistory();

    const handleClick = () => {
        history.push(linkUrl);
      };

    return (
        <div className={clsx("cardContainer", styles.cardContainer)} onClick={handleClick}>
            <img className={clsx("img", styles.cardImg)} src={imageUrl} alt={title} />
            <div className={clsx("content", styles.content)}>
                <h2>{title}</h2>
                <p>{description}
                    <Link
                        to={linkUrl}
                        className={clsx(
                            styles.cardButton,
                        )}
                    > <AiOutlineArrowRight />
                    </Link>
                </p>
                
            </div>
        </div>
    )
}

export default ImageCard 

Чтобы описание помещалось на карточке и не выглядело так, как показано ниже, мы можем обрезатьтекст.

Во-первых, нам нужно установить ограничение на количество символов. Для этого я начал со 100 символов, а затем скорректировал его до 80, чтобы убедиться, что оно работает с нашим контентом.

После этого я создал переменную с именем truncatedDescription и установил для нее описание, которое передается авторами как props в файлах уценки.

Следующий шаг — проверить длину описания, и если она меньше установленного выше предела, мы хотим показать его как есть, в противном случае нам нужно его обрезать.

Но мы не хотим обрезать описание в середине слова только потому, что оно превышает лимит символов. Мы хотим добавить ... к последнему слову, если описание слишком длинное, чтобы указать читателю, что оно продолжается.

Для этого я создал еще одну переменную под названием lastSpaceIndex и сохранил индекс последнего пробела с помощью метода .lastIndexOf.

Если lastSpaceIndex равен -1, что является концом описания, у нас есть полное слово прямо перед ним, поэтому нам просто нужно добавить ... в конце, но если это не так, это означает, что символ 80, он находится в середине слова, поэтому нам придется вернуться к последнему пробелу и добавить туда ....

Вот код вышеизложенного:

const characterLimit = 80;
    let truncatedDescription = description;
    if (truncatedDescription.length > characterLimit) {
        const lastSpaceIndex = truncatedDescription.lastIndexOf(' ', characterLimit);
        if (lastSpaceIndex !== -1) {
            truncatedDescription = truncatedDescription.substring(0, lastSpaceIndex) + '...';
        } else {
            truncatedDescription = truncatedDescription.substring(0, characterLimit) + '...';
        }
    }

Как только это будет добавлено в файл машинописного текста и JSX изменится с {description} на {truncatedDescription}, все должно идеально вписаться в карточки изображений, как показано ниже 🎉