@articles-media/articles-dev-box 1.1.1 → 1.1.2

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
@@ -35,71 +35,43 @@ npm run dev
35
35
 
36
36
  ## Package Exports
37
37
 
38
- - ReturnToLauncherButton
39
- - For bringing users back to their state in the games showcase/launcher
40
- - SignInButton
41
- - For bringing users to the accounts service to login at and redirecting back
42
- - SessionButton
43
- - Button that manages sign in, sign out, and account details.
44
- - GameScoreboard
45
- - Scoreboard for registered games that links with a user's Articles Media account.
46
- - Ad
47
- - Articles Ad component that connects with user data.
48
- - GameMenu
49
- - All in one component that handles the sidebar and menu-bar inside a game page.
50
- - GameMenuPrimaryButtonGroup
51
- - The common button groups for landing page and menu content across our games
52
- - NicknameInput
53
- - Handles nickname UI on landing page
54
- - GlobalHead
55
- - Not used at this time, allows for just <head> related tags to be added to site without other logic.
56
- - GlobalBody
57
- - Easy way to add future logic and components to all projects with ease. For now handling the font awesome script. Also shows connection status to required servers in development. Will ping the main and auth server as they are needed for some dev-box features.
58
- - ViewUserModal
59
- - View user profile data and recent activity.
60
- - SettingsModal
61
- - All in one component to handle game settings UI across multiple games.
62
- - CreditsModal
63
- - All in one component to handle game credits UI across multiple games.
64
- - DarkModeHandler
65
- - Consumes a Zustand store, detects prefers-color-scheme, sets data-bs-theme on body element.
66
- - ToontownModeHandler
67
- - Handles setting zustand state from url params if toontownMode is passed.
68
- - SocketServerUrlHandler
69
- - Handles setting socket server state from url params if socketServerUrl is passed.
70
- - HasNoMouseHandler
71
- - Sets hasNoMouse and isTouchCapable on first load
72
- - useUserToken
73
- - Hook for getting the subdomain auth token.
74
- - useUserDetails
75
- - Hook for getting the details of the current user if a valid user token is found.
76
- - useFullscreen
77
- - Hook for going fullscreen on the body or provided element
78
- - typicalZustandStoreExcludes
79
- - Array of strings that every game published by Articles Media would want to normally exclude from persisting in base game store.
80
- - typicalZustandStoreStateSlice
81
- - Slice of zustand states that every game normally uses
82
- - getSignOutRedirectUrl
83
- - Handles signout redirect api logic
38
+ | Name | Description | Usage Example |
39
+ | :--- | :--- | :--- |
40
+ | ReturnToLauncherButton | For bringing users back to their state in the games showcase/launcher | |
41
+ | SignInButton | For bringing users to the accounts service to login at and redirecting back | |
42
+ | SessionButton | Button that manages sign in, sign out, and account details. | Catching Game and School Run |
43
+ | GameScoreboard | Scoreboard for registered games that links with a user's Articles Media account. | |
44
+ | Ad | Articles Ad component that connects with user data. | |
45
+ | GameMenu | All in one component that handles the sidebar and menu-bar inside a game page. | Catching Game and School Run use Static Panel for sidebarStyle and Corner Button for menuBarStyle. Ice Slide uses Floating Panel for sidebarStyle and Bar for menuBarStyle. |
46
+ | GameMenuPrimaryButtonGroup | The common button groups for landing page and menu content across our games | Catching Game and Move Match |
47
+ | NicknameInput | Handles nickname UI on landing page | Catching Game |
48
+ | GlobalHead | Not used at this time, allows for just <head> related tags to be added to site without other logic. | |
49
+ | GlobalBody | Easy way to add future logic and components to all projects with ease. For now handling the font awesome script. Also shows connection status to required servers in development. Will ping the main and auth server as they are needed for some dev-box features. | |
50
+ | ViewUserModal | View user profile data and recent activity. | |
51
+ | SettingsModal | All in one component to handle game settings UI across multiple games. | |
52
+ | CreditsModal | All in one component to handle game credits UI across multiple games. | |
53
+ | InfoModal | All in one component to handle game info modal across multiple games. | USA Tycoon |
54
+ | DarkModeHandler | Consumes a Zustand store, detects prefers-color-scheme, sets data-bs-theme on body element. | |
55
+ | ToontownModeHandler | Handles setting zustand state from url params if toontownMode is passed. | |
56
+ | SocketServerUrlHandler | Handles setting socket server state from url params if socketServerUrl is passed. | |
57
+ | HasNoMouseHandler | Sets hasNoMouse and isTouchCapable on first load | |
58
+ | useUserToken | Hook for getting the subdomain auth token. | |
59
+ | useUserDetails | Hook for getting the details of the current user if a valid user token is found. | |
60
+ | useFullscreen | Hook for going fullscreen on the body or provided element | |
61
+ | typicalZustandStoreExcludes | Array of strings that every game published by Articles Media would want to normally exclude from persisting in base game store. | Catching Game and School Run |
62
+ | typicalZustandStoreStateSlice | Slice of zustand states that every game normally uses | Catching Game and School Run |
63
+ | getSignOutRedirectUrl | Handles signout redirect api logic | Catching Game |
64
+ | GlobalClientModals | Imports all global client modals like FriendsList, CreditsModal, SettingsModal, InfoModal, and so on | USA Tycoon |
65
+ | generateRandomNickname | Reusable way of doing random nicknames from package | USA Tycoon |
66
+ | defaultGameNextConfig | Not usable, for reference | None |
67
+ | defaultGameThemeConfig | Not usable, for reference | None |
68
+ | useModalNavigation | Handles navigating a modal with controller | None |
69
+ | gameLandingPageTemplate | All in one component that sets up the default landing page as much as possible | USA Tycoon |
70
+ | gamePageTemplate | All in one component that sets up the default game page as much as possible | USA Tycoon |
84
71
 
