mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-12-12 02:35:42 +00:00
refactor: additional design feedback improvements
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { zkillLink } from '../helpers';
|
||||||
|
import classes from './SystemKillRow.module.scss';
|
||||||
|
|
||||||
|
interface AttackerRowSubInfoProps {
|
||||||
|
finalBlowCharId: number | null | undefined;
|
||||||
|
finalBlowCharName?: string;
|
||||||
|
attackerPortraitUrl: string | null;
|
||||||
|
|
||||||
|
finalBlowCorpId: number | null | undefined;
|
||||||
|
finalBlowCorpName?: string;
|
||||||
|
attackerCorpLogoUrl: string | null;
|
||||||
|
|
||||||
|
finalBlowAllianceId: number | null | undefined;
|
||||||
|
finalBlowAllianceName?: string;
|
||||||
|
attackerAllianceLogoUrl: string | null;
|
||||||
|
|
||||||
|
containerHeight?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AttackerRowSubInfo: React.FC<AttackerRowSubInfoProps> = ({
|
||||||
|
finalBlowCharId = 0,
|
||||||
|
finalBlowCharName,
|
||||||
|
attackerPortraitUrl,
|
||||||
|
containerHeight = 8,
|
||||||
|
}) => {
|
||||||
|
if (!attackerPortraitUrl || finalBlowCharId === null || finalBlowCharId <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const containerClass = `h-${containerHeight}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx('flex items-start gap-1', containerClass)}>
|
||||||
|
<div className="relative shrink-0 w-auto h-full overflow-hidden">
|
||||||
|
<a
|
||||||
|
href={zkillLink('character', finalBlowCharId)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="block h-full"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={attackerPortraitUrl}
|
||||||
|
alt={finalBlowCharName || 'AttackerPortrait'}
|
||||||
|
className={clsx(classes.killRowImage, 'h-full w-auto object-contain')}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -7,9 +7,13 @@ import {
|
|||||||
zkillLink,
|
zkillLink,
|
||||||
getAttackerSubscript,
|
getAttackerSubscript,
|
||||||
buildVictimImageUrls,
|
buildVictimImageUrls,
|
||||||
buildAttackerShipUrl,
|
buildAttackerImageUrls,
|
||||||
|
getPrimaryLogoAndTooltip,
|
||||||
|
getAttackerPrimaryImageAndTooltip,
|
||||||
} from '../helpers';
|
} from '../helpers';
|
||||||
|
import { WdTooltipWrapper } from '../../../../ui-kit/WdTooltipWrapper';
|
||||||
import classes from './SystemKillRow.module.scss';
|
import classes from './SystemKillRow.module.scss';
|
||||||
|
import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
|
||||||
export interface CompactKillRowProps {
|
export interface CompactKillRowProps {
|
||||||
killDetails: DetailedKill;
|
killDetails: DetailedKill;
|
||||||
@@ -19,44 +23,69 @@ export interface CompactKillRowProps {
|
|||||||
|
|
||||||
export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, systemName, onlyOneSystem }) => {
|
export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, systemName, onlyOneSystem }) => {
|
||||||
const {
|
const {
|
||||||
killmail_id,
|
killmail_id = 0,
|
||||||
|
|
||||||
victim_char_name = 'Unknown Pilot',
|
victim_char_name = 'Unknown Pilot',
|
||||||
|
victim_alliance_ticker = '',
|
||||||
|
victim_corp_ticker = '',
|
||||||
victim_ship_name = 'Unknown Ship',
|
victim_ship_name = 'Unknown Ship',
|
||||||
victim_alliance_ticker,
|
victim_corp_name = '',
|
||||||
victim_corp_ticker,
|
victim_alliance_name = '',
|
||||||
victim_char_id,
|
victim_char_id = 0,
|
||||||
victim_corp_id,
|
victim_corp_id = 0,
|
||||||
victim_alliance_id,
|
victim_alliance_id = 0,
|
||||||
victim_ship_type_id,
|
victim_ship_type_id = 0,
|
||||||
|
|
||||||
final_blow_char_id,
|
final_blow_char_id = 0,
|
||||||
final_blow_char_name = '',
|
final_blow_char_name = '',
|
||||||
final_blow_alliance_ticker,
|
final_blow_alliance_ticker = '',
|
||||||
final_blow_corp_ticker,
|
final_blow_alliance_name = '',
|
||||||
final_blow_ship_type_id,
|
final_blow_alliance_id = 0,
|
||||||
|
final_blow_corp_ticker = '',
|
||||||
|
final_blow_corp_id = 0,
|
||||||
|
final_blow_corp_name = '',
|
||||||
|
final_blow_ship_type_id = 0,
|
||||||
|
|
||||||
kill_time,
|
kill_time = '',
|
||||||
total_value,
|
total_value = 0,
|
||||||
} = killDetails;
|
} = killDetails || {};
|
||||||
|
|
||||||
const attackerIsNpc = final_blow_char_id == null;
|
|
||||||
|
|
||||||
|
const attackerIsNpc = final_blow_char_id === 0;
|
||||||
const victimAffiliationTicker = victim_alliance_ticker || victim_corp_ticker || 'No Ticker';
|
const victimAffiliationTicker = victim_alliance_ticker || victim_corp_ticker || 'No Ticker';
|
||||||
const killValueFormatted = total_value && total_value > 0 ? `${formatISK(total_value)} ISK` : null;
|
const killValueFormatted = total_value != null && total_value > 0 ? `${formatISK(total_value)} ISK` : null;
|
||||||
|
|
||||||
const attackerName = attackerIsNpc ? '' : final_blow_char_name;
|
const attackerName = attackerIsNpc ? '' : final_blow_char_name;
|
||||||
const attackerTicker = attackerIsNpc ? '' : final_blow_alliance_ticker || final_blow_corp_ticker || '';
|
const attackerTicker = attackerIsNpc ? '' : final_blow_alliance_ticker || final_blow_corp_ticker || '';
|
||||||
|
|
||||||
const killTimeAgo = kill_time ? formatTimeMixed(kill_time) : '0h ago';
|
const killTimeAgo = kill_time ? formatTimeMixed(kill_time) : '0h ago';
|
||||||
const attackerSubscript = getAttackerSubscript(killDetails);
|
const attackerSubscript = getAttackerSubscript(killDetails);
|
||||||
|
|
||||||
const { victimShipUrl } = buildVictimImageUrls({
|
const { victimCorpLogoUrl, victimAllianceLogoUrl } = buildVictimImageUrls({
|
||||||
victim_char_id,
|
victim_char_id,
|
||||||
victim_ship_type_id,
|
victim_ship_type_id,
|
||||||
victim_corp_id,
|
victim_corp_id,
|
||||||
victim_alliance_id,
|
victim_alliance_id,
|
||||||
});
|
});
|
||||||
const finalBlowShipUrl = buildAttackerShipUrl(final_blow_ship_type_id);
|
const { attackerCorpLogoUrl, attackerAllianceLogoUrl } = buildAttackerImageUrls({
|
||||||
|
final_blow_char_id,
|
||||||
|
final_blow_corp_id,
|
||||||
|
final_blow_alliance_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { url: victimPrimaryLogoUrl, tooltip: victimPrimaryTooltip } = getPrimaryLogoAndTooltip(
|
||||||
|
victimAllianceLogoUrl,
|
||||||
|
victimCorpLogoUrl,
|
||||||
|
victim_alliance_name,
|
||||||
|
victim_corp_name,
|
||||||
|
'Victim',
|
||||||
|
);
|
||||||
|
|
||||||
|
const { url: attackerPrimaryImageUrl, tooltip: attackerPrimaryTooltip } = getAttackerPrimaryImageAndTooltip(
|
||||||
|
attackerIsNpc,
|
||||||
|
attackerAllianceLogoUrl,
|
||||||
|
attackerCorpLogoUrl,
|
||||||
|
final_blow_alliance_name,
|
||||||
|
final_blow_corp_name,
|
||||||
|
final_blow_ship_type_id || 0,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -65,15 +94,21 @@ export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, sys
|
|||||||
'text-xs whitespace-nowrap overflow-hidden leading-none',
|
'text-xs whitespace-nowrap overflow-hidden leading-none',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{victimShipUrl && (
|
{victimPrimaryLogoUrl && (
|
||||||
|
<WdTooltipWrapper content={victimPrimaryTooltip} position={TooltipPosition.top}>
|
||||||
<a
|
<a
|
||||||
href={zkillLink('kill', killmail_id)}
|
href={zkillLink('kill', killmail_id)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="relative shrink-0 w-8 h-8 overflow-hidden"
|
className="relative shrink-0 w-8 h-8 overflow-hidden"
|
||||||
>
|
>
|
||||||
<img src={victimShipUrl} alt="VictimShip" className={clsx(classes.killRowImage, 'w-full h-full')} />
|
<img
|
||||||
|
src={victimPrimaryLogoUrl}
|
||||||
|
alt="VictimPrimaryLogo"
|
||||||
|
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
|
</WdTooltipWrapper>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex flex-col ml-2 min-w-0 overflow-hidden leading-[1rem]">
|
<div className="flex flex-col ml-2 min-w-0 overflow-hidden leading-[1rem]">
|
||||||
@@ -111,14 +146,19 @@ export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, sys
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{finalBlowShipUrl && (
|
{attackerPrimaryImageUrl && (
|
||||||
|
<WdTooltipWrapper content={attackerPrimaryTooltip} position={TooltipPosition.top}>
|
||||||
<a
|
<a
|
||||||
href={zkillLink('kill', killmail_id)}
|
href={zkillLink('kill', killmail_id)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="relative shrink-0 w-8 h-8 overflow-hidden"
|
className="relative shrink-0 w-8 h-8 overflow-hidden"
|
||||||
>
|
>
|
||||||
<img src={finalBlowShipUrl} alt="AttackerShip" className={clsx(classes.killRowImage, 'w-full h-full')} />
|
<img
|
||||||
|
src={attackerPrimaryImageUrl}
|
||||||
|
alt={attackerIsNpc ? 'NpcShip' : 'AttackerPrimaryLogo'}
|
||||||
|
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
|
||||||
|
/>
|
||||||
{attackerSubscript && (
|
{attackerSubscript && (
|
||||||
<span
|
<span
|
||||||
className={clsx(
|
className={clsx(
|
||||||
@@ -132,6 +172,7 @@ export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, sys
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</a>
|
</a>
|
||||||
|
</WdTooltipWrapper>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
|
// FullKillRow.tsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { DetailedKill } from '@/hooks/Mapper/types/kills';
|
import { DetailedKill } from '@/hooks/Mapper/types/kills';
|
||||||
import { KillRowSubInfo } from './KillRowSubInfo';
|
|
||||||
import {
|
import {
|
||||||
formatISK,
|
formatISK,
|
||||||
formatTimeMixed,
|
formatTimeMixed,
|
||||||
zkillLink,
|
zkillLink,
|
||||||
getAttackerSubscript,
|
getAttackerSubscript,
|
||||||
buildVictimImageUrls,
|
buildVictimImageUrls,
|
||||||
buildAttackerShipUrl,
|
buildAttackerImageUrls,
|
||||||
|
getPrimaryLogoAndTooltip,
|
||||||
|
getAttackerPrimaryImageAndTooltip,
|
||||||
} from '../helpers';
|
} from '../helpers';
|
||||||
|
import { VictimRowSubInfo } from './VictimRowSubInfo';
|
||||||
|
import { WdTooltipWrapper } from '../../../../ui-kit/WdTooltipWrapper';
|
||||||
import classes from './SystemKillRow.module.scss';
|
import classes from './SystemKillRow.module.scss';
|
||||||
|
import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||||
|
|
||||||
export interface FullKillRowProps {
|
export interface FullKillRowProps {
|
||||||
killDetails: DetailedKill;
|
killDetails: DetailedKill;
|
||||||
@@ -20,50 +25,79 @@ export interface FullKillRowProps {
|
|||||||
|
|
||||||
export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemName, onlyOneSystem }) => {
|
export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemName, onlyOneSystem }) => {
|
||||||
const {
|
const {
|
||||||
killmail_id,
|
killmail_id = 0,
|
||||||
|
|
||||||
victim_char_name = '',
|
victim_char_name = '',
|
||||||
victim_alliance_ticker,
|
victim_alliance_ticker = '',
|
||||||
victim_corp_ticker,
|
victim_corp_ticker = '',
|
||||||
victim_ship_name = '',
|
victim_ship_name = '',
|
||||||
victim_char_id,
|
victim_char_id = 0,
|
||||||
victim_corp_id,
|
victim_corp_id = 0,
|
||||||
victim_alliance_id,
|
victim_alliance_id = 0,
|
||||||
victim_ship_type_id,
|
victim_ship_type_id = 0,
|
||||||
|
victim_corp_name = '',
|
||||||
|
victim_alliance_name = '',
|
||||||
|
|
||||||
total_value,
|
final_blow_char_id = 0,
|
||||||
kill_time,
|
|
||||||
|
|
||||||
final_blow_char_id,
|
|
||||||
final_blow_char_name = '',
|
final_blow_char_name = '',
|
||||||
final_blow_alliance_ticker,
|
final_blow_alliance_ticker = '',
|
||||||
final_blow_corp_ticker,
|
final_blow_corp_ticker = '',
|
||||||
|
final_blow_corp_name = '',
|
||||||
|
final_blow_alliance_name = '',
|
||||||
|
final_blow_corp_id = 0,
|
||||||
|
final_blow_alliance_id = 0,
|
||||||
final_blow_ship_name = '',
|
final_blow_ship_name = '',
|
||||||
final_blow_ship_type_id,
|
final_blow_ship_type_id = 0,
|
||||||
} = killDetails;
|
|
||||||
|
|
||||||
const attackerIsNpc = final_blow_char_id == null;
|
total_value = 0,
|
||||||
|
kill_time = '',
|
||||||
|
} = killDetails || {};
|
||||||
|
|
||||||
const victimAffiliation = victim_alliance_ticker || victim_corp_ticker || '';
|
const attackerIsNpc = final_blow_char_id === 0;
|
||||||
|
const victimAffiliation = victim_alliance_ticker || victim_corp_ticker;
|
||||||
const attackerAffiliation = attackerIsNpc ? '' : final_blow_alliance_ticker || final_blow_corp_ticker || '';
|
const attackerAffiliation = attackerIsNpc ? '' : final_blow_alliance_ticker || final_blow_corp_ticker || '';
|
||||||
|
|
||||||
const killValueFormatted = total_value && total_value > 0 ? `${formatISK(total_value)} ISK` : null;
|
const killValueFormatted = total_value !== null && total_value > 0 ? `${formatISK(total_value)} ISK` : null;
|
||||||
const killTimeAgo = kill_time ? formatTimeMixed(kill_time) : '0h ago';
|
const killTimeAgo = kill_time ? formatTimeMixed(kill_time) : '0h ago';
|
||||||
|
|
||||||
const { victimPortraitUrl, victimCorpLogoUrl, victimAllianceLogoUrl, victimShipUrl } = buildVictimImageUrls({
|
const { victimPortraitUrl, victimCorpLogoUrl, victimAllianceLogoUrl } = buildVictimImageUrls({
|
||||||
victim_char_id,
|
victim_char_id,
|
||||||
victim_ship_type_id,
|
victim_ship_type_id,
|
||||||
victim_corp_id,
|
victim_corp_id,
|
||||||
victim_alliance_id,
|
victim_alliance_id,
|
||||||
});
|
});
|
||||||
|
const { attackerPortraitUrl, attackerCorpLogoUrl, attackerAllianceLogoUrl } = buildAttackerImageUrls({
|
||||||
|
final_blow_char_id,
|
||||||
|
final_blow_corp_id,
|
||||||
|
final_blow_alliance_id,
|
||||||
|
});
|
||||||
|
|
||||||
const finalBlowShipUrl = buildAttackerShipUrl(final_blow_ship_type_id);
|
const { url: victimPrimaryImageUrl, tooltip: victimPrimaryTooltip } = getPrimaryLogoAndTooltip(
|
||||||
|
victimAllianceLogoUrl,
|
||||||
|
victimCorpLogoUrl,
|
||||||
|
victim_alliance_name,
|
||||||
|
victim_corp_name,
|
||||||
|
'Victim',
|
||||||
|
);
|
||||||
|
|
||||||
|
const { url: attackerPrimaryImageUrl, tooltip: attackerPrimaryTooltip } = getAttackerPrimaryImageAndTooltip(
|
||||||
|
attackerIsNpc,
|
||||||
|
attackerAllianceLogoUrl,
|
||||||
|
attackerCorpLogoUrl,
|
||||||
|
final_blow_alliance_name,
|
||||||
|
final_blow_corp_name,
|
||||||
|
final_blow_ship_type_id || 0,
|
||||||
|
);
|
||||||
|
|
||||||
const attackerSubscript = getAttackerSubscript(killDetails);
|
const attackerSubscript = getAttackerSubscript(killDetails);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(classes.killRowContainer, 'h-18 w-full justify-between items-start text-sm py-[4px]')}>
|
<div className={clsx(classes.killRowContainer, 'h-18 w-full justify-between items-start text-sm py-[4px]')}>
|
||||||
|
{/* ---------------- Victim Side ---------------- */}
|
||||||
<div className="flex items-start gap-1 min-w-0 h-full">
|
<div className="flex items-start gap-1 min-w-0 h-full">
|
||||||
{victimShipUrl && (
|
{/* Victim top-level logo (corp or alliance), with tooltip */}
|
||||||
|
{victimPrimaryImageUrl && (
|
||||||
|
<WdTooltipWrapper content={victimPrimaryTooltip} position={TooltipPosition.top}>
|
||||||
<div className="relative shrink-0 w-14 h-14 overflow-hidden">
|
<div className="relative shrink-0 w-14 h-14 overflow-hidden">
|
||||||
<a
|
<a
|
||||||
href={zkillLink('kill', killmail_id)}
|
href={zkillLink('kill', killmail_id)}
|
||||||
@@ -71,22 +105,20 @@ export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemNam
|
|||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="block w-full h-full"
|
className="block w-full h-full"
|
||||||
>
|
>
|
||||||
<img src={victimShipUrl} alt="VictimShip" className={clsx(classes.killRowImage, 'w-full h-full')} />
|
<img
|
||||||
|
src={victimPrimaryImageUrl}
|
||||||
|
alt="VictimPrimaryLogo"
|
||||||
|
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</WdTooltipWrapper>
|
||||||
)}
|
)}
|
||||||
|
<VictimRowSubInfo
|
||||||
<div className="flex items-start h-14 gap-1 shrink-0">
|
victimCharName={victim_char_name}
|
||||||
<KillRowSubInfo
|
|
||||||
victimCorpId={victim_corp_id}
|
|
||||||
victimCorpLogoUrl={victimCorpLogoUrl}
|
|
||||||
victimAllianceId={victim_alliance_id}
|
|
||||||
victimAllianceLogoUrl={victimAllianceLogoUrl}
|
|
||||||
victimCharacterId={victim_char_id}
|
victimCharacterId={victim_char_id}
|
||||||
victimPortraitUrl={victimPortraitUrl}
|
victimPortraitUrl={victimPortraitUrl}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col text-stone-200 leading-4 min-w-0 overflow-hidden">
|
<div className="flex flex-col text-stone-200 leading-4 min-w-0 overflow-hidden">
|
||||||
<div className="truncate">
|
<div className="truncate">
|
||||||
<span className="font-semibold">{victim_char_name}</span>
|
<span className="font-semibold">{victim_char_name}</span>
|
||||||
@@ -105,7 +137,7 @@ export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemNam
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-start gap-2 min-w-0 h-full">
|
<div className="flex items-start gap-1 min-w-0 h-full">
|
||||||
<div className="flex flex-col items-end leading-4 min-w-0 overflow-hidden text-right">
|
<div className="flex flex-col items-end leading-4 min-w-0 overflow-hidden text-right">
|
||||||
{!attackerIsNpc && (
|
{!attackerIsNpc && (
|
||||||
<div className="truncate font-semibold">
|
<div className="truncate font-semibold">
|
||||||
@@ -118,7 +150,26 @@ export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemNam
|
|||||||
)}
|
)}
|
||||||
<div className="truncate text-red-400">{killTimeAgo}</div>
|
<div className="truncate text-red-400">{killTimeAgo}</div>
|
||||||
</div>
|
</div>
|
||||||
{finalBlowShipUrl && (
|
|
||||||
|
{!attackerIsNpc && attackerPortraitUrl && final_blow_char_id !== null && final_blow_char_id > 0 && (
|
||||||
|
<div className="relative shrink-0 w-14 h-14 overflow-hidden">
|
||||||
|
<a
|
||||||
|
href={zkillLink('character', final_blow_char_id)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="block w-full h-full"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={attackerPortraitUrl}
|
||||||
|
alt="AttackerPortrait"
|
||||||
|
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{attackerPrimaryImageUrl && (
|
||||||
|
<WdTooltipWrapper content={attackerPrimaryTooltip} position={TooltipPosition.top}>
|
||||||
<div className="relative shrink-0 w-14 h-14 overflow-hidden">
|
<div className="relative shrink-0 w-14 h-14 overflow-hidden">
|
||||||
<a
|
<a
|
||||||
href={zkillLink('kill', killmail_id)}
|
href={zkillLink('kill', killmail_id)}
|
||||||
@@ -126,7 +177,11 @@ export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemNam
|
|||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="block w-full h-full"
|
className="block w-full h-full"
|
||||||
>
|
>
|
||||||
<img src={finalBlowShipUrl} alt="AttackerShip" className={clsx(classes.killRowImage, 'w-full h-full')} />
|
<img
|
||||||
|
src={attackerPrimaryImageUrl}
|
||||||
|
alt={attackerIsNpc ? 'NpcShip' : 'AttackerPrimaryLogo'}
|
||||||
|
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
|
||||||
|
/>
|
||||||
{attackerSubscript && (
|
{attackerSubscript && (
|
||||||
<span className={clsx(attackerSubscript.cssClass, classes.attackerCountLabel)}>
|
<span className={clsx(attackerSubscript.cssClass, classes.attackerCountLabel)}>
|
||||||
{attackerSubscript.label}
|
{attackerSubscript.label}
|
||||||
@@ -134,6 +189,7 @@ export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemNam
|
|||||||
)}
|
)}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</WdTooltipWrapper>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import { zkillLink } from '../helpers';
|
|
||||||
import classes from './SystemKillRow.module.scss';
|
|
||||||
|
|
||||||
interface KillRowSubInfoProps {
|
|
||||||
victimCorpId: number | null | undefined;
|
|
||||||
victimCorpLogoUrl: string | null;
|
|
||||||
victimAllianceId: number | null | undefined;
|
|
||||||
victimAllianceLogoUrl: string | null;
|
|
||||||
victimCharacterId: number | null | undefined;
|
|
||||||
victimPortraitUrl: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const KillRowSubInfo: React.FC<KillRowSubInfoProps> = ({
|
|
||||||
victimCorpId,
|
|
||||||
victimCorpLogoUrl,
|
|
||||||
victimAllianceId,
|
|
||||||
victimAllianceLogoUrl,
|
|
||||||
victimCharacterId,
|
|
||||||
victimPortraitUrl,
|
|
||||||
}) => {
|
|
||||||
const hasAnything = victimPortraitUrl || victimCorpLogoUrl || victimAllianceLogoUrl;
|
|
||||||
|
|
||||||
if (!hasAnything) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex items-start gap-1 h-full">
|
|
||||||
{victimPortraitUrl && victimCharacterId && (
|
|
||||||
<a
|
|
||||||
href={zkillLink('character', victimCharacterId)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="shrink-0 h-full"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src={victimPortraitUrl}
|
|
||||||
alt="VictimPortrait"
|
|
||||||
className={clsx(classes.killRowImage, 'h-full w-auto object-contain')}
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
<div className="flex flex-col h-full justify-between">
|
|
||||||
{victimCorpLogoUrl && victimCorpId && (
|
|
||||||
<a
|
|
||||||
href={zkillLink('corporation', victimCorpId)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="shrink-0 h-[26px]"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src={victimCorpLogoUrl}
|
|
||||||
alt="VictimCorp"
|
|
||||||
className={clsx(classes.killRowImage, 'w-auto h-full object-contain')}
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
{victimAllianceLogoUrl && victimAllianceId && (
|
|
||||||
<a
|
|
||||||
href={zkillLink('alliance', victimAllianceId)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="shrink-0 h-[26px]"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src={victimAllianceLogoUrl}
|
|
||||||
alt="VictimAlliance"
|
|
||||||
className={clsx(classes.killRowImage, 'w-auto h-full object-contain')}
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
.killRowContainer {
|
.killRowContainer {
|
||||||
@apply flex items-center whitespace-nowrap overflow-hidden;
|
@apply flex items-center whitespace-nowrap overflow-hidden;
|
||||||
|
|
||||||
&:not(:last-child) {
|
&:not(:last-child) {
|
||||||
@apply border-b border-stone-800;
|
@apply border-b border-stone-800;
|
||||||
}
|
}
|
||||||
|
|
||||||
@apply bg-transparent transition-all hover:bg-stone-900 hover:border-stone-700;
|
@apply bg-transparent transition-all hover:bg-stone-900 hover:border-stone-700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ export const KillsSettingsDialog: React.FC<KillsSettingsDialogProps> = ({ visibl
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleAddSystemSubmit: SearchOnSubmitCallback = useCallback(item => {
|
const handleAddSystemSubmit: SearchOnSubmitCallback = useCallback(item => {
|
||||||
|
|
||||||
if (localRef.current.excludedSystems.includes(item.value)) {
|
if (localRef.current.excludedSystems.includes(item.value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// VictimSubRowInfo.tsx
|
||||||
|
import React from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { zkillLink } from '../helpers';
|
||||||
|
import classes from './SystemKillRow.module.scss';
|
||||||
|
|
||||||
|
interface VictimRowSubInfoProps {
|
||||||
|
victimCharacterId: number | null;
|
||||||
|
victimPortraitUrl: string | null;
|
||||||
|
victimCharName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VictimRowSubInfo: React.FC<VictimRowSubInfoProps> = ({
|
||||||
|
victimCharacterId = 0,
|
||||||
|
victimPortraitUrl,
|
||||||
|
victimCharName,
|
||||||
|
}) => {
|
||||||
|
if (!victimPortraitUrl || victimCharacterId === null || victimCharacterId <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-start gap-1 h-14">
|
||||||
|
<div className="relative shrink-0 w-14 h-14 overflow-hidden">
|
||||||
|
<a
|
||||||
|
href={zkillLink('character', victimCharacterId)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="block w-full h-full"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={victimPortraitUrl}
|
||||||
|
alt={victimCharName || 'Victim Portrait'}
|
||||||
|
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -33,10 +33,6 @@ export function formatISK(value: number): string {
|
|||||||
return Math.round(value).toString();
|
return Math.round(value).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether this was an NPC kill, solo kill, etc.
|
|
||||||
* Returns { label: string, cssClass: string } for display, or null if none.
|
|
||||||
*/
|
|
||||||
export function getAttackerSubscript(kill: DetailedKill) {
|
export function getAttackerSubscript(kill: DetailedKill) {
|
||||||
if (kill.npc) {
|
if (kill.npc) {
|
||||||
return { label: 'npc', cssClass: 'text-purple-400' };
|
return { label: 'npc', cssClass: 'text-purple-400' };
|
||||||
|
|||||||
@@ -50,3 +50,62 @@ export function buildVictimImageUrls(args: {
|
|||||||
export function buildAttackerShipUrl(final_blow_ship_type_id?: number | null): string | null {
|
export function buildAttackerShipUrl(final_blow_ship_type_id?: number | null): string | null {
|
||||||
return eveImageUrl('types', final_blow_ship_type_id, 'render', 64);
|
return eveImageUrl('types', final_blow_ship_type_id, 'render', 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildAttackerImageUrls(args: {
|
||||||
|
final_blow_char_id?: number | null;
|
||||||
|
final_blow_corp_id?: number | null;
|
||||||
|
final_blow_alliance_id?: number | null;
|
||||||
|
}) {
|
||||||
|
const { final_blow_char_id, final_blow_corp_id, final_blow_alliance_id } = args;
|
||||||
|
|
||||||
|
const attackerPortraitUrl = eveImageUrl('characters', final_blow_char_id, 'portrait', 64);
|
||||||
|
const attackerCorpLogoUrl = eveImageUrl('corporations', final_blow_corp_id, 'logo', 32);
|
||||||
|
const attackerAllianceLogoUrl = eveImageUrl('alliances', final_blow_alliance_id, 'logo', 32);
|
||||||
|
|
||||||
|
return {
|
||||||
|
attackerPortraitUrl,
|
||||||
|
attackerCorpLogoUrl,
|
||||||
|
attackerAllianceLogoUrl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPrimaryLogoAndTooltip(
|
||||||
|
allianceUrl: string | null,
|
||||||
|
corpUrl: string | null,
|
||||||
|
allianceName: string,
|
||||||
|
corpName: string,
|
||||||
|
fallback: string,
|
||||||
|
) {
|
||||||
|
let url: string | null = null;
|
||||||
|
let tooltip = '';
|
||||||
|
|
||||||
|
if (allianceUrl) {
|
||||||
|
url = allianceUrl;
|
||||||
|
tooltip = allianceName || fallback;
|
||||||
|
} else if (corpUrl) {
|
||||||
|
url = corpUrl;
|
||||||
|
tooltip = corpName || fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { url, tooltip };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAttackerPrimaryImageAndTooltip(
|
||||||
|
isNpc: boolean,
|
||||||
|
allianceUrl: string | null,
|
||||||
|
corpUrl: string | null,
|
||||||
|
allianceName: string,
|
||||||
|
corpName: string,
|
||||||
|
finalBlowShipTypeId: number,
|
||||||
|
npcFallback: string = 'NPC Attacker',
|
||||||
|
) {
|
||||||
|
if (isNpc) {
|
||||||
|
const shipUrl = buildAttackerShipUrl(finalBlowShipTypeId);
|
||||||
|
return {
|
||||||
|
url: shipUrl,
|
||||||
|
tooltip: npcFallback,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return getPrimaryLogoAndTooltip(allianceUrl, corpUrl, allianceName, corpName, 'Attacker');
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,17 +14,22 @@ export interface DetailedKill {
|
|||||||
victim_char_name?: string;
|
victim_char_name?: string;
|
||||||
victim_corp_id?: number | null;
|
victim_corp_id?: number | null;
|
||||||
victim_corp_ticker?: string;
|
victim_corp_ticker?: string;
|
||||||
|
victim_corp_name?: string;
|
||||||
victim_alliance_id?: number | null;
|
victim_alliance_id?: number | null;
|
||||||
victim_alliance_ticker?: string;
|
victim_alliance_ticker?: string;
|
||||||
|
victim_alliance_name?: string;
|
||||||
victim_ship_type_id?: number | null;
|
victim_ship_type_id?: number | null;
|
||||||
victim_ship_name?: string;
|
victim_ship_name?: string;
|
||||||
|
|
||||||
|
|
||||||
final_blow_char_id?: number | null;
|
final_blow_char_id?: number | null;
|
||||||
final_blow_char_name?: string;
|
final_blow_char_name?: string;
|
||||||
final_blow_corp_id?: number | null;
|
final_blow_corp_id?: number | null;
|
||||||
final_blow_corp_ticker?: string;
|
final_blow_corp_ticker?: string;
|
||||||
|
final_blow_corp_name?: string;
|
||||||
final_blow_alliance_id?: number | null;
|
final_blow_alliance_id?: number | null;
|
||||||
final_blow_alliance_ticker?: string;
|
final_blow_alliance_ticker?: string;
|
||||||
|
final_blow_alliance_name?: string;
|
||||||
final_blow_ship_type_id?: number | null;
|
final_blow_ship_type_id?: number | null;
|
||||||
final_blow_ship_name?: string;
|
final_blow_ship_name?: string;
|
||||||
|
|
||||||
|
|||||||
@@ -231,19 +231,21 @@ defmodule WandererApp.Zkb.KillsProvider.Parser do
|
|||||||
|> enrich_final_blow()
|
|> enrich_final_blow()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
defp enrich_victim(km) do
|
defp enrich_victim(km) do
|
||||||
km
|
km
|
||||||
|> maybe_put_character_name("victim_char_id", "victim_char_name")
|
|> maybe_put_character_name("victim_char_id", "victim_char_name")
|
||||||
|> maybe_put_corp_ticker("victim_corp_id", "victim_corp_ticker")
|
|> maybe_put_corp_info("victim_corp_id", "victim_corp_ticker", "victim_corp_name")
|
||||||
|> maybe_put_alliance_ticker("victim_alliance_id", "victim_alliance_ticker")
|
|> maybe_put_alliance_info("victim_alliance_id", "victim_alliance_ticker", "victim_alliance_name")
|
||||||
|> maybe_put_ship_name("victim_ship_type_id", "victim_ship_name")
|
|> maybe_put_ship_name("victim_ship_type_id", "victim_ship_name")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
defp enrich_final_blow(km) do
|
defp enrich_final_blow(km) do
|
||||||
km
|
km
|
||||||
|> maybe_put_character_name("final_blow_char_id", "final_blow_char_name")
|
|> maybe_put_character_name("final_blow_char_id", "final_blow_char_name")
|
||||||
|> maybe_put_corp_ticker("final_blow_corp_id", "final_blow_corp_ticker")
|
|> maybe_put_corp_info("final_blow_corp_id", "final_blow_corp_ticker", "final_blow_corp_name")
|
||||||
|> maybe_put_alliance_ticker("final_blow_alliance_id", "final_blow_alliance_ticker")
|
|> maybe_put_alliance_info("final_blow_alliance_id", "final_blow_alliance_ticker", "final_blow_alliance_name")
|
||||||
|> maybe_put_ship_name("final_blow_ship_type_id", "final_blow_ship_name")
|
|> maybe_put_ship_name("final_blow_ship_type_id", "final_blow_ship_name")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -262,14 +264,16 @@ defmodule WandererApp.Zkb.KillsProvider.Parser do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp maybe_put_corp_ticker(km, id_key, ticker_key) do
|
defp maybe_put_corp_info(km, id_key, ticker_key, name_key) do
|
||||||
case Map.get(km, id_key) do
|
case Map.get(km, id_key) do
|
||||||
nil -> km
|
nil -> km
|
||||||
0 -> km
|
0 -> km
|
||||||
corp_id ->
|
corp_id ->
|
||||||
case WandererApp.Esi.get_corporation_info(corp_id) do
|
case WandererApp.Esi.get_corporation_info(corp_id) do
|
||||||
{:ok, %{"ticker" => ticker}} ->
|
{:ok, %{"ticker" => ticker, "name" => corp_name}} ->
|
||||||
Map.put(km, ticker_key, ticker)
|
km
|
||||||
|
|> Map.put(ticker_key, ticker)
|
||||||
|
|> Map.put(name_key, corp_name)
|
||||||
|
|
||||||
{:error, reason} ->
|
{:error, reason} ->
|
||||||
Logger.warning("[Parser] Failed to fetch corp info: ID=#{corp_id}, reason=#{inspect(reason)}")
|
Logger.warning("[Parser] Failed to fetch corp info: ID=#{corp_id}, reason=#{inspect(reason)}")
|
||||||
@@ -281,14 +285,16 @@ defmodule WandererApp.Zkb.KillsProvider.Parser do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp maybe_put_alliance_ticker(km, id_key, ticker_key) do
|
defp maybe_put_alliance_info(km, id_key, ticker_key, name_key) do
|
||||||
case Map.get(km, id_key) do
|
case Map.get(km, id_key) do
|
||||||
nil -> km
|
nil -> km
|
||||||
0 -> km
|
0 -> km
|
||||||
alliance_id ->
|
alliance_id ->
|
||||||
case WandererApp.Esi.get_alliance_info(alliance_id) do
|
case WandererApp.Esi.get_alliance_info(alliance_id) do
|
||||||
{:ok, %{"ticker" => alliance_ticker}} ->
|
{:ok, %{"ticker" => alliance_ticker, "name" => alliance_name}} ->
|
||||||
Map.put(km, ticker_key, alliance_ticker)
|
km
|
||||||
|
|> Map.put(ticker_key, alliance_ticker)
|
||||||
|
|> Map.put(name_key, alliance_name)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
km
|
km
|
||||||
|
|||||||
Reference in New Issue
Block a user