This commit is contained in:
Nate 2025-01-18 18:45:54 -03:00
parent d50bb137e6
commit ee0e314b29
9 changed files with 148 additions and 121 deletions

View File

@ -7,7 +7,7 @@
"featured": "Destaques",
"hot": "Populares",
"weekly": "📅 Mais baixados da semana",
"achievements": "🏆 Pra platinar",
"achievements": "🏆 Para platinar",
"surprise_me": "Surpreenda-me",
"no_results": "Nenhum resultado encontrado",
"start_typing": "Comece a digitar para pesquisar…"

View File

@ -29,16 +29,15 @@
border-color: vars.$danger-color;
}
&__focused {
&--focused {
border-color: vars.$search-border-color-focused;
}
&:not(&--focused):hover {
border-color: vars.$search-border-color-hover;
}
}
.text-field__input {
&__input {
background-color: transparent;
border: none;
width: 100%;
@ -57,19 +56,20 @@
&__read-only {
text-overflow: inherit;
}
}
}
.text-field__toggle-password-button {
&__toggle-password-button {
cursor: pointer;
color: vars.$muted-color;
padding: vars.$spacing-unit;
}
}
.text-field__wrapper {
&__wrapper {
display: flex;
gap: vars.$spacing-unit;
}
}
.text-field__error-label {
&__error-label {
color: vars.$danger-color;
}
}

View File

