Skip to content

Latest commit

 

History

History
153 lines (98 loc) · 21.7 KB

File metadata and controls

153 lines (98 loc) · 21.7 KB

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

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

Общие правила использования интерактивных модулей

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

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

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

Поисковый движок

Поисковый движок предназначен для поиска по текущей странице FAQ или разделу статей. Главным оркестратором поиска и точкой публичных экспортов является файл src/components/features/searchEngine/SearchEngine.tsx. Он управляет ветками рендеринга, включая категории, результаты и отсутствие совпадений, а также подключает модальное окно.

Вся логика состояния и поведения интерфейса сосредоточена в файле src/components/features/searchEngine/SearchState.tsx, где определены контекст SearchContext, провайдер, хоткеи открытия, навигация по результатам, логика фокуса и скроллинга в модальном окне, а также история недавних запросов. Основной runtime поиска вынесен в файл src/components/features/searchEngine/useSearchLogic.ts, который выполняет сбор и кэширование деталей страницы, дебаунс запроса, запуск worker с fallback на main thread и маппинг ранжированных результатов в UI-модель.

За визуальное отображение отвечает файл src/components/features/searchEngine/SearchUi.tsx, содержащий компоненты кнопки открытия, модального окна, категорий, результатов, недавних запросов, сообщения об отсутствии результатов и формы внешнего поиска, а также логику карточки результата и подсветку совпадений на стороне клиента. Тяжёлое ранжирование выполняется в отдельном потоке с помощью Web Worker в файле src/components/features/searchEngine/searchWorker.ts, хранящем инициализированные детали и отвечающем результатами по запросу.

В файле src/components/features/searchEngine/searchQueryCore.ts находится ядро матчинг-логики, включающее компиляцию запроса, построение поисковых индексов, проверку совпадений по полям и общий pipeline поиска и сортировки. Фонетическая и морфологическая обработка для устойчивости к опечаткам реализована в файле src/components/features/searchEngine/searchPhoneticUtilities.ts, где используются stem-алгоритмы, consonant signature, транслит-нормализация и word features. В файле src/components/features/searchEngine/searchHighlightUtilities.ts сосредоточена подсветка совпадений в тексте и HTML-сниппетах с выделением match-типов.

Утилиты контента, включая нормализацию текста, сбор содержимого параграфов, списков, таблиц и вложенных блоков, находятся в src/components/features/searchEngine/searchContentUtilities.ts. Стилистическое оформление модуля поиска, включая layout модалки, masonry-сетку результатов и различные визуальные состояния, описано в src/components/features/searchEngine/SearchEngine.module.scss.

Поисковая система индексирует верхнеуровневые элементы details, при этом полностью пропуская спойлеры, в которых кроме заглушки .article-placeholder нет другого контента. Процесс индексации охватывает заголовки, теги, абзацы, списки, таблицы, блоки Addition, разделители Divider и ссылки, в том числе вложенные в .flexible-links. При ранжировании учитывается порядок слов запроса и более ранняя позиция совпадений в поле, а для коротких запросов длиной до трех символов включительно снижается приоритет слабых совпадений только внутри контента.

Компонент поддерживает горячие клавиши и навигацию по результатам с клавиатуры. Длительное нажатие или вызов контекстного меню на результатах и категориях осуществляет копирование ссылки на конкретный якорь. При нулевом результате поиска пользователю предлагается fallback-вариант с возможностью перехода на внешние поисковые системы, такие как Яндекс или Perplexity.

Для обеспечения стабильной выдачи разделители в запросе нормализуются к единому виду. Высота блока результатов в модальном окне автоматически адаптируется к состоянию экранной клавиатуры за счет отдельного лимита для класса keyboard-open. При этом категории рендерятся в статичном контейнере без свойств overflow, а скролл-контейнер применяется только для веток с результатами или сообщением об их отсутствии.

Поиск функционирует на базе собственного SearchContext и модального окна antd/Modal. В локальном хранилище браузера сохраняется до 24 недавних успешных запросов, которые вернули хотя бы один результат. Запрос автоматически записывается в историю через 5 секунд после прекращения ввода, а также мгновенно при переходе по результату. Реализована интеллектуальная дедупликация недавних запросов по границам слов, которая заменяет промежуточные фразы более полными и исключает добавление общих фраз при наличии более специфичных.

Публичный интерфейс поискового модуля описывается следующими интерфейсами и типами:

export interface SearchContextType {
  addQueryToHistory: (query: string) => void;
  clearQueryHistory: () => void;
  closeModal: () => void;
  isModalOpen: boolean;
  isPageLoaded: boolean;
  openModal: () => void;
  queryHistory: string[];
}

export type SearchSection = {
  id: string;
  title: string;
  icon?: React.ReactNode;
};

export const SearchProvider: React.FC<{
  children: React.ReactNode;
  isPageLoaded: boolean;
}>;

export const SearchInPage: React.FC<{sections: SearchSection[]}>;

Дополнительно экспортируется компонент SearchButton для открытия поиска из шапки страницы. Пример интеграции поискового движка на страницу FAQ выглядит следующим образом:

import {
  SearchInPage,
  SearchProvider,
} from "../components/features/searchEngine/SearchEngine";

<SearchProvider isPageLoaded={isPageLoaded}>
  {/* контент страницы */}
  <SearchInPage sections={sections} />
</SearchProvider>;

Веса ранжирования поиска определяются в файле src/components/features/searchEngine/searchScoringUtilities.ts и служат для обеспечения баланса между точностью выдачи, устойчивостью к опечаткам и быстродействием.

