Widget: add versioning support and add v2 with improved a11y-support (#5136)

* Add support for versioning widget.js

* add versionable css

* add version deprecation + redirect

* use dynamic template_path instead of dynamic css_path

* remove dummy code from widget.v1.scss

* fix typo

* [A11y] fix input border & focus style (#5149)

* [A11y] fix input border & focus style

* Fix double semi-colon

* [A11y] make collapse-indicator a button (#5150)

* Fix source order for cart-exists-message (#5152)

* [A11y] underline links (#5151)

* [A11y] Move modal-dialogs to HTMLDialogElement (#5147)

* [A11y] move widget/iframe to html-dialog

* make lightbox a dialog

* move error-alert to dialog

* re-add crossorigin

* fix esc-handling and move animation to icon to enable focusing the button

* fix code-style issues

* block canceling loading iframe

* Escape/cancel blocking fix for Chrome

* add round focus-outline when dialog is loading

* Widget v2: change voucher-link to hash-based link (#5161)

* Fix variants toggle-button being submit-button

* Widget v2: make single-item-select button and always show custom-spinners (#5165)

* Widget v2: make single-item-select=button default

* remove native-spinners and single_item_select

* Stop suggesting old parameter

---------

Co-authored-by: Raphael Michel <michel@rami.io>

* Widget v2: add filter button to events metadata-filter (#5162)

* Widget v2: do not underline events in list and calendar (#5163)

* Fix checkbox button missing border radius (#5158)

* Widget v2: turn add-to-cart-button into resume-button if cart-exists and no items selected (#5160)

* Widget v2: make cart-alert live=polite

* Add resume-button if cart-exists and no items selected

* fix error handling with new-tab and later returning to old window

* Fix cart-message button being full height

* fix amount_selected recalc

* Fix broken v-model

* fix merge

* Widget v2: Remove link from variation-product title (#5159)

* Remove link from variation-product, focus associated input

* open variations onclick on product-title

* clickable elements should be focussable and interactive, so better remove click-handler on product-title

* Widget v2: Fix calendar events color contrast (#5164)

* Widget v2: Fix calendar events color contrast

* fix status-bubbles in list-view

* fix color in mobile

* add striped-background to calendar and week

* improve display of calendar for super small screens

* Fix meta-filter legend not being screen-reader accessible

* update version_default to 2

Co-authored-by: Raphael Michel <michel@rami.io>

---------

Co-authored-by: Raphael Michel <michel@rami.io>
This commit is contained in:
Richard Schreiber
2025-05-28 15:02:39 +02:00
committed by GitHub
parent e46e689f01
commit 92f7456eca
11 changed files with 4130 additions and 500 deletions

View File

@@ -19,8 +19,8 @@
section of your website:
{% endblocktrans %}
</p>
<pre>&lt;link rel="stylesheet" type="text/css" href="{% abseventurl request.event "presale:event.widget.css" %}" crossorigin&gt;
&lt;script type="text/javascript" src="{{ urlprefix }}{% url "presale:widget.js" lang=form.cleaned_data.language %}" async crossorigin&gt;&lt;/script&gt;</pre>
<pre>&lt;link rel="stylesheet" type="text/css" href="{% abseventurl request.event "presale:event.widget.css" version=widget_version_default %}" crossorigin&gt;
&lt;script type="text/javascript" src="{{ urlprefix }}{% url "presale:widget.js" lang=form.cleaned_data.language version=widget_version_default %}" async crossorigin&gt;&lt;/script&gt;</pre>
<p>
{% blocktrans trimmed %}
Then, copy the following code to the place of your website where you want the widget to show up:
@@ -32,7 +32,7 @@
{% abseventurl request.event "presale:event.index" as indexurl %}
{% endif %}
{% if form.cleaned_data.compatibility_mode %}
<pre>&lt;div class="pretix-widget-compat" event="{% abseventurl request.event "presale:event.index" %}"{% if form.cleaned_data.subevent %} subevent="{{ form.cleaned_data.subevent.pk }}"{% endif %}{% if form.cleaned_data.voucher %} voucher="{{ form.cleaned_data.voucher }}"{% endif %} single-item-select="button"&gt;&lt;/div&gt;
<pre>&lt;div class="pretix-widget-compat" event="{% abseventurl request.event "presale:event.index" %}"{% if form.cleaned_data.subevent %} subevent="{{ form.cleaned_data.subevent.pk }}"{% endif %}{% if form.cleaned_data.voucher %} voucher="{{ form.cleaned_data.voucher }}"{% endif %}&gt;&lt;/div&gt;
&lt;noscript&gt;
&lt;div class="pretix-widget"&gt;
&lt;div class="pretix-widget-info-message"&gt;
@@ -45,7 +45,7 @@
&lt;/noscript&gt;
</pre>
{% else %}
<pre>&lt;pretix-widget event="{% abseventurl request.event "presale:event.index" %}"{% if form.cleaned_data.subevent %} subevent="{{ form.cleaned_data.subevent.pk }}"{% endif %}{% if form.cleaned_data.voucher %} voucher="{{ form.cleaned_data.voucher }}"{% endif %} single-item-select="button"&gt;&lt;/pretix-widget&gt;
<pre>&lt;pretix-widget event="{% abseventurl request.event "presale:event.index" %}"{% if form.cleaned_data.subevent %} subevent="{{ form.cleaned_data.subevent.pk }}"{% endif %}{% if form.cleaned_data.voucher %} voucher="{{ form.cleaned_data.voucher }}"{% endif %}&gt;&lt;/pretix-widget&gt;
&lt;noscript&gt;
&lt;div class="pretix-widget"&gt;
&lt;div class="pretix-widget-info-message"&gt;

View File

@@ -96,6 +96,9 @@ from pretix.control.views.user import RecentAuthenticationRequiredMixin
from pretix.helpers.database import rolledback_transaction
from pretix.multidomain.urlreverse import build_absolute_uri, get_event_domain
from pretix.plugins.stripe.payment import StripeSettingsHolder
from pretix.presale.views.widget import (
version_default as widget_version_default,
)
from ...base.i18n import language
from ...base.models.items import (
@@ -1408,6 +1411,7 @@ class WidgetSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, FormV
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['urlprefix'] = settings.SITE_URL
ctx['widget_version_default'] = widget_version_default
domain = get_event_domain(self.request.event, fallback=True)
if domain:
siteurlsplit = urlsplit(settings.SITE_URL)

View File

@@ -0,0 +1,5 @@
{% load compress %}
{% load static %}
{% compress css %}
<link rel="stylesheet" type="text/x-scss" href="{% static "pretixpresale/scss/widget.v1.scss" %}"/>
{% endcompress %}

View File

@@ -32,7 +32,7 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
from django.urls import include, re_path
from django.urls import include, path, re_path
from django.views.decorators.csrf import csrf_exempt
import pretix.presale.views.cart
@@ -173,7 +173,7 @@ event_patterns = [
re_path(r'^widget/product_list$', pretix.presale.views.widget.WidgetAPIProductList.as_view(),
name='event.widget.productlist'),
re_path(r'^widget/v1.css$', pretix.presale.views.widget.widget_css, name='event.widget.css'),
path('widget/v<int:version>.css', pretix.presale.views.widget.widget_css, name='event.widget.css'),
re_path(r'^(?P<subevent>\d+)/widget/product_list$', pretix.presale.views.widget.WidgetAPIProductList.as_view(),
name='event.widget.productlist'),
@@ -196,7 +196,7 @@ organizer_patterns = [
re_path(r'^widget/product_list$', pretix.presale.views.widget.WidgetAPIProductList.as_view(),
name='organizer.widget.productlist'),
re_path(r'^widget/v1.css$', pretix.presale.views.widget.widget_css, name='organizer.widget.css'),
path('widget/v<int:version>.css', pretix.presale.views.widget.widget_css, name='organizer.widget.css'),
re_path(r'^theme.css$', pretix.presale.views.theme.theme_css, name='organizer.theme.css'),
re_path(r'^accessibility$', pretix.presale.views.organizer.AccessibilityView.as_view(), name='organizer.accessibility'),
@@ -237,5 +237,5 @@ locale_patterns = [
re_path(r'^robots.txt$', pretix.presale.views.robots.robots_txt, name='robots.txt'),
re_path(r'^browserconfig.xml$', pretix.presale.views.theme.browserconfig_xml, name='browserconfig.xml'),
re_path(r'^site.webmanifest$', pretix.presale.views.theme.webmanifest, name='site.webmanifest'),
re_path(r'^widget/v1\.(?P<lang>[a-zA-Z0-9_\-]+)\.js$', pretix.presale.views.widget.widget_js, name='widget.js'),
path('widget/v<int:version>.<slug:lang>.js', pretix.presale.views.widget.widget_js, name='widget.js'),
]

View File

@@ -38,8 +38,10 @@ from django.core.files.base import ContentFile, File
from django.core.files.storage import default_storage
from django.db.models import Q
from django.http import FileResponse, Http404, HttpResponse, JsonResponse
from django.shortcuts import redirect
from django.template import Context, Engine
from django.template.loader import get_template
from django.urls import reverse
from django.utils.formats import date_format
from django.utils.timezone import now
from django.utils.translation import get_language, gettext, pgettext
@@ -81,15 +83,22 @@ logger = logging.getLogger(__name__)
# we never change static source without restart, so we can cache this thread-wise
_source_cache_key = None
version_min = 1
version_max = 2
version_default = 2 # used for output in widget-embed-code
def _get_source_cache_key():
def _get_source_cache_key(version):
global _source_cache_key
checksum = hashlib.sha256()
if not _source_cache_key:
with open(finders.find("pretixbase/scss/_theme_variables.scss"), "r") as f:
checksum.update(f.read().encode())
tpl = get_template('pretixpresale/widget_dummy.html')
et = html.fromstring(tpl.render({})).xpath('/html/head/link')[0].attrib['href'].replace(settings.STATIC_URL, '')
template_path = 'pretixpresale/widget_dummy.html' if version == version_max else 'pretixpresale/widget_dummy.v{}.html'.format(version)
tpl = get_template(template_path)
et = html.fromstring(tpl.render()).xpath('/html/head/link')[0].attrib['href'].replace(settings.STATIC_URL, '')
checksum.update(et.encode())
_source_cache_key = checksum.hexdigest()[:12]
return _source_cache_key
@@ -99,29 +108,39 @@ def indent(s):
return s.replace('\n', '\n ')
def widget_css_etag(request, **kwargs):
def widget_css_etag(request, version, **kwargs):
# This makes sure a new version of the theme is loaded whenever settings or the source files have changed
if hasattr(request, 'event'):
return (f'{_get_source_cache_key()}-'
return (f'{_get_source_cache_key(version)}-'
f'{request.organizer.cache.get_or_set("css_version", default=lambda: int(time.time()))}-'
f'{request.event.cache.get_or_set("css_version", default=lambda: int(time.time()))}')
else:
return f'{_get_source_cache_key()}-{request.organizer.cache.get_or_set("css_version", default=lambda: int(time.time()))}'
return f'{_get_source_cache_key(version)}-{request.organizer.cache.get_or_set("css_version", default=lambda: int(time.time()))}'
def widget_js_etag(request, lang, **kwargs):
def widget_js_etag(request, version, lang, **kwargs):
gs = GlobalSettingsObject()
return gs.settings.get('widget_checksum_{}'.format(lang))
return gs.settings.get('widget_checksum_{}_{}'.format(version, lang))
@gzip_page
@condition(etag_func=widget_css_etag)
@cache_page(60)
def widget_css(request, **kwargs):
def widget_css(request, version, **kwargs):
if version > version_max:
raise Http404()
if version < version_min:
return redirect(reverse('presale:event.widget.css' if hasattr(request, 'event') else 'organizer.widget.css', kwargs={
'version': version_min,
'organizer': request.organizer.slug,
'event': request.event.slug if hasattr(request, 'event') else None,
}))
o = getattr(request, 'event', request.organizer)
tpl = get_template('pretixpresale/widget_dummy.html')
et = html.fromstring(tpl.render({})).xpath('/html/head/link')[0].attrib['href'].replace(settings.STATIC_URL, '')
template_path = 'pretixpresale/widget_dummy.html' if version == version_max else 'pretixpresale/widget_dummy.v{}.html'.format(version)
tpl = get_template(template_path)
et = html.fromstring(tpl.render()).xpath('/html/head/link')[0].attrib['href'].replace(settings.STATIC_URL, '')
with open(finders.find(et), 'r') as f:
widget_css = f.read()
@@ -134,7 +153,7 @@ def widget_css(request, **kwargs):
return resp
def generate_widget_js(lang):
def generate_widget_js(version, lang):
code = []
with language(lang):
# Provide isolation
@@ -169,7 +188,7 @@ def generate_widget_js(lang):
'vuejs/vue.js' if settings.DEBUG else 'vuejs/vue.min.js',
'pretixpresale/js/widget/docready.js',
'pretixpresale/js/widget/floatformat.js',
'pretixpresale/js/widget/widget.js',
'pretixpresale/js/widget/widget.js' if version == version_max else 'pretixpresale/js/widget/widget.v{}.js'.format(version),
]
for fname in files:
f = finders.find(fname)
@@ -188,11 +207,17 @@ def generate_widget_js(lang):
@gzip_page
@condition(etag_func=widget_js_etag)
def widget_js(request, lang, **kwargs):
if lang not in [lc for lc, ll in settings.LANGUAGES]:
def widget_js(request, version, lang, **kwargs):
if version > version_max or lang not in [lc for lc, ll in settings.LANGUAGES]:
raise Http404()
cached_js = cache.get('widget_js_data_{}'.format(lang))
if version < version_min:
return redirect(reverse('presale:widget.js', kwargs={
'version': version_min,
'lang': lang,
}))
cached_js = cache.get('widget_js_data_{}_{}'.format(version, lang))
if cached_js and not settings.DEBUG:
resp = HttpResponse(cached_js, content_type='text/javascript')
resp._csp_ignore = True
@@ -200,7 +225,7 @@ def widget_js(request, lang, **kwargs):
return resp
gs = GlobalSettingsObject()
fname = gs.settings.get('widget_file_{}'.format(lang))
fname = gs.settings.get('widget_file_{}_{}'.format(version, lang))
resp = None
if fname and not settings.DEBUG:
if isinstance(fname, File):
@@ -208,21 +233,21 @@ def widget_js(request, lang, **kwargs):
try:
data = default_storage.open(fname).read()
resp = HttpResponse(data, content_type='text/javascript')
cache.set('widget_js_data_{}'.format(lang), data, 3600 * 4)
cache.set('widget_js_data_{}_{}'.format(version, lang), data, 3600 * 4)
except:
logger.exception('Failed to open widget.js')
if not resp:
data = generate_widget_js(lang).encode()
data = generate_widget_js(version, lang).encode()
checksum = hashlib.sha1(data).hexdigest()
if not settings.DEBUG:
newname = default_storage.save(
'widget/widget.{}.{}.js'.format(lang, checksum),
'widget/widget.{}.{}.{}.js'.format(version, lang, checksum),
ContentFile(data)
)
gs.settings.set('widget_file_{}'.format(lang), 'file://' + newname)
gs.settings.set('widget_checksum_{}'.format(lang), checksum)
cache.set('widget_js_data_{}'.format(lang), data, 3600 * 4)
gs.settings.set('widget_file_{}_{}'.format(version, lang), 'file://' + newname)
gs.settings.set('widget_checksum_{}_{}'.format(version, lang), checksum)
cache.set('widget_js_data_{}_{}'.format(version, lang), data, 3600 * 4)
resp = HttpResponse(data, content_type='text/javascript')
resp._csp_ignore = True
resp['Access-Control-Allow-Origin'] = '*'

View File

@@ -14,6 +14,7 @@ $input-color-placeholder: lighten(#000, 70%) !default;
$border-radius-base: var(--pretix-border-radius-base);
$border-radius-large: var(--pretix-border-radius-large);
$border-radius-small: var(--pretix-border-radius-small);
$input-border: #949494 !default;
$navbar-inverse-bg: #3b1c4a !default;
$navbar-inverse-link-color: white;
@@ -72,7 +73,7 @@ $panel-default-heading-bg: #e5e5e5 !default;
$link-hover-color: var(--pretix-brand-primary-darken-15);
$btn-default-border: #CCCCCC;
$btn-default-border: #949494;
$btn-primary-border: var(--pretix-brand-primary-darken-5);
$btn-primary-border-active: var(--pretix-brand-primary-darken-30);
@@ -122,6 +123,12 @@ $label-warning-bg-hover: var(--pretix-brand-warning-darken-10);
$label-danger-bg: var(--pretix-brand-danger);
$label-danger-bg-hover: var(--pretix-brand-danger-darken-10);
$alert-primary-bg: var(--pretix-brand-primary-tint-90);
$alert-primary-text: var(--pretix-brand-primary-shade-42);
$alert-primary-border: var(--pretix-brand-primary);
$alert-primary-hr: var(--pretix-brand-primary-darken-5);
$alert-primary-link: var(--pretix-brand-primary-shade-42);
$alert-success-bg: var(--pretix-brand-success-tint-85);
$alert-success-text: var(--pretix-brand-success-shade-25);
$alert-success-border: var(--pretix-brand-success);

View File

@@ -16,6 +16,8 @@ var strings = {
'quantity': django.pgettext('widget', 'Quantity'),
'quantity_dec': django.pgettext('widget', 'Decrease quantity'),
'quantity_inc': django.pgettext('widget', 'Increase quantity'),
'filter_events_by': django.pgettext('widget', 'Filter events by'),
'filter': django.pgettext('widget', 'Filter'),
'price': django.pgettext('widget', 'Price'),
'original_price': django.pgettext('widget', 'Original price: %s'),
'new_price': django.pgettext('widget', 'New price: %s'),
@@ -57,6 +59,8 @@ var strings = {
'redeem': django.pgettext('widget', 'Redeem'),
'voucher_code': django.pgettext('widget', 'Voucher code'),
'close': django.pgettext('widget', 'Close'),
'close_checkout': django.pgettext('widget', 'Close checkout'),
'cancel_blocked': django.pgettext('widget', 'You cannot cancel this operation. Please wait for loading to finish.'),
'continue': django.pgettext('widget', 'Continue'),
'variations': django.pgettext('widget', 'Show variants'),
'hide_variations': django.pgettext('widget', 'Hide variants'),
@@ -208,7 +212,7 @@ Vue.component('availbox', {
template: ('<div class="pretix-widget-availability-box">'
+ '<div class="pretix-widget-availability-unavailable"'
+ ' v-if="item.current_unavailability_reason === \'require_voucher\'">'
+ '<small><a @click.prevent.stop="focus_voucher_field" role="button" tabindex="0">{{unavailability_reason_message}}</a></small>'
+ '<small><a :href="voucher_jump_link" v-bind:aria-describedby="aria_labelledby">{{unavailability_reason_message}}</a></small>'
+ '</div>'
+ '<div class="pretix-widget-availability-unavailable"'
+ ' v-else-if="unavailability_reason_message">'
@@ -227,24 +231,19 @@ Vue.component('availbox', {
+ '<a :href="waiting_list_url" target="_blank" @click="$root.open_link_in_frame">' + strings.waiting_list + '</a>'
+ '</div>'
+ '<div class="pretix-widget-availability-available" v-if="!unavailability_reason_message && avail[0] === 100">'
+ '<label class="pretix-widget-item-count-single-label pretix-widget-btn-checkbox" v-if="order_max === 1 && $root.single_item_select == \'button\'">'
+ '<input type="checkbox" value="1" :checked="!!amount_selected" @change="amount_selected = $event.target.checked" :name="input_name"'
+ '<label class="pretix-widget-item-count-single-label pretix-widget-btn-checkbox" v-if="order_max === 1">'
+ '<input ref="quantity" type="checkbox" value="1" :name="input_name"'
+ ' v-bind:aria-label="label_select_item"'
+ '>'
+ '<span class="pretix-widget-icon-cart" aria-hidden="true"></span> ' + strings.select
+ '</label>'
+ '<label class="pretix-widget-item-count-single-label" v-else-if="order_max === 1">'
+ '<input type="checkbox" value="1" :checked="!!amount_selected" @change="amount_selected = $event.target.checked" :name="input_name"'
+ ' v-bind:aria-label="label_select_item"'
+ '>'
+ '</label>'
+ '<div :class="count_group_classes" v-else role="group" v-bind:aria-label="item.name">'
+ '<button v-if="!$root.use_native_spinners" type="button" @click.prevent.stop="on_step" data-step="-1" v-bind:data-controls="\'input_\' + input_name" class="pretix-widget-btn-default pretix-widget-item-count-dec" v-bind:aria-label="dec_label"><span>-</span></button>'
+ '<input type="number" inputmode="numeric" pattern="\d*" class="pretix-widget-item-count-multiple" placeholder="0" min="0"'
+ ' v-model="amount_selected" :max="order_max" :name="input_name" :id="\'input_\' + input_name"'
+ ' v-bind:aria-labelledby="aria_labelledby" ref="quantity"'
+ '<div class="pretix-widget-item-count-group" v-else role="group" v-bind:aria-label="item.name">'
+ '<button type="button" @click.prevent.stop="on_step" data-step="-1" v-bind:data-controls="\'input_\' + input_name" class="pretix-widget-btn-default pretix-widget-item-count-dec" v-bind:aria-label="dec_label"><span>-</span></button>'
+ '<input ref="quantity" type="number" inputmode="numeric" pattern="\d*" class="pretix-widget-item-count-multiple" placeholder="0" min="0"'
+ ' :max="order_max" :name="input_name" :id="\'input_\' + input_name"'
+ ' v-bind:aria-labelledby="aria_labelledby"'
+ ' >'
+ '<button v-if="!$root.use_native_spinners" type="button" @click.prevent.stop="on_step" data-step="1" v-bind:data-controls="\'input_\' + input_name" class="pretix-widget-btn-default pretix-widget-item-count-inc" v-bind:aria-label="inc_label"><span>+</span></button>'
+ '<button type="button" @click.prevent.stop="on_step" data-step="1" v-bind:data-controls="\'input_\' + input_name" class="pretix-widget-btn-default pretix-widget-item-count-inc" v-bind:aria-label="inc_label"><span>+</span></button>'
+ '</div>'
+ '</div>'
+ '</div>'),
@@ -253,15 +252,17 @@ Vue.component('availbox', {
variation: Object
},
mounted: function() {
if (this.item.has_variations) {
this.$set(this.variation, 'amount_selected', 0);
} else {
// Automatically set the only available item to be selected.
this.$set(this.item, 'amount_selected', this.$root.itemnum === 1 && !this.$root.has_seating_plan ? 1 : 0);
if (this.$root.itemnum === 1 && !this.$root.has_seating_plan ? 1 : 0) {
this.$refs.quantity.value = 1;
if (this.order_max === 1) {
this.$refs.quantity.checked = true;
}
}
this.$root.$emit('amounts_changed')
},
computed: {
voucher_jump_link: function () {
return '#' + this.$root.html_id + '-voucher-input';
},
aria_labelledby: function () {
return this.$root.html_id + '-item-label-' + this.item.id;
},
@@ -271,11 +272,6 @@ Vue.component('availbox', {
inc_label: function () {
return '+ ' + (this.item.has_variations ? this.variation.value : this.item.name) + ': ' + strings.quantity_inc;
},
count_group_classes: function () {
return {
'pretix-widget-item-count-group': !this.$root.use_native_spinners
}
},
unavailability_reason_message: function () {
var reason = this.item.current_unavailability_reason || this.variation?.current_unavailability_reason;
if (reason) {
@@ -283,29 +279,6 @@ Vue.component('availbox', {
}
return "";
},
amount_selected: {
cache: false,
get: function () {
var selected = this.item.has_variations ? this.variation.amount_selected : this.item.amount_selected
if (selected === 0) return undefined;
return selected
},
set: function (value) {
// Unary operator to force boolean to integer conversion, as the HTML form submission
// needs the value to be integer for all products.
value = (+value);
if (this.item.has_variations) {
this.variation.amount_selected = value;
} else {
this.item.amount_selected = value;
}
if (this.$refs.quantity) {
// manually set value on quantity as on reload somehow v-model binding breaks
this.$refs.quantity.value = value;
}
this.$root.$emit("amounts_changed")
}
},
label_select_item: function () {
return this.item.has_variations
? strings.select_variant.replace("%s", this.variation.value)
@@ -341,14 +314,14 @@ Vue.component('availbox', {
}
},
methods: {
focus_voucher_field: function () {
this.$root.$emit('focus_voucher_field')
},
on_step: function (e) {
var t = e.target.tagName == 'BUTTON' ? e.target : e.target.closest('button');
var step = parseFloat(t.getAttribute("data-step"));
var controls = document.getElementById(t.getAttribute("data-controls"));
this.amount_selected = Math.max(controls.min, Math.min(controls.max || Number.MAX_SAFE_INTEGER, (this.amount_selected || 0) + step));
this.$refs.quantity.value = Math.max(controls.min, Math.min(controls.max || Number.MAX_SAFE_INTEGER, (parseInt(this.$refs.quantity.value || "0")) + step));
this.$refs.quantity.dispatchEvent(new CustomEvent("change", {
bubbles: true,
}));
}
}
});
@@ -537,12 +510,7 @@ Vue.component('item', {
+ '<div class="pretix-widget-item-info-col">'
+ '<a :href="item.picture_fullsize" v-if="item.picture" class="pretix-widget-item-picture-link" @click.prevent.stop="lightbox"><img :src="item.picture" class="pretix-widget-item-picture" :alt="picture_alt_text"></a>'
+ '<div class="pretix-widget-item-title-and-description">'
+ '<a v-if="item.has_variations && show_toggle" :id="item_label_id" role="heading" v-bind:aria-level="headingLevel" class="pretix-widget-item-title" :href="\'#\' + item.id + \'-variants\'"'
+ ' @click.prevent.stop="expand"'
+ '>'
+ '{{ item.name }}'
+ '</a>'
+ '<strong v-else class="pretix-widget-item-title" :id="item_label_id" role="heading" v-bind:aria-level="headingLevel">{{ item.name }}</strong>'
+ '<strong class="pretix-widget-item-title" :id="item_label_id" role="heading" v-bind:aria-level="headingLevel">{{ item.name }}</strong>'
+ '<div class="pretix-widget-item-description" :id="item_desc_id" v-if="item.description" v-html="item.description"></div>'
+ '<p class="pretix-widget-item-meta" v-if="item.order_min && item.order_min > 1">'
+ '<small>{{ min_order_str }}</small>'
@@ -566,8 +534,8 @@ Vue.component('item', {
// Availability
+ '<div class="pretix-widget-item-availability-col">'
+ '<a class="pretix-widget-collapse-indicator" v-if="show_toggle" :href="\'#\' + item.id + \'-variants\'" @click.prevent.stop="expand" role="button" tabindex="0"'
+ ' v-bind:aria-expanded="expanded ? \'true\': \'false\'" v-bind:aria-controls="item.id + \'-variants\'">{{ variationsToggleLabel }}</a>'
+ '<button type="button" class="pretix-widget-collapse-indicator" v-if="show_toggle" @click.prevent.stop="expand"'
+ ' v-bind:aria-expanded="expanded ? \'true\': \'false\'" v-bind:aria-controls="item.id + \'-variants\'" v-bind:aria-describedby="item_desc_id">{{ variationsToggleLabel }}</button>'
+ '<availbox v-if="!item.has_variations" :item="item"></availbox>'
+ '</div>'
@@ -622,7 +590,7 @@ Vue.component('item', {
image: this.item.picture_fullsize,
description: this.item.name,
}
}
},
},
computed: {
classObject: function () {
@@ -855,53 +823,54 @@ var shared_loading_fragment = (
);
var shared_iframe_fragment = (
'<div :class="frameClasses" role="dialog" aria-modal="true" aria-label="'+strings.checkout+'">'
'<dialog :class="frameClasses" role="alertdialog" aria-label="'+strings.checkout+'" @close="close" @cancel="cancel">'
+ '<div class="pretix-widget-frame-loading" v-show="$root.frame_loading">'
+ '<svg width="256" height="256" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path class="pretix-widget-primary-color" d="M1152 896q0-106-75-181t-181-75-181 75-75 181 75 181 181 75 181-75 75-181zm512-109v222q0 12-8 23t-20 13l-185 28q-19 54-39 91 35 50 107 138 10 12 10 25t-9 23q-27 37-99 108t-94 71q-12 0-26-9l-138-108q-44 23-91 38-16 136-29 186-7 28-36 28h-222q-14 0-24.5-8.5t-11.5-21.5l-28-184q-49-16-90-37l-141 107q-10 9-25 9-14 0-25-11-126-114-165-168-7-10-7-23 0-12 8-23 15-21 51-66.5t54-70.5q-27-50-41-99l-183-27q-13-2-21-12.5t-8-23.5v-222q0-12 8-23t19-13l186-28q14-46 39-92-40-57-107-138-10-12-10-24 0-10 9-23 26-36 98.5-107.5t94.5-71.5q13 0 26 10l138 107q44-23 91-38 16-136 29-186 7-28 36-28h222q14 0 24.5 8.5t11.5 21.5l28 184q49 16 90 37l142-107q9-9 24-9 13 0 25 10 129 119 165 170 7 8 7 22 0 12-8 23-15 21-51 66.5t-54 70.5q26 50 41 98l183 28q13 2 21 12.5t8 23.5z"/></svg>'
+ '<svg width="256" height="256" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path class="pretix-widget-primary-color" d="M1152 896q0-106-75-181t-181-75-181 75-75 181 75 181 181 75 181-75 75-181zm512-109v222q0 12-8 23t-20 13l-185 28q-19 54-39 91 35 50 107 138 10 12 10 25t-9 23q-27 37-99 108t-94 71q-12 0-26-9l-138-108q-44 23-91 38-16 136-29 186-7 28-36 28h-222q-14 0-24.5-8.5t-11.5-21.5l-28-184q-49-16-90-37l-141 107q-10 9-25 9-14 0-25-11-126-114-165-168-7-10-7-23 0-12 8-23 15-21 51-66.5t54-70.5q-27-50-41-99l-183-27q-13-2-21-12.5t-8-23.5v-222q0-12 8-23t19-13l186-28q14-46 39-92-40-57-107-138-10-12-10-24 0-10 9-23 26-36 98.5-107.5t94.5-71.5q13 0 26 10l138 107q44-23 91-38 16-136 29-186 7-28 36-28h222q14 0 24.5 8.5t11.5 21.5l28 184q49 16 90 37l142-107q9-9 24-9 13 0 25 10 129 119 165 170 7 8 7 22 0 12-8 23-15 21-51 66.5t-54 70.5q26 50 41 98l183 28q13 2 21 12.5t8 23.5z"/></svg>'
+ '<p :class="cancelBlockedClasses"><strong>'+strings.cancel_blocked+'</strong></p>'
+ '</div>'
+ '<div class="pretix-widget-frame-inner" ref="frame-container" v-show="$root.frame_shown">'
+ '<div class="pretix-widget-frame-close"><a href="#" @click.prevent.stop="close" role="button" aria-label="'+strings.close+'">'
+ '<svg alt="'+strings.close+'" height="16" viewBox="0 0 512 512" width="16" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M437.5,386.6L306.9,256l130.6-130.6c14.1-14.1,14.1-36.8,0-50.9c-14.1-14.1-36.8-14.1-50.9,0L256,205.1L125.4,74.5 c-14.1-14.1-36.8-14.1-50.9,0c-14.1,14.1-14.1,36.8,0,50.9L205.1,256L74.5,386.6c-14.1,14.1-14.1,36.8,0,50.9 c14.1,14.1,36.8,14.1,50.9,0L256,306.9l130.6,130.6c14.1,14.1,36.8,14.1,50.9,0C451.5,423.4,451.5,400.6,437.5,386.6z"/></svg>'
+ '</a></div>'
+ '<iframe frameborder="0" width="650" height="650" @load="iframeLoaded" '
+ ' :name="$root.parent.widget_id" src="about:blank" v-once'
+ ' allow="autoplay *; camera *; fullscreen *; payment *"'
+ ' title="'+strings.checkout+'"'
+ ' referrerpolicy="origin">'
+ 'Please enable frames in your browser!'
+ '</iframe>'
+ '</div>'
+ '<form class="pretix-widget-frame-close" method="dialog"><button aria-label="'+strings.close_checkout+'" autofocus="autofocus">'
+ '<svg alt="'+strings.close+'" height="16" viewBox="0 0 512 512" width="16" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M437.5,386.6L306.9,256l130.6-130.6c14.1-14.1,14.1-36.8,0-50.9c-14.1-14.1-36.8-14.1-50.9,0L256,205.1L125.4,74.5 c-14.1-14.1-36.8-14.1-50.9,0c-14.1,14.1-14.1,36.8,0,50.9L205.1,256L74.5,386.6c-14.1,14.1-14.1,36.8,0,50.9 c14.1,14.1,36.8,14.1,50.9,0L256,306.9l130.6,130.6c14.1,14.1,36.8,14.1,50.9,0C451.5,423.4,451.5,400.6,437.5,386.6z"/></svg>'
+ '</button></form>'
+ '<iframe frameborder="0" width="650" height="650" @load="iframeLoaded" '
+ ' :name="$root.parent.widget_id" src="about:blank" v-once'
+ ' allow="autoplay *; camera *; fullscreen *; payment *"'
+ ' title="'+strings.checkout+'"'
+ ' referrerpolicy="origin">'
+ 'Please enable frames in your browser!'
+ '</iframe>'
+ '</div>'
+ '</dialog>'
);
var shared_alert_fragment = (
'<div :class="alertClasses" role="alertdialog" v-bind:aria-labelledby="$root.parent.html_id + \'-error-message\'">'
+ '<transition name="bounce" @after-enter="focusButton">'
+ '<div class="pretix-widget-alert-box" v-if="$root.error_message">'
'<dialog :class="alertClasses" role="alertdialog" v-bind:aria-labelledby="$root.parent.html_id + \'-error-message\'" @close="errorClose">'
+ '<form class="pretix-widget-alert-box" method="dialog">'
+ '<p :id="$root.parent.html_id + \'-error-message\'">{{ $root.error_message }}</p>'
+ '<p><button v-if="$root.error_url_after" @click.prevent.stop="errorContinue">' + strings.continue + '</button>'
+ '<button v-else @click.prevent.stop="errorClose">' + strings.close + '</button></p>'
+ '</div>'
+ '<p><button v-if="$root.error_url_after" value="continue" autofocus v-bind:aria-describedby="$root.parent.html_id + \'-error-message\'">' + strings.continue + '</button>'
+ '<button v-else autofocus v-bind:aria-describedby="$root.parent.html_id + \'-error-message\'">' + strings.close + '</button></p>'
+ '</form>'
+ '<transition name="bounce">'
+ '<svg v-if="$root.error_message" width="64" height="64" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg" class="pretix-widget-alert-icon"><path style="fill:#ffffff;" d="M 599.86438,303.72882 H 1203.5254 V 1503.4576 H 599.86438 Z" /><path class="pretix-widget-primary-color" d="M896 128q209 0 385.5 103t279.5 279.5 103 385.5-103 385.5-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103zm128 1247v-190q0-14-9-23.5t-22-9.5h-192q-13 0-23 10t-10 23v190q0 13 10 23t23 10h192q13 0 22-9.5t9-23.5zm-2-344l18-621q0-12-10-18-10-8-24-8h-220q-14 0-24 8-10 6-10 18l17 621q0 10 10 17.5t24 7.5h185q14 0 23.5-7.5t10.5-17.5z"/></svg>'
+ '</transition>'
+ '<svg width="64" height="64" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg" class="pretix-widget-alert-icon"><path style="fill:#ffffff;" d="M 599.86438,303.72882 H 1203.5254 V 1503.4576 H 599.86438 Z" /><path class="pretix-widget-primary-color" d="M896 128q209 0 385.5 103t279.5 279.5 103 385.5-103 385.5-279.5 279.5-385.5 103-385.5-103-279.5-279.5-103-385.5 103-385.5 279.5-279.5 385.5-103zm128 1247v-190q0-14-9-23.5t-22-9.5h-192q-13 0-23 10t-10 23v190q0 13 10 23t23 10h192q13 0 22-9.5t9-23.5zm-2-344l18-621q0-12-10-18-10-8-24-8h-220q-14 0-24 8-10 6-10 18l17 621q0 10 10 17.5t24 7.5h185q14 0 23.5-7.5t10.5-17.5z"/></svg>'
+ '</div>'
+ '</dialog>'
);
var shared_lightbox_fragment = (
'<div :class="lightboxClasses" role="dialog" aria-modal="true" v-if="$root.lightbox" @click="lightboxClose">'
'<dialog :class="lightboxClasses" role="alertdialog" @close="lightboxClose">'
+ '<div class="pretix-widget-lightbox-loading" v-if="$root.lightbox?.loading">'
+ '<svg width="256" height="256" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path class="pretix-widget-primary-color" d="M1152 896q0-106-75-181t-181-75-181 75-75 181 75 181 181 75 181-75 75-181zm512-109v222q0 12-8 23t-20 13l-185 28q-19 54-39 91 35 50 107 138 10 12 10 25t-9 23q-27 37-99 108t-94 71q-12 0-26-9l-138-108q-44 23-91 38-16 136-29 186-7 28-36 28h-222q-14 0-24.5-8.5t-11.5-21.5l-28-184q-49-16-90-37l-141 107q-10 9-25 9-14 0-25-11-126-114-165-168-7-10-7-23 0-12 8-23 15-21 51-66.5t54-70.5q-27-50-41-99l-183-27q-13-2-21-12.5t-8-23.5v-222q0-12 8-23t19-13l186-28q14-46 39-92-40-57-107-138-10-12-10-24 0-10 9-23 26-36 98.5-107.5t94.5-71.5q13 0 26 10l138 107q44-23 91-38 16-136 29-186 7-28 36-28h222q14 0 24.5 8.5t11.5 21.5l28 184q49 16 90 37l142-107q9-9 24-9 13 0 25 10 129 119 165 170 7 8 7 22 0 12-8 23-15 21-51 66.5t-54 70.5q26 50 41 98l183 28q13 2 21 12.5t8 23.5z"/></svg>'
+ '</div>'
+ '<div class="pretix-widget-lightbox-inner" @click.stop="">'
+ '<div class="pretix-widget-lightbox-inner" v-if="$root.lightbox">'
+ '<form class="pretix-widget-lightbox-close" method="dialog"><button aria-label="'+strings.close+'" autofocus="autofocus">'
+ '<svg alt="'+strings.close+'" height="16" viewBox="0 0 512 512" width="16" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M437.5,386.6L306.9,256l130.6-130.6c14.1-14.1,14.1-36.8,0-50.9c-14.1-14.1-36.8-14.1-50.9,0L256,205.1L125.4,74.5 c-14.1-14.1-36.8-14.1-50.9,0c-14.1,14.1-14.1,36.8,0,50.9L205.1,256L74.5,386.6c-14.1,14.1-14.1,36.8,0,50.9 c14.1,14.1,36.8,14.1,50.9,0L256,306.9l130.6,130.6c14.1,14.1,36.8,14.1,50.9,0C451.5,423.4,451.5,400.6,437.5,386.6z"/></svg>'
+ '</button></form>'
+ '<figure class="pretix-widget-lightbox-image">'
+ '<img :src="$root.lightbox.image" :alt="$root.lightbox.description" @load="lightboxLoaded" ref="lightboxImage" crossorigin>'
+ '<figcaption v-if="$root.lightbox.description">{{$root.lightbox.description}}</figcaption>'
+ '</figure>'
+ '<button type="button" class="pretix-widget-lightbox-close" @click="lightboxClose" aria-label="'+strings.close+'">'
+ '<svg alt="'+strings.close+'" height="16" viewBox="0 0 512 512" width="16" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M437.5,386.6L306.9,256l130.6-130.6c14.1-14.1,14.1-36.8,0-50.9c-14.1-14.1-36.8-14.1-50.9,0L256,205.1L125.4,74.5 c-14.1-14.1-36.8-14.1-50.9,0c-14.1,14.1-14.1,36.8,0,50.9L205.1,256L74.5,386.6c-14.1,14.1-14.1,36.8,0,50.9 c14.1,14.1,36.8,14.1,50.9,0L256,306.9l130.6,130.6c14.1,14.1,36.8,14.1,50.9,0C451.5,423.4,451.5,400.6,437.5,386.6z"/></svg>'
+ '</button>'
+ '</div>'
+ '</div>'
+ '</dialog>'
);
Vue.component('pretix-overlay', {
@@ -911,6 +880,11 @@ Vue.component('pretix-overlay', {
+ shared_lightbox_fragment
+ '</div>'
),
data: function () {
return {
cancelBlocked: false,
}
},
watch: {
'$root.lightbox': function (newValue, oldValue) {
if (newValue) {
@@ -918,18 +892,24 @@ Vue.component('pretix-overlay', {
this.$set(newValue, "loading", true);
}
if (!oldValue) {
window.addEventListener('keyup', this.lightboxCloseOnKeyup);
this.$el?.querySelector(".pretix-widget-lightbox-holder").showModal();
}
} else {
window.removeEventListener('keyup', this.lightboxCloseOnKeyup);
}
}
},
'$root.error_message': function (newValue, oldValue) {
if (newValue) {
if (!oldValue) {
this.$el?.querySelector(".pretix-widget-alert-holder").showModal();
}
}
},
},
computed: {
frameClasses: function () {
return {
'pretix-widget-frame-holder': true,
'pretix-widget-frame-shown': this.$root.frame_shown || this.$root.frame_loading,
'pretix-widget-frame-isloading': this.$root.frame_loading,
};
},
alertClasses: function () {
@@ -945,54 +925,67 @@ Vue.component('pretix-overlay', {
'pretix-widget-lightbox-isloading': this.$root.lightbox?.loading,
};
},
cancelBlockedClasses: function () {
return {
'pretix-widget-visibility-hidden': !this.cancelBlocked,
}
},
},
methods: {
lightboxCloseOnKeyup: function (event) {
if (event.keyCode === 27) {
// abort on ESC-key
this.lightboxClose();
}
},
lightboxClose: function () {
this.$root.lightbox = null;
},
lightboxLoaded: function () {
this.$root.lightbox.loading = false;
},
errorClose: function () {
errorClose: function (e) {
var dialog = e.target;
if (dialog.returnValue == "continue" && this.$root.error_url_after) {
if (this.$root.error_url_after_new_tab) {
window.open(this.$root.error_url_after);
} else if (this.$root.overlay) {
this.$root.overlay.frame_src = this.$root.error_url_after;
this.$root.frame_loading = true;
}
}
this.$root.error_message = null;
this.$root.error_url_after = null;
this.$root.error_url_after_new_tab = false;
},
errorContinue: function () {
if (this.$root.error_url_after_new_tab) {
window.open(this.$root.error_url_after);
close: function (e) {
if (this.$root.frame_loading) {
// Chrome does not allow blocking dialog.cancel event more than once
// => wiggle the loading-element and re-open the modal
this.cancel(e);
e.target.showModal();
return;
}
this.$root.overlay.frame_src = this.$root.error_url_after;
this.$root.frame_loading = true;
this.$root.error_message = null;
this.$root.error_url_after = null;
},
close: function () {
this.$root.frame_shown = false;
this.$root.parent.frame_dismissed = true;
this.$root.frame_src = "";
this.$root.parent.reload();
this.$root.parent.trigger_close_callback();
},
cancel: function (e) {
// do not allow to cancel while frame is loading as we cannot abort the operation
if (this.$root.frame_loading) {
e.preventDefault();
e.target.addEventListener("animationend", function () {
e.target.classList.remove("pretix-widget-shake-once");
}, {once: true});
e.target.classList.add("pretix-widget-shake-once");
this.cancelBlocked = true;
}
},
iframeLoaded: function () {
if (this.$root.frame_loading) {
this.$root.frame_loading = false;
this.cancelBlocked = false;
if (this.$root.frame_src) {
this.$root.frame_shown = true;
}
}
},
focusButton: function () {
this.$el.querySelector(".pretix-widget-alert-box button").focus();
},
}
});
@@ -1033,13 +1026,11 @@ Vue.component('pretix-widget-event-form', {
+ '<div class="pretix-widget-error-message" v-if="$root.error">{{ $root.error }}</div>'
// Resume cart
+ '<div class="pretix-widget-info-message pretix-widget-clickable"'
+ ' v-if="$root.cart_exists">'
+ '<div class="pretix-widget-info-message pretix-widget-clickable" v-if="$root.cart_exists">'
+ '<span :id="id_cart_exists_msg">' + strings['cart_exists'] + '</span>'
+ '<button @click.prevent.stop="$parent.resume" class="pretix-widget-resume-button" type="button" v-bind:aria-describedby="id_cart_exists_msg">'
+ strings['resume_checkout']
+ '</button>'
+ '<span :id="id_cart_exists_msg">' + strings['cart_exists'] + '</span>'
+ '<div class="pretix-widget-clear"></div>'
+ '</div>'
// Seating plan
@@ -1067,7 +1058,10 @@ Vue.component('pretix-widget-event-form', {
// Buy button
+ '<div class="pretix-widget-action" v-if="$root.display_add_to_cart">'
+ '<button type="submit">{{ this.buy_label }}</button>'
+ '<button v-if="!this.$root.cart_exists || this.is_items_selected" type="submit" v-bind:aria-describedby="id_cart_exists_msg">{{ buy_label }}</button>'
+ '<button v-else @click.prevent.stop="$parent.resume" type="button" v-bind:aria-describedby="id_cart_exists_msg">'
+ strings['resume_checkout']
+ '</button>'
+ '</div>'
+ '</form>'
@@ -1079,7 +1073,7 @@ Vue.component('pretix-widget-event-form', {
+ '<h3 class="pretix-widget-voucher-headline" :id="aria_labelledby">'+ strings['redeem_voucher'] +'</h3>'
+ '<div v-if="$root.voucher_explanation_text" class="pretix-widget-voucher-text" v-html="$root.voucher_explanation_text"></div>'
+ '<div class="pretix-widget-voucher-input-wrap">'
+ '<input class="pretix-widget-voucher-input" ref="voucherinput" type="text" v-model="$parent.voucher" name="voucher" placeholder="'+strings.voucher_code+'" v-bind:aria-labelledby="aria_labelledby">'
+ '<input :id="id_voucher_input" class="pretix-widget-voucher-input" ref="voucherinput" type="text" v-model="$parent.voucher" name="voucher" placeholder="'+strings.voucher_code+'" v-bind:aria-labelledby="aria_labelledby">'
+ '</div>'
+ '<input type="hidden" v-for="p in hiddenParams" :name="p[0]" :value="p[1]" />'
+ '<div class="pretix-widget-voucher-button-wrap">'
@@ -1091,14 +1085,32 @@ Vue.component('pretix-widget-event-form', {
+ '</div>'
),
data: function () {
return {
is_items_selected: false,
}
},
watch: {
'$root.overlay.frame_shown': function (newValue) {
if (!newValue) {
this.$refs.form.reset();
this.calc_items_selected();
}
}
},
mounted: function() {
this.$root.$on('focus_voucher_field', this.focus_voucher_field)
this.$root.$on('focus_voucher_field', this.focus_voucher_field);
this.$refs.form.addEventListener("change", this.calc_items_selected);
},
beforeDestroy: function() {
this.$root.$off('focus_voucher_field', this.focus_voucher_field)
this.$root.$off('focus_voucher_field', this.focus_voucher_field);
this.$refs.form.removeEventListener("change", this.calc_items_selected);
},
computed: {
aria_labelledby: function() {
id_voucher_input: function () {
return this.$root.html_id + '-voucher-input';
},
aria_labelledby: function () {
return this.$root.html_id + '-voucher-headline';
},
display_event_info: function () {
@@ -1143,10 +1155,6 @@ Vue.component('pretix-widget-event-form', {
},
},
methods: {
focus_voucher_field: function() {
this.$refs.voucherinput.scrollIntoView(false)
this.$refs.voucherinput.focus()
},
back_to_list: function() {
this.$root.target_url = this.$root.parent_stack.pop();
this.$root.error = null;
@@ -1173,32 +1181,26 @@ Vue.component('pretix-widget-event-form', {
$el.focus();
});
},
calc_items_selected: function () {
this.is_items_selected = [...this.$refs.form.querySelectorAll("input[type=checkbox], input[type=radio]")].some(function(element) {
return element.checked;
}) || [...this.$refs.form.querySelectorAll(".pretix-widget-item-count-group input")].some(function(element) {
return parseInt(element.value || "0") > 0;
});
},
}
});
Vue.component('pretix-widget-event-list-filter-field', {
template: ('<div class="pretix-widget-event-list-filter-field">'
+ '<label :for="id">{{ field.label }}</label>'
+ '<select :id="id" :name="field.key" @change="onChange($event)" :value="currentValue">'
+ '<select :id="id" :name="field.key" :value="currentValue">'
+ '<option v-for="choice in field.choices" :value="choice[0]">{{ choice[1] }}</option>'
+ '</select>'
+ '</div>'),
props: {
field: Object
},
methods: {
onChange: function(event) {
var filterParams = new URLSearchParams(this.$root.filter);
if (event.target.value) {
filterParams.set(this.field.key, event.target.value);
} else {
filterParams.delete(this.field.key);
}
this.$root.filter = filterParams.toString();
this.$root.loading++;
this.$root.reload();
},
},
computed: {
id: function () {
return widget_id + "_" + this.field.key;
@@ -1211,9 +1213,29 @@ Vue.component('pretix-widget-event-list-filter-field', {
});
Vue.component('pretix-widget-event-list-filter-form', {
template: ('<div class="pretix-widget-event-list-filter-form">'
+ '<pretix-widget-event-list-filter-field v-for="field in $root.meta_filter_fields" :field="field" :key="field.key"></pretix-widget-event-list-filter-field>'
+ '</div>'),
template: ('<form ref="filterform" class="pretix-widget-event-list-filter-form" @submit="onSubmit">'
+ '<fieldset class="pretix-widget-event-list-filter-fieldset">'
+ '<legend>' + strings.filter_events_by + '</legend>'
+ '<pretix-widget-event-list-filter-field v-for="field in $root.meta_filter_fields" :field="field" :key="field.key"></pretix-widget-event-list-filter-field>'
+ '<button>' + strings.filter + '</button>'
+ '</fieldset>'
+ '</form>'),
methods: {
onSubmit: function(e) {
e.preventDefault();
var formData = new FormData(this.$refs.filterform);
var filterParams = new URLSearchParams(formData);
formData.forEach(function (value, key) {
if (value == "") {
filterParams.delete(key);
}
});
this.$root.filter = filterParams.toString();
this.$root.loading++;
this.$root.reload();
},
},
});
Vue.component('pretix-widget-event-list-entry', {
@@ -1740,7 +1762,7 @@ Vue.component('pretix-widget', {
return {
'pretix-widget': true,
'pretix-widget-mobile': this.mobile,
'pretix-widget-use-custom-spinners': !this.$root.use_native_spinners
'pretix-widget-use-custom-spinners': true,
};
}
}
@@ -1902,7 +1924,6 @@ var shared_root_methods = {
root.categories = data.items_by_category;
root.currency = data.currency;
root.display_net_prices = data.display_net_prices;
root.use_native_spinners = data.use_native_spinners;
root.voucher_explanation_text = data.voucher_explanation_text;
root.error = data.error;
root.display_add_to_cart = data.display_add_to_cart;
@@ -2161,28 +2182,11 @@ var create_overlay = function (app) {
// show loading spinner only when previously no frame_src was set
if (newValue && !oldValue) {
this.frame_loading = true;
this.$el?.querySelector('dialog.pretix-widget-frame-holder').showModal();
}
// to close and unload the iframe, frame_src can be empty -> make it valid HTML with about:blank
this.$el.querySelector("iframe").src = newValue || "about:blank";
},
frame_shown: function (newValue) {
if (newValue) {
this.prevActiveElement = document.activeElement;
var btn = this.$el?.querySelector(".pretix-widget-frame-close a");
this.$nextTick(function () {
btn?.focus();
});
} else {
this.prevActiveElement?.focus();
}
},
error_message: function (newValue) {
if (newValue) {
this.prevActiveElement = document.activeElement;
} else {
this.prevActiveElement?.focus();
}
},
}
});
app.$root.overlay = framechild;
@@ -2228,7 +2232,6 @@ var create_widget = function (element, html_id=null) {
var items = element.attributes.items ? element.attributes.items.value : null;
var variations = element.attributes.variations ? element.attributes.variations.value : null;
var categories = element.attributes.categories ? element.attributes.categories.value : null;
var single_item_select = element.getAttribute("single-item-select") || "checkbox";
for (var i = 0; i < element.attributes.length; i++) {
var attrib = element.attributes[i];
if (attrib.name.match(/^data-.*$/)) {
@@ -2275,8 +2278,6 @@ var create_widget = function (element, html_id=null) {
variation_filter: variations,
voucher_code: voucher,
display_net_prices: false,
use_native_spinners: false,
single_item_select: single_item_select,
voucher_explanation_text: null,
show_variations_expanded: !!variations,
skip_ssl: skip_ssl,

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
// before variables.scss because it only affects presale, not control
$body-bg: #f5f5f5 !default;
$input-border: #949494;
$font-size-base: 0.875rem !default;/* 14px/16px = 0.875rem */

View File

@@ -9,7 +9,7 @@
.pretix-widget, .pretix-widget-alert-box {
a {
color: $link-color;
text-decoration: none;
text-decoration: underline;
&:hover,
&:focus {
@@ -17,9 +17,9 @@
text-decoration: $link-hover-decoration;
}
&:focus {
outline: thin dotted;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
outline: 2px solid $brand-primary;
outline-offset: 2px;
z-index: 999;
}
}
img {
@@ -57,6 +57,9 @@
&.focus {
text-decoration: none;
@include tab-focus;
outline: 2px solid $brand-primary;
outline-offset: 2px;
z-index: 999;
}
}
&.disabled,
@@ -72,6 +75,7 @@
}
label.pretix-widget-btn-checkbox {
@include button-variant($btn-default-color, $btn-default-bg, $btn-default-border, darken($btn-default-bg, 10%), darken($btn-default-border, 25%), darken($btn-default-border, 12%));
border-radius: $input-border-radius;
border-width: 1px;
border-style: solid;
position: relative;
@@ -88,6 +92,11 @@
background-color: #e6e6e6;
border-color: #adadad;
}
&:focus-within {
outline: 2px solid $brand-primary;
outline-offset: 2px;
z-index: 999;
}
}
.pretix-widget-icon-cart {
display: inline-block;
@@ -114,9 +123,9 @@
$color-rgba: rgba(red($input-border-focus), green($input-border-focus), blue($input-border-focus), .6);
&:focus {
border-color: $input-border-focus;
outline: 0;
@include box-shadow(inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px $color-rgba);
outline: 2px solid $brand-primary;
outline-offset: 2px;
z-index: 999;
}
}
input[type=number] {
@@ -151,7 +160,6 @@
border-radius: $input-border-radius;
.pretix-widget-resume-button {
float: right;
margin-left: 10px;
}
@@ -160,6 +168,9 @@
}
.pretix-widget-info-message {
display: flex;
justify-content: space-between;
align-items: flex-end;
padding: 10px;
text-align: left;
margin: 10px 0;
@@ -168,6 +179,15 @@
color: $state-info-text;
border-radius: $alert-border-radius;
}
&.pretix-widget-mobile {
.pretix-widget-info-message {
flex-direction: column;
}
.pretix-widget-resume-button {
margin-top: 10px;
margin-left: 0;
}
}
.pretix-widget-error-message {
padding: 10px;
@@ -352,12 +372,15 @@
font-size: 12px;
}
.pretix-widget-item-picture {
.pretix-widget-item-picture-link {
width: 60px;
height: 60px;
margin-right: 10px;
float: left;
}
.pretix-widget-item-picture {
max-width: 100%;
}
.pretix-widget-action {
margin-left: 75%;
@@ -431,6 +454,17 @@
.pretix-widget-item-availability-col {
text-align: center;
.pretix-widget-collapse-indicator {
width: 100%;
border: 1px solid $input-border;
border-radius: $input-border-radius;
height: $input-height-base;
padding: $padding-base-vertical $padding-base-horizontal;
color: $input-color;
background-color: $input-bg;
}
.pretix-widget-collapse-indicator::before {
content: "";
display: inline-block;
@@ -514,6 +548,10 @@
flex-wrap: wrap;
color: $text-color;
&:has(.pretix-widget-event-list-entry-availability) {
text-decoration: none;
}
&:hover, &:active, &:focus {
background: $gray-lighter;
text-decoration: none;
@@ -540,41 +578,59 @@
padding: 7px 5px 3px;
box-sizing: border-box;
span {
position: relative;
display: inline;
padding: 2px 6px 3px;
padding: 6px 6px 4px 17px;
font-size: 75%;
font-weight: bold;
line-height: 1;
color: #fff;
color: var(--status-text-color, #000);
background-color: var(--status-bg-color, #fff);
border: 1px solid var(--status-border-color, #000);
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: 4px;
}
span:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 11px;
height: 100%;
background: var(--status-border-color, #000);
}
}
}
.pretix-widget-event-availability-orange .pretix-widget-event-list-entry-availability span,
.pretix-widget-event-availability-orange.pretix-widget-event-calendar-event {
background-color: $brand-warning;
.pretix-widget-event-availability-orange,
.pretix-widget-day-availability-orange {
--status-bg-color: #{$alert-warning-bg};
--status-text-color: #{$alert-warning-text};
--status-border-color: #{$alert-warning-border};
}
.pretix-widget-event-availability-none .pretix-widget-event-list-entry-availability span,
.pretix-widget-event-availability-none.pretix-widget-event-calendar-event {
background-color: $brand-primary;
.pretix-widget-event-availability-none,
.pretix-widget-day-availability-none {
--status-bg-color: #{$alert-primary-bg};
--status-text-color: #{$alert-primary-text};
--status-border-color: #{$alert-primary-border};
}
.pretix-widget-event-availability-green .pretix-widget-event-list-entry-availability span,
.pretix-widget-event-availability-green.pretix-widget-event-calendar-event {
background-color: $brand-success;
.pretix-widget-event-availability-green,
.pretix-widget-day-availability-green {
--status-bg-color: #{$alert-success-bg};
--status-text-color: #{$alert-success-text};
--status-border-color: #{$alert-success-border};
}
.pretix-widget-event-availability-red .pretix-widget-event-list-entry-availability span,
.pretix-widget-event-availability-red.pretix-widget-event-calendar-event {
background-color: $brand-danger;
.pretix-widget-event-availability-red,
.pretix-widget-day-availability-red {
--status-bg-color: #{$alert-danger-bg};
--status-text-color: #{$alert-danger-text};
--status-border-color: #{$alert-danger-border};
}
.pretix-widget-event-availability-low .pretix-widget-event-list-entry-availability span {
border-left: 10px solid $brand-warning;
}
.pretix-widget-event-availability-low.pretix-widget-event-calendar-event {
border-right: 10px solid $brand-warning;
.pretix-widget-event-list .pretix-widget-event-availability-low .pretix-widget-event-list-entry-availability span:before,
.pretix-widget-event-calendar .pretix-widget-event-availability-low.pretix-widget-event-calendar-event:before {
background: linear-gradient(to bottom, var(--pretix-brand-warning) 1em, var(--status-border-color) 2.5em);
}
.pretix-widget-event-calendar {
@@ -587,7 +643,7 @@
.pretix-widget-event-week-col {
flex: 1;
margin: 0 5px;
margin: 0;
&:first-child {
margin-left: 0;
@@ -595,6 +651,12 @@
&:last-child {
margin-right: 0;
}
&:nth-child(even) {
background-color: $table-bg-accent;
}
.pretix-widget-event-calendar-events {
margin: 4px;
}
}
}
@@ -616,31 +678,62 @@
}
}
.pretix-widget-event-calendar-event {
position: relative;
display: block;
border-radius: 4px;
border: 1px solid var(--status-border-color, #000);
background-color: var(--status-bg-color, #fff);
color: var(--status-text-color, #000);
padding: 5px;
color: white;
padding-left: 17px;
cursor: pointer;
margin-bottom: 5px;
&:before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 11px;
height: 100%;
background: var(--status-border-color, #000);
}
&:last-child {
margin-bottom: 0;
}
&:hover {
text-decoration: none;
}
text-decoration: none;
}
.pretix-widget-event-calendar-table {
width: 100%;
border-spacing: 0;
th, td {
width: 14.285714285714286%;
vertical-align: top;
padding: 10px 5px;
padding: 4px;
border-bottom: 1px solid $table-border-color;
}
th {
border-bottom-width: 2px;
color: $text-muted;
}
td:has(.pretix-widget-event-calendar-day):nth-child(even) {
background: $table-bg-accent;
}
}
.pretix-widget-event-calendar-day {
font-weight: bold;
font-size: 86%;
padding: 5px 5px 1em;
}
.pretix-widget-event-week-table .pretix-widget-event-calendar-day {
padding-bottom: 5px;
background-color: #fff;
border-bottom: 2px solid $table-border-color;
color: $text-muted;
font-size: 100%;
}
}
@@ -656,9 +749,24 @@
.pretix-widget-event-list-filter-form {
display: flex;
flex-direction: row;
align-items: end;
.pretix-widget-event-list-filter-fieldset {
display: flex;
flex-direction: row;
align-items: end;
border: none;
padding: 0;
margin: 0;
> legend {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
}
margin-bottom: 15px;
.pretix-widget-event-list-filter-field {
@@ -667,7 +775,7 @@
margin: 0 15px 0 0;
label {
display: inline-block;
display: block;
font-weight: bold;
margin-bottom: 5px;
}
@@ -682,7 +790,9 @@
}
}
.pretix-widget.pretix-widget-mobile .pretix-widget-event-list-filter-form {
display: block;
.pretix-widget-event-list-filter-fieldset {
display: block;
}
.pretix-widget-event-list-filter-field {
display: block;
@@ -701,24 +811,120 @@
transform: scale(1);
}
}
.pretix-widget-alert-holder {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.8);
z-index: 16777271;
.pretix-widget-visibility-hidden {
visibility: hidden;
opacity: 0;
transition: opacity 0.5s; /* do not animate visibility or we'll have a flashing thing on load */
}
.pretix-widget-shake-once {
animation: pretix-widget-shake .2s;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
}
&.pretix-widget-alert-shown {
visibility: visible;
opacity: 1;
transition: opacity 0.5s, visibility 0.5s;
@keyframes pretix-widget-shake {
0% { transform: skewX(0deg); }
20% { transform: skewX(-5deg); }
40% { transform: skewX(5deg); }
60% { transform: skewX(-5deg); }
80% { transform: skewX(5deg); }
100% { transform: skewX(0deg); }
}
.pretix-widget-alert-holder,
.pretix-widget-frame-holder,
.pretix-widget-lightbox-holder {
border: none;
background: transparent;
overflow: visible;
&::backdrop {
background: rgba(255, 255, 255, 0.8);
}
&:focus {
outline: 2px solid $brand-primary;
outline-offset: 2px;
}
}
.pretix-widget-frame-isloading:focus {
outline: none;
svg {
outline: 2px solid $brand-primary;
border-radius: 100%;
}
}
.pretix-widget-frame-loading p,
.pretix-widget-lightbox-loading p {
text-align: center;
width: 256px;
margin: 0 auto;
color: $brand-danger;
}
.pretix-widget-frame-loading svg,
.pretix-widget-lightbox-loading svg {
margin: 40px;
-webkit-animation: pretix-widget-spin 6s linear infinite;
-moz-animation: pretix-widget-spin 6s linear infinite;
animation: pretix-widget-spin 6s linear infinite;
}
.pretix-widget-frame-close,
.pretix-widget-lightbox-close {
position: absolute;
top: -12px;
right: -12px;
z-index: 2;
}
.pretix-widget-frame-close button,
.pretix-widget-lightbox-close button {
color: white;
cursor: pointer;
font-weight: bold;
font-family: sans-serif;
text-decoration: none;
padding: 4px 0;
display: inline-block;
line-height: 16px;
border: none;
background: none;
width: 24px;
height: 24px;
background: $brand-primary;
border-radius: 12px;
-moz-border-radius: 12px;
-webkit-border-radius: 12px;
text-align: center;
&:focus {
outline: 2px solid $brand-primary;
outline-offset: 2px;
}
}
.pretix-widget-frame-close svg,
.pretix-widget-lightbox-close svg {
display: inline-block;
border: none;
}
.pretix-widget-frame-inner,
.pretix-widget-lightbox-inner,
.pretix-widget-alert-box {
position: relative;
background: white;
border-radius: 5px 5px 5px 5px;
-moz-border-radius: 5px 5px 5px 5px;
-webkit-border-radius: 5px 5px 5px 5px;
box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
-webkit-box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
-moz-box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
box-sizing: border-box;
padding: 10px;
}
.pretix-widget-alert-holder {
.bounce-enter-active {
animation: pretix-widget-bounce-in .5s;
}
@@ -727,19 +933,6 @@
}
.pretix-widget-alert-box {
position: fixed;
left: 50%;
width: 600px;
margin-left: -300px;
top: 100px;
background: white;
border-radius: 5px 5px 5px 5px;
-moz-border-radius: 5px 5px 5px 5px;
-webkit-border-radius: 5px 5px 5px 5px;
box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
-webkit-box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
-moz-box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
box-sizing: border-box;
padding: 42px 20px 20px 20px;
text-align: center;
font-size: 20px;
@@ -752,197 +945,47 @@
}
}
.pretix-widget-alert-icon {
position: fixed;
position: absolute;
left: 50%;
width: 64px;
margin-left: -32px;
top: 68px;
top: -20px;
}
}
.pretix-widget-frame-holder {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.8);
z-index: 16777271;
.pretix-widget-frame-inner {
width: 80vw;
height: 80vh;
}
.pretix-widget-frame-inner iframe {
width: 100% !important;
height: 100% !important;
}
.pretix-widget-lightbox-inner {
max-width: 90vw;
max-height: 90vh;
}
.pretix-widget-lightbox-isloading .pretix-widget-lightbox-inner {
visibility: hidden;
opacity: 0;
transition: opacity 0.5s, visibility 0.5s;
.pretix-widget-frame-loading {
text-align: center;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
position: fixed;
left: 0;
top: 0;
}
.pretix-widget-frame-loading svg {
margin: 40px;
-webkit-animation: pretix-widget-spin 6s linear infinite;
-moz-animation: pretix-widget-spin 6s linear infinite;
animation: pretix-widget-spin 6s linear infinite;
}
&.pretix-widget-frame-shown {
visibility: visible;
opacity: 1;
transition: opacity 0.5s, visibility 0.5s;
}
.pretix-widget-frame-inner {
position: fixed;
left: 10%;
width: 80%;
height: 80%;
top: 10%;
background: white;
border-radius: 5px 5px 5px 5px;
-moz-border-radius: 5px 5px 5px 5px;
-webkit-border-radius: 5px 5px 5px 5px;
box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
-webkit-box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
-moz-box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
box-sizing: border-box;
padding: 10px;
}
.pretix-widget-frame-close {
position: fixed;
right: 10%;
top: 10%;
width: 24px;
height: 24px;
background: $brand-primary;
margin: -12px -12px 0 0;
border-radius: 12px;
-moz-border-radius: 12px;
-webkit-border-radius: 12px;
text-align: center;
}
.pretix-widget-frame-close a {
color: white;
font-weight: bold;
font-family: sans-serif;
text-decoration: none;
padding: 4px 0;
display: inline-block;
line-height: 16px;
}
.pretix-widget-frame-close svg {
display: inline-block;
border: none;
}
.pretix-widget-frame-inner iframe {
width: 100% !important;
height: 100% !important;
}
}
.pretix-widget-lightbox-image {
margin: 0;
padding: 0;
text-align: center;
}
.pretix-widget-lightbox-image img {
max-width: 80vw;
max-height: 80vh;
object-fit: scale-down;
}
.pretix-widget-lightbox-image figcaption {
margin: 0.5em 0 0;
}
.pretix-widget-lightbox-holder {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.8);
z-index: 16777271;
visibility: hidden;
opacity: 0;
transition: opacity 0.5s, visibility 0.5s;
display: flex;
align-items: center;
justify-content: center;
.pretix-widget-lightbox-loading svg {
margin: 40px;
-webkit-animation: pretix-widget-spin 6s linear infinite;
-moz-animation: pretix-widget-spin 6s linear infinite;
animation: pretix-widget-spin 6s linear infinite;
}
&.pretix-widget-lightbox-shown {
visibility: visible;
opacity: 1;
transition: opacity 0.5s, visibility 0.5s;
}
.pretix-widget-lightbox-inner {
position: relative;
background: white;
border-radius: 5px 5px 5px 5px;
-moz-border-radius: 5px 5px 5px 5px;
-webkit-border-radius: 5px 5px 5px 5px;
box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
-webkit-box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
-moz-box-shadow: 0 4px 18px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.09);
box-sizing: border-box;
padding: 10px;
max-width: 90%;
max-height: 90%;
}
&.pretix-widget-lightbox-isloading .pretix-widget-lightbox-inner {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0,0,0,0);
border: 0;
}
.pretix-widget-lightbox-image {
margin: 0;
padding: 0;
text-align: center;
}
.pretix-widget-lightbox-image img {
max-width: 80vw;
max-height: 80vh;
object-fit: scale-down;
}
.pretix-widget-lightbox-image figcaption {
margin: 0.5em 0 0;
}
.pretix-widget-lightbox-close {
position: absolute;
right: -12px;
top: -12px;
width: 24px;
height: 24px;
background: $brand-primary;
margin: 0;
border: none;
border-radius: 12px;
-moz-border-radius: 12px;
-webkit-border-radius: 12px;
text-align: center;
color: white;
font-weight: bold;
font-family: sans-serif;
text-decoration: none;
padding: 4px 0;
display: inline-block;
line-height: 16px;
cursor: pointer;
}
.pretix-widget-lightbox-close svg {
display: inline-block;
border: none;
}
}
.pretix-widget-primary-color {
/* in SVG */
@@ -1015,22 +1058,14 @@
display: block;
}
}
td.pretix-widget-has-events {
background: $brand-primary;
color: white;
td.pretix-widget-has-events .pretix-widget-event-calendar-day {
background: var(--status-bg-color, #fff);
color: var(--status-text-color, #000);
border: 1px solid var(--status-border-color, inherit);
border-top-width: 11px;
padding-bottom: 5px;
border-radius: $input-border-radius;
cursor: pointer;
&.pretix-widget-day-availability-red {
background: $brand-danger;
}
&.pretix-widget-day-availability-green {
background: $brand-success;
}
&.pretix-widget-day-availability-low {
border-right: 5px solid $brand-warning;
}
&.pretix-widget-day-availability-orange {
background: $brand-warning;
}
}
.pretix-widget-event-calendar-head {
@@ -1048,41 +1083,3 @@
}
}
@media (min-width: 1200px) {
.pretix-widget-frame-holder {
.pretix-widget-frame-inner {
left: 50%;
margin-left: -540px;
width: 1080px;
}
.pretix-widget-frame-close {
left: 50%;
margin-left: 528px;
}
}
}
@media (max-width: 800px) {
.pretix-widget-frame-holder .pretix-widget-frame-inner {
left: 0;
width: 100%;
height: 100%;
top: 0;
background: $brand-primary;
border-radius: 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
box-shadow: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
padding: 40px 0 0 0;
}
.pretix-widget-frame-holder .pretix-widget-frame-close {
right: 20px;
top: 20px;
background: white;
svg path {
fill: $brand-primary;
}
}
}

File diff suppressed because it is too large Load Diff