feat: improve teaser popup/modal by integrating with htmx
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
use EP\EpProducts\Domain\Model\Concept;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class AjaxTeaserPopupController extends ActionController
|
||||
{
|
||||
public function conceptAction(Concept $concept, string $targetUrl)
|
||||
{
|
||||
$this->view->assignMultiple([
|
||||
'concept' => $concept,
|
||||
'targetUrl' => $targetUrl,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -135,8 +135,8 @@ class ProductRepository extends AbstractRepository
|
||||
'pseudo_price as pseudoPrice', 'nights as nights', 'available as available', 'season as season',
|
||||
'skipass_included as skipassIncluded', 'bus_included as busIncluded',
|
||||
'earlybird', 'new', 'daytrip', 'hide_booking_button as hideBookingButton',
|
||||
'low_contingent as lowContingent', 'concept_code as conceptCode', 'concept_name as conceptName',
|
||||
'date.concept_popup_text as conceptPopupText', 'board', 'new'
|
||||
'low_contingent as lowContingent', 'concept as conceptUid', 'concept_code as conceptCode',
|
||||
'concept_name as conceptName', 'concept_popup_text as conceptPopupText', 'board', 'new'
|
||||
)
|
||||
->from('tx_epproducts_domain_model_date', 'date')
|
||||
->where('date_start >= NOW()')
|
||||
|
||||
@@ -203,6 +203,7 @@ class ProductDataService implements SingletonInterface
|
||||
'images' => $this->productImageService->getImages($teaserData['productUid']),
|
||||
],
|
||||
'concept' => [
|
||||
'uid' => $teaserData['conceptUid'],
|
||||
'name' => $teaserData['conceptName'],
|
||||
'code' => $teaserData['conceptCode'],
|
||||
'popupText' => $teaserData['conceptPopupText'],
|
||||
|
||||
+1
@@ -225,6 +225,7 @@ return [
|
||||
'cols' => 40,
|
||||
'rows' => 5,
|
||||
'eval' => 'trim',
|
||||
'enableRichtext' => true,
|
||||
],
|
||||
],
|
||||
'teaser_images' => [
|
||||
|
||||
@@ -181,6 +181,9 @@ tx_epproducts_ajax_json {
|
||||
AjaxGroupsPrice {
|
||||
1 = processForm
|
||||
}
|
||||
AjaxTeaserPopup {
|
||||
1 = concept
|
||||
}
|
||||
}
|
||||
features.requireCHashArgumentForActionArguments = 0
|
||||
settings =< plugin.tx_epproducts.settings
|
||||
|
||||
@@ -268,6 +268,7 @@ $boot = function () {
|
||||
'AjaxCalendar' => 'range,contingents,availableRooms',
|
||||
'AjaxWatchlist' => 'list',
|
||||
'AjaxGroupsPrice' => 'processForm',
|
||||
'AjaxTeaserPopup' => 'concept',
|
||||
],
|
||||
[
|
||||
'AjaxSearch' => 'searchresult',
|
||||
@@ -278,6 +279,7 @@ $boot = function () {
|
||||
'AjaxCalendar' => 'range,contingents,availableRooms',
|
||||
'AjaxWatchlist' => 'list',
|
||||
'AjaxGroupsPrice' => 'processForm',
|
||||
'AjaxTeaserPopup' => 'concept',
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -44,3 +44,8 @@ import { definitionsFromContext } from '@hotwired/stimulus-webpack-helpers'
|
||||
const application = Application.start()
|
||||
const context = require.context('./controllers', true, /\.js$/)
|
||||
application.load(definitionsFromContext(context))
|
||||
|
||||
window.htmx = require('htmx.org')
|
||||
htmx.config.includeIndicatorStyles = false
|
||||
htmx.config.historyEnabled = false
|
||||
htmx.config.allowScriptTags = false
|
||||
|
||||
+4
@@ -15,4 +15,8 @@ export default class extends Controller {
|
||||
close() {
|
||||
this.element.classList.add('hidden', true)
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.element.remove()
|
||||
}
|
||||
}
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
import { Controller } from '@hotwired/stimulus'
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
static outlets = ['teaser-popup-modal']
|
||||
static values = {
|
||||
title: {
|
||||
type: String,
|
||||
default: 'Hinweis',
|
||||
},
|
||||
text: String,
|
||||
}
|
||||
|
||||
open(e) {
|
||||
if (this.hasTextValue) {
|
||||
this.teaserPopupModalOutlet.titleTarget.innerText = this.titleValue
|
||||
this.teaserPopupModalOutlet.contentTarget.innerHTML = this.textValue
|
||||
this.teaserPopupModalOutlet.buttonTarget.href = this.element.href
|
||||
this.teaserPopupModalOutlet.open()
|
||||
}
|
||||
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
import { Controller } from '@hotwired/stimulus'
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
static targets = ['title', 'content', 'button']
|
||||
|
||||
open() {
|
||||
this.element.classList.remove('hidden')
|
||||
}
|
||||
|
||||
close() {
|
||||
this.element.classList.add('hidden')
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,5 @@
|
||||
<f:render partial="Topnav" arguments="{_all}"/>
|
||||
<f:render partial="Mobilenav" section="Main" arguments="{_all}"/>
|
||||
<f:render partial="Search/MobileSearch" arguments="{_all}"/>
|
||||
<f:render partial="TeaserPopup" arguments="{_all}" />
|
||||
<f:render partial="Config" arguments="{_all}" />
|
||||
</html>
|
||||
|
||||
@@ -19,6 +19,5 @@
|
||||
<f:render partial="Search/MobileSearch" arguments="{_all}"/>
|
||||
</f:else>
|
||||
</f:if>
|
||||
<f:render partial="TeaserPopup" arguments="{_all}" />
|
||||
<f:render partial="Config" arguments="{_all}" />
|
||||
</html>
|
||||
|
||||
@@ -10,6 +10,5 @@
|
||||
<f:render partial="ContactBar" arguments="{_all}"/>
|
||||
<f:render partial="Topnav" arguments="{_all}"/>
|
||||
<f:render partial="Mobilenav" section="Main" arguments="{_all}"/>
|
||||
<f:render partial="TeaserPopup" arguments="{_all}" />
|
||||
<f:render partial="Config" arguments="{_all}" />
|
||||
</html>
|
||||
|
||||
@@ -8,6 +8,5 @@
|
||||
<f:render partial="ContactBar" arguments="{_all}"/>
|
||||
<f:render partial="Topnav" arguments="{_all}"/>
|
||||
<f:render partial="Mobilenav" section="Main" arguments="{_all}"/>
|
||||
<f:render partial="TeaserPopup" arguments="{_all}" />
|
||||
<f:render partial="Config" arguments="{_all}" />
|
||||
</html>
|
||||
|
||||
@@ -21,6 +21,5 @@
|
||||
<f:render partial="Search/MobileSearch" arguments="{_all}"/>
|
||||
</f:else>
|
||||
</f:if>
|
||||
<f:render partial="TeaserPopup" arguments="{_all}" />
|
||||
<f:render partial="Config" arguments="{_all}" />
|
||||
</html>
|
||||
|
||||
@@ -25,6 +25,5 @@
|
||||
<f:render partial="Topnav" arguments="{_all}"/>
|
||||
<f:render partial="Mobilenav" section="Main" arguments="{_all}"/>
|
||||
<f:render partial="Search/MobileSearch" arguments="{_all}"/>
|
||||
<f:render partial="TeaserPopup" arguments="{_all}" />
|
||||
<f:render partial="Config" arguments="{_all}" />
|
||||
</html>
|
||||
|
||||
-1
@@ -19,6 +19,5 @@
|
||||
<f:render partial="ContactBar" arguments="{_all}"/>
|
||||
<f:render partial="Topnav" arguments="{_all}"/>
|
||||
<f:render partial="Mobilenav" section="Main" arguments="{_all}"/>
|
||||
<f:render partial="TeaserPopup" arguments="{_all}" />
|
||||
<f:render partial="Config" arguments="{_all}" />
|
||||
</html>
|
||||
|
||||
@@ -25,6 +25,5 @@
|
||||
<f:render partial="Topnav" arguments="{_all}"/>
|
||||
<f:render partial="Mobilenav" section="Main" arguments="{_all}"/>
|
||||
<f:render partial="Search/MobileSearch" arguments="{_all}"/>
|
||||
<f:render partial="TeaserPopup" arguments="{_all}" />
|
||||
<f:render partial="Config" arguments="{_all}" />
|
||||
</html>
|
||||
|
||||
-1
@@ -19,6 +19,5 @@
|
||||
<f:render partial="ContactBar" arguments="{_all}"/>
|
||||
<f:render partial="Topnav" arguments="{_all}"/>
|
||||
<f:render partial="Mobilenav" section="Main" arguments="{_all}"/>
|
||||
<f:render partial="TeaserPopup" arguments="{_all}" />
|
||||
<f:render partial="Config" arguments="{_all}" />
|
||||
</html>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
|
||||
|
||||
<f:section name="Teaser">
|
||||
<f:variable name="targetUrl" value="{ep:uri.product(forceHotelUid: forceHotelUid, product: product, hotel: hotel, dateFrom: dateFrom, dateTo: dateTo, ref: referringPageUri)}"/>
|
||||
<div class="product-teaser flex flex-col h-full bg-white group{f:if(condition: landscape, then: ' sm:flex-row sm:h-auto')}">
|
||||
<f:render section="TeaserImage" arguments="{_all}"/>
|
||||
<f:render section="TeaserContent" arguments="{_all}"/>
|
||||
@@ -13,12 +14,11 @@
|
||||
|
||||
<f:section name="TeaserImage">
|
||||
<div class="relative{f:if(condition: landscape, then: ' sm:w-2/5')}">
|
||||
<a href="{ep:uri.product(forceHotelUid: forceHotelUid, product: product, hotel: hotel, dateFrom: dateFrom, dateTo: dateTo, ref: referringPageUri)}"
|
||||
<a href="{targetUrl}"
|
||||
<f:if condition="{concept.popupText} && {settings.globalConceptCode} != {concept.code}">
|
||||
data-controller="teaser-popup"
|
||||
data-teaser-popup-text-value="{concept.popupText}"
|
||||
data-teaser-popup-teaser-popup-modal-outlet="#teaser-popup-modal"
|
||||
data-action="teaser-popup#open"
|
||||
hx-get="{ep:uri.ajax(action: 'concept', controller: 'AjaxTeaserPopup', arguments: '{concept: concept.uid, targetUrl: targetUrl}', format: 'html', pageUid: settings.defaultAjaxUid)}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend"
|
||||
</f:if>
|
||||
title="{region.name} {product.name} Details und Buchen">
|
||||
<f:if condition="{productImage}">
|
||||
@@ -78,12 +78,11 @@
|
||||
|
||||
<f:section name="TeaserContent">
|
||||
{f:variable(name: 'including', value: '{f:render(section: \'Including\', arguments: \'{_all}\') -> v:format.trim()}')}
|
||||
<a href="{ep:uri.product(forceHotelUid: forceHotelUid, product: product, hotel: hotel, dateFrom: dateFrom, dateTo: dateTo, ref: referringPageUri)}"
|
||||
<a href="{targetUrl}"
|
||||
<f:if condition="{concept.popupText} && {globalConceptCode} != {concept.code}">
|
||||
data-controller="teaser-popup"
|
||||
data-teaser-popup-text-value="{concept.popupText}"
|
||||
data-teaser-popup-teaser-popup-modal-outlet="#teaser-popup-modal"
|
||||
data-action="teaser-popup#open"
|
||||
hx-get="{ep:uri.ajax(action: 'concept', controller: 'AjaxTeaserPopup', arguments: '{concept: concept.uid, targetUrl: targetUrl}', format: 'html', pageUid: settings.defaultAjaxUid)}"
|
||||
hx-target="body"
|
||||
hx-swap="beforeend"
|
||||
</f:if>
|
||||
title="{region.name} {product.name} Details und Buchen"
|
||||
class="flex-1 flex flex-col space-y-1 px-2 py-4 md:p-4">
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<div class="hidden fixed inset-0 w-full h-full z-50"
|
||||
id="teaser-popup-modal"
|
||||
data-controller="teaser-popup-modal">
|
||||
<div class="absolute inset-0 w-full h-full bg-black/85 z-25"
|
||||
data-action="click->teaser-popup-modal#close"></div>
|
||||
<div class="absolute top-1/2 left-1/2 transform -translate-xy-1/2 w-full max-w-xl px-4">
|
||||
<div class="shadow flex items-center justify-between p-4 bg-ep-primary-light text-white rounded-t">
|
||||
<span class="text-xl font-bold" data-teaser-popup-modal-target="title"></span>
|
||||
<button type="button"
|
||||
class="inline-block"
|
||||
data-action="teaser-popup-modal#close">
|
||||
<svg class="w-8 h-8">
|
||||
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-close"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-4 bg-white rounded-b" data-rte-content>
|
||||
<p data-teaser-popup-modal-target="content"></p>
|
||||
<a href="#" class="button bg-button" data-teaser-popup-modal-target="button">
|
||||
Ok
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
|
||||
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers"
|
||||
data-namespace-typo3-fluid="true">
|
||||
|
||||
<f:layout name="Default"/>
|
||||
|
||||
<f:section name="Main">
|
||||
<div class="fixed inset-0 w-full h-full z-50 {concept.code}" data-controller="modal">
|
||||
<div class="absolute inset-0 w-full h-full bg-black/75 z-25"
|
||||
data-action="click->modal#remove"></div>
|
||||
<div class="absolute top-1/2 left-1/2 transform -translate-xy-1/2 w-full max-w-screen-lg px-4">
|
||||
<div class="shadow flex items-center justify-between p-4 bg-concept-{concept.code} text-white rounded-t">
|
||||
<span class="text-xl font-bold">
|
||||
Hinweis
|
||||
</span>
|
||||
<button type="button"
|
||||
class="inline-block"
|
||||
data-action="modal#remove">
|
||||
<svg class="w-8 h-8">
|
||||
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-close"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-4 bg-white rounded-b">
|
||||
<div class="grid md:grid-cols-3 gap-8">
|
||||
<f:image image="{concept.teaserImages.0}" width="640" class="block w-full h-auto" alt="{concept.name}"/>
|
||||
<div class="md:col-span-2" data-rte-content>
|
||||
<h3>
|
||||
{concept.name}
|
||||
</h3>
|
||||
{concept.popupText -> f:format.html()}
|
||||
<a href="{targetUrl}" class="button bg-button">
|
||||
Ok
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</f:section>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user