ps99-api 2.4.0 → 2.5.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/.github/workflows/release-on-main.yml +1 -2
- package/.idea/runConfigurations/test_changing.xml +1 -1
- package/debug_currency.json +57 -0
- package/debug_goals.json +271 -0
- package/dist/ps99-api.d.ts +2 -0
- package/dist/ps99-api.js +4 -1
- package/dist/ps99-api.js.map +1 -1
- package/dist/request-client/axios.js +6 -1
- package/dist/request-client/axios.js.map +1 -1
- package/dist/responses/collection/index.d.ts +1 -0
- package/dist/responses/collection/index.js +15 -0
- package/dist/responses/collection/index.js.map +1 -1
- package/dist/responses/collection/rarity.d.ts +1 -0
- package/example-web/react/package-lock.json +1504 -1470
- package/example-web/react2/package-lock.json +3082 -2759
- package/example-web/react2/package.json +6 -1
- package/example-web/react2/public/assets/gold_variant_icon.png +0 -0
- package/example-web/react2/public/assets/hot_cocoa_egg.png +0 -0
- package/example-web/react2/public/index.html +34 -31
- package/example-web/react2/src/App.tsx +6 -9
- package/example-web/react2/src/assets/guild_placeholder.png +0 -0
- package/example-web/react2/src/components/AchievementsComponent.tsx +74 -19
- package/example-web/react2/src/components/BoostsComponent.tsx +16 -5
- package/example-web/react2/src/components/BoothsComponent.tsx +22 -52
- package/example-web/react2/src/components/BoxesComponent.tsx +48 -16
- package/example-web/react2/src/components/BuffsComponent.tsx +82 -34
- package/example-web/react2/src/components/CharmsComponent.tsx +47 -24
- package/example-web/react2/src/components/CollectionConfigIndex.tsx +398 -35
- package/example-web/react2/src/components/CollectionsIndex.tsx +132 -23
- package/example-web/react2/src/components/CollectionsLayout.tsx +50 -0
- package/example-web/react2/src/components/CurrencyComponent.tsx +55 -39
- package/example-web/react2/src/components/DynamicCollectionConfigData.tsx +163 -15
- package/example-web/react2/src/components/EggsComponent.tsx +50 -12
- package/example-web/react2/src/components/EnchantsComponent.tsx +81 -40
- package/example-web/react2/src/components/FishingRodsComponent.tsx +36 -22
- package/example-web/react2/src/components/Footer.tsx +1 -8
- package/example-web/react2/src/components/FruitsComponent.tsx +40 -17
- package/example-web/react2/src/components/GenericFetchComponent.tsx +9 -1
- package/example-web/react2/src/components/GuildBattlesComponent.tsx +41 -34
- package/example-web/react2/src/components/Header.tsx +5 -37
- package/example-web/react2/src/components/HomePage.tsx +15 -17
- package/example-web/react2/src/components/HoverboardsComponent.tsx +23 -99
- package/example-web/react2/src/components/ImageComponent.tsx +255 -45
- package/example-web/react2/src/components/ItemCard.tsx +240 -0
- package/example-web/react2/src/components/LootboxesComponent.tsx +22 -7
- package/example-web/react2/src/components/MasteryComponent.tsx +92 -29
- package/example-web/react2/src/components/MerchantsComponent.tsx +41 -16
- package/example-web/react2/src/components/MiscItemsComponent.tsx +26 -31
- package/example-web/react2/src/components/PetsComponent.tsx +100 -61
- package/example-web/react2/src/components/PotionsComponent.tsx +43 -27
- package/example-web/react2/src/components/RandomEventsComponent.tsx +32 -23
- package/example-web/react2/src/components/RanksComponent.tsx +187 -62
- package/example-web/react2/src/components/RarityComponent.tsx +123 -5
- package/example-web/react2/src/components/RebirthsComponent.tsx +36 -19
- package/example-web/react2/src/components/SecretRoomsComponent.tsx +5 -4
- package/example-web/react2/src/components/SeedsComponent.tsx +41 -21
- package/example-web/react2/src/components/ShovelsComponent.tsx +21 -9
- package/example-web/react2/src/components/Sidebar.tsx +105 -0
- package/example-web/react2/src/components/SprinklersComponent.tsx +25 -10
- package/example-web/react2/src/components/Tooltip.tsx +36 -0
- package/example-web/react2/src/components/UltimatesComponent.tsx +28 -16
- package/example-web/react2/src/components/UpgradesComponent.tsx +96 -47
- package/example-web/react2/src/components/WateringCansComponent.tsx +20 -14
- package/example-web/react2/src/components/WorldsComponent.tsx +21 -11
- package/example-web/react2/src/components/XPPotionsComponent.tsx +28 -11
- package/example-web/react2/src/components/ZoneFlagsComponent.tsx +25 -14
- package/example-web/react2/src/components/ZonesComponent.tsx +43 -60
- package/example-web/react2/src/constants/collectionIcons.ts +29 -0
- package/example-web/react2/src/context/CollectionDataContext.tsx +62 -0
- package/example-web/react2/src/hooks/useExpandableList.ts +38 -0
- package/example-web/react2/src/hooks/useItemResolution.ts +351 -0
- package/example-web/react2/src/index.css +257 -0
- package/example-web/react2/src/index.tsx +2 -1
- package/example-web/react2/temp_model.rbxm +0 -0
- package/example-web/react2/webpack.config.js +103 -47
- package/package.json +11 -11
- package/ranks.json +1 -0
- package/repro_collection_fetch.ts +33 -0
- package/repro_image_fetch.ts +50 -0
- package/src/__tests__/__snapshots__/ps99-api-changes.ts.snap +34841 -10439
- package/src/__tests__/__snapshots__/ps99-api-live.ts.snap +160667 -67217
- package/src/ps99-api.ts +9 -5
- package/src/request-client/axios.ts +6 -2
- package/src/responses/collection/index.ts +1 -0
- package/src/responses/collection/rarity.ts +1 -0
- package/tsconfig.json +1 -1
- package/example-web/react2/public/service-worker.js +0 -63
|
@@ -1,46 +1,109 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CollectionConfigData } from "ps99-api";
|
|
3
|
-
import
|
|
3
|
+
import ItemCard from "./ItemCard";
|
|
4
|
+
import { useExpandableList } from "../hooks/useExpandableList";
|
|
4
5
|
|
|
5
6
|
const MasteryComponent: React.FC<{
|
|
6
7
|
configData: CollectionConfigData<"Mastery">;
|
|
7
8
|
}> = ({ configData }) => {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
const perksEntries = React.useMemo(() => configData.Perks ? Object.entries(configData.Perks) : [], [configData.Perks]);
|
|
10
|
+
const { expandedIndices, toggle, expandAll, collapseAll, isExpanded } = useExpandableList(perksEntries.length);
|
|
11
|
+
|
|
12
|
+
const renderPerks = () => {
|
|
13
|
+
return perksEntries.map(
|
|
14
|
+
([perkType, perkDetails]: [string, any], index: number) => (
|
|
15
|
+
<div key={perkType} style={{ marginBottom: '15px', textAlign: 'left', background: '#f9f9f9', padding: '10px', borderRadius: '8px' }}>
|
|
16
|
+
<h4
|
|
17
|
+
onClick={() => toggle(index)}
|
|
18
|
+
style={{ margin: '0 0 10px 0', color: '#333', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '8px' }}
|
|
19
|
+
>
|
|
20
|
+
{isExpanded(index) ? '▼' : '▶'} {perkType}
|
|
21
|
+
</h4>
|
|
22
|
+
{isExpanded(index) && (
|
|
23
|
+
<div>
|
|
24
|
+
{perkDetails.map((detail: any, idx: number) => (
|
|
25
|
+
<div key={idx} style={{ marginBottom: '8px', paddingLeft: '10px', borderLeft: '2px solid #ddd' }}>
|
|
26
|
+
<div style={{ fontWeight: 'bold', fontSize: '0.9em' }}>Lvl {detail.Level}: {detail.Title}</div>
|
|
27
|
+
<div style={{ fontSize: '0.9em', color: '#666' }}>{detail.Text}</div>
|
|
28
|
+
{detail.Power && <div style={{ fontSize: '0.8em', color: '#1976d2' }}>Power: {detail.Power}</div>}
|
|
29
|
+
</div>
|
|
30
|
+
))}
|
|
19
31
|
</div>
|
|
20
|
-
)
|
|
32
|
+
)}
|
|
21
33
|
</div>
|
|
22
34
|
),
|
|
23
35
|
);
|
|
24
36
|
};
|
|
25
37
|
|
|
26
38
|
return (
|
|
27
|
-
<div>
|
|
28
|
-
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
40
|
+
|
|
41
|
+
<div style={{
|
|
42
|
+
display: 'grid',
|
|
43
|
+
gridTemplateColumns: 'minmax(300px, 1fr) 2fr',
|
|
44
|
+
gap: '40px',
|
|
45
|
+
height: '100%',
|
|
46
|
+
alignItems: 'start'
|
|
47
|
+
}}>
|
|
48
|
+
|
|
49
|
+
{/* Left Column: Icon */}
|
|
50
|
+
<div style={{
|
|
51
|
+
display: 'flex',
|
|
52
|
+
flexDirection: 'column',
|
|
53
|
+
alignItems: 'center',
|
|
54
|
+
gap: '20px',
|
|
55
|
+
background: '#f9f9f9',
|
|
56
|
+
padding: '30px',
|
|
57
|
+
borderRadius: '24px',
|
|
58
|
+
border: '2px solid #eee'
|
|
59
|
+
}}>
|
|
60
|
+
<div style={{ width: '100%', maxWidth: '300px' }}>
|
|
61
|
+
<ItemCard
|
|
62
|
+
id={configData.Name}
|
|
63
|
+
amount={1}
|
|
64
|
+
label={configData.Name}
|
|
65
|
+
itemData={{
|
|
66
|
+
icon: configData.Icon,
|
|
67
|
+
rarity: undefined,
|
|
68
|
+
name: configData.Name
|
|
69
|
+
}}
|
|
70
|
+
rarityColor={null}
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
<p style={{ fontStyle: 'italic', textAlign: 'center', color: '#666' }}>{configData.Desc}</p>
|
|
39
74
|
</div>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<
|
|
43
|
-
|
|
75
|
+
|
|
76
|
+
{/* Right Column: Perks */}
|
|
77
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
|
|
78
|
+
|
|
79
|
+
{configData.ToggleablePerks && (
|
|
80
|
+
<div style={{ background: '#fff', padding: '20px', borderRadius: '16px', border: '1px solid #eee', boxShadow: '0 2px 4px rgba(0,0,0,0.02)' }}>
|
|
81
|
+
<h3 style={{ fontSize: '1.1em', marginTop: 0, borderBottom: '1px solid #eee', paddingBottom: '10px' }}>Toggleable Perks</h3>
|
|
82
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}>
|
|
83
|
+
{Object.entries(configData.ToggleablePerks).map(([perk, value]) => (
|
|
84
|
+
<span key={perk} className="badge" style={{ background: value ? '#e8f5e9' : '#ffebee', color: value ? '#2e7d32' : '#c62828', padding: '8px 12px', fontSize: '0.9rem' }}>
|
|
85
|
+
{perk}: {value ? "Enabled" : "Disabled"}
|
|
86
|
+
</span>
|
|
87
|
+
))}
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
)}
|
|
91
|
+
|
|
92
|
+
{configData.Perks && (
|
|
93
|
+
<div style={{ background: '#fff' }}>
|
|
94
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '15px' }}>
|
|
95
|
+
<h3 style={{ fontSize: '1.4em', margin: 0 }}>Mastery Perks</h3>
|
|
96
|
+
<div style={{ display: 'flex', gap: '10px' }}>
|
|
97
|
+
<button onClick={expandAll} style={{ padding: '6px 12px', borderRadius: '6px', border: '1px solid #ddd', background: '#fff', cursor: 'pointer', fontSize: '0.9rem' }}>Expand All</button>
|
|
98
|
+
<button onClick={collapseAll} style={{ padding: '6px 12px', borderRadius: '6px', border: '1px solid #ddd', background: '#fff', cursor: 'pointer', fontSize: '0.9rem' }}>Collapse All</button>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
{renderPerks()}
|
|
102
|
+
</div>
|
|
103
|
+
)}
|
|
104
|
+
|
|
105
|
+
</div>
|
|
106
|
+
|
|
44
107
|
</div>
|
|
45
108
|
</div>
|
|
46
109
|
);
|
|
@@ -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
|
-
<
|
|
12
|
-
|
|
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
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{
|
|
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
|
-
<
|
|
31
|
-
<
|
|
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
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
</
|
|
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={{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
<
|
|
26
|
-
|
|
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
|
-
|
|
70
|
-
<div>
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -1,46 +1,62 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CollectionConfigData } from "ps99-api";
|
|
3
|
+
import ItemCard from "./ItemCard";
|
|
3
4
|
import ImageComponent from "./ImageComponent";
|
|
5
|
+
import { useItemResolution } from "../hooks/useItemResolution";
|
|
4
6
|
|
|
5
7
|
const PotionsComponent: React.FC<{
|
|
6
8
|
configData: CollectionConfigData<"Potions">;
|
|
7
9
|
}> = ({ configData }) => {
|
|
10
|
+
const { getRarityColor } = useItemResolution();
|
|
11
|
+
|
|
8
12
|
return (
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<div style={{ minWidth: '250px' }}>
|
|
13
|
+
|
|
14
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
15
|
+
|
|
16
|
+
<div style={{ display: 'flex', gap: '20px', alignItems: 'center', marginBottom: '20px', flexWrap: 'wrap', justifyContent: 'center' }}>
|
|
17
|
+
<div style={{ width: '150px', height: '150px' }}>
|
|
15
18
|
<ImageComponent
|
|
16
19
|
src={configData.Tiers[0].Icon}
|
|
17
20
|
alt={configData.Tiers[0].DisplayName}
|
|
18
21
|
/>
|
|
19
22
|
</div>
|
|
20
|
-
<div>
|
|
21
|
-
<p><strong>Description:</strong> {configData.Tiers[0].Desc}</p>
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
<div style={{ textAlign: 'left', flex: 1, minWidth: '200px' }}>
|
|
24
|
+
<p style={{ marginBottom: '8px' }}><strong>Description:</strong> {configData.Tiers[0].Desc}</p>
|
|
25
|
+
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px' }}>
|
|
26
|
+
<p><strong>Primary:</strong> <span style={{ color: configData.PrimaryColor }}>{configData.PrimaryColor}</span></p>
|
|
27
|
+
<p><strong>Secondary:</strong> <span style={{ color: configData.SecondaryColor }}>{configData.SecondaryColor}</span></p>
|
|
28
|
+
<p><strong>Base Tier:</strong> {configData.BaseTier}</p>
|
|
29
|
+
<p><strong>Max Tier:</strong> {configData.MaxTier}</p>
|
|
30
|
+
</div>
|
|
26
31
|
</div>
|
|
27
32
|
</div>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
|
|
34
|
+
<div style={{ marginTop: '20px' }}>
|
|
35
|
+
<h3>Tiers</h3>
|
|
36
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: '15px' }}>
|
|
37
|
+
{configData.Tiers.map((tier, index) => {
|
|
38
|
+
const rarityColor = tier.Rarity ? getRarityColor(tier.Rarity) : null;
|
|
39
|
+
return (
|
|
40
|
+
<div key={index} style={{ marginBottom: '10px' }}>
|
|
41
|
+
<ItemCard
|
|
42
|
+
id={tier.DisplayName}
|
|
43
|
+
amount={1}
|
|
44
|
+
label={tier.DisplayName}
|
|
45
|
+
tn={index + 1}
|
|
46
|
+
itemData={{
|
|
47
|
+
icon: tier.Icon,
|
|
48
|
+
rarity: tier.Rarity,
|
|
49
|
+
name: tier.DisplayName
|
|
50
|
+
}}
|
|
51
|
+
rarityColor={rarityColor}
|
|
52
|
+
/>
|
|
53
|
+
<div style={{ marginTop: '10px', fontSize: '0.9em', color: '#666', textAlign: 'center' }}>
|
|
54
|
+
<p style={{ fontWeight: 'bold' }}>Power: {tier.Power}</p>
|
|
55
|
+
<p>Time: {tier.Time}s</p>
|
|
56
|
+
</div>
|
|
38
57
|
</div>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<p><strong>Rarity:</strong> {tier.Rarity.DisplayName}</p>
|
|
42
|
-
</div>
|
|
43
|
-
))}
|
|
58
|
+
);
|
|
59
|
+
})}
|
|
44
60
|
</div>
|
|
45
61
|
</div>
|
|
46
62
|
</div>
|
|
@@ -1,38 +1,47 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { CollectionConfigData } from "ps99-api";
|
|
3
|
-
import
|
|
3
|
+
import ItemCard from "./ItemCard";
|
|
4
4
|
|
|
5
5
|
const RandomEventsComponent: React.FC<{
|
|
6
6
|
configData: CollectionConfigData<"RandomEvents">;
|
|
7
7
|
}> = ({ configData }) => {
|
|
8
8
|
return (
|
|
9
|
-
<div>
|
|
10
|
-
|
|
11
|
-
<div>
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
<div style={{ width: '100%', height: '100%', boxSizing: 'border-box' }}>
|
|
10
|
+
|
|
11
|
+
<div style={{ maxWidth: '300px', margin: '0 auto 15px auto' }}>
|
|
12
|
+
<ItemCard
|
|
13
|
+
id={configData.Name}
|
|
14
|
+
amount={1}
|
|
15
|
+
label={configData.Name}
|
|
16
|
+
itemData={{
|
|
17
|
+
icon: configData.Icon,
|
|
18
|
+
rarity: undefined,
|
|
19
|
+
name: configData.Name
|
|
20
|
+
}}
|
|
21
|
+
rarityColor={configData.Color}
|
|
22
|
+
/>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px', marginBottom: '20px', textAlign: 'left' }}>
|
|
26
|
+
<p><strong>Color:</strong> <span style={{ color: configData.Color }}>{configData.Color}</span></p>
|
|
27
|
+
<p><strong>Duration:</strong> {configData.Duration}s</p>
|
|
28
|
+
<p><strong>Chance:</strong> {configData.Chance}</p>
|
|
29
|
+
{configData.BreakingRequirement && <p><strong>Break Req:</strong> {configData.BreakingRequirement}</p>}
|
|
24
30
|
</div>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<
|
|
31
|
+
|
|
32
|
+
<div style={{ borderTop: '1px solid #eee', paddingTop: '15px' }}>
|
|
33
|
+
<h3 style={{ fontSize: '1.1em', marginBottom: '10px' }}>Area Whitelist</h3>
|
|
34
|
+
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '5px', justifyContent: 'center' }}>
|
|
28
35
|
{Object.entries(configData.AreaWhitelist).map(
|
|
29
36
|
([area, allowed], index) => (
|
|
30
|
-
|
|
31
|
-
{
|
|
32
|
-
|
|
37
|
+
allowed && (
|
|
38
|
+
<span key={index} className="badge">
|
|
39
|
+
{area.replace(/_/g, " ")}
|
|
40
|
+
</span>
|
|
41
|
+
)
|
|
33
42
|
),
|
|
34
43
|
)}
|
|
35
|
-
</
|
|
44
|
+
</div>
|
|
36
45
|
</div>
|
|
37
46
|
</div>
|
|
38
47
|
);
|