Fix ShortcutLabel drawing of consecutive key labels

This commit is contained in:
Keavon Chambers 2025-12-04 22:04:37 -08:00
parent 8ca546c164
commit 74d9c911bd
5 changed files with 50 additions and 25 deletions

1
.gitignore vendored
View File

@ -9,5 +9,6 @@ profile.json.gz
flamegraph.svg flamegraph.svg
.idea/ .idea/
.direnv .direnv
.DS_Store
hierarchical_message_system_tree.txt hierarchical_message_system_tree.txt
hierarchical_message_system_tree.html hierarchical_message_system_tree.html

View File

@ -411,6 +411,7 @@ pub fn input_mappings() -> Mapping {
entry!(KeyDown(Equal); modifiers=[Accel], action_dispatch=NavigationMessage::CanvasZoomIncrease { center_on_mouse: false }), entry!(KeyDown(Equal); modifiers=[Accel], action_dispatch=NavigationMessage::CanvasZoomIncrease { center_on_mouse: false }),
entry!(KeyDown(Minus); modifiers=[Accel], action_dispatch=NavigationMessage::CanvasZoomDecrease { center_on_mouse: false }), entry!(KeyDown(Minus); modifiers=[Accel], action_dispatch=NavigationMessage::CanvasZoomDecrease { center_on_mouse: false }),
entry!(WheelScroll; modifiers=[Control], action_dispatch=NavigationMessage::CanvasZoomMouseWheel), entry!(WheelScroll; modifiers=[Control], action_dispatch=NavigationMessage::CanvasZoomMouseWheel),
entry!(WheelScroll; modifiers=[Command], action_dispatch=NavigationMessage::CanvasZoomMouseWheel),
entry!(WheelScroll; modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: true }), entry!(WheelScroll; modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: true }),
entry!(WheelScroll; action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: false }), entry!(WheelScroll; action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: false }),
entry!(KeyDown(PageUp); modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanByViewportFraction { delta: DVec2::new(1., 0.) }), entry!(KeyDown(PageUp); modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanByViewportFraction { delta: DVec2::new(1., 0.) }),

View File

