ps99-api 2.4.0 → 2.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.
Files changed (92) hide show
  1. package/.github/workflows/release-on-main.yml +1 -2
  2. package/.idea/runConfigurations/test_changing.xml +1 -1
  3. package/debug_currency.json +57 -0
  4. package/debug_goals.json +271 -0
  5. package/dist/ps99-api.d.ts +2 -0
  6. package/dist/ps99-api.js +4 -1
  7. package/dist/ps99-api.js.map +1 -1
  8. package/dist/request-client/axios.js +6 -1
  9. package/dist/request-client/axios.js.map +1 -1
  10. package/dist/responses/collection/index.d.ts +1 -0
  11. package/dist/responses/collection/index.js +15 -0
  12. package/dist/responses/collection/index.js.map +1 -1
  13. package/dist/responses/collection/rarity.d.ts +1 -0
  14. package/example-web/react/package-lock.json +1504 -1470
  15. package/example-web/react2/package-lock.json +3089 -2766
  16. package/example-web/react2/package.json +6 -1
  17. package/example-web/react2/public/assets/gold_variant_icon.png +0 -0
  18. package/example-web/react2/public/assets/hot_cocoa_egg.png +0 -0
  19. package/example-web/react2/public/index.html +34 -31
  20. package/example-web/react2/src/App.tsx +15 -15
  21. package/example-web/react2/src/assets/guild_placeholder.png +0 -0
  22. package/example-web/react2/src/components/AchievementsComponent.tsx +74 -19
  23. package/example-web/react2/src/components/AutoSizer.tsx +49 -0
  24. package/example-web/react2/src/components/BoostsComponent.tsx +16 -5
  25. package/example-web/react2/src/components/BoothsComponent.tsx +22 -52
  26. package/example-web/react2/src/components/BoxesComponent.tsx +48 -16
  27. package/example-web/react2/src/components/BuffsComponent.tsx +82 -34
  28. package/example-web/react2/src/components/CharmsComponent.tsx +84 -24
  29. package/example-web/react2/src/components/CollectionConfigIndex.tsx +867 -33
  30. package/example-web/react2/src/components/CollectionsIndex.tsx +380 -27
  31. package/example-web/react2/src/components/CollectionsLayout.tsx +60 -0
  32. package/example-web/react2/src/components/CurrencyComponent.tsx +57 -39
  33. package/example-web/react2/src/components/DynamicCollectionConfigData.tsx +172 -15
  34. package/example-web/react2/src/components/EggsComponent.tsx +50 -12
  35. package/example-web/react2/src/components/EnchantsComponent.tsx +88 -42
  36. package/example-web/react2/src/components/FishingRodsComponent.tsx +36 -22
  37. package/example-web/react2/src/components/Footer.tsx +18 -8
  38. package/example-web/react2/src/components/FruitsComponent.tsx +40 -17
  39. package/example-web/react2/src/components/GenericFetchComponent.tsx +9 -1
  40. package/example-web/react2/src/components/GuildBattlesComponent.tsx +41 -34
  41. package/example-web/react2/src/components/Header.tsx +39 -52
  42. package/example-web/react2/src/components/HomePage.tsx +15 -17
  43. package/example-web/react2/src/components/HoverboardsComponent.tsx +23 -99
  44. package/example-web/react2/src/components/ImageComponent.tsx +255 -45
  45. package/example-web/react2/src/components/ItemCard.tsx +240 -0
  46. package/example-web/react2/src/components/LootboxesComponent.tsx +22 -7
  47. package/example-web/react2/src/components/MasteryComponent.tsx +165 -30
  48. package/example-web/react2/src/components/MerchantsComponent.tsx +41 -16
  49. package/example-web/react2/src/components/MiscItemsComponent.tsx +26 -31
  50. package/example-web/react2/src/components/PetsComponent.tsx +100 -61
  51. package/example-web/react2/src/components/PotionsComponent.tsx +121 -27
  52. package/example-web/react2/src/components/RandomEventsComponent.tsx +32 -23
  53. package/example-web/react2/src/components/RanksComponent.tsx +187 -62
  54. package/example-web/react2/src/components/RarityComponent.tsx +123 -5
  55. package/example-web/react2/src/components/ReactWindowMock.tsx +73 -0
  56. package/example-web/react2/src/components/RebirthsComponent.tsx +36 -19
  57. package/example-web/react2/src/components/SecretRoomsComponent.tsx +5 -4
  58. package/example-web/react2/src/components/SeedsComponent.tsx +41 -21
  59. package/example-web/react2/src/components/ShovelsComponent.tsx +21 -9
  60. package/example-web/react2/src/components/Sidebar.tsx +105 -0
  61. package/example-web/react2/src/components/SprinklersComponent.tsx +25 -10
  62. package/example-web/react2/src/components/Tooltip.tsx +36 -0
  63. package/example-web/react2/src/components/UltimatesComponent.tsx +28 -16
  64. package/example-web/react2/src/components/UpgradesComponent.tsx +97 -47
  65. package/example-web/react2/src/components/WateringCansComponent.tsx +20 -14
  66. package/example-web/react2/src/components/WorldsComponent.tsx +21 -11
  67. package/example-web/react2/src/components/XPPotionsComponent.tsx +28 -11
  68. package/example-web/react2/src/components/ZoneFlagsComponent.tsx +25 -14
  69. package/example-web/react2/src/components/ZonesComponent.tsx +43 -60
  70. package/example-web/react2/src/constants/collectionIcons.ts +29 -0
  71. package/example-web/react2/src/context/CollectionDataContext.tsx +62 -0
  72. package/example-web/react2/src/context/ScrollContext.tsx +35 -0
  73. package/example-web/react2/src/hooks/useCollapsibleHeader.ts +69 -0
  74. package/example-web/react2/src/hooks/useExpandableList.ts +38 -0
  75. package/example-web/react2/src/hooks/useItemResolution.ts +351 -0
  76. package/example-web/react2/src/index.css +257 -0
  77. package/example-web/react2/src/index.tsx +2 -1
  78. package/example-web/react2/src/utils/gigantix.ts +40 -0
  79. package/example-web/react2/temp_model.rbxm +0 -0
  80. package/example-web/react2/webpack.config.js +103 -47
  81. package/package.json +11 -11
  82. package/ranks.json +1 -0
  83. package/repro_collection_fetch.ts +33 -0
  84. package/repro_image_fetch.ts +50 -0
  85. package/src/__tests__/__snapshots__/ps99-api-changes.ts.snap +34841 -10439
  86. package/src/__tests__/__snapshots__/ps99-api-live.ts.snap +160667 -67217
  87. package/src/ps99-api.ts +9 -5
  88. package/src/request-client/axios.ts +6 -2
  89. package/src/responses/collection/index.ts +1 -0
  90. package/src/responses/collection/rarity.ts +1 -0
  91. package/tsconfig.json +1 -1
  92. package/example-web/react2/public/service-worker.js +0 -63
