@articles-media/articles-dev-box 1.0.41 → 1.1.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/README.md CHANGED
@@ -67,6 +67,8 @@ npm run dev
67
67
  - Handles setting zustand state from url params if toontownMode is passed.
68
68
  - SocketServerUrlHandler
69
69
  - Handles setting socket server state from url params if socketServerUrl is passed.
70
+ - HasNoMouseHandler
71
+ - Sets hasNoMouse and isTouchCapable on first load
70
72
  - useUserToken
71
73
  - Hook for getting the subdomain auth token.
72
74
  - useUserDetails
@@ -89,6 +91,14 @@ For newly developed components I sometimes find myself trying to remember what r
89
91
  - getSignOutRedirectUrl - Catching Game
90
92
  - GameMenuPrimaryButtonGroup - Catching Game and Move Match
91
93
  - NicknameInput - Catching Game
94
+ - InfoModal - USA Tycoon
95
+ - GlobalClientModals - USA Tycoon
96
+ - generateRandomNickname - USA Tycoon
97
+ - defaultGameNextConfig - USA Tycoon
98
+ - defaultGameThemeConfig - USA Tycoon
99
+ - useModalNavigation - USA Tycoon
100
+ - gameLandingPageTemplate - USA Tycoon
101
+ - gamePageTemplate - USA Tycoon
92
102
 
93
103
  # Roadmap
94
104
  ⏹️ Remove Bootstrap reliance?
@@ -7,18 +7,6 @@ var import_classnames = /* @__PURE__ */ __toESM(require_classnames(), 1);
7
7
  function MobileMenu({ useStore, LeftPanelContent, menuBarConfig }) {
8
8
  const showMenu = useStore((state) => state.showMenu);
9
9
  const setShowMenu = useStore((state) => state.setShowMenu);
10
- const MenuButton = () => /* @__PURE__ */ jsxs(ArticlesButton, {
11
- small: true,
12
- active: showMenu,
13
- onClick: () => {
14
- setShowMenu(!showMenu);
15
- },
16
- className: "d-flex",
17
- children: [/* @__PURE__ */ jsx("i", { className: "fad fa-bars" }), /* @__PURE__ */ jsx("span", {
18
- className: "text",
19
- children: "Menu"
20
- })]
21
- });
22
10
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
23
11
  className: (0, import_classnames.default)(`menu-bar ${menuBarConfig.menuBarClassName || ""}`, {
24
12
  "card card-articles p-1 justify-content-center": menuBarConfig.style == "Bar",
@@ -30,19 +18,28 @@ function MobileMenu({ useStore, LeftPanelContent, menuBarConfig }) {
30
18
  ...menuBarConfig.style == "Bar" && { borderRadius: "0px" }
31
19
  },
32
20
  children: /* @__PURE__ */ jsxs("div", {
33
- className: "flex-header align-items-center",
21
+ className: "menu-bar-container flex-header align-items-center",
34
22
  children: [
35
23
  /* @__PURE__ */ jsxs("div", {
36
24
  className: "Left d-flex align-items-center",
37
- children: [(menuBarConfig.menuBarButtonPosition == "Left" || !menuBarConfig.menuBarButtonPosition) && /* @__PURE__ */ jsx(MenuButton, {}), menuBarConfig.leftSlotChildren && menuBarConfig.leftSlotChildren]
25
+ children: [(menuBarConfig.menuBarButtonPosition == "Left" || !menuBarConfig.menuBarButtonPosition) && /* @__PURE__ */ jsx(MenuButton, {
26
+ useStore,
27
+ menuBarConfig
28
+ }), menuBarConfig.leftSlotChildren && menuBarConfig.leftSlotChildren]
38
29
  }),
39
30
  /* @__PURE__ */ jsxs("div", {
40
31
  className: "Center d-flex align-items-center",
41
- children: [menuBarConfig.menuBarButtonPosition == "Center" && /* @__PURE__ */ jsx(MenuButton, {}), menuBarConfig.centerSlotChildren && menuBarConfig.centerSlotChildren]
32
+ children: [menuBarConfig.menuBarButtonPosition == "Center" && /* @__PURE__ */ jsx(MenuButton, {
33
+ useStore,
34
+ menuBarConfig
35
+ }), menuBarConfig.centerSlotChildren && menuBarConfig.centerSlotChildren]
42
36
  }),
43
37
  /* @__PURE__ */ jsxs("div", {
44
38
  className: "Right d-flex align-items-center",
45
- children: [menuBarConfig.menuBarButtonPosition == "Right" && /* @__PURE__ */ jsx(MenuButton, {}), menuBarConfig.rightSlotChildren && menuBarConfig.rightSlotChildren]
39
+ children: [menuBarConfig.menuBarButtonPosition == "Right" && /* @__PURE__ */ jsx(MenuButton, {
40
+ useStore,
41
+ menuBarConfig
42
+ }), menuBarConfig.rightSlotChildren && menuBarConfig.rightSlotChildren]
46
43
  })
47
44
  ]
48
45
  })
@@ -65,6 +62,29 @@ function MobileMenu({ useStore, LeftPanelContent, menuBarConfig }) {
65
62
  })
66
63
  })] });
67
64
  }
