Added vim-like navigation (#12)
This commit is contained in:
parent
175fe64a36
commit
b72d1f8502
|
@ -78,3 +78,8 @@ a:hover {
|
|||
padding: 1em;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
.active:before {
|
||||
content: "> ";
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
|
|
@ -8,36 +8,143 @@
|
|||
* - G (scroll to bottom)
|
||||
*/
|
||||
|
||||
const scroll_vertical = 100;
|
||||
const scroll_behavior = "smooth";
|
||||
let last_key = null;
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
console.log(e);
|
||||
class ContentItems {
|
||||
constructor() {
|
||||
this.items = document.getElementsByClassName("content-item");
|
||||
this.current_index = 0;
|
||||
|
||||
let scroll_factor = 1;
|
||||
|
||||
if (e.key === "k") {
|
||||
scroll_factor *= -1;
|
||||
if (this.items.length) {
|
||||
this.items[0].parentElement.classList.add("active");
|
||||
}
|
||||
}
|
||||
|
||||
get current_item() {
|
||||
return this.items[this.current_index];
|
||||
}
|
||||
|
||||
_traverse(delta) {
|
||||
this.current_index += delta;
|
||||
|
||||
if (this.current_index >= this.items.length) {
|
||||
console.warn("Items exhausted (returning last item)");
|
||||
this.current_index = this.items.length - 1;
|
||||
} else if (this.current_index < 0) {
|
||||
console.warn("Items exhausted (returning first item)");
|
||||
this.current_index = 0;
|
||||
}
|
||||
|
||||
return this.current_item;
|
||||
}
|
||||
|
||||
next() {
|
||||
return this._traverse(1);
|
||||
}
|
||||
|
||||
prev() {
|
||||
return this._traverse(-1);
|
||||
}
|
||||
|
||||
begin() {
|
||||
this.current_index = 0;
|
||||
return this.current_item;
|
||||
}
|
||||
|
||||
end() {
|
||||
this.current_index = this.items.length - 1;
|
||||
return this.current_item;
|
||||
}
|
||||
|
||||
is_empty() {
|
||||
return this.items.length <= 0;
|
||||
}
|
||||
}
|
||||
let items = new ContentItems();
|
||||
|
||||
class KeyNav {
|
||||
constructor(listing) {
|
||||
this.listing = listing;
|
||||
this._vertical_scroll_px = 100;
|
||||
this._scroll_behavior = "smooth";
|
||||
}
|
||||
|
||||
_is_scrolling() {
|
||||
return this.listing.is_empty();
|
||||
}
|
||||
|
||||
_toggle_active_element(item) {
|
||||
item.parentElement.classList.toggle("active");
|
||||
}
|
||||
|
||||
next() {
|
||||
if (this._is_scrolling()) {
|
||||
window.scrollBy({
|
||||
top: this._vertical_scroll_px,
|
||||
behavior: this._scroll_behavior,
|
||||
});
|
||||
} else {
|
||||
this._toggle_active_element(items.current_item);
|
||||
this._toggle_active_element(items.next());
|
||||
}
|
||||
}
|
||||
|
||||
prev() {
|
||||
if (this._is_scrolling()) {
|
||||
window.scrollBy({
|
||||
top: -this._vertical_scroll_px,
|
||||
behavior: this._scroll_behavior,
|
||||
});
|
||||
} else {
|
||||
this._toggle_active_element(items.current_item);
|
||||
this._toggle_active_element(items.prev());
|
||||
}
|
||||
}
|
||||
|
||||
begin() {
|
||||
if (this._is_scrolling()) {
|
||||
window.scroll(0, 0);
|
||||
} else {
|
||||
this._toggle_active_element(items.current_item);
|
||||
this._toggle_active_element(items.begin());
|
||||
}
|
||||
}
|
||||
|
||||
end() {
|
||||
if (this._is_scrolling()) {
|
||||
window.scroll(0, document.body.scrollHeight);
|
||||
} else {
|
||||
this._toggle_active_element(items.current_item);
|
||||
this._toggle_active_element(items.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
let keynav = new KeyNav(items);
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
switch (e.key) {
|
||||
case "j":
|
||||
keynav.next();
|
||||
break;
|
||||
|
||||
case "k":
|
||||
window.scrollBy({
|
||||
top: scroll_factor * scroll_vertical,
|
||||
behavior: scroll_behavior,
|
||||
});
|
||||
keynav.prev();
|
||||
break;
|
||||
|
||||
case "g":
|
||||
if (last_key === "g") {
|
||||
window.scroll(0, 0);
|
||||
keynav.begin();
|
||||
}
|
||||
break;
|
||||
|
||||
case "G":
|
||||
window.scroll(0, document.body.scrollHeight);
|
||||
keynav.end();
|
||||
break;
|
||||
|
||||
case "Enter":
|
||||
if (items.current_item !== undefined) {
|
||||
window.location.href = items.current_item.href;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
{{ define "main" }}
|
||||
{{ $paginator := .Paginate (where .Site.RegularPages.ByPublishDate.Reverse "Type" "posts") }}
|
||||
{{ range $paginator.Pages}}
|
||||
<p>
|
||||
<h3><a class="title" href="{{ .RelPermalink }}">{{ .Title }}</a></h3>
|
||||
{{ $paginator := .Paginate (where .Site.RegularPages.ByPublishDate.Reverse "Type" "posts") }}
|
||||
{{ range $paginator.Pages }}
|
||||
<div>
|
||||
<h3>
|
||||
<a
|
||||
id="{{ .File.TranslationBaseName }}"
|
||||
class="content-item"
|
||||
href="{{ .RelPermalink }}"
|
||||
>{{ .Title }}</a
|
||||
>
|
||||
</h3>
|
||||
{{ partial "metadata.html" . }}
|
||||
</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
|
Loading…
Reference in a new issue