build fixes and static files fix, closes #28
This commit is contained in:
parent
bff2525c65
commit
6a44ef30a3
26 changed files with 91 additions and 39 deletions
|
|
@ -1,48 +0,0 @@
|
|||
[x-cloak] { display: none !important; }
|
||||
|
||||
/* Beta Badge */
|
||||
#navbar-logo::after {
|
||||
content: 'BETA';
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: var(--color-base-content);
|
||||
background-color: var(--color-base-300);
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.gravatar-hovercard .gravatar-hovercard__inner {
|
||||
background-color: var(--color-base-100) !important;
|
||||
border-color: var(--color-base-300) !important;
|
||||
color: var(--color-base-content) !important;
|
||||
}
|
||||
|
||||
.gravatar-hovercard .gravatar-hovercard__inner,
|
||||
.gravatar-hovercard .gravatar-hovercard__header-image,
|
||||
.gravatar-hovercard .gravatar-hovercard__header,
|
||||
.gravatar-hovercard .gravatar-hovercard__avatar-link,
|
||||
.gravatar-hovercard .gravatar-hovercard__avatar,
|
||||
.gravatar-hovercard .gravatar-hovercard__personal-info-plink,
|
||||
.gravatar-hovercard .gravatar-hovercard__name,
|
||||
.gravatar-hovercard .gravatar-hovercard__job,
|
||||
.gravatar-hovercard .gravatar-hovercard__location,
|
||||
.gravatar-hovercard .gravatar-hovercard__body,
|
||||
.gravatar-hovercard .gravatar-hovercard__description,
|
||||
.gravatar-hovercard .gravatar-hovercard__social-links,
|
||||
.gravatar-hovercard .gravatar-hovercard__buttons,
|
||||
.gravatar-hovercard .gravatar-hovercard__button,
|
||||
.gravatar-hovercard .gravatar-hovercard__button:hover,
|
||||
.gravatar-hovercard .gravatar-hovercard__footer,
|
||||
.gravatar-hovercard .gravatar-hovercard__profile-url,
|
||||
.gravatar-hovercard .gravatar-hovercard__profile-link,
|
||||
.gravatar-hovercard .gravatar-hovercard__profile-color {
|
||||
color: var(--color-base-content) !important;
|
||||
}
|
||||
|
||||
.gravatar-hovercard .gravatar-hovercard__location {
|
||||
color: var(--color-base-content) !important;
|
||||
}
|
||||
|
||||
.dark .gravatar-hovercard .gravatar-hovercard__social-icon {
|
||||
filter: invert(1) !important;
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
select.card-multiselect {
|
||||
height: calc(var(--spacing) * 35);
|
||||
/*background-image: linear-gradient(45deg, #0000 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, #0000 50%); */
|
||||
background-image: none;
|
||||
}
|
||||
.choices.is-disabled .choices__inner,
|
||||
.choices.is-disabled .choices__input {
|
||||
background-color: var(--color-neutral);
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__input {
|
||||
border-bottom: 1px solid var(--btn-shadow);
|
||||
background-color: var(--color-base-100);
|
||||
}
|
||||
.choices[data-type*=select-one] .choices__button:focus {
|
||||
box-shadow: 0 0 0 2px #005F75;
|
||||
}
|
||||
.choices__inner {
|
||||
background-color: var(--color-base-100);
|
||||
border: 1px solid var(--btn-shadow);
|
||||
}
|
||||
.is-focused .choices__inner, .is-open .choices__inner {
|
||||
border-color: var(--btn-shadow);
|
||||
}
|
||||
.choices__list--multiple .choices__item {
|
||||
background-color: var(--color-base-100);
|
||||
border: 1px solid var(--btn-shadow);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.choices__list--multiple .choices__item.is-highlighted {
|
||||
background-color: var(--color-base-100);
|
||||
border: 1px solid var(--btn-shadow);
|
||||
}
|
||||
.is-disabled .choices__list--multiple .choices__item {
|
||||
background-color: var(--color-neutral);
|
||||
border: 1px solid var(--btn-shadow);
|
||||
}
|
||||
.choices__list--dropdown, .choices__list[aria-expanded] {
|
||||
background-color: var(--color-base-100);
|
||||
border: 1px solid var(--btn-shadow);
|
||||
}
|
||||
.is-open .choices__list--dropdown, .is-open .choices__list[aria-expanded] {
|
||||
border-color: var(--btn-shadow);
|
||||
}
|
||||
.choices__list--dropdown .choices__item--selectable.is-highlighted, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
|
||||
background-color: var(--color-base-100);
|
||||
border: 1px solid var(--btn-shadow);
|
||||
}
|
||||
.choices__heading {
|
||||
border-bottom: 1px solid var(--btn-shadow);
|
||||
color: var(--color-neutral);
|
||||
}
|
||||
.choices__input {
|
||||
background-color: var(--color-base-100);
|
||||
}
|
||||
.choices.select {
|
||||
height: inherit;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
.choices__inner {
|
||||
border: 1px solid var(--color-gray-500) !important;
|
||||
}
|
||||
.choices__list {
|
||||
border: none !important;
|
||||
}
|
||||
.choices__list--dropdown {
|
||||
border-left: 1px solid var(--color-gray-500) !important;
|
||||
border-right: 1px solid var(--color-gray-500) !important;
|
||||
border-bottom: 1px solid var(--color-gray-500) !important;
|
||||
border-top: none !important;
|
||||
}
|
||||
.choices.select[data-type*="select-one"]::after {
|
||||
display: none;
|
||||
}
|
||||
.choices__inner.bg-secondary {
|
||||
background-color: var(--color-secondary);
|
||||
border: none;
|
||||
z-index: 10;
|
||||
}
|
||||
.choices__item.mx-auto.w-max:hover {
|
||||
background-color: #e2e8f0;
|
||||
}
|
||||
.choices__input,
|
||||
.choices__input--cloned {
|
||||
width: 100% !important;
|
||||
}
|
||||
.choices__list--dropdown span.card-quantity-badge {
|
||||
display: none;
|
||||
}
|
||||
1
theme/static/css/choices.min.css
vendored
1
theme/static/css/choices.min.css
vendored
File diff suppressed because one or more lines are too long
3
theme/static/css/hovercards.min.css
vendored
3
theme/static/css/hovercards.min.css
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 549 B |
|
|
@ -1 +0,0 @@
|
|||
(()=>{function g(n){n.directive("collapse",e),e.inline=(t,{modifiers:i})=>{i.includes("min")&&(t._x_doShow=()=>{},t._x_doHide=()=>{})};function e(t,{modifiers:i}){let r=l(i,"duration",250)/1e3,h=l(i,"min",0),u=!i.includes("min");t._x_isShown||(t.style.height=`${h}px`),!t._x_isShown&&u&&(t.hidden=!0),t._x_isShown||(t.style.overflow="hidden");let c=(d,s)=>{let o=n.setStyles(d,s);return s.height?()=>{}:o},f={transitionProperty:"height",transitionDuration:`${r}s`,transitionTimingFunction:"cubic-bezier(0.4, 0.0, 0.2, 1)"};t._x_transition={in(d=()=>{},s=()=>{}){u&&(t.hidden=!1),u&&(t.style.display=null);let o=t.getBoundingClientRect().height;t.style.height="auto";let a=t.getBoundingClientRect().height;o===a&&(o=h),n.transition(t,n.setStyles,{during:f,start:{height:o+"px"},end:{height:a+"px"}},()=>t._x_isShown=!0,()=>{Math.abs(t.getBoundingClientRect().height-a)<1&&(t.style.overflow=null)})},out(d=()=>{},s=()=>{}){let o=t.getBoundingClientRect().height;n.transition(t,c,{during:f,start:{height:o+"px"},end:{height:h+"px"}},()=>t.style.overflow="hidden",()=>{t._x_isShown=!1,t.style.height==`${h}px`&&u&&(t.style.display="none",t.hidden=!0)})}}}}function l(n,e,t){if(n.indexOf(e)===-1)return t;let i=n[n.indexOf(e)+1];if(!i)return t;if(e==="duration"){let r=i.match(/([0-9]+)ms/);if(r)return r[1]}if(e==="min"){let r=i.match(/([0-9]+)px/);if(r)return r[1]}return i}document.addEventListener("alpine:init",()=>{window.Alpine.plugin(g)});})();
|
||||
5
theme/static/js/alpinejs@3.14.8.min.js
vendored
5
theme/static/js/alpinejs@3.14.8.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,146 +0,0 @@
|
|||
/* global window, document, localStorage */
|
||||
|
||||
const $ = selector => Array.from(document.querySelectorAll(selector));
|
||||
const $$ = selector => Array.from(document.querySelector(selector));
|
||||
|
||||
(() => {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Initialize the theme toggle button functionality.
|
||||
* Toggles between 'dark' and 'light' themes and persists the state in localStorage.
|
||||
*/
|
||||
function initThemeToggle() {
|
||||
const themeToggleButton = document.getElementById("theme-toggle-btn");
|
||||
if (!themeToggleButton) return;
|
||||
themeToggleButton.classList.toggle("btn-ghost", !("theme" in localStorage));
|
||||
themeToggleButton.addEventListener("click", () => {
|
||||
const documentRoot = document.documentElement;
|
||||
const isSystemTheme = themeToggleButton.classList.contains("btn-ghost");
|
||||
const isDarkTheme = documentRoot.classList.contains("dark");
|
||||
const newTheme = isSystemTheme ? "dark" : (isDarkTheme ? "light" : "system");
|
||||
|
||||
if (newTheme === "system") {
|
||||
documentRoot.classList.toggle("dark", window.matchMedia("(prefers-color-scheme: dark)").matches);
|
||||
documentRoot.setAttribute("data-theme", window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
|
||||
localStorage.removeItem("theme");
|
||||
} else {
|
||||
if (newTheme === "light") {
|
||||
documentRoot.classList.remove("dark");
|
||||
} else if (newTheme === "dark") {
|
||||
documentRoot.classList.add("dark");
|
||||
}
|
||||
documentRoot.setAttribute("data-theme", newTheme);
|
||||
localStorage.setItem("theme", newTheme);
|
||||
}
|
||||
themeToggleButton.classList.toggle("btn-ghost", newTheme === "system");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize event listeners for forms containing multiselect fields.
|
||||
* When the form is submitted, process each 'card-multiselect' to create hidden inputs.
|
||||
*/
|
||||
function initCardMultiselectHandling() {
|
||||
const forms = document.querySelectorAll("form");
|
||||
forms.forEach(form => {
|
||||
if (form.querySelector("select.card-multiselect")) {
|
||||
form.addEventListener("submit", () => {
|
||||
processMultiselectForm(form);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Process multiselect fields within a form before submission by:
|
||||
* - Creating hidden inputs for each selected option with value in 'card_id:quantity' format.
|
||||
* - Removing the original name attribute to avoid duplicate submissions.
|
||||
*
|
||||
* @param {HTMLFormElement} form - The form element to process.
|
||||
*/
|
||||
function processMultiselectForm(form) {
|
||||
const multiselectFields = form.querySelectorAll("select.card-multiselect");
|
||||
multiselectFields.forEach(selectField => {
|
||||
const originalFieldName =
|
||||
selectField.getAttribute("data-original-name") || selectField.getAttribute("name");
|
||||
if (!originalFieldName) return;
|
||||
selectField.setAttribute("data-original-name", originalFieldName);
|
||||
|
||||
// Remove any previously generated hidden inputs for this multiselect.
|
||||
form
|
||||
.querySelectorAll(`input[data-generated-for-card-multiselect="${originalFieldName}"]`)
|
||||
.forEach(input => input.remove());
|
||||
|
||||
// For each selected option, create a hidden input.
|
||||
selectField.querySelectorAll("option:checked").forEach(option => {
|
||||
const cardId = option.value;
|
||||
const quantity = option.getAttribute("data-quantity") || "1";
|
||||
const hiddenInput = document.createElement("input");
|
||||
hiddenInput.type = "hidden";
|
||||
hiddenInput.name = originalFieldName;
|
||||
hiddenInput.value = `${cardId}:${quantity}`;
|
||||
hiddenInput.setAttribute("data-generated-for-card-multiselect", originalFieldName);
|
||||
form.appendChild(hiddenInput);
|
||||
});
|
||||
|
||||
// Prevent the browser from submitting the select field directly.
|
||||
selectField.removeAttribute("name");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset stale selections in all card multiselect fields.
|
||||
* This is triggered on the window's 'pageshow' event to clear any lingering selections.
|
||||
*/
|
||||
function resetCardMultiselectState() {
|
||||
const multiselectFields = document.querySelectorAll("select.card-multiselect");
|
||||
multiselectFields.forEach(selectField => {
|
||||
// Deselect all options.
|
||||
selectField.querySelectorAll("option").forEach(option => {
|
||||
option.selected = false;
|
||||
});
|
||||
|
||||
// If the select field has an associated Choices.js instance, clear its selection.
|
||||
if (selectField.choicesInstance) {
|
||||
const activeSelections = selectField.choicesInstance.getValue(true);
|
||||
if (activeSelections.length > 0) {
|
||||
selectField.choicesInstance.removeActiveItemsByValue(activeSelections);
|
||||
}
|
||||
selectField.choicesInstance.setValue([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all elements with the 'marquee' class.
|
||||
* For each element, if its content is overflowing (using isElementOverflowing),
|
||||
* wrap its innerHTML within a <marquee> tag and remove the 'marquee' class.
|
||||
*/
|
||||
function processMarqueeElements() {
|
||||
document.querySelectorAll('.marquee-calc').forEach(element => {
|
||||
if (element.offsetWidth >= 148 || element.offsetWidth < element.scrollWidth) {
|
||||
element.innerHTML = '<marquee behavior="scroll" direction="left" scrolldelay="80">' + element.innerHTML + '</marquee>';
|
||||
}
|
||||
|
||||
element.classList.remove('marquee-calc');
|
||||
});
|
||||
}
|
||||
|
||||
// Expose processMarqueeElements to be available for AJAX-loaded partial updates.
|
||||
window.processMarqueeElements = processMarqueeElements;
|
||||
|
||||
// On DOMContentLoaded, initialize theme toggling, form processing, and marquee wrapping.
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
initThemeToggle();
|
||||
initCardMultiselectHandling();
|
||||
processMarqueeElements();
|
||||
});
|
||||
|
||||
// On pageshow, only reset multiselect state if the page was loaded from bfcache.
|
||||
window.addEventListener("pageshow", function(event) {
|
||||
if (event.persisted) {
|
||||
resetCardMultiselectState();
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
@ -1,219 +0,0 @@
|
|||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (!window.updateGlobalCardFilters) {
|
||||
window.updateGlobalCardFilters = function() {
|
||||
const selects = document.querySelectorAll('.card-multiselect');
|
||||
|
||||
// Rebuild global selections and rarity filtering.
|
||||
const globalSelectedIds = [];
|
||||
let globalRarity = null;
|
||||
|
||||
selects.forEach(select => {
|
||||
const selectedValues = select.choicesInstance ? select.choicesInstance.getValue(true) : [];
|
||||
selectedValues.forEach(cardId => {
|
||||
if (cardId && globalSelectedIds.indexOf(cardId) === -1) {
|
||||
globalSelectedIds.push(cardId);
|
||||
}
|
||||
});
|
||||
if (selectedValues.length > 0 && globalRarity === null) {
|
||||
const option = select.querySelector('option[value="${selectedValues[0]}"]');
|
||||
if (option) {
|
||||
globalRarity = option.getAttribute('data-rarity');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
selects.forEach(select => {
|
||||
if (select.choicesInstance && select.choicesInstance.dropdown.element) {
|
||||
// Reset all options to enabled.
|
||||
select.querySelectorAll('option').forEach(function(option) {
|
||||
option.disabled = false;
|
||||
});
|
||||
// Reset all items to visible.
|
||||
select.choicesInstance.dropdown.element.querySelectorAll('[data-card-id]').forEach(function(item) {
|
||||
item.style.display = '';
|
||||
});
|
||||
// Filter out options/items that do not match the global rarity.
|
||||
if (globalRarity) {
|
||||
select.querySelectorAll('option[data-rarity]:not([data-rarity="'+globalRarity+'"])').forEach(function(option) {
|
||||
option.disabled = true;
|
||||
});
|
||||
select.choicesInstance.dropdown.element.querySelectorAll('[data-rarity]:not([data-rarity="'+globalRarity+'"])').forEach(function(item) {
|
||||
item.style.display = 'none';
|
||||
});
|
||||
}
|
||||
// Filter out options/items that match the global selected card IDs.
|
||||
for (const cardId of globalSelectedIds) {
|
||||
select.choicesInstance.dropdown.element.querySelectorAll('[data-card-id="' + cardId + '"]').forEach(function(item) {
|
||||
item.style.display = 'none';
|
||||
});
|
||||
select.querySelectorAll('option[data-card-id="'+cardId+'"]:not(option[selected])').forEach(function(option) {
|
||||
option.disabled = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
if (!window.updateOptionQuantity) {
|
||||
window.updateOptionQuantity = function(item, quantity) {
|
||||
const cardId = item.getAttribute('data-card-id');
|
||||
const option = item.closest('.choices__inner').querySelector('option[value="' + cardId + '"]');
|
||||
if (option) {
|
||||
option.setAttribute('data-quantity', quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!window.getOptionQuantity) {
|
||||
window.getOptionQuantity = function(item) {
|
||||
const cardId = item.getAttribute('data-card-id');
|
||||
const option = item.closest('.choices__inner').querySelector('option[value="' + cardId + '"]');
|
||||
return option ? parseInt(option.getAttribute('data-quantity')) : "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const selectFields = document.querySelectorAll('.card-multiselect');
|
||||
selectFields.forEach(selectField => {
|
||||
const placeholder = selectField.getAttribute('data-placeholder') || '';
|
||||
|
||||
const choicesInstance = new Choices(selectField, {
|
||||
removeItemButton: false,
|
||||
placeholderValue: placeholder,
|
||||
searchEnabled: true,
|
||||
shouldSort: false,
|
||||
allowHTML: true,
|
||||
closeDropdownOnSelect: true,
|
||||
removeItemButton: true,
|
||||
searchFields: ['label'],
|
||||
resetScrollPosition: false,
|
||||
callbackOnCreateTemplates: function(template) {
|
||||
const getCardContent = (data) => {
|
||||
let htmlContent = (data.element && data.element.getAttribute('data-html-content')) || data.label;
|
||||
let quantity = data.element.getAttribute('data-quantity');
|
||||
quantity = quantity ? parseInt(quantity) : 1;
|
||||
htmlContent = htmlContent.replace('__QUANTITY__', quantity);
|
||||
return htmlContent;
|
||||
};
|
||||
|
||||
const renderCard = (classNames, data, type) => {
|
||||
const rarity = data.element ? data.element.getAttribute('data-rarity') : '';
|
||||
const cardId = data.element ? data.element.getAttribute('data-card-id') : 0;
|
||||
const cardname = data.element ? data.element.getAttribute('data-name') : '';
|
||||
const content = getCardContent(data);
|
||||
if (type === 'item') {
|
||||
return template(`
|
||||
<div class="${classNames.item} mx-auto w-max ${data.highlighted ? classNames.highlightedState : ''} relative"
|
||||
data-id="${data.id}"
|
||||
data-card-id="${cardId}"
|
||||
data-item
|
||||
data-rarity="${rarity}"
|
||||
data-name="${cardname}"
|
||||
aria-selected="true"
|
||||
style="cursor: pointer; padding: 1rem;">
|
||||
<button type="button" class="decrement absolute left-[-1.5rem] top-1/2 transform -translate-y-1/2 bg-base-300 text-base-content px-2">-</button>
|
||||
<button type="button" class="increment absolute right-[-1.5rem] top-1/2 transform -translate-y-1/2 bg-base-300 text-base-content px-2">+</button>
|
||||
<div class="card-content">${content}</div>
|
||||
</div>
|
||||
`);
|
||||
} else {
|
||||
const extraAttributes = `data-select-text="${this.config.itemSelectText}" data-choice ${
|
||||
data.disabled ? 'data-choice-disabled aria-disabled="true"' : 'data-choice-selectable'
|
||||
}`;
|
||||
const extraClasses = classNames.itemChoice;
|
||||
return template(`
|
||||
<div class="${classNames.item} ${extraClasses} ${data.highlighted ? classNames.highlightedState : ''} mx-auto w-max"
|
||||
${extraAttributes}
|
||||
data-id="${data.id}"
|
||||
data-card-id="${cardId}"
|
||||
data-name="${cardname}"
|
||||
data-choice
|
||||
data-rarity="${rarity}"
|
||||
style="cursor: pointer;">
|
||||
${content}
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
choice: function(classNames, data) {
|
||||
return renderCard(classNames, data, 'choice');
|
||||
},
|
||||
item: function(classNames, data) {
|
||||
return renderCard(classNames, data, 'item');
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Associate the Choices instance with the select field.
|
||||
selectField.choicesInstance = choicesInstance;
|
||||
|
||||
if (!window.cardMultiselectInstances) {
|
||||
window.cardMultiselectInstances = [];
|
||||
}
|
||||
window.cardMultiselectInstances.push(selectField);
|
||||
|
||||
selectField.addEventListener('change', function() {
|
||||
if (window.updateGlobalCardFilters) {
|
||||
window.updateGlobalCardFilters();
|
||||
}
|
||||
});
|
||||
|
||||
if (choicesInstance.getValue(true).length > 0 && window.updateGlobalCardFilters) {
|
||||
window.updateGlobalCardFilters();
|
||||
}
|
||||
|
||||
// Listen for increment/decrement clicks (scoped to the choices container).
|
||||
const choicesContainer = selectField.closest('.choices') || document;
|
||||
|
||||
choicesContainer.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('increment')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
const container = e.target.closest('[data-item]');
|
||||
if (container) {
|
||||
let quantityBadge = container.querySelector('.card-quantity-badge');
|
||||
let quantity = window.getOptionQuantity(container);
|
||||
quantity = quantity + 1;
|
||||
quantityBadge.innerText = quantity;
|
||||
window.updateOptionQuantity(container, quantity);
|
||||
}
|
||||
}
|
||||
if (e.target.classList.contains('decrement')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
const container = e.target.closest('[data-item]');
|
||||
if (container) {
|
||||
let quantityBadge = container.querySelector('.card-quantity-badge');
|
||||
let quantity = window.getOptionQuantity(container);
|
||||
const cardId = container.getAttribute('data-card-id');
|
||||
if (quantity === 1) {
|
||||
const option = selectField.querySelector('option[value="' + cardId + '"]');
|
||||
if (option) {
|
||||
choicesInstance.removeActiveItemsByValue(option.value);
|
||||
option.selected = false;
|
||||
}
|
||||
if (window.updateGlobalCardFilters) {
|
||||
window.updateGlobalCardFilters();
|
||||
}
|
||||
} else {
|
||||
quantity = quantity - 1;
|
||||
quantityBadge.innerText = quantity;
|
||||
window.updateOptionQuantity(container, quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (e.target.closest('[data-item]') &&
|
||||
!e.target.classList.contains('increment') &&
|
||||
!e.target.classList.contains('decrement')) {
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
2
theme/static/js/choices.min.js
vendored
2
theme/static/js/choices.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
theme/static/js/hovercards.min.js
vendored
2
theme/static/js/hovercards.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,123 +0,0 @@
|
|||
/**
|
||||
* tooltip.js
|
||||
*
|
||||
* This script uses FloatingUI to create modern, styled tooltips for elements with the
|
||||
* custom attribute "data-tooltip-html". The tooltips are styled using Tailwind CSS classes
|
||||
* to support both light and dark themes and include a dynamically positioned arrow.
|
||||
*
|
||||
* Make sure the FloatingUIDOM global is available.
|
||||
* For example, include in your base template:
|
||||
* <script src="https://unpkg.com/@floating-ui/dom"></script>
|
||||
*/
|
||||
|
||||
const { computePosition, offset, flip, shift, arrow } = FloatingUIDOM;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.querySelectorAll('[data-tooltip-html]').forEach((el) => {
|
||||
let tooltipContainer = null;
|
||||
let arrowElement = null;
|
||||
let fadeOutTimeout;
|
||||
|
||||
const showTooltip = () => {
|
||||
if (tooltipContainer) return; // Tooltip already visible
|
||||
|
||||
// Retrieve the custom HTML content from the data attribute
|
||||
const tooltipContent = el.getAttribute('data-tooltip-html');
|
||||
|
||||
// Create a container for the tooltip (with modern styling)
|
||||
tooltipContainer = document.createElement('div');
|
||||
tooltipContainer.classList.add(
|
||||
'bg-black', 'text-white',
|
||||
'shadow-lg', 'rounded-lg', 'p-2',
|
||||
// Transition classes for simple fade in/out
|
||||
'transition-opacity', 'duration-200', 'opacity-0'
|
||||
);
|
||||
tooltipContainer.style.position = 'absolute';
|
||||
tooltipContainer.style.zIndex = '9999';
|
||||
|
||||
// Set the HTML content for the tooltip
|
||||
tooltipContainer.innerHTML = '<div class="p-2">' + tooltipContent + '</div>';
|
||||
|
||||
// Create the arrow element. The arrow is styled as a small rotated square.
|
||||
arrowElement = document.createElement('div');
|
||||
arrowElement.classList.add(
|
||||
'w-3', 'h-3',
|
||||
'bg-black',
|
||||
'transform', 'rotate-45'
|
||||
);
|
||||
arrowElement.style.position = 'absolute';
|
||||
|
||||
// Append the arrow into the tooltip container
|
||||
tooltipContainer.appendChild(arrowElement);
|
||||
|
||||
// Append the tooltip container to the document body
|
||||
document.body.appendChild(tooltipContainer);
|
||||
|
||||
// Use Floating UI to position the tooltip, including the arrow middleware
|
||||
computePosition(el, tooltipContainer, {
|
||||
middleware: [
|
||||
offset(8),
|
||||
flip(),
|
||||
shift({ padding: 5 }),
|
||||
arrow({ element: arrowElement })
|
||||
]
|
||||
}).then(({ x, y, placement, middlewareData }) => {
|
||||
Object.assign(tooltipContainer.style, {
|
||||
left: `${x}px`,
|
||||
top: `${y}px`
|
||||
});
|
||||
|
||||
// Position the arrow using the arrow middleware data
|
||||
const { x: arrowX, y: arrowY } = middlewareData.arrow || {};
|
||||
|
||||
// Reset any previous inline values
|
||||
arrowElement.style.left = '';
|
||||
arrowElement.style.top = '';
|
||||
arrowElement.style.right = '';
|
||||
arrowElement.style.bottom = '';
|
||||
|
||||
// Adjust the arrow's position according to the placement
|
||||
if (placement.startsWith('top')) {
|
||||
arrowElement.style.bottom = '-4px';
|
||||
arrowElement.style.left = arrowX !== undefined ? `${arrowX}px` : '50%';
|
||||
} else if (placement.startsWith('bottom')) {
|
||||
arrowElement.style.top = '-4px';
|
||||
arrowElement.style.left = arrowX !== undefined ? `${arrowX}px` : '50%';
|
||||
} else if (placement.startsWith('left')) {
|
||||
arrowElement.style.right = '-4px';
|
||||
arrowElement.style.top = arrowY !== undefined ? `${arrowY}px` : '50%';
|
||||
} else if (placement.startsWith('right')) {
|
||||
arrowElement.style.left = '-4px';
|
||||
arrowElement.style.top = arrowY !== undefined ? `${arrowY}px` : '50%';
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger a fade-in by moving from opacity-0 to opacity-100
|
||||
requestAnimationFrame(() => {
|
||||
tooltipContainer.classList.remove('opacity-0');
|
||||
tooltipContainer.classList.add('opacity-100');
|
||||
});
|
||||
};
|
||||
|
||||
const hideTooltip = () => {
|
||||
if (tooltipContainer) {
|
||||
tooltipContainer.classList.remove('opacity-100');
|
||||
tooltipContainer.classList.add('opacity-0');
|
||||
// Remove the tooltip from the DOM after the transition duration
|
||||
fadeOutTimeout = setTimeout(() => {
|
||||
if (tooltipContainer && tooltipContainer.parentNode) {
|
||||
tooltipContainer.parentNode.removeChild(tooltipContainer);
|
||||
}
|
||||
tooltipContainer = null;
|
||||
arrowElement = null;
|
||||
}, 200); // Matches the duration-200 class (200ms)
|
||||
}
|
||||
};
|
||||
|
||||
// Attach event listeners to show/hide the tooltip
|
||||
el.addEventListener('mouseenter', showTooltip);
|
||||
el.addEventListener('mouseleave', hideTooltip);
|
||||
el.addEventListener('focus', showTooltip);
|
||||
el.addEventListener('blur', hideTooltip);
|
||||
});
|
||||
});
|
||||
|
|
@ -25,12 +25,12 @@
|
|||
</a>
|
||||
<!-- Main Card Row: Single row with the acceptance's cards -->
|
||||
<div class="px-2 pb-0">
|
||||
<div class="grid grid-cols-2 items-center">
|
||||
<div class="grid grid-cols-2 items-center gap-2">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="cursor-pointer">{% card_badge acceptance.requested_card %}</div>
|
||||
{% card_badge acceptance.requested_card %}
|
||||
</div>
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="cursor-pointer">{% card_badge acceptance.offered_card %}</div>
|
||||
{% card_badge acceptance.offered_card %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue