helpdesk_rating_five_stars/static/description/widget_demo.html
2025-11-26 10:39:26 +07:00

259 lines
9.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rating Stars Widget Demo</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
max-width: 800px;
margin: 40px auto;
padding: 20px;
background: #f5f5f5;
}
.demo-section {
background: white;
padding: 30px;
margin-bottom: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 {
color: #333;
margin-bottom: 10px;
}
h2 {
color: #666;
margin-top: 0;
margin-bottom: 20px;
font-size: 18px;
}
.demo-item {
margin-bottom: 30px;
}
.demo-label {
font-weight: 600;
margin-bottom: 10px;
color: #555;
}
.demo-description {
font-size: 14px;
color: #777;
margin-bottom: 10px;
}
.selected-value {
margin-top: 10px;
padding: 10px;
background: #e3f2fd;
border-radius: 4px;
font-size: 14px;
color: #1976d2;
}
/* Include the rating stars styles inline for demo */
.rating-stars-container {
display: inline-flex;
align-items: center;
gap: 4px;
outline: none;
}
.rating-stars-container:focus {
outline: 2px solid #007bff;
outline-offset: 4px;
border-radius: 4px;
}
.rating-star {
display: inline-block;
line-height: 1;
transition: all 0.2s ease;
user-select: none;
}
.rating-star.rating-star-filled {
color: #ffc107;
}
.rating-star.rating-star-empty {
color: #e0e0e0;
}
.rating-star.rating-star-interactive {
cursor: pointer;
}
.rating-star.rating-star-interactive:hover {
transform: scale(1.15);
filter: brightness(1.1);
}
.rating-star.rating-star-focused {
outline: 2px solid #007bff;
outline-offset: 2px;
border-radius: 2px;
}
.rating-stars-small .rating-star {
font-size: 16px;
}
.rating-stars-medium .rating-star {
font-size: 24px;
}
.rating-stars-large .rating-star {
font-size: 36px;
}
@media (max-width: 768px) {
.rating-stars-container {
gap: 8px;
}
.rating-star {
min-width: 44px;
min-height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
}
}
</style>
</head>
<body>
<div class="demo-section">
<h1>Rating Stars Widget Demo</h1>
<h2>Interactive 5-Star Rating Component for Odoo 18</h2>
</div>
<div class="demo-section">
<div class="demo-item">
<div class="demo-label">Interactive Rating (Medium Size)</div>
<div class="demo-description">Click on a star to select a rating. Hover to preview.</div>
<div class="rating-stars-container rating-stars-medium" id="demo1" tabindex="0">
<span class="rating-star rating-star-empty rating-star-interactive"></span>
<span class="rating-star rating-star-empty rating-star-interactive"></span>
<span class="rating-star rating-star-empty rating-star-interactive"></span>
<span class="rating-star rating-star-empty rating-star-interactive"></span>
<span class="rating-star rating-star-empty rating-star-interactive"></span>
</div>
<div class="selected-value" id="value1">Selected: 0 stars</div>
</div>
<div class="demo-item">
<div class="demo-label">Small Size</div>
<div class="demo-description">Compact version for list views.</div>
<div class="rating-stars-container rating-stars-small" id="demo2" tabindex="0">
<span class="rating-star rating-star-filled"></span>
<span class="rating-star rating-star-filled"></span>
<span class="rating-star rating-star-filled"></span>
<span class="rating-star rating-star-empty"></span>
<span class="rating-star rating-star-empty"></span>
</div>
<div class="selected-value">Pre-selected: 3 stars (readonly)</div>
</div>
<div class="demo-item">
<div class="demo-label">Large Size</div>
<div class="demo-description">Prominent display for rating forms.</div>
<div class="rating-stars-container rating-stars-large" id="demo3" tabindex="0">
<span class="rating-star rating-star-empty rating-star-interactive"></span>
<span class="rating-star rating-star-empty rating-star-interactive"></span>
<span class="rating-star rating-star-empty rating-star-interactive"></span>
<span class="rating-star rating-star-empty rating-star-interactive"></span>
<span class="rating-star rating-star-empty rating-star-interactive"></span>
</div>
<div class="selected-value" id="value3">Selected: 0 stars</div>
</div>
</div>
<div class="demo-section">
<h2>Features</h2>
<ul>
<li><strong>Click to select:</strong> Click any star to set the rating</li>
<li><strong>Hover feedback:</strong> Hover over stars to preview the rating</li>
<li><strong>Keyboard navigation:</strong> Use arrow keys to change rating, Enter to confirm</li>
<li><strong>Accessibility:</strong> Full ARIA labels and keyboard support</li>
<li><strong>Touch-friendly:</strong> Optimized for mobile devices with larger touch targets</li>
<li><strong>Responsive:</strong> Adapts to different screen sizes</li>
</ul>
</div>
<script>
// Simple demo JavaScript (the actual OWL component handles this automatically)
function setupDemo(containerId, valueId) {
const container = document.getElementById(containerId);
const valueDisplay = document.getElementById(valueId);
const stars = container.querySelectorAll('.rating-star');
let selectedValue = 0;
stars.forEach((star, index) => {
const starValue = index + 1;
// Click handler
star.addEventListener('click', () => {
selectedValue = starValue;
updateStars(selectedValue);
if (valueDisplay) {
valueDisplay.textContent = `Selected: ${selectedValue} stars`;
}
});
// Hover handler
star.addEventListener('mouseenter', () => {
updateStars(starValue);
});
});
// Mouse leave handler
container.addEventListener('mouseleave', () => {
updateStars(selectedValue);
});
// Keyboard handler
container.addEventListener('keydown', (e) => {
if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {
if (selectedValue < 5) {
selectedValue++;
updateStars(selectedValue);
if (valueDisplay) {
valueDisplay.textContent = `Selected: ${selectedValue} stars`;
}
}
e.preventDefault();
} else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {
if (selectedValue > 0) {
selectedValue--;
updateStars(selectedValue);
if (valueDisplay) {
valueDisplay.textContent = `Selected: ${selectedValue} stars`;
}
}
e.preventDefault();
}
});
function updateStars(value) {
stars.forEach((star, index) => {
if (index < value) {
star.classList.add('rating-star-filled');
star.classList.remove('rating-star-empty');
star.textContent = '★';
} else {
star.classList.remove('rating-star-filled');
star.classList.add('rating-star-empty');
star.textContent = '☆';
}
});
}
}
// Initialize demos
setupDemo('demo1', 'value1');
setupDemo('demo3', 'value3');
</script>
</body>
</html>