Release v0.2.10: Update package-lock.json and CI config
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { PlayerState, Profile, Equipment } from './types'
|
||||
import { getAssetPath } from '../../utils/assetPath'
|
||||
import { getTranslatedText } from '../../utils/i18nUtils'
|
||||
import InventoryModal from './InventoryModal'
|
||||
|
||||
interface PlayerSidebarProps {
|
||||
@@ -37,16 +40,18 @@ function PlayerSidebar({
|
||||
|
||||
|
||||
|
||||
const { t } = useTranslation()
|
||||
|
||||
const renderEquipmentSlot = (slot: string, item: any, emoji: string, label: string) => (
|
||||
<div className={`equipment-slot ${item ? 'filled' : 'empty'}`}>
|
||||
{item ? (
|
||||
<>
|
||||
<button className="equipment-unequip-btn" onClick={() => onUnequipItem(slot)} title="Unequip">✕</button>
|
||||
<button className="equipment-unequip-btn" onClick={() => onUnequipItem(slot)} title={t('game.unequip')}>✕</button>
|
||||
<div className="equipment-item-content">
|
||||
{item.image_path ? (
|
||||
<img
|
||||
src={item.image_path}
|
||||
alt={item.name}
|
||||
src={getAssetPath(item.image_path)}
|
||||
alt={getTranslatedText(item.name)}
|
||||
className="equipment-emoji"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
@@ -56,52 +61,52 @@ function PlayerSidebar({
|
||||
/>
|
||||
) : null}
|
||||
<span className={`equipment-emoji ${item.image_path ? 'hidden' : ''}`}>{item.emoji}</span>
|
||||
<span className={`equipment-name ${item.tier ? `tier-${item.tier}` : ''}`}>{item.name}</span>
|
||||
<span className={`equipment-name ${item.tier ? `tier-${item.tier}` : ''}`}>{getTranslatedText(item.name)}</span>
|
||||
{item.durability && item.durability !== null && (
|
||||
<span className="equipment-durability">{item.durability}/{item.max_durability}</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="equipment-tooltip">
|
||||
{item.description && <div className="item-tooltip-desc">{item.description}</div>}
|
||||
{item.description && <div className="item-tooltip-desc">{getTranslatedText(item.description)}</div>}
|
||||
{/* Use unique_stats if available, otherwise fall back to base stats */}
|
||||
{(item.unique_stats || item.stats) && Object.keys(item.unique_stats || item.stats).length > 0 && (
|
||||
<>
|
||||
{(item.unique_stats?.armor || item.stats?.armor) && (
|
||||
<div className="item-tooltip-stat">
|
||||
🛡️ Armor: +{item.unique_stats?.armor || item.stats?.armor}
|
||||
{t('stats.armor')}: +{item.unique_stats?.armor || item.stats?.armor}
|
||||
</div>
|
||||
)}
|
||||
{(item.unique_stats?.hp_max || item.stats?.hp_max) && (
|
||||
<div className="item-tooltip-stat">
|
||||
❤️ Max HP: +{item.unique_stats?.hp_max || item.stats?.hp_max}
|
||||
{t('stats.hp')}: +{item.unique_stats?.hp_max || item.stats?.hp_max}
|
||||
</div>
|
||||
)}
|
||||
{(item.unique_stats?.stamina_max || item.stats?.stamina_max) && (
|
||||
<div className="item-tooltip-stat">
|
||||
⚡ Max Stamina: +{item.unique_stats?.stamina_max || item.stats?.stamina_max}
|
||||
{t('stats.stamina')}: +{item.unique_stats?.stamina_max || item.stats?.stamina_max}
|
||||
</div>
|
||||
)}
|
||||
{(item.unique_stats?.damage_min !== undefined || item.stats?.damage_min !== undefined) &&
|
||||
(item.unique_stats?.damage_max !== undefined || item.stats?.damage_max !== undefined) && (
|
||||
<div className="item-tooltip-stat">
|
||||
⚔️ Damage: {item.unique_stats?.damage_min || item.stats?.damage_min}-{item.unique_stats?.damage_max || item.stats?.damage_max}
|
||||
{t('stats.damage')}: {item.unique_stats?.damage_min || item.stats?.damage_min}-{item.unique_stats?.damage_max || item.stats?.damage_max}
|
||||
</div>
|
||||
)}
|
||||
{(item.unique_stats?.weight_capacity || item.stats?.weight_capacity) && (
|
||||
<div className="item-tooltip-stat">
|
||||
⚖️ Weight: +{item.unique_stats?.weight_capacity || item.stats?.weight_capacity}kg
|
||||
{t('stats.weight')}: +{item.unique_stats?.weight_capacity || item.stats?.weight_capacity}kg
|
||||
</div>
|
||||
)}
|
||||
{(item.unique_stats?.volume_capacity || item.stats?.volume_capacity) && (
|
||||
<div className="item-tooltip-stat">
|
||||
📦 Volume: +{item.unique_stats?.volume_capacity || item.stats?.volume_capacity}L
|
||||
{t('stats.volume')}: +{item.unique_stats?.volume_capacity || item.stats?.volume_capacity}L
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{item.durability !== undefined && item.durability !== null && (
|
||||
<div className="item-tooltip-stat">
|
||||
🔧 Durability: {item.durability}/{item.max_durability}
|
||||
{t('stats.durability')}: {item.durability}/{item.max_durability}
|
||||
</div>
|
||||
)}
|
||||
{item.tier !== undefined && item.tier !== null && item.tier > 0 && (
|
||||
@@ -126,12 +131,12 @@ function PlayerSidebar({
|
||||
<div className={`right-sidebar mobile-menu-panel ${mobileMenuOpen === 'right' ? 'open' : ''}`}>
|
||||
{/* Profile Stats */}
|
||||
<div className="profile-sidebar">
|
||||
<h3>👤 Character</h3>
|
||||
<h3>{t('game.character')}</h3>
|
||||
|
||||
<div className="sidebar-stat-bars">
|
||||
<div className="sidebar-stat-bar">
|
||||
<div className="sidebar-stat-header">
|
||||
<span className="sidebar-stat-label">❤️ HP</span>
|
||||
<span className="sidebar-stat-label">{t('stats.hp')}</span>
|
||||
<span className="sidebar-stat-numbers">{playerState.health}/{playerState.max_health}</span>
|
||||
</div>
|
||||
<div className="sidebar-progress-bar">
|
||||
@@ -145,7 +150,7 @@ function PlayerSidebar({
|
||||
|
||||
<div className="sidebar-stat-bar">
|
||||
<div className="sidebar-stat-header">
|
||||
<span className="sidebar-stat-label">⚡ Stamina</span>
|
||||
<span className="sidebar-stat-label">{t('stats.stamina')}</span>
|
||||
<span className="sidebar-stat-numbers">{playerState.stamina}/{playerState.max_stamina}</span>
|
||||
</div>
|
||||
<div className="sidebar-progress-bar">
|
||||
@@ -161,13 +166,13 @@ function PlayerSidebar({
|
||||
{profile && (
|
||||
<div className="sidebar-stats">
|
||||
<div className="sidebar-stat-row">
|
||||
<span className="sidebar-label">Level:</span>
|
||||
<span className="sidebar-label">{t('stats.level')}:</span>
|
||||
<span className="sidebar-value">{profile.level}</span>
|
||||
</div>
|
||||
|
||||
<div className="sidebar-stat-bar">
|
||||
<div className="sidebar-stat-header">
|
||||
<span className="sidebar-stat-label">⭐ XP</span>
|
||||
<span className="sidebar-stat-label">{t('stats.xp')}</span>
|
||||
<span className="sidebar-stat-numbers">{profile.xp} / {(profile.level * 100)}</span>
|
||||
</div>
|
||||
<div className="sidebar-progress-bar">
|
||||
@@ -181,7 +186,7 @@ function PlayerSidebar({
|
||||
|
||||
{profile.unspent_points > 0 && (
|
||||
<div className="sidebar-stat-row highlight">
|
||||
<span className="sidebar-label">⭐ Unspent:</span>
|
||||
<span className="sidebar-label">{t('stats.unspentPoints')}:</span>
|
||||
<span className="sidebar-value">{profile.unspent_points}</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -191,28 +196,28 @@ function PlayerSidebar({
|
||||
{/* Compact 2x2 Stats Grid */}
|
||||
<div className="stats-grid">
|
||||
<div className="sidebar-stat-row compact">
|
||||
<span className="sidebar-label">💪 STR:</span>
|
||||
<span className="sidebar-label">{t('stats.strength')}:</span>
|
||||
<span className="sidebar-value">{profile.strength}</span>
|
||||
{profile.unspent_points > 0 && (
|
||||
<button className="stat-plus-btn" onClick={() => onSpendPoint('strength')}>+</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="sidebar-stat-row compact">
|
||||
<span className="sidebar-label">🏃 AGI:</span>
|
||||
<span className="sidebar-label">{t('stats.agility')}:</span>
|
||||
<span className="sidebar-value">{profile.agility}</span>
|
||||
{profile.unspent_points > 0 && (
|
||||
<button className="stat-plus-btn" onClick={() => onSpendPoint('agility')}>+</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="sidebar-stat-row compact">
|
||||
<span className="sidebar-label">🛡️ END:</span>
|
||||
<span className="sidebar-label">{t('stats.endurance')}:</span>
|
||||
<span className="sidebar-value">{profile.endurance}</span>
|
||||
{profile.unspent_points > 0 && (
|
||||
<button className="stat-plus-btn" onClick={() => onSpendPoint('endurance')}>+</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="sidebar-stat-row compact">
|
||||
<span className="sidebar-label">🧠 INT:</span>
|
||||
<span className="sidebar-label">{t('stats.intellect')}:</span>
|
||||
<span className="sidebar-value">{profile.intellect}</span>
|
||||
{profile.unspent_points > 0 && (
|
||||
<button className="stat-plus-btn" onClick={() => onSpendPoint('intellect')}>+</button>
|
||||
@@ -225,7 +230,7 @@ function PlayerSidebar({
|
||||
{/* Inventory Capacity - matching HP/Stamina/XP style */}
|
||||
<div className="sidebar-stat-bar">
|
||||
<div className="sidebar-stat-header">
|
||||
<span className="sidebar-stat-label">⚖️ Weight</span>
|
||||
<span className="sidebar-stat-label">{t('stats.weight')}</span>
|
||||
<span className="sidebar-stat-numbers">{(profile.current_weight || 0).toFixed(1)}/{profile.max_weight || 0}kg</span>
|
||||
</div>
|
||||
<div className="sidebar-progress-bar">
|
||||
@@ -239,7 +244,7 @@ function PlayerSidebar({
|
||||
|
||||
<div className="sidebar-stat-bar">
|
||||
<div className="sidebar-stat-header">
|
||||
<span className="sidebar-stat-label">📦 Volume</span>
|
||||
<span className="sidebar-stat-label">{t('stats.volume')}</span>
|
||||
<span className="sidebar-stat-numbers">{(profile.current_volume || 0).toFixed(1)}/{profile.max_volume || 0}L</span>
|
||||
</div>
|
||||
<div className="sidebar-progress-bar">
|
||||
@@ -271,7 +276,7 @@ function PlayerSidebar({
|
||||
transition: 'all 0.2s'
|
||||
}}
|
||||
>
|
||||
🎒 Open Inventory
|
||||
{t('game.inventory')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
@@ -279,24 +284,24 @@ function PlayerSidebar({
|
||||
|
||||
{/* Equipment Display - Proper Grid Layout */}
|
||||
<div className="equipment-sidebar">
|
||||
<h3>⚔️ Equipment</h3>
|
||||
<h3>{t('game.equipment')}</h3>
|
||||
<div className="equipment-grid">
|
||||
{/* Row 1: Head */}
|
||||
<div className="equipment-row">
|
||||
{renderEquipmentSlot('head', equipment.head, '🪖', 'Head')}
|
||||
{renderEquipmentSlot('head', equipment.head, '🪖', t('equipment.head'))}
|
||||
</div>
|
||||
|
||||
{/* Row 2: Weapon, Torso, Backpack */}
|
||||
<div className="equipment-row three-cols">
|
||||
{renderEquipmentSlot('weapon', equipment.weapon, '⚔️', 'Weapon')}
|
||||
{renderEquipmentSlot('torso', equipment.torso, '👕', 'Torso')}
|
||||
{renderEquipmentSlot('backpack', equipment.backpack, '🎒', 'Backpack')}
|
||||
{renderEquipmentSlot('weapon', equipment.weapon, '⚔️', t('equipment.weapon'))}
|
||||
{renderEquipmentSlot('torso', equipment.torso, '👕', t('equipment.torso'))}
|
||||
{renderEquipmentSlot('backpack', equipment.backpack, '🎒', t('equipment.backpack'))}
|
||||
</div>
|
||||
|
||||
{/* Row 3: Legs & Feet */}
|
||||
<div className="equipment-row two-cols">
|
||||
{renderEquipmentSlot('legs', equipment.legs, '👖', 'Legs')}
|
||||
{renderEquipmentSlot('feet', equipment.feet, '👟', 'Feet')}
|
||||
{renderEquipmentSlot('legs', equipment.legs, '👖', t('equipment.legs'))}
|
||||
{renderEquipmentSlot('feet', equipment.feet, '👟', t('equipment.feet'))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user