[html]
<!-- ===========================================================
RPG ITEMS SHOWCASE v1.0 - HTML BLOCK VERSION
=========================================================== -->
<style>
/* СТИЛИ ВИТРИНЫ */
.rpg-showcase-container {
background: #1a202c;
border-radius: 12px;
padding: 25px;
color: #e2e8f0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.showcase-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 2px solid #2d3748;
}
.header-left h1 {
font-family: 'Alumni Sans', sans-serif;
font-size: 32px;
font-weight: 700;
color: #fff;
margin: 0 0 5px 0;
}
.header-left .subtitle {
color: #a0aec0;
font-size: 14px;
margin: 0;
}
.stats-counter {
display: flex;
gap: 25px;
}
.stat-item {
text-align: center;
}
.stat-item i {
font-size: 24px;
color: #ff6b35;
margin-bottom: 5px;
display: block;
}
.stat-value {
display: block;
font-size: 28px;
font-weight: 700;
color: #fff;
line-height: 1;
}
.stat-label {
font-size: 12px;
color: #a0aec0;
text-transform: uppercase;
letter-spacing: 1px;
}
.showcase-controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
gap: 20px;
}
.controls-left {
flex: 1;
}
.search-box {
position: relative;
margin-bottom: 15px;
}
.search-box i {
position: absolute;
left: 15px;
top: 50%;
transform: translateY(-50%);
color: #a0aec0;
}
.search-box input {
width: 100%;
padding: 12px 45px 12px 45px;
background: #2d3748;
border: 2px solid #4a5568;
border-radius: 8px;
color: #fff;
font-size: 14px;
transition: all 0.3s ease;
}
.search-box input:focus {
outline: none;
border-color: #ff6b35;
box-shadow: 0 0 0 3px rgba(255, 107, 53, 0.1);
}
.clear-search {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
color: #a0aec0;
cursor: pointer;
padding: 5px;
}
.filter-tags {
display: flex;
align-items: center;
gap: 10px;
}
.filter-label {
font-size: 12px;
color: #a0aec0;
}
.tags-container {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.filter-tag {
background: rgba(255, 107, 53, 0.1);
border: 1px solid rgba(255, 107, 53, 0.3);
border-radius: 20px;
padding: 5px 12px;
font-size: 12px;
display: flex;
align-items: center;
gap: 6px;
}
.filter-remove {
background: none;
border: none;
color: #ff6b35;
cursor: pointer;
padding: 0;
font-size: 10px;
}
.sort-controls {
display: flex;
gap: 15px;
align-items: center;
}
.sort-select {
position: relative;
}
.sort-select i {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: #a0aec0;
pointer-events: none;
}
.sort-select select {
padding: 10px 15px 10px 35px;
background: #2d3748;
border: 2px solid #4a5568;
border-radius: 6px;
color: #fff;
font-size: 13px;
cursor: pointer;
min-width: 180px;
}
.view-toggle {
display: flex;
gap: 5px;
background: #2d3748;
border-radius: 6px;
padding: 4px;
}
.view-btn {
padding: 8px 12px;
background: none;
border: none;
color: #a0aec0;
cursor: pointer;
border-radius: 4px;
transition: all 0.3s ease;
}
.view-btn.active {
background: #4a5568;
color: #fff;
}
.showcase-filters {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 25px;
margin-bottom: 30px;
padding: 20px;
background: #2d3748;
border-radius: 10px;
}
.filter-section h3 {
font-size: 16px;
margin: 0 0 15px 0;
color: #fff;
display: flex;
align-items: center;
gap: 10px;
}
.filter-options {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.filter-btn {
padding: 8px 15px;
background: #4a5568;
border: 1px solid transparent;
border-radius: 6px;
color: #e2e8f0;
font-size: 13px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 6px;
}
.filter-btn.active {
background: rgba(255, 107, 53, 0.2);
border-color: #ff6b35;
color: #ff6b35;
}
.rarity-dot {
width: 10px;
height: 10px;
border-radius: 50%;
display: inline-block;
}
.rarity-dot.legendary { background: #ff6b35; }
.rarity-dot.rare { background: #9d4edd; }
.rarity-dot.uncommon { background: #4ecdc4; }
.showcase-content {
min-height: 500px;
}
.items-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
display: none;
}
.items-grid.active {
display: grid;
}
.items-list {
display: none;
flex-direction: column;
gap: 10px;
}
.items-list.active {
display: flex;
}
.item-card {
background: #2d3748;
border-radius: 10px;
overflow: hidden;
transition: all 0.3s ease;
border: 2px solid transparent;
}
.item-card:hover {
transform: translateY(-5px);
border-color: #ff6b35;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
}
.card-header {
padding: 15px;
border-bottom: 2px solid;
display: flex;
justify-content: space-between;
align-items: center;
}
.rarity-badge {
padding: 4px 10px;
border-radius: 4px;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
color: white;
}
.card-category {
font-size: 12px;
color: #a0aec0;
display: flex;
align-items: center;
gap: 5px;
}
.card-image {
position: relative;
height: 180px;
overflow: hidden;
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.item-card:hover .card-image img {
transform: scale(1.05);
}
.image-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to bottom, transparent 50%, rgba(0,0,0,0.8));
}
.card-body {
padding: 15px;
}
.item-name {
font-size: 18px;
font-weight: 700;
margin: 0 0 5px 0;
display: flex;
align-items: center;
gap: 8px;
}
.item-type {
font-size: 14px;
color: #a0aec0;
margin-bottom: 15px;
}
.item-stats {
background: rgba(0, 0, 0, 0.2);
border-radius: 6px;
padding: 10px;
}
.stat {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
}
.card-footer {
padding: 0 15px 15px 15px;
}
.btn-details {
width: 100%;
padding: 10px;
background: linear-gradient(135deg, #ff6b35, #ff8e53);
border: none;
border-radius: 6px;
color: white;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-details:hover {
background: linear-gradient(135deg, #ff8e53, #ff6b35);
box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);
}
.item-list-item {
background: #2d3748;
border-radius: 8px;
padding: 15px;
display: flex;
align-items: center;
gap: 20px;
transition: all 0.3s ease;
}
.item-list-item:hover {
background: #4a5568;
border-left: 4px solid #ff6b35;
}
.list-image {
width: 80px;
height: 60px;
border-radius: 4px;
overflow: hidden;
flex-shrink: 0;
}
.list-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.list-content {
flex: 1;
}
.list-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.list-header .item-name {
font-size: 16px;
margin: 0;
}
.item-rarity {
font-size: 12px;
font-weight: 600;
}
.list-details {
display: flex;
gap: 20px;
}
.detail {
display: flex;
align-items: center;
gap: 5px;
font-size: 13px;
color: #a0aec0;
}
.list-actions {
flex-shrink: 0;
}
.showcase-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60px 20px;
color: #a0aec0;
text-align: center;
display: none;
}
.showcase-empty.active {
display: flex;
}
.showcase-empty h3 {
font-size: 24px;
margin: 20px 0 10px 0;
color: #fff;
}
.showcase-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #2d3748;
}
.pagination {
display: flex;
align-items: center;
gap: 10px;
}
.page-btn {
padding: 8px 16px;
background: #2d3748;
border: 1px solid #4a5568;
border-radius: 6px;
color: #e2e8f0;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
transition: all 0.3s ease;
}
.page-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.page-btn:not(:disabled):hover {
background: #4a5568;
border-color: #ff6b35;
}
.page-numbers {
display: flex;
gap: 5px;
}
.page-number {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: #2d3748;
border: 1px solid #4a5568;
border-radius: 6px;
color: #e2e8f0;
cursor: pointer;
transition: all 0.3s ease;
}
.page-number.active {
background: #ff6b35;
border-color: #ff6b35;
color: white;
}
.page-number:hover:not(.active) {
background: #4a5568;
border-color: #ff6b35;
}
.page-dots {
display: flex;
align-items: center;
padding: 0 5px;
color: #a0aec0;
}
.items-per-page {
display: flex;
align-items: center;
gap: 10px;
}
.items-per-page select {
padding: 8px 12px;
background: #2d3748;
border: 1px solid #4a5568;
border-radius: 6px;
color: #fff;
cursor: pointer;
}
.item-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
z-index: 1000;
align-items: center;
justify-content: center;
padding: 20px;
}
.modal-content {
background: #1a202c;
border-radius: 12px;
width: 100%;
max-width: 800px;
max-height: 90vh;
overflow-y: auto;
position: relative;
border: 2px solid #ff6b35;
}
.modal-close {
position: absolute;
top: 15px;
right: 15px;
background: none;
border: none;
color: #a0aec0;
font-size: 20px;
cursor: pointer;
z-index: 1;
}
.modal-body {
padding: 30px;
}
.modal-header {
margin-bottom: 25px;
}
.modal-title h2 {
font-size: 28px;
margin: 0 0 10px 0;
}
.modal-subtitle {
display: flex;
gap: 15px;
align-items: center;
}
.modal-subtitle span {
padding: 5px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
}
.item-category {
background: rgba(78, 205, 196, 0.1);
border: 1px solid #4ecdc4;
color: #4ecdc4;
}
.modal-body-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
}
.modal-image {
border-radius: 8px;
overflow: hidden;
height: 300px;
}
.modal-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.modal-info {
display: flex;
flex-direction: column;
gap: 25px;
}
.info-section h3 {
font-size: 18px;
margin: 0 0 15px 0;
color: #fff;
display: flex;
align-items: center;
gap: 10px;
}
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
.info-item {
display: flex;
flex-direction: column;
gap: 5px;
}
.info-label {
font-size: 13px;
color: #a0aec0;
display: flex;
align-items: center;
gap: 6px;
}
.info-value {
font-size: 16px;
font-weight: 600;
color: #fff;
}
.stats-bars {
display: flex;
flex-direction: column;
gap: 15px;
}
.stat-bar {
display: flex;
align-items: center;
gap: 15px;
}
.stat-label {
width: 80px;
font-size: 14px;
color: #a0aec0;
}
.stat-progress {
flex: 1;
height: 8px;
background: #2d3748;
border-radius: 4px;
overflow: hidden;
}
.stat-fill {
height: 100%;
border-radius: 4px;
}
@media (max-width: 768px) {
.showcase-header {
flex-direction: column;
align-items: flex-start;
gap: 20px;
}
.showcase-controls {
flex-direction: column;
align-items: stretch;
}
.controls-right {
width: 100%;
}
.modal-body-content {
grid-template-columns: 1fr;
}
.items-grid {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.item-list-item {
flex-direction: column;
align-items: stretch;
gap: 15px;
}
.list-header {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
.list-details {
flex-direction: column;
gap: 10px;
}
}
</style>
<script>
// ===========================================================
// RPG ITEMS SHOWCASE v1.0 - JavaScript
// ===========================================================
// База данных предметов (можно загрузить из внешнего файла)
const ITEMS_DATABASE = {
'Акцельтра': {
name: 'Акцельтра',
type: 'винтовка',
category: 'первичное оружие',
rarity: 'легенда',
image: 'https://upforme.ru/uploads/001c/92/09/2/965755.png',
icon: 'fas fa-gun',
value: 0
},
'Бронко': {
name: 'Бронко',
type: 'пистолет',
category: 'вторичное оружие',
rarity: 'штамповка',
image: 'https://upforme.ru/uploads/001c/92/09/2/965755.png',
icon: 'fas fa-gun',
value: 20
},
'Бо': {
name: 'Бо',
type: 'шест',
category: 'оружие ближнего боя',
rarity: 'раритет',
image: 'https://upforme.ru/uploads/001c/92/09/2/965755.png',
icon: 'fas fa-staff',
value: 30
},
'Бассоцист': {
name: 'Бассоцист',
type: 'дробовик',
category: 'первичное оружие',
rarity: 'легенда',
image: 'https://upforme.ru/uploads/001c/92/09/2/965755.png',
icon: 'fas fa-gun',
value: 50
},
'Катана': {
name: 'Катана',
type: 'меч',
category: 'оружие ближнего боя',
rarity: 'штамповка',
image: 'https://upforme.ru/uploads/001c/92/09/2/965755.png',
icon: 'fas fa-sword',
value: 40
},
'Токсики': {
name: 'Токсики',
type: 'пистолет',
category: 'вторичное оружие',
rarity: 'раритет',
image: 'https://upforme.ru/uploads/001c/92/09/2/965755.png',
icon: 'fas fa-gun',
value: 25
},
'Акариус': {
name: 'Акариус',
type: 'пистолет',
category: 'вторичное оружие',
rarity: 'легенда',
image: 'https://upforme.ru/uploads/001c/92/09/2/965755.png',
icon: 'fas fa-gun',
value: 60
},
'Цист': {
name: 'Цист',
type: 'мачете',
category: 'оружие ближнего боя',
rarity: 'легенда',
image: 'https://upforme.ru/uploads/001c/92/09/2/965755.png',
icon: 'fas fa-machete',
value: 45
},
'Споромёт': {
name: 'Споромёт',
type: 'дробовик',
category: 'первичное оружие',
rarity: 'раритет',
image: 'https://upforme.ru/uploads/001c/92/09/2/965755.png',
icon: 'fas fa-gun',
value: 25
},
'Споротрикс': {
name: 'Споротрикс',
type: 'винтовка',
category: 'первичное оружие',
rarity: 'раритет',
image: 'https://upforme.ru/uploads/001c/92/09/2/965755.png',
icon: 'fas fa-gun',
value: 30
}
};
// Конфигурация витрины
const SHOWCASE_CONFIG = {
itemsPerPage: 12,
defaultSort: 'name',
defaultSortDirection: 'asc',
rarityColors: {
'легенда': '#ff6b35',
'раритет': '#9d4edd',
'штамповка': '#4ecdc4',
'обычный': '#a0aec0'
},
categoryIcons: {
'первичное оружие': 'fas fa-gun',
'вторичное оружие': 'fas fa-gun',
'оружие ближнего боя': 'fas fa-sword',
'разное': 'fas fa-box'
},
typeIcons: {
'винтовка': 'fas fa-crosshairs',
'пистолет': 'fas fa-gun',
'шест': 'fas fa-staff',
'дробовик': 'fas fa-gun',
'меч': 'fas fa-sword',
'мачете': 'fas fa-machete'
}
};
// Класс витрины
class RPGItemsShowcase {
constructor(containerId) {
this.items = Object.values(ITEMS_DATABASE);
this.filteredItems = [...this.items];
this.currentPage = 1;
this.sortBy = SHOWCASE_CONFIG.defaultSort;
this.sortDirection = SHOWCASE_CONFIG.defaultSortDirection;
this.currentCategory = 'all';
this.currentRarity = 'all';
this.containerId = containerId;
this.init();
}
init() {
this.createHTML();
this.renderItems();
this.setupEventListeners();
this.updateStats();
}
createHTML() {
const container = document.getElementById(this.containerId);
if (!container) {
console.error('Контейнер не найден');
return;
}
container.innerHTML = `
<div class="rpg-showcase-container">
<div class="showcase-header">
<div class="header-left">
<h1><i class="fas fa-warehouse"></i> ОРУЖЕЙНАЯ</h1>
<p class="subtitle">База данных вооружения и снаряжения</p>
</div>
<div class="header-right">
<div class="stats-counter">
<div class="stat-item">
<i class="fas fa-boxes"></i>
<span class="stat-value" id="total-items">0</span>
<span class="stat-label">Предметов</span>
</div>
<div class="stat-item">
<i class="fas fa-layer-group"></i>
<span class="stat-value" id="total-categories">0</span>
<span class="stat-label">Категорий</span>
</div>
</div>
</div>
</div>
<div class="showcase-controls">
<div class="controls-left">
<div class="search-box">
<i class="fas fa-search"></i>
<input type="text" id="item-search" placeholder="Поиск предмета...">
<button class="clear-search" id="clear-search">
<i class="fas fa-times"></i>
</button>
</div>
<div class="filter-tags">
<span class="filter-label"><i class="fas fa-filter"></i> Фильтры:</span>
<div class="tags-container" id="active-filters"></div>
</div>
</div>
<div class="controls-right">
<div class="sort-controls">
<div class="sort-select">
<i class="fas fa-sort-amount-down"></i>
<select id="sort-select">
<option value="name">Имя (А-Я)</option>
<option value="name-desc">Имя (Я-А)</option>
<option value="value">Цена (низкая)</option>
<option value="value-desc">Цена (высокая)</option>
<option value="rarity">Редкость</option>
<option value="category">Категория</option>
<option value="type">Тип</option>
</select>
</div>
<div class="view-toggle">
<button class="view-btn active" data-view="grid">
<i class="fas fa-th"></i>
</button>
<button class="view-btn" data-view="list">
<i class="fas fa-list"></i>
</button>
</div>
</div>
</div>
</div>
<div class="showcase-filters">
<div class="filter-section">
<h3><i class="fas fa-tags"></i> Редкость</h3>
<div class="filter-options rarity-filters">
<button class="filter-btn active" data-filter="rarity" data-value="all">Все</button>
<button class="filter-btn" data-filter="rarity" data-value="легенда">
<span class="rarity-dot legendary"></span> Легенда
</button>
<button class="filter-btn" data-filter="rarity" data-value="раритет">
<span class="rarity-dot rare"></span> Раритет
</button>
<button class="filter-btn" data-filter="rarity" data-value="штамповка">
<span class="rarity-dot uncommon"></span> Штамповка
</button>
</div>
</div>
<div class="filter-section">
<h3><i class="fas fa-folder"></i> Категория</h3>
<div class="filter-options category-filters">
<button class="filter-btn active" data-filter="category" data-value="all">Все</button>
<button class="filter-btn" data-filter="category" data-value="первичное оружие">
<i class="fas fa-gun"></i> Первичное
</button>
<button class="filter-btn" data-filter="category" data-value="вторичное оружие">
<i class="fas fa-gun"></i> Вторичное
</button>
<button class="filter-btn" data-filter="category" data-value="оружие ближнего боя">
<i class="fas fa-sword"></i> Ближний бой
</button>
</div>
</div>
</div>
<div class="showcase-content">
<div class="items-grid active" id="items-grid"></div>
<div class="items-list" id="items-list"></div>
<div class="showcase-empty" id="no-results">
<i class="fas fa-search fa-3x"></i>
<h3>Ничего не найдено</h3>
<p>Попробуйте изменить фильтры или поисковый запрос</p>
</div>
</div>
<div class="showcase-footer">
<div class="pagination">
<button class="page-btn prev" id="prev-page" disabled>
<i class="fas fa-chevron-left"></i> Назад
</button>
<div class="page-numbers" id="page-numbers"></div>
<button class="page-btn next" id="next-page">
Далее <i class="fas fa-chevron-right"></i>
</button>
</div>
<div class="items-per-page">
<span>Показать:</span>
<select id="items-per-page">
<option value="12">12</option>
<option value="24">24</option>
<option value="48">48</option>
<option value="all">Все</option>
</select>
</div>
</div>
<div class="item-modal" id="item-modal">
<div class="modal-content">
<button class="modal-close" id="modal-close">
<i class="fas fa-times"></i>
</button>
<div class="modal-body" id="modal-body"></div>
</div>
</div>
</div>
`;
// Сохраняем ссылки на элементы
this.elements = {
container: container.querySelector('.rpg-showcase-container'),
grid: document.getElementById('items-grid'),
list: document.getElementById('items-list'),
search: document.getElementById('item-search'),
clearSearch: document.getElementById('clear-search'),
sortSelect: document.getElementById('sort-select'),
viewButtons: document.querySelectorAll('.view-btn'),
filterButtons: document.querySelectorAll('.filter-btn'),
activeFilters: document.getElementById('active-filters'),
noResults: document.getElementById('no-results'),
prevPage: document.getElementById('prev-page'),
nextPage: document.getElementById('next-page'),
pageNumbers: document.getElementById('page-numbers'),
itemsPerPage: document.getElementById('items-per-page'),
modal: document.getElementById('item-modal'),
modalClose: document.getElementById('modal-close'),
modalBody: document.getElementById('modal-body'),
totalItems: document.getElementById('total-items'),
totalCategories: document.getElementById('total-categories')
};
}
setupEventListeners() {
// Поиск
this.elements.search.addEventListener('input', (e) => {
this.filterItems();
this.updateActiveFilters();
});
this.elements.clearSearch.addEventListener('click', () => {
this.elements.search.value = '';
this.filterItems();
this.updateActiveFilters();
});
// Сортировка
this.elements.sortSelect.addEventListener('change', (e) => {
const value = e.target.value;
if (value.includes('-desc')) {
this.sortBy = value.replace('-desc', '');
this.sortDirection = 'desc';
} else {
this.sortBy = value;
this.sortDirection = 'asc';
}
this.sortItems();
this.renderItems();
});
// Переключение вида
this.elements.viewButtons.forEach(btn => {
btn.addEventListener('click', (e) => {
const view = e.target.closest('.view-btn').dataset.view;
this.elements.viewButtons.forEach(b => b.classList.remove('active'));
e.target.closest('.view-btn').classList.add('active');
this.elements.grid.classList.toggle('active', view === 'grid');
this.elements.list.classList.toggle('active', view === 'list');
});
});
// Фильтры
this.elements.filterButtons.forEach(btn => {
btn.addEventListener('click', (e) => {
const filter = e.target.closest('.filter-btn').dataset.filter;
const value = e.target.closest('.filter-btn').dataset.value;
// Сбрасываем другие кнопки в этой группе
if (value !== 'all') {
document.querySelectorAll(`.filter-btn[data-filter="${filter}"]`)
.forEach(b => b.classList.remove('active'));
} else {
document.querySelectorAll(`.filter-btn[data-filter="${filter}"]`)
.forEach(b => b.classList.remove('active'));
}
e.target.closest('.filter-btn').classList.add('active');
if (filter === 'category') this.currentCategory = value;
if (filter === 'rarity') this.currentRarity = value;
this.filterItems();
this.updateActiveFilters();
});
});
// Пагинация
this.elements.prevPage.addEventListener('click', () => {
if (this.currentPage > 1) {
this.currentPage--;
this.renderItems();
this.updatePagination();
}
});
this.elements.nextPage.addEventListener('click', () => {
const totalPages = Math.ceil(this.filteredItems.length / SHOWCASE_CONFIG.itemsPerPage);
if (this.currentPage < totalPages) {
this.currentPage++;
this.renderItems();
this.updatePagination();
}
});
// Количество предметов на странице
this.elements.itemsPerPage.addEventListener('change', (e) => {
SHOWCASE_CONFIG.itemsPerPage = e.target.value === 'all' ? this.filteredItems.length : parseInt(e.target.value);
this.currentPage = 1;
this.renderItems();
this.updatePagination();
});
// Модальное окно
this.elements.modalClose.addEventListener('click', () => {
this.elements.modal.style.display = 'none';
});
this.elements.modal.addEventListener('click', (e) => {
if (e.target === this.elements.modal) {
this.elements.modal.style.display = 'none';
}
});
// Закрытие по ESC
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && this.elements.modal.style.display === 'block') {
this.elements.modal.style.display = 'none';
}
});
}
filterItems() {
const searchTerm = this.elements.search.value.toLowerCase();
this.filteredItems = this.items.filter(item => {
// Поиск
const matchesSearch = !searchTerm ||
item.name.toLowerCase().includes(searchTerm) ||
item.type.toLowerCase().includes(searchTerm) ||
item.category.toLowerCase().includes(searchTerm);
// Фильтр по категории
const matchesCategory = this.currentCategory === 'all' ||
item.category === this.currentCategory;
// Фильтр по редкости
const matchesRarity = this.currentRarity === 'all' ||
item.rarity === this.currentRarity;
return matchesSearch && matchesCategory && matchesRarity;
});
this.sortItems();
this.currentPage = 1;
this.renderItems();
this.updatePagination();
this.updateStats();
}
sortItems() {
this.filteredItems.sort((a, b) => {
let aValue, bValue;
switch (this.sortBy) {
case 'name':
aValue = a.name.toLowerCase();
bValue = b.name.toLowerCase();
break;
case 'value':
aValue = a.value;
bValue = b.value;
break;
case 'rarity':
const rarityOrder = { 'легенда': 4, 'раритет': 3, 'штамповка': 2, 'обычный': 1 };
aValue = rarityOrder[a.rarity] || 0;
bValue = rarityOrder[b.rarity] || 0;
break;
case 'category':
aValue = a.category;
bValue = b.category;
break;
case 'type':
aValue = a.type;
bValue = b.type;
break;
default:
aValue = a.name.toLowerCase();
bValue = b.name.toLowerCase();
}
if (aValue < bValue) return this.sortDirection === 'asc' ? -1 : 1;
if (aValue > bValue) return this.sortDirection === 'asc' ? 1 : -1;
return 0;
});
}
renderItems() {
const startIndex = (this.currentPage - 1) * SHOWCASE_CONFIG.itemsPerPage;
const endIndex = startIndex + SHOWCASE_CONFIG.itemsPerPage;
const pageItems = this.filteredItems.slice(startIndex, endIndex);
// Показываем/скрываем сообщение "нет результатов"
this.elements.noResults.classList.toggle('active', this.filteredItems.length === 0);
// Очищаем контейнеры
this.elements.grid.innerHTML = '';
this.elements.list.innerHTML = '';
if (pageItems.length === 0) return;
// Рендерим карточки
pageItems.forEach(item => {
this.elements.grid.appendChild(this.createItemCard(item));
this.elements.list.appendChild(this.createListItem(item));
});
}
createItemCard(item) {
const card = document.createElement('div');
card.className = 'item-card';
card.dataset.id = item.name;
const rarityColor = SHOWCASE_CONFIG.rarityColors[item.rarity] || '#a0aec0';
card.innerHTML = `
<div class="card-header" style="border-color: ${rarityColor}">
<div class="rarity-badge" style="background: ${rarityColor}">
${item.rarity}
</div>
<div class="card-category">
<i class="${SHOWCASE_CONFIG.categoryIcons[item.category] || 'fas fa-box'}"></i>
${item.category}
</div>
</div>
<div class="card-image">
<img src="${item.image}"
alt="${item.name}"
onerror="this.onerror=null; this.src='https://via.placeholder.com/200x150/2d3748/ffffff?text=No+Image'">
<div class="image-overlay"></div>
</div>
<div class="card-body">
<h3 class="item-name" style="color: ${rarityColor}">
<i class="${SHOWCASE_CONFIG.typeIcons[item.type] || 'fas fa-question'}"></i>
${item.name}
</h3>
<div class="item-type">${item.type}</div>
<div class="item-stats">
<div class="stat">
<i class="fas fa-coins"></i>
<span>${item.value} кредитов</span>
</div>
</div>
</div>
<div class="card-footer">
<button class="btn-details" data-id="${item.name}">
<i class="fas fa-info-circle"></i> Подробнее
</button>
</div>
`;
card.querySelector('.btn-details').addEventListener('click', (e) => {
e.stopPropagation();
this.showItemDetails(item);
});
return card;
}
createListItem(item) {
const listItem = document.createElement('div');
listItem.className = 'item-list-item';
listItem.dataset.id = item.name;
const rarityColor = SHOWCASE_CONFIG.rarityColors[item.rarity] || '#a0aec0';
listItem.innerHTML = `
<div class="list-image">
<img src="${item.image}"
alt="${item.name}"
onerror="this.onerror=null; this.src='https://via.placeholder.com/80x60/2d3748/ffffff?text=No+Image'">
</div>
<div class="list-content">
<div class="list-header">
<h3 class="item-name" style="color: ${rarityColor}">
${item.name}
</h3>
<span class="item-rarity" style="color: ${rarityColor}">
<i class="fas fa-star"></i> ${item.rarity}
</span>
</div>
<div class="list-details">
<div class="detail">
<i class="${SHOWCASE_CONFIG.categoryIcons[item.category] || 'fas fa-box'}"></i>
${item.category}
</div>
<div class="detail">
<i class="${SHOWCASE_CONFIG.typeIcons[item.type] || 'fas fa-question'}"></i>
${item.type}
</div>
<div class="detail">
<i class="fas fa-coins"></i>
${item.value} кредитов
</div>
</div>
</div>
<div class="list-actions">
<button class="btn-details" data-id="${item.name}">
<i class="fas fa-eye"></i> Просмотр
</button>
</div>
`;
listItem.querySelector('.btn-details').addEventListener('click', (e) => {
e.stopPropagation();
this.showItemDetails(item);
});
return listItem;
}
showItemDetails(item) {
const rarityColor = SHOWCASE_CONFIG.rarityColors[item.rarity] || '#a0aec0';
this.elements.modalBody.innerHTML = `
<div class="modal-header">
<div class="modal-title">
<h2 style="color: ${rarityColor}">${item.name}</h2>
<div class="modal-subtitle">
<span class="item-rarity" style="background: ${rarityColor}">${item.rarity}</span>
<span class="item-category">${item.category}</span>
</div>
</div>
</div>
<div class="modal-body-content">
<div class="modal-image">
<img src="${item.image}"
alt="${item.name}"
onerror="this.onerror=null; this.src='https://via.placeholder.com/400x300/2d3748/ffffff?text=No+Image'">
</div>
<div class="modal-info">
<div class="info-section">
<h3><i class="fas fa-info-circle"></i> Информация</h3>
<div class="info-grid">
<div class="info-item">
<span class="info-label"><i class="fas fa-tag"></i> Тип:</span>
<span class="info-value">${item.type}</span>
</div>
<div class="info-item">
<span class="info-label"><i class="fas fa-layer-group"></i> Категория:</span>
<span class="info-value">${item.category}</span>
</div>
<div class="info-item">
<span class="info-label"><i class="fas fa-star"></i> Редкость:</span>
<span class="info-value" style="color: ${rarityColor}">${item.rarity}</span>
</div>
<div class="info-item">
<span class="info-label"><i class="fas fa-coins"></i> Ценность:</span>
<span class="info-value">${item.value} кредитов</span>
</div>
</div>
</div>
<div class="info-section">
<h3><i class="fas fa-history"></i> История предмета</h3>
<p>Этот предмет доступен в базе данных оружия. Может быть получен различными способами в игре.</p>
</div>
<div class="info-section">
<h3><i class="fas fa-chart-bar"></i> Статистика</h3>
<div class="stats-bars">
<div class="stat-bar">
<span class="stat-label">Урон:</span>
<div class="stat-progress">
<div class="stat-fill" style="width: ${Math.min(item.value * 2, 100)}%; background: ${rarityColor}"></div>
</div>
</div>
<div class="stat-bar">
<span class="stat-label">Точность:</span>
<div class="stat-progress">
<div class="stat-fill" style="width: ${Math.min(item.value * 1.5, 100)}%; background: ${rarityColor}"></div>
</div>
</div>
<div class="stat-bar">
<span class="stat-label">Скорость:</span>
<div class="stat-progress">
<div class="stat-fill" style="width: ${Math.min(item.value * 1.2, 100)}%; background: ${rarityColor}"></div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
this.elements.modal.style.display = 'block';
}
updateActiveFilters() {
const filters = [];
if (this.elements.search.value) {
filters.push({
type: 'search',
label: `Поиск: "${this.elements.search.value}"`,
clear: () => {
this.elements.search.value = '';
this.filterItems();
}
});
}
if (this.currentCategory !== 'all') {
filters.push({
type: 'category',
label: `Категория: ${this.currentCategory}`,
clear: () => {
document.querySelector(`.filter-btn[data-filter="category"][data-value="all"]`).click();
}
});
}
if (this.currentRarity !== 'all') {
filters.push({
type: 'rarity',
label: `Редкость: ${this.currentRarity}`,
clear: () => {
document.querySelector(`.filter-btn[data-filter="rarity"][data-value="all"]`).click();
}
});
}
this.elements.activeFilters.innerHTML = filters.map(filter => `
<span class="filter-tag">
${filter.label}
<button class="filter-remove" data-type="${filter.type}">
<i class="fas fa-times"></i>
</button>
</span>
`).join('');
// Добавляем обработчики для кнопок удаления фильтров
this.elements.activeFilters.querySelectorAll('.filter-remove').forEach(btn => {
btn.addEventListener('click', (e) => {
const type = e.target.closest('.filter-remove').dataset.type;
const filter = filters.find(f => f.type === type);
if (filter) filter.clear();
});
});
}
updatePagination() {
const totalItems = this.filteredItems.length;
const totalPages = Math.ceil(totalItems / SHOWCASE_CONFIG.itemsPerPage);
// Обновляем кнопки
this.elements.prevPage.disabled = this.currentPage === 1;
this.elements.nextPage.disabled = this.currentPage === totalPages;
// Обновляем номера страниц
let pagesHTML = '';
const maxVisible = 5;
let startPage = Math.max(1, this.currentPage - Math.floor(maxVisible / 2));
let endPage = Math.min(totalPages, startPage + maxVisible - 1);
if (endPage - startPage + 1 < maxVisible) {
startPage = Math.max(1, endPage - maxVisible + 1);
}
if (startPage > 1) {
pagesHTML += `<button class="page-number" data-page="1">1</button>`;
if (startPage > 2) pagesHTML += `<span class="page-dots">...</span>`;
}
for (let i = startPage; i <= endPage; i++) {
pagesHTML += `
<button class="page-number ${i === this.currentPage ? 'active' : ''}" data-page="${i}">
${i}
</button>
`;
}
if (endPage < totalPages) {
if (endPage < totalPages - 1) pagesHTML += `<span class="page-dots">...</span>`;
pagesHTML += `<button class="page-number" data-page="${totalPages}">${totalPages}</button>`;
}
this.elements.pageNumbers.innerHTML = pagesHTML;
// Добавляем обработчики для номеров страниц
this.elements.pageNumbers.querySelectorAll('.page-number').forEach(btn => {
btn.addEventListener('click', (e) => {
const page = parseInt(e.target.dataset.page);
if (page !== this.currentPage) {
this.currentPage = page;
this.renderItems();
this.updatePagination();
}
});
});
}
updateStats() {
const categories = new Set(this.items.map(item => item.category));
this.elements.totalItems.textContent = this.filteredItems.length;
this.elements.totalCategories.textContent = categories.size;
}
}
// Инициализация витрины при загрузке страницы
document.addEventListener('DOMContentLoaded', function() {
// Создаем контейнер для витрины
const showcaseContainer = document.createElement('div');
showcaseContainer.id = 'rpg-items-showcase';
document.body.appendChild(showcaseContainer);
// Инициализируем витрину
const showcase = new RPGItemsShowcase('rpg-items-showcase');
console.log('🎮 RPG Items Showcase загружен!');
});
</script>
<!-- Контейнер для витрины -->
<div id="rpg-items-showcase"></div>
<script>
// Инициализация витрины (альтернативный способ)
window.addEventListener('load', function() {
if (!document.getElementById('rpg-items-showcase').querySelector('.rpg-showcase-container')) {
const showcase = new RPGItemsShowcase('rpg-items-showcase');
}
});
</script>
[/html]
