feat: list all modules for adding them to fits (#40)
This commit is contained in:
@@ -21,6 +21,7 @@ export interface TypeID {
|
||||
published: boolean,
|
||||
factionID?: number,
|
||||
marketGroupID?: number,
|
||||
metaGroupID?: number,
|
||||
capacity?: number,
|
||||
mass?: number,
|
||||
radius?: number,
|
||||
@@ -36,6 +37,7 @@ export interface GroupID {
|
||||
export interface MarketGroup {
|
||||
name: string,
|
||||
parentGroupID?: number,
|
||||
iconID?: number,
|
||||
}
|
||||
|
||||
export interface DogmaAttribute {
|
||||
|
||||
@@ -263,12 +263,13 @@ export const esf = $root.esf = (() => {
|
||||
TypeID.prototype.groupID = 0;
|
||||
TypeID.prototype.categoryID = 0;
|
||||
TypeID.prototype.published = false;
|
||||
TypeID.prototype.factionID = 0;
|
||||
TypeID.prototype.marketGroupID = 0;
|
||||
TypeID.prototype.capacity = 0;
|
||||
TypeID.prototype.mass = 0;
|
||||
TypeID.prototype.radius = 0;
|
||||
TypeID.prototype.volume = 0;
|
||||
TypeID.prototype.factionID = undefined;
|
||||
TypeID.prototype.marketGroupID = undefined;
|
||||
TypeID.prototype.metaGroupID = undefined;
|
||||
TypeID.prototype.capacity = undefined;
|
||||
TypeID.prototype.mass = undefined;
|
||||
TypeID.prototype.radius = undefined;
|
||||
TypeID.prototype.volume = undefined;
|
||||
|
||||
TypeID.decode = function decode(r, l) {
|
||||
if (!(r instanceof $Reader))
|
||||
@@ -302,18 +303,22 @@ export const esf = $root.esf = (() => {
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
m.capacity = r.float();
|
||||
m.metaGroupID = r.int32();
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
m.mass = r.float();
|
||||
m.capacity = r.float();
|
||||
break;
|
||||
}
|
||||
case 9: {
|
||||
m.radius = r.float();
|
||||
m.mass = r.float();
|
||||
break;
|
||||
}
|
||||
case 10: {
|
||||
m.radius = r.float();
|
||||
break;
|
||||
}
|
||||
case 11: {
|
||||
m.volume = r.float();
|
||||
break;
|
||||
}
|
||||
@@ -511,7 +516,8 @@ export const esf = $root.esf = (() => {
|
||||
}
|
||||
|
||||
MarketGroup.prototype.name = "";
|
||||
MarketGroup.prototype.parentGroupID = 0;
|
||||
MarketGroup.prototype.parentGroupID = undefined;
|
||||
MarketGroup.prototype.iconID = undefined;
|
||||
|
||||
MarketGroup.decode = function decode(r, l) {
|
||||
if (!(r instanceof $Reader))
|
||||
@@ -528,6 +534,10 @@ export const esf = $root.esf = (() => {
|
||||
m.parentGroupID = r.int32();
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
m.iconID = r.int32();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
r.skipType(t & 7);
|
||||
break;
|
||||
@@ -738,14 +748,14 @@ export const esf = $root.esf = (() => {
|
||||
DogmaEffect.prototype.isWarpSafe = false;
|
||||
DogmaEffect.prototype.propulsionChance = false;
|
||||
DogmaEffect.prototype.rangeChance = false;
|
||||
DogmaEffect.prototype.dischargeAttributeID = 0;
|
||||
DogmaEffect.prototype.durationAttributeID = 0;
|
||||
DogmaEffect.prototype.rangeAttributeID = 0;
|
||||
DogmaEffect.prototype.falloffAttributeID = 0;
|
||||
DogmaEffect.prototype.trackingSpeedAttributeID = 0;
|
||||
DogmaEffect.prototype.fittingUsageChanceAttributeID = 0;
|
||||
DogmaEffect.prototype.resistanceAttributeID = 0;
|
||||
DogmaEffect.prototype.modifierInfo = emptyArray;
|
||||
DogmaEffect.prototype.dischargeAttributeID = undefined;
|
||||
DogmaEffect.prototype.durationAttributeID = undefined;
|
||||
DogmaEffect.prototype.rangeAttributeID = undefined;
|
||||
DogmaEffect.prototype.falloffAttributeID = undefined;
|
||||
DogmaEffect.prototype.trackingSpeedAttributeID = undefined;
|
||||
DogmaEffect.prototype.fittingUsageChanceAttributeID = undefined;
|
||||
DogmaEffect.prototype.resistanceAttributeID = undefined;
|
||||
DogmaEffect.prototype.modifierInfo = undefined;
|
||||
|
||||
DogmaEffect.decode = function decode(r, l) {
|
||||
if (!(r instanceof $Reader))
|
||||
@@ -855,11 +865,11 @@ export const esf = $root.esf = (() => {
|
||||
|
||||
ModifierInfo.prototype.domain = 0;
|
||||
ModifierInfo.prototype.func = 0;
|
||||
ModifierInfo.prototype.modifiedAttributeID = 0;
|
||||
ModifierInfo.prototype.modifyingAttributeID = 0;
|
||||
ModifierInfo.prototype.operation = 0;
|
||||
ModifierInfo.prototype.groupID = 0;
|
||||
ModifierInfo.prototype.skillTypeID = 0;
|
||||
ModifierInfo.prototype.modifiedAttributeID = undefined;
|
||||
ModifierInfo.prototype.modifyingAttributeID = undefined;
|
||||
ModifierInfo.prototype.operation = undefined;
|
||||
ModifierInfo.prototype.groupID = undefined;
|
||||
ModifierInfo.prototype.skillTypeID = undefined;
|
||||
|
||||
ModifierInfo.decode = function decode(r, l) {
|
||||
if (!(r instanceof $Reader))
|
||||
|
||||
57
src/HardwareListing/HardwareListing.module.css
Normal file
57
src/HardwareListing/HardwareListing.module.css
Normal file
@@ -0,0 +1,57 @@
|
||||
.listing {
|
||||
background-color: #111111;
|
||||
color: #c5c5c5;
|
||||
font-size: 15px;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.listingContent {
|
||||
height: calc(100% - 42px - 32px - 5px);
|
||||
overflow-y: auto;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.topbar > input {
|
||||
background-color: #1d1d1d;
|
||||
color: #c5c5c5;
|
||||
flex: 1;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
margin: 6px 0;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.filter {
|
||||
display: flex;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.filter > span {
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
user-select: none;
|
||||
width: 32px;
|
||||
}
|
||||
.filter > span:hover {
|
||||
background-color: #4f4f4f;
|
||||
}
|
||||
.filter > span.selected {
|
||||
background-color: #7a7a7a;
|
||||
}
|
||||
|
||||
.filter > span.disabled {
|
||||
color: #7a7a7a;
|
||||
cursor: default;
|
||||
}
|
||||
.filter > span.disabled:hover {
|
||||
background-color: #111111;
|
||||
}
|
||||
29
src/HardwareListing/HardwareListing.stories.tsx
Normal file
29
src/HardwareListing/HardwareListing.stories.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||
import React from "react";
|
||||
|
||||
import { EveDataProvider } from '../EveDataProvider';
|
||||
|
||||
import { HardwareListing } from './';
|
||||
|
||||
const meta: Meta<typeof HardwareListing> = {
|
||||
component: HardwareListing,
|
||||
tags: ['autodocs'],
|
||||
title: 'Component/HardwareListing',
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof HardwareListing>;
|
||||
|
||||
const withEveDataProvider: Decorator<Record<string, never>> = (Story) => {
|
||||
return (
|
||||
<EveDataProvider>
|
||||
<div style={{height: "400px"}}>
|
||||
<Story />
|
||||
</div>
|
||||
</EveDataProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export const Default: Story = {
|
||||
decorators: [withEveDataProvider],
|
||||
};
|
||||
219
src/HardwareListing/HardwareListing.tsx
Normal file
219
src/HardwareListing/HardwareListing.tsx
Normal file
@@ -0,0 +1,219 @@
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
import { defaultDataUrl } from "../settings";
|
||||
import { EveDataContext } from "../EveDataProvider";
|
||||
import { Icon } from "../Icon";
|
||||
import { ShipSnapshotContext, ShipSnapshotSlotsType } from "../ShipSnapshotProvider";
|
||||
import { TreeListing, TreeHeader, TreeLeaf } from "../TreeListing";
|
||||
|
||||
import styles from "./HardwareListing.module.css";
|
||||
|
||||
interface ListingItem {
|
||||
name: string;
|
||||
meta: number;
|
||||
typeId: number;
|
||||
slotType: ShipSnapshotSlotsType | "dronebay";
|
||||
}
|
||||
|
||||
interface ListingGroup {
|
||||
name: string;
|
||||
meta: number;
|
||||
iconID?: number;
|
||||
groups: Record<string, ListingGroup>;
|
||||
items: ListingItem[];
|
||||
}
|
||||
|
||||
const ModuleGroup = (props: { level: number, group: ListingGroup }) => {
|
||||
const shipSnapShot = React.useContext(ShipSnapshotContext);
|
||||
|
||||
const getChildren = React.useCallback(() => {
|
||||
return <>
|
||||
{props.group.items.sort((a, b) => a.meta - b.meta || a.name.localeCompare(b.name)).map((item) => {
|
||||
return <TreeLeaf key={item.typeId} level={2} content={item.name} onClick={() => shipSnapShot.addModule(item.typeId, item.slotType)} />;
|
||||
})}
|
||||
{Object.keys(props.group.groups).sort((a, b) => props.group.groups[a].meta - props.group.groups[b].meta || props.group.groups[a].name.localeCompare(props.group.groups[b].name)).map((groupId) => {
|
||||
return <ModuleGroup key={groupId} level={props.level + 1} group={props.group.groups[groupId]} />
|
||||
})}
|
||||
</>;
|
||||
}, [props, shipSnapShot]);
|
||||
|
||||
const header = <TreeHeader icon={props.group.iconID === undefined ? "" : `${defaultDataUrl}icons/${props.group.iconID}.png`} text={props.group.name} />;
|
||||
return <TreeListing level={props.level} header={header} getChildren={getChildren} />;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show all the modules you can fit to a ship.
|
||||
*/
|
||||
export const HardwareListing = () => {
|
||||
const eveData = React.useContext(EveDataContext);
|
||||
|
||||
const [moduleGroups, setModuleGroups] = React.useState<ListingGroup>({
|
||||
name: "Modules",
|
||||
meta: 0,
|
||||
groups: {},
|
||||
items: [],
|
||||
});
|
||||
const [search, setSearch] = React.useState<string>("");
|
||||
const [filter, setFilter] = React.useState({
|
||||
lowslot: false,
|
||||
medslot: false,
|
||||
hislot: false,
|
||||
rig_subsystem: false,
|
||||
drone: false,
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!eveData.loaded) return;
|
||||
|
||||
const newModuleGroups: ListingGroup = {
|
||||
name: "Modules",
|
||||
meta: 0,
|
||||
groups: {},
|
||||
items: [],
|
||||
};
|
||||
|
||||
for (const typeId in eveData.typeIDs) {
|
||||
const module = eveData.typeIDs[typeId];
|
||||
/* Modules (7), Drones (18), Subsystems (32), and Structures (66) */
|
||||
if (module.categoryID !== 7 && module.categoryID !== 18 && module.categoryID !== 32 && module.categoryID !== 66) continue;
|
||||
if (module.marketGroupID === undefined) continue;
|
||||
if (!module.published) continue;
|
||||
|
||||
let slotType: ShipSnapshotSlotsType | "dronebay" | undefined = eveData.typeDogma?.[typeId]?.dogmaEffects.map((effect) => {
|
||||
switch (effect.effectID) {
|
||||
case 11: return "lowslot";
|
||||
case 13: return "medslot";
|
||||
case 12: return "hislot";
|
||||
case 2663: return "rig";
|
||||
case 3772: return "subsystem";
|
||||
}
|
||||
}).filter((slot) => slot !== undefined)[0];
|
||||
if (module.categoryID === 18) {
|
||||
slotType = "dronebay";
|
||||
}
|
||||
|
||||
if (slotType === undefined) continue;
|
||||
|
||||
if (filter.lowslot && slotType !== "lowslot") continue;
|
||||
if (filter.medslot && slotType !== "medslot") continue;
|
||||
if (filter.hislot && slotType !== "hislot") continue;
|
||||
if (filter.rig_subsystem && slotType !== "rig" && slotType !== "subsystem") continue;
|
||||
if (filter.drone && module.categoryID !== 18) continue;
|
||||
|
||||
if (search !== "" && !module.name.toLowerCase().includes(search.toLowerCase())) continue;
|
||||
|
||||
const marketGroups: number[] = [];
|
||||
|
||||
switch (module.metaGroupID) {
|
||||
case 3: // Storyline
|
||||
case 4: // Faction
|
||||
marketGroups.push(-1);
|
||||
break;
|
||||
|
||||
case 5: // Officer
|
||||
marketGroups.push(-2);
|
||||
break;
|
||||
|
||||
case 6: // Deadspace
|
||||
marketGroups.push(-3);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Construct the tree of the module's market groups. */
|
||||
let marketGroup: number | undefined = module.marketGroupID;
|
||||
while (marketGroup !== undefined) {
|
||||
marketGroups.push(marketGroup);
|
||||
marketGroup = eveData.marketGroups?.[marketGroup].parentGroupID;
|
||||
}
|
||||
|
||||
/* Remove the root group. */
|
||||
marketGroups.pop();
|
||||
/* Put Drones and Structures in their own group. */
|
||||
if (module.categoryID === 18) marketGroups.push(157);
|
||||
if (module.categoryID === 66) marketGroups.push(477);
|
||||
|
||||
/* Build up the tree till the find the leaf node. */
|
||||
let groupTree = newModuleGroups;
|
||||
for (const group of marketGroups.reverse()) {
|
||||
if (groupTree.groups[group] === undefined) {
|
||||
let name;
|
||||
let meta;
|
||||
let iconID = undefined;
|
||||
switch (group) {
|
||||
case -1:
|
||||
name = "Faction & Storyline";
|
||||
iconID = 24146;
|
||||
meta = 3;
|
||||
break;
|
||||
|
||||
case -2:
|
||||
name = "Officer";
|
||||
iconID = 24149;
|
||||
meta = 5;
|
||||
break;
|
||||
|
||||
case -3:
|
||||
name = "Deadspace";
|
||||
iconID = 24148;
|
||||
meta = 6;
|
||||
break;
|
||||
|
||||
default:
|
||||
name = eveData.marketGroups?.[group].name ?? "Unknown group";
|
||||
meta = 1;
|
||||
iconID = eveData.marketGroups?.[group].iconID;
|
||||
break;
|
||||
}
|
||||
|
||||
groupTree.groups[group] = {
|
||||
name,
|
||||
meta,
|
||||
iconID,
|
||||
groups: {},
|
||||
items: [],
|
||||
};
|
||||
}
|
||||
|
||||
groupTree = groupTree.groups[group];
|
||||
}
|
||||
|
||||
groupTree.items.push({
|
||||
name: module.name,
|
||||
meta: module.metaGroupID ?? 0,
|
||||
typeId: parseInt(typeId),
|
||||
slotType,
|
||||
});
|
||||
}
|
||||
|
||||
setModuleGroups(newModuleGroups);
|
||||
}, [eveData, search, filter]);
|
||||
|
||||
return <div className={styles.listing}>
|
||||
<div className={styles.topbar}>
|
||||
<input type="text" placeholder="Search" value={search} onChange={(e) => setSearch(e.target.value)} />
|
||||
</div>
|
||||
<div className={styles.filter}>
|
||||
<span className={clsx({[styles.selected]: filter.lowslot})} onClick={() => setFilter({...filter, lowslot: !filter.lowslot})}>
|
||||
<Icon name="fitting-lowslot" size={32} title="Filter: Low Slot" />
|
||||
</span>
|
||||
<span className={clsx({[styles.selected]: filter.medslot})} onClick={() => setFilter({...filter, medslot: !filter.medslot})}>
|
||||
<Icon name="fitting-medslot" size={32} title="Filter: Mid Slot" />
|
||||
</span>
|
||||
<span className={clsx({[styles.selected]: filter.hislot})} onClick={() => setFilter({...filter, hislot: !filter.hislot})}>
|
||||
<Icon name="fitting-hislot" size={32} title="Filter: High Slot" />
|
||||
</span>
|
||||
<span className={clsx({[styles.selected]: filter.rig_subsystem})} onClick={() => setFilter({...filter, rig_subsystem: !filter.rig_subsystem})}>
|
||||
<Icon name="fitting-rig-subsystem" size={32} title="Filter: Rig & Subsystem Slots" />
|
||||
</span>
|
||||
<span className={clsx({[styles.selected]: filter.drone})} onClick={() => setFilter({...filter, drone: !filter.drone})}>
|
||||
<Icon name="fitting-drones" size={32} title="Filter: Drones" />
|
||||
</span>
|
||||
</div>
|
||||
<div className={styles.listingContent}>
|
||||
{Object.keys(moduleGroups.groups).sort((a, b) => moduleGroups.groups[a].name.localeCompare(moduleGroups.groups[b].name)).map((groupId) => {
|
||||
return <ModuleGroup key={groupId} level={1} group={moduleGroups.groups[groupId]} />
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
};
|
||||
1
src/HardwareListing/index.ts
Normal file
1
src/HardwareListing/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { HardwareListing } from "./HardwareListing";
|
||||
@@ -11,8 +11,13 @@ const iconMapping = {
|
||||
"fitting-alliance": "texture/classes/fitting/taballiancefits.png",
|
||||
"fitting-character": "texture/windowicons/member.png",
|
||||
"fitting-corporation": "texture/windowicons/corporation.png",
|
||||
"fitting-drones": "texture/classes/fitting/filtericondrones.png",
|
||||
"fitting-hislot": "texture/classes/fitting/filtericonhighslot.png",
|
||||
"fitting-hull": "texture/classes/fitting/tabfittings.png",
|
||||
"fitting-local": "texture/windowicons/note.png",
|
||||
"fitting-lowslot": "texture/classes/fitting/filtericonlowslot.png",
|
||||
"fitting-medslot": "texture/classes/fitting/filtericonmediumslot.png",
|
||||
"fitting-rig-subsystem": "texture/classes/fitting/filtericonrigslot.png",
|
||||
"hull-hp": "texture/classes/fitting/statsicons/structurehp.png",
|
||||
"hull-repair-rate": "texture/classes/fitting/statsicons/hullrepairrate.png",
|
||||
"inertia-modifier": "texture/classes/fitting/statsicons/inertiamodifier.png",
|
||||
|
||||
@@ -57,6 +57,7 @@ interface ShipSnapshot {
|
||||
|
||||
fit?: EsiFit;
|
||||
|
||||
addModule: (typeId: number, slot: ShipSnapshotSlotsType | "dronebay") => void;
|
||||
changeHull: (typeId: number) => void;
|
||||
changeFit: (fit: EsiFit) => void;
|
||||
setItemState: (flag: number, state: string) => void;
|
||||
@@ -71,11 +72,20 @@ export const ShipSnapshotContext = React.createContext<ShipSnapshot>({
|
||||
"subsystem": 0,
|
||||
"rig": 0,
|
||||
},
|
||||
addModule: () => {},
|
||||
changeHull: () => {},
|
||||
changeFit: () => {},
|
||||
setItemState: () => {},
|
||||
});
|
||||
|
||||
const slotStart: Record<ShipSnapshotSlotsType, number> = {
|
||||
"hislot": 27,
|
||||
"medslot": 19,
|
||||
"lowslot": 11,
|
||||
"subsystem": 125,
|
||||
"rig": 92,
|
||||
};
|
||||
|
||||
export interface ShipSnapshotProps {
|
||||
/** Children that can use this provider. */
|
||||
children: React.ReactNode;
|
||||
@@ -99,6 +109,7 @@ export const ShipSnapshotProvider = (props: ShipSnapshotProps) => {
|
||||
"subsystem": 0,
|
||||
"rig": 0,
|
||||
},
|
||||
addModule: () => {},
|
||||
changeHull: () => {},
|
||||
changeFit: () => {},
|
||||
setItemState: () => {},
|
||||
@@ -107,8 +118,6 @@ export const ShipSnapshotProvider = (props: ShipSnapshotProps) => {
|
||||
const dogmaEngine = React.useContext(DogmaEngineContext);
|
||||
|
||||
const setItemState = React.useCallback((flag: number, state: string) => {
|
||||
if (currentFit === undefined) return;
|
||||
|
||||
setCurrentFit((oldFit: EsiFit | undefined) => {
|
||||
if (oldFit === undefined) return undefined;
|
||||
|
||||
@@ -126,7 +135,42 @@ export const ShipSnapshotProvider = (props: ShipSnapshotProps) => {
|
||||
}),
|
||||
};
|
||||
})
|
||||
}, [currentFit]);
|
||||
}, []);
|
||||
|
||||
const addModule = React.useCallback((typeId: number, slot: ShipSnapshotSlotsType | "dronebay") => {
|
||||
setCurrentFit((oldFit: EsiFit | undefined) => {
|
||||
if (oldFit === undefined) return undefined;
|
||||
|
||||
let flag = 0;
|
||||
|
||||
/* Find the first free slot for that slot-type. */
|
||||
if (slot !== "dronebay") {
|
||||
for (let i = slotStart[slot]; i < slotStart[slot] + shipSnapshot.slots[slot]; i++) {
|
||||
if (oldFit.items.find((item) => item.flag === i) !== undefined) continue;
|
||||
|
||||
flag = i;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
flag = 87;
|
||||
}
|
||||
|
||||
/* Couldn't find a free slot. */
|
||||
if (flag === 0) return oldFit;
|
||||
|
||||
return {
|
||||
...oldFit,
|
||||
items: [
|
||||
...oldFit.items,
|
||||
{
|
||||
flag: flag,
|
||||
type_id: typeId,
|
||||
quantity: 1,
|
||||
}
|
||||
],
|
||||
};
|
||||
})
|
||||
}, [shipSnapshot.slots]);
|
||||
|
||||
const changeHull = React.useCallback((typeId: number) => {
|
||||
setCurrentFit({
|
||||
@@ -137,6 +181,16 @@ export const ShipSnapshotProvider = (props: ShipSnapshotProps) => {
|
||||
})
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
setShipSnapshot((oldSnapshot) => ({
|
||||
...oldSnapshot,
|
||||
addModule,
|
||||
changeHull,
|
||||
changeFit: setCurrentFit,
|
||||
setItemState,
|
||||
}));
|
||||
}, [addModule, changeHull, setItemState]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dogmaEngine.loaded) return;
|
||||
if (currentFit === undefined || props.skills === undefined) return;
|
||||
@@ -164,17 +218,17 @@ export const ShipSnapshotProvider = (props: ShipSnapshotProps) => {
|
||||
slots.lowslot += item.attributes.get(eveData?.attributeMapping?.lowSlotModifier || 0)?.value || 0;
|
||||
}
|
||||
|
||||
setShipSnapshot({
|
||||
loaded: true,
|
||||
hull: snapshot.hull,
|
||||
items: snapshot.items,
|
||||
slots,
|
||||
fit: currentFit,
|
||||
changeHull,
|
||||
changeFit: setCurrentFit,
|
||||
setItemState,
|
||||
setShipSnapshot((oldSnapshot) => {
|
||||
return {
|
||||
...oldSnapshot,
|
||||
loaded: true,
|
||||
hull: snapshot.hull,
|
||||
items: snapshot.items,
|
||||
slots,
|
||||
fit: currentFit,
|
||||
};
|
||||
});
|
||||
}, [eveData, dogmaEngine, currentFit, props.skills, changeHull, setItemState]);
|
||||
}, [eveData, dogmaEngine, currentFit, props.skills]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setCurrentFit(props.fit);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.header {
|
||||
display: flex;
|
||||
height: var(--height);
|
||||
padding: 2px 0;
|
||||
line-height: var(--height);
|
||||
padding: 2px 0;
|
||||
user-select: none;
|
||||
}
|
||||
.header > span {
|
||||
@@ -18,12 +18,13 @@
|
||||
|
||||
.headerText {
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.headerAction {
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
margin-right: 4px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.headerAction:hover {
|
||||
opacity: 1.0;
|
||||
|
||||
@@ -6,6 +6,7 @@ export * from './EveDataProvider';
|
||||
export * from './EveShipFitHash';
|
||||
export * from './EveShipFitLink';
|
||||
export * from './FormatEftToEsi';
|
||||
export * from './HardwareListing';
|
||||
export * from './HullListing';
|
||||
export * from './Icon';
|
||||
export * from './ShipAttribute';
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const defaultDataUrl = "https://data.eveship.fit/v4.1-20231115/";
|
||||
export const defaultDataUrl = "https://data.eveship.fit/v6.1-20231115/";
|
||||
|
||||
Reference in New Issue
Block a user