85
72
  # Usage Examples
86
73
  For newly developed components I sometimes find myself trying to remember what repos used it. Here is a short list of recent components developed and what project is using it. Doing this until AMPM can search by imports or enough projects adopted the component.
87
74
 
88
- - typicalZustandStoreExcludes - Catching Game and School Run
89
- - SessionButton - Catching Game and School Run
90
- - GameMenu - Catching Game and School Run use Static Panel for sidebarStyle and Corner Button for menuBarStyle. Ice Slide uses Floating Panel for sidebarStyle and Bar for menuBarStyle.
91
- - getSignOutRedirectUrl - Catching Game
92
- - GameMenuPrimaryButtonGroup - Catching Game and Move Match
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
102
-
103
75
  # Roadmap
104
76
  ⏹️ Remove Bootstrap reliance?
105
77
  ⏹️ Figure out why this package does not work outside webpack, on Turbopack for example it fails. Bootstrap SASS related I think.
@@ -22,14 +22,14 @@ function FriendsList({ show, setShow, componentType, className, style = {}, id =
22
22
  friend?.populated_user?.username,
23
23
  " - ",
24
24
  friend?.populated_user?.display_name || "No Display Name"
25
- ] }, friend.user_id))
25
+ ] }, friend.friend_id))
26
26
  });
27
27
  }
