Skip to content

Commit 10dbd9a

Browse files
committed
fix: improve keyboard shortcuts
1 parent 018e848 commit 10dbd9a

14 files changed

Lines changed: 85 additions & 43 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package frontend
2+
3+
type keys struct {
4+
Bucket string
5+
Pen string
6+
Rubber string
7+
Size8 string
8+
Size16 string
9+
Size24 string
10+
Size32 string
11+
Undo string
12+
UndoModifier string
13+
}
14+
15+
var lobbyKeyboardShortcuts = keys{
16+
Bucket: "w",
17+
Pen: "q",
18+
Rubber: "e",
19+
Size8: "1",
20+
Size16: "2",
21+
Size24: "3",
22+
Size32: "4",
23+
Undo: "z",
24+
UndoModifier: "ctrl",
25+
}

internal/frontend/lobby.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type lobbyPageData struct {
1818

1919
Translation *translations.Translation
2020
Locale string
21+
Keys *keys
2122
}
2223

2324
type lobbyJsData struct {
@@ -26,6 +27,7 @@ type lobbyJsData struct {
2627

2728
Translation *translations.Translation
2829
Locale string
30+
Keys *keys
2931
}
3032

3133
func (handler *SSRHandler) lobbyJs(writer http.ResponseWriter, request *http.Request) {
@@ -35,6 +37,7 @@ func (handler *SSRHandler) lobbyJs(writer http.ResponseWriter, request *http.Req
3537
GameConstants: api.GameConstantsData,
3638
Translation: translation,
3739
Locale: locale,
40+
Keys: &lobbyKeyboardShortcuts,
3841
}
3942

4043
writer.Header().Set("Content-Type", "text/javascript")
@@ -111,6 +114,7 @@ func (handler *SSRHandler) ssrEnterLobbyNoChecks(
111114
LobbyData: api.CreateLobbyData(handler.cfg, lobby),
112115
Translation: translation,
113116
Locale: locale,
117+
Keys: &lobbyKeyboardShortcuts,
114118
}
115119
})
116120

