Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 45 additions & 13 deletions src/components/Equipment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function Equipment({ adminMode = false }: { adminMode?: boolean }) {
const selectedSlots = searchParams.getAll("slot");
const compatibleWeapon = searchParams.get("weapon") || "";
const sort = searchParams.get("sort") || "name";
const showHidden = searchParams.get("hidden") === "1";
const hiddenSectionActive = searchParams.get("section") === "hidden";
const selectedId = searchParams.get("item");
const changes = Object.entries(draft).filter(([, value]) => value.category || value.hidden !== undefined);

Expand Down Expand Up @@ -230,6 +230,7 @@ export function Equipment({ adminMode = false }: { adminMode?: boolean }) {
next.delete(name);
for (const entry of values) next.append(name, entry);
next.delete("item");
if (name === "category") next.delete("section");
});
}

Expand All @@ -238,6 +239,17 @@ export function Equipment({ adminMode = false }: { adminMode?: boolean }) {
next.delete("category");
next.append("category", category);
next.delete("item");
next.delete("section");
});
setFiltersOpen(false);
window.requestAnimationFrame(() => resultsTop.current?.scrollIntoView({ behavior: "smooth", block: "start" }));
}

function openHiddenSection() {
patchParams((next) => {
next.delete("category");
next.delete("item");
next.set("section", "hidden");
});
setFiltersOpen(false);
window.requestAnimationFrame(() => resultsTop.current?.scrollIntoView({ behavior: "smooth", block: "start" }));
Expand All @@ -259,13 +271,13 @@ export function Equipment({ adminMode = false }: { adminMode?: boolean }) {
.filter(Boolean)
.some((value) => normalize(String(value)).includes(normalized));
const slots = new Set((item.attachableTo || []).map((slot) => slot.slotName || slot.name || ""));
const matchesCategory = ignoredFacet === "category" || !selectedCategories.length
const matchesCategory = hiddenSectionActive || ignoredFacet === "category" || !selectedCategories.length
|| selectedCategories.includes(effectiveCategory(id, item));
const matchesSlot = ignoredFacet === "slot" || !selectedSlots.length
|| selectedSlots.some((slot) => slots.has(slot));
const matchesWeapon = !compatibleWeapon || itemCompatibleWith(item, compatibleWeapon);
const override = draft[id];
const matchesVisibility = !adminMode || showHidden || override?.hidden !== true;
const matchesVisibility = !adminMode || hiddenSectionActive === (override?.hidden === true);
return matchesQuery && matchesCategory && matchesSlot && matchesWeapon && matchesVisibility;
};

Expand Down Expand Up @@ -319,14 +331,30 @@ export function Equipment({ adminMode = false }: { adminMode?: boolean }) {
return counts;
})();

const hiddenCount = (() => {
if (!catalog) return 0;
const normalized = normalize(query);
let count = 0;
for (const id of publicIds) {
if (draft[id]?.hidden !== true) continue;
const item = catalog.items[id];
if (!item) continue;
const matchesQuery = !normalized || [item.name, descriptionText(item.description), id]
.filter(Boolean)
.some((value) => normalize(String(value)).includes(normalized));
if (matchesQuery) count += 1;
}
return count;
})();

const activeFilters = [
...selectedCategories.map((value) => ({ key: `category:${value}`, label: value, clear: () => toggleParam("category", value) })),
...selectedSlots.map((value) => ({ key: `slot:${value}`, label: `Обвес: ${value}`, clear: () => toggleParam("slot", value) })),
...(compatibleWeapon && catalog?.items[compatibleWeapon]
? [{ key: "weapon", label: `Для: ${catalog.items[compatibleWeapon].name}`, clear: () => setParam("weapon", null) }]
: []),
...(adminMode && showHidden
? [{ key: "hidden", label: "Показаны скрытые", clear: () => setParam("hidden", null) }]
...(hiddenSectionActive
? [{ key: "hidden", label: "Раздел «Скрытые»", clear: () => setParam("section", null) }]
: []),
];

Expand Down Expand Up @@ -459,15 +487,16 @@ export function Equipment({ adminMode = false }: { adminMode?: boolean }) {
</div>
);
})}
{adminMode && (
<div className={`category-row hidden-section-row${hiddenSectionActive ? " is-selected" : ""}`}>
<button type="button" onClick={openHiddenSection} disabled={!hiddenCount && !hiddenSectionActive}>
<span>Скрытые</span>
<small>{hiddenCount}</small>
</button>
</div>
)}
</div>

{adminMode && (
<label className="check-option admin-visibility-filter">
<input type="checkbox" checked={showHidden} onChange={(event) => setParam("hidden", event.target.checked ? "1" : null)} />
<span>Показать скрытые</span>
</label>
)}

