From 92f7456eca5fc1f93cf43e8698348a4207f90e74 Mon Sep 17 00:00:00 2001
From: Richard Schreiber
<link rel="stylesheet" type="text/css" href="{% abseventurl request.event "presale:event.widget.css" %}" crossorigin>
-<script type="text/javascript" src="{{ urlprefix }}{% url "presale:widget.js" lang=form.cleaned_data.language %}" async crossorigin></script>
+ <link rel="stylesheet" type="text/css" href="{% abseventurl request.event "presale:event.widget.css" version=widget_version_default %}" crossorigin>
+<script type="text/javascript" src="{{ urlprefix }}{% url "presale:widget.js" lang=form.cleaned_data.language version=widget_version_default %}" async crossorigin></script>
{% 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 %} -
<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"></div>
+ <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 %}></div>
<noscript>
<div class="pretix-widget">
<div class="pretix-widget-info-message">
@@ -45,7 +45,7 @@
</noscript>
{% else %}
- <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"></pretix-widget>
+ <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 %}></pretix-widget>
<noscript>
<div class="pretix-widget">
<div class="pretix-widget-info-message">
diff --git a/src/pretix/control/views/event.py b/src/pretix/control/views/event.py
index 4667a6b96f..9ffb76eac0 100644
--- a/src/pretix/control/views/event.py
+++ b/src/pretix/control/views/event.py
@@ -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)
diff --git a/src/pretix/presale/templates/pretixpresale/widget_dummy.v1.html b/src/pretix/presale/templates/pretixpresale/widget_dummy.v1.html
new file mode 100644
index 0000000000..72f58a9066
--- /dev/null
+++ b/src/pretix/presale/templates/pretixpresale/widget_dummy.v1.html
@@ -0,0 +1,5 @@
+{% load compress %}
+{% load static %}
+{% compress css %}
+
+{% endcompress %}
diff --git a/src/pretix/presale/urls.py b/src/pretix/presale/urls.py
index 2289c41661..18089751d5 100644
--- a/src/pretix/presale/urls.py
+++ b/src/pretix/presale/urls.py
@@ -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.css', pretix.presale.views.widget.widget_css, name='event.widget.css'),
re_path(r'^(?P\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.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[a-zA-Z0-9_\-]+)\.js$', pretix.presale.views.widget.widget_js, name='widget.js'),
+ path('widget/v..js', pretix.presale.views.widget.widget_js, name='widget.js'),
]
diff --git a/src/pretix/presale/views/widget.py b/src/pretix/presale/views/widget.py
index 8ae618a6ca..f16755eaed 100644
--- a/src/pretix/presale/views/widget.py
+++ b/src/pretix/presale/views/widget.py
@@ -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'] = '*'
diff --git a/src/pretix/static/pretixbase/scss/_bootstrap_vars.scss b/src/pretix/static/pretixbase/scss/_bootstrap_vars.scss
index b944766cd8..9d6648d8a2 100644
--- a/src/pretix/static/pretixbase/scss/_bootstrap_vars.scss
+++ b/src/pretix/static/pretixbase/scss/_bootstrap_vars.scss
@@ -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);
diff --git a/src/pretix/static/pretixpresale/js/widget/widget.js b/src/pretix/static/pretixpresale/js/widget/widget.js
index 260606e946..db9eb55966 100644
--- a/src/pretix/static/pretixpresale/js/widget/widget.js
+++ b/src/pretix/static/pretixpresale/js/widget/widget.js
@@ -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: (''),
@@ -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', {
+ ''
+ ),
+ data: shared_widget_data,
+ methods: shared_methods,
+});
+
+/* Function to create the actual Vue instances */
+
+var shared_root_methods = {
+ open_link_in_frame: function (event) {
+ var url = event.target.attributes.href.value;
+ if (this.$root.additionalURLParams) {
+ if (url.indexOf('?')) {
+ url += '&' + this.$root.additionalURLParams;
+ } else {
+ url += '?' + this.$root.additionalURLParams;
+ }
+ }
+ if (this.$root.useIframe) {
+ event.preventDefault();
+ if (url.indexOf('?')) {
+ url += '&iframe=1';
+ } else {
+ url += '?iframe=1';
+ }
+ this.$root.overlay.frame_src = url;
+ } else {
+ event.target.href = url;
+ return;
+ }
+ },
+ trigger_load_callback: function () {
+ this.$nextTick(function () {
+ for (var i = 0; i < window.PretixWidget._loaded.length; i++) {
+ window.PretixWidget._loaded[i]()
+ }
+ });
+ },
+ trigger_close_callback: function () {
+ this.$nextTick(function () {
+ for (var i = 0; i < window.PretixWidget._closed.length; i++) {
+ window.PretixWidget._closed[i]()
+ }
+ });
+ },
+ reload: function (opt = {}) {
+ var url;
+ if (this.$root.is_button) {
+ return;
+ }
+ if (this.$root.subevent) {
+ url = this.$root.target_url + this.$root.subevent + '/widget/product_list?lang=' + lang;
+ } else {
+ url = this.$root.target_url + 'widget/product_list?lang=' + lang;
+ }
+ if (this.$root.offset) {
+ url += '&offset=' + this.$root.offset;
+ }
+ if (this.$root.filter) {
+ url += '&' + this.$root.filter;
+ }
+ if (this.$root.item_filter) {
+ url += '&items=' + encodeURIComponent(this.$root.item_filter);
+ }
+ if (this.$root.category_filter) {
+ url += '&categories=' + encodeURIComponent(this.$root.category_filter);
+ }
+ if (this.$root.variation_filter) {
+ url += '&variations=' + encodeURIComponent(this.$root.variation_filter);
+ }
+ var cart_id = getCookie(this.cookieName);
+ if (this.$root.voucher_code) {
+ url += '&voucher=' + encodeURIComponent(this.$root.voucher_code);
+ }
+ if (cart_id) {
+ url += "&cart_id=" + encodeURIComponent(cart_id);
+ }
+ if (this.$root.date !== null) {
+ url += "&date=" + this.$root.date.substr(0, 7);
+ } else if (this.$root.week !== null) {
+ url += "&date=" + this.$root.week[0] + "-W" + this.$root.week[1];
+ }
+ if (this.$root.style !== null) {
+ url = url + '&style=' + encodeURIComponent(this.$root.style);
+ }
+ var root = this.$root;
+ api._getJSON(url, function (data, xhr) {
+ if (typeof xhr.responseURL !== "undefined") {
+ var new_url = xhr.responseURL.substr(0, xhr.responseURL.indexOf("/widget/product_list?") + 1);
+ var old_url = url.substr(0, url.indexOf("/widget/product_list?") + 1);
+ if (new_url !== old_url) {
+ if (root.subevent) {
+ new_url = new_url.substr(0, new_url.lastIndexOf("/", new_url.length - 1) + 1);
+ }
+ root.target_url = new_url;
+ root.reload();
+ return;
+ }
+ }
+ root.connection_error = false;
+ if (data.weeks !== undefined) {
+ root.weeks = data.weeks;
+ root.date = data.date;
+ root.week = null;
+ root.events = undefined;
+ root.view = "weeks";
+ root.name = data.name;
+ root.frontpage_text = data.frontpage_text;
+ root.meta_filter_fields = data.meta_filter_fields;
+ } else if (data.days !== undefined) {
+ root.days = data.days;
+ root.date = null;
+ root.week = data.week;
+ root.events = undefined;
+ root.view = "days";
+ root.name = data.name;
+ root.frontpage_text = data.frontpage_text;
+ root.meta_filter_fields = data.meta_filter_fields;
+ } else if (data.events !== undefined) {
+ root.events = root.append_events && root.events ? root.events.concat(data.events) : data.events;
+ root.append_events = false;
+ root.weeks = undefined;
+ root.view = "events";
+ root.name = data.name;
+ root.frontpage_text = data.frontpage_text;
+ root.has_more_events = data.has_more_events;
+ root.meta_filter_fields = data.meta_filter_fields;
+ } else {
+ root.view = "event";
+ // Replace target_url and subevent with canonical values in case they were slightly wrong
+ root.target_url = data.target_url;
+ root.subevent = data.subevent;
+ // Event data
+ root.name = data.name;
+ root.frontpage_text = data.frontpage_text;
+ root.date_range = data.date_range;
+ root.location = data.location;
+ 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;
+ root.waiting_list_enabled = data.waiting_list_enabled;
+ root.show_variations_expanded = data.show_variations_expanded || !!root.variation_filter;
+ root.cart_id = cart_id;
+ root.cart_exists = data.cart_exists;
+ root.vouchers_exist = data.vouchers_exist;
+ root.has_seating_plan = data.has_seating_plan;
+ root.has_seating_plan_waitinglist = data.has_seating_plan_waitinglist;
+ root.itemnum = data.itemnum;
+ }
+ root.poweredby = data.poweredby;
+ if (root.loading > 0) {
+ root.loading--;
+ root.trigger_load_callback();
+ }
+ if (root.parent_stack.length > 0 && root.has_seating_plan && root.categories.length === 0 && !root.frame_dismissed && root.useIframe && !root.error && !root.has_seating_plan_waitinglist) {
+ // If we're on desktop and someone selects a seating-only event in a calendar, let's open it right away,
+ // but only if the person didn't close it before.
+ root.startseating()
+ } else {
+ // make sure to only move focus to content element when it had focus before the reload/click
+ // this is needed because reload is also called on initial load and we do not want to move focus on initial load
+ if (root.$el.contains(document.activeElement)) {
+ root.$nextTick(function() {
+ // wait for redraw, then focus content element for better a11y
+ (opt.focus ? document.querySelector(opt.focus) : root.$el).focus();
+ });
+ }
+ }
+ }, function (error) {
+ root.categories = [];
+ root.currency = '';
+ if (error.status === 429) {
+ root.error = strings['loading_error_429'];
+ root.connection_error = true;
+ } else {
+ root.error = strings['loading_error'];
+ root.connection_error = true;
+ }
+ if (root.loading > 0) {
+ root.loading--;
+ root.trigger_load_callback();
+ }
+ });
+ },
+ startwaiting: function () {
+ var redirect_url = this.$root.target_url + 'w/' + widget_id + '/waitinglist/?iframe=1&locale=' + lang;
+ if (this.$root.subevent){
+ redirect_url += '&subevent=' + this.$root.subevent;
+ }
+ if (this.$root.additionalURLParams) {
+ redirect_url += '&' + this.$root.additionalURLParams;
+ }
+ if (this.$root.useIframe) {
+ this.$root.overlay.frame_src = redirect_url;
+ } else {
+ window.open(redirect_url);
+ }
+ },
+ startseating: function () {
+ var redirect_url = this.$root.target_url + 'w/' + widget_id;
+ if (this.$root.subevent){
+ redirect_url += '/' + this.$root.subevent;
+ }
+ redirect_url += '/seatingframe/?iframe=1&locale=' + lang;
+ if (this.$root.voucher_code) {
+ redirect_url += '&voucher=' + encodeURIComponent(this.$root.voucher_code);
+ }
+ if (this.$root.cart_id) {
+ redirect_url += '&take_cart_id=' + this.$root.cart_id;
+ }
+ if (this.$root.widget_data) {
+ redirect_url += '&widget_data=' + encodeURIComponent(this.$root.widget_data_json);
+ }
+ if (this.$root.additionalURLParams) {
+ redirect_url += '&' + this.$root.additionalURLParams;
+ }
+ redirect_url += this.$root.consent_parameter;
+ if (this.$root.useIframe) {
+ this.$root.overlay.frame_src = redirect_url;
+ } else {
+ window.open(redirect_url);
+ }
+ },
+ choose_event: function (event) {
+ this.$root.target_url = event.event_url;
+ this.$root.error = null;
+ this.$root.connection_error = false;
+ this.$root.subevent = event.subevent;
+ this.$root.loading++;
+ this.$root.reload();
+ }
+};
+
+var shared_root_computed = {
+ cookieName: function () {
+ return "pretix_widget_" + this.target_url.replace(/[^a-zA-Z0-9]+/g, "_");
+ },
+ formTarget: function () {
+ var is_firefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
+ var is_android = navigator.userAgent.toLowerCase().indexOf("android") > -1;
+ if (is_android && is_firefox) {
+ // Opening a POST form in a new browser fails in Firefox. This is supposed to be fixed since FF 76
+ // but for some reason, it is still the case in FF for Android.
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1629441
+ // https://github.com/pretix/pretix/issues/1040
+ return "_top";
+ } else {
+ return "_blank";
+ }
+ },
+ voucherFormTarget: function () {
+ var form_target = this.target_url + 'w/' + widget_id + '/redeem?iframe=1&locale=' + lang;
+ var cookie = getCookie(this.cookieName);
+ if (cookie) {
+ form_target += "&take_cart_id=" + cookie;
+ }
+ if (this.subevent) {
+ form_target += "&subevent=" + this.subevent;
+ }
+ if (this.$root.widget_data) {
+ form_target += '&widget_data=' + encodeURIComponent(this.$root.widget_data_json);
+ }
+ form_target += this.$root.consent_parameter;
+ if (this.$root.additionalURLParams) {
+ form_target += '&' + this.$root.additionalURLParams;
+ }
+ return form_target;
+ },
+ formMethod: function () {
+ if (!this.useIframe && this.is_button && this.items.length === 0) {
+ return 'get';
+ }
+ return 'post';
+ },
+ formAction: function () {
+ if (!this.useIframe && this.is_button && this.items.length === 0) {
+ var target;
+ if (this.voucher_code) {
+ target = this.target_url + 'redeem';
+ } else if (this.subevent) {
+ target = this.target_url + this.subevent + '/';
+ } else {
+ target = this.target_url;
+ }
+ return target;
+ }
+ var checkout_url = "/" + this.target_url.replace(/^[^\/]+:\/\/([^\/]+)\//, "") + "w/" + widget_id + "/";
+ if (!this.$root.cart_exists) {
+ checkout_url += "checkout/start";
+ }
+ if (this.$root.additionalURLParams) {
+ checkout_url += '?' + this.$root.additionalURLParams;
+ }
+ var form_target = this.target_url + 'w/' + widget_id + '/cart/add?iframe=1&next=' + encodeURIComponent(checkout_url);
+ var cookie = getCookie(this.cookieName);
+ if (cookie) {
+ form_target += "&take_cart_id=" + cookie;
+ }
+ form_target += this.$root.consent_parameter
+ return form_target
+ },
+ newTabTarget: function () {
+ var target = this.target_url;
+ if (this.subevent) {
+ target = this.target_url + this.subevent + '/';
+ }
+ return target;
+ },
+ useIframe: function () {
+ if (window.crossOriginIsolated === true) {
+ console.warn("pretix Widget cannot use iframe due to Cross-Origin-Embed-Policy")
+ return false;
+ }
+ return !this.disable_iframe && (this.skip_ssl || site_is_secure());
+ },
+ showPrices: function () {
+ var has_priced = false;
+ var cnt_items = 0;
+ for (var i = 0; i < this.categories.length; i++) {
+ for (var j = 0; j < this.categories[i].items.length; j++) {
+ var item = this.categories[i].items[j];
+ if (item.has_variations) {
+ cnt_items += item.variations.length;
+ has_priced = true;
+ } else {
+ cnt_items++;
+ has_priced = has_priced || item.price.gross != "0.00" || item.free_price;
+ }
+ }
+ }
+ return has_priced || cnt_items > 1;
+ },
+ consent_parameter_value: function () {
+ if (typeof this.widget_data["consent"] !== "undefined") {
+ return encodeURIComponent(this.widget_data["consent"]);
+ }
+ return "";
+ },
+ consent_parameter: function () {
+ if (typeof this.widget_data["consent"] !== "undefined") {
+ return "&consent=" + encodeURIComponent(this.widget_data["consent"]);
+ }
+ return "";
+ },
+ widget_data_json: function () {
+ var cloned_data = Object.assign({}, this.widget_data);
+ if (typeof cloned_data["consent"] !== "undefined") {
+ // Remove consent as we pass it differently. We still keep it as widget_data in the input to avoid breaking
+ // the JS API of the widget.
+ delete cloned_data["consent"];
+ }
+ return JSON.stringify(cloned_data);
+ },
+ additionalURLParams: function () {
+ if (!window.location.search.indexOf('utm_')) {
+ return '';
+ }
+ var params = new URLSearchParams(window.location.search);
+ for (var [key, value] of params.entries()) {
+ if (!key.startsWith('utm_')) {
+ params.delete(key);
+ }
+ }
+ return params.toString();
+ },
+};
+
+var create_overlay = function (app) {
+ var elem = document.createElement('pretix-overlay');
+ document.body.appendChild(elem);
+
+ var framechild = new Vue({
+ el: elem,
+ data: function () {
+ return {
+ parent: app,
+ frame_loading: false,
+ frame_shown: false,
+ error_url_after: null,
+ error_url_after_new_tab: true,
+ error_message: null,
+ lightbox: null,
+ prevActiveElement: null,
+ }
+ },
+ props: {
+ frame_src: String,
+ },
+ methods: {
+ },
+ watch: {
+ frame_src: function (newValue, oldValue) {
+ // show loading spinner only when previously no frame_src was set
+ if (newValue && !oldValue) {
+ this.frame_loading = true;
+ }
+ // 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;
+};
+
+function get_ga_client_id(tracking_id) {
+ if (typeof ga === "undefined") {
+ return null;
+ }
+ try {
+ var trackers = ga.getAll();
+ var i, len;
+ for (i = 0, len = trackers.length; i < len; i += 1) {
+ if (trackers[i].get('trackingId') === tracking_id) {
+ return trackers[i].get('clientId');
+ }
+ }
+ } catch (e) {
+ }
+ return null;
+}
+
+var create_widget = function (element, html_id=null) {
+ var target_url = element.attributes.event.value;
+ if (!target_url.match(/\/$/)) {
+ target_url += "/";
+ }
+ var voucher = element.attributes.voucher ? element.attributes.voucher.value : null;
+ var subevent = element.attributes.subevent ? element.attributes.subevent.value : null;
+ var style = element.attributes["list-type"] ? element.attributes["list-type"].value : (element.attributes.style ? element.attributes.style.value : null);
+ var skip_ssl = element.attributes["skip-ssl-check"] ? true : false;
+ var disable_iframe = element.attributes["disable-iframe"] ? true : false;
+ var disable_vouchers = element.attributes["disable-vouchers"] ? true : false;
+ var disable_filters = element.attributes["disable-filters"] ? true : false;
+ var display_event_info = element.getAttribute("display-event-info"); // null means "auto" (as before), everything other than "false" is true
+ if (display_event_info !== null && display_event_info !== "auto") {
+ display_event_info = display_event_info !== "false";
+ } else {
+ display_event_info = null;
+ }
+ var widget_data = JSON.parse(JSON.stringify(window.PretixWidget.widget_data));
+ var filter = element.attributes.filter ? element.attributes.filter.value : 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-.*$/)) {
+ widget_data[attrib.name.replace(/^data-/, '')] = attrib.value;
+ }
+ }
+ html_id = html_id || element.id || makeid(16);
+
+ var observer = new MutationObserver((mutationList) => {
+ mutationList.forEach((mutation) => {
+ if (mutation.type == "attributes" && mutation.attributeName.startsWith("data-")) {
+ Vue.set(app.widget_data, mutation.attributeName.substring(5), mutation.target.getAttribute(mutation.attributeName));
+ }
+ });
+ });
+ var observerOptions = { attributes: true };
+
+ if (element.tagName !== "pretix-widget") {
+ element.innerHTML = " ";
+ // we need to watch the container as well as the replaced root-node (see mounted())
+ observer.observe(element, observerOptions);
+ }
+
+ var app = new Vue({
+ el: element,
+ data: function () {
+ return {
+ target_url: target_url,
+ parent_stack: [],
+ subevent: subevent,
+ is_button: false,
+ categories: null,
+ currency: null,
+ name: null,
+ date_range: null,
+ location: null,
+ offset: 0,
+ has_more_events: false,
+ append_events: false,
+ frontpage_text: null,
+ filter: filter,
+ item_filter: items,
+ category_filter: categories,
+ 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,
+ disable_iframe: disable_iframe,
+ style: style,
+ connection_error: false,
+ error: null,
+ weeks: null,
+ days: null,
+ date: null,
+ week: null,
+ frame_dismissed: false,
+ events: null,
+ view: null,
+ display_add_to_cart: false,
+ widget_data: widget_data,
+ loading: 1,
+ widget_id: 'pretix-widget-' + widget_id,
+ html_id: html_id,
+ vouchers_exist: false,
+ disable_vouchers: disable_vouchers,
+ disable_filters: disable_filters,
+ display_event_info: display_event_info,
+ cart_exists: false,
+ itemcount: 0,
+ overlay: null,
+ poweredby: "",
+ has_seating_plan: false,
+ has_seating_plan_waitinglist: false,
+ meta_filter_fields: [],
+ }
+ },
+ created: function () {
+ this.reload();
+ },
+ mounted: function () {
+ observer.observe(this.$el, observerOptions);
+ },
+ computed: shared_root_computed,
+ methods: shared_root_methods,
+ watch: {
+ 'view': function (newValue, oldValue) {
+ if (oldValue) {
+ // always make sure the widget is scrolled to the top
+ // as we only check top, we do not need to wait for a redraw
+ var rect = this.$el.getBoundingClientRect();
+ if (rect.top < 0) {
+ this.$el.scrollIntoView();
+ }
+ }
+ }
+ }
+ });
+ create_overlay(app);
+ return app;
+};
+
+var create_button = function (element, html_id=null) {
+ var target_url = element.attributes.event.value;
+ if (!target_url.match(/\/$/)) {
+ target_url += "/";
+ }
+ var voucher = element.attributes.voucher ? element.attributes.voucher.value : null;
+ var subevent = element.attributes.subevent ? element.attributes.subevent.value : null;
+ var raw_items = element.attributes.items ? element.attributes.items.value : "";
+ var skip_ssl = element.attributes["skip-ssl-check"] ? true : false;
+ var disable_iframe = element.attributes["disable-iframe"] ? true : false;
+ var button_text = element.innerHTML;
+ var widget_data = JSON.parse(JSON.stringify(window.PretixWidget.widget_data));
+ for (var i = 0; i < element.attributes.length; i++) {
+ var attrib = element.attributes[i];
+ if (attrib.name.match(/^data-.*$/)) {
+ widget_data[attrib.name.replace(/^data-/, '')] = attrib.value;
+ }
+ }
+ html_id = html_id || element.id || makeid(16);
+
+ var observer = new MutationObserver((mutationList) => {
+ mutationList.forEach((mutation) => {
+ if (mutation.type == "attributes" && mutation.attributeName.startsWith("data-")) {
+ Vue.set(app.widget_data, mutation.attributeName.substring(5), mutation.target.getAttribute(mutation.attributeName));
+ }
+ });
+ });
+ var observerOptions = { attributes: true };
+
+ if (element.tagName !== "pretix-button") {
+ element.innerHTML = "" + element.innerHTML + " ";
+ // Vue does not replace the container, so watch container as well
+ observer.observe(element, observerOptions);
+ }
+
+ var itemsplit = raw_items.split(",");
+ var items = [];
+ for (var i = 0; i < itemsplit.length; i++) {
+ if (itemsplit[i].indexOf("=") > 0 ) {
+ var splitthis = itemsplit[i].split("=");
+ items.push({'item': splitthis[0], 'count': splitthis[1]})
+ }
+ }
+
+ var app = new Vue({
+ el: element,
+ data: function () {
+ return {
+ target_url: target_url,
+ subevent: subevent,
+ is_button: true,
+ skip_ssl: skip_ssl,
+ disable_iframe: disable_iframe,
+ voucher_code: voucher,
+ items: items,
+ error: null,
+ filter: null,
+ frame_dismissed: false,
+ widget_data: widget_data,
+ widget_id: 'pretix-widget-' + widget_id,
+ html_id: html_id,
+ button_text: button_text
+ }
+ },
+ created: function () {
+ },
+ mounted: function () {
+ observer.observe(this.$el, observerOptions);
+ },
+ computed: shared_root_computed,
+ methods: shared_root_methods
+ });
+ create_overlay(app);
+ return app;
+};
+
+/* Find all widgets on the page and render them */
+widgetlist = [];
+buttonlist = [];
+window.PretixWidget._loaded = [];
+window.PretixWidget._closed = [];
+window.PretixWidget.addLoadListener = function (f) {
+ window.PretixWidget._loaded.push(f);
+}
+window.PretixWidget.addCloseListener = function (f) {
+ window.PretixWidget._closed.push(f);
+}
+window.PretixWidget.buildWidgets = function () {
+ document.createElement("pretix-widget");
+ document.createElement("pretix-button");
+ docReady(function () {
+ var widgets = document.querySelectorAll("pretix-widget, div.pretix-widget-compat");
+ var wlength = widgets.length;
+ for (var i = 0; i < wlength; i++) {
+ var widget = widgets[i];
+ widgetlist.push(create_widget(widget, widget.id || "pretix-widget-"+i));
+ }
+
+ var buttons = document.querySelectorAll("pretix-button, div.pretix-button-compat");
+ var blength = buttons.length;
+ for (var i = 0; i < blength; i++) {
+ var button = buttons[i];
+ buttonlist.push(create_button(button, button.id || "pretix-button-"+i));
+ }
+ });
+};
+
+window.PretixWidget.open = function (target_url, voucher, subevent, items, widget_data, skip_ssl_check, disable_iframe) {
+ if (!target_url.match(/\/$/)) {
+ target_url += "/";
+ }
+
+ var all_widget_data = JSON.parse(JSON.stringify(window.PretixWidget.widget_data));
+ if (widget_data) {
+ Object.keys(widget_data).forEach(function(key) { all_widget_data[key] = widget_data[key]; });
+ }
+ var root = document.createElement("div");
+ document.body.appendChild(root);
+ root.classList.add("pretix-widget-hidden");
+ root.innerHTML = " ";
+ var app = new Vue({
+ el: root,
+ data: function () {
+ return {
+ target_url: target_url,
+ subevent: subevent || null,
+ is_button: true,
+ skip_ssl: skip_ssl_check || false,
+ disable_iframe: disable_iframe || false,
+ voucher_code: voucher || null,
+ items: items || [],
+ error: null,
+ filter: null,
+ frame_dismissed: false,
+ widget_data: all_widget_data,
+ widget_id: 'pretix-widget-' + widget_id,
+ button_text: ""
+ }
+ },
+ created: function () {
+ },
+ computed: shared_root_computed,
+ methods: shared_root_methods
+ });
+ create_overlay(app);
+ app.$nextTick(function () {
+ if (this.$root.useIframe) {
+ this.$refs.btn.buy();
+ } else {
+ this.$refs.btn.$refs.form.submit();
+ }
+ })
+};
+
+if (typeof window.pretixWidgetCallback !== "undefined") {
+ window.pretixWidgetCallback();
+}
+if (window.PretixWidget.build_widgets) {
+ window.PretixWidget.buildWidgets();
+}
+
+/* Set a global variable for debugging. In DEBUG mode, siteglobals will be window, otherwise it will be something
+ unnamed. */
+siteglobals.pretixwidget_debug = {
+ 'Vue': Vue,
+ 'widgets': widgetlist,
+ 'buttons': buttonlist
+};
diff --git a/src/pretix/static/pretixpresale/scss/main.scss b/src/pretix/static/pretixpresale/scss/main.scss
index 17acd4dccb..b047b1827b 100644
--- a/src/pretix/static/pretixpresale/scss/main.scss
+++ b/src/pretix/static/pretixpresale/scss/main.scss
@@ -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 */
diff --git a/src/pretix/static/pretixpresale/scss/widget.scss b/src/pretix/static/pretixpresale/scss/widget.scss
index 900b153691..ebd59a945b 100644
--- a/src/pretix/static/pretixpresale/scss/widget.scss
+++ b/src/pretix/static/pretixpresale/scss/widget.scss
@@ -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;
- }
- }
-}
diff --git a/src/pretix/static/pretixpresale/scss/widget.v1.scss b/src/pretix/static/pretixpresale/scss/widget.v1.scss
new file mode 100644
index 0000000000..900b153691
--- /dev/null
+++ b/src/pretix/static/pretixpresale/scss/widget.v1.scss
@@ -0,0 +1,1088 @@
+// not included, will be dynamically prepended @import "../../pretixbase/scss/_theme_variables.scss";
+@import "../../pretixbase/scss/_bootstrap_vars.scss";
+@import "../../bootstrap/scss/bootstrap/variables";
+@import "../../bootstrap/scss/bootstrap/mixins";
+
+.pretix-widget-hidden {
+ display: none;
+}
+.pretix-widget, .pretix-widget-alert-box {
+ a {
+ color: $link-color;
+ text-decoration: none;
+
+ &:hover,
+ &:focus {
+ color: $link-hover-color;
+ text-decoration: $link-hover-decoration;
+ }
+ &:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+ }
+ }
+ img {
+ border: 0;
+ }
+ b, strong {
+ font-weight: bold;
+ }
+ h3 {
+ font-size: $font-size-h3;
+ font-weight: bold;
+ padding: 0 15px;
+ }
+ button, input[type="button"], a.pretix-widget-button {
+ overflow: visible;
+ text-transform: none;
+ cursor: pointer;
+ display: inline-block;
+ margin-bottom: 0;
+ text-align: center;
+ vertical-align: middle;
+ touch-action: manipulation;
+ background-image: none;
+ border: 1px solid transparent;
+ white-space: nowrap;
+ text-decoration: none;
+ @include button-size($padding-base-vertical, $padding-base-horizontal, $font-size-base, $line-height-base, $btn-border-radius-base);
+ @include user-select(none);
+ @include button-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border, $btn-primary-background-active, $btn-primary-border-active, $btn-primary-border-hover);
+
+ &,
+ &:active,
+ &.active {
+ &:focus,
+ &.focus {
+ text-decoration: none;
+ @include tab-focus;
+ }
+ }
+ &.disabled,
+ &[disabled],
+ fieldset[disabled] & {
+ cursor: $cursor-disabled;
+ @include opacity(.65);
+ @include box-shadow(none);
+ }
+ &.pretix-widget-btn-default {
+ @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%));
+ }
+ }
+ 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-width: 1px;
+ border-style: solid;
+ position: relative;
+ cursor: pointer;
+ padding: 6px 24px;
+ min-height: 32px;
+ box-sizing: border-box;
+ color: #333;
+ input {
+ position: absolute;
+ left: 10px;
+ }
+ &:has(input:checked) {
+ background-color: #e6e6e6;
+ border-color: #adadad;
+ }
+ }
+ .pretix-widget-icon-cart {
+ display: inline-block;
+ width: 1em;
+ height: 1em;
+ vertical-align: text-bottom;
+ fill: #333;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.267 6.756c0-.312-.202-.563-.453-.563-.252 0-.454.251-.454.563 0 .312.202.563.454.563.251 0 .453-.251.453-.563Zm3.174 0c0-.312-.202-.563-.454-.563-.251 0-.453.251-.453.563 0 .312.202.563.453.563.252 0 .454-.251.454-.563Zm.453-4.785c0-.154-.103-.282-.227-.282H1.413c-.035-.211-.039-.563-.28-.563H.227c-.124 0-.227.128-.227.282 0 .153.103.281.227.281h.722l.627 3.62c-.049.127-.216.466-.216.603 0 .153.103.281.227.281h3.627c.124 0 .227-.128.227-.281 0-.154-.103-.282-.227-.282H1.955c.036-.088.085-.18.085-.281 0-.102-.032-.212-.046-.308l3.698-.537c.117-.018.202-.141.202-.281V1.971Z' transform='matrix(2.52069 0 0 2.02994 -.035 -.523)'/%3E%3C/svg%3E%0A");
+ }
+ input:checked + .pretix-widget-icon-cart {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.534 3.097a.317.317 0 0 1-.067.197L3.56 4.42a.207.207 0 0 1-.16.084.207.207 0 0 1-.159-.084l-.907-1.126a.317.317 0 0 1-.067-.197c0-.154.103-.282.227-.282.06 0 .117.031.159.084l.521.642V2.252c0-.154.102-.281.226-.281.124 0 .227.127.227.281v1.289l.521-.642a.205.205 0 0 1 .159-.084c.124 0 .227.128.227.282ZM2.267 6.756c0-.312-.202-.563-.453-.563-.252 0-.454.251-.454.563 0 .312.202.563.454.563.251 0 .453-.251.453-.563Zm3.174 0c0-.312-.202-.563-.454-.563-.251 0-.453.251-.453.563 0 .312.202.563.453.563.252 0 .454-.251.454-.563Zm.453-4.785c0-.154-.103-.282-.227-.282H1.413c-.035-.211-.039-.563-.28-.563H.227c-.124 0-.227.128-.227.282 0 .153.103.281.227.281h.722l.627 3.62c-.049.127-.216.466-.216.603 0 .153.103.281.227.281h3.627c.124 0 .227-.128.227-.281 0-.154-.103-.282-.227-.282H1.955c.036-.088.085-.18.085-.281 0-.102-.032-.212-.046-.308l3.698-.537c.117-.018.202-.141.202-.281V1.971Z' transform='matrix(2.52069 0 0 2.02994 -.035 -.523)'/%3E%3C/svg%3E%0A");
+ }
+ input[type="text"], input[type="number"], select {
+ line-height: normal;
+ 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;
+ @include box-shadow(inset 0 1px 1px rgba(0, 0, 0, .075));
+ @include transition(border-color ease-in-out .15s, box-shadow ease-in-out .15s);
+ @include placeholder;
+ $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);
+ }
+ }
+ input[type=number] {
+ padding-right: 0; // Setting the padding-right to zero, as some versions Firefox render the arrow-buttons on number inputs useless.
+ }
+ input[type="checkbox"],
+ input[type="radio"] {
+ box-sizing: border-box; // 1
+ padding: 0; // 2
+ &:focus {
+ outline: thin dotted;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+ }
+ }
+}
+.pretix-widget-use-custom-spinners input[type=number] {
+ padding-right: $padding-base-horizontal;
+ -moz-appearance: textfield;
+}
+.pretix-widget-use-custom-spinners input[type=number]::-webkit-outer-spin-button,
+.pretix-widget-use-custom-spinners input[type=number]::-webkit-inner-spin-button {
+ -webkit-appearance: none;
+ margin: 0;
+}
+.pretix-widget {
+ margin: 10px 0;
+ padding: 0 10px;
+ border: 1px solid #ccc;
+ position: relative;
+ min-height: 208px;
+ border-radius: $input-border-radius;
+
+ .pretix-widget-resume-button {
+ float: right;
+ margin-left: 10px;
+ }
+
+ .pretix-widget-clickable {
+ cursor: pointer;
+ }
+
+ .pretix-widget-info-message {
+ padding: 10px;
+ text-align: left;
+ margin: 10px 0;
+ background-color: white;
+ border: 2px solid $brand-info;
+ color: $state-info-text;
+ border-radius: $alert-border-radius;
+ }
+
+ .pretix-widget-error-message {
+ padding: 10px;
+ text-align: center;
+ margin: 10px 0;
+ background-color: white;
+ border: 2px solid $brand-danger;
+ color: $state-danger-text;
+ border-radius: $alert-border-radius;
+ }
+
+ .pretix-widget-error-action {
+ padding: 10px;
+ text-align: center;
+ }
+
+ .pretix-widget-loading {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ background: rgba(255, 255, 255, .8);
+ text-align: center;
+ }
+
+ @-moz-keyframes pretix-widget-spin {
+ 100% {
+ -moz-transform: rotate(360deg);
+ }
+ }
+
+ @-webkit-keyframes pretix-widget-spin {
+ 100% {
+ -webkit-transform: rotate(360deg);
+ }
+ }
+
+ @keyframes pretix-widget-spin {
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+ }
+
+ .pretix-widget-loading svg {
+ margin: 40px;
+ /*Fallback*/
+ position: absolute;
+ top: 50%;
+ margin-top: -64px;
+ /*Sticky*/
+ position: -webkit-sticky;
+ position: sticky;
+ top: Min(50vh, 50%);/* use uppercase M to use CSS-min and not SASS-min*/
+
+ -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-item-row, .pretix-widget-category {
+ clear: both;
+ }
+
+ .pretix-widget-item-title {
+ font-weight: bold;
+ }
+
+ .pretix-widget-item-row {
+ padding: 10px 0;
+ }
+
+ .pretix-widget-category {
+ margin: 10px 0;
+ }
+
+ .pretix-widget-category-description {
+ padding: 0 15px;
+ }
+
+ .pretix-widget-category-name {
+ margin: 10px 0 0 0;
+ }
+
+ .pretix-widget-item-info-col {
+ width: 50%;
+ float: left;
+ padding: 0 15px;
+ box-sizing: border-box;
+ }
+
+ .pretix-widget-item-price-col, .pretix-widget-item-availability-col {
+ width: 25%;
+ float: left;
+ padding: 0 15px;
+ box-sizing: border-box;
+ }
+
+ .pretix-widget-item-description p, .pretix-widget-item-meta {
+ margin: 0;
+ }
+
+ .pretix-widget-item-price-col {
+ text-align: right;
+ }
+
+ del.pretix-widget-pricebox-original-price {
+ color: $text-muted;
+ }
+
+ ins.pretix-widget-pricebox-new-price {
+ font-size: 120%;
+ font-weight: bold;
+ text-decoration: none;
+ }
+
+ .pretix-widget-clear {
+ clear: both;
+ }
+
+ .pretix-widget-category-description p {
+ margin: 0 0 10px;
+ }
+
+ .pretix-widget-pricebox-tax {
+ display: block;
+ }
+
+ .pretix-widget-item-count-group {
+ display: flex;
+ }
+
+ .pretix-widget-item-count-group input {
+ border-radius: 0;
+ border-left: none;
+ border-right: none;
+ }
+
+ .pretix-widget-item-count-group button span {
+ vertical-align: 25%;
+ line-height: 0.5;
+ }
+
+ .pretix-widget-item-count-dec {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ width: 2.5em;
+ z-index: 2;
+ }
+
+ .pretix-widget-item-count-inc {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ width: 2.5em;
+ }
+
+ .pretix-widget-item-count-multiple {
+ display: block;
+ width: 100%;
+ box-sizing: border-box;
+ padding: 5px;
+ text-align: center;
+ }
+
+ .pretix-widget-pricebox-price-input {
+ display: inline;
+ width: 100px;
+ box-sizing: border-box;
+ text-align: right;
+ }
+
+ .pretix-widget-item-count-single-label {
+ display: block;
+ text-align: center;
+ width: 100%;
+ }
+
+ .pretix-widget-attribution {
+ padding: 10px 15px;
+ text-align: center;
+ font-size: 12px;
+ }
+
+ .pretix-widget-item-picture {
+ width: 60px;
+ height: 60px;
+ margin-right: 10px;
+ float: left;
+ }
+
+ .pretix-widget-action {
+ margin-left: 75%;
+ width: 25%;
+ padding: 0 15px;
+ box-sizing: border-box;
+ }
+
+ .pretix-widget-action button {
+ width: 100%;
+ }
+
+ .pretix-widget-voucher-text {
+ margin: 10px 0;
+ padding: 0 15px;
+ }
+
+ .pretix-widget-voucher-headline {
+ margin: 10px 0 0 0;
+ }
+
+ .pretix-widget-voucher-input-wrap {
+ padding: 0 15px;
+ width: 75%;
+ box-sizing: border-box;
+ float: left;
+ }
+
+ .pretix-widget-voucher input {
+ width: 100%;
+ box-sizing: border-box;
+ }
+
+ .pretix-widget-voucher-button-wrap {
+ padding: 0 15px;
+ width: 25%;
+ box-sizing: border-box;
+ float: left;
+ }
+
+ .pretix-widget-voucher button {
+ width: 100%;
+ }
+
+ .pretix-widget-seating-waitinglist {
+ margin: 15px 0;
+ }
+
+ .pretix-widget-seating-waitinglist-text {
+ padding: 0 15px;
+ width: 75%;
+ box-sizing: border-box;
+ float: left;
+ }
+
+ .pretix-widget-seating-waitinglist-button-wrap {
+ padding: 0 15px;
+ width: 25%;
+ box-sizing: border-box;
+ float: left;
+ }
+
+ .pretix-widget-seating-waitinglist-button {
+ width: 100%;
+ }
+
+ .pretix-widget-item-with-picture .pretix-widget-main-item-row .pretix-widget-item-title-and-description {
+ margin-left: 70px;
+ }
+
+ .pretix-widget-item-availability-col {
+ text-align: center;
+
+ .pretix-widget-collapse-indicator::before {
+ content: "";
+ display: inline-block;
+ width: $font-size-base;
+ height: $font-size-base;
+ background: url("data:image/svg+xml,%3Csvg viewBox='0 0 14 14' xmlns='http://www.w3.org/2000/svg' xml:space='preserve'%3E%3Cpath fill='#{url-friendly-colour($link-color)}' d='M6.395 4.151a.268.268 0 0 0-.177.077l-.386.386a.259.259 0 0 0-.077.177c.002.067.029.13.077.179l3.033 3.031-3.033 3.032a.255.255 0 0 0-.077.177.253.253 0 0 0 .077.178l.386.385a.268.268 0 0 0 .177.077.27.27 0 0 0 .178-.077l3.595-3.595a.259.259 0 0 0 .077-.177.255.255 0 0 0-.077-.176L6.573 4.228a.257.257 0 0 0-.178-.077Z'/%3E%3C/svg%3E");
+ transition: transform .5s;
+ }
+
+ .pretix-widget-collapse-indicator[aria-expanded=true]::before {
+ transform: rotate(90deg);
+ }
+ }
+
+ .pretix-widget-availability-gone {
+ font-weight: bold;
+ color: $brand-danger;
+ text-transform: uppercase;
+ }
+
+ .pretix-widget-availability-unavailable {
+ color: $brand-danger;
+ }
+
+ .pretix-widget-item-variations {
+ overflow: hidden;
+ padding-top: 0;
+ padding-bottom: 0;
+ margin-top: 0;
+ margin-bottom: 0;
+ -moz-transition-duration: 0.5s;
+ -webkit-transition-duration: 0.5s;
+ -o-transition-duration: 0.5s;
+ transition-duration: 0.5s;
+ -moz-transition-timing-function: ease-in-out;
+ -webkit-transition-timing-function: ease-in-out;
+ -o-transition-timing-function: ease-in-out;
+ transition-timing-function: ease-in-out;
+ }
+ .pretix-widget-event-header {
+ padding-top: 10px;
+ text-align: center;
+ }
+ .pretix-widget-event-details {
+ padding-top: 10px;
+ text-align: center;
+ }
+ .pretix-widget-event-location {
+ display: none;
+ padding-top: 10px;
+ text-align: center;
+ }
+ .pretix-widget-event-description {
+ padding: 0 15px;
+ }
+ .pretix-widget-event-list-back {
+ padding-top: 10px;
+ text-align: center;
+ display: block;
+ a {
+ display: block;
+ }
+ }
+ .pretix-widget-back {
+ padding-bottom: 10px;
+ text-align: center;
+ display: block;
+ a {
+ display: block;
+ }
+ }
+
+ .pretix-widget-event-list {
+ padding: 10px 0;
+ cursor: pointer;
+ }
+ .pretix-widget-event-list-entry {
+ display: flex;
+ flex-direction: row;
+ padding: 5px 0;
+ flex-wrap: wrap;
+ color: $text-color;
+
+ &:hover, &:active, &:focus {
+ background: $gray-lighter;
+ text-decoration: none;
+ }
+
+ .pretix-widget-event-list-entry-name {
+ width: 50%;
+ padding: 5px;
+ box-sizing: border-box;
+ }
+ .pretix-widget-event-list-entry-location {
+ padding: 5px;
+ box-sizing: border-box;
+ display: none;
+ }
+ .pretix-widget-event-list-entry-date {
+ width: 25%;
+ padding: 5px;
+ box-sizing: border-box;
+ }
+ .pretix-widget-event-list-entry-availability {
+ width: 25%;
+ text-align: right;
+ padding: 7px 5px 3px;
+ box-sizing: border-box;
+ span {
+ display: inline;
+ padding: 2px 6px 3px;
+ font-size: 75%;
+ font-weight: bold;
+ line-height: 1;
+ color: #fff;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: 4px;
+ }
+ }
+ }
+
+ .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-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-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-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-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-calendar {
+ padding-top: 10px;
+ word-break: break-word;
+
+ .pretix-widget-event-week-table {
+ display: flex;
+ flex-direction: row;
+
+ .pretix-widget-event-week-col {
+ flex: 1;
+ margin: 0 5px;
+
+ &:first-child {
+ margin-left: 0;
+ }
+ &:last-child {
+ margin-right: 0;
+ }
+ }
+ }
+
+ .pretix-widget-event-calendar-head {
+ display: flex;
+ flex-direction: row;
+
+ strong {
+ width: 50%;
+ text-align: center;
+ display: block;
+ }
+ .pretix-widget-event-calendar-next-month, .pretix-widget-event-calendar-previous-month {
+ display: block;
+ width: 25%;
+ }
+ .pretix-widget-event-calendar-next-month {
+ text-align: right;
+ }
+ }
+ .pretix-widget-event-calendar-event {
+ display: block;
+ border-radius: 4px;
+ padding: 5px;
+ color: white;
+ cursor: pointer;
+ margin-bottom: 5px;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ &:hover {
+ text-decoration: none;
+ }
+ }
+
+ .pretix-widget-event-calendar-table {
+ width: 100%;
+
+ th, td {
+ width: 14.285714285714286%;
+ vertical-align: top;
+ padding: 10px 5px;
+ }
+ }
+ .pretix-widget-event-calendar-day {
+ font-weight: bold;
+ }
+ }
+
+ .pretix-widget-seating-link-wrapper {
+ padding: 0 15px;
+ margin: 15px 0 10px;
+ }
+ .pretix-widget-seating-link {
+ display: block;
+ width: 100%;
+ }
+}
+
+
+.pretix-widget-event-list-filter-form {
+ display: flex;
+ flex-direction: row;
+ align-items: end;
+ margin-bottom: 15px;
+
+ .pretix-widget-event-list-filter-field {
+ display: block;
+ width: 100%;
+ margin: 0 15px 0 0;
+
+ label {
+ display: inline-block;
+ font-weight: bold;
+ margin-bottom: 5px;
+ }
+
+ select {
+ display: block;
+ width: 100%;
+ }
+ }
+ .pretix-widget-event-list-filter-field:last-child {
+ margin: 0;
+ }
+}
+.pretix-widget.pretix-widget-mobile .pretix-widget-event-list-filter-form {
+ display: block;
+
+ .pretix-widget-event-list-filter-field {
+ display: block;
+ margin: 0 0 5px;
+ }
+}
+
+@keyframes pretix-widget-bounce-in {
+ 0% {
+ transform: scale(0);
+ }
+ 50% {
+ transform: scale(1.5);
+ }
+ 100% {
+ 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;
+ visibility: hidden;
+ opacity: 0;
+ transition: opacity 0.5s; /* do not animate visibility or we'll have a flashing thing on load */
+
+ &.pretix-widget-alert-shown {
+ visibility: visible;
+ opacity: 1;
+ transition: opacity 0.5s, visibility 0.5s;
+ }
+
+ .bounce-enter-active {
+ animation: pretix-widget-bounce-in .5s;
+ }
+ .bounce-leave-active {
+ animation: pretix-widget-bounce-in .5s reverse;
+ }
+
+ .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;
+
+ p:first-child {
+ margin-top: 0;
+ }
+ p:last-child {
+ margin-bottom: 0;
+ }
+ }
+ .pretix-widget-alert-icon {
+ position: fixed;
+ left: 50%;
+ width: 64px;
+ margin-left: -32px;
+ top: 68px;
+ }
+}
+.pretix-widget-frame-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;
+
+ .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-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 */
+ fill: $brand-primary;
+}
+
+.pretix-widget-event-list-load-more {
+ text-align: center;
+}
+
+.pretix-widget.pretix-widget-mobile {
+ .pretix-widget-event-week-table {
+ display: block;
+
+ .pretix-widget-event-week-col {
+ flex: 1;
+ margin: 10px 0;
+ }
+ }
+
+ .pretix-widget-item-info-col {
+ width: 100%;
+ float: none;
+ margin-bottom: 5px;
+ }
+ .pretix-widget-item-info-col:after {
+ display: block;
+ content: "";
+ clear: both;
+ }
+ .pretix-widget-item-price-col, .pretix-widget-item-availability-col {
+ width: 50%;
+ min-width: 140px;
+ }
+ .pretix-widget-action {
+ width: 100%;
+ margin-left: 0;
+ }
+ .pretix-widget-voucher-input-wrap {
+ width: 100%;
+ float: none;
+ }
+ .pretix-widget-voucher-button-wrap {
+ width: 100%;
+ float: none;
+ margin-top: 10px;
+ }
+
+ .pretix-widget-event-list-entry {
+ .pretix-widget-event-list-entry-name {
+ width: 100%;
+ }
+ .pretix-widget-event-list-entry-location {
+ width: 100%;
+ }
+ .pretix-widget-event-list-entry-date {
+ width: 50%;
+ }
+ .pretix-widget-event-list-entry-availability {
+ width: 50%;
+ }
+ }
+
+ .pretix-widget-event-calendar {
+ .pretix-widget-event-calendar-events {
+ display: none;
+ }
+ .pretix-widget-event-week-table {
+ .pretix-widget-event-calendar-events {
+ display: block;
+ }
+ }
+ td.pretix-widget-has-events {
+ background: $brand-primary;
+ color: white;
+ 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 {
+ display: block;
+ strong {
+ width: 100%;
+ display: block;
+ }
+ .pretix-widget-event-calendar-next-month, .pretix-widget-event-calendar-previous-month {
+ display: block;
+ width: 100%;
+ text-align: center;
+ }
+ }
+ }
+}
+
+@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;
+ }
+ }
+}