Skip to content

Latest commit

 

History

History
311 lines (234 loc) · 27.3 KB

File metadata and controls

311 lines (234 loc) · 27.3 KB

Компоненты контента и правила их использования

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

Контейнер статей

Каждая статья проекта в обязательном порядке должна быть обернута в корневой контейнер с классом article-content. Использование данного класса является строго обязательным условием для правильного позиционирования и отображения всех дочерних элементов контента.

Этот класс полностью управляет внешними и внутренними отступами, определяет базовую типографику, включая размеры шрифтов и межстрочные интервалы, а также задает стили для списков, адаптивных таблиц, медиафайлов и блоков выделения информации. Кроме того, класс отвечает за эффект затемнения фона при открытии спойлеров. Использование контейнера с классом article-content гарантирует визуальную согласованность страниц и предотвращает появление ошибок в разметке.

Ниже представлен пример базовой структуры компонента статьи с использованием контейнера:

const ArticleComponent: React.FC = () => {
  return (
    <div className="article-content">
      {/* Сюда помещаются компоненты DetailsSummary */}
    </div>
  );
};

Компонент Addition

Компонент Addition реализован в файле src/components/content/Addition.tsx и предназначен для создания выделенных блоков информации внутри ответов, таких как ремарки, предупреждения, технические примечания или краткие выжимки. Интерфейс пропсов компонента описывается структурой AdditionProperties, которая содержит свойство children с типом React.ReactNode и свойство type, задающее один из четырех возможных режимов выделения информации.

interface AdditionProperties {
  children: React.ReactNode;
  type: "info" | "warning" | "danger" | "tldr";
}

Режим info применяется для вывода справочной информации, контекста и полезных нюансов. Тип warning используется для обозначения ограничений, рисков и предупреждений. Вариант danger служит для вывода критически важных предупреждений, требующих повышенного внимания пользователя из-за рисков сбоев или потери данных. Тип tldr позволяет отобразить краткий итог ответа с подписью TL;DR.

При верстке текста внутри компонента Addition необходимо соблюдать важное правило, согласно которому одиночные строки текста не оборачиваются в тег параграфа, а помещаются непосредственно внутрь компонента. В тех случаях, когда внутри блока требуется отобразить список, необходимо использовать стандартные HTML-теги списков.

Компонент уместно использовать тогда, когда действия пользователя сопряжены с рисками потери данных или сбоя рендеринга, когда нужно акцентировать внимание на техническом требовании или ограничении, либо предоставить быстрое решение длинного объяснения через режим резюме. При этом не следует применять компонент для обычных текстовых абзацев, не содержащих примечаний. Также запрещается размещать несколько таких блоков подряд, чтобы не перегружать интерфейс и не рассеивать внимание пользователя.

Пример использования компонента для вывода справочной информации:

<Addition type="info">
  Проверить текущую версию <mark className="app">Adobe After Effects</mark> можно в меню{" "}
  <mark className="select">«Help» → «About After Effects»</mark>.
</Addition>

Пример использования компонента с внутренним списком для предупреждения:

<Addition type="warning">
  <ul>
    <li>Для изменения системных файлов требуются права администратора.</li>
    <li>После сохранения изменений рекомендуется перезагрузить систему.</li>
  </ul>
</Addition>

Компонент ArticleMedia

Компонент ArticleMedia находится в файле src/components/content/ArticleMedia.tsx и представляет собой универсальное решение для отображения медиаконтента в статьях. Он поддерживает ленивую загрузку ресурсов и имеет встроенный оверлей для детального просмотра изображений. Для настройки компонента используется объединение интерфейсов, разделяющее параметры для картинок, локального видео и роликов с внешнего видеохостинга YouTube.

interface BaseMediaProperties {
  src: string;
}

interface ImageMediaProperties extends BaseMediaProperties {
  caption: string;
  height?: number | string;
  type: "image";
  width?: number | string;
}

interface VideoMediaProperties extends BaseMediaProperties {
  autoPlay?: boolean;
  caption: string;
  height?: number | string;
  loop?: boolean;
  type: "video";
  width?: number | string;
}

interface YouTubeMediaProperties extends BaseMediaProperties {
  height?: number | string;
  type: "youtube";
  width?: number | string;
}

type ArticleMediaProperties =
  | ImageMediaProperties
  | VideoMediaProperties
  | YouTubeMediaProperties;

Свойство src является общим и указывает источник данных, который для изображений и видео файлов содержит путь к файлу относительно папки public/media/ или полный URL-адрес, а для YouTube задает идентификатор ролика или путь к нему. Для типов image и video свойство caption с текстовым описанием медиафайла является обязательным. Параметры автоматического воспроизведения autoPlay и зацикливания loop применяются только к видеороликам. Параметры ширины width и высоты height поддерживаются типами, но в процессе отрисовки приоритет отдается автоматически вычисляемым размерам из метаданных virtual:media-metadata.

Тип image предназначен для демонстрации скриншотов программных интерфейсов или схем, при этом оверлей просмотра поддерживает масштабирование изображения, перетаскивание и закрытие по клавише Esc. Тип video используется для воспроизведения локальных файлов в формате .mp4. Тип youtube позволяет интегрировать ролики через iframe.

