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,
|
||||
getAttackerSubscript,
|
||||
buildVictimImageUrls,
|
||||
buildAttackerShipUrl,
|
||||
buildAttackerImageUrls,
|
||||
getPrimaryLogoAndTooltip,
|
||||
getAttackerPrimaryImageAndTooltip,
|
||||
} from '../helpers';
|
||||
import { WdTooltipWrapper } from '../../../../ui-kit/WdTooltipWrapper';
|
||||
import classes from './SystemKillRow.module.scss';
|
||||
import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
export interface CompactKillRowProps {
|
||||
killDetails: DetailedKill;
|
||||
@@ -19,44 +23,69 @@ export interface CompactKillRowProps {
|
||||
|
||||
export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, systemName, onlyOneSystem }) => {
|
||||
const {
|
||||
killmail_id,
|
||||
killmail_id = 0,
|
||||
|
||||
victim_char_name = 'Unknown Pilot',
|
||||
victim_alliance_ticker = '',
|
||||
victim_corp_ticker = '',
|
||||
victim_ship_name = 'Unknown Ship',
|
||||
victim_alliance_ticker,
|
||||
victim_corp_ticker,
|
||||
victim_char_id,
|
||||
victim_corp_id,
|
||||
victim_alliance_id,
|
||||
victim_ship_type_id,
|
||||
victim_corp_name = '',
|
||||
victim_alliance_name = '',
|
||||
victim_char_id = 0,
|
||||
victim_corp_id = 0,
|
||||
victim_alliance_id = 0,
|
||||
victim_ship_type_id = 0,
|
||||
|
||||
final_blow_char_id,
|
||||
final_blow_char_id = 0,
|
||||
final_blow_char_name = '',
|
||||
final_blow_alliance_ticker,
|
||||
final_blow_corp_ticker,
|
||||
final_blow_ship_type_id,
|
||||
final_blow_alliance_ticker = '',
|
||||
final_blow_alliance_name = '',
|
||||
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,
|
||||
total_value,
|
||||
} = killDetails;
|
||||
|
||||
const attackerIsNpc = final_blow_char_id == null;
|
||||
kill_time = '',
|
||||
total_value = 0,
|
||||
} = killDetails || {};
|
||||
|
||||
const attackerIsNpc = final_blow_char_id === 0;
|
||||
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 attackerTicker = attackerIsNpc ? '' : final_blow_alliance_ticker || final_blow_corp_ticker || '';
|
||||
|
||||
const killTimeAgo = kill_time ? formatTimeMixed(kill_time) : '0h ago';
|
||||
const attackerSubscript = getAttackerSubscript(killDetails);
|
||||
|
||||
const { victimShipUrl } = buildVictimImageUrls({
|
||||
const { victimCorpLogoUrl, victimAllianceLogoUrl } = buildVictimImageUrls({
|
||||
victim_char_id,
|
||||
victim_ship_type_id,
|
||||
victim_corp_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 (
|
||||
<div
|
||||
@@ -65,15 +94,21 @@ export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, sys
|
||||
'text-xs whitespace-nowrap overflow-hidden leading-none',
|
||||
)}
|
||||
>
|
||||
{victimShipUrl && (
|
||||
<a
|
||||
href={zkillLink('kill', killmail_id)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="relative shrink-0 w-8 h-8 overflow-hidden"
|
||||
>
|
||||
<img src={victimShipUrl} alt="VictimShip" className={clsx(classes.killRowImage, 'w-full h-full')} />
|
||||
</a>
|
||||
{victimPrimaryLogoUrl && (
|
||||
<WdTooltipWrapper content={victimPrimaryTooltip} position={TooltipPosition.top}>
|
||||
<a
|
||||
href={zkillLink('kill', killmail_id)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="relative shrink-0 w-8 h-8 overflow-hidden"
|
||||
>
|
||||
<img
|
||||
src={victimPrimaryLogoUrl}
|
||||
alt="VictimPrimaryLogo"
|
||||
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
|
||||
/>
|
||||
</a>
|
||||
</WdTooltipWrapper>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col ml-2 min-w-0 overflow-hidden leading-[1rem]">
|
||||
@@ -103,7 +138,7 @@ export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, sys
|
||||
<div className="truncate text-stone-400">
|
||||
{!onlyOneSystem && systemName ? (
|
||||
<>
|
||||
{systemName} /<span className="ml-1 text-red-400">{killTimeAgo}</span>
|
||||
{systemName} / <span className="ml-1 text-red-400">{killTimeAgo}</span>
|
||||
</>
|
||||
) : (
|
||||
<span className="text-red-400">{killTimeAgo}</span>
|
||||
@@ -111,27 +146,33 @@ export const CompactKillRow: React.FC<CompactKillRowProps> = ({ killDetails, sys
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{finalBlowShipUrl && (
|
||||
<a
|
||||
href={zkillLink('kill', killmail_id)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="relative shrink-0 w-8 h-8 overflow-hidden"
|
||||
>
|
||||
<img src={finalBlowShipUrl} alt="AttackerShip" className={clsx(classes.killRowImage, 'w-full h-full')} />
|
||||
{attackerSubscript && (
|
||||
<span
|
||||
className={clsx(
|
||||
classes.attackerCountLabel,
|
||||
attackerSubscript.cssClass,
|
||||
'text-[0.6rem] leading-none px-[2px]',
|
||||
)}
|
||||
style={{ bottom: 0, right: 0 }}
|
||||
>
|
||||
{attackerSubscript.label}
|
||||
</span>
|
||||
)}
|
||||
</a>
|
||||
{attackerPrimaryImageUrl && (
|
||||
<WdTooltipWrapper content={attackerPrimaryTooltip} position={TooltipPosition.top}>
|
||||
<a
|
||||
href={zkillLink('kill', killmail_id)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="relative shrink-0 w-8 h-8 overflow-hidden"
|
||||
>
|
||||
<img
|
||||
src={attackerPrimaryImageUrl}
|
||||
alt={attackerIsNpc ? 'NpcShip' : 'AttackerPrimaryLogo'}
|
||||
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
|
||||
/>
|
||||
{attackerSubscript && (
|
||||
<span
|
||||
className={clsx(
|
||||
classes.attackerCountLabel,
|
||||
attackerSubscript.cssClass,
|
||||
'text-[0.6rem] leading-none px-[2px]',
|
||||
)}
|
||||
style={{ bottom: 0, right: 0 }}
|
||||
>
|
||||
{attackerSubscript.label}
|
||||
</span>
|
||||
)}
|
||||
</a>
|
||||
</WdTooltipWrapper>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
// FullKillRow.tsx
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { DetailedKill } from '@/hooks/Mapper/types/kills';
|
||||
import { KillRowSubInfo } from './KillRowSubInfo';
|
||||
import {
|
||||
formatISK,
|
||||
formatTimeMixed,
|
||||
zkillLink,
|
||||
getAttackerSubscript,
|
||||
buildVictimImageUrls,
|
||||
buildAttackerShipUrl,
|
||||
buildAttackerImageUrls,
|
||||
getPrimaryLogoAndTooltip,
|
||||
getAttackerPrimaryImageAndTooltip,
|
||||
} from '../helpers';
|
||||
import { VictimRowSubInfo } from './VictimRowSubInfo';
|
||||
import { WdTooltipWrapper } from '../../../../ui-kit/WdTooltipWrapper';
|
||||
import classes from './SystemKillRow.module.scss';
|
||||
import { TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
|
||||
|
||||
export interface FullKillRowProps {
|
||||
killDetails: DetailedKill;
|
||||
@@ -20,73 +25,100 @@ export interface FullKillRowProps {
|
||||
|
||||
export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemName, onlyOneSystem }) => {
|
||||
const {
|
||||
killmail_id,
|
||||
killmail_id = 0,
|
||||
|
||||
victim_char_name = '',
|
||||
victim_alliance_ticker,
|
||||
victim_corp_ticker,
|
||||
victim_alliance_ticker = '',
|
||||
victim_corp_ticker = '',
|
||||
victim_ship_name = '',
|
||||
victim_char_id,
|
||||
victim_corp_id,
|
||||
victim_alliance_id,
|
||||
victim_ship_type_id,
|
||||
victim_char_id = 0,
|
||||
victim_corp_id = 0,
|
||||
victim_alliance_id = 0,
|
||||
victim_ship_type_id = 0,
|
||||
victim_corp_name = '',
|
||||
victim_alliance_name = '',
|
||||
|
||||
total_value,
|
||||
kill_time,
|
||||
|
||||
final_blow_char_id,
|
||||
final_blow_char_id = 0,
|
||||
final_blow_char_name = '',
|
||||
final_blow_alliance_ticker,
|
||||
final_blow_corp_ticker,
|
||||
final_blow_alliance_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_type_id,
|
||||
} = killDetails;
|
||||
final_blow_ship_type_id = 0,
|
||||
|
||||
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 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 { victimPortraitUrl, victimCorpLogoUrl, victimAllianceLogoUrl, victimShipUrl } = buildVictimImageUrls({
|
||||
const { victimPortraitUrl, victimCorpLogoUrl, victimAllianceLogoUrl } = buildVictimImageUrls({
|
||||
victim_char_id,
|
||||
victim_ship_type_id,
|
||||
victim_corp_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);
|
||||
|
||||
return (
|
||||
<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">
|
||||
{victimShipUrl && (
|
||||
<div className="relative shrink-0 w-14 h-14 overflow-hidden">
|
||||
<a
|
||||
href={zkillLink('kill', killmail_id)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block w-full h-full"
|
||||
>
|
||||
<img src={victimShipUrl} alt="VictimShip" className={clsx(classes.killRowImage, 'w-full h-full')} />
|
||||
</a>
|
||||
</div>
|
||||
{/* 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">
|
||||
<a
|
||||
href={zkillLink('kill', killmail_id)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block w-full h-full"
|
||||
>
|
||||
<img
|
||||
src={victimPrimaryImageUrl}
|
||||
alt="VictimPrimaryLogo"
|
||||
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</WdTooltipWrapper>
|
||||
)}
|
||||
|
||||
<div className="flex items-start h-14 gap-1 shrink-0">
|
||||
<KillRowSubInfo
|
||||
victimCorpId={victim_corp_id}
|
||||
victimCorpLogoUrl={victimCorpLogoUrl}
|
||||
victimAllianceId={victim_alliance_id}
|
||||
victimAllianceLogoUrl={victimAllianceLogoUrl}
|
||||
victimCharacterId={victim_char_id}
|
||||
victimPortraitUrl={victimPortraitUrl}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<VictimRowSubInfo
|
||||
victimCharName={victim_char_name}
|
||||
victimCharacterId={victim_char_id}
|
||||
victimPortraitUrl={victimPortraitUrl}
|
||||
/>
|
||||
<div className="flex flex-col text-stone-200 leading-4 min-w-0 overflow-hidden">
|
||||
<div className="truncate">
|
||||
<span className="font-semibold">{victim_char_name}</span>
|
||||
@@ -105,7 +137,7 @@ export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemNam
|
||||
</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">
|
||||
{!attackerIsNpc && (
|
||||
<div className="truncate font-semibold">
|
||||
@@ -118,23 +150,47 @@ export const FullKillRow: React.FC<FullKillRowProps> = ({ killDetails, systemNam
|
||||
)}
|
||||
<div className="truncate text-red-400">{killTimeAgo}</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('kill', killmail_id)}
|
||||
href={zkillLink('character', final_blow_char_id)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block w-full h-full"
|
||||
>
|
||||
<img src={finalBlowShipUrl} alt="AttackerShip" className={clsx(classes.killRowImage, 'w-full h-full')} />
|
||||
{attackerSubscript && (
|
||||
<span className={clsx(attackerSubscript.cssClass, classes.attackerCountLabel)}>
|
||||
{attackerSubscript.label}
|
||||
</span>
|
||||
)}
|
||||
<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">
|
||||
<a
|
||||
href={zkillLink('kill', killmail_id)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block w-full h-full"
|
||||
>
|
||||
<img
|
||||
src={attackerPrimaryImageUrl}
|
||||
alt={attackerIsNpc ? 'NpcShip' : 'AttackerPrimaryLogo'}
|
||||
className={clsx(classes.killRowImage, 'w-full h-full object-contain')}
|
||||
/>
|
||||
{attackerSubscript && (
|
||||
<span className={clsx(attackerSubscript.cssClass, classes.attackerCountLabel)}>
|
||||
{attackerSubscript.label}
|
||||
</span>
|
||||
)}
|
||||
</a>
|
||||
</div>
|
||||
</WdTooltipWrapper>
|
||||
)}
|
||||
</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 {
|
||||
@apply flex items-center whitespace-nowrap overflow-hidden;
|
||||
|
||||
&:not(:last-child) {
|
||||
@apply border-b border-stone-800;
|
||||
}
|
||||
|
||||
@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 => {
|
||||
|
||||
if (localRef.current.excludedSystems.includes(item.value)) {
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
if (kill.npc) {
|
||||
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 {
|
||||
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_corp_id?: number | null;
|
||||
victim_corp_ticker?: string;
|
||||
victim_corp_name?: string;
|
||||
victim_alliance_id?: number | null;
|
||||
victim_alliance_ticker?: string;
|
||||
victim_alliance_name?: string;
|
||||
victim_ship_type_id?: number | null;
|
||||
victim_ship_name?: string;
|
||||
|
||||
|
||||
final_blow_char_id?: number | null;
|
||||
final_blow_char_name?: string;
|
||||
final_blow_corp_id?: number | null;
|
||||
final_blow_corp_ticker?: string;
|
||||
final_blow_corp_name?: string;
|
||||
final_blow_alliance_id?: number | null;
|
||||
final_blow_alliance_ticker?: string;
|
||||
final_blow_alliance_name?: string;
|
||||
final_blow_ship_type_id?: number | null;
|
||||
final_blow_ship_name?: string;
|
||||
|
||||
|
||||
@@ -231,19 +231,21 @@ defmodule WandererApp.Zkb.KillsProvider.Parser do
|
||||
|> enrich_final_blow()
|
||||
end
|
||||
|
||||
|
||||
defp enrich_victim(km) do
|
||||
km
|
||||
|> maybe_put_character_name("victim_char_id", "victim_char_name")
|
||||
|> maybe_put_corp_ticker("victim_corp_id", "victim_corp_ticker")
|
||||
|> maybe_put_alliance_ticker("victim_alliance_id", "victim_alliance_ticker")
|
||||
|> maybe_put_corp_info("victim_corp_id", "victim_corp_ticker", "victim_corp_name")
|
||||
|> maybe_put_alliance_info("victim_alliance_id", "victim_alliance_ticker", "victim_alliance_name")
|
||||
|> maybe_put_ship_name("victim_ship_type_id", "victim_ship_name")
|
||||
end
|
||||
|
||||
|
||||
defp enrich_final_blow(km) do
|
||||
km
|
||||
|> 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_alliance_ticker("final_blow_alliance_id", "final_blow_alliance_ticker")
|
||||
|> maybe_put_corp_info("final_blow_corp_id", "final_blow_corp_ticker", "final_blow_corp_name")
|
||||
|> 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")
|
||||
end
|
||||
|
||||
@@ -262,14 +264,16 @@ defmodule WandererApp.Zkb.KillsProvider.Parser do
|
||||
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
|
||||
nil -> km
|
||||
0 -> km
|
||||
corp_id ->
|
||||
case WandererApp.Esi.get_corporation_info(corp_id) do
|
||||
{:ok, %{"ticker" => ticker}} ->
|
||||
Map.put(km, ticker_key, ticker)
|
||||
{:ok, %{"ticker" => ticker, "name" => corp_name}} ->
|
||||
km
|
||||
|> Map.put(ticker_key, ticker)
|
||||
|> Map.put(name_key, corp_name)
|
||||
|
||||
{:error, 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
|
||||
|
||||
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
|
||||
nil -> km
|
||||
0 -> km
|
||||
alliance_id ->
|
||||
case WandererApp.Esi.get_alliance_info(alliance_id) do
|
||||
{:ok, %{"ticker" => alliance_ticker}} ->
|
||||
Map.put(km, ticker_key, alliance_ticker)
|
||||
{:ok, %{"ticker" => alliance_ticker, "name" => alliance_name}} ->
|
||||
km
|
||||
|> Map.put(ticker_key, alliance_ticker)
|
||||
|> Map.put(name_key, alliance_name)
|
||||
|
||||
_ ->
|
||||
km
|
||||
|
||||
Reference in New Issue
Block a user