28
28
  if (componentType.toLowerCase() == "modal") return /* @__PURE__ */ jsxs(Modal, {
29
29
  show,
30
30
  size: "md",
31
31
  className: `articles-modal ${className}`,
32
- modalBackdropClassName,
32
+ backdropClassName: modalBackdropClassName,
33
33
  centered: true,
34
34
  onHide: () => setShow(false),
35
35
  style,
@@ -56,11 +56,13 @@ function FriendsList({ show, setShow, componentType, className, style = {}, id =
56
56
  children: /* @__PURE__ */ jsx("i", { className: "fad fa-comment-check" })
57
57
  }), /* @__PURE__ */ jsx(ArticlesButton, {
58
58
  variant: "articles",
59
- onClick: () => {},
60
- children: /* @__PURE__ */ jsx("i", { className: "fad fa-info" })
59
+ onClick: () => {
60
+ console.log("View friend details for ", friend);
61
+ },
62
+ children: /* @__PURE__ */ jsx("i", { className: "fad fa-info me-0" })
61
63
  })] })
62
64
  ]
63
- }, friend.user_id)) })
65
+ }, friend.friend_id)) })
64
66
  ] }),
65
67
  /* @__PURE__ */ jsxs(Modal.Footer, {
66
68
  className: "justify-content-between",
@@ -9,7 +9,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  * @param {string} [props.owner] Optional GitHub owner
10
10
  * @param {string} [props.repo] Optional GitHub repo
11
11
  */
12
- function PrimaryButtonGroup({ useStore, type, owner, repo }) {
12
+ function PrimaryButtonGroup({ useStore, type, owner, repo, LeaveGameOverride, SidebarOverride, SettingsOverride }) {
13
13
  if (!useStore) return null;
14
14
  const { isFullscreen, requestFullscreen, exitFullscreen } = useFullscreen();
15
15
  const setShowSettingsModal = useStore((state) => state.setShowSettingsModal);
@@ -69,7 +69,7 @@ function PrimaryButtonGroup({ useStore, type, owner, repo }) {
69
69
  })
70
70
  ] });
