@zthun/romulator-web 1.4.0 → 1.6.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/index.html CHANGED
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Romulator: Organize your Games</title>
7
- <script type="module" crossorigin src="/assets/index-Com8X0qx.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-DUOIpN_h.js"></script>
8
8
  </head>
9
9
  <body>
10
10
  <div id="zthunworks-romulator"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zthun/romulator-web",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Romulator frontend",
5
5
  "author": "Anthony Bonta",
6
6
  "license": "MIT",
@@ -18,29 +18,29 @@
18
18
  "access": "public"
19
19
  },
20
20
  "devDependencies": {
21
- "@types/node": "^24.7.2",
21
+ "@types/node": "^24.8.1",
22
22
  "@zthun/cirque": "^7.1.10",
23
23
  "@zthun/cirque-du-react": "^7.1.10",
24
- "@zthun/fashion-boutique": "^10.2.7",
25
- "@zthun/fashion-tailor": "^10.2.7",
26
- "@zthun/fashion-theme": "^10.2.7",
27
- "@zthun/helpful-fn": "^9.4.5",
28
- "@zthun/helpful-query": "^9.5.0",
29
- "@zthun/helpful-react": "^9.5.0",
24
+ "@zthun/fashion-boutique": "^11.0.1",
25
+ "@zthun/fashion-tailor": "^11.0.1",
26
+ "@zthun/fashion-theme": "^11.0.1",
27
+ "@zthun/helpful-fn": "^9.6.0",
28
+ "@zthun/helpful-query": "^9.7.1",
29
+ "@zthun/helpful-react": "^9.7.1",
30
30
  "@zthun/janitor-build-config": "^19.3.6",
31
- "@zthun/romulator-client": "^1.4.0",
32
- "@zthun/webigail-http": "^4.0.8",
33
- "@zthun/webigail-rest": "^4.0.8",
34
- "@zthun/webigail-url": "^4.0.8",
31
+ "@zthun/romulator-client": "^1.6.0",
32
+ "@zthun/webigail-http": "^4.0.9",
33
+ "@zthun/webigail-rest": "^4.0.9",
34
+ "@zthun/webigail-url": "^4.0.9",
35
35
  "history": "^5.3.0",
36
36
  "lodash-es": "^4.17.21",
37
37
  "react": "^19.2.0",
38
38
  "react-dom": "^19.2.0",
39
39
  "tsconfig-paths": "^4.2.0",
40
40
  "typescript": "^5.9.3",
41
- "vite": "^7.1.9",
41
+ "vite": "^7.1.10",
42
42
  "vitest": "^3.2.4",
43
43
  "vitest-mock-extended": "^3.1.0"
44
44
  },
45
- "gitHead": "1074a358943150732e7fff33a8555e1b0490aab5"
45
+ "gitHead": "9f3e9d22ba3ef2561e18c72a11b8c85f45052438"
46
46
  }
