From f199bcfa3445835258bb370d49a0d10d7d11769f Mon Sep 17 00:00:00 2001
From: KoalaTrapLord <265133236+KoalaTrapLord@users.noreply.github.com>
Date: Wed, 25 Mar 2026 08:31:12 -0400
Subject: [PATCH] feat: column visibility toggle UI for collection table
---
ui/collection.css | 95 +++++++++++++++++++++++++++++++++++++++++++++
ui/collection.js | 98 +++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 186 insertions(+), 7 deletions(-)
diff --git a/ui/collection.css b/ui/collection.css
index f16ec86..a2a0adc 100644
--- a/ui/collection.css
+++ b/ui/collection.css
@@ -3052,3 +3052,98 @@
}
}
+
+
+/* ── 18. Column Visibility Panel ───────────────────────────── */
+
+.coll-col-toggle-btn {
+ background: rgba(139,148,158,0.1);
+ border: 1px solid var(--border, #30363d);
+ color: var(--text-secondary, #8b949e);
+ border-radius: 6px;
+ padding: 6px 12px;
+ font-size: 0.8rem;
+ cursor: pointer;
+ white-space: nowrap;
+ transition: background 0.15s;
+}
+.coll-col-toggle-btn:hover {
+ background: rgba(139,148,158,0.2);
+ color: var(--text, #e6edf3);
+}
+
+.coll-col-panel {
+ position: absolute;
+ top: calc(100% + 6px);
+ right: 0;
+ z-index: 500;
+ background: var(--surface, #161b22);
+ border: 1px solid var(--border, #30363d);
+ border-radius: 10px;
+ box-shadow: 0 8px 24px rgba(0,0,0,0.4);
+ min-width: 180px;
+ animation: coll-fade-in 0.15s ease;
+}
+
+.coll-col-panel-inner {
+ padding: 10px 12px 12px;
+}
+
+.coll-col-panel-hdr {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-size: 0.78rem;
+ font-weight: 600;
+ color: var(--text-secondary, #8b949e);
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ margin-bottom: 8px;
+ padding-bottom: 6px;
+ border-bottom: 1px solid var(--border, #30363d);
+}
+
+.coll-col-close {
+ background: none;
+ border: none;
+ color: var(--text-secondary, #8b949e);
+ cursor: pointer;
+ font-size: 1rem;
+ padding: 0 4px;
+ line-height: 1;
+}
+.coll-col-close:hover { color: var(--text, #e6edf3); }
+
+.coll-col-toggle-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 4px 0;
+ font-size: 0.8rem;
+ color: var(--text, #e6edf3);
+ cursor: pointer;
+ user-select: none;
+}
+.coll-col-toggle-item input[type="checkbox"] {
+ accent-color: var(--accent, #6366f1);
+ cursor: pointer;
+}
+.coll-col-toggle-item:hover {
+ color: var(--accent, #6366f1);
+}
+
+.coll-col-reset {
+ margin-top: 10px;
+ width: 100%;
+ background: rgba(99,102,241,0.1);
+ border: 1px solid rgba(99,102,241,0.3);
+ color: var(--accent, #6366f1);
+ border-radius: 5px;
+ padding: 5px 8px;
+ font-size: 0.75rem;
+ cursor: pointer;
+ transition: background 0.15s;
+}
+.coll-col-reset:hover {
+ background: rgba(99,102,241,0.25);
+}
diff --git a/ui/collection.js b/ui/collection.js
index 1f957d8..fed7991 100644
--- a/ui/collection.js
+++ b/ui/collection.js
@@ -586,7 +586,8 @@ const Collection = (() => {
// Pre-load set/keyword caches for filter autocomplete
loadSetsCache();
loadKeywordsCache();
- await fetchCollection();
+ applyColumnVisibility();
+ await fetchCollection();
}
/** Adjust table container height based on actual topbar height */
@@ -632,7 +633,11 @@ const Collection = (() => {
- ⚔ Deck Builder
+
+ ⚔ Deck Builder
⚡ Auto Gen
@@ -966,6 +971,79 @@ const Collection = (() => {
`;
}
+ // ── Column Visibility ──────────────────────────────────────
+ function colVis(key) {
+ return state.preferences.visibleColumns.includes(key) ? '' : 'display:none;';
+ }
+
+ function toggleColumn(key) {
+ const cols = state.preferences.visibleColumns;
+ const idx = cols.indexOf(key);
+ if (idx >= 0) {
+ if (cols.length <= 1) return; // keep at least 1 column
+ cols.splice(idx, 1);
+ } else {
+ cols.push(key);
+ }
+ savePreferences();
+ renderTable();
+ applyColumnVisibility();
+ }
+
+ function renderColumnPanel() {
+ const panel = document.getElementById('coll-col-panel');
+ if (!panel) return;
+ const cols = COLUMNS.map(col => {
+ const checked = state.preferences.visibleColumns.includes(col.key) ? 'checked' : '';
+ return ``;
+ }).join('');
+ panel.innerHTML = `
+
+
Columns
+ ${cols}
+
+
`;
+ panel.style.display = 'block';
+ }
+
+ function openColumnPanel() {
+ const panel = document.getElementById('coll-col-panel');
+ if (!panel) return;
+ if (panel.style.display === 'block') {
+ panel.style.display = 'none';
+ } else {
+ renderColumnPanel();
+ }
+ }
+
+ function closeColumnPanel() {
+ const panel = document.getElementById('coll-col-panel');
+ if (panel) panel.style.display = 'none';
+ }
+
+ function resetColumns() {
+ state.preferences.visibleColumns = ['quantity','name','mana_cost','type_line','color_identity','cmc','power_toughness','rarity','set_name','tcg_price','edhrec_rank','salt_score','category','finish'];
+ savePreferences();
+ renderTable();
+ renderColumnPanel();
+ }
+ function applyColumnVisibility() {
+ let styleEl = document.getElementById('coll-col-vis-style');
+ if (!styleEl) {
+ styleEl = document.createElement('style');
+ styleEl.id = 'coll-col-vis-style';
+ document.head.appendChild(styleEl);
+ }
+ const hidden = COLUMNS.filter(col => !state.preferences.visibleColumns.includes(col.key));
+ styleEl.textContent = hidden.map(col =>
+ `.coll-th-${col.key}, .coll-td-${col.key} { display: none !important; }`
+ ).join('\n');
+ }
+
+
// ── Table Header ────────────────────────────────────────
const COLUMNS = [
@@ -988,8 +1066,8 @@ const Collection = (() => {
];
function renderTableHeaderHtml() {
- const headers = COLUMNS.map(col => {
- if (!col.sortable) {
+ const visibleCols = COLUMNS.filter(col => state.preferences.visibleColumns.includes(col.key));
+ const headers = visibleCols.map(col => { if (!col.sortable) {
return `${col.label} | `;
}
const isActive = state.sortField === col.key;
@@ -1018,12 +1096,12 @@ const Collection = (() => {
}
if (state.loading) {
- tbody.innerHTML = `| Loading… |
`;
+ tbody.innerHTML = `| Loading… |
`;
return;
}
if (state.items.length === 0) {
- tbody.innerHTML = `|
+ tbody.innerHTML = ` |
🃏
No cards in collection
@@ -2244,7 +2322,8 @@ const Collection = (() => {
if (footer) footer.style.display = 'none';
// Refresh collection
- await fetchCollection();
+ applyColumnVisibility();
+ await fetchCollection();
} catch (err) {
if (statusEl) {
@@ -2997,5 +3076,10 @@ const Collection = (() => {
reEnrich,
autoClassify,
toggleStats,
+ // Column visibility
+ toggleColumn,
+ openColumnPanel,
+ closeColumnPanel,
+ resetColumns,
};
})();
|