add keystroke hints

This commit is contained in:
marlon-erler
2026-09-29 22:24:34 +02:00
parent 7a532bbf5c
commit d3f3a1db21
25 changed files with 494 additions and 266 deletions
+8
View File
@@ -1,6 +1,7 @@
import { BoardStatusGridPage } from "./boardStatusGridPage";
import { BoardKanbanPage } from "./boardKanbanPage";
import { ViewController } from "../viewController";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import { TaskSettingsModal } from "../Modals/taskSettingsModal";
import { SearchModal } from "../Modals/searchModal";
import { BoardSettingsModal } from "../Modals/boardSettingsModal";
@@ -96,6 +97,7 @@ export function BoardPage(
toggle:selected={
boardViewModel.taskPageViewModel.isShowingBoadList
}
ctkeystroke={getKeySymbol(CommonKeys.Options)}
>
<span class="icon">dock_to_right</span>
</button>
@@ -106,6 +108,7 @@ export function BoardPage(
.boardSettingsHeadline
}
on:click={boardViewModel.showSettings}
ctkeystroke={getKeySymbol(CommonKeys.Settings)}
>
<span class="icon">settings</span>
</button>
@@ -117,6 +120,7 @@ export function BoardPage(
"view_list",
BoardPageTypes.List,
boardViewModel,
"j",
)}
{BoardViewToggleButton(
coreViewModel.translations.chatPage.task
@@ -124,6 +128,7 @@ export function BoardPage(
"view_kanban",
BoardPageTypes.Kanban,
boardViewModel,
"k",
)}
{BoardViewToggleButton(
coreViewModel.translations.chatPage.task
@@ -131,6 +136,7 @@ export function BoardPage(
"grid_view",
BoardPageTypes.StatusGrid,
boardViewModel,
"l",
)}
</span>
<span>
@@ -142,6 +148,7 @@ export function BoardPage(
}
on:click={boardViewModel.showFilterModal}
toggle:selected={boardViewModel.isFilterActive}
ctkeystroke={CommonKeys.Filter}
>
<span class="icon">filter_alt</span>
</button>
@@ -152,6 +159,7 @@ export function BoardPage(
.createTaskButtonAudioLabel
}
on:click={boardViewModel.createTask}
ctkeystroke={getKeySymbol(CommonKeys.Create)}
>
<span class="icon">add</span>
</button>
+5
View File
@@ -1,5 +1,6 @@
import "./calendarPage.css";
import { ViewController } from "../viewController";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import { TaskSettingsModal } from "../Modals/taskSettingsModal";
import { TaskViewModelToEntry } from "../Components/taskEntry";
import { PlaceholderView } from "../Components/placeholderView";
@@ -115,6 +116,7 @@ export function CalendarPage(
.todayButtonAudioLabel
}
on:click={calendarPageViewModel.showToday}
ctkeystroke={getKeySymbol(CommonKeys.Reset)}
>
<span class="icon">today</span>
</button>
@@ -129,6 +131,7 @@ export function CalendarPage(
on:click={
calendarPageViewModel.showPreviousMonth
}
ctkeystroke="k"
>
<span class="icon">arrow_back</span>
</button>
@@ -171,6 +174,7 @@ export function CalendarPage(
.nextMonthButtonAudioLabel
}
on:click={calendarPageViewModel.showNextMonth}
ctkeystroke="l"
>
<span class="icon">arrow_forward</span>
</button>
@@ -183,6 +187,7 @@ export function CalendarPage(
.createTaskButtonAudioLabel
}
on:click={calendarPageViewModel.createEvent}
ctkeystroke={getKeySymbol(CommonKeys.Create)}
>
<span class="icon">add</span>
</button>
+2
View File
@@ -1,5 +1,6 @@
import "./messagePage.css";
import { ViewController } from "../viewController";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import { MessageFilterModal } from "../Modals/messageFilterModal";
import { ReplyPreview } from "../Components/replyPreview";
import { ChatMessage } from "../Components/chatMessage";
@@ -129,6 +130,7 @@ export function MessagePage(
toggle:selected={
messagePageViewModel.isFilterActive
}
ctkeystroke={getKeySymbol(CommonKeys.Filter)}
>
<span class="icon">filter_alt</span>
</button>
@@ -9,6 +9,7 @@ export function BoardViewToggleButton(
icon: string,
page: BoardPageTypes,
boardViewModel: BoardViewModel,
key: string,
) {
function select() {
boardViewModel.selectedPage.value = page;
@@ -19,5 +20,5 @@ export function BoardViewToggleButton(
() => boardViewModel.selectedPage.value == page,
);
return RibbonButton(label, icon, isSelected, select);
return RibbonButton(label, icon, isSelected, select, undefined, key);
}
+2 -1
View File
@@ -9,6 +9,7 @@ export function ChatViewToggleButton(
icon: string,
page: ChatPageTypes,
chatViewModel: ChatViewModel,
key: string,
) {
function select() {
chatViewModel.openPage(page);
@@ -26,5 +27,5 @@ export function ChatViewToggleButton(
);
}
return RibbonButton(label, icon, isSelected, select, isHighlighted);
return RibbonButton(label, icon, isSelected, select, isHighlighted, key);
}
+2 -1
View File
@@ -4,9 +4,10 @@ export function HomePageButton(
action: () => void,
label: string,
icon: string,
key: string,
) {
return (
<button class="tile flex-no" on:click={action}>
<button class="tile flex-no" on:click={action} ctkeystroke={key}>
<span class="icon">{icon}</span>
<div>
<span>{label}</span>
+2
View File
@@ -1,3 +1,4 @@
import { CommonKeys, getKeySymbol } from "../keystrokes";
import * as React from "../../react";
import CoreViewModel from "../../ViewModel/Global/coreViewModel";
import ChatMessageViewModel from "../../ViewModel/Chat/chatMessageViewModel";
@@ -25,6 +26,7 @@ export function ReplyPreview(
coreViewModel.translations.chatPage.message
.cancelReplyAudioLabel
}
ctkeystroke={getKeySymbol(CommonKeys.CloseOrCancel)}
>
<span class="icon">close</span>
</button>
+2
View File
@@ -6,6 +6,7 @@ export function RibbonButton(
isSelected: React.State<boolean>,
select: () => void,
isHighlighted: React.State<boolean> = new React.State(false),
key: string,
) {
return (
<button
@@ -14,6 +15,7 @@ export function RibbonButton(
toggle:selected={isSelected}
toggle:highlight={isHighlighted}
on:click={select}
ctkeystroke={key}
>
<span class="icon">{icon}</span>
</button>
+5 -1
View File
@@ -1,4 +1,5 @@
import { ViewController } from "../viewController";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import { DangerousActionButton } from "../Components/dangerousActionButton";
import { ColorPicker } from "../Components/colorPicker";
import * as React from "../../react";
@@ -60,7 +61,10 @@ export function BoardSettingsModal(
)}
</div>
</main>
<button on:click={boardViewModel.hideSettings}>
<button
on:click={boardViewModel.hideSettings}
ctkeystroke={getKeySymbol(CommonKeys.Apply)}
>
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
+5 -1
View File
@@ -1,4 +1,5 @@
import { ViewController } from "../viewController";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import { StringToTextSpan } from "../Components/textSpan";
import * as React from "../../react";
import FileTransferViewModel, {
@@ -172,7 +173,10 @@ function DirectionSelectionModal(
</button>
</div>
</main>
<button on:click={fileTransferViewModel.close}>
<button
on:click={fileTransferViewModel.close}
ctkeystroke={getKeySymbol(CommonKeys.CloseOrCancel)}
>
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
+5 -1
View File
@@ -1,4 +1,5 @@
import { ViewController } from "../viewController";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import { MessageReactionFilterButton } from "../Components/messageReactionFilterButton";
import * as React from "../../react";
import MessagePageViewModel from "../../ViewModel/Pages/messagePageViewModel";
@@ -112,7 +113,10 @@ export function MessageFilterModal<T>(
</div>
</div>
</main>
<button on:click={messagePageViewModel.hideFilterModal}>
<button
on:click={messagePageViewModel.hideFilterModal}
ctkeystroke={getKeySymbol(CommonKeys.CloseOrCancel)}
>
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
+6 -1
View File
@@ -1,5 +1,6 @@
import { v4 } from "uuid";
import { ViewController } from "../viewController";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import { StringToOption } from "../Components/option";
import { DeletableListItem } from "../Components/deletableListItem";
import * as React from "../../react";
@@ -55,6 +56,7 @@ export function SearchModal<T>(
}
on:click={searchViewModel.clear}
toggle:disabled={searchViewModel.cannotClear}
ctkeystroke={getKeySymbol(CommonKeys.Reset)}
>
<span class="icon">close</span>
</button>
@@ -93,7 +95,10 @@ export function SearchModal<T>(
></div>
</div>
</main>
<button on:click={close}>
<button
on:click={close}
ctkeystroke={getKeySymbol(CommonKeys.CloseOrCancel)}
>
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
+5 -1
View File
@@ -1,5 +1,6 @@
import { SplitModal } from "./splitModal";
import { languageNames } from "../translations";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import { PlaceholderView } from "../Components/placeholderView";
import { OptionButtonList } from "../Components/optionButtonList";
import { NavigationButton } from "../Components/navigationButton";
@@ -62,7 +63,10 @@ export function SettingsModal(
settingsViewModel.selectedModalPage,
)}
</main>
<button on:click={settingsViewModel.close}>
<button
on:click={settingsViewModel.close}
ctkeystroke={getKeySymbol(CommonKeys.CloseOrCancel)}
>
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
+5 -1
View File
@@ -1,4 +1,5 @@
import { SplitModal } from "./splitModal";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import { UsageBar } from "../Components/usageBar";
import { DirectoryItemList } from "../Components/directoryItemList";
import { DangerousActionButton } from "../Components/dangerousActionButton";
@@ -95,7 +96,10 @@ export function StorageModal(
true,
)}
</main>
<button on:click={storageViewModel.close}>
<button
on:click={storageViewModel.close}
ctkeystroke={getKeySymbol(CommonKeys.CloseOrCancel)}
>
{coreViewModel.translations.general.closeButton}
<span class="icon">close</span>
</button>
+3
View File
@@ -1,4 +1,5 @@
import { v4 } from "uuid";
import { CommonKeys, getKeySymbol } from "../keystrokes";
import {
Entry,
Option,
@@ -269,12 +270,14 @@ export function TaskSettingsModal(
<button
class="flex"
on:click={taskViewModel.closeAndDiscard}
ctkeystroke={getKeySymbol(CommonKeys.CloseOrCancel)}
>
{coreViewModel.translations.general.closeButton}
</button>
<button
class="flex primary"
on:click={taskViewModel.closeAndSave}
ctkeystroke={getKeySymbol(CommonKeys.Apply)}
>
{coreViewModel.translations.general.saveButton}
<span class="icon">save</span>
+6
View File
@@ -1,4 +1,5 @@
import { ViewController } from "./viewController";
import { CommonKeys, getKeySymbol } from "./keystrokes";
import "./homePage.css";
import { ChatViewToggleButton } from "./Components/chatViewToggleButton";
import { TaskPage } from "./ChatPages/taskPage";
@@ -80,6 +81,7 @@ export function ChatPage(
.closeChatAudioLabe
}
on:click={chatViewModel.close}
ctkeystroke={getKeySymbol(CommonKeys.Home)}
>
<span class="icon">close</span>
</button>
@@ -111,24 +113,28 @@ export function ChatPage(
"calendar_month",
ChatPageTypes.Calendar,
chatViewModel,
"o",
)}
{ChatViewToggleButton(
coreViewModel.translations.chatPage.pages.tasks,
"task_alt",
ChatPageTypes.Tasks,
chatViewModel,
"i",
)}
{ChatViewToggleButton(
coreViewModel.translations.chatPage.pages.messages,
"forum",
ChatPageTypes.Messages,
chatViewModel,
"u",
)}
{ChatViewToggleButton(
coreViewModel.translations.chatPage.pages.settings,
"settings",
ChatPageTypes.Settings,
chatViewModel,
getKeySymbol(CommonKeys.Settings),
)}
</span>
</div>
+5
View File
@@ -57,6 +57,7 @@ export function HomePage(
}
on:click={connectionViewModel.disconnect}
toggle:disabled={connectionViewModel.cannotDisonnect}
ctkeystroke="x"
>
<span class="icon">link_off</span>
</button>
@@ -80,6 +81,7 @@ export function HomePage(
}
on:click={connectionViewModel.connect}
toggle:disabled={connectionViewModel.cannotConnect}
ctkeystroke="c"
>
<span class="icon">link</span>
</button>
@@ -91,16 +93,19 @@ export function HomePage(
settingsViewModel.showSettingsModal,
coreViewModel.translations.homePage.settingsButton,
"settings",
",",
)}
{HomePageButton(
fileTransferViewModel.showDirectionSelectionModal,
coreViewModel.translations.homePage.transferDataButton,
"sync_alt",
"t",
)}
{HomePageButton(
storageViewModel.showStorageModal,
coreViewModel.translations.homePage.manageStorageButton,
"hard_drive",
"e",
)}
<button
+12 -1
View File
@@ -1,5 +1,5 @@
export enum CommonKeys {
Home = " ",
Home = "w",
Filter = "=",
Reset = "-",
Options = ".",
@@ -8,3 +8,14 @@ export enum CommonKeys {
Settings = ",",
Create = "a",
}
export function getKeySymbol(keystroke: string): string {
switch (keystroke) {
case "backspace":
return "⌫";
case "enter":
return "⏎";
default:
return keystroke;
}
}
+6
View File
@@ -65,6 +65,7 @@ export default class CoreViewModel {
if (!(e instanceof KeyboardEvent))
return console.trace("NOT A KEY EVENT");
if (CoreViewModel.checkIsKeystroke(e) == false) return;
document.body.setAttribute("keystroke-active", "");
e.preventDefault();
const contexts: Context[] = this.contexts;
while (contexts.length > 0) {
@@ -75,6 +76,10 @@ export default class CoreViewModel {
}
};
handleKeyUp = (): void => {
document.body.removeAttribute("keystroke-active");
};
// CHRON
chronHandlerManager = new HandlerManager<void>();
todayDate = new React.State<Date>(new Date());
@@ -154,6 +159,7 @@ export default class CoreViewModel {
});
document.body.addEventListener("keydown", this.handleKeyDown);
document.body.addEventListener("keyup", this.handleKeyUp);
window.onpopstate = () => {
if (!this.context) return;
+1 -1
View File
@@ -324,7 +324,7 @@ export default class BoardViewModel extends TaskContainingPageViewModel {
// keystrokes
this.registerKeyStroke(CommonKeys.Filter, this.showFilterModal);
this.registerKeyStroke(CommonKeys.Reset, this.resetFilter);
this.registerKeyStroke(CommonKeys.Reset, this.resetFilter); //
this.registerKeyStroke(CommonKeys.CloseOrCancel, this.hideFilterModal);
this.registerKeyStroke(CommonKeys.Settings, this.showSettings);
this.registerKeyStroke(CommonKeys.Apply, this.hideSettings);
+34
View File
@@ -113,3 +113,37 @@ body[theme="dark"] #background-wrapper #grass-2 {
padding: var(--content-padding);
}
/* Keystrokes */
[ctkeystroke] {
position: relative;
}
[ctkeystroke]::after {
content: attr(ctkeystroke);
background: var(--primary);
color: var(--text-on-color);
--size: 24px;
position: absolute;
top: calc(50% - var(--size) / 2);
left: calc(50% - var(--size) / 2);
width: var(--size);
height: var(--size);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transform: translateY(10px);
transition: all calc(var(--animation-duration) / 2);
}
body[keystroke-active] [ctkeystroke]::after {
opacity: 1;
transform: translateY(0px);
}