@rpg-engine/long-bow 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
+ import { FaDiscord, FaWhatsapp } from 'react-icons/fa';
2
3
  import styled from 'styled-components';
4
+ import { uiColors } from '../../constants/uiColors';
3
5
  import { useChat } from '../../hooks/useChat';
4
6
  import { Chat } from '../Chat/Chat';
5
7
  import { ChatContent } from './ChatContent';
@@ -8,10 +10,24 @@ import { ExpandButton } from './ExpandButton';
8
10
  import { RecentChats } from './RecentChats';
9
11
  import { IChatRevampProps } from './types';
10
12
 
11
- export const ChatRevamp = ({
13
+ interface ITopBarProps {
14
+ isExpanded: boolean;
15
+ }
16
+
17
+ interface IAllChatsContainerProps {
18
+ width: string;
19
+ height: string;
20
+ isExpanded: boolean;
21
+ }
22
+
23
+ interface IChatContentWrapperProps {
24
+ isPrivate: boolean;
25
+ }
26
+
27
+ export const ChatRevamp: React.FC<IChatRevampProps> = ({
12
28
  chatMessages,
13
29
  onSendGlobalChatMessage,
14
- onSendGuildChatMessage, // Add this new prop
30
+ onSendGuildChatMessage,
15
31
  onChangeCharacterName,
16
32
  onFocus,
17
33
  onBlur,
@@ -29,12 +45,14 @@ export const ChatRevamp = ({
29
45
  onRemoveRecentChatCharacter,
30
46
  unseenMessageCharacterIds,
31
47
  onSendTradeMessage,
32
- searchCharacterUI,
33
- hideSearchCharacterUI,
34
- showSearchCharacterUI,
48
+ searchCharacterUI = false,
49
+ hideSearchCharacterUI = () => {},
50
+ showSearchCharacterUI = () => {},
35
51
  minimizedByDefault = false,
36
52
  autoCloseOnSend,
37
53
  onSendLocalChatMessage,
54
+ onDiscordClick,
55
+ onWhatsAppClick,
38
56
  }: IChatRevampProps) => {
39
57
  const isPrivate = activeTab === 'private';
40
58
  const isTrade = activeTab === 'trade';
@@ -48,15 +66,35 @@ export const ChatRevamp = ({
48
66
  unseenMessageCharacterIds,
49
67
  });
50
68
 
69
+ const handleDiscordClick = (e: React.MouseEvent) => {
70
+ e.preventDefault();
71
+ onDiscordClick?.();
72
+ };
73
+
74
+ const handleWhatsAppClick = (e: React.MouseEvent) => {
75
+ e.preventDefault();
76
+ onWhatsAppClick?.();
77
+ };
78
+
51
79
  return (
52
80
  <ChatRevampContainer>
53
81
  <TopBar isExpanded={chatHook.isExpanded}>
54
82
  {chatHook.isExpanded && (
55
- <ChatTabs
56
- tabs={tabs}
57
- activeTab={activeTab}
58
- onChangeTab={chatHook.handleTabChange}
59
- />
83
+ <>
84
+ <ChatTabs
85
+ tabs={tabs}
86
+ activeTab={activeTab}
87
+ onChangeTab={chatHook.handleTabChange}
88
+ />
89
+ <SocialButtons>
90
+ <SocialButton onClick={handleDiscordClick}>
91
+ <FaDiscord />
92
+ </SocialButton>
93
+ <SocialButton onClick={handleWhatsAppClick}>
94
+ <FaWhatsapp />
95
+ </SocialButton>
96
+ </SocialButtons>
97
+ </>
60
98
  )}
61
99
  <ExpandButton
62
100
  isExpanded={chatHook.isExpanded}
@@ -74,7 +112,7 @@ export const ChatRevamp = ({
74
112
  <RecentChats
75
113
  showRecentChats={chatHook.showRecentChats}
76
114
  toggleRecentChats={chatHook.toggleRecentChats}
77
- hasUnseenMessages={chatHook.hasUnseenMessages || false}
115
+ hasUnseenMessages={!!chatHook.hasUnseenMessages}
78
116
  showSearchCharacterUI={showSearchCharacterUI}
79
117
  recentChatCharacters={recentChatCharacters}
80
118
  recentSelectedChatCharacterId={recentSelectedChatCharacterId}
@@ -139,18 +177,15 @@ const ChatRevampContainer = styled.div`
139
177
  position: relative;
140
178
  `;
141
179
 
142
- const TopBar = styled.div<{ isExpanded: boolean }>`
180
+ const TopBar = styled.div<ITopBarProps>`
143
181
  display: flex;
144
182
  align-items: center;
145
- justify-content: flex-start;
183
+ justify-content: space-between;
146
184
  min-height: ${({ isExpanded }) => (isExpanded ? 'auto' : '32px')};
185
+ padding: 0 8px;
147
186
  `;
148
187
 
149
- const AllChatsContainer = styled.div<{
150
- width: string;
151
- height: string;
152
- isExpanded: boolean;
153
- }>`
188
+ const AllChatsContainer = styled.div<IAllChatsContainerProps>`
154
189
  width: ${({ width }) => width};
155
190
  height: ${({ height, isExpanded }) => (isExpanded ? height : 'auto')};
156
191
  padding: 10px;
@@ -160,13 +195,13 @@ const AllChatsContainer = styled.div<{
160
195
  flex-wrap: wrap;
161
196
  `;
162
197
 
163
- const ChatContentWrapper = styled.div<{ isPrivate: boolean }>`
198
+ const ChatContentWrapper = styled.div<IChatContentWrapperProps>`
164
199
  flex-grow: 1;
165
200
  overflow: hidden;
166
201
  display: flex;
167
202
  flex-direction: column;
168
203
  position: relative;
169
- width: ${props => (props.isPrivate ? '75%' : '100%')};
204
+ width: ${({ isPrivate }) => (isPrivate ? '75%' : '100%')};
170
205
  `;
171
206
 
172
207
  const CollapsedChatInput = styled.div`
@@ -181,3 +216,23 @@ const ExpandedChatContent = styled.div`
181
216
  width: 100%;
182
217
  height: 100%;
183
218
  `;
219
+
220
+ const SocialButtons = styled.div`
221
+ display: flex;
222
+ gap: 8px;
223
+ margin-right: 32px;
224
+ `;
225
+
226
+ const SocialButton = styled.button`
227
+ background-color: transparent;
228
+ border: none;
229
+ color: white;
230
+ font-size: 16px;
231
+ cursor: pointer;
232
+ transition: color 0.3s ease;
233
+ padding: 4px;
234
+
235
+ &:hover {
236
+ color: ${uiColors.yellow};
237
+ }
238
+ `;
@@ -18,15 +18,16 @@ export type ChatMessage =
18
18
  export interface IChatRevampProps {
19
19
  chatMessages: ChatMessage[];
20
20
  onSendGlobalChatMessage: (message: string) => void;
21
- onCloseButton: () => void;
21
+ onSendGuildChatMessage: (message: string) => void;
22
+ onChangeCharacterName: (characterName: string) => void;
22
23
  onFocus?: () => void;
23
24
  onBlur?: () => void;
25
+ onCloseButton: () => void;
24
26
  styles?: IStyles;
25
- tabs: { label: string; id: string }[];
26
- activeTab: string;
27
- onChangeTab: (tabId: string) => void;
27
+ tabs: any[];
28
+ onChangeTab: (tab: string) => void;
29
+ activeTab?: string;
28
30
  privateChatCharacters?: PrivateChatCharacter[];
29
- onChangeCharacterName: (characterName: string) => void;
30
31
  onCharacterClick?: (character: PrivateChatCharacter) => void;
31
32
  onSendPrivateChatMessage: (message: string) => void;
32
33
  recentChatCharacters?: PrivateChatCharacter[];
@@ -35,12 +36,12 @@ export interface IChatRevampProps {
35
36
  onRemoveRecentChatCharacter?: (character: PrivateChatCharacter) => void;
36
37
  unseenMessageCharacterIds?: string[];
37
38
  onSendTradeMessage: (message: string) => void;
38
- searchCharacterUI: boolean;
39
- hideSearchCharacterUI: () => void;
40
- showSearchCharacterUI: () => void;
39
+ searchCharacterUI?: boolean;
40
+ hideSearchCharacterUI?: () => void;
41
+ showSearchCharacterUI?: () => void;
41
42
  minimizedByDefault?: boolean;
42
43
  autoCloseOnSend?: boolean;
43
- onSendGuildChatMessage: (message: string) => void;
44
- isInGuild: boolean;
45
44
  onSendLocalChatMessage: (message: string) => void;
45
+ onDiscordClick?: () => void;
46
+ onWhatsAppClick?: () => void;
46
47
  }
@@ -176,20 +176,13 @@ export const ItemSlot: React.FC<IProps> = observer(
176
176
  position: { x: 0, y: 0 },
177
177
  isFocused: false,
178
178
  });
179
- }, [
180
- containerType,
181
- isDepotSystem,
182
- setContextActions,
183
- clearContextActions,
184
- isContextMenuDisabled, // Added missing dependency
185
- ]);
186
179
 
187
- useEffect(() => {
188
- // Reset drag position and focus when item changes
189
180
  clearDraggingState();
190
181
 
191
182
  // Clear context actions when component unmounts or dependencies change
192
183
  return () => {
184
+ clearDraggingState();
185
+ clearDetailsState();
193
186
  clearContextActions();
194
187
  };
195
188
  }, [
@@ -198,7 +191,9 @@ export const ItemSlot: React.FC<IProps> = observer(
198
191
  setContextActions,
199
192
  clearContextActions,
200
193
  isContextMenuDisabled,
201
- updateDraggingState, // Add this dependency
194
+ clearDraggingState,
195
+ clearDetailsState,
196
+ updateDraggingState,
202
197
  ]);
203
198
 
204
199
  const resetItem = () => {
@@ -0,0 +1,192 @@
1
+ import React, { useState } from 'react';
2
+ import { FaDiscord, FaReddit, FaWhatsapp } from 'react-icons/fa';
3
+ import styled from 'styled-components';
4
+ import { DraggableContainer } from '../DraggableContainer';
5
+ import { Dropdown, IOptionsProps } from '../Dropdown';
6
+ import { Divider } from '../shared/Divider/Divider';
7
+ import socialModalGroup from './images/social-modal-group.png';
8
+
9
+ interface ISocialModalProps {
10
+ onClose: () => void;
11
+ }
12
+
13
+ type WhatsAppLanguage = 'english' | 'pt-BR' | 'polski' | 'español';
14
+
15
+ const whatsAppGroups: IOptionsProps[] = [
16
+ { id: 1, value: 'english', option: 'Global (English)' },
17
+ { id: 2, value: 'pt-BR', option: 'Brasil (Português)' },
18
+ { id: 3, value: 'español', option: 'Español' },
19
+ { id: 4, value: 'polski', option: 'Polski' },
20
+ ];
21
+
22
+ const socialLinks = {
23
+ discord: 'https://discord.gg/xWBYBWanvE',
24
+ reddit: 'https://www.reddit.com/r/DefinyaMMO/',
25
+ whatsapp: {
26
+ english: 'https://chat.whatsapp.com/H8U1Jt7hJNdIWO19atAnRu',
27
+ 'pt-BR': 'https://chat.whatsapp.com/DwXJz2RXDsG2X6ANOm4FtQ',
28
+ español: 'https://chat.whatsapp.com/BPlJ1RxshEiErNceZkdhyf',
29
+ polski: 'https://chat.whatsapp.com/DromXMChOmZK5JHXXdrEWr',
30
+ } as Record<WhatsAppLanguage, string>,
31
+ };
32
+
33
+ export const SocialModal: React.FC<ISocialModalProps> = ({ onClose }) => {
34
+ const [selectedLanguage, setSelectedLanguage] = useState<WhatsAppLanguage>(
35
+ 'english'
36
+ );
37
+
38
+ const handleLanguageChange = (value: string) => {
39
+ setSelectedLanguage(value as WhatsAppLanguage);
40
+ };
41
+
42
+ const handleWhatsAppClick = () => {
43
+ window.open(
44
+ socialLinks.whatsapp[selectedLanguage],
45
+ '_blank',
46
+ 'noopener,noreferrer'
47
+ );
48
+ };
49
+
50
+ const handleDiscordClick = () => {
51
+ window.open(socialLinks.discord, '_blank', 'noopener,noreferrer');
52
+ };
53
+
54
+ const handleRedditClick = () => {
55
+ window.open(socialLinks.reddit, '_blank', 'noopener,noreferrer');
56
+ };
57
+
58
+ return (
59
+ <DraggableContainer
60
+ title="Social Channels"
61
+ width="500px"
62
+ onCloseButton={onClose}
63
+ >
64
+ <Container>
65
+ <HeaderImage src={socialModalGroup} alt="" />
66
+ <ButtonsContainer>
67
+ <MainButtons>
68
+ <SocialButton onClick={handleDiscordClick}>
69
+ <FaDiscord /> Discord
70
+ </SocialButton>
71
+ <SocialButton onClick={handleRedditClick}>
72
+ <FaReddit /> Reddit
73
+ </SocialButton>
74
+ </MainButtons>
75
+
76
+ <Divider margin="8px 0" />
77
+
78
+ <DropdownContainer>
79
+ <Dropdown
80
+ options={whatsAppGroups}
81
+ onChange={handleLanguageChange}
82
+ width="100%"
83
+ opensUp={true}
84
+ />
85
+
86
+ <WhatsAppButton onClick={handleWhatsAppClick}>
87
+ <FaWhatsapp /> Join WhatsApp
88
+ </WhatsAppButton>
89
+ </DropdownContainer>
90
+ </ButtonsContainer>
91
+ </Container>
92
+ </DraggableContainer>
93
+ );
94
+ };
95
+
96
+ const Container = styled.div`
97
+ width: 100%;
98
+ display: flex;
99
+ flex-direction: column;
100
+ gap: 16px;
101
+ background-color: #5c4132;
102
+ position: relative;
103
+ border-radius: 8px;
104
+ overflow: hidden;
105
+
106
+ &:before,
107
+ &:after {
108
+ content: '';
109
+ position: absolute;
110
+ left: 0;
111
+ right: 0;
112
+ height: 3px;
113
+ }
114
+
115
+ &:before {
116
+ bottom: 0;
117
+ background: linear-gradient(
118
+ to right,
119
+ #5c4132 0%,
120
+ #2b1810 2%,
121
+ #2b1810 98%,
122
+ #5c4132 100%
123
+ );
124
+ }
125
+ `;
126
+
127
+ const HeaderImage = styled.img`
128
+ width: 100%;
129
+ height: 160px;
130
+ object-fit: cover;
131
+ border-bottom: 2px solid rgba(0, 0, 0, 0.3);
132
+ display: block;
133
+ border-top-left-radius: 8px;
134
+ border-top-right-radius: 8px;
135
+ `;
136
+
137
+ const ButtonsContainer = styled.div`
138
+ padding: 16px 24px 24px;
139
+ display: flex;
140
+ flex-direction: column;
141
+ gap: 16px;
142
+ `;
143
+
144
+ const MainButtons = styled.div`
145
+ display: grid;
146
+ grid-template-columns: 1fr 1fr;
147
+ gap: 16px;
148
+ `;
149
+
150
+ const SocialButton = styled.button`
151
+ display: flex;
152
+ align-items: center;
153
+ justify-content: center;
154
+ gap: 8px;
155
+ background-color: rgba(255, 255, 255, 0.08);
156
+ border: 1px solid rgba(255, 255, 255, 0.15);
157
+ color: white;
158
+ padding: 12px;
159
+ border-radius: 4px;
160
+ cursor: pointer;
161
+ font-family: 'Press Start 2P', cursive;
162
+ font-size: 0.7rem;
163
+ transition: all 0.2s ease;
164
+
165
+ &:hover {
166
+ background-color: rgba(255, 255, 255, 0.12);
167
+ }
168
+
169
+ svg {
170
+ font-size: 1.1rem;
171
+ }
172
+ `;
173
+
174
+ const WhatsAppButton = styled(SocialButton)`
175
+ width: 100%;
176
+ background-color: #0f1f0f;
177
+ border: 1px solid #1a2f1a;
178
+ padding: 14px;
179
+
180
+ &:hover {
181
+ background-color: #162716;
182
+ }
183
+
184
+ margin-top: 8px;
185
+ `;
186
+
187
+ const DropdownContainer = styled.div`
188
+ background-color: rgba(0, 0, 0, 0.2);
189
+ padding: 8px;
190
+ border-radius: 4px;
191
+ border: 1px solid rgba(0, 0, 0, 0.3);
192
+ `;
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ interface IDividerProps {
5
+ className?: string;
6
+ margin?: string;
7
+ }
8
+
9
+ export const Divider: React.FC<IDividerProps> = ({
10
+ className,
11
+ margin = '4px 0',
12
+ }) => {
13
+ return <DividerLine className={className} margin={margin} />;
14
+ };
15
+
16
+ const DividerLine = styled.div<{ margin: string }>`
17
+ width: 100%;
18
+ height: 2px;
19
+ background: linear-gradient(
20
+ to right,
21
+ transparent,
22
+ rgba(255, 255, 255, 0.1) 20%,
23
+ rgba(255, 255, 255, 0.1) 80%,
24
+ transparent
25
+ );
26
+ margin: ${({ margin }) => margin};
27
+ `;
@@ -0,0 +1,30 @@
1
+ import { ComponentMeta, ComponentStory } from '@storybook/react';
2
+ import React from 'react';
3
+ import { RPGUIRoot } from '../../..';
4
+ import { Divider } from '../../../components/shared/Divider/Divider';
5
+
6
+ export default {
7
+ title: 'UI/Divider',
8
+ component: Divider,
9
+ parameters: {
10
+ layout: 'centered',
11
+ },
12
+ } as ComponentMeta<typeof Divider>;
13
+
14
+ const Template: ComponentStory<typeof Divider> = args => (
15
+ <RPGUIRoot>
16
+ <div style={{ width: '300px', padding: '20px', background: '#333' }}>
17
+ <div>Content Above</div>
18
+ <Divider {...args} />
19
+ <div>Content Below</div>
20
+ </div>
21
+ </RPGUIRoot>
22
+ );
23
+
24
+ export const Default: ComponentStory<typeof Divider> = Template.bind({});
25
+ Default.args = {};
26
+
27
+ export const CustomMargin: ComponentStory<typeof Divider> = Template.bind({});
28
+ CustomMargin.args = {
29
+ margin: '16px 0',
30
+ };
@@ -0,0 +1,23 @@
1
+ import { ComponentMeta, ComponentStory } from '@storybook/react';
2
+ import React from 'react';
3
+ import { RPGUIRoot } from '../../..';
4
+ import { SocialModal } from '../../../components/SocialModal/SocialModal';
5
+
6
+ export default {
7
+ title: 'UI/Social/SocialModal',
8
+ component: SocialModal,
9
+ parameters: {
10
+ layout: 'centered',
11
+ },
12
+ } as ComponentMeta<typeof SocialModal>;
13
+
14
+ const Template: ComponentStory<typeof SocialModal> = args => (
15
+ <RPGUIRoot>
16
+ <SocialModal {...args} />
17
+ </RPGUIRoot>
18
+ );
19
+
20
+ export const Default: ComponentStory<typeof SocialModal> = Template.bind({});
21
+ Default.args = {
22
+ onClose: () => console.log('Modal closed'),
23
+ };