|
9 | 9 |
|
10 | 10 | export let shortcut: ActionShortcut; |
11 | 11 |
|
12 | | - function keyTextOrIconList(keyGroup: LabeledShortcut): { label?: string; icon?: IconName; mouseMotion?: MouseMotion }[] { |
13 | | - const list = keyGroup.map((labeledKeyOrMouseMotion) => { |
| 12 | + function keyTextOrIconList(keyGroup: LabeledShortcut): ({ label?: string; icon?: IconName }[] | { mouseMotion?: MouseMotion }[])[] { |
| 13 | + const list = keyGroup.map((labeledKeyOrMouseMotion): { label?: string; icon?: IconName; mouseMotion?: MouseMotion } => { |
14 | 14 | // Use a mouse icon if it's a mouse motion instead of a key |
15 | 15 | if (typeof labeledKeyOrMouseMotion === "string") return { mouseMotion: labeledKeyOrMouseMotion }; |
16 | 16 |
|
|
33 | 33 | }); |
34 | 34 |
|
35 | 35 | // Consolidate consecutive labels into a concatenated single label |
36 | | - const consolidatedList: typeof list = []; |
37 | | - list.forEach((item) => { |
38 | | - const lastItem = consolidatedList[consolidatedList.length - 1]; |
39 | | - if (item.label && lastItem?.label) lastItem.label += " " + item.label; |
40 | | - else consolidatedList.push(item); |
| 36 | + const consolidatedList: ReturnType<typeof keyTextOrIconList> = []; |
| 37 | + list.forEach((currentItem) => { |
| 38 | + const lastGroup = consolidatedList.length > 0 ? consolidatedList[consolidatedList.length - 1] : undefined; |
| 39 | + const lastItem = lastGroup !== undefined ? lastGroup[lastGroup.length - 1] : undefined; |
| 40 | +
|
| 41 | + // If current and last are both labels, concatenate both within their existing label |
| 42 | + if (currentItem.label && lastItem && "label" in lastItem && lastItem.label) { |
| 43 | + lastItem.label += " " + currentItem.label; |
| 44 | + return; |
| 45 | + } |
| 46 | +
|
| 47 | + // If current and last are both of the same group type (both icons/labels, or both mouseMotion), join them within their existing |
| 48 | + if (lastItem && (((currentItem.label || currentItem.icon) && ("label" in lastItem || "icon" in lastItem)) || (currentItem.mouseMotion && "mouseMotion" in lastItem))) { |
| 49 | + lastGroup?.push(currentItem); |
| 50 | + return; |
| 51 | + } |
| 52 | +
|
| 53 | + // Otherwise, start a new group with the first item of its group type |
| 54 | + consolidatedList.push([currentItem]); |
41 | 55 | }); |
42 | 56 | return consolidatedList; |
43 | 57 | } |
|
73 | 87 | } |
74 | 88 | } |
75 | 89 |
|
76 | | - function mouseHintIcon(input?: MouseMotion): IconName { |
| 90 | + function mouseHintIcon(input: MouseMotion): IconName { |
77 | 91 | return `MouseHint${input}` as IconName; |
78 | 92 | } |
79 | 93 | </script> |
80 | 94 |
|
81 | 95 | <LayoutRow class="shortcut-label"> |
82 | | - {#each keyTextOrIconList(shortcut.shortcut) as { label, icon, mouseMotion }} |
83 | | - {#if label} |
| 96 | + {#each keyTextOrIconList(shortcut.shortcut) as group} |
| 97 | + {#if "label" in group[0] || "icon" in group[0]} |
84 | 98 | <div class="key-label"> |
85 | | - <TextLabel>{label}</TextLabel> |
86 | | - </div> |
87 | | - {:else if icon} |
88 | | - <div class="key-icon"> |
89 | | - <IconLabel {icon} /> |
90 | | - </div> |
91 | | - {:else if mouseMotion} |
92 | | - <div class="mouse-icon"> |
93 | | - <IconLabel icon={mouseHintIcon(mouseMotion)} /> |
| 99 | + {#each group as item} |
| 100 | + {#if "label" in item && item.label} |
| 101 | + <TextLabel>{item.label}</TextLabel> |
| 102 | + {:else if "icon" in item && item.icon} |
| 103 | + <IconLabel icon={item.icon} /> |
| 104 | + {/if} |
| 105 | + {/each} |
94 | 106 | </div> |
95 | 107 | {/if} |
| 108 | + {#if "mouseMotion" in group[0]} |
| 109 | + {#each group as item} |
| 110 | + {#if "mouseMotion" in item && item.mouseMotion} |
| 111 | + <div class="mouse-icon"> |
| 112 | + <IconLabel icon={mouseHintIcon(item.mouseMotion)} /> |
| 113 | + </div> |
| 114 | + {/if} |
| 115 | + {/each} |
| 116 | + {/if} |
96 | 117 | {/each} |
97 | 118 | </LayoutRow> |
98 | 119 |
|
99 | 120 | <style lang="scss" global> |
100 | 121 | .shortcut-label { |
101 | | - .key-icon, |
102 | 122 | .key-label { |
103 | 123 | display: flex; |
104 | 124 | align-items: center; |
|
108 | 128 | background: var(--color-3-darkgray); |
109 | 129 | color: var(--color-b-lightgray); |
110 | 130 | fill: var(--color-b-lightgray); |
| 131 | +
|
| 132 | + * + * { |
| 133 | + margin-left: 4px; |
| 134 | + } |
111 | 135 | } |
112 | 136 |
|
113 | 137 | svg { |
|
120 | 144 |
|
121 | 145 | .floating-menu-content .row > & { |
122 | 146 | .key-label, |
123 | | - .key-icon, |
124 | 147 | .mouse-icon { |
125 | 148 | color: var(--color-8-uppergray); |
126 | 149 | background: none; |
|
134 | 157 | } |
135 | 158 | } |
136 | 159 |
|
137 | | - .key-icon svg { |
| 160 | + .key-label svg { |
138 | 161 | fill: var(--color-8-uppergray); |
139 | 162 | } |
140 | 163 |
|
|
0 commit comments