/* app.jsx — корневое приложение, состояние, Tweaks */ const { useState: useS, useEffect } = React; const WA = window.WC; const UA = window.U; const FAV_KEY = 'wc26_favs'; function loadFavs() { try { const raw = localStorage.getItem(FAV_KEY); if (raw) return new Set(JSON.parse(raw)); } catch (e) {} return new Set(WA.defaultFavs); } function App() { const tw = typeof useTweaks === 'function' ? useTweaks({ theme: 'light', accent: '#b8863a', font: 'oswald', simDate: 'off' }) : [{ theme: 'light', accent: '#b8863a', font: 'oswald', simDate: 'off' }, () => {}]; const tweaks = tw[0]; const setTweak = tw[1]; const [favs, setFavs] = useS(loadFavs); const [showBars, setShowBars] = useS(false); const [showBridges, setShowBridges] = useS(false); const cur = tweaks.simDate && tweaks.simDate !== 'off' ? tweaks.simDate : UA.realToday(); useEffect(() => { try { localStorage.setItem(FAV_KEY, JSON.stringify([...favs])); } catch (e) {} }, [favs]); useEffect(() => { const r = document.documentElement; r.setAttribute('data-theme', tweaks.theme === 'night' ? 'night' : 'light'); r.setAttribute('data-font', tweaks.font || 'oswald'); if (tweaks.accent) { r.style.setProperty('--accent', tweaks.accent); r.style.setProperty('--accent-ink', accentInk(tweaks.accent)); } }, [tweaks.theme, tweaks.font, tweaks.accent]); function toggleFav(code) { setFavs((prev) => { const n = new Set(prev); if (n.has(code)) n.delete(code); else n.add(code); return n; }); } return ( <>
setShowBars(true)} onOpenBridges={() => setShowBridges(true)} /> {/* Компактная CTA-секция для пабов */}
Где смотреть

7 площадок
2 города

Гастрономические пабы Петербурга и Москвы. Большие экраны, бельгийское пиво и авторская кухня.
{showBars && setShowBars(false)} />} {showBridges && setShowBridges(false)} />} {typeof TweaksPanel === 'function' && setTweak('theme', v)} options={[{ value: 'light', label: 'Свет' }, { value: 'night', label: 'Ночь' }]} /> setTweak('font', v)} options={[{ value: 'oswald', label: 'Постер' }, { value: 'modern', label: 'Гротеск' }, { value: 'classic', label: 'Классика' }]} /> setTweak('accent', v)} options={['#b8863a', '#c0392b', '#1f6f54', '#3563c9', '#7b3fa0']} /> setTweak('simDate', v)} options={simDateOptions()} />
Меняет «текущий день», чтобы проверить, как обновляются баннеры «сегодня» и «завтра».
} ); } function simDateOptions() { const opts = [ { value: 'off', label: 'Реальная дата (' + UA.realToday() + ')' }, { value: '2026-06-05', label: '5 июня — за неделю до старта' }, { value: '2026-06-10', label: '10 июня — канун открытия' }, ]; const sample = ['2026-06-11', '2026-06-13', '2026-06-15', '2026-06-17', '2026-06-21', '2026-06-24', '2026-06-27']; sample.forEach((d) => { const n = UA.matchesOn(d).length; opts.push({ value: d, label: UA.fmtLong(d) + ' — ' + n + ' ' + window.matchWord(n) }); }); opts.push({ value: '2026-07-20', label: '20 июля — после финала' }); return opts; } function accentInk(hex) { const c = hex.replace('#', ''); const r = parseInt(c.substr(0, 2), 16), g = parseInt(c.substr(2, 2), 16), b = parseInt(c.substr(4, 2), 16); const lum = (0.299 * r + 0.587 * g + 0.114 * b) / 255; return lum > 0.62 ? '#1b1205' : '#fff8ea'; } ReactDOM.createRoot(document.getElementById('root')).render();