Updated Modals

This commit is contained in:
MaksSlyzar 2026-04-18 19:02:11 +03:00
parent 1254db3963
commit 79c38c36ea
4 changed files with 242 additions and 84 deletions

View File

@ -18,24 +18,23 @@
border-radius: 12px; border-radius: 12px;
width: 90%; width: 90%;
max-width: 450px; max-width: 450px;
padding: 24px;
box-shadow: 0 0 30px rgba(0, 204, 255, 0.15); box-shadow: 0 0 30px rgba(0, 204, 255, 0.15);
} }
.modal-header { .modal-headerr {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 10px;
text-align: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.1); border-bottom: 1px solid rgba(255, 255, 255, 0.1);
padding-bottom: 15px;
margin-bottom: 20px;
} }
.modal-header h3 { .modal-header {
margin: 0; margin: 0;
color: #00ccff; color: #00ccff;
font-family: "Orbitron", sans-serif; font-family: "Orbitron", sans-serif;
font-size: 1.1rem; font-size: 0.8rem;
} }
.close-x { .close-x {
@ -125,7 +124,7 @@
height: 100%; height: 100%;
background: var(--primary-color); background: var(--primary-color);
box-shadow: 0 0 10px var(--primary-color); box-shadow: 0 0 10px var(--primary-color);
transition: width 1s linear; /* Плавне заповнення */ transition: width 1s linear;
} }
@keyframes pulse { @keyframes pulse {
@ -140,7 +139,6 @@
} }
} }
/* Стани інгредієнтів */
.res-item { .res-item {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -161,7 +159,6 @@
background: rgba(255, 68, 68, 0.1); background: rgba(255, 68, 68, 0.1);
} }
/* Кольори значень */
.val-red { .val-red {
color: #ff4444; color: #ff4444;
font-weight: bold; font-weight: bold;
@ -181,7 +178,6 @@
font-size: 0.9rem; font-size: 0.9rem;
} }
/* Кнопка */
.btn-start-craft { .btn-start-craft {
background: #28a745; background: #28a745;
color: white; color: white;
@ -202,3 +198,60 @@
background: #218838; background: #218838;
box-shadow: 0 0 10px rgba(40, 167, 69, 0.4); box-shadow: 0 0 10px rgba(40, 167, 69, 0.4);
} }
.item-preview-header {
display: flex;
gap: 20px;
padding: 15px;
background: rgba(0, 212, 255, 0.05);
border: 1px solid rgba(0, 212, 255, 0.1);
margin-bottom: 20px;
border-radius: 4px;
}
.item-icon-container {
position: relative;
width: 90px;
height: 90px;
background: #000;
border: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.item-display-icon {
max-width: 80%;
max-height: 80%;
object-fit: contain;
filter: drop-shadow(0 0 5px var(--primary-color));
}
.item-qty-badge {
position: absolute;
top: -8px;
right: -8px;
background: var(--primary-color);
color: #000;
padding: 2px 8px;
font-size: 11px;
font-weight: bold;
border-radius: 2px;
}
.item-type-tag {
display: block;
font-size: 10px;
color: var(--primary-color);
letter-spacing: 1px;
margin-bottom: 5px;
opacity: 0.8;
}
.item-description {
font-size: 13px;
color: #ccc;
line-height: 1.4;
margin: 0;
}

View File

@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import "./CraftModal.css"; import "./CraftModal.css";
import { getServerUrl } from "../../../../config/api";
const CraftModal = ({ const CraftModal = ({
recipe, recipe,
@ -10,6 +11,15 @@ const CraftModal = ({
}) => { }) => {
if (!recipe) return null; if (!recipe) return null;
const CONNECT_URL = getServerUrl();
const ASSET_BASE_URL = `${CONNECT_URL}/static/`;
const getFullTextureUrl = (path) => {
if (!path) return "/assets/no-image.png";
if (path.startsWith("http")) return path;
return `${ASSET_BASE_URL}${path}`;
};
const isBusy = !!activeCraft; const isBusy = !!activeCraft;
const outputQty = Object.values(recipe.output || {})[0] || 1; const outputQty = Object.values(recipe.output || {})[0] || 1;
const canAfford = recipe.ingredients?.every( const canAfford = recipe.ingredients?.every(
@ -19,7 +29,7 @@ const CraftModal = ({
return ( return (
<div className="craft-modal-overlay" onClick={onClose}> <div className="craft-modal-overlay" onClick={onClose}>
<div className="craft-modal" onClick={(e) => e.stopPropagation()}> <div className="craft-modal" onClick={(e) => e.stopPropagation()}>
<div className="modal-header"> <div className="modal-headerr">
<h3> <h3>
<i className="fas fa-tools"></i> Construction: {recipe.displayName} <i className="fas fa-tools"></i> Construction: {recipe.displayName}
</h3> </h3>
@ -29,6 +39,25 @@ const CraftModal = ({
</div> </div>
<div className="modal-body"> <div className="modal-body">
{/* Секція з картинкою предмета */}
<div className="item-preview-header">
<div className="item-icon-container">
<img
src={getFullTextureUrl(recipe.texture)}
alt={recipe.displayName}
className="item-display-icon"
/>
<div className="item-qty-badge">x{outputQty}</div>
</div>
<div className="item-header-info">
<span className="item-type-tag">PROTOTYPE_UNIT</span>
<p className="item-description">
{recipe.description ||
"Technical data encrypted or unavailable."}
</p>
</div>
</div>
<div className="requirements-section"> <div className="requirements-section">
<h4> <h4>
<i className="fas fa-list-ul"></i> Required Resources <i className="fas fa-list-ul"></i> Required Resources

View File

@ -12,133 +12,184 @@
backdrop-filter: blur(4px); backdrop-filter: blur(4px);
} }
.modal-content { .datapack-modal-content {
background: #12151a; background: #0f1115;
border: 1px solid #00d2ff; border: 1px solid rgba(0, 210, 255, 0.3);
border-radius: 8px; width: 90%;
width: 100%; max-width: 450px;
max-width: 400px; border-radius: 12px;
padding: 25px;
position: relative; position: relative;
box-shadow: 0 0 30px rgba(0, 210, 255, 0.2); padding: 25px;
color: #fff; box-shadow: 0 20px 50px rgba(0, 0, 0, 0.8);
font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif; animation: modalSlideUp 0.3s ease-out;
}
.modal-close {
position: absolute;
top: 10px;
right: 15px;
background: none;
border: none;
color: #888;
font-size: 28px;
cursor: pointer;
transition: color 0.2s;
}
.modal-close:hover {
color: #fff; color: #fff;
} }
.details-header { .modal-header {
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 15px; gap: 20px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1); margin-bottom: 20px;
padding-bottom: 10px; padding-bottom: 15px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
} }
.item-name { .modal-icon-big {
width: 80px;
height: 80px;
background: rgba(0, 0, 0, 0.4);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.modal-icon-big img {
width: 60px;
height: 60px;
object-fit: contain;
}
.modal-icon-big.common {
border-color: #888;
}
.modal-icon-big.rare {
border-color: #0070dd;
box-shadow: inset 0 0 10px rgba(0, 112, 221, 0.2);
}
.modal-icon-big.epic {
border-color: #a335ee;
box-shadow: inset 0 0 10px rgba(163, 53, 238, 0.2);
}
.modal-icon-big.legendary {
border-color: #ff8000;
box-shadow: inset 0 0 10px rgba(255, 128, 0, 0.2);
}
.modal-title-group h3 {
margin: 0; margin: 0;
font-size: 1.2rem; font-family: "Orbitron", sans-serif;
font-size: 1.3rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 1px;
} }
.rarity-badge { .modal-title-group h3.common {
font-size: 0.7rem; color: #fff;
padding: 2px 8px;
border-radius: 4px;
text-transform: uppercase;
background: rgba(255, 255, 255, 0.1);
} }
.modal-title-group h3.rare {
.item-name.common { color: #00d2ff;
color: #ffffff;
} }
.item-name.uncommon { .modal-title-group h3.epic {
color: #1eff00;
}
.item-name.rare {
color: #0070dd;
}
.item-name.epic {
color: #a335ee; color: #a335ee;
} }
.item-name.legendary { .modal-title-group h3.legendary {
color: #ff8000; color: #ff8000;
} }
.item-description { .modal-raw-id {
font-size: 0.7rem;
color: #888;
margin-top: 4px;
font-family: monospace;
}
.details-description {
font-size: 0.9rem; font-size: 0.9rem;
line-height: 1.5;
color: #aaa; color: #aaa;
line-height: 1.4;
margin-bottom: 20px; margin-bottom: 20px;
font-style: italic;
}
.details-section h4 {
font-size: 0.8rem;
text-transform: uppercase;
color: #00d2ff;
letter-spacing: 1px;
margin-bottom: 10px;
border-left: 3px solid #00d2ff;
padding-left: 10px;
} }
.item-stats-container { .item-stats-container {
background: rgba(0, 0, 0, 0.3); background: rgba(0, 0, 0, 0.2);
padding: 10px; padding: 10px;
border-radius: 4px; border-radius: 8px;
margin-bottom: 25px;
} }
.stat-row { .stat-row {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
padding: 5px 0; padding: 8px 0;
font-size: 0.85rem; border-bottom: 1px solid rgba(255, 255, 255, 0.03);
}
.stat-row:last-child {
border-bottom: none;
} }
.stat-label { .stat-label {
color: #00d2ff; color: #888;
font-size: 0.85rem;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
} }
.stat-value { .stat-value {
color: #fff; color: #00ff88;
font-family: monospace;
font-weight: bold; font-weight: bold;
} }
.btn-equip { .btn-equip {
width: 100%; width: 100%;
padding: 12px; padding: 12px;
background: none; background: rgba(0, 210, 255, 0.05);
border: 1px solid #00d2ff; border: 1px solid #00d2ff;
color: #00d2ff; color: #00d2ff;
cursor: pointer; cursor: pointer;
text-transform: uppercase; font-family: "Orbitron", sans-serif;
font-weight: bold; font-size: 0.8rem;
letter-spacing: 1px;
transition: all 0.2s; transition: all 0.2s;
} }
.btn-equip:hover { .btn-equip:hover {
background: #00d2ff; background: #00d2ff;
color: #000; color: #000;
box-shadow: 0 0 15px rgba(0, 210, 255, 0.4);
} }
.btn-equip.unequip { .btn-equip.unequip {
border-color: #ff4444; border-color: #ff4444;
color: #ff4444; color: #ff4444;
background: rgba(255, 68, 68, 0.05);
} }
.btn-equip.unequip:hover { .btn-equip.unequip:hover {
background: #ff4444; background: #ff4444;
color: #fff; color: #fff;
} }
.modal-close {
position: absolute;
top: 15px;
right: 15px;
background: none;
border: none;
color: #444;
font-size: 24px;
cursor: pointer;
}
@keyframes modalSlideUp {
from {
transform: translateY(20px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}

View File

@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import "./ItemModal.css"; import "./ItemModal.css";
import { getServerUrl } from "../../../../config/api";
const ItemModal = ({ const ItemModal = ({
item, item,
@ -12,23 +13,45 @@ const ItemModal = ({
}) => { }) => {
if (!item) return null; if (!item) return null;
const CONNECT_URL = getServerUrl();
const ASSET_BASE_URL = `${CONNECT_URL}/static/`;
const getFullTextureUrl = (path) => {
if (!path) return "/assets/no-image.png";
if (path.startsWith("http")) return path;
return `${ASSET_BASE_URL}${path}`;
};
return ( return (
<div className="modal-overlay" onClick={onClose}> <div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}> <div
className="datapack-modal-content"
onClick={(e) => e.stopPropagation()}
>
<button className="modal-close" onClick={onClose}> <button className="modal-close" onClick={onClose}>
&times; &times;
</button> </button>
<div className="details-view"> <div className="modal-header">
<div className="details-header"> <div className={`modal-icon-big ${item.rarity}`}>
<h4 className={`item-name ${item.rarity}`}> <img src={getFullTextureUrl(item.texture)} alt={item.displayName} />
{item.displayName || item.name} </div>
</h4> <div className="modal-title-group">
<span className={`rarity-badge ${item.rarity}`}>{item.rarity}</span> <h3 className={item.rarity}>{item.displayName || item.name}</h3>
<div className="modal-raw-id">
{item.rarity?.toUpperCase()} SYSTEM_ID: {item.id}
</div>
</div>
</div> </div>
<p className="item-description">{item.description}</p> <div className="details-section">
<p className="details-description">{item.description}</p>
</div>
<div className="details-section">
<h4>
<i className="fas fa-microchip"></i> Technical Specs
</h4>
<div className="item-stats-container"> <div className="item-stats-container">
{item.stats && {item.stats &&
Object.entries(item.stats).map(([statName, value]) => ( Object.entries(item.stats).map(([statName, value]) => (
@ -43,7 +66,9 @@ const ItemModal = ({
</div> </div>
))} ))}
</div> </div>
</div>
<div className="modal-actions" style={{ marginTop: "20px" }}>
{isEquipped ? ( {isEquipped ? (
<button <button
className="btn-equip unequip" className="btn-equip unequip"
@ -52,7 +77,7 @@ const ItemModal = ({
onClose(); onClose();
}} }}
> >
DISCONNECT_SYSTEM TERMINATE_CONNECTION
</button> </button>
) : ( ) : (
item.canEquip && ( item.canEquip && (