Add Stimulus controller for navigation shortcuts
This commit is contained in:
parent
dbd6f96f53
commit
a64a4699b0
|
@ -107,6 +107,7 @@ $unicodeRangeValues in Lexend.$unicodeMap {
|
|||
"components/comments",
|
||||
"components/container",
|
||||
"components/entry",
|
||||
"components/hotkey",
|
||||
"components/icons",
|
||||
"components/inbox-actions",
|
||||
"components/inbox-entry",
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
.js-hotkey-navigating {
|
||||
[data-navigation-target="current"] {
|
||||
outline: var(--primary) solid 4px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
import { Controller } from "@hotwired/stimulus";
|
||||
import { install, uninstall } from "@github/hotkey";
|
||||
|
||||
export default class extends Controller {
|
||||
static classes = ["current"];
|
||||
static targets = ["current", "traversable"];
|
||||
|
||||
declare readonly hasCurrentTarget: boolean;
|
||||
declare readonly currentTarget: HTMLElement;
|
||||
declare readonly traversableTargets: HTMLElement[];
|
||||
|
||||
traversableTargetConnected(target: HTMLElement) {
|
||||
if (!this.hasCurrentTarget) {
|
||||
const first = this.traversableTargets[0];
|
||||
first.dataset.navigationTarget = "current";
|
||||
}
|
||||
}
|
||||
|
||||
currentTargetConnected(target: HTMLElement) {
|
||||
target.querySelectorAll<HTMLElement>("[data-selection-hotkey]")
|
||||
.forEach(el => install(el, el.dataset.selectionHotkey))
|
||||
}
|
||||
|
||||
currentTargetDisconnected(target: HTMLElement) {
|
||||
target.querySelectorAll<HTMLElement>("[data-selection-hotkey]")
|
||||
.forEach(el => uninstall(el))
|
||||
}
|
||||
|
||||
up(): void {
|
||||
this.navigate(this.currentTarget.previousElementSibling as HTMLElement);
|
||||
}
|
||||
|
||||
down(): void {
|
||||
this.navigate(this.currentTarget.nextElementSibling as HTMLElement);
|
||||
}
|
||||
|
||||
navigate(target: HTMLElement): void {
|
||||
if (!document.body.classList.contains("js-hotkey-navigating")) {
|
||||
document.body.classList.add("js-hotkey-navigating");
|
||||
}
|
||||
|
||||
if (target.dataset.navigationTarget == "traversable") {
|
||||
this.currentTarget.dataset.navigationTarget = "traversable";
|
||||
target.dataset.navigationTarget = "current";
|
||||
target.scrollIntoView(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import CropperController from "retrospring/controllers/cropper_controller";
|
|||
import InboxSharingController from "retrospring/controllers/inbox_sharing_controller";
|
||||
import ToastController from "retrospring/controllers/toast_controller";
|
||||
import PwaBadgeController from "retrospring/controllers/pwa_badge_controller";
|
||||
import NavigationController from "retrospring/controllers/navigation_controller";
|
||||
|
||||
/**
|
||||
* This module sets up Stimulus and our controllers
|
||||
|
@ -31,6 +32,7 @@ export default function (): void {
|
|||
window['Stimulus'].register('format-popup', FormatPopupController);
|
||||
window['Stimulus'].register('inbox-sharing', InboxSharingController);
|
||||
window['Stimulus'].register('pwa-badge', PwaBadgeController);
|
||||
window['Stimulus'].register('navigation', NavigationController);
|
||||
window['Stimulus'].register('theme', ThemeController);
|
||||
window['Stimulus'].register('toast', ToastController);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
%button.btn.btn-link.answerbox__action{ type: :button, name: "ab-smile", data: { a_id: a.id, action: current_user&.smiled?(a) ? :unsmile : :smile }, disabled: !user_signed_in? }
|
||||
%button.btn.btn-link.answerbox__action{ type: :button, name: "ab-smile", data: { a_id: a.id, action: current_user&.smiled?(a) ? :unsmile : :smile, selection_hotkey: "l" }, disabled: !user_signed_in? }
|
||||
%i.fa.fa-fw.fa-smile-o
|
||||
%span{ id: "ab-smile-count-#{a.id}" }= a.smiles.count
|
||||
- unless display_all
|
||||
%button.btn.btn-link.answerbox__action{ type: :button, name: "ab-comments", data: { a_id: a.id, state: :hidden } }
|
||||
%button.btn.btn-link.answerbox__action{ type: :button, name: "ab-comments", data: { a_id: a.id, state: :hidden, selection_hotkey: "x" } }
|
||||
%i.fa.fa-fw.fa-comments
|
||||
%span{ id: "ab-comment-count-#{a.id}" }= a.comment_count
|
||||
.btn-group
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- display_all ||= nil
|
||||
.card.answerbox{ data: { id: a.id, q_id: a.question.id } }
|
||||
.card.answerbox{ data: { id: a.id, q_id: a.question.id, navigation_target: "traversable" } }
|
||||
- if @question.nil?
|
||||
= render "answerbox/header", a: a, display_all: display_all
|
||||
.card-body
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#timeline
|
||||
#timeline{ data: { controller: "navigation" } }
|
||||
%button.d-none{ data: { hotkey: "j", action: "navigation#down" } }
|
||||
%button.d-none{ data: { hotkey: "k", action: "navigation#up" } }
|
||||
- @timeline.each do |answer|
|
||||
= render "answerbox", a: answer
|
||||
|
||||
|
|
Loading…
Reference in New Issue