@rpg-engine/long-bow 0.6.68 → 0.6.70

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.6.68",
3
+ "version": "0.6.70",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import styled from 'styled-components';
3
3
  import { uiColors } from '../../constants/uiColors';
4
4
  import { Button, ButtonTypes } from '../Button';
@@ -10,6 +10,7 @@ import {
10
10
  TableCell,
11
11
  TableHeader,
12
12
  TableRow,
13
+ UserActionLink,
13
14
  } from '../Table/Table';
14
15
  import { SearchFriend } from './SearchFriend';
15
16
  export type IFriend = Pick<ICharacter, 'name' | '_id' | 'isOnline'>;
@@ -27,6 +28,8 @@ interface IFriendListProps {
27
28
  onSearch: (characterName: string) => void;
28
29
  onAcceptRequest: (character: IFriend) => void;
29
30
  onRejectRequest: (character: IFriend) => void;
31
+ onAddFriend?: () => void;
32
+ onBackFriendList?: () => void;
30
33
  }
31
34
 
32
35
  export const FriendList: React.FC<IFriendListProps> = ({
@@ -41,9 +44,19 @@ export const FriendList: React.FC<IFriendListProps> = ({
41
44
  onRemoveFriend,
42
45
  onOpenPrivateMessage,
43
46
  onRejectRequest,
47
+ onAddFriend,
48
+ onBackFriendList,
44
49
  }) => {
45
50
  const [isAddFriendUI, setIsAddFriendUI] = useState(false);
46
51
 
52
+ useEffect(() => {
53
+ if (isAddFriendUI) {
54
+ onAddFriend?.();
55
+ } else {
56
+ onBackFriendList?.();
57
+ }
58
+ }, [isAddFriendUI]);
59
+
47
60
  return (
48
61
  <ListWrapper>
49
62
  {isAddFriendUI ? (
@@ -77,18 +90,18 @@ export const FriendList: React.FC<IFriendListProps> = ({
77
90
  <TableCell>{friend.name}</TableCell>
78
91
  <TableCell>
79
92
  <ActionButtons>
80
- <UserAction
81
- color={uiColors.yellow}
93
+ <UserActionLink
94
+ color={uiColors.white}
82
95
  onClick={() => onOpenPrivateMessage(friend)}
83
96
  >
84
97
  Chat
85
- </UserAction>
86
- <UserAction
98
+ </UserActionLink>
99
+ <UserActionLink
87
100
  color={uiColors.red}
88
101
  onClick={() => onRemoveFriend(friend)}
89
102
  >
90
103
  Remove
91
- </UserAction>
104
+ </UserActionLink>
92
105
  </ActionButtons>
93
106
  </TableCell>
94
107
  </TableRow>
@@ -140,17 +153,3 @@ const ButtonContainer = styled.div`
140
153
  width: 100%;
141
154
  margin-top: 1rem;
142
155
  `;
143
-
144
- interface IUserActionProps {
145
- color: string;
146
- }
147
-
148
- const UserAction = styled.span<IUserActionProps>`
149
- color: ${({ color }) => color} !important;
150
- cursor: pointer;
151
- margin-right: 0.5rem;
152
-
153
- &:hover {
154
- text-decoration: underline;
155
- }
156
- `;
@@ -1,11 +1,12 @@
1
- import React, { useState } from 'react';
1
+ import { debounce } from 'lodash';
2
+ import React, { useCallback, useState } from 'react';
2
3
  import styled from 'styled-components';
4
+ import { TableTab, UserActionLink } from '../..';
5
+ import { uiColors } from '../../constants/uiColors';
3
6
  import { uiFonts } from '../../constants/uiFonts';
4
- import { Button, ButtonTypes } from '../Button';
5
- import { Column } from '../shared/Column';
6
- import type { IFriend } from './FriendList';
7
+ import { IFriend } from './FriendList';
7
8
 
8
- interface ISearchFriendProp {
9
+ interface ISearchFriendProps {
9
10
  searchedCharacters: IFriend[];
10
11
  friendRequests: IFriend[];
11
12
  onFocus?: () => void;
@@ -16,142 +17,194 @@ interface ISearchFriendProp {
16
17
  onRejectRequest: (character: IFriend) => void;
17
18
  }
18
19
 
19
- export const SearchFriend = (props: ISearchFriendProp) => {
20
- const {
21
- searchedCharacters,
22
- friendRequests,
23
- onBlur,
24
- onFocus,
25
- onSearch,
26
- onSendFriendRequest,
27
- onAcceptRequest,
28
- onRejectRequest,
29
- } = props;
20
+ export const SearchFriend: React.FC<ISearchFriendProps> = ({
21
+ searchedCharacters,
22
+ friendRequests,
23
+ onBlur,
24
+ onFocus,
25
+ onSearch,
26
+ onSendFriendRequest,
27
+ onAcceptRequest,
28
+ onRejectRequest,
29
+ }) => {
30
30
  const [characterName, setCharacterName] = useState('');
31
31
 
32
+ const debouncedSearch = useCallback(
33
+ debounce((name: string) => {
34
+ onSearch(name);
35
+ }, 300),
36
+ []
37
+ );
38
+
39
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
40
+ const name = e.target.value;
41
+ setCharacterName(name);
42
+ debouncedSearch(name);
43
+ };
44
+
32
45
  const handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
33
46
  event.preventDefault();
34
- if (!characterName || characterName.trim() === '') return;
35
- onSearch(characterName);
47
+ if (characterName.trim()) {
48
+ onSearch(characterName);
49
+ }
36
50
  };
37
51
 
52
+ const searchTabContent = (
53
+ <ListContainer>
54
+ <SearchForm onSubmit={handleSubmit}>
55
+ <SearchInput
56
+ value={characterName}
57
+ id="characterName"
58
+ name="characterName"
59
+ onChange={handleInputChange}
60
+ type="text"
61
+ autoComplete="off"
62
+ onFocus={onFocus}
63
+ onBlur={onBlur}
64
+ onPointerDown={onFocus}
65
+ autoFocus
66
+ placeholder="Search for a character..."
67
+ />
68
+ </SearchForm>
69
+ <CharacterList
70
+ characters={searchedCharacters}
71
+ onAction={onSendFriendRequest}
72
+ actionLabel="Add Friend"
73
+ />
74
+ </ListContainer>
75
+ );
76
+
77
+ const requestsTabContent = (
78
+ <ListContainer>
79
+ <FriendRequestSection
80
+ friendRequests={friendRequests}
81
+ onAccept={onAcceptRequest}
82
+ onReject={onRejectRequest}
83
+ />
84
+ </ListContainer>
85
+ );
86
+
87
+ const tabs = [
88
+ { id: 'search', title: 'Search', content: searchTabContent },
89
+ {
90
+ id: 'requests',
91
+ title: `Requests (${friendRequests.length})`,
92
+ content: requestsTabContent,
93
+ },
94
+ ];
95
+
38
96
  return (
39
- <>
40
- <Form onSubmit={handleSubmit}>
41
- <Column flex={70}>
42
- <TextField
43
- value={characterName}
44
- id="characterName"
45
- name="characterName"
46
- onChange={e => {
47
- setCharacterName(e.target.value);
48
- }}
49
- height={20}
50
- type="text"
51
- autoComplete="off"
52
- onFocus={onFocus}
53
- onBlur={onBlur}
54
- onPointerDown={onFocus}
55
- autoFocus
56
- />
57
- </Column>
58
- <Column justifyContent="flex-end">
59
- <Button type="submit" buttonType={ButtonTypes.RPGUIButton}>
60
- Search
61
- </Button>
62
- </Column>
63
- </Form>
97
+ <Container>
98
+ <TableTab
99
+ tabs={tabs}
100
+ activeTextColor="#000"
101
+ inactiveColor="#777"
102
+ borderColor="#f59e0b"
103
+ />
104
+ </Container>
105
+ );
106
+ };
107
+
108
+ const CharacterList: React.FC<{
109
+ characters: IFriend[];
110
+ onAction: (character: IFriend) => void;
111
+ actionLabel: string;
112
+ }> = ({ characters, onAction, actionLabel }) => (
113
+ <ListContainer>
114
+ {characters.map(character => (
115
+ <ListItem key={character._id}>
116
+ <CharacterName>{character.name}</CharacterName>
117
+ <UserActionLink
118
+ color={uiColors.lightGreen}
119
+ onClick={() => onAction(character)}
120
+ >
121
+ {actionLabel}
122
+ </UserActionLink>
123
+ </ListItem>
124
+ ))}
125
+ </ListContainer>
126
+ );
127
+
128
+ const FriendRequestSection: React.FC<{
129
+ friendRequests: IFriend[];
130
+ onAccept: (character: IFriend) => void;
131
+ onReject: (character: IFriend) => void;
132
+ }> = ({ friendRequests, onAccept, onReject }) => (
133
+ <>
134
+ {friendRequests.length > 0 && (
64
135
  <ListContainer>
65
- {searchedCharacters.map(character => (
66
- <ListElement key={character._id}>
67
- <p>{character.name}</p>
68
-
69
- <Button
70
- buttonType={ButtonTypes.RPGUIButton}
71
- onPointerDown={() => onSendFriendRequest(character)}
72
- >
73
- Add Friend
74
- </Button>
75
- </ListElement>
136
+ {friendRequests.map(character => (
137
+ <ListItem key={character._id}>
138
+ <CharacterName>{character.name}</CharacterName>
139
+ <AcceptRejectActions>
140
+ <UserActionLink
141
+ color={uiColors.lightGreen}
142
+ onClick={() => onAccept(character)}
143
+ >
144
+ Accept
145
+ </UserActionLink>
146
+ <UserActionLink
147
+ color={uiColors.red}
148
+ onClick={() => onReject(character)}
149
+ >
150
+ Reject
151
+ </UserActionLink>
152
+ </AcceptRejectActions>
153
+ </ListItem>
76
154
  ))}
77
155
  </ListContainer>
78
- <FriendRequestTitle>
79
- Friend Requests <span>({friendRequests.length})</span>
80
- </FriendRequestTitle>
81
- {friendRequests.length > 0 && (
82
- <ListContainer>
83
- {friendRequests.map(character => (
84
- <ListElement key={character._id}>
85
- <p>{character.name}</p>
86
-
87
- <AcceptRejectButtonContainer>
88
- <Button
89
- buttonType={ButtonTypes.RPGUIButton}
90
- onPointerDown={() => onAcceptRequest(character)}
91
- >
92
- Accept
93
- </Button>
94
- <Button
95
- buttonType={ButtonTypes.RPGUIButton}
96
- onPointerDown={() => onRejectRequest(character)}
97
- >
98
- Reject
99
- </Button>
100
- </AcceptRejectButtonContainer>
101
- </ListElement>
102
- ))}
103
- </ListContainer>
104
- )}
105
- </>
106
- );
107
- };
156
+ )}
157
+ </>
158
+ );
108
159
 
109
- const Form = styled.form`
160
+ const Container = styled.div`
161
+ display: flex;
162
+ flex-direction: column;
163
+ gap: 1rem;
164
+ `;
165
+
166
+ const SearchForm = styled.form`
110
167
  display: flex;
111
- width: 100%;
112
- justify-content: center;
113
168
  align-items: center;
169
+ width: 100%;
114
170
  margin-top: 1rem;
115
171
  `;
116
172
 
117
- const TextField = styled.input`
173
+ const SearchInput = styled.input`
118
174
  width: 100%;
119
- background-color: rgba(0, 0, 0, 0.25) !important;
120
- border: none !important;
121
- max-height: 28px !important;
175
+ background-color: rgba(0, 0, 0, 0.25);
176
+ border: none;
177
+ padding: 0.5rem;
178
+ font-size: ${uiFonts.size.small};
122
179
  `;
123
180
 
124
181
  const ListContainer = styled.ul`
125
- width: 100%;
126
- c4height: 50vh;
127
- border: none;
128
- overflow-y: scroll;
129
182
  list-style: none;
130
183
  padding: 0;
184
+ margin: 0;
185
+ width: 100%;
186
+ max-height: 50vh;
187
+ overflow-y: auto;
131
188
 
132
189
  @media (max-width: 768px) {
133
- max-height: 90wh;
190
+ max-height: 90vh;
134
191
  }
135
192
  `;
136
193
 
137
- const ListElement = styled.li`
138
- margin: 0.5rem 0 !important;
139
- font-size: ${uiFonts.size.small};
140
- padding: 0.5rem 2px;
194
+ const ListItem = styled.li`
141
195
  display: flex;
142
196
  align-items: center;
143
197
  justify-content: space-between;
198
+ padding: 0.5rem;
199
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
144
200
  `;
145
201
 
146
- const FriendRequestTitle = styled.h3`
147
- font-size: ${uiFonts.size.small} !important;
148
- margin-top: 0.5rem !important;
149
- text-align: center;
150
- gap: 0.5rem;
202
+ const CharacterName = styled.p`
203
+ font-size: ${uiFonts.size.small};
204
+ margin: 0;
151
205
  `;
152
206
 
153
- const AcceptRejectButtonContainer = styled.div`
207
+ const AcceptRejectActions = styled.div`
154
208
  display: flex;
155
- justify-content: space-between;
156
209
  gap: 0.5rem;
157
210
  `;
@@ -24,6 +24,7 @@ export const TableCell = styled.td`
24
24
  padding: 0.5rem;
25
25
  color: ${uiColors.white};
26
26
  border-bottom: 1px solid ${uiColors.lightGray};
27
+ text-align: ${({ align }) => (align ? align : 'left')}; /* Add this line */
27
28
  `;
28
29
 
29
30
  export const ActionButtons = styled.div`
@@ -31,3 +32,17 @@ export const ActionButtons = styled.div`
31
32
  gap: 10px;
32
33
  align-items: center;
33
34
  `;
35
+
36
+ interface IUserActionProps {
37
+ color: string;
38
+ }
39
+
40
+ export const UserActionLink = styled.span<IUserActionProps>`
41
+ color: ${({ color }) => color} !important;
42
+ cursor: pointer;
43
+ margin-right: 0.5rem;
44
+
45
+ &:hover {
46
+ text-decoration: underline;
47
+ }
48
+ `;
@@ -38,6 +38,8 @@ const Template = () => {
38
38
  onRejectRequest={(character) => console.log(character)}
39
39
  onBlur={() => console.log('blur')}
40
40
  onFocus={() => console.log('focus')}
41
+ onAddFriend={() => console.log('add friend')}
42
+ onBackFriendList={() => console.log('back friend list')}
41
43
  />
42
44
  </RPGUIRoot>;
43
45
  }