Skip to content

Commit bad7d5a

Browse files
committed
Close #42
1 parent 617f937 commit bad7d5a

File tree

5 files changed

+166
-0
lines changed

5 files changed

+166
-0
lines changed

css/components/rating.css

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/* Star Rating Container */
2+
.rating {
3+
display: inline-flex;
4+
align-items: center;
5+
gap: clamp(var(--space-1), 0.5vw, var(--space-2));
6+
padding: clamp(var(--space-2), 1vw, var(--space-3));
7+
background-color: var(--neutral-50);
8+
border-radius: var(--radius-md);
9+
box-shadow: var(--shadow-sm);
10+
transition: var(--transition-all);
11+
position: relative;
12+
}
13+
14+
/* Data Variant */
15+
.rating[data-variant="primary"] {
16+
--star-color: var(--primary);
17+
--star-color-hover: var(--primary-hover);
18+
--star-color-shadow: var(--primary-shadow);
19+
}
20+
.rating[data-variant="success"] {
21+
--star-color: var(--success);
22+
--star-color-hover: var(--success-hover);
23+
--star-color-shadow: var(--success-shadow);
24+
}
25+
.rating[data-variant="danger"] {
26+
--star-color: var(--danger);
27+
--star-color-hover: var(--danger-hover);
28+
--star-color-shadow: var(--danger-shadow);
29+
}
30+
.rating[data-variant="warning"] {
31+
--star-color: var(--warning);
32+
--star-color-hover: var(--warning-hover);
33+
--star-color-shadow: var(--warning-shadow);
34+
}
35+
.rating[data-variant="info"] {
36+
--star-color: var(--info);
37+
--star-color-hover: var(--info-hover);
38+
--star-color-shadow: var(--info-shadow);
39+
}
40+
41+
/* Star Rating Icon Styling */
42+
.rating .star {
43+
font-size: clamp(1rem, 2vw, 1.5rem);
44+
color: var(--neutral-300);
45+
cursor: pointer;
46+
transition: color var(--transition-colors), transform var(--transition-transform);
47+
}
48+
.rating .star.filled {
49+
color: var(--star-color, var(--primary));
50+
}
51+
.rating .star.filled:hover,
52+
.rating .star.filled:focus {
53+
color: var(--star-color-hover, var(--primary-hover));
54+
transform: scale(1.1);
55+
box-shadow: var(--star-color-shadow, var(--primary-shadow));
56+
}
57+
58+
/* Accessibility - Hide Star Labels for Screen Readers */
59+
.rating .star[aria-hidden="true"] {
60+
display: inline-block;
61+
position: absolute;
62+
width: 0;
63+
height: 0;
64+
overflow: hidden;
65+
white-space: nowrap;
66+
clip: rect(0 0 0 0);
67+
clip-path: inset(50%);
68+
}
69+
70+
/* Responsive Adjustments */
71+
@media (min-width: 768px) {
72+
.rating {
73+
gap: clamp(var(--space-2), 1vw, var(--space-4));
74+
padding: clamp(var(--space-2), 1vw, var(--space-4));
75+
border-radius: var(--radius-lg);
76+
}
77+
}
78+
79+
/* Animations for Star Hover and Active States */
80+
.rating .star:hover,
81+
.rating .star:focus {
82+
color: var(--star-color-hover, var(--primary-hover));
83+
transform: scale(1.1);
84+
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
85+
}

css/main.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,5 @@
3838
@import './components/pagination.css';
3939
@import './components/stat-metrics.css';
4040
@import './components/timeline.css';
41+
@import './components/rating.css';
4142

