nodebb-plugin-calendar-onekite 11.1.94 → 11.1.95
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.
- package/lib/admin.js +8 -15
- package/package.json +1 -1
- package/public/client.js +70 -117
- package/templates/calendar-onekite.tpl +0 -25
package/lib/admin.js
CHANGED
|
@@ -20,39 +20,33 @@ function formatFR(tsOrIso) {
|
|
|
20
20
|
|
|
21
21
|
async function sendEmail(template, toEmail, subject, data) {
|
|
22
22
|
if (!toEmail) return;
|
|
23
|
-
const params = Object.assign({}, data || {});
|
|
24
|
-
if (subject) {
|
|
25
|
-
params.subject = subject;
|
|
26
|
-
}
|
|
27
|
-
// NodeBB emailer expects: (template, email, language, params)
|
|
28
|
-
const lang = params.lang || (meta && meta.config && (meta.config.defaultLang || meta.config.defaultLanguage)) || 'fr';
|
|
29
|
-
|
|
30
23
|
try {
|
|
31
24
|
if (typeof emailer.sendToEmail === 'function') {
|
|
32
25
|
if (emailer.sendToEmail.length >= 4) {
|
|
33
|
-
await emailer.sendToEmail(template, toEmail,
|
|
26
|
+
await emailer.sendToEmail(template, toEmail, subject, data);
|
|
34
27
|
} else {
|
|
35
|
-
|
|
28
|
+
const dataWithSubject = Object.assign({}, data || {}, subject ? { subject } : {});
|
|
29
|
+
await emailer.sendToEmail(template, toEmail, dataWithSubject);
|
|
36
30
|
}
|
|
37
31
|
return;
|
|
38
32
|
}
|
|
39
33
|
if (typeof emailer.send === 'function') {
|
|
40
34
|
if (emailer.send.length >= 4) {
|
|
41
|
-
await emailer.send(template, toEmail,
|
|
35
|
+
await emailer.send(template, toEmail, subject, data);
|
|
42
36
|
return;
|
|
43
37
|
}
|
|
44
38
|
if (emailer.send.length === 3) {
|
|
45
|
-
|
|
39
|
+
const dataWithSubject = Object.assign({}, data || {}, subject ? { subject } : {});
|
|
40
|
+
await emailer.send(template, toEmail, dataWithSubject);
|
|
46
41
|
return;
|
|
47
42
|
}
|
|
48
|
-
await emailer.send(template, toEmail,
|
|
43
|
+
await emailer.send(template, toEmail, subject, data);
|
|
49
44
|
}
|
|
50
45
|
} catch (err) {
|
|
51
|
-
console.warn('[calendar-onekite] Failed to send email', { template, toEmail, err: String(
|
|
46
|
+
console.warn('[calendar-onekite] Failed to send email', { template, toEmail, err: String(err && err.message || err) });
|
|
52
47
|
}
|
|
53
48
|
}
|
|
54
49
|
|
|
55
|
-
|
|
56
50
|
function normalizeCallbackUrl(configured, meta) {
|
|
57
51
|
const base = (meta && meta.config && (meta.config.url || meta.config['url'])) ? (meta.config.url || meta.config['url']) : '';
|
|
58
52
|
let url = (configured || '').trim();
|
|
@@ -523,4 +517,3 @@ admin.purgeAccounting = async function (req, res) {
|
|
|
523
517
|
|
|
524
518
|
|
|
525
519
|
module.exports = admin;
|
|
526
|
-
|
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -58,7 +58,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
58
58
|
cancel: {
|
|
59
59
|
label: 'Annuler',
|
|
60
60
|
className: 'btn-secondary',
|
|
61
|
-
callback: () =>
|
|
61
|
+
callback: () => resolve(null),
|
|
62
62
|
},
|
|
63
63
|
ok: {
|
|
64
64
|
label: 'Créer',
|
|
@@ -71,7 +71,7 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
71
71
|
const notes = (document.getElementById('onekite-se-notes')?.value || '').trim();
|
|
72
72
|
const lat = (document.getElementById('onekite-se-lat')?.value || '').trim();
|
|
73
73
|
const lon = (document.getElementById('onekite-se-lon')?.value || '').trim();
|
|
74
|
-
|
|
74
|
+
resolve({ title, start: startVal, end: endVal, address, notes, lat, lon });
|
|
75
75
|
return true;
|
|
76
76
|
},
|
|
77
77
|
},
|
|
@@ -233,15 +233,6 @@ define('forum/calendar-onekite', ['alerts', 'bootbox', 'hooks'], function (alert
|
|
|
233
233
|
return await res.json();
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
-
|
|
237
|
-
async function apiJson(v3Url, legacyUrl, opts) {
|
|
238
|
-
try {
|
|
239
|
-
return await fetchJson(v3Url, opts);
|
|
240
|
-
} catch (e) {
|
|
241
|
-
return await fetchJson(legacyUrl, opts);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
236
|
async function loadCapabilities() {
|
|
246
237
|
try {
|
|
247
238
|
return await fetchJson('/api/v3/plugins/calendar-onekite/capabilities');
|
|
@@ -455,34 +446,34 @@ function attachAddressAutocomplete(inputEl, onPick) {
|
|
|
455
446
|
|
|
456
447
|
async function loadItems() {
|
|
457
448
|
try {
|
|
458
|
-
return await
|
|
449
|
+
return await fetchJson('/api/v3/plugins/calendar-onekite/items');
|
|
459
450
|
} catch (e) {
|
|
460
451
|
return [];
|
|
461
452
|
}
|
|
462
453
|
}
|
|
463
454
|
|
|
464
455
|
async function requestReservation(payload) {
|
|
465
|
-
return await
|
|
456
|
+
return await fetchJson('/api/v3/plugins/calendar-onekite/reservations', {
|
|
466
457
|
method: 'POST',
|
|
467
458
|
body: JSON.stringify(payload),
|
|
468
459
|
});
|
|
469
460
|
}
|
|
470
461
|
|
|
471
462
|
async function approveReservation(rid, payload) {
|
|
472
|
-
return await
|
|
463
|
+
return await fetchJson(`/api/v3/plugins/calendar-onekite/reservations/${rid}/approve`, {
|
|
473
464
|
method: 'PUT',
|
|
474
465
|
body: JSON.stringify(payload || {}),
|
|
475
466
|
});
|
|
476
467
|
}
|
|
477
468
|
|
|
478
469
|
async function cancelReservation(rid) {
|
|
479
|
-
return await
|
|
470
|
+
return await fetchJson(`/api/v3/plugins/calendar-onekite/reservations/${rid}/cancel`, {
|
|
480
471
|
method: 'PUT',
|
|
481
472
|
});
|
|
482
473
|
}
|
|
483
474
|
|
|
484
475
|
async function refuseReservation(rid) {
|
|
485
|
-
return await
|
|
476
|
+
return await fetchJson(`/api/v3/plugins/calendar-onekite/reservations/${rid}/refuse`, {
|
|
486
477
|
method: 'PUT',
|
|
487
478
|
});
|
|
488
479
|
}
|
|
@@ -506,26 +497,6 @@ function attachAddressAutocomplete(inputEl, onPick) {
|
|
|
506
497
|
}
|
|
507
498
|
|
|
508
499
|
|
|
509
|
-
function formatPeriodWithTime(start, end) {
|
|
510
|
-
const s = formatDtWithTime(start);
|
|
511
|
-
if (!end) {
|
|
512
|
-
return s;
|
|
513
|
-
}
|
|
514
|
-
try {
|
|
515
|
-
const st = new Date(start).getTime();
|
|
516
|
-
const en = new Date(end).getTime();
|
|
517
|
-
if (Number.isFinite(st) && Number.isFinite(en) && en <= st) {
|
|
518
|
-
return s;
|
|
519
|
-
}
|
|
520
|
-
} catch (e) {}
|
|
521
|
-
const eTxt = formatDtWithTime(end);
|
|
522
|
-
if (!eTxt || eTxt === 'Invalid Date') {
|
|
523
|
-
return s;
|
|
524
|
-
}
|
|
525
|
-
return `${s} → ${eTxt}`;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
|
|
529
500
|
|
|
530
501
|
function toLocalYmd(date) {
|
|
531
502
|
const d = new Date(date);
|
|
@@ -551,7 +522,7 @@ function toDatetimeLocalValue(date) {
|
|
|
551
522
|
let blocked = new Set();
|
|
552
523
|
try {
|
|
553
524
|
const qs = new URLSearchParams({ start: selectionInfo.startStr, end: selectionInfo.endStr });
|
|
554
|
-
const evs = await
|
|
525
|
+
const evs = await fetchJson(`/api/v3/plugins/calendar-onekite/events?${qs.toString()}`);
|
|
555
526
|
(evs || []).forEach((ev) => {
|
|
556
527
|
const st = (ev.extendedProps && ev.extendedProps.status) || '';
|
|
557
528
|
if (!['pending', 'awaiting_payment', 'approved', 'paid'].includes(st)) return;
|
|
@@ -600,8 +571,6 @@ function toDatetimeLocalValue(date) {
|
|
|
600
571
|
`;
|
|
601
572
|
|
|
602
573
|
return new Promise((resolve) => {
|
|
603
|
-
let __settled = false;
|
|
604
|
-
const __settle = (v) => { if (__settled) return; __settled = true; __settle(v); };
|
|
605
574
|
const dlg = bootbox.dialog({
|
|
606
575
|
title: 'Demander une réservation',
|
|
607
576
|
message: messageHtml,
|
|
@@ -610,7 +579,7 @@ function toDatetimeLocalValue(date) {
|
|
|
610
579
|
label: 'Annuler',
|
|
611
580
|
className: 'btn-secondary',
|
|
612
581
|
callback: function () {
|
|
613
|
-
|
|
582
|
+
resolve(null);
|
|
614
583
|
},
|
|
615
584
|
},
|
|
616
585
|
ok: {
|
|
@@ -626,16 +595,13 @@ function toDatetimeLocalValue(date) {
|
|
|
626
595
|
const itemNames = cbs.map(cb => cb.getAttribute('data-name'));
|
|
627
596
|
const sum = cbs.reduce((acc, cb) => acc + (parseFloat(cb.getAttribute('data-price') || '0') || 0), 0);
|
|
628
597
|
const total = (sum / 100) * days;
|
|
629
|
-
|
|
598
|
+
resolve({ itemIds, itemNames, total, days });
|
|
630
599
|
},
|
|
631
600
|
},
|
|
632
601
|
},
|
|
633
602
|
});
|
|
634
603
|
|
|
635
|
-
|
|
636
|
-
// Ensure the promise resolves even if the modal is dismissed externally (e.g. mobile rotate)
|
|
637
|
-
dlg.on('hidden.bs.modal', () => __settle(null));
|
|
638
|
-
// live total update
|
|
604
|
+
// live total update
|
|
639
605
|
setTimeout(() => {
|
|
640
606
|
const totalEl = document.getElementById('onekite-total');
|
|
641
607
|
function refreshTotal() {
|
|
@@ -668,7 +634,30 @@ function toDatetimeLocalValue(date) {
|
|
|
668
634
|
const canCreateSpecial = !!caps.canCreateSpecial;
|
|
669
635
|
const canDeleteSpecial = !!caps.canDeleteSpecial;
|
|
670
636
|
|
|
671
|
-
let
|
|
637
|
+
let setMode('reservation');
|
|
638
|
+
function refreshDesktopModeButton() {
|
|
639
|
+
try {
|
|
640
|
+
const btn = document.querySelector('#onekite-calendar .fc-newSpecial-button');
|
|
641
|
+
if (!btn) return;
|
|
642
|
+
const isSpecial = mode === 'special';
|
|
643
|
+
btn.textContent = isSpecial ? 'Évènement ✓' : 'Évènement';
|
|
644
|
+
btn.classList.toggle('onekite-active', isSpecial);
|
|
645
|
+
} catch (e) {}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function setMode(next) {
|
|
649
|
+
mode = next;
|
|
650
|
+
refreshDesktopModeButton();
|
|
651
|
+
try {
|
|
652
|
+
const mb = document.querySelector('#onekite-mobile-controls .onekite-mode-btn');
|
|
653
|
+
if (mb) {
|
|
654
|
+
const isSpecial = mode === 'special';
|
|
655
|
+
mb.textContent = isSpecial ? 'Mode évènement ✓' : 'Mode évènement';
|
|
656
|
+
mb.classList.toggle('onekite-active', isSpecial);
|
|
657
|
+
}
|
|
658
|
+
} catch (e) {}
|
|
659
|
+
}
|
|
660
|
+
// or 'special'
|
|
672
661
|
|
|
673
662
|
// Inject lightweight responsive CSS once.
|
|
674
663
|
try {
|
|
@@ -694,7 +683,21 @@ function toDatetimeLocalValue(date) {
|
|
|
694
683
|
#onekite-calendar .fc .fc-toolbar-title { font-size: 1rem; }
|
|
695
684
|
#onekite-calendar .fc .fc-button { padding: .2rem .4rem; font-size: .8rem; }
|
|
696
685
|
}
|
|
697
|
-
|
|
686
|
+
|
|
687
|
+
/* Violet action button (events mode) */
|
|
688
|
+
#onekite-calendar .fc .fc-newSpecial-button,
|
|
689
|
+
.onekite-btn-violet {
|
|
690
|
+
background: #6f42c1 !important;
|
|
691
|
+
border-color: #6f42c1 !important;
|
|
692
|
+
color: #fff !important;
|
|
693
|
+
}
|
|
694
|
+
/* Active state */
|
|
695
|
+
#onekite-calendar .fc .fc-newSpecial-button.onekite-active,
|
|
696
|
+
.onekite-btn-violet.onekite-active {
|
|
697
|
+
filter: brightness(0.95);
|
|
698
|
+
box-shadow: 0 0 0 0.15rem rgba(111,66,193,.25);
|
|
699
|
+
}
|
|
700
|
+
`;
|
|
698
701
|
document.head.appendChild(st);
|
|
699
702
|
}
|
|
700
703
|
} catch (e) {}
|
|
@@ -724,31 +727,6 @@ function toDatetimeLocalValue(date) {
|
|
|
724
727
|
right: (canCreateSpecial ? 'newSpecial ' : '') + 'dayGridMonth,timeGridWeek',
|
|
725
728
|
};
|
|
726
729
|
|
|
727
|
-
// Mode UI helpers (desktop FullCalendar button + mobile toggle)
|
|
728
|
-
let mobileModeBtn = null;
|
|
729
|
-
function refreshModeIndicators() {
|
|
730
|
-
const isSpecial = mode === 'special';
|
|
731
|
-
|
|
732
|
-
// Desktop "Évènement" button in the FullCalendar header
|
|
733
|
-
try {
|
|
734
|
-
const desktopBtn = document.querySelector('#onekite-calendar .fc-newSpecial-button');
|
|
735
|
-
if (desktopBtn) {
|
|
736
|
-
desktopBtn.textContent = isSpecial ? 'Évènement ✓' : 'Évènement';
|
|
737
|
-
desktopBtn.classList.toggle('onekite-mode-active', isSpecial);
|
|
738
|
-
}
|
|
739
|
-
} catch (e) {}
|
|
740
|
-
|
|
741
|
-
// Mobile mode toggle (under the calendar)
|
|
742
|
-
try {
|
|
743
|
-
if (mobileModeBtn) {
|
|
744
|
-
mobileModeBtn.textContent = isSpecial ? 'Mode évènement ✓' : 'Mode évènement';
|
|
745
|
-
mobileModeBtn.classList.toggle('active', isSpecial);
|
|
746
|
-
mobileModeBtn.classList.toggle('onekite-btn-violet', isSpecial);
|
|
747
|
-
mobileModeBtn.classList.toggle('onekite-btn-violet-outline', !isSpecial);
|
|
748
|
-
}
|
|
749
|
-
} catch (e) {}
|
|
750
|
-
}
|
|
751
|
-
|
|
752
730
|
const calendar = new FullCalendar.Calendar(el, {
|
|
753
731
|
initialView: 'dayGridMonth',
|
|
754
732
|
height: 'auto',
|
|
@@ -763,8 +741,7 @@ function toDatetimeLocalValue(date) {
|
|
|
763
741
|
newSpecial: {
|
|
764
742
|
text: 'Évènement',
|
|
765
743
|
click: () => {
|
|
766
|
-
|
|
767
|
-
refreshModeIndicators();
|
|
744
|
+
setMode((mode === 'special') ? 'reservation' : 'special');
|
|
768
745
|
if (mode === 'special') {
|
|
769
746
|
showAlert('success', 'Mode évènement : sélectionne une plage (date/heure) sur le calendrier.');
|
|
770
747
|
}
|
|
@@ -778,7 +755,7 @@ function toDatetimeLocalValue(date) {
|
|
|
778
755
|
events: async function (info, successCallback, failureCallback) {
|
|
779
756
|
try {
|
|
780
757
|
const qs = new URLSearchParams({ start: info.startStr, end: info.endStr });
|
|
781
|
-
const data = await
|
|
758
|
+
const data = await fetchJson(`/api/v3/plugins/calendar-onekite/events?${qs.toString()}`);
|
|
782
759
|
successCallback(data);
|
|
783
760
|
} catch (e) {
|
|
784
761
|
failureCallback(e);
|
|
@@ -792,7 +769,7 @@ function toDatetimeLocalValue(date) {
|
|
|
792
769
|
try {
|
|
793
770
|
if (mode === 'special' && canCreateSpecial) {
|
|
794
771
|
const payload = await openSpecialEventDialog(info);
|
|
795
|
-
|
|
772
|
+
setMode('reservation');
|
|
796
773
|
if (!payload) {
|
|
797
774
|
calendar.unselect();
|
|
798
775
|
isDialogOpen = false;
|
|
@@ -854,35 +831,8 @@ function toDatetimeLocalValue(date) {
|
|
|
854
831
|
}
|
|
855
832
|
},
|
|
856
833
|
dateClick: async function (info) {
|
|
857
|
-
// One-day selection convenience
|
|
858
|
-
// For reservations, selecting a day makes a 1-day range.
|
|
859
|
-
// For special events ("mode évènement"), we want a single date (no implicit J+1 end).
|
|
834
|
+
// One-day selection convenience
|
|
860
835
|
const start = info.date;
|
|
861
|
-
|
|
862
|
-
if (mode === 'special' && canCreateSpecial) {
|
|
863
|
-
if (isDialogOpen) {
|
|
864
|
-
return;
|
|
865
|
-
}
|
|
866
|
-
isDialogOpen = true;
|
|
867
|
-
try {
|
|
868
|
-
const payload = await openSpecialEventDialog({ start, end: start });
|
|
869
|
-
mode = 'reservation';
|
|
870
|
-
if (!payload) {
|
|
871
|
-
isDialogOpen = false;
|
|
872
|
-
return;
|
|
873
|
-
}
|
|
874
|
-
await createSpecialEvent(payload);
|
|
875
|
-
showAlert('success', 'Évènement créé.');
|
|
876
|
-
calendar.refetchEvents();
|
|
877
|
-
isDialogOpen = false;
|
|
878
|
-
return;
|
|
879
|
-
} catch (e) {
|
|
880
|
-
showAlert('error', 'Impossible de créer l\'évènement.');
|
|
881
|
-
isDialogOpen = false;
|
|
882
|
-
return;
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
|
|
886
836
|
const end = new Date(start.getTime() + 24 * 60 * 60 * 1000);
|
|
887
837
|
calendar.select(start, end);
|
|
888
838
|
},
|
|
@@ -908,7 +858,7 @@ function toDatetimeLocalValue(date) {
|
|
|
908
858
|
const html = `
|
|
909
859
|
<div class="mb-2"><strong>Titre</strong><br>${escapeHtml(p.title || ev.title || '')}</div>
|
|
910
860
|
${userLine}
|
|
911
|
-
<div class="mb-2"><strong>Période</strong><br>${escapeHtml(
|
|
861
|
+
<div class="mb-2"><strong>Période</strong><br>${escapeHtml(formatDtWithTime(ev.start))} → ${escapeHtml(formatDtWithTime(ev.end))}</div>
|
|
912
862
|
${addr ? `<div class="mb-2"><strong>Adresse</strong><br>${addrHtml}</div>` : ''}
|
|
913
863
|
${notes ? `<div class="mb-2"><strong>Notes</strong><br>${escapeHtml(notes).replace(/\n/g,'<br>')}</div>` : ''}
|
|
914
864
|
`;
|
|
@@ -1113,10 +1063,7 @@ function toDatetimeLocalValue(date) {
|
|
|
1113
1063
|
},
|
|
1114
1064
|
});
|
|
1115
1065
|
|
|
1116
|
-
|
|
1117
|
-
// Ensure the promise resolves even if the modal is dismissed externally (e.g. mobile rotate)
|
|
1118
|
-
dlg.on('hidden.bs.modal', () => __settle(null));
|
|
1119
|
-
// Init Leaflet map once the modal is visible.
|
|
1066
|
+
// Init Leaflet map once the modal is visible.
|
|
1120
1067
|
dlg.on('shown.bs.modal', async () => {
|
|
1121
1068
|
try {
|
|
1122
1069
|
const L = await loadLeaflet();
|
|
@@ -1217,8 +1164,9 @@ function toDatetimeLocalValue(date) {
|
|
|
1217
1164
|
try { window.oneKiteCalendar = calendar; } catch (e) {}
|
|
1218
1165
|
|
|
1219
1166
|
calendar.render();
|
|
1220
|
-
|
|
1221
|
-
|
|
1167
|
+
|
|
1168
|
+
refreshDesktopModeButton();
|
|
1169
|
+
|
|
1222
1170
|
|
|
1223
1171
|
// Mobile controls: view (month/week) + mode (reservation/event) without bloating the header.
|
|
1224
1172
|
try {
|
|
@@ -1267,17 +1215,22 @@ function toDatetimeLocalValue(date) {
|
|
|
1267
1215
|
if (canCreateSpecial) {
|
|
1268
1216
|
const modeBtn = document.createElement('button');
|
|
1269
1217
|
modeBtn.type = 'button';
|
|
1270
|
-
modeBtn.className = 'btn btn-sm onekite-btn-violet
|
|
1271
|
-
|
|
1272
|
-
|
|
1218
|
+
modeBtn.className = 'btn btn-sm onekite-btn-violet onekite-mode-btn';
|
|
1219
|
+
function refreshModeBtn() {
|
|
1220
|
+
const isSpecial = mode === 'special';
|
|
1221
|
+
modeBtn.textContent = isSpecial ? 'Mode évènement ✓' : 'Mode évènement';
|
|
1222
|
+
modeBtn.classList.toggle('active', isSpecial);
|
|
1223
|
+
// Keep violet, only toggle active class
|
|
1224
|
+
modeBtn.classList.toggle('onekite-active', isSpecial);
|
|
1225
|
+
}
|
|
1273
1226
|
modeBtn.addEventListener('click', () => {
|
|
1274
|
-
|
|
1275
|
-
|
|
1227
|
+
setMode((mode === 'special') ? 'reservation' : 'special');
|
|
1228
|
+
refreshModeBtn();
|
|
1276
1229
|
if (mode === 'special') {
|
|
1277
1230
|
showAlert('success', 'Mode évènement : sélectionne une plage (date/heure) sur le calendrier.');
|
|
1278
1231
|
}
|
|
1279
1232
|
});
|
|
1280
|
-
|
|
1233
|
+
refreshModeBtn();
|
|
1281
1234
|
controls.appendChild(modeBtn);
|
|
1282
1235
|
}
|
|
1283
1236
|
|
|
@@ -27,31 +27,6 @@
|
|
|
27
27
|
.fc .fc-newSpecial-button:hover {
|
|
28
28
|
filter: brightness(0.95);
|
|
29
29
|
}
|
|
30
|
-
/* Indicate active "mode évènement" (desktop) */
|
|
31
|
-
.fc .fc-newSpecial-button.onekite-mode-active {
|
|
32
|
-
box-shadow: inset 0 0 0 2px rgba(255,255,255,0.35);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/* Violet button variants for mobile mode toggle */
|
|
36
|
-
.onekite-btn-violet {
|
|
37
|
-
background: #8e44ad !important;
|
|
38
|
-
border-color: #8e44ad !important;
|
|
39
|
-
color: #fff !important;
|
|
40
|
-
}
|
|
41
|
-
.onekite-btn-violet:hover {
|
|
42
|
-
filter: brightness(0.95);
|
|
43
|
-
color: #fff !important;
|
|
44
|
-
}
|
|
45
|
-
.onekite-btn-violet-outline {
|
|
46
|
-
background: transparent !important;
|
|
47
|
-
border-color: #8e44ad !important;
|
|
48
|
-
color: #8e44ad !important;
|
|
49
|
-
}
|
|
50
|
-
.onekite-btn-violet-outline:hover {
|
|
51
|
-
background: #8e44ad !important;
|
|
52
|
-
border-color: #8e44ad !important;
|
|
53
|
-
color: #fff !important;
|
|
54
|
-
}
|
|
55
30
|
|
|
56
31
|
/* Mobile tweaks for FullCalendar */
|
|
57
32
|
@media (max-width: 576px) {
|