65
+ function MenuButton({ useStore, menuBarConfig }) {
66
+ const showMenu = useStore((state) => state.showMenu);
67
+ const setShowMenu = useStore((state) => state.setShowMenu);
68
+ const setShowSettingsModal = useStore((state) => state.setShowSettingsModal);
69
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(ArticlesButton, {
70
+ small: true,
71
+ active: showMenu,
72
+ onClick: () => {
73
+ console.log("Menu button clicked, toggling menu visibility");
74
+ setShowMenu(!showMenu);
75
+ },
76
+ className: "d-flex",
77
+ children: [/* @__PURE__ */ jsx("i", { className: "fad fa-bars" }), /* @__PURE__ */ jsx("span", {
78
+ className: "text",
79
+ children: "Menu"
80
+ })]
81
+ }), menuBarConfig?.settingsWithMenuButton && /* @__PURE__ */ jsx(ArticlesButton, {
82
+ onClick: () => {
83
+ setShowSettingsModal(true);
84
+ },
85
+ children: /* @__PURE__ */ jsx("i", { className: "fad fa-cog" })
86
+ })] });
87
+ }
68
88
  //#endregion
69
89
  //#region src/components/Games/GameMenu/GameMenu.jsx
70
90
  /**
package/dist/GameMenu.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as GameMenu } from "./GameMenu-CyW1MF3Y.js";
1
+ import { t as GameMenu } from "./GameMenu-DeFdYvvR.js";
2
2
  export { GameMenu as default };
@@ -2,6 +2,13 @@ import { t as ArticlesButton } from "./Button-DvEZjsVV.js";
2
2
  import useFullscreen from "./useFullscreen.js";
3
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region src/components/Games/GameMenuPrimaryButtonGroup.jsx
5
+ /**
6
+ * @param {Object} props
7
+ * @param {function} props.useStore Zustand store hook
8
+ * @param {('Landing'|'GameMenu')} props.type Only "Landing" or "GameMenu" allowed
9
+ * @param {string} [props.owner] Optional GitHub owner
10
+ * @param {string} [props.repo] Optional GitHub repo
11
+ */
5
12
  function PrimaryButtonGroup({ useStore, type, owner, repo }) {
6
13
  if (!useStore) return null;
7
14
  const { isFullscreen, requestFullscreen, exitFullscreen } = useFullscreen();
@@ -0,0 +1,57 @@
1
+ "use client";
2
+ import useUserDetails from "./useUserDetails.js";
3
+ import useUserToken from "./useUserToken.js";
4
+ import { lazy } from "react";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/Global/GlobalClientModals.jsx
7
+ var InfoModal = lazy(() => import("./InfoModal.js"));
8
+ var CreditsModal = lazy(() => import("./CreditsModal.js"));
9
+ var FriendsList = lazy(() => import("./FriendsList.js"));
10
+ var SettingsModal = lazy(() => import("./SettingsModal.js"));
11
+ function GlobalClientModals({ useStore, useAudioStore, useTouchControlsStore, useSocketStore, packageInfo, settingsModalConfig, infoModalConfig }) {
12
+ const showInfoModal = useStore((state) => state.showInfoModal);
13
+ const setShowInfoModal = useStore((state) => state.setShowInfoModal);
14
+ const showSettingsModal = useStore((state) => state.showSettingsModal);
15
+ const setShowSettingsModal = useStore((state) => state.setShowSettingsModal);
16
+ const showCreditsModal = useStore((state) => state.showCreditsModal);
17
+ const setShowCreditsModal = useStore((state) => state.setShowCreditsModal);
18
+ const showFriendsModal = useStore((state) => state.showFriendsModal);
19
+ const setShowFriendsModal = useStore((state) => state.setShowFriendsModal);
20
+ const { data: userToken, error: userTokenError, isLoading: userTokenLoading, mutate: userTokenMutate } = useUserToken(process.env.NEXT_PUBLIC_GAME_PORT);
21
+ const { data: userDetails, error: userDetailsError, isLoading: userDetailsLoading, mutate: userDetailsMutate } = useUserDetails({ token: userToken });
22
+ if (!settingsModalConfig) {
23
+ console.error("GlobalClientModals: settingsModalConfig is not provided!");
24
+ return;
25
+ }
26
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
27
+ showInfoModal && /* @__PURE__ */ jsx(InfoModal, {
28
+ show: showInfoModal,
29
+ setShow: setShowInfoModal,
30
+ useStore,
31
+ packageInfo,
32
+ infoModalConfig
33
+ }),
34
+ showSettingsModal && /* @__PURE__ */ jsx(SettingsModal, {
35
+ show: showSettingsModal,
36
+ setShow: setShowSettingsModal,
37
+ store: useStore,
38
+ useAudioStore,
39
+ useTouchControlsStore,
40
+ useSocketStore,
41
+ config: settingsModalConfig
42
+ }),
43
+ showCreditsModal && /* @__PURE__ */ jsx(CreditsModal, {
44
+ show: showCreditsModal,
45
+ setShow: setShowCreditsModal
46
+ }),
47
+ showFriendsModal && /* @__PURE__ */ jsx(FriendsList, {
48
+ componentType: "modal",
49
+ show: showFriendsModal,
50
+ setShow: setShowFriendsModal,
51
+ user_id: userDetails ? userDetails.user_id : null,
52
+ user_token: userToken ? userToken : null
53
+ })
54
+ ] });
55
+ }
56
+ //#endregion
57
+ export { GlobalClientModals as default };
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ import { Fragment, jsx } from "react/jsx-runtime";
4
+ //#region src/components/Handlers/HasNoMouseHandler.jsx
5
+ function HasNoMouseHandler({ useStore }) {
6
+ const hasHydrated = useStore((state) => state._hasHydrated);
7
+ const hasNoMouse = useStore((state) => state.hasNoMouse);
8
+ const setHasNoMouse = useStore((state) => state.setHasNoMouse);
9
+ const isTouchCapable = useStore((state) => state.isTouchCapable);
10
+ const setIsTouchCapable = useStore((state) => state.setIsTouchCapable);
11
+ useEffect(() => {
12
+ if (!hasHydrated) return;
13
+ if (hasNoMouse === null) {
14
+ const hasMouse = window.matchMedia("(pointer: fine)").matches;
15
+ setHasNoMouse(!hasMouse);
16
+ }
17
+ if (isTouchCapable === null) setIsTouchCapable("ontouchstart" in window || navigator.maxTouchPoints > 0);
18
+ }, [
19
+ hasHydrated,
20
+ hasNoMouse,
21
+ isTouchCapable,
22
+ setHasNoMouse,
23
+ setIsTouchCapable
24
+ ]);
25
+ return /* @__PURE__ */ jsx(Fragment, {});
26
+ }
27
+ //#endregion
28
+ export { HasNoMouseHandler as default };
@@ -0,0 +1,58 @@
1
+ import { t as ArticlesButton } from "./Button-DvEZjsVV.js";
2
+ import { useRef, useState } from "react";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { Modal } from "react-bootstrap";
5
+ //#region src/components/Games/InfoModal.jsx
6
+ function InfoModal({ show, setShow, useStore, packageInfo, infoModalConfig }) {
7
+ const [showModal, setShowModal] = useState(true);
8
+ const darkMode = useStore((state) => state.darkMode);
9
+ useRef([]);
10
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Modal, {
11
+ className: "articles-modal games-info-modal",
12
+ size: "md",
13
+ show: showModal,
14
+ centered: true,
15
+ scrollable: true,
16
+ onExited: () => {
17
+ setShow(false);
18
+ },
19
+ onHide: () => {
20
+ setShowModal(false);
21
+ },
22
+ children: [
23
+ /* @__PURE__ */ jsx(Modal.Header, {
24
+ closeButton: true,
25
+ children: /* @__PURE__ */ jsxs(Modal.Title, { children: [process.env.NEXT_PUBLIC_GAME_NAME, " Info"] })
26
+ }),
27
+ /* @__PURE__ */ jsxs(Modal.Body, {
28
+ className: "flex-column p-0",
29
+ children: [/* @__PURE__ */ jsx("div", {
30
+ className: "ratio ratio-16x9",
31
+ children: darkMode ? /* @__PURE__ */ jsx("img", { src: infoModalConfig?.previewImage }) : /* @__PURE__ */ jsx("img", { src: infoModalConfig?.previewImage })
32
+ }), /* @__PURE__ */ jsx("div", {
33
+ className: "p-3",
34
+ children: /* @__PURE__ */ jsx("div", {
35
+ className: "",
36
+ children: packageInfo?.description
37
+ })
38
+ })]
39
+ }),
40
+ /* @__PURE__ */ jsxs(Modal.Footer, {
41
+ className: "justify-content-between",
42
+ children: [/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", {
43
+ className: "version small",
44
+ children: ["Version: ", packageInfo?.version]
45
+ }) }), /* @__PURE__ */ jsx(ArticlesButton, {
46
+ variant: "outline-dark",
47
+ onClick: () => {
48
+ setShow(false);
49
+ },
50
+ className: "d-flex align-items-center",
51
+ children: "Close"
52
+ })]
53
+ })
54
+ ]
55
+ }) });
56
+ }
57
+ //#endregion
58
+ export { InfoModal as default };
@@ -0,0 +1,195 @@
1
+ "use client";
2
+ import { t as ArticlesButton } from "./Button-DvEZjsVV.js";
3
+ import useUserDetails from "./useUserDetails.js";
4
+ import useUserToken from "./useUserToken.js";
5
+ import PrimaryButtonGroup from "./GameMenuPrimaryButtonGroup.js";
6
+ import NicknameInput from "./NicknameInput.js";
7
+ import { lazy } from "react";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/components/Games/PageTemplates/PageTemplateLandingPage.jsx
10
+ var SessionButton = lazy(() => import("./SessionButton.js"));
11
+ var ReturnToLauncherButton = lazy(() => import("./ReturnToLauncherButton.js"));
12
+ var GameScoreboard = lazy(() => import("./GameScoreboard.js"));
13
+ var Ad = lazy(() => import("./Ad.js"));
14
+ function PageTemplateLandingPage({ useStore, useSocketStore, RotatingMascot, Link, logoImage, backgroundImage, CardBodyOverride, singlePlayerConfig, multiplayerConfig, brandingTextClass, disableHero, disableAd, disableGameScoreboard, maxInnerWidth = "20rem", AdditionalContent = null, PostCardContent = null, PostExtrasContent = null, PreHeroContent = null, PostHeroContent = null }) {
15
+ const { data: userToken, error: userTokenError, isLoading: userTokenLoading, mutate: userTokenMutate } = useUserToken(process.env.NEXT_PUBLIC_GAME_PORT);
16
+ const { data: userDetails, error: userDetailsError, isLoading: userDetailsLoading, mutate: userDetailsMutate } = useUserDetails({ token: userToken });
17
+ const darkMode = useStore((state) => state.darkMode);
18
+ const lobbyDetails = useStore((state) => state.lobbyDetails);
19
+ return /* @__PURE__ */ jsxs("div", {
20
+ className: "landing-page",
21
+ children: [
22
+ AdditionalContent,
23
+ /* @__PURE__ */ jsx("div", {
24
+ className: "background-wrap",
25
+ children: /* @__PURE__ */ jsx("img", {
26
+ src: backgroundImage,
27
+ alt: "",
28
+ width: "100%",
29
+ height: "100%",
30
+ style: {
31
+ objectFit: "cover",
32
+ objectPosition: "bottom"
33
+ }
34
+ })
35
+ }),
36
+ /* @__PURE__ */ jsxs("div", {
37
+ className: "container d-flex flex-column-reverse flex-lg-row justify-content-center align-items-center py-3",
38
+ children: [
39
+ /* @__PURE__ */ jsxs("div", {
40
+ className: "",
41
+ style: { "width": maxInnerWidth },
42
+ children: [
43
+ PreHeroContent,
44
+ !disableHero && /* @__PURE__ */ jsxs("div", {
45
+ className: "landing-hero text-center mb-2",
46
+ children: [/* @__PURE__ */ jsx("img", {
47
+ src: logoImage,
48
+ alt: "",
49
+ width: "200",
50
+ height: "auto",
51
+ style: {
52
+ objectFit: "cover",
53
+ objectPosition: "bottom"
54
+ }
55
+ }), /* @__PURE__ */ jsx("h1", {
56
+ className: `text-center mb-0 ${brandingTextClass}`,
57
+ children: process.env.NEXT_PUBLIC_GAME_NAME
58
+ })]
59
+ }),
60
+ PostHeroContent,
61
+ /* @__PURE__ */ jsxs("div", {
62
+ className: "card card-articles mb-3",
63
+ children: [
64
+ /* @__PURE__ */ jsx("div", {
65
+ className: "card-header",
66
+ children: /* @__PURE__ */ jsx(NicknameInput, { useStore })
67
+ }),
68
+ CardBodyOverride ? /* @__PURE__ */ jsx(CardBodyOverride, {}) : /* @__PURE__ */ jsxs("div", {
69
+ className: "card-body",
70
+ children: [singlePlayerConfig && /* @__PURE__ */ jsx(Link, {
71
+ href: "/play",
72
+ style: { textDecoration: "none" },
73
+ children: /* @__PURE__ */ jsxs(ArticlesButton, {
74
+ variant: "",
75
+ className: "d-flex justify-content-center align-items-center mb-3 w-100",
76
+ onClick: () => {},
77
+ children: [/* @__PURE__ */ jsx("i", { className: "fad fa-play me-2" }), "Single Player"]
78
+ })
79
+ }), multiplayerConfig && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
80
+ className: "fw-bold mb-1 small text-center",
81
+ children: [
82
+ lobbyDetails?.players.length || 0,
83
+ " player",
84
+ lobbyDetails?.players.length !== 1 && "s",
85
+ " in the lobby."
86
+ ]
87
+ }), /* @__PURE__ */ jsx("div", {
88
+ className: "servers",
89
+ children: Array.from({ length: multiplayerConfig?.defaultServers }).map((_, id) => {
90
+ let lobbyLookup = lobbyDetails?.games?.find((lobby) => parseInt(lobby.server_id) == id);
91
+ return /* @__PURE__ */ jsxs("div", {
92
+ className: "server",
93
+ children: [
94
+ /* @__PURE__ */ jsxs("div", {
95
+ className: "d-flex justify-content-between align-items-center w-100 mb-2",
96
+ children: [/* @__PURE__ */ jsx("div", {
97
+ className: "mb-0",
98
+ style: { fontSize: "0.9rem" },
99
+ children: /* @__PURE__ */ jsxs("b", { children: ["Server ", id] })
100
+ }), /* @__PURE__ */ jsxs("div", {
101
+ className: "mb-0",
102
+ children: [lobbyLookup?.players?.length || 0, "/4"]
103
+ })]
104
+ }),
105
+ /* @__PURE__ */ jsx("div", {
106
+ className: "d-flex justify-content-around w-100 mb-1",
107
+ children: [
108
+ 1,
109
+ 2,
110
+ 3,
111
+ 4
112
+ ].map((player_count) => {
113
+ let playerLookup = false;
114
+ if (lobbyLookup?.players?.length >= player_count) playerLookup = true;
115
+ return /* @__PURE__ */ jsx("div", {
116
+ className: "icon",
117
+ style: {
118
+ width: "20px",
119
+ height: "20px",
120
+ ...playerLookup ? { backgroundColor: "black" } : { backgroundColor: "gray" },
121
+ border: "1px solid black"
122
+ }
123
+ }, player_count);
124
+ })
125
+ }),
126
+ /* @__PURE__ */ jsx(Link, {
127
+ className: ``,
128
+ href: {
129
+ pathname: `/play`,
130
+ query: { server: id }
131
+ },
132
+ style: { ...multiplayerConfig?.comingSoon ? { pointerEvents: "none" } : {} },
133
+ children: /* @__PURE__ */ jsx(ArticlesButton, {
134
+ small: true,
135
+ className: "px-3",
136
+ disabled: multiplayerConfig?.comingSoon,
137
+ children: multiplayerConfig?.comingSoon ? "Coming Soon" : "Join Game"
138
+ })
139
+ })
140
+ ]
141
+ }, id);
142
+ })
143
+ })] })]
144
+ }),
145
+ /* @__PURE__ */ jsx("div", {
146
+ className: "card-footer d-flex flex-wrap justify-content-center",
147
+ children: /* @__PURE__ */ jsx(PrimaryButtonGroup, {
148
+ useStore,
149
+ type: "Landing"
150
+ })
151
+ })
152
+ ]
153
+ }),
154
+ PostCardContent,
155
+ /* @__PURE__ */ jsxs("div", {
156
+ className: "extras",
157
+ children: [/* @__PURE__ */ jsx(SessionButton, {
158
+ port: process.env.NEXT_PUBLIC_GAME_PORT,
159
+ friendsButton: true
160
+ }), /* @__PURE__ */ jsx(ReturnToLauncherButton, {})]
161
+ }),
162
+ PostExtrasContent
163
+ ]
164
+ }),
165
+ !disableGameScoreboard && /* @__PURE__ */ jsx(GameScoreboard, {
166
+ game: process.env.NEXT_PUBLIC_GAME_NAME,
167
+ style: "Default",
168
+ darkMode: darkMode ? true : false,
169
+ prepend: RotatingMascot && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("div", {
170
+ style: {
171
+ width: "100%",
172
+ height: "200px",
173
+ display: "flex",
174
+ justifyContent: "center",
175
+ alignItems: "center"
176
+ },
177
+ children: /* @__PURE__ */ jsx(RotatingMascot, {})
178
+ }) })
179
+ }),
180
+ !disableAd && /* @__PURE__ */ jsx(Ad, {
181
+ style: "Default",
182
+ section: "Games",
183
+ section_id: process.env.NEXT_PUBLIC_GAME_NAME,
184
+ darkMode: darkMode ? true : false,
185
+ user_ad_token: userToken,
186
+ userDetails,
187
+ userDetailsLoading
188
+ })
189
+ ]
190
+ })
191
+ ]
192
+ });
193
+ }
194
+ //#endregion
195
+ export { PageTemplateLandingPage as default };
@@ -89,9 +89,12 @@ function AudioTab({ useAudioStore, config }) {
89
89
  /* @__PURE__ */ jsx("div", {
90
90
  className: "border mb-3 p-2",
91
91
  children: config?.tabs?.Audio?.sliders?.map((slider_obj) => {
92
- return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Form.Label, {
92
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(Form.Label, {
93
93
  className: "mb-0",
94
- children: slider_obj.label
94
+ children: [/* @__PURE__ */ jsx("span", { children: slider_obj.label }), audioSettings?.[slider_obj.key] && /* @__PURE__ */ jsxs("span", {
95
+ className: "ms-2 text-muted",
96
+ children: [audioSettings[slider_obj.key], "%"]
97
+ })]
95
98
  }), /* @__PURE__ */ jsx(Form.Range, {
96
99
  value: audioSettings?.[slider_obj.key],
97
100
  onChange: (value) => {
@@ -103,7 +106,7 @@ function AudioTab({ useAudioStore, config }) {
103
106
  })] }, slider_obj.key);
104
107
  })
105
108
  }),
106
- config?.tabs?.Controls?.children
109
+ config?.tabs?.Audio?.children
107
110
  ] });
