feat(card): search spotlight
This commit is contained in:
@@ -210,3 +210,4 @@ ul.plain li:last-child { border-bottom: none; }
|
|||||||
.sv-bar { height: 5px; border-radius: 3px; background: #221820; overflow: hidden; margin-top: 3px; }
|
.sv-bar { height: 5px; border-radius: 3px; background: #221820; overflow: hidden; margin-top: 3px; }
|
||||||
.sv-bar > i { display: block; height: 100%; border-radius: 3px; background: linear-gradient(90deg, var(--accent-dim), var(--accent)); transition: box-shadow .35s; }
|
.sv-bar > i { display: block; height: 100%; border-radius: 3px; background: linear-gradient(90deg, var(--accent-dim), var(--accent)); transition: box-shadow .35s; }
|
||||||
.sv-card:hover .sv-bar > i { box-shadow: 0 0 9px rgba(255,79,46,.55); }
|
.sv-card:hover .sv-bar > i { box-shadow: 0 0 9px rgba(255,79,46,.55); }
|
||||||
|
.sv-search-input{width:100%;background:#0d0d13;border:1px solid var(--border);border-radius:6px;padding:8px 10px;color:var(--text);font-family:var(--font-mono);font-size:12px}
|
||||||
|
|||||||
29
public/views/cards/search.js
Normal file
29
public/views/cards/search.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// public/views/cards/search.js
|
||||||
|
import { el, mount } from '../../dom.js';
|
||||||
|
import { api } from '../../api.js';
|
||||||
|
import { navigate } from '../../router.js';
|
||||||
|
|
||||||
|
const ROUTE = { page: id => '#/page/' + id, ref: id => '#/ref/' + id, source_doc: () => '#/', message: () => '#/' };
|
||||||
|
let body, input, results, deb;
|
||||||
|
async function run(q) {
|
||||||
|
if (!q) { mount(results); return; }
|
||||||
|
try {
|
||||||
|
const hits = await api.get('/api/search?q=' + encodeURIComponent(q));
|
||||||
|
mount(results, (hits || []).slice(0, 6).map(h =>
|
||||||
|
el('div', { class: 'sv-row', style: { cursor: 'pointer' },
|
||||||
|
onclick: () => { const r = ROUTE[h.kind]; if (r) navigate(r(h.id)); } },
|
||||||
|
el('span', {}, h.title_or_snippet || '(untitled)'), el('span', { class: 'k' }, h.kind))
|
||||||
|
));
|
||||||
|
} catch { mount(results, el('span', { class: 'muted' }, 'Search failed')); }
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
id: 'search', title: 'Spotlight', size: 'l',
|
||||||
|
mount(el_) {
|
||||||
|
body = el_;
|
||||||
|
input = el('input', { class: 'sv-search-input', placeholder: 'Search the Void…',
|
||||||
|
oninput: e => { clearTimeout(deb); const q = e.target.value.trim(); deb = setTimeout(() => run(q), 250); } });
|
||||||
|
results = el('div', { style: { marginTop: '10px' } });
|
||||||
|
mount(body, input, results);
|
||||||
|
},
|
||||||
|
start() {}, stop() { body = null; }
|
||||||
|
};
|
||||||
@@ -8,8 +8,9 @@ import weather from './cards/weather.js';
|
|||||||
import hostPerf from './cards/host_perf.js';
|
import hostPerf from './cards/host_perf.js';
|
||||||
import jobs from './cards/jobs.js';
|
import jobs from './cards/jobs.js';
|
||||||
import inbox from './cards/inbox.js';
|
import inbox from './cards/inbox.js';
|
||||||
|
import search from './cards/search.js';
|
||||||
|
|
||||||
const CARD_MODULES = [clock, weather, hostPerf, jobs, inbox]; // grows in later tasks
|
const CARD_MODULES = [clock, weather, hostPerf, jobs, inbox, search]; // grows in later tasks
|
||||||
let active = []; // mounted cards needing stop()
|
let active = []; // mounted cards needing stop()
|
||||||
|
|
||||||
export async function render(main) {
|
export async function render(main) {
|
||||||
|
|||||||
Reference in New Issue
Block a user