From 75897440c92a9192d5735c5195e081469d5b94d8 Mon Sep 17 00:00:00 2001 From: MaksSlyzar Date: Tue, 5 May 2026 01:37:32 +0300 Subject: [PATCH] Fixed inventory equipment, crafting tab scroll --- src/services/GameDataManager.js | 2 +- .../GameInterface/components/Navigation.jsx | 2 +- src/views/GameInterface/tabs/CraftingTab.jsx | 64 +++--- src/views/GameInterface/tabs/InventoryTab.jsx | 42 ++-- .../GameInterface/tabs/styles/CraftingTab.css | 210 ++++++++++-------- 5 files changed, 170 insertions(+), 150 deletions(-) diff --git a/src/services/GameDataManager.js b/src/services/GameDataManager.js index 76ebee5..a155525 100644 --- a/src/services/GameDataManager.js +++ b/src/services/GameDataManager.js @@ -36,7 +36,7 @@ class GameDataManager { data.quests.forEach((q) => this.quests.set(q.id, q)); } - console.log(this.skills); + console.log(this.recipes); if (data.languages) { this.translations = data.languages; } diff --git a/src/views/GameInterface/components/Navigation.jsx b/src/views/GameInterface/components/Navigation.jsx index 8513283..458bd78 100644 --- a/src/views/GameInterface/components/Navigation.jsx +++ b/src/views/GameInterface/components/Navigation.jsx @@ -50,7 +50,7 @@ const Navigation = ({ activeTab, onTabChange }) => { if (id === "itemlist") return "ITEM_LIST"; if (id === "chat") return "CHAT"; if (id === "notifications") return "ALERTS"; - return GameDataManager.t(`category.tabs.original.${id}`); + return GameDataManager.t(`category.tabs.core.${id}`); }; return ( diff --git a/src/views/GameInterface/tabs/CraftingTab.jsx b/src/views/GameInterface/tabs/CraftingTab.jsx index 23544f0..9659d9d 100644 --- a/src/views/GameInterface/tabs/CraftingTab.jsx +++ b/src/views/GameInterface/tabs/CraftingTab.jsx @@ -2,14 +2,12 @@ import React, { useState, useEffect } from "react"; import { useSocket } from "../../../hooks/useSocket"; import GameDataManager from "../../../services/GameDataManager"; import "./styles/CraftingTab.css"; -import CategorySelector from "../components/CategorySelector"; import CraftModal from "./components/CraftModal"; import { config } from "../../../config/api"; import MeteorRegion from "../../../components/Meteor/MeteorRegion.jsx"; const CraftingTab = () => { const { socket } = useSocket(); - const [categories, setCategories] = useState([]); const [recipes, setRecipes] = useState([]); const [userInventory, setUserInventory] = useState([]); @@ -27,9 +25,7 @@ const CraftingTab = () => { useEffect(() => { if (activeCategory) { - const filteredRecipes = - GameDataManager.getRecipesByCategory(activeCategory); - setRecipes(filteredRecipes); + setRecipes(GameDataManager.getRecipesByCategory(activeCategory)); } }, [activeCategory]); @@ -43,8 +39,7 @@ const CraftingTab = () => { const handleCraftStarted = (data) => { const recipeData = GameDataManager.getRecipe(data.recipeId); - const now = Date.now(); - const diff = (data.finishAt - now) / 1000; + const diff = (data.finishAt - Date.now()) / 1000; if (diff <= 0) { setActiveCraft(null); @@ -59,9 +54,7 @@ const CraftingTab = () => { timeLeft: Math.max(0, Math.ceil(diff)), }); - if (recipeData) { - setSelectedRecipe(recipeData); - } + if (recipeData) setSelectedRecipe(recipeData); }; const handleCraftSuccess = () => { @@ -83,11 +76,11 @@ const CraftingTab = () => { useEffect(() => { if (!activeCraft) return; - const timer = setInterval(() => { - const now = Date.now(); - const diff = Math.max(0, Math.ceil((activeCraft.finishAt - now) / 1000)); - + const diff = Math.max( + 0, + Math.ceil((activeCraft.finishAt - Date.now()) / 1000), + ); if (diff <= 0) { clearInterval(timer); setActiveCraft(null); @@ -95,7 +88,6 @@ const CraftingTab = () => { setActiveCraft((prev) => (prev ? { ...prev, timeLeft: diff } : null)); } }, 1000); - return () => clearInterval(timer); }, [activeCraft?.finishAt]); @@ -119,8 +111,7 @@ const CraftingTab = () => {
- Assembling:{" "} - {activeCraft.name} + {activeCraft.name} {activeCraft.timeLeft}s
@@ -137,27 +128,32 @@ const CraftingTab = () => {

- Fabrication Unit + Fabrication

- +
+ {categories.map((cat) => ( + + ))} +
{recipes.map((recipe) => { - const isThisRecipeCrafting = activeCraft?.recipeId === recipe.id; + const isCrafting = activeCraft?.recipeId === recipe.id; const canCraft = recipe.ingredients.every( (ing) => getOwnedAmount(ing.itemId) >= ing.quantity, ); - return (
setSelectedRecipe(recipe)} >
@@ -165,21 +161,17 @@ const CraftingTab = () => { {recipe.displayName} ) : (
{recipe.displayName[0]}
)}
-
- {recipe.displayName} -
- - {recipe.time_seconds}s - -
-
- {isThisRecipeCrafting && ( + {recipe.displayName} + + {recipe.time_seconds}s + + {isCrafting && (
diff --git a/src/views/GameInterface/tabs/InventoryTab.jsx b/src/views/GameInterface/tabs/InventoryTab.jsx index 67d1bbf..eb203d5 100644 --- a/src/views/GameInterface/tabs/InventoryTab.jsx +++ b/src/views/GameInterface/tabs/InventoryTab.jsx @@ -19,7 +19,6 @@ const InventoryTab = () => { const manifest = GameDataManager.manifest || {}; const coreSystems = manifest.core_systems?.categories || {}; - const getFullTextureUrl = (path) => { if (!path) return "/assets/no-image.png"; if (path.startsWith("http")) return path; @@ -89,36 +88,43 @@ const InventoryTab = () => { const equipmentSlots = { personal: Object.keys(coreSystems) + .filter((k) => { + const system = coreSystems[k]; + return ( + system.slotType === "personal" && + !k.includes("accessory") && + k !== "original:weapon" + ); + }) + .map((k) => ({ + id: k, + label: GameDataManager.t(coreSystems[k].displayName), + })), + + weapons: Object.keys(coreSystems) + .filter((k) => k === "original:weapon") + .map((k) => ({ + id: k, + label: GameDataManager.t(coreSystems[k].displayName), + })), + + accessories: Object.keys(coreSystems) .filter( (k) => - k.startsWith("original:personal_") && - !k.includes("accessory") && - k !== "original:personal_weapons", + k.includes("accessory") && coreSystems[k].slotType === "personal", ) .map((k) => ({ id: k, label: GameDataManager.t(coreSystems[k].displayName), })), - weapons: Object.keys(coreSystems) - .filter((k) => k === "original:personal_weapons") - .map((k) => ({ - id: k, - label: GameDataManager.t(coreSystems[k].displayName), - })), - accessories: Object.keys(coreSystems) - .filter((k) => k.includes("personal_accessory")) - .map((k) => ({ - id: k, - label: GameDataManager.t(coreSystems[k].displayName), - })), + ship: Object.keys(coreSystems) - .filter((k) => k.startsWith("original:ship_")) + .filter((k) => coreSystems[k].slotType === "ship") .map((k) => ({ id: k, label: GameDataManager.t(coreSystems[k].displayName), })), }; - const renderSlotGroup = (title, groupSlots) => (
{title}
diff --git a/src/views/GameInterface/tabs/styles/CraftingTab.css b/src/views/GameInterface/tabs/styles/CraftingTab.css index 0244106..546b194 100644 --- a/src/views/GameInterface/tabs/styles/CraftingTab.css +++ b/src/views/GameInterface/tabs/styles/CraftingTab.css @@ -3,83 +3,56 @@ height: 100%; display: flex; flex-direction: column; + overflow: hidden; } .crafting-header { display: flex; justify-content: space-between; align-items: center; - margin-bottom: 20px; + margin-bottom: 15px; } .crafting-header h2 { font-size: 1.2rem; -} - -.crafting-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); - gap: 15px; - margin-top: 20px; -} - -.recipe-card { - background: var(--bg-secondary); - border: 1px solid var(--border-color); - padding: 15px; - border-radius: 8px; - text-align: center; - cursor: pointer; - transition: all 0.2s ease; - display: flex; - flex-direction: column; - align-items: center; - gap: 8px; -} - -.recipe-card:hover { - transform: translateY(-5px); - border-color: var(--primary-color); - box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); -} - -.recipe-icon img { - max-width: 50px; - height: auto; -} - -.recipe-name { - font-size: 0.85rem; - line-height: 1.2; - color: #fff; - font-weight: 500; -} - -.badge-time { - font-size: 0.75rem; - color: var(--text-secondary); + margin: 0; + color: var(--primary-color); + text-transform: uppercase; + letter-spacing: 1px; } .crafting-categories { display: flex; + flex-wrap: nowrap; gap: 10px; - margin-bottom: 15px; - padding: 5px 0; + margin-bottom: 20px; + padding: 5px 5px 12px 5px; overflow-x: auto; - scrollbar-width: none; -webkit-overflow-scrolling: touch; + scrollbar-width: thin; + scrollbar-color: var(--primary-color) transparent; + border-bottom: 1px solid rgba(255, 255, 255, 0.05); } .crafting-categories::-webkit-scrollbar { - display: none; + height: 3px; +} + +.crafting-categories::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.2); +} + +.crafting-categories::-webkit-scrollbar-thumb { + background: var(--primary-color); + border-radius: 10px; } .crafting-cat-btn { flex: 0 0 auto; - padding: 8px 16px; + padding: 10px 18px; background: rgba(255, 255, 255, 0.03); border: 1px solid var(--border-color); - border-radius: 4px; + border-left: 3px solid var(--border-color); color: var(--text-secondary); font-family: "Orbitron", sans-serif; font-size: 0.75rem; @@ -90,56 +63,105 @@ transition: all 0.2s ease; } -.crafting-cat-btn.active { - background: var(--primary-color); +.crafting-cat-btn:hover { + background: rgba(255, 255, 255, 0.08); border-color: var(--primary-color); - color: #000; + color: #fff; +} + +.crafting-cat-btn.active { + background: linear-gradient( + 90deg, + rgba(0, 243, 255, 0.15) 0%, + transparent 100% + ); + border-color: var(--primary-color); + border-left: 3px solid var(--primary-color); + color: var(--primary-color); font-weight: 700; + box-shadow: inset 5px 0 10px rgba(0, 243, 255, 0.05); } -@media (max-width: 600px) { - .crafting-container { - padding: 12px; - } - - .crafting-header { - margin-bottom: 12px; - } - - .crafting-header h2 { - font-size: 1rem; - } - - .crafting-grid { - grid-template-columns: repeat(2, 1fr); - gap: 8px; - margin-top: 10px; - } - - .recipe-card { - padding: 10px; - gap: 6px; - } - - .recipe-icon img { - max-width: 40px; - } - - .recipe-name { - font-size: 0.75rem; - } - - .crafting-cat-btn { - padding: 6px 12px; - font-size: 0.7rem; - } +.crafting-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + gap: 15px; + overflow-y: auto; + padding-right: 5px; } -.tab-content.active { - height: 100%; +.crafting-grid::-webkit-scrollbar { + width: 4px; +} + +.crafting-grid::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + border-radius: 2px; +} + +.recipe-card { + background: rgba(255, 255, 255, 0.03); + border: 1px solid var(--border-color); + padding: 15px; + border-radius: 4px; + text-align: center; + cursor: pointer; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + position: relative; +} + +.recipe-card:hover { + background: rgba(255, 255, 255, 0.06); + border-color: var(--primary-color); + transform: translateY(-2px); +} + +.recipe-card.insufficient-resources { + opacity: 0.6; + filter: grayscale(0.5); +} + +.recipe-card.crafting-active { + border-color: var(--primary-color); + box-shadow: 0 0 15px rgba(0, 243, 255, 0.2); +} + +.active-craft-panel { + background: rgba(0, 243, 255, 0.05); + border: 1px solid var(--primary-color); + padding: 12px; + margin-bottom: 20px; + border-radius: 4px; +} + +.craft-info { + display: flex; + justify-content: space-between; + font-family: "Orbitron", sans-serif; + font-size: 0.8rem; + margin-bottom: 8px; +} + +.progress-bar-bg { + height: 4px; + background: rgba(255, 255, 255, 0.1); + border-radius: 2px; overflow: hidden; } -.meteor-region-content { - width: 100%; +.progress-bar-fill { + height: 100%; + background: var(--primary-color); + box-shadow: 0 0 10px var(--primary-color); + transition: width 1s linear; +} + +@media (max-width: 600px) { + .crafting-grid { + grid-template-columns: repeat(2, 1fr); + } }