1(function () { 2 var header = document.querySelector("[data-header]"); 3 var nav = document.querySelector("[data-nav]"); 4 var menuToggle = document.querySelector("[data-menu-toggle]"); 5 var lightbox = document.querySelector("[data-lightbox-modal]"); 6 var lightboxImage = lightbox ? lightbox.querySelector("img") : null; 7 var lightboxClose = document.querySelector("[data-lightbox-close]"); 8 var languageSwitch = document.querySelector(".language-switch"); 9 var siteConfig = window.SITE_CONTENT || {}; 10 var languages = siteConfig.languages || { pl: siteConfig }; 11 var urlParams = new URLSearchParams(window.location.search); 12 var requestedLanguage = urlParams.get("lang"); 13 function getPathLanguage() { 14 var segments = window.location.pathname.split("/").filter(Boolean); 15 for (var i = 0; i < segments.length; i += 1) { 16 if (languages[segments[i]]) return segments[i]; 17 } 18 return ""; 19 } 20 function getHostDefaultLanguage() { 21 var host = window.location.hostname.replace(/^www\./, ""); 22 if (host === "bubble-theatre.com") return "en"; 23 if (host === "teatrbaniek.pl") return "pl"; 24 return siteConfig.defaultLanguage || "pl"; 25 } 26 var pathLanguage = getPathLanguage(); 27 var currentLanguage = requestedLanguage || pathLanguage || getHostDefaultLanguage(); 28 if (!languages[currentLanguage]) currentLanguage = Object.keys(languages)[0] || "pl"; 29 localStorage.setItem("siteLanguage", currentLanguage); 30 document.documentElement.lang = currentLanguage; 31 var siteContent = languages[currentLanguage] || {}; 32 var subpageContent = { 33 "format-teatry.html": { 34 pl: { 35 seo: { 36 title: "Teatry, domy kultury i instytucje | Teatr Baniek Mydlanych", 37 description: "Profesjonalny spektakl baniek mydlanych dla teatrów, scen teatralnych, domów kultury, bibliotek i instytucji publicznych.", 38 ogTitle: "Spektakl dla teatrów i domów kultury", 39 ogDescription: "Gotowy program sceniczny z oprawÄ teatralnÄ , technikÄ i interakcjÄ z publicznoÅciÄ ." 40 }, 41 heroEyebrow: "Format sceniczny", 42 heroTitle: "Teatry i <span>instytucje</span>", 43 heroText: "PeÅnowymiarowe widowisko rodzinne przygotowane dla scen teatralnych, domów kultury, bibliotek, centrów kultury i wydarzeÅ miejskich.", 44 heroCta: "ZAPROÅ NAS NA SCENÄ", 45 panelTitle: "Profesjonalna produkcja <span>gotowa na scenÄ</span>", 46 panelText: "To nie jest pojedynczy pokaz, ale kompletne widowisko z wÅasnÄ oprawÄ scenicznÄ , dekoracjami, kostiumami i doÅwiadczonym zespoÅem technicznym. Przyjeżdżamy przygotowani do pracy na różnych typach scen i przestrzeni, z zapleczem organizacyjnym wypracowanym podczas ponad 1000 wystÄpów w Polsce i za granicÄ .", 47 bullets: ["profesjonalne dekoracje, kostiumy i teatralna oprawa wizualna,", "wÅasna ekipa techniczna oraz przygotowane wymagania sceniczne,", "możliwoÅÄ przyjazdu wÅasnym transportem ciÄżarowym,", "doÅwiadczenie ponad 1000 wystÄpów na scenach różnej skali i w wielu krajach,", "warianty jÄzykowe dla publicznoÅci miÄdzynarodowej."], 48 mediaEyebrow: "Photo-Video", 49 mediaTitle: "ZOBACZ FORMAT <span>NA SCENIE</span>", 50 videoText: "MateriaÅ video formatu scenicznego", 51 ctaEyebrow: "Dla repertuaru i wydarzeÅ specjalnych", 52 ctaTitle: "Stwórzmy baÅkowÄ scenÄ w Twoim mieÅcie", 53 leadTitle: "Napisz swój e-mail i wkrótce siÄ skontaktujemy", 54 emailPlaceholder: "Twój e-mail", 55 leadButton: "SKONTAKTUJEMY SIÄ" 56 }, 57 en: { 58 seo: { 59 title: "Theatres, Cultural Centers and Institutions | Soap Bubble Theatre", 60 description: "A professional soap bubble stage show for theatres, theatre venues, cultural centers, libraries and public institutions.", 61 ogTitle: "Stage show for theatres and cultural venues", 62 ogDescription: "A ready-made theatrical program with staging, technical crew and audience interaction." 63 }, 64 heroEyebrow: "Stage format", 65 heroTitle: "Theatres and <span>institutions</span>", 66 heroText: "A full-scale family show prepared for theatre stages, cultural centers, libraries, civic venues and city events.", 67 heroCta: "BRING US ON STAGE", 68 panelTitle: "A professional production <span>ready for the stage</span>", 69 panelText: "This is not a single act, but a complete show with its own stage design, set
69s, costumes and experienced technical team. We arrive prepared to work on different types of stages and venues, with production know-how built through more than 1000 performances in Poland and abroad.", 70 bullets: ["professional sets, costumes and theatrical visual staging,", "our own technical crew and prepared stage requirements,", "possibility to arrive with our own truck transport,", "experience from 1000+ performances on stages of many scales and in many countries,", "language versions for international audiences."], 71 mediaEyebrow: "Photo-Video", 72 mediaTitle: "SEE THE FORMAT <span>ON STAGE</span>", 73 videoText: "Video material for the stage format", 74 ctaEyebrow: "For repertoire and special events", 75 ctaTitle: "Let us create a bubble stage in your city", 76 leadTitle: "Leave your email and we will contact you soon", 77 emailPlaceholder: "Your email", 78 leadButton: "WE WILL CONTACT YOU" 79 }, 80 es: { 81 seo: { 82 title: "Teatros, centros culturales e instituciones | Teatro de Pompas de Jabón", 83 description: "Un espectáculo profesional de pompas de jabón para teatros, espacios escénicos, centros culturales, bibliotecas e instituciones públicas.", 84 ogTitle: "Espectáculo para teatros y centros culturales", 85 ogDescription: "Un programa escénico listo con puesta teatral, equipo técnico e interacción con el público." 86 }, 87 heroEyebrow: "Formato escénico", 88 heroTitle: "Teatros e <span>instituciones</span>", 89 heroText: "Un espectáculo familiar de gran formato preparado para teatros, centros culturales, bibliotecas, espacios municipales y eventos urbanos.", 90 heroCta: "LLEVARNOS AL ESCENARIO", 91 panelTitle: "Una producción profesional <span>lista para escena</span>", 92 panelText: "No es un número aislado, sino un espectáculo completo con escenografÃa propia, decorados, vestuario y un equipo técnico experimentado. Llegamos preparados para trabajar en distintos tipos de escenarios y espacios, con experiencia acumulada en más de 1000 funciones en Polonia y en el extranjero.", 93 bullets: ["decorados, vestuario y puesta visual teatral profesional,", "equipo técnico propio y requisitos escénicos preparados,", "posibilidad de llegada con transporte de carga propio,", "experiencia de más de 1000 funciones en escenarios de diferentes escalas y paÃses,", "versiones lingüÃsticas para público internacional."], 94 mediaEyebrow: "Foto-Video", 95 mediaTitle: "VER EL FORMATO <span>EN ESCENA</span>", 96 videoText: "Material de video del formato escénico", 97 ctaEyebrow: "Para programación y eventos especiales", 98 ctaTitle: "Creemos un escenario de pompas en tu ciudad", 99 leadTitle: "Deja tu email y nos pondremos en contacto pronto", 100 emailPlaceholder: "Tu email", 101 leadButton: "NOS PONDREMOS EN CONTACTO" 102 } 103 }, 104 "format-galerie.html": { 105 pl: { 106 seo: { title: "Galerie i centra rozrywkowe | Teatr Baniek Mydlanych", description: "Efektowne rodzinne widowisko do galerii handlowych, centrów rozrywkowych i akcji promocyjnych.", ogTitle: "Show do galerii i centrów rozrywkowych", ogDescription: "Kolorowa atrakcja, która przyciÄ ga rodziny i buduje ruch w obiekcie." }, 107 heroEyebrow: "Event rodzinny", 108 heroTitle: "Galerie i <span>centra rozrywki</span>", 109 heroText: "Widowisko zaprojektowane tak, aby zatrzymaÄ publicznoÅÄ, stworzyÄ naturalny punkt programu i daÄ rodzinom powód do wspólnego zdjÄcia, uÅmiechu i powrotu.", 110 heroCta: "ZRÃBMY SHOW", 111 panelTitle: "Atrakcja, która <span>pracuje dla miejsca</span>", 112 panelText: "Format galerii może dziaÅaÄ jako gÅówny punkt dnia, czÄÅÄ kampanii sezonowej albo cykl krótszych wejÅÄ w przestrzeni eventowej. Oprócz widowiska scenicznego możemy przygotowaÄ animacje wÅród publicznoÅci, w tym efektowne zamkniÄcie dziecka w dużej baÅce.", 113 bullets: ["show do pasaży, scen mobilnych i przestrzeni centralnych,", "animacje rodzinne w przestrzeni galer
113ii, np. zamkniÄcie dziecka w dużej baÅce,", "programy na ferie, DzieÅ Dziecka, MikoÅajki i akcje tematyczne,", "efektowne momenty do zdjÄÄ i materiaÅów promocyjnych,", "elastyczny czas trwania i liczba wejÅÄ w ciÄ gu dnia."], 114 mediaEyebrow: "Photo-Video", 115 mediaTitle: "ZOBACZ EVENT <span>W PRZESTRZENI</span>", 116 videoText: "MateriaÅ video z eventu", 117 ctaEyebrow: "Promocje, ÅwiÄta, rodzinne weekendy", 118 ctaTitle: "Dodaj do programu efekt wow", 119 leadTitle: "Napisz swój e-mail i wkrótce siÄ skontaktujemy", 120 emailPlaceholder: "Twój e-mail", 121 leadButton: "SKONTAKTUJEMY SIÄ" 122 }, 123 en: { 124 seo: { title: "Malls and Entertainment Centers | Soap Bubble Theatre", description: "A spectacular family show for shopping malls, entertainment centers and promotional campaigns.", ogTitle: "Show for malls and entertainment centers", ogDescription: "A colorful attraction that draws families in and builds foot traffic." }, 125 heroEyebrow: "Family event", 126 heroTitle: "Malls and <span>entertainment centers</span>", 127 heroText: "A show designed to stop the audience, create a natural program highlight and give families a reason for a shared photo, smile and return visit.", 128 heroCta: "MAKE IT A SHOW", 129 panelTitle: "An attraction that <span>works for the venue</span>", 130 panelText: "The mall format can work as the main event of the day, part of a seasonal campaign or a series of shorter appearances in an event space. In addition to the stage show, we can prepare audience animations, including the spectacular moment of placing a child inside a giant bubble.", 131 bullets: ["show for passages, mobile stages and central spaces,", "family animations in the mall space, for example a child inside a giant bubble,", "programs for holidays, Children's Day, Christmas events and themed campaigns,", "strong photo moments for promotional materials,", "flexible duration and number of entries during the day."], 132 mediaEyebrow: "Photo-Video", 133 mediaTitle: "SEE THE EVENT <span>IN THE SPACE</span>", 134 videoText: "Video material from the event", 135 ctaEyebrow: "Promotions, holidays, family weekends", 136 ctaTitle: "Add a wow moment to the program", 137 leadTitle: "Leave your email and we will contact you soon", 138 emailPlaceholder: "Your email", 139 leadButton: "WE WILL CONTACT YOU" 140 }, 141 es: { 142 seo: { title: "Centros comerciales y de entretenimiento | Teatro de Pompas de Jabón", description: "Un espectáculo familiar impactante para centros comerciales, espacios de entretenimiento y campañas promocionales.", ogTitle: "Show para centros comerciales y de entretenimiento", ogDescription: "Una atracción colorida que atrae familias y aumenta el flujo de visitantes." }, 143 heroEyebrow: "Evento familiar", 144 heroTitle: "Centros comerciales y <span>de entretenimiento</span>", 145 heroText: "Un espectáculo diseñado para detener al público, crear un punto natural del programa y dar a las familias un motivo para una foto, una sonrisa y una nueva visita.", 146 heroCta: "HAGAMOS SHOW", 147 panelTitle: "Una atracción que <span>trabaja para el lugar</span>", 148 panelText: "El formato para centros comerciales puede funcionar como punto principal del dÃa, parte de una campaña de temporada o una serie de apariciones breves en el espacio de eventos. Además del show escénico, podemos preparar animaciones con el público, incluido el efecto de encerrar a un niño dentro de una pompa gigante.", 149 bullets: ["show para pasillos, escenarios móviles y espacios centrales,", "animaciones familiares en el centro comercial, por ejemplo un niño dentro de una pompa gigante,", "programas para vacaciones, DÃa del Niño, Navidad y acciones temáticas,", "momentos visuales fuertes para fotos y materiales promocionales,", "duración flexible y número de pases durante el dÃa."], 150 mediaEyebrow: "Foto-Video", 151 mediaTitle: "VER EL EVENTO <span>EN EL ESPACIO</span>", 152 videoText: "Material de video del evento", 153 ctaEyebrow: "Promociones, fiestas, fines de semana familiares",
154 ctaTitle: "Añade un efecto wow al programa", 155 leadTitle: "Deja tu email y nos pondremos en contacto pronto", 156 emailPlaceholder: "Tu email", 157 leadButton: "NOS PONDREMOS EN CONTACTO" 158 } 159 }, 160 "format-tury.html": { 161 pl: { 162 seo: { title: "Tury i wyjazdy | Teatr Baniek Mydlanych", description: "MiÄdzynarodowe widowisko objazdowe gotowe do pracy na trasach, festiwalach i scenach różnej skali.", ogTitle: "MiÄdzynarodowe show objazdowe", ogDescription: "Format gotowy do tras koncertowych, wystÄpów zagranicznych i dużych przestrzeni eventowych." }, 163 heroEyebrow: "Touring show", 164 heroTitle: "MiÄdzynarodowe <span>trasy</span>", 165 heroText: "Spektakl zaprojektowany jako mobilne, skalowalne widowisko rodzinne: od sal teatralnych po duże hale, festiwale, eventy i programy wyjazdowe.", 166 heroCta: "RUSZAJMY W TRASÄ", 167 panelTitle: "Show gotowe <span>do drogi</span>", 168 panelText: "To miÄdzynarodowa produkcja objazdowa z doÅwiadczeniem ponad 1000 zagranych spektakli w wiÄcej niż 8 krajach Åwiata, m.in. w Niemczech, Czechach, Polsce, Zjednoczonych Emiratach Arabskich, Grecji, Hiszpanii, Izraelu i Ukrainie. Pracujemy w modelu, który ÅÄ czy profesjonalny management, wÅasnÄ ekipÄ technicznÄ i kompaktowy zespóŠgotowy do sprawnej logistyki miÄdzy miastami oraz krajami.", 169 bullets: ["ponad 1000 zagranych spektakli na scenach różnej skali,", "doÅwiadczenie w ponad 8 krajach: Niemcy, Czechy, Polska, ZEA, Grecja, Hiszpania, Izrael, Ukraina,", "profesjonalny management produkcji i wÅasna ekipa techniczna,", "adaptacja formatu pod przeloty lotnicze oraz przejazdy naziemne,", "kompaktowy skÅad zespoÅu przy zachowaniu jakoÅci peÅnego widowiska."], 170 mediaEyebrow: "Video", 171 mediaTitle: "ZOBACZ SHOW <span>W TRASIE</span>", 172 videoText: "MateriaÅ video z trasy", 173 leadTitle: "Napisz swój e-mail i wkrótce siÄ skontaktujemy", 174 emailPlaceholder: "Twój e-mail", 175 leadButton: "SKONTAKTUJEMY SIÄ" 176 }, 177 en: { 178 seo: { title: "Tours and Travel Programs | Soap Bubble Theatre", description: "An international touring show ready for routes, festivals and venues of different scales.", ogTitle: "International touring show", ogDescription: "A format ready for concert tours, international performances and large event spaces." }, 179 heroEyebrow: "Touring show", 180 heroTitle: "International <span>tours</span>", 181 heroText: "A performance designed as a mobile, scalable family show: from theatre halls to large arenas, festivals, events and travel programs.", 182 heroCta: "LET'S TOUR", 183 panelTitle: "A show <span>ready to travel</span>", 184 panelText: "This is an international touring production with experience from more than 1000 performed shows in over 8 countries, including Germany, Czech Republic, Poland, the United Arab Emirates, Greece, Spain, Israel and Ukraine. We work in a model that combines professional management, our own technical crew and a compact team ready for efficient logistics between cities and countries.", 185 bullets: ["more than 1000 performances on stages of different scales,", "experience in 8+ countries: Germany, Czech Republic, Poland, UAE, Greece, Spain, Israel, Ukraine,", "professional production management and our own technical crew,", "format adapted for air travel and ground transport,", "compact team while keeping the quality of a full show."], 186 mediaEyebrow: "Video", 187 mediaTitle: "SEE THE SHOW <span>ON TOUR</span>", 188 videoText: "Video material from the tour", 189 leadTitle: "Leave your email and we will contact you soon", 190 emailPlaceholder: "Your email", 191 leadButton: "WE WILL CONTACT YOU" 192 }, 193 es: { 194 seo: { title: "Giras y programas de viaje | Teatro de Pompas de Jabón", description: "Un espectáculo internacional itinerante listo para giras, festivales y escenarios de diferentes escalas.", ogTitle: "Show internacional de gira", ogDescription: "Un formato listo para giras, actuaciones internacionales y grandes espacios de eventos." }, 195 heroEyebrow: "Show de gira", 196 heroTitle: "Giras <span>internacionales</span>",
197 heroText: "Un espectáculo diseñado como show familiar móvil y escalable: desde salas teatrales hasta grandes pabellones, festivales, eventos y programas de viaje.", 198 heroCta: "VAMOS DE GIRA", 199 panelTitle: "Un show <span>listo para viajar</span>", 200 panelText: "Es una producción internacional itinerante con experiencia de más de 1000 funciones realizadas en más de 8 paÃses, entre ellos Alemania, Chequia, Polonia, Emiratos Ãrabes Unidos, Grecia, España, Israel y Ucrania. Trabajamos con un modelo que combina management profesional, equipo técnico propio y un equipo compacto preparado para una logÃstica eficiente entre ciudades y paÃses.", 201 bullets: ["más de 1000 funciones en escenarios de distintas escalas,", "experiencia en más de 8 paÃses: Alemania, Chequia, Polonia, EAU, Grecia, España, Israel, Ucrania,", "management profesional de producción y equipo técnico propio,", "adaptación del formato para vuelos y traslados terrestres,", "equipo compacto manteniendo la calidad de un espectáculo completo."], 202 mediaEyebrow: "Video", 203 mediaTitle: "VER EL SHOW <span>EN GIRA</span>", 204 videoText: "Material de video de la gira", 205 leadTitle: "Deja tu email y nos pondremos en contacto pronto", 206 emailPlaceholder: "Tu email", 207 leadButton: "NOS PONDREMOS EN CONTACTO" 208 } 209 }, 210 "format-urodziny.html": { 211 pl: { 212 seo: { title: "Urodziny i przyjÄcia prywatne | Teatr Baniek Mydlanych", description: "Kameralne widowisko baniek mydlanych na urodziny, komunie, chrzciny i rodzinne okazje.", ogTitle: "Magiczne urodziny i przyjÄcia", ogDescription: "Rodzinny format show peÅen baniek, humoru i wspólnej zabawy." }, 213 heroEyebrow: "Kameralna magia", 214 heroTitle: "Urodziny i <span>przyjÄcia</span>", 215 heroText: "Mini widowisko dla rodzinnych okazji: efektowne, ciepÅe, interaktywne i dopasowane do wieku dzieci oraz charakteru spotkania.", 216 heroCta: "LET'S PARTY!", 217 panelTitle: "MaÅy format, <span>duży zachwyt</span>", 218 panelText: "Przygotowujemy pokaz tak, aby dziaÅaÅ w domu, sali przyjÄÄ, ogrodzie lub kameralnej przestrzeni eventowej. Liczy siÄ bliskoÅÄ, Åmiech i moment, w którym solenizant staje siÄ czÄÅciÄ baÅkowej historii.", 219 bullets: ["urodziny, komunie, chrzciny i rodzinne spotkania,", "program dopasowany do wieku i liczby goÅci,", "bezpieczna interakcja i wspólna zabawa,", "możliwoÅÄ krótszego lub rozszerzonego formatu."], 220 mediaEyebrow: "Photo-Video", 221 mediaTitle: "ZOBACZ MAGIÄ <span>Z BLISKA</span>", 222 videoText: "MateriaÅ video z przyjÄcia", 223 ctaEyebrow: "Urodziny, komunie, rodzinne okazje", 224 ctaTitle: "Niech przyjÄcie zapamiÄtajÄ wszyscy", 225 leadTitle: "Napisz swój e-mail i wkrótce siÄ skontaktujemy", 226 emailPlaceholder: "Twój e-mail", 227 leadButton: "SKONTAKTUJEMY SIÄ" 228 }, 229 en: { 230 seo: { title: "Birthdays and Private Parties | Soap Bubble Theatre", description: "A chamber soap bubble show for birthdays, communions, christenings and family occasions.", ogTitle: "Magical birthdays and parties", ogDescription: "A family show format full of bubbles, humor and shared fun." }, 231 heroEyebrow: "Intimate magic", 232 heroTitle: "Birthdays and <span>parties</span>", 233 heroText: "A mini show for family occasions: impressive, warm, interactive and adapted to the children's age and the character of the gathering.", 234 heroCta: "LET'S PARTY!", 235 panelTitle: "Small format, <span>big delight</span>", 236 panelText: "We prepare the show so it works at home, in a party room, garden or intimate event space. What matters is closeness, laughter and the moment when the birthday child becomes part of the bubble story.", 237 bullets: ["birthdays, communions, christenings and family gatherings,", "program adapted to age and number of guests,", "safe interaction and shared fun,", "possibility of a shorter or extended format."], 238 mediaEyebrow: "Photo-Video", 239 mediaTitle: "SEE THE MAGIC <span>UP CLOSE</span>", 240 videoText: "Video material from the party", 241 ctaEyebrow: "Birthdays, communions, family occasions", 242 ctaTitle: "Make the party unforgettable for everyone",
243 leadTitle: "Leave your email and we will contact you soon", 244 emailPlaceholder: "Your email", 245 leadButton: "WE WILL CONTACT YOU" 246 }, 247 es: { 248 seo: { title: "Cumpleaños y fiestas privadas | Teatro de Pompas de Jabón", description: "Un show Ãntimo de pompas de jabón para cumpleaños, comuniones, bautizos y ocasiones familiares.", ogTitle: "Cumpleaños y fiestas mágicas", ogDescription: "Un formato familiar lleno de pompas, humor y diversión compartida." }, 249 heroEyebrow: "Magia Ãntima", 250 heroTitle: "Cumpleaños y <span>fiestas</span>", 251 heroText: "Un mini espectáculo para ocasiones familiares: impactante, cálido, interactivo y adaptado a la edad de los niños y al carácter del encuentro.", 252 heroCta: "LET'S PARTY!", 253 panelTitle: "Formato pequeño, <span>gran asombro</span>", 254 panelText: "Preparamos el show para que funcione en casa, en un salón de fiestas, jardÃn o espacio Ãntimo de eventos. Lo importante es la cercanÃa, la risa y el momento en que el homenajeado se convierte en parte de la historia de pompas.", 255 bullets: ["cumpleaños, comuniones, bautizos y encuentros familiares,", "programa adaptado a la edad y al número de invitados,", "interacción segura y diversión compartida,", "posibilidad de formato más corto o ampliado."], 256 mediaEyebrow: "Foto-Video", 257 mediaTitle: "VER LA MAGIA <span>DE CERCA</span>", 258 videoText: "Material de video de la fiesta", 259 ctaEyebrow: "Cumpleaños, comuniones, ocasiones familiares", 260 ctaTitle: "Haz que todos recuerden la fiesta", 261 leadTitle: "Deja tu email y nos pondremos en contacto pronto", 262 emailPlaceholder: "Tu email", 263 leadButton: "NOS PONDREMOS EN CONTACTO" 264 } 265 }, 266 "bohaterowie.html": { 267 pl: { 268 seo: { title: "Bohaterowie spektaklu | Teatr Baniek Mydlanych", description: "Poznaj bohaterów Krainy Mydlanych Baniek: Crodziejska Wróżka, Mistrz Bulbulas, BÄ belek, Mydlaneczka i Profesor Cudak.", ogTitle: "Bohaterowie spektaklu", ogDescription: "PiÄÄ barwnych postaci, które prowadzÄ publicznoÅÄ przez baÅkowÄ przygodÄ." }, 269 heroEyebrow: "Åwiat spektaklu", 270 heroTitle: "Bohaterowie <span>baÅkowej przygody</span>", 271 heroText: "PiÄÄ barwnych charakterów z Krainy Mydlanych Baniek: przyjaźÅ, fantazja, humor i magia, która prowadzi publicznoÅÄ przez caÅy spektakl.", 272 heroCta: "ZAPROÅ BOHATERÃW", 273 mediaEyebrow: "Postacie", 274 mediaTitle: "MAGICZNA <span>DRUÅ»YNA</span>", 275 cards: [ 276 { subtitle: "gÅówna wróżka krainy", title: "Crodziejska Wróżka", text: "MÄ dra opiekunka i nauczycielka mÅodych czarodziejów, która przypomina, że prawdziwa magia zaczyna siÄ od dobrego serca.", traits: "Gracyjna, wielkoduszna, inspirujÄ ca" }, 277 { subtitle: "mistrz szalonych mikstur", title: "Mistrz Bulbulas", text: "Ekscentryczny twórca najbardziej nieprzewidywalnych baniek. Groźny, zabawny i w gÅÄbi serca dużo bardziej czuÅy, niż przyznaje.", traits: "Teatralny, charyzmatyczny, przewrotny" }, 278 { subtitle: "wesoÅy wynalazca", title: "BÄ belek", text: "Nieustanny eksperymentator, który wymyÅla nowe baÅkowe mechanizmy i potrafi zmieniÄ każdÄ pomyÅkÄ w przygodÄ.", traits: "PomysÅowy, odważny, optymistyczny" }, 279 { subtitle: "uczennica szkoÅy Bul-Bul", title: "Mydlaneczka", text: "Najlepsza uczennica magicznej szkoÅy, która wierzy w dobro, fantazjÄ i maÅe cuda ukryte w każdej baÅce.", traits: "WesoÅa, romantyczna, energiczna" }, 280 { subtitle: "dobry profesor", title: "Profesor Cudak", text: "Roztrzepany, genialny twórca niezwykÅych maszyn do baniek, który w każdym maÅym eksperymencie widzi wielkie odkrycie.", traits: "Dobry, zabawny, peÅen wyobraźni" } 281 ], 282 ctaEyebrow: "Postacie, kostiumy, materiaÅy promocyjne", 283 ctaTitle: "Zaprosimy publicznoÅÄ do Åwiata baniek", 284 heroCtaBottom: "ZAMÃW SPEKTAKL" 285 }, 286 en: { 287 seo: { title: "Show Characters | Soap Bubble Theatre", description: "Meet the characters from the Land of Soap Bubbles: Miss Wizardson, Master Blowcheater, Saponice, Bubblittle and Academician Wackadoodle.", ogTitle: "Show characters", ogDescription: "Five colorful characters guiding the audience through the bubble adventure." }, 288 heroEyebrow: "World of the show", 289 heroTitle: "Characters of the <span>bubble adventure</span>", 290 heroText: "Five vivid personalities from the Land of Soap Bubbles: friendship, fantasy, humor and magic leading the audience through the whole performance.", 291 heroCta: "INVITE THE CHARACTERS", 292 mediaEyebrow: "Characters", 293 mediaTitle: "THE MAGICAL <span>TEAM</span>", 294 cards: [ 295 { subtitle: "main fairy of the land", title: "Miss Wizardson", text: "A wise guardian and teacher of young magicians who reminds everyone that true magic begins with a kind heart.", traits: "Graceful, generous, inspiring" }, 296 { subtitle: "master of wild mixtures", title: "Master Blowcheater", text: "An ecce
296ntric creator of the most unpredictable bubbles. Fierce, funny and much softer at heart than he wants to admit.", traits: "Theatrical, charismatic, mischievous" }, 297 { subtitle: "joyful inventor", title: "Saponice", text: "A tireless experimenter who invents new bubble mechanisms and can turn every mistake into an adventure.", traits: "Inventive, brave, optimistic", image: "assets/character-mylochka.jpg" }, 298 { subtitle: "student of Bul-Bul school", title: "Bubblittle", text: "The top student of the magical school, believing in kindness, imagination and small wonders hidden inside every bubble.", traits: "Cheerful, romantic, energetic", image: "assets/character-puzyrik.jpg" }, 299 { subtitle: "kind professor", title: "Academician Wackadoodle", text: "A distracted, brilliant maker of bubble machines who sees a great discovery in every tiny experiment.", traits: "Kind, funny, imaginative" } 300 ], 301 ctaEyebrow: "Characters, costumes, promotional materials", 302 ctaTitle: "We will invite the audience into the world of bubbles", 303 heroCtaBottom: "BOOK THE SHOW" 304 }, 305 es: { 306 seo: { title: "Personajes del espectáculo | Teatro de Pompas de Jabón", description: "Conoce a los personajes del PaÃs de las Pompas de Jabón: Hada Encantadora, Maestro Enflautador, BurbujÃn, Jaboncita y CientÃfico Loco.", ogTitle: "Personajes del espectáculo", ogDescription: "Cinco personajes coloridos que guÃan al público por la aventura de pompas." }, 307 heroEyebrow: "Mundo del espectáculo", 308 heroTitle: "Personajes de la <span>aventura de pompas</span>", 309 heroText: "Cinco personalidades brillantes del PaÃs de las Pompas de Jabón: amistad, fantasÃa, humor y magia que guÃan al público durante todo el espectáculo.", 310 heroCta: "INVITAR A LOS PERSONAJES", 311 mediaEyebrow: "Personajes", 312 mediaTitle: "EL EQUIPO <span>MÃGICO</span>", 313 cards: [ 314 { subtitle: "hada principal del paÃs", title: "Hada Encantadora", text: "Una sabia guardiana y maestra de jóvenes magos que recuerda que la verdadera magia empieza en un corazón bondadoso.", traits: "Elegante, generosa, inspiradora" }, 315 { subtitle: "maestro de mezclas locas", title: "Maestro Enflautador", text: "Un creador excéntrico de las pompas más imprevisibles. Amenazante, divertido y mucho más tierno de lo que admite.", traits: "Teatral, carismático, travieso" }, 316 { subtitle: "inventor alegre", title: "BurbujÃn", text: "Un experimentador incansable que inventa nuevos mecanismos de pompas y convierte cada error en una aventura.", traits: "Ingenioso, valiente, optimista" }, 317 { subtitle: "alumna de la escuela Bul-Bul", title: "Jaboncita", text: "La mejor alumna de la escuela mágica, que cree en la bondad, la fantasÃa y los pequeños milagros escondidos en cada pompa.", traits: "Alegre, romántica, energética" }, 318 { subtitle: "profesor bondadoso", title: "CientÃfico Loco", text: "Un inventor despistado y genial de máquinas de pompas que ve un gran descubrimiento en cada pequeño experimento.", traits: "Bondadoso, divertido, imaginativo" } 319 ], 320 ctaEyebrow: "Personajes, vestuario, materiales promocionales", 321 ctaTitle: "Invitaremos al público al mundo de las pompas", 322 heroCtaBottom: "RESERVAR SHOW" 323 } 324 } 325 }; 326 327 function setText(selector, value) { 328 var element = document.querySelector(selector); 329 if (element && typeof value === "string") element.textContent = value; 330 } 331 332 function setHtml(selector, value) { 333 var element = document.querySelector(selector); 334 if (element && typeof value === "string") element.innerHTML = value; 335 } 336 337 function setMeta(selector, value) { 338 var element = document.querySelector(selector); 339 if (element && typeof value === "string") element.setAttribute("content", value); 340 } 341
342 function renderSeo() { 343 var seo = siteContent.seo || {}; 344 if (seo.title) document.title = seo.title; 345 setMeta('meta[name="description"]', seo.description); 346 setMeta('meta[name="keywords"]', seo.keywords); 347 setMeta('meta[property="og:title"]', seo.ogTitle || seo.title); 348 setMeta('meta[property="og:description"]', seo.ogDescription || seo.description); 349 setMeta('meta[property="og:locale"]', seo.ogLocale); 350 } 351 352 function setLabelText(selector, value) { 353 var label = document.querySelector(selector); 354 if (!label || typeof value !== "string") return; 355 var field = label.querySelector("input, textarea, select"); 356 label.textContent = value + " "; 357 if (field) label.appendChild(field); 358 } 359 360 function escapeHtml(value) { 361 return String(value || "") 362 .replace(/&/g, "&") 363 .replace(/</g, "<") 364 .replace(/>/g, ">") 365 .replace(/"/g, """) 366 .replace(/'/g, "'"); 367 } 368 369 function formatEventDate(value) { 370 if (!value) return ""; 371 var date = new Date(value + "T12:00:00"); 372 if (Number.isNaN(date.getTime())) return value; 373 var locale = currentLanguage === "en" ? "en-GB" : currentLanguage === "es" ? "es-ES" : "pl-PL"; 374 return new Intl.DateTimeFormat(locale, { 375 day: "2-digit", 376 month: "short", 377 year: "numeric" 378 }).format(date); 379 } 380 381 function fallbackImage(title, colors) { 382 var svg = 383 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">' + 384 '<defs><linearGradient id="g" x1="0" x2="1" y1="0" y2="1"><stop stop-color="' + 385 colors[0] + 386 '"/><stop offset="1" stop-color="' + 387 colors[1] + 388 '"/></linearGradient><filter id="blur"><feGaussianBlur stdDeviation="22"/></filter></defs>' + 389 '<rect width="1200" height="800" fill="url(#g)"/>' + 390 '<circle cx="240" cy="640" r="210" fill="#ff3f9a" opacity=".28" filter="url(#blur)"/>' + 391 '<circle cx="920" cy="210" r="250" fill="#59d8ff" opacity=".24" filter="url(#blur)"/>' + 392 '<circle cx="740" cy="470" r="180" fill="none" stroke="#fff" stroke-width="10" opacity=".55"/>' + 393 '<circle cx="812" cy="390" r="44" fill="#fff" opacity=".72"/>' + 394 '<text x="70" y="690" fill="#fff" font-family="Arial, Helvetica, sans-serif" font-size="72" font-weight="900">' + 395 title + 396 "</text></svg>"; 397 return "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg); 398 } 399 400 function renderEditableContent() { 401 var ui = siteContent.ui || {}; 402 var logoImage = document.querySelector(".logo img"); 403 404 renderSeo(); 405 406 if (logoImage && siteContent.logo) { 407 logoImage.src = resolveAssetPath(siteContent.logo.src || "assets/logo.png"); 408 logoImage.alt = siteContent.logo.alt || "Teatr Baniek Mydlanych"; 409 } 410 411 setText('.main-nav a[href="#about"]', ui.navAbout); 412 setText('.main-nav a[href="#offer"]', ui.navOffer); 413 setText('.main-nav a[href="#events"]', ui.navEvents); 414 setText('.main-nav a[href="#gallery"]', ui.navGallery); 415 document.querySelectorAll('.main-nav a[href*="bohaterowie.html"]').forEach(function (link) { 416 link.textContent = ui.navCharacters || link.textContent; 417 }); 418 setText('.main-nav a[href="#faq"]', ui.navFaq); 419 setText('.main-nav a[href="#contact"]', ui.navContact); 420 421 setText(".hero-copy .eyebrow", ui.heroEyebrow); 422 setText(".hero h1 span:nth-child(1)", ui.heroLine1); 423 setText(".hero h1 span:nth-child(2)", ui.heroLine2); 424 setText(".hero h1 span:nth-child(3)", ui.heroLine3); 425 setText(".hero-text", ui.heroText); 426 setText(".hero-buttons .btn-primary", ui.ctaOrder); 427 var videoButtonText = document.querySelector("[data-video-trigger]"); 428 if (videoButtonText && ui.ctaVideo) { 429 videoButtonText.childNodes[videoButtonText.childNodes.length - 1].textContent = " " + ui.ctaVideo; 430 } 431 432 setText("#offer .section-heading p", ui.offerEyebrow); 433 setHtml("#offer-title", ui.offerTitle); 434 435 if (Array.isArray(siteContent.offers)) { 436 document.querySelectorAll(".offer-card").forEach(function (card, index) { 437 var offer = siteContent.offers[index]; 438 if (!offer) return; 439 var title = card.querySelector("h3"); 440 var text = card.querySelector(".card-body p"); 441 var list = card.querySelector("ul"); 442 var link = card.querySelector(".btn-card"); 443 if (title) title.textContent = offer.title; 444 if (text) text.textContent = offer.text; 445 if (list) { 446 list.innerHTML = offer.bullets.map(function (item) { 447 return "<li>" + escapeHtml(item) + "</li>"; 448 }).join(""); 449 } 450 if (link) { 451 link.textContent = offer.cta || ui.learnMore || link.textContent; 452 if (offer.url) link.href = withLanguage(offer.url); 453 } 454 }); 455 } 456 457 setHtml("#showcase-title", ui.showcaseTitle);
458 setText(".showcase-copy p", ui.showcaseText); 459 setText(".showcase-copy .btn-primary", ui.ctaOrder); 460 461 setText("#about .eyebrow", ui.aboutEyebrow); 462 setText("#about-title", ui.aboutTitle); 463 setText(".split-copy > p:not(.eyebrow)", ui.aboutText); 464 setText(".stats div:nth-child(1) strong", ui.statOneValue); 465 setText(".stats div:nth-child(1) span", ui.statOneLabel); 466 setText(".stats div:nth-child(2) strong", ui.statTwoValue); 467 setText(".stats div:nth-child(2) span", ui.statTwoLabel); 468 setText(".stats div:nth-child(3) strong", ui.statThreeValue); 469 setText(".stats div:nth-child(3) span", ui.statThreeLabel); 470 471 setText("#places .eyebrow", ui.placesEyebrow); 472 setText("#places-title", ui.placesTitle); 473 setText("#places .narrow p:last-child", ui.placesText); 474 475 setText(".scale .section-heading p", ui.scaleEyebrow); 476 setHtml("#scale-title", ui.scaleTitle); 477 setText(".scale-item:nth-child(1) strong", ui.scaleMiniTitle); 478 setText(".scale-item:nth-child(1) span", ui.scaleMiniText); 479 setText(".scale-item:nth-child(2) strong", ui.scaleStageTitle); 480 setText(".scale-item:nth-child(2) span", ui.scaleStageText); 481 setText(".scale-item:nth-child(3) strong", ui.scaleEventTitle); 482 setText(".scale-item:nth-child(3) span", ui.scaleEventText); 483 484 setText("#gallery .section-heading p", ui.galleryEyebrow); 485 setHtml("#gallery-title", ui.galleryTitle); 486 setText(".video-placeholder strong", ui.videoPlaceholderTitle); 487 setText(".video-placeholder span", ui.videoPlaceholderText); 488 489 setText("#faq .section-heading p", ui.faqEyebrow); 490 setHtml("#faq-title", ui.faqTitle); 491 492 setText("#order .eyebrow", ui.orderEyebrow); 493 setText("#order-title", ui.orderTitle); 494 setText(".step:nth-child(1) strong", ui.stepOneTitle); 495 setText(".step:nth-child(1) p", ui.stepOneText); 496 setText(".step:nth-child(2) strong", ui.stepTwoTitle); 497 setText(".step:nth-child(2) p", ui.stepTwoText); 498 setText(".step:nth-child(3) strong", ui.stepThreeTitle); 499 setText(".step:nth-child(3) p", ui.stepThreeText); 500 501 setLabelText('[data-contact-form] label:nth-of-type(1)', ui.formName); 502 setLabelText('[data-contact-form] label:nth-of-type(2)', ui.formEmail); 503 setLabelText('[data-contact-form] label:nth-of-type(3)', ui.formPhone); 504 setLabelText('[data-contact-form] label:nth-of-type(4)', ui.formMessage); 505 setText('[data-contact-form] button[type="submit"]', ui.formSubmit); 506 setText(".mobile-cta", ui.ctaOrder); 507 508 if (siteContent.contact) { 509 setText("[data-contact-eyebrow]", siteContent.contact.eyebrow); 510 setText("[data-contact-title]", siteContent.contact.headline); 511 setText("[data-contact-text]", siteContent.contact.text); 512 setHtml("[data-contact-details]", siteContent.contact.detailsHtml); 513 } 514 515 var faqList = document.querySelector("[data-faq-list]"); 516 if (faqList && Array.isArray(siteContent.faq)) { 517 faqList.innerHTML = siteContent.faq 518 .map(function (item) { 519 return ( 520 '<div class="faq-item">' + 521 '<button type="button" aria-expanded="false">' + 522 escapeHtml(item.question) + 523 "</button>" + 524 '<div class="faq-panel">' + 525 escapeHtml(item.answer) + 526 "</div>" + 527 "</div>" 528 ); 529 }) 530 .join(""); 531 } 532 533 if (siteContent.events) { 534 setText("[data-events-eyebrow]", siteContent.events.eyebrow); 535 setHtml("[data-events-title]", siteContent.events.headline); 536 setText("[data-events-text]", siteContent.events.text); 537 538 var eventsList = document.querySelector("[data-events-list]"); 539 if (eventsList) { 540 var items = Array.isArray(siteContent.events.items) ? siteContent.events.items : []; 541 if (items.length) { 542 var visibleCount = Number(siteContent.events.visibleCount) || items.length; 543 eventsList.innerHTML = items 544 .slice(0, visibleCount) 545 .map(function (eventItem) { 546 var ticketUrl = eventItem.ticketUrl || eventItem.url || ""; 547 var labels = siteContent.events.labels || {}; 548 var ticketLabel = eventItem.ticketLabel || eventItem.label || "KUP BILET"; 549 var dateTime = [formatEventDate(eventItem.date), eventItem.time].filter(
549Boolean).join(" · "); 550 var action = ticketUrl 551 ? '<a class="event-ticket" href="' + 552 escapeHtml(ticketUrl) + 553 '" target="_blank" rel="noopener">' + 554 escapeHtml(ticketLabel) + 555 "</a>" 556 : '<span class="event-note">' + escapeHtml(eventItem.note || labels.ticketsSoon || "BILETY WKRÃTCE") + "</span>"; 557 558 return ( 559 '<article class="event-card reveal">' + 560 '<div class="event-row event-city"><span>' + escapeHtml(labels.city || "Miasto") + "</span><strong>" + 561 escapeHtml(eventItem.city) + 562 "</strong></div>" + 563 '<div class="event-row"><span>' + escapeHtml(labels.venue || "Miejsce") + "</span><strong>" + 564 escapeHtml(eventItem.venue) + 565 "</strong></div>" + 566 '<div class="event-row"><span>' + escapeHtml(labels.dateTime || "Data i godzina") + '</span><time datetime="' + 567 escapeHtml(eventItem.date) + 568 '">' + 569 escapeHtml(dateTime) + 570 "</time></div>" + 571 action + 572 "</article>" 573 ); 574 }) 575 .join(""); 576 } else { 577 eventsList.innerHTML = 578 '<div class="events-empty reveal">' + escapeHtml(siteContent.events.emptyText) + "</div>"; 579 } 580 } 581 582 var eventsActions = document.querySelector("[data-events-actions]"); 583 if (eventsActions && siteContent.events.allEvents) { 584 var allEvents = siteContent.events.allEvents; 585 var allEventsUrl = allEvents.url || "#contact"; 586 var isExternal = /^https?:\/\//.test(allEventsUrl); 587 eventsActions.innerHTML = 588 '<a class="btn btn-primary" href="' + 589 escapeHtml(allEventsUrl) + 590 '"' + 591 (isExternal ? ' target="_blank" rel="noopener"' : "") + 592 ">" + 593 escapeHtml(allEvents.label || "WSZYSTKIE WYDARZENIA") + 594 "</a>"; 595 } 596 } 597 598 var youtubeFrames = document.querySelectorAll("[data-youtube-frame]"); 599 if (youtubeFrames.length && siteContent.youtube && siteContent.youtube.videoId) { 600 var videoId = encodeURIComponent(siteContent.youtube.videoId); 601 var videoTitle = escapeHtml(siteContent.youtube.title || "Video"); 602 var youtubeUrl = "https://www.youtube.com/watch?v=" + videoId; 603 youtubeFrames.forEach(function (youtubeFrame) { 604 youtubeFrame.innerHTML = 605 '<iframe src="https://www.youtube.com/embed/' + 606 videoId + 607 '?rel=0" title="' + 608 videoTitle + 609 '" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen loading="lazy" referrerpolicy="strict-origin-when-cross-origin"></iframe>' + 610 '<a class="youtube-fallback-link" href="' + 611 youtubeUrl + 612 '" target="_blank" rel="noopener">' + 613 escapeHtml(ui.videoFallbackLink || "Watch on YouTube") + 614 "</a>"; 615 }); 616 } 617 618 renderSubpageContent(); 619 } 620 621 renderEditableContent(); 622 623 function resolveAssetPath(path) { 624 if (!path || path.indexOf("assets/") !== 0) return path; 625 return pathLanguage ? "../" + path : path; 626 } 627 628 function withLanguage(url) { 629 if (!url || url.charAt(0) === "#" || /^https?:\/\//.test(url)) return url; 630 var nextUrl = new URL(url, window.location.href); 631 if (pathLanguage) { 632 nextUrl.searchParams.delete("lang"); 633 } else { 634 nextUrl.searchParams.set("lang", currentLanguage); 635 } 636 return nextUrl.pathname.split("/").pop() + nextUrl.search + nextUrl.hash; 637 } 638 639 function getLanguageUrl(code) { 640 var nextUrl = new URL(window.location.href); 641 var parts = nextUrl.pathname.split("/"); 642 var file = parts.pop() || "index.html"; 643 var languageIndex = -1; 644 for (var i = 0; i < parts.length; i += 1) { 645 if (languages[parts[i]]) { 646 languageIndex = i; 647 break; 648 } 649 } 650 if (languageIndex >= 0) { 651 parts[languageIndex] = code; 652 } else { 653 parts.push(code); 654 } 655 nextUrl.pathname = parts.concat(file).join("/"); 656 nextUrl.searchParams.delete("lang"); 657 return nextUrl.toString(); 658 } 659 660 function setListItems(list, items) { 661 if (!list || !Array.isArray(items)) return; 662 list.innerHTML = items.map(function (item) { 663 return "<li>" + escapeHtml(item) + "</li>"; 664 }).join(""); 665 } 666
667 function renderSubpageContent() { 668 var page = window.location.pathname.split("/").pop() || "index.html"; 669 var pageLanguages = subpageContent[page]; 670 if (!pageLanguages) return; 671 var pageContent = pageLanguages[currentLanguage] || pageLanguages.pl; 672 if (!pageContent) return; 673 var seo = pageContent.seo || {}; 674 675 if (seo.title) document.title = seo.title; 676 setMeta('meta[name="description"]', seo.description); 677 setMeta('meta[property="og:title"]', seo.ogTitle || seo.title); 678 setMeta('meta[property="og:description"]', seo.ogDescription || seo.description); 679 680 document.querySelectorAll(".logo").forEach(function (link) { 681 link.href = withLanguage("index.html"); 682 }); 683 684 document.querySelectorAll(".main-nav a").forEach(function (link) { 685 var href = link.getAttribute("href") || ""; 686 if (href.indexOf("#about") !== -1) link.textContent = (siteContent.ui && siteContent.ui.navAbout) || link.textContent; 687 if (href.indexOf("#offer") !== -1) link.textContent = (siteContent.ui && siteContent.ui.navOffer) || link.textContent; 688 if (href.indexOf("#events") !== -1) link.textContent = (siteContent.ui && siteContent.ui.navEvents) || link.textContent; 689 if (href.indexOf("#gallery") !== -1) link.textContent = (siteContent.ui && siteContent.ui.navGallery) || link.textContent; 690 if (href.indexOf("bohaterowie.html") !== -1) link.textContent = (siteContent.ui && siteContent.ui.navCharacters) || link.textContent; 691 if (href.indexOf("#faq") !== -1) link.textContent = (siteContent.ui && siteContent.ui.navFaq) || link.textContent; 692 if (href.indexOf("#contact") !== -1) link.textContent = (siteContent.ui && siteContent.ui.navContact) || link.textContent; 693 link.href = withLanguage(href); 694 }); 695 696 setText(".subpage-hero-inner .eyebrow", pageContent.heroEyebrow); 697 setHtml(".subpage-hero-inner h1", pageContent.heroTitle); 698 setText(".subpage-hero-inner > p:not(.eyebrow)", pageContent.heroText); 699 setText(".subpage-hero-inner .btn", pageContent.heroCta); 700 var heroButton = document.querySelector(".subpage-hero-inner .btn"); 701 if (heroButton) heroButton.href = withLanguage(heroButton.getAttribute("href") || "index.html#contact"); 702 703 setHtml(".subpage-panel h2", pageContent.panelTitle); 704 setText(".subpage-panel > p", pageContent.panelText); 705 setListItems(document.querySelector(".subpage-panel ul"), pageContent.bullets); 706 707 setText(".section-heading .eyebrow, .section-heading p", pageContent.mediaEyebrow); 708 setHtml(".section-heading h2", pageContent.mediaTitle); 709 setText(".video-placeholder span", pageContent.videoText); 710 711 setText(".subpage-cta .eyebrow", pageContent.ctaEyebrow); 712 setText(".subpage-cta h2", pageContent.ctaTitle); 713 setText(".quick-lead-title", pageContent.leadTitle); 714 document.querySelectorAll(".quick-lead input[type='email']").forEach(function (input) { 715 if (pageContent.emailPlaceholder) input.placeholder = pageContent.emailPlaceholder; 716 }); 717 document.querySelectorAll(".quick-lead button[type='submit']").forEach(function (button) { 718 if (pageContent.leadButton) button.textContent = pageContent.leadButton; 719 }); 720 721 if (Array.isArray(pageContent.cards)) { 722 document.querySelectorAll(".hero-card").forEach(function (card, index) { 723 var cardContent = pageContent.cards[index]; 724 if (!cardContent) return; 725 var title = card.querySelector("h3"); 726 var text = card.querySelector("p"); 727 var subtitle = card.querySelector("span"); 728 var traits = card.querySelector("strong"); 729 var image = card.querySelector("img"); 730 if (subtitle) subtitle.textContent = cardContent.subtitle || ""; 731 if (title) title.textContent = cardContent.title; 732 if (text) text.textContent = cardContent.text; 733 if (traits) traits.textContent = cardContent.traits || ""; 734 if (image && cardContent.image) image.src = resolveAssetPath(cardContent.image); 735 }); 736 } 737 738 var bottomButton = document.querySelector(".subpage-cta .btn"); 739 if (bottomButton && pageContent.heroCtaBottom) bottomButton.textContent = pageContent.heroCtaBottom; 740 } 741
742 function renderSocialLinks() { 743 if (!siteConfig.socialEnabled) { 744 document.querySelectorAll("[data-social-links]").forEach(function (container) { 745 container.innerHTML = ""; 746 container.setAttribute("hidden", ""); 747 }); 748 return; 749 } 750 var social = Array.isArray(siteConfig.social) ? siteConfig.social : []; 751 document.querySelectorAll("[data-social-links]").forEach(function (container) { 752 if (container.hasAttribute("hidden")) return; 753 container.innerHTML = social 754 .map(function (item) { 755 var label = escapeHtml(item.label || "Social"); 756 return ( 757 '<a href="' + 758 escapeHtml(item.url || "#") + 759 '" target="_blank" rel="noopener" aria-label="' + 760 label + 761 '">' + 762 '<img src="' + 763 escapeHtml(item.icon || "") + 764 '" alt="" aria-hidden="true">' + 765 "<span>" + 766 label + 767 "</span></a>" 768 ); 769 }) 770 .join(""); 771 }); 772 } 773 774 renderSocialLinks(); 775 776 function renderLanguageMenu() { 777 if (!languageSwitch) return; 778 languageSwitch.innerHTML = (siteContent.label || currentLanguage.toUpperCase()) + ' <span aria-hidden="true">â</span>'; 779 var menu = document.createElement("div"); 780 menu.className = "language-menu"; 781 menu.setAttribute("hidden", ""); 782 Object.keys(languages).forEach(function (code) { 783 var option = document.createElement("button"); 784 option.type = "button"; 785 option.textContent = languages[code].label || code.toUpperCase(); 786 option.className = code === currentLanguage ? "is-active" : ""; 787 option.addEventListener("click", function () { 788 localStorage.setItem("siteLanguage", code); 789 window.location.href = getLanguageUrl(code); 790 }); 791 menu.appendChild(option); 792 }); 793 languageSwitch.insertAdjacentElement("afterend", menu); 794 languageSwitch.addEventListener("click", function () { 795 menu.toggleAttribute("hidden"); 796 }); 797 document.addEventListener("click", function (event) { 798 if (!languageSwitch.contains(event.target) && !menu.contains(event.target)) { 799 menu.setAttribute("hidden", ""); 800 } 801 }); 802 } 803 804 renderLanguageMenu(); 805 806 document.querySelectorAll("img").forEach(function (image) { 807 image.addEventListener( 808 "error", 809 function () { 810 var src = image.getAttribute("src") || ""; 811 if (src.indexOf("assets/icon-") === 0 && src.indexOf(".png") !== -1) { 812 image.src = src.replace(".png", ".svg"); 813 return; 814 } 815 var isLogo = src.indexOf("logo") !== -1; 816 if (isLogo && src !== resolveAssetPath("assets/logo.png")) { 817 image.src = resolveAssetPath("assets/logo.png"); 818 return; 819 } 820 image.src = isLogo 821 ? fallbackImage("TEATR BANIEK", ["#06104d", "#ff3f9a"]) 822 : fallbackImage("TEATR BANIEK MYDLANYCH", ["#040318", "#102a9b"]); 823 }, 824 { once: true } 825 ); 826 }); 827 828 function updateHeader() { 829 if (!header) return; 830 header.classList.toggle("is-scrolled", window.scrollY > 24); 831 } 832 833 updateHeader(); 834 window.addEventListener("scroll", updateHeader, { passive: true }); 835 836 if (menuToggle && nav) { 837 menuToggle.addEventListener("click", function () { 838 var isOpen = nav.classList.toggle("is-open"); 839 header.classList.toggle("is-open", isOpen); 840 menuToggle.setAttribute("aria-expanded", String(isOpen)); 841 }); 842 843 nav.querySelectorAll("a").forEach(function (link) { 844 link.addEventListener("click", function () { 845 nav.classList.remove("is-open"); 846 header.classList.remove("is-open"); 847 menuToggle.setAttribute("aria-expanded", "false"); 848 }); 849 }); 850 } 851 852 document.querySelectorAll('a[href^="#"]').forEach(function (anchor) { 853 anchor.addEventListener("click", function (event) { 854 var target = document.querySelector(anchor.getAttribute("href")); 855 if (!target) return; 856 event.preventDefault(); 857 target.scrollIntoView({ behavior: "smooth", block: "start" }); 858 });
859 }); 860 861 document.querySelectorAll(".faq-item button").forEach(function (button) { 862 button.addEventListener("click", function () { 863 var item = button.closest(".faq-item"); 864 var isOpen = item.classList.toggle("is-open"); 865 button.setAttribute("aria-expanded", String(isOpen)); 866 }); 867 }); 868 869 document.querySelectorAll("[data-lightbox]").forEach(function (button) { 870 button.addEventListener("click", function () { 871 if (!lightbox || !lightboxImage) return; 872 var thumbnail = button.querySelector("img"); 873 lightboxImage.src = thumbnail.currentSrc || thumbnail.src || button.getAttribute("data-lightbox"); 874 lightboxImage.alt = thumbnail.alt; 875 lightbox.classList.add("is-open"); 876 lightbox.setAttribute("aria-hidden", "false"); 877 if (lightboxClose) lightboxClose.focus(); 878 }); 879 }); 880 881 function closeLightbox() { 882 if (!lightbox || !lightboxImage) return; 883 lightbox.classList.remove("is-open"); 884 lightbox.setAttribute("aria-hidden", "true"); 885 lightboxImage.src = ""; 886 } 887 888 if (lightboxClose) { 889 lightboxClose.addEventListener("click", closeLightbox); 890 } 891 892 if (lightbox) { 893 lightbox.addEventListener("click", function (event) { 894 if (event.target === lightbox) closeLightbox(); 895 }); 896 } 897 898 document.addEventListener("keydown", function (event) { 899 if (event.key === "Escape") closeLightbox(); 900 }); 901 902 var videoTrigger = document.querySelector("[data-video-trigger]"); 903 if (videoTrigger) { 904 videoTrigger.addEventListener("click", function () { 905 var gallery = document.querySelector("#gallery"); 906 if (gallery) gallery.scrollIntoView({ behavior: "smooth", block: "start" }); 907 }); 908 } 909 910 var reveals = document.querySelectorAll(".reveal"); 911 if ("IntersectionObserver" in window) { 912 var observer = new IntersectionObserver( 913 function (entries) { 914 entries.forEach(function (entry) { 915 if (entry.isIntersecting) { 916 entry.target.classList.add("is-visible"); 917 observer.unobserve(entry.target); 918 } 919 }); 920 }, 921 { threshold: 0.12 } 922 ); 923 924 reveals.forEach(function (element) { 925 observer.observe(element); 926 }); 927 } else { 928 reveals.forEach(function (element) { 929 element.classList.add("is-visible"); 930 }); 931 } 932 933 document.querySelectorAll("[data-contact-form]").forEach(function (form) { 934 form.addEventListener("submit", async function (event) { 935 event.preventDefault(); 936 937 var button = form.querySelector("button"); 938 var status = form.querySelector("[data-form-status]"); 939 var originalText = button.textContent; 940 var formConfig = Object.assign({}, siteConfig.form || {}, siteContent.form || {}); 941 var data = {}; 942 943 new FormData(form).forEach(function (value, key) { 944 data[key] = value; 945 }); 946 data.page = window.location.href; 947 data.sentAt = new Date().toISOString(); 948 949 button.disabled = true; 950 button.textContent = (siteContent.ui && siteContent.ui.formSending) || "WYSYÅAM..."; 951 if (status) status.textContent = ""; 952 953 try { 954 if (formConfig.endpoint) { 955 var isGoogleScript = formConfig.endpoint.indexOf("script.google.com") !== -1; 956 var response = await fetch(formConfig.endpoint, { 957 method: "POST", 958 mode: isGoogleScript ? "no-cors" : "cors", 959 headers: { "Content-Type": "text/plain;charset=utf-8" }, 960 body: JSON.stringify(data) 961 }); 962 if (!isGoogleScript && !response.ok) throw new Error("Form endpoint error"); 963 } else if (formConfig.fallbackEmail) { 964 var subject = encodeURIComponent("Zapytanie ze strony - Teatr Baniek Mydlanych"); 965 var body = encodeURIComponent( 966 "ImiÄ i nazwisko: " + 967 (data.name || "") + 968 "\nE-mail: " + 969 (data.email || "") + 970 "\nTelefon: " + 971 (data.phone || "") + 972 "\n\nWiadomoÅÄ:\n" + 973 (data.message || "") 974 ); 975 window.location.href = "mailto:" + formConfig.fallbackEmail + "?subject=" + subject + "&body=" + body; 976 } 977 978 form.reset(); 979 button.textContent = formConfig.successMessage || "DZIÄKUJEMY!"; 980 if (status) status.textContent = formConfig.endpoint ? ((siteContent.ui && siteContent.ui.formSent) || "WiadomoÅÄ zostaÅa wysÅana.") : ((siteContent.ui && siteContent.ui.formMail) || "Otwieramy program pocztowy."); 981 } catch (error) { 982 button.textContent = formConfig.errorMessage || "BÅÄD WYSYÅKI"; 983 if (status) status.textContent = (siteContent.ui && siteContent.ui.formRetry) || "Spróbuj ponownie lub napisz do nas bezpoÅrednio."; 984 } finally { 985 setTimeout(function () { 986 button.disabled = false; 987 button.textContent = originalText; 988 }, 2600); 989 } 990 });
991 }); 992})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.