Colonie de vacances nature

Découvrez toutes nos colonies de vacances sur le thème des animaux, de l'environnement et de l'écologie. Votre enfant s'épanouira en France ou à l'étranger et découvrira des paysages à couper le souffle.

Une erreur s'est produite lors du traitement du gabarit.
The following has evaluated to null or missing:
==> Titre  [in template "20097#20123#40872926" at line 6, column 17]

----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----

----
FTL stack trace ("~" means nesting-related):
	- Failed at: ${Titre.getData()}  [in template "20097#20123#40872926" at line 6, column 15]
----
1<div id="first"> 
2  <div class="container custom-container"> 
3    <div class="row section"> 
4      <div class="col-md-8 p-3"> 
5        <div class="text-white"> 
6          <h1>${Titre.getData()}</h1> 
7          <p class="title-desc">${ZoneDeSaisie1x48.getData()}</p> 
8        </div> 
9      </div> 
10      <div id="background-image"></div> 
11      <div class="diagonal-divider"></div> 
12    </div> 
13  </div> 
14</div> 
15 
16<div class="container"> 
17  <#attempt> 
18    <#assign offerLocalService = serviceLocator.findService("com.totemia.commerce.type.offer.service.OfferLocalService")> 
19    <#assign produits = offerLocalService.searchProducts(Texteq55r.getData(), themeDisplay) > 
20    <div class="row justify-content-center align-items-center mt-4 mb-2"> 
21      <#if produits?size == 0> 
22        <div class="col"> 
23          <div class="d-flex text-center">  
24            <i class="fa fa-exclamation-triangle" style="margin-top: 3px; margin-right: 10px; color: orange;"></i> 
25            <h4>Catalogue en cours d'intégration pour cette catégorie</h4> 
26          </div> 
27           
28          <p class="text-center">N'hésitez pas à nous contacter par téléphone au  
29            <a href="tel:+33176381092">01 76 38 10 92</a>, par email à  
30            <a href="mailto:contact@totemia.com">contact@totemia.com</a>  
31            ou à demander un rappel via le formulaire ci-dessous pour bénéficier de nos conseils et vous inscrire sur liste d'attente. 
32          </p> 
33           
34          <div id="recalled-form"></div> 
35        </div> 
36         
37        <img src="https://totemia.com/documents/37901/0/sad_cat.gif/ce486981-2149-275f-3b95-74f21a62e914?t=1710349975702" 
38             alt="Sad gif" class="gif-responsive"> 
39         
40        <style> 
41          .gif-responsive { 
42            max-width: 100%; 
43            height: auto; 
44            display: block; 
45            margin: auto; 
46
47        </style> 
48      <#else> 
49        <span class="h3 text-center">Nos séjours coups de cœur </span> 
50        <i class="fa fa-heart text-secondary ml-2 mb-2"></i> 
51      </#if> 
52    </div> 
53     
54    <div class="row justify-content-center"> 
55      <#list produits as produit> 
56        <#assign productName = produit.getProductName()> 
57        <#assign url = "${produit.getUrl()}" > 
58        <#assign img = "${produit.getImg()}" > 
59        <#assign id = "${produit.getCPDefinitionId()}" > 
60        <#assign min = produit.getAgeMin() > 
61        <#assign max = produit.getAgeMax() > 
62        <#assign address = produit.getAddress() > 
63        <#assign cat = produit.getCatName() > 
64        <#assign price = produit.getMinPrice()> 
65        <#assign promo = produit.getMinPromoPrice()> 
66        <#assign isPromo = produit.getMinPrice() != produit.getMinPromoPrice() && produit.getMinPromoPrice() != "0"> 
67        <#assign csePrice = produit.getCSEPrice()!""> 
68        <#assign isCSE = csePrice?has_content && csePrice != "0"> 
69 
70        <%-- Nouveaux champs alignés avec ProductDisplayData --%> 
71        <#assign productTag   = produit.getProductTag()!""> 
72        <#assign isOfferFull  = produit.isOfferFull()!false> 
73        <#assign durations    = produit.getDurations()!""> 
74        <#assign activities   = produit.getActivities()![]> 
75        <#assign accommodations       = produit.getAccommodationTypeNames()![]> 
76        <#assign hasAccIncluded       = produit.isHasAccommodationIncluded()!false> 
77 
78        <div class="col-sm-6 col-xl-4 mb-3 hover-animate p-3 p-md-2"> 
79          <div class="card h-100 shadow w-100 card-clickable" 
80               data-url="${url}" 
81               style="cursor: pointer; border-radius: 20px;"> 
82 
83            <img loading="lazy" 
84                 class="card-img-top-new overflow-hidden gradient-overlay" 
85                 src="${img}" 
86                 alt="${productName}"/> 
87 
88            <%-- Badge produit (full / lowStock / bestSeller / newOffer) --%> 
89            <#if productTag?has_content> 
90              <div class="card-img-overlay-top text-left"> 
91                <span style="margin-right:2px;" class="badge ${productTag}"> 
92                  <#if productTag == "full"> 
93                    Complet 
94                  <#elseif productTag == "lowStock"> 
95                    Dernières places 
96                  <#elseif productTag == "bestSeller"> 
97                    Best-seller 
98                  <#elseif productTag == "newOffer"> 
99                    Nouveau 
100                  </#if> 
101                </span> 
102              </div> 
103            </#if> 
104 
105            <!-- Titre et référence --> 
106            <div class="px-3 pb-2 card-content"> 
107              <div class="d-flex flex-wrap" style="margin-bottom: 0.5rem;"> 
108                <span class="badge title-tag"> 
109                  ${min}-${max} ans 
110                </span> 
111                <#if durations?has_content> 
112                  <span class="badge title-tag"> 
113                    ${durations} 
114                  </span> 
115                </#if> 
116                <span class="badge title-tag"> 
117                  ${cat} 
118                </span> 
119              </div> 
120 
121              <h5 style="letter-spacing: 0;" 
122                  class="text-decoration-none text-dark mb-0"> 
123                ${productName} 
124              </h5> 
125 
126              <span class="card-title mb-0 text-decoration-none font-weight-normal text-dark mt-2" 
127                    style="letter-spacing: 0;"> 
128                ${address} 
129                <#if accommodations?has_content> 
130                  &bull; 
131                  <#if !hasAccIncluded> 
132                    Sans hébergement ou 
133                  </#if> 
134                  <#list accommodations as acc> 
135                    ${acc}<#if acc?has_next> ou </#if> 
136                  </#list> 
137                <#else> 
138                  &bull; Sans hébergement 
139                </#if> 
140 
141                <#if activities?has_content> 
142                  <br> 
143                  <span class="text-xs activities-container mt-2" 
144                        style="color:#91284D; text-transform: capitalize;"> 
145                    <#list activities as activity> 
146                      ${activity}<#if activity?has_next> &bull; </#if> 
147                    </#list> 
148                  </span> 
149                <#elseif produit.getShortDesc()?has_content> 
150                  <br> 
151                  <span class="text-xs activities-container mt-2" 
152                        style="color:#91284D;"> 
153                    ${produit.getShortDesc()} 
154                  </span> 
155                </#if> 
156              </span> 
157            </div> 
158 
159            <!-- Prix --> 
160            <div class="price-block px-3 pb-3 mt-auto"> 
161              <div class="d-flex align-items-center justify-content-between"> 
162                <div class="price-container"> 
163                  <#if isOfferFull> 
164                    <span class="text-danger font-weight-bold">Complet</span> 
165                  <#else> 
166                    <span class="card-text text-muted mb-0"> 
167                      À partir de 
168 
169                      <#if isPromo || isCSE> 
170                        <span style="text-decoration: line-through;" 
171                              class="text-dark text-sm ml-1"> 
172                          ${price}€ 
173                        </span> 
174 
175                        <#if isCSE> 
176                          <span class="h5 promo-price ml-2"> 
177                            ${csePrice}€ 
178                          </span> 
179                        <#else> 
180                          <span class="h5 promo-price ml-2"> 
181                            ${promo}€ 
182                          </span> 
183                        </#if> 
184                      <#else> 
185                        <span class="h5 ml-1"> 
186                          ${price}€ 
187                        </span> 
188                      </#if> 
189                    </span> 
190                  </#if> 
191                </div> 
192 
193                <a href="${url}" class="btn-discover"> 
194                  Voir l'offre 
195                </a> 
196              </div> 
197            </div> 
198 
199          </div> 
200        </div> 
201 
202      </#list> 
203    </div> 
204    <#recover> 
205  </#attempt> 
206 
207  <#if produits?size != 0> 
208    <div class="text-right d-flex align-items-center justify-content-end mb-4"> 
209      <a class="h3 text-secondary pr-3 mb-0" href="${Texteq55r.getData()}"> 
210        Découvrir tous les séjours ${Titre.getData()} 
211      </a> 
212      <i class="fa text-secondary fa-arrow-right"></i> 
213    </div> 
214  </#if> 
215   
216  <div class="article mt-5 p-1 p-md-3"> 
217    ${HTML1yo0.getData()} 
218  </div> 
219   
220  <#if Texte1szp?? && Texte1szp.getData()?has_content> 
221    <div class="row justify-content-center"> 
222      <h2 class="">FAQ ${Titre.getData()}</h2> 
223      <div class="accordion"> 
224        <#list Texte1szp.getData()?eval.faq as item> 
225          <div class="accordion-item" itemscope itemprop="mainEntity" 
226               itemtype="https://schema.org/Question"> 
227            <button aria-expanded="false"> 
228              <h3 itemprop="name" class="accordion-title h4 p-1">${item.question}</h3> 
229              <span class="icon" aria-hidden="true"></span> 
230            </button> 
231            <div itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer" 
232                 class="accordion-content"> 
233              <p itemprop="text" class="h5 p-4 font-weight-normal m-0">${item.answer}</p> 
234            </div> 
235          </div> 
236        </#list> 
237      </div> 
238    </div> 
239  </#if> 
240</div> 
241 
242<style> 
243  /* ==================== CARDS ==================== */ 
244 
245  .card h5 { 
246    display: -webkit-box; 
247    -webkit-line-clamp: 2; 
248    -webkit-box-orient: vertical; 
249    overflow: hidden; 
250    text-overflow: ellipsis; 
251    min-height: 2.4em; 
252    line-height: 1.2em; 
253
254 
255  .activities-container { 
256    display: -webkit-box; 
257    -webkit-line-clamp: 2; 
258    -webkit-box-orient: vertical; 
259    overflow: hidden; 
260    text-overflow: ellipsis; 
261    max-height: 2.8em; 
262    line-height: 1.4em; 
263    margin-bottom: 6px; 
264
265 
266  .col-sm-6.col-xl-4 { 
267    display: flex; 
268
269 
270  .card.h-100 { 
271    display: flex; 
272    flex-direction: column; 
273
274 
275  .card-content { 
276    flex: 1; 
277    display: flex; 
278    flex-direction: column; 
279
280 
281  .card-img-top-new { 
282    height: 190px; 
283    object-fit: cover; 
284    padding: 5px; 
285    border-radius: 20px; 
286
287 
288  .card-img-overlay-top { 
289    position: absolute; 
290    top: 10px; 
291    left: 10px; 
292    z-index: 10; 
293
294 
295  /* Badges produit (alignés avec la JSP) */ 
296  .badge.full      { background: #ffab96; color: red; } 
297  .badge.lowStock  { background: #F7C32E; color: #450A00; } 
298  .badge.bestSeller{ background: #00EADF; color: #162F70; } 
299  .badge.newOffer  { background: #162F70; color: #00EADF; } 
300 
301  .price-block { 
302    margin-top: auto; 
303    padding: 5px 0px 0px 0px; 
304    background-color: #ffffff; 
305    border-radius: 20px; 
306
307 
308  .price-block .d-flex { 
309    align-items: center; 
310    justify-content: space-between; 
311    gap: 15px; 
312
313 
314  .price-container { flex: 1; } 
315 
316  .promo-price { 
317    color: #dc3545; 
318    font-weight: 700; 
319
320 
321  .btn-discover { 
322    flex-shrink: 0; 
323    display: inline-flex; 
324    align-items: center; 
325    justify-content: center; 
326    padding: 12px 8px; 
327    border-radius: 16px; 
328    background-color: #0C41B8; 
329    color: white; 
330    font-size: 16px; 
331    font-weight: 600; 
332    text-decoration: none; 
333    transition: background-color 0.3s ease, transform 0.2s ease; 
334    white-space: nowrap; 
335
336 
337  .btn-discover:hover { 
338    background-color: white; 
339    border: 1px solid #0C41B8; 
340    color: #0C41B8; 
341    transform: translateY(-2px); 
342    text-decoration: none; 
343
344 
345  .btn-discover:active { transform: translateY(0); } 
346 
347  .title-tag { 
348    background: white; 
349    color: #91284D; 
350    padding: 4px 5px; 
351    border: 1px solid #91284D; 
352    font-size: 10px; 
353    margin-right: 4px; 
354    margin-bottom: 4px; 
355
356 
357  @media (max-width: 767px) { 
358    .badge { 
359      font-size: 60%; 
360      white-space: normal; 
361
362
363 
364  /* ==================== STYLES EXISTANTS ==================== */ 
365 
366  .article img { 
367    max-width: -webkit-fill-available; 
368    object-fit: cover; 
369
370 
371  #first { 
372    background: #1e2c63; 
373    position: relative; 
374    overflow: hidden; 
375
376 
377  <#if (Image29wz.getData())?? && Image29wz.getData() != ""> 
378  <#assign backgroundImage = '${Image29wz.getData()}'> 
379  <#assign extraStyle = '-4%'> 
380  <#else> 
381  <#assign backgroundImage = 'https://totemia.com/documents/37901/0/homepage_page_cat.jpg/0fb81309-6f8e-91af-aafe-4c6e44de0ec2?t=1707217228005'> 
382  <#assign extraStyle = '0%'> 
383  </#if> 
384 
385  #background-image { 
386    background: url('${backgroundImage}'); 
387    background-size: cover; 
388    background-position: right; 
389    position: absolute; 
390    top: 0; 
391    right: ${extraStyle}; 
392    height: 100%; 
393    width: 30%; 
394
395 
396  .section { color: white; } 
397 
398  .diagonal-divider::before { 
399    content: ''; 
400    position: absolute; 
401    top: 0; 
402    right: 25%; 
403    width: 10%; 
404    height: 100%; 
405    background-color: #1e2c63; 
406    transform: skew(-15deg); 
407    z-index: 1; 
408
409 
410  .title-desc { margin-bottom: 0 !important; } 
411 
412  @media (max-width: 767.98px) { 
413    .diagonal-divider { display: none; } 
414    #background-image { position: relative; width: 100%; } 
415    .title-desc { font-size: 0.7rem; } 
416    .section div { text-align: center !important; } 
417
418 
419  .breadcrumb { margin: 0; padding-bottom: 0; } 
420 
421  /* ==================== ACCORDION FAQ ==================== */ 
422 
423  .accordion .accordion-item { border-bottom: 1px solid #212529; } 
424  .accordion .accordion-item button[aria-expanded=true] { border-bottom: 1px solid #212529; } 
425 
426  .accordion button { 
427    position: relative; 
428    display: block; 
429    text-align: left; 
430    width: 100%; 
431    padding: 1em 0; 
432    font-size: 1.15rem; 
433    font-weight: 400; 
434    border: none; 
435    background: none; 
436    outline: none; 
437
438 
439  .accordion button:hover, 
440  .accordion button:focus { cursor: pointer; color: #e83e8c; } 
441 
442  .accordion button:hover::after, 
443  .accordion button:focus::after { cursor: pointer; color: #e83e8c; border: 1px solid #e83e8c; } 
444 
445  .accordion button .accordion-title { padding: 1em 1.5em 1em 0; } 
446 
447  .accordion button .icon { 
448    display: inline-block; 
449    position: absolute; 
450    top: 18px; 
451    right: 0; 
452    width: 22px; 
453    height: 22px; 
454    border: 1px solid; 
455    border-radius: 22px; 
456
457 
458  .accordion button .icon::before { 
459    display: block; 
460    position: absolute; 
461    content: ""; 
462    top: 9px; 
463    left: 5px; 
464    width: 10px; 
465    height: 2px; 
466    background: currentColor; 
467
468 
469  .accordion button .icon::after { 
470    display: block; 
471    position: absolute; 
472    content: ""; 
473    top: 5px; 
474    left: 9px; 
475    width: 2px; 
476    height: 10px; 
477    background: currentColor; 
478
479 
480  .accordion button[aria-expanded=true] { color: #212529; } 
481  .accordion button[aria-expanded=true] .icon::after { width: 0; } 
482 
483  .accordion button[aria-expanded=true] + .accordion-content { 
484    opacity: 1; 
485    max-height: 200em; 
486    transition: all 200ms linear; 
487    will-change: opacity, max-height; 
488
489 
490  .accordion .accordion-content { 
491    opacity: 0; 
492    max-height: 0; 
493    overflow: hidden; 
494    transition: opacity 200ms linear, max-height 200ms linear; 
495    will-change: opacity, max-height; 
496
497 
498  .accordion .accordion-content p { font-size: 1rem; margin: 2em 0; } 
499</style> 
500 
501<script> 
502  // Card clickable 
503  document.addEventListener('DOMContentLoaded', function() { 
504    const cards = document.querySelectorAll('.card-clickable'); 
505    cards.forEach(function(card) { 
506      card.addEventListener('click', function(e) { 
507        const closestLink = e.target.closest('a, button'); 
508        if (closestLink) return; 
509        const url = this.getAttribute('data-url'); 
510        if (url) window.location.href = url; 
511      }); 
512    }); 
513  }); 
514 
515  // Accordion FAQ 
516  let items = document.querySelectorAll(".accordion button"); 
517 
518  function toggleAccordion() { 
519    const itemToggle = this.getAttribute("aria-expanded"); 
520    for (i = 0; i < items.length; i++) { 
521      items[i].setAttribute("aria-expanded", "false"); 
522
523    if (itemToggle == "false") { 
524      this.setAttribute("aria-expanded", "true"); 
525
526
527 
528  items.forEach((item) => item.addEventListener("click", toggleAccordion)); 
529 
530  // Trustpilot (si utilisé) 
531  var element = document.getElementsByClassName("trustpilot-widget"); 
532  for(var i=0; i<element.length; i++) { 
533    if (window.Trustpilot) window.Trustpilot.loadFromElement(element[i]); 
534
535 
536  // HubSpot form 
537  function onVariableExist(varName, callback) { 
538    const checkExist = setInterval(() => { 
539      if (typeof window[varName] !== 'undefined') { 
540        clearInterval(checkExist); 
541        callback(window[varName]); 
542
543    }, 100); 
544
545 
546  onVariableExist('hbspt', function(value) { 
547    hbspt.forms.create({ 
548      region: "na1", 
549      portalId: "8587022", 
550      formId: "dedc835c-9a30-443a-9029-77321fc48d33", 
551      target: '#recalled-form', 
552    }); 
553  }); 
554</script> 

Parcourez nos colonies de vacances classées par thème :