71
71
  case "GameMenu": return /* @__PURE__ */ jsxs(Fragment, { children: [
72
- /* @__PURE__ */ jsx("a", {
72
+ LeaveGameOverride ? LeaveGameOverride : /* @__PURE__ */ jsx("a", {
73
73
  href: "/",
74
74
  className: "w-50",
75
75
  children: /* @__PURE__ */ jsxs(ArticlesButton, {
@@ -92,7 +92,7 @@ function PrimaryButtonGroup({ useStore, type, owner, repo }) {
92
92
  /* @__PURE__ */ jsx("span", { children: "Fullscreen" })
93
93
  ]
94
94
  }),
95
- /* @__PURE__ */ jsxs("div", {
95
+ SettingsOverride ? SettingsOverride : /* @__PURE__ */ jsxs("div", {
96
96
  className: "w-50 d-flex",
97
97
  children: [/* @__PURE__ */ jsxs(ArticlesButton, {
98
98
  className: `w-100`,
@@ -110,7 +110,7 @@ function PrimaryButtonGroup({ useStore, type, owner, repo }) {
110
110
  children: darkMode ? /* @__PURE__ */ jsx("i", { className: "fad fa-sun" }) : /* @__PURE__ */ jsx("i", { className: "fad fa-moon" })
111
111
  })]
112
112
  }),
113
- /* @__PURE__ */ jsxs(ArticlesButton, {
113
+ SidebarOverride ? SidebarOverride : /* @__PURE__ */ jsxs(ArticlesButton, {
114
114
  className: `w-50`,
115
115
  small: true,
116
116
  active: sidebar,
@@ -4,7 +4,7 @@ import useUserDetails from "./useUserDetails.js";
4
4
  import useUserToken from "./useUserToken.js";
5
5
  import { t as ViewUserModal } from "./ViewUserModal-Dgo1C4sR.js";
6
6
  import FriendsList from "./FriendsList.js";
7
- import { useState } from "react";
7
+ import { lazy, useState } from "react";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Modal } from "react-bootstrap";
10
10
  //#region src/components/User/SignOutModal.jsx
@@ -40,28 +40,41 @@ function SignOutModal({ show, setShow, action }) {
40
40
  }
41
41
  //#endregion
42
42
  //#region src/components/User/SessionButton.jsx
43
- function SessionButton({ port, friendsButton }) {
43
+ var Textfit = lazy(() => import("./Textfit-XtAzfT0P.js").then((module) => ({ default: module.Textfit })));
44
+ function SessionButton({ port, friendsButton, enableTextfit = false, size = "sm" }) {
44
45
  const { data: userToken, error: userTokenError, isLoading: userTokenLoading, mutate: userTokenMutate } = useUserToken(port);
45
46
  const { data: userDetails, error: userDetailsError, isLoading: userDetailsLoading, mutate: userDetailsMutate } = useUserDetails({ token: userToken });
46
47
  const [showFriendsModal, setShowFriendsModal] = useState(false);
47
48
  const [confirmSignOut, setConfirmSignOut] = useState(false);
48
- return /* @__PURE__ */ jsx(Fragment, { children: !userDetails ? /* @__PURE__ */ jsx(SignInButton, { className: "mb-2" }) : /* @__PURE__ */ jsxs("div", {
49
- className: "w-100 d-flex align-items-stretch mb-2",
49
+ return /* @__PURE__ */ jsx(Fragment, { children: !userDetails ? /* @__PURE__ */ jsx(SignInButton, {
50
+ className: "mb-2",
51
+ size
52
+ }) : /* @__PURE__ */ jsxs("div", {
53
+ className: "SessionButton w-100 d-flex align-items-stretch mb-2",
50
54
  children: [
51
55
  /* @__PURE__ */ jsx(ViewUserModal, {
52
56
  buttonType: "Link",
53
57
  className: "w-100",
54
- children: /* @__PURE__ */ jsxs(ArticlesButton, {
55
- className: "w-100",
56
- small: true,
58
+ children: /* @__PURE__ */ jsx(ArticlesButton, {
59
+ className: "w-100 h-100",
60
+ size,
57
61
  onClick: () => {
58
62
  console.log("userDetails", userDetails);
59
63
  },
60
- children: [
64
+ children: enableTextfit ? /* @__PURE__ */ jsxs(Textfit, {
65
+ maxFontSize: 11,
66
+ minFontSize: 6,
67
+ justifyContent: "center",
68
+ children: [
69
+ /* @__PURE__ */ jsx("i", { className: "fad fa-sign-out" }),
70
+ "Logged in as ",
71
+ userDetails?.display_name || "Unknown User"
72
+ ]
73
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [
61
74
  /* @__PURE__ */ jsx("i", { className: "fad fa-sign-out" }),
62
75
  "Logged in as ",
63
76
  userDetails?.display_name || "Unknown User"
64
- ]
77
+ ] })
65
78
  })
66
79
  }),
67
80
  confirmSignOut && /* @__PURE__ */ jsx(SignOutModal, {
@@ -3,5 +3,5 @@ import "./SignInButton.js";
3
3
  import "./useUserDetails.js";
4
4
  import "./useUserToken.js";
5
5
  import "./FriendsList.js";
6
- import { t as SessionButton } from "./SessionButton-D3cupnzD.js";
6
+ import { t as SessionButton } from "./SessionButton-DsXEzmff.js";
7
7
  export { SessionButton as default };
@@ -88,22 +88,25 @@ function AudioTab({ useAudioStore, config }) {
88
88
  }),
89
89
  /* @__PURE__ */ jsx("div", {
90
90
  className: "border mb-3 p-2",
91
- children: config?.tabs?.Audio?.sliders?.map((slider_obj) => {
92
- return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs(Form.Label, {
93
- className: "mb-0",
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], "%"]
91
+ children: config?.tabs?.Audio?.sliders?.map((slider_obj, i) => {
92
+ return /* @__PURE__ */ jsxs("div", {
93
+ className: "mb-3",
94
+ children: [/* @__PURE__ */ jsxs(Form.Label, {
95
+ className: "mb-0",
96
+ children: [/* @__PURE__ */ jsx("span", { children: slider_obj.label }), audioSettings?.[slider_obj.key] && /* @__PURE__ */ jsxs("span", {
97
+ className: "ms-2 text-muted",
98
+ children: [audioSettings[slider_obj.key], "%"]
99
+ })]
100
+ }), /* @__PURE__ */ jsx(Form.Range, {
101
+ value: audioSettings?.[slider_obj.key],
102
+ onChange: (value) => {
103
+ setAudioSettings({
104
+ ...audioSettings,
105
+ [slider_obj.key]: value.target.value
106
+ });
107
+ }
97
108
  })]
98
- }), /* @__PURE__ */ jsx(Form.Range, {
99
- value: audioSettings?.[slider_obj.key],
100
- onChange: (value) => {
101
- setAudioSettings({
102
- ...audioSettings,
103
- [slider_obj.key]: value.target.value
104
- });
105
- }
106
- })] }, slider_obj.key);
109
+ }, slider_obj.key + "_" + i);
107
110
  })
108
111
  }),
109
112
  config?.tabs?.Audio?.children
@@ -235,7 +238,7 @@ function OtherTab({ useStore, config }) {
235
238
  var package_default = {
236
239
  name: "@articles-media/articles-dev-box",
237
240
  description: "Shared code, functions, and components for different Articles Media projects.",
238
- version: "1.1.1",
241
+ version: "1.1.2",
239
242
  type: "module",
240
243
  sideEffects: false,
241
244
  imports: { "#root/src/*": "./src/*" },
@@ -321,16 +324,18 @@ function DebugTab({ useStore, config }) {
321
324
  className: "mb-3",
322
325
  children: ["dev-box version: ", package_default.version]
323
326
  }),
324
- /* @__PURE__ */ jsx("div", { children: "Show Debug Stats" }),
325
- /* @__PURE__ */ jsx("div", {
327
+ config?.tabs?.Debug?.showStats !== false && /* @__PURE__ */ jsxs("div", {
326
328
  className: "mb-3",
327
- children: [false, true].map((level, i) => /* @__PURE__ */ jsx(ArticlesButton, {
328
- active: showStats === level,
329
- onClick: () => {
330
- setDebugConfigKey("showStats", level);
331
- },
332
- children: level ? "Enabled" : "Disabled"
333
- }, i))
329
+ children: [/* @__PURE__ */ jsx("div", { children: "Show Debug Stats" }), /* @__PURE__ */ jsx("div", {
330
+ className: "",
331
+ children: [false, true].map((level, i) => /* @__PURE__ */ jsx(ArticlesButton, {
332
+ active: showStats === level,
333
+ onClick: () => {
334
+ setDebugConfigKey("showStats", level);
335
+ },
336
+ children: level ? "Enabled" : "Disabled"
337
+ }, i))
338
+ })]
334
339
  }),
335
340
  config?.tabs?.Debug?.children && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("hr", {}), config?.tabs?.Debug?.children] })
336
341
  ] });
@@ -1,2 +1,2 @@
1
- import { t as SettingsModal } from "./SettingsModal-BKcxlAg_.js";
1
+ import { t as SettingsModal } from "./SettingsModal-DxRRcKLZ.js";
2
2
  export { SettingsModal as default };
@@ -3,7 +3,7 @@ import { t as ArticlesButton } from "./Button-DvEZjsVV.js";
3
3
  import { useEffect, useState } from "react";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  //#region src/components/User/SignInButton.jsx
6
- function SignInButton({ className, id, text }) {
6
+ function SignInButton({ className, id, text, size = "sm" }) {
7
7
  const [isMounted, setIsMounted] = useState(false);
8
8
  const baseLink = process.env.NODE_ENV === "development" ? "http://localhost:3012" : "https://accounts.articles.media";
9
9
  const [finalLink, setFinalLink] = useState(`${baseLink}/login`);
@@ -19,7 +19,7 @@ function SignInButton({ className, id, text }) {
19
19
  children: /* @__PURE__ */ jsxs(ArticlesButton, {
20
20
  className: `${className} w-100`,
21
21
  id,
22
- small: true,
22
+ size,
23
23
  style: {
24
24
  zIndex: 10,
25
25
  position: "relative"
@@ -0,0 +1,52 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/components/UI/Textfit.jsx
4
+ var Textfit = ({ children, maxFontSize = 18, minFontSize = 10, justifyContent = "left" }) => {
5
+ const containerRef = useRef(null);
6
+ const textRef = useRef(null);
7
+ const [fontSize, setFontSize] = useState(maxFontSize);
8
+ useEffect(() => {
9
+ const adjustFontSize = () => {
10
+ if (!containerRef.current || !textRef.current) return;
11
+ let currentFontSize = maxFontSize;
12
+ textRef.current.style.fontSize = `${currentFontSize}px`;
13
+ while (textRef.current.scrollWidth > containerRef.current.clientWidth && currentFontSize > minFontSize) {
14
+ currentFontSize -= 1;
15
+ textRef.current.style.fontSize = `${currentFontSize}px`;
16
+ }
17
+ setFontSize(currentFontSize);
18
+ };
19
+ const resizeObserver = new ResizeObserver(adjustFontSize);
20
+ if (containerRef.current) resizeObserver.observe(containerRef.current);
21
+ adjustFontSize();
22
+ window.addEventListener("resize", adjustFontSize);
23
+ return () => {
24
+ window.removeEventListener("resize", adjustFontSize);
25
+ resizeObserver.disconnect();
26
+ };
27
+ }, [
28
+ children,
29
+ maxFontSize,
30
+ minFontSize
31
+ ]);
32
+ return /* @__PURE__ */ jsx("div", {
33
+ ref: containerRef,
34
+ style: {
35
+ width: "100%",
36
+ display: "flex",
37
+ justifyContent,
38
+ overflow: "hidden"
39
+ },
40
+ children: /* @__PURE__ */ jsx("span", {
41
+ ref: textRef,
42
+ style: {
43
+ fontSize,
44
+ whiteSpace: "nowrap",
45
+ lineHeight: 1
46
+ },
47
+ children
48
+ })
49
+ });
50
+ };
51
+ //#endregion
52
+ export { Textfit };
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { t as ViewUserModal } from "./ViewUserModal-Dgo1C4sR.js";
6
6
  import { t as Ad_default } from "./Ad-bic8syS1.js";
7
7
  import useUserFriends from "./useUserFriends.js";
8
8
  import FriendsList from "./FriendsList.js";
9
- import { t as SessionButton } from "./SessionButton-D3cupnzD.js";
9
+ import { t as SessionButton } from "./SessionButton-DsXEzmff.js";
10
10
  import ArticlesAd from "./ArticlesAd.js";
11
11
  import { t as GameMenu } from "./GameMenu-DeFdYvvR.js";
12
12
  import useFullscreen from "./useFullscreen.js";
@@ -16,7 +16,7 @@ import { t as GameScoreboard } from "./GameScoreboard-CYuTBE_E.js";
16
16
  import PageTemplateLandingPage from "./PageTemplateLandingPage.js";
17
17
  import GlobalHead from "./GlobalHead.js";
18
18
  import GlobalBody_default from "./GlobalBody.js";
19
- import { t as SettingsModal } from "./SettingsModal-BKcxlAg_.js";
19
+ import { t as SettingsModal } from "./SettingsModal-DxRRcKLZ.js";
20
20
  import CreditsModal from "./CreditsModal.js";
21
21
  import InfoModal from "./InfoModal.js";
22
22
  import DarkModeHandler from "./DarkModeHandler.js";
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.1.1",
4
+ "version": "1.1.2",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "imports": {