@rpg-engine/long-bow 0.8.7 → 0.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/InformationCenter/sections/bestiary/{BestiarySection.d.ts → InformationCenterBestiarySection.d.ts} +1 -1
- package/dist/components/InformationCenter/sections/faq/{FaqSection.d.ts → InformationCenterFaqSection.d.ts} +1 -1
- package/dist/components/InformationCenter/sections/items/{ItemsSection.d.ts → InformationCenterItemsSection.d.ts} +1 -1
- package/dist/components/InformationCenter/sections/tutorials/{TutorialsSection.d.ts → InformationCenterTutorialsSection.d.ts} +2 -1
- package/dist/components/Item/Inventory/ItemPropertyColorSelector.d.ts +10 -0
- package/dist/components/Item/Inventory/ItemPropertySimpleHandler.d.ts +10 -0
- package/dist/components/Store/CartView.d.ts +15 -0
- package/dist/components/Store/StoreItemDetails.d.ts +16 -0
- package/dist/components/Store/StoreItemRow.d.ts +1 -2
- package/dist/components/Store/StoreTypes.d.ts +33 -4
- package/dist/components/Store/hooks/useStoreCart.d.ts +14 -0
- package/dist/components/Store/sections/StoreItemsSection.d.ts +12 -0
- package/dist/components/Store/sections/StorePacksSection.d.ts +9 -0
- package/dist/components/shared/CTAButton/CTAButton.d.ts +13 -0
- package/dist/components/shared/Card/Card.d.ts +14 -0
- package/dist/components/shared/Ellipsis.d.ts +1 -1
- package/dist/components/shared/PaginatedContent/PaginatedContent.d.ts +3 -1
- package/dist/components/shared/ScrollableContent/ScrollableContent.d.ts +23 -0
- package/dist/components/shared/SearchBar/SearchBar.d.ts +2 -3
- package/dist/components/shared/SearchHeader/SearchHeader.d.ts +17 -0
- package/dist/components/shared/ShoppingCart/CartCard.d.ts +14 -0
- package/dist/components/shared/ShoppingCart/CartCardHorizontal.d.ts +13 -0
- package/dist/index.d.ts +1 -0
- package/dist/long-bow.cjs.development.js +105 -39
- package/dist/long-bow.cjs.development.js.map +1 -1
- package/dist/long-bow.cjs.production.min.js +1 -1
- package/dist/long-bow.cjs.production.min.js.map +1 -1
- package/dist/long-bow.esm.js +105 -40
- package/dist/long-bow.esm.js.map +1 -1
- package/dist/stories/UI/buttonsAndInputs/CTAButton.stories.d.ts +18 -0
- package/dist/stories/UI/dropdownsAndSelectors/ItemPropertyColorSelector.stories.d.ts +3 -0
- package/package.json +3 -2
- package/src/components/InformationCenter/InformationCenter.tsx +8 -8
- package/src/components/InformationCenter/InformationCenterTabView.tsx +0 -1
- package/src/components/InformationCenter/sections/bestiary/{BestiarySection.tsx → InformationCenterBestiarySection.tsx} +2 -1
- package/src/components/InformationCenter/sections/faq/InformationCenterFaqSection.tsx +81 -0
- package/src/components/InformationCenter/sections/items/{ItemsSection.tsx → InformationCenterItemsSection.tsx} +2 -10
- package/src/components/InformationCenter/sections/tutorials/InformationCenterTutorialsSection.tsx +135 -0
- package/src/components/Item/Inventory/ItemPropertyColorSelector.tsx +75 -0
- package/src/components/Item/Inventory/ItemPropertySimpleHandler.tsx +26 -0
- package/src/components/Item/Inventory/itemContainerHelper.ts +10 -1
- package/src/components/Store/CartView.tsx +271 -0
- package/src/components/Store/Store.tsx +199 -96
- package/src/components/Store/StoreItemDetails.tsx +161 -0
- package/src/components/Store/StoreItemRow.tsx +24 -40
- package/src/components/Store/StoreTypes.ts +38 -4
- package/src/components/Store/hooks/useStoreCart.ts +121 -0
- package/src/components/Store/sections/StoreItemsSection.tsx +52 -0
- package/src/components/Store/sections/StorePacksSection.tsx +89 -0
- package/src/components/Store/sections/images/custom-skin.png +0 -0
- package/src/components/shared/CTAButton/CTAButton.tsx +127 -0
- package/src/components/shared/Card/Card.tsx +107 -0
- package/src/components/shared/Ellipsis.tsx +20 -22
- package/src/components/shared/PaginatedContent/PaginatedContent.tsx +48 -79
- package/src/components/shared/ScrollableContent/ScrollableContent.tsx +160 -0
- package/src/components/shared/SearchBar/SearchBar.tsx +43 -24
- package/src/components/shared/SearchHeader/SearchHeader.tsx +80 -0
- package/src/components/shared/ShoppingCart/CartCard.tsx +116 -0
- package/src/components/shared/ShoppingCart/CartCardHorizontal.tsx +120 -0
- package/src/components/shared/SpriteFromAtlas.tsx +2 -0
- package/src/index.tsx +1 -0
- package/src/stories/Features/store/Store.stories.tsx +54 -4
- package/src/stories/UI/buttonsAndInputs/CTAButton.stories.tsx +77 -0
- package/src/stories/UI/dropdownsAndSelectors/ItemPropertyColorSelector.stories.tsx +77 -0
- package/dist/components/Store/InternalStoreTab.d.ts +0 -15
- package/dist/components/Store/StoreTabContent.d.ts +0 -14
- package/src/components/InformationCenter/sections/faq/FaqSection.tsx +0 -51
- package/src/components/InformationCenter/sections/tutorials/TutorialsSection.tsx +0 -144
- package/src/components/Store/InternalStoreTab.tsx +0 -142
- package/src/components/Store/StoreTabContent.tsx +0 -46
|
@@ -1,52 +1,71 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { FaSearch } from 'react-icons/fa';
|
|
2
3
|
import styled from 'styled-components';
|
|
3
4
|
|
|
4
|
-
interface
|
|
5
|
+
interface ISearchBarProps {
|
|
5
6
|
value: string;
|
|
6
7
|
onChange: (value: string) => void;
|
|
7
8
|
placeholder?: string;
|
|
8
9
|
className?: string;
|
|
9
|
-
autoFocus?: boolean;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export const SearchBar: React.FC<
|
|
12
|
+
export const SearchBar: React.FC<ISearchBarProps> = ({
|
|
13
13
|
value,
|
|
14
14
|
onChange,
|
|
15
|
-
placeholder
|
|
15
|
+
placeholder,
|
|
16
16
|
className,
|
|
17
|
-
autoFocus = false,
|
|
18
17
|
}) => {
|
|
19
18
|
return (
|
|
20
19
|
<Container className={className}>
|
|
21
|
-
<
|
|
20
|
+
<Input
|
|
22
21
|
type="text"
|
|
23
|
-
className="rpgui-input"
|
|
24
|
-
placeholder={placeholder}
|
|
25
22
|
value={value}
|
|
26
23
|
onChange={e => onChange(e.target.value)}
|
|
27
|
-
|
|
24
|
+
placeholder={placeholder}
|
|
25
|
+
className="rpgui-input"
|
|
28
26
|
/>
|
|
27
|
+
<IconContainer>
|
|
28
|
+
<SearchIcon />
|
|
29
|
+
</IconContainer>
|
|
29
30
|
</Container>
|
|
30
31
|
);
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
const Container = styled.div`
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
padding: 8px 12px;
|
|
38
|
-
background-color: rgba(0, 0, 0, 0.3);
|
|
39
|
-
border: none;
|
|
40
|
-
color: white;
|
|
41
|
-
border-radius: 4px;
|
|
35
|
+
position: relative;
|
|
36
|
+
width: 100%;
|
|
37
|
+
`;
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
const Input = styled.input`
|
|
40
|
+
width: 100%;
|
|
41
|
+
padding-right: 2.5rem !important;
|
|
42
|
+
background: rgba(0, 0, 0, 0.2) !important;
|
|
43
|
+
border: 2px solid #f59e0b !important;
|
|
44
|
+
box-shadow: 0 0 10px rgba(245, 158, 11, 0.3);
|
|
45
|
+
color: #ffffff !important;
|
|
46
|
+
font-family: 'Press Start 2P', cursive !important;
|
|
47
|
+
font-size: 0.875rem !important;
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
background-color: rgba(0, 0, 0, 0.4);
|
|
50
|
-
}
|
|
49
|
+
&::placeholder {
|
|
50
|
+
color: rgba(255, 255, 255, 0.5) !important;
|
|
51
51
|
}
|
|
52
52
|
`;
|
|
53
|
+
|
|
54
|
+
const IconContainer = styled.div`
|
|
55
|
+
position: absolute;
|
|
56
|
+
right: 0.75rem;
|
|
57
|
+
top: 50%;
|
|
58
|
+
transform: translateY(-50%);
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
width: 24px;
|
|
63
|
+
height: 24px;
|
|
64
|
+
pointer-events: none;
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
const SearchIcon = styled(FaSearch)`
|
|
68
|
+
font-size: 1rem;
|
|
69
|
+
color: #f59e0b;
|
|
70
|
+
filter: drop-shadow(0 0 2px rgba(245, 158, 11, 0.3));
|
|
71
|
+
`;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { Dropdown, IOptionsProps } from '../../Dropdown';
|
|
4
|
+
import { SearchBar } from '../SearchBar/SearchBar';
|
|
5
|
+
|
|
6
|
+
interface ISearchHeaderProps {
|
|
7
|
+
searchOptions?: {
|
|
8
|
+
value: string;
|
|
9
|
+
onChange: (value: string) => void;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
};
|
|
12
|
+
filterOptions?: {
|
|
13
|
+
options: IOptionsProps[];
|
|
14
|
+
selectedOption: string;
|
|
15
|
+
onOptionChange: (value: string) => void;
|
|
16
|
+
};
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const SearchHeader: React.FC<ISearchHeaderProps> = ({
|
|
21
|
+
searchOptions,
|
|
22
|
+
filterOptions,
|
|
23
|
+
className,
|
|
24
|
+
}) => {
|
|
25
|
+
if (!searchOptions && !filterOptions) return null;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<HeaderContainer className={className}>
|
|
29
|
+
<HeaderContent>
|
|
30
|
+
{searchOptions && (
|
|
31
|
+
<SearchContainer>
|
|
32
|
+
<StyledSearchBar
|
|
33
|
+
value={searchOptions.value}
|
|
34
|
+
onChange={searchOptions.onChange}
|
|
35
|
+
placeholder={searchOptions.placeholder || 'Search...'}
|
|
36
|
+
/>
|
|
37
|
+
</SearchContainer>
|
|
38
|
+
)}
|
|
39
|
+
{filterOptions && (
|
|
40
|
+
<FilterContainer>
|
|
41
|
+
<StyledDropdown
|
|
42
|
+
options={filterOptions.options}
|
|
43
|
+
onChange={filterOptions.onOptionChange}
|
|
44
|
+
width="200px"
|
|
45
|
+
/>
|
|
46
|
+
</FilterContainer>
|
|
47
|
+
)}
|
|
48
|
+
</HeaderContent>
|
|
49
|
+
</HeaderContainer>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const HeaderContainer = styled.div``;
|
|
54
|
+
|
|
55
|
+
const HeaderContent = styled.div`
|
|
56
|
+
display: flex;
|
|
57
|
+
justify-content: space-between;
|
|
58
|
+
align-items: center;
|
|
59
|
+
gap: 1rem;
|
|
60
|
+
background: rgba(0, 0, 0, 0.2);
|
|
61
|
+
padding: 1rem;
|
|
62
|
+
border-radius: 4px;
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
const SearchContainer = styled.div`
|
|
66
|
+
flex: 1;
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
const FilterContainer = styled.div`
|
|
70
|
+
display: flex;
|
|
71
|
+
justify-content: flex-end;
|
|
72
|
+
`;
|
|
73
|
+
|
|
74
|
+
const StyledSearchBar = styled(SearchBar)`
|
|
75
|
+
width: 100%;
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
const StyledDropdown = styled(Dropdown)`
|
|
79
|
+
min-width: 150px;
|
|
80
|
+
`;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { uiColors } from '../../../constants/uiColors';
|
|
4
|
+
import { Ellipsis } from '../Ellipsis';
|
|
5
|
+
|
|
6
|
+
export interface ICardProps {
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
imageUrl?: string | { src: string; default?: string };
|
|
10
|
+
category?: string;
|
|
11
|
+
onClick?: () => void;
|
|
12
|
+
footer?: React.ReactNode;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const ShoppingCard: React.FC<ICardProps> = ({
|
|
17
|
+
title,
|
|
18
|
+
description,
|
|
19
|
+
imageUrl,
|
|
20
|
+
category,
|
|
21
|
+
onClick,
|
|
22
|
+
footer,
|
|
23
|
+
className,
|
|
24
|
+
}) => {
|
|
25
|
+
const getImageSrc = () => {
|
|
26
|
+
if (!imageUrl) return '/placeholder-thumbnail.png';
|
|
27
|
+
if (typeof imageUrl === 'string') return imageUrl;
|
|
28
|
+
return imageUrl.default || imageUrl.src;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<CardContainer onClick={onClick} className={className}>
|
|
33
|
+
{imageUrl && (
|
|
34
|
+
<CardThumbnail>
|
|
35
|
+
<img src={getImageSrc()} alt={title} />
|
|
36
|
+
</CardThumbnail>
|
|
37
|
+
)}
|
|
38
|
+
<CardContent>
|
|
39
|
+
<CardTitle>
|
|
40
|
+
<Ellipsis maxLines={1} maxWidth="100%">
|
|
41
|
+
{title}
|
|
42
|
+
</Ellipsis>
|
|
43
|
+
</CardTitle>
|
|
44
|
+
<CardDescription>
|
|
45
|
+
<Ellipsis maxLines={5} maxWidth="100%">
|
|
46
|
+
{description}
|
|
47
|
+
</Ellipsis>
|
|
48
|
+
</CardDescription>
|
|
49
|
+
{category && <CardCategory>{category}</CardCategory>}
|
|
50
|
+
{footer && <CardFooter>{footer}</CardFooter>}
|
|
51
|
+
</CardContent>
|
|
52
|
+
</CardContainer>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const CardContainer = styled.div<{ onClick?: () => void }>`
|
|
57
|
+
background: rgba(0, 0, 0, 0.3);
|
|
58
|
+
border-radius: 4px;
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
border: 1px solid ${uiColors.darkGray};
|
|
61
|
+
cursor: ${props => (props.onClick ? 'pointer' : 'default')};
|
|
62
|
+
transition: transform 0.2s ease;
|
|
63
|
+
|
|
64
|
+
&:hover {
|
|
65
|
+
transform: ${props => (props.onClick ? 'translateY(-2px)' : 'none')};
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
const CardThumbnail = styled.div`
|
|
70
|
+
width: 100%;
|
|
71
|
+
height: 168px;
|
|
72
|
+
background: rgba(0, 0, 0, 0.2);
|
|
73
|
+
overflow: hidden;
|
|
74
|
+
|
|
75
|
+
img {
|
|
76
|
+
width: 100%;
|
|
77
|
+
height: 100%;
|
|
78
|
+
object-fit: cover;
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
81
|
+
|
|
82
|
+
const CardContent = styled.div`
|
|
83
|
+
padding: 12px;
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
const CardTitle = styled.h3`
|
|
87
|
+
margin: 0;
|
|
88
|
+
font-size: 0.6rem;
|
|
89
|
+
color: ${uiColors.yellow};
|
|
90
|
+
font-family: 'Press Start 2P', cursive;
|
|
91
|
+
margin-bottom: 8px;
|
|
92
|
+
`;
|
|
93
|
+
|
|
94
|
+
const CardDescription = styled.p`
|
|
95
|
+
margin: 0;
|
|
96
|
+
font-size: 0.55rem;
|
|
97
|
+
color: ${uiColors.lightGray};
|
|
98
|
+
font-family: 'Press Start 2P', cursive;
|
|
99
|
+
margin-bottom: 8px;
|
|
100
|
+
line-height: 1.4;
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
const CardCategory = styled.span`
|
|
104
|
+
font-size: 0.5rem;
|
|
105
|
+
color: ${uiColors.yellow};
|
|
106
|
+
font-family: 'Press Start 2P', cursive;
|
|
107
|
+
background: rgba(255, 255, 255, 0.1);
|
|
108
|
+
padding: 4px 8px;
|
|
109
|
+
border-radius: 4px;
|
|
110
|
+
`;
|
|
111
|
+
|
|
112
|
+
const CardFooter = styled.div`
|
|
113
|
+
margin-top: 12px;
|
|
114
|
+
padding-top: 12px;
|
|
115
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
116
|
+
`;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { uiColors } from '../../../constants/uiColors';
|
|
4
|
+
import { Ellipsis } from '../Ellipsis';
|
|
5
|
+
|
|
6
|
+
export interface ICardProps {
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
imageUrl?: string | { src: string; default?: string };
|
|
10
|
+
onClick?: () => void;
|
|
11
|
+
footer?: React.ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const ShoppingCardHorizontal: React.FC<ICardProps> = ({
|
|
16
|
+
title,
|
|
17
|
+
description,
|
|
18
|
+
imageUrl,
|
|
19
|
+
onClick,
|
|
20
|
+
footer,
|
|
21
|
+
className,
|
|
22
|
+
}) => {
|
|
23
|
+
const getImageSrc = () => {
|
|
24
|
+
if (!imageUrl) return '/placeholder-thumbnail.png';
|
|
25
|
+
if (typeof imageUrl === 'string') return imageUrl;
|
|
26
|
+
return imageUrl.default || imageUrl.src;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<CardContainer onClick={onClick} className={className}>
|
|
31
|
+
<LeftSection>
|
|
32
|
+
{imageUrl && (
|
|
33
|
+
<CardThumbnail>
|
|
34
|
+
<img src={getImageSrc()} alt={title} />
|
|
35
|
+
</CardThumbnail>
|
|
36
|
+
)}
|
|
37
|
+
</LeftSection>
|
|
38
|
+
<RightSection>
|
|
39
|
+
<CardTitle>
|
|
40
|
+
<Ellipsis maxLines={1} maxWidth="100%">
|
|
41
|
+
{title}
|
|
42
|
+
</Ellipsis>
|
|
43
|
+
</CardTitle>
|
|
44
|
+
<CardDescription>
|
|
45
|
+
<Ellipsis maxLines={3} maxWidth="100%">
|
|
46
|
+
{description}
|
|
47
|
+
</Ellipsis>
|
|
48
|
+
</CardDescription>
|
|
49
|
+
{footer && (
|
|
50
|
+
<CardFooter onClick={e => e.stopPropagation()}>{footer}</CardFooter>
|
|
51
|
+
)}
|
|
52
|
+
</RightSection>
|
|
53
|
+
</CardContainer>
|
|
54
|
+
);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const CardContainer = styled.div<{ onClick?: () => void }>`
|
|
58
|
+
display: flex;
|
|
59
|
+
background: rgba(0, 0, 0, 0.3);
|
|
60
|
+
border-radius: 4px;
|
|
61
|
+
border: 1px solid ${uiColors.darkGray};
|
|
62
|
+
cursor: ${props => (props.onClick ? 'pointer' : 'default')};
|
|
63
|
+
transition: transform 0.2s ease;
|
|
64
|
+
|
|
65
|
+
&:hover {
|
|
66
|
+
transform: ${props => (props.onClick ? 'translateY(-2px)' : 'none')};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
max-width: 380px;
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
const LeftSection = styled.div`
|
|
73
|
+
width: 120px;
|
|
74
|
+
flex-shrink: 0;
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
const RightSection = styled.div`
|
|
78
|
+
flex: 1;
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
padding: 12px;
|
|
82
|
+
min-width: 0;
|
|
83
|
+
max-width: 100%;
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
const CardThumbnail = styled.div`
|
|
87
|
+
width: 100%;
|
|
88
|
+
height: 100%;
|
|
89
|
+
background: rgba(0, 0, 0, 0.2);
|
|
90
|
+
overflow: hidden;
|
|
91
|
+
|
|
92
|
+
img {
|
|
93
|
+
width: 100%;
|
|
94
|
+
height: 100%;
|
|
95
|
+
object-fit: cover;
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
const CardTitle = styled.h3`
|
|
100
|
+
margin: 0;
|
|
101
|
+
font-size: 0.6rem;
|
|
102
|
+
color: ${uiColors.yellow};
|
|
103
|
+
font-family: 'Press Start 2P', cursive;
|
|
104
|
+
margin-bottom: 8px;
|
|
105
|
+
`;
|
|
106
|
+
|
|
107
|
+
const CardDescription = styled.p`
|
|
108
|
+
margin: 0;
|
|
109
|
+
font-size: 0.55rem;
|
|
110
|
+
color: ${uiColors.lightGray};
|
|
111
|
+
font-family: 'Press Start 2P', cursive;
|
|
112
|
+
line-height: 1.4;
|
|
113
|
+
margin-bottom: 8px;
|
|
114
|
+
`;
|
|
115
|
+
|
|
116
|
+
const CardFooter = styled.div`
|
|
117
|
+
margin-top: auto;
|
|
118
|
+
padding-top: 8px;
|
|
119
|
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
|
120
|
+
`;
|
package/src/index.tsx
CHANGED
|
@@ -22,6 +22,7 @@ export * from './components/Input';
|
|
|
22
22
|
export * from './components/InternalTabs/InternalTabs';
|
|
23
23
|
export { ErrorBoundary } from './components/Item/Inventory/ErrorBoundary';
|
|
24
24
|
export * from './components/Item/Inventory/ItemContainer';
|
|
25
|
+
export * from './components/Item/Inventory/ItemPropertySimpleHandler';
|
|
25
26
|
export * from './components/Item/Inventory/ItemQuantitySelectorModal';
|
|
26
27
|
export * from './components/Item/Inventory/ItemSlot';
|
|
27
28
|
export * from './components/itemSelector/ItemSelector';
|
|
@@ -2,8 +2,9 @@ import { UserAccountTypes } from '@rpg-engine/shared';
|
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { RPGUIRoot } from '../../../components/RPGUI/RPGUIRoot';
|
|
5
|
+
import customSkinImage from '../../../components/Store/sections/images/custom-skin.png';
|
|
5
6
|
import { Store } from '../../../components/Store/Store';
|
|
6
|
-
import { IStoreItem } from '../../../components/Store/StoreTypes';
|
|
7
|
+
import { IItemPack, IPurchase, IStoreItem } from '../../../components/Store/StoreTypes';
|
|
7
8
|
import itemsAtlasJSON from '../../../mocks/atlas/items/items.json';
|
|
8
9
|
import itemsAtlasIMG from '../../../mocks/atlas/items/items.png';
|
|
9
10
|
import { mockItems } from '../../../mocks/informationCenter.mocks';
|
|
@@ -85,15 +86,64 @@ const duplicatedItems: IStoreItem[] = [
|
|
|
85
86
|
})),
|
|
86
87
|
];
|
|
87
88
|
|
|
89
|
+
// Mock packs data
|
|
90
|
+
const mockPacks: IItemPack[] = [
|
|
91
|
+
// Regular Packs
|
|
92
|
+
{
|
|
93
|
+
key: 'starter-pack',
|
|
94
|
+
title: 'Starter Pack',
|
|
95
|
+
description: 'Perfect for beginners! Get essential items to start your adventure.',
|
|
96
|
+
priceUSD: 4.99,
|
|
97
|
+
image: customSkinImage,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
key: 'custom-skin-pack',
|
|
101
|
+
title: 'Custom Skin Pack',
|
|
102
|
+
description: 'Get a unique look with this custom skin pack! Stand out from the crowd.',
|
|
103
|
+
priceUSD: 7.99,
|
|
104
|
+
image: customSkinImage,
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
{
|
|
108
|
+
key: 'ultimate-pack',
|
|
109
|
+
title: '👑 Ultimate Premium Pack',
|
|
110
|
+
description: 'The most exclusive collection of items, effects, and perks. Includes everything from previous tiers plus legendary items!',
|
|
111
|
+
priceUSD: 99.99,
|
|
112
|
+
image: customSkinImage,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
key: 'gold-pack',
|
|
116
|
+
title: '🥇 Gold Premium Pack',
|
|
117
|
+
description: 'The ultimate premium experience with rare items, unique effects, and exclusive content. For true champions!',
|
|
118
|
+
priceUSD: 49.99,
|
|
119
|
+
image: customSkinImage,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
key: 'silver-pack',
|
|
123
|
+
title: '🥈 Silver Premium Pack',
|
|
124
|
+
description: 'Enhanced premium features with more exclusive items and special effects. For dedicated adventurers.',
|
|
125
|
+
priceUSD: 24.99,
|
|
126
|
+
image: customSkinImage,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
key: 'bronze-pack',
|
|
130
|
+
title: '🥉 Bronze Premium Pack',
|
|
131
|
+
description: 'Start your premium journey with exclusive items and basic perks. Perfect for casual players.',
|
|
132
|
+
priceUSD: 14.99,
|
|
133
|
+
image: customSkinImage,
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
];
|
|
137
|
+
|
|
88
138
|
// Create the story with the static mock data
|
|
89
139
|
export const Default: Story = {
|
|
90
140
|
render: () => (
|
|
91
141
|
<Store
|
|
92
142
|
items={duplicatedItems}
|
|
93
|
-
|
|
143
|
+
packs={mockPacks}
|
|
94
144
|
userAccountType={UserAccountTypes.Free}
|
|
95
|
-
onPurchase={(
|
|
96
|
-
console.log('
|
|
145
|
+
onPurchase={(purchase: IPurchase) => {
|
|
146
|
+
console.log('Purchase details:', purchase);
|
|
97
147
|
}}
|
|
98
148
|
atlasJSON={itemsAtlasJSON}
|
|
99
149
|
atlasIMG={itemsAtlasIMG}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Meta, Story } from '@storybook/react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { FaPlus, FaShoppingBag, FaShoppingCart, FaTrash } from 'react-icons/fa';
|
|
4
|
+
import { RPGUIRoot } from '../../../components/RPGUI/RPGUIRoot';
|
|
5
|
+
import { CTAButton } from '../../../components/shared/CTAButton/CTAButton';
|
|
6
|
+
|
|
7
|
+
interface ICTAButtonProps {
|
|
8
|
+
icon: React.ReactNode;
|
|
9
|
+
label?: React.ReactNode;
|
|
10
|
+
onClick?: () => void;
|
|
11
|
+
fullWidth?: boolean;
|
|
12
|
+
textColor?: string;
|
|
13
|
+
iconColor?: string;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const meta: Meta = {
|
|
18
|
+
title: 'UI/Buttons & Inputs/CTAButton',
|
|
19
|
+
component: CTAButton,
|
|
20
|
+
argTypes: {
|
|
21
|
+
icon: { control: false },
|
|
22
|
+
label: { control: 'text' },
|
|
23
|
+
fullWidth: { control: 'boolean' },
|
|
24
|
+
textColor: { control: 'color' },
|
|
25
|
+
iconColor: { control: 'color' },
|
|
26
|
+
disabled: { control: 'boolean' },
|
|
27
|
+
},
|
|
28
|
+
decorators: [
|
|
29
|
+
Story => (
|
|
30
|
+
<RPGUIRoot>
|
|
31
|
+
<div style={{ padding: '2rem', background: '#333' }}>
|
|
32
|
+
<Story />
|
|
33
|
+
</div>
|
|
34
|
+
</RPGUIRoot>
|
|
35
|
+
),
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default meta;
|
|
40
|
+
|
|
41
|
+
const Template: Story<ICTAButtonProps> = args => <CTAButton {...args} />;
|
|
42
|
+
|
|
43
|
+
export const CartButton = Template.bind({});
|
|
44
|
+
CartButton.args = {
|
|
45
|
+
icon: <FaShoppingCart />,
|
|
46
|
+
label: '3',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const DeleteButton = Template.bind({});
|
|
50
|
+
DeleteButton.args = {
|
|
51
|
+
icon: <FaTrash />,
|
|
52
|
+
textColor: '#ef4444',
|
|
53
|
+
iconColor: '#ef4444',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const AddButton = Template.bind({});
|
|
57
|
+
AddButton.args = {
|
|
58
|
+
icon: <FaPlus />,
|
|
59
|
+
label: 'Add Item',
|
|
60
|
+
textColor: '#22c55e',
|
|
61
|
+
iconColor: '#22c55e',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const CheckoutButton = Template.bind({});
|
|
65
|
+
CheckoutButton.args = {
|
|
66
|
+
icon: <FaShoppingBag />,
|
|
67
|
+
label: 'Complete Purchase',
|
|
68
|
+
fullWidth: true,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const DisabledCheckoutButton = Template.bind({});
|
|
72
|
+
DisabledCheckoutButton.args = {
|
|
73
|
+
icon: <FaShoppingBag />,
|
|
74
|
+
label: 'Complete Purchase',
|
|
75
|
+
fullWidth: true,
|
|
76
|
+
disabled: true,
|
|
77
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Meta, Story } from '@storybook/react';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import { ItemPropertySimpleHandler } from '../../../components/Item/Inventory/ItemPropertySimpleHandler';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'UI/Dropdowns & Selectors/ItemPropertySimpleHandler',
|
|
7
|
+
component: ItemPropertySimpleHandler,
|
|
8
|
+
parameters: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: {
|
|
11
|
+
component:
|
|
12
|
+
'A simple handler for selecting and confirming item properties, including colors.',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
isOpen: {
|
|
18
|
+
control: { type: 'boolean' },
|
|
19
|
+
description: 'Controls whether the color selector is open.',
|
|
20
|
+
},
|
|
21
|
+
selectedColor: {
|
|
22
|
+
control: { type: 'color' },
|
|
23
|
+
description: 'Initial selected color.',
|
|
24
|
+
},
|
|
25
|
+
onClose: {
|
|
26
|
+
action: 'onClose',
|
|
27
|
+
description: 'Callback when the selector is closed.',
|
|
28
|
+
},
|
|
29
|
+
onConfirm: {
|
|
30
|
+
action: 'onConfirm',
|
|
31
|
+
description: 'Callback when a color is confirmed.',
|
|
32
|
+
},
|
|
33
|
+
onChange: {
|
|
34
|
+
action: 'onChange',
|
|
35
|
+
description: 'Callback when a color is being selected.',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
} as Meta;
|
|
39
|
+
|
|
40
|
+
const Template: Story = args => {
|
|
41
|
+
const [isOpen, setIsOpen] = useState(args.isOpen ?? true);
|
|
42
|
+
const [currentColor, setCurrentColor] = useState(
|
|
43
|
+
args.selectedColor || '#000000'
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const handleClose = () => {
|
|
47
|
+
setIsOpen(false);
|
|
48
|
+
args.onClose?.();
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const handleConfirm = (color: string) => {
|
|
52
|
+
setCurrentColor(color);
|
|
53
|
+
setIsOpen(false);
|
|
54
|
+
args.onConfirm?.(color);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleChange = (color: string) => {
|
|
58
|
+
setCurrentColor(color);
|
|
59
|
+
args.onChange?.(color);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<ItemPropertySimpleHandler
|
|
64
|
+
isOpen={isOpen}
|
|
65
|
+
selectedColor={currentColor}
|
|
66
|
+
onClose={handleClose}
|
|
67
|
+
onConfirm={handleConfirm}
|
|
68
|
+
onChange={handleChange}
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const Default = Template.bind({});
|
|
74
|
+
Default.args = {
|
|
75
|
+
isOpen: true,
|
|
76
|
+
selectedColor: '#ff0000',
|
|
77
|
+
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { ItemType, UserAccountTypes } from '@rpg-engine/shared';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { IStoreItem } from './StoreTypes';
|
|
4
|
-
interface IInternalStoreTabProps {
|
|
5
|
-
items: IStoreItem[];
|
|
6
|
-
atlasJSON: Record<string, any>;
|
|
7
|
-
atlasIMG: string;
|
|
8
|
-
onPurchase: (item: IStoreItem, quantity: number) => void;
|
|
9
|
-
userGold: number;
|
|
10
|
-
userAccountType: UserAccountTypes;
|
|
11
|
-
type?: ItemType | 'premium' | 'all';
|
|
12
|
-
initialSearchQuery?: string;
|
|
13
|
-
}
|
|
14
|
-
export declare const InternalStoreTab: React.FC<IInternalStoreTabProps>;
|
|
15
|
-
export {};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { UserAccountTypes } from '@rpg-engine/shared';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { IStoreItem } from './StoreTypes';
|
|
4
|
-
interface IStoreTabContentProps {
|
|
5
|
-
items: IStoreItem[];
|
|
6
|
-
atlasJSON: Record<string, any>;
|
|
7
|
-
atlasIMG: string;
|
|
8
|
-
onPurchase: (item: IStoreItem, quantity: number) => void;
|
|
9
|
-
userGold: number;
|
|
10
|
-
userAccountType: UserAccountTypes;
|
|
11
|
-
tabId: string;
|
|
12
|
-
}
|
|
13
|
-
export declare const StoreTabContent: React.FC<IStoreTabContentProps>;
|
|
14
|
-
export {};
|