@xsolla/xui-game-card 0.151.0 → 0.152.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/native/index.d.mts +24 -3
- package/native/index.d.ts +24 -3
- package/native/index.js +297 -202
- package/native/index.js.map +1 -1
- package/native/index.mjs +298 -203
- package/native/index.mjs.map +1 -1
- package/package.json +3 -3
- package/web/index.d.mts +24 -3
- package/web/index.d.ts +24 -3
- package/web/index.js +297 -202
- package/web/index.js.map +1 -1
- package/web/index.mjs +298 -203
- package/web/index.mjs.map +1 -1
package/native/index.d.mts
CHANGED
|
@@ -2,21 +2,34 @@ import React from 'react';
|
|
|
2
2
|
import { ThemeOverrideProps } from '@xsolla/xui-core';
|
|
3
3
|
|
|
4
4
|
type GameCardSize = "lg" | "md" | "sm";
|
|
5
|
+
type GameCardImageRatio = "16:9" | "1:1" | "2:3" | "3:2" | "4:3" | "9:16" | "custom";
|
|
6
|
+
type GameCardLayout = "horizontal" | "vertical";
|
|
7
|
+
type GameCardPlatform = "mobile" | "desktop";
|
|
5
8
|
interface GameCardProps extends ThemeOverrideProps {
|
|
6
|
-
/** Game artwork image URL */
|
|
7
|
-
image
|
|
9
|
+
/** Game artwork image URL. When omitted, a placeholder is rendered. */
|
|
10
|
+
image?: string;
|
|
8
11
|
/** Game title */
|
|
9
12
|
title: string;
|
|
10
13
|
/** Game subtitle (e.g., genre tags) */
|
|
11
14
|
subtitle?: string;
|
|
12
15
|
/** Size variant of the card */
|
|
13
16
|
size?: GameCardSize;
|
|
17
|
+
/** Aspect ratio of the image area (default "16:9") */
|
|
18
|
+
imageRatio?: GameCardImageRatio;
|
|
19
|
+
/** Custom width for the image area when imageRatio is "custom" */
|
|
20
|
+
customImageWidth?: number;
|
|
21
|
+
/** Custom height for the image area when imageRatio is "custom" */
|
|
22
|
+
customImageHeight?: number;
|
|
14
23
|
/** Custom badge element displayed above tags on the image (top-left corner) */
|
|
15
24
|
badge?: React.ReactNode;
|
|
16
25
|
/** Custom content for top-left corner tags */
|
|
17
26
|
tagsTopLeft?: React.ReactNode;
|
|
18
27
|
/** Custom content for top-right corner tags */
|
|
19
28
|
tagsTopRight?: React.ReactNode;
|
|
29
|
+
/** Custom content for bottom-left corner tags */
|
|
30
|
+
tagsBottomLeft?: React.ReactNode;
|
|
31
|
+
/** Custom content for bottom-right corner tags */
|
|
32
|
+
tagsBottomRight?: React.ReactNode;
|
|
20
33
|
/** Custom trailing content (button, price, etc.) - overrides buttonText if provided */
|
|
21
34
|
trailing?: React.ReactNode;
|
|
22
35
|
/** Button label text (used if trailing is not provided) */
|
|
@@ -25,6 +38,14 @@ interface GameCardProps extends ThemeOverrideProps {
|
|
|
25
38
|
onButtonClick?: () => void;
|
|
26
39
|
/** Whether the button is disabled (used if trailing is not provided) */
|
|
27
40
|
buttonDisabled?: boolean;
|
|
41
|
+
/** Footer layout direction (default "horizontal") */
|
|
42
|
+
layout?: GameCardLayout;
|
|
43
|
+
/** Platform variant affecting footer spacing (default "mobile") */
|
|
44
|
+
platform?: GameCardPlatform;
|
|
45
|
+
/** When true, hides the footer (title/subtitle/button area) entirely. Useful for image-only cards like XWP presets. */
|
|
46
|
+
hideFooter?: boolean;
|
|
47
|
+
/** Hover overlay content rendered at the bottom of the image area on hover */
|
|
48
|
+
hoverContent?: React.ReactNode;
|
|
28
49
|
/** Card click handler */
|
|
29
50
|
onPress?: () => void;
|
|
30
51
|
/** Alt text for game image */
|
|
@@ -35,4 +56,4 @@ interface GameCardProps extends ThemeOverrideProps {
|
|
|
35
56
|
|
|
36
57
|
declare const GameCard: React.FC<GameCardProps>;
|
|
37
58
|
|
|
38
|
-
export { GameCard, type GameCardProps, type GameCardSize };
|
|
59
|
+
export { GameCard, type GameCardImageRatio, type GameCardLayout, type GameCardPlatform, type GameCardProps, type GameCardSize };
|
package/native/index.d.ts
CHANGED
|
@@ -2,21 +2,34 @@ import React from 'react';
|
|
|
2
2
|
import { ThemeOverrideProps } from '@xsolla/xui-core';
|
|
3
3
|
|
|
4
4
|
type GameCardSize = "lg" | "md" | "sm";
|
|
5
|
+
type GameCardImageRatio = "16:9" | "1:1" | "2:3" | "3:2" | "4:3" | "9:16" | "custom";
|
|
6
|
+
type GameCardLayout = "horizontal" | "vertical";
|
|
7
|
+
type GameCardPlatform = "mobile" | "desktop";
|
|
5
8
|
interface GameCardProps extends ThemeOverrideProps {
|
|
6
|
-
/** Game artwork image URL */
|
|
7
|
-
image
|
|
9
|
+
/** Game artwork image URL. When omitted, a placeholder is rendered. */
|
|
10
|
+
image?: string;
|
|
8
11
|
/** Game title */
|
|
9
12
|
title: string;
|
|
10
13
|
/** Game subtitle (e.g., genre tags) */
|
|
11
14
|
subtitle?: string;
|
|
12
15
|
/** Size variant of the card */
|
|
13
16
|
size?: GameCardSize;
|
|
17
|
+
/** Aspect ratio of the image area (default "16:9") */
|
|
18
|
+
imageRatio?: GameCardImageRatio;
|
|
19
|
+
/** Custom width for the image area when imageRatio is "custom" */
|
|
20
|
+
customImageWidth?: number;
|
|
21
|
+
/** Custom height for the image area when imageRatio is "custom" */
|
|
22
|
+
customImageHeight?: number;
|
|
14
23
|
/** Custom badge element displayed above tags on the image (top-left corner) */
|
|
15
24
|
badge?: React.ReactNode;
|
|
16
25
|
/** Custom content for top-left corner tags */
|
|
17
26
|
tagsTopLeft?: React.ReactNode;
|
|
18
27
|
/** Custom content for top-right corner tags */
|
|
19
28
|
tagsTopRight?: React.ReactNode;
|
|
29
|
+
/** Custom content for bottom-left corner tags */
|
|
30
|
+
tagsBottomLeft?: React.ReactNode;
|
|
31
|
+
/** Custom content for bottom-right corner tags */
|
|
32
|
+
tagsBottomRight?: React.ReactNode;
|
|
20
33
|
/** Custom trailing content (button, price, etc.) - overrides buttonText if provided */
|
|
21
34
|
trailing?: React.ReactNode;
|
|
22
35
|
/** Button label text (used if trailing is not provided) */
|
|
@@ -25,6 +38,14 @@ interface GameCardProps extends ThemeOverrideProps {
|
|
|
25
38
|
onButtonClick?: () => void;
|
|
26
39
|
/** Whether the button is disabled (used if trailing is not provided) */
|
|
27
40
|
buttonDisabled?: boolean;
|
|
41
|
+
/** Footer layout direction (default "horizontal") */
|
|
42
|
+
layout?: GameCardLayout;
|
|
43
|
+
/** Platform variant affecting footer spacing (default "mobile") */
|
|
44
|
+
platform?: GameCardPlatform;
|
|
45
|
+
/** When true, hides the footer (title/subtitle/button area) entirely. Useful for image-only cards like XWP presets. */
|
|
46
|
+
hideFooter?: boolean;
|
|
47
|
+
/** Hover overlay content rendered at the bottom of the image area on hover */
|
|
48
|
+
hoverContent?: React.ReactNode;
|
|
28
49
|
/** Card click handler */
|
|
29
50
|
onPress?: () => void;
|
|
30
51
|
/** Alt text for game image */
|
|
@@ -35,4 +56,4 @@ interface GameCardProps extends ThemeOverrideProps {
|
|
|
35
56
|
|
|
36
57
|
declare const GameCard: React.FC<GameCardProps>;
|
|
37
58
|
|
|
38
|
-
export { GameCard, type GameCardProps, type GameCardSize };
|
|
59
|
+
export { GameCard, type GameCardImageRatio, type GameCardLayout, type GameCardPlatform, type GameCardProps, type GameCardSize };
|
package/native/index.js
CHANGED
|
@@ -34,6 +34,9 @@ __export(index_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
|
+
// src/GameCard.tsx
|
|
38
|
+
var import_react2 = require("react");
|
|
39
|
+
|
|
37
40
|
// ../../foundation/primitives-native/src/Box.tsx
|
|
38
41
|
var import_react_native = require("react-native");
|
|
39
42
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -381,76 +384,77 @@ var isWeb = false;
|
|
|
381
384
|
// src/GameCard.tsx
|
|
382
385
|
var import_xui_core = require("@xsolla/xui-core");
|
|
383
386
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
384
|
-
var
|
|
387
|
+
var IMAGE_RATIOS = {
|
|
388
|
+
"16:9": 240 / 135,
|
|
389
|
+
"1:1": 1,
|
|
390
|
+
"2:3": 240 / 360,
|
|
391
|
+
"3:2": 240 / 160,
|
|
392
|
+
"4:3": 360 / 270,
|
|
393
|
+
"9:16": 135 / 240
|
|
394
|
+
};
|
|
395
|
+
var BORDER_RADIUS = 8;
|
|
396
|
+
var TAG_INSET = 8;
|
|
397
|
+
var TAG_GAP = 4;
|
|
398
|
+
var getSizeConfig = (size, platform) => {
|
|
399
|
+
const isDesktop = platform === "desktop";
|
|
385
400
|
switch (size) {
|
|
386
401
|
case "lg":
|
|
387
402
|
return {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
subtitleLineHeight: 18,
|
|
393
|
-
padding: 8,
|
|
394
|
-
footerPadding: 12,
|
|
395
|
-
footerGap: 12,
|
|
396
|
-
tagGap: 4,
|
|
397
|
-
buttonHeight: 32,
|
|
398
|
-
buttonPaddingX: 20,
|
|
399
|
-
buttonFontSize: 12,
|
|
400
|
-
buttonLineHeight: 14,
|
|
401
|
-
borderRadius: 8,
|
|
402
|
-
fadeHeight: 64
|
|
403
|
+
titleFontSize: isDesktop ? 16 : 14,
|
|
404
|
+
titleLineHeight: isDesktop ? 20 : 18,
|
|
405
|
+
subtitleFontSize: isDesktop ? 12 : 11,
|
|
406
|
+
subtitleLineHeight: isDesktop ? 18 : 14
|
|
403
407
|
};
|
|
404
408
|
case "md":
|
|
405
409
|
return {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
subtitleLineHeight: 16,
|
|
411
|
-
padding: 6,
|
|
412
|
-
footerPadding: 8,
|
|
413
|
-
footerGap: 8,
|
|
414
|
-
tagGap: 3,
|
|
415
|
-
buttonHeight: 28,
|
|
416
|
-
buttonPaddingX: 16,
|
|
417
|
-
buttonFontSize: 11,
|
|
418
|
-
buttonLineHeight: 13,
|
|
419
|
-
borderRadius: 8,
|
|
420
|
-
fadeHeight: 48
|
|
410
|
+
titleFontSize: isDesktop ? 16 : 14,
|
|
411
|
+
titleLineHeight: isDesktop ? 20 : 18,
|
|
412
|
+
subtitleFontSize: isDesktop ? 12 : 11,
|
|
413
|
+
subtitleLineHeight: isDesktop ? 18 : 14
|
|
421
414
|
};
|
|
422
415
|
case "sm":
|
|
423
416
|
return {
|
|
424
|
-
imageAspectRatio: 200 / 113,
|
|
425
417
|
titleFontSize: 12,
|
|
426
418
|
titleLineHeight: 16,
|
|
427
419
|
subtitleFontSize: 10,
|
|
428
|
-
subtitleLineHeight: 14
|
|
429
|
-
padding: 4,
|
|
430
|
-
footerPadding: 6,
|
|
431
|
-
footerGap: 6,
|
|
432
|
-
tagGap: 2,
|
|
433
|
-
buttonHeight: 24,
|
|
434
|
-
buttonPaddingX: 12,
|
|
435
|
-
buttonFontSize: 10,
|
|
436
|
-
buttonLineHeight: 12,
|
|
437
|
-
borderRadius: 8,
|
|
438
|
-
fadeHeight: 32
|
|
420
|
+
subtitleLineHeight: 14
|
|
439
421
|
};
|
|
440
422
|
}
|
|
441
423
|
};
|
|
424
|
+
var getFooterPadding = (platform) => platform === "desktop" ? 16 : 12;
|
|
425
|
+
var getFooterGap = () => 12;
|
|
426
|
+
var resolveAspectRatio = (imageRatio, customWidth, customHeight) => {
|
|
427
|
+
if (imageRatio === "custom" && customWidth && customHeight) {
|
|
428
|
+
return customWidth / customHeight;
|
|
429
|
+
}
|
|
430
|
+
return IMAGE_RATIOS[imageRatio] ?? IMAGE_RATIOS["16:9"];
|
|
431
|
+
};
|
|
432
|
+
var ellipsisStyle = isWeb ? {
|
|
433
|
+
overflow: "hidden",
|
|
434
|
+
textOverflow: "ellipsis",
|
|
435
|
+
whiteSpace: "nowrap"
|
|
436
|
+
} : void 0;
|
|
442
437
|
var GameCard = ({
|
|
443
438
|
image,
|
|
444
439
|
title,
|
|
445
440
|
subtitle,
|
|
446
441
|
size = "lg",
|
|
442
|
+
imageRatio = "16:9",
|
|
443
|
+
customImageWidth,
|
|
444
|
+
customImageHeight,
|
|
447
445
|
badge,
|
|
448
446
|
tagsTopLeft,
|
|
449
447
|
tagsTopRight,
|
|
448
|
+
tagsBottomLeft,
|
|
449
|
+
tagsBottomRight,
|
|
450
450
|
trailing,
|
|
451
451
|
buttonText,
|
|
452
452
|
onButtonClick,
|
|
453
453
|
buttonDisabled,
|
|
454
|
+
layout = "horizontal",
|
|
455
|
+
platform = "mobile",
|
|
456
|
+
hideFooter = false,
|
|
457
|
+
hoverContent,
|
|
454
458
|
onPress,
|
|
455
459
|
imageAlt,
|
|
456
460
|
className,
|
|
@@ -458,8 +462,247 @@ var GameCard = ({
|
|
|
458
462
|
themeProductContext
|
|
459
463
|
}) => {
|
|
460
464
|
const { theme } = (0, import_xui_core.useResolvedTheme)({ themeMode, themeProductContext });
|
|
461
|
-
const config = getSizeConfig(size);
|
|
465
|
+
const config = getSizeConfig(size, platform);
|
|
466
|
+
const footerPadding = getFooterPadding(platform);
|
|
467
|
+
const footerGap = getFooterGap();
|
|
468
|
+
const aspectRatio = resolveAspectRatio(
|
|
469
|
+
imageRatio,
|
|
470
|
+
customImageWidth,
|
|
471
|
+
customImageHeight
|
|
472
|
+
);
|
|
473
|
+
const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
|
|
462
474
|
const wrapperProps = onPress ? { onPress } : {};
|
|
475
|
+
const hoverHandlers = isWeb && hoverContent ? {
|
|
476
|
+
onMouseEnter: () => setIsHovered(true),
|
|
477
|
+
onMouseLeave: () => setIsHovered(false)
|
|
478
|
+
} : {};
|
|
479
|
+
const isHorizontal = layout === "horizontal";
|
|
480
|
+
const renderPlaceholder = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
481
|
+
Box,
|
|
482
|
+
{
|
|
483
|
+
width: "100%",
|
|
484
|
+
height: "100%",
|
|
485
|
+
backgroundColor: theme.colors.background.secondary,
|
|
486
|
+
alignItems: "center",
|
|
487
|
+
justifyContent: "center",
|
|
488
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
489
|
+
Box,
|
|
490
|
+
{
|
|
491
|
+
width: imageRatio === "16:9" || imageRatio === "9:16" || imageRatio === "custom" ? 48 : 56,
|
|
492
|
+
height: imageRatio === "16:9" || imageRatio === "9:16" || imageRatio === "custom" ? 48 : 56,
|
|
493
|
+
alignItems: "center",
|
|
494
|
+
justifyContent: "center",
|
|
495
|
+
style: { opacity: 0.4 },
|
|
496
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
497
|
+
Text,
|
|
498
|
+
{
|
|
499
|
+
color: theme.colors.content.tertiary,
|
|
500
|
+
fontSize: 24,
|
|
501
|
+
style: { textAlign: "center" },
|
|
502
|
+
children: "\u{1F5BC}"
|
|
503
|
+
}
|
|
504
|
+
)
|
|
505
|
+
}
|
|
506
|
+
)
|
|
507
|
+
}
|
|
508
|
+
);
|
|
509
|
+
const renderImage = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
510
|
+
Box,
|
|
511
|
+
{
|
|
512
|
+
position: "relative",
|
|
513
|
+
width: "100%",
|
|
514
|
+
overflow: "hidden",
|
|
515
|
+
style: { aspectRatio },
|
|
516
|
+
...hoverHandlers,
|
|
517
|
+
children: [
|
|
518
|
+
image ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
519
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
520
|
+
Box,
|
|
521
|
+
{
|
|
522
|
+
as: "img",
|
|
523
|
+
src: image,
|
|
524
|
+
alt: imageAlt || title,
|
|
525
|
+
position: "absolute",
|
|
526
|
+
top: 0,
|
|
527
|
+
left: 0,
|
|
528
|
+
width: "100%",
|
|
529
|
+
height: "100%",
|
|
530
|
+
style: isWeb ? {
|
|
531
|
+
objectFit: "cover",
|
|
532
|
+
pointerEvents: "none"
|
|
533
|
+
} : void 0
|
|
534
|
+
}
|
|
535
|
+
),
|
|
536
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
537
|
+
LinearGradient,
|
|
538
|
+
{
|
|
539
|
+
colors: ["transparent", "rgba(0, 0, 0, 0.48)"],
|
|
540
|
+
start: { x: 0, y: 0 },
|
|
541
|
+
end: { x: 0, y: 1 },
|
|
542
|
+
position: "absolute",
|
|
543
|
+
bottom: 0,
|
|
544
|
+
left: 0,
|
|
545
|
+
right: 0,
|
|
546
|
+
height: "100%",
|
|
547
|
+
style: { maxHeight: 206 }
|
|
548
|
+
}
|
|
549
|
+
)
|
|
550
|
+
] }) : renderPlaceholder(),
|
|
551
|
+
(badge || tagsTopLeft) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
552
|
+
Box,
|
|
553
|
+
{
|
|
554
|
+
position: "absolute",
|
|
555
|
+
top: TAG_INSET,
|
|
556
|
+
left: TAG_INSET,
|
|
557
|
+
flexDirection: "column",
|
|
558
|
+
gap: TAG_GAP,
|
|
559
|
+
alignItems: "flex-start",
|
|
560
|
+
children: [
|
|
561
|
+
badge,
|
|
562
|
+
tagsTopLeft
|
|
563
|
+
]
|
|
564
|
+
}
|
|
565
|
+
),
|
|
566
|
+
tagsTopRight && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
567
|
+
Box,
|
|
568
|
+
{
|
|
569
|
+
position: "absolute",
|
|
570
|
+
top: TAG_INSET,
|
|
571
|
+
right: TAG_INSET,
|
|
572
|
+
flexDirection: "column",
|
|
573
|
+
gap: TAG_GAP,
|
|
574
|
+
alignItems: "flex-end",
|
|
575
|
+
children: tagsTopRight
|
|
576
|
+
}
|
|
577
|
+
),
|
|
578
|
+
tagsBottomLeft && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
579
|
+
Box,
|
|
580
|
+
{
|
|
581
|
+
position: "absolute",
|
|
582
|
+
bottom: TAG_INSET,
|
|
583
|
+
left: TAG_INSET,
|
|
584
|
+
flexDirection: "column",
|
|
585
|
+
gap: TAG_GAP,
|
|
586
|
+
alignItems: "flex-start",
|
|
587
|
+
children: tagsBottomLeft
|
|
588
|
+
}
|
|
589
|
+
),
|
|
590
|
+
tagsBottomRight && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
591
|
+
Box,
|
|
592
|
+
{
|
|
593
|
+
position: "absolute",
|
|
594
|
+
bottom: TAG_INSET,
|
|
595
|
+
right: TAG_INSET,
|
|
596
|
+
flexDirection: "column",
|
|
597
|
+
gap: TAG_GAP,
|
|
598
|
+
alignItems: "flex-end",
|
|
599
|
+
children: tagsBottomRight
|
|
600
|
+
}
|
|
601
|
+
),
|
|
602
|
+
isWeb && hoverContent && isHovered && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
603
|
+
Box,
|
|
604
|
+
{
|
|
605
|
+
position: "absolute",
|
|
606
|
+
bottom: 0,
|
|
607
|
+
left: 0,
|
|
608
|
+
right: 0,
|
|
609
|
+
height: 72,
|
|
610
|
+
flexDirection: "row",
|
|
611
|
+
alignItems: "center",
|
|
612
|
+
gap: 8,
|
|
613
|
+
padding: 16,
|
|
614
|
+
borderRadius: 4,
|
|
615
|
+
overflow: "hidden",
|
|
616
|
+
style: {
|
|
617
|
+
backdropFilter: "blur(15px)",
|
|
618
|
+
WebkitBackdropFilter: "blur(15px)",
|
|
619
|
+
backgroundColor: theme.colors.layer.float
|
|
620
|
+
},
|
|
621
|
+
children: hoverContent
|
|
622
|
+
}
|
|
623
|
+
)
|
|
624
|
+
]
|
|
625
|
+
}
|
|
626
|
+
);
|
|
627
|
+
const renderFooter = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
628
|
+
Box,
|
|
629
|
+
{
|
|
630
|
+
backgroundColor: theme.colors.overlay.mono,
|
|
631
|
+
padding: footerPadding,
|
|
632
|
+
flexDirection: isHorizontal ? "row" : "column",
|
|
633
|
+
alignItems: isHorizontal ? "center" : "flex-start",
|
|
634
|
+
justifyContent: isHorizontal ? void 0 : "center",
|
|
635
|
+
gap: footerGap,
|
|
636
|
+
children: [
|
|
637
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
638
|
+
Box,
|
|
639
|
+
{
|
|
640
|
+
flex: isHorizontal ? 1 : void 0,
|
|
641
|
+
width: isHorizontal ? void 0 : "100%",
|
|
642
|
+
flexDirection: "column",
|
|
643
|
+
style: { minWidth: 0 },
|
|
644
|
+
children: [
|
|
645
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
646
|
+
Text,
|
|
647
|
+
{
|
|
648
|
+
color: theme.colors.content.primary,
|
|
649
|
+
fontSize: config.titleFontSize,
|
|
650
|
+
lineHeight: config.titleLineHeight,
|
|
651
|
+
fontWeight: "500",
|
|
652
|
+
numberOfLines: 1,
|
|
653
|
+
style: ellipsisStyle,
|
|
654
|
+
children: title
|
|
655
|
+
}
|
|
656
|
+
),
|
|
657
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
658
|
+
Text,
|
|
659
|
+
{
|
|
660
|
+
color: theme.colors.content.tertiary,
|
|
661
|
+
fontSize: config.subtitleFontSize,
|
|
662
|
+
lineHeight: config.subtitleLineHeight,
|
|
663
|
+
fontWeight: "400",
|
|
664
|
+
numberOfLines: 1,
|
|
665
|
+
style: ellipsisStyle,
|
|
666
|
+
children: subtitle
|
|
667
|
+
}
|
|
668
|
+
)
|
|
669
|
+
]
|
|
670
|
+
}
|
|
671
|
+
),
|
|
672
|
+
trailing,
|
|
673
|
+
!trailing && buttonText && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
674
|
+
Box,
|
|
675
|
+
{
|
|
676
|
+
onPress: buttonDisabled ? void 0 : onButtonClick,
|
|
677
|
+
backgroundColor: theme.colors.control.mono.secondary.bg,
|
|
678
|
+
borderRadius: BORDER_RADIUS,
|
|
679
|
+
height: 40,
|
|
680
|
+
paddingHorizontal: 20,
|
|
681
|
+
alignItems: "center",
|
|
682
|
+
justifyContent: "center",
|
|
683
|
+
style: isWeb ? {
|
|
684
|
+
opacity: buttonDisabled ? 0.4 : 1,
|
|
685
|
+
backdropFilter: "blur(30px)",
|
|
686
|
+
WebkitBackdropFilter: "blur(30px)",
|
|
687
|
+
border: `1px solid ${theme.colors.control.mono.secondary.border}`,
|
|
688
|
+
cursor: buttonDisabled ? "not-allowed" : onButtonClick ? "pointer" : "default"
|
|
689
|
+
} : { opacity: buttonDisabled ? 0.4 : 1 },
|
|
690
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
691
|
+
Text,
|
|
692
|
+
{
|
|
693
|
+
color: theme.colors.control.mono.text.secondary,
|
|
694
|
+
fontSize: 14,
|
|
695
|
+
lineHeight: 18,
|
|
696
|
+
fontWeight: "500",
|
|
697
|
+
style: { letterSpacing: 0.4 },
|
|
698
|
+
children: buttonText
|
|
699
|
+
}
|
|
700
|
+
)
|
|
701
|
+
}
|
|
702
|
+
)
|
|
703
|
+
]
|
|
704
|
+
}
|
|
705
|
+
);
|
|
463
706
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
464
707
|
Box,
|
|
465
708
|
{
|
|
@@ -470,170 +713,22 @@ var GameCard = ({
|
|
|
470
713
|
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
471
714
|
Box,
|
|
472
715
|
{
|
|
473
|
-
|
|
474
|
-
borderRadius: config.borderRadius,
|
|
716
|
+
borderRadius: BORDER_RADIUS,
|
|
475
717
|
overflow: "hidden",
|
|
476
718
|
flexDirection: "column",
|
|
477
719
|
style: isWeb ? {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
720
|
+
borderRadius: `${BORDER_RADIUS}px`,
|
|
721
|
+
overflow: "hidden",
|
|
722
|
+
border: `1px solid ${theme.colors.border.secondary}`
|
|
481
723
|
} : {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
elevation: 4,
|
|
487
|
-
borderRadius: config.borderRadius,
|
|
488
|
-
overflow: "hidden"
|
|
724
|
+
borderRadius: BORDER_RADIUS,
|
|
725
|
+
overflow: "hidden",
|
|
726
|
+
borderWidth: 1,
|
|
727
|
+
borderColor: theme.colors.border.secondary
|
|
489
728
|
},
|
|
490
729
|
children: [
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
{
|
|
494
|
-
position: "relative",
|
|
495
|
-
width: "100%",
|
|
496
|
-
overflow: "hidden",
|
|
497
|
-
style: {
|
|
498
|
-
aspectRatio: config.imageAspectRatio,
|
|
499
|
-
borderTopLeftRadius: config.borderRadius,
|
|
500
|
-
borderTopRightRadius: config.borderRadius
|
|
501
|
-
},
|
|
502
|
-
children: [
|
|
503
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
504
|
-
Box,
|
|
505
|
-
{
|
|
506
|
-
as: "img",
|
|
507
|
-
src: image,
|
|
508
|
-
alt: imageAlt || title,
|
|
509
|
-
position: "absolute",
|
|
510
|
-
top: 0,
|
|
511
|
-
left: 0,
|
|
512
|
-
width: "100%",
|
|
513
|
-
height: "100%",
|
|
514
|
-
style: isWeb ? { objectFit: "cover" } : void 0
|
|
515
|
-
}
|
|
516
|
-
),
|
|
517
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
518
|
-
LinearGradient,
|
|
519
|
-
{
|
|
520
|
-
colors: ["transparent", "rgba(0, 0, 0, 0.48)"],
|
|
521
|
-
start: { x: 0, y: 0 },
|
|
522
|
-
end: { x: 0, y: 1 },
|
|
523
|
-
position: "absolute",
|
|
524
|
-
bottom: 0,
|
|
525
|
-
left: 0,
|
|
526
|
-
right: 0,
|
|
527
|
-
height: config.fadeHeight
|
|
528
|
-
}
|
|
529
|
-
),
|
|
530
|
-
(badge || tagsTopLeft) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
531
|
-
Box,
|
|
532
|
-
{
|
|
533
|
-
position: "absolute",
|
|
534
|
-
top: config.padding,
|
|
535
|
-
left: config.padding,
|
|
536
|
-
flexDirection: "column",
|
|
537
|
-
gap: config.tagGap,
|
|
538
|
-
alignItems: "flex-start",
|
|
539
|
-
children: [
|
|
540
|
-
badge,
|
|
541
|
-
tagsTopLeft
|
|
542
|
-
]
|
|
543
|
-
}
|
|
544
|
-
),
|
|
545
|
-
tagsTopRight && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
546
|
-
Box,
|
|
547
|
-
{
|
|
548
|
-
position: "absolute",
|
|
549
|
-
top: config.padding,
|
|
550
|
-
right: config.padding,
|
|
551
|
-
flexDirection: "column",
|
|
552
|
-
gap: config.tagGap,
|
|
553
|
-
alignItems: "flex-end",
|
|
554
|
-
children: tagsTopRight
|
|
555
|
-
}
|
|
556
|
-
)
|
|
557
|
-
]
|
|
558
|
-
}
|
|
559
|
-
),
|
|
560
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
561
|
-
Box,
|
|
562
|
-
{
|
|
563
|
-
backgroundColor: theme.colors.overlay.mono,
|
|
564
|
-
padding: config.footerPadding,
|
|
565
|
-
flexDirection: "row",
|
|
566
|
-
alignItems: "center",
|
|
567
|
-
gap: config.footerGap,
|
|
568
|
-
children: [
|
|
569
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Box, { flex: 1, flexDirection: "column", style: { minWidth: 0 }, children: [
|
|
570
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
571
|
-
Text,
|
|
572
|
-
{
|
|
573
|
-
color: theme.colors.content.primary,
|
|
574
|
-
fontSize: config.titleFontSize,
|
|
575
|
-
lineHeight: config.titleLineHeight,
|
|
576
|
-
fontWeight: "500",
|
|
577
|
-
numberOfLines: 1,
|
|
578
|
-
style: isWeb ? {
|
|
579
|
-
overflow: "hidden",
|
|
580
|
-
textOverflow: "ellipsis",
|
|
581
|
-
whiteSpace: "nowrap"
|
|
582
|
-
} : void 0,
|
|
583
|
-
children: title
|
|
584
|
-
}
|
|
585
|
-
),
|
|
586
|
-
subtitle && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
587
|
-
Text,
|
|
588
|
-
{
|
|
589
|
-
color: theme.colors.content.tertiary,
|
|
590
|
-
fontSize: config.subtitleFontSize,
|
|
591
|
-
lineHeight: config.subtitleLineHeight,
|
|
592
|
-
fontWeight: "400",
|
|
593
|
-
numberOfLines: 1,
|
|
594
|
-
style: isWeb ? {
|
|
595
|
-
overflow: "hidden",
|
|
596
|
-
textOverflow: "ellipsis",
|
|
597
|
-
whiteSpace: "nowrap"
|
|
598
|
-
} : void 0,
|
|
599
|
-
children: subtitle
|
|
600
|
-
}
|
|
601
|
-
)
|
|
602
|
-
] }),
|
|
603
|
-
trailing,
|
|
604
|
-
!trailing && buttonText && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
605
|
-
Box,
|
|
606
|
-
{
|
|
607
|
-
onPress: buttonDisabled ? void 0 : onButtonClick,
|
|
608
|
-
backgroundColor: theme.colors.control.mono.secondary.bg,
|
|
609
|
-
borderRadius: config.borderRadius,
|
|
610
|
-
height: config.buttonHeight,
|
|
611
|
-
paddingHorizontal: config.buttonPaddingX,
|
|
612
|
-
alignItems: "center",
|
|
613
|
-
justifyContent: "center",
|
|
614
|
-
opacity: buttonDisabled ? 0.4 : 1,
|
|
615
|
-
style: isWeb ? {
|
|
616
|
-
backdropFilter: "blur(30px)",
|
|
617
|
-
WebkitBackdropFilter: "blur(30px)",
|
|
618
|
-
border: `1px solid ${theme.colors.control.mono.secondary.border}`,
|
|
619
|
-
cursor: buttonDisabled ? "not-allowed" : onButtonClick ? "pointer" : "default"
|
|
620
|
-
} : void 0,
|
|
621
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
622
|
-
Text,
|
|
623
|
-
{
|
|
624
|
-
color: theme.colors.control.mono.text.secondary,
|
|
625
|
-
fontSize: config.buttonFontSize,
|
|
626
|
-
lineHeight: config.buttonLineHeight,
|
|
627
|
-
fontWeight: "500",
|
|
628
|
-
letterSpacing: 0.4,
|
|
629
|
-
children: buttonText
|
|
630
|
-
}
|
|
631
|
-
)
|
|
632
|
-
}
|
|
633
|
-
)
|
|
634
|
-
]
|
|
635
|
-
}
|
|
636
|
-
)
|
|
730
|
+
renderImage(),
|
|
731
|
+
!hideFooter && renderFooter()
|
|
637
732
|
]
|
|
638
733
|
}
|
|
639
734
|
)
|