From 66c8809799611a729a39b7d31d7b1e41f286201c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 8 Nov 2022 21:17:45 +0000 Subject: [PATCH] Started interface user shortcut form interface Built controller actions and initual UI. Still needs JS logic for shortcut input handling. --- app/Config/setting-defaults.php | 2 + .../Controllers/UserPreferencesController.php | 32 ++++++++ app/Settings/UserShortcutMap.php | 82 +++++++++++++++++++ resources/icons/shortcuts.svg | 1 + resources/js/components/shortcuts.js | 36 +------- resources/sass/_forms.scss | 6 ++ resources/views/common/header.blade.php | 10 ++- .../views/entities/favourite-action.blade.php | 2 +- .../entities/sibling-navigation.blade.php | 2 +- resources/views/layouts/base.blade.php | 7 +- .../parts/shortcut-control.blade.php | 11 +++ .../users/preferences/shortcuts.blade.php | 78 ++++++++++++++++++ routes/web.php | 3 + 13 files changed, 232 insertions(+), 40 deletions(-) create mode 100644 app/Settings/UserShortcutMap.php create mode 100644 resources/icons/shortcuts.svg create mode 100644 resources/views/users/preferences/parts/shortcut-control.blade.php create mode 100644 resources/views/users/preferences/shortcuts.blade.php diff --git a/app/Config/setting-defaults.php b/app/Config/setting-defaults.php index cb6082c52..5e1e4348a 100644 --- a/app/Config/setting-defaults.php +++ b/app/Config/setting-defaults.php @@ -26,6 +26,8 @@ return [ // User-level default settings 'user' => [ + 'ui-shortcuts' => '{}', + 'ui-shortcuts-enabled' => false, 'dark-mode-enabled' => env('APP_DEFAULT_DARK_MODE', false), 'bookshelves_view_type' => env('APP_VIEWS_BOOKSHELVES', 'grid'), 'bookshelf_view_type' => env('APP_VIEWS_BOOKSHELF', 'grid'), diff --git a/app/Http/Controllers/UserPreferencesController.php b/app/Http/Controllers/UserPreferencesController.php index 972742e03..b8bb31468 100644 --- a/app/Http/Controllers/UserPreferencesController.php +++ b/app/Http/Controllers/UserPreferencesController.php @@ -3,6 +3,7 @@ namespace BookStack\Http\Controllers; use BookStack\Auth\UserRepo; +use BookStack\Settings\UserShortcutMap; use Illuminate\Http\Request; class UserPreferencesController extends Controller @@ -14,6 +15,37 @@ class UserPreferencesController extends Controller $this->userRepo = $userRepo; } + /** + * Show the user-specific interface shortcuts. + */ + public function showShortcuts() + { + $shortcuts = UserShortcutMap::fromUserPreferences(); + $enabled = setting()->getForCurrentUser('ui-shortcuts-enabled', false); + + return view('users.preferences.shortcuts', [ + 'shortcuts' => $shortcuts, + 'enabled' => $enabled, + ]); + } + + /** + * Update the user-specific interface shortcuts. + */ + public function updateShortcuts(Request $request) + { + $enabled = $request->get('enabled') === 'true'; + $providedShortcuts = $request->get('shortcuts', []); + $shortcuts = new UserShortcutMap($providedShortcuts); + + setting()->putUser(user(), 'ui-shortcuts', $shortcuts->toJson()); + setting()->putUser(user(), 'ui-shortcuts-enabled', $enabled); + + $this->showSuccessNotification('Shortcuts preferences have been updated!'); + + return redirect('/preferences/shortcuts'); + } + /** * Update the user's preferred book-list display setting. */ diff --git a/app/Settings/UserShortcutMap.php b/app/Settings/UserShortcutMap.php new file mode 100644 index 000000000..da2ea3c10 --- /dev/null +++ b/app/Settings/UserShortcutMap.php @@ -0,0 +1,82 @@ + "1", + "shelves_view" => "2", + "books_view" => "3", + "settings_view" => "4", + "favourites_view" => "5", + "profile_view" => "6", + "global_search" => "/", + "logout" => "0", + + // Common actions + "edit" => "e", + "new" => "n", + "copy" => "c", + "delete" => "d", + "favourite" => "f", + "export" => "x", + "sort" => "s", + "permissions" => "p", + "move" => "m", + "revisions" => "r", + + // Navigation + "next" => "ArrowRight", + "previous" => "ArrowLeft", + ]; + + /** + * @var array + */ + protected array $mapping; + + public function __construct(array $map) + { + $this->mapping = static::DEFAULTS; + $this->merge($map); + } + + /** + * Merge the given map into the current shortcut mapping. + */ + protected function merge(array $map): void + { + foreach ($map as $key => $value) { + if (is_string($value) && isset($this->mapping[$key])) { + $this->mapping[$key] = $value; + } + } + } + + /** + * Get the shortcut defined for the given ID. + */ + public function getShortcut(string $id): string + { + return $this->mapping[$id] ?? ''; + } + + /** + * Convert this mapping to JSON. + */ + public function toJson(): string + { + return json_encode($this->mapping); + } + + /** + * Create a new instance from the current user's preferences. + */ + public static function fromUserPreferences(): self + { + $userKeyMap = setting()->getForCurrentUser('ui-shortcuts'); + return new self(json_decode($userKeyMap, true) ?: []); + } +} diff --git a/resources/icons/shortcuts.svg b/resources/icons/shortcuts.svg new file mode 100644 index 000000000..8d23aac2b --- /dev/null +++ b/resources/icons/shortcuts.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/js/components/shortcuts.js b/resources/js/components/shortcuts.js index a3cca5ddc..ccad00f5d 100644 --- a/resources/js/components/shortcuts.js +++ b/resources/js/components/shortcuts.js @@ -1,35 +1,3 @@ -/** - * The default mapping of unique id to shortcut key. - * @type {Object} - */ -const defaultMap = { - // Header actions - "home": "1", - "shelves_view": "2", - "books_view": "3", - "settings_view": "4", - "favorites_view": "5", - "profile_view": "6", - "global_search": "/", - "logout": "0", - - // Generic actions - "edit": "e", - "new": "n", - "copy": "c", - "delete": "d", - "favorite": "f", - "export": "x", - "sort": "s", - "permissions": "p", - "move": "m", - "revisions": "r", - - // Navigation - "next": "ArrowRight", - "prev": "ArrowLeft", -}; - function reverseMap(map) { const reversed = {}; for (const [key, value] of Object.entries(map)) { @@ -45,14 +13,12 @@ class Shortcuts { setup() { this.container = this.$el; - this.mapById = defaultMap; + this.mapById = JSON.parse(this.$opts.keyMap); this.mapByShortcut = reverseMap(this.mapById); this.hintsShowing = false; this.hideHints = this.hideHints.bind(this); - // TODO - Allow custom key maps - // TODO - Allow turning off shortcuts this.setupListeners(); } diff --git a/resources/sass/_forms.scss b/resources/sass/_forms.scss index 7e0f72355..7de8a9d7d 100644 --- a/resources/sass/_forms.scss +++ b/resources/sass/_forms.scss @@ -473,4 +473,10 @@ div[editor-type="markdown"] .title-input.page-title input[type="text"] { .custom-file-input:focus + label { border-color: var(--color-primary); outline: 1px solid var(--color-primary); +} + +input.shortcut-input { + width: auto; + max-width: 120px; + height: auto; } \ No newline at end of file diff --git a/resources/views/common/header.blade.php b/resources/views/common/header.blade.php index 0481b3412..dd463b76e 100644 --- a/resources/views/common/header.blade.php +++ b/resources/views/common/header.blade.php @@ -2,7 +2,7 @@
-