mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 03:43:10 +00:00
merge: bring shortcut and fullscreen fix into main
This commit is contained in:
@@ -38,6 +38,7 @@ import {
|
||||
isCloseTabShortcut,
|
||||
isExecuteSqlShortcut,
|
||||
isFocusSearchShortcut,
|
||||
isNewQueryShortcut,
|
||||
isObjectSourceSaveShortcutTarget,
|
||||
isRefreshDataShortcut,
|
||||
isSaveShortcut,
|
||||
@@ -587,6 +588,12 @@ function handleKeydown(e: KeyboardEvent) {
|
||||
contentAreaRef.value?.refreshData();
|
||||
return;
|
||||
}
|
||||
if (isNewQueryShortcut(e, shortcuts)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
void newQuery();
|
||||
return;
|
||||
}
|
||||
if (isCloseTabShortcut(e, shortcuts)) {
|
||||
e.preventDefault();
|
||||
if (showDriverStore.value) {
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import WindowControls from "@/components/layout/WindowControls.vue";
|
||||
import { useWindowControls } from "@/composables/useWindowControls";
|
||||
import { shouldReserveMacTrafficLightInset, useWindowControls } from "@/composables/useWindowControls";
|
||||
import { currentLocale, setLocale, type Locale } from "@/i18n";
|
||||
import type { AppThemeMode } from "@/lib/appTheme";
|
||||
|
||||
@@ -68,7 +68,8 @@ const emit = defineEmits<{
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
const { isMac, isDesktop, showControls, isMaximized, minimize, toggleMaximize, close } = useWindowControls();
|
||||
const { isMac, isDesktop, showControls, isMaximized, isFullscreen, minimize, toggleMaximize, close } =
|
||||
useWindowControls();
|
||||
|
||||
function onToolbarDblClick(e: MouseEvent) {
|
||||
if (isDesktop) return;
|
||||
@@ -81,7 +82,7 @@ function onToolbarDblClick(e: MouseEvent) {
|
||||
<template>
|
||||
<div
|
||||
class="h-10 flex items-center gap-1 px-2 border-b bg-muted/30 shrink-0"
|
||||
:class="{ 'pl-17.5': isMac }"
|
||||
:class="{ 'pl-17.5': shouldReserveMacTrafficLightInset(isMac, isFullscreen) }"
|
||||
data-tauri-drag-region
|
||||
@dblclick="onToolbarDblClick"
|
||||
>
|
||||
|
||||
@@ -2,18 +2,26 @@ import { ref, onMounted, onUnmounted } from "vue";
|
||||
import { isTauriRuntime } from "@/lib/tauriRuntime";
|
||||
import { isMacOS } from "@/lib/platform";
|
||||
|
||||
export function shouldReserveMacTrafficLightInset(isMac: boolean, isFullscreen: boolean): boolean {
|
||||
return isMac && !isFullscreen;
|
||||
}
|
||||
|
||||
export function useWindowControls() {
|
||||
const isMaximized = ref(false);
|
||||
const isFullscreen = ref(false);
|
||||
const isMac = isMacOS();
|
||||
const isDesktop = isTauriRuntime();
|
||||
const showControls = isDesktop && !isMac;
|
||||
|
||||
let unlisten: (() => void) | null = null;
|
||||
|
||||
async function updateMaximizedState() {
|
||||
async function updateWindowState() {
|
||||
if (!isDesktop) return;
|
||||
const { getCurrentWindow } = await import("@tauri-apps/api/window");
|
||||
isMaximized.value = await getCurrentWindow().isMaximized();
|
||||
const currentWindow = getCurrentWindow();
|
||||
const [maximized, fullscreen] = await Promise.all([currentWindow.isMaximized(), currentWindow.isFullscreen()]);
|
||||
isMaximized.value = maximized;
|
||||
isFullscreen.value = fullscreen;
|
||||
}
|
||||
|
||||
async function minimize() {
|
||||
@@ -24,7 +32,7 @@ export function useWindowControls() {
|
||||
async function toggleMaximize() {
|
||||
const { getCurrentWindow } = await import("@tauri-apps/api/window");
|
||||
await getCurrentWindow().toggleMaximize();
|
||||
setTimeout(updateMaximizedState, 50);
|
||||
setTimeout(updateWindowState, 50);
|
||||
}
|
||||
|
||||
async function close() {
|
||||
@@ -34,10 +42,10 @@ export function useWindowControls() {
|
||||
|
||||
onMounted(async () => {
|
||||
if (!isDesktop) return;
|
||||
await updateMaximizedState();
|
||||
await updateWindowState();
|
||||
const { getCurrentWindow } = await import("@tauri-apps/api/window");
|
||||
const unlistenFn = await getCurrentWindow().onResized(() => {
|
||||
updateMaximizedState();
|
||||
void updateWindowState();
|
||||
});
|
||||
unlisten = unlistenFn;
|
||||
});
|
||||
@@ -51,6 +59,7 @@ export function useWindowControls() {
|
||||
isDesktop,
|
||||
showControls,
|
||||
isMaximized,
|
||||
isFullscreen,
|
||||
minimize,
|
||||
toggleMaximize,
|
||||
close,
|
||||
|
||||
@@ -1198,6 +1198,7 @@ export default {
|
||||
redisScanPageSizeOption: "{count} keys",
|
||||
shortcutExecuteSql: "Execute SQL",
|
||||
shortcutSaveSql: "Save SQL",
|
||||
shortcutNewQuery: "New query",
|
||||
shortcutCloseTab: "Close tab",
|
||||
shortcutFocusSearch: "Focus search",
|
||||
shortcutRefreshData: "Refresh data",
|
||||
|
||||
@@ -1097,6 +1097,7 @@ export default {
|
||||
redisScanPageSizeOption: "{count} claves",
|
||||
shortcutExecuteSql: "Ejecutar SQL",
|
||||
shortcutSaveSql: "Guardar SQL",
|
||||
shortcutNewQuery: "Nueva consulta",
|
||||
shortcutCloseTab: "Cerrar pestaña",
|
||||
shortcutFocusSearch: "Enfocar búsqueda",
|
||||
shortcutRefreshData: "Actualizar datos",
|
||||
|
||||
@@ -1176,6 +1176,7 @@ export default {
|
||||
redisScanPageSizeOption: "{count} 个 Key",
|
||||
shortcutExecuteSql: "执行 SQL",
|
||||
shortcutSaveSql: "保存 SQL",
|
||||
shortcutNewQuery: "新建查询",
|
||||
shortcutCloseTab: "关闭标签页",
|
||||
shortcutFocusSearch: "聚焦搜索",
|
||||
shortcutRefreshData: "刷新数据",
|
||||
|
||||
@@ -76,6 +76,10 @@ export function isCloseTabShortcut(event: ShortcutLikeEvent, shortcuts?: Partial
|
||||
return matchesShortcut(event, actionShortcut("closeTab", shortcuts));
|
||||
}
|
||||
|
||||
export function isNewQueryShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||
return matchesShortcut(event, actionShortcut("newQuery", shortcuts));
|
||||
}
|
||||
|
||||
export function isFocusSearchShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||
return matchesShortcut(event, actionShortcut("focusSearch", shortcuts));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
export type ShortcutActionId = "executeSql" | "saveSql" | "closeTab" | "focusSearch" | "refreshData" | "cancelSearch";
|
||||
export type ShortcutActionId =
|
||||
| "executeSql"
|
||||
| "saveSql"
|
||||
| "newQuery"
|
||||
| "closeTab"
|
||||
| "focusSearch"
|
||||
| "refreshData"
|
||||
| "cancelSearch";
|
||||
|
||||
export type ShortcutScope = "global" | "editor" | "search";
|
||||
|
||||
@@ -24,6 +31,12 @@ export const SHORTCUT_DEFINITIONS: ShortcutDefinition[] = [
|
||||
scope: "editor",
|
||||
defaultShortcut: "Mod+S",
|
||||
},
|
||||
{
|
||||
id: "newQuery",
|
||||
labelKey: "settings.shortcutNewQuery",
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+T",
|
||||
},
|
||||
{
|
||||
id: "closeTab",
|
||||
labelKey: "settings.shortcutCloseTab",
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
isCloseTabShortcut,
|
||||
isExecuteSqlShortcut,
|
||||
isFocusSearchShortcut,
|
||||
isNewQueryShortcut,
|
||||
isObjectSourceSaveShortcutTarget,
|
||||
isRefreshDataShortcut,
|
||||
isSaveShortcut,
|
||||
@@ -44,6 +45,18 @@ test("matches Ctrl+Enter for SQL execution", () => {
|
||||
assert.equal(isExecuteSqlShortcut({ key: "Enter", ctrlKey: true }), true);
|
||||
});
|
||||
|
||||
test("matches Cmd+T for opening a new query", () => {
|
||||
assert.equal(isNewQueryShortcut({ key: "t", metaKey: true }), true);
|
||||
});
|
||||
|
||||
test("matches custom shortcut settings for opening a new query", () => {
|
||||
assert.equal(isNewQueryShortcut({ key: "t", metaKey: true }, { newQuery: "Shift+Mod+N" } as any), false);
|
||||
assert.equal(
|
||||
isNewQueryShortcut({ key: "n", ctrlKey: true, shiftKey: true } as any, { newQuery: "Shift+Mod+N" } as any),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("ignores Enter without modifier", () => {
|
||||
assert.equal(isExecuteSqlShortcut({ key: "Enter" }), false);
|
||||
});
|
||||
|
||||
@@ -28,14 +28,16 @@ test("defaults shortcut settings", () => {
|
||||
|
||||
assert.equal(settings.shortcuts.executeSql, "Mod+Enter");
|
||||
assert.equal(settings.shortcuts.saveSql, "Mod+S");
|
||||
assert.equal(settings.shortcuts.newQuery, "Mod+T");
|
||||
assert.equal(settings.shortcuts.focusSearch, "Mod+F");
|
||||
assert.equal(settings.shortcuts.refreshData, "F5");
|
||||
});
|
||||
|
||||
test("keeps saved shortcut overrides", () => {
|
||||
const settings = normalizeEditorSettings({ shortcuts: { executeSql: "Shift+Mod+Enter" } as any });
|
||||
const settings = normalizeEditorSettings({ shortcuts: { executeSql: "Shift+Mod+Enter", newQuery: "Shift+Mod+N" } as any });
|
||||
|
||||
assert.equal(settings.shortcuts.executeSql, "Shift+Mod+Enter");
|
||||
assert.equal(settings.shortcuts.newQuery, "Shift+Mod+N");
|
||||
assert.equal(settings.shortcuts.saveSql, "Mod+S");
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import * as windowControlsModule from "../../apps/desktop/src/composables/useWindowControls.ts";
|
||||
|
||||
test("mac traffic-light inset is removed in fullscreen", () => {
|
||||
assert.equal(typeof windowControlsModule.shouldReserveMacTrafficLightInset, "function");
|
||||
assert.equal(windowControlsModule.shouldReserveMacTrafficLightInset(true, false), true);
|
||||
assert.equal(windowControlsModule.shouldReserveMacTrafficLightInset(true, true), false);
|
||||
assert.equal(windowControlsModule.shouldReserveMacTrafficLightInset(false, false), false);
|
||||
});
|
||||
Reference in New Issue
Block a user