From 1f05dc8f78683addf65df8f8ebc1f7db29b27316 Mon Sep 17 00:00:00 2001
From: Moyasee
Date: Sat, 4 Oct 2025 20:12:01 +0300
Subject: [PATCH] Feat: Rating score display redesign, Rating choosing
redesign, added avg rating on the game page
---
src/locales/en/translation.json | 3 ++
.../game-details/game-details-content.tsx | 43 ++++++++++++++----
.../src/pages/game-details/game-details.scss | 45 ++++++++++++++++++-
.../pages/game-details/sidebar/sidebar.scss | 5 +--
.../pages/game-details/sidebar/sidebar.tsx | 11 +++++
src/shared/html-sanitizer.ts | 4 +-
6 files changed, 95 insertions(+), 16 deletions(-)
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index 22bb9380..b54fe2fb 100755
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -200,6 +200,7 @@
"stats": "Stats",
"download_count": "Downloads",
"player_count": "Active players",
+ "rating_count": "Rating",
"download_error": "This download option is not available",
"download": "Download",
"executable_path_in_use": "Executable already in use by \"{{game}}\"",
@@ -220,6 +221,8 @@
"sort_lowest_score": "Lowest Score",
"sort_most_voted": "Most Voted",
"rating": "Rating",
+ "rating_stats": "Rating",
+ "select_rating": "Select Rating",
"submit_review": "Submit Review",
"submitting": "Submitting...",
"loading_reviews": "Loading reviews...",
diff --git a/src/renderer/src/pages/game-details/game-details-content.tsx b/src/renderer/src/pages/game-details/game-details-content.tsx
index 28321f1e..03959506 100644
--- a/src/renderer/src/pages/game-details/game-details-content.tsx
+++ b/src/renderer/src/pages/game-details/game-details-content.tsx
@@ -24,6 +24,14 @@ import { useUserDetails, useLibrary, useDate } from "@renderer/hooks";
import { useSubscription } from "@renderer/hooks/use-subscription";
import "./game-details.scss";
+// Helper function to get score color class
+const getScoreColorClass = (score: number): string => {
+ if (score >= 0 && score <= 3) return "game-details__review-score--red";
+ if (score >= 4 && score <= 6) return "game-details__review-score--yellow";
+ if (score >= 7 && score <= 10) return "game-details__review-score--green";
+ return "";
+};
+
export function GameDetailsContent() {
const heroRef = useRef(null);
const navigate = useNavigate();
@@ -103,7 +111,7 @@ export function GameDetailsContent() {
// Reviews state management
const [reviews, setReviews] = useState([]);
const [reviewsLoading, setReviewsLoading] = useState(false);
- const [reviewScore, setReviewScore] = useState(5);
+ const [reviewScore, setReviewScore] = useState(null);
const [submittingReview, setSubmittingReview] = useState(false);
const [reviewCharCount, setReviewCharCount] = useState(0);
const MAX_REVIEW_CHARS = 1000;
@@ -302,6 +310,7 @@ export function GameDetailsContent() {
if (
!objectId ||
!reviewHtml.trim() ||
+ reviewScore === null ||
submittingReview ||
reviewCharCount > MAX_REVIEW_CHARS
) {
@@ -322,7 +331,7 @@ export function GameDetailsContent() {
console.log("Review submitted successfully");
editor?.commands.clearContent();
- setReviewScore(5);
+ setReviewScore(null);
await loadReviews(true); // Reload reviews after submission
setShowReviewForm(false); // Hide the review form after successful submission
setShowReviewPrompt(false); // Hide the prompt banner
@@ -606,10 +615,14 @@ export function GameDetailsContent() {
-
+ onClick={() => editor?.commands.focus()}
+ >
+
+
@@ -618,12 +631,23 @@ export function GameDetailsContent() {
{t("rating")}
-
diff --git a/src/renderer/src/pages/game-details/game-details.scss b/src/renderer/src/pages/game-details/game-details.scss
index dd479ab1..76b6cdcb 100644
--- a/src/renderer/src/pages/game-details/game-details.scss
+++ b/src/renderer/src/pages/game-details/game-details.scss
@@ -75,10 +75,30 @@ $hero-height: 300px;
padding: 6px 12px;
font-size: 14px;
cursor: pointer;
+ transition: border-color 0.2s ease, background-color 0.2s ease;
&:focus {
outline: none;
- border-color: #0078d4;
+ }
+
+ &--red {
+ border-color: #e74c3c;
+ background-color: rgba(231, 76, 60, 0.1);
+ }
+
+ &--yellow {
+ border-color: #f39c12;
+ background-color: rgba(243, 156, 18, 0.1);
+ }
+
+ &--green {
+ border-color: #27ae60;
+ background-color: rgba(39, 174, 96, 0.1);
+ }
+
+ option {
+ background-color: #2a2a2a;
+ color: #ffffff;
}
}
@@ -373,6 +393,25 @@ $hero-height: 300px;
font-size: globals.$small-font-size;
font-weight: 600;
border: 1px solid rgba(255, 255, 255, 0.15);
+
+ // Color variants based on score
+ &--red {
+ background: rgba(239, 68, 68, 0.2);
+ color: #fca5a5;
+ border-color: rgba(239, 68, 68, 0.4);
+ }
+
+ &--yellow {
+ background: rgba(245, 158, 11, 0.2);
+ color: #fcd34d;
+ border-color: rgba(245, 158, 11, 0.4);
+ }
+
+ &--green {
+ background: rgba(34, 197, 94, 0.2);
+ color: #86efac;
+ border-color: rgba(34, 197, 94, 0.4);
+ }
}
&__review-date {
@@ -953,12 +992,16 @@ $hero-height: 300px;
&__review-input {
min-height: 120px;
padding: 12px;
+ cursor: text;
.ProseMirror {
outline: none;
color: #ffffff;
font-size: 14px;
line-height: 1.5;
+ min-height: 96px; // 120px - 24px padding
+ width: 100%;
+ cursor: text;
&:focus {
outline: none;
diff --git a/src/renderer/src/pages/game-details/sidebar/sidebar.scss b/src/renderer/src/pages/game-details/sidebar/sidebar.scss
index 06519f6c..b48e8a8f 100755
--- a/src/renderer/src/pages/game-details/sidebar/sidebar.scss
+++ b/src/renderer/src/pages/game-details/sidebar/sidebar.scss
@@ -106,7 +106,7 @@
.stats {
&__section {
display: flex;
- gap: calc(globals.$spacing-unit * 2);
+ gap: calc(globals.$spacing-unit * 1);
padding: calc(globals.$spacing-unit * 2);
justify-content: space-between;
transition: max-height ease 0.5s;
@@ -116,9 +116,6 @@
flex-direction: column;
}
- @media (min-width: 1280px) {
- flex-direction: row;
- }
}
&__category-title {
diff --git a/src/renderer/src/pages/game-details/sidebar/sidebar.tsx b/src/renderer/src/pages/game-details/sidebar/sidebar.tsx
index 0a24c418..d8aa2128 100755
--- a/src/renderer/src/pages/game-details/sidebar/sidebar.tsx
+++ b/src/renderer/src/pages/game-details/sidebar/sidebar.tsx
@@ -14,6 +14,7 @@ import {
DownloadIcon,
LockIcon,
PeopleIcon,
+ StarIcon,
} from "@primer/octicons-react";
import { HowLongToBeatSection } from "./how-long-to-beat-section";
import { howLongToBeatEntriesTable } from "@renderer/dexie";
@@ -225,6 +226,16 @@ export function Sidebar() {
{numberFormatter.format(stats?.playerCount)}
+
+ {stats?.averageScore && (
+
+
+
+ {t("rating_count")}
+
+
{stats.averageScore.toFixed(1)}/10
+
+ )}
)}
diff --git a/src/shared/html-sanitizer.ts b/src/shared/html-sanitizer.ts
index d8391d88..4f8042e3 100644
--- a/src/shared/html-sanitizer.ts
+++ b/src/shared/html-sanitizer.ts
@@ -24,7 +24,7 @@ function decodeHtmlEntities(text: string): string {
function removeHtmlTags(html: string): string {
let result = "";
let inTag = false;
-
+
for (const char of html) {
if (char === "<") {
inTag = true;
@@ -34,7 +34,7 @@ function removeHtmlTags(html: string): string {
result += char;
}
}
-
+
return result;
}