@rpg-engine/long-bow 0.8.7 → 0.8.8

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 (70) hide show
  1. package/dist/components/InformationCenter/sections/bestiary/{BestiarySection.d.ts → InformationCenterBestiarySection.d.ts} +1 -1
  2. package/dist/components/InformationCenter/sections/faq/{FaqSection.d.ts → InformationCenterFaqSection.d.ts} +1 -1
  3. package/dist/components/InformationCenter/sections/items/{ItemsSection.d.ts → InformationCenterItemsSection.d.ts} +1 -1
  4. package/dist/components/InformationCenter/sections/tutorials/{TutorialsSection.d.ts → InformationCenterTutorialsSection.d.ts} +2 -1
  5. package/dist/components/Item/Inventory/ItemPropertyColorSelector.d.ts +10 -0
  6. package/dist/components/Item/Inventory/ItemPropertySimpleHandler.d.ts +10 -0
  7. package/dist/components/Store/CartView.d.ts +15 -0
  8. package/dist/components/Store/StoreItemDetails.d.ts +16 -0
  9. package/dist/components/Store/StoreItemRow.d.ts +1 -2
  10. package/dist/components/Store/StoreTypes.d.ts +33 -4
  11. package/dist/components/Store/hooks/useStoreCart.d.ts +14 -0
  12. package/dist/components/Store/sections/StoreItemsSection.d.ts +12 -0
  13. package/dist/components/Store/sections/StorePacksSection.d.ts +9 -0
  14. package/dist/components/shared/CTAButton/CTAButton.d.ts +13 -0
  15. package/dist/components/shared/Card/Card.d.ts +14 -0
  16. package/dist/components/shared/Ellipsis.d.ts +1 -1
  17. package/dist/components/shared/PaginatedContent/PaginatedContent.d.ts +3 -1
  18. package/dist/components/shared/ScrollableContent/ScrollableContent.d.ts +23 -0
  19. package/dist/components/shared/SearchBar/SearchBar.d.ts +2 -3
  20. package/dist/components/shared/SearchHeader/SearchHeader.d.ts +17 -0
  21. package/dist/components/shared/ShoppingCart/CartCard.d.ts +14 -0
  22. package/dist/components/shared/ShoppingCart/CartCardHorizontal.d.ts +13 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/long-bow.cjs.development.js +104 -43
  25. package/dist/long-bow.cjs.development.js.map +1 -1
  26. package/dist/long-bow.cjs.production.min.js +1 -1
  27. package/dist/long-bow.cjs.production.min.js.map +1 -1
  28. package/dist/long-bow.esm.js +104 -44
  29. package/dist/long-bow.esm.js.map +1 -1
  30. package/dist/stories/UI/buttonsAndInputs/CTAButton.stories.d.ts +18 -0
  31. package/dist/stories/UI/dropdownsAndSelectors/ItemPropertyColorSelector.stories.d.ts +3 -0
  32. package/package.json +3 -2
  33. package/src/components/InformationCenter/InformationCenter.tsx +8 -8
  34. package/src/components/InformationCenter/InformationCenterTabView.tsx +0 -1
  35. package/src/components/InformationCenter/sections/bestiary/{BestiarySection.tsx → InformationCenterBestiarySection.tsx} +2 -1
  36. package/src/components/InformationCenter/sections/faq/InformationCenterFaqSection.tsx +81 -0
  37. package/src/components/InformationCenter/sections/items/{ItemsSection.tsx → InformationCenterItemsSection.tsx} +2 -10
  38. package/src/components/InformationCenter/sections/tutorials/InformationCenterTutorialsSection.tsx +135 -0
  39. package/src/components/Item/Inventory/ItemPropertyColorSelector.tsx +75 -0
  40. package/src/components/Item/Inventory/ItemPropertySimpleHandler.tsx +26 -0
  41. package/src/components/Item/Inventory/itemContainerHelper.ts +10 -1
  42. package/src/components/Store/CartView.tsx +271 -0
  43. package/src/components/Store/Store.tsx +199 -96
  44. package/src/components/Store/StoreItemDetails.tsx +161 -0
  45. package/src/components/Store/StoreItemRow.tsx +24 -40
  46. package/src/components/Store/StoreTypes.ts +38 -4
  47. package/src/components/Store/hooks/useStoreCart.ts +121 -0
  48. package/src/components/Store/sections/StoreItemsSection.tsx +52 -0
  49. package/src/components/Store/sections/StorePacksSection.tsx +89 -0
  50. package/src/components/Store/sections/images/custom-skin.png +0 -0
  51. package/src/components/shared/CTAButton/CTAButton.tsx +127 -0
  52. package/src/components/shared/Card/Card.tsx +107 -0
  53. package/src/components/shared/Ellipsis.tsx +20 -22
  54. package/src/components/shared/PaginatedContent/PaginatedContent.tsx +48 -79
  55. package/src/components/shared/ScrollableContent/ScrollableContent.tsx +160 -0
  56. package/src/components/shared/SearchBar/SearchBar.tsx +43 -24
  57. package/src/components/shared/SearchHeader/SearchHeader.tsx +80 -0
  58. package/src/components/shared/ShoppingCart/CartCard.tsx +116 -0
  59. package/src/components/shared/ShoppingCart/CartCardHorizontal.tsx +120 -0
  60. package/src/components/shared/SpriteFromAtlas.tsx +56 -48
  61. package/src/index.tsx +1 -0
  62. package/src/stories/Features/store/Store.stories.tsx +54 -4
  63. package/src/stories/UI/buttonsAndInputs/CTAButton.stories.tsx +77 -0
  64. package/src/stories/UI/dropdownsAndSelectors/ItemPropertyColorSelector.stories.tsx +77 -0
  65. package/dist/components/Store/InternalStoreTab.d.ts +0 -15
  66. package/dist/components/Store/StoreTabContent.d.ts +0 -14
  67. package/src/components/InformationCenter/sections/faq/FaqSection.tsx +0 -51
  68. package/src/components/InformationCenter/sections/tutorials/TutorialsSection.tsx +0 -144
  69. package/src/components/Store/InternalStoreTab.tsx +0 -142
  70. 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 SearchBarProps {
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<SearchBarProps> = ({
12
+ export const SearchBar: React.FC<ISearchBarProps> = ({
13
13
  value,
14
14
  onChange,
15
- placeholder = 'Search...',
15
+ placeholder,
16
16
  className,
17
- autoFocus = false,
18
17
  }) => {
19
18
  return (
20
19
  <Container className={className}>
21
- <input
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
- autoFocus={autoFocus}
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
- input {
35
- width: 100%;
36
- font-size: 0.8rem;
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
- &::placeholder {
44
- color: rgba(255, 255, 255, 0.5);
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
- &:focus {
48
- outline: none;
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
+ `;
@@ -37,43 +37,42 @@ export const SpriteFromAtlas: React.FC<IProps> = ({
37
37
  centered,
38
38
  borderRadius,
39
39
  }) => {
40
- //! If an item is not showing, remember that you MUST run yarn atlas:copy everytime you add a new item to the atlas (it will sync our public folder atlas with src/atlas).
41
- //!Due to React's limitations, we cannot import it from the public folder directly!
40
+ //! If an item is not showing, remember that you MUST run yarn atlas:copy everytime you add a new item to the atlas (it will sync our public folder atlas with src/atlas).
41
+ //!Due to React's limitations, we cannot import it from the public folder directly!
42
+ const spriteData =
43
+ atlasJSON?.frames?.[spriteKey] ||
44
+ atlasJSON?.frames?.['others/no-image.png'];
42
45
 
43
- const spriteData =
44
- atlasJSON?.frames?.[spriteKey] ||
45
- atlasJSON?.frames?.['others/no-image.png'];
46
+ if (!spriteData) {
47
+ console.error(
48
+ `SpriteFromAtlas: Could not find sprite with key ${spriteKey} in atlasJSON.`
49
+ );
50
+ return null;
51
+ }
46
52
 
47
- if (!spriteData) {
48
- console.error(
49
- `SpriteFromAtlas: Could not find sprite with key ${spriteKey} in atlasJSON.`
50
- );
51
- return null;
52
- }
53
-
54
- return (
55
- <Container
56
- width={width}
57
- height={height}
58
- hasHover={grayScale}
59
- onPointerDown={onPointerDown}
60
- style={containerStyle}
61
- >
62
- <ImgSprite
63
- className={`sprite-from-atlas-img ${imgClassname || ''}`}
64
- atlasIMG={atlasIMG}
65
- frame={spriteData.frame}
66
- scale={imgScale}
67
- grayScale={grayScale}
68
- opacity={opacity}
69
- style={imgStyle}
70
- centered={centered}
71
- borderRadius={borderRadius}
72
- tintColor={tintColor}
73
- />
74
- </Container>
75
- );
76
- };
53
+ return (
54
+ <Container
55
+ width={width}
56
+ height={height}
57
+ hasHover={grayScale}
58
+ onPointerDown={onPointerDown}
59
+ style={containerStyle}
60
+ >
61
+ <ImgSprite
62
+ className={`sprite-from-atlas-img ${imgClassname || ''}`}
63
+ atlasIMG={atlasIMG}
64
+ frame={spriteData.frame}
65
+ scale={imgScale}
66
+ grayScale={grayScale}
67
+ opacity={opacity}
68
+ style={imgStyle}
69
+ centered={centered}
70
+ borderRadius={borderRadius}
71
+ tintColor={tintColor}
72
+ />
73
+ </Container>
74
+ );
75
+ };
77
76
 
78
77
  interface IImgSpriteProps {
79
78
  atlasIMG: any;
@@ -112,21 +111,30 @@ const ImgSprite = styled.div<IImgSpriteProps>`
112
111
  width: ${props => props.frame.w}px;
113
112
  height: ${props => props.frame.h}px;
114
113
  background-image: url(${props => props.atlasIMG});
115
- background-position: -${props => props.frame.x}px -${props => props.frame.y}px;
114
+ background-position: -${props => props.frame.x}px -${props =>
115
+ props.frame.y}px;
116
116
  transform: scale(${props => props.scale});
117
117
  position: relative;
118
118
  top: ${props => (props.centered ? '0' : '8px')};
119
119
  left: ${props => (props.centered ? '0' : '8px')};
120
- filter: ${props => {
121
- const filters = [];
122
- if (props.grayScale) filters.push('grayscale(100%)');
123
- if (props.tintColor)
124
- filters.push(
125
- `brightness(0.8) contrast(1.2) sepia(100%) hue-rotate(${
126
- props.tintColor === '#FFD700' ? '40deg' : '210deg'
127
- }) saturate(400%)`
128
- );
129
- return filters.length ? filters.join(' ') : 'none';
130
- }};
120
+ ${props =>
121
+ props.tintColor &&
122
+ `
123
+ &::after {
124
+ content: '';
125
+ position: absolute;
126
+ top: 0;
127
+ left: 0;
128
+ width: ${props.frame.w}px;
129
+ height: ${props.frame.h}px;
130
+ background-color: ${props.tintColor};
131
+ mask-image: url(${props.atlasIMG});
132
+ mask-position: -${props.frame.x}px -${props.frame.y}px;
133
+ -webkit-mask-image: url(${props.atlasIMG});
134
+ -webkit-mask-position: -${props.frame.x}px -${props.frame.y}px;
135
+ mix-blend-mode: color;
136
+ ${props.grayScale ? 'filter: grayscale(100%);' : 'none'}
137
+ }
138
+ `}
131
139
  opacity: ${props => props.opacity};
132
- `;
140
+ `;
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
- userGold={1000}
143
+ packs={mockPacks}
94
144
  userAccountType={UserAccountTypes.Free}
95
- onPurchase={(item: IStoreItem, quantity: number) => {
96
- console.log('Purchased', quantity, 'x', item.name);
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
+ };