mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-20 01:33:56 +00:00
feat: improving skeleton
This commit is contained in:
@@ -17,6 +17,7 @@ import cloudIconAnimated from "@renderer/assets/icons/cloud-animated.gif";
|
||||
import { useUserDetails, useLibrary } from "@renderer/hooks";
|
||||
import { useSubscription } from "@renderer/hooks/use-subscription";
|
||||
import "./game-details.scss";
|
||||
import "./hero.scss";
|
||||
|
||||
const processMediaElements = (document: Document) => {
|
||||
const $images = Array.from(document.querySelectorAll("img"));
|
||||
|
||||
@@ -1,63 +1,170 @@
|
||||
import Skeleton from "react-loading-skeleton";
|
||||
import { Button } from "@renderer/components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import "./game-details.scss";
|
||||
import "react-loading-skeleton/dist/skeleton.css";
|
||||
|
||||
export function GameDetailsSkeleton() {
|
||||
const { t } = useTranslation("game_details");
|
||||
|
||||
return (
|
||||
<div className="game-details__container">
|
||||
<div className="game-details__hero">
|
||||
<Skeleton className="game-details__hero-image-skeleton" />
|
||||
</div>
|
||||
<div className="game-details__hero-panel-skeleton">
|
||||
<section className="description-header__info">
|
||||
<Skeleton width={155} />
|
||||
<Skeleton width={135} />
|
||||
</section>
|
||||
</div>
|
||||
<div className="game-details__description-container">
|
||||
<div className="game-details__description-content">
|
||||
<div className="description-header">
|
||||
<section className="description-header__info">
|
||||
<Skeleton width={145} />
|
||||
<Skeleton width={150} />
|
||||
</section>
|
||||
<div className="game-details__wrapper game-details__skeleton">
|
||||
<section className="game-details__container">
|
||||
<div className="game-details__hero">
|
||||
<Skeleton
|
||||
height={350}
|
||||
style={{
|
||||
borderRadius: "0px 0px 8px 8px",
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
zIndex: 0,
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="game-details__hero-logo-backdrop">
|
||||
<div className="game-details__hero-content">
|
||||
<div className="game-details__game-logo" />
|
||||
<div className="game-details__hero-buttons game-details__hero-buttons--right" />
|
||||
</div>
|
||||
|
||||
<div className="game-details__hero-panel">
|
||||
<div className="hero-panel__container">
|
||||
<div className="hero-panel">
|
||||
<div className="hero-panel__content">
|
||||
<Skeleton height={16} width={150} />
|
||||
<Skeleton height={16} width={120} />
|
||||
</div>
|
||||
<div className="hero-panel__actions" style={{ gap: "16px" }}>
|
||||
<Skeleton
|
||||
height={36}
|
||||
width={36}
|
||||
style={{ borderRadius: "6px" }}
|
||||
/>
|
||||
<Skeleton
|
||||
height={36}
|
||||
width={36}
|
||||
style={{ borderRadius: "6px" }}
|
||||
/>
|
||||
<Skeleton
|
||||
height={36}
|
||||
width={100}
|
||||
style={{ borderRadius: "6px" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="game-details__description-skeleton">
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
<Skeleton key={index} />
|
||||
))}
|
||||
<Skeleton className="game-details__hero-image-skeleton" />
|
||||
{Array.from({ length: 2 }).map((_, index) => (
|
||||
<Skeleton key={index} />
|
||||
))}
|
||||
<Skeleton className="game-details__hero-image-skeleton" />
|
||||
<Skeleton />
|
||||
</div>
|
||||
|
||||
<div className="game-details__description-container">
|
||||
<div className="game-details__description-content">
|
||||
<div className="description-header">
|
||||
<section className="description-header__info">
|
||||
<Skeleton height={16} width={200} />
|
||||
<Skeleton height={16} width={150} />
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: "24px" }}>
|
||||
<Skeleton
|
||||
height={200}
|
||||
width="100%"
|
||||
style={{ borderRadius: "8px" }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="game-details__description">
|
||||
<Skeleton count={8} height={22} style={{ marginBottom: "8px" }} />
|
||||
<Skeleton height={22} width="60%" />
|
||||
</div>
|
||||
|
||||
<Skeleton
|
||||
width={120}
|
||||
height={36}
|
||||
className="game-details__description-toggle"
|
||||
width={100}
|
||||
style={{
|
||||
borderRadius: "4px",
|
||||
marginTop: "24px",
|
||||
alignSelf: "center",
|
||||
}}
|
||||
/>
|
||||
|
||||
<div style={{ marginTop: "48px" }} />
|
||||
</div>
|
||||
|
||||
<aside className="content-sidebar">
|
||||
<div className="sidebar-section">
|
||||
<div
|
||||
className="sidebar-section__button"
|
||||
style={{ pointerEvents: "none" }}
|
||||
>
|
||||
<Skeleton height={16} width={16} />
|
||||
<Skeleton height={16} width={60} />
|
||||
</div>
|
||||
|
||||
<div className="sidebar-section__content">
|
||||
<div className="stats__section">
|
||||
<div className="stats__category">
|
||||
<div className="stats__category-title">
|
||||
<Skeleton height={14} width={14} />
|
||||
<Skeleton height={14} width={80} />
|
||||
</div>
|
||||
<Skeleton height={14} width={40} />
|
||||
</div>
|
||||
|
||||
<div className="stats__category">
|
||||
<div className="stats__category-title">
|
||||
<Skeleton height={14} width={14} />
|
||||
<Skeleton height={14} width={70} />
|
||||
</div>
|
||||
<Skeleton height={14} width={35} />
|
||||
</div>
|
||||
|
||||
<div className="stats__category">
|
||||
<div className="stats__category-title">
|
||||
<Skeleton height={14} width={14} />
|
||||
<Skeleton height={14} width={60} />
|
||||
</div>
|
||||
<Skeleton height={14} width={30} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="sidebar-section">
|
||||
<div
|
||||
className="sidebar-section__button"
|
||||
style={{ pointerEvents: "none" }}
|
||||
>
|
||||
<Skeleton height={16} width={16} />
|
||||
<Skeleton height={16} width={120} />
|
||||
</div>
|
||||
|
||||
<div className="sidebar-section__content">
|
||||
<ul className="list">
|
||||
{Array.from({ length: 4 }).map((_, index) => (
|
||||
<li key={index}>
|
||||
<div
|
||||
className="list__item"
|
||||
style={{ pointerEvents: "none" }}
|
||||
>
|
||||
<Skeleton
|
||||
height={54}
|
||||
width={54}
|
||||
style={{ borderRadius: "4px" }}
|
||||
/>
|
||||
<div>
|
||||
<Skeleton
|
||||
height={14}
|
||||
width={120}
|
||||
style={{ marginBottom: "4px" }}
|
||||
/>
|
||||
<Skeleton height={12} width={80} />
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
<div className="content-sidebar">
|
||||
<div className="requirement__button-container">
|
||||
<Button className="requirement__button" theme="primary" disabled>
|
||||
{t("minimum")}
|
||||
</Button>
|
||||
<Button className="requirement__button" theme="outline" disabled>
|
||||
{t("recommended")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="requirement__details-skeleton">
|
||||
{Array.from({ length: 6 }).map((_, index) => (
|
||||
<Skeleton key={index} height={20} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
@use "../../scss/globals.scss";
|
||||
|
||||
$hero-height: 350px;
|
||||
|
||||
@keyframes slide-in {
|
||||
0% {
|
||||
transform: translateY(calc(40px + globals.$spacing-unit * 2));
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.game-details {
|
||||
&__wrapper {
|
||||
display: flex;
|
||||
@@ -27,569 +13,6 @@ $hero-height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
&__hero-panel {
|
||||
padding: globals.$spacing-unit;
|
||||
}
|
||||
|
||||
&__review-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
&__review-form-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&__review-score-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
&__review-score-select {
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 4px;
|
||||
color: #ffffff;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
background-color 0.2s ease;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&--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;
|
||||
}
|
||||
}
|
||||
|
||||
&__star-rating {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
&__star {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #666666;
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: #ffffff;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
&--filled {
|
||||
color: #ffffff;
|
||||
|
||||
&.game-details__review-score-select--red {
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
&.game-details__review-score-select--yellow {
|
||||
color: #f39c12;
|
||||
}
|
||||
|
||||
&.game-details__review-score-select--green {
|
||||
color: #27ae60;
|
||||
}
|
||||
}
|
||||
|
||||
&--empty {
|
||||
color: #666666;
|
||||
|
||||
&:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
&__reviews-sort {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(globals.$spacing-unit * 0.75);
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
&__reviews-sort-label {
|
||||
display: block;
|
||||
font-size: globals.$body-font-size;
|
||||
color: globals.$body-color;
|
||||
}
|
||||
|
||||
&__reviews-sort-select {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid globals.$border-color;
|
||||
border-radius: 4px;
|
||||
padding: calc(globals.$spacing-unit * 0.75) calc(globals.$spacing-unit * 1);
|
||||
color: globals.$body-color;
|
||||
font-size: globals.$body-font-size;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
background-color 0.2s ease;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
border-color: globals.$brand-teal;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
option {
|
||||
background-color: globals.$dark-background-color;
|
||||
color: globals.$body-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__reviews-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(globals.$spacing-unit * 4);
|
||||
}
|
||||
|
||||
&__reviews-separator {
|
||||
height: 1px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
margin: calc(globals.$spacing-unit * 3) 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__reviews-list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: calc(globals.$spacing-unit * 1);
|
||||
}
|
||||
|
||||
&__reviews-empty {
|
||||
text-align: center;
|
||||
padding: calc(globals.$spacing-unit * 4) calc(globals.$spacing-unit * 2);
|
||||
margin-bottom: calc(globals.$spacing-unit * 2);
|
||||
}
|
||||
|
||||
&__reviews-empty-icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: calc(globals.$spacing-unit * 2);
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
&__reviews-empty-title {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-weight: 600;
|
||||
margin: 0 0 calc(globals.$spacing-unit * 1) 0;
|
||||
}
|
||||
|
||||
&__reviews-empty-message {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: globals.$small-font-size;
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
&__review-item {
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
&__review-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: calc(globals.$spacing-unit * 1.5);
|
||||
}
|
||||
|
||||
&__review-user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: calc(globals.$spacing-unit * 1);
|
||||
}
|
||||
|
||||
&__review-user-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(globals.$spacing-unit * 0.25);
|
||||
}
|
||||
|
||||
&__review-display-name {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: globals.$small-font-size;
|
||||
font-weight: 600;
|
||||
display: inline-flex;
|
||||
|
||||
&--clickable {
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__review-actions {
|
||||
margin-top: 12px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__review-votes {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__vote-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 6px;
|
||||
padding: 6px 12px;
|
||||
color: #ccc;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
&--active {
|
||||
&.game-details__vote-button--upvote {
|
||||
svg {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
|
||||
&.game-details__vote-button--downvote {
|
||||
svg {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: 500;
|
||||
display: inline-block;
|
||||
min-width: 1ch;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&__delete-review-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(244, 67, 54, 0.1);
|
||||
border: 1px solid rgba(244, 67, 54, 0.3);
|
||||
border-radius: 6px;
|
||||
padding: 6px;
|
||||
color: #f44336;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
gap: 6px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(244, 67, 54, 0.2);
|
||||
border-color: #f44336;
|
||||
color: #ff5722;
|
||||
}
|
||||
}
|
||||
|
||||
&__blocked-review-simple {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: globals.$small-font-size;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: calc(globals.$spacing-unit * 0.5);
|
||||
}
|
||||
|
||||
&__blocked-review-show-link {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #ffc107;
|
||||
font-size: globals.$small-font-size;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
padding: 0;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: #ffeb3b;
|
||||
}
|
||||
}
|
||||
|
||||
&__blocked-review-hide-link {
|
||||
background: none;
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: globals.$small-font-size;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
padding: 0;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
&__review-score-stars {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
&__review-star {
|
||||
color: #666666;
|
||||
transition: color 0.2s ease;
|
||||
cursor: default;
|
||||
|
||||
&--filled {
|
||||
color: #ffffff;
|
||||
|
||||
&.game-details__review-score--red {
|
||||
color: #fca5a5;
|
||||
}
|
||||
|
||||
&.game-details__review-score--yellow {
|
||||
color: #fcd34d;
|
||||
}
|
||||
|
||||
&.game-details__review-score--green {
|
||||
color: #86efac;
|
||||
}
|
||||
}
|
||||
|
||||
&--empty {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
&__review-date {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: globals.$small-font-size;
|
||||
}
|
||||
|
||||
&__review-content {
|
||||
color: globals.$body-color;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&__reviews-loading {
|
||||
text-align: center;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
padding: calc(globals.$spacing-unit * 2);
|
||||
}
|
||||
|
||||
&__load-more-reviews {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid globals.$border-color;
|
||||
color: globals.$body-color;
|
||||
padding: calc(globals.$spacing-unit * 1) calc(globals.$spacing-unit * 2);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: globals.$body-font-size;
|
||||
font-family: inherit;
|
||||
transition: all 0.2s ease;
|
||||
width: 100%;
|
||||
margin-top: calc(globals.$spacing-unit * 2);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border-color: globals.$brand-teal;
|
||||
}
|
||||
}
|
||||
|
||||
&__hero {
|
||||
width: 100%;
|
||||
height: $hero-height;
|
||||
min-height: $hero-height;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
transition: all ease 0.2s;
|
||||
|
||||
@media (min-width: 1250px) {
|
||||
height: 350px;
|
||||
min-height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
&__hero-content {
|
||||
padding: calc(globals.$spacing-unit * 1.5);
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
padding: calc(globals.$spacing-unit * 2);
|
||||
}
|
||||
}
|
||||
|
||||
&__hero-buttons {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit;
|
||||
align-items: center;
|
||||
|
||||
&--right {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&__edit-custom-game-button {
|
||||
padding: calc(globals.$spacing-unit * 1.5);
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 8px;
|
||||
transition: all ease 0.2s;
|
||||
cursor: pointer;
|
||||
min-height: 40px;
|
||||
min-width: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: globals.$muted-color;
|
||||
border: solid 1px globals.$border-color;
|
||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.8);
|
||||
animation: slide-in 0.3s cubic-bezier(0.33, 1, 0.68, 1);
|
||||
|
||||
&:active {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
color: globals.$body-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__hero-logo-backdrop {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(0deg, rgba(0, 0, 0, 0.3) 60%, transparent 100%);
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__hero-image {
|
||||
width: 100%;
|
||||
height: $hero-height;
|
||||
min-height: $hero-height;
|
||||
object-fit: cover;
|
||||
object-position: top;
|
||||
transition: all ease 0.2s;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
|
||||
@media (min-width: 1250px) {
|
||||
object-position: center;
|
||||
height: $hero-height;
|
||||
min-height: $hero-height;
|
||||
}
|
||||
}
|
||||
|
||||
&__game-logo {
|
||||
width: 200px;
|
||||
align-self: flex-end;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
&__game-logo-text {
|
||||
width: 200px;
|
||||
align-self: flex-end;
|
||||
font-size: 1.8rem;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
|
||||
text-align: left;
|
||||
line-height: 1.2;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
hyphens: auto;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
width: 250px;
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
width: 300px;
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -598,6 +21,7 @@ $hero-height: 350px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
// Description Section Styles
|
||||
&__description-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
@@ -706,276 +130,51 @@ $hero-height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
&__description-skeleton {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: globals.$spacing-unit;
|
||||
padding: calc(globals.$spacing-unit * 2) calc(globals.$spacing-unit * 1.5);
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
padding: calc(globals.$spacing-unit * 2.5) calc(globals.$spacing-unit * 2);
|
||||
// Skeleton-specific styles
|
||||
&__skeleton {
|
||||
.react-loading-skeleton {
|
||||
background: linear-gradient(90deg, #1c1c1c 25%, #2a2a2a 50%, #1c1c1c 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: skeleton-loading 1.5s infinite;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
padding: calc(globals.$spacing-unit * 3) calc(globals.$spacing-unit * 2);
|
||||
width: 80%;
|
||||
// Ensure skeleton elements maintain proper spacing
|
||||
.description-header {
|
||||
margin-bottom: calc(globals.$spacing-unit * 1.5);
|
||||
}
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
width: 60%;
|
||||
line-height: 22px;
|
||||
.content-sidebar {
|
||||
min-width: 300px;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
@media (min-width: 1536px) {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
&__hero-panel-skeleton {
|
||||
width: 100%;
|
||||
padding: calc(globals.$spacing-unit * 2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: globals.$background-color;
|
||||
height: 72px;
|
||||
border-bottom: solid 1px globals.$border-color;
|
||||
}
|
||||
|
||||
&__cloud-sync-button {
|
||||
padding: calc(globals.$spacing-unit * 1.5) calc(globals.$spacing-unit * 2);
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 8px;
|
||||
transition: all ease 0.2s;
|
||||
cursor: pointer;
|
||||
min-height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: globals.$spacing-unit;
|
||||
color: globals.$muted-color;
|
||||
font-size: globals.$small-font-size;
|
||||
border: solid 1px globals.$border-color;
|
||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.8);
|
||||
animation: slide-in 0.3s cubic-bezier(0.33, 1, 0.68, 1);
|
||||
|
||||
&:active {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: globals.$disabled-opacity;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
&__cloud-icon-container {
|
||||
width: 20px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__cloud-icon {
|
||||
width: 26px;
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
&__reviews-section {
|
||||
margin-top: calc(globals.$spacing-unit * 3);
|
||||
padding-top: calc(globals.$spacing-unit * 3);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
@media (min-width: 1536px) {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
&__reviews-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: calc(globals.$spacing-unit * 2);
|
||||
|
||||
@media (max-width: 768px) {
|
||||
// Hero panel skeleton spacing
|
||||
.hero-panel__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: calc(globals.$spacing-unit * 1.5);
|
||||
}
|
||||
}
|
||||
|
||||
&__reviews-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: globals.$muted-color;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__reviews-title-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: calc(globals.$spacing-unit);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__reviews-badge {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
min-width: 24px;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__leave-review-cta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: calc(globals.$spacing-unit * 0.5);
|
||||
padding: calc(globals.$spacing-unit * 0.75)
|
||||
calc(globals.$spacing-unit * 1.5);
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
globals.$brand-teal,
|
||||
globals.$brand-blue
|
||||
);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
margin-bottom: calc(globals.$spacing-unit);
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(globals.$brand-teal, 0.3);
|
||||
gap: calc(globals.$spacing-unit * 0.5);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
// Review items skeleton spacing
|
||||
.review-item-skeleton {
|
||||
border: 1px solid globals.$border-color;
|
||||
border-radius: 8px;
|
||||
padding: calc(globals.$spacing-unit * 1);
|
||||
margin-bottom: calc(globals.$spacing-unit * 1);
|
||||
}
|
||||
|
||||
svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__review-input-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
background-color: globals.$dark-background-color;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__review-input-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
background-color: globals.$background-color;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
&__review-editor-toolbar {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
&__editor-button {
|
||||
background: none;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
border-radius: 4px;
|
||||
color: #ffffff;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: globals.$brand-blue;
|
||||
border-color: globals.$brand-blue;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&__review-char-counter {
|
||||
font-size: 12px;
|
||||
color: #888888;
|
||||
|
||||
.over-limit {
|
||||
color: #ff6b6b;
|
||||
}
|
||||
}
|
||||
|
||||
&__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;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 8px 0;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
u {
|
||||
text-decoration: underline;
|
||||
}
|
||||
// Sidebar section spacing
|
||||
.sidebar-section-skeleton {
|
||||
margin-bottom: calc(globals.$spacing-unit * 1.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes skeleton-loading {
|
||||
0% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import { Downloader, getDownloadersForUri } from "@shared";
|
||||
import { CloudSyncModal } from "./cloud-sync-modal/cloud-sync-modal";
|
||||
import { CloudSyncFilesModal } from "./cloud-sync-files-modal/cloud-sync-files-modal";
|
||||
import "./game-details.scss";
|
||||
import "./hero.scss";
|
||||
|
||||
export default function GameDetails() {
|
||||
const [randomGame, setRandomGame] = useState<Steam250Game | null>(null);
|
||||
|
||||
116
src/renderer/src/pages/game-details/game-reviews.scss
Normal file
116
src/renderer/src/pages/game-details/game-reviews.scss
Normal file
@@ -0,0 +1,116 @@
|
||||
@use "../../scss/globals.scss";
|
||||
|
||||
.game-details {
|
||||
&__reviews-section {
|
||||
margin-top: calc(globals.$spacing-unit * 3);
|
||||
padding-top: calc(globals.$spacing-unit * 3);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
@media (min-width: 1536px) {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
&__reviews-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: globals.$muted-color;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__reviews-title-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: calc(globals.$spacing-unit);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__reviews-badge {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
min-width: 24px;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__reviews-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(globals.$spacing-unit * 4);
|
||||
}
|
||||
|
||||
&__reviews-separator {
|
||||
height: 1px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
margin: calc(globals.$spacing-unit * 3) 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__reviews-list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: calc(globals.$spacing-unit * 1);
|
||||
}
|
||||
|
||||
&__reviews-empty {
|
||||
text-align: center;
|
||||
padding: calc(globals.$spacing-unit * 4) calc(globals.$spacing-unit * 2);
|
||||
margin-bottom: calc(globals.$spacing-unit * 2);
|
||||
}
|
||||
|
||||
&__reviews-empty-icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: calc(globals.$spacing-unit * 2);
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
&__reviews-empty-title {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-weight: 600;
|
||||
margin: 0 0 calc(globals.$spacing-unit * 1) 0;
|
||||
}
|
||||
|
||||
&__reviews-empty-message {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: globals.$small-font-size;
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
&__reviews-loading {
|
||||
text-align: center;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
padding: calc(globals.$spacing-unit * 2);
|
||||
}
|
||||
|
||||
&__load-more-reviews {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid globals.$border-color;
|
||||
color: globals.$body-color;
|
||||
padding: calc(globals.$spacing-unit * 1) calc(globals.$spacing-unit * 2);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: globals.$body-font-size;
|
||||
font-family: inherit;
|
||||
transition: all 0.2s ease;
|
||||
width: 100%;
|
||||
margin-top: calc(globals.$spacing-unit * 2);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
border-color: globals.$brand-teal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { ReviewForm } from "./review-form";
|
||||
import { ReviewItem } from "./review-item";
|
||||
import { ReviewSortOptions } from "./review-sort-options";
|
||||
import { ReviewPromptBanner } from "./review-prompt-banner";
|
||||
import "./game-reviews.scss";
|
||||
import { useToast } from "@renderer/hooks";
|
||||
|
||||
type ReviewSortOption =
|
||||
@@ -144,8 +145,6 @@ export function GameReviews({
|
||||
}
|
||||
}, [objectId, userDetailsId, shop, game, onUserReviewedChange]);
|
||||
|
||||
console.log("reviews", reviews);
|
||||
|
||||
const loadReviews = useCallback(
|
||||
async (reset = false) => {
|
||||
if (!objectId) return;
|
||||
@@ -440,8 +439,6 @@ export function GameReviews({
|
||||
});
|
||||
}, [reviews]);
|
||||
|
||||
console.log("reviews", reviews);
|
||||
|
||||
return (
|
||||
<div className="game-details__reviews-section">
|
||||
{showReviewPrompt &&
|
||||
|
||||
271
src/renderer/src/pages/game-details/hero.scss
Normal file
271
src/renderer/src/pages/game-details/hero.scss
Normal file
@@ -0,0 +1,271 @@
|
||||
@use "../../scss/globals.scss";
|
||||
|
||||
$hero-height: 350px;
|
||||
|
||||
@keyframes slide-in {
|
||||
0% {
|
||||
transform: translateY(calc(40px + globals.$spacing-unit * 2));
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.game-details {
|
||||
&__hero-panel {
|
||||
padding: globals.$spacing-unit;
|
||||
}
|
||||
|
||||
&__hero {
|
||||
width: 100%;
|
||||
height: $hero-height;
|
||||
min-height: $hero-height;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
transition: all ease 0.2s;
|
||||
|
||||
@media (min-width: 1250px) {
|
||||
height: 350px;
|
||||
min-height: 350px;
|
||||
}
|
||||
}
|
||||
|
||||
&__hero-content {
|
||||
padding: calc(globals.$spacing-unit * 1.5);
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
padding: calc(globals.$spacing-unit * 2);
|
||||
}
|
||||
}
|
||||
|
||||
&__hero-buttons {
|
||||
display: flex;
|
||||
gap: globals.$spacing-unit;
|
||||
align-items: center;
|
||||
|
||||
&--right {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&__edit-custom-game-button {
|
||||
padding: calc(globals.$spacing-unit * 1.5);
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 8px;
|
||||
transition: all ease 0.2s;
|
||||
cursor: pointer;
|
||||
min-height: 40px;
|
||||
min-width: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: globals.$muted-color;
|
||||
border: solid 1px globals.$border-color;
|
||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.8);
|
||||
animation: slide-in 0.3s cubic-bezier(0.33, 1, 0.68, 1);
|
||||
|
||||
&:active {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
color: globals.$body-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__hero-logo-backdrop {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__hero-image-wrapper {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 384px;
|
||||
max-height: 384px;
|
||||
overflow: hidden;
|
||||
border-radius: 0px 0px 8px 8px;
|
||||
z-index: 0;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
rgba(0, 0, 0, 0.3) 60%,
|
||||
transparent 100%
|
||||
);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
@media (min-width: 1250px) {
|
||||
height: calc(350px + 82px);
|
||||
min-height: calc(350px + 84px);
|
||||
}
|
||||
}
|
||||
|
||||
&__hero-image {
|
||||
width: 100%;
|
||||
height: $hero-height;
|
||||
min-height: $hero-height;
|
||||
object-fit: cover;
|
||||
object-position: top;
|
||||
transition: all ease 0.2s;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
border-radius: 0px 0px 8px 8px;
|
||||
|
||||
@media (min-width: 1250px) {
|
||||
object-position: center;
|
||||
height: $hero-height;
|
||||
min-height: $hero-height;
|
||||
}
|
||||
}
|
||||
|
||||
&__game-logo {
|
||||
width: 200px;
|
||||
align-self: flex-end;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
&__game-logo-text {
|
||||
width: 200px;
|
||||
align-self: flex-end;
|
||||
font-size: 1.8rem;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
|
||||
text-align: left;
|
||||
line-height: 1.2;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
hyphens: auto;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
width: 250px;
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
width: 300px;
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
&__cloud-sync-button {
|
||||
padding: calc(globals.$spacing-unit * 1.5) calc(globals.$spacing-unit * 2);
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 8px;
|
||||
transition: all ease 0.2s;
|
||||
cursor: pointer;
|
||||
min-height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: globals.$spacing-unit;
|
||||
color: globals.$muted-color;
|
||||
font-size: globals.$small-font-size;
|
||||
border: solid 1px globals.$border-color;
|
||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.8);
|
||||
animation: slide-in 0.3s cubic-bezier(0.33, 1, 0.68, 1);
|
||||
|
||||
&:active {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: globals.$disabled-opacity;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
&__cloud-icon-container {
|
||||
width: 20px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__cloud-icon {
|
||||
width: 26px;
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
&__randomizer-button {
|
||||
padding: calc(globals.$spacing-unit * 1.5);
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(20px);
|
||||
border-radius: 8px;
|
||||
transition: all ease 0.2s;
|
||||
cursor: pointer;
|
||||
min-height: 40px;
|
||||
min-width: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: globals.$muted-color;
|
||||
border: solid 1px globals.$border-color;
|
||||
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.8);
|
||||
animation: slide-in 0.3s cubic-bezier(0.33, 1, 0.68, 1);
|
||||
|
||||
&:active {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
color: globals.$body-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__stars-icon-container {
|
||||
width: 20px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__stars-icon {
|
||||
width: 26px;
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,18 @@
|
||||
&__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: globals.$spacing-unit;
|
||||
gap: calc(globals.$spacing-unit * 0.5);
|
||||
|
||||
p {
|
||||
font-size: globals.$small-font-size;
|
||||
color: globals.$muted-color;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
|
||||
&:first-child {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__actions {
|
||||
|
||||
@@ -50,25 +50,29 @@ export function HeroPanel() {
|
||||
game?.download?.status === "paused";
|
||||
|
||||
return (
|
||||
<div className="hero-panel">
|
||||
<div className="hero-panel__content">{getInfo()}</div>
|
||||
<div className="hero-panel__actions">
|
||||
<HeroPanelActions />
|
||||
</div>
|
||||
<div className="hero-panel__container">
|
||||
<div className="hero-panel">
|
||||
<div className="hero-panel__content">{getInfo()}</div>
|
||||
<div className="hero-panel__actions">
|
||||
<HeroPanelActions />
|
||||
</div>
|
||||
|
||||
{showProgressBar && (
|
||||
<progress
|
||||
max={1}
|
||||
value={
|
||||
isGameDownloading ? lastPacket?.progress : game?.download?.progress
|
||||
}
|
||||
className={`hero-panel__progress-bar ${
|
||||
game?.download?.status === "paused"
|
||||
? "hero-panel__progress-bar--disabled"
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
{showProgressBar && (
|
||||
<progress
|
||||
max={1}
|
||||
value={
|
||||
isGameDownloading
|
||||
? lastPacket?.progress
|
||||
: game?.download?.progress
|
||||
}
|
||||
className={`hero-panel__progress-bar ${
|
||||
game?.download?.status === "paused"
|
||||
? "hero-panel__progress-bar--disabled"
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
232
src/renderer/src/pages/game-details/review-form.scss
Normal file
232
src/renderer/src/pages/game-details/review-form.scss
Normal file
@@ -0,0 +1,232 @@
|
||||
@use "../../scss/globals.scss";
|
||||
|
||||
.game-details {
|
||||
&__reviews-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: calc(globals.$spacing-unit * 2);
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: calc(globals.$spacing-unit * 1.5);
|
||||
}
|
||||
}
|
||||
|
||||
&__reviews-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: globals.$muted-color;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__review-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
&__review-form-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&__review-score-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
&__review-score-select {
|
||||
background-color: #2a2a2a;
|
||||
border: 1px solid #3a3a3a;
|
||||
border-radius: 4px;
|
||||
color: #ffffff;
|
||||
padding: 6px 12px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
border-color 0.2s ease,
|
||||
background-color 0.2s ease;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&--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;
|
||||
}
|
||||
}
|
||||
|
||||
&__star-rating {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
&__star {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #666666;
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: #ffffff;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
&--filled {
|
||||
color: #ffffff;
|
||||
|
||||
&.game-details__review-score-select--red {
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
&.game-details__review-score-select--yellow {
|
||||
color: #f39c12;
|
||||
}
|
||||
|
||||
&.game-details__review-score-select--green {
|
||||
color: #27ae60;
|
||||
}
|
||||
}
|
||||
|
||||
&--empty {
|
||||
color: #666666;
|
||||
|
||||
&:hover {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
&__review-input-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
background-color: globals.$dark-background-color;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__review-input-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
background-color: globals.$background-color;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
&__review-editor-toolbar {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
&__editor-button {
|
||||
background: none;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
border-radius: 4px;
|
||||
color: #ffffff;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background-color: globals.$brand-blue;
|
||||
border-color: globals.$brand-blue;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&__review-char-counter {
|
||||
font-size: 12px;
|
||||
color: #888888;
|
||||
|
||||
.over-limit {
|
||||
color: #ff6b6b;
|
||||
}
|
||||
}
|
||||
|
||||
&__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;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 8px 0;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
u {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { Star } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { EditorContent, Editor } from "@tiptap/react";
|
||||
import { Button } from "@renderer/components";
|
||||
import "./review-form.scss";
|
||||
|
||||
interface ReviewFormProps {
|
||||
editor: Editor | null;
|
||||
|
||||
@@ -1,6 +1,213 @@
|
||||
@use "../../scss/globals.scss";
|
||||
|
||||
.game-details {
|
||||
&__review-item {
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
&__review-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: calc(globals.$spacing-unit * 1.5);
|
||||
}
|
||||
|
||||
&__review-user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: calc(globals.$spacing-unit * 1);
|
||||
}
|
||||
|
||||
&__review-user-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(globals.$spacing-unit * 0.25);
|
||||
}
|
||||
|
||||
&__review-display-name {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: globals.$small-font-size;
|
||||
font-weight: 600;
|
||||
display: inline-flex;
|
||||
|
||||
&--clickable {
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__review-actions {
|
||||
margin-top: 12px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__review-votes {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__vote-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 6px;
|
||||
padding: 6px 12px;
|
||||
color: #ccc;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
&--active {
|
||||
&.game-details__vote-button--upvote {
|
||||
svg {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
|
||||
&.game-details__vote-button--downvote {
|
||||
svg {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: 500;
|
||||
display: inline-block;
|
||||
min-width: 1ch;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&__delete-review-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(244, 67, 54, 0.1);
|
||||
border: 1px solid rgba(244, 67, 54, 0.3);
|
||||
border-radius: 6px;
|
||||
padding: 6px;
|
||||
color: #f44336;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
gap: 6px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(244, 67, 54, 0.2);
|
||||
border-color: #f44336;
|
||||
color: #ff5722;
|
||||
}
|
||||
}
|
||||
|
||||
&__blocked-review-simple {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: globals.$small-font-size;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: calc(globals.$spacing-unit * 0.5);
|
||||
}
|
||||
|
||||
&__blocked-review-show-link {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #ffc107;
|
||||
font-size: globals.$small-font-size;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
padding: 0;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: #ffeb3b;
|
||||
}
|
||||
}
|
||||
|
||||
&__blocked-review-hide-link {
|
||||
background: none;
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: globals.$small-font-size;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
padding: 0;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
&__review-score-stars {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
&__review-star {
|
||||
color: #666666;
|
||||
transition: color 0.2s ease;
|
||||
cursor: default;
|
||||
|
||||
&--filled {
|
||||
color: #ffffff;
|
||||
|
||||
&.game-details__review-score--red {
|
||||
color: #fca5a5;
|
||||
}
|
||||
|
||||
&.game-details__review-score--yellow {
|
||||
color: #fcd34d;
|
||||
}
|
||||
|
||||
&.game-details__review-score--green {
|
||||
color: #86efac;
|
||||
}
|
||||
}
|
||||
|
||||
&--empty {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
&__review-date {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
font-size: globals.$small-font-size;
|
||||
}
|
||||
|
||||
&__review-content {
|
||||
color: globals.$body-color;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&__review-translation-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user