@rpg-engine/long-bow 0.8.21 → 0.8.22

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 (32) hide show
  1. package/dist/components/InformationCenter/InformationCenter.d.ts +16 -13
  2. package/dist/components/InformationCenter/sections/bestiary/InformationCenterBestiarySection.d.ts +1 -1
  3. package/dist/components/InformationCenter/sections/bestiary/InformationCenterNPCDetails.d.ts +2 -1
  4. package/dist/components/InformationCenter/sections/bestiary/InformationCenterNPCTooltip.d.ts +1 -1
  5. package/dist/components/InformationCenter/sections/faq/InformationCenterFaqSection.d.ts +1 -1
  6. package/dist/components/InformationCenter/sections/items/InformationCenterItemDetails.d.ts +1 -1
  7. package/dist/components/InformationCenter/sections/items/InformationCenterItemTooltip.d.ts +1 -1
  8. package/dist/components/InformationCenter/sections/items/InformationCenterItemsSection.d.ts +2 -1
  9. package/dist/components/InformationCenter/sections/tutorials/InformationCenterTutorialsSection.d.ts +1 -1
  10. package/dist/long-bow.cjs.development.js +788 -687
  11. package/dist/long-bow.cjs.development.js.map +1 -1
  12. package/dist/long-bow.cjs.production.min.js +1 -1
  13. package/dist/long-bow.cjs.production.min.js.map +1 -1
  14. package/dist/long-bow.esm.js +789 -688
  15. package/dist/long-bow.esm.js.map +1 -1
  16. package/dist/mocks/informationCenter.mocks.d.ts +1 -2
  17. package/package.json +2 -2
  18. package/src/components/CraftBook/CraftBook.tsx +1 -1
  19. package/src/components/Dropdown.tsx +25 -3
  20. package/src/components/InformationCenter/InformationCenter.tsx +125 -124
  21. package/src/components/InformationCenter/sections/bestiary/InformationCenterBestiarySection.tsx +52 -7
  22. package/src/components/InformationCenter/sections/bestiary/InformationCenterNPCDetails.tsx +201 -207
  23. package/src/components/InformationCenter/sections/bestiary/InformationCenterNPCTooltip.tsx +7 -6
  24. package/src/components/InformationCenter/sections/faq/InformationCenterFaqSection.tsx +1 -1
  25. package/src/components/InformationCenter/sections/items/InformationCenterItemDetails.tsx +8 -6
  26. package/src/components/InformationCenter/sections/items/InformationCenterItemTooltip.tsx +1 -1
  27. package/src/components/InformationCenter/sections/items/InformationCenterItemsSection.tsx +36 -10
  28. package/src/components/InformationCenter/sections/tutorials/InformationCenterTutorialsSection.tsx +133 -34
  29. package/src/mocks/informationCenter.mocks.ts +158 -47
  30. package/src/stories/UI/info/InformationCenter.stories.tsx +1 -1
  31. package/dist/components/InformationCenter/InformationCenterTypes.d.ts +0 -96
  32. package/src/components/InformationCenter/InformationCenterTypes.ts +0 -105
@@ -1,5 +1,4 @@
1
- import { IFaqItem, IVideoGuide } from '../components/InformationCenter/InformationCenter';
2
- import { IInformationCenterItem, IInformationCenterNPC } from '../components/InformationCenter/InformationCenterTypes';
1
+ import { IFaqItem, IInformationCenterItem, IInformationCenterNPC, IVideoGuide } from '@rpg-engine/shared';
3
2
  export declare const mockBestiaryItems: IInformationCenterNPC[];
4
3
  export declare const mockItems: IInformationCenterItem[];
