feat: show icons in statistics (#16)
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
"author": "Patric Stout <eveshipfit@truebrain.nl>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eveshipfit/dogma-engine": "^2.2.0",
|
||||
"@eveshipfit/dogma-engine": "^2.2.1",
|
||||
"clsx": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -61,7 +61,7 @@
|
||||
"typescript-plugin-css-modules": "^5.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@eveshipfit/dogma-engine": "^2.2.0",
|
||||
"@eveshipfit/dogma-engine": "^2.2.1",
|
||||
"react": "^18.2.0"
|
||||
},
|
||||
"main": "dist/cjs/index.js",
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import React from "react";
|
||||
|
||||
import { DogmaAttribute, DogmaEffect, TypeDogma, TypeID } from "./DataTypes";
|
||||
import { defaultDataUrl } from "../settings";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line import/extensions
|
||||
import * as esf_pb2 from "./esf_pb2.js";
|
||||
|
||||
const defaultDataUrl = "https://data.eveship.fit/20231115-0/";
|
||||
|
||||
interface DogmaData {
|
||||
loaded?: boolean;
|
||||
typeIDs?: Record<string, TypeID>;
|
||||
@@ -59,7 +58,7 @@ function isLoaded(dogmaData: DogmaData): boolean | undefined {
|
||||
* ```
|
||||
*/
|
||||
export const EveDataProvider = (props: DogmaDataProps) => {
|
||||
const dataUrl = props.dataUrl ?? defaultDataUrl;
|
||||
const dataUrl = props.dataUrl ?? `${defaultDataUrl}sde/`;
|
||||
const [dogmaData, setDogmaData] = React.useState<DogmaData>({});
|
||||
|
||||
React.useEffect(() => {
|
||||
|
||||
18
src/Icon/Icon.stories.tsx
Normal file
18
src/Icon/Icon.stories.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { Icon } from './';
|
||||
|
||||
const meta: Meta<typeof Icon> = {
|
||||
component: Icon,
|
||||
tags: ['autodocs'],
|
||||
title: 'Component/Icon',
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Icon>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
name: "em-resistance",
|
||||
},
|
||||
};
|
||||
45
src/Icon/Icon.tsx
Normal file
45
src/Icon/Icon.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import React from "react";
|
||||
|
||||
import { defaultDataUrl } from "../settings";
|
||||
|
||||
const iconMapping = {
|
||||
"align-time": "texture/classes/fitting/statsicons/aligntime.png",
|
||||
"armor-hp": "texture/classes/fitting/statsicons/armorhp.png",
|
||||
"armor-repair-rate": "texture/classes/fitting/statsicons/armorrepairrate.png",
|
||||
"em-resistance": "texture/classes/fitting/statsicons/emresistance.png",
|
||||
"explosive-resistance": "texture/classes/fitting/statsicons/explosiveresistance.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",
|
||||
"kinetic-resistance": "texture/classes/fitting/statsicons/kineticresistance.png",
|
||||
"mass": "texture/classes/fitting/statsicons/mass.png",
|
||||
"maximum-locked-targets": "texture/classes/fitting/statsicons/maximumlockedtargets.png",
|
||||
"passive-shield-recharge": "texture/classes/fitting/statsicons/passiveshieldrecharge.png",
|
||||
"scan-resolution": "texture/classes/fitting/statsicons/scanresolution.png",
|
||||
"sensor-strength": "texture/classes/fitting/statsicons/sensorstrength.png",
|
||||
"shield-boost-rate": "texture/classes/fitting/statsicons/shieldboostrate.png",
|
||||
"shield-hp": "texture/classes/fitting/statsicons/shieldhp.png",
|
||||
"signature-radius": "texture/classes/fitting/statsicons/signatureradius.png",
|
||||
"thermal-resistance": "texture/classes/fitting/statsicons/thermalresistance.png",
|
||||
"warp-speed": "texture/classes/fitting/statsicons/warpspeed.png",
|
||||
} as const;
|
||||
|
||||
export type IconName = keyof typeof iconMapping;
|
||||
|
||||
export interface IconProps {
|
||||
/** Name of the icon. */
|
||||
name: IconName;
|
||||
/** Size (in pixels) of the icon. */
|
||||
size?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a single attribute of a ship's snapshot.
|
||||
*/
|
||||
export const Icon = (props: IconProps) => {
|
||||
const icon = iconMapping[props.name];
|
||||
if (icon === undefined) {
|
||||
return <span>Unknown icon: {props.name}</span>;
|
||||
}
|
||||
return <img src={`${defaultDataUrl}ui/${icon}`} width={props.size} />
|
||||
};
|
||||
1
src/Icon/index.ts
Normal file
1
src/Icon/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { type IconName, Icon } from "./Icon";
|
||||
@@ -4,21 +4,32 @@ import { useShipAttribute } from '../ShipAttribute';
|
||||
|
||||
import styles from "./ShipStatistics.module.css";
|
||||
import clsx from "clsx";
|
||||
import { IconName, Icon } from "../Icon";
|
||||
|
||||
export const RechargeRateItem = (props: {name: string, icon: React.ReactNode}) => {
|
||||
export const RechargeRateItem = (props: {name: string, icon: IconName}) => {
|
||||
const stringValue = useShipAttribute({
|
||||
name: props.name,
|
||||
fixed: 1,
|
||||
});
|
||||
|
||||
if (stringValue == "0.0") {
|
||||
return <span>
|
||||
{props.icon} No Module
|
||||
return <span className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name={props.icon} size={24} />
|
||||
</span>
|
||||
<span>
|
||||
No Module
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
|
||||
return <span>
|
||||
{props.icon} {stringValue} hp/s
|
||||
return <span className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name={props.icon} size={24} />
|
||||
</span>
|
||||
<span>
|
||||
{stringValue} hp/s
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
|
||||
@@ -37,10 +48,10 @@ export const RechargeRate = () => {
|
||||
<div onClick={() => { setModuleType("shieldBoostRate"); setShowDropdown(false); }} className={clsx({[styles.rechargeRateDropdownContentSelected]: moduleType == "shieldBoostRate"})}>Shield boost rate</div>
|
||||
</div> }
|
||||
<div onClick={() => setShowDropdown((current) => !current)}>
|
||||
{ moduleType == "armorRepairRate" && <RechargeRateItem name="armorRepairRate" icon={<>A</>} /> }
|
||||
{ moduleType == "hullRepairRate" && <RechargeRateItem name="hullRepairRate" icon={<>H</>} /> }
|
||||
{ moduleType == "passiveShieldRecharge" && <RechargeRateItem name="passiveShieldRecharge" icon={<>P</>} /> }
|
||||
{ moduleType == "shieldBoostRate" && <RechargeRateItem name="shieldBoostRate" icon={<>S</>} /> }
|
||||
{ moduleType == "armorRepairRate" && <RechargeRateItem name="armorRepairRate" icon="armor-repair-rate" /> }
|
||||
{ moduleType == "hullRepairRate" && <RechargeRateItem name="hullRepairRate" icon="hull-repair-rate" /> }
|
||||
{ moduleType == "passiveShieldRecharge" && <RechargeRateItem name="passiveShieldRecharge" icon="passive-shield-recharge" /> }
|
||||
{ moduleType == "shieldBoostRate" && <RechargeRateItem name="shieldBoostRate" icon="shield-boost-rate" /> }
|
||||
</div>
|
||||
</span>
|
||||
}
|
||||
|
||||
@@ -42,27 +42,38 @@
|
||||
margin: 0px 5px;
|
||||
}
|
||||
|
||||
.statistic {
|
||||
display: flex;
|
||||
}
|
||||
.statistic > span:last-child {
|
||||
line-height: 24px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.defense {
|
||||
margin: 20px 0px;
|
||||
}
|
||||
.defense:last-child {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.defenseShield {
|
||||
display: flex;
|
||||
position: relative;
|
||||
top: -5px;
|
||||
}
|
||||
.defenseShield > span:first-child {
|
||||
line-height: 30px;
|
||||
}
|
||||
.defenseShield > span:first-child > img {
|
||||
padding-top: 4px;
|
||||
}
|
||||
.defenseShield > span:last-child {
|
||||
line-height: 15px;
|
||||
}
|
||||
|
||||
.resistanceHeader {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
margin-left: 5px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
import { ShipAttribute } from '../ShipAttribute';
|
||||
@@ -7,6 +8,7 @@ import { RechargeRate } from "./RechargeRate";
|
||||
import { Resistance } from "./Resistance";
|
||||
|
||||
import styles from "./ShipStatistics.module.css";
|
||||
import { Icon } from "../Icon";
|
||||
|
||||
/**
|
||||
* Render ship statistics similar to how it is done in-game.
|
||||
@@ -47,16 +49,16 @@ export const ShipStatistics = () => {
|
||||
<CategoryLine>
|
||||
<RechargeRate />
|
||||
<span style={{flex: 2}}>
|
||||
<span className={styles.resistanceHeader}>E</span>
|
||||
<span className={styles.resistanceHeader}>T</span>
|
||||
<span className={styles.resistanceHeader}>K</span>
|
||||
<span className={styles.resistanceHeader}>X</span>
|
||||
<span className={styles.resistanceHeader}><Icon name="em-resistance" size={28} /></span>
|
||||
<span className={styles.resistanceHeader}><Icon name="thermal-resistance" size={28} /></span>
|
||||
<span className={styles.resistanceHeader}><Icon name="kinetic-resistance" size={28} /></span>
|
||||
<span className={styles.resistanceHeader}><Icon name="explosive-resistance" size={28} /></span>
|
||||
</span>
|
||||
</CategoryLine>
|
||||
<CategoryLine className={styles.defense}>
|
||||
<span className={styles.defenseShield}>
|
||||
<span className={clsx(styles.statistic, styles.defenseShield)}>
|
||||
<span>
|
||||
S
|
||||
<Icon name="shield-hp" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="shieldCapacity" fixed={0} /> hp<br/>
|
||||
@@ -71,9 +73,13 @@ export const ShipStatistics = () => {
|
||||
</span>
|
||||
</CategoryLine>
|
||||
<CategoryLine className={styles.defense}>
|
||||
<span>
|
||||
A
|
||||
<ShipAttribute name="armorHP" fixed={0} /> hp
|
||||
<span className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name="armor-hp" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="armorHP" fixed={0} /> hp
|
||||
</span>
|
||||
</span>
|
||||
<span style={{flex: 2}}>
|
||||
<Resistance name="armorEmDamageResonance" />
|
||||
@@ -83,9 +89,13 @@ export const ShipStatistics = () => {
|
||||
</span>
|
||||
</CategoryLine>
|
||||
<CategoryLine className={styles.defense}>
|
||||
<span>
|
||||
S
|
||||
<ShipAttribute name="hp" fixed={0} /> hp
|
||||
<span className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name="hull-hp" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="hp" fixed={0} /> hp
|
||||
</span>
|
||||
</span>
|
||||
<span style={{flex: 2}}>
|
||||
<Resistance name="emDamageResonance" />
|
||||
@@ -100,19 +110,39 @@ export const ShipStatistics = () => {
|
||||
<span><ShipAttribute name="maxTargetRange" fixed={2} divideBy={1000} /> km</span>
|
||||
}>
|
||||
<CategoryLine>
|
||||
<span title="Scan Strength">
|
||||
<ShipAttribute name="scanStrength" fixed={2} /> points
|
||||
<span title="Scan Strength" className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name="sensor-strength" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="scanStrength" fixed={2} /> points
|
||||
</span>
|
||||
</span>
|
||||
<span title="Scan Resolution">
|
||||
<ShipAttribute name="scanResolution" fixed={0} /> mm
|
||||
<span title="Scan Resolution" className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name="scan-resolution" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="scanResolution" fixed={0} /> mm
|
||||
</span>
|
||||
</span>
|
||||
</CategoryLine>
|
||||
<CategoryLine>
|
||||
<span title="Signature Radius">
|
||||
<ShipAttribute name="signatureRadius" fixed={0} /> m
|
||||
<span title="Signature Radius" className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name="signature-radius" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="signatureRadius" fixed={0} /> m
|
||||
</span>
|
||||
</span>
|
||||
<span title="Maximum Locked Targets">
|
||||
<ShipAttribute name="maxLockedTargets" fixed={0} />x
|
||||
<span title="Maximum Locked Targets" className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name="maximum-locked-targets" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="maxLockedTargets" fixed={0} />x
|
||||
</span>
|
||||
</span>
|
||||
</CategoryLine>
|
||||
</Category>
|
||||
@@ -121,19 +151,39 @@ export const ShipStatistics = () => {
|
||||
<span><ShipAttribute name="maxVelocity" fixed={1} /> m/s</span>
|
||||
}>
|
||||
<CategoryLine>
|
||||
<span title="Mass">
|
||||
<ShipAttribute name="mass" fixed={2} /> t
|
||||
<span title="Mass" className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name="mass" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="mass" fixed={2} /> t
|
||||
</span>
|
||||
</span>
|
||||
<span title="Inertia Modifier">
|
||||
<ShipAttribute name="agility" fixed={4} />x
|
||||
<span title="Inertia Modifier" className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name="inertia-modifier" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="agility" fixed={4} />x
|
||||
</span>
|
||||
</span>
|
||||
</CategoryLine>
|
||||
<CategoryLine>
|
||||
<span title="Ship Warp Speed">
|
||||
<ShipAttribute name="warpSpeedMultiplier" fixed={2} /> AU/s
|
||||
<span title="Ship Warp Speed" className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name="warp-speed" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="warpSpeedMultiplier" fixed={2} /> AU/s
|
||||
</span>
|
||||
</span>
|
||||
<span title="Align Time">
|
||||
<ShipAttribute name="alignTime" fixed={2} />s
|
||||
<span title="Align Time" className={styles.statistic}>
|
||||
<span>
|
||||
<Icon name="align-time" size={24} />
|
||||
</span>
|
||||
<span>
|
||||
<ShipAttribute name="alignTime" fixed={2} />s
|
||||
</span>
|
||||
</span>
|
||||
</CategoryLine>
|
||||
</Category>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from './DogmaEngineProvider';
|
||||
export * from './EveDataProvider';
|
||||
export * from './FormatEftToEsi';
|
||||
export * from './Icon';
|
||||
export * from './ShipAttribute';
|
||||
export * from './ShipFit';
|
||||
export * from './ShipFitExtended';
|
||||
|
||||
1
src/settings.ts
Normal file
1
src/settings.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const defaultDataUrl = "https://data.eveship.fit/v1.1-20231115/";
|
||||
Reference in New Issue
Block a user