@freegamestore/games 0.3.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/dist/GameButton.d.ts +21 -0
- package/dist/GameButton.d.ts.map +1 -0
- package/dist/GameButton.js +57 -0
- package/dist/GameButton.js.map +1 -0
- package/dist/GameShell.d.ts +26 -0
- package/dist/GameShell.d.ts.map +1 -0
- package/dist/GameShell.js +45 -0
- package/dist/GameShell.js.map +1 -0
- package/dist/GameTopbar.d.ts +43 -0
- package/dist/GameTopbar.d.ts.map +1 -0
- package/dist/GameTopbar.js +50 -0
- package/dist/GameTopbar.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
export type GameButtonVariant = 'primary' | 'secondary' | 'ghost';
|
|
4
|
+
export type GameButtonSize = 'sm' | 'md' | 'lg';
|
|
5
|
+
export interface GameButtonProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
/** Visual style. Default: 'primary'. */
|
|
8
|
+
variant?: GameButtonVariant;
|
|
9
|
+
/** Touch-target size. Default: 'md'. All sizes meet the 44px minimum. */
|
|
10
|
+
size?: GameButtonSize;
|
|
11
|
+
onClick?: () => void;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Full width. */
|
|
14
|
+
block?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Prescribed game button. Touch-friendly (min 44px target), brand-consistent
|
|
18
|
+
* styling. Three variants, three sizes — all opinionated, nothing custom.
|
|
19
|
+
*/
|
|
20
|
+
export declare function GameButton({ children, variant, size, onClick, disabled, block, }: GameButtonProps): React.JSX.Element;
|
|
21
|
+
//# sourceMappingURL=GameButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameButton.d.ts","sourceRoot":"","sources":["../src/GameButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AAClE,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,SAAS,CAAC;IACpB,wCAAwC;IACxC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,yEAAyE;IACzE,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kBAAkB;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAQD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,OAAmB,EACnB,IAAW,EACX,OAAO,EACP,QAAgB,EAChB,KAAa,GACd,EAAE,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA0DrC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
const SIZE = {
|
|
3
|
+
sm: { minHeight: '2.75rem', padding: '0.5rem 1rem', fontSize: '0.85rem', borderRadius: '0.625rem' },
|
|
4
|
+
md: { minHeight: '3rem', padding: '0.625rem 1.25rem', fontSize: '0.9rem', borderRadius: '0.75rem' },
|
|
5
|
+
lg: { minHeight: '3.5rem', padding: '0.75rem 1.75rem', fontSize: '1rem', borderRadius: '0.875rem' },
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Prescribed game button. Touch-friendly (min 44px target), brand-consistent
|
|
9
|
+
* styling. Three variants, three sizes — all opinionated, nothing custom.
|
|
10
|
+
*/
|
|
11
|
+
export function GameButton({ children, variant = 'primary', size = 'md', onClick, disabled = false, block = false, }) {
|
|
12
|
+
const s = SIZE[size];
|
|
13
|
+
const base = {
|
|
14
|
+
display: block ? 'flex' : 'inline-flex',
|
|
15
|
+
width: block ? '100%' : undefined,
|
|
16
|
+
alignItems: 'center',
|
|
17
|
+
justifyContent: 'center',
|
|
18
|
+
gap: '0.5rem',
|
|
19
|
+
minHeight: s.minHeight,
|
|
20
|
+
padding: s.padding,
|
|
21
|
+
fontSize: s.fontSize,
|
|
22
|
+
fontFamily: '"Manrope", system-ui, sans-serif',
|
|
23
|
+
fontWeight: 700,
|
|
24
|
+
lineHeight: 1,
|
|
25
|
+
borderRadius: s.borderRadius,
|
|
26
|
+
border: 'none',
|
|
27
|
+
cursor: disabled ? 'default' : 'pointer',
|
|
28
|
+
opacity: disabled ? 0.4 : 1,
|
|
29
|
+
transition: 'transform 120ms ease, opacity 120ms ease',
|
|
30
|
+
WebkitTapHighlightColor: 'transparent',
|
|
31
|
+
touchAction: 'manipulation',
|
|
32
|
+
};
|
|
33
|
+
const variantStyles = {
|
|
34
|
+
primary: {
|
|
35
|
+
background: 'var(--accent, #10b981)',
|
|
36
|
+
color: '#fff',
|
|
37
|
+
},
|
|
38
|
+
secondary: {
|
|
39
|
+
background: 'var(--panel, #f5f3f0)',
|
|
40
|
+
color: 'var(--ink, #1a1a1a)',
|
|
41
|
+
boxShadow: 'inset 0 0 0 1px var(--line, #e5e5e5)',
|
|
42
|
+
},
|
|
43
|
+
ghost: {
|
|
44
|
+
background: 'transparent',
|
|
45
|
+
color: 'var(--muted, #6b7280)',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
return (_jsx("button", { style: { ...base, ...variantStyles[variant] }, onClick: disabled ? undefined : onClick, disabled: disabled, onPointerDown: (e) => {
|
|
49
|
+
if (!disabled)
|
|
50
|
+
e.currentTarget.style.transform = 'scale(0.96)';
|
|
51
|
+
}, onPointerUp: (e) => {
|
|
52
|
+
e.currentTarget.style.transform = '';
|
|
53
|
+
}, onPointerLeave: (e) => {
|
|
54
|
+
e.currentTarget.style.transform = '';
|
|
55
|
+
}, children: children }));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=GameButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameButton.js","sourceRoot":"","sources":["../src/GameButton.tsx"],"names":[],"mappings":";AAkBA,MAAM,IAAI,GAA2G;IACnH,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE;IACnG,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE;IACnG,EAAE,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE;CACpG,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,EACzB,QAAQ,EACR,OAAO,GAAG,SAAS,EACnB,IAAI,GAAG,IAAI,EACX,OAAO,EACP,QAAQ,GAAG,KAAK,EAChB,KAAK,GAAG,KAAK,GACG;IAChB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IAErB,MAAM,IAAI,GAAwB;QAChC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa;QACvC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QACjC,UAAU,EAAE,QAAQ;QACpB,cAAc,EAAE,QAAQ;QACxB,GAAG,EAAE,QAAQ;QACb,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,UAAU,EAAE,kCAAkC;QAC9C,UAAU,EAAE,GAAG;QACf,UAAU,EAAE,CAAC;QACb,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACxC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3B,UAAU,EAAE,0CAA0C;QACtD,uBAAuB,EAAE,aAAa;QACtC,WAAW,EAAE,cAAc;KAC5B,CAAC;IAEF,MAAM,aAAa,GAAmD;QACpE,OAAO,EAAE;YACP,UAAU,EAAE,wBAAwB;YACpC,KAAK,EAAE,MAAM;SACd;QACD,SAAS,EAAE;YACT,UAAU,EAAE,uBAAuB;YACnC,KAAK,EAAE,qBAAqB;YAC5B,SAAS,EAAE,sCAAsC;SAClD;QACD,KAAK,EAAE;YACL,UAAU,EAAE,aAAa;YACzB,KAAK,EAAE,uBAAuB;SAC/B;KACF,CAAC;IAEF,OAAO,CACL,iBACE,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,aAAa,CAAC,OAAO,CAAC,EAAE,EAC7C,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EACvC,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE;YACnB,IAAI,CAAC,QAAQ;gBAAG,CAAC,CAAC,aAA6B,CAAC,KAAK,CAAC,SAAS,GAAG,aAAa,CAAC;QAClF,CAAC,EACD,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE;YAChB,CAAC,CAAC,aAA6B,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC;QACxD,CAAC,EACD,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE;YACnB,CAAC,CAAC,aAA6B,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC;QACxD,CAAC,YAEA,QAAQ,GACF,CACV,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
export interface GameShellProps {
|
|
4
|
+
/**
|
|
5
|
+
* Optional top bar — typically `<GameTopbar score={…} />`. Renders
|
|
6
|
+
* above the play area in a fixed-height row.
|
|
7
|
+
*/
|
|
8
|
+
topbar?: ReactNode;
|
|
9
|
+
/** The game itself. Sized to fill the remaining viewport. */
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Brand-consistent layout for a game.
|
|
14
|
+
*
|
|
15
|
+
* Hard guarantees:
|
|
16
|
+
* - Outer wrapper is exactly 100svh tall, full-width — no body scroll.
|
|
17
|
+
* - The play area fills whatever's left after the topbar — never larger.
|
|
18
|
+
* - `overflow: hidden` on the wrapper means a game's internal overflow
|
|
19
|
+
* can't bleed out and create document-level scroll.
|
|
20
|
+
*
|
|
21
|
+
* Why 100svh (small viewport units) and not 100vh: on iOS Safari, 100vh
|
|
22
|
+
* includes the URL bar's hidden area, which lets content overflow when
|
|
23
|
+
* the bar reveals. 100svh stays equal to the *visible* viewport.
|
|
24
|
+
*/
|
|
25
|
+
export declare function GameShell({ topbar, children }: GameShellProps): React.JSX.Element;
|
|
26
|
+
//# sourceMappingURL=GameShell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameShell.d.ts","sourceRoot":"","sources":["../src/GameShell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,6DAA6D;IAC7D,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA8CjF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Brand-consistent layout for a game.
|
|
4
|
+
*
|
|
5
|
+
* Hard guarantees:
|
|
6
|
+
* - Outer wrapper is exactly 100svh tall, full-width — no body scroll.
|
|
7
|
+
* - The play area fills whatever's left after the topbar — never larger.
|
|
8
|
+
* - `overflow: hidden` on the wrapper means a game's internal overflow
|
|
9
|
+
* can't bleed out and create document-level scroll.
|
|
10
|
+
*
|
|
11
|
+
* Why 100svh (small viewport units) and not 100vh: on iOS Safari, 100vh
|
|
12
|
+
* includes the URL bar's hidden area, which lets content overflow when
|
|
13
|
+
* the bar reveals. 100svh stays equal to the *visible* viewport.
|
|
14
|
+
*/
|
|
15
|
+
export function GameShell({ topbar, children }) {
|
|
16
|
+
return (_jsxs("div", { style: {
|
|
17
|
+
position: 'fixed',
|
|
18
|
+
inset: 0,
|
|
19
|
+
display: 'flex',
|
|
20
|
+
flexDirection: 'column',
|
|
21
|
+
background: 'var(--paper)',
|
|
22
|
+
color: 'var(--ink)',
|
|
23
|
+
overflow: 'hidden',
|
|
24
|
+
// 100svh handles iOS URL-bar height changes correctly.
|
|
25
|
+
height: '100svh',
|
|
26
|
+
width: '100vw',
|
|
27
|
+
// Games are touch-first — prevent text selection, long-press menus,
|
|
28
|
+
// and the 300ms tap delay that makes games feel sluggish.
|
|
29
|
+
WebkitUserSelect: 'none',
|
|
30
|
+
userSelect: 'none',
|
|
31
|
+
WebkitTouchCallout: 'none',
|
|
32
|
+
touchAction: 'manipulation',
|
|
33
|
+
}, children: [topbar !== undefined && (_jsx("div", { style: {
|
|
34
|
+
flexShrink: 0,
|
|
35
|
+
borderBottom: '1px solid var(--line, #e5e5e5)',
|
|
36
|
+
background: 'var(--panel, var(--paper))',
|
|
37
|
+
}, children: topbar })), _jsx("div", { style: {
|
|
38
|
+
flex: 1,
|
|
39
|
+
minHeight: 0,
|
|
40
|
+
minWidth: 0,
|
|
41
|
+
position: 'relative',
|
|
42
|
+
overflow: 'hidden',
|
|
43
|
+
}, children: children })] }));
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=GameShell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameShell.js","sourceRoot":"","sources":["../src/GameShell.tsx"],"names":[],"mappings":";AAaA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAkB;IAC5D,OAAO,CACL,eACE,KAAK,EAAE;YACL,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC;YACR,OAAO,EAAE,MAAM;YACf,aAAa,EAAE,QAAQ;YACvB,UAAU,EAAE,cAAc;YAC1B,KAAK,EAAE,YAAY;YACnB,QAAQ,EAAE,QAAQ;YAClB,uDAAuD;YACvD,MAAM,EAAE,QAAQ;YAChB,KAAK,EAAE,OAAO;YACd,oEAAoE;YACpE,0DAA0D;YAC1D,gBAAgB,EAAE,MAAM;YACxB,UAAU,EAAE,MAAM;YAClB,kBAAkB,EAAE,MAAM;YAC1B,WAAW,EAAE,cAAc;SAC5B,aAEA,MAAM,KAAK,SAAS,IAAI,CACvB,cACE,KAAK,EAAE;oBACL,UAAU,EAAE,CAAC;oBACb,YAAY,EAAE,gCAAgC;oBAC9C,UAAU,EAAE,4BAA4B;iBACzC,YAEA,MAAM,GACH,CACP,EACD,cACE,KAAK,EAAE;oBACL,IAAI,EAAE,CAAC;oBACP,SAAS,EAAE,CAAC;oBACZ,QAAQ,EAAE,CAAC;oBACX,QAAQ,EAAE,UAAU;oBACpB,QAAQ,EAAE,QAAQ;iBACnB,YAEA,QAAQ,GACL,IACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
export interface GameTopbarStat {
|
|
4
|
+
/** Short uppercase label, e.g. "Score", "Lives", "Level". */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Display value — string or number. Shown big. */
|
|
7
|
+
value: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* Optional accent — flips the value's color to the platform accent
|
|
10
|
+
* (typically used for the primary score).
|
|
11
|
+
*/
|
|
12
|
+
accent?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface GameTopbarProps {
|
|
15
|
+
/** The game's display name. Shows on the left in Fraunces. */
|
|
16
|
+
title?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Convenience: the most-common case. If present, renders as a single
|
|
19
|
+
* "Score" stat. Equivalent to passing `stats: [{ label: 'Score',
|
|
20
|
+
* value: score, accent: true }]`.
|
|
21
|
+
*/
|
|
22
|
+
score?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Custom stat lineup. Use for games that need more than just a score
|
|
25
|
+
* (lives, level, time, etc.). Replaces the score-only convenience.
|
|
26
|
+
*/
|
|
27
|
+
stats?: GameTopbarStat[];
|
|
28
|
+
/**
|
|
29
|
+
* Optional right-side action slot. Common: <button>Pause</button>,
|
|
30
|
+
* <button>Reset</button>. Keep to ≤2 buttons — the topbar is brand
|
|
31
|
+
* surface, not a settings menu.
|
|
32
|
+
*/
|
|
33
|
+
actions?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The single allowed topbar shape for FreeGameStore games. Brand
|
|
37
|
+
* consistency: same font, same paddings, same color tokens, same stat
|
|
38
|
+
* layout across every game on the storefront.
|
|
39
|
+
*
|
|
40
|
+
* Use inside <GameShell topbar={<GameTopbar … />}>.
|
|
41
|
+
*/
|
|
42
|
+
export declare function GameTopbar({ title, score, stats, actions }: GameTopbarProps): React.JSX.Element;
|
|
43
|
+
//# sourceMappingURL=GameTopbar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameTopbar.d.ts","sourceRoot":"","sources":["../src/GameTopbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,KAAK,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IAEzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAgD/F"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The single allowed topbar shape for FreeGameStore games. Brand
|
|
4
|
+
* consistency: same font, same paddings, same color tokens, same stat
|
|
5
|
+
* layout across every game on the storefront.
|
|
6
|
+
*
|
|
7
|
+
* Use inside <GameShell topbar={<GameTopbar … />}>.
|
|
8
|
+
*/
|
|
9
|
+
export function GameTopbar({ title, score, stats, actions }) {
|
|
10
|
+
// Resolve the stat list: explicit `stats` wins; otherwise synthesize
|
|
11
|
+
// from `score` if provided.
|
|
12
|
+
const resolvedStats = stats && stats.length > 0
|
|
13
|
+
? stats
|
|
14
|
+
: score !== undefined
|
|
15
|
+
? [{ label: 'Score', value: score, accent: true }]
|
|
16
|
+
: [];
|
|
17
|
+
return (_jsxs("div", { style: {
|
|
18
|
+
display: 'flex',
|
|
19
|
+
alignItems: 'center',
|
|
20
|
+
justifyContent: 'space-between',
|
|
21
|
+
gap: '0.75rem',
|
|
22
|
+
padding: '0.25rem 0.75rem',
|
|
23
|
+
height: '2rem',
|
|
24
|
+
}, children: [_jsx("div", { style: { display: 'flex', alignItems: 'center', gap: '1rem', minWidth: 0 }, children: title !== undefined && (_jsx("span", { style: {
|
|
25
|
+
fontFamily: '"Fraunces", Georgia, serif',
|
|
26
|
+
fontWeight: 700,
|
|
27
|
+
fontSize: '0.8rem',
|
|
28
|
+
whiteSpace: 'nowrap',
|
|
29
|
+
overflow: 'hidden',
|
|
30
|
+
textOverflow: 'ellipsis',
|
|
31
|
+
}, children: title })) }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '0.75rem' }, children: [resolvedStats.map((s) => (_jsx(Stat, { stat: s }, s.label))), actions !== undefined && (_jsx("div", { style: { display: 'flex', gap: '0.4rem', alignItems: 'center' }, children: actions }))] })] }));
|
|
32
|
+
}
|
|
33
|
+
function Stat({ stat }) {
|
|
34
|
+
return (_jsxs("div", { style: { textAlign: 'right', lineHeight: 1.05 }, children: [_jsx("div", { style: {
|
|
35
|
+
fontFamily: '"Fraunces", Georgia, serif',
|
|
36
|
+
fontWeight: 700,
|
|
37
|
+
fontSize: '0.85rem',
|
|
38
|
+
color: stat.accent === true ? 'var(--accent)' : 'var(--ink)',
|
|
39
|
+
fontVariantNumeric: 'tabular-nums',
|
|
40
|
+
lineHeight: 1,
|
|
41
|
+
}, children: stat.value }), _jsx("div", { style: {
|
|
42
|
+
fontSize: '0.5rem',
|
|
43
|
+
fontWeight: 700,
|
|
44
|
+
textTransform: 'uppercase',
|
|
45
|
+
letterSpacing: '0.06em',
|
|
46
|
+
color: 'var(--muted)',
|
|
47
|
+
lineHeight: 1,
|
|
48
|
+
}, children: stat.label })] }));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=GameTopbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameTopbar.js","sourceRoot":"","sources":["../src/GameTopbar.tsx"],"names":[],"mappings":";AAwCA;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAmB;IAC1E,qEAAqE;IACrE,4BAA4B;IAC5B,MAAM,aAAa,GACjB,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QACvB,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,KAAK,KAAK,SAAS;YACnB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YAClD,CAAC,CAAC,EAAE,CAAC;IAEX,OAAO,CACL,eACE,KAAK,EAAE;YACL,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,eAAe;YAC/B,GAAG,EAAE,SAAS;YACd,OAAO,EAAE,iBAAiB;YAC1B,MAAM,EAAE,MAAM;SACf,aAED,cAAK,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,YAC5E,KAAK,KAAK,SAAS,IAAI,CACtB,eACE,KAAK,EAAE;wBACL,UAAU,EAAE,4BAA4B;wBACxC,UAAU,EAAE,GAAG;wBACf,QAAQ,EAAE,QAAQ;wBAClB,UAAU,EAAE,QAAQ;wBACpB,QAAQ,EAAE,QAAQ;wBAClB,YAAY,EAAE,UAAU;qBACzB,YAEA,KAAK,GACD,CACR,GACG,EAEN,eAAK,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,aAClE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACxB,KAAC,IAAI,IAAe,IAAI,EAAE,CAAC,IAAhB,CAAC,CAAC,KAAK,CAAa,CAChC,CAAC,EACD,OAAO,KAAK,SAAS,IAAI,CACxB,cAAK,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAG,OAAO,GAAO,CACtF,IACG,IACF,CACP,CAAC;AACJ,CAAC;AAED,SAAS,IAAI,CAAC,EAAE,IAAI,EAA4B;IAC9C,OAAO,CACL,eAAK,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,aAClD,cACE,KAAK,EAAE;oBACL,UAAU,EAAE,4BAA4B;oBACxC,UAAU,EAAE,GAAG;oBACf,QAAQ,EAAE,SAAS;oBACnB,KAAK,EAAE,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY;oBAC5D,kBAAkB,EAAE,cAAc;oBAClC,UAAU,EAAE,CAAC;iBACd,YAEA,IAAI,CAAC,KAAK,GACP,EACN,cACE,KAAK,EAAE;oBACL,QAAQ,EAAE,QAAQ;oBAClB,UAAU,EAAE,GAAG;oBACf,aAAa,EAAE,WAAW;oBAC1B,aAAa,EAAE,QAAQ;oBACvB,KAAK,EAAE,cAAc;oBACrB,UAAU,EAAE,CAAC;iBACd,YAEA,IAAI,CAAC,KAAK,GACP,IACF,CACP,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @freeappstore/games — shared React UI primitives for FreeGameStore games.
|
|
3
|
+
*
|
|
4
|
+
* Why this exists:
|
|
5
|
+
* - Games on the platform must be **brand-consistent** (no per-game custom
|
|
6
|
+
* topbars). The compliance suite enforces brand fonts and CSS tokens; the
|
|
7
|
+
* topbar is the next leak.
|
|
8
|
+
* - Games must **fit the viewport** (no scrolling). GameShell hard-locks
|
|
9
|
+
* layout to 100svh and prevents overflow on the wrapper, so a game can't
|
|
10
|
+
* accidentally introduce vertical / horizontal scroll.
|
|
11
|
+
*
|
|
12
|
+
* What you get:
|
|
13
|
+
* <GameShell topbar={<GameTopbar score={42} />}>{your game}</GameShell>
|
|
14
|
+
*/
|
|
15
|
+
export { GameShell, type GameShellProps } from './GameShell.js';
|
|
16
|
+
export { GameTopbar, type GameTopbarProps, type GameTopbarStat, } from './GameTopbar.js';
|
|
17
|
+
export { GameButton, type GameButtonProps, type GameButtonVariant, type GameButtonSize, } from './GameButton.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EACL,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @freeappstore/games — shared React UI primitives for FreeGameStore games.
|
|
3
|
+
*
|
|
4
|
+
* Why this exists:
|
|
5
|
+
* - Games on the platform must be **brand-consistent** (no per-game custom
|
|
6
|
+
* topbars). The compliance suite enforces brand fonts and CSS tokens; the
|
|
7
|
+
* topbar is the next leak.
|
|
8
|
+
* - Games must **fit the viewport** (no scrolling). GameShell hard-locks
|
|
9
|
+
* layout to 100svh and prevents overflow on the wrapper, so a game can't
|
|
10
|
+
* accidentally introduce vertical / horizontal scroll.
|
|
11
|
+
*
|
|
12
|
+
* What you get:
|
|
13
|
+
* <GameShell topbar={<GameTopbar score={42} />}>{your game}</GameShell>
|
|
14
|
+
*/
|
|
15
|
+
export { GameShell } from './GameShell.js';
|
|
16
|
+
export { GameTopbar, } from './GameTopbar.js';
|
|
17
|
+
export { GameButton, } from './GameButton.js';
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,SAAS,EAAuB,MAAM,gBAAgB,CAAC;AAChE,OAAO,EACL,UAAU,GAGX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,UAAU,GAIX,MAAM,iBAAiB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@freegamestore/games",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Shared React UI primitives for games on FreeGameStore — GameShell, GameTopbar, etc. Brand-consistent, scroll-free.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/freeappstore-online/sdk#readme",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/freeappstore-online/sdk.git",
|
|
19
|
+
"directory": "packages/games-sdk"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/freeappstore-online/sdk/issues"
|
|
23
|
+
},
|
|
24
|
+
"keywords": ["freegamestore", "game", "ui", "react", "topbar", "shell"],
|
|
25
|
+
"files": ["dist", "README.md"],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=22"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc",
|
|
31
|
+
"typecheck": "tsc --noEmit"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"react": "^19.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/react": "^19.2.14",
|
|
38
|
+
"react": "^19.2.5",
|
|
39
|
+
"typescript": "^5.7.0"
|
|
40
|
+
},
|
|
41
|
+
"sideEffects": false
|
|
42
|
+
}
|