fix(ui): stable sort for ground items, improved loot modal (images/desc, outside click)

This commit is contained in:
Joan
2026-02-07 22:44:51 +01:00
parent ff9472048d
commit c9d180379a

View File

@@ -360,12 +360,14 @@ function LocationView({
</div> </div>
)} )}
{/* Items on Ground */} {/* Items on Ground - Stable Sort */}
{location.items.length > 0 && ( {location.items.length > 0 && (
<div className="entity-section items-section"> <div className="entity-section items-section">
<h3>{t('location.itemsOnGround')}</h3> <h3>{t('location.itemsOnGround')}</h3>
<div className="entity-list grid-view"> <div className="entity-list grid-view">
{location.items.map((item: any, i: number) => { {[...location.items]
.sort((a: any, b: any) => (a.id || 0) - (b.id || 0))
.map((item: any, i: number) => {
const isShaking = failedActionItemId == item.id; const isShaking = failedActionItemId == item.id;
const itemId = `item-${item.id}-${i}`; const itemId = `item-${item.id}-${i}`;
@@ -394,7 +396,7 @@ function LocationView({
}; };
return ( return (
<div key={i} className={`entity-card item-card ${isShaking ? 'shake' : ''} grid-card`} <div key={item.id} className={`entity-card item-card ${isShaking ? 'shake' : ''} grid-card`}
onClick={(e) => handleDropdownClick(e, itemId)} onClick={(e) => handleDropdownClick(e, itemId)}
> >
<GameTooltip content={ <GameTooltip content={
@@ -496,8 +498,8 @@ function LocationView({
{/* Corpse Loot Overlay Modal */} {/* Corpse Loot Overlay Modal */}
{expandedCorpse && corpseDetails && corpseDetails.loot_items && ( {expandedCorpse && corpseDetails && corpseDetails.loot_items && (
<div className="corpse-loot-overlay"> <div className="corpse-loot-overlay" onClick={() => onSetExpandedCorpse(null)}>
<div className="corpse-loot-modal"> <div className="corpse-loot-modal" onClick={(e) => e.stopPropagation()}>
<div className="corpse-details-header"> <div className="corpse-details-header">
<h4>{t('location.lootableItems')}</h4> <h4>{t('location.lootableItems')}</h4>
<button <button
@@ -512,10 +514,28 @@ function LocationView({
<div className="corpse-items-list"> <div className="corpse-items-list">
{corpseDetails.loot_items.map((item: any) => ( {corpseDetails.loot_items.map((item: any) => (
<div key={item.index} className={`corpse-item ${!item.can_loot ? 'locked' : ''}`}> <div key={item.index} className={`corpse-item ${!item.can_loot ? 'locked' : ''}`}>
<div className="corpse-item-info"> {/* Item Image */}
<div className="corpse-item-name"> <div className="corpse-item-image">
{item.emoji} {getTranslatedText(item.item_name)} {item.image_path ? (
<img
src={getAssetPath(item.image_path)}
alt={item.item_name}
className="item-img-thumb"
style={{ width: '40px', height: '40px', objectFit: 'contain', marginRight: '10px' }}
onError={(e) => {
(e.target as HTMLImageElement).style.display = 'none';
// Fallback emoji next to it will show if image fails?
// Current logic doesn't have fallback emoji element sibling, just keeping it simple.
}}
/>
) : <span style={{ fontSize: '2rem', marginRight: '10px' }}>{item.emoji || '📦'}</span>}
</div> </div>
<div className="corpse-item-info" style={{ flex: 1 }}>
<div className="corpse-item-name">
{getTranslatedText(item.item_name)}
</div>
{item.description && <div className="corpse-item-desc" style={{ fontSize: '0.75rem', color: '#a0aec0' }}>{getTranslatedText(item.description)}</div>}
<div className="corpse-item-qty"> <div className="corpse-item-qty">
{t('common.qty')}: {item.quantity_min}{item.quantity_min !== item.quantity_max ? `-${item.quantity_max}` : ''} {t('common.qty')}: {item.quantity_min}{item.quantity_min !== item.quantity_max ? `-${item.quantity_max}` : ''}
</div> </div>
@@ -525,6 +545,7 @@ function LocationView({
</div> </div>
)} )}
</div> </div>
<GameTooltip content={!item.can_loot ? `Requires ${getTranslatedText(item.required_tool_name)}` : 'Loot this item'}> <GameTooltip content={!item.can_loot ? `Requires ${getTranslatedText(item.required_tool_name)}` : 'Loot this item'}>
<button <button
className="corpse-item-loot-btn" className="corpse-item-loot-btn"