mirror of
https://github.com/heyarne/airsonic-ui.git
synced 2026-05-06 18:33:38 +02:00
Add rudimentary keyboard shortcuts; closes #41
This commit is contained in:
parent
3c6c788c56
commit
f9290562fa
8 changed files with 109 additions and 41 deletions
96
package-lock.json
generated
96
package-lock.json
generated
|
|
@ -1352,9 +1352,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"events": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
|
||||
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz",
|
||||
"integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==",
|
||||
"dev": true
|
||||
},
|
||||
"evp_bytestokey": {
|
||||
|
|
@ -1766,7 +1766,8 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
|
|
@ -1787,12 +1788,14 @@
|
|||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
|
@ -1807,17 +1810,20 @@
|
|||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
|
@ -1934,7 +1940,8 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
|
@ -1946,6 +1953,7 @@
|
|||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
|
|
@ -1960,6 +1968,7 @@
|
|||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
|
@ -1967,12 +1976,14 @@
|
|||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
|
|
@ -1991,6 +2002,7 @@
|
|||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
|
|
@ -2071,7 +2083,8 @@
|
|||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
|
|
@ -2083,6 +2096,7 @@
|
|||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
|
|
@ -2168,7 +2182,8 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
|
|
@ -2204,6 +2219,7 @@
|
|||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
|
@ -2223,6 +2239,7 @@
|
|||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
|
|
@ -2266,12 +2283,14 @@
|
|||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -2568,9 +2587,9 @@
|
|||
}
|
||||
},
|
||||
"hash.js": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz",
|
||||
"integrity": "sha512-eWI5HG9Np+eHV1KQhisXWwM+4EPPYe5dFX1UZZH7k/E3JzDEazVH+VGlZi6R94ZqImq+A3D1mCEtrFIfg/E7sA==",
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
|
|
@ -3649,9 +3668,9 @@
|
|||
}
|
||||
},
|
||||
"node-libs-browser": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz",
|
||||
"integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz",
|
||||
"integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert": "^1.1.1",
|
||||
|
|
@ -3661,7 +3680,7 @@
|
|||
"constants-browserify": "^1.0.0",
|
||||
"crypto-browserify": "^3.11.0",
|
||||
"domain-browser": "^1.1.1",
|
||||
"events": "^1.0.0",
|
||||
"events": "^3.0.0",
|
||||
"https-browserify": "^1.0.0",
|
||||
"os-browserify": "^0.3.0",
|
||||
"path-browserify": "0.0.0",
|
||||
|
|
@ -3675,7 +3694,7 @@
|
|||
"timers-browserify": "^2.0.4",
|
||||
"tty-browserify": "0.0.0",
|
||||
"url": "^0.11.0",
|
||||
"util": "^0.10.3",
|
||||
"util": "^0.11.0",
|
||||
"vm-browserify": "0.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
@ -4077,22 +4096,23 @@
|
|||
}
|
||||
},
|
||||
"pako": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
|
||||
"integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==",
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz",
|
||||
"integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA==",
|
||||
"dev": true
|
||||
},
|
||||
"parse-asn1": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
|
||||
"integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.3.tgz",
|
||||
"integrity": "sha512-VrPoetlz7B/FqjBLD2f5wBVZvsZVLnRUrxVLfRYhGXCODa/NWE4p3Wp+6+aV3ZPL3KM7/OZmxDIwwijD7yuucg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asn1.js": "^4.0.0",
|
||||
"browserify-aes": "^1.0.0",
|
||||
"create-hash": "^1.1.0",
|
||||
"evp_bytestokey": "^1.0.0",
|
||||
"pbkdf2": "^3.0.3"
|
||||
"pbkdf2": "^3.0.3",
|
||||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
|
|
@ -4814,9 +4834,9 @@
|
|||
}
|
||||
},
|
||||
"shadow-cljs": {
|
||||
"version": "2.7.6",
|
||||
"resolved": "https://registry.npmjs.org/shadow-cljs/-/shadow-cljs-2.7.6.tgz",
|
||||
"integrity": "sha512-hk9dtt3mLkLQzu2YJG+T2/8YyevRNYtGZTGjTrGCUzjLaqKHJInJELY16vU2W17Kq/u9tCsPV0Y+bbnHRv52uw==",
|
||||
"version": "2.7.21",
|
||||
"resolved": "https://registry.npmjs.org/shadow-cljs/-/shadow-cljs-2.7.21.tgz",
|
||||
"integrity": "sha512-izl5S11oS+p1i46o481VDFOuT1y1LM2k3j9g3JG04KM7exEr02Q10Sz1m5yETM/MkyDxqFGhZWpMfJmCZrOILw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mkdirp": "^0.5.1",
|
||||
|
|
@ -5221,9 +5241,9 @@
|
|||
}
|
||||
},
|
||||
"stream-browserify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
|
||||
"integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
|
||||
"integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "~2.0.1",
|
||||
|
|
@ -5680,9 +5700,9 @@
|
|||
}
|
||||
},
|
||||
"util": {
|
||||
"version": "0.10.4",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
|
||||
"integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
|
||||
"integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "2.0.3"
|
||||
|
|
|
|||
|
|
@ -43,6 +43,6 @@
|
|||
"react-flip-move": "^3.0.3",
|
||||
"react-highlight.js": "^1.0.7",
|
||||
"sass": "^1.15.1",
|
||||
"shadow-cljs": "^2.7.6"
|
||||
"shadow-cljs": "^2.7.21"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
:dependencies
|
||||
[[reagent "0.8.0"]
|
||||
[re-frame "0.10.6"]
|
||||
[re-pressed "0.3.0"]
|
||||
[day8.re-frame/http-fx "0.1.6"]
|
||||
[akiroz.re-frame/storage "0.1.2"]
|
||||
[funcool/bide "1.6.0"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
(ns airsonic-ui.components.keyboard-shortcuts.config)
|
||||
|
||||
;; this keymap has the following structure:
|
||||
;; [[readable-key readable-description event-vector event-keys]
|
||||
;; ...]
|
||||
|
||||
(def keymap
|
||||
[["Space" "Toggle play / pause"
|
||||
[:audio-player/toggle-play-pause]
|
||||
[{:keyCode 32}]]
|
||||
["←" "Previous song"
|
||||
[:audio-player/previous-song]
|
||||
[{:keyCode 37}]]
|
||||
["→" "Next song"
|
||||
[:audio-player/next-song]
|
||||
[{:keyCode 39}]]
|
||||
["?" "Show / hide keyboard shortcut help"
|
||||
[:bulma.modal.events/toggle :keyboard-shortcuts-help]
|
||||
[{:keyCode 63}]]])
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
(ns airsonic-ui.components.keyboard-shortcuts.events
|
||||
(:require [re-frame.core :as rf]
|
||||
[re-pressed.core :as rp]
|
||||
[airsonic-ui.components.keyboard-shortcuts.config :as config]))
|
||||
|
||||
(rf/reg-event-fx
|
||||
::init-shortcuts
|
||||
(fn []
|
||||
(let [event-keys (map (juxt #(nth % 2) #(nth % 3)) config/keymap)
|
||||
prevent-default-keys (mapcat last event-keys)]
|
||||
{:dispatch-n [[::rp/add-keyboard-event-listener "keydown"]
|
||||
[::rp/set-keydown-rules {:event-keys event-keys
|
||||
:prevent-default-keys prevent-default-keys}]]})))
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
(ns airsonic-ui.components.keyboard-shortcuts.views
|
||||
(:require [bulma.modal.views :as bulma]
|
||||
[airsonic-ui.components.keyboard-shortcuts.config :as config]))
|
||||
|
||||
(defn help-modal []
|
||||
[bulma/modal-card {:title "Keyboard Shortcuts"
|
||||
:modal-id :keyboard-shortcuts-help}
|
||||
[:table.table.is-hoverable.is-fullwidth
|
||||
[:thead [:tr [:th "Key"] [:th "Function"]]]
|
||||
[:tbody
|
||||
(for [[idx [k desc]] (map-indexed vector config/keymap)]
|
||||
^{:key idx} [:tr [:td>code k] [:td desc]])]]])
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
[airsonic-ui.api.events]
|
||||
[airsonic-ui.api.subs]
|
||||
[airsonic-ui.components.audio-player.events]
|
||||
[airsonic-ui.components.keyboard-shortcuts.events :as keyboard]
|
||||
[airsonic-ui.components.library.subs]
|
||||
[airsonic-ui.components.search.events]
|
||||
[airsonic-ui.components.search.subs]
|
||||
|
|
@ -28,8 +29,8 @@
|
|||
(reagent/render [views/main-panel] (.getElementById js/document "app")))
|
||||
|
||||
(defn ^:export init []
|
||||
(storage/reg-co-fx! :airsonic-ui {:fx :store
|
||||
:cofx :store})
|
||||
(storage/reg-co-fx! :airsonic-ui {:fx :store, :cofx :store})
|
||||
(rf/dispatch-sync [::events/initialize-app])
|
||||
(rf/dispatch [::keyboard/init-shortcuts])
|
||||
(dev-setup)
|
||||
(mount-root))
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
[airsonic-ui.components.bangpow.views :refer [not-found]]
|
||||
[airsonic-ui.components.collection.views :as collection]
|
||||
[airsonic-ui.components.current-queue.views :refer [current-queue]]
|
||||
[airsonic-ui.components.keyboard-shortcuts.views :as keyboard]
|
||||
[airsonic-ui.components.library.views :as library]
|
||||
[airsonic-ui.components.podcast.views :as podcast]
|
||||
[airsonic-ui.components.search.views :as search]))
|
||||
|
|
@ -130,6 +131,7 @@
|
|||
[route-id :as route] @(subscribe [:routes/current-route])]
|
||||
[(add-classes :div route-id)
|
||||
[notification-list notifications]
|
||||
[keyboard/help-modal]
|
||||
(if is-booting?
|
||||
[:div.app-loading>div.loader]
|
||||
[:div
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue