@rpg-engine/long-bow 0.8.74 → 0.8.75
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/long-bow.cjs.development.js +36 -26
- 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 +36 -26
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/DailyTasks/DailyTaskItem.tsx +32 -35
- package/src/components/DailyTasks/DailyTasks.tsx +24 -20
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
TaskType,
|
|
6
6
|
} from '@rpg-engine/shared';
|
|
7
7
|
import React from 'react';
|
|
8
|
-
import styled, {
|
|
8
|
+
import styled, { css, keyframes } from 'styled-components';
|
|
9
9
|
import { uiColors } from '../../constants/uiColors';
|
|
10
10
|
import { Button, ButtonTypes } from '../Button';
|
|
11
11
|
import { Ellipsis } from '../shared/Ellipsis';
|
|
@@ -36,6 +36,7 @@ export const DailyTaskItem: React.FC<IDailyTaskItemProps> = ({
|
|
|
36
36
|
iconAtlasJSON,
|
|
37
37
|
iconAtlasIMG,
|
|
38
38
|
isRewardClaimed,
|
|
39
|
+
isPinned,
|
|
39
40
|
}) => {
|
|
40
41
|
const isMobile = isMobileOrTablet();
|
|
41
42
|
|
|
@@ -43,19 +44,22 @@ export const DailyTaskItem: React.FC<IDailyTaskItemProps> = ({
|
|
|
43
44
|
const isInProgress = task.status === TaskStatus.InProgress;
|
|
44
45
|
const isNotStarted = task.status === TaskStatus.NotStarted;
|
|
45
46
|
const isClaimed = task.claimed || isRewardClaimed;
|
|
47
|
+
const isChallenge = task.difficulty?.toLowerCase() === 'challenge';
|
|
46
48
|
|
|
47
49
|
const handleClaimReward = () => {
|
|
48
50
|
onClaimReward(task.key, task.type);
|
|
49
51
|
};
|
|
50
52
|
|
|
51
53
|
return (
|
|
52
|
-
<TaskContainer
|
|
54
|
+
<TaskContainer
|
|
53
55
|
isMobile={isMobile}
|
|
54
56
|
isCompleted={isCompleted}
|
|
55
57
|
isInProgress={isInProgress}
|
|
56
58
|
isNotStarted={isNotStarted}
|
|
59
|
+
isPinned={isPinned}
|
|
60
|
+
isChallenge={isChallenge}
|
|
57
61
|
>
|
|
58
|
-
<TaskHeader>
|
|
62
|
+
<TaskHeader isMobile={isMobile}>
|
|
59
63
|
<TaskHeaderLeft>
|
|
60
64
|
{iconAtlasJSON && iconAtlasIMG && (
|
|
61
65
|
<IconWrapper>
|
|
@@ -99,7 +103,7 @@ export const DailyTaskItem: React.FC<IDailyTaskItemProps> = ({
|
|
|
99
103
|
</TaskHeaderRight>
|
|
100
104
|
</TaskHeader>
|
|
101
105
|
|
|
102
|
-
<TaskBody>
|
|
106
|
+
<TaskBody isMobile={isMobile}>
|
|
103
107
|
<TaskDescription isMobile={isMobile}>
|
|
104
108
|
<Ellipsis maxWidth="100%" maxLines={isMobile ? 2 : 1}>
|
|
105
109
|
{task.description}
|
|
@@ -122,7 +126,7 @@ export const DailyTaskItem: React.FC<IDailyTaskItemProps> = ({
|
|
|
122
126
|
</TaskBody>
|
|
123
127
|
|
|
124
128
|
{isCompleted && !isClaimed && (
|
|
125
|
-
<TaskFooter>
|
|
129
|
+
<TaskFooter isMobile={isMobile}>
|
|
126
130
|
<Button
|
|
127
131
|
buttonType={ButtonTypes.RPGUIButton}
|
|
128
132
|
onPointerDown={handleClaimReward}
|
|
@@ -147,24 +151,25 @@ const pulseAnimation = keyframes`
|
|
|
147
151
|
}
|
|
148
152
|
`;
|
|
149
153
|
|
|
150
|
-
const TaskContainer = styled.div<{
|
|
154
|
+
const TaskContainer = styled.div<{
|
|
151
155
|
isMobile: boolean;
|
|
152
156
|
isCompleted: boolean;
|
|
153
157
|
isInProgress: boolean;
|
|
154
158
|
isNotStarted: boolean;
|
|
155
159
|
isPinned?: boolean;
|
|
160
|
+
isChallenge?: boolean;
|
|
156
161
|
}>`
|
|
157
|
-
background:
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
uiColors.darkGray
|
|
162
|
+
background: ${props =>
|
|
163
|
+
props.isChallenge ? 'rgb(209, 39, 42)' :
|
|
164
|
+
props.isPinned ? 'rgba(255, 215, 0, 0.1)' :
|
|
165
|
+
'rgba(0, 0, 0, 0.6)'
|
|
162
166
|
} !important;
|
|
167
|
+
border: 1px solid ${uiColors.darkGray} !important;
|
|
163
168
|
border-radius: ${props => props.isMobile ? '4px' : '6px'};
|
|
164
|
-
padding: ${props => props.isMobile ? '
|
|
169
|
+
padding: ${props => props.isMobile ? '10px' : '14px'};
|
|
165
170
|
display: flex;
|
|
166
171
|
flex-direction: column;
|
|
167
|
-
gap: ${props => props.isMobile ? '
|
|
172
|
+
gap: ${props => props.isMobile ? '8px' : '12px'};
|
|
168
173
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
169
174
|
transition: all 0.2s ease;
|
|
170
175
|
font-style: normal;
|
|
@@ -173,11 +178,7 @@ const TaskContainer = styled.div<{
|
|
|
173
178
|
box-sizing: border-box;
|
|
174
179
|
|
|
175
180
|
/* Task status visual states */
|
|
176
|
-
opacity:
|
|
177
|
-
props.isCompleted ? 1 :
|
|
178
|
-
props.isInProgress ? 1 :
|
|
179
|
-
0.6
|
|
180
|
-
};
|
|
181
|
+
opacity: 1;
|
|
181
182
|
|
|
182
183
|
${props => props.isNotStarted && `
|
|
183
184
|
filter: grayscale(0.7);
|
|
@@ -192,26 +193,21 @@ const TaskContainer = styled.div<{
|
|
|
192
193
|
}
|
|
193
194
|
|
|
194
195
|
&:hover {
|
|
195
|
-
background: ${props =>
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
border-color: ${
|
|
199
|
-
|
|
200
|
-
props.isCompleted ? uiColors.green :
|
|
201
|
-
props.isInProgress ? uiColors.yellow :
|
|
202
|
-
uiColors.yellow
|
|
203
|
-
};
|
|
204
|
-
opacity: ${props => props.isNotStarted ? 0.8 : 1};
|
|
196
|
+
background: ${props =>
|
|
197
|
+
props.isPinned ? 'rgba(255, 215, 0, 0.25)' : 'rgba(0, 0, 0, 0.7)'
|
|
198
|
+
} !important;
|
|
199
|
+
border-color: ${uiColors.yellow};
|
|
200
|
+
opacity: 1;
|
|
205
201
|
}
|
|
206
202
|
`;
|
|
207
203
|
|
|
208
|
-
const TaskHeader = styled.div
|
|
204
|
+
const TaskHeader = styled.div<{ isMobile?: boolean }>`
|
|
209
205
|
display: flex;
|
|
210
206
|
width: 100%;
|
|
211
207
|
justify-content: space-between;
|
|
212
208
|
align-items: flex-start;
|
|
213
209
|
border-bottom: 1px solid ${uiColors.darkGray};
|
|
214
|
-
padding-bottom:
|
|
210
|
+
padding-bottom: ${props => props.isMobile ? '8px' : '10px'};
|
|
215
211
|
min-height: 36px;
|
|
216
212
|
`;
|
|
217
213
|
|
|
@@ -270,7 +266,7 @@ const TaskDifficulty = styled.span<{ difficulty: string }>`
|
|
|
270
266
|
`;
|
|
271
267
|
|
|
272
268
|
const StatusText = styled.span<{ color: string }>`
|
|
273
|
-
color: ${props => props.color};
|
|
269
|
+
color: ${props => props.color} !important;
|
|
274
270
|
font-size: 0.65rem;
|
|
275
271
|
font-weight: 500;
|
|
276
272
|
`;
|
|
@@ -286,23 +282,24 @@ const ClaimedBadge = styled.div<{ isMobile: boolean }>`
|
|
|
286
282
|
justify-content: center;
|
|
287
283
|
font-size: ${props => props.isMobile ? '10px' : '12px'};
|
|
288
284
|
font-weight: bold;
|
|
285
|
+
margin-left: 8px;
|
|
289
286
|
`;
|
|
290
287
|
|
|
291
|
-
const TaskBody = styled.div
|
|
288
|
+
const TaskBody = styled.div<{ isMobile?: boolean }>`
|
|
292
289
|
display: flex;
|
|
293
290
|
flex-direction: column;
|
|
294
291
|
gap: 8px;
|
|
295
|
-
padding: 6px 0;
|
|
292
|
+
padding: ${props => props.isMobile ? '4px 0' : '6px 0'};
|
|
296
293
|
`;
|
|
297
294
|
|
|
298
295
|
const RewardsSection = styled.div`
|
|
299
296
|
margin-top: 4px;
|
|
300
297
|
`;
|
|
301
298
|
|
|
302
|
-
const TaskFooter = styled.div
|
|
299
|
+
const TaskFooter = styled.div<{ isMobile?: boolean }>`
|
|
303
300
|
display: flex;
|
|
304
301
|
justify-content: center;
|
|
305
|
-
padding-top:
|
|
302
|
+
padding-top: ${props => props.isMobile ? '8px' : '10px'};
|
|
306
303
|
border-top: 1px solid ${uiColors.darkGray};
|
|
307
304
|
`;
|
|
308
305
|
|
|
@@ -2,18 +2,18 @@ import {
|
|
|
2
2
|
ICharacterDailyTask,
|
|
3
3
|
ICollectGlobalRewardRequest,
|
|
4
4
|
ICollectRewardRequest,
|
|
5
|
-
TaskType,
|
|
6
5
|
TaskStatus,
|
|
6
|
+
TaskType,
|
|
7
7
|
isMobileOrTablet,
|
|
8
8
|
} from '@rpg-engine/shared';
|
|
9
|
-
import React, {
|
|
9
|
+
import React, { useMemo, useState } from 'react';
|
|
10
|
+
import { FaClipboardList, FaThumbtack } from 'react-icons/fa';
|
|
10
11
|
import styled from 'styled-components';
|
|
11
|
-
import { FaThumbtack, FaClipboardList } from 'react-icons/fa';
|
|
12
12
|
import { uiColors } from '../../constants/uiColors';
|
|
13
13
|
import { useLocalStorage } from '../../hooks/useLocalStorage';
|
|
14
14
|
import { DraggableContainer } from '../DraggableContainer';
|
|
15
|
-
import { RPGUIContainerTypes } from '../RPGUI/RPGUIContainer';
|
|
16
15
|
import { Dropdown, IOptionsProps as DropdownOption } from '../Dropdown';
|
|
16
|
+
import { RPGUIContainerTypes } from '../RPGUI/RPGUIContainer';
|
|
17
17
|
import { SearchBar } from '../shared/SearchBar/SearchBar';
|
|
18
18
|
import { DailyTaskItem } from './DailyTaskItem';
|
|
19
19
|
import { GlobalDailyProgress } from './GlobalDailyProgress';
|
|
@@ -50,7 +50,7 @@ export const DailyTasks: React.FC<IDailyTasksProps> = ({
|
|
|
50
50
|
const [globalRewardClaimedLocal, setGlobalRewardClaimedLocal] = useState(
|
|
51
51
|
false
|
|
52
52
|
);
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
// Search and filter state
|
|
55
55
|
const [searchQuery, setSearchQuery] = useState('');
|
|
56
56
|
const [selectedStatus, setSelectedStatus] = useState('all');
|
|
@@ -72,15 +72,15 @@ export const DailyTasks: React.FC<IDailyTasksProps> = ({
|
|
|
72
72
|
const isTaskRewardClaimed = (taskKey: string): boolean => {
|
|
73
73
|
return claimedTasks.includes(taskKey);
|
|
74
74
|
};
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
const togglePinTask = (taskKey: string) => {
|
|
77
|
-
setPinnedTasks(prev =>
|
|
77
|
+
setPinnedTasks(prev =>
|
|
78
78
|
prev.includes(taskKey)
|
|
79
79
|
? prev.filter(key => key !== taskKey)
|
|
80
80
|
: [...prev, taskKey]
|
|
81
81
|
);
|
|
82
82
|
};
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
// Filter options using Store pattern
|
|
85
85
|
const statusOptions: DropdownOption[] = [
|
|
86
86
|
{ id: 0, value: 'all', option: 'All' },
|
|
@@ -89,25 +89,25 @@ export const DailyTasks: React.FC<IDailyTasksProps> = ({
|
|
|
89
89
|
{ id: 3, value: 'inprogress', option: 'In Progress' },
|
|
90
90
|
{ id: 4, value: 'notstarted', option: 'Not Started' },
|
|
91
91
|
];
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
// Filtered tasks using InformationCenter pattern
|
|
94
94
|
const filteredTasks = useMemo(() => {
|
|
95
95
|
let filtered = localTasks.filter(task => {
|
|
96
|
-
const matchesSearch =
|
|
96
|
+
const matchesSearch =
|
|
97
97
|
task.name?.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
98
98
|
task.description?.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
99
99
|
task.key.toLowerCase().includes(searchQuery.toLowerCase());
|
|
100
|
-
|
|
101
|
-
const matchesStatus =
|
|
100
|
+
|
|
101
|
+
const matchesStatus =
|
|
102
102
|
selectedStatus === 'all' ||
|
|
103
103
|
(selectedStatus === 'pinned' && pinnedTasks.includes(task.key)) ||
|
|
104
104
|
(selectedStatus === 'completed' && task.status === TaskStatus.Completed) ||
|
|
105
105
|
(selectedStatus === 'inprogress' && task.status === TaskStatus.InProgress) ||
|
|
106
106
|
(selectedStatus === 'notstarted' && task.status === TaskStatus.NotStarted);
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
return matchesSearch && matchesStatus;
|
|
109
109
|
});
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
// Sort with pinned tasks first
|
|
112
112
|
return filtered.sort((a, b) => {
|
|
113
113
|
const aIsPinned = pinnedTasks.includes(a.key);
|
|
@@ -139,7 +139,7 @@ export const DailyTasks: React.FC<IDailyTasksProps> = ({
|
|
|
139
139
|
}
|
|
140
140
|
/>
|
|
141
141
|
</GlobalProgressFixed>
|
|
142
|
-
|
|
142
|
+
|
|
143
143
|
<SearchHeader>
|
|
144
144
|
<SearchBarContainer>
|
|
145
145
|
<SearchBar
|
|
@@ -156,7 +156,7 @@ export const DailyTasks: React.FC<IDailyTasksProps> = ({
|
|
|
156
156
|
/>
|
|
157
157
|
</DropdownContainer>
|
|
158
158
|
</SearchHeader>
|
|
159
|
-
|
|
159
|
+
|
|
160
160
|
<TasksList className="tasks-container" isMobile={isMobile}>
|
|
161
161
|
{filteredTasks.length > 0 ? (
|
|
162
162
|
filteredTasks.map(task => (
|
|
@@ -262,14 +262,18 @@ const TasksList = styled.div<{ isMobile: boolean }>`
|
|
|
262
262
|
|
|
263
263
|
const GlobalProgressFixed = styled.div`
|
|
264
264
|
flex-shrink: 0;
|
|
265
|
-
padding:
|
|
265
|
+
padding: 12px;
|
|
266
266
|
background-color: transparent;
|
|
267
267
|
`;
|
|
268
268
|
|
|
269
269
|
const SearchHeader = styled.div`
|
|
270
270
|
display: flex;
|
|
271
|
-
gap: 12px;
|
|
272
|
-
|
|
271
|
+
gap: 12px;
|
|
272
|
+
justify-content: center;
|
|
273
|
+
align-items: center;
|
|
274
|
+
margin-left: 12px;
|
|
275
|
+
margin-right: 12px;
|
|
276
|
+
padding: 0.25rem;
|
|
273
277
|
border-bottom: 1px solid ${uiColors.darkGray};
|
|
274
278
|
background: rgba(0, 0, 0, 0.3);
|
|
275
279
|
`;
|
|
@@ -291,7 +295,7 @@ const TaskWrapper = styled.div`
|
|
|
291
295
|
const PinButton = styled.button<{ isPinned: boolean }>`
|
|
292
296
|
position: absolute;
|
|
293
297
|
top: 8px;
|
|
294
|
-
right:
|
|
298
|
+
right: 32px;
|
|
295
299
|
background: rgba(0, 0, 0, 0.7);
|
|
296
300
|
color: ${props => props.isPinned ? uiColors.yellow : uiColors.lightGray};
|
|
297
301
|
border: 1px solid ${props => props.isPinned ? uiColors.yellow : 'transparent'};
|