diff --git a/js/ui.js b/js/ui.js index bd9db3f..9238ea9 100644 --- a/js/ui.js +++ b/js/ui.js @@ -13,7 +13,9 @@ import { calculateTotalDuration, formatDuration, escapeHtml, + decodeHtml, getShareUrl, + createModal, } from './utils.js'; import { openLyricsPanel, renderLyricsInFullscreen, clearFullscreenLyricsSync } from './lyrics.js'; import { @@ -3853,11 +3855,69 @@ export class UIRenderer { ); const data = await response.json(); - rateCriticsEl.innerHTML = `Critic Score: ${data.critic.score}, Based on ${data.critic.count} reviews`; + const critviews = data.critic.reviews || []; + + rateCriticsEl.innerHTML = `Critic Score: ${data.critic.score}, Based on ${data.critic.count} reviews`; if (data.critic.score == 'NR') { rateCriticsEl.innerHTML = `Critic Score Not Available Yet`; + } else { + rateCriticsEl.querySelector('a').onclick = () => { + const con = document.createElement('div'); + con.style.display = 'flex'; + con.style.flexDirection = 'column'; + con.style.gap = '1.5rem'; + + critviews.forEach((review) => { + const reviewdiv = document.createElement('div'); + reviewdiv.style.display = 'flex'; + reviewdiv.style.gap = '1rem'; + reviewdiv.style.paddingBottom = '1rem'; + reviewdiv.style.borderBottom = '1px solid var(--border)'; + + const publication = decodeHtml(review.publication || review.source || 'Unknown Publication'); + const author = decodeHtml(review.author || ''); + const quote = decodeHtml(review.text || review.quote || 'No review text available.'); + + reviewdiv.innerHTML = ` + +
+
+
+
${review.score}
+
+
+
+
+ `; + + reviewdiv.querySelector('.pub-name').textContent = publication; + if (author) { + reviewdiv.querySelector('.author-name').textContent = `By ${author}`; + } else { + reviewdiv.querySelector('.author-name').remove(); + } + reviewdiv.querySelector('.quote-text').textContent = `"${quote}"`; + + con.appendChild(reviewdiv); + }); + + if (critviews.length === 0) { + con.innerHTML = + '
No reviews found.
'; + } + + createModal({ + title: 'Critics Reviews', + content: con, + className: 'extra-wide', + }); + }; } + rateUsersEl.innerHTML = `User Score: ${data.user.score}, Based on ${data.user.count} reviews`; } catch (e) { rateCriticsEl.innerHTML = `Unable to Fetch Critic Score`; diff --git a/js/utils.js b/js/utils.js index 240b264..25bceba 100644 --- a/js/utils.js +++ b/js/utils.js @@ -381,6 +381,13 @@ export const escapeHtml = (unsafe) => { .replace(/'/g, '''); }; +export const decodeHtml = (html) => { + if (!html) return ''; + const div = document.createElement('div'); + div.innerHTML = html; + return div.textContent; +}; + export const getTrackTitle = (track, { fallback = 'Unknown Title' } = {}) => { if (!track?.title) return fallback; return track?.version ? `${track.title} (${track.version})` : track.title; @@ -778,3 +785,39 @@ export function replaceTokens(template, tokens) { return key in tokens ? tokens[key] : match; }); } + +export function createModal({ title, content, className = '', onClose }) { + const modal = document.createElement('div'); + modal.className = 'modal active'; + modal.style.zIndex = '10000'; + + modal.innerHTML = ` + + + `; + + const body = modal.querySelector('.modal-body'); + if (typeof content === 'string') { + body.innerHTML = content; + } else if (content instanceof HTMLElement) { + body.appendChild(content); + } + + document.body.appendChild(modal); + + const close = () => { + modal.remove(); + if (onClose) onClose(); + }; + + modal.querySelector('.modal-overlay').onclick = close; + modal.querySelector('.btn-close').onclick = close; + + return { modal, close }; +}