108
111
  }
109
112
  //#endregion
@@ -163,7 +166,7 @@ function SocketSettings({ useStore }) {
163
166
  function ControlsTab({ useTouchControlsStore, config }) {
164
167
  return /* @__PURE__ */ jsxs("div", {
165
168
  className: "",
166
- children: [useTouchControlsStore && /* @__PURE__ */ jsx(TouchControls, { useTouchControlsStore }), config?.tabs?.Controls?.children]
169
+ children: [useTouchControlsStore && config?.tabs?.Controls?.touchControls && /* @__PURE__ */ jsx(TouchControls, { useTouchControlsStore }), config?.tabs?.Controls?.children]
167
170
  });
168
171
  }
169
172
  function TouchControls({ useTouchControlsStore }) {
@@ -232,7 +235,7 @@ function OtherTab({ useStore, config }) {
232
235
  var package_default = {
233
236
  name: "@articles-media/articles-dev-box",
234
237
  description: "Shared code, functions, and components for different Articles Media projects.",
235
- version: "1.0.41",
238
+ version: "1.1.0",
236
239
  type: "module",
237
240
  imports: { "#root/src/*": "./src/*" },
238
241
  main: "./dist/index.js",
@@ -250,17 +253,21 @@ var package_default = {
250
253
  "./NicknameInput": "./dist/NicknameInput.js",
251
254
  "./ArticlesAd": "./dist/ArticlesAd.js",
252
255
  "./GameScoreboard": "./dist/GameScoreboard.js",
256
+ "./PageTemplateLandingPage": "./dist/PageTemplateLandingPage.js",
253
257
  "./ReturnToLauncherButton": "./dist/ReturnToLauncherButton.js",
254
258
  "./SignInButton": "./dist/SignInButton.js",
255
259
  "./SessionButton": "./dist/SessionButton.js",
256
260
  "./GlobalHead": "./dist/GlobalHead.js",
257
261
  "./GlobalBody": "./dist/GlobalBody.js",
262
+ "./GlobalClientModals": "./dist/GlobalClientModals.js",
258
263
  "./ViewUserModal": "./dist/ViewUserModal.js",
259
264
  "./SettingsModal": "./dist/SettingsModal.js",
260
265
  "./CreditsModal": "./dist/CreditsModal.js",
266
+ "./InfoModal": "./dist/InfoModal.js",
261
267
  "./DarkModeHandler": "./dist/DarkModeHandler.js",
262
268
  "./ToontownModeHandler": "./dist/ToontownModeHandler.js",
263
269
  "./SocketServerUrlHandler": "./dist/SocketServerUrlHandler.js",
270
+ "./HasNoMouseHandler": "./dist/HasNoMouseHandler.js",
264
271
  "./FriendsList": "./dist/FriendsList.js",
265
272
  "./useUserDetails": "./dist/useUserDetails.js",
266
273
  "./useUserToken": "./dist/useUserToken.js",
@@ -268,7 +275,10 @@ var package_default = {
268
275
  "./useFullscreen": "./dist/useFullscreen.js",
269
276
  "./typicalZustandStoreExcludes": "./dist/typicalZustandStoreExcludes.js",
270
277
  "./typicalZustandStoreStateSlice": "./dist/typicalZustandStoreStateSlice.js",
278
+ "./defaultGameNextConfig": "./dist/defaultGameNextConfig.js",
279
+ "./defaultGameThemeConfig": "./dist/defaultGameThemeConfig.js",
271
280
  "./getSignOutRedirectUrl": "./dist/getSignOutRedirectUrl.js",
281
+ "./generateRandomNickname": "./dist/generateRandomNickname.js",
272
282
  "./dist/style.css": "./dist/articles-dev-box.css",
273
283
  "./dist/articles-dev-box.css": "./dist/articles-dev-box.css"
274
284
  },
@@ -303,10 +313,26 @@ var package_default = {
303
313
  //#endregion
304
314
  //#region src/components/Games/Settings/DebugTab.jsx
305
315
  function DebugTab({ useStore, config }) {
306
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
307
- className: "mb-3",
308
- children: ["dev-box version: ", package_default.version]
309
- }), config?.tabs?.Debug?.children && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("hr", {}), config?.tabs?.Debug?.children] })] });
316
+ const showStats = useStore((state) => state?.debugConfig?.showStats);
317
+ const setDebugConfigKey = useStore((state) => state?.setDebugConfigKey);
318
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
319
+ /* @__PURE__ */ jsxs("div", {
320
+ className: "mb-3",
321
+ children: ["dev-box version: ", package_default.version]
322
+ }),
323
+ /* @__PURE__ */ jsx("div", { children: "Show Debug Stats" }),
324
+ /* @__PURE__ */ jsx("div", {
325
+ className: "mb-3",
326
+ children: [false, true].map((level, i) => /* @__PURE__ */ jsx(ArticlesButton, {
327
+ active: showStats === level,
328
+ onClick: () => {
329
+ setDebugConfigKey("showStats", level);
330
+ },
331
+ children: level ? "Enabled" : "Disabled"
332
+ }, i))
333
+ }),
334
+ config?.tabs?.Debug?.children && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("hr", {}), config?.tabs?.Debug?.children] })
335
+ ] });
310
336
  }
