@rpg-engine/long-bow 0.7.91 → 0.7.92
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/CraftBook/CraftingTooltip.d.ts +13 -0
- package/dist/components/CraftBook/components/CraftBookHeader.d.ts +9 -0
- package/dist/components/CraftBook/components/CraftBookPagination.d.ts +0 -0
- package/dist/components/CraftBook/components/CraftBookSearch.d.ts +0 -0
- package/dist/components/CraftBook/hooks/useCraftBookFilters.d.ts +9 -0
- package/dist/components/CraftBook/hooks/useFilteredItems.d.ts +9 -0
- package/dist/components/CraftBook/hooks/usePagination.d.ts +13 -0
- package/dist/components/CraftBook/hooks/useResponsiveSize.d.ts +6 -0
- package/dist/components/CraftBook/utils/modifyString.d.ts +1 -0
- package/dist/components/shared/Pagination/Pagination.d.ts +9 -0
- package/dist/components/shared/SearchBar/SearchBar.d.ts +10 -0
- package/dist/hooks/useLocalStorage.d.ts +1 -0
- package/dist/long-bow.cjs.development.js +448 -293
- 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 +448 -294
- package/dist/long-bow.esm.js.map +1 -1
- package/dist/stories/Features/craftbook/CraftBook.stories.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/CraftBook/CraftBook.tsx +281 -138
- package/src/components/CraftBook/CraftingRecipe.tsx +97 -97
- package/src/components/CraftBook/CraftingTooltip.tsx +137 -0
- package/src/components/CraftBook/components/CraftBookHeader.tsx +81 -0
- package/src/components/CraftBook/components/CraftBookPagination.tsx +1 -0
- package/src/components/CraftBook/components/CraftBookSearch.tsx +1 -0
- package/src/components/CraftBook/hooks/useCraftBookFilters.ts +39 -0
- package/src/components/CraftBook/hooks/useFilteredItems.ts +39 -0
- package/src/components/CraftBook/hooks/usePagination.ts +39 -0
- package/src/components/CraftBook/hooks/useResponsiveSize.ts +50 -0
- package/src/components/CraftBook/utils/modifyString.ts +11 -0
- package/src/components/shared/Pagination/Pagination.tsx +69 -0
- package/src/components/shared/SearchBar/SearchBar.tsx +52 -0
- package/src/hooks/useLocalStorage.ts +44 -0
- package/src/stories/Features/craftbook/CraftBook.stories.tsx +41 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { uiColors } from '../../../constants/uiColors';
|
|
5
|
+
|
|
6
|
+
interface PaginationProps {
|
|
7
|
+
currentPage: number;
|
|
8
|
+
totalPages: number;
|
|
9
|
+
onPageChange: (page: number) => void;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const Pagination: React.FC<PaginationProps> = ({
|
|
14
|
+
currentPage,
|
|
15
|
+
totalPages,
|
|
16
|
+
onPageChange,
|
|
17
|
+
className,
|
|
18
|
+
}) => {
|
|
19
|
+
return (
|
|
20
|
+
<Container className={className}>
|
|
21
|
+
<PaginationButton
|
|
22
|
+
onClick={() => onPageChange(Math.max(1, currentPage - 1))}
|
|
23
|
+
disabled={currentPage === 1}
|
|
24
|
+
>
|
|
25
|
+
<FaChevronLeft size={12} />
|
|
26
|
+
</PaginationButton>
|
|
27
|
+
<PageInfo>
|
|
28
|
+
Page {currentPage} of {totalPages}
|
|
29
|
+
</PageInfo>
|
|
30
|
+
<PaginationButton
|
|
31
|
+
onClick={() => onPageChange(Math.min(totalPages, currentPage + 1))}
|
|
32
|
+
disabled={currentPage === totalPages}
|
|
33
|
+
>
|
|
34
|
+
<FaChevronRight size={12} />
|
|
35
|
+
</PaginationButton>
|
|
36
|
+
</Container>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const Container = styled.div`
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: center;
|
|
44
|
+
gap: 16px;
|
|
45
|
+
padding: 8px;
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
const PaginationButton = styled.button<{ disabled?: boolean }>`
|
|
49
|
+
background: none;
|
|
50
|
+
border: none;
|
|
51
|
+
color: ${props => (props.disabled ? uiColors.darkGray : uiColors.yellow)};
|
|
52
|
+
cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')};
|
|
53
|
+
opacity: ${props => (props.disabled ? 0.5 : 0.8)};
|
|
54
|
+
padding: 4px;
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
transition: opacity 0.2s;
|
|
59
|
+
|
|
60
|
+
&:hover:not(:disabled) {
|
|
61
|
+
opacity: 1;
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
const PageInfo = styled.div`
|
|
66
|
+
color: ${uiColors.lightGray};
|
|
67
|
+
font-size: 0.8rem;
|
|
68
|
+
font-family: 'Press Start 2P', cursive;
|
|
69
|
+
`;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
interface SearchBarProps {
|
|
5
|
+
value: string;
|
|
6
|
+
onChange: (value: string) => void;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
autoFocus?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const SearchBar: React.FC<SearchBarProps> = ({
|
|
13
|
+
value,
|
|
14
|
+
onChange,
|
|
15
|
+
placeholder = 'Search...',
|
|
16
|
+
className,
|
|
17
|
+
autoFocus = false,
|
|
18
|
+
}) => {
|
|
19
|
+
return (
|
|
20
|
+
<Container className={className}>
|
|
21
|
+
<input
|
|
22
|
+
type="text"
|
|
23
|
+
className="rpgui-input"
|
|
24
|
+
placeholder={placeholder}
|
|
25
|
+
value={value}
|
|
26
|
+
onChange={e => onChange(e.target.value)}
|
|
27
|
+
autoFocus={autoFocus}
|
|
28
|
+
/>
|
|
29
|
+
</Container>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
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;
|
|
42
|
+
|
|
43
|
+
&::placeholder {
|
|
44
|
+
color: rgba(255, 255, 255, 0.5);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&:focus {
|
|
48
|
+
outline: none;
|
|
49
|
+
background-color: rgba(0, 0, 0, 0.4);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
|
|
5
|
+
export function useLocalStorage<T>(key: string, initialValue: T) {
|
|
6
|
+
// State to store our value
|
|
7
|
+
// Pass initial state function to useState so logic is only executed once
|
|
8
|
+
const [storedValue, setStoredValue] = useState<T>(() => {
|
|
9
|
+
if (typeof window === 'undefined') {
|
|
10
|
+
return initialValue;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
// Get from local storage by key
|
|
14
|
+
const item = window.localStorage.getItem(key);
|
|
15
|
+
// Parse stored json or if none return initialValue
|
|
16
|
+
return item ? JSON.parse(item) : initialValue;
|
|
17
|
+
} catch (error) {
|
|
18
|
+
// If error also return initialValue
|
|
19
|
+
console.log(error);
|
|
20
|
+
return initialValue;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Return a wrapped version of useState's setter function that ...
|
|
25
|
+
// ... persists the new value to localStorage.
|
|
26
|
+
const setValue = (value: T | ((val: T) => T)) => {
|
|
27
|
+
try {
|
|
28
|
+
// Allow value to be a function so we have same API as useState
|
|
29
|
+
const valueToStore =
|
|
30
|
+
value instanceof Function ? value(storedValue) : value;
|
|
31
|
+
// Save state
|
|
32
|
+
setStoredValue(valueToStore);
|
|
33
|
+
// Save to local storage
|
|
34
|
+
if (typeof window !== 'undefined') {
|
|
35
|
+
window.localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
// A more advanced implementation would handle the error case
|
|
39
|
+
console.log(error);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return [storedValue, setValue] as const;
|
|
44
|
+
}
|
|
@@ -7,9 +7,37 @@ import atlasJSON from '../../../mocks/atlas/items/items.json';
|
|
|
7
7
|
import atlasIMG from '../../../mocks/atlas/items/items.png';
|
|
8
8
|
import { equipmentSetMock } from '../../../mocks/equipmentSet.mocks';
|
|
9
9
|
|
|
10
|
+
// Generate more mock items for pagination testing
|
|
11
|
+
const generateMoreItems = (baseItems: typeof craftableItems) => {
|
|
12
|
+
const moreItems = [...baseItems];
|
|
13
|
+
|
|
14
|
+
// Create 3 variations of each item
|
|
15
|
+
baseItems.forEach(item => {
|
|
16
|
+
for (let i = 1; i <= 3; i++) {
|
|
17
|
+
moreItems.push({
|
|
18
|
+
...item,
|
|
19
|
+
key: `${item.key}-${i}`,
|
|
20
|
+
name: `${item.name} ${i}`,
|
|
21
|
+
ingredients: item.ingredients.map(ing => ({
|
|
22
|
+
...ing,
|
|
23
|
+
key: `${ing.key}-${i}`,
|
|
24
|
+
qty: ing.qty + i,
|
|
25
|
+
})),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return moreItems;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const extendedCraftableItems = generateMoreItems(craftableItems);
|
|
34
|
+
|
|
10
35
|
const meta: Meta = {
|
|
11
36
|
title: 'Features/Crafting/Craft Book',
|
|
12
37
|
component: CraftBook,
|
|
38
|
+
parameters: {
|
|
39
|
+
layout: 'fullscreen',
|
|
40
|
+
},
|
|
13
41
|
};
|
|
14
42
|
|
|
15
43
|
export default meta;
|
|
@@ -21,7 +49,7 @@ const Template: Story = args => (
|
|
|
21
49
|
atlasJSON={atlasJSON}
|
|
22
50
|
onSelect={onSelect}
|
|
23
51
|
onClose={() => console.log('closing Equipment Set Container')}
|
|
24
|
-
craftablesItems={
|
|
52
|
+
craftablesItems={extendedCraftableItems}
|
|
25
53
|
onCraftItem={(value, maxCraftable) => {
|
|
26
54
|
console.log('Crafting:', {
|
|
27
55
|
itemKey: value,
|
|
@@ -41,3 +69,15 @@ const onSelect = (value: string) => {
|
|
|
41
69
|
};
|
|
42
70
|
|
|
43
71
|
Default.args = {};
|
|
72
|
+
|
|
73
|
+
// Add a story with search pre-filled
|
|
74
|
+
export const WithSearch = Template.bind({});
|
|
75
|
+
WithSearch.args = {
|
|
76
|
+
searchTerm: 'sword',
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Add a story with a specific category selected
|
|
80
|
+
export const WithCategory = Template.bind({});
|
|
81
|
+
WithCategory.args = {
|
|
82
|
+
savedSelectedType: 'Weapon',
|
|
83
|
+
};
|