<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
    <title></title>
    <link rel="self" type="application/atom+xml" href="https://soal.red/ru/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://soal.red"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-02-06T00:00:00+00:00</updated>
    <id>https://soal.red/ru/atom.xml</id>
    <entry xml:lang="ru">
        <title>В начале Осени</title>
        <published>2026-02-06T00:00:00+00:00</published>
        <updated>2026-02-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Alex Soal
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://soal.red/ru/stories/cms-idea/"/>
        <id>https://soal.red/ru/stories/cms-idea/</id>
        
        <content type="html" xml:base="https://soal.red/ru/stories/cms-idea/">&lt;p&gt;В этой главе мы увидим основные идеи, стоящие за новой CMS
(кодовое имя «Осень»).
Из этого хаотичного наброска вырастет цельное представление о том, что мы
хотим реализовать. Основная идея — создать простую в обращении и обслуживании,
продуманную и отполированную систему в духе Ghost и Craft, но добавить
больше инструментов редактирования и представления контента. Это позволит
использовать CMS изданиям, требующим большего, чем просто блог.&lt;&#x2F;p&gt;
&lt;p&gt;Одновременно мы хотим избежать хаоса и тяжёлого наследия прошлого, которым
страдает WordPress. Вопрос кастомизации должен быть продуман с самого начала,
но конкретная форма требует дополнительного исследования.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sushchestvuiushchie-resheniia&quot;&gt;Существующие решения&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;wordpress&quot;&gt;WordPress&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;ghost&quot;&gt;Ghost&lt;&#x2F;h3&gt;
&lt;p&gt;Он классный, но в нём не хватает нескольких компонентов:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Публикации на нескольких языках&lt;&#x2F;li&gt;
&lt;li&gt;Шаблонов для разных видов публикаций, который могут потребоваться
онлайн-изданию (новости, интервью, эссе, репортажи, около-академические статьи)&lt;&#x2F;li&gt;
&lt;li&gt;Интеграции с соцсетями, не распространёнными на Западе&lt;&#x2F;li&gt;
&lt;li&gt;Интеграции с платёжными системами, не распространёнными на Западе&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;craft-cms&quot;&gt;Craft CMS&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;craftcms.com&#x2F;&quot;&gt;Craft CMS&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;publikatsiia-kliuchevoi-element&quot;&gt;Публикация, ключевой элемент&lt;&#x2F;h2&gt;
&lt;figure class=&quot;breakout&quot;&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;img src=&quot;publication.svg&quot; alt=&quot;Схема публикации&quot; &#x2F;&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h3 id=&quot;metadannye&quot;&gt;Метаданные&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Авторы.&lt;&#x2F;strong&gt; Нам нужна гибкая настройка авторов — их может быть несколько и они
могут отличаться между версиями на разных языках.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Переводчики.&lt;&#x2F;strong&gt; Указывать авторство перевода это хороший тон.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Иллюстраторы.&lt;&#x2F;strong&gt; Иногда иллюстрации могут быть не менее важной частью
публикации.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Редакторы.&lt;&#x2F;strong&gt; Если это большая статья, то она может быть результатом
коллективной работы и редакторы тоже могут быть указаны.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Тэги.&lt;&#x2F;strong&gt; Категоризация публикаций.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;SEO&lt;&#x2F;strong&gt;. Заголовок, описание и микроформаты для поисковиков и социальных сетей.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Связи между публикациями.&lt;&#x2F;strong&gt; Публикации могут быть объединены в серии или
представлять собой онлайн-дискуссию.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Даты.&lt;&#x2F;strong&gt; Дата создания, последнего изменения и публикации.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Внешние связи&lt;&#x2F;strong&gt;. Если публикация была также опубликована в соцсетях и
других внешних источниках, мы должны сохранить эту связь, хотя бы в виде
ссылки.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dokument&quot;&gt;Документ&lt;&#x2F;h3&gt;
&lt;p&gt;Сам документ должен хранится в формате, который отвечает нескольким
требованиям:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Поддерживает совместное редактирование (&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;automerge.org&#x2F;&quot;&gt;Automerge&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Поддерживает шаблоны для вёрстки контента&lt;&#x2F;li&gt;
&lt;li&gt;Позволяет эффективно представить контент в виде HTML с дополнениями в виде
веб-компонентов&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;komponenty-sistemy&quot;&gt;Компоненты системы&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;redaktor-v-kotorom-khochetsia-pisat&quot;&gt;Редактор, в котором хочется писать&lt;&#x2F;h3&gt;
&lt;p&gt;Цель создать редактор, который будет использоваться напрямую, а не просто
«написал в другом месте и скопировал сюда».&lt;&#x2F;p&gt;
&lt;h4 id=&quot;bazovoe-formatirovanie&quot;&gt;Базовое форматирование&lt;&#x2F;h4&gt;
&lt;p&gt;Редактор должен поддерживать базовое форматирование (&lt;em&gt;курсив&lt;&#x2F;em&gt;, &lt;strong&gt;полужирный&lt;&#x2F;strong&gt;,
таблицы и т.д.). Администратор должен иметь возможность настроить доступные
редактору возможности форматирования для сохранения общего стиля издания.
К примеру, отключить выделение разными цветами или ограничить палитру цветами
бренда.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;blochnoe-redaktirovanie&quot;&gt;Блочное редактирование&lt;&#x2F;h4&gt;
&lt;p&gt;Документ разбит на сегменты, которые инкапсулируют свой контент в универсальный
контейнер. Внутри может быть параграф текста, заголовок, изображение,
произвольный HTML и т.д.
&lt;details&gt;
  
    &lt;summary&gt;Виды сегментов&lt;&#x2F;summary&gt;
  
  &lt;ul&gt;
&lt;li&gt;Параграф&lt;&#x2F;li&gt;
&lt;li&gt;Разделитель&lt;&#x2F;li&gt;
&lt;li&gt;Закладка
&lt;em&gt;(Ссылка с изображением и предпросмотром, аналогичная preview в соцсетях)&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Разделение на публичную&#x2F;закрытыю часть&lt;&#x2F;li&gt;
&lt;li&gt;Call to Action&#x2F;Ad&lt;&#x2F;li&gt;
&lt;li&gt;Email content&lt;&#x2F;li&gt;
&lt;li&gt;Callout&#x2F;Hero&lt;&#x2F;li&gt;
&lt;li&gt;Header&lt;&#x2F;li&gt;
&lt;li&gt;Signup&lt;&#x2F;li&gt;
&lt;li&gt;Toggle&lt;&#x2F;li&gt;
&lt;li&gt;Video&lt;&#x2F;li&gt;
&lt;li&gt;Audio&lt;&#x2F;li&gt;
&lt;li&gt;File&lt;&#x2F;li&gt;
&lt;li&gt;Product&lt;&#x2F;li&gt;
&lt;li&gt;HTML&lt;&#x2F;li&gt;
&lt;li&gt;Markdown&lt;&#x2F;li&gt;
&lt;li&gt;Картинка&lt;&#x2F;li&gt;
&lt;li&gt;Галерея&lt;&#x2F;li&gt;
&lt;li&gt;Кнопка&#x2F;Группа кнопок&lt;&#x2F;li&gt;
&lt;li&gt;Вставки
&lt;ul&gt;
&lt;li&gt;Youtube&lt;&#x2F;li&gt;
&lt;li&gt;X&lt;&#x2F;li&gt;
&lt;li&gt;Unsplash&lt;&#x2F;li&gt;
&lt;li&gt;Vimeo&lt;&#x2F;li&gt;
&lt;li&gt;CodePen&lt;&#x2F;li&gt;
&lt;li&gt;Spotify&lt;&#x2F;li&gt;
&lt;li&gt;SoundCloud&lt;&#x2F;li&gt;
&lt;li&gt;Telegram&lt;&#x2F;li&gt;
&lt;li&gt;Custom&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;details&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Сегмент можно перемещать по документу.
Сегмент можно расположить в зоне шаблона.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;shablony&quot;&gt;Шаблоны&lt;&#x2F;h4&gt;
&lt;p&gt;К документу можно применить шаблон, который описывает какие сегменты могут
быть в документе и как они расположены.
К примеру, шаблон &lt;strong&gt;«Интервью»&lt;&#x2F;strong&gt; содержит в себе сегменты «Вопрос» и «Ответ»
помимо сегментов по умолчанию, таких как параграф.

    














    
    

    
    

    
    

    
    



    




&lt;figure class=&quot;breakout&quot;&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;a href=&quot;https:&#x2F;&#x2F;soal.red&#x2F;ru&#x2F;stories&#x2F;cms-idea&#x2F;interview.jpg&quot; target=&quot;_blank&quot;&gt;
        &lt;picture&gt;
            
            
            
                
                    
                    
                
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;interview.0dfd61ae86463306.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;interview.550503312e8f8b16.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &lt;= 400px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;interview.0c9dbdfabb3a7c15.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;interview.cc6ab37095187fc0.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &gt; 400px) and (width &lt;= 800px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;interview.c2fd86ac2c074ea4.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;interview.665ec12e728eeb19.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &gt; 800px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;img
                    src=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;interview.c2fd86ac2c074ea4.avif&quot; alt=&quot;Выбор сегмента в шаблоне интервью&quot;
                    height=&quot;458&quot;
                    loading=&quot;lazy&quot;
                    width=&quot;857&quot;
                &gt;
            
        &lt;&#x2F;picture&gt;
    &lt;&#x2F;a&gt;
    
      &lt;figcaption&gt;Выбор сегмента в шаблоне интервью&lt;&#x2F;figcaption&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Шаблоны могут также описывать вёрстку и расположение сегментов относительно
друг друга для создания более динамичной структуры контента.

    














    
    

    
    

    
    

    
    



    




&lt;figure class=&quot;breakout&quot;&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;a href=&quot;https:&#x2F;&#x2F;soal.red&#x2F;ru&#x2F;stories&#x2F;cms-idea&#x2F;segment-movement.jpg&quot; target=&quot;_blank&quot;&gt;
        &lt;picture&gt;
            
            
            
                
                    
                    
                
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;segment-movement.8afde406f53f9db8.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;segment-movement.4ec2e416b7179da5.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &lt;= 400px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;segment-movement.a07ab80d8cf80415.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;segment-movement.9555bbbf7817e7db.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &gt; 400px) and (width &lt;= 800px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;segment-movement.666714fe28988cf4.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;segment-movement.8f5b93333de499ca.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &gt; 800px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;img
                    src=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;segment-movement.666714fe28988cf4.avif&quot; alt=&quot;Шаблон в вёрсткой в две колонки&quot;
                    height=&quot;659&quot;
                    loading=&quot;lazy&quot;
                    width=&quot;857&quot;
                &gt;
            
        &lt;&#x2F;picture&gt;
    &lt;&#x2F;a&gt;
    
      &lt;figcaption&gt;Шаблон в вёрсткой в две колонки&lt;&#x2F;figcaption&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Нам нужна спецификация и API для создания и использования блоков.
Это позволит создавать специализированные продукты для разных сегментов
рынка и, в будущем, позволит пользователям создавать собственные шаблоны.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;predprosmotr&quot;&gt;Предпросмотр&lt;&#x2F;h4&gt;
&lt;p&gt;Редактор должен быть реализован таким образом, чтобы использовать стили
темы и сделать оформление в процессе редактирования максимально близким к
отображению публикации на сайте. Для этого надо реализовать загрузку стиля из
темы, установленной администратором сайта.
Отдельно нужен полноэкранный предпросмотр в двух режимах — мобильный и десктоп.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;vopros-markdown&quot;&gt;Вопрос Markdown&lt;&#x2F;h4&gt;
&lt;p&gt;В Ghost можно вставить Markdown отдельным блоком, который будет распознан
и трансформирован в HTML. Хотим ли мы сделать также или стоит создать
отдельный режим редактирования для Markdown, в котором редактор будет
трансформировать Markdown на лету (как, к примеру, в Obsidian)?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;vsio-dlia-perevoda&quot;&gt;Всё для перевода&lt;&#x2F;h3&gt;
&lt;p&gt;Перевод сайта должен быть всеобъемлющим, все компоненты системы должны быть
доступны для локализации.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;perevod-interfeisa&quot;&gt;Перевод интерфейса&lt;&#x2F;h4&gt;
&lt;p&gt;Система должна предоставлять возможность добавить перевод любых строк в
интерфейсе и набор функций для более глубокой локализации (форматы дат и
единиц измерения, варианты множественного числа)
Переводы должны хранится в одном или нескольких файлах (чтобы загружать их
отдельно по необходимости). В будущем нужно предоставить интерфейс для загрузки
перевода и базовой проверки на полноту.
Возможно, в будущем можно предоставить механизм автоматического перевода, но
это требует дополнительного исследования вопроса.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;perevod-kontenta&quot;&gt;Перевод контента&lt;&#x2F;h4&gt;
&lt;p&gt;Каждая сущность в системе (публикация, автор и прочие создатели, тэг и т.д.)
должна иметь версии на разных языках и собственный набор связей с другими
сущностями.
Публикации на разных языках могут иметь разный набор тэгов, авторов и
переводчиков, могут попадать в разные категории, если издание имеет разный
набор категорий на разных языках.
В связи с этим, каждая языковая версия должна быть отдельной записью в базе
данных, связанной с сестринскими версиями отдельным уникальным
идентификатором.
&lt;figure&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;em&gt;структура тэгов на разных языках&lt;&#x2F;em&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;h4 id=&quot;perevod-publikatsii&quot;&gt;Перевод публикаций&lt;&#x2F;h4&gt;
&lt;p&gt;«Осень» должна предоставлять удобный интерфейс для перевода контента.
Каждый перевод это отдельный документ со своими авторами,
переводчиками, иллюстраторами и т.д., датами публикации и т.д.
Как указано выше, каждая языковая версия публикации должна быть отдельной
записью в БД и иметь общий уникальный идентификатор.&lt;&#x2F;p&gt;
&lt;p&gt;Переводы должны быть интегрированы в процесс работы и интерфейс.&lt;&#x2F;p&gt;
&lt;p&gt;Списки сущностей должны иметь фильтр по языку.
&lt;figure&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;em&gt;список публикаций отфильтрованных по языку&lt;&#x2F;em&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Каждая публикация должна ясно показывать, на какие языки она переведена.
&lt;figure&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;em&gt;языки на которые переведена публикация&lt;&#x2F;em&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Создание перевода должно быть легко доступно из интерфейса публикации.
&lt;figure&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;em&gt;интерфейс создания перевода&lt;&#x2F;em&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Редактор должен поддерживать продвинутые методы работы с переводом.
Две версии рядом друг с другом
&lt;figure&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;em&gt;две версии перевода рядом друг с другом&lt;&#x2F;em&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Предложение автоматического перевода с возможностью редактирования
&lt;figure&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;em&gt;автоматическая и окончательная версии перевода рядом друг с другом&lt;&#x2F;em&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;p&gt;Интерфейс с оригиналом, переводом и предложенным автоматическим переводом
&lt;figure&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;em&gt;оригинал, окончательный и автоматический перевод рядом друг с другом&lt;&#x2F;em&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;&#x2F;p&gt;
&lt;h3 id=&quot;instrumenty-redaktora&quot;&gt;Инструменты редактора&lt;&#x2F;h3&gt;
&lt;p&gt;Для эффективной работы онлайн-издания CMS должна поддерживать гибкий рабочий
процесс, где каждая публикация может проходить через несколько этапов перед
публикацией.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;protsess-proizvodstva-i-publikatsii&quot;&gt;Процесс производства и публикации&lt;&#x2F;h4&gt;
&lt;p&gt;Публикация начинается с черновика, который доступен только в административном
интерфейсе.&lt;&#x2F;p&gt;
&lt;p&gt;Далее черновик может быть переведён в статус &quot;готово&quot; и ожидать публикации.
Здесь нам нужен интерфейс для обсуждения и редактуры материала, который
включает в себя:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Комментирование, привязанное к отдельным разделам материала&lt;&#x2F;li&gt;
&lt;li&gt;Обсуждения (треды) по каждому комментарию&lt;&#x2F;li&gt;
&lt;li&gt;Предложения изменений, которые могут быть приняты или модифицированы автором&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;После того, как работа закончена, материалу назначается время публикации,
включая публикацию немедленно, к определённому времени, или в специальный
режим &quot;ожидания&quot;, когда материал публикуется по триггеру, ручному или
автоматическому.&lt;&#x2F;p&gt;
&lt;p&gt;Статусы публикации:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Черновик&lt;&#x2F;strong&gt;. Назначается при создании нового материала&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Готов&lt;&#x2F;strong&gt;. Назначается, если материал требует этапа редактуры и не
публикуется немедленно.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Ожидает доработки&lt;&#x2F;strong&gt;. Назначается, если редактор вернул материал на
доработку автору.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Ожидает публикации&lt;&#x2F;strong&gt;. Назначается, если материалу назначено время
публикации в будущем.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;До звонка&#x2F;по триггеру&lt;&#x2F;strong&gt;. Назначается, если материал должен быть
опубликован по триггеру.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Опубликован&lt;&#x2F;strong&gt;. Назначается, когда материал опубликован в открытый доступ.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Отозван&lt;&#x2F;strong&gt;. Назначается, когда ранее опубликованный материал отозван.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Описанный выше порядок работы это &quot;программа-максимум&quot;. Администратор сайта
должен иметь возможность выбрать несколько вариантов порядка работы — &quot;полный&quot;,
&quot;упрощённый&quot; или какую-либо ещё комбинацию статусов.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;dostup-dlia-vneshnikh-avtorov&quot;&gt;Доступ для внешних авторов&lt;&#x2F;h4&gt;
&lt;p&gt;CMS должна иметь возможность предоставить доступ к редактированию
одной публикации для внешнего автора и последующего обсуждения при редактуре.
Для этого может потребоваться специальная роль и возможность авторизации
через внешние источники, которые поддерживают OAuth и аналогичные механизмы.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;sovmestnaia-rabota&quot;&gt;Совместная работа&lt;&#x2F;h4&gt;
&lt;p&gt;Система должна поддерживать одновременное редактирование несколькими
пользователями, сохраняя и совмещая изменения в виде CRDT.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;raspisanie-publikatsii&quot;&gt;Расписание публикаций&lt;&#x2F;h4&gt;
&lt;p&gt;«Осень» должна предоставлять интерфейс для контент-плана, в виде календаря с
запланированными публикациями и временными слотами.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;versionirovanie&quot;&gt;Версионирование&lt;&#x2F;h4&gt;
&lt;p&gt;Каждое изменение статуса публикации создаёт новую версию.
Система должна предоставлять механизм для просмотра истории версий и
изменений между версиями.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dostavka-kontenta&quot;&gt;Доставка контента&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;html-stranitsy&quot;&gt;HTML страницы&lt;&#x2F;h4&gt;
&lt;h4 id=&quot;json-api&quot;&gt;JSON API&lt;&#x2F;h4&gt;
&lt;h4 id=&quot;rss-i-atom&quot;&gt;RSS и Atom&lt;&#x2F;h4&gt;
&lt;h4 id=&quot;integratsii&quot;&gt;Интеграции&lt;&#x2F;h4&gt;
&lt;h4 id=&quot;seo&quot;&gt;SEO&lt;&#x2F;h4&gt;
&lt;h4 id=&quot;mikroformaty&quot;&gt;Микроформаты&lt;&#x2F;h4&gt;
&lt;h3 id=&quot;analitika&quot;&gt;Аналитика&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;platezhi-i-podpiski&quot;&gt;Платежи и подписки&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;roli-prava-i-dostupy&quot;&gt;Роли, права и доступы&lt;&#x2F;h3&gt;
&lt;h2 id=&quot;struktura-dannykh&quot;&gt;Структура данных&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;publikatsii&quot;&gt;Публикации&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;resursy&quot;&gt;Ресурсы&lt;&#x2F;h3&gt;
&lt;h2 id=&quot;rendering-html-i-api&quot;&gt;Рендеринг HTML и API&lt;&#x2F;h2&gt;
&lt;p&gt;CMS должна предоставлять серверный рендеринг HTML и REST API — публичный для
отображения контента используя фронтенд пользователя и закрытый за авторизацией
для административной панели.&lt;&#x2F;p&gt;
&lt;p&gt;Возможно, нужно предусмотреть возможность отделить модуль рендеринга HTML и
запустить его вместе с веб-сервером на Edge-воркерах и подобных системах,
получая при этом контент из базы данных через API. Насколько это востребованный
и полезный функционал пока неясно.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;federatsiia&quot;&gt;Федерация&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;activitypub&quot;&gt;ActivityPub&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;atproto&quot;&gt;ATProto&lt;&#x2F;h3&gt;
</content>
        
    </entry>
    <entry xml:lang="ru">
        <title>Редакторы текста в Вебе</title>
        <published>2026-02-01T00:00:00+00:00</published>
        <updated>2026-02-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Alex Soal
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://soal.red/ru/stories/web-text-editors/"/>
        <id>https://soal.red/ru/stories/web-text-editors/</id>
        
        <content type="html" xml:base="https://soal.red/ru/stories/web-text-editors/">&lt;p&gt;Ниже краткий путеводитель по редакторам текста для Веба. Мы пройдёмся по
базовым технологиям, подходам и свободным библиотекам.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zadachi-kakie-my-redaktory-my-rassmatrivaem&quot;&gt;Задачи: какие мы редакторы мы рассматриваем?&lt;&#x2F;h2&gt;
&lt;p&gt;Мы будем исходить из задачи создания редактора текста общего назначения — для
редактирования публикаций в CMS, чат-клиенте, написания комментариев в
социальной сети и так далее. Нам нужно разнообразное форматирование:
общепринятые выделения &lt;em&gt;курсивом&lt;&#x2F;em&gt; и &lt;strong&gt;полужирным&lt;&#x2F;strong&gt;, заголовки и так далее. Также
нам нужны добавление изображений, видео, кода и прочих произвольных виджетов.&lt;&#x2F;p&gt;

    










    
    

    
    

    
    

    
    



    
    

    
    

    
    

    
    




    
    

    
    

    
    

    
    



    




&lt;figure class=&quot;breakout&quot;&gt;
  &lt;div class=&quot;double-frame&quot;&gt;
    &lt;a href=&quot;https:&#x2F;&#x2F;soal.red&#x2F;ru&#x2F;stories&#x2F;web-text-editors&#x2F;ghost-editor-light.png&quot; target=&quot;_blank&quot;&gt;
        &lt;picture&gt;
            
                
                    
                    
                
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-dark.2cfd010b09463466.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-dark.1e2655a769292ae0.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: dark) and (width &lt;= 400px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-dark.40c1f09c28b20953.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-dark.cc51e1dc37895ad6.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: dark) and (width &gt; 400px) and (width &lt;= 800px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-dark.5dec03b330af4839.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-dark.814a6c5a949ccf00.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: dark) and (width &gt; 800px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
            
            
                
                    
                    
                
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.5c053ec120f916ee.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.9219b9674d9a6531.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &lt;= 400px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.f04f518042598374.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.765f250eb946aa7f.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &gt; 400px) and (width &lt;= 800px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.e7437cc1adcc4dec.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.43a5d1154e1e012f.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &gt; 800px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
            
            
                
                    
                    
                
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.5c053ec120f916ee.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.9219b9674d9a6531.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &lt;= 400px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.f04f518042598374.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.765f250eb946aa7f.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &gt; 400px) and (width &lt;= 800px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;source
                    srcset=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.e7437cc1adcc4dec.avif, https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.43a5d1154e1e012f.avif 2x&quot;
                    media=&quot;(prefers-color-scheme: light) and (width &gt; 800px)&quot;
                    type=&quot;image&#x2F;avif&quot;
                &gt;
                &lt;img
                    src=&quot;https:&amp;#x2F;&amp;#x2F;soal.red&amp;#x2F;processed_images&amp;#x2F;ghost-editor-light.e7437cc1adcc4dec.avif&quot; alt=&quot;Редактор текста в CMS Ghost&quot;
                    height=&quot;633&quot;
                    loading=&quot;lazy&quot;
                    width=&quot;857&quot;
                &gt;
            
        &lt;&#x2F;picture&gt;
    &lt;&#x2F;a&gt;
    
      &lt;figcaption&gt;Редактор текста в CMS Ghost. Типичный представитель софта, о котором мы будем говорить далее&lt;&#x2F;figcaption&gt;
    
  &lt;&#x2F;div&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;obshchie-printsipy&quot;&gt;Общие принципы&lt;&#x2F;h2&gt;
&lt;p&gt;Рассмотренные здесь редакторы воплощают несколько общих базовых подходов,
на которых сошлись как на оптимальных:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;conteditable-kak-baza&quot;&gt;Conteditable как база&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;immutabel-nye-struktury-dannykh&quot;&gt;Иммутабельные структуры данных&lt;&#x2F;h3&gt;
&lt;p&gt;ProseMirror хранит контент и метаданные редактора в &lt;strong&gt;состоянии (state)&lt;&#x2F;strong&gt;, иммутабельной
структуре состоящей из объединённых в дерево &lt;strong&gt;нод&lt;&#x2F;strong&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
Такой подход стал общим местом и похожие решения используются в других
редакторах.
Автор ProseMirror описывает главное преимущество иммутабельности: при каждом
изменении контента создаётся новый объект состояния всего редактора, что
позволяет избежать «промежуточных» некорректных состояний.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tekstovye-koordinaty&quot;&gt;Текстовые координаты&lt;&#x2F;h3&gt;
&lt;h2 id=&quot;lexical&quot;&gt;Lexical&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;quill&quot;&gt;Quill&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;prosemirror&quot;&gt;ProseMirror&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;redaktory-na-osnove-prosemirror&quot;&gt;Редакторы на основе ProseMirror&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;tiptap&quot;&gt;TipTap&lt;&#x2F;h4&gt;
&lt;h4 id=&quot;proseblock&quot;&gt;ProseBlock&lt;&#x2F;h4&gt;
&lt;h2 id=&quot;ckeditor&quot;&gt;CKEditor&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;overtype&quot;&gt;Overtype&lt;&#x2F;h2&gt;
&lt;p&gt;Достоин отдельного упоминания &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;overtype.dev&#x2F;&quot;&gt;Overtype&lt;&#x2F;a&gt;
— простой редактор для Markdown, который
использует интересный трюк чтобы избежать всех сложностей описанных выше.
Он совсем из другой лиги, но идея отличная!&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;prosemirror.net&#x2F;docs&#x2F;guide&#x2F;#doc&quot;&gt;ProseMirror Guide&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        
    </entry>
    <entry xml:lang="ru">
        <title></title>
        <published>2025-11-04T00:00:00+00:00</published>
        <updated>2025-11-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Alex Soal
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://soal.red/ru/stories/smoll-modern-css/"/>
        <id>https://soal.red/ru/stories/smoll-modern-css/</id>
        
        <content type="html" xml:base="https://soal.red/ru/stories/smoll-modern-css/">&lt;p&gt;Заскочил чтобы написать что &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;smolcss.dev&#x2F;&quot;&gt;SmolCSS&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;moderncss.dev&#x2F;&quot;&gt;Modern CSS&lt;&#x2F;a&gt; прекрасны. CSS прошёл большой путь за последние
несколько лет.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="ru">
        <title></title>
        <published>2025-10-29T00:00:00+00:00</published>
        <updated>2025-10-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Alex Soal
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://soal.red/ru/stories/perf-conf/"/>
        <id>https://soal.red/ru/stories/perf-conf/</id>
        
        <content type="html" xml:base="https://soal.red/ru/stories/perf-conf/">&lt;p&gt;Performance.now() это одна из конференций, на которые всё ещё стоит сходить
(или, по крайней мере, посмотреть выступления).
Фундаментальные темы, содержательные выступления.
Множество конференций превратились в маркетинговые мероприятия (вспоминается
VueConf. И почти всё, что касается Реакта)&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
