@freegamestore/games 0.5.0 → 0.7.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/GameAuth.d.ts +10 -0
- package/dist/GameAuth.d.ts.map +1 -0
- package/dist/GameAuth.js +108 -0
- package/dist/GameAuth.js.map +1 -0
- package/dist/GameTopbar.d.ts +7 -1
- package/dist/GameTopbar.d.ts.map +1 -1
- package/dist/GameTopbar.js +74 -18
- package/dist/GameTopbar.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/useAuth.d.ts +12 -0
- package/dist/useAuth.d.ts.map +1 -0
- package/dist/useAuth.js +46 -0
- package/dist/useAuth.js.map +1 -0
- package/dist/useLeaderboard.d.ts +18 -0
- package/dist/useLeaderboard.d.ts.map +1 -0
- package/dist/useLeaderboard.js +49 -0
- package/dist/useLeaderboard.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Sign-in / avatar widget for the GameTopbar `actions` slot.
|
|
4
|
+
*
|
|
5
|
+
* When not signed in: shows a small "Sign in" text button.
|
|
6
|
+
* When signed in: shows the user's avatar + first name, with a
|
|
7
|
+
* dropdown containing "Sign out".
|
|
8
|
+
*/
|
|
9
|
+
export declare function GameAuth(): React.JSX.Element;
|
|
10
|
+
//# sourceMappingURL=GameAuth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameAuth.d.ts","sourceRoot":"","sources":["../src/GameAuth.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAIpC;;;;;;GAMG;AACH,wBAAgB,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CA2I5C"}
|
package/dist/GameAuth.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useEffect } from 'react';
|
|
3
|
+
import { useAuth } from './useAuth.js';
|
|
4
|
+
/**
|
|
5
|
+
* Sign-in / avatar widget for the GameTopbar `actions` slot.
|
|
6
|
+
*
|
|
7
|
+
* When not signed in: shows a small "Sign in" text button.
|
|
8
|
+
* When signed in: shows the user's avatar + first name, with a
|
|
9
|
+
* dropdown containing "Sign out".
|
|
10
|
+
*/
|
|
11
|
+
export function GameAuth() {
|
|
12
|
+
const { user, loading, signIn, signOut } = useAuth();
|
|
13
|
+
const [open, setOpen] = useState(false);
|
|
14
|
+
const ref = useRef(null);
|
|
15
|
+
// Close dropdown when clicking outside
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!open)
|
|
18
|
+
return;
|
|
19
|
+
const handler = (e) => {
|
|
20
|
+
if (ref.current && !ref.current.contains(e.target)) {
|
|
21
|
+
setOpen(false);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
document.addEventListener('pointerdown', handler, true);
|
|
25
|
+
return () => document.removeEventListener('pointerdown', handler, true);
|
|
26
|
+
}, [open]);
|
|
27
|
+
if (loading)
|
|
28
|
+
return _jsx("div", {});
|
|
29
|
+
if (user === null) {
|
|
30
|
+
return (_jsx("button", { onClick: signIn, style: {
|
|
31
|
+
background: 'none',
|
|
32
|
+
border: 'none',
|
|
33
|
+
cursor: 'pointer',
|
|
34
|
+
fontFamily: '"Manrope", system-ui, sans-serif',
|
|
35
|
+
fontSize: '0.7rem',
|
|
36
|
+
fontWeight: 600,
|
|
37
|
+
color: 'var(--muted, #6b7280)',
|
|
38
|
+
padding: 0,
|
|
39
|
+
margin: 0,
|
|
40
|
+
// 44px minimum touch target
|
|
41
|
+
minWidth: '44px',
|
|
42
|
+
minHeight: '44px',
|
|
43
|
+
display: 'inline-flex',
|
|
44
|
+
alignItems: 'center',
|
|
45
|
+
justifyContent: 'center',
|
|
46
|
+
WebkitTapHighlightColor: 'transparent',
|
|
47
|
+
touchAction: 'manipulation',
|
|
48
|
+
}, children: "Sign in" }));
|
|
49
|
+
}
|
|
50
|
+
const firstName = user.name.split(' ')[0] ?? user.name;
|
|
51
|
+
return (_jsxs("div", { ref: ref, style: { position: 'relative' }, children: [_jsxs("button", { onClick: () => setOpen((v) => !v), style: {
|
|
52
|
+
background: 'none',
|
|
53
|
+
border: 'none',
|
|
54
|
+
cursor: 'pointer',
|
|
55
|
+
display: 'inline-flex',
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
gap: '0.35rem',
|
|
58
|
+
padding: 0,
|
|
59
|
+
margin: 0,
|
|
60
|
+
minWidth: '44px',
|
|
61
|
+
minHeight: '44px',
|
|
62
|
+
justifyContent: 'center',
|
|
63
|
+
WebkitTapHighlightColor: 'transparent',
|
|
64
|
+
touchAction: 'manipulation',
|
|
65
|
+
}, children: [_jsx("img", { src: user.avatar, alt: "", width: 24, height: 24, style: {
|
|
66
|
+
width: '24px',
|
|
67
|
+
height: '24px',
|
|
68
|
+
borderRadius: '50%',
|
|
69
|
+
objectFit: 'cover',
|
|
70
|
+
flexShrink: 0,
|
|
71
|
+
} }), _jsx("span", { style: {
|
|
72
|
+
fontFamily: '"Manrope", system-ui, sans-serif',
|
|
73
|
+
fontSize: '0.7rem',
|
|
74
|
+
fontWeight: 600,
|
|
75
|
+
color: 'var(--ink, #1a1a1a)',
|
|
76
|
+
whiteSpace: 'nowrap',
|
|
77
|
+
}, children: firstName })] }), open && (_jsx("div", { style: {
|
|
78
|
+
position: 'absolute',
|
|
79
|
+
top: '100%',
|
|
80
|
+
right: 0,
|
|
81
|
+
marginTop: '0.25rem',
|
|
82
|
+
background: 'var(--panel, #fff)',
|
|
83
|
+
border: '1px solid var(--line, #e5e5e5)',
|
|
84
|
+
borderRadius: '0.5rem',
|
|
85
|
+
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
|
|
86
|
+
zIndex: 100,
|
|
87
|
+
minWidth: '7rem',
|
|
88
|
+
}, children: _jsx("button", { onClick: () => {
|
|
89
|
+
setOpen(false);
|
|
90
|
+
signOut();
|
|
91
|
+
}, style: {
|
|
92
|
+
display: 'flex',
|
|
93
|
+
alignItems: 'center',
|
|
94
|
+
width: '100%',
|
|
95
|
+
background: 'none',
|
|
96
|
+
border: 'none',
|
|
97
|
+
cursor: 'pointer',
|
|
98
|
+
fontFamily: '"Manrope", system-ui, sans-serif',
|
|
99
|
+
fontSize: '0.7rem',
|
|
100
|
+
fontWeight: 600,
|
|
101
|
+
color: 'var(--ink, #1a1a1a)',
|
|
102
|
+
padding: '0.5rem 0.75rem',
|
|
103
|
+
minHeight: '44px',
|
|
104
|
+
WebkitTapHighlightColor: 'transparent',
|
|
105
|
+
touchAction: 'manipulation',
|
|
106
|
+
}, children: "Sign out" }) }))] }));
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=GameAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameAuth.js","sourceRoot":"","sources":["../src/GameAuth.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ;IACtB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;IACrD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAEzC,uCAAuC;IACvC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,OAAO,GAAG,CAAC,CAAa,EAAE,EAAE;YAChC,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAc,CAAC,EAAE,CAAC;gBAC3D,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;QACH,CAAC,CAAC;QACF,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QACxD,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1E,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,IAAI,OAAO;QAAE,OAAO,eAAO,CAAC;IAE5B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,OAAO,CACL,iBACE,OAAO,EAAE,MAAM,EACf,KAAK,EAAE;gBACL,UAAU,EAAE,MAAM;gBAClB,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,SAAS;gBACjB,UAAU,EAAE,kCAAkC;gBAC9C,QAAQ,EAAE,QAAQ;gBAClB,UAAU,EAAE,GAAG;gBACf,KAAK,EAAE,uBAAuB;gBAC9B,OAAO,EAAE,CAAC;gBACV,MAAM,EAAE,CAAC;gBACT,4BAA4B;gBAC5B,QAAQ,EAAE,MAAM;gBAChB,SAAS,EAAE,MAAM;gBACjB,OAAO,EAAE,aAAa;gBACtB,UAAU,EAAE,QAAQ;gBACpB,cAAc,EAAE,QAAQ;gBACxB,uBAAuB,EAAE,aAAa;gBACtC,WAAW,EAAE,cAAc;aAC5B,wBAGM,CACV,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC;IAEvD,OAAO,CACL,eAAK,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,aAC5C,kBACE,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EACjC,KAAK,EAAE;oBACL,UAAU,EAAE,MAAM;oBAClB,MAAM,EAAE,MAAM;oBACd,MAAM,EAAE,SAAS;oBACjB,OAAO,EAAE,aAAa;oBACtB,UAAU,EAAE,QAAQ;oBACpB,GAAG,EAAE,SAAS;oBACd,OAAO,EAAE,CAAC;oBACV,MAAM,EAAE,CAAC;oBACT,QAAQ,EAAE,MAAM;oBAChB,SAAS,EAAE,MAAM;oBACjB,cAAc,EAAE,QAAQ;oBACxB,uBAAuB,EAAE,aAAa;oBACtC,WAAW,EAAE,cAAc;iBAC5B,aAED,cACE,GAAG,EAAE,IAAI,CAAC,MAAM,EAChB,GAAG,EAAC,EAAE,EACN,KAAK,EAAE,EAAE,EACT,MAAM,EAAE,EAAE,EACV,KAAK,EAAE;4BACL,KAAK,EAAE,MAAM;4BACb,MAAM,EAAE,MAAM;4BACd,YAAY,EAAE,KAAK;4BACnB,SAAS,EAAE,OAAO;4BAClB,UAAU,EAAE,CAAC;yBACd,GACD,EACF,eACE,KAAK,EAAE;4BACL,UAAU,EAAE,kCAAkC;4BAC9C,QAAQ,EAAE,QAAQ;4BAClB,UAAU,EAAE,GAAG;4BACf,KAAK,EAAE,qBAAqB;4BAC5B,UAAU,EAAE,QAAQ;yBACrB,YAEA,SAAS,GACL,IACA,EAER,IAAI,IAAI,CACP,cACE,KAAK,EAAE;oBACL,QAAQ,EAAE,UAAU;oBACpB,GAAG,EAAE,MAAM;oBACX,KAAK,EAAE,CAAC;oBACR,SAAS,EAAE,SAAS;oBACpB,UAAU,EAAE,oBAAoB;oBAChC,MAAM,EAAE,gCAAgC;oBACxC,YAAY,EAAE,QAAQ;oBACtB,SAAS,EAAE,4BAA4B;oBACvC,MAAM,EAAE,GAAG;oBACX,QAAQ,EAAE,MAAM;iBACjB,YAED,iBACE,OAAO,EAAE,GAAG,EAAE;wBACZ,OAAO,CAAC,KAAK,CAAC,CAAC;wBACf,OAAO,EAAE,CAAC;oBACZ,CAAC,EACD,KAAK,EAAE;wBACL,OAAO,EAAE,MAAM;wBACf,UAAU,EAAE,QAAQ;wBACpB,KAAK,EAAE,MAAM;wBACb,UAAU,EAAE,MAAM;wBAClB,MAAM,EAAE,MAAM;wBACd,MAAM,EAAE,SAAS;wBACjB,UAAU,EAAE,kCAAkC;wBAC9C,QAAQ,EAAE,QAAQ;wBAClB,UAAU,EAAE,GAAG;wBACf,KAAK,EAAE,qBAAqB;wBAC5B,OAAO,EAAE,gBAAgB;wBACzB,SAAS,EAAE,MAAM;wBACjB,uBAAuB,EAAE,aAAa;wBACtC,WAAW,EAAE,cAAc;qBAC5B,yBAGM,GACL,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
|
package/dist/GameTopbar.d.ts
CHANGED
|
@@ -31,6 +31,12 @@ export interface GameTopbarProps {
|
|
|
31
31
|
* surface, not a settings menu.
|
|
32
32
|
*/
|
|
33
33
|
actions?: ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* Game rules/instructions. When provided, an ℹ info icon appears in the
|
|
36
|
+
* topbar. Tapping it opens a fullscreen overlay with the rules content.
|
|
37
|
+
* Every game should populate this so players know how to play.
|
|
38
|
+
*/
|
|
39
|
+
rules?: ReactNode;
|
|
34
40
|
}
|
|
35
41
|
/**
|
|
36
42
|
* The single allowed topbar shape for FreeGameStore games. Brand
|
|
@@ -39,5 +45,5 @@ export interface GameTopbarProps {
|
|
|
39
45
|
*
|
|
40
46
|
* Use inside <GameShell topbar={<GameTopbar … />}>.
|
|
41
47
|
*/
|
|
42
|
-
export declare function GameTopbar({ title, score, stats, actions }: GameTopbarProps): React.JSX.Element;
|
|
48
|
+
export declare function GameTopbar({ title, score, stats, actions, rules }: GameTopbarProps): React.JSX.Element;
|
|
43
49
|
//# sourceMappingURL=GameTopbar.d.ts.map
|
package/dist/GameTopbar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GameTopbar.d.ts","sourceRoot":"","sources":["../src/GameTopbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"GameTopbar.d.ts","sourceRoot":"","sources":["../src/GameTopbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC,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,6DAA6D;IAC7D,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;IAEpB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAiFtG"}
|
package/dist/GameTopbar.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
2
3
|
/**
|
|
3
4
|
* The single allowed topbar shape for FreeGameStore games. Brand
|
|
4
5
|
* consistency: same font, same paddings, same color tokens, same stat
|
|
@@ -6,30 +7,85 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
6
7
|
*
|
|
7
8
|
* Use inside <GameShell topbar={<GameTopbar … />}>.
|
|
8
9
|
*/
|
|
9
|
-
export function GameTopbar({ title, score, stats, actions }) {
|
|
10
|
-
|
|
11
|
-
// from `score` if provided.
|
|
10
|
+
export function GameTopbar({ title, score, stats, actions, rules }) {
|
|
11
|
+
const [showRules, setShowRules] = useState(false);
|
|
12
12
|
const resolvedStats = stats && stats.length > 0
|
|
13
13
|
? stats
|
|
14
14
|
: score !== undefined
|
|
15
15
|
? [{ label: 'Score', value: score, accent: true }]
|
|
16
16
|
: [];
|
|
17
|
+
return (_jsxs(_Fragment, { children: [_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: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '0.5rem', minWidth: 0 }, children: [rules !== undefined && (_jsx("button", { onClick: () => setShowRules(true), style: {
|
|
25
|
+
background: 'none',
|
|
26
|
+
border: 'none',
|
|
27
|
+
cursor: 'pointer',
|
|
28
|
+
padding: 0,
|
|
29
|
+
minWidth: '2.75rem',
|
|
30
|
+
minHeight: '2.75rem',
|
|
31
|
+
display: 'flex',
|
|
32
|
+
alignItems: 'center',
|
|
33
|
+
justifyContent: 'center',
|
|
34
|
+
color: 'var(--muted, #999)',
|
|
35
|
+
fontSize: '1rem',
|
|
36
|
+
lineHeight: 1,
|
|
37
|
+
WebkitTapHighlightColor: 'transparent',
|
|
38
|
+
}, "aria-label": "Game rules", children: _jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("circle", { cx: "8", cy: "8", r: "6.5" }), _jsx("path", { d: "M8 11.5v0M8 5v4" })] }) })), title !== undefined && (_jsx("span", { style: {
|
|
39
|
+
fontFamily: '"Manrope", system-ui, sans-serif',
|
|
40
|
+
fontWeight: 600,
|
|
41
|
+
fontSize: '0.8rem',
|
|
42
|
+
letterSpacing: '-0.01em',
|
|
43
|
+
whiteSpace: 'nowrap',
|
|
44
|
+
overflow: 'hidden',
|
|
45
|
+
textOverflow: 'ellipsis',
|
|
46
|
+
}, 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 }))] })] }), showRules && rules !== undefined && (_jsx(RulesOverlay, { onClose: () => setShowRules(false), children: rules }))] }));
|
|
47
|
+
}
|
|
48
|
+
function RulesOverlay({ children, onClose }) {
|
|
17
49
|
return (_jsxs("div", { style: {
|
|
50
|
+
position: 'fixed',
|
|
51
|
+
inset: 0,
|
|
52
|
+
zIndex: 9999,
|
|
53
|
+
background: 'var(--paper, #0f0f0f)',
|
|
54
|
+
color: 'var(--ink, #f0f0f0)',
|
|
18
55
|
display: 'flex',
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
56
|
+
flexDirection: 'column',
|
|
57
|
+
overflow: 'hidden',
|
|
58
|
+
}, children: [_jsxs("div", { style: {
|
|
59
|
+
display: 'flex',
|
|
60
|
+
alignItems: 'center',
|
|
61
|
+
justifyContent: 'space-between',
|
|
62
|
+
padding: '0.5rem 0.75rem',
|
|
63
|
+
borderBottom: '1px solid var(--line, #2a2a2a)',
|
|
64
|
+
flexShrink: 0,
|
|
65
|
+
}, children: [_jsx("span", { style: {
|
|
66
|
+
fontFamily: '"Manrope", system-ui, sans-serif',
|
|
67
|
+
fontWeight: 700,
|
|
68
|
+
fontSize: '0.9rem',
|
|
69
|
+
}, children: "How to Play" }), _jsx("button", { onClick: onClose, style: {
|
|
70
|
+
background: 'none',
|
|
71
|
+
border: 'none',
|
|
72
|
+
cursor: 'pointer',
|
|
73
|
+
color: 'var(--muted, #999)',
|
|
74
|
+
fontSize: '1.2rem',
|
|
75
|
+
minWidth: '2.75rem',
|
|
76
|
+
minHeight: '2.75rem',
|
|
77
|
+
display: 'flex',
|
|
78
|
+
alignItems: 'center',
|
|
79
|
+
justifyContent: 'center',
|
|
80
|
+
WebkitTapHighlightColor: 'transparent',
|
|
81
|
+
}, "aria-label": "Close rules", children: "\u00D7" })] }), _jsx("div", { style: {
|
|
82
|
+
flex: 1,
|
|
83
|
+
overflowY: 'auto',
|
|
84
|
+
padding: '1rem',
|
|
85
|
+
fontFamily: '"Manrope", system-ui, sans-serif',
|
|
86
|
+
fontSize: '0.9rem',
|
|
87
|
+
lineHeight: 1.6,
|
|
88
|
+
}, children: children })] }));
|
|
33
89
|
}
|
|
34
90
|
function Stat({ stat }) {
|
|
35
91
|
return (_jsxs("div", { style: { textAlign: 'right', lineHeight: 1.05 }, children: [_jsx("div", { style: {
|
package/dist/GameTopbar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GameTopbar.js","sourceRoot":"","sources":["../src/GameTopbar.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"GameTopbar.js","sourceRoot":"","sources":["../src/GameTopbar.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,4 +15,7 @@
|
|
|
15
15
|
export { GameShell, type GameShellProps } from './GameShell.js';
|
|
16
16
|
export { GameTopbar, type GameTopbarProps, type GameTopbarStat, } from './GameTopbar.js';
|
|
17
17
|
export { GameButton, type GameButtonProps, type GameButtonVariant, type GameButtonSize, } from './GameButton.js';
|
|
18
|
+
export { GameAuth } from './GameAuth.js';
|
|
19
|
+
export { useAuth, type User } from './useAuth.js';
|
|
20
|
+
export { useLeaderboard, type LeaderboardEntry, } from './useLeaderboard.js';
|
|
18
21
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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"}
|
|
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;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EACL,cAAc,EACd,KAAK,gBAAgB,GACtB,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -15,4 +15,7 @@
|
|
|
15
15
|
export { GameShell } from './GameShell.js';
|
|
16
16
|
export { GameTopbar, } from './GameTopbar.js';
|
|
17
17
|
export { GameButton, } from './GameButton.js';
|
|
18
|
+
export { GameAuth } from './GameAuth.js';
|
|
19
|
+
export { useAuth } from './useAuth.js';
|
|
20
|
+
export { useLeaderboard, } from './useLeaderboard.js';
|
|
18
21
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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"}
|
|
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;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAAa,MAAM,cAAc,CAAC;AAClD,OAAO,EACL,cAAc,GAEf,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../src/useAuth.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,OAAO,IAAI;IACzB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CA4CA"}
|
package/dist/useAuth.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
export function useAuth() {
|
|
3
|
+
const [user, setUser] = useState(null);
|
|
4
|
+
const [loading, setLoading] = useState(true);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
let cancelled = false;
|
|
7
|
+
fetch('https://auth.freegamestore.online/me', { credentials: 'include' })
|
|
8
|
+
.then((res) => {
|
|
9
|
+
if (!cancelled && res.ok)
|
|
10
|
+
return res.json();
|
|
11
|
+
return null;
|
|
12
|
+
})
|
|
13
|
+
.then((data) => {
|
|
14
|
+
if (!cancelled)
|
|
15
|
+
setUser(data);
|
|
16
|
+
})
|
|
17
|
+
.catch(() => {
|
|
18
|
+
// 401 or network error — user is not signed in
|
|
19
|
+
})
|
|
20
|
+
.finally(() => {
|
|
21
|
+
if (!cancelled)
|
|
22
|
+
setLoading(false);
|
|
23
|
+
});
|
|
24
|
+
return () => {
|
|
25
|
+
cancelled = true;
|
|
26
|
+
};
|
|
27
|
+
}, []);
|
|
28
|
+
const signIn = useCallback(() => {
|
|
29
|
+
window.location.href = `https://auth.freegamestore.online/login?redirect=${encodeURIComponent(window.location.href)}`;
|
|
30
|
+
}, []);
|
|
31
|
+
const signOut = useCallback(() => {
|
|
32
|
+
fetch('https://auth.freegamestore.online/logout', {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
credentials: 'include',
|
|
35
|
+
})
|
|
36
|
+
.catch(() => {
|
|
37
|
+
// best-effort
|
|
38
|
+
})
|
|
39
|
+
.finally(() => {
|
|
40
|
+
setUser(null);
|
|
41
|
+
window.location.reload();
|
|
42
|
+
});
|
|
43
|
+
}, []);
|
|
44
|
+
return { user, loading, signIn, signOut };
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=useAuth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAuth.js","sourceRoot":"","sources":["../src/useAuth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAQzD,MAAM,UAAU,OAAO;IAMrB,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAc,IAAI,CAAC,CAAC;IACpD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE7C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,KAAK,CAAC,sCAAsC,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;aACtE,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;YACZ,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,EAAE;gBAAE,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,IAAiB,EAAE,EAAE;YAC1B,IAAI,CAAC,SAAS;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,+CAA+C;QACjD,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE;YACZ,IAAI,CAAC,SAAS;gBAAE,UAAU,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QACL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9B,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,oDAAoD,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;IACxH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;QAC/B,KAAK,CAAC,0CAA0C,EAAE;YAChD,MAAM,EAAE,MAAM;YACd,WAAW,EAAE,SAAS;SACvB,CAAC;aACC,KAAK,CAAC,GAAG,EAAE;YACV,cAAc;QAChB,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE;YACZ,OAAO,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;IACP,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface LeaderboardEntry {
|
|
2
|
+
player_name: string;
|
|
3
|
+
score: number;
|
|
4
|
+
user_id?: string;
|
|
5
|
+
avatar_url?: string;
|
|
6
|
+
created_at: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function useLeaderboard(gameId: string): {
|
|
9
|
+
topScores: LeaderboardEntry[];
|
|
10
|
+
recentScores: LeaderboardEntry[];
|
|
11
|
+
submitScore: (score: number) => Promise<{
|
|
12
|
+
ok: boolean;
|
|
13
|
+
rank?: number;
|
|
14
|
+
}>;
|
|
15
|
+
loading: boolean;
|
|
16
|
+
refresh: () => void;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=useLeaderboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLeaderboard.d.ts","sourceRoot":"","sources":["../src/useLeaderboard.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAC9C,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAiDA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
const API_BASE = 'https://freegamestore-leaderboard.serge-the-dev.workers.dev';
|
|
3
|
+
export function useLeaderboard(gameId) {
|
|
4
|
+
const [topScores, setTopScores] = useState([]);
|
|
5
|
+
const [recentScores, setRecentScores] = useState([]);
|
|
6
|
+
const [loading, setLoading] = useState(true);
|
|
7
|
+
const load = useCallback(() => {
|
|
8
|
+
setLoading(true);
|
|
9
|
+
Promise.all([
|
|
10
|
+
fetch(`${API_BASE}/scores/${gameId}?sort=top`, { credentials: 'include' })
|
|
11
|
+
.then((r) => (r.ok ? r.json() : []))
|
|
12
|
+
.catch(() => []),
|
|
13
|
+
fetch(`${API_BASE}/scores/${gameId}?sort=recent`, { credentials: 'include' })
|
|
14
|
+
.then((r) => (r.ok ? r.json() : []))
|
|
15
|
+
.catch(() => []),
|
|
16
|
+
]).then(([top, recent]) => {
|
|
17
|
+
setTopScores(top);
|
|
18
|
+
setRecentScores(recent);
|
|
19
|
+
setLoading(false);
|
|
20
|
+
});
|
|
21
|
+
}, [gameId]);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
load();
|
|
24
|
+
}, [load]);
|
|
25
|
+
const submitScore = useCallback(async (score) => {
|
|
26
|
+
try {
|
|
27
|
+
const res = await fetch(`${API_BASE}/scores/${gameId}`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
credentials: 'include',
|
|
30
|
+
headers: { 'Content-Type': 'application/json' },
|
|
31
|
+
body: JSON.stringify({ score }),
|
|
32
|
+
});
|
|
33
|
+
if (!res.ok)
|
|
34
|
+
return { ok: false };
|
|
35
|
+
const data = (await res.json());
|
|
36
|
+
// Refresh scores after submission
|
|
37
|
+
load();
|
|
38
|
+
const result = { ok: true };
|
|
39
|
+
if (data.rank !== undefined)
|
|
40
|
+
result.rank = data.rank;
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return { ok: false };
|
|
45
|
+
}
|
|
46
|
+
}, [gameId, load]);
|
|
47
|
+
return { topScores, recentScores, submitScore, loading, refresh: load };
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=useLeaderboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLeaderboard.js","sourceRoot":"","sources":["../src/useLeaderboard.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED