finished conversion to tailwind
This commit is contained in:
parent
6e2843c60e
commit
d62956d465
50 changed files with 2490 additions and 1273 deletions
123
theme/static/js/tooltip.js
Normal file
123
theme/static/js/tooltip.js
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* 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);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue