feat(shortcuts): open data in a new tab
This commit is contained in:
16 files changed
+265
-23
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { parseShortcutParts } from "@/lib/editor/shortcutDisplay";
|
||||
import { isMacShortcutPlatform, parseShortcutParts } from "@/lib/editor/shortcutDisplay";
|
||||
import { normalizeShortcutSettings, type ShortcutActionId, type ShortcutSettings } from "@/lib/editor/shortcutRegistry";
|
||||
|
||||
export interface ShortcutLikeEvent {
|
||||
@@ -41,6 +41,29 @@ export function eventToShortcut(event: ShortcutLikeEvent): string | null {
|
||||
return parts.join("+");
|
||||
}
|
||||
|
||||
export function eventToModifierOnlyShortcut(event: ShortcutLikeEvent, platform = globalThis.navigator?.platform || ""): string | null {
|
||||
if (event.isComposing) return null;
|
||||
if (event.key === "Alt") return "Alt";
|
||||
if (event.key === "Shift") return "Shift";
|
||||
if (event.key === "Meta") return isMacShortcutPlatform(platform) ? "Mod" : "Meta";
|
||||
if (event.key === "Control") return isMacShortcutPlatform(platform) ? "Ctrl" : "Mod";
|
||||
return null;
|
||||
}
|
||||
|
||||
export function matchesModifierOnlyShortcut(event: Omit<ShortcutLikeEvent, "key">, shortcut: string): boolean {
|
||||
if (event.isComposing || !shortcut) return false;
|
||||
const meta = !!event.metaKey;
|
||||
const ctrl = !!event.ctrlKey;
|
||||
const alt = !!event.altKey;
|
||||
const shift = !!event.shiftKey;
|
||||
if (shortcut === "Mod") return meta !== ctrl && !alt && !shift;
|
||||
if (shortcut === "Meta") return meta && !ctrl && !alt && !shift;
|
||||
if (shortcut === "Ctrl") return ctrl && !meta && !alt && !shift;
|
||||
if (shortcut === "Alt") return alt && !meta && !ctrl && !shift;
|
||||
if (shortcut === "Shift") return shift && !meta && !ctrl && !alt;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function matchesShortcut(event: ShortcutLikeEvent, shortcut: string): boolean {
|
||||
if (event.isComposing || !shortcut) return false;
|
||||
const parts = parseShortcutParts(shortcut);
|
||||
|
||||
@@ -50,6 +50,7 @@ export type ShortcutActionId =
|
||||
| "copySidebarSelection"
|
||||
| "pasteSidebarSelection"
|
||||
| "editSidebarConnection"
|
||||
| "openDataInNewTab"
|
||||
| "sendSelectionToAi";
|
||||
|
||||
export type ShortcutScope = "global" | "editor" | "grid" | "search" | "sidebar";
|
||||
@@ -59,6 +60,7 @@ export interface ShortcutDefinition {
|
||||
labelKey: string;
|
||||
scope: ShortcutScope;
|
||||
defaultShortcut: string;
|
||||
inputKind?: "keyboard" | "modifier-only";
|
||||
}
|
||||
|
||||
export type ShortcutSettings = Record<ShortcutActionId, string>;
|
||||
@@ -358,6 +360,13 @@ export const SHORTCUT_DEFINITIONS: ShortcutDefinition[] = [
|
||||
scope: "sidebar",
|
||||
defaultShortcut: "Mod+E",
|
||||
},
|
||||
{
|
||||
id: "openDataInNewTab",
|
||||
labelKey: "settings.shortcutOpenDataInNewTab",
|
||||
scope: "sidebar",
|
||||
defaultShortcut: "Alt",
|
||||
inputKind: "modifier-only",
|
||||
},
|
||||
{
|
||||
id: "sendSelectionToAi",
|
||||
labelKey: "settings.shortcutSendSelectionToAi",
|
||||
@@ -368,8 +377,23 @@ export const SHORTCUT_DEFINITIONS: ShortcutDefinition[] = [
|
||||
|
||||
export const DEFAULT_SHORTCUT_SETTINGS: ShortcutSettings = Object.fromEntries(SHORTCUT_DEFINITIONS.map((definition) => [definition.id, definition.defaultShortcut])) as ShortcutSettings;
|
||||
|
||||
const modifierOnlyShortcuts = new Set(["Alt", "Shift", "Mod", "Ctrl", "Meta"]);
|
||||
|
||||
export function normalizeModifierOnlyShortcut(shortcut: string, fallback = ""): string {
|
||||
const normalized = shortcut.trim() === "Control" ? "Ctrl" : shortcut.trim();
|
||||
if (normalized === "") return "";
|
||||
return modifierOnlyShortcuts.has(normalized) ? normalized : fallback;
|
||||
}
|
||||
|
||||
export function normalizeShortcutSettings(settings?: Partial<ShortcutSettings>): ShortcutSettings {
|
||||
return Object.fromEntries(SHORTCUT_DEFINITIONS.map((definition) => [definition.id, typeof settings?.[definition.id] === "string" ? settings[definition.id] : definition.defaultShortcut])) as ShortcutSettings;
|
||||
return Object.fromEntries(
|
||||
SHORTCUT_DEFINITIONS.map((definition) => {
|
||||
const configuredValue = settings?.[definition.id];
|
||||
const configured = typeof configuredValue === "string" ? configuredValue : definition.defaultShortcut;
|
||||
const normalized = definition.inputKind === "modifier-only" ? normalizeModifierOnlyShortcut(configured, definition.defaultShortcut) : configured;
|
||||
return [definition.id, normalized];
|
||||
}),
|
||||
) as ShortcutSettings;
|
||||
}
|
||||
|
||||
export function shortcutToCodeMirrorKey(shortcut: string): string {
|
||||
|
||||
Reference in new issue
Block a user