@@ -0,0 +1,74 @@
1
+ import {
2
+ useFashionTheme,
3
+ useNavigate,
4
+ ZBox,
5
+ ZGridView,
6
+ ZImageSource,
7
+ ZStack,
8
+ type IZComponentValue,
9
+ } from "@zthun/fashion-boutique";
10
+ import { ZSizeFixed, ZSizeVaried } from "@zthun/fashion-tailor";
11
+ import { ZDataRequestBuilder, type IZDataRequest } from "@zthun/helpful-query";
12
+ import { useAmbassadorState } from "@zthun/helpful-react";
13
+ import type { IZRomulatorGame } from "@zthun/romulator-client";
14
+ import { ZRomulatorEnvironmentBuilder } from "../environment/environment.mjs";
15
+ import { useGamesService } from "./games-service.mjs";
16
+
17
+ export interface IZRomulatorGamesList extends IZComponentValue<IZDataRequest> {}
18
+
19
+ export function ZRomulatorGamesList(props: IZRomulatorGamesList) {
20
+ const { value, onValueChange } = props;
21
+ const [request, setRequest] = useAmbassadorState(
22
+ value,
23
+ onValueChange,
24
+ new ZDataRequestBuilder().build(),
25
+ );
26
+ const games = useGamesService();
27
+ const { body } = useFashionTheme();
28
+ const navigate = useNavigate();
29
+
30
+ const renderTile = (value: IZRomulatorGame) => {
31
+ const { api } = new ZRomulatorEnvironmentBuilder().build();
32
+ const id = `${value.id}-marquees`;
33
+ const wheel = `${api}/media/${id}`;
34
+
35
+ return (
36
+ <ZBox
37
+ className="ZRomulatorGameTile-root"
38
+ fashion={body}
39
+ interactive
40
+ key={value.id}
41
+ cursor="pointer"
42
+ padding={ZSizeFixed.Small}
43
+ data-name={value.id}
44
+ onClick={() => navigate(`/games/${value.id}`)}
45
+ >
46
+ <ZStack
47
+ justify={{ content: "center" }}
48
+ align={{ items: "center" }}
49
+ height={ZSizeVaried.Full}
50
+ >
51
+ <ZImageSource src={wheel} width={ZSizeVaried.Full} />
52
+ </ZStack>
53
+ </ZBox>
54
+ );
55
+ };
56
+
57
+ return (
58
+ <ZGridView
59
+ GridProps={{
60
+ columns: {
61
+ xl: "1fr 1fr 1fr 1fr",
62
+ lg: "1fr 1fr 1fr",
63
+ md: "1fr 1fr",
64
+ sm: "1fr",
65
+ },
66
+ gap: ZSizeFixed.Medium,
67
+ }}
68
+ dataSource={games}
69
+ renderItem={renderTile}
70
+ value={request}
71
+ onValueChange={setRequest}
72
+ />
73
+ );
74
+ }
@@ -0,0 +1,25 @@
1
+ import type { IZDataSource } from "@zthun/helpful-query";
2
+ import type { IZRomulatorGame } from "@zthun/romulator-client";
3
+ import { ZHttpService } from "@zthun/webigail-http";
4
+ import type { IZRestfulGet } from "@zthun/webigail-rest";
5
+ import { ZRestfulService } from "@zthun/webigail-rest";
6
+ import { ZUrlBuilder } from "@zthun/webigail-url";
7
+ import { createContext, useContext } from "react";
8
+ import { ZRomulatorEnvironmentBuilder } from "../environment/environment.mjs";
9
+
10
+ export interface IZRomulatorGamesService
11
+ extends IZRestfulGet<IZRomulatorGame>,
12
+ IZDataSource<IZRomulatorGame> {}
13
+
14
+ export function createDefaultGamesService(): IZRomulatorGamesService {
15
+ const { api } = new ZRomulatorEnvironmentBuilder().build();
16
+ const endpoint = new ZUrlBuilder().parse(api).append("games").build();
17
+ const http = new ZHttpService();
18
+ return new ZRestfulService<IZRomulatorGame>(http, endpoint);
19
+ }
20
+
21
+ export const ZRomulatorGamesServiceContext = createContext(
22
+ createDefaultGamesService(),
23
+ );
24
+
25
+ export const useGamesService = () => useContext(ZRomulatorGamesServiceContext);
@@ -1,15 +1,21 @@
1
1
  import { ZCircusBy, ZCircusComponentModel } from "@zthun/cirque";
2
2
  import {
3
3
  ZAlertComponentModel,
4
+ ZBoxComponentModel,
5
+ ZCardComponentModel,
6
+ ZGridViewComponentModel,
4
7
  ZSuspenseComponentModel,
5
8
  } from "@zthun/fashion-boutique";
6
- import { ZRomulatorSystemAvatarCardComponentModel } from "./system-avatar-card.cm.mjs";
7
9
 
