mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-21 06:28:11 +08:00
* Remove the svelte-preprocess dev dependency, keeping global styles with a custom Vite plugin * More robust style tag detection * Fix CSS regressions
191 lines
5.6 KiB
Svelte
191 lines
5.6 KiB
Svelte
<script lang="ts">
|
|
import LayoutRow from "/src/components/layout/LayoutRow.svelte";
|
|
import IconLabel from "/src/components/widgets/labels/IconLabel.svelte";
|
|
import TextLabel from "/src/components/widgets/labels/TextLabel.svelte";
|
|
import type { IconName } from "/src/icons";
|
|
import { operatingSystem } from "/src/utility-functions/platform";
|
|
import type { ActionShortcut, Key, LabeledShortcut, MouseMotion } from "/wrapper/pkg/graphite_wasm_wrapper";
|
|
|
|
// Content
|
|
export let shortcut: ActionShortcut;
|
|
|
|
function keyTextOrIconList(keyGroup: LabeledShortcut): ({ label?: string; icon?: IconName }[] | { mouseMotion?: MouseMotion }[])[] {
|
|
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
|
|
if (typeof labeledKeyOrMouseMotion === "string") return { mouseMotion: labeledKeyOrMouseMotion };
|
|
|
|
// `key` is the name of the `Key` enum in Rust, while `label` is the localized string to display (if it doesn't become an icon)
|
|
let key: Key | "Option" = labeledKeyOrMouseMotion.key;
|
|
const label = labeledKeyOrMouseMotion.label;
|
|
|
|
// Replace Alt and Accel keys with their Mac-specific equivalents
|
|
if (operatingSystem() === "Mac") {
|
|
if (key === "Alt") key = "Option";
|
|
if (key === "Accel") key = "Command";
|
|
}
|
|
|
|
// Either display an icon...
|
|
const icon = keyboardHintIcon(key);
|
|
if (icon) return { icon };
|
|
|
|
// ...or display text
|
|
return { label };
|
|
});
|
|
|
|
// Consolidate consecutive labels into a concatenated single label
|
|
const consolidatedList: ReturnType<typeof keyTextOrIconList> = [];
|
|
list.forEach((currentItem) => {
|
|
const lastGroup = consolidatedList.length > 0 ? consolidatedList[consolidatedList.length - 1] : undefined;
|
|
const lastItem = lastGroup !== undefined ? lastGroup[lastGroup.length - 1] : undefined;
|
|
|
|
// 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;
|
|
}
|
|
|
|
function keyboardHintIcon(input: Key | "Option"): IconName | undefined {
|
|
switch (input) {
|
|
case "ArrowDown":
|
|
return "KeyboardArrowDown";
|
|
case "ArrowLeft":
|
|
return "KeyboardArrowLeft";
|
|
case "ArrowRight":
|
|
return "KeyboardArrowRight";
|
|
case "ArrowUp":
|
|
return "KeyboardArrowUp";
|
|
case "Backspace":
|
|
return "KeyboardBackspace";
|
|
case "Enter":
|
|
return "KeyboardEnter";
|
|
case "Space":
|
|
return "KeyboardSpace";
|
|
case "Tab":
|
|
return "KeyboardTab";
|
|
case "Command":
|
|
return operatingSystem() === "Mac" ? "KeyboardCommand" : undefined;
|
|
case "Control":
|
|
return operatingSystem() === "Mac" ? "KeyboardControl" : undefined;
|
|
case "Option":
|
|
return operatingSystem() === "Mac" ? "KeyboardOption" : undefined;
|
|
case "Shift":
|
|
return operatingSystem() === "Mac" ? "KeyboardShift" : undefined;
|
|
default:
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
function mouseHintIcon(input: MouseMotion): IconName {
|
|
return {
|
|
None: "MouseHintNone" as const,
|
|
Lmb: "MouseHintLmb" as const,
|
|
Rmb: "MouseHintRmb" as const,
|
|
Mmb: "MouseHintMmb" as const,
|
|
ScrollUp: "MouseHintScrollUp" as const,
|
|
ScrollDown: "MouseHintScrollDown" as const,
|
|
Drag: "MouseHintDrag" as const,
|
|
LmbDouble: "MouseHintLmbDouble" as const,
|
|
LmbDrag: "MouseHintLmbDrag" as const,
|
|
RmbDrag: "MouseHintRmbDrag" as const,
|
|
RmbDouble: "MouseHintRmbDouble" as const,
|
|
MmbDrag: "MouseHintMmbDrag" as const,
|
|
}[input];
|
|
}
|
|
</script>
|
|
|
|
<LayoutRow class="shortcut-label">
|
|
{#each keyTextOrIconList(shortcut.shortcut) as group}
|
|
{#if "label" in group[0] || "icon" in group[0]}
|
|
<div class="key-label">
|
|
{#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>
|
|
{/if}
|
|
{#if "mouseMotion" in group[0]}
|
|
{#each group as item}
|
|
{#if "mouseMotion" in item && item.mouseMotion}
|
|
<div class="mouse-icon">
|
|
<IconLabel icon={mouseHintIcon(item.mouseMotion)} />
|
|
</div>
|
|
{/if}
|
|
{/each}
|
|
{/if}
|
|
{/each}
|
|
</LayoutRow>
|
|
|
|
<style lang="scss">
|
|
.shortcut-label {
|
|
align-items: center;
|
|
|
|
.key-label {
|
|
display: flex;
|
|
align-items: center;
|
|
height: 16px;
|
|
padding: 0 4px;
|
|
border-radius: 4px;
|
|
background: var(--color-3-darkgray);
|
|
color: var(--color-b-lightgray);
|
|
fill: var(--color-b-lightgray);
|
|
|
|
* + * {
|
|
margin-left: 4px;
|
|
}
|
|
}
|
|
|
|
svg {
|
|
fill: var(--color-b-lightgray);
|
|
|
|
.dim {
|
|
fill: var(--color-8-uppergray);
|
|
}
|
|
}
|
|
}
|
|
|
|
.floating-menu-content .row > .shortcut-label {
|
|
.key-label,
|
|
.mouse-icon {
|
|
color: var(--color-8-uppergray);
|
|
background: none;
|
|
|
|
&:first-child {
|
|
padding-left: 0;
|
|
}
|
|
|
|
&:last-child {
|
|
padding-right: 0;
|
|
}
|
|
}
|
|
|
|
.key-label svg {
|
|
fill: var(--color-8-uppergray);
|
|
}
|
|
|
|
.mouse-icon svg {
|
|
// 3 shades brighter than the 8-uppergray of key labels/icons
|
|
fill: var(--color-b-lightgray);
|
|
|
|
.dim {
|
|
// 3 shades darker than the 8-uppergray of key labels/icons
|
|
fill: var(--color-5-dullgray);
|
|
}
|
|
}
|
|
}
|
|
</style>
|