demo.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,25 @@ <h3 class="timeline-title">Final Product Development</h3>
11831183
</div>
11841184
</section>
11851185
</section>
1186+
1187+
<section class="p-4 bg-neutral-50 shadow-md rounded my-6">
1188+
<h2 class="font-lg text-primary my-4">Rating Component Demo</h2>
1189+
<div class="rating" data-variant="primary" data-rating="4" aria-label="4 out of 5 stars">
1190+
<span class="star filled" role="button" tabindex="0"></span>
1191+
<span class="star filled" role="button" tabindex="0"></span>
1192+
<span class="star filled" role="button" tabindex="0"></span>
1193+
<span class="star filled" role="button" tabindex="0"></span>
1194+
<span class="star" role="button" tabindex="0"></span>
1195+
</div>
1196+
1197+
<div class="rating" data-variant="success" data-rating="3" aria-label="3 out of 5 stars">
1198+
<span class="star filled" role="button" tabindex="0"></span>
1199+
<span class="star filled" role="button" tabindex="0"></span>
1200+
<span class="star filled" role="button" tabindex="0"></span>
1201+
<span class="star" role="button" tabindex="0"></span>
1202+
<span class="star" role="button" tabindex="0"></span>
1203+
</div>
1204+
</section>
11861205

11871206
</body>
11881207
<script type="module" src="js/main.js"></script>

js/components/rating.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
export function initializeRatingComponents() {
2+
// Select and initialize all rating components on the page
3+
document.querySelectorAll('.rating').forEach(initRatingComponent);
4+
}
5+
6+
function initRatingComponent(ratingElement) {
7+
const stars = ratingElement.querySelectorAll('.star');
8+
9+
// Helper function to update star visual state based on the rating value
10+
const updateStars = (ratingValue) => {
11+
stars.forEach((star, index) => {
12+
star.classList.toggle('filled', index < ratingValue);
13+
});
14+
};
15+
16+
// Set initial rating from data attribute or default to 0
17+
const initialRating = parseInt(ratingElement.getAttribute('data-rating'), 10) || 0;
18+
updateStars(initialRating);
19+
20+
// Add event listeners for interactivity
21+
stars.forEach((star, index) => {
22+
star.addEventListener('click', () => {
23+
const newRating = index + 1;
24+
ratingElement.setAttribute('data-rating', newRating);
25+
updateStars(newRating);
26+
27+
// Dispatch the custom "ratingSet" event for developers to listen to
28+
const ratingEvent = new CustomEvent('ratingSet', {
29+
detail: { rating: newRating, element: ratingElement }
30+
});
31+
ratingElement.dispatchEvent(ratingEvent);
32+
});
33+
34+
star.addEventListener('mouseover', () => updateStars(index + 1));
35+
star.addEventListener('mouseleave', () => updateStars(ratingElement.getAttribute('data-rating')));
36+
});
37+
}
38+
39+
// Automatically initialize on DOMContentLoaded
40+
document.addEventListener("DOMContentLoaded", initializeRatingComponents);

js/main.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { Modal } from './components/modal.js';
77
import { MultiSelect } from './components/multiselect.js';
88
import { DateTimePicker } from './components/datetime-picker.js';
99
import { Slideshow } from './components/slideshow.js';
10+
import { initializeRatingComponents } from './components/rating.js';
11+
1012

1113
document.querySelectorAll('.alert .alert-close').forEach(button => {
1214
button.addEventListener('click', event => {
@@ -19,6 +21,23 @@ document.querySelectorAll('.alert .alert-close').forEach(button => {
1921
});
2022
});
2123

24+
document.addEventListener("DOMContentLoaded", () => {
25+
// Initialize rating components
26+
initializeRatingComponents();
27+
28+
// Initialize other components, if applicable
29+
document.querySelectorAll('.alert .alert-close').forEach(button => {
30+
button.addEventListener('click', event => {
31+
const alert = button.closest('.alert');
32+
alert.style.maxHeight = alert.scrollHeight + 'px';
33+
alert.classList.add('fade-out');
34+
alert.addEventListener('transitionend', () => {
35+
if (alert.parentNode) alert.remove();
36+
});
37+
});
38+
});
39+
});
40+
2241

2342
// Export functions globally if needed
2443
window.toggleAccordion = toggleAccordion;
@@ -33,3 +52,5 @@ window.closeToastHistory = closeToastHistory;
3352
window.Modal = Modal;
3453
window.MultiSelect = MultiSelect;
3554
window.DateTimePicker = DateTimePicker;
55+
window.initializeRatingComponents = initializeRatingComponents;
56+

0 commit comments

Comments
 (0)