При импорте новых медиафайлов их имена необходимо записывать латиницей в формате kebab-case с использованием символа дефиса в качестве разделителя. Папки с медиафайлами должны быть четко структурированы по приложениям и темам. Уже существующие старые файлы в папке legacy/ сохраняются со своими исходными названиями для обеспечения совместимости.

Примеры интеграции различных типов медиаконтента:

import {ArticleMedia} from "../../../components/content/ArticleMedia";

{
  /* Пример с изображением */
}
<ArticleMedia
  caption="Ошибка AfterCodecs при экспорте с нечетным разрешением"
  src="legacy/odd_resolution_error.png"
  type="image"
/>;

{
  /* Пример с локальным видео */
}
<ArticleMedia
  caption="Включение режима написания выражений"
  src="legacy/aftereffects/enable_expression_property.mp4"
  type="video"
/>;

{
  /* Пример с YouTube видео по его ID */
}
<ArticleMedia
  src="dQw4w9WgXcQ"
  type="youtube"
/>;

Компонент CodeSnippet

Компонент CodeSnippet расположен в файле src/components/content/CodeSnippet.tsx и служит для отображения многострочных фрагментов кода, скриптов, файлов конфигурации или консольных команд. Компонент обеспечивает красивую подсветку синтаксиса с помощью библиотеки highlight.js и оснащен кнопкой для копирования содержимого в буфер обмена по клику мыши.

interface CodeSnippetProperties {
  children: React.ReactNode;
  className?: string;
  language?: string;
}

Свойство children принимает отображаемый код в виде строки или JSX-контента, который затем приводится к строковому типу. Необязательное свойство language указывает язык программирования для подсветки синтаксиса, по умолчанию принимая значение javascript. Дополнительный CSS-класс для индивидуальной стилизации блока можно задать через свойство className.

При использовании компонента для других языков, например, для bash, html или json, необходимо явно указывать соответствующий идентификатор языка. Для коротких выражений или одиночных команд данный компонент не применяется, вместо него следует использовать тег <mark className="copy">...</mark>. Содержимое компонента обязательно оборачивается в фигурные скобки и шаблонную строку для предотвращения некорректной обработки переносов строк в JSX.

Пример отображения команд терминала:

import CodeSnippet from "../../../components/content/CodeSnippet";

<CodeSnippet language="bash">
  {`yarn install
yarn dev`}
</CodeSnippet>;

Компонент ContentFilter

Компонент ContentFilter описан в файле src/components/content/ContentFilter.tsx и используется для разделения инструкций под разные операционные системы Windows и macOS в пределах одного ответа. Система автоматически определяет платформу пользователя с помощью анализа navigator.userAgent, относя мобильные устройства на базе iOS к ветке macOS, но также предоставляет ручной переключатель для выбора операционной системы.

type ContentFilterProperties =
  | {windowsContent: React.ReactNode; macContent?: React.ReactNode}
  | {windowsContent?: React.ReactNode; macContent: React.ReactNode};

Свойства windowsContent и macContent содержат разметку и информацию для пользователей Windows и macOS соответственно. Определение типов требует обязательной передачи хотя бы одного из этих свойств. Если переданы оба свойства, то на странице отображается переключатель платформ, а если передано только одно свойство, переключатель автоматически скрывается.

Компонент применяется в ситуациях, когда один и тот же сценарий действий имеет различия в зависимости от операционной системы. При этом структура шагов в обеих ветках должна оставаться максимально одинаковой. Все общие пояснения необходимо выносить за пределы ContentFilter, оставляя внутри только специфические для конкретной системы шаги, чтобы избежать дублирования текста.

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

Пример использования переключателя контента по операционным системам:

import ContentFilter from "../../../components/content/ContentFilter";

<ContentFilter
  windowsContent={
    <p>
      Чтобы изменить настройки внешнего вида программы, перейдите в{" "}
      <mark className="select">«Edit» → «Preferences» → «Appearance»</mark>.
    </p>
  }
  macContent={
    <p>
      Чтобы изменить настройки внешнего вида программы, перейдите в{" "}
      <mark className="select">«After Effects» → «Preferences» → «Appearance»</mark>.
    </p>
  }
/>;

Компонент DetailsSummary

Компонент DetailsSummary реализован в файле src/components/detailsSummary/DetailsSummary.tsx и является ключевым элементом разметки статей, представляя собой раскрывающийся спойлер для вывода вопросов и подробных ответов на них. Он предназначен для размещения внутри родительского контейнера с классом article-content. При отображении на странице спойлеры автоматически нумеруются по иерархической схеме.

Компонент отвечает за хэш-навигацию, синхронизируя адресную строку браузера с открытым спойлером и обеспечивая плавную прокрутку страницы к нему при прямом переходе. Рядом с заголовком отображается кнопка копирования прямой ссылки на вопрос. Компонент также перехватывает клики по внутренним и внешним ссылкам, при необходимости показывая модальное окно для подтверждения перехода.