{attachmentSlots.length > 0 && (
<details className="filter-disclosure">
<summary>Место установки обвеса</summary>
Expand Down Expand Up @@ -543,7 +572,10 @@ export function Equipment({ adminMode = false }: { adminMode?: boolean }) {
</label>
)}
<button className="equipment-card-main" onClick={() => setParam("item", id)} aria-haspopup="dialog">
<span className="equipment-section">{effectiveCategory(id, item)}</span>
<span className="equipment-card-heading">
<span className="equipment-section">{effectiveCategory(id, item)}</span>
{adminMode && override && <span className="edited-badge">Изменено</span>}
</span>
<Sprite item={item} />
<strong>{capitalizeName(item.name)}</strong>
<small className="equipment-id">{item.id}</small>
Expand Down
28 changes: 16 additions & 12 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ nav a:hover, nav a.active { color: #c7ee7a; font-weight: 700; }
.category-row:hover { border-color: #b5bbc3; }
.category-row.is-selected { border-color: #7d858f; background: #eef0f3; }
.category-row:has(button:disabled) { opacity: 0.45; }
.hidden-section-row { grid-template-columns: minmax(0, 1fr); border-color: #a96565; }
.hidden-section-row.is-selected { border-color: var(--uscm-red, #a96565); background: #2a1c1c; }
.hidden-section-row > button { color: #a96565; }
.category-check { position: relative; display: grid; place-items: center; border-right: 1px solid #e1e4e8; cursor: pointer; }
.category-check input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.category-check span { width: 15px; height: 15px; border: 1px solid #8f969f; border-radius: 4px; background: #fff; }
Expand Down Expand Up @@ -133,16 +136,18 @@ nav a:hover, nav a.active { color: #c7ee7a; font-weight: 700; }
.admin-grid { grid-auto-rows: auto; }
.admin-grid .equipment-card { height: 378px; }
.equipment-card.is-edited { position: relative; }
.equipment-card.is-edited::after {
content: "";
position: absolute;
top: 7px;
right: 7px;
width: 5px;
height: 5px;
border-radius: 50%;
background: rgba(157, 122, 52, 0.55);
pointer-events: none;
.equipment-card-heading { display: flex; align-items: center; gap: 6px; width: 100%; }
.edited-badge {
padding: 2px 6px;
border: 1px solid #664c2a;
border-radius: 2px;
background: #261f15;
color: var(--uscm-amber, #e7ba70);
font-size: 0.6rem;
font-weight: 700;
letter-spacing: 0.03em;
text-transform: uppercase;
white-space: nowrap;
}
.equipment-card.is-admin-selected { box-shadow: 0 0 0 2px rgba(68, 86, 106, 0.2); }
.equipment-card.is-hidden .equipment-card-main { opacity: 0.48; }
Expand Down Expand Up @@ -257,7 +262,6 @@ nav a:hover, nav a.active { color: #c7ee7a; font-weight: 700; }
.admin-sync-status.is-error { background: #fbefef; color: #8a3434; }
.bulk-category { display: grid; gap: 3px; color: #69727e; font-size: 0.68rem; }
.bulk-category select { min-height: 36px; padding: 7px 9px; border: 1px solid #c9ced5; border-radius: 7px; background: #fff; color: #303741; }
.admin-visibility-filter { margin-top: 16px; padding-top: 16px; border-top: 1px solid #e3e6ea; }
.back-to-top { position: fixed; right: 22px; bottom: 22px; z-index: 35; padding: 10px 13px; border: 1px solid #c9ced5; border-radius: 999px; background: #fff; color: #303741; font-weight: 700; box-shadow: 0 8px 24px rgba(23, 28, 35, 0.14); cursor: pointer; }

.placeholder-page { max-width: 820px; }
Expand Down Expand Up @@ -343,7 +347,7 @@ nav a:hover, nav a.active { color: #c7ee7a; font-weight: 700; }
.category-row > button small, .check-option small { color: #829082; }
.check-option { color: #c0cabd; }
.check-option input { accent-color: #a8d860; }
.filter-select, .filter-disclosure, .admin-visibility-filter { border-color: #354236; }
.filter-select, .filter-disclosure { border-color: #354236; }
.filter-disclosure summary { color: #d5dfd1; }
.reset-filters, .mobile-filter-button, .active-filters button, .button-link, .item-link-list button, .admin-toolbar button, .back-to-top { border-color: #465847; border-radius: 2px; background: #171f18; color: #d8e2d4; }
.reset-filters:hover:not(:disabled), .mobile-filter-button:hover, .active-filters button:hover, .button-link:hover, .item-link-list button:hover, .admin-toolbar button:hover:not(:disabled), .back-to-top:hover { border-color: #b1e06d; color: #d8ff9b; }
Expand Down
Loading