Как устроен FeedbackForm для Quartz 4
FeedbackForm нужен там, где статический Quartz-сайт должен не только показывать страницы, но и принимать нормальную обратную связь: заявку, бриф, контактные данные и короткое описание задачи. Для автора сайта это способ не терять заинтересованного читателя после CTA, а для читателя — понятный маршрут от «хочу обсудить проект» к конкретной форме.
В этом проекте компонент не рисует готовую форму прямо в TSX. Он работает как ресурсный placeholder: подключает стили и inline-скрипт, а реальный DOM формы создаётся уже в браузере по JSON-конфигу.
Для Quartz со SPA-навигацией такой подход особенно важен. Страница может меняться без полной перезагрузки, поэтому форма должна аккуратно монтироваться повторно после события nav, не ломая переходы и не превращая Markdown-страницу в набор ручных HTML-вставок.
Компонент как placeholder
quartz/components/FeedbackForm.tsx устроен минимально:
const FeedbackForm: QuartzComponent = () => {
return <div class="feedback-form-resources" aria-hidden="true"></div>
}
FeedbackForm.css = style
FeedbackForm.afterDOMLoaded = scriptНа странице этот div сам по себе ничего не показывает, и это нормально: он не является местом формы. Его задача тише и важнее — подключить CSS и feedbackForm.inline.ts к ресурсам Quartz, чтобы настоящая форма могла появиться там, где для неё оставлен отдельный placeholder.
Где создаётся настоящая форма
Настоящая форма создаётся в quartz/components/scripts/feedbackForm.inline.ts. Скрипт ищет элементы вида:
<div class="feedback-form" data-source="/static/data/feedback-form.json"></div>Дальше начинается пользовательская часть сценария: читатель видит карточку формы, заполняет поля, получает понятный статус отправки, а автор сайта получает структурированный payload вместо разрозненного сообщения. Технически после поиска placeholder скрипт:
- загружает JSON из
data-source; - создаёт поля;
- валидирует обязательные значения;
- собирает JSON-payload;
- отправляет его на
action; - показывает статус отправки прямо в карточке.
Скрипт подписывается на SPA-событие nav, чтобы форма продолжала работать после внутренних переходов Quartz.
Конфиг формы
Данные лежат в quartz/static/data/feedback-form.json. Это место описывает не внешний вид ради внешнего вида, а смысл разговора с посетителем. Сейчас это не абстрактная форма «напишите нам», а бриф на разработку:
- имя;
- компания;
- телефон;
- email;
- Telegram;
- тип услуги;
- scope работ;
- бюджет через range;
- сроки;
- материалы;
- описание задачи;
- согласие на обработку персональных данных.
action указывает на endpoint https://app.slavx.ru/api/v1/f/12a7dd50d5c0, метод — POST.
Почему JSON, а не Markdown
Форма быстро становится неудобной, если описывать её в Markdown или HTML-вставках: поля перемешиваются с текстом страницы, сложнее поддерживать обязательность, варианты выбора и служебные параметры отправки. JSON даёт нормальную структуру:
{
"type": "email",
"name": "email",
"label": "Email",
"placeholder": "you@example.com",
"required": true,
"autocomplete": "email"
}Так проще менять поля, порядок, варианты select/checkbox и обязательность. Код компонента при этом остаётся тем же, а статья или страница не превращается в технический черновик с большим куском формы внутри Markdown.
Подключение в layout
FeedbackForm подключён глобально в sharedPageComponents.afterBody:
afterBody: [
Component.SiteGeometryBackground(siteGeometryBackgroundData),
Component.ServicesCarousel(),
Component.FeedbackForm(),
Component.HomeCallback(),
Component.CookieConsent(),
]Это не значит, что форма видна на каждой странице. Глобально подключаются только ресурсы, чтобы они были готовы к работе после загрузки и внутренних переходов. Конкретное место формы определяется HTML-placeholder в контенте или компоненте.
Связь с HomeCallback
Рядом подключён HomeCallback. Он тоже выглядит как ресурсный компонент: отдаёт скрытый placeholder и подключает homeCallback.inline.ts. По смыслу это соседняя часть того же пользовательского сценария: CTA на главной или в лендинговых блоках подталкивает читателя к действию, callback/brief-механика помогает начать контакт без лишних шагов, а FeedbackForm отвечает за полноценную форму.
Поэтому при изменении формы нужно проверять не только FeedbackForm, но и кнопки, которые открывают или ведут к ней на главной и странице контактов.
Юридические документы
В форме есть обязательное согласие на обработку персональных данных. Это не декоративный checkbox: он связан с юридической частью сайта. На лендинговых блоках также есть тексты и ссылки на legal-документы, например в contact CTA главной.
Если меняется текст согласия, privacy note или сценарий отправки, нужно сверять это с юридическими страницами сайта. Форма собирает персональные данные, значит текст должен быть не только красивым, но и аккуратным.
Что менять на практике
Практический плюс такой схемы в том, что большинство изменений остаётся на уровне данных. Если нужно уточнить вопрос, поменять подпись или переставить поля, не обязательно переписывать компонент. Чаще всего правятся только:
titleиsubtitleформы;- набор
fields; - варианты
options; privacyNote;submitLabel;- endpoint
action, если меняется backend.
Код компонента трогать стоит только если нужен новый тип поля или другая логика отправки. Так меньше риск случайно сломать поведение формы, SPA-переходы или соседний сценарий с HomeCallback.
Итог
FeedbackForm в текущем Quartz-проекте — это не «форма в TSX», а связка из placeholder-компонента, inline-скрипта и JSON-конфига. Идея этой связки простая: дать статическому сайту живой канал обратной связи, но не смешивать контент, ресурсы и клиентскую логику в одном месте. Markdown остаётся чистым, форма настраивается данными, а клиентское поведение переживает SPA-переходы.