@ -9,8 +9,8 @@
export let shortcut: ActionShortcut; export let shortcut: ActionShortcut;
function keyTextOrIconList(keyGroup: LabeledShortcut): { label?: string; icon?: IconName; mouseMotion?: MouseMotion }[] { function keyTextOrIconList(keyGroup: LabeledShortcut): ({ label?: string; icon?: IconName }[] | { mouseMotion?: MouseMotion }[])[] {
const list = keyGroup.map((labeledKeyOrMouseMotion) => { const list = keyGroup.map((labeledKeyOrMouseMotion): { label?: string; icon?: IconName; mouseMotion?: MouseMotion } => {
// Use a mouse icon if it's a mouse motion instead of a key // Use a mouse icon if it's a mouse motion instead of a key
if (typeof labeledKeyOrMouseMotion === "string") return { mouseMotion: labeledKeyOrMouseMotion }; if (typeof labeledKeyOrMouseMotion === "string") return { mouseMotion: labeledKeyOrMouseMotion };
@ -33,11 +33,25 @@
}); });
// Consolidate consecutive labels into a concatenated single label // Consolidate consecutive labels into a concatenated single label
const consolidatedList: typeof list = []; const consolidatedList: ReturnType<typeof keyTextOrIconList> = [];
list.forEach((item) => { list.forEach((currentItem) => {
const lastItem = consolidatedList[consolidatedList.length - 1]; const lastGroup = consolidatedList.length > 0 ? consolidatedList[consolidatedList.length - 1] : undefined;
if (item.label && lastItem?.label) lastItem.label += " " + item.label; const lastItem = lastGroup !== undefined ? lastGroup[lastGroup.length - 1] : undefined;
else consolidatedList.push(item);
// If current and last are both labels, concatenate both within their existing label
if (currentItem.label && lastItem && "label" in lastItem && lastItem.label) {
lastItem.label += " " + currentItem.label;
return;
}
// If current and last are both of the same group type (both icons/labels, or both mouseMotion), join them within their existing
if (lastItem && (((currentItem.label || currentItem.icon) && ("label" in lastItem || "icon" in lastItem)) || (currentItem.mouseMotion && "mouseMotion" in lastItem))) {
lastGroup?.push(currentItem);
return;
}
// Otherwise, start a new group with the first item of its group type
consolidatedList.push([currentItem]);
}); });
return consolidatedList; return consolidatedList;
} }
@ -73,32 +87,38 @@
} }
} }
function mouseHintIcon(input?: MouseMotion): IconName { function mouseHintIcon(input: MouseMotion): IconName {
return `MouseHint${input}` as IconName; return `MouseHint${input}` as IconName;
} }
</script> </script>
<LayoutRow class="shortcut-label"> <LayoutRow class="shortcut-label">
{#each keyTextOrIconList(shortcut.shortcut) as { label, icon, mouseMotion }} {#each keyTextOrIconList(shortcut.shortcut) as group}
{#if label} {#if "label" in group[0] || "icon" in group[0]}
<div class="key-label"> <div class="key-label">
<TextLabel>{label}</TextLabel> {#each group as item}
{#if "label" in item && item.label}
<TextLabel>{item.label}</TextLabel>
{:else if "icon" in item && item.icon}
<IconLabel icon={item.icon} />
{/if}
{/each}
</div> </div>
{:else if icon} {/if}
<div class="key-icon"> {#if "mouseMotion" in group[0]}
<IconLabel {icon} /> {#each group as item}
</div> {#if "mouseMotion" in item && item.mouseMotion}
{:else if mouseMotion}
<div class="mouse-icon"> <div class="mouse-icon">
<IconLabel icon={mouseHintIcon(mouseMotion)} /> <IconLabel icon={mouseHintIcon(item.mouseMotion)} />
</div> </div>
{/if} {/if}
{/each} {/each}
{/if}
{/each}
</LayoutRow> </LayoutRow>
<style lang="scss" global> <style lang="scss" global>
.shortcut-label { .shortcut-label {
.key-icon,
.key-label { .key-label {
display: flex; display: flex;
align-items: center; align-items: center;
@ -108,6 +128,10 @@
background: var(--color-3-darkgray); background: var(--color-3-darkgray);
color: var(--color-b-lightgray); color: var(--color-b-lightgray);
fill: var(--color-b-lightgray); fill: var(--color-b-lightgray);
* + * {
margin-left: 4px;
}
} }
svg { svg {
@ -120,7 +144,6 @@
.floating-menu-content .row > & { .floating-menu-content .row > & {
.key-label, .key-label,
.key-icon,
.mouse-icon { .mouse-icon {
color: var(--color-8-uppergray); color: var(--color-8-uppergray);
background: none; background: none;
@ -134,7 +157,7 @@
} }
} }
.key-icon svg { .key-label svg {
fill: var(--color-8-uppergray); fill: var(--color-8-uppergray);
} }

View File

@ -33,7 +33,7 @@
export let tabMinWidths = false; export let tabMinWidths = false;
export let tabCloseButtons = false; export let tabCloseButtons = false;
export let tabLabels: { name: string; unsaved?: boolean; tooltipDescription?: string; tooltipShortcut?: string }[]; export let tabLabels: { name: string; unsaved?: boolean; tooltipLabel?: string; tooltipDescription?: string; tooltipShortcut?: string }[];
export let tabActiveIndex: number; export let tabActiveIndex: number;
export let panelType: PanelType | undefined = undefined; export let panelType: PanelType | undefined = undefined;
export let clickAction: ((index: number) => void) | undefined = undefined; export let clickAction: ((index: number) => void) | undefined = undefined;
@ -67,7 +67,7 @@
<LayoutRow <LayoutRow
class="tab" class="tab"
classes={{ active: tabIndex === tabActiveIndex }} classes={{ active: tabIndex === tabActiveIndex }}
tooltipLabel={tabLabel.name} tooltipLabel={tabLabel.tooltipLabel}
tooltipDescription={tabLabel.tooltipDescription} tooltipDescription={tabLabel.tooltipDescription}
on:click={(e) => { on:click={(e) => {
e.stopPropagation(); e.stopPropagation();

View File

@ -33,7 +33,7 @@
if (!editor.handle.inDevelopmentMode()) return { name, unsaved }; if (!editor.handle.inDevelopmentMode()) return { name, unsaved };
const tooltipDescription = `Document ID: ${doc.id}`; const tooltipDescription = `Document ID: ${doc.id}`;
return { name, unsaved, tooltipDescription }; return { name, unsaved, tooltipLabel: name, tooltipDescription };
}); });
const editor = getContext<Editor>("editor"); const editor = getContext<Editor>("editor");