Adopt recent changes, migrate product detail page

This commit is contained in:
Björn Fromme
2021-12-20 16:00:41 +01:00
parent aef0f3df68
commit 34d36a68d9
28 changed files with 618 additions and 582 deletions
+8
View File
@@ -63,11 +63,13 @@ host('production')
->forwardAgent()
->multiplexing()
->set('deploy_path', '/home/www/p546128/html/{{application}}')
->set('buspronet_path', '/home/www/p546128/html/kuschick/buspronet/buspronet')
->set('bin/php', '/usr/local/bin/php')
->set('http_user', 'p546128')
->set('bin/composer', '/usr/local/bin/composer')
->set('rsync_src', __DIR__)
->set('rsync', $rsyncOptions)
->set('bin/cachetool', 'cachetool-7.0.0.phar')
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{release_path}}/public/ --web-url=https://www.ep-reisen.de')
;
@@ -86,6 +88,7 @@ host('staging')
->set('bin/composer', '/usr/local/bin/composer')
->set('rsync_src', __DIR__)
->set('rsync', $rsyncOptions)
->set('bin/cachetool', 'cachetool-7.0.0.phar')
->set('cachetool_args', '--web=SymfonyHttpClient --web-path={{release_path}}/public/ --web-url=https://staging.ep-reisen.de --web-basic-auth=ep:reisen')
->set('shared_files', $sharedFilesStaging)
;
@@ -102,6 +105,7 @@ task('deploy', [
'typo3:language:update',
'typo3:cache:flush',
'deploy:symlink',
'deploy:buspronet:symlink',
'deploy:unlock',
'cachetool:clear:opcache',
'cleanup',
@@ -125,6 +129,10 @@ task('deploy_staging', [
'cleanup',
]);
task('deploy:buspronet:symlink', function () {
run('ln -s {{buspronet_path}} {{release_path}}/public/buchung');
});
task ('deploy:assets:build', function () {
runLocally('npm i && npm run build');
});
@@ -11,12 +11,6 @@ page {
main = typo3_encore:EpEventsConfig:main
}
includeJS {
remarketing = https://www.googleadservices.com/pagead/conversion_async.js
remarketing.external = 1
remarketing.disableCompression = 1
}
includeJSFooter {
main = typo3_encore:EpEventsConfig:main
}
@@ -73,6 +67,17 @@ page {
}
}
headerData.998 = TEXT
headerData.998.value (
<!-- Google Tag Manager -->
<script type="text/plain" data-cookiefirst-category="functional">(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','{$plugin.tx_epevents.settings.googleTagManagerId}');</script>
<!-- End Google Tag Manager -->
)
headerData.998.stdWrap.if.isTrue = {$plugin.tx_epevents.settings.googleTagManagerId}
headerData.999 = TEXT
headerData.999 {
@@ -0,0 +1,10 @@
.cookiefirst {
h2 {
@extend .headline;
@extend .headline--primary;
}
h3 {
@extend .headline;
@extend .headline--secondary;
}
}
@@ -38,3 +38,4 @@ $output-bourbon-deprecation-warnings: false;
@import "paginator";
@import "news";
@import "datepicker";
@import "cookiefirst";
@@ -41,6 +41,7 @@
class="page-footer__link page-footer__link--legal">{f:translate(key: 'tx_epevents.label.legal_notice', extensionName: 'ep_events') -> f:format.raw()}</f:link.typolink>
<f:link.typolink parameter="{settings.termsPageUid}" title="AGB"
class="page-footer__link page-footer__link--legal">{f:translate(key: 'tx_epevents.label.terms', extensionName: 'ep_events') -> f:format.raw()}</f:link.typolink>
<a class="page-footer__link page-footer__link--legal" href="#" onclick="cookiefirst_show_settings(); return false">Cookie-Einstellungen</a>
</span>
</div>
</div>
@@ -1,45 +0,0 @@
<?php
namespace EP\EpProducts\Controller;
/***************************************************************
*
* Copyright notice
*
* (c) 2018 Björn Fromme <[email protected]>, dreipunktnull
*
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class PasswordController extends ActionController
{
public function indexAction()
{
// Conflicting argument 'id' needs to be replaced with 'bpn_id'!
$this->view->assignMultiple([
'bpnDbPassword' => GeneralUtility::_GET('db_passwort'),
'bpnId' => GeneralUtility::_GET('bpn_id'),
]);
}
}
@@ -28,6 +28,7 @@ namespace EP\EpProducts\Utility;
***************************************************************/
use Symfony\Component\OptionsResolver\OptionsResolver;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class BookingUrlUtility
@@ -148,8 +149,13 @@ class BookingUrlUtility
* @param array $query
* @return string
*/
protected static function buildUrl(array $query)
protected static function buildUrl(array $query): string
{
return static::URL_BASE . '?' . http_build_query($query, '', '&');
$pageId = $GLOBALS['TSFE']->id;
$baseUrl = GeneralUtility::makeInstance(SiteFinder::class)
->getSiteByPageId($pageId)
->getBase();
return $baseUrl . '/buchung/maske_buchung.php?' . http_build_query($query, '', '&');
}
}
@@ -167,12 +167,6 @@ call_user_func(function () {
'Merkliste'
);
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
'EP.EpProducts',
'password',
'Passwort BusPro'
);
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_product_detail'] = 'pi_flexform';
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
'epproducts_product_detail', 'FILE:EXT:ep_products/Configuration/FlexForms/flexform_product_detail.xml'
@@ -267,14 +267,6 @@ $boot = function () {
]
);
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'EP.ep_products',
'password',
[
'Password' => 'index',
]
);
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'EP.ep_products',
'ajax',
@@ -72,6 +72,15 @@ call_user_func(function() {
'eval' => 'trim'
]
],
'tx_eptheme_navitemclass' => [
'exclude' => 0,
'label' => 'CSS Klasse(n) für Topnavigation',
'config' => [
'type' => 'input',
'size' => 30,
'eval' => 'trim'
]
],
'tx_eptheme_slides' => [
'exclude' => 0,
'label' => 'Slides',
@@ -118,7 +127,7 @@ call_user_func(function() {
'pages',
'--div--;Kontext,
tx_eptheme_context_pacode,tx_eptheme_context_country,tx_eptheme_context_region,
tx_eptheme_hide_searchbar,tx_eptheme_new_tab,tx_eptheme_bodyclass,
tx_eptheme_hide_searchbar,tx_eptheme_new_tab,tx_eptheme_bodyclass,tx_eptheme_navitemclass,
--div--;Slider,
tx_eptheme_slides,
--div--;Badge,
@@ -1,4 +1,9 @@
tt_content.nlform =< lib.contentElement
tt_content.nlform {
templateName = NewsletterForm
variables {
formUrl = TEXT
formUrl.wrap = |/buchung/anmeldung_news.php
formUrl.data = site:base
}
}
@@ -133,6 +133,18 @@ page {
settings < plugin.tx_eptheme.settings
}
headerData.998 = TEXT
headerData.998.value (
<!-- Google Tag Manager -->
<script type="text/plain" data-cookiefirst-category="functional">(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','{$plugin.tx_eptheme.settings.googleTagManagerId}');</script>
<!-- End Google Tag Manager -->
)
headerData.998.stdWrap.if.isTrue = {$plugin.tx_eptheme.settings.googleTagManagerId}
headerData.999 = TEXT
headerData.999 {
wrap = <script src="https://consent.cookiefirst.com/banner.js" data-cookiefirst-key="|"></script>
@@ -5,7 +5,10 @@ export default class extends Controller {
static values = { props: Object }
connect() {
fbq('track', 'ViewContent', this.propsValue)
const CF = window.CookieFirst
if (CF && null !== CF.consent && true === CF.consent.advertising) {
fbq('track', 'ViewContent', this.propsValue)
}
}
}
@@ -3,29 +3,39 @@ import { useDispatch } from 'stimulus-use'
export default class extends Controller {
static targets = [ 'tab', 'button' ]
static classes = [ 'buttonActive' ]
static values = { scroll: Boolean }
static targets = [ 'tab', 'pulldown', 'label' ]
static values = { activeTab: String }
initialize() {
useDispatch(this)
}
connect() {
this.activeTabValue = this.tabTargets[0].dataset.tab
}
togglePulldown() {
this.pulldownTarget.classList.toggle('hidden')
}
select(e) {
e.preventDefault()
let selectedTab = e.currentTarget.dataset.tab
this.buttonTargets.forEach(element => {
let currentTab = element.dataset.tab
element.classList.toggle('button--active', selectedTab === currentTab)
})
this.tabTargets.forEach(element => {
let currentTab = element.dataset.tab
element.classList.toggle('hidden', selectedTab !== currentTab)
})
if (true === this.scrollValue) {
this.element.scrollIntoView({ block: 'start', behavior: 'smooth' })
}
this.activeTabValue = selectedTab
this.pulldownTarget.classList.toggle('hidden', true)
this.dispatch('selected', selectedTab)
}
activeTabValueChanged() {
let activeTab = this.activeTabValue
this.tabTargets.forEach(element => {
let currentTab = element.dataset.tab
element.classList.toggle('hidden', activeTab !== currentTab)
if (activeTab === currentTab) {
this.labelTarget.innerText = element.dataset.label
}
})
}
}
@@ -101,7 +101,7 @@
/>
</div>
<div class="grid lg:grid-cols-2 gap-4 p-2">
<table class="table table-condensed text-sm mb-0">
<table class="text-sm mb-0">
<tbody>
<tr>
<th class="w-1/5">Zimmer</th>
@@ -132,9 +132,9 @@
</tbody>
</table>
<textarea rows="2" class="border-gray-400 focus:border-gray-800 ring-0 focus:ring-0 mt-1 w-full"
v-model="participant.data.accommodationRequest"
v-model="participant.data.additionRequest"
@change="dirty = true"
placeholder="Anmerkungen"
placeholder="Sonstiges (z. B. Allergien, Verleihgrößen)"
/>
</div>
</template>
@@ -1,52 +1,54 @@
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
{city.name}
<div class="space-y-2">
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
{city.name}
</div>
</f:then>
<f:else>
<h2>
Ort
</h2>
</f:else>
</f:if>
{city.description -> f:format.html()}
</div>
<f:if condition="{city.images -> f:count()} > 0">
<f:render partial="ImageGallery" arguments="{images: city.images, id: 'city-{city.uid}', thumbnails: 1}"/>
</f:if>
<f:if condition="{city.party}">
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
Party
</div>
</f:then>
<f:else>
<h2>
Party
</h2>
</f:else>
</f:if>
{city.party -> f:format.html()}
</div>
</f:then>
<f:else>
<h2>
Ort
</h2>
</f:else>
</f:if>
<div class="city-details city-details--description" data-rte-content>
{city.description -> f:format.html()}
</f:if>
<f:if condition="{city.leisure}">
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
Freizeitangebot
</div>
</f:then>
<f:else>
<h2>
Freizeitangebot
</h2>
</f:else>
</f:if>
{city.leisure -> f:format.html()}
</div>
</f:if>
</div>
<f:if condition="{city.images -> f:count()} > 0">
<f:render partial="ImageGallery" arguments="{images: city.images, id: 'city-{city.uid}', thumbnails: 1}"/>
</f:if>
<f:if condition="{city.party}">
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
Party
</div>
</f:then>
<f:else>
<h2>
Party
</h2>
</f:else>
</f:if>
<div class="city-details city-details--party" data-rte-content>
{city.party -> f:format.html()}
</div>
</f:if>
<f:if condition="{city.leisure}">
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
Freizeitangebot
</div>
</f:then>
<f:else>
<h2>
Freizeitangebot
</h2>
</f:else>
</f:if>
<div class="city-details city-details--leisure" data-rte-content>
{city.leisure -> f:format.html()}
</div>
</f:if>
@@ -1,17 +0,0 @@
{namespace v=FluidTYPO3\Vhs\ViewHelpers}
<!-- Facebook Pixel Code -->
<script>
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
document,'script','https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '1669863793235509');
fbq('track', 'PageView');
<f:if condition="{viewContent.productUid} && {viewContent.nameInternal}">
fbq('track', 'ViewContent', { content_ids: [ {viewContent.productUid} ], content_name: '{viewContent.nameInternal -> f:format.htmlentitiesDecode()}', content_type: 'product' });
</f:if>
</script>
<noscript><img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=1669863793235509&ev=PageView&noscript=1"/></noscript>
<!-- End Facebook Pixel Code -->
@@ -129,10 +129,10 @@
</a>
</li>
<li>
<a href="{f:uri.typolink(parameter: settings.imageCreditsPageUid)}"
<a href="#"
class="text-white"
title="AGB">
Bildrechte
onclick="cookiefirst_show_settings(); return false">
Cookie-Einstellungen
</a>
</li>
</ul>
@@ -1,5 +0,0 @@
<f:if condition="{googleTagManagerId}">
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id={googleTagManagerId}" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
</f:if>
@@ -1,129 +1,134 @@
{namespace ep=EP\EpTheme\ViewHelpers}
<f:variable name="hotelTitle">{hotel.name -> f:format.raw()}{f:if(condition: hotel.categoryLabel, then: ' ({hotel.categoryLabel -> f:format.raw()})')}</f:variable>
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
{hotelTitle}</div>
</f:then>
<f:else>
<h1>
{hotelTitle}
</h1>
</f:else>
</f:if>
<div class="hotel-details hotel-details--description" data-rte-content>
{hotel.description -> f:format.html()}
</div>
<f:if condition="{teasers}">
<f:then>
<a id="teasers" class="anchor"></a>
<div class="splide"
data-controller="slider"
data-slider-preset-value="teasers">
<div class="splide__track">
<ul class="splide__list">
<f:for each="{teasers}" as="teaser">
<li class="splide__slide">
<f:render partial="Product/Teaser" section="Teaser" arguments="{teaser: teaser}"/>
</li>
</f:for>
</ul>
</div>
</div>
<f:if condition="{settings.showMoreLink}">
<p class="text-right">
<f:link.action pageUid="{settings.defaultStaticSearchPageUid}" class="button"
action="staticresult" controller="Search"
arguments="{encodedFilterSettings: '{filterSettings -> ep:filterSettingsEncoder()}'}"
additionalAttributes="{rel: 'nofollow'}">
Alle anzeigen
</f:link.action>
</p>
<div class="space-y-2">
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
{hotelTitle}
</div>
</f:then>
<f:else>
<h1>
{hotelTitle}
</h1>
</f:else>
</f:if>
</f:then>
<f:else>
<f:if condition="{showNonBookableHint}">
<div class="alert alert-info">
<p>Gerade noch kein Angebot buchbar? Dann frag doch schon mal an: <f:link.typolink parameter="{settings.defaultContactFormPageUid}">hier geht es zum Kontaktformular</f:link.typolink>.</p>
</div>
</f:if>
</f:else>
</f:if>
<f:if condition="{hotel.images -> f:count()} > 0">
<f:render partial="ImageGallery" arguments="{images: hotel.images, id: 'hotel-{hotel.uid}', thumbnails: 1}"/>
</f:if>
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
Ausstattung
</div>
</f:then>
<f:else>
<h2>
Ausstattung
</h2>
</f:else>
</f:if>
<div class="hotel-details hotel-details--features" data-rte-content>
{hotel.features -> f:format.html()}
</div>
<f:if condition="{hotel.isApartment}">
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
Apartments
</div>
</f:then>
<f:else>
<h2>Apartments</h2>
</f:else>
</f:if>
</f:if>
<f:if condition="{hotel.isHolidayFlat}">
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
Ferienwohnungen
</div>
</f:then>
<f:else>
<h2>
Ferienwohnungen
</h2>
</f:else>
</f:if>
</f:if>
<f:if condition="{hotel.isOther}">
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
Zimmerarten
</div>
</f:then>
<f:else>
<h2>
Zimmerarten
</h2>
</f:else>
</f:if>
</f:if>
<div class="hotel-details hotel-details--roomtypes" data-rte-content>
{hotel.roomTypes -> f:format.html()}
</div>
<f:if condition="{hotel.additionalInformation}">
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
Zusatzinformationen
</div>
</f:then>
<f:else>
<h2>
Zusatzinformationen
</h2>
</f:else>
</f:if>
<div class="hotel-details hotel-details--additional" data-rte-content>
{hotel.additionalInformation -> f:format.html()}
{hotel.description -> f:format.html()}
</div>
</f:if>
<f:if condition="{teasers}">
<f:then>
<a id="teasers" class="anchor"></a>
<div class="splide"
data-controller="slider"
data-slider-preset-value="teasers">
<div class="splide__track">
<ul class="splide__list">
<f:for each="{teasers}" as="teaser">
<li class="splide__slide">
<f:render partial="Product/Teaser" section="Teaser" arguments="{teaser: teaser}"/>
</li>
</f:for>
</ul>
</div>
</div>
<f:if condition="{settings.showMoreLink}">
<p class="text-right">
<f:link.action pageUid="{settings.defaultStaticSearchPageUid}" class="button"
action="staticresult" controller="Search"
arguments="{encodedFilterSettings: '{filterSettings -> ep:filterSettingsEncoder()}'}"
additionalAttributes="{rel: 'nofollow'}">
Alle anzeigen
</f:link.action>
</p>
</f:if>
</f:then>
<f:else>
<f:if condition="{showNonBookableHint}">
<div class="alert alert-info">
<p>Gerade noch kein Angebot buchbar? Dann frag doch schon mal an: <f:link.typolink parameter="{settings.defaultContactFormPageUid}">hier geht es zum Kontaktformular</f:link.typolink>.</p>
</div>
</f:if>
</f:else>
</f:if>
<f:if condition="{hotel.images -> f:count()} > 0">
<f:render partial="ImageGallery" arguments="{images: hotel.images, id: 'hotel-{hotel.uid}', thumbnails: 1}"/>
</f:if>
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
Ausstattung
</div>
</f:then>
<f:else>
<h2>
Ausstattung
</h2>
</f:else>
</f:if>
{hotel.features -> f:format.html()}
</div>
<f:if condition="{hotel.isApartment} || hotel.isHolidayFlat || hotel.isOther">
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<f:if condition="{hotel.isApartment}">
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
Apartments
</div>
</f:then>
<f:else>
<h2>Apartments</h2>
</f:else>
</f:if>
</f:if>
<f:if condition="{hotel.isHolidayFlat}">
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
Ferienwohnungen
</div>
</f:then>
<f:else>
<h2>
Ferienwohnungen
</h2>
</f:else>
</f:if>
</f:if>
<f:if condition="{hotel.isOther}">
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
Zimmerarten
</div>
</f:then>
<f:else>
<h2>
Zimmerarten
</h2>
</f:else>
</f:if>
</f:if>
{hotel.roomTypes -> f:format.html()}
</div>
</f:if>
<f:if condition="{hotel.additionalInformation}">
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
Zusatzinformationen
</div>
</f:then>
<f:else>
<h2>
Zusatzinformationen
</h2>
</f:else>
</f:if>
{hotel.additionalInformation -> f:format.html()}
</div>
</f:if>
</div>
@@ -1,17 +1,16 @@
<f:if condition="{bars}">
<div class="headerbar">
Anreise
</div>
</f:if>
<div data-rte-content>
<h2>Eigenanreise</h2>
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<h3>
Eigenanreise
</h3>
{journey.byCar -> f:format.html()}
<f:if condition="{journey.image}">
<img src="{f:uri.image(image: journey.image, width: '770', height: '430c+100')}"
alt="{journey.image.alternative}" title="{journey.image.title}">
</f:if>
<f:if condition="{journey.byBus}">
<h2>Busanreise</h2>
<h3>
Busanreise
</h3>
{journey.byBus -> f:format.html()}
</f:if>
</div>
@@ -1,132 +1,132 @@
{namespace ep=EP\EpTheme\ViewHelpers}
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
{region.name -> f:format.raw()}
</div>
</f:then>
<f:else>
<h2 class="headline--has-subline">
<f:if condition="{region.season} == 's'">
<f:then>
<span class="subline">Urlaub im</span> Gebiet {region.name -> f:format.raw()}
</f:then>
<f:else>
<span class="subline">Skiurlaub im</span> Skigebiet {region.name -> f:format.raw()}
</f:else>
</f:if>
</h2>
</f:else>
</f:if>
<div class="region-details region-details--ski-area" data-rte-content>
<div class="grid grid-cols-3 gap-4 bg-gray-50 p-2 mb-4">
<div class="flex items-center space-x-2"
data-cooltipz-dir="top-left" aria-label="Pisten" role="tooltip">
<svg class="w-4 h-4 md:w-6 md:h-6">
<use href="#icon-ski"></use>
</svg>
<span class="text-sm md:text-base">
{region.length}
</span>
</div>
<div class="flex items-center space-x-2"
data-cooltipz-dir="top-left" aria-label="Höhe" role="tooltip">
<svg class="w-4 h-4 md:w-6 md:h-6">
<use href="#icon-mountain"></use>
</svg>
<span class="text-sm md:text-base">
{region.height}
</span>
</div>
<f:if condition="{region.lifts}">
<div class="space-y-2">
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
{region.name -> f:format.raw()}
</div>
</f:then>
<f:else>
<h2 class="headline--has-subline">
<f:if condition="{region.season} == 's'">
<f:then>
<span class="subline">Urlaub im</span> Gebiet {region.name -> f:format.raw()}
</f:then>
<f:else>
<span class="subline">Skiurlaub im</span> Skigebiet {region.name -> f:format.raw()}
</f:else>
</f:if>
</h2>
</f:else>
</f:if>
<div class="grid grid-cols-3 gap-4 bg-gray-50 p-2 mb-4">
<div class="flex items-center space-x-2"
data-cooltipz-dir="top-left" aria-label="Lifte" role="tooltip">
data-cooltipz-dir="top-left" aria-label="Pisten" role="tooltip">
<svg class="w-4 h-4 md:w-6 md:h-6">
<use href="#icon-lift"></use>
<use href="#icon-ski"></use>
</svg>
<span class="text-sm md:text-base">
{region.lifts}
{region.length}
</span>
</div>
<div class="flex items-center space-x-2"
data-cooltipz-dir="top-left" aria-label="Höhe" role="tooltip">
<svg class="w-4 h-4 md:w-6 md:h-6">
<use href="#icon-mountain"></use>
</svg>
<span class="text-sm md:text-base">
{region.height}
</span>
</div>
<f:if condition="{region.lifts}">
<div class="flex items-center space-x-2"
data-cooltipz-dir="top-left" aria-label="Lifte" role="tooltip">
<svg class="w-4 h-4 md:w-6 md:h-6">
<use href="#icon-lift"></use>
</svg>
<span class="text-sm md:text-base">
{region.lifts}
</span>
</div>
</f:if>
</div>
{region.skiArea -> f:format.html()}
<f:if condition="{teasers}">
<f:then>
<a id="teasers" class="anchor"></a>
<div class="splide"
data-controller="slider"
data-slider-preset-value="teasersEmbedded">
<div class="splide__track">
<ul class="splide__list">
<f:for each="{teasers}" as="teaser">
<li class="splide__slide">
<f:render partial="Product/Teaser" section="Teaser" arguments="{teaser: teaser}"/>
</li>
</f:for>
</ul>
</div>
</div>
<f:if condition="{settings.showMoreLink}">
<p class="text-right">
<f:link.action pageUid="{settings.defaultStaticSearchPageUid}" class="button"
action="staticresult" controller="Search"
arguments="{encodedFilterSettings: '{filterSettings -> ep:filterSettingsEncoder()}'}"
additionalAttributes="{rel: 'nofollow'}">
Alle anzeigen
</f:link.action>
</p>
</f:if>
</f:then>
<f:else>
<f:if condition="{region.images -> f:count()} > 0">
<f:render partial="ImageGallery" arguments="{images: region.images, id: 'region-{region.uid}', thumbnails: 1}"/>
</f:if>
</f:else>
</f:if>
<f:if condition="{region.skiAreaExtended}">{region.skiAreaExtended -> f:format.html()}</f:if>
</div>
<f:if condition="{teasers}">
<f:if condition="{region.images -> f:count()} > 0">
<f:render partial="ImageGallery" arguments="{images: region.images, id: 'region-{region.uid}', thumbnails: 1}"/>
</f:if>
</f:if>
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
{f:if(condition: '{region.season} == "w"', then: 'Skipass', else: 'Highlights')} {region.name}
</div>
</f:then>
<f:else>
<h3>
{f:if(condition: '{region.season} == "w"', then: 'Skipass', else: 'Highlights')} {region.name}
</h3>
</f:else>
</f:if>
<f:if condition="{region.skiPass}">
{region.skiPass -> f:format.html()}
</f:if>
<f:if condition="{region.description}">
{region.description -> f:format.html()}
</f:if>
</div>
{region.skiArea -> f:format.html()}
<f:if condition="{teasers}">
<f:then>
<a id="teasers" class="anchor"></a>
<div class="splide"
data-controller="slider"
data-slider-preset-value="teasersEmbedded">
<div class="splide__track">
<ul class="splide__list">
<f:for each="{teasers}" as="teaser">
<li class="splide__slide">
<f:render partial="Product/Teaser" section="Teaser" arguments="{teaser: teaser}"/>
</li>
</f:for>
</ul>
</div>
</div>
<f:if condition="{settings.showMoreLink}">
<p class="text-right">
<f:link.action pageUid="{settings.defaultStaticSearchPageUid}" class="button"
action="staticresult" controller="Search"
arguments="{encodedFilterSettings: '{filterSettings -> ep:filterSettingsEncoder()}'}"
additionalAttributes="{rel: 'nofollow'}">
Alle anzeigen
</f:link.action>
</p>
<f:if condition="{region.news}">
<div class="even:bg-ep-primary-bg p-4" data-rte-content>
<f:if condition="{bars}">
<f:then>
<div class="headline--3 headline--underlined">
Aktuelles {region.name}
</div>
</f:then>
<f:else>
<h2>
Aktuelles {region.name}
</h2>
</f:else>
</f:if>
</f:then>
<f:else>
<f:if condition="{region.images -> f:count()} > 0">
<f:render partial="ImageGallery" arguments="{images: region.images, id: 'region-{region.uid}', thumbnails: 1}"/>
</f:if>
</f:else>
</f:if>
<f:if condition="{region.skiAreaExtended}">{region.skiAreaExtended -> f:format.html()}</f:if>
</div>
<f:if condition="{teasers}">
<f:if condition="{region.images -> f:count()} > 0">
<f:render partial="ImageGallery" arguments="{images: region.images, id: 'region-{region.uid}', thumbnails: 1}"/>
</f:if>
</f:if>
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
{f:if(condition: '{region.season} == "w"', then: 'Skipass', else: 'Highlights')} {region.name}
{region.news -> f:format.html()}
</div>
</f:then>
<f:else>
<h3>
{f:if(condition: '{region.season} == "w"', then: 'Skipass', else: 'Highlights')} {region.name}
</h3>
</f:else>
</f:if>
<f:if condition="{region.skiPass}">
<div class="region-details region-details--skipass" data-rte-content>
{region.skiPass -> f:format.html()}
</div>
</f:if>
<f:if condition="{region.description}">
<div class="region-details region-details--description" data-rte-content>
{region.description -> f:format.html()}
</div>
</f:if>
<f:if condition="{region.news}">
<f:if condition="{bars}">
<f:then>
<div class="headerbar">
Aktuelles {region.name}
</div>
</f:then>
<f:else>
<h2>
Aktuelles {region.name}
</h2>
</f:else>
</f:if>
<div class="region-details region-details--news" data-rte-content>
{region.news -> f:format.html()}
</div>
</f:if>
</div>
@@ -11,7 +11,7 @@
<svg class="w-5 h-5"><use href="#icon-home"/></svg>
</f:link.typolink>
<f:for each="{topnav}" as="menuitem">
<a class="block flex flex-grow h-8 justify-center items-center uppercase text-sm leading-none text-white hover:text-white focus:text-white hover:bg-ep-secondary{f:if(condition: '{menuitem.active} or {menuitem.data.uid} == {settings.forceActiveTopnavUid}', then: ' bg-ep-secondary')}"
<a class="block flex flex-grow h-8 justify-center items-center uppercase text-sm leading-none text-white hover:text-white focus:text-white hover:bg-ep-secondary{f:if(condition: menuitem.tx_eptheme_navitemclass, then: ' {menuitem.tx_eptheme_navitemclass}')}{f:if(condition: '{menuitem.active} or {menuitem.data.uid} == {settings.forceActiveTopnavUid}', then: ' bg-ep-secondary')}"
href="{menuitem.link}"{f:if(condition: '{menuitem.data.doktype} == 3', then: ' target="_blank"')}
title="{menuitem.title}">
{menuitem.title -> ep:topnavItem()}
@@ -6,7 +6,7 @@
<f:section name="Main">
<iframe class="border-0 h-96"
src="https://bpn.ep-reisen.de/buspronet/anmeldung_news.php"
src="{formUrl}"
width="100%" height="100"></iframe>
</f:section>
@@ -18,183 +18,134 @@
<f:render partial="Header/Header" arguments="{layout: 8, subheader: '{product.region.name} / {product.name}', header: product.headline}"/>
<div class="flex flex-col lg:flex-row-reverse lg:items-start"
data-controller="tabs"
data-tabs-button-active-class="tab-button--active"
data-tabs-scroll-value="true">
<div class="w-full lg:w-1/3">
<div class="lg:pl-4">
<div class="grid grid-cols-2 gap-2">
<f:if condition="{settings.hotelOnTop}">
<f:then>
<button type="button"
class="button button--light button--active col-span-1 md:col-span-2"
data-action="tabs#select"
data-tabs-target="button"
data-tab="hotel">
Unterkunft
</button>
<button type="button"
class="button button--light col-span-1 md:col-span-2"
data-action="tabs#select"
data-tabs-target="button"
data-tab="dates">
Termine/Preise
</button>
</f:then>
<f:else>
<button type="button"
class="button button--light button--active col-span-1 md:col-span-2"
data-action="tabs#select"
data-tabs-target="button"
data-tab="dates">
Termine/Preise
</button>
<button type="button"
class="button button--light col-span-1 md:col-span-2"
data-action="tabs#select"
data-tabs-target="button"
data-tab="hotel">
Unterkunft
</button>
</f:else>
</f:if>
<button type="button"
class="button button--light col-span-1 md:col-span-2"
data-action="tabs#select"
data-tabs-target="button"
data-tab="region">
Gebiet
</button>
<button type="button"
class="button button--light col-span-1 md:col-span-2"
data-action="tabs#select"
data-tabs-target="button"
data-tab="city">
Ort
</button>
<f:if condition="{product.journey}">
<button type="button"
class="button button--light col-span-1 md:col-span-2"
data-action="tabs#select"
data-tabs-target="button"
data-tab="journey">
Anreise
</button>
</f:if>
<f:if condition="{product.faqs}">
<button type="button"
class="button button--light col-span-1 md:col-span-2"
data-controller="scroll-to"
data-scroll-to-target-value="faq"
data-action="scroll-to#scroll">
FAQ
</button>
</f:if>
<div class="col-span-2">
<p class="mb-4">
<button type="button"
class="button button--light w-full"
data-controller="watchlist-toggle"
data-watchlist-toggle-key-value="{hotel.uid}:{product.uid}"
data-action="watchlist-toggle#toggle">
<span data-watchlist-toggle-target="label">
Auf die Merkliste setzen
</span>
</button>
</p>
<p class="mb-4">
<a href="{f:uri.typolink(parameter: settings.coronaUpdatesPageUid)}"
class="block w-full px-4 py-2 bg-red-500 text-white flex items-center space-x-2"
title="Corona Updates">
<svg class="w-4 h-4">
<use href="#icon-virus"></use>
</svg>
<span>
Corona Updates
</span>
</a>
</p>
</div>
</div>
<div class="hidden lg:block">
<div class="flex flex-col space-y-2 mb-4">
<a href="{f:uri.typolink(parameter: settings.coronaUpdatesPageUid)}"
class="block w-full px-4 py-2 bg-red-500 text-white flex items-center space-x-2"
title="Corona Updates">
<svg class="w-4 h-4">
<use href="#icon-virus"></use>
</svg>
<span>
Corona Updates
</span>
</a>
<f:if condition="{product.faqs}">
<button type="button"
class="button button--light col-span-1 md:col-span-2"
data-controller="scroll-to"
data-scroll-to-target-value="faq"
data-action="scroll-to#scroll">
FAQ
</button>
</f:if>
<button type="button"
class="button button--light w-full"
data-controller="watchlist-toggle"
data-watchlist-toggle-key-value="{hotel.uid}:{product.uid}"
data-action="watchlist-toggle#toggle">
<span data-watchlist-toggle-target="label">
Auf die Merkliste setzen
</span>
</button>
</div>
<f:render section="Sidebar" arguments="{_all}"/>
</div>
</div>
</div>
<div id="main" class="w-full lg:w-2/3">
<div class="lg:pr-4">
<!-- Loader -->
<div class="flex items-center space-x-2 mb-4 hidden bg-ep-secondary text-white p-2"
data-product-details-target="loadingIndicator">
<svg class="w-4 h-4 text-white">
<use href="#icon-spinner"></use>
</svg>
<span data-product-details-target="loadingMessage">
Loading...
</span>
</div>
<!-- /Loader -->
<!-- Dates -->
<div class="{f:if(condition: settings.hotelOnTop, then: 'hidden')}"
data-tabs-target="tab"
data-tab="dates">
<f:if condition="{isProductWithExcludedConcept}">
<f:if condition="{product.region.season} == 'w'">
<div class="alert alert-info">
<p><strong>Gruppenrabatt bis zu 100€ möglich</strong></p>
<p>Für Gruppen bis 15 Personen könnt ihr <f:link.typolink parameter="31">hier direkt buchen</f:link.typolink>.
Für Gruppen ab 16 Personen erstellen wir euch ein konkretes Angebot zu günstigen
Gruppenkonditionen zu dieser Reise. Anfrage via Tel. 0221 - 272 276 18 oder mit einer
<f:link.typolink parameter="{settings.defaultContactFormPageUid}">Kurzanfrage</f:link.typolink>!</p>
</div>
<div class="lg:pr-4 flex flex-col space-y-4">
<div class="relative">
<button type="button"
data-action="tabs#togglePulldown"
class="w-full flex items-center space-x-2 bg-ep-primary-light text-white uppercase p-2">
<svg class="w-6 h-6">
<use href="#icon-chevron-down"></use>
</svg>
<span data-tabs-target="label">
Termine/Preise
</span>
</button>
<div class="absolute z-20 top-100 left-0 w-full flex flex-col items-start divide-y divide-overlay-white bg-ep-primary-light text-white uppercase shadow hidden"
data-tabs-target="pulldown">
<f:if condition="{settings.hotelOnTop}">
<f:then>
<button type="button"
data-action="tabs#select"
data-tab="hotel"
class="w-full text-left p-2 pl-10">
Unterkunft
</button>
<button type="button"
data-action="tabs#select"
data-tab="dates"
class="w-full text-left p-2 pl-10">
Termine/Preise
</button>
</f:then>
<f:else>
<button type="button"
data-action="tabs#select"
data-tab="dates"
class="w-full text-left p-2 pl-10">
Termine/Preise
</button>
<button type="button"
data-action="tabs#select"
data-tab="hotel"
class="w-full text-left p-2 pl-10">
Unterkunft
</button>
</f:else>
</f:if>
</f:if>
<f:if condition="{product.daytrip}">
<f:then>
<f:render section="DaytripDateSelect" arguments="{_all}"/>
</f:then>
<f:else>
<div class="hidden" data-product-details-target="datesTableContainer"></div>
<div class="hidden" data-product-details-target="priceTableContainer"></div>
<f:if condition="{isProductWithNoInfoConcept}">
<f:else>
<template x-if="!available">
<f:render partial="NotBookable" arguments="{_all}"/>
</template>
</f:else>
</f:if>
</f:else>
</f:if>
<f:render partial="Product/Details" arguments="{_all}"/>
<button type="button"
data-action="tabs#select"
data-tab="region"
class="w-full text-left p-2 pl-10">
Gebiet
</button>
<button type="button"
data-action="tabs#select"
data-tab="city"
class="w-full text-left p-2 pl-10">
Ort
</button>
<f:if condition="{product.journey}">
<button type="button"
data-action="tabs#select"
data-tab="journey"
class="w-full text-left p-2 pl-10">
Anreise
</button>
</f:if>
</div>
</div>
<!-- /Dates -->
<!-- Hotel -->
<div class="{f:if(condition: settings.hotelOnTop, else: 'hidden')}"
data-tabs-target="tab"
data-tab="hotel">
<f:render partial="Hotel/Details" arguments="{hotel: hotel, bars: 1, showNonBookableHint: 0}"/>
</div>
<!-- /Hotel -->
<!-- City -->
<div class="hidden"
data-tabs-target="tab"
data-tab="city">
<f:render partial="City/Details" arguments="{city: product.city, bars: 1}"/>
</div>
<!-- /City -->
<!-- Region -->
<div class="hidden"
data-tabs-target="tab"
data-tab="region">
<f:render partial="Region/Details" arguments="{region: product.region, bars: 1}"/>
</div>
<!-- /Region -->
<!-- Journey -->
<div class="hidden"
data-tabs-target="tab"
data-tab="journey">
<f:render partial="Journey/Details" arguments="{journey: product.journey, bars: 1}"/>
</div>
<!-- /Journey -->
<f:if condition="{settings.hotelOnTop}">
<f:then>
<f:render section="Hotel" arguments="{_all}"/>
<f:render section="Dates" arguments="{_all}"/>
</f:then>
<f:else>
<f:render section="Dates" arguments="{_all}"/>
<f:render section="Hotel" arguments="{_all}"/>
</f:else>
</f:if>
<f:render section="City" arguments="{_all}"/>
<f:render section="Region" arguments="{_all}"/>
<f:render section="Journey" arguments="{_all}"/>
<div class="md:hidden">
<a href="{f:uri.typolink(parameter: settings.coronaUpdatesPageUid)}"
class="block w-full px-4 py-2 bg-red-500 text-white flex items-center space-x-2"
title="Corona Updates">
<svg class="w-4 h-4">
<use href="#icon-virus"></use>
</svg>
<span>Corona Updates</span>
</a>
<f:render section="Sidebar" arguments="{_all}"/>
</div>
</div>
@@ -209,6 +160,95 @@
</div>
</f:section>
<f:section name="Dates">
<div class="mb-4{f:if(condition: settings.hotelOnTop, then: ' hidden')}"
data-tabs-target="tab"
data-tab="dates"
data-label="Termine/Preise">
<f:if condition="{isProductWithExcludedConcept}">
<f:if condition="{product.region.season} == 'w'">
<div class="alert alert-info">
<p>
<strong>Gruppenrabatt bis zu 100€ möglich</strong>
</p>
<p>
Für Gruppen bis 15 Personen könnt ihr <f:link.typolink parameter="31">hier direkt buchen</f:link.typolink>.
Für Gruppen ab 16 Personen erstellen wir euch ein konkretes Angebot zu günstigen
Gruppenkonditionen zu dieser Reise. Anfrage via Tel. 0221 - 272 276 18 oder mit einer
<f:link.typolink parameter="{settings.defaultContactFormPageUid}">Kurzanfrage</f:link.typolink>!
</p>
</div>
</f:if>
</f:if>
<f:if condition="{product.daytrip}">
<f:then>
<f:render section="DaytripDateSelect" arguments="{_all}"/>
</f:then>
<f:else>
<div class="hidden" data-product-details-target="datesTableContainer"></div>
<div class="hidden" data-product-details-target="priceTableContainer"></div>
<f:if condition="{isProductWithNoInfoConcept}">
<f:else>
<f:if condition="{product.available}">
<f:else>
<f:render partial="NotBookable" arguments="{_all}"/>
</f:else>
</f:if>
</f:else>
</f:if>
</f:else>
</f:if>
<f:render partial="Product/Details" arguments="{_all}"/>
<div class="p-4 hidden"
data-product-details-target="loadingIndicator">
<div class="flex items-center space-x-4 bg-ep-secondary text-white text-lg p-4 rounded">
<svg class="w-6 h-6">
<use href="#icon-spinner"></use>
</svg>
<span data-product-details-target="loadingMessage">Loading...</span>
</div>
</div>
</div>
</f:section>
<f:section name="Hotel">
<div class="mb-4{f:if(condition: settings.hotelOnTop, else: ' hidden')}"
data-tabs-target="tab"
data-tab="hotel"
data-label="Unterkunft">
<f:render partial="Hotel/Details" arguments="{hotel: hotel, bars: 1, showNonBookableHint: 0}"/>
</div>
</f:section>
<f:section name="City">
<div class="mb-4 hidden"
data-tabs-target="tab"
data-tab="city"
data-label="Ort">
<f:render partial="City/Details" arguments="{city: product.city, bars: 1}"/>
</div>
</f:section>
<f:section name="Region">
<div class="mb-4 hidden"
data-tabs-target="tab"
data-tab="region"
data-label="Gebiet">
<f:render partial="Region/Details" arguments="{region: product.region, bars: 1}"/>
</div>
</f:section>
<f:section name="Journey">
<f:if condition="{product.journey}">
<div class="mb-4 hidden"
data-tabs-target="tab"
data-tab="journey"
data-label="Anreise">
<f:render partial="Journey/Details" arguments="{journey: product.journey, bars: 1}"/>
</div>
</f:if>
</f:section>
<f:section name="Sidebar">
<f:render section="Calendar" arguments="{_all}"/>
<f:render partial="Facts" arguments="{facts: product.facts}"/>
@@ -151,6 +151,7 @@ CREATE TABLE pages
tx_eptheme_hide_searchbar tinyint(4) unsigned DEFAULT '0' NOT NULL,
tx_eptheme_new_tab tinyint(4) unsigned DEFAULT '0' NOT NULL,
tx_eptheme_bodyclass varchar(255) DEFAULT '' NOT NULL,
tx_eptheme_navitemclass varchar(255) DEFAULT '' NOT NULL,
tx_eptheme_slides int(11) unsigned DEFAULT '0',
tx_eptheme_badge int(11) unsigned DEFAULT '0'
);
+1
View File
@@ -12,6 +12,7 @@ module.exports = {
'./public/typo3conf/ext/ep_theme/Classes/ViewHelpers/**/*.php',
],
safelist: [
'bg-red-600',
'bg-header-season-w',
'bg-header-season-s',
'bg-concept-bdg', 'bg-concept-bdg-overlay',