Skip to content

Commit 44b5968

Browse files
committed
✨ Add new content
1 parent da49e5c commit 44b5968

19 files changed

+1029
-86
lines changed

client/components.json

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": false,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "tailwind.config.ts",
8+
"css": "src/index.css",
9+
"baseColor": "neutral",
10+
"cssVariables": true,
11+
"prefix": ""
12+
},
13+
"aliases": {
14+
"components": "@/components",
15+
"utils": "@/lib/utils",
16+
"ui": "@/components/ui",
17+
"lib": "@/lib",
18+
"hooks": "@/hooks"
19+
},
20+
"iconLibrary": "lucide"
21+
}

client/package.json

+15-8
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,37 @@
1212
"preview": "vite preview"
1313
},
1414
"dependencies": {
15-
"@bal7hazar/arcade-sdk": "0.0.76",
16-
"@cartridge/connector": "0.7.4",
17-
"@cartridge/controller": "0.7.4",
15+
"@bal7hazar/arcade-sdk": "0.0.79",
16+
"@cartridge/connector": "0.7.5",
17+
"@cartridge/controller": "0.7.5",
1818
"@cartridge/penpal": "^6.2.3",
1919
"@cartridge/presets": "0.5.4",
20-
"@cartridge/ui-next": "0.7.4",
21-
"@cartridge/utils": "0.7.4",
22-
"@hookform/resolvers": "^3.9.1",
20+
"@cartridge/ui-next": "0.7.5",
21+
"@cartridge/utils": "0.7.5",
22+
"@hookform/resolvers": "^3.10.0",
23+
"@radix-ui/react-label": "^2.1.2",
24+
"@radix-ui/react-slot": "^1.1.2",
2325
"@starknet-react/chains": "^3.1.2",
2426
"@starknet-react/core": "^3.7.1",
27+
"class-variance-authority": "^0.7.1",
28+
"clsx": "^2.1.1",
2529
"compare-versions": "^6.1.1",
2630
"lodash": "^4.17.21",
31+
"lucide-react": "^0.479.0",
2732
"react": "^18.3.1",
2833
"react-dom": "^18.3.1",
29-
"react-hook-form": "^7.53.2",
34+
"react-hook-form": "^7.54.2",
3035
"react-query": "^3.39.2",
3136
"react-router-dom": "^6.27.0",
3237
"sonner": "^1.4.41",
3338
"starknet": "^6.11.0",
39+
"tailwind-merge": "^3.0.2",
40+
"tailwindcss-animate": "^1.0.7",
3441
"viem": "^2.22.9",
3542
"vite-plugin-mkcert": "^1.17.6",
3643
"vite-plugin-top-level-await": "^1.4.4",
3744
"vite-plugin-wasm": "^3.3.0",
38-
"zod": "^3.23.8"
45+
"zod": "^3.24.1"
3946
},
4047
"devDependencies": {
4148
"@eslint/js": "^9.9.0",

client/pnpm-lock.yaml

+127-42
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/src/components/achievements/index.tsx

+10-5
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,20 @@ import {
1010
AchievementSummary,
1111
} from "@cartridge/ui-next";
1212
import { useUsername } from "@/hooks/account";
13-
import { useCallback, useMemo } from "react";
13+
import { useCallback, useMemo, useState } from "react";
1414
import { Trophies } from "./trophies";
1515
import { useArcade } from "@/hooks/arcade";
1616
import { GameModel } from "@bal7hazar/arcade-sdk";
1717
import { addAddressPadding } from "starknet";
1818
import { useAchievements, usePlayerStats } from "@/hooks/achievements";
1919
import { useAccount } from "@starknet-react/core";
2020
import { Item } from "@/helpers/achievements";
21-
22-
const PLACEHOLDER =
23-
"https://static.cartridge.gg/presets/cartridge/cover-dark.png";
21+
import { PLACEHOLDER } from "@/constants";
2422

2523
export function Achievements({ game }: { game?: GameModel }) {
24+
const [tab, setTab] = useState<"achievements" | "leaderboard">(
25+
"achievements",
26+
);
2627
const { address: self } = useAccount();
2728
const { achievements, globals, players, usernames, isLoading } =
2829
useAchievements();
@@ -153,6 +154,10 @@ export function Achievements({ game }: { game?: GameModel }) {
153154
<LayoutContent className="gap-y-6 select-none h-full overflow-clip">
154155
{isSelf ? (
155156
<AchievementTabs
157+
value={tab}
158+
onValueChange={(value) =>
159+
setTab(value as "achievements" | "leaderboard")
160+
}
156161
count={!game ? gamesCompleted : count}
157162
total={!game ? gamesTotal : total}
158163
rank={!game ? gamesRank : gameRank}
@@ -308,5 +313,5 @@ export function GameRow({
308313
};
309314
}, [gameAchievements, game, pinneds]);
310315

311-
return <AchievementSummary {...summaryProps} variant={variant} />;
316+
return <AchievementSummary {...summaryProps} variant={variant} active />;
312317
}

client/src/components/app.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useEffect } from "react";
77
import { useAchievements } from "@/hooks/achievements";
88
import { ArcadeTabs, TabsContent } from "@cartridge/ui-next";
99
import { useAccount } from "@starknet-react/core";
10+
import { DiscoverScene } from "./scenes/discover";
1011

1112
export function App() {
1213
const { isConnected } = useAccount();
@@ -45,7 +46,7 @@ export function App() {
4546
>
4647
<Games />
4748
<TabsContent className="p-0 mt-0 grow w-full" value="discover">
48-
<InventoryScene />
49+
<DiscoverScene />
4950
</TabsContent>
5051
<TabsContent className="p-0 mt-0 grow w-full" value="inventory">
5152
<InventoryScene />
+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import {
2+
LayoutContent,
3+
LayoutContentLoader,
4+
ArcadeDiscoveryGroup,
5+
} from "@cartridge/ui-next";
6+
import { useMemo } from "react";
7+
import { useArcade } from "@/hooks/arcade";
8+
import { GameModel } from "@bal7hazar/arcade-sdk";
9+
import { useAchievements } from "@/hooks/achievements";
10+
import { PLACEHOLDER } from "@/constants";
11+
12+
interface Event {
13+
name: string;
14+
achievement: { title: string; icon: string };
15+
timestamp: number;
16+
}
17+
18+
export function Discover({ game }: { game?: GameModel }) {
19+
const { events, usernames, isLoading } = useAchievements();
20+
const { games } = useArcade();
21+
22+
const filteredGames = useMemo(() => {
23+
return !game ? games : [game];
24+
}, [games, game]);
25+
26+
const gameEvents = useMemo(() => {
27+
return filteredGames.map((game) => {
28+
const data = events[game?.project]?.map((event) => {
29+
return {
30+
name: usernames[event.player],
31+
achievement: event.achievement,
32+
timestamp: event.timestamp,
33+
};
34+
});
35+
if (!data) return [];
36+
if (filteredGames.length > 1) {
37+
return data.slice(0, 3);
38+
}
39+
return data.slice(0, 20);
40+
});
41+
}, [events, filteredGames, usernames]);
42+
43+
if (isLoading) return <LayoutContentLoader />;
44+
45+
return (
46+
<LayoutContent className="gap-y-6 select-none h-full overflow-clip">
47+
<div
48+
className="p-0 mt-0 pb-6 overflow-y-scroll"
49+
style={{ scrollbarWidth: "none" }}
50+
>
51+
<div className="flex flex-col gap-y-6">
52+
{filteredGames.map((item, index) => (
53+
<GameRow key={index} game={item} events={gameEvents[index]} />
54+
))}
55+
</div>
56+
</div>
57+
</LayoutContent>
58+
);
59+
}
60+
61+
export function GameRow({
62+
game,
63+
events,
64+
}: {
65+
game: GameModel;
66+
events: Event[];
67+
}) {
68+
const gameData = useMemo(() => {
69+
return {
70+
metadata: {
71+
name: game.metadata.name,
72+
logo: game.metadata.image,
73+
cover: game.metadata.banner ?? PLACEHOLDER,
74+
},
75+
socials: game.socials,
76+
};
77+
}, [game]);
78+
79+
return (
80+
<div className="rounded-lg overflow-hidden">
81+
<ArcadeDiscoveryGroup
82+
className={
83+
game.metadata.color
84+
? `data-[theme=true]:text-[${game.metadata.color}]`
85+
: ""
86+
}
87+
game={gameData}
88+
events={events}
89+
/>
90+
</div>
91+
);
92+
}

client/src/components/games/index.tsx

+20-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { ArcadeGameSelect, CardListContent, cn } from "@cartridge/ui-next";
1+
import {
2+
ArcadeGameSelect,
3+
Button,
4+
CardListContent,
5+
cn,
6+
GearIcon,
7+
} from "@cartridge/ui-next";
28
import { useCallback, useState } from "react";
39
import { useTheme } from "@/hooks/context";
410
import {
@@ -8,20 +14,20 @@ import {
814
import { useArcade } from "@/hooks/arcade";
915
import { useProject } from "@/hooks/project";
1016
import { usePlayerGameStats, usePlayerStats } from "@/hooks/achievements";
17+
import { Register } from "./register";
1118

1219
export const Games = () => {
1320
const [selected, setSelected] = useState(0);
1421
const { games } = useArcade();
1522

1623
return (
1724
<div
18-
className="flex flex-col gap-y-px min-w-[324px] grow overflow-clip"
25+
className="flex flex-col gap-y-px min-w-[324px] h-full overflow-clip pb-6"
1926
style={{ scrollbarWidth: "none" }}
2027
>
2128
<Game
2229
index={0}
2330
first={true}
24-
last={false}
2531
project=""
2632
namespace=""
2733
preset="default"
@@ -31,15 +37,14 @@ export const Games = () => {
3137
setSelected={setSelected}
3238
/>
3339
<CardListContent
34-
className="p-0 pb-6 grow overflow-y-scroll"
40+
className="p-0 overflow-y-scroll"
3541
style={{ scrollbarWidth: "none" }}
3642
>
3743
{games.map((game, index) => (
3844
<Game
3945
key={`${game.worldAddress}-${game.namespace}`}
4046
index={index + 1}
4147
first={false}
42-
last={index === games.length - 1}
4348
project={game.project}
4449
namespace={game.namespace}
4550
preset={game.preset ?? "default"}
@@ -51,14 +56,14 @@ export const Games = () => {
5156
/>
5257
))}
5358
</CardListContent>
59+
<Register />
5460
</div>
5561
);
5662
};
5763

5864
export const Game = ({
5965
index,
6066
first,
61-
last,
6267
project,
6368
namespace,
6469
preset,
@@ -70,7 +75,6 @@ export const Game = ({
7075
}: {
7176
index: number;
7277
first: boolean;
73-
last: boolean;
7478
project: string;
7579
namespace: string;
7680
preset: string;
@@ -126,21 +130,23 @@ export const Game = ({
126130
]);
127131

128132
return (
129-
<div
130-
className={cn(
131-
first && "rounded-t overflow-clip",
132-
last && "rounded-b overflow-clip",
133-
)}
134-
onClick={handleClick}
135-
>
133+
<div className={cn("flex gap-px", first && "rounded-t overflow-clip")}>
136134
<ArcadeGameSelect
137135
name={name}
138136
logo={icon}
139137
cover={cover}
140138
points={project ? gameEarnings : totalEarnings}
141139
active={active}
142140
onClick={handleClick}
141+
className="grow"
143142
/>
143+
<Button
144+
variant="secondary"
145+
size="icon"
146+
className="w-7 h-full rounded-none"
147+
>
148+
<GearIcon size="xs" />
149+
</Button>
144150
</div>
145151
);
146152
};

0 commit comments

Comments
 (0)