@ -1,7 +1,6 @@
import React, { useId, useMemo, useState } from "react";
import { EyeClosedIcon, EyeIcon } from "@primer/octicons-react";
import { useTranslation } from "react-i18next";
import cn from "classnames";
import "./text-field.scss";
@ -42,9 +41,7 @@ export const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
) => {
const id = useId();
const [isFocused, setIsFocused] = useState(false);
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
const { t } = useTranslation("forms");
const showPasswordToggleButton = props.type === "password";
@ -57,7 +54,7 @@ export const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
const hintContent = useMemo(() => {
if (error && typeof error === "object" && "message" in error)
return (
<small className="text-field-container__error-label">
<small className="text-field__error-label">
{error.message as string}
</small>
);
@ -82,24 +79,19 @@ export const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
<div className="text-field-container" {...containerProps}>
{label && <label htmlFor={id}>{label}</label>}
<div className="text-field-container__text-field-wrapper">
<div className="text-field__wrapper">
<div
className={cn(
"text-field-container__text-field",
`text-field-container__text-field--${theme}`,
{
"text-field-container__text-field__has-error": hasError,
"text-field-container__text-field__focused": isFocused,
}
)}
className={cn("text-field", `text-field__${theme}`, {
"text-field__has-error": hasError,
"text-field--focused": isFocused,
})}
{...textFieldProps}
>
<input
ref={ref}
id={id}
className={cn("text-field-container__text-field-input", {
"text-field-container__text-field-input__read-only":
props.readOnly,
className={cn("text-field__input", {
"text-field__input__read-only": props.readOnly,
})}
{...props}
onFocus={handleFocus}
@ -110,7 +102,7 @@ export const TextField = React.forwardRef<HTMLInputElement, TextFieldProps>(
{showPasswordToggleButton && (
<button
type="button"
className="text-field-container__toggle-password-button"
className="text-field__toggle-password-button"
onClick={() => setIsPasswordVisible(!isPasswordVisible)}
aria-label={t("toggle_password_visibility")}
>

View File

@ -76,7 +76,7 @@ export default function Achievements() {
(otherUserId && comparedAchievements === null);
return (
<SkeletonTheme baseColor="#1c1c1c" highlightColor="#444">
<SkeletonTheme baseColor="var(--background-color)" highlightColor="#444">
{showSkeleton ? (
<AchievementsSkeleton />
) : (

View File

@ -3,7 +3,7 @@
.sidebar-section {
&__button {
height: 72px;
padding: #{vars.$spacing-unit * 2};
padding: #{vars.$spacing-unit * 2} #{vars.$spacing-unit * 2};
display: flex;
align-items: center;
background-color: vars.$background-color;

View File

@ -31,7 +31,7 @@ export function SidebarSection({ title, children }: SidebarSectionProps) {
>
<ChevronDownIcon
className={classNames("chevron", {
"chevron--open": isOpen,
"sidebar-section__chevron--open": isOpen,
})}
/>
<span>{title}</span>

View File

@ -40,7 +40,7 @@ export function HowLongToBeatSection({
className="sidebar__how-long-to-beat-category"
>
<p
className="sidebar__how-long-to-beat-category"
className="sidebar__how-long-to-beat-category-label"
style={{
fontWeight: "bold",
}}
@ -48,7 +48,7 @@ export function HowLongToBeatSection({
{category.title}
</p>
<p className="sidebar__how-long-to-beat-category">
<p className="sidebar__how-long-to-beat-category-label">
{getDuration(category.duration)}
</p>

View File

@ -31,86 +31,53 @@
width: 100%;
}
&__requirements-details {
padding: #{vars.$spacing-unit * 2};
&__requirement-details {
padding: vars.$spacing-unit * 2;
line-height: 22px;
font-size: 16px;
a {
display: flex;
color: vars.$body-color;
}
}
&__requirements-details-skeleton {
&__requirement-details-skeleton {
display: flex;
flex-direction: column;
gap: 8px;
padding: #{vars.$spacing-unit * 2};
font-size: 16px;
padding: vars.$spacing-unit * 2;
}
&__how-long-to-beat-categories-list {
margin: 0;
padding: #{vars.$spacing-unit * 2};
display: flex;
flex-direction: column;
gap: 16px;
}
&__how-long-to-beat-category {
display: flex;
flex-direction: column;
gap: 4px;
background: linear-gradient(
90deg,
transparent 20%,
rgb(255 255 255 / 2%) 100%
);
border-radius: 4px;
padding: 8px 16px;
border: solid 1px vars.$border-color;
}
&__how-long-to-beat-category-label {
color: vars.$muted-color;
}
&__how-long-to-beat-category-skeleton {
border: solid 1px vars.$border-color;
border-radius: 4px;
height: 76px;
}
&__stats-section {
display: flex;
gap: #{vars.$spacing-unit * 2};
padding: #{vars.$spacing-unit * 2};
justify-content: space-between;
transition: max-height ease 0.5s;
overflow: hidden;
&__achievements-content {
border-left: solid 1px vars.$border-color;
background-color: vars.$dark-background-color;
width: 100%;
height: 100%;
@media (min-width: 1024px) {
flex-direction: column;
max-width: 300px;
width: 100%;
}
@media (min-width: 1280px) {
flex-direction: row;
width: 100%;
max-width: 400px;
}
}
&__stats-category-title {
font-size: 14px;
font-weight: bold;
display: flex;
align-items: center;
gap: vars.$spacing-unit;
}
&__stats-category {
&__overlay {
min-height: 100%;
inset: 0;
position: absolute;
display: flex;
flex-direction: column;
gap: calc(vars.$spacing-unit / 2);
align-items: center;
justify-content: center;
gap: vars.$spacing-unit;
color: vars.$muted-color;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
z-index: 1;
text-align: center;
}
&__list {
@ -120,6 +87,11 @@
flex-direction: column;
gap: #{vars.$spacing-unit * 2};
padding: #{vars.$spacing-unit * 2};
position: relative;
&--blurred {
filter: blur(3px);
}
}
&__list-item {
@ -148,8 +120,43 @@
object-fit: cover;
&--unlocked {
filter: grayscale(100%);
filter: grayscale(0%);
}
&--blurred {
filter: blur(1px);
}
}
&__stats-section {
display: flex;
gap: vars.$spacing-unit;
padding: vars.$spacing-unit * 2;
justify-content: space-between;
transition: max-height ease 0.5s;
overflow: hidden;
@media (min-width: 1024px) {
flex-direction: column;
}
@media (min-width: 1280px) {
flex-direction: row;
}
}
&__stats-category-title {
font-size: vars.$body-font-size;
font-weight: bold;
display: flex;
align-items: center;
gap: vars.$spacing-unit;
}
&__stats-category {
display: flex;
flex-direction: column;
gap: vars.$spacing-unit;
}
&__subscription-required-button {
@ -165,4 +172,32 @@
text-decoration: underline;
}
}
&__how-long-to-beat-category {
display: flex;
flex-direction: column;
gap: 4px;
background: linear-gradient(90deg, transparent 20%, rgba(255, 255, 255, 0.2) 100%);
border-radius: 4px;
padding: 8px 16px;
border: solid 1px vars.$border-color;
}
&__how-long-to-beat-category-skeleton {
border: solid 1px vars.$border-color;
border-radius: 4px;
height: 76px;
}
&__how-long-to-beat-categories-list {
margin: 0;
padding: calc(vars.$spacing-unit * 2);
display: flex;
flex-direction: column;
gap: 16px
}
&__how-long-to-beat-category-label {
color: vars.$muted-color;
}
}

View File

@ -119,7 +119,7 @@ export function Sidebar() {
}, [objectId, shop, gameTitle]);
return (
<aside className="sidebar__content">
<aside className="sidebar__achievements-content">
{userDetails === null && (
<SidebarSection title={t("achievements")}>
<div className="sidebar__overlay">
@ -182,8 +182,8 @@ export function Sidebar() {
title={achievement.description}
>
<img
className={classNames("achievements__list-item-image", {
"achievements__list-item-image--unlocked":
className={classNames("sidebar__list-item-image", {
"sidebar__list-item-image--unlocked":
achievement.unlocked,
})}
src={achievement.icon}
@ -261,7 +261,7 @@ export function Sidebar() {
</div>
<div
className="sidebar__requirements-details"
className="sidebar__requirement-details"
dangerouslySetInnerHTML={{
__html:
shopDetails?.pc_requirements?.[activeRequirement] ??