interface DetailsSummaryProperties {
  anchor: string;
  children: React.ReactNode;
  tag?: string;
  title: string;
}

Свойство title задает текст заголовка спойлера с формулировкой вопроса. Свойство anchor используется в качестве уникального латинского идентификатора для формирования якорных ссылок. Свойство tag принимает строку с ключевыми поисковыми тегами, разделенными запятыми, а само содержимое ответа передается через свойство children.

Каждый спойлер должен быть строго посвящен только одной конкретной проблеме, поэтому объединение разных по смыслу вопросов в один общий блок не допускается. Все передаваемые параметры, такие как заголовок, якорь и теги, должны содержать только плоскую строку без использования HTML- или JSX-тегов. Якорный идентификатор в свойстве anchor записывается латиницей в формате kebab-case.

Поисковые теги перечисляются через запятую и пробел, при этом рекомендуется указывать синонимы, альтернативные формулировки ошибок и смежные понятия, но избегать дублирования слов, которые уже присутствуют в заголовке вопроса. Внутри DetailsSummary допускается использование компонента NestedDetailsSummary для деления длинной статьи на подразделы.

Пример базового использования спойлера:

import DetailsSummary from "../../../components/detailsSummary/DetailsSummary";

<DetailsSummary
  anchor="change-language"
  tag="интерфейс, язык, сменить язык"
  title="Как сменить язык интерфейса на английский?"
>
  <p>
    Для смены языка создайте текстовый файл с именем{" "}
    <mark className="file">ae_force_english.txt</mark>в папке документов пользователя и
    перезапустите программу.
  </p>
</DetailsSummary>;

Пример использования спойлера с вложенными подразделами:

import DetailsSummary from "../../../components/detailsSummary/DetailsSummary";
import NestedDetailsSummary from "../../../components/detailsSummary/NestedDetailsSummary";

<DetailsSummary
  anchor="render-issues"
  tag="ошибки рендера, не рендерит, сбой"
  title="Что делать, если After Effects выдает ошибку при рендере?"
>
  <NestedDetailsSummary title="Проблемы с диском или правами доступа">
    <p>Проверьте путь сохранения и наличие свободного места на диске.</p>
  </NestedDetailsSummary>
  <NestedDetailsSummary title="Ошибки эффектов">
    <p>Отключите сторонние эффекты на проблемном тайм-коде.</p>
  </NestedDetailsSummary>
</DetailsSummary>;

Компонент NestedDetailsSummary

Компонент NestedDetailsSummary реализован в файле src/components/detailsSummary/NestedDetailsSummary.tsx и представляет собой вложенный спойлер, предназначенный для структурирования длинных ответов на подразделы или группировки крупных подпунктов внутри основного спойлера. Данный компонент должен использоваться исключительно внутри родительского компонента DetailsSummary. Использование его в других местах приводит к выводу сообщения об ошибке в консоль браузера, а сам компонент при этом не отображается.

interface NestedDetailsSummaryProperties {
  anchor?: string;
  children: React.ReactNode;
  modifierClass?: string;
  startOpen?: boolean;
  title: string;
}

Обязательное свойство title задает заголовок вложенного спойлера, а свойство children определяет его внутреннее содержимое. С помощью свойства anchor можно задать необязательный уникальный идентификатор для создания прямых якорных ссылок на конкретный вложенный спойлер. Свойство startOpen указывает, должен ли спойлер быть открыт по умолчанию. Свойство modifierClass позволяет передать дополнительный CSS-класс для индивидуальной стилизации.

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

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

Пример использования вложенного спойлера:

import NestedDetailsSummary from "../../../components/detailsSummary/NestedDetailsSummary";

<NestedDetailsSummary title="Проверяем настройки кеша">
  <p>Откройте Preferences и проверьте путь к Disk Cache.</p>
</NestedDetailsSummary>;

Компонент HostsAdobe

Компонент HostsAdobe описан в файле src/components/content/HostsAdobe.tsx и экспортируется по умолчанию под именем HostsAdobeModal. Он представляет собой готовый функциональный блок для автоматической загрузки и отображения актуального списка блокируемых серверов компании Adobe, а также содержит предупреждения и инструкции по редактированию системного файла HOSTS.

Компонент специально разработан для интеграции с DetailsSummary, благодаря чему запрос к внешнему источнику GitHub для получения списка адресов отправляется исключительно в момент открытия пользователем родительского спойлера. Сами данные загружаются в реальном времени, поэтому при отсутствии интернет-соединения список адресов может остаться пустым. Внутри себя компонент использует CodeSnippet для форматированного вывода адресов и Addition для отображения сопутствующих предупреждений.

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

Пример встраивания компонента в спойлер с инструкцией:

import HostsAdobeModal from "../../../components/content/HostsAdobe";

<DetailsSummary
  anchor="fix-connection-error"
  tag="соединение, блокировка, домены"
  title="Как заблокировать доступ приложениям к серверам проверки лицензии?"
>
  <p>
    Для решения проблемы с подключением необходимо внести адреса серверов в файл HOSTS.
  </p>
  <HostsAdobeModal />
</DetailsSummary>;