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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -31,86 +31,53 @@
width: 100%; width: 100%;
} }
&__requirements-details { &__requirement-details {
padding: #{vars.$spacing-unit * 2}; padding: vars.$spacing-unit * 2;
line-height: 22px; line-height: 22px;
font-size: 16px; font-size: 16px;
a {
display: flex;
color: vars.$body-color;
}
} }
&__requirements-details-skeleton { &__requirement-details-skeleton {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 8px;
padding: #{vars.$spacing-unit * 2}; padding: vars.$spacing-unit * 2;
font-size: 16px;
} }
&__how-long-to-beat-categories-list { &__achievements-content {
margin: 0; border-left: solid 1px vars.$border-color;
padding: #{vars.$spacing-unit * 2}; background-color: vars.$dark-background-color;
display: flex; width: 100%;
flex-direction: column; height: 100%;
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;
@media (min-width: 1024px) { @media (min-width: 1024px) {
flex-direction: column; max-width: 300px;
width: 100%;
} }
@media (min-width: 1280px) { @media (min-width: 1280px) {
flex-direction: row; width: 100%;
max-width: 400px;
} }
} }
&__stats-category-title { &__overlay {
font-size: 14px; min-height: 100%;
font-weight: bold; inset: 0;
display: flex; position: absolute;
align-items: center;
gap: vars.$spacing-unit;
}
&__stats-category {
display: flex; display: flex;
flex-direction: column; 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 { &__list {
@ -120,6 +87,11 @@
flex-direction: column; flex-direction: column;
gap: #{vars.$spacing-unit * 2}; gap: #{vars.$spacing-unit * 2};
padding: #{vars.$spacing-unit * 2}; padding: #{vars.$spacing-unit * 2};
position: relative;
&--blurred {
filter: blur(3px);
}
} }
&__list-item { &__list-item {
@ -148,8 +120,43 @@
object-fit: cover; object-fit: cover;
&--unlocked { &--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 { &__subscription-required-button {
@ -165,4 +172,32 @@
text-decoration: underline; 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]); }, [objectId, shop, gameTitle]);
return ( return (
<aside className="sidebar__content"> <aside className="sidebar__achievements-content">
{userDetails === null && ( {userDetails === null && (
<SidebarSection title={t("achievements")}> <SidebarSection title={t("achievements")}>
<div className="sidebar__overlay"> <div className="sidebar__overlay">
@ -182,8 +182,8 @@ export function Sidebar() {
title={achievement.description} title={achievement.description}
> >
<img <img
className={classNames("achievements__list-item-image", { className={classNames("sidebar__list-item-image", {
"achievements__list-item-image--unlocked": "sidebar__list-item-image--unlocked":
achievement.unlocked, achievement.unlocked,
})} })}
src={achievement.icon} src={achievement.icon}
@ -261,7 +261,7 @@ export function Sidebar() {
</div> </div>
<div <div
className="sidebar__requirements-details" className="sidebar__requirement-details"
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: __html:
shopDetails?.pc_requirements?.[activeRequirement] ?? shopDetails?.pc_requirements?.[activeRequirement] ??