В конфигурации SEARCH_SCORING_WEIGHTS параметр tagAndTitleMatch определяет базовый бонус при одновременном совпадении в заголовке и тегах, а tagOrTitleMatch задает базовый бонус при совпадении только в одном из этих полей. Дополнительно к ним, параметр titleAndTagMatchCountStep устанавливает шаговой бонус за количество совпавших слов в заголовке и тегах, в то время как contentMatchCount отвечает за бонус за число совпадений в контенте, а entityMatchCount регулирует бонус за число совпадений в ссылках и выделенных сущностях. Параметр phraseTitle начисляет крупный бонус за фразовое совпадение запроса в заголовке, phraseTag — за фразовое совпадение в тегах с учетом демпфирования длинных тегов, а contentPhraseMatch — за фразовое совпадение в самом контенте.

Для случаев отсутствия точного фразового попадания в заголовке предусмотрен компенсационный бонус foldedTitleFallback, начисляемый при сильных неточных сигналах вроде folded, stem, consonant или prefix. В свою очередь, параметр contentOnlyPenalty задает штраф для результатов, в которых сигнал обнаружен исключительно в контенте без совпадений в заголовке, тегах или сущностях.

В структуре SEARCH_FIELD_WEIGHTS определяется вес полей для оценки типов совпадений, где максимальный приоритет получает поле title, высокий приоритет отдается полю tag, а также полю entity с оценкой чуть ниже заголовка, в то время как поле content обладает минимальным приоритетом.

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

В блоке SEARCH_LEADING_WEIGHTS настроены коэффициенты бонуса за раннюю позицию первого слова запроса, где самый высокий вес назначен заголовку, а самый низкий — контенту.

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

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

В числе дополнительных констант параметр WORD_MATCH_SCORE задает веса различных типов совпадений, таких как exact, prefix, folded, consonant и stem. Константы группы SHORT_QUERY_* отвечают за корректировки для коротких запросов длиной до трех символов включительно. Параметры PROXIMITY_*, ORDER_* и LEADING_* определяют базовые лимиты и скорость затухания для бонусов близости, порядка и ранней позиции.

Редактор кривых сглаживания

Интерактивный редактор кривых сглаживания реализован в файле src/components/features/easingEditor/EasingEditor.tsx и предназначен для демонстрации и анализа поведения кривых анимации. Он отображает два совмещенных графика, а именно график значений Value Graph и график скорости Speed Graph. Пользователь имеет возможность перетаскивать управляющие ручки кривой Безье с помощью мыши или сенсорного ввода на мобильных устройствах, управляя при этом режимом циклического воспроизведения анимации, включая ping-pong, loop и однократное воспроизведение once.

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

Компонент не принимает внешних props и экспортируется по умолчанию:

const EasingEditor: React.FC = () => { ... };
export default EasingEditor;

Пример использования редактора кривых сглаживания в статьях, таких как src/pages/sections/aefaq/AeFromNewbies.tsx, выглядит следующим образом:

import EasingEditor from "../../../components/features/easingEditor/EasingEditor";

<EasingEditor />;

Конвертеры файлов

Конвертеры файлов сосредоточены в каталоге src/components/features/converters и предназначены для локального преобразования данных. Они разделяют общую таблицу стилей src/components/features/converters/Converter.module.scss для сохранения единого внешнего вида.

Компонент ConverterJsonToTgs.tsx представляет собой локальный конвертер файлов JSON в формат TGS, который является gzip-сжатым JSON для стикеров. Он принимает файл через drag-and-drop, показывает оценку размеров до и после сжатия и позволяет скачать результат. Процесс конвертации полностью выполняется на стороне клиента в браузере.

Для сжатия применяется библиотека pako/gzip, а сохранение итогового файла на диск осуществляется с помощью библиотеки file-saver. В интерфейсе предусмотрена опция округления чисел внутри JSON, которая позволяет существенно уменьшить размер файла, однако при этом существует вероятность незначительного искажения исходной анимации. Разница в размерах файлов до и после сжатия рассчитывается и форматируется с использованием утилит formatBytes и formatPercentDelta.

Компонент не принимает props и экспортируется по умолчанию:

const JsonToTgsConverter: React.FC = () => { ... };
export default JsonToTgsConverter;

Пример интеграции конвертера JSON в TGS в статье src/pages/sections/aefaq/AeExport.tsx выглядит так:

import JsonToTgsConverter from "../../../components/features/converters/ConverterJsonToTgs";

<Divider>Конвертер JSON в TGS</Divider>
<JsonToTgsConverter />;

Компонент ConverterTgsToJson.tsx осуществляет обратное преобразование файлов TGS в JSON. Он принимает файлы с расширением .tgs, распаковывает gzip-содержимое локально в браузере с помощью метода pako/inflate, валидирует полученный JSON и отдает результат на скачивание через библиотеку file-saver. По завершении распаковки в интерфейсе отображается сравнение примерных размеров файлов до и после обработки.

Компонент не принимает props и экспортируется по умолчанию:

const TgsToJsonConverter: React.FC = () => { ... };
export default TgsToJsonConverter;

Пример интеграции конвертера TGS в JSON в статье src/pages/sections/aefaq/AeImport.tsx выглядит следующим образом:

import TgsToJsonConverter from "../../../components/features/converters/ConverterTgsToJson";

<Divider>Конвертер TGS в JSON</Divider>
<TgsToJsonConverter />;