5
4
  export declare const mockFaqItems: IFaqItem[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.8.21",
3
+ "version": "0.8.22",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -84,7 +84,7 @@
84
84
  "dependencies": {
85
85
  "@capacitor/core": "^6.1.0",
86
86
  "@rollup/plugin-image": "^2.1.1",
87
- "@rpg-engine/shared": "^0.9.96",
87
+ "@rpg-engine/shared": "^0.9.101",
88
88
  "dayjs": "^1.11.2",
89
89
  "font-awesome": "^4.7.0",
90
90
  "fs-extra": "^10.1.0",
@@ -368,7 +368,7 @@ const ContentContainer = styled.div`
368
368
  padding-bottom: 0;
369
369
  width: 100%;
370
370
  position: relative;
371
- min-height: 250px;
371
+ min-height: 300px;
372
372
  overflow: hidden;
373
373
  `;
374
374
 
@@ -15,6 +15,10 @@ export interface IDropdownProps {
15
15
  opensUp?: boolean; // Add a new prop to control the dropdown direction
16
16
  }
17
17
 
18
+ const ITEM_HEIGHT = 35;
19
+ const MAX_ITEMS_VISIBLE = 10;
20
+ const MAX_HEIGHT = MAX_ITEMS_VISIBLE * ITEM_HEIGHT;
21
+
18
22
  export const Dropdown: React.FC<IDropdownProps> = ({
19
23
  options,
20
24
  width,
@@ -65,6 +69,7 @@ export const Dropdown: React.FC<IDropdownProps> = ({
65
69
  className="rpgui-dropdown-imp"
66
70
  opened={opened}
67
71
  opensUp={opensUp}
72
+ optionsCount={options.length}
68
73
  >
69
74
  {options.map(option => {
70
75
  return (
@@ -88,11 +93,16 @@ export const Dropdown: React.FC<IDropdownProps> = ({
88
93
  const Container = styled.div<{ width: string | undefined }>`
89
94
  position: relative;
90
95
  width: ${props => props.width || '100%'};
96
+ max-height: ${MAX_HEIGHT}px;
91
97
  `;
92
98
 
93
99
  const DropdownSelect = styled.p`
94
100
  width: 100%;
95
101
  box-sizing: border-box;
102
+ white-space: nowrap;
103
+ overflow: hidden;
104
+ text-overflow: ellipsis;
105
+ max-height: ${ITEM_HEIGHT}px;
96
106
 
97
107
  label {
98
108
  display: inline-block;
@@ -103,10 +113,14 @@ const DropdownSelect = styled.p`
103
113
  const DropdownOptions = styled.ul<{
104
114
  opened: boolean;
105
115
  opensUp: boolean;
116
+ optionsCount: number;
106
117
  }>`
107
118
  position: absolute;
108
119
  width: 100%;
109
- max-height: 300px;
120
+ max-height: ${props =>
121
+ props.opened
122
+ ? `${Math.min(props.optionsCount * ITEM_HEIGHT, MAX_HEIGHT)}px`
123
+ : '0'};
110
124
  overflow-y: auto;
111
125
  display: ${props => (props.opened ? 'block' : 'none')};
112
126
  box-sizing: border-box;
@@ -114,7 +128,15 @@ const DropdownOptions = styled.ul<{
114
128
  top: ${props => (props.opensUp ? 'auto' : '100%')};
115
129
  margin: 0;
116
130
  padding: 0;
117
- @media (max-width: 768px) {
118
- padding: 8px 0;
131
+
132
+ li {
133
+ white-space: nowrap;
134
+ overflow: hidden;
135
+ text-overflow: ellipsis;
136
+ padding: 8px 12px;
137
+ min-height: ${ITEM_HEIGHT}px;
138
+ max-height: ${ITEM_HEIGHT}px;
139
+ box-sizing: border-box;
140
+ line-height: 1.2;
119
141
  }
120
142
  `;
@@ -1,145 +1,146 @@
1
1
  import React, { useState } from 'react';
2
2
  import styled from 'styled-components';
3
3
 
4
- import { InternalTabs } from '../InternalTabs/InternalTabs';
5
4
  import {
5
+ IFaqItem,
6
6
  IInformationCenterItem,
7
- IInformationCenterProps,
8
- } from './InformationCenterTypes';
7
+ IInformationCenterNPC,
8
+ IVideoGuide,
9
+ } from '@rpg-engine/shared';
10
+ import { InternalTabs } from '../InternalTabs/InternalTabs';
9
11
  import { InformationCenterBestiarySection } from './sections/bestiary/InformationCenterBestiarySection';
10
12
  import { InformationCenterFAQSection } from './sections/faq/InformationCenterFaqSection';
11
13
  import { InformationCenterItemDetails } from './sections/items/InformationCenterItemDetails';
12
14
  import { InformationCenterItemsSection } from './sections/items/InformationCenterItemsSection';
13
15
  import { InformationCenterTutorialsSection } from './sections/tutorials/InformationCenterTutorialsSection';
14
16
 
15
- export interface IFaqItem {
16
- id: string;
17
- question: string;
18
- answer: string;
19
- }
20
-
21
- export interface IVideoGuide {
22
- id: string;
23
- title: string;
24
- description: string;
25
- thumbnailUrl: string;
26
- videoUrl: string;
27
- category: 'Combat' | 'Crafting' | 'Exploration' | 'General';
17
+ interface IInformationCenterProps {
18
+ itemsAtlasJSON: Record<string, any>;
19
+ itemsAtlasIMG: string;
20
+ entitiesAtlasJSON: Record<string, any>;
21
+ entitiesAtlasIMG: string;
22
+ iconsAtlasJSON: any;
23
+ iconsAtlasIMG: any;
24
+ faqItems?: IFaqItem[];
25
+ bestiaryItems?: IInformationCenterNPC[];
26
+ videoGuides?: IVideoGuide[];
27
+ items?: IInformationCenterItem[];
28
+ loading?: boolean;
29
+ error?: string;
30
+ initialSearchQuery?: string;
28
31
  }
29
32
 
30
33
  export const InformationCenter: React.FC<IInformationCenterProps> = ({
31
- itemsAtlasJSON,
32
- itemsAtlasIMG,
33
- entitiesAtlasJSON,
34
- entitiesAtlasIMG,
35
- iconsAtlasIMG,
36
- iconsAtlasJSON,
37
- faqItems = [],
38
- bestiaryItems = [],
39
- videoGuides = [],
40
- items = [],
41
- loading = false,
42
- error,
43
- initialSearchQuery = '',
44
- }) => {
45
- const [activeTab, setActiveTab] = useState('bestiary');
46
- const [
47
- selectedItem,
48
- setSelectedItem,
49
- ] = useState<IInformationCenterItem | null>(null);
34
+ itemsAtlasJSON,
35
+ itemsAtlasIMG,
36
+ entitiesAtlasJSON,
37
+ entitiesAtlasIMG,
38
+ iconsAtlasIMG,
39
+ iconsAtlasJSON,
40
+ faqItems = [],
41
+ bestiaryItems = [],
42
+ videoGuides = [],
43
+ items = [],
44
+ loading = false,
45
+ error,
46
+ initialSearchQuery = '',
47
+ }) => {
48
+ const [activeTab, setActiveTab] = useState('bestiary');
49
+ const [
50
+ selectedItem,
51
+ setSelectedItem,
52
+ ] = useState<IInformationCenterItem | null>(null);
50
53
 
51
- if (loading) {
52
- return <LoadingMessage>Loading...</LoadingMessage>;
53
- }
54
+ if (loading) {
55
+ return <LoadingMessage>Loading...</LoadingMessage>;
56
+ }
54
57
 
55
- if (error) {
56
- return <ErrorMessage>{error}</ErrorMessage>;
57
- }
58
+ if (error) {
59
+ return <ErrorMessage>{error}</ErrorMessage>;
60
+ }
58
61
 
59
- const tabs = [
60
- {
61
- id: 'bestiary',
62
- title: 'Bestiary',
63
- content: (
64
- <InformationCenterBestiarySection
65
- bestiaryItems={bestiaryItems}
66
- itemsAtlasJSON={itemsAtlasJSON}
67
- itemsAtlasIMG={itemsAtlasIMG}
68
- iconsAtlasIMG={iconsAtlasIMG}
69
- iconsAtlasJSON={iconsAtlasJSON}
70
- entitiesAtlasJSON={entitiesAtlasJSON}
71
- entitiesAtlasIMG={entitiesAtlasIMG}
72
- initialSearchQuery={initialSearchQuery}
73
- tabId="bestiary"
74
- />
75
- ),
76
- },
77
- {
78
- id: 'items',
79
- title: 'Items',
80
- content: (
81
- <InformationCenterItemsSection
82
- items={items}
83
- bestiaryItems={bestiaryItems}
84
- itemsAtlasJSON={itemsAtlasJSON}
85
- itemsAtlasIMG={itemsAtlasIMG}
86
- initialSearchQuery={initialSearchQuery}
87
- tabId="items"
88
- />
89
- ),
90
- },
91
- {
92
- id: 'faq',
93
- title: 'FAQ',
94
- content: (
95
- <InformationCenterFAQSection
96
- faqItems={faqItems}
97
- initialSearchQuery={initialSearchQuery}
98
- tabId="faq"
99
- />
100
- ),
101
- },
102
- {
103
- id: 'tutorials',
104
- title: 'Tutorials',
105
- content: (
106
- <InformationCenterTutorialsSection
107
- videoGuides={videoGuides}
108
- initialSearchQuery={initialSearchQuery}
109
- tabId="tutorials"
110
- />
111
- ),
112
- },
113
- ];
62
+ const tabs = [
63
+ {
64
+ id: 'bestiary',
65
+ title: 'Bestiary',
66
+ content: (
67
+ <InformationCenterBestiarySection
68
+ bestiaryItems={bestiaryItems}
69
+ itemsAtlasJSON={itemsAtlasJSON}
70
+ itemsAtlasIMG={itemsAtlasIMG}
71
+ iconsAtlasIMG={iconsAtlasIMG}
72
+ iconsAtlasJSON={iconsAtlasJSON}
73
+ entitiesAtlasJSON={entitiesAtlasJSON}
74
+ entitiesAtlasIMG={entitiesAtlasIMG}
75
+ initialSearchQuery={initialSearchQuery}
76
+ tabId="bestiary"
77
+ />
78
+ ),
79
+ },
80
+ {
81
+ id: 'items',
82
+ title: 'Items',
83
+ content: (
84
+ <InformationCenterItemsSection
85
+ items={items}
86
+ bestiaryItems={bestiaryItems}
87
+ itemsAtlasJSON={itemsAtlasJSON}
88
+ itemsAtlasIMG={itemsAtlasIMG}
89
+ initialSearchQuery={initialSearchQuery}
90
+ tabId="items"
91
+ />
92
+ ),
93
+ },
94
+ {
95
+ id: 'faq',
96
+ title: 'FAQ',
97
+ content: (
98
+ <InformationCenterFAQSection
99
+ faqItems={faqItems}
100
+ initialSearchQuery={initialSearchQuery}
101
+ tabId="faq"
102
+ />
103
+ ),
104
+ },
105
+ {
106
+ id: 'tutorials',
107
+ title: 'Tutorials',
108
+ content: (
109
+ <InformationCenterTutorialsSection
110
+ videoGuides={videoGuides}
111
+ initialSearchQuery={initialSearchQuery}
112
+ tabId="tutorials"
113
+ />
114
+ ),
115
+ },
116
+ ];
114
117
 
115
- return (
116
- <Container>
117
- <InternalTabs
118
- tabs={tabs}
119
- activeTextColor="#000000"
120
- activeTab={activeTab}
121
- onTabChange={setActiveTab}
122
- activeColor="#fef08a"
123
- inactiveColor="#6b7280"
124
- borderColor="#f59e0b"
125
- hoverColor="#fef3c7"
126
- />
127
- {selectedItem && (
128
- <InformationCenterItemDetails
129
- item={selectedItem}
130
- itemsAtlasJSON={itemsAtlasJSON}
131
- itemsAtlasIMG={itemsAtlasIMG}
132
- droppedBy={bestiaryItems.filter(npc =>
133
- npc.loots?.some(
134
- loot => loot.itemBlueprintKey === selectedItem.key
135
- )
136
- )}
137
- onBack={() => setSelectedItem(null)}
138
- />
139
- )}
140
- </Container>
141
- );
142
- };
118
+ return (
119
+ <Container>
120
+ <InternalTabs
121
+ tabs={tabs}
122
+ activeTextColor="#000000"
123
+ activeTab={activeTab}
124
+ onTabChange={setActiveTab}
125
+ activeColor="#fef08a"
126
+ inactiveColor="#6b7280"
127
+ borderColor="#f59e0b"
128
+ hoverColor="#fef3c7"
129
+ />
130
+ {selectedItem && (
131
+ <InformationCenterItemDetails
132
+ item={selectedItem}
133
+ itemsAtlasJSON={itemsAtlasJSON}
134
+ itemsAtlasIMG={itemsAtlasIMG}
135
+ droppedBy={bestiaryItems.filter(npc =>
136
+ npc.loots?.some(loot => loot.itemBlueprintKey === selectedItem.key)
137
+ )}
138
+ onBack={() => setSelectedItem(null)}
139
+ />
140
+ )}
141
+ </Container>
142
+ );
143
+ };
143
144
 
144
145
  const Container = styled.div`
145
146
  width: 100%;
@@ -1,12 +1,13 @@
1
- import React, { useState } from 'react';
1
+ import { IInformationCenterNPC, NPCAlignment } from '@rpg-engine/shared';
2
+ import React, { useMemo, useState } from 'react';
2
3
  import styled from 'styled-components';
4
+ import { IOptionsProps } from '../../../Dropdown';
3
5
  import { PaginatedContent } from '../../../shared/PaginatedContent/PaginatedContent';
4
6
  import { Portal } from '../../../shared/Portal/Portal';
5
7
  import { InformationCenterCell } from '../../InformationCenterCell';
6
- import { IInformationCenterNPC } from '../../InformationCenterTypes';
8
+ import { formatItemType } from '../items/InformationCenterItemsSection';
7
9
  import { InformationCenterNPCDetails } from './InformationCenterNPCDetails';
8
10
  import { InformationCenterNPCTooltip } from './InformationCenterNPCTooltip';
9
-
10
11
  interface IBestiarySectionProps {
11
12
  bestiaryItems: IInformationCenterNPC[];
12
13
  itemsAtlasJSON: Record<string, any>;
@@ -91,6 +92,20 @@ export const InformationCenterBestiarySection: React.FC<IBestiarySectionProps> =
91
92
  setTooltipData(null);
92
93
  };
93
94
 
95
+ const [selectedBestiaryCategory, setSelectedBestiaryCategory] = useState<
96
+ string
97
+ >('all');
98
+
99
+ const bestiaryCategoryOptions: IOptionsProps[] = [
100
+ { id: 0, value: 'all', option: 'All Monsters' },
101
+ { id: 1, value: 'bosses', option: 'Bosses' },
102
+ ...Object.entries(NPCAlignment).map(([, value], index) => ({
103
+ id: index + 1,
104
+ value,
105
+ option: formatItemType(value),
106
+ })),
107
+ ];
108
+
94
109
  const renderItem = (item: IInformationCenterNPC) => (
95
110
  <InformationCenterCell
96
111
  key={item.id}
@@ -106,9 +121,33 @@ export const InformationCenterBestiarySection: React.FC<IBestiarySectionProps> =
106
121
  />
107
122
  );
108
123
 
109
- const filteredItems = bestiaryItems.filter(item =>
110
- item.name.toLowerCase().includes(searchQuery.toLowerCase())
111
- );
124
+ const filteredItems = useMemo(() => {
125
+ return bestiaryItems.filter(item => {
126
+ const matchesSearch = item.name
127
+ .toLowerCase()
128
+ .includes(searchQuery.toLowerCase());
129
+
130
+ let matchesCategory = true;
131
+
132
+ if (selectedBestiaryCategory === 'bosses') {
133
+ matchesCategory = item.isBoss === true;
134
+ } else if (selectedBestiaryCategory === NPCAlignment.Hostile) {
135
+ matchesCategory =
136
+ item.alignment === NPCAlignment.Hostile && !item.isBoss;
137
+ } else if (selectedBestiaryCategory !== 'all') {
138
+ matchesCategory = item.alignment === selectedBestiaryCategory;
139
+ }
140
+
141
+ return matchesSearch && matchesCategory;
142
+ });
143
+ }, [bestiaryItems, searchQuery, selectedBestiaryCategory]);
144
+
145
+ const handleSearchChange = (newQuery: string) => {
146
+ setSearchQuery(newQuery);
147
+ if (newQuery && selectedBestiaryCategory !== 'all') {
148
+ setSelectedBestiaryCategory('all');
149
+ }
150
+ };
112
151
 
113
152
  return (
114
153
  <>
@@ -118,11 +157,17 @@ export const InformationCenterBestiarySection: React.FC<IBestiarySectionProps> =
118
157
  emptyMessage="No monsters found"
119
158
  tabId={tabId}
120
159
  layout="grid"
160
+ filterOptions={{
161
+ options: bestiaryCategoryOptions,
162
+ selectedOption: selectedBestiaryCategory,
163
+ onOptionChange: setSelectedBestiaryCategory,
164
+ }}
121
165
  searchOptions={{
122
166
  value: searchQuery,
123
- onChange: setSearchQuery,
167
+ onChange: handleSearchChange,
124
168
  placeholder: 'Search monsters...',
125
169
  }}
170
+ dependencies={[selectedBestiaryCategory]}
126
171
  itemHeight="180px"
127
172
  />
128
173
  {tooltipData && (