internal/frontend/lobby.js

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ function createDialogButton(text) {
151151
function createDialogButtonBar(...buttons) {
152152
const buttonBar = document.createElement("div");
153153
buttonBar.classList.add("button-bar");
154-
buttons.forEach(buttonBar.appendChild);
154+
buttons.forEach((button) => buttonBar.appendChild(button));
155155
return buttonBar;
156156
}
157157

@@ -171,18 +171,19 @@ function showHelpDialog() {
171171
const controlsLabel = document.createElement("b");
172172
controlsLabel.innerText = '{{.Translation.Get "controls"}}';
173173

174-
const controlsTextOne = document.createElement("p");
175-
controlsTextOne.innerText = '{{.Translation.Get "switch-tools-intro"}}:';
176-
177-
const controlsTextTwo = document.createElement("p");
178-
controlsTextTwo.innerHTML =
179-
'{{.Translation.Get "pencil"}}: <kbd>Q</kbd><br/>' +
180-
'{{.Translation.Get "fill-bucket"}}: <kbd>W</kbd><br/>' +
181-
'{{.Translation.Get "eraser"}}: <kbd>E</kbd><br/>';
182-
183-
const controlsTextThree = document.createElement("p");
184-
controlsTextThree.innerHTML =
185-
'{{printf (.Translation.Get "switch-pencil-sizes") "<kbd>1</kbd>" "<kbd>4</kbd>"}}';
174+
const size8Key = {{printf "%q" .Keys.Size8}};
175+
const size32Key = {{printf "%q" .Keys.Size32}};
176+
const undoModifierKeysString = {{printf "%q" .Keys.UndoModifier}}.split("+").map(k => `<kbd>${k}</kbd>`).join("+");
177+
const controlsText = document.createElement("div");
178+
controlsText.classList.add("help-controls-grid");
179+
controlsText.innerHTML =
180+
`
181+
<span>{{.Translation.Get "pencil"}}</span><span dir="ltr"><kbd>{{.Keys.Pen}}</kbd></span>
182+
<span>{{.Translation.Get "fill-bucket"}}</span><span dir="ltr"><kbd>{{.Keys.Bucket}}</kbd></span>
183+
<span>{{.Translation.Get "eraser"}}</span><span dir="ltr"><kbd>{{.Keys.Rubber}}</kbd></span>
184+
<span>{{.Translation.Get "undo-help-message"}}</span><span dir="ltr">${undoModifierKeysString}+<kbd>{{.Keys.Undo}}</kbd></span>
185+
<span>{{.Translation.Get "switch-pencil-sizes"}}</span><span dir="ltr"><kbd>${size8Key}</kbd>-<kbd>${size32Key}</kbd></span>
186+
`;
186187

187188
const closeButton = createDialogButton('{{.Translation.Get "close"}}');
188189
closeButton.addEventListener("click", () => {
@@ -197,9 +198,7 @@ function showHelpDialog() {
197198

198199
const dialogContent = document.createElement("div");
199200
dialogContent.appendChild(controlsLabel);
200-
dialogContent.appendChild(controlsTextOne);
201-
dialogContent.appendChild(controlsTextTwo);
202-
dialogContent.appendChild(controlsTextThree);
201+
dialogContent.appendChild(controlsText);
203202
dialogContent.appendChild(footer);
204203

205204
showDialog(
@@ -1890,6 +1889,13 @@ function isAnyDialogVisible() {
18901889
return false;
18911890
}
18921891

1892+
function getModifierKey(event, modifierKey) {
1893+
// Split by "+" and ensure every specified modifier property is true on the event.
1894+
// e.g. "ctrl+shift" checks event.ctrlKey AND event.shiftKey
1895+
return modifierKey.split("+").every(modifier => event[`${modifier}Key`]);
1896+
}
1897+
1898+
18931899
function onKeyDown(event) {
18941900
//Avoid firing actions if the user is in the chat.
18951901
if (document.activeElement instanceof HTMLInputElement) {
@@ -1907,28 +1913,29 @@ function onKeyDown(event) {
19071913
//find it better than having to find specific keys on your
19081914
//keyboard. Especially for people that aren't used to typing
19091915
//without looking at their keyboard, this might help.
1910-
if (event.key === "q") {
1916+
if (event.key === {{printf "%q" .Keys.Pen}}) {
19111917
toolButtonPen.click();
19121918
chooseTool(pen);
1913-
} else if (event.key === "w") {
1919+
} else if (event.key === {{printf "%q" .Keys.Bucket}}) {
19141920
toolButtonFill.click();
19151921
chooseTool(fillBucket);
1916-
} else if (event.key === "e") {
1922+
} else if (event.key === {{printf "%q" .Keys.Rubber}}){
19171923
toolButtonRubber.click();
19181924
chooseTool(rubber);
1919-
} else if (event.key === "1") {
1925+
} else if (event.key === {{printf "%q" .Keys.Size8}}) {
19201926
sizeButton8.click();
19211927
setLineWidth(8);
1922-
} else if (event.key === "2") {
1928+
} else if (event.key === {{printf "%q" .Keys.Size16}}) {
19231929
sizeButton16.click();
19241930
setLineWidth(16);
1925-
} else if (event.key === "3") {
1931+
} else if (event.key === {{printf "%q" .Keys.Size24}}) {
19261932
sizeButton24.click();
19271933
setLineWidth(24);
1928-
} else if (event.key === "4") {
1934+
} else if (event.key === {{printf "%q" .Keys.Size32}}) {
19291935
sizeButton32.click();
19301936
setLineWidth(32);
1931-
} else if (event.key === "z" && event.ctrlKey) {
1937+
} else if (getModifierKey(event, "{{.Keys.UndoModifier}}") && event.key.toLowerCase() === {{printf "%q" .Keys.Undo }}) {
1938+
// TODO: how to match .Keys.UndoModifier to event.ctrlKey ??
19321939
undoAndSendEvent();
19331940
}
19341941
}

internal/frontend/resources/lobby.css

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ kbd {
4747
display: inline-block;
4848
font-size: 0.85em;
4949
font-weight: 700;
50-
line-height: 1;
5150
vertical-align: middle;
5251
padding: 2px 4px;
5352
white-space: nowrap;
53+
width: fit-content;
5454
}
5555

5656
@media only screen and (max-width: 812px),
@@ -811,3 +811,14 @@ kbd {
811811
gap: 10px;
812812
font-size: 1rem !important;
813813
}
814+
815+
#help-dialog {
816+
width: 16%;
817+
}
818+
819+
.help-controls-grid {
820+
display: grid;
821+
grid-template-columns: max-content auto;
822+
gap: 0.25rem 1rem;
823+
margin-top: 0.5rem;
824+
}

internal/frontend/templates/lobby.html

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@
298298
<input id="tool-type-pencil" class="custom-check-or-radio line-width-button" type="radio"
299299
name="tool-type" checked>
300300
<div id="tool-type-pencil-wrapper" class="line-width-button-content">
301-
<img title="{{.Translation.Get "use-pencil"}}" alt="{{.Translation.Get "use-pencil"}}"
301+
<img title="{{.Translation.Get "use-pencil"}} ({{.Keys.Pen}})" alt="{{.Translation.Get "use-pencil"}}"
302302
src='{{.RootPath}}/resources/{{.WithCacheBust "pencil.svg"}}'
303303
style="transform: scaleX(-1)" />
304304
</div>
@@ -308,15 +308,15 @@
308308
name="tool-type">
309309
<div id="tool-type-fill-wrapper" class="line-width-button-content">
310310
<img alt="{{.Translation.Get "use-fill-bucket"}}"
311-
title="{{.Translation.Get "use-fill-bucket"}}"
311+
title="{{.Translation.Get "use-fill-bucket"}} ({{.Keys.Bucket}})"
312312
src='{{.RootPath}}/resources/{{.WithCacheBust "fill.svg"}}' />
313313
</div>
314314
</label>
315315
<label for="tool-type-rubber">
316316
<input id="tool-type-rubber" class="custom-check-or-radio line-width-button" type="radio"
317317
name="tool-type">
318318
<div id="tool-type-rubber-wrapper" class="line-width-button-content">
319-
<img alt="{{.Translation.Get "use-eraser"}}" title="{{.Translation.Get "use-eraser"}}"
319+
<img alt="{{.Translation.Get "use-eraser"}}" title="{{.Translation.Get "use-eraser"}} ({{.Keys.Rubber}})"
320320
src='{{.RootPath}}/resources/{{.WithCacheBust "rubber.svg"}}' />
321321
</div>
322322
</label>
@@ -327,7 +327,7 @@
327327
name="line-width" checked>
328328
<div id="size-8-button-wrapper" class="line-width-button-content"
329329
alt="{{printf (.Translation.Get "change-pencil-size-to") "8"}}"
330-
title="{{printf (.Translation.Get "change-pencil-size-to") "8"}}">
330+
title="{{printf (.Translation.Get "change-pencil-size-to") "8"}} ({{.Keys.Size8}})">
331331
<div class="dot" style="width: 8px; height: 8px"></div>
332332
</div>
333333
</label>
@@ -336,7 +336,7 @@
336336
name="line-width">
337337
<div id="size-16-button-wrapper" class="line-width-button-content"
338338
alt="{{printf (.Translation.Get "change-pencil-size-to") "16"}}"
339-
title="{{printf (.Translation.Get "change-pencil-size-to") "16"}}">
339+
title="{{printf (.Translation.Get "change-pencil-size-to") "16"}} ({{.Keys.Size16}})">
340340
<div class="dot" style="width: 16px; height: 16px"></div>
341341
</div>
342342
</label>
@@ -345,7 +345,7 @@
345345
name="line-width">
346346
<div id="size-24-button-wrapper" class="line-width-button-content"
347347
alt="{{printf (.Translation.Get "change-pencil-size-to") "24"}}"
348-
title="{{printf (.Translation.Get "change-pencil-size-to") "24"}}">
348+
title="{{printf (.Translation.Get "change-pencil-size-to") "24"}} ({{.Keys.Size24}})">
349349
<div class="dot" style="width: 24px; height: 24px"></div>
350350
</div>
351351
</label>
@@ -354,7 +354,7 @@
354354
name="line-width">
355355
<div id="size-32-button-wrapper" class="line-width-button-content"
356356
alt="{{printf (.Translation.Get "change-pencil-size-to") "32"}}"
357-
title="{{printf (.Translation.Get "change-pencil-size-to") "32"}}">
357+
title="{{printf (.Translation.Get "change-pencil-size-to") "32"}} ({{.Keys.Size32}})">
358358
<div class="dot" style="width: 32px; height: 32px"></div>
359359
</div>
360360
</label>
@@ -368,7 +368,7 @@
368368
<!--We won't make this button easier to click, as there's no going back. -->
369369
<button id="undo-button" class="canvas-button toolbox-group" alt="{{.Translation.Get "undo"}}"
370370
title="{{.Translation.Get "undo"}}">
371-
<img alt="{{.Translation.Get "undo"}}" title="{{.Translation.Get "undo"}}"
371+
<img alt="{{.Translation.Get "undo"}}" title="{{.Translation.Get "undo"}} ({{.Keys.UndoModifier}}+{{.Keys.Undo}})"
372372
src='{{.RootPath}}/resources/{{.WithCacheBust "undo.svg"}}' />
373373
</button>
374374
</div>

internal/frontend/templating_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func Test_templateLobbyPage(t *testing.T) {
2424
GameConstants: api.GameConstantsData,
2525
},
2626
Translation: translations.DefaultTranslation,
27+
Keys: &lobbyKeyboardShortcuts,
2728
})
2829
if err != nil {
2930
t.Errorf("Error templating: %s", err)

internal/translations/ar.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ func initArabicTranslation() *Translation {
117117
translation.put("pencil", "القلم")
118118
translation.put("eraser", "الممحاة")
119119
translation.put("fill-bucket", "الملء بالدلو")
120-
translation.put("switch-tools-intro", "يمكنك التحويل بين الأدوات بواسطة الاختصارات")
121120
translation.put("switch-pencil-sizes", "يمكنك التغيير بين احجام القلم من %s إلى %s.")
122121

123122
// Generic words

internal/translations/de_DE.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ func initGermanTranslation() {
110110
translation.put("pencil", "Stift")
111111
translation.put("eraser", "Radiergummi")
112112
translation.put("fill-bucket", "Fülleimer")
113-
translation.put("switch-tools-intro", "Zwischen den Werkzeugen kannst du mit Tastaturkürzel wechseln")
114113
translation.put("switch-pencil-sizes", "Die Stiftgröße kannst du mit den Tasten %s bis %s verändern.")
115114

116115
// Generic words

internal/translations/en_us.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ func initEnglishTranslation() *Translation {
128128
translation.put("pencil", "Pencil")
129129
translation.put("eraser", "Eraser")
130130
translation.put("fill-bucket", "Fill bucket")
131-
translation.put("switch-tools-intro", "You can switch between tools using shortcuts")
132-
translation.put("switch-pencil-sizes", "You can also switch between pencil sizes using keys %s to %s.")
131+
translation.put("switch-pencil-sizes", "Tool sizes")
132+
translation.put("undo-help-message", "Undo")
133133

134134
// Generic words
135135
// "close" as in "closing the window"

internal/translations/es_ES.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ func initSpainTranslation() {
116116
translation.put("pencil", "Lápiz")
117117
translation.put("eraser", "Borrador")
118118
translation.put("fill-bucket", "Llenar el cubo")
119-
translation.put("switch-tools-intro", "Puede cambiar entre herramientas mediante atajos")
120119
translation.put("switch-pencil-sizes", "También puedes cambiar entre tamaños de lápiz usando teclas %s para %s.")
121120

122121
// Generic words

0 commit comments

Comments
 (0)