@@ -29,7 +29,10 @@ entries.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
2929 const date = entry .data .date .toISOString ().slice (0 , 10 );
3030 const tag = entry .data .tags ?.[0 ] ?? ' ' ;
3131 return (
32- <div class = " grid grid-cols-[100px_1fr_80px] sm:grid-cols-[100px_60px_1fr_80px] gap-4 py-2.5 items-baseline border-b border-dashed border-zinc-800 light:border-zinc-200 min-w-[360px]" >
32+ <div
33+ class = " thought-row grid grid-cols-[100px_1fr_80px] sm:grid-cols-[100px_60px_1fr_80px] gap-4 py-2.5 items-baseline border-b border-dashed border-zinc-800 light:border-zinc-200 min-w-[360px] transition-colors duration-100"
34+ data-name = { ` ${entry .data .title } ${tag } ` }
35+ >
3336 <span class = " text-zinc-500 text-xs" >{ date } </span >
3437 <span class = " hidden sm:block text-zinc-600 text-xs text-right" >—</span >
3538 <a href = { ` /thoughts/${entry .id } ` } class = " text-sm font-medium truncate" >
@@ -45,8 +48,69 @@ entries.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
4548 )
4649 }
4750
48- <div class =" term-prompt mt-6" >
51+ <div class =" term-prompt border border-accent/40 px-3 py-1.5 inline-flex items-center mt-6" >
4952 <span class =" text-accent" >$</span >
50- <span class =" ml-1" >_</span >
53+ <span
54+ id =" thought-filter"
55+ role =" textbox"
56+ contenteditable =" plaintext-only"
57+ spellcheck =" false"
58+ data-placeholder =" filter..."
59+ aria-label =" Filter thoughts"
60+ class =" terminal-filter font-mono text-sm text-zinc-100 light:text-zinc-900 ml-1 outline-none inline-block"
61+ ></span >
5162 </div >
5263</BaseLayout >
64+
65+ <script >
66+ const input = document.getElementById('thought-filter') as HTMLElement;
67+ const rows = Array.from(document.querySelectorAll<HTMLElement>('.thought-row'));
68+
69+ let focusedIndex = -1;
70+
71+ const visibleRows = () => rows.filter(r => r.style.display !== 'none');
72+
73+ function setFocus(index: number) {
74+ focusedIndex = index;
75+ rows.forEach(r => r.classList.remove('ls-row-focused'));
76+ const visible = visibleRows();
77+ if (focusedIndex >= 0 && focusedIndex < visible.length) {
78+ visible[focusedIndex].classList.add('ls-row-focused');
79+ }
80+ }
81+
82+ input.focus();
83+
84+ input.addEventListener('input', () => {
85+ if (input.innerHTML === '<br>') input.innerHTML = '';
86+ const q = (input.textContent ?? '').toLowerCase();
87+ rows.forEach(r => {
88+ r.style.display = !q || r.dataset.name!.toLowerCase().includes(q) ? '' : 'none';
89+ });
90+ setFocus(-1);
91+ });
92+
93+ input.addEventListener('keydown', (e: KeyboardEvent) => {
94+ const visible = visibleRows();
95+ if (e.key === 'ArrowDown') {
96+ e.preventDefault();
97+ setFocus(Math.min(focusedIndex + 1, visible.length - 1));
98+ } else if (e.key === 'ArrowUp') {
99+ e.preventDefault();
100+ setFocus(Math.max(focusedIndex - 1, 0));
101+ } else if (e.key === 'Enter') {
102+ e.preventDefault();
103+ const target = focusedIndex >= 0 ? visible[focusedIndex] : visible[0];
104+ if (target) {
105+ const link = target.querySelector('a');
106+ if (link) window.location.href = link.href;
107+ }
108+ }
109+ });
110+
111+ input.addEventListener('paste', (e: ClipboardEvent) => {
112+ e.preventDefault();
113+ const text = e.clipboardData?.getData('text/plain') ?? '';
114+ document.execCommand('insertText', false, text);
115+ });
116+ </script >
0 commit comments