311
337
  //#endregion
312
338
  //#region src/components/Games/Settings/SettingsModal.jsx
@@ -323,6 +349,7 @@ function SettingsModal({ show, setShow, store, useAudioStore, useTouchControlsSt
323
349
  setShow(false);
324
350
  },
325
351
  children: store && /* @__PURE__ */ jsx(ModalContent, {
352
+ setShow,
326
353
  useStore: store,
327
354
  useAudioStore,
328
355
  useTouchControlsStore,
@@ -331,7 +358,7 @@ function SettingsModal({ show, setShow, store, useAudioStore, useTouchControlsSt
331
358
  })
332
359
  });
333
360
  }
334
- function ModalContent({ useStore, useAudioStore, useTouchControlsStore, useSocketStore, config }) {
361
+ function ModalContent({ setShow, useStore, useAudioStore, useTouchControlsStore, useSocketStore, config }) {
335
362
  const [tab, setTab] = useState(localStorage.getItem("articles_settings_tab") || "Graphics");
336
363
  const handleTabChange = (newTab) => {
337
364
  setTab(newTab);
@@ -1,2 +1,2 @@
1
- import { t as SettingsModal } from "./SettingsModal-DDTYTP4z.js";
1
+ import { t as SettingsModal } from "./SettingsModal-Cy49y82s.js";
2
2
  export { SettingsModal as default };
@@ -303,6 +303,14 @@
303
303
  margin-right: 0;
304
304
  font-size: 1.25rem;
305
305
  }
306
+ @media (min-width: 992px) {
307
+ .menu-bar .menu-bar-container .Center {
308
+ position: absolute;
309
+ top: 50%;
310
+ left: 50%;
311
+ transform: translate(-50%, -50%);
312
+ }
313
+ }
306
314
 
307
315
  .mobile-menu {
308
316
  position: fixed;
@@ -0,0 +1,25 @@
1
+ //#region src/constants/defaultGameNextConfig.js
2
+ var defaultGameNextConfig = {
3
+ poweredByHeader: false,
4
+ reactCompiler: true,
5
+ images: { remotePatterns: [{
6
+ protocol: "https",
7
+ hostname: "cdn.articles.media",
8
+ port: ""
9
+ }, {
10
+ protocol: "https",
11
+ hostname: "articles-website.s3.amazonaws.com",
12
+ port: ""
13
+ }] },
14
+ async headers() {
15
+ return [{
16
+ source: "/(.*)",
17
+ headers: [{
18
+ key: "X-Frame-Options",
19
+ value: "SAMEORIGIN"
20
+ }]
21
+ }];
22
+ }
23
+ };
24
+ //#endregion
25
+ export { defaultGameNextConfig as default };
@@ -0,0 +1,11 @@
1
+ //#region src/constants/defaultGameThemeConfig.js
2
+ var getTheme = (createTheme) => createTheme({
3
+ cssVariables: true,
4
+ palette: { mode: "dark" },
5
+ components: { MuiAlert: { styleOverrides: { root: { variants: [{
6
+ props: { severity: "info" },
7
+ style: { backgroundColor: "#60a5fa" }
8
+ }] } } } }
9
+ });
10
+ //#endregion
11
+ export { getTheme as default };
@@ -0,0 +1,78 @@
1
+ //#region src/util/generateRandomNickname.js
2
+ var defaultAdjectives = [
3
+ "Swift",
4
+ "Clever",
5
+ "Bright",
6
+ "Bold",
7
+ "Calm",
8
+ "Quick",
9
+ "Smart",
10
+ "Witty",
11
+ "Sharp",
12
+ "Kind",
13
+ "Cool",
14
+ "Vast",
15
+ "Fair",
16
+ "Brave",
17
+ "Keen",
18
+ "Grand",
19
+ "Pure",
20
+ "Rich",
21
+ "Smooth",
22
+ "Strong",
23
+ "Sunny",
24
+ "Wild",
25
+ "Wise",
26
+ "Zero",
27
+ "Great",
28
+ "Elite",
29
+ "Prime",
30
+ "Solid",
31
+ "Global",
32
+ "Unique"
33
+ ];
34
+ var defaultNouns = [
35
+ "Fox",
36
+ "Wolf",
37
+ "Bear",
38
+ "Eagle",
39
+ "Hawk",
40
+ "Lion",
41
+ "Tiger",
42
+ "Shark",
43
+ "Owl",
44
+ "Deer",
45
+ "Falcon",
46
+ "Raven",
47
+ "Panda",
48
+ "Koala",
49
+ "Otter",
50
+ "Lynx",
51
+ "River",
52
+ "Star",
53
+ "Sky",
54
+ "Mountain",
55
+ "Cloud",
56
+ "Ocean",
57
+ "Forest",
58
+ "Storm",
59
+ "Peak",
60
+ "Valley",
61
+ "Desert",
62
+ "Island",
63
+ "Bridge"
64
+ ];
65
+ /**
66
+ * Generates a random pattern/solving-themed nickname.
67
+ * @returns {string} A random nickname like "CleverSolver42" or "SwiftMatcher7".
68
+ */
69
+ var generateRandomNickname = (config) => {
70
+ const { type, parts } = config || {};
71
+ if (type == "Basic") {
72
+ const adjectives = parts[0] || defaultAdjectives;
73
+ const nouns = parts[1] || defaultNouns;
74
+ return `${(adjectives || defaultAdjectives)[Math.floor(Math.random() * (adjectives || defaultAdjectives).length)]}${(nouns || defaultNouns)[Math.floor(Math.random() * (nouns || defaultNouns).length)]}${Math.floor(Math.random() * 100)}`;
75
+ }
76
+ };
77
+ //#endregion
78
+ export { generateRandomNickname as default };
package/dist/index.js CHANGED
@@ -8,19 +8,25 @@ import useUserFriends from "./useUserFriends.js";
8
8
  import FriendsList from "./FriendsList.js";
9
9
  import { t as SessionButton } from "./SessionButton-D3cupnzD.js";
10
10
  import ArticlesAd from "./ArticlesAd.js";
11
- import { t as GameMenu } from "./GameMenu-CyW1MF3Y.js";
11
+ import { t as GameMenu } from "./GameMenu-DeFdYvvR.js";
12
12
  import useFullscreen from "./useFullscreen.js";
13
13
  import PrimaryButtonGroup from "./GameMenuPrimaryButtonGroup.js";
14
14
  import NicknameInput from "./NicknameInput.js";
15
15
  import { t as GameScoreboard } from "./GameScoreboard-CYuTBE_E.js";
16
+ import PageTemplateLandingPage from "./PageTemplateLandingPage.js";
16
17
  import GlobalHead from "./GlobalHead.js";
17
18
  import GlobalBody_default from "./GlobalBody.js";
18
- import { t as SettingsModal } from "./SettingsModal-DDTYTP4z.js";
19
+ import { t as SettingsModal } from "./SettingsModal-Cy49y82s.js";
19
20
  import CreditsModal from "./CreditsModal.js";
21
+ import InfoModal from "./InfoModal.js";
20
22
  import DarkModeHandler from "./DarkModeHandler.js";
21
23
  import ToontownModeHandler from "./ToontownModeHandler.js";
22
24
  import SocketServerUrlHandler from "./SocketServerUrlHandler.js";
25
+ import HasNoMouseHandler from "./HasNoMouseHandler.js";
23
26
  import typicalZustandStoreExcludes from "./typicalZustandStoreExcludes.js";
24
27
  import typicalZustandStoreStateSlice from "./typicalZustandStoreStateSlice.js";
28
+ import defaultGameNextConfig from "./defaultGameNextConfig.js";
29
+ import getTheme from "./defaultGameThemeConfig.js";
25
30
  import getSignOutRedirectUrl from "./getSignOutRedirectUrl.js";
26
- export { Ad_default as Ad, ArticlesAd, CreditsModal, DarkModeHandler, FriendsList, GameMenu, PrimaryButtonGroup as GameMenuPrimaryButtonGroup, GameScoreboard, GlobalBody_default as GlobalBody, GlobalHead, NicknameInput, ReturnToLauncherButton, SessionButton, SettingsModal, SignInButton, SocketServerUrlHandler, ToontownModeHandler, ViewUserModal, getSignOutRedirectUrl, typicalZustandStoreExcludes, typicalZustandStoreStateSlice, useFullscreen, useUserDetails, useUserFriends, useUserToken };
31
+ import generateRandomNickname from "./generateRandomNickname.js";
32
+ export { Ad_default as Ad, ArticlesAd, CreditsModal, DarkModeHandler, FriendsList, GameMenu, PrimaryButtonGroup as GameMenuPrimaryButtonGroup, GameScoreboard, GlobalBody_default as GlobalBody, GlobalHead, HasNoMouseHandler, InfoModal, NicknameInput, PageTemplateLandingPage, ReturnToLauncherButton, SessionButton, SettingsModal, SignInButton, SocketServerUrlHandler, ToontownModeHandler, ViewUserModal, defaultGameNextConfig, getTheme as defaultGameThemeConfig, generateRandomNickname, getSignOutRedirectUrl, typicalZustandStoreExcludes, typicalZustandStoreStateSlice, useFullscreen, useUserDetails, useUserFriends, useUserToken };
@@ -22,9 +22,22 @@ var typicalZustandStoreStateSlice = (set, get, generateRandomNickname) => ({
22
22
  set((prev) => ({ nicknameKeyboard: newValue }));
23
23
  },
24
24
  debug: false,
25
+ toggleDebug: () => {
26
+ set((prev) => ({ debug: !prev.debug }));
27
+ },
25
28
  setDebug: (newValue) => {
26
29
  set((prev) => ({ debug: newValue }));
27
30
  },
31
+ debugConfig: { showStats: false },
32
+ setDebugConfig: (newValue) => {
33
+ set((prev) => ({ debugConfig: { ...newValue } }));
34
+ },
35
+ setDebugConfigKey: (key, value) => {
36
+ set((prev) => ({ debugConfig: {
37
+ ...prev.debugConfig,
38
+ [key]: value
39
+ } }));
40
+ },
28
41
  sidebar: true,
29
42
  toggleSidebar: () => {
30
43
  set((prev) => ({ sidebar: !prev.sidebar }));
@@ -33,6 +46,9 @@ var typicalZustandStoreStateSlice = (set, get, generateRandomNickname) => ({
33
46
  set((prev) => ({ sidebar: newValue }));
34
47
  },
35
48
  showMenu: false,
49
+ toggleShowMenu: () => {
50
+ set((prev) => ({ showMenu: !prev.showMenu }));
51
+ },
36
52
  setShowMenu: (value) => set({ showMenu: value }),
37
53
  showSettingsModal: false,
38
54
  setShowSettingsModal: (newValue) => {
@@ -77,7 +93,11 @@ var typicalZustandStoreStateSlice = (set, get, generateRandomNickname) => ({
77
93
  },
78
94
  reloadScene: () => {
79
95
  set((prev) => ({ sceneKey: prev.sceneKey + 1 }));
80
- }
96
+ },
97
+ hasNoMouse: null,
98
+ setHasNoMouse: (value) => set({ hasNoMouse: value }),
99
+ isTouchCapable: null,
100
+ setIsTouchCapable: (value) => set({ isTouchCapable: value })
81
101
  });
82
102
  //#endregion
83
103
  export { typicalZustandStoreStateSlice as default };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@articles-media/articles-dev-box",
3
3
  "description": "Shared code, functions, and components for different Articles Media projects.",
4
- "version": "1.0.41",
4
+ "version": "1.1.0",
5
5
  "type": "module",
6
6
  "imports": {
7
7
  "#root/src/*": "./src/*"
@@ -23,17 +23,21 @@
23
23
  "./NicknameInput": "./dist/NicknameInput.js",
24
24
  "./ArticlesAd": "./dist/ArticlesAd.js",
25
25
  "./GameScoreboard": "./dist/GameScoreboard.js",
26
+ "./PageTemplateLandingPage": "./dist/PageTemplateLandingPage.js",
26
27
  "./ReturnToLauncherButton": "./dist/ReturnToLauncherButton.js",
27
28
  "./SignInButton": "./dist/SignInButton.js",
28
29
  "./SessionButton": "./dist/SessionButton.js",
29
30
  "./GlobalHead": "./dist/GlobalHead.js",
30
31
  "./GlobalBody": "./dist/GlobalBody.js",
32
+ "./GlobalClientModals": "./dist/GlobalClientModals.js",
31
33
  "./ViewUserModal": "./dist/ViewUserModal.js",
32
34
  "./SettingsModal": "./dist/SettingsModal.js",
33
35
  "./CreditsModal": "./dist/CreditsModal.js",
36
+ "./InfoModal": "./dist/InfoModal.js",
34
37
  "./DarkModeHandler": "./dist/DarkModeHandler.js",
35
38
  "./ToontownModeHandler": "./dist/ToontownModeHandler.js",
36
39
  "./SocketServerUrlHandler": "./dist/SocketServerUrlHandler.js",
40
+ "./HasNoMouseHandler": "./dist/HasNoMouseHandler.js",
37
41
  "./FriendsList": "./dist/FriendsList.js",
38
42
  "./useUserDetails": "./dist/useUserDetails.js",
39
43
  "./useUserToken": "./dist/useUserToken.js",
@@ -41,7 +45,10 @@
41
45
  "./useFullscreen": "./dist/useFullscreen.js",
42
46
  "./typicalZustandStoreExcludes": "./dist/typicalZustandStoreExcludes.js",
43
47
  "./typicalZustandStoreStateSlice": "./dist/typicalZustandStoreStateSlice.js",
48
+ "./defaultGameNextConfig": "./dist/defaultGameNextConfig.js",
49
+ "./defaultGameThemeConfig": "./dist/defaultGameThemeConfig.js",
44
50
  "./getSignOutRedirectUrl": "./dist/getSignOutRedirectUrl.js",
51
+ "./generateRandomNickname": "./dist/generateRandomNickname.js",
45
52
  "./dist/style.css": "./dist/articles-dev-box.css",
46
53
  "./dist/articles-dev-box.css": "./dist/articles-dev-box.css"
47
54
  },