From 60346f3580637ba48c698f4c20fd5e5de6cf6f0e Mon Sep 17 00:00:00 2001 From: HotelSync Date: Sun, 12 Apr 2026 00:39:27 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20widget=20code=20tab=20=E2=80=94=203=20i?= =?UTF-8?q?nstall=20modes=20+=20width=20customization=20+=20better=20expan?= =?UTF-8?q?d=20button?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Expand button now shows "X фото / Детали ▾" and "Скрыть ▴" instead of bare chevron 2. Code tab: 3 install modes - Встроенный (iframe) — width presets 400/500/700px/full-width + custom input - Плавающая кнопка — floating button script with custom text, color from settings - По классу — script that opens modal on click of .hotelsync-book (or custom class) 3. Floating/trigger modes share modal logic, generate ready-to-paste ` + + const triggerSnippet = `` + + const activeSnippet = codeMode === 'iframe' ? iframeSnippet : codeMode === 'floating' ? floatingSnippet : triggerSnippet const copyCode = () => { - navigator.clipboard.writeText(snippet).catch(() => {}) + navigator.clipboard.writeText(activeSnippet).catch(() => {}) setCopied(true) setTimeout(() => setCopied(false), 2000) } @@ -1854,11 +1892,124 @@ export function BookingWidgetPage() { {/* ── Code ── */} {pageTab === 'code' && (
+ + {/* Install mode selector */} +
+

Способ установки

+
+ {([ + { key: 'iframe', icon: Code2, title: 'Встроенный', desc: 'Вставить блоком на страницу' }, + { key: 'floating', icon: Zap, title: 'Плавающая кнопка', desc: 'Кнопка в углу сайта' }, + { key: 'trigger', icon: Scan, title: 'По классу', desc: 'Клик на любой элемент сайта' }, + ] as const).map(m => ( + + ))} +
+
+ + {/* Options per mode */} + {codeMode === 'iframe' && ( +
+

Ширина виджета

+
+ {[ + { label: 'Узкий (400px)', value: '400px' }, + { label: 'Стандарт (500px)', value: '500px' }, + { label: 'Широкий (700px)', value: '700px' }, + { label: 'Во всю ширину', value: '100%' }, + ].map(opt => ( + + ))} + setWidgetMaxWidth(e.target.value)} + className="w-24 text-xs border border-slate-200 dark:border-slate-600 rounded-lg px-2 py-1.5 bg-white dark:bg-slate-800 text-slate-700 dark:text-slate-300" + placeholder="700px" + /> +
+

Виджет автоматически отцентрируется на странице

+
+ )} + + {codeMode === 'floating' && ( +
+

Настройки кнопки

+
+
+ + setFloatBtnText(e.target.value)} + className="w-full text-sm border border-slate-200 dark:border-slate-600 rounded-lg px-3 py-1.5 bg-white dark:bg-slate-800" + placeholder="Забронировать" + /> +
+
+ +
+
+

Кнопка появится в правом нижнем углу сайта. Цвет берётся из настроек виджета.

+
+ )} + + {codeMode === 'trigger' && ( +
+

CSS-класс триггера

+
+ . + setTriggerClass(e.target.value.replace(/[^a-z0-9-_]/gi, ''))} + className="flex-1 text-sm border border-slate-200 dark:border-slate-600 rounded-lg px-3 py-1.5 bg-white dark:bg-slate-800 font-mono" + placeholder="hotelsync-book" + /> +
+

+ Добавьте этот класс любой кнопке или ссылке на сайте — при клике откроется виджет: +

+
{``}
+
+ )} + + {/* Code block */}
-

Код для вставки на сайт

+

+ {codeMode === 'iframe' ? 'Код для вставки' : codeMode === 'floating' ? 'Скрипт плавающей кнопки' : 'Скрипт триггера по классу'} +

-
-              {snippet}
+            
+              {activeSnippet}
             
-
- -
-

Инструкция по установке

- {[ - { step: '1', text: 'Скопируйте код выше' }, - { step: '2', text: 'Вставьте перед закрывающим тегом на страницах, где хотите показать виджет' }, - { step: '3', text: 'Виджет автоматически добавит кнопку "Забронировать" или встроится в нужный блок' }, - { step: '4', text: 'Настройте цвета и параметры в конструкторе — изменения применяются сразу' }, - ].map(s => ( -
- {s.step} -

{s.text}

-
- ))} +

+ {codeMode === 'iframe' + ? 'Вставьте в любое место страницы где должен отображаться виджет.' + : 'Вставьте перед закрывающим тегом .'} +

{[ - { icon: CalendarCheck2, title: 'Мгновенное подтверждение', desc: 'Email + SMS гостю' }, + { icon: CalendarCheck2, title: 'Мгновенное подтверждение', desc: 'Email гостю' }, { icon: CreditCard, title: 'Онлайн-оплата', desc: 'ЮKassa, Тинькофф, СБП' }, - { icon: Globe, title: 'Без комиссии OTA', desc: 'Только платёжная комиссия ~1.5%' }, + { icon: Globe, title: 'Без комиссии OTA', desc: 'Только ~1.5% платёжной комиссии' }, ].map(f => (