mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-03-09 15:40:26 +00:00
Merge pull request #1462 from hydralauncher/feat/improve-theming
Feat/improve theming
This commit is contained in:
commit
92ac5b0d1a
4 changed files with 36 additions and 54 deletions
|
@ -57,7 +57,7 @@ export class WindowManager {
|
|||
trafficLightPosition: { x: 16, y: 16 },
|
||||
titleBarOverlay: {
|
||||
symbolColor: "#DADBE1",
|
||||
color: "#151515",
|
||||
color: "#00000000",
|
||||
height: 34,
|
||||
},
|
||||
webPreferences: {
|
||||
|
|
|
@ -16,13 +16,8 @@ import { useUserDetails } from "@renderer/hooks";
|
|||
import { useSubscription } from "@renderer/hooks/use-subscription";
|
||||
import "./game-details.scss";
|
||||
|
||||
const HERO_HEIGHT = 300;
|
||||
const HERO_ANIMATION_THRESHOLD = 25;
|
||||
|
||||
export function GameDetailsContent() {
|
||||
const heroRef = useRef<HTMLDivElement | null>(null);
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const [isHeaderStuck, setIsHeaderStuck] = useState(false);
|
||||
|
||||
const { t } = useTranslation("game_details");
|
||||
|
||||
|
@ -61,7 +56,7 @@ export function GameDetailsContent() {
|
|||
return t("no_shop_details");
|
||||
}, [shopDetails, t]);
|
||||
|
||||
const [backdropOpactiy, setBackdropOpacity] = useState(1);
|
||||
const [backdropOpacity, setBackdropOpacity] = useState(1);
|
||||
|
||||
const handleHeroLoad = async () => {
|
||||
const output = await average(steamUrlBuilder.libraryHero(objectId!), {
|
||||
|
@ -80,26 +75,6 @@ export function GameDetailsContent() {
|
|||
setBackdropOpacity(1);
|
||||
}, [objectId]);
|
||||
|
||||
const onScroll: React.UIEventHandler<HTMLElement> = (event) => {
|
||||
const heroHeight = heroRef.current?.clientHeight ?? HERO_HEIGHT;
|
||||
|
||||
const scrollY = (event.target as HTMLDivElement).scrollTop;
|
||||
const opacity = Math.max(
|
||||
0,
|
||||
1 - scrollY / (heroHeight - HERO_ANIMATION_THRESHOLD)
|
||||
);
|
||||
|
||||
if (scrollY >= heroHeight && !isHeaderStuck) {
|
||||
setIsHeaderStuck(true);
|
||||
}
|
||||
|
||||
if (scrollY <= heroHeight && isHeaderStuck) {
|
||||
setIsHeaderStuck(false);
|
||||
}
|
||||
|
||||
setBackdropOpacity(opacity);
|
||||
};
|
||||
|
||||
const handleCloudSaveButtonClick = () => {
|
||||
if (!userDetails) {
|
||||
window.electron.openAuthWindow(AuthPage.SignIn);
|
||||
|
@ -122,31 +97,25 @@ export function GameDetailsContent() {
|
|||
<div
|
||||
className={`game-details__wrapper ${hasNSFWContentBlocked ? "game-details__wrapper--blurred" : ""}`}
|
||||
>
|
||||
<img
|
||||
src={steamUrlBuilder.libraryHero(objectId!)}
|
||||
className="game-details__hero-image"
|
||||
alt={game?.title}
|
||||
onLoad={handleHeroLoad}
|
||||
/>
|
||||
|
||||
<section
|
||||
ref={containerRef}
|
||||
onScroll={onScroll}
|
||||
className="game-details__container"
|
||||
>
|
||||
<section className="game-details__container">
|
||||
<div ref={heroRef} className="game-details__hero">
|
||||
<img
|
||||
src={steamUrlBuilder.libraryHero(objectId!)}
|
||||
className="game-details__hero-image"
|
||||
alt={game?.title}
|
||||
onLoad={handleHeroLoad}
|
||||
/>
|
||||
<div
|
||||
className="game-details__hero-backdrop"
|
||||
style={{
|
||||
backgroundColor: gameColor,
|
||||
flex: 1,
|
||||
opacity: Math.min(1, 1 - backdropOpactiy),
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
className="game-details__hero-logo-backdrop"
|
||||
style={{ opacity: backdropOpactiy }}
|
||||
style={{ opacity: backdropOpacity }}
|
||||
>
|
||||
<div className="game-details__hero-content">
|
||||
<img
|
||||
|
@ -173,7 +142,7 @@ export function GameDetailsContent() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<HeroPanel isHeaderStuck={isHeaderStuck} />
|
||||
<HeroPanel />
|
||||
|
||||
<div className="game-details__description-container">
|
||||
<div className="game-details__description-content">
|
||||
|
|
|
@ -9,11 +9,7 @@ import { HeroPanelPlaytime } from "./hero-panel-playtime";
|
|||
import { gameDetailsContext } from "@renderer/context";
|
||||
import "./hero-panel.scss";
|
||||
|
||||
export interface HeroPanelProps {
|
||||
isHeaderStuck: boolean;
|
||||
}
|
||||
|
||||
export function HeroPanel({ isHeaderStuck }: HeroPanelProps) {
|
||||
export function HeroPanel() {
|
||||
const { t } = useTranslation("game_details");
|
||||
|
||||
const { formatDate } = useDate();
|
||||
|
@ -54,10 +50,7 @@ export function HeroPanel({ isHeaderStuck }: HeroPanelProps) {
|
|||
game?.download?.status === "paused";
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{ backgroundColor: gameColor }}
|
||||
className={`hero-panel ${isHeaderStuck ? "hero-panel--stuck" : ""}`}
|
||||
>
|
||||
<div style={{ backgroundColor: gameColor }} className="hero-panel">
|
||||
<div className="hero-panel__content">{getInfo()}</div>
|
||||
<div className="hero-panel__actions">
|
||||
<HeroPanelActions />
|
||||
|
|
|
@ -4,6 +4,7 @@ import { ThemeActions, ThemeCard, ThemePlaceholder } from "./index";
|
|||
import type { Theme } from "@types";
|
||||
import { ImportThemeModal } from "./modals/import-theme-modal";
|
||||
import { settingsContext } from "@renderer/context";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
interface SettingsAppearanceProps {
|
||||
appearance: {
|
||||
|
@ -24,8 +25,10 @@ export function SettingsAppearance({
|
|||
authorId: string;
|
||||
authorName: string;
|
||||
} | null>(null);
|
||||
const [hasShownModal, setHasShownModal] = useState(false);
|
||||
|
||||
const { clearTheme } = useContext(settingsContext);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const loadThemes = useCallback(async () => {
|
||||
const themesList = await window.electron.getAllCustomThemes();
|
||||
|
@ -45,20 +48,37 @@ export function SettingsAppearance({
|
|||
}, [loadThemes]);
|
||||
|
||||
useEffect(() => {
|
||||
if (appearance.theme && appearance.authorId && appearance.authorName) {
|
||||
if (
|
||||
appearance.theme &&
|
||||
appearance.authorId &&
|
||||
appearance.authorName &&
|
||||
!hasShownModal
|
||||
) {
|
||||
setIsImportThemeModalVisible(true);
|
||||
setImportTheme({
|
||||
theme: appearance.theme,
|
||||
authorId: appearance.authorId,
|
||||
authorName: appearance.authorName,
|
||||
});
|
||||
setHasShownModal(true);
|
||||
|
||||
navigate("/settings", { replace: true });
|
||||
clearTheme();
|
||||
}
|
||||
}, [appearance.theme, appearance.authorId, appearance.authorName]);
|
||||
}, [
|
||||
appearance.theme,
|
||||
appearance.authorId,
|
||||
appearance.authorName,
|
||||
navigate,
|
||||
hasShownModal,
|
||||
clearTheme,
|
||||
]);
|
||||
|
||||
const onThemeImported = useCallback(() => {
|
||||
setIsImportThemeModalVisible(false);
|
||||
setImportTheme(null);
|
||||
loadThemes();
|
||||
}, [clearTheme, loadThemes]);
|
||||
}, [loadThemes]);
|
||||
|
||||
return (
|
||||
<div className="settings-appearance">
|
||||
|
|
Loading…
Add table
Reference in a new issue