Collapse to learn, review, callible into one column
This commit is contained in:
parent
cccfba0712
commit
58c4dc08f3
3 changed files with 51 additions and 34 deletions
46
app.js
46
app.js
|
|
@ -241,9 +241,7 @@ const filters = {
|
|||
modal: null,
|
||||
instrument: null,
|
||||
tuning: null,
|
||||
callable: null,
|
||||
review: null,
|
||||
to_learn: null,
|
||||
status: null,
|
||||
difficulty: null,
|
||||
};
|
||||
|
||||
|
|
@ -251,8 +249,8 @@ const popover = $('filter-popover');
|
|||
const popoverInner = $('filter-popover-inner');
|
||||
let activeFilterKey = null;
|
||||
|
||||
const BOOL_FILTERS = new Set(['modal', 'callable', 'review', 'to_learn']);
|
||||
const DROPDOWN_FILTERS = new Set(['source', 'instrument', 'tuning', 'difficulty']);
|
||||
const BOOL_FILTERS = new Set(['modal']);
|
||||
const DROPDOWN_FILTERS = new Set(['source', 'instrument', 'tuning', 'difficulty', 'status']);
|
||||
|
||||
function openFilterPopover(key, thEl) {
|
||||
if (activeFilterKey === key) { closeFilterPopover(); return; }
|
||||
|
|
@ -267,7 +265,7 @@ function openFilterPopover(key, thEl) {
|
|||
if (filters[key] === true) { cb.checked = true; cb.indeterminate = false; }
|
||||
else if (filters[key] === false) { cb.checked = false; cb.indeterminate = true; }
|
||||
else { cb.checked = false; cb.indeterminate = false; }
|
||||
const names = { modal: 'Modal', callable: 'Callable', review: 'Needs review', to_learn: 'To learn' };
|
||||
const names = { modal: 'Modal' };
|
||||
label.appendChild(cb);
|
||||
label.appendChild(document.createTextNode(names[key] ?? key));
|
||||
popoverInner.appendChild(label);
|
||||
|
|
@ -328,6 +326,7 @@ function buildDropdownOptions(key) {
|
|||
if (key === 'instrument') return [...none, ...allInstruments.map(i => [String(i.id), i.name])];
|
||||
if (key === 'tuning') return [...none, ...allTunings.map(t => [String(t.id), t.name])];
|
||||
if (key === 'difficulty') return [...none, ['easy', 'Easy'], ['hard', 'Hard']];
|
||||
if (key === 'status') return [...none, ['callable', 'Callable'], ['review', 'Needs Review'], ['to_learn', 'To Learn']];
|
||||
return none;
|
||||
}
|
||||
|
||||
|
|
@ -367,9 +366,7 @@ function rowMatchesFilters(tune, entry) {
|
|||
if (filters.instrument && (!entry || String(entry.instrument_id) !== filters.instrument)) return false;
|
||||
if (entry) {
|
||||
if (filters.tuning && String(entry.tuning_id) !== filters.tuning) return false;
|
||||
if (filters.callable !== null && entry.callable !== filters.callable) return false;
|
||||
if (filters.review !== null && entry.review !== filters.review) return false;
|
||||
if (filters.to_learn !== null && entry.to_learn !== filters.to_learn) return false;
|
||||
if (filters.status && entry.status !== filters.status) return false;
|
||||
if (filters.difficulty && entry.difficulty?.toLowerCase() !== filters.difficulty) return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -420,11 +417,7 @@ function renderTable() {
|
|||
? (tune.modal ? `${tune.key} modal` : tune.key)
|
||||
: (tune.modal ? 'modal' : '');
|
||||
const metaRaw = [instStr, keyStr].filter(Boolean).join(' · ');
|
||||
const mobPills = entry ? [
|
||||
`<span class="pill mob-pill ${entry.callable ? 'pill-yes' : 'pill-dim'}">Call</span>`,
|
||||
`<span class="pill mob-pill ${entry.review ? 'pill-warn' : 'pill-dim'}">Rev</span>`,
|
||||
`<span class="pill mob-pill ${entry.to_learn ? 'pill-warn' : 'pill-dim'}">Lrn</span>`,
|
||||
].join('') : '';
|
||||
const mobPills = entry ? pillStatus(entry.status, 'mob-pill') : '';
|
||||
const mobActions = [
|
||||
hasNotes ? `<button class="action-btn btn-notes" data-tune-id="${tune.id}" data-entry-id="${entry?.id ?? ''}">📝</button>` : '',
|
||||
tune.references?.length > 0 ? `<button class="action-btn btn-show-refs" data-tune-id="${tune.id}">🔗</button>` : '',
|
||||
|
|
@ -439,9 +432,7 @@ function renderTable() {
|
|||
<td>${tune.modal ? '<span class="pill pill-yes">Yes</span>' : '<span class="pill" style="background:#222">—</span>'}</td>
|
||||
<td>${esc(entry?.instrument_name ?? '')}</td>
|
||||
<td>${esc(entry?.tuning ?? '')}</td>
|
||||
<td>${pillBool(entry?.callable)}</td>
|
||||
<td>${pillBool(entry?.review, true)}</td>
|
||||
<td>${pillBool(entry?.to_learn, false, true)}</td>
|
||||
<td>${pillStatus(entry?.status)}</td>
|
||||
<td>${hasNotes
|
||||
? `<button class="action-btn btn-notes" data-tune-id="${tune.id}" data-entry-id="${entry?.id ?? ''}">📝</button>`
|
||||
: ''}</td>
|
||||
|
|
@ -486,6 +477,14 @@ function pillBool(val, warnIfTrue = false, neutralIfTrue = false) {
|
|||
return '<span class="pill pill-no">No</span>';
|
||||
}
|
||||
|
||||
function pillStatus(status, extraClass = '') {
|
||||
const c = extraClass ? ' ' + extraClass : '';
|
||||
if (status === 'callable') return `<span class="pill pill-yes${c}">Callable</span>`;
|
||||
if (status === 'review') return `<span class="pill pill-warn${c}">Needs Review</span>`;
|
||||
if (status === 'to_learn') return `<span class="pill pill-to-learn${c}">To Learn</span>`;
|
||||
return `<span class="pill pill-dim${c}">—</span>`;
|
||||
}
|
||||
|
||||
// ── Add / Edit modal ──────────────────────────────────────────
|
||||
btnAddTune.addEventListener('click', openAdd);
|
||||
|
||||
|
|
@ -524,9 +523,7 @@ function openEdit(tuneId, entryId) {
|
|||
tuneForm.elements.inst_tuning.value = entry.tuning ?? '';
|
||||
tuneForm.elements.inst_learned_from.value = entry.learned_from ?? '';
|
||||
tuneForm.elements.inst_date_learned.value = entry.date_learned ?? '';
|
||||
tuneForm.elements.inst_callable.checked = !!entry.callable;
|
||||
tuneForm.elements.inst_review.checked = !!entry.review;
|
||||
tuneForm.elements.inst_to_learn.checked = !!entry.to_learn;
|
||||
tuneForm.elements.inst_status.value = entry.status ?? '';
|
||||
tuneForm.elements.inst_difficulty.value = entry.difficulty ?? '';
|
||||
}
|
||||
|
||||
|
|
@ -657,9 +654,7 @@ async function saveTune() {
|
|||
tuning_id: resolveTuningId(f.inst_tuning.value),
|
||||
learned_from_id: resolveMusicianId(f.inst_learned_from.value),
|
||||
date_learned: f.inst_date_learned.value || null,
|
||||
callable: f.inst_callable.checked,
|
||||
review: f.inst_review.checked,
|
||||
to_learn: f.inst_to_learn.checked,
|
||||
status: f.inst_status.value || null,
|
||||
difficulty: f.inst_difficulty.value || null,
|
||||
} : null;
|
||||
|
||||
|
|
@ -891,7 +886,7 @@ function callGetEntries() {
|
|||
const result = [];
|
||||
for (const tune of allTunes)
|
||||
for (const entry of tune.instruments)
|
||||
if (entry[callMode]) result.push({ tune, entry });
|
||||
if (entry.status === callMode) result.push({ tune, entry });
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -986,8 +981,7 @@ function callSelect(value, modal) {
|
|||
callStep = 2;
|
||||
renderCallStep();
|
||||
} else {
|
||||
filters.callable = callMode === 'callable' ? true : null;
|
||||
filters.to_learn = callMode === 'to_learn' ? true : null;
|
||||
filters.status = callMode;
|
||||
filters.instrument = callInstrumentId !== null ? String(callInstrumentId) : null;
|
||||
filters.tuning = callTuningId !== null ? String(callTuningId) : null;
|
||||
filters.key = value;
|
||||
|
|
|
|||
15
index.html
15
index.html
|
|
@ -33,9 +33,7 @@
|
|||
<th data-filter="modal"><span class="col-full">Modal</span><span class="col-short">Mod.</span></th>
|
||||
<th data-filter="instrument">Instrument</th>
|
||||
<th data-filter="tuning">Tuning</th>
|
||||
<th data-filter="callable"><span class="col-full">Callable</span><span class="col-short">Call.</span></th>
|
||||
<th data-filter="review"><span class="col-full">Review</span><span class="col-short">Rev.</span></th>
|
||||
<th data-filter="to_learn"><span class="col-full">To learn</span><span class="col-short">Learn</span></th>
|
||||
<th data-filter="status">Status</th>
|
||||
<th>Notes</th>
|
||||
<th>Refs</th>
|
||||
<th class="edit-col" hidden></th>
|
||||
|
|
@ -129,9 +127,14 @@
|
|||
</span>
|
||||
</label>
|
||||
<label>Date learned <input name="inst_date_learned" type="date" /></label>
|
||||
<label>Callable <input name="inst_callable" type="checkbox" /></label>
|
||||
<label>Review <input name="inst_review" type="checkbox" /></label>
|
||||
<label>To learn <input name="inst_to_learn" type="checkbox" /></label>
|
||||
<label>Status
|
||||
<span class="status-radios">
|
||||
<label class="radio-row"><input type="radio" name="inst_status" value="" /> None</label>
|
||||
<label class="radio-row"><input type="radio" name="inst_status" value="callable" /> Callable</label>
|
||||
<label class="radio-row"><input type="radio" name="inst_status" value="review" /> Needs Review</label>
|
||||
<label class="radio-row"><input type="radio" name="inst_status" value="to_learn" /> To Learn</label>
|
||||
</span>
|
||||
</label>
|
||||
<label>Difficulty
|
||||
<select name="inst_difficulty">
|
||||
<option value="">—</option>
|
||||
|
|
|
|||
22
style.css
22
style.css
|
|
@ -234,6 +234,7 @@ th.sort-desc .sort-indicator::after { content: '▼'; }
|
|||
.pill-yes { background: #1e4d2b; color: #6fcf97; }
|
||||
.pill-no { background: #4d1e1e; color: #eb5757; }
|
||||
.pill-warn { background: #4d3a1e; color: #f2c94c; }
|
||||
.pill-to-learn { background: #2a1a4e; color: #c4b5fd; }
|
||||
|
||||
.action-btn {
|
||||
background: transparent;
|
||||
|
|
@ -361,6 +362,25 @@ fieldset.active .fs-body { display: contents; }
|
|||
justify-content: flex-end;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.status-radios {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .3rem;
|
||||
}
|
||||
.radio-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: .5rem;
|
||||
font-size: .85rem;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
.radio-row input[type="radio"] {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
accent-color: var(--accent);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#btn-save-tune { background: var(--accent); }
|
||||
#btn-cancel { background: transparent; border: 1px solid var(--border); }
|
||||
|
|
@ -426,7 +446,7 @@ fieldset.active .fs-body { display: contents; }
|
|||
min-width: 1.5rem;
|
||||
}
|
||||
.mob-status { display: flex; gap: .2rem; align-items: center; flex-shrink: 0; }
|
||||
.mob-pill { font-size: .62rem; padding: .1rem .3rem; }
|
||||
.mob-pill { font-size: .7rem; padding: .1rem .4rem; }
|
||||
|
||||
/* Line 2: Instrument (Tuning) · Key [actions] */
|
||||
.mob-line2 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue