mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-11 13:56:16 +00:00
Fix: Format-check fail and translations. Feat: added animations to upvote and downvote buttons
This commit is contained in:
@@ -213,7 +213,6 @@
|
||||
"leave_a_review": "Leave a Review",
|
||||
"write_review_placeholder": "Share your thoughts about this game...",
|
||||
"sort_newest": "Newest",
|
||||
"sort_by": "Sort by",
|
||||
"no_reviews_yet": "No reviews yet",
|
||||
"be_first_to_review": "Be the first to share your thoughts about this game!",
|
||||
"sort_oldest": "Oldest",
|
||||
@@ -226,7 +225,6 @@
|
||||
"loading_reviews": "Loading reviews...",
|
||||
"loading_more_reviews": "Loading more reviews...",
|
||||
"load_more_reviews": "Load More Reviews",
|
||||
"youve_played_for_hours": "You've played for {{hours}} hours",
|
||||
"would_you_recommend_this_game": "Would you like to leave a review to this game?",
|
||||
"yes": "Yes",
|
||||
"maybe_later": "Maybe Later",
|
||||
@@ -330,8 +328,8 @@
|
||||
"delete_review": "Delete review",
|
||||
"delete_review_modal_title": "Are you sure you want to delete your review?",
|
||||
"delete_review_modal_description": "This action cannot be undone.",
|
||||
"delete_review_button": "Delete",
|
||||
"delete_review_karma_warning": "You will lose any karma points earned from this review."
|
||||
"delete_review_modal_delete_button": "Delete",
|
||||
"delete_review_modal_cancel_button": "Cancel"
|
||||
},
|
||||
"activation": {
|
||||
"title": "Activate Hydra",
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ThumbsUp, ThumbsDown } from "lucide-react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useEditor, EditorContent } from "@tiptap/react";
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
import { motion } from "framer-motion";
|
||||
import type { GameReview } from "@types";
|
||||
|
||||
import { HeroPanel } from "./hero";
|
||||
@@ -131,10 +132,10 @@ export function GameDetailsContent() {
|
||||
},
|
||||
handlePaste: (view, event) => {
|
||||
// Strip formatting from pasted content to prevent overflow issues
|
||||
const text = event.clipboardData?.getData('text/plain') || '';
|
||||
const text = event.clipboardData?.getData("text/plain") || "";
|
||||
const currentText = view.state.doc.textContent;
|
||||
const remainingChars = MAX_REVIEW_CHARS - currentText.length;
|
||||
|
||||
|
||||
if (text && remainingChars > 0) {
|
||||
event.preventDefault();
|
||||
const truncatedText = text.slice(0, remainingChars);
|
||||
@@ -147,7 +148,7 @@ export function GameDetailsContent() {
|
||||
onUpdate: ({ editor }) => {
|
||||
const text = editor.getText();
|
||||
setReviewCharCount(text.length);
|
||||
|
||||
|
||||
// Prevent typing beyond character limit
|
||||
if (text.length > MAX_REVIEW_CHARS) {
|
||||
const truncatedContent = text.slice(0, MAX_REVIEW_CHARS);
|
||||
@@ -293,7 +294,12 @@ export function GameDetailsContent() {
|
||||
console.log("reviewScore:", reviewScore);
|
||||
console.log("submittingReview:", submittingReview);
|
||||
|
||||
if (!objectId || !reviewHtml.trim() || submittingReview || reviewCharCount > MAX_REVIEW_CHARS) {
|
||||
if (
|
||||
!objectId ||
|
||||
!reviewHtml.trim() ||
|
||||
submittingReview ||
|
||||
reviewCharCount > MAX_REVIEW_CHARS
|
||||
) {
|
||||
console.log("Early return - validation failed");
|
||||
return;
|
||||
}
|
||||
@@ -584,7 +590,13 @@ export function GameDetailsContent() {
|
||||
</button>
|
||||
</div>
|
||||
<div className="game-details__review-char-counter">
|
||||
<span className={reviewCharCount > MAX_REVIEW_CHARS ? "over-limit" : ""}>
|
||||
<span
|
||||
className={
|
||||
reviewCharCount > MAX_REVIEW_CHARS
|
||||
? "over-limit"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{reviewCharCount}/{MAX_REVIEW_CHARS}
|
||||
</span>
|
||||
</div>
|
||||
@@ -619,12 +631,14 @@ export function GameDetailsContent() {
|
||||
<option value={10}>10/10</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<button
|
||||
className="game-details__review-submit-button"
|
||||
onClick={handleSubmitReview}
|
||||
disabled={
|
||||
!editor?.getHTML().trim() || submittingReview || reviewCharCount > MAX_REVIEW_CHARS
|
||||
!editor?.getHTML().trim() ||
|
||||
submittingReview ||
|
||||
reviewCharCount > MAX_REVIEW_CHARS
|
||||
}
|
||||
>
|
||||
{submittingReview
|
||||
@@ -739,24 +753,56 @@ export function GameDetailsContent() {
|
||||
/>
|
||||
<div className="game-details__review-actions">
|
||||
<div className="game-details__review-votes">
|
||||
<button
|
||||
<motion.button
|
||||
className={`game-details__vote-button game-details__vote-button--upvote ${review.hasUpvoted ? "game-details__vote-button--active" : ""}`}
|
||||
onClick={() =>
|
||||
handleVoteReview(review.id, "upvote")
|
||||
}
|
||||
whileTap={{
|
||||
scale: 0.9,
|
||||
transition: { duration: 0.1 },
|
||||
}}
|
||||
whileHover={{
|
||||
scale: 1.05,
|
||||
transition: { duration: 0.2 },
|
||||
}}
|
||||
animate={
|
||||
review.hasUpvoted
|
||||
? {
|
||||
scale: [1, 1.2, 1],
|
||||
transition: { duration: 0.3 },
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<ThumbsUp size={16} />
|
||||
<span>{review.upvotes || 0}</span>
|
||||
</button>
|
||||
<button
|
||||
</motion.button>
|
||||
<motion.button
|
||||
className={`game-details__vote-button game-details__vote-button--downvote ${review.hasDownvoted ? "game-details__vote-button--active" : ""}`}
|
||||
onClick={() =>
|
||||
handleVoteReview(review.id, "downvote")
|
||||
}
|
||||
whileTap={{
|
||||
scale: 0.9,
|
||||
transition: { duration: 0.1 },
|
||||
}}
|
||||
whileHover={{
|
||||
scale: 1.05,
|
||||
transition: { duration: 0.2 },
|
||||
}}
|
||||
animate={
|
||||
review.hasDownvoted
|
||||
? {
|
||||
scale: [1, 1.2, 1],
|
||||
transition: { duration: 0.3 },
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<ThumbsDown size={16} />
|
||||
<span>{review.downvotes || 0}</span>
|
||||
</button>
|
||||
</motion.button>
|
||||
</div>
|
||||
{userDetails?.id === review.user?.id && (
|
||||
<button
|
||||
|
||||
@@ -659,7 +659,7 @@ $hero-height: 300px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border-color: globals.$brand-teal;
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -945,20 +945,20 @@ $hero-height: 300px;
|
||||
&__review-input {
|
||||
min-height: 120px;
|
||||
padding: 12px;
|
||||
|
||||
|
||||
.ProseMirror {
|
||||
outline: none;
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 8px 0;
|
||||
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@@ -15,5 +15,6 @@
|
||||
&__actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,11 @@ export function DeleteReviewModal({
|
||||
>
|
||||
<div className="delete-review-modal__actions">
|
||||
<Button onClick={onClose} theme="outline">
|
||||
{t("cancel")}
|
||||
{t("delete_review_modal_cancel_button")}
|
||||
</Button>
|
||||
|
||||
<Button onClick={handleDeleteReview} theme="danger">
|
||||
{t("delete_review_button")}
|
||||
{t("delete_review_modal_delete_button")}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user