Skip to content

Commit df0df6a

Browse files
authored
Enhance layout and visual design of game card info section (#305)
* style(GameCard): enhance layout and visual design of game card info section * fix(SettingsPage): adjust maximum poster size from 150 to 135 * fix(GameCard): move game title to the bottom of the game card info section
1 parent 1047d43 commit df0df6a

3 files changed

Lines changed: 62 additions & 43 deletions

File tree

opennow-stable/src/renderer/src/components/GameCard.tsx

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -248,48 +248,48 @@ export const GameCard = memo(function GameCard({
248248
<Play size={24} fill="currentColor" />
249249
</button>
250250
</div>
251-
</div>
252251

253-
<div className="game-card-info">
254-
<h3 className="game-card-title" title={game.title}>
255-
{game.title}
256-
</h3>
257-
{activeStoreOption && (
258-
<p className="game-card-platform" title={activeStoreOption.displayName}>
259-
{activeStoreOption.displayName}
260-
</p>
261-
)}
262-
{storeOptions.length > 0 && (
263-
<div className="game-card-stores">
264-
{storeOptions.map((store) => {
265-
const isActive = store.variantId === activeVariantId;
266-
const className = `game-card-store-chip ${isActive ? "active" : ""}`;
267-
const title = `${store.displayName}${isActive ? " (selected)" : ""}`;
252+
<div className="game-card-info">
253+
{activeStoreOption && (
254+
<p className="game-card-platform" title={activeStoreOption.displayName}>
255+
{activeStoreOption.displayName}
256+
</p>
257+
)}
258+
{storeOptions.length > 0 && (
259+
<div className="game-card-stores">
260+
{storeOptions.map((store) => {
261+
const isActive = store.variantId === activeVariantId;
262+
const className = `game-card-store-chip ${isActive ? "active" : ""}`;
263+
const title = `${store.displayName}${isActive ? " (selected)" : ""}`;
264+
265+
if (onSelectStore) {
266+
return (
267+
<button
268+
key={store.storeKey}
269+
type="button"
270+
className={className}
271+
title={title}
272+
onClick={(event) => handleStoreClick(event, store.variantId)}
273+
aria-label={`${store.displayName} store`}
274+
aria-pressed={isActive}
275+
>
276+
<store.IconComponent />
277+
</button>
278+
);
279+
}
268280

269-
if (onSelectStore) {
270281
return (
271-
<button
272-
key={store.storeKey}
273-
type="button"
274-
className={className}
275-
title={title}
276-
onClick={(event) => handleStoreClick(event, store.variantId)}
277-
aria-label={`${store.displayName} store`}
278-
aria-pressed={isActive}
279-
>
282+
<span key={store.storeKey} className={className} title={title}>
280283
<store.IconComponent />
281-
</button>
284+
</span>
282285
);
283-
}
284-
285-
return (
286-
<span key={store.storeKey} className={className} title={title}>
287-
<store.IconComponent />
288-
</span>
289-
);
290-
})}
291-
</div>
292-
)}
286+
})}
287+
</div>
288+
)}
289+
<h3 className="game-card-title" title={game.title}>
290+
{game.title}
291+
</h3>
292+
</div>
293293
</div>
294294
</div>
295295
);

opennow-stable/src/renderer/src/components/SettingsPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type ThanksLoadState = "idle" | "loading" | "loaded" | "error";
4040
type SettingsSectionId = "stream" | "game" | "audio" | "input" | "interface" | "thanks";
4141

4242
const POSTER_SIZE_MIN = 75;
43-
const POSTER_SIZE_MAX = 150;
43+
const POSTER_SIZE_MAX = 135;
4444
const POSTER_SIZE_STEP = 5;
4545

4646
const codecOptions: VideoCodec[] = [...USER_FACING_VIDEO_CODEC_OPTIONS];

opennow-stable/src/renderer/src/styles.css

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,6 +1866,7 @@ body.controller-mode.controller-hide-cursor * {
18661866
overflow: hidden;
18671867
background: var(--bg-c);
18681868
backface-visibility: hidden;
1869+
flex: 1;
18691870
}
18701871

18711872
.game-card-image {
@@ -1908,7 +1909,7 @@ body.controller-mode.controller-hide-cursor * {
19081909
.game-card-gradient {
19091910
position: absolute;
19101911
inset: 0;
1911-
background: linear-gradient(to bottom, transparent 20%, rgba(10, 10, 12, 0.8) 100%);
1912+
background: linear-gradient(to bottom, transparent 30%, rgba(10, 10, 12, 0.72) 60%, rgba(10, 10, 12, 0.92) 100%);
19121913
}
19131914

19141915
.game-card-play-button {
@@ -1933,30 +1934,48 @@ body.controller-mode.controller-hide-cursor * {
19331934
background: var(--accent-press);
19341935
}
19351936

1936-
/* Card info (bottom section) */
1937+
/* Card info — overlaid at the bottom of the poster */
19371938
.game-card-info {
1939+
position: absolute;
1940+
inset: auto 0 0 0;
19381941
padding: 10px 12px;
19391942
display: flex;
19401943
flex-direction: column;
1941-
gap: 6px;
1944+
gap: 5px;
1945+
z-index: 2;
1946+
pointer-events: none;
1947+
}
1948+
1949+
.game-card-info::before {
1950+
content: "";
1951+
position: absolute;
1952+
inset: -80px 0 0 0;
1953+
background: linear-gradient(to bottom, transparent 0%, rgba(6, 8, 7, 0.6) 50%, rgba(6, 8, 7, 0.88) 100%);
1954+
pointer-events: none;
1955+
z-index: -1;
1956+
}
1957+
1958+
.game-card-info .game-card-stores {
1959+
pointer-events: auto;
19421960
}
19431961

19441962
.game-card-title {
19451963
margin: 0;
19461964
font-size: 0.8rem;
19471965
font-weight: 600;
1948-
color: var(--ink);
1966+
color: #fff;
19491967
white-space: nowrap;
19501968
overflow: hidden;
19511969
text-overflow: ellipsis;
19521970
line-height: 1.3;
1971+
text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
19531972
}
19541973

19551974
.game-card-platform {
19561975
margin: 0;
19571976
font-size: 0.72rem;
19581977
font-weight: 500;
1959-
color: var(--ink-muted);
1978+
color: rgba(255, 255, 255, 0.65);
19601979
white-space: nowrap;
19611980
overflow: hidden;
19621981
text-overflow: ellipsis;

0 commit comments

Comments
 (0)