henry-search 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2887 +0,0 @@
1
- <script setup>
2
-
3
- import { ref, onMounted, onUnmounted, computed } from 'vue'
4
- import {
5
- AisClearRefinements,
6
- AisConfigure,
7
- AisCurrentRefinements,
8
- AisHighlight,
9
- AisHits,
10
- AisInstantSearch,
11
- AisPagination,
12
- AisRangeInput,
13
- AisRefinementList,
14
- AisSearchBox,
15
- AisStats
16
- } from 'vue-instantsearch/vue3/es'
17
- import TypesenseInstantSearchAdapter from 'typesense-instantsearch-adapter'
18
- import VueDatePicker from '@vuepic/vue-datepicker';
19
- import '@vuepic/vue-datepicker/dist/main.css'
20
- import VueSelect from 'vue-select'
21
- import { history as historyRouter } from 'instantsearch.js/es/lib/routers'
22
- import { simple as simpleStateMapping } from 'instantsearch.js/es/lib/stateMappings'
23
-
24
- const props = defineProps({
25
- indexName: {
26
- type: String,
27
- default: "performances"
28
- }
29
- })
30
-
31
-
32
- const routing = ref({
33
- router: historyRouter({
34
- // Disable scroll restoration to prevent erratic behavior
35
- writeDelay: 0
36
- }),
37
- stateMapping: simpleStateMapping()
38
- })
39
- const byDate = ref(true)
40
- const displayDate = ref(null)
41
- const datepicker = ref(null)
42
- const rangeInput = ref(null)
43
- const venueOptions = ref([])
44
- const ensembleOptions = ref([])
45
-
46
- const today = Date.now()
47
- const date = ref([today, today])
48
-
49
- // Modal state management
50
- let isCreatingModal = false
51
- let modalCreated = false
52
-
53
- // Reusable multi-select modal template function
54
- function createMultiSelectModalHTML(options = {}) {
55
- const {
56
- modalId = 'multi-select-modal',
57
- title = 'Make Selection',
58
- description = 'Choose your options',
59
- cancelText = 'Cancel',
60
- selectText = 'Select',
61
- cancelButtonClass = 'js-modal-cancel',
62
- selectButtonClass = 'js-modal-select',
63
- contentContainerClass = 'eventsModal__contentContainer'
64
- } = options
65
-
66
- return `
67
- <div class="modal-container">
68
- <div class="eventsModal js--modal -full menu-is-open ${modalId}" aria-hidden="false">
69
- <div class="eventsModal__headerGrid">
70
- <div class="event__performance-wrapper">
71
- <span class="event__performance-name">${title}</span>
72
- </div>
73
- <button class="js--modal-close" aria-label="Close modal">
74
- <svg xmlns="http://www.w3.org/2000/svg" width="18" height="17" fill="none">
75
- <path stroke="#686F73" d="m1.354.646 16 16m-16.708 0 16-16"/>
76
- </svg>
77
- </button>
78
- </div>
79
-
80
- <div class="eventsModal__content -full">
81
- <div class="eventsModal__dropdown -isMultiSelect">
82
- <span class="eventsModal__numberOfPerformances">${description}</span>
83
- <div class="${contentContainerClass}">
84
- <!-- Dynamic content will be inserted here -->
85
- </div>
86
- </div>
87
- </div>
88
-
89
- <div class="eventsModal__actions-container js-performance-actions" data-performance-id="${modalId}">
90
- <div class="performance__buttons">
91
- <div class="event__buttons">
92
- <div class="event__buy-button-wrapper js-event-buttons" data-where="modal" data-performance-id="${modalId}" style="display: flex; gap: 1rem; justify-content: center; width: 100%;">
93
- <button type="button" class="event__buy-button event__buy-button--secondary ${cancelButtonClass}" style="background: #F5F5F5; color: #333; border: 1px solid #ddd;">
94
- <strong>${cancelText}</strong>
95
- </button>
96
- <button type="button" class="event__buy-button ${selectButtonClass}">
97
- <strong>${selectText}</strong>
98
- </button>
99
- </div>
100
- </div>
101
- </div>
102
- </div>
103
- </div>
104
- </div>
105
- `
106
- }
107
-
108
- // Handle date picker opened event
109
- function onDatePickerOpened() {
110
- const windowWidth = typeof window !== 'undefined' ? window.innerWidth : 1024
111
- // Only create modal on mobile and if not already created or in progress
112
- if (windowWidth <= 767 && !modalCreated && !isCreatingModal) {
113
- isCreatingModal = true
114
- setTimeout(() => {
115
- createMobileDatePickerModal()
116
- isCreatingModal = false
117
- }, 150) // Timeout to ensure menu is fully rendered
118
- }
119
- }
120
-
121
- // Handle date picker closed event
122
- function onDatePickerClosed(value) {
123
- const windowWidth = typeof window !== 'undefined' ? window.innerWidth : 1024
124
-
125
- // Process the date selection
126
- if (value && Array.isArray(value) && value.length >= 2) {
127
- console.log('Processing date selection:', Math.floor(value[0]/1000), Math.floor(value[1]/1000))
128
- } else {
129
- console.log('No date selection or incomplete selection:', value)
130
- }
131
-
132
- // Clean up mobile fullscreen styling
133
- if (windowWidth <= 767) {
134
- const menu = document.querySelector('.dp__menu')
135
- if (menu) {
136
- // Reset styles
137
- menu.style.position = ''
138
- menu.style.top = ''
139
- menu.style.left = ''
140
- menu.style.right = ''
141
- menu.style.bottom = ''
142
- menu.style.width = ''
143
- menu.style.height = ''
144
- menu.style.zIndex = ''
145
- menu.style.background = ''
146
- menu.style.padding = ''
147
- }
148
-
149
- // Remove body class
150
- document.body.classList.remove('menu-is-open')
151
- }
152
- }
153
-
154
-
155
-
156
- const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
157
- server: {
158
- connectionTimeoutSeconds: 20,
159
- apiKey: 'qoWHCTjesGfIaxdXbw9vOgod1VToEXNI', // Be sure to use an API key that only allows search operations
160
- nodes: [
161
- {
162
- host: 'go8f04wi19tuvlyrp-1.a1.typesense.net',
163
- path: '', // Optional. Example: If you have your typesense mounted in localhost:8108/typesense, path should be equal to '/typesense'
164
- port: '443',
165
- protocol: 'https',
166
- },
167
- ],
168
- cacheSearchResultsForSeconds: 0, // Cache search results from server. Defaults to 2 minutes. Set to 0 to disable caching.
169
- },
170
- // The following parameters are directly passed to Typesense's search API endpoint.
171
- // So you can pass any parameters supported by the search endpoint below.
172
- // query_by is required.
173
- additionalSearchParameters: {
174
- query_by: 'title, excerpt, subhead, content_keywords',
175
- sort_by: 'performance_date:asc',
176
- // group_by: 'event_id',
177
- group_limit: 1
178
- },
179
- })
180
-
181
- const searchClient = typesenseInstantsearchAdapter.searchClient
182
-
183
- const perPage = computed(() => byDate.value ? 10 : 8)
184
-
185
- // Check if we're on mobile
186
- const isMobile = ref(false)
187
-
188
- // Function to check mobile status
189
- function checkMobile() {
190
- if (typeof window !== 'undefined') {
191
- isMobile.value = window.innerWidth <= 767
192
- }
193
- }
194
-
195
- onMounted(() => {
196
- // const startDate = new Date();
197
- // const endDate = new Date(new Date().setDate(startDate.getDate() + 7));
198
- // date.value = [startDate, endDate];
199
- //datepicker.value.clearValue()
200
- console.log("index name", props.indexName)
201
-
202
- // Disable browser scroll restoration
203
- if ('scrollRestoration' in history) {
204
- history.scrollRestoration = 'manual'
205
- }
206
-
207
- // Listen for clicks on pagination and scroll after a delay
208
- setupPaginationScrollFix()
209
-
210
- // Check mobile status and add resize listener
211
- checkMobile()
212
- if (typeof window !== 'undefined') {
213
- window.addEventListener('resize', checkMobile)
214
- }
215
-
216
- // Fallback: Watch for date picker menu to appear/disappear using MutationObserver
217
- const observer = new MutationObserver((mutations) => {
218
- mutations.forEach((mutation) => {
219
- // Watch for added nodes (menu opening)
220
- mutation.addedNodes.forEach((node) => {
221
- if (node.nodeType === 1 && node.classList) {
222
- // Only trigger for the main menu, not wrapper elements or our modal
223
- if (node.classList.contains('dp__menu') &&
224
- !node.classList.contains('dp__mobile_modal') &&
225
- !modalCreated && !isCreatingModal) {
226
- if (typeof window !== 'undefined' && window.innerWidth <= 767) {
227
- onDatePickerOpened()
228
- }
229
- }
230
- }
231
- })
232
- })
233
- })
234
-
235
- observer.observe(document.body, {
236
- childList: true,
237
- subtree: true
238
- })
239
-
240
- })
241
-
242
-
243
- onUnmounted(() => {
244
- // Restore browser scroll restoration
245
- if ('scrollRestoration' in history) {
246
- history.scrollRestoration = 'auto'
247
- }
248
-
249
- // Remove resize listener
250
- if (typeof window !== 'undefined') {
251
- window.removeEventListener('resize', checkMobile)
252
- }
253
- })
254
-
255
- function setupPaginationScrollFix() {
256
- // Use event delegation to catch pagination clicks
257
- document.addEventListener('click', (event) => {
258
- const paginationLink = event.target.closest('.ais-Pagination-link')
259
-
260
- if (paginationLink) {
261
- // Don't prevent default - let InstantSearch handle navigation normally
262
- // Schedule a scroll after InstantSearch updates
263
- setTimeout(() => {
264
- scrollToResults()
265
- }, 200)
266
- }
267
- })
268
- }
269
-
270
- function scrollToResults() {
271
- const resultsSection = document.querySelector('.eventsCalendar__results')
272
- if (resultsSection) {
273
- const rect = resultsSection.getBoundingClientRect()
274
- const scrollTop = window.pageYOffset + rect.top - 20 // 20px offset from top
275
-
276
- window.scrollTo({
277
- top: scrollTop,
278
- behavior: 'smooth'
279
- })
280
- }
281
- }
282
-
283
- const format = (date) => {
284
- if (date && date.length > 1) {
285
- const startDay = date[0].getDate();
286
- const startMonth = date[0].getMonth() + 1;
287
- const startYear = date[0].getFullYear();
288
-
289
- const endDay = date[1].getDate();
290
- const endMonth = date[1].getMonth() + 1;
291
- const endYear = date[1].getFullYear();
292
-
293
- return `${startMonth}/${startDay}/${startYear} - ${endMonth}/${endDay}/${endYear}`;
294
- }
295
- return ''
296
-
297
- }
298
-
299
- function formatDate(unix_timestamp, display = true) {
300
- // multiplied by 1000 so that the argument is in milliseconds, not seconds
301
- const date = new Date(unix_timestamp * 1000)
302
- const days = ["Sun", "Mon", "Tues", "Weds", "Thurs", "Fri", "Sat"]
303
- const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
304
- const hour = date.getHours() + 1 > 12 ? date.getHours() - 11 : date.getHours() + 1
305
- const amPm = date.getHours() + 1 > 12 ? "pm" : "am"
306
- const minutes = "0" + date.getMinutes()
307
-
308
- if (display) {
309
- return `${days[date.getDay()]}, ${(months[date.getMonth()]).substring(0, 3)} ${date.getDate()}, ${hour}:${minutes.substr(-2)}${amPm} EDT`
310
- } else {
311
- return `${months[date.getMonth()]}, ${date.getFullYear()}`
312
- }
313
- }
314
-
315
- function groupItemsByMonth(items) {
316
- console.log(items)
317
- let groupedItems = {}
318
- let currentMonth = null
319
- items.forEach(item => {
320
- if (currentMonth != formatDate(item.performance_date, false)) {
321
- currentMonth = formatDate(item.performance_date, false)
322
- groupedItems[currentMonth] = []
323
- }
324
- groupedItems[currentMonth].push(item)
325
- })
326
- return groupedItems
327
- }
328
-
329
- function toValue(value, range) {
330
- return [
331
- typeof value.min === "number" ? value.min * 1000 : range.min * 1000,
332
- typeof value.max === "number" ? value.max * 1000 : range.max * 1000,
333
- ];
334
- }
335
-
336
- function setView(viewType) {
337
- byDate.value = viewType === 'date'
338
- if (byDate.value) {
339
- typesenseInstantsearchAdapter.updateConfiguration({...typesenseInstantsearchAdapter.configuration, additionalSearchParameters: {
340
- query_by: 'title, excerpt, subhead, content_keywords',
341
- sort_by: 'performance_date:asc'
342
- }})
343
- } else {
344
- typesenseInstantsearchAdapter.updateConfiguration({...typesenseInstantsearchAdapter.configuration, additionalSearchParameters: {
345
- query_by: 'title, excerpt, subhead, content_keywords',
346
- sort_by: 'performance_date:asc',
347
- group_by: 'event_id',
348
- group_limit: 1
349
- }})
350
- }
351
- }
352
-
353
- const setDate = (value) => {
354
- date.value = value
355
- displayDate.value = value
356
-
357
- // Note: Modal closing is now handled by the Select button click handler
358
- }
359
-
360
- // Function to determine event status
361
- function getEventStatus(item) {
362
- // First check if backend provides real status data
363
- if (item.event_status && item.event_status.length > 0) {
364
- const status = item.event_status[0]; // Assuming first status is primary
365
- return getStatusMapping(status);
366
- }
367
-
368
- // Fallback logic until backend provides data
369
- if (item.performance_categories && item.performance_categories.includes('Free')) {
370
- return { status: 'Free Event', class: '-free' };
371
- }
372
-
373
- // Check if past date
374
- const eventDate = new Date(item.performance_date * 1000);
375
- const now = new Date();
376
- if (eventDate < now) {
377
- return { status: 'Past Event', class: '-past-date' };
378
- }
379
-
380
- // Default status
381
- return { status: 'On Sale', class: '-status' };
382
- }
383
-
384
- // Status mapping function to match Dropdown.vue status
385
- function getStatusMapping(status) {
386
- const statusMap = {
387
- 'Cancelled': { status: 'Cancelled', class: '-cancelled' },
388
- 'Rescheduled': { status: 'Rescheduled', class: '-rescheduled' },
389
- 'Postponed': { status: 'Postponed', class: '-postponed' },
390
- 'Sold Out': { status: 'Sold Out', class: '-sold-out' },
391
- 'Best Availability': { status: 'Best Availability', class: '-best-availability' },
392
- 'Limited Availability': { status: 'Limited Availability', class: '-limited-availability' },
393
- 'Coming Soon': { status: 'Coming Soon', class: '-coming-soon' },
394
- 'Past Event': { status: 'Past Event', class: '-past-date' },
395
- 'Free': { status: 'Free Event', class: '-free' },
396
- 'On Sale': { status: 'On Sale', class: '-status' },
397
- // Add fallback for unknown statuses
398
- 'default': { status: 'Status', class: '-status' }
399
- };
400
-
401
- return statusMap[status] || statusMap['default'];
402
- }
403
-
404
- // Get brand-specific CSS custom properties
405
- function getBrandColors(eventBrand) {
406
- // Map event_brand values to brand identifiers
407
- const brandMap = {
408
- 'bso': 'bso',
409
- 'boston symphony orchestra': 'bso',
410
- 'pops': 'pops',
411
- 'boston pops': 'pops',
412
- 'tanglewood': 'tw',
413
- 'tanglewood learning institute': 'tw',
414
- 'symphonyhall': 'sh',
415
- 'symphony hall': 'sh'
416
- };
417
-
418
- const brand = brandMap[eventBrand?.toLowerCase()] || 'bso';
419
-
420
- return {
421
- '--brand-200': `var(--c-brand-${brand}-200)`,
422
- '--brand-400': `var(--c-brand-${brand}-400)`,
423
- '--brand-600': `var(--c-brand-${brand}-600)`,
424
- '--brand-800': `var(--c-brand-${brand}-800)`
425
- };
426
- }
427
-
428
- // Check if notice should be displayed
429
- function hasNotice(item) {
430
- return item.notice && item.notice.trim().length > 0;
431
- }
432
-
433
- // Render notice icon using SVG symbol reference
434
- function renderNoticeIcon(iconName) {
435
- if (!iconName) return '';
436
-
437
- // Clean the icon name - remove any 'icon-' prefix if it exists
438
- const cleanIconName = iconName.replace(/^icon-/, '');
439
-
440
- return `<svg class="eventsCalendar__noticeIconSvg">
441
- <use xlink:href="#icon-${cleanIconName}"></use>
442
- </svg>`;
443
- }
444
-
445
- // Generate venue placeholder with count
446
- function getVenuePlaceholder(items) {
447
- const selectedCount = items.filter(item => item.isRefined).length;
448
- return selectedCount > 0 ? `Venue (${selectedCount})` : 'Venue';
449
- }
450
-
451
- // Generate ensemble placeholder with count
452
- function getEnsemblePlaceholder(items) {
453
- const selectedCount = items.filter(item => item.isRefined).length;
454
- return selectedCount > 0 ? `Ensemble (${selectedCount})` : 'Ensemble';
455
- }
456
-
457
- // Helper functions to split venue name from city
458
- function getVenueName(venueLabel) {
459
- const cleanLabel = venueLabel.replace(/<[^>]*>/g, ''); // Remove HTML tags
460
- const parts = cleanLabel.split(/,\s*(?=[A-Z])|(?:\s*\|\s*[^|]*,\s*)/);
461
- return parts[0]?.trim() || cleanLabel;
462
- }
463
-
464
- function getVenueCity(venueLabel) {
465
- const cleanLabel = venueLabel.replace(/<[^>]*>/g, ''); // Remove HTML tags
466
- const parts = cleanLabel.split(/,\s*(?=[A-Z])|(?:\s*\|\s*[^|]*,\s*)/);
467
- return parts.length >= 2 ? parts.slice(1).join(', ').trim() : '';
468
- }
469
-
470
- // Generic mobile filter modal function
471
- function createMobileFilterModal(filterType, displayName, items, refineFunction) {
472
- const modalHTML = createMultiSelectModalHTML({
473
- modalId: `${filterType}__mobile_modal`,
474
- title: `Select ${displayName}`,
475
- description: `Choose your ${displayName.toLowerCase()}`,
476
- cancelText: 'Cancel',
477
- selectText: 'Apply',
478
- cancelButtonClass: `js-${filterType}-cancel`,
479
- selectButtonClass: `js-${filterType}-select`,
480
- contentContainerClass: `eventsModal__${filterType}Container`
481
- })
482
-
483
- // Insert modal into body
484
- document.body.insertAdjacentHTML('beforeend', modalHTML)
485
-
486
- const modal = document.querySelector(`.${filterType}__mobile_modal`)
487
- const container = modal.querySelector(`.eventsModal__${filterType}Container`)
488
-
489
- if (modal && container) {
490
- // Generate filter options HTML
491
- let optionsHTML = '<div class="filterModal__items">'
492
-
493
- items.forEach((item) => {
494
- const isChecked = item.isRefined ? 'checked' : ''
495
- const cleanLabel = item.value.replace(/<[^>]*>/g, '') // Remove HTML tags
496
-
497
- // For venue, split venue name from city
498
- let itemTextHTML = `<span class="filterModal__itemText">${cleanLabel}</span>`
499
- if (filterType === 'venue') {
500
- // Split on common patterns: ", City" or " | City" or similar
501
- const parts = cleanLabel.split(/,\s*(?=[A-Z])|(?:\s*\|\s*[^|]*,\s*)/);
502
- if (parts.length >= 2) {
503
- const venueName = parts[0].trim();
504
- const cityInfo = parts.slice(1).join(', ').trim();
505
- itemTextHTML = `
506
- <span class="filterModal__itemText">
507
- <span class="filterModal__venueName">${venueName}</span>
508
- <span class="filterModal__venueCity">${cityInfo}</span>
509
- </span>
510
- `
511
- }
512
- }
513
-
514
- optionsHTML += `
515
- <div class="filterModal__item">
516
- <label class="filterModal__itemLabel">
517
- <input type="checkbox"
518
- class="${filterType}-checkbox"
519
- value="${item.value.replace(/"/g, '&quot;')}"
520
- ${isChecked}
521
- data-count="${item.count}"
522
- style="display: block !important; width: 20px !important; height: 20px !important; margin: 0 !important; opacity: 1 !important; visibility: visible !important;">
523
- ${itemTextHTML}
524
- </label>
525
- </div>
526
- `
527
- })
528
-
529
- optionsHTML += '</div>'
530
- container.innerHTML = optionsHTML
531
-
532
- // Add body class for modal
533
- document.body.classList.add('menu-is-open')
534
-
535
- // Add close functionality
536
- const closeBtn = modal.querySelector('.js--modal-close')
537
- if (closeBtn) {
538
- closeBtn.addEventListener('click', (e) => {
539
- e.preventDefault()
540
- closeMobileFilterModal(filterType)
541
- })
542
- }
543
-
544
- // Add escape key handler
545
- const escapeHandler = (evt) => {
546
- if (evt.keyCode === 27) { // ESC key
547
- closeMobileFilterModal(filterType)
548
- }
549
- }
550
- document.addEventListener('keydown', escapeHandler)
551
-
552
- // Add click listeners to buttons
553
- const selectBtn = modal.querySelector(`.js-${filterType}-select`)
554
- const cancelBtn = modal.querySelector(`.js-${filterType}-cancel`)
555
-
556
- if (selectBtn) {
557
- selectBtn.addEventListener('click', () => {
558
- // Get all checkboxes
559
- const checkboxes = modal.querySelectorAll(`.${filterType}-checkbox`)
560
-
561
- // Get currently selected values from checkboxes
562
- const selectedValues = []
563
- checkboxes.forEach(checkbox => {
564
- if (checkbox.checked) {
565
- selectedValues.push(checkbox.value)
566
- }
567
- })
568
-
569
- // First, clear all existing refinements
570
- items.forEach(item => {
571
- if (item.isRefined) {
572
- refineFunction(item.value)
573
- }
574
- })
575
-
576
- // Then apply new selections
577
- selectedValues.forEach(value => {
578
- refineFunction(value)
579
- })
580
-
581
- closeMobileFilterModal(filterType)
582
- })
583
- }
584
-
585
- if (cancelBtn) {
586
- cancelBtn.addEventListener('click', () => {
587
- closeMobileFilterModal(filterType)
588
- })
589
-
590
- // Add hover effects for secondary button
591
- cancelBtn.addEventListener('mouseenter', () => {
592
- cancelBtn.style.background = '#e5e5e5'
593
- })
594
-
595
- cancelBtn.addEventListener('mouseleave', () => {
596
- cancelBtn.style.background = '#F5F5F5'
597
- })
598
- }
599
- }
600
- }
601
-
602
- function closeMobileFilterModal(filterType) {
603
- const modal = document.querySelector(`.${filterType}__mobile_modal`)
604
- if (modal) {
605
- modal.remove()
606
- document.body.classList.remove('menu-is-open')
607
- }
608
- }
609
-
610
- // Generic click handler for filter dropdowns
611
- function handleFilterDropdownClick(event, filterType, displayName, items, refine) {
612
- let windowWidth = 1024; // Default to desktop
613
-
614
- try {
615
- if (typeof window !== 'undefined' && window) {
616
- windowWidth = window.innerWidth || 1024;
617
- }
618
- } catch (e) {
619
- // Window not available, use default
620
- }
621
-
622
- // Show modal on mobile only
623
- const shouldShowModal = windowWidth <= 767;
624
-
625
- if (shouldShowModal) {
626
- event.preventDefault();
627
- event.stopPropagation();
628
- createMobileFilterModal(filterType, displayName, items, refine);
629
- return false;
630
- } else {
631
- // console.log('Desktop - allowing normal dropdown');
632
- }
633
- }
634
-
635
- function createMobileDatePickerModal() {
636
- const menu = document.querySelector('.dp__menu')
637
- if (!menu) {
638
- setTimeout(() => {
639
- const retryMenu = document.querySelector('.dp__menu')
640
- if (retryMenu) {
641
- createMobileDatePickerModal()
642
- }
643
- }, 50)
644
- return
645
- }
646
-
647
- // Create modal structure using reusable template function
648
- const modalHTML = createMultiSelectModalHTML({
649
- modalId: 'dp__mobile_modal',
650
- title: 'Select Date Range',
651
- description: 'Choose your date range',
652
- cancelText: 'Cancel',
653
- selectText: 'Select',
654
- cancelButtonClass: 'js-datepicker-cancel',
655
- selectButtonClass: 'js-datepicker-select',
656
- contentContainerClass: 'eventsModal__datePickerContainer'
657
- })
658
-
659
- // Insert modal into body
660
- document.body.insertAdjacentHTML('beforeend', modalHTML)
661
-
662
- // Move the date picker menu into the modal
663
- const modal = document.querySelector('.dp__mobile_modal')
664
- const datePickerContainer = modal.querySelector('.eventsModal__datePickerContainer')
665
-
666
- if (modal && datePickerContainer && menu) {
667
- datePickerContainer.appendChild(menu)
668
-
669
- // Hide the original VueDatePicker buttons since we have modal buttons
670
- const originalActionRow = menu.querySelector('.dp__action_row')
671
- if (originalActionRow) {
672
- originalActionRow.style.display = 'none'
673
- }
674
-
675
- // Add body class for modal
676
- document.body.classList.add('menu-is-open')
677
-
678
- // Track selected range manually
679
- let selectedRange = null
680
-
681
- // Add close functionality
682
- const closeBtn = modal.querySelector('.js--modal-close')
683
- if (closeBtn) {
684
- closeBtn.addEventListener('click', (e) => {
685
- e.preventDefault()
686
- closeMobileDatePickerModal()
687
- })
688
- }
689
-
690
- // Add escape key handler
691
- document.addEventListener('keydown', handleModalEscape)
692
-
693
- // Add click listeners to our custom buttons
694
- const selectBtn = modal.querySelector('.js-datepicker-select')
695
- const cancelBtn = modal.querySelector('.js-datepicker-cancel')
696
-
697
- if (selectBtn) {
698
- selectBtn.addEventListener('click', () => {
699
-
700
- // Get currently selected dates from the calendar
701
- const selectedDates = menu.querySelectorAll('.dp__calendar_item[aria-selected="true"]')
702
-
703
- if (selectedDates.length >= 2) {
704
- const dateRange = []
705
- selectedDates.forEach((dateEl) => {
706
- const dateId = dateEl.id // Format: "2025-11-01"
707
- if (dateId) {
708
- const dateObj = new Date(dateId + 'T00:00:00')
709
- dateRange.push(dateObj)
710
- }
711
- })
712
-
713
- // Sort dates to ensure proper range
714
- dateRange.sort((a, b) => a - b)
715
-
716
- // Set the date range
717
- setDate(dateRange)
718
- displayDate.value = [...dateRange]
719
-
720
- } else if (selectedDates.length === 1) {
721
- // Single date selected - create a single day range
722
- const dateId = selectedDates[0].id
723
- const singleDate = new Date(dateId + 'T00:00:00')
724
- const endDate = new Date(singleDate)
725
- endDate.setDate(endDate.getDate() + 1)
726
-
727
- const range = [singleDate, endDate]
728
- setDate(range)
729
- displayDate.value = [...range]
730
-
731
- } else {
732
- console.log('No dates selected')
733
- }
734
-
735
- // Close modal
736
- setTimeout(() => {
737
- closeMobileDatePickerModal()
738
- }, 100)
739
- })
740
- }
741
-
742
- if (cancelBtn) {
743
- cancelBtn.addEventListener('click', () => {
744
- closeMobileDatePickerModal()
745
- })
746
-
747
- // Add hover effects for secondary button
748
- cancelBtn.addEventListener('mouseenter', () => {
749
- cancelBtn.style.background = '#e5e5e5'
750
- })
751
-
752
- cancelBtn.addEventListener('mouseleave', () => {
753
- cancelBtn.style.background = '#F5F5F5'
754
- })
755
- }
756
-
757
- modalCreated = true
758
- } else {
759
- console.error('Failed to find modal elements after creation')
760
- }
761
- }
762
-
763
- function closeMobileDatePickerModal() {
764
-
765
- // Close the VueDatePicker directly
766
- if (datepicker.value && datepicker.value.closeMenu) {
767
- datepicker.value.closeMenu()
768
- }
769
-
770
- const modal = document.querySelector('.dp__mobile_modal')
771
- if (modal) {
772
- modal.remove()
773
- document.body.classList.remove('menu-is-open')
774
- document.removeEventListener('keydown', handleModalEscape)
775
- modalCreated = false // Reset the flag
776
- } else {
777
- console.log('No modal found to remove')
778
- }
779
- // Always reset the flag, even if no modal was found
780
- modalCreated = false
781
- }
782
-
783
- function handleModalEscape(evt) {
784
- if (evt.keyCode === 27) { // ESC key
785
- closeMobileDatePickerModal()
786
- if (datepicker.value && datepicker.value.closeMenu) {
787
- datepicker.value.closeMenu()
788
- }
789
- }
790
- }
791
- </script>
792
-
793
-
794
- <template>
795
- <div class="eventsCalendar">
796
- <ais-instant-search
797
- :search-client="searchClient"
798
- :index-name="props.indexName"
799
- :routing="routing"
800
- class="eventsCalendar__search"
801
- >
802
- <ais-configure
803
- :hits-per-page.camel="perPage"
804
- />
805
-
806
- <!-- Header and Search Section -->
807
- <div class="eventsCalendar__topSection">
808
-
809
- <!-- Search Filters Section -->
810
- <section class="eventsCalendar__filters">
811
- <header class="eventsCalendar__header">
812
- <h1 class="eventsCalendar__title">Find Concerts & Events</h1>
813
- </header>
814
- <div class="eventsCalendar__filtersRow">
815
- <!-- Search Box -->
816
- <div class="eventsCalendar__filterGroup eventsCalendar__filterGroup--search">
817
- <ais-search-box
818
- placeholder="Performance name, artist, work, or category"
819
- class="eventsCalendar__searchBox"
820
- />
821
- </div>
822
-
823
- <!-- Date Filter -->
824
- <div class="eventsCalendar__filterGroup eventsCalendar__filterGroup--date">
825
- <ais-range-input attribute="performance_date" ref="rangeInput" :min="date && date[0] ? Math.floor(date[0]/1000) : Math.floor(today/1000)">
826
- <template v-slot="{ currentRefinement, range, refine }">
827
- <vue-date-picker
828
- ref="datepicker"
829
- :format="format"
830
- :model-value="displayDate"
831
- @update:model-value="setDate"
832
- range
833
- :multi-calendars="false"
834
- :enable-time-picker="false"
835
- @open="onDatePickerOpened"
836
- @close="onDatePickerClosed"
837
- placeholder="Date"
838
- class="eventsCalendar__datePicker"
839
- />
840
- </template>
841
- </ais-range-input>
842
- </div>
843
-
844
- <!-- Venue Filter -->
845
- <div class="eventsCalendar__filterGroup eventsCalendar__filterGroup--venue">
846
- <ais-refinement-list attribute="performance_venue.display_name" show-more>
847
- <template
848
- v-slot="{
849
- items,
850
- refine
851
- }"
852
- >
853
- <div
854
- class="eventsCalendar__vueSelectWrapper"
855
- @click="(event) => handleFilterDropdownClick(event, 'venue', 'Venue', items, refine)"
856
- >
857
- <vue-select
858
- :options="items"
859
- :model-value="items.filter(item => item.isRefined).map(item => ({ ...item, label: item.value}))"
860
- label="label"
861
- placeholder="Venue"
862
- multiple
863
- :searchable="!isMobile"
864
- :filterable="!isMobile"
865
- :disabled="isMobile"
866
- class="eventsCalendar__vueSelect"
867
- @update:modelValue="(selected) => {
868
- // Clear previous refinements first
869
- items.forEach(item => {
870
- if (item.isRefined) refine(item.value);
871
- });
872
- // Apply new refinements
873
- selected.forEach(venue => refine(venue.value));
874
- }"
875
- >
876
- <template #search="{ attributes, events }">
877
- <div class="eventsCalendar__searchWithIcon">
878
- <svg width="18" height="19" fill="none" class="eventsCalendar__venueIcon">
879
- <g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" clip-path="url(#a)">
880
- <path d="M9 10.063a2.25 2.25 0 1 0 0-4.5 2.25 2.25 0 0 0 0 4.5Z"/>
881
- <path d="M14.625 7.813c0 5.062-5.625 9-5.625 9s-5.625-3.938-5.625-9a5.625 5.625 0 0 1 11.25 0v0Z"/>
882
- </g>
883
- <defs>
884
- <clipPath id="a">
885
- <path fill="#fff" d="M0 .5h18v18H0z"/>
886
- </clipPath>
887
- </defs>
888
- </svg>
889
- <input
890
- class="vs__search"
891
- v-bind="attributes"
892
- v-on="events"
893
- :placeholder="getVenuePlaceholder(items)"
894
- />
895
- </div>
896
- </template>
897
- <template #option="{ label, count }">
898
- <div class="eventsCalendar__selectOption eventsCalendar__selectOption--venue">
899
- <input
900
- type="checkbox"
901
- class="venue-checkbox eventsCalendar__checkbox"
902
- :checked="items.find(item => item.value === label)?.isRefined || false"
903
- />
904
- <div class="eventsCalendar__venueInfo">
905
- <span class="eventsCalendar__venueName">{{ getVenueName(label) }}</span>
906
- <span class="eventsCalendar__venueCity">{{ getVenueCity(label) }}</span>
907
- </div>
908
- <!-- <span class="eventsCalendar__selectCount">({{ count }})</span> -->
909
- </div>
910
- </template>
911
- </vue-select>
912
- </div>
913
- </template>
914
- </ais-refinement-list>
915
- </div>
916
-
917
- <!-- Ensemble Filter -->
918
- <div class="eventsCalendar__filterGroup eventsCalendar__filterGroup--ensemble">
919
- <ais-refinement-list attribute="ensembles" show-more>
920
- <template
921
- v-slot="{
922
- items,
923
- refine
924
- }"
925
- >
926
- <div
927
- class="eventsCalendar__vueSelectWrapper"
928
- @click="(event) => handleFilterDropdownClick(event, 'ensemble', 'Ensemble', items, refine)"
929
- >
930
- <vue-select
931
- :model-value="items.filter(item => item.isRefined).map(item => ({ ...item, label: item.value.replace(/<\/[^>]*>/g, ' ').replace(/<[^>]*>/g, '') }))"
932
- :options="items.map(item => ({ ...item, label: item.value.replace(/<\/[^>]*>/g, ' ').replace(/<[^>]*>/g, '') }))"
933
- label="label"
934
- placeholder="Ensemble"
935
- multiple
936
- :searchable="!isMobile"
937
- :filterable="!isMobile"
938
- :disabled="isMobile"
939
- class="eventsCalendar__vueSelect"
940
- @update:modelValue="(selected) => {
941
- // Clear previous refinements first
942
- items.forEach(item => {
943
- if (item.isRefined) refine(item.value);
944
- });
945
- // Apply new refinements
946
- selected.forEach(ensemble => refine(ensemble.value));
947
- }"
948
- >
949
- <template #search="{ attributes, events }">
950
- <div class="eventsCalendar__searchWithIcon">
951
- <svg width="19" height="18" viewBox="0 0 19 18" fill="none" class="eventsCalendar__ensembleIcon">
952
- <path d="M7 14.3333V2.77778L17.6667 1V12.5556" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
953
- <path d="M4.33317 17.0001C5.80593 17.0001 6.99984 15.8062 6.99984 14.3334C6.99984 12.8607 5.80593 11.6667 4.33317 11.6667C2.86041 11.6667 1.6665 12.8607 1.6665 14.3334C1.6665 15.8062 2.86041 17.0001 4.33317 17.0001Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
954
- <path d="M14.9997 15.2222C16.4724 15.2222 17.6663 14.0283 17.6663 12.5556C17.6663 11.0828 16.4724 9.88892 14.9997 9.88892C13.5269 9.88892 12.333 11.0828 12.333 12.5556C12.333 14.0283 13.5269 15.2222 14.9997 15.2222Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
955
- </svg>
956
- <input
957
- class="vs__search"
958
- v-bind="attributes"
959
- v-on="events"
960
- :placeholder="getEnsemblePlaceholder(items)"
961
- />
962
- </div>
963
- </template>
964
- <template #option="{ label, count }">
965
- <div class="eventsCalendar__selectOption eventsCalendar__selectOption--ensemble">
966
- <input
967
- type="checkbox"
968
- class="ensemble-checkbox eventsCalendar__checkbox"
969
- :checked="items.find(item => item.value === label)?.isRefined || false"
970
- />
971
- <span v-html="label"></span>
972
- <!-- <span class="eventsCalendar__selectCount">({{ count }})</span> -->
973
- </div>
974
- </template>
975
- </vue-select>
976
- </div>
977
- </template>
978
- </ais-refinement-list>
979
- </div>
980
- </div>
981
- </section>
982
- </div>
983
-
984
- <!-- View Toggle and Active Filters -->
985
- <div class="eventsCalendar__filtersControls">
986
- <div class="eventsCalendar__filtersControlsInner" :class="{ '-eventView': !byDate }">
987
- <div class="eventsCalendar__filtersTitle">Calendar</div>
988
- <div class="eventsCalendar__filtersActions">
989
- <button
990
- @click="window.print()"
991
- class="eventsCalendar__printButton"
992
- title="Print Calendar"
993
- >
994
- <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
995
- <path d="M4 7V1H14V7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
996
- <path d="M3.2 14H2.6C2.17565 14 1.76869 13.8361 1.46863 13.5444C1.16857 13.2527 1 12.857 1 12.4444V8.55556C1 8.143 1.16857 7.74734 1.46863 7.45561C1.76869 7.16389 2.17565 7 2.6 7H15.4C15.8243 7 16.2313 7.16389 16.5314 7.45561C16.8314 7.74734 17 8.143 17 8.55556V12.4444C17 12.857 16.8314 13.2527 16.5314 13.5444C16.2313 13.8361 15.8243 14 15.4 14H14.8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
997
- <path d="M14 11H4V17H14V11Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
998
- </svg>
999
- <span>Print</span>
1000
- </button>
1001
- <div class="eventsCalendar__viewToggle">
1002
- <label class="eventsCalendar__radioOption" :class="{ '-selected': byDate }">
1003
- <input
1004
- type="radio"
1005
- name="viewType"
1006
- value="date"
1007
- :checked="byDate"
1008
- @change="setView('date')"
1009
- class="eventsCalendar__radioInput"
1010
- />
1011
- <span class="eventsCalendar__radioLabel">Date View</span>
1012
- </label>
1013
- <label class="eventsCalendar__radioOption" :class="{ '-selected': !byDate }">
1014
- <input
1015
- type="radio"
1016
- name="viewType"
1017
- value="event"
1018
- :checked="!byDate"
1019
- @change="setView('event')"
1020
- class="eventsCalendar__radioInput"
1021
- />
1022
- <span class="eventsCalendar__radioLabel">Event View</span>
1023
- </label>
1024
- </div>
1025
- </div>
1026
- <!-- Current Refinements -->
1027
- <ais-current-refinements :excluded-attributes="['performance_date']">
1028
- <template v-slot="{ items, createURL }">
1029
- <div class="eventsCalendar__filtersArea" v-if="items.length">
1030
- <!-- Results Count -->
1031
- <ais-stats>
1032
- <template v-slot="{ nbHits, query }">
1033
- <span v-if="query != '*'" class="eventsCalendar__resultsCount">{{ nbHits }} Results</span>
1034
- <span v-else class=""></span>
1035
- </template>
1036
- </ais-stats>
1037
-
1038
- <div class="eventsCalendar__activeFilters">
1039
- <ul class="eventsCalendar__activeFiltersList">
1040
- <li v-for="item in items" :key="item.attribute" class="eventsCalendar__activeFiltersGroup">
1041
- <ul class="eventsCalendar__activeFiltersItems">
1042
- <li
1043
- v-for="refinement in item.refinements"
1044
- :key="[
1045
- refinement.attribute,
1046
- refinement.type,
1047
- refinement.value,
1048
- refinement.operator
1049
- ].join(':')"
1050
- class="eventsCalendar__activeFilterItem"
1051
- >
1052
- <a
1053
- :href="createURL(refinement)"
1054
- @click.prevent="item.refine(refinement)"
1055
- v-html="refinement.label + ' ×'"
1056
- class="eventsCalendar__activeFilterRemove"
1057
- ></a>
1058
- </li>
1059
- </ul>
1060
- </li>
1061
- </ul>
1062
- <ais-clear-refinements>
1063
-
1064
- <template v-slot="{ canRefine, refine, createURL }">
1065
- <a
1066
- :href="createURL()"
1067
- @click.prevent="refine"
1068
- v-if="canRefine"
1069
- class="eventsCalendar__clearFilters"
1070
- >
1071
- Clear all filters
1072
- </a>
1073
- <span v-else></span>
1074
- </template>
1075
- </ais-clear-refinements>
1076
-
1077
- </div>
1078
- </div>
1079
- </template>
1080
- </ais-current-refinements>
1081
- </div>
1082
- </div>
1083
-
1084
- <!-- Search Results Section -->
1085
- <section class="eventsCalendar__results">
1086
- <ais-hits class="eventsCalendar__hits">
1087
- <template v-slot="{ items }">
1088
-
1089
- <!-- Results by Date View -->
1090
- <div v-if="byDate" class="eventsCalendar__resultsByDate">
1091
- <div v-for="month, key in groupItemsByMonth(items)" :key="key" class="eventsCalendar__monthGroup">
1092
- <h2 class="eventsCalendar__monthTitle">{{ key }}</h2>
1093
- <div class="eventsCalendar__monthEvents">
1094
- <article v-for="item in month" :key="item.objectId" class="eventsCalendar__eventCard">
1095
- <div class="eventsCalendar__eventMeta">
1096
- <div class="eventsCalendar__eventStatus" :class="getEventStatus(item).class">
1097
- {{ getEventStatus(item).status }}
1098
- </div>
1099
- </div>
1100
- <div class="eventsCalendar__eventContent">
1101
- <div class="eventsCalendar__categories" v-if="item.performance_categories && item.performance_categories.length">
1102
- <span
1103
- class="eventsCalendar__category"
1104
- v-for="category in item.performance_categories"
1105
- :key="category"
1106
- :style="getBrandColors(item.event_brand)"
1107
- >{{ category }}</span>
1108
- </div>
1109
- <h3 class="eventsCalendar__eventTitle" v-html="item.title"></h3>
1110
- <p v-if="item.subhead" class="eventsCalendar__eventSubhead">{{ item.subhead }}</p>
1111
-
1112
- <div class="eventsCalendar__eventDetails">
1113
- <time class="eventsCalendar__eventDate">
1114
- <svg xmlns="http://www.w3.org/2000/svg" width="19" height="19" fill="none"><g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" clip-path="url(#a)"><path d="M15.438 2.969H3.562a.594.594 0 0 0-.593.594v11.874c0 .328.266.594.594.594h11.874a.594.594 0 0 0 .594-.593V3.562a.594.594 0 0 0-.593-.593Zm-2.375-1.188v2.375M5.938 1.781v2.375M2.969 6.531H16.03"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h19v19H0z"/></clipPath></defs></svg>
1115
- {{ formatDate(item.performance_date) }}
1116
- </time>
1117
- <div class="eventsCalendar__eventVenue">
1118
- <svg width="18" height="19" fill="none"><g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" clip-path="url(#a)"><path d="M9 10.063a2.25 2.25 0 1 0 0-4.5 2.25 2.25 0 0 0 0 4.5Z"/><path d="M14.625 7.813c0 5.062-5.625 9-5.625 9s-5.625-3.938-5.625-9a5.625 5.625 0 0 1 11.25 0v0Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 .5h18v18H0z"/></clipPath></defs></svg>
1119
- <div class="eventsCalendar__eventVenueInner">
1120
- <a :href="item.performance_venue.link" class="eventsCalendar__venueLink">
1121
- {{ item.performance_venue.name }}
1122
- </a>
1123
- <span class="eventsCalendar__venueLocation">, {{ item.performance_venue.location }}</span>
1124
- </div>
1125
- </div>
1126
- <p v-if="item.performance_note" class="eventsCalendar__eventNote">
1127
- {{ item.performance_note }}</p>
1128
- <!-- Notice Display -->
1129
- <div v-if="hasNotice(item)" class="eventsCalendar__eventNotice" :style="{ color: item.notice_color }">
1130
- <span v-if="item.notice_icon" class="eventsCalendar__noticeIcon" v-html="renderNoticeIcon(item.notice_icon)" :style="{ color: item.notice_color }"></span>
1131
- <span class="eventsCalendar__noticeText">{{ item.notice }}</span>
1132
- </div>
1133
- </div>
1134
-
1135
- <div class="eventsCalendar__eventActions">
1136
- <a :href="item.performance_link" class="eventsCalendar__eventLink">Learn more</a>
1137
- <a
1138
- :href="item.ticket_link"
1139
- class="eventsCalendar__ticketLink"
1140
- :style="getBrandColors(item.event_brand)"
1141
- >
1142
- {{ item.ticket_text ? item.ticket_text : 'Buy Tickets' }}
1143
- <svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
1144
- <path d="M0 7.5H12" stroke="#686F73" stroke-width="1.5"/>
1145
- <path d="M6 1.5L12 7.5L6 13.5" stroke="#686F73" stroke-width="1.5"/>
1146
- </svg>
1147
- </a>
1148
- </div>
1149
- </div>
1150
- <div class="eventsCalendar__eventImage">
1151
- <img :src="item.image_src" :alt="item.image_alt" class="eventsCalendar__eventImg" />
1152
- </div>
1153
- </article>
1154
- </div>
1155
- </div>
1156
- </div>
1157
-
1158
- <!-- Results by Event View -->
1159
- <div v-else class="eventsCalendar__resultsByEvent">
1160
- <div class="eventsCalendar__eventsList">
1161
- <article v-for="item in items" :key="item.objectId" class="eventsCalendar__eventCard">
1162
- <div class="eventsCalendar__eventMeta">
1163
- <div class="eventsCalendar__eventStatus" :class="getEventStatus(item).class">
1164
- {{ getEventStatus(item).status }}
1165
- </div>
1166
- </div>
1167
- <div class="eventsCalendar__eventContent">
1168
- <div class="eventsCalendar__categories" v-if="item.performance_categories && item.performance_categories.length">
1169
- <span
1170
- class="eventsCalendar__category"
1171
- v-for="category in item.performance_categories"
1172
- :key="category"
1173
- :style="getBrandColors(item.event_brand)"
1174
- >{{ category }}</span>
1175
- </div>
1176
- <h3 class="eventsCalendar__eventTitle" v-html="item.title"></h3>
1177
- <p v-if="item.subhead" class="eventsCalendar__eventSubhead">{{ item.subhead }}</p>
1178
-
1179
- <div class="eventsCalendar__eventDetails">
1180
- <time v-if="item.num_performances == 1" class="eventsCalendar__eventDate">
1181
- <svg xmlns="http://www.w3.org/2000/svg" width="19" height="19" fill="none"><g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" clip-path="url(#a)"><path d="M15.438 2.969H3.562a.594.594 0 0 0-.593.594v11.874c0 .328.266.594.594.594h11.874a.594.594 0 0 0 .594-.593V3.562a.594.594 0 0 0-.593-.593Zm-2.375-1.188v2.375M5.938 1.781v2.375M2.969 6.531H16.03"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h19v19H0z"/></clipPath></defs></svg>
1182
- {{ formatDate(item.performance_date) }}
1183
- </time>
1184
- <time v-else-if="item.performance_range" class="eventsCalendar__eventDateRange">
1185
- {{ item.performance_range }}
1186
- </time>
1187
-
1188
- <div class="eventsCalendar__eventVenue">
1189
- <a :href="item.performance_venue.link" class="eventsCalendar__venueLink">
1190
- <svg width="18" height="19" fill="none"><g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" clip-path="url(#a)"><path d="M9 10.063a2.25 2.25 0 1 0 0-4.5 2.25 2.25 0 0 0 0 4.5Z"/><path d="M14.625 7.813c0 5.062-5.625 9-5.625 9s-5.625-3.938-5.625-9a5.625 5.625 0 0 1 11.25 0v0Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 .5h18v18H0z"/></clipPath></defs></svg>
1191
- {{ item.performance_venue.name }}
1192
- </a>
1193
- <span class="eventsCalendar__venueLocation">, {{ item.performance_venue.location }}</span>
1194
- </div>
1195
- <p v-if="item.performance_note" class="eventsCalendar__eventNote">{{ item.performance_note }}</p>
1196
- <!-- Notice Display -->
1197
- <div v-if="hasNotice(item)" class="eventsCalendar__eventNotice" :style="{ color: item.notice_color }">
1198
- <span v-if="item.notice_icon" class="eventsCalendar__noticeIcon" v-html="renderNoticeIcon(item.notice_icon)" :style="{ color: item.notice_color }"></span>
1199
- <span class="eventsCalendar__noticeText">{{ item.notice }}</span>
1200
- </div>
1201
- </div>
1202
-
1203
- <div class="eventsCalendar__eventActions">
1204
- <a :href="item.performance_link" class="eventsCalendar__eventLink">Learn more</a>
1205
- <a
1206
- v-if="item.ticket_link && item.num_performances == 1"
1207
- :href="item.ticket_link"
1208
- class="eventsCalendar__ticketLink"
1209
- :style="getBrandColors(item.event_brand)"
1210
- >
1211
- {{ item.ticket_text ? item.ticket_text : 'Buy Tickets' }}
1212
- <svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
1213
- <path d="M0 7.5H12" stroke="#686F73" stroke-width="1.5"/>
1214
- <path d="M6 1.5L12 7.5L6 13.5" stroke="#686F73" stroke-width="1.5"/>
1215
- </svg>
1216
- </a>
1217
- <a
1218
- v-else
1219
- :href="item.performance_link"
1220
- class="eventsCalendar__ticketLink"
1221
- :style="getBrandColors(item.event_brand)"
1222
- >Get Tickets</a>
1223
- </div>
1224
- </div>
1225
- <div class="eventsCalendar__eventImage">
1226
- <img :src="item.image_src" :alt="item.image_alt" class="eventsCalendar__eventImg" />
1227
- </div>
1228
- </article>
1229
- </div>
1230
- </div>
1231
- </template>
1232
- </ais-hits>
1233
-
1234
- <!-- Pagination -->
1235
- <nav class="eventsCalendar__pagination">
1236
- <ais-pagination
1237
- :show-first="true"
1238
- :show-previous="true"
1239
- :show-next="true"
1240
- :show-last="true"
1241
- class="eventsCalendar__paginationComponent"
1242
- />
1243
- </nav>
1244
- </section>
1245
- </ais-instant-search>
1246
- </div>
1247
-
1248
- </template>
1249
-
1250
- <style lang="scss">
1251
- .eventsCalendar {
1252
- // Ensure full width in responsive design mode
1253
- width: 100%;
1254
- max-width: 100%;
1255
- overflow-x: hidden;
1256
- &__topSection {
1257
- background-color: #FBF4EF;
1258
- display: flex;
1259
- align-items: flex-start;
1260
- gap: 2rem;
1261
- padding: 2rem 20px;
1262
- width: 100%;
1263
- box-sizing: border-box;
1264
-
1265
- @media screen and (min-width: 768px) {
1266
- padding: 2rem 80px;
1267
- }
1268
-
1269
- @media screen and (max-width: 768px) {
1270
- flex-direction: column;
1271
- gap: 1rem;
1272
- }
1273
-
1274
- @media screen and (min-width: 1070px) {
1275
- padding: 2rem 80px 2rem 140px;
1276
- }
1277
- }
1278
-
1279
- &__header {
1280
- flex-shrink: 0;
1281
- min-width: 200px;
1282
- margin-bottom: .5rem;
1283
- }
1284
-
1285
- &__title {
1286
- font-weight: var(--font-weight-bold);
1287
- font-size: var(--font-size-2);
1288
- line-height: var(--line-height-heading);
1289
- letter-spacing: -0.01em;
1290
- color: var(--c-theme-800);
1291
- margin-bottom: 0;
1292
- }
1293
-
1294
- &__searchBox {
1295
- border: 1px solid #D7D7D7;
1296
- border-radius: 5px;
1297
- width: 100%;
1298
- background-color: #FDF9F7;
1299
- padding: .5rem;
1300
- height: 40px;
1301
- display: flex;
1302
- align-items: center;
1303
- box-sizing: border-box;
1304
-
1305
- .ais-SearchBox-form {
1306
- display: flex;
1307
- align-items: center;
1308
- justify-content: start;
1309
- flex-direction: row-reverse;
1310
- gap: .5rem;
1311
- height: 100%;
1312
- width: 100%;
1313
- }
1314
-
1315
- .ais-SearchBox-input {
1316
- font-size: var(--font-size-2);
1317
- width: 90%;
1318
- height: 100%;
1319
- border: none;
1320
- outline: none;
1321
- }
1322
-
1323
- .ais-SearchBox-submitIcon {
1324
- width: 16px;
1325
- height: 16px;
1326
- }
1327
-
1328
- .ais-SearchBox-reset {
1329
- align-self: center !important;
1330
- display: flex;
1331
- align-items: center !important;
1332
- justify-content: center !important;
1333
- line-height: 1 !important;
1334
- vertical-align: middle !important;
1335
- }
1336
- }
1337
-
1338
- &__filters,
1339
- &__filtersControlsInner {
1340
- flex: 1;
1341
- min-width: 0;
1342
- }
1343
-
1344
- &__filtersControlsInner {
1345
- display: grid;
1346
- grid-template-columns: 1fr auto;
1347
- grid-template-areas:
1348
- "title actions"
1349
- "filters filters";
1350
-
1351
- @media screen and (min-width: 1070px) {
1352
- grid-template-columns: 1fr auto;
1353
- grid-template-rows: auto auto;
1354
- grid-template-areas:
1355
- "title actions"
1356
- "filters filters";
1357
- }
1358
-
1359
- // Add border-bottom when Event view is active
1360
- &.-eventView {
1361
- border-bottom: 1px solid #D3D0CD;
1362
- padding-bottom: 1rem;
1363
- margin-bottom: 1rem;
1364
- }
1365
- }
1366
-
1367
- &__filtersRow {
1368
- display: grid;
1369
- gap: 1rem;
1370
- grid-template-columns: 1fr 1fr 1fr;
1371
- grid-template-areas:
1372
- "search search search"
1373
- "date venue ensemble";
1374
-
1375
- @media screen and (min-width: 768px) {
1376
- grid-template-columns: 1fr 1fr;
1377
- grid-template-areas:
1378
- "search search"
1379
- "date date"
1380
- "venue ensemble";
1381
- }
1382
-
1383
- @media screen and (min-width: 1070px) {
1384
- grid-template-columns: 1fr 200px 200px 200px;
1385
- grid-template-areas:
1386
- "search date venue ensemble";
1387
- }
1388
- }
1389
-
1390
- &__filterGroup {
1391
- flex: 1;
1392
-
1393
- &--search {
1394
- grid-area: search;
1395
- }
1396
-
1397
- &--date {
1398
- grid-area: date;
1399
- .dp__input_wrap {
1400
- height: 40px !important;
1401
- }
1402
-
1403
- .dp__input {
1404
- height: 40px !important;
1405
- border: 1px solid #D6D6D6 !important;
1406
- border-radius: 5px !important;
1407
- background: #FDF9F7 !important;
1408
- padding: 0 2.5rem !important;
1409
- font-size: 14px !important;
1410
- box-sizing: border-box !important;
1411
- display: flex !important;
1412
- align-items: center !important;
1413
-
1414
- &::placeholder {
1415
- color: #666;
1416
- }
1417
-
1418
- @media screen and (min-width: 1070px) {
1419
- font-size: 16px !important;
1420
- padding: 0 2.75rem !important;
1421
- }
1422
- }
1423
-
1424
- .dp__input_icon {
1425
- margin-left: 8px !important;
1426
- flex-shrink: 0 !important;
1427
- }
1428
-
1429
- // Mobile fullscreen date picker styles
1430
- @media screen and (max-width: 767px) {
1431
- .dp__menu {
1432
- position: fixed !important;
1433
- top: 60px !important; // Leave space for custom header
1434
- left: 0 !important;
1435
- right: 0 !important;
1436
- bottom: 0 !important;
1437
- width: 100vw !important;
1438
- height: calc(100vh - 60px) !important; // Adjust for header
1439
- max-width: none !important;
1440
- max-height: none !important;
1441
- border-radius: 0 !important;
1442
- z-index: 9999 !important;
1443
- background: white !important;
1444
- box-shadow: none !important;
1445
- border: none !important;
1446
- margin: 0 !important;
1447
- padding: 0 !important;
1448
- display: flex !important;
1449
- flex-direction: column !important;
1450
- }
1451
-
1452
-
1453
- .dp__menu_inner {
1454
- flex: 1 !important;
1455
- display: flex !important;
1456
- flex-direction: column !important;
1457
- padding: 1rem !important;
1458
- height: 100% !important;
1459
- box-sizing: border-box !important;
1460
- }
1461
-
1462
- .dp__calendar_header {
1463
- padding: 1rem 0 !important;
1464
- border-bottom: 1px solid #e0e0e0 !important;
1465
- margin-bottom: 1rem !important;
1466
- }
1467
-
1468
- .dp__calendar_header_item {
1469
- font-size: 18px !important;
1470
- font-weight: 600 !important;
1471
- }
1472
-
1473
- .dp__calendar_wrap {
1474
- flex: 1 !important;
1475
- display: flex !important;
1476
- flex-direction: column !important;
1477
- justify-content: flex-start !important;
1478
- overflow: hidden !important;
1479
- }
1480
-
1481
- .dp__calendar {
1482
- width: 100% !important;
1483
- max-width: none !important;
1484
- }
1485
-
1486
- // Force single month display
1487
- .dp__instance_calendar {
1488
- width: 100% !important;
1489
-
1490
- &:not(:first-child) {
1491
- display: none !important;
1492
- }
1493
- }
1494
-
1495
- // Hide multi-calendar controls if they exist
1496
- .dp__calendar_header_separator,
1497
- .dp__calendar_next,
1498
- .dp__calendar_prev {
1499
- display: none !important;
1500
- }
1501
-
1502
- .dp__calendar_row {
1503
- margin-bottom: 0.5rem !important;
1504
- }
1505
-
1506
- .dp__calendar_item {
1507
- height: 48px !important;
1508
- width: 48px !important;
1509
- font-size: 16px !important;
1510
- margin: 2px !important;
1511
- }
1512
-
1513
- // Essential dp__ button styles for functionality
1514
- .dp__action_button {
1515
- cursor: pointer !important;
1516
- border: none !important;
1517
- padding: 0.75rem 1.5rem !important;
1518
- border-radius: 0.375rem !important;
1519
- font-weight: 500 !important;
1520
- transition: all 0.2s ease !important;
1521
- }
1522
-
1523
- .dp__action_select,
1524
- .dp__select {
1525
- background: var(--c-brand, #007bff) !important;
1526
- color: white !important;
1527
- border: none !important;
1528
-
1529
- &:hover {
1530
- background: var(--c-brand-dark, #0056b3) !important;
1531
- }
1532
- }
1533
-
1534
- .dp__action_cancel {
1535
- background: #f5f5f5 !important;
1536
- color: #333 !important;
1537
- border: 1px solid #ddd !important;
1538
-
1539
- &:hover {
1540
- background: #e8e8e8 !important;
1541
- }
1542
- }
1543
-
1544
- // Hide original action row positioning to prevent flash
1545
- .dp__action_row {
1546
- &:not(.dp__action_row--repositioned) {
1547
- opacity: 0 !important;
1548
- transition: opacity 0.1s ease !important;
1549
- }
1550
- }
1551
-
1552
- // Note: CSS styles don't work for modals inserted outside component scope
1553
- // Using inline styles in JavaScript instead
1554
-
1555
- // Add overlay backdrop
1556
- .dp__overlay {
1557
- position: fixed !important;
1558
- top: 0 !important;
1559
- left: 0 !important;
1560
- right: 0 !important;
1561
- bottom: 0 !important;
1562
- background: rgba(0, 0, 0, 0.5) !important;
1563
- z-index: 9998 !important;
1564
- }
1565
- }
1566
- }
1567
-
1568
- &--venue {
1569
- grid-area: venue;
1570
- }
1571
-
1572
- &--ensemble {
1573
- grid-area: ensemble;
1574
- }
1575
- }
1576
-
1577
- &__filtersControls {
1578
- display: flex;
1579
- align-items: center;
1580
- gap: 1rem;
1581
- margin-top: 1rem;
1582
- flex-wrap: wrap;
1583
- font-size: 14px;
1584
- padding: 0 20px;
1585
-
1586
- @media screen and (min-width: 768px) {
1587
- padding: 0 80px;
1588
- }
1589
-
1590
- @media screen and (min-width: 1070px) {
1591
- margin-top: 3rem;
1592
- margin-left: 60px;
1593
- padding: 0 80px;
1594
- }
1595
- }
1596
-
1597
- &__filtersTitle {
1598
- font-size: 32px;
1599
- font-weight: 700;
1600
- color: var(--c-theme-800);
1601
- grid-area: title;
1602
- margin-bottom: .5rem;
1603
-
1604
- @media screen and (min-width: 1070px) {
1605
- font-size: 50px;
1606
- margin-bottom: 0;
1607
- }
1608
- }
1609
-
1610
- .ais-CurrentRefinements {
1611
- grid-area: filters;
1612
- }
1613
-
1614
- &__filtersArea {
1615
- grid-area: filters;
1616
- border-top: 1px solid #D3D0CD;
1617
- margin-top: .5rem;
1618
- padding: .75rem 0;
1619
- }
1620
-
1621
- &__activeFilters {
1622
- display: grid;
1623
- grid-template-columns: 1fr auto;
1624
- gap: 0.5rem;
1625
- align-items: center;
1626
- }
1627
-
1628
- &__activeFiltersList {
1629
- display: flex;
1630
- flex-direction: column;
1631
- gap: .75rem;
1632
- }
1633
-
1634
- &__activeFiltersItems {
1635
- display: flex;
1636
- flex-wrap: wrap;
1637
- align-items: center;
1638
- gap: 0.5rem;
1639
- }
1640
-
1641
- &__activeFilterItem {
1642
- background-color: #f5f5f5;
1643
- border-radius: 4px;
1644
- padding: .25rem .5rem;
1645
- }
1646
-
1647
- &__activeFilterRemove {
1648
- .eventLocation {
1649
- margin-left: 0.25rem;
1650
- }
1651
- }
1652
-
1653
- &__filtersActions {
1654
- display: flex;
1655
- align-items: center;
1656
- gap: 1rem;
1657
- grid-area: actions;
1658
- }
1659
-
1660
- &__printButton {
1661
- background: none;
1662
- border: none;
1663
- cursor: pointer;
1664
- padding: 8px 12px;
1665
- border-radius: 4px;
1666
- display: none;
1667
- color: #686F73;
1668
- font-size: 14px;
1669
- transition: background-color 0.2s, color 0.2s;
1670
-
1671
- @media screen and (min-width: 1070px) {
1672
- display: flex;
1673
- align-items: center;
1674
- justify-content: center;
1675
- gap: 6px;
1676
- }
1677
-
1678
- &:hover {
1679
- background-color: #f0f0f0;
1680
- color: var(--c-theme-800);
1681
- }
1682
-
1683
- svg {
1684
- display: block;
1685
- flex-shrink: 0;
1686
- }
1687
-
1688
- span {
1689
- white-space: nowrap;
1690
- }
1691
- }
1692
-
1693
- &__viewToggle {
1694
- display: flex;
1695
- gap: 0;
1696
- border: 1px solid var(--brand-200, var(--c-theme-200));
1697
- border-radius: 4px;
1698
- overflow: hidden;
1699
- background: white;
1700
- }
1701
-
1702
- &__radioOption {
1703
- position: relative;
1704
- cursor: pointer;
1705
- display: flex;
1706
- align-items: center;
1707
- justify-content: center;
1708
- padding: 8px 16px;
1709
- background: white;
1710
- color: #686F73;
1711
- font-size: 14px;
1712
- font-weight: 500;
1713
- transition: all 0.2s ease;
1714
- border: none;
1715
- min-width: 80px;
1716
-
1717
- &:first-child {
1718
- border-right: 1px solid var(--brand-200, var(--c-theme-200));
1719
- }
1720
-
1721
- &:hover {
1722
- background-color: #f8f8f8;
1723
- color: var(--c-theme-800);
1724
- }
1725
-
1726
- &.-selected {
1727
- background-color: var(--brand-200, var(--c-theme-200));
1728
- color: var(--brand-800, var(--c-theme-800));
1729
-
1730
- &:hover {
1731
- background-color: var(--brand-200, var(--c-theme-200));
1732
- color: var(--brand-800, var(--c-theme-800));
1733
- }
1734
- }
1735
- }
1736
-
1737
- &__radioInput {
1738
- position: absolute;
1739
- opacity: 0;
1740
- width: 0;
1741
- height: 0;
1742
- pointer-events: none;
1743
- }
1744
-
1745
- &__radioLabel {
1746
- white-space: nowrap;
1747
- user-select: none;
1748
- }
1749
-
1750
- &__printButton {
1751
- color: #686F73;
1752
- }
1753
-
1754
- // Dropdown styles
1755
- &__vueSelectWrapper {
1756
- position: relative;
1757
-
1758
- // On mobile, add pointer cursor to indicate clickability
1759
- @media screen and (max-width: 767px) {
1760
- cursor: pointer;
1761
-
1762
- // Add a pseudo-element to capture clicks
1763
- &::before {
1764
- content: '';
1765
- position: absolute;
1766
- top: 0;
1767
- left: 0;
1768
- right: 0;
1769
- bottom: 0;
1770
- z-index: 10;
1771
- background: transparent;
1772
- }
1773
- }
1774
- }
1775
-
1776
- &__vueSelect {
1777
- &.v-select {
1778
- min-height: auto;
1779
- border: 0;
1780
- padding: 0;
1781
- }
1782
-
1783
- // On mobile, style disabled state to look normal and clickable
1784
- @media screen and (max-width: 767px) {
1785
- &.vs--disabled {
1786
- opacity: 1 !important;
1787
-
1788
- .vs__dropdown-toggle {
1789
- cursor: pointer !important;
1790
- background: #FDF9F7 !important;
1791
- border-color: #D6D6D6 !important;
1792
- }
1793
-
1794
- .vs__selected {
1795
- display: none !important;
1796
- }
1797
-
1798
- .vs__search {
1799
- cursor: pointer !important;
1800
- }
1801
- }
1802
- }
1803
-
1804
- .vs__dropdown-toggle {
1805
- border-radius: 5px !important;
1806
- border: 1px solid #D6D6D6 !important;
1807
- background: #FDF9F7 !important;
1808
- padding: 0 12px 0 12px !important;
1809
- height: 40px !important;
1810
- min-height: 40px !important;
1811
- max-height: 40px !important;
1812
- max-width: 100% !important;
1813
- display: flex !important;
1814
- align-items: center !important;
1815
- box-sizing: border-box !important;
1816
- outline: none !important;
1817
- overflow: hidden !important;
1818
- }
1819
-
1820
- &.vs--focused .vs__dropdown-toggle {
1821
- border: 1px solid var(--c-brand) !important; // Keep original border
1822
- outline: none !important;
1823
- box-sizing: border-box !important;
1824
- }
1825
-
1826
- &.vs--open .vs__dropdown-toggle {
1827
- border: 1px solid var(--c-brand) !important; // Keep original border
1828
- outline: none !important;
1829
- box-sizing: border-box !important;
1830
- }
1831
-
1832
- .vs__selected-options {
1833
- padding: 0;
1834
- flex-wrap: wrap;
1835
- gap: 4px;
1836
- max-width: calc(100% - 32px) !important; // Reserve space for dropdown arrow
1837
- overflow: hidden !important;
1838
- }
1839
-
1840
- .vs__search {
1841
- margin: 0 !important;
1842
- padding: 0 !important;
1843
- border: none !important;
1844
- font-size: 14px !important;
1845
- flex: 1 !important;
1846
- position: relative !important;
1847
- top: 0 !important;
1848
- left: 0 !important;
1849
-
1850
- @media screen and (min-width: 1070px) {
1851
- font-size: 16px !important;
1852
- }
1853
-
1854
- &::placeholder {
1855
- color: #666;
1856
- position: relative !important;
1857
- top: 0 !important;
1858
- left: 0 !important;
1859
- }
1860
- }
1861
-
1862
- &.vs--open {
1863
- border: none !important;
1864
- .vs__search {
1865
- margin: 0 !important;
1866
- padding: 0 !important;
1867
- position: relative !important;
1868
- top: 0 !important;
1869
- left: 0 !important;
1870
-
1871
- &::placeholder {
1872
- position: relative !important;
1873
- top: 0 !important;
1874
- left: 0 !important;
1875
- }
1876
- }
1877
-
1878
- .vs__dropdown-toggle {
1879
- padding: 0 12px 0 12px !important;
1880
- }
1881
-
1882
- .vs__selected-options {
1883
- padding: 0 !important;
1884
- }
1885
- }
1886
-
1887
- .vs__selected {
1888
- display: none !important;
1889
-
1890
- .vs__deselect {
1891
- color: white;
1892
- position: absolute !important;
1893
- right: 4px !important;
1894
- top: 50% !important;
1895
- transform: translateY(-50%) !important;
1896
- margin: 0 !important;
1897
- display: flex !important;
1898
- align-items: center !important;
1899
- justify-content: center !important;
1900
- width: 16px !important;
1901
- height: 16px !important;
1902
- }
1903
- }
1904
-
1905
- .vs__dropdown-menu {
1906
- border: 1px solid #D6D6D6;
1907
- border-radius: 5px;
1908
- box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.12);
1909
- max-height: 200px;
1910
- overflow-y: auto;
1911
- padding: 8px 0;
1912
- display: grid;
1913
- gap: 0.75rem;
1914
- }
1915
-
1916
- .vs__dropdown-option {
1917
- padding: 12px 16px;
1918
- cursor: pointer;
1919
- font-size: 17px !important;
1920
- margin: 0 16px;
1921
- border-radius: 4px;
1922
- white-space: normal !important;
1923
- word-wrap: break-word !important;
1924
- overflow-wrap: break-word !important;
1925
- line-height: 1.4 !important;
1926
-
1927
- &:hover,
1928
- &--highlight {
1929
- color: var(--c-theme-400) !important;
1930
- }
1931
- }
1932
-
1933
- .vs__actions {
1934
- padding: 0 12px 0 8px !important;
1935
- margin: 0 !important;
1936
- display: flex !important;
1937
- position: relative !important;
1938
- align-items: center !important;
1939
- justify-content: center !important;
1940
- height: 38px !important;
1941
- min-width: 32px !important;
1942
- flex-shrink: 0 !important;
1943
-
1944
- &::after {
1945
- content: '' !important;
1946
- border: 1px solid var(--c-theme-800) !important;
1947
- border-width: 0 1.5px 1.5px 0 !important;
1948
- display: inline-block !important;
1949
- padding: 4px !important;
1950
- transform: rotate(45deg) !important;
1951
- transition: transform 0.3s ease !important;
1952
- position: absolute !important;
1953
- top: 50% !important;
1954
- right: 0 !important;
1955
- margin-top: -6px !important;
1956
- z-index: 10 !important;
1957
- pointer-events: none !important;
1958
-
1959
- @media screen and (min-width: 768px) {
1960
- right: 12px !important;
1961
- }
1962
- }
1963
- }
1964
-
1965
- .vs__open-indicator {
1966
- display: none !important;
1967
- opacity: 0 !important;
1968
- visibility: hidden !important;
1969
- }
1970
-
1971
- &.vs--open .vs__actions::after {
1972
- transform: rotate(-135deg) !important;
1973
- }
1974
-
1975
- }
1976
-
1977
- &__selectOption {
1978
- display: flex;
1979
- justify-content: space-between;
1980
- align-items: center;
1981
- width: 100%;
1982
- gap: 4px;
1983
-
1984
- span {
1985
- white-space: normal;
1986
- word-wrap: break-word;
1987
- overflow-wrap: break-word;
1988
- line-height: 1.4;
1989
- min-width: 0; // Important for flex wrapping
1990
- max-width: calc(100% - 30px); // Reserve minimal space for count
1991
- }
1992
- }
1993
-
1994
- &__selectCount {
1995
- color: #999;
1996
- font-size: 11px;
1997
- margin-left: 2px;
1998
- padding: 0 2px;
1999
- flex-shrink: 0;
2000
- align-self: flex-start;
2001
- min-width: 0;
2002
- width: fit-content;
2003
- white-space: nowrap;
2004
- line-height: 1.2;
2005
- }
2006
-
2007
- &__searchWithIcon {
2008
- display: flex;
2009
- align-items: center;
2010
- gap: 8px;
2011
- width: 100%;
2012
- padding: 0;
2013
- }
2014
-
2015
- &__venueIcon,
2016
- &__ensembleIcon {
2017
- flex-shrink: 0;
2018
- color: #666;
2019
- width: 19px;
2020
- height: 18px;
2021
- max-height: 18px;
2022
- }
2023
-
2024
- // Search Results
2025
- &__resultsByDate,
2026
- &__resultsByEvent {
2027
- padding: 0 20px;
2028
-
2029
- @media screen and (min-width: 768px) {
2030
- padding: 0 80px;
2031
- }
2032
-
2033
- @media screen and (min-width: 1070px) {
2034
- margin-left: 60px;
2035
- padding: 0 80px;
2036
- }
2037
- }
2038
-
2039
-
2040
- &__resultsCount {
2041
- color: #686F73;
2042
- display: inline-block;
2043
- font-size: var(--font-size-3);
2044
- font-weight: var(--font-weight-bold);
2045
- margin-bottom: .75rem;
2046
- }
2047
-
2048
- // Results by Date View
2049
- &__resultsByDate {
2050
- .eventsCalendar__eventImage {
2051
- width: 222px;
2052
- height: 139px;
2053
- margin-left: 0;
2054
-
2055
- @media screen and (min-width: 768px) {
2056
- margin-left: auto;
2057
- }
2058
- }
2059
-
2060
- .eventsCalendar__eventTitle {
2061
- font-size: 18px;
2062
-
2063
- @media screen and (min-width: 1070px) {
2064
- font-size: 22px;
2065
- }
2066
- }
2067
-
2068
- .eventsCalendar__eventDate,
2069
- .eventsCalendar__eventVenue,
2070
- .eventsCalendar__eventActions {
2071
- font-size: var(--font-size-1);
2072
-
2073
- @media screen and (min-width: 1070px) {
2074
- font-size: var(--font-size-2);
2075
- }
2076
- }
2077
-
2078
- .eventsCalendar__eventCard {
2079
- @media screen and (min-width: 1070px) {
2080
- grid-template-columns: 1fr 2fr 1fr;
2081
- grid-template-areas: "status content image";
2082
- }
2083
- }
2084
-
2085
- .eventsCalendar__eventDetails {
2086
- margin-top: .5rem;
2087
-
2088
- @media screen and (min-width: 1070px) {
2089
- margin-top: 1rem;
2090
- }
2091
- }
2092
- }
2093
-
2094
- // Results by Event View
2095
- &__resultsByEvent {
2096
- .eventsCalendar__eventImage {
2097
- width: 100%;
2098
- max-width: 100%;
2099
- height: auto;
2100
- margin-left: 0;
2101
-
2102
- @media screen and (min-width: 768px) {
2103
- max-width: 580px;
2104
- height: 360px;
2105
- margin-left: auto;
2106
- }
2107
- }
2108
-
2109
- .eventsCalendar__eventImg {
2110
- height: auto;
2111
- aspect-ratio: 16 / 10;
2112
-
2113
- @media screen and (min-width: 768px) {
2114
- height: 360px;
2115
- aspect-ratio: 580 / 360;
2116
- }
2117
- }
2118
-
2119
- .eventsCalendar__eventTitle {
2120
- font-size: var(--font-size-3);
2121
-
2122
- @media screen and (min-width: 1070px) {
2123
- font-size: 40px;
2124
- }
2125
- }
2126
-
2127
- .eventsCalendar__eventDetails {
2128
- margin-top: 1rem;
2129
-
2130
- @media screen and (min-width: 1070px) {
2131
- margin-top: 1.5rem;
2132
- }
2133
- }
2134
-
2135
- .eventsCalendar__eventDate,
2136
- .eventsCalendar__eventVenue,
2137
- .eventsCalendar__eventActions {
2138
- font-size: var(--font-size-2);
2139
-
2140
- @media screen and (min-width: 1070px) {
2141
- font-size: 22px;
2142
- }
2143
- }
2144
-
2145
- .eventsCalendar__eventCard {
2146
- .eventsCalendar__eventMeta {
2147
- display: none;
2148
- }
2149
-
2150
- @media screen and (min-width: 1070px) {
2151
- grid-template-columns: 1fr 1fr;
2152
- grid-template-areas: "content image";
2153
- }
2154
- }
2155
- }
2156
-
2157
- &__eventDetails {
2158
- display: flex;
2159
- flex-direction: column;
2160
- gap: 0.5rem;
2161
- }
2162
-
2163
- &__eventActions {
2164
- margin-top: 1rem;
2165
- display: flex;
2166
- gap: 1rem;
2167
-
2168
- @media screen and (min-width: 1070px) {
2169
- margin-top: 1.5rem;
2170
- }
2171
- }
2172
-
2173
- &__ticketLink {
2174
- color: var(--brand-600, var(--c-theme-600));
2175
- font-weight: 700;
2176
- display: flex;
2177
- align-items: center;
2178
- gap: 0.5rem;
2179
- transition: color 0.2s, text-decoration 0.2s;
2180
-
2181
- &:hover {
2182
- color: var(--brand-800, var(--c-theme-800));
2183
- text-decoration: underline;
2184
- }
2185
- }
2186
-
2187
- &__eventLink {
2188
- color: #686F73;
2189
- transition: color 0.2s, text-decoration 0.2s;
2190
-
2191
- &:hover {
2192
- color: var(--c-theme-800);
2193
- text-decoration: underline;
2194
- }
2195
- }
2196
-
2197
- &__monthTitle {
2198
- font-size: var(--font-size-3);
2199
- font-weight: 700;
2200
- border-bottom: 1px solid #D3D0CD;
2201
- border-top: 1px solid #D3D0CD;
2202
- padding-top: .5rem;
2203
- padding-bottom: .5rem;
2204
- margin-bottom: .5rem;
2205
- }
2206
-
2207
- &__eventCard {
2208
- display: grid;
2209
- grid-template-columns: 1fr;
2210
- gap: 1rem;
2211
- margin-top: 1rem;
2212
- border-bottom: 1px solid #D3D0CD;
2213
- padding-bottom: 1rem;
2214
- margin-bottom: 1rem;
2215
-
2216
- @media screen and (min-width: 1070px) {
2217
- gap: 2rem;
2218
- align-items: start;
2219
- margin-top: 1.5rem;
2220
- padding-bottom: 1.5rem;
2221
- margin-bottom: 1.5rem;
2222
- }
2223
-
2224
- &:last-child {
2225
- border-bottom: none;
2226
- margin-bottom: 0;
2227
- }
2228
- }
2229
-
2230
- &__eventMeta {
2231
- justify-self: start;
2232
-
2233
- @media screen and (min-width: 1070px) {
2234
- grid-area: status;
2235
- }
2236
- }
2237
-
2238
- &__eventStatus {
2239
- font-size: var(--font-size-1);
2240
- padding: 9px 12px;
2241
- border-radius: 5px;
2242
- border: 1px solid var(--status-border-default);
2243
- background-color: transparent;
2244
- color: var(--status-color-default);
2245
-
2246
- // Import status styles from Dropdown component
2247
- &.-status {
2248
- background-color: var(--status-border-default);
2249
- color: var(--status-color-default);
2250
- }
2251
-
2252
- &.-cancelled {
2253
- background-color: transparent;
2254
- border: 1px solid var(--status-border-cancelled);
2255
- color: var(--status-color-cancelled);
2256
- }
2257
-
2258
- &.-rescheduled {
2259
- background-color: transparent;
2260
- border: 1px solid var(--status-border-rescheduled);
2261
- color: var(--status-color-rescheduled);
2262
- }
2263
-
2264
- &.-postponed {
2265
- background-color: transparent;
2266
- border: 1px solid var(--status-border-postponed);
2267
- color: var(--status-color-postponed);
2268
- }
2269
-
2270
- &.-sold-out {
2271
- background-color: transparent;
2272
- border: 1px solid var(--status-border-sold-out);
2273
- color: var(--status-color-sold-out);
2274
- }
2275
-
2276
- &.-best-availability {
2277
- background-color: transparent;
2278
- border-color: var(--status-border-best-availability);
2279
- color: var(--status-color-best-availability);
2280
- }
2281
-
2282
- &.-limited-availability {
2283
- background-color: transparent;
2284
- border: 1px solid var(--status-border-limited-availability);
2285
- color: var(--status-color-limited-availability);
2286
- }
2287
-
2288
- &.-coming-soon {
2289
- background-color: transparent;
2290
- border: 1px solid var(--status-border-coming-soon);
2291
- color: var(--status-color-coming-soon);
2292
- }
2293
-
2294
- &.-past-date {
2295
- background-color: transparent;
2296
- border: 1px solid var(--status-border-default);
2297
- color: var(--status-color-default);
2298
- }
2299
-
2300
- &.-free {
2301
- background-color: transparent;
2302
- border: 1px solid var(--c-theme-400);
2303
- color: var(--c-theme-600);
2304
- }
2305
- }
2306
-
2307
- &__eventContent {
2308
- @media screen and (min-width: 1070px) {
2309
- grid-area: content;
2310
- }
2311
- }
2312
-
2313
- &__eventImage {
2314
- width: 222px;
2315
- height: 139px;
2316
- overflow: hidden;
2317
- border-radius: 4px;
2318
- flex-shrink: 0;
2319
-
2320
- @media screen and (min-width: 1070px) {
2321
- grid-area: image;
2322
- }
2323
-
2324
- @media screen and (max-width: 767px) {
2325
- width: 100%;
2326
- max-width: 222px;
2327
- height: 139px;
2328
- }
2329
- }
2330
-
2331
- &__eventImg {
2332
- border-radius: 4px;
2333
- width: 100%;
2334
- height: 139px;
2335
- object-fit: cover;
2336
- object-position: center;
2337
- aspect-ratio: 222 / 139;
2338
- }
2339
-
2340
- &__eventTitle {
2341
- font-weight: 700;
2342
- }
2343
-
2344
- &__eventNotice {
2345
- display: flex;
2346
- align-items: center;
2347
- gap: 0.5rem;
2348
- margin-top: 0.75rem;
2349
- font-weight: 500;
2350
- }
2351
-
2352
- &__eventNote {
2353
- margin-top: 0.75rem;
2354
- }
2355
-
2356
- &__noticeIcon {
2357
- display: flex;
2358
- align-items: center;
2359
- justify-content: center;
2360
- flex-shrink: 0;
2361
- width: 16px;
2362
- height: 16px;
2363
- }
2364
-
2365
- &__noticeIconSvg {
2366
- width: 100%;
2367
- height: 100%;
2368
- display: block;
2369
- fill: currentColor;
2370
- stroke: currentColor;
2371
-
2372
- use {
2373
- fill: inherit;
2374
- stroke: inherit;
2375
- }
2376
- }
2377
-
2378
- &__eventNote,
2379
- &__noticeText {
2380
- font-size: var(--font-size-1);
2381
- font-weight: var(--font-weight-bold);
2382
- line-height: 1.4;
2383
- }
2384
-
2385
- &__noticeText {
2386
- flex: 1;
2387
- }
2388
-
2389
- &__categories {
2390
- display: flex;
2391
- gap: 0.5rem;
2392
- margin-bottom: 1.5rem;
2393
- flex-wrap: wrap;
2394
- }
2395
-
2396
- &__category {
2397
- background-color: var(--brand-600, var(--c-theme-600));
2398
- color: white;
2399
- padding: .5rem .75rem;
2400
- border-radius: 3px;
2401
- font-size: var(--font-size-1);
2402
- font-weight: 500;
2403
-
2404
- // Second sibling and beyond get lighter styling
2405
- &:nth-child(n+2) {
2406
- background-color: var(--brand-200, var(--c-theme-200));
2407
- color: var(--brand-800, var(--c-theme-800));
2408
- }
2409
- }
2410
-
2411
- &__eventDate {
2412
- display: flex;
2413
- align-items: center;
2414
- gap: 0.5rem;
2415
- font-size: var(--font-size-1);
2416
-
2417
- @media screen and (min-width: 1070px) {
2418
- font-size: var(--font-size-2);
2419
- }
2420
- }
2421
-
2422
- &__eventVenue {
2423
- display: flex;
2424
- align-items: center;
2425
- gap: 0.5rem;
2426
- font-size: var(--font-size-1);
2427
-
2428
- @media screen and (min-width: 1070px) {
2429
- font-size: var(--font-size-2);
2430
- }
2431
- }
2432
-
2433
- &__venueLink {
2434
- text-decoration: underline;
2435
- transition: text-decoration 0.2s, color 0.2s;
2436
-
2437
- &:hover {
2438
- color: var(--c-brand);
2439
- text-decoration: underline;
2440
- }
2441
- }
2442
-
2443
- // Pagination styles
2444
- &__pagination {
2445
- margin-top: 2rem;
2446
- display: flex;
2447
- justify-content: center;
2448
- padding: 0 20px;
2449
-
2450
- @media screen and (min-width: 768px) {
2451
- padding: 0 80px;
2452
- }
2453
-
2454
- @media screen and (min-width: 1070px) {
2455
- margin-left: 60px;
2456
- padding: 0 80px;
2457
- }
2458
- }
2459
-
2460
- &__paginationComponent {
2461
- .ais-Pagination {
2462
- &-list {
2463
- display: flex;
2464
- align-items: center;
2465
- gap: 0.5rem;
2466
- list-style: none;
2467
- margin: 0;
2468
- padding: 0;
2469
- }
2470
-
2471
- &-item {
2472
- &--firstPage,
2473
- &--previousPage,
2474
- &--page,
2475
- &--nextPage,
2476
- &--lastPage {
2477
- .ais-Pagination-link {
2478
- display: flex;
2479
- align-items: center;
2480
- justify-content: center;
2481
- min-width: 40px;
2482
- height: 40px;
2483
- padding: 0 12px;
2484
- border: 1px solid #D6D6D6;
2485
- border-radius: 4px;
2486
- background: white;
2487
- color: #333;
2488
- text-decoration: none;
2489
- font-size: var(--font-size-1);
2490
- transition: all 0.2s;
2491
-
2492
- &:hover {
2493
- background: #f5f5f5;
2494
- border-color: #999;
2495
- }
2496
- }
2497
- }
2498
-
2499
- &--selected {
2500
- .ais-Pagination-link {
2501
- background: var(--c-brand, #007bff);
2502
- color: white;
2503
- border-color: var(--c-brand, #007bff);
2504
- }
2505
- }
2506
-
2507
- &--disabled {
2508
- .ais-Pagination-link {
2509
- opacity: 0.5;
2510
- cursor: not-allowed;
2511
-
2512
- &:hover {
2513
- background: white;
2514
- border-color: #D6D6D6;
2515
- }
2516
- }
2517
- }
2518
- }
2519
- }
2520
- }
2521
-
2522
- // Mobile date picker modal styles
2523
- .dp__mobile_modal {
2524
- .dp__menu {
2525
- position: static !important;
2526
- top: auto !important;
2527
- left: auto !important;
2528
- right: auto !important;
2529
- bottom: auto !important;
2530
- width: 100% !important;
2531
- height: auto !important;
2532
- max-width: none !important;
2533
- max-height: none !important;
2534
- border-radius: 0 !important;
2535
- z-index: auto !important;
2536
- background: transparent !important;
2537
- box-shadow: none !important;
2538
- border: none !important;
2539
- margin: 0 !important;
2540
- padding: 0 !important;
2541
- }
2542
-
2543
- .dp__modal_body {
2544
- padding: 1rem !important;
2545
- flex: 1 !important;
2546
- display: flex !important;
2547
- flex-direction: column !important;
2548
- }
2549
- }
2550
-
2551
- // Filter modal styles (venue and ensemble)
2552
- .venue__mobile_modal,
2553
- .ensemble__mobile_modal {
2554
- .eventsModal__venueContainer,
2555
- .eventsModal__ensembleContainer {
2556
- padding: 1rem;
2557
- max-height: 60vh;
2558
- overflow-y: auto;
2559
- }
2560
-
2561
- // Ensure checkboxes are visible in modals
2562
- input[type="checkbox"] {
2563
- display: block !important;
2564
- opacity: 1 !important;
2565
- visibility: visible !important;
2566
- width: 20px !important;
2567
- height: 20px !important;
2568
- margin: 0 !important;
2569
- padding: 0 !important;
2570
- border: 2px solid #ccc !important;
2571
- border-radius: 3px !important;
2572
- background: white !important;
2573
- appearance: checkbox !important;
2574
- -webkit-appearance: checkbox !important;
2575
- -moz-appearance: checkbox !important;
2576
-
2577
- &:checked {
2578
- background: var(--c-brand, #007bff) !important;
2579
- border-color: var(--c-brand, #007bff) !important;
2580
- }
2581
- }
2582
- }
2583
-
2584
- // Desktop dropdown checkbox styles (matching mobile modal)
2585
- .eventsCalendar__checkbox {
2586
- margin: 0 12px 0 0 !important;
2587
- flex-shrink: 0;
2588
- width: 20px !important;
2589
- height: 20px !important;
2590
- min-width: 20px !important;
2591
- min-height: 20px !important;
2592
- accent-color: var(--c-brand, #007bff) !important;
2593
- appearance: checkbox !important;
2594
- -webkit-appearance: checkbox !important;
2595
- -moz-appearance: checkbox !important;
2596
- display: block !important;
2597
- opacity: 1 !important;
2598
- visibility: visible !important;
2599
- position: relative !important;
2600
- z-index: 1 !important;
2601
- background: white !important;
2602
- border: 2px solid #ccc !important;
2603
- border-radius: 3px !important;
2604
- cursor: pointer;
2605
-
2606
- &:checked {
2607
- background: var(--c-brand, #007bff) !important;
2608
- border-color: var(--c-brand, #007bff) !important;
2609
- }
2610
- }
2611
-
2612
- // Desktop venue dropdown styles
2613
- .eventsCalendar__selectOption--venue {
2614
- display: flex;
2615
- align-items: center;
2616
- gap: 12px;
2617
-
2618
- .eventsCalendar__venueInfo {
2619
- flex: 1;
2620
- }
2621
-
2622
- .eventsCalendar__venueName {
2623
- display: block;
2624
- font-weight: 500;
2625
- }
2626
-
2627
- .eventsCalendar__venueCity {
2628
- display: block;
2629
- font-size: 14px;
2630
- color: #686F73;
2631
- font-weight: 400;
2632
- }
2633
- }
2634
-
2635
- // Desktop ensemble dropdown styles
2636
- .eventsCalendar__selectOption--ensemble {
2637
- display: flex;
2638
- align-items: center;
2639
- gap: 12px;
2640
-
2641
- span:not(.eventsCalendar__selectCount) {
2642
- flex: 1;
2643
- }
2644
- }
2645
-
2646
- // Make dropdown menus span across both venue and ensemble filters
2647
- .eventsCalendar__filtersRow {
2648
- position: relative;
2649
- }
2650
-
2651
- .eventsCalendar__filterGroup--venue,
2652
- .eventsCalendar__filterGroup--ensemble {
2653
- .vs__dropdown-menu {
2654
- position: absolute;
2655
- left: 0;
2656
- right: 0;
2657
- width: auto !important;
2658
- min-width: 100%;
2659
- z-index: 1000;
2660
-
2661
- // Calculate width to span both filter groups plus gap
2662
- // Assuming the filters row has the two filter groups side by side
2663
- @media (min-width: 768px) {
2664
- width: calc(200% + 1rem) !important; // 200% for both filters + gap between them
2665
- }
2666
- }
2667
- }
2668
-
2669
- // Ensure the ensemble dropdown menu aligns to the left edge of the filters row
2670
- .eventsCalendar__filterGroup--ensemble {
2671
- .vs__dropdown-menu {
2672
- // Position the ensemble dropdown to start from the venue filter position
2673
- left: calc(-100% - 1rem); // Move left by the width of venue filter + gap
2674
- }
2675
- }
2676
-
2677
- // Modal styles moved outside .eventsCalendar scope
2678
-
2679
- // Ensure modal button styles are applied globally
2680
- .event__buy-button-wrapper {
2681
- display: flex !important;
2682
- gap: 1rem !important;
2683
- justify-content: center !important;
2684
- width: 100% !important;
2685
- }
2686
-
2687
- .event__buy-button--secondary {
2688
- background: #F5F5F5 !important;
2689
- color: #333 !important;
2690
- border: 1px solid #ddd !important;
2691
-
2692
- &:hover {
2693
- background: #e5e5e5 !important;
2694
- }
2695
- }
2696
- }
2697
-
2698
- /* Filter modal styles - outside eventsCalendar scope since modals are in document.body */
2699
- .eventsModal .filterModal__items {
2700
- display: flex;
2701
- flex-direction: column;
2702
- gap: 0.75rem;
2703
- }
2704
-
2705
- .eventsModal .filterModal__item:has(input:checked) {
2706
- border-color: var(--c-brand, #007bff);
2707
- background-color: #f0f8ff;
2708
- }
2709
-
2710
- .eventsModal .filterModal__itemLabel {
2711
- display: flex;
2712
- align-items: center;
2713
- cursor: pointer;
2714
- gap: 0.75rem;
2715
- width: 100%;
2716
- margin: 0;
2717
- }
2718
-
2719
- .eventsModal .filterModal__itemLabel input[type="checkbox"] {
2720
- margin: 0 !important;
2721
- flex-shrink: 0;
2722
- width: 20px !important;
2723
- height: 20px !important;
2724
- min-width: 20px !important;
2725
- min-height: 20px !important;
2726
- accent-color: var(--c-brand, #007bff) !important;
2727
- appearance: checkbox !important;
2728
- -webkit-appearance: checkbox !important;
2729
- -moz-appearance: checkbox !important;
2730
- display: block !important;
2731
- opacity: 1 !important;
2732
- visibility: visible !important;
2733
- position: relative !important;
2734
- z-index: 1 !important;
2735
- background: white !important;
2736
- border: 2px solid #ccc !important;
2737
- border-radius: 3px !important;
2738
- }
2739
-
2740
- .eventsModal .filterModal__itemLabel input[type="checkbox"]:checked {
2741
- background: var(--c-brand, #007bff) !important;
2742
- border-color: var(--c-brand, #007bff) !important;
2743
- }
2744
-
2745
- .eventsModal .filterModal__itemText {
2746
- flex: 1;
2747
- font-size: 16px;
2748
- line-height: 1.4;
2749
- color: var(--c-theme-800, #333);
2750
- }
2751
-
2752
- .eventsModal .filterModal__venueName {
2753
- display: block;
2754
- }
2755
-
2756
- .eventsModal .filterModal__venueCity {
2757
- display: block;
2758
- font-size: 14px;
2759
- color: #686F73;
2760
- font-weight: 400;
2761
- }
2762
-
2763
- // Calendar styles
2764
- .dp__menu {
2765
- @media (max-width: 768px) {
2766
- border: none !important;
2767
- }
2768
- }
2769
-
2770
- // Desktop positioning for date picker to span across Date and Venue inputs
2771
- .eventsCalendar__filterGroup--date {
2772
- @media (min-width: 769px) {
2773
- position: relative;
2774
- }
2775
-
2776
- .dp__outer_menu_wrap {
2777
- @media (min-width: 769px) {
2778
- position: absolute !important;
2779
- left: 0 !important;
2780
- top: calc(100% + .5rem) !important;
2781
- width: calc(200% + 1rem) !important;
2782
- z-index: 1000 !important;
2783
- }
2784
-
2785
- .dp__menu {
2786
- @media (min-width: 769px) {
2787
- width: 100% !important;
2788
- left: 0 !important;
2789
- }
2790
- }
2791
- }
2792
- }
2793
-
2794
- .dp__menu_inner {
2795
- --dp-menu-padding: 16px 8px;
2796
- @media (max-width: 769px) {
2797
- --dp-menu-padding: 0 !important;
2798
- }
2799
- }
2800
-
2801
- .dp__cell_inner.dp__today {
2802
- border-radius: 50% !important;
2803
- border-color: var(--c-brand) !important;
2804
- color: var(--c-brand) !important;
2805
- }
2806
-
2807
- .dp__cell_inner {
2808
- --dp-cell-border-radius: 16px !important;
2809
- --dp-font-size: 14px !important;
2810
- --dp-cell-size: 48px;
2811
- font-size: var(--dp-font-size);
2812
- }
2813
-
2814
- .dp__range_start,
2815
- .dp__range_end {
2816
- --dp-cell-border-radius: 32px !important;
2817
- --dp-primary-color: var(--c-brand) !important;
2818
- }
2819
-
2820
- .dp__range_between {
2821
- --dp-range-between-dates-background-color: var(--c-theme-200) !important;
2822
- --dp-range-between-dates-text-color: var(--c-theme-400) !important;
2823
- border: none !important;
2824
- }
2825
-
2826
- .dp__calendar_item,
2827
- .dp__calendar_header_item {
2828
- flex-grow: 0 !important;
2829
- --dp-cell-size: 48px;
2830
- }
2831
-
2832
- .dp--year-select, .dp__month_year_select {
2833
- font-size: 22px !important;
2834
- font-weight: 800 !important;
2835
- --dp-text-color: var(--c-theme-800) !important;
2836
- }
2837
-
2838
- .dp__calendar_header_item {
2839
- color: #686F73 !important;
2840
- }
2841
-
2842
- // Date picker action buttons to match mobile modal buttons
2843
- .dp__action_buttons {
2844
- gap: 12px !important;
2845
- }
2846
-
2847
- .dp__action_button {
2848
- padding: 16px 24px !important;
2849
- border-radius: 8px !important;
2850
- font-weight: 600 !important;
2851
- font-size: 17px !important;
2852
- border: none !important;
2853
- cursor: pointer !important;
2854
- transition: all 0.2s ease !important;
2855
-
2856
- &.dp__action_select {
2857
- background: var(--c-brand, #007bff) !important;
2858
- color: white !important;
2859
-
2860
- &:hover {
2861
- background: var(--c-brand-dark, #0056b3) !important;
2862
- }
2863
- }
2864
-
2865
- &.dp__action_cancel {
2866
- background: #F5F5F5 !important;
2867
- color: #333 !important;
2868
- border: none !important;
2869
- font-weight: 400 !important;
2870
-
2871
- &:hover {
2872
- background: #e8e8e8 !important;
2873
- }
2874
- }
2875
- }
2876
- .dp__calendar_header_separator{
2877
- height: 0 !important;
2878
- }
2879
-
2880
- .dp__month_year_wrap {
2881
- margin-bottom: .5rem !important;
2882
- }
2883
-
2884
- .dp__action_row {
2885
- border-top: 1px solid #D6D6D6 !important;
2886
- }
2887
- </style>