@@ -1,49 +1,184 @@
1
1
  import React from "react";
2
2
  import { CollectionConfigData } from "ps99-api";
3
- import ImageComponent from "./ImageComponent";
3
+ import ItemCard from "./ItemCard";
4
4
 
5
5
  const MasteryComponent: React.FC<{
6
6
  configData: CollectionConfigData<"Mastery">;
7
7
  }> = ({ configData }) => {
8
- const renderPerks = (perks: any) => {
9
- return Object.entries(perks).map(
10
- ([perkType, perkDetails]: [string, any]) => (
11
- <div key={perkType}>
12
- <h3>{perkType}</h3>
13
- {perkDetails.map((detail: any, index: number) => (
14
- <div key={index}>
15
- <p>Level: {detail.Level}</p>
16
- <p>Title: {detail.Title}</p>
17
- <p>Description: {detail.Text}</p>
18
- {detail.Power && <p>Power: {detail.Power}</p>}
8
+ const groupedPerks = React.useMemo(() => {
9
+ if (!configData.Perks) return [];
10
+ const groups = new Map<number, any[]>();
11
+
12
+ Object.entries(configData.Perks).forEach(([type, levels]) => {
13
+ if (Array.isArray(levels)) {
14
+ levels.forEach((levelDetail: any) => {
15
+ const level = levelDetail.Level;
16
+ if (!groups.has(level)) {
17
+ groups.set(level, []);
18
+ }
19
+ groups.get(level)?.push({ ...levelDetail, type });
20
+ });
21
+ }
22
+ });
23
+
24
+ // Sort levels
25
+ const sortedLevels = Array.from(groups.keys()).sort((a, b) => a - b);
26
+ return sortedLevels.map(level => ({
27
+ level,
28
+ perks: groups.get(level) || []
29
+ }));
30
+ }, [configData.Perks]);
31
+
32
+ const renderGroupedPerks = () => {
33
+ return groupedPerks.map((group) => (
34
+ <div key={group.level} style={{
35
+ marginBottom: '20px',
36
+ background: '#fff',
37
+ borderRadius: '16px',
38
+ overflow: 'hidden',
39
+ boxShadow: '0 4px 6px rgba(0,0,0,0.05)',
40
+ border: '1px solid #eee'
41
+ }}>
42
+ {/* Level Header */}
43
+ <div style={{
44
+ background: 'linear-gradient(90deg, #4CAF50 0%, #45a049 100%)',
45
+ padding: '12px 20px',
46
+ color: 'white',
47
+ fontWeight: 'bold',
48
+ fontSize: '1.2em',
49
+ display: 'flex',
50
+ alignItems: 'center',
51
+ gap: '10px'
52
+ }}>
53
+ <span style={{ background: 'rgba(255,255,255,0.2)', padding: '4px 10px', borderRadius: '8px', fontSize: '0.9em' }}>
54
+ Lvl {group.level}
55
+ </span>
56
+ <span>Unlocks</span>
57
+ </div>
58
+
59
+ {/* Perks List */}
60
+ <div style={{ padding: '0' }}>
61
+ {group.perks.map((perk: any, index: number) => (
62
+ <div key={index} style={{
63
+ padding: '15px 20px',
64
+ borderBottom: index < group.perks.length - 1 ? '1px solid #f0f0f0' : 'none',
65
+ display: 'flex',
66
+ flexDirection: 'column',
67
+ gap: '4px'
68
+ }}>
69
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
70
+ <div style={{ fontWeight: '700', color: '#333', fontSize: '1.05em' }}>{perk.Title}</div>
71
+ <div style={{
72
+ fontSize: '0.75em',
73
+ color: '#888',
74
+ background: '#f5f5f5',
75
+ padding: '2px 8px',
76
+ borderRadius: '4px',
77
+ textTransform: 'uppercase',
78
+ fontWeight: '600',
79
+ letterSpacing: '0.5px'
80
+ }}>
81
+ {perk.type}
82
+ </div>
83
+ </div>
84
+ <div style={{ color: '#555', lineHeight: '1.4' }}>{perk.Text}</div>
85
+ {perk.Power && (
86
+ <div style={{
87
+ color: '#1976d2',
88
+ fontWeight: '600',
89
+ fontSize: '0.9em',
90
+ marginTop: '4px',
91
+ display: 'inline-flex',
92
+ alignItems: 'center',
93
+ gap: '4px'
94
+ }}>
95
+ ⚡ Power: {perk.Power}
96
+ </div>
97
+ )}
19
98
  </div>
20
99
  ))}
21
100
  </div>
22
- ),
23
- );
101
+ </div>
102
+ ));
24
103
  };
25
104
 
26
105
  return (
27
- <div>
28
- <h2>{configData.Name}</h2>
29
- <ImageComponent src={configData.Icon} alt={configData.Name} />
30
- <p>Description: {configData.Desc}</p>
31
- {configData.ToggleablePerks && (
32
- <div>
33
- <h3>Toggleable Perks</h3>
34
- {Object.entries(configData.ToggleablePerks).map(([perk, value]) => (
35
- <p key={perk}>
36
- {perk}: {value ? "Enabled" : "Disabled"}
37
- </p>
38
- ))}
106
+ <div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
107
+
108
+ <div style={{
109
+ display: 'flex',
110
+ flexWrap: 'wrap',
111
+ gap: '40px',
112
+ height: '100%',
113
+ alignItems: 'start'
114
+ }}>
115
+
116
+ {/* Left Column: Icon */}
117
+ <div style={{
118
+ flex: '1 1 300px',
119
+ display: 'flex',
120
+ flexDirection: 'column',
121
+ alignItems: 'center',
122
+ gap: '20px',
123
+ background: '#f9f9f9',
124
+ padding: '30px',
125
+ borderRadius: '24px',
126
+ border: '2px solid #eee'
127
+ }}>
128
+ <div style={{ width: '100%', maxWidth: '300px' }}>
129
+ <ItemCard
130
+ id={configData.Name}
131
+ amount={1}
132
+ label={configData.Name}
133
+ itemData={{
134
+ icon: configData.Icon,
135
+ rarity: undefined,
136
+ name: configData.Name
137
+ }}
138
+ rarityColor={null}
139
+ />
140
+ </div>
141
+ <p style={{ fontStyle: 'italic', textAlign: 'center', color: '#666' }}>{configData.Desc}</p>
39
142
  </div>
40
- )}
41
- <div>
42
- <h3>Perks</h3>
43
- {renderPerks(configData.Perks)}
143
+
144
+ {/* Right Column: Perks */}
145
+ <div style={{
146
+ flex: '2 1 300px',
147
+ display: 'flex',
148
+ flexDirection: 'column',
149
+ gap: '20px',
150
+ minWidth: '300px'
151
+ }}>
152
+
153
+ {configData.ToggleablePerks && (
154
+ <div style={{ background: '#fff', padding: '20px', borderRadius: '16px', border: '1px solid #eee', boxShadow: '0 2px 4px rgba(0,0,0,0.02)' }}>
155
+ <h3 style={{ fontSize: '1.1em', marginTop: 0, borderBottom: '1px solid #eee', paddingBottom: '10px' }}>Toggleable Perks</h3>
156
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
157
+ {Object.entries(configData.ToggleablePerks).map(([perk, value]) => (
158
+ <span key={perk} className="badge" style={{ background: value ? '#e8f5e9' : '#ffebee', color: value ? '#2e7d32' : '#c62828', padding: '8px 12px', fontSize: '0.9rem' }}>
159
+ {perk}: {value ? "Enabled" : "Disabled"}
160
+ </span>
161
+ ))}
162
+ </div>
163
+ </div>
164
+ )}
165
+
166
+ {configData.Perks && (
167
+ <div style={{ background: '#fff' }}>
168
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '15px' }}>
169
+ <h3 style={{ fontSize: '1.4em', margin: 0 }}>Mastery Perks</h3>
170
+ </div>
171
+ {renderGroupedPerks()}
172
+ </div>
173
+ )}
174
+
175
+ </div>
176
+
44
177
  </div>
45
178
  </div>
46
179
  );
47
180
  };
48
181
 
182
+
183
+
49
184
  export default MasteryComponent;
@@ -7,28 +7,53 @@ const MerchantsComponent: React.FC<{
7
7
  const renderStockRange = (stockRange: number[][] | undefined) => {
8
8
  if (!stockRange) return null;
9
9
  return stockRange.map((range, index) => (
10
- <div key={index}>
11
- <p>
12
- Level {index + 1}: {range[0]} - {range[1]}
13
- </p>
10
+ <div key={index} style={{ background: '#e1f5fe', padding: '8px', borderRadius: '4px', textAlign: 'center' }}>
11
+ <strong>Lvl {index + 1}</strong>
12
+ <div>{range[0]} - {range[1]} items</div>
14
13
  </div>
15
14
  ));
16
15
  };
17
16
 
18
17
  return (
19
- <div>
20
- <h2>{configData.DisplayName}</h2>
21
- <p>Price Multiplier: {configData.PriceMult}</p>
22
- <p>Machine Name: {configData.MachineName}</p>
23
- <p>Refresh Rate: {configData.RefreshRate} seconds</p>
24
- {configData.HideNotification && <p>Notification: Hidden</p>}
25
- {configData.HideRespect && <p>Respect: Hidden</p>}
26
- {configData.IsStatic && <p>Static Merchant</p>}
27
- {renderStockRange(configData.StockRangeByRespectLevel)}
18
+ <div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
19
+ <div style={{ textAlign: 'left', width: '100%', marginBottom: '15px' }}>
20
+ <p><strong>Machine:</strong> {configData.MachineName}</p>
21
+ <p><strong>Price Mult:</strong> {configData.PriceMult}x</p>
22
+ <p><strong>Refresh:</strong> {configData.RefreshRate}s</p>
23
+ {configData.IsStatic && <p><strong>Type:</strong> Static Merchant</p>}
24
+ </div>
25
+
26
+ {configData.StockRangeByRespectLevel && (
27
+ <div style={{ width: '100%', marginBottom: '15px' }}>
28
+ <h4>Stock Ranges</h4>
29
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))', gap: '10px' }}>
30
+ {renderStockRange(configData.StockRangeByRespectLevel)}
31
+ </div>
32
+ </div>
33
+ )}
34
+
28
35
  {configData.SlotRespectLevels && (
29
- <div>
30
- <h3>Slot Respect Levels</h3>
31
- <p>{configData.SlotRespectLevels.join(", ")}</p>
36
+ <div style={{ width: '100%' }}>
37
+ <h4>Slot Respect Levels</h4>
38
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', justifyContent: 'center' }}>
39
+ {configData.SlotRespectLevels.map((level, idx) => (
40
+ <span key={idx} style={{
41
+ background: '#fff9c4',
42
+ color: '#fbc02d',
43
+ padding: '5px 10px',
44
+ borderRadius: '50%',
45
+ width: '30px',
46
+ height: '30px',
47
+ display: 'flex',
48
+ alignItems: 'center',
49
+ justifyContent: 'center',
50
+ fontWeight: 'bold',
51
+ border: '2px solid #fbc02d'
52
+ }}>
53
+ {level}
54
+ </span>
55
+ ))}
56
+ </div>
32
57
  </div>
33
58
  )}
34
59
  </div>
@@ -1,42 +1,37 @@
1
1
  import React from "react";
2
2
  import { CollectionConfigData } from "ps99-api";
3
- import ImageComponent from "./ImageComponent";
3
+ import ItemCard from "./ItemCard";
4
+ import { useItemResolution } from "../hooks/useItemResolution";
4
5
 
5
6
  const MiscItemsComponent: React.FC<{
6
7
  configData: CollectionConfigData<"MiscItems">;
7
8
  }> = ({ configData }) => {
9
+ const { getRarityColor } = useItemResolution();
10
+ const rarityColor = configData.Rarity ? getRarityColor(configData.Rarity) : null;
11
+
8
12
  return (
9
- <div
10
- style={{
11
- padding: "1em",
12
- border: "1px solid #ccc",
13
- borderRadius: "8px",
14
- backgroundColor: "#f9f9f9",
15
- }}
16
- >
17
- <h2 style={{ borderBottom: "2px solid #ccc", paddingBottom: "0.5em" }}>
18
- {configData.DisplayName}
19
- </h2>
20
- <p>
21
- <strong>Category:</strong> {configData.Category}
22
- </p>
23
- <ImageComponent src={configData.Icon} alt={configData.DisplayName} />
24
- {configData.AltIcon && (
25
- <ImageComponent
26
- src={configData.AltIcon}
27
- alt={`${configData.DisplayName} (Alternate)`}
13
+ <div style={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: '30px' }}>
14
+
15
+ <div style={{ width: '100%', maxWidth: '400px' }}>
16
+ <ItemCard
17
+ id={configData.DisplayName}
18
+ amount={1}
19
+ label={configData.DisplayName}
20
+ itemData={{
21
+ icon: configData.Icon,
22
+ rarity: configData.Rarity,
23
+ name: configData.DisplayName
24
+ }}
25
+ rarityColor={rarityColor}
28
26
  />
29
- )}
30
- <p>
31
- <strong>Description:</strong> {configData.Desc}
32
- </p>
33
- <p>
34
- <strong>Rarity:</strong> {configData.Rarity.DisplayName} (Rarity Number:{" "}
35
- {configData.Rarity.RarityNumber})
36
- </p>
37
- <p>
38
- <strong>Tradable:</strong> {configData.Tradable ? "Yes" : "No"}
39
- </p>
27
+ </div>
28
+
29
+ <div style={{ fontSize: '1.1em', color: '#555', textAlign: 'center', maxWidth: '600px', lineHeight: '1.6' }}>
30
+ <p style={{ marginBottom: '20px', background: '#fff', padding: '20px', borderRadius: '12px', border: '1px solid #eee' }}>"{configData.Desc}"</p>
31
+ <div style={{ display: 'flex', gap: '10px', justifyContent: 'center' }}>
32
+ {configData.Tradable && <span className="badge" style={{ background: '#9c27b0', color: 'white', padding: '8px 16px', borderRadius: '20px', fontWeight: 'bold' }}>Tradable</span>}
33
+ </div>
34
+ </div>
40
35
  </div>
41
36
  );
42
37
  };
@@ -1,12 +1,17 @@
1
1
  import React from "react";
2
2
  import { CollectionConfigData } from "ps99-api";
3
3
  import ImageComponent from "./ImageComponent";
4
+ import ItemCard from "./ItemCard";
5
+ import { useItemResolution } from "../hooks/useItemResolution";
4
6
 
5
7
  const PetsComponent: React.FC<{
6
8
  configData: CollectionConfigData<"Pets">;
7
9
  displayType?: "all" | "specific";
8
10
  pt?: number;
9
11
  }> = ({ configData, displayType = "all", pt }) => {
12
+ const { getRarityColor } = useItemResolution();
13
+ const rarityColor = (configData as any).rarity ? getRarityColor((configData as any).rarity) : null;
14
+
10
15
  const getVariationName = () => {
11
16
  if (pt === 1) return "(Golden)";
12
17
  if (pt === 2) return "(Rainbow)";
@@ -14,79 +19,113 @@ const PetsComponent: React.FC<{
14
19
  };
15
20
 
16
21
  return (
17
- <div style={{ padding: "1em", border: "1px solid #ccc", borderRadius: "8px", backgroundColor: "#f9f9f9" }}>
18
- <h2 style={{ borderBottom: "2px solid #ccc", paddingBottom: "0.5em" }}>
19
- {configData.name} {getVariationName()}
20
- </h2>
21
- {displayType === "all" && (
22
- <>
23
- <ImageComponent src={configData.thumbnail} alt={configData.name} />
22
+ <div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
23
+ {/* 2-Column Grid Layout */}
24
+ <div style={{
25
+ display: 'grid',
26
+ gridTemplateColumns: 'minmax(300px, 1fr) 2fr', // Left (Image) : Right (Details)
27
+ gap: '40px',
28
+ height: '100%',
29
+ alignItems: 'start'
30
+ }}>
31
+
32
+ {/* Left Column: Images */}
33
+ <div style={{
34
+ display: 'flex',
35
+ flexDirection: 'column',
36
+ alignItems: 'center',
37
+ gap: '20px'
38
+ }}>
39
+ {/* Main Image */}
40
+ <div style={{ width: '250px', height: '250px' }}>
41
+ <ImageComponent src={configData.thumbnail} alt={configData.name} />
42
+ </div>
43
+ {/* Golden Variant if exists */}
24
44
  {configData.goldenThumbnail && (
25
- <ImageComponent
26
- src={configData.goldenThumbnail}
27
- alt={`${configData.name} (Golden)`}
28
- />
29
- )}
30
- </>
31
- )}
32
- {displayType === "specific" && (
33
- <>
34
- {pt === 1 && configData.goldenThumbnail ? (
35
- <div style={{ minWidth: '250px' }}>
45
+ <div style={{ width: '150px', height: '150px', opacity: 0.8 }}>
46
+ <p style={{ textAlign: 'center', margin: '0 0 5px 0', fontSize: '0.9rem', fontWeight: 'bold', color: '#888' }}>Golden Variant</p>
36
47
  <ImageComponent
37
48
  src={configData.goldenThumbnail}
38
49
  alt={`${configData.name} (Golden)`}
39
50
  />
40
51
  </div>
41
- ) : (
42
- <div style={{ minWidth: '250px', outline: pt === 2 ? '4px solid #FFD700' : 'none', borderRadius: '8px' }}>
43
- <ImageComponent
44
- src={configData.thumbnail}
45
- alt={configData.name}
46
- />
47
- </div>
48
52
  )}
49
- </>
50
- )}
51
- <p><strong>From World Number:</strong> {configData.fromWorldNumber}</p>
52
- <p><strong>From Zone Number:</strong> {configData.fromZoneNumber}</p>
53
- {configData.indexObtainable && <p><strong>Index Obtainable:</strong> Yes</p>}
54
- {configData.huge && <p><strong>Huge:</strong> Yes</p>}
55
- {configData.fly && <p><strong>Can Fly:</strong> Yes</p>}
56
- {configData.tradable && <p><strong>Tradable:</strong> Yes</p>}
57
- {configData.secret && <p><strong>Secret:</strong> Yes</p>}
58
- {configData.hidden && <p><strong>Hidden:</strong> Yes</p>}
59
- {configData.cachedPower && (
60
- <div>
61
- <h3>Cached Power:</h3>
62
- <ul>
63
- {configData.cachedPower.map((power, index) => (
64
- <li key={index}>{power}</li>
65
- ))}
66
- </ul>
67
53
  </div>
68
- )}
69
- {configData.animations && (
70
- <div>
71
- <h3>Animations:</h3>
72
- <ul>
73
- {Object.entries(configData.animations).map(
74
- ([key, value], index) => (
75
- <li key={index}>
76
- {key}: {JSON.stringify(value)}
77
- </li>
78
- ),
54
+
55
+ {/* Right Column: details */}
56
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
57
+
58
+ {/* Stats Grid */}
59
+ <div style={{
60
+ display: 'grid',
61
+ gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
62
+ gap: '20px',
63
+ width: '100%'
64
+ }}>
65
+ <div style={{ background: '#f5f5f5', padding: '15px', borderRadius: '12px', border: '1px solid #ddd' }}>
66
+ <strong style={{ display: 'block', fontSize: '0.9rem', color: '#666', marginBottom: '5px' }}>FROM WORLD</strong>
67
+ <span style={{ fontSize: '1.5rem', fontWeight: 'bold', color: '#333' }}>{configData.fromWorldNumber || "?"}</span>
68
+ </div>
69
+ <div style={{ background: '#f5f5f5', padding: '15px', borderRadius: '12px', border: '1px solid #ddd' }}>
70
+ <strong style={{ display: 'block', fontSize: '0.9rem', color: '#666', marginBottom: '5px' }}>FROM ZONE</strong>
71
+ <span style={{ fontSize: '1.5rem', fontWeight: 'bold', color: '#333' }}>{configData.fromZoneNumber || "?"}</span>
72
+ </div>
73
+ {configData.power && (
74
+ <div style={{ background: '#e3f2fd', padding: '15px', borderRadius: '12px', border: '1px solid #90caf9' }}>
75
+ <strong style={{ display: 'block', fontSize: '0.9rem', color: '#1565c0', marginBottom: '5px' }}>POWER</strong>
76
+ <span style={{ fontSize: '1.5rem', fontWeight: 'bold', color: '#1565c0' }}>{configData.power}</span>
77
+ </div>
79
78
  )}
80
- </ul>
79
+ {configData.exclusiveLevel && (
80
+ <div style={{ background: '#f3e5f5', padding: '15px', borderRadius: '12px', border: '1px solid #ce93d8' }}>
81
+ <strong style={{ display: 'block', fontSize: '0.9rem', color: '#7b1fa2', marginBottom: '5px' }}>EXCLUSIVE LEVEL</strong>
82
+ <span style={{ fontSize: '1.5rem', fontWeight: 'bold', color: '#7b1fa2' }}>{configData.exclusiveLevel}</span>
83
+ </div>
84
+ )}
85
+ </div>
86
+
87
+ {/* Badges */}
88
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '10px' }}>
89
+ {configData.indexObtainable && <span className="badge" style={{ background: '#4caf50', color: 'white', padding: '8px 16px', borderRadius: '20px', fontWeight: 'bold' }}>Index Obtainable</span>}
90
+ {configData.huge && <span className="badge" style={{ background: '#ff9800', color: 'white', padding: '8px 16px', borderRadius: '20px', fontWeight: 'bold' }}>HUGE</span>}
91
+ {configData.fly && <span className="badge" style={{ background: '#2196f3', color: 'white', padding: '8px 16px', borderRadius: '20px', fontWeight: 'bold' }}>Fly</span>}
92
+ {configData.tradable && <span className="badge" style={{ background: '#9c27b0', color: 'white', padding: '8px 16px', borderRadius: '20px', fontWeight: 'bold' }}>Tradable</span>}
93
+ {configData.secret && <span className="badge" style={{ background: '#607d8b', color: 'white', padding: '8px 16px', borderRadius: '20px', fontWeight: 'bold' }}>Secret</span>}
94
+ {configData.hidden && <span className="badge" style={{ background: '#333', color: 'white', padding: '8px 16px', borderRadius: '20px', fontWeight: 'bold' }}>Hidden</span>}
95
+ </div>
96
+
97
+ {/* Description / Index Desc */}
98
+ {configData.indexDesc && (
99
+ <div style={{
100
+ marginTop: '10px',
101
+ padding: '20px',
102
+ background: '#fff3e0',
103
+ borderLeft: '5px solid #ff9800',
104
+ borderRadius: '4px',
105
+ fontStyle: 'italic',
106
+ fontSize: '1.1rem',
107
+ lineHeight: '1.6',
108
+ color: '#5d4037'
109
+ }}>
110
+ "{configData.indexDesc}"
111
+ </div>
112
+ )}
113
+
114
+ {/* Cached Power (Debug/Extra info) */}
115
+ {configData.cachedPower && (
116
+ <div style={{ marginTop: 'auto', paddingTop: '20px', borderTop: '1px solid #eee' }}>
117
+ <h4 style={{ margin: '0 0 10px 0', color: '#999', fontSize: '0.8rem', textTransform: 'uppercase' }}>Technical Data</h4>
118
+ <div style={{ fontSize: '0.86rem', color: '#aaa', fontFamily: 'monospace' }}>
119
+ Cached Power: {configData.cachedPower.join(', ')}
120
+ </div>
121
+ </div>
122
+ )}
123
+
81
124
  </div>
82
- )}
83
- {configData.indexDesc && <p><strong>Description:</strong> {configData.indexDesc}</p>}
84
- {configData.exclusiveLevel && (
85
- <p><strong>Exclusive Level:</strong> {configData.exclusiveLevel}</p>
86
- )}
87
- {configData.power && <p><strong>Power:</strong> {configData.power}</p>}
125
+ </div>
88
126
  </div>
89
127
  );
90
128
  };
91
129
 
130
+
92
131
  export default PetsComponent;