Темная тема и кастомизация

Настройка визуального оформления через стили

Remark и Rehype работают с деревом синтаксиса Markdown и HTML, что позволяет гибко управлять визуальным представлением документа на фронтенде. Для реализации темной темы основным инструментом становится комбинация CSS-переменных и кастомных плагинов.

CSS-переменные для цветовой схемы:

:root {
  --background-color: #ffffff;
  --text-color: #000000;
  --link-color: #1a0dab;
}

[data-theme="dark"] {
  --background-color: #121212;
  --text-color: #e0e0e0;
  --link-color: #8ab4f8;
}

С помощью атрибута data-theme можно динамически переключать тему, не перезапуская генерацию HTML. Remark и Rehype при этом остаются источником чистой структуры, а CSS отвечает за отображение.

Кастомизация Markdown через Remark

Remark предоставляет мощные возможности для расширения функциональности Markdown с помощью плагинов. Каждый плагин может модифицировать AST (Abstract Syntax Tree), добавляя новые узлы или изменяя существующие.

Пример добавления кастомных блоков:

import { remark } from 'remark';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';

function remarkCustomBlocks() {
  return (tree) => {
    visit(tree, 'paragraph', (node, index, parent) => {
      if (node.children[0].value.startsWith('::note')) {
        const content = node.children[0].value.replace('::note', '').trim();
        parent.children[index] = {
          type: 'html',
          value: `<div class="custom-note">${content}</div>`
        };
      }
    });
  };
}

remark()
  .use(remarkParse)
  .use(remarkCustomBlocks)
  .use(remarkRehype)
  .use(rehypeStringify)
  .processSync('# Заголовок\n\n::note Важная заметка');

В этом примере создается блок заметки, который затем можно стилизовать через CSS:

.custom-note {
  border-left: 4px solid #ffcc00;
  padding: 10px;
  background-color: var(--background-color);
  color: var(--text-color);
}
[data-theme="dark"] .custom-note {
  border-left-color: #ffbb33;
}

Расширение возможностей Rehype для темы

Rehype работает с HTML-деревом и позволяет напрямую манипулировать тегами, атрибутами и структурой документа. При интеграции темной темы важно использовать Rehype-плагины для добавления классов и атрибутов, чтобы управлять стилями через CSS.

Добавление класса к тегам по типу контента:

import { visit } from 'unist-util-visit';

function rehypeAddThemeClasses() {
  return (tree) => {
    visit(tree, 'element', (node) => {
      if (node.tagName === 'pre') {
        node.properties.className = (node.properties.className || []).concat('code-block');
      }
      if (node.tagName === 'img') {
        node.properties.className = (node.properties.className || []).concat('responsive-image');
      }
    });
  };
}

Такой подход позволяет централизованно управлять отображением блоков кода, картинок и других элементов для светлой и темной темы через CSS:

.code-block {
  background-color: #f5f5f5;
  color: #212121;
}
[data-theme="dark"] .code-block {
  background-color: #1e1e1e;
  color: #d4d4d4;
}

.responsive-image {
  max-width: 100%;
  height: auto;
}

Динамическое переключение темы

Для сайтов с клиентской частью можно использовать JavaScript для динамического изменения атрибута data-theme на <html> или <body>, что позволяет моментально переключать светлую и темную тему без повторного рендера Markdown через Remark/Rehype.

function toggleTheme() {
  const currentTheme = document.documentElement.getAttribute('data-theme');
  const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
  document.documentElement.setAttribute('data-theme', newTheme);
}

Интеграция с синтаксисом кода

Remark/Rehype поддерживают плагины для подсветки синтаксиса (например, rehype-prism или rehype-highlight). Для темной темы важно, чтобы цвета подсветки адаптировались к выбранной схеме:

import rehypePrism from '@mapbox/rehype-prism';

remark()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypePrism, { plugins: ['line-numbers'] })
  .use(rehypeStringify)
  .processSync(markdownContent);

Подсветка кода автоматически использует CSS, поэтому нужно подключать файлы стилей для каждой темы:

/* light theme */
pre code {
  background: #f5f5f5;
  color: #212121;
}

/* dark theme */
[data-theme="dark"] pre code {
  background: #1e1e1e;
  color: #d4d4d4;
}

Вывод

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