levineuwirth.org/templates/library.html

490 lines
23 KiB
HTML

<div id="markdownBody">
<h1 class="page-title">Library</h1>
<p class="library-intro">Everything on this site, organized by portal.</p>
<div class="library-controls">
<div class="library-controls-row">
<span class="library-controls-label">Sort by</span>
<div class="library-controls-options" role="group" aria-label="Sort order">
<button class="library-sort-btn" data-sort="date">date</button>
<button class="library-sort-btn" data-sort="title">title</button>
<button class="library-sort-btn" data-sort="score">trust</button>
</div>
<button class="library-filter-toggle" aria-expanded="false" aria-controls="library-filters">
Filters<span class="filter-toggle-badge"></span>
</button>
</div>
<div id="library-filters" class="library-filters" hidden>
<div class="filter-row">
<span class="filter-label" data-ep-term="status">status</span>
<div class="filter-options">
<button class="filter-btn filter-status-btn" data-value="draft">draft</button>
<button class="filter-btn filter-status-btn" data-value="working model">working model</button>
<button class="filter-btn filter-status-btn" data-value="durable">durable</button>
<button class="filter-btn filter-status-btn" data-value="refined">refined</button>
<button class="filter-btn filter-status-btn" data-value="superseded">superseded</button>
<button class="filter-btn filter-status-btn" data-value="deprecated">deprecated</button>
</div>
</div>
<div class="filter-row">
<span class="filter-label" data-ep-term="confidence">confidence</span>
<div class="filter-options">
<span class="filter-prefix">&ge;</span>
<input type="number" id="filter-confidence" class="filter-number" min="0" max="100" placeholder="&mdash;" aria-label="Minimum confidence" />
</div>
</div>
<div class="filter-row">
<span class="filter-label" data-ep-term="importance">importance</span>
<div class="filter-options">
<span class="filter-prefix">&ge;</span>
<button class="filter-btn filter-threshold-btn" data-field="importance" data-value="1">1</button>
<button class="filter-btn filter-threshold-btn" data-field="importance" data-value="2">2</button>
<button class="filter-btn filter-threshold-btn" data-field="importance" data-value="3">3</button>
<button class="filter-btn filter-threshold-btn" data-field="importance" data-value="4">4</button>
<button class="filter-btn filter-threshold-btn" data-field="importance" data-value="5">5</button>
</div>
</div>
<div class="filter-row">
<span class="filter-label" data-ep-term="evidence">evidence</span>
<div class="filter-options">
<span class="filter-prefix">&ge;</span>
<button class="filter-btn filter-threshold-btn" data-field="evidence" data-value="1">1</button>
<button class="filter-btn filter-threshold-btn" data-field="evidence" data-value="2">2</button>
<button class="filter-btn filter-threshold-btn" data-field="evidence" data-value="3">3</button>
<button class="filter-btn filter-threshold-btn" data-field="evidence" data-value="4">4</button>
<button class="filter-btn filter-threshold-btn" data-field="evidence" data-value="5">5</button>
</div>
</div>
<div class="filter-row">
<span class="filter-label" data-ep-term="trust">trust</span>
<div class="filter-options">
<span class="filter-prefix">&ge;</span>
<input type="number" id="filter-score" class="filter-number" min="0" max="100" placeholder="&mdash;" aria-label="Minimum trust score" />
</div>
</div>
<div class="filter-row">
<span class="filter-label" data-ep-term="scope">scope</span>
<div class="filter-options">
<span class="filter-prefix">&ge;</span>
<button class="filter-btn filter-ordinal-btn" data-field="scope" data-index="0">personal</button>
<button class="filter-btn filter-ordinal-btn" data-field="scope" data-index="1">average</button>
<button class="filter-btn filter-ordinal-btn" data-field="scope" data-index="2">broad</button>
<button class="filter-btn filter-ordinal-btn" data-field="scope" data-index="3">civilizational</button>
</div>
</div>
<div class="filter-row">
<span class="filter-label" data-ep-term="novelty">novelty</span>
<div class="filter-options">
<span class="filter-prefix">&ge;</span>
<button class="filter-btn filter-ordinal-btn" data-field="novelty" data-index="0">conventional</button>
<button class="filter-btn filter-ordinal-btn" data-field="novelty" data-index="1">moderate</button>
<button class="filter-btn filter-ordinal-btn" data-field="novelty" data-index="2">idiosyncratic</button>
<button class="filter-btn filter-ordinal-btn" data-field="novelty" data-index="3">innovative</button>
</div>
</div>
<div class="filter-row">
<span class="filter-label" data-ep-term="practicality">practicality</span>
<div class="filter-options">
<span class="filter-prefix">&ge;</span>
<button class="filter-btn filter-ordinal-btn" data-field="practicality" data-index="0">abstract</button>
<button class="filter-btn filter-ordinal-btn" data-field="practicality" data-index="1">moderate</button>
<button class="filter-btn filter-ordinal-btn" data-field="practicality" data-index="2">high</button>
<button class="filter-btn filter-ordinal-btn" data-field="practicality" data-index="3">exceptional</button>
</div>
</div>
<div class="filter-row">
<span class="filter-label" data-ep-term="stability">stability</span>
<div class="filter-options">
<span class="filter-prefix">&ge;</span>
<button class="filter-btn filter-ordinal-btn" data-field="stability" data-index="0">volatile</button>
<button class="filter-btn filter-ordinal-btn" data-field="stability" data-index="1">revising</button>
<button class="filter-btn filter-ordinal-btn" data-field="stability" data-index="2">fairly stable</button>
<button class="filter-btn filter-ordinal-btn" data-field="stability" data-index="3">stable</button>
<button class="filter-btn filter-ordinal-btn" data-field="stability" data-index="4">established</button>
</div>
</div>
<div class="filter-row filter-row-actions">
<button class="filter-clear-btn">Clear all</button>
</div>
</div>
</div>
<p class="library-empty is-filtered">No entries match the current filters.</p>
$if(research-entries)$
<section class="library-section">
<h2 id="research"><a href="/research/">Research</a></h2>
<ul class="library-list">$for(research-entries)$
<li class="library-entry" data-date="$date-iso$"$if(overall-score)$ data-score="$overall-score$"$endif$$if(status)$ data-status="$status$"$endif$$if(confidence)$ data-confidence="$confidence$"$endif$$if(importance)$ data-importance="$importance$"$endif$$if(evidence)$ data-evidence="$evidence$"$endif$$if(scope)$ data-scope="$scope$"$endif$$if(novelty)$ data-novelty="$novelty$"$endif$$if(practicality)$ data-practicality="$practicality$"$endif$$if(stability)$ data-stability="$stability$"$endif$>
<div class="library-entry-header">
<a class="library-entry-title" href="$url$">$title$</a>
<span class="library-entry-date">$date-created$</span>
</div>
$if(abstract)$<p class="library-entry-abstract">$abstract$</p>$endif$
</li>$endfor$</ul>
</section>
$endif$
$if(nonfiction-entries)$
<section class="library-section">
<h2 id="nonfiction"><a href="/nonfiction/">Nonfiction</a></h2>
<ul class="library-list">$for(nonfiction-entries)$
<li class="library-entry" data-date="$date-iso$"$if(overall-score)$ data-score="$overall-score$"$endif$$if(status)$ data-status="$status$"$endif$$if(confidence)$ data-confidence="$confidence$"$endif$$if(importance)$ data-importance="$importance$"$endif$$if(evidence)$ data-evidence="$evidence$"$endif$$if(scope)$ data-scope="$scope$"$endif$$if(novelty)$ data-novelty="$novelty$"$endif$$if(practicality)$ data-practicality="$practicality$"$endif$$if(stability)$ data-stability="$stability$"$endif$>
<div class="library-entry-header">
<a class="library-entry-title" href="$url$">$title$</a>
<span class="library-entry-date">$date-created$</span>
</div>
$if(abstract)$<p class="library-entry-abstract">$abstract$</p>$endif$
</li>$endfor$</ul>
</section>
$endif$
$if(fiction-entries)$
<section class="library-section">
<h2 id="fiction"><a href="/fiction/">Fiction</a></h2>
<ul class="library-list">$for(fiction-entries)$
<li class="library-entry" data-date="$date-iso$"$if(overall-score)$ data-score="$overall-score$"$endif$$if(status)$ data-status="$status$"$endif$$if(confidence)$ data-confidence="$confidence$"$endif$$if(importance)$ data-importance="$importance$"$endif$$if(evidence)$ data-evidence="$evidence$"$endif$$if(scope)$ data-scope="$scope$"$endif$$if(novelty)$ data-novelty="$novelty$"$endif$$if(practicality)$ data-practicality="$practicality$"$endif$$if(stability)$ data-stability="$stability$"$endif$>
<div class="library-entry-header">
<a class="library-entry-title" href="$url$">$title$</a>
<span class="library-entry-date">$date-created$</span>
</div>
$if(abstract)$<p class="library-entry-abstract">$abstract$</p>$endif$
</li>$endfor$</ul>
</section>
$endif$
$if(poetry-entries)$
<section class="library-section">
<h2 id="poetry"><a href="/poetry/">Poetry</a></h2>
<ul class="library-list">$for(poetry-entries)$
<li class="library-entry" data-date="$date-iso$"$if(overall-score)$ data-score="$overall-score$"$endif$$if(status)$ data-status="$status$"$endif$$if(confidence)$ data-confidence="$confidence$"$endif$$if(importance)$ data-importance="$importance$"$endif$$if(evidence)$ data-evidence="$evidence$"$endif$$if(scope)$ data-scope="$scope$"$endif$$if(novelty)$ data-novelty="$novelty$"$endif$$if(practicality)$ data-practicality="$practicality$"$endif$$if(stability)$ data-stability="$stability$"$endif$>
<div class="library-entry-header">
<a class="library-entry-title" href="$url$">$title$</a>
<span class="library-entry-date">$date-created$</span>
</div>
$if(abstract)$<p class="library-entry-abstract">$abstract$</p>$endif$
</li>$endfor$</ul>
</section>
$endif$
$if(music-entries)$
<section class="library-section">
<h2 id="music"><a href="/music/">Music</a></h2>
<ul class="library-list">$for(music-entries)$
<li class="library-entry" data-date="$date-iso$"$if(overall-score)$ data-score="$overall-score$"$endif$$if(status)$ data-status="$status$"$endif$$if(confidence)$ data-confidence="$confidence$"$endif$$if(importance)$ data-importance="$importance$"$endif$$if(evidence)$ data-evidence="$evidence$"$endif$$if(scope)$ data-scope="$scope$"$endif$$if(novelty)$ data-novelty="$novelty$"$endif$$if(practicality)$ data-practicality="$practicality$"$endif$$if(stability)$ data-stability="$stability$"$endif$>
<div class="library-entry-header">
<a class="library-entry-title" href="$url$">$title$</a>
<span class="library-entry-date">$date-created$</span>
</div>
$if(abstract)$<p class="library-entry-abstract">$abstract$</p>$endif$
</li>$endfor$</ul>
</section>
$endif$
$if(ai-entries)$
<section class="library-section">
<h2 id="ai"><a href="/ai/">AI</a></h2>
<ul class="library-list">$for(ai-entries)$
<li class="library-entry" data-date="$date-iso$"$if(overall-score)$ data-score="$overall-score$"$endif$$if(status)$ data-status="$status$"$endif$$if(confidence)$ data-confidence="$confidence$"$endif$$if(importance)$ data-importance="$importance$"$endif$$if(evidence)$ data-evidence="$evidence$"$endif$$if(scope)$ data-scope="$scope$"$endif$$if(novelty)$ data-novelty="$novelty$"$endif$$if(practicality)$ data-practicality="$practicality$"$endif$$if(stability)$ data-stability="$stability$"$endif$>
<div class="library-entry-header">
<a class="library-entry-title" href="$url$">$title$</a>
<span class="library-entry-date">$date-created$</span>
</div>
$if(abstract)$<p class="library-entry-abstract">$abstract$</p>$endif$
</li>$endfor$</ul>
</section>
$endif$
$if(tech-entries)$
<section class="library-section">
<h2 id="tech"><a href="/tech/">Tech</a></h2>
<ul class="library-list">$for(tech-entries)$
<li class="library-entry" data-date="$date-iso$"$if(overall-score)$ data-score="$overall-score$"$endif$$if(status)$ data-status="$status$"$endif$$if(confidence)$ data-confidence="$confidence$"$endif$$if(importance)$ data-importance="$importance$"$endif$$if(evidence)$ data-evidence="$evidence$"$endif$$if(scope)$ data-scope="$scope$"$endif$$if(novelty)$ data-novelty="$novelty$"$endif$$if(practicality)$ data-practicality="$practicality$"$endif$$if(stability)$ data-stability="$stability$"$endif$>
<div class="library-entry-header">
<a class="library-entry-title" href="$url$">$title$</a>
<span class="library-entry-date">$date-created$</span>
</div>
$if(abstract)$<p class="library-entry-abstract">$abstract$</p>$endif$
</li>$endfor$</ul>
</section>
$endif$
$if(miscellany-entries)$
<section class="library-section">
<h2 id="miscellany"><a href="/miscellany/">Miscellany</a></h2>
<ul class="library-list">$for(miscellany-entries)$
<li class="library-entry" data-date="$date-iso$"$if(overall-score)$ data-score="$overall-score$"$endif$$if(status)$ data-status="$status$"$endif$$if(confidence)$ data-confidence="$confidence$"$endif$$if(importance)$ data-importance="$importance$"$endif$$if(evidence)$ data-evidence="$evidence$"$endif$$if(scope)$ data-scope="$scope$"$endif$$if(novelty)$ data-novelty="$novelty$"$endif$$if(practicality)$ data-practicality="$practicality$"$endif$$if(stability)$ data-stability="$stability$"$endif$>
<div class="library-entry-header">
<a class="library-entry-title" href="$url$">$title$</a>
<span class="library-entry-date">$date-created$</span>
</div>
$if(abstract)$<p class="library-entry-abstract">$abstract$</p>$endif$
</li>$endfor$</ul>
</section>
$endif$
</div>
<script>
(function () {
'use strict';
var KEY = 'library-state';
var SORT_MODES = { date: 1, title: 1, score: 1 };
var SCALES = {
scope: ['personal', 'average', 'broad', 'civilizational'],
novelty: ['conventional', 'moderate', 'idiosyncratic', 'innovative'],
practicality: ['abstract', 'moderate', 'high', 'exceptional'],
stability: ['volatile', 'revising', 'fairly stable', 'stable', 'established']
};
var state = {
sort: 'date',
status: [],
confidence: null,
importance: null,
evidence: null,
score: null,
scope: null,
novelty: null,
practicality: null,
stability: null
};
/* ---- Persistence ---- */
function load() {
try {
var raw = localStorage.getItem(KEY);
if (raw) {
var obj = JSON.parse(raw);
for (var k in state) {
if (obj.hasOwnProperty(k)) state[k] = obj[k];
}
} else {
var old = localStorage.getItem('library-sort');
if (old && SORT_MODES[old]) state.sort = old;
}
} catch (e) {}
}
function save() {
try {
localStorage.setItem(KEY, JSON.stringify(state));
localStorage.removeItem('library-sort');
} catch (e) {}
}
/* ---- Filtering ---- */
function passes(entry) {
var d = entry.dataset;
if (state.status.length) {
var s = (d.status || '').toLowerCase();
if (!s || state.status.indexOf(s) === -1) return false;
}
if (state.confidence !== null) {
if (!d.confidence || +d.confidence < state.confidence) return false;
}
if (state.importance !== null) {
if (!d.importance || +d.importance < state.importance) return false;
}
if (state.evidence !== null) {
if (!d.evidence || +d.evidence < state.evidence) return false;
}
if (state.score !== null) {
if (!d.score || +d.score < state.score) return false;
}
var ords = ['scope', 'novelty', 'practicality', 'stability'];
for (var i = 0; i < ords.length; i++) {
var k = ords[i];
if (state[k] !== null) {
var v = (d[k] || '').toLowerCase();
var idx = SCALES[k].indexOf(v);
if (idx === -1 || idx < state[k]) return false;
}
}
return true;
}
/* ---- Sorting ---- */
function titleOf(e) {
var el = e.querySelector('.library-entry-title');
return el ? el.textContent.trim().toLowerCase() : '';
}
function compare(a, b) {
var m = state.sort;
if (m === 'title') return titleOf(a).localeCompare(titleOf(b));
if (m === 'score') {
var hA = a.dataset.score !== undefined;
var hB = b.dataset.score !== undefined;
if (hA && !hB) return -1;
if (!hA && hB) return 1;
if (hA && hB) {
var diff = Number(b.dataset.score) - Number(a.dataset.score);
if (diff !== 0) return diff;
}
}
var da = a.dataset.date || '';
var db = b.dataset.date || '';
return da < db ? 1 : da > db ? -1 : 0;
}
/* ---- Apply ---- */
function apply() {
if (!SORT_MODES[state.sort]) state.sort = 'date';
document.querySelectorAll('.library-entry').forEach(function (e) {
e.classList.toggle('is-filtered', !passes(e));
});
document.querySelectorAll('.library-list').forEach(function (list) {
var entries = [].slice.call(list.querySelectorAll('.library-entry'));
entries.sort(compare);
entries.forEach(function (e) { list.appendChild(e); });
});
document.querySelectorAll('.library-section').forEach(function (sec) {
sec.classList.toggle('is-filtered', !sec.querySelector('.library-entry:not(.is-filtered)'));
});
var any = document.querySelector('.library-section:not(.is-filtered)');
var msg = document.querySelector('.library-empty');
if (msg) msg.classList.toggle('is-filtered', !!any);
syncUI();
save();
}
/* ---- UI sync ---- */
function activeCount() {
var n = 0;
if (state.status.length) n++;
var fields = ['confidence', 'importance', 'evidence', 'score',
'scope', 'novelty', 'practicality', 'stability'];
for (var i = 0; i < fields.length; i++) {
if (state[fields[i]] !== null) n++;
}
return n;
}
function syncUI() {
document.querySelectorAll('.library-sort-btn').forEach(function (btn) {
btn.classList.toggle('is-active', btn.dataset.sort === state.sort);
});
var badge = document.querySelector('.filter-toggle-badge');
var n = activeCount();
if (badge) badge.textContent = n ? ' (' + n + ')' : '';
document.querySelectorAll('.filter-status-btn').forEach(function (btn) {
btn.classList.toggle('is-active', state.status.indexOf(btn.dataset.value) !== -1);
});
var ci = document.getElementById('filter-confidence');
if (ci) ci.value = state.confidence !== null ? state.confidence : '';
var si = document.getElementById('filter-score');
if (si) si.value = state.score !== null ? state.score : '';
document.querySelectorAll('.filter-threshold-btn').forEach(function (btn) {
btn.classList.toggle('is-active', state[btn.dataset.field] === +btn.dataset.value);
});
document.querySelectorAll('.filter-ordinal-btn').forEach(function (btn) {
btn.classList.toggle('is-active', state[btn.dataset.field] === +btn.dataset.index);
});
}
/* ---- Init ---- */
document.addEventListener('DOMContentLoaded', function () {
load();
apply();
var panel = document.getElementById('library-filters');
var toggle = document.querySelector('.library-filter-toggle');
if (activeCount() > 0 && panel && toggle) {
panel.hidden = false;
toggle.setAttribute('aria-expanded', 'true');
}
document.querySelectorAll('.library-sort-btn').forEach(function (btn) {
btn.addEventListener('click', function () {
state.sort = btn.dataset.sort;
apply();
});
});
if (toggle && panel) {
toggle.addEventListener('click', function () {
var opening = panel.hidden;
panel.hidden = !opening;
toggle.setAttribute('aria-expanded', opening ? 'true' : 'false');
});
}
document.querySelectorAll('.filter-status-btn').forEach(function (btn) {
btn.addEventListener('click', function () {
var v = btn.dataset.value;
var i = state.status.indexOf(v);
if (i === -1) state.status.push(v);
else state.status.splice(i, 1);
apply();
});
});
document.querySelectorAll('.filter-threshold-btn').forEach(function (btn) {
btn.addEventListener('click', function () {
var f = btn.dataset.field;
var v = +btn.dataset.value;
state[f] = (state[f] === v) ? null : v;
apply();
});
});
document.querySelectorAll('.filter-ordinal-btn').forEach(function (btn) {
btn.addEventListener('click', function () {
var f = btn.dataset.field;
var idx = +btn.dataset.index;
state[f] = (state[f] === idx) ? null : idx;
apply();
});
});
['confidence', 'score'].forEach(function (field) {
var el = document.getElementById('filter-' + (field === 'score' ? 'score' : field));
if (!el) return;
el.addEventListener('input', function () {
var v = el.value.trim();
state[field] = v !== '' ? Math.max(0, Math.min(100, parseInt(v, 10) || 0)) : null;
apply();
});
});
var clearBtn = document.querySelector('.filter-clear-btn');
if (clearBtn) {
clearBtn.addEventListener('click', function () {
state.status = [];
state.confidence = null;
state.importance = null;
state.evidence = null;
state.score = null;
state.scope = null;
state.novelty = null;
state.practicality = null;
state.stability = null;
apply();
});
}
});
}());
</script>