8
10
  export class ZRomulatorSystemPageComponentModel extends ZCircusComponentModel {
9
11
  public static readonly Selector = ".ZRomulatorSystemPage-root";
10
12
 
11
13
  public async loader(): Promise<ZSuspenseComponentModel | null> {
12
- return ZCircusBy.optional(this.driver, ZSuspenseComponentModel);
14
+ return ZCircusBy.optional(
15
+ this.driver,
16
+ ZSuspenseComponentModel,
17
+ "system-loading",
18
+ );
13
19
  }
14
20
 
15
21
  public async loading(): Promise<boolean> {
@@ -24,10 +30,15 @@ export class ZRomulatorSystemPageComponentModel extends ZCircusComponentModel {
24
30
  return ZCircusBy.optional(this.driver, ZAlertComponentModel);
25
31
  }
26
32
 
27
- public system(): Promise<ZRomulatorSystemAvatarCardComponentModel | null> {
28
- return ZCircusBy.optional(
29
- this.driver,
30
- ZRomulatorSystemAvatarCardComponentModel,
31
- );
33
+ public system(): Promise<ZCardComponentModel | null> {
34
+ return ZCircusBy.optional(this.driver, ZCardComponentModel, "system-info");
35
+ }
36
+
37
+ public games(): Promise<ZGridViewComponentModel | null> {
38
+ return ZCircusBy.optional(this.driver, ZGridViewComponentModel);
39
+ }
40
+
41
+ public game(id: string): Promise<ZBoxComponentModel | null> {
42
+ return ZCircusBy.optional(this.driver, ZBoxComponentModel, id);
32
43
  }
33
44
  }
@@ -13,7 +13,9 @@ import {
13
13
  ZDataSourceStatic,
14
14
  ZFilterBinaryBuilder,
15
15
  } from "@zthun/helpful-query";
16
+ import type { IZRomulatorGame } from "@zthun/romulator-client";
16
17
  import {
18
+ ZRomulatorGameBuilder,
17
19
  ZRomulatorSystemBuilder,
18
20
  ZRomulatorSystemId,
19
21
  } from "@zthun/romulator-client";
@@ -23,6 +25,10 @@ import { noop } from "lodash-es";
23
25
  import type { Mocked } from "vitest";
24
26
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
25
27
  import { mock } from "vitest-mock-extended";
28
+ import {
29
+ ZRomulatorGamesServiceContext,
30
+ type IZRomulatorGamesService,
31
+ } from "../games/games-service.mjs";
26
32
  import { ZRomulatorSystemPageComponentModel } from "./system-page.cm.mjs";
27
33
  import { ZRomulatorSystemPage } from "./system-page.js";
28
34
  import type { IZRomulatorSystemsService } from "./systems-service.mjs";
@@ -35,11 +41,29 @@ interface ZRomulatorSystemPageProps {
35
41
  describe("SystemPage", () => {
36
42
  const nes = new ZRomulatorSystemBuilder()
37
43
  .id(ZRomulatorSystemId.Nintendo)
44
+ .name("Nintendo Entertainment System")
45
+ .build();
46
+
47
+ const batman = new ZRomulatorGameBuilder()
48
+ .id("nes-batman")
49
+ .name("Batman")
50
+ .system(ZRomulatorSystemId.Nintendo)
51
+ .build();
52
+ const mario = new ZRomulatorGameBuilder()
53
+ .id("nes-super-mario-bros")
54
+ .name("Super Mario Bros.")
55
+ .system(ZRomulatorSystemId.Nintendo)
56
+ .build();
57
+ const superMetroid = new ZRomulatorGameBuilder()
58
+ .id("snes-super-metroid")
59
+ .name("Super Metroid")
60
+ .system(ZRomulatorSystemId.SuperNintendo)
38
61
  .build();
39
62
 
40
63
  let _driver: IZCircusDriver;
41
64
  let _renderer: IZCircusSetup;
42
65
  let _systems: Mocked<IZRomulatorSystemsService>;
66
+ let _games: Mocked<IZRomulatorGamesService>;
43
67
 
44
68
  beforeEach(() => {
45
69
  const source = new ZDataSourceStatic([nes]);
@@ -56,6 +80,16 @@ describe("SystemPage", () => {
56
80
 
57
81
  return required(item);
58
82
  });
83
+
84
+ const __games = new ZDataSourceStatic<IZRomulatorGame>([
85
+ batman,
86
+ mario,
87
+ superMetroid,
88
+ ]);
89
+
90
+ _games = mock<IZRomulatorGamesService>();
91
+ _games.retrieve.mockImplementation(async (req) => __games.retrieve(req));
92
+ _games.count.mockImplementation(async (req) => __games.count(req));
59
93
  });
60
94
 
61
95
  afterEach(async () => {
@@ -63,19 +97,23 @@ describe("SystemPage", () => {
63
97
  await _renderer?.destroy?.call(_renderer);
64
98
  });
65
99
 
100
+ function createSystemMemoryHistory(system: string) {
101
+ return createMemoryHistory({ initialEntries: [`/systems/${system}`] });
102
+ }
103
+
66
104
  async function createTestTarget(props: ZRomulatorSystemPageProps = {}) {
67
- const {
68
- history = createMemoryHistory({ initialEntries: [`/systems/${nes.id}`] }),
69
- } = props;
105
+ const { history = createSystemMemoryHistory(nes.id) } = props;
70
106
 
71
107
  const element = (
72
108
  <ZRomulatorSystemsServiceContext value={_systems}>
73
- <ZTestRouter navigator={history} location={history.location}>
74
- <ZRouteMap>
75
- <ZRoute path="/systems/:id" element={<ZRomulatorSystemPage />} />
76
- <ZRoute path="*" element={<ZNotFound />} />
77
- </ZRouteMap>
78
- </ZTestRouter>
109
+ <ZRomulatorGamesServiceContext value={_games}>
110
+ <ZTestRouter navigator={history} location={history.location}>
111
+ <ZRouteMap>
112
+ <ZRoute path="/systems/:id" element={<ZRomulatorSystemPage />} />
113
+ <ZRoute path="*" element={<ZNotFound />} />
114
+ </ZRouteMap>
115
+ </ZTestRouter>
116
+ </ZRomulatorGamesServiceContext>
79
117
  </ZRomulatorSystemsServiceContext>
80
118
  );
81
119
 
@@ -101,9 +139,7 @@ describe("SystemPage", () => {
101
139
  describe("Error", () => {
102
140
  it("should show an error alert if the system cannot be found", async () => {
103
141
  // Arrange.
104
- const history = createMemoryHistory({
105
- initialEntries: ["/systems/does-not-exist"],
106
- });
142
+ const history = createSystemMemoryHistory("does-not-exist");
107
143
  const target = await createTestTarget({ history });
108
144
  await target.load();
109
145
 
@@ -122,11 +158,58 @@ describe("SystemPage", () => {
122
158
  await target.load();
123
159
 
124
160
  // Act.
125
- const system = await target.system();
126
- const actual = await system?.id();
161
+ const actual = await target.system();
162
+
163
+ // Assert.
164
+ expect(actual).toBeTruthy();
165
+ });
166
+
167
+ it("should render the games list", async () => {
168
+ // Arrange.
169
+ const target = await createTestTarget();
170
+ await target.load();
171
+
172
+ // Act.
173
+ const actual = target.games();
174
+
175
+ // Assert.
176
+ expect(actual).toBeTruthy();
177
+ });
178
+ });
179
+
180
+ describe("Games", () => {
181
+ it("should only load games that are assigned to the given system", async () => {
182
+ // Arrange.
183
+ const target = await createTestTarget();
184
+ await target.load();
185
+ const games = await target.games();
186
+ await games?.load();
187
+
188
+ // Act.
189
+ const _batman = await target.game(batman.id);
190
+ const _mario = await target.game(mario.id);
191
+ const _metroid = await target.game(superMetroid.id);
192
+
193
+ // Assert.
194
+ expect(_batman).toBeTruthy();
195
+ expect(_mario).toBeTruthy();
196
+ expect(_metroid).toBeFalsy();
197
+ });
198
+
199
+ it("should navigate to the games page when clicked", async () => {
200
+ // Arrange.
201
+ const history = createSystemMemoryHistory(nes.id);
202
+ const target = await createTestTarget({ history });
203
+ await target.load();
204
+ const games = await target.games();
205
+ await games?.load();
206
+
207
+ // Act.
208
+ const _batman = await target.game(batman.id);
209
+ await _batman?.click();
127
210
 
128
211
  // Assert.
129
- expect(actual).toEqual(nes.id);
212
+ expect(history.location.pathname).toEqual(`/games/${batman.id}`);
130
213
  });
131
214
  });
132
215
  });
@@ -3,23 +3,48 @@ import {
3
3
  useParams,
4
4
  ZAlert,
5
5
  ZBreadcrumbsLocation,
6
+ ZCard,
7
+ ZIconFontAwesome,
6
8
  ZStack,
7
9
  ZSuspenseProgress,
8
10
  } from "@zthun/fashion-boutique";
9
11
  import { ZSizeFixed } from "@zthun/fashion-tailor";
10
- import { cssJoinDefined, firstDefined } from "@zthun/helpful-fn";
11
- import { isStateErrored, isStateLoading } from "@zthun/helpful-react";
12
- import { ZRomulatorSystemAvatarCard } from "./system-avatar-card.js";
12
+ import { firstDefined } from "@zthun/helpful-fn";
13
+ import {
14
+ ZDataRequestBuilder,
15
+ ZFilterBinaryBuilder,
16
+ } from "@zthun/helpful-query";
17
+ import {
18
+ isStateErrored,
19
+ isStateLoading,
20
+ useSyncState,
21
+ } from "@zthun/helpful-react";
22
+ import { useMemo } from "react";
23
+ import { ZRomulatorGamesList } from "../games/games-list.js";
13
24
  import { useSystem } from "./systems-service.mjs";
14
25
 
15
26
  export function ZRomulatorSystemPage() {
16
27
  const { id } = useParams();
17
28
  const { error } = useFashionTheme();
18
29
  const [system] = useSystem(firstDefined("", id));
30
+ const gameFilter = useMemo(
31
+ () =>
32
+ new ZFilterBinaryBuilder().subject("system").equal().value(id).build(),
33
+ [id],
34
+ );
35
+
36
+ const baseGameRequest = useMemo(
37
+ () => new ZDataRequestBuilder().filter(gameFilter).build(),
38
+ [gameFilter],
39
+ );
40
+
41
+ const [userRequest, setGameRequest] = useSyncState(baseGameRequest);
19
42
 
20
43
  const renderSystemInformation = () => {
21
44
  if (isStateLoading(system)) {
22
- return <ZSuspenseProgress height={ZSizeFixed.Large} />;
45
+ return (
46
+ <ZSuspenseProgress name="system-loading" height={ZSizeFixed.Large} />
47
+ );
23
48
  }
24
49
 
25
50
  if (isStateErrored(system)) {
@@ -32,14 +57,39 @@ export function ZRomulatorSystemPage() {
32
57
  );
33
58
  }
34
59
 
35
- return <ZRomulatorSystemAvatarCard system={system} />;
60
+ return (
61
+ <ZStack gap={ZSizeFixed.Medium}>
62
+ <ZCard
63
+ name="system-info"
64
+ TitleProps={{
65
+ avatar: (
66
+ <ZIconFontAwesome name="puzzle-piece" width={ZSizeFixed.Medium} />
67
+ ),
68
+ heading: system.name,
69
+ subHeading: `Generation ${system.generation}`,
70
+ }}
71
+ />
72
+ <ZCard
73
+ name="game-list"
74
+ TitleProps={{
75
+ avatar: (
76
+ <ZIconFontAwesome name="gamepad" width={ZSizeFixed.Medium} />
77
+ ),
78
+ heading: "Games",
79
+ subHeading: `Your ${system.name} Games`,
80
+ }}
81
+ >
82
+ <ZRomulatorGamesList
83
+ value={userRequest}
84
+ onValueChange={setGameRequest}
85
+ />
86
+ </ZCard>
87
+ </ZStack>
88
+ );
36
89
  };
37
90
 
38
91
  return (
39
- <ZStack
40
- gap={ZSizeFixed.Medium}
41
- className={cssJoinDefined("ZRomulatorSystemPage-root")}
42
- >
92
+ <ZStack gap={ZSizeFixed.Medium} className={"ZRomulatorSystemPage-root"}>
43
93
  <ZBreadcrumbsLocation />
44
94
 
45
95
  {renderSystemInformation()}
@@ -1,18 +1,15 @@
1
1
  import {
2
- useCss,
3
2
  useFashionTheme,
4
3
  useNavigate,
5
4
  ZBox,
6
5
  ZBreadcrumbsLocation,
7
6
  ZCard,
8
- ZContentTitle,
9
7
  ZGridView,
10
8
  ZIconFontAwesome,
11
9
  ZImageSource,
12
10
  ZStack,
13
11
  } from "@zthun/fashion-boutique";
14
12
  import { ZSizeFixed, ZSizeVaried } from "@zthun/fashion-tailor";
15
- import { css, cssJoinDefined, ZOrientation } from "@zthun/helpful-fn";
16
13
  import { ZDataRequestBuilder, ZSortBuilder } from "@zthun/helpful-query";
17
14
  import type { IZRomulatorSystem } from "@zthun/romulator-client";
18
15
  import { useState } from "react";
@@ -31,15 +28,9 @@ const DefaultSystemRequest = new ZDataRequestBuilder()
31
28
  export function ZRomulatorSystemsPage() {
32
29
  const { body } = useFashionTheme();
33
30
  const navigate = useNavigate();
34
- const source = useSystemsService();
31
+ const systems = useSystemsService();
35
32
  const [request, setRequest] = useState(DefaultSystemRequest);
36
33
 
37
- const tile = useCss(css`
38
- & {
39
- height: 100%;
40
- }
41
- `);
42
-
43
34
  const renderTile = (system: IZRomulatorSystem) => {
44
35
  const { api } = new ZRomulatorEnvironmentBuilder().build();
45
36
  const id = `${system.id}-wheel`;
@@ -57,21 +48,11 @@ export function ZRomulatorSystemsPage() {
57
48
  onClick={() => navigate(system.id)}
58
49
  >
59
50
  <ZStack
60
- className={cssJoinDefined(tile)}
61
- gap={ZSizeFixed.Medium}
62
- orientation={ZOrientation.Horizontal}
63
51
  justify={{ content: "center" }}
64
52
  align={{ items: "center" }}
53
+ height={ZSizeVaried.Full}
65
54
  >
66
- <ZContentTitle
67
- avatar={
68
- <ZImageSource
69
- src={wheel}
70
- height={ZSizeVaried.Full}
71
- width={ZSizeVaried.Full}
72
- />
73
- }
74
- />
55
+ <ZImageSource src={wheel} width={ZSizeVaried.Full} />
75
56
  </ZStack>
76
57
  </ZBox>
77
58
  );
@@ -101,10 +82,10 @@ export function ZRomulatorSystemsPage() {
101
82
  },
102
83
  gap: ZSizeFixed.Medium,
103
84
  }}
85
+ dataSource={systems}
86
+ renderItem={renderTile}
104
87
  value={request}
105
88
  onValueChange={setRequest}
106
- dataSource={source}
107
- renderItem={renderTile}
108
89
  />
109
90
  </ZCard>
110
91
  </ZStack>
@@ -1,17 +0,0 @@
1
- import { ZCircusComponentModel } from "@zthun/cirque";
2
- import { ZCardComponentModel } from "@zthun/fashion-boutique";
3
- import { firstDefined } from "@zthun/helpful-fn";
4
-
5
- export class ZRomulatorSystemAvatarCardComponentModel extends ZCircusComponentModel {
6
- public static readonly Selector = ".ZRomulatorSystemCard-root";
7
-
8
- public card(): Promise<ZCardComponentModel> {
9
- return Promise.resolve(new ZCardComponentModel(this.driver));
10
- }
11
-
12
- public async id(): Promise<string> {
13
- const card = await this.card();
14
- const name = await card.driver.attribute("data-name");
15
- return firstDefined("", name);
16
- }
17
- }
@@ -1,39 +0,0 @@
1
- import type { IZCard } from "@zthun/fashion-boutique";
2
- import { useCss, ZCard, ZImageSource, ZStack } from "@zthun/fashion-boutique";
3
- import { ZSizeFixed } from "@zthun/fashion-tailor";
4
- import { css, cssJoinDefined, ZOrientation } from "@zthun/helpful-fn";
5
-
6
- export interface IZRomulatorSystemAvatarCard {
7
- system: any;
8
-
9
- CardProps?: Pick<IZCard, "footer">;
10
- }
11
-
12
- export function ZRomulatorSystemAvatarCard(props: IZRomulatorSystemAvatarCard) {
13
- const { system, CardProps } = props;
14
- const src = `/systems/wheel/${system.id}.png`;
15
-
16
- const _className = useCss(css`
17
- &.ZRomulatorSystemCard-root .ZRomulatorSystemCard-avatar {
18
- height: 100%;
19
- width: 100%;
20
- }
21
- `);
22
-
23
- return (
24
- <ZCard
25
- className={cssJoinDefined("ZRomulatorSystemCard-root", _className)}
26
- name={system.id}
27
- {...CardProps}
28
- >
29
- <ZStack
30
- className="ZRomulatorSystemCard-avatar"
31
- orientation={ZOrientation.Horizontal}
32
- justify={{ content: "center", items: "center" }}
33
- align={{ content: "center", items: "center" }}
34
- >
35
- <ZImageSource src={src} width={ZSizeFixed.ExtraLarge} />
36
- </ZStack>
37
- </ZCard>
38
- );
39
- }