Replace Cmd with Ctrl on Windows computers

This commit is contained in:
Konstantin Wohlwend 2026-04-17 17:04:30 -07:00
parent 1de8a17183
commit 22ae47fe73
4 changed files with 42 additions and 6 deletions

View File

@ -5,6 +5,7 @@ import { FormDialog } from "@/components/form-dialog";
import { InputField } from "@/components/form-fields";
import { useRouter } from "@/components/router";
import { ActionDialog, Button, Typography } from "@/components/ui";
import { getShortcutModifierKeyLabel } from "@/lib/keyboard-shortcuts";
import { useUpdateConfig } from "@/lib/config-update";
import {
ChartBarIcon,
@ -28,6 +29,7 @@ export default function PageClient() {
const adminApp = useAdminApp();
const project = adminApp.useProject();
const config = project.useConfig();
const modifierKeyLabel = getShortcutModifierKeyLabel();
const updateConfig = useUpdateConfig();
const router = useRouter();
const [deleteDialogId, setDeleteDialogId] = useState<string | null>(null);
@ -77,7 +79,9 @@ export default function PageClient() {
<div>
<Typography className="font-semibold text-foreground">No dashboards yet</Typography>
<Typography variant="secondary" className="text-sm mt-1">
Create a dashboard from the command palette ( K) or click &quot;New Dashboard&quot; above.
Create a dashboard from the command palette (
<span suppressHydrationWarning>{modifierKeyLabel} K</span>
) or click &quot;New Dashboard&quot; above.
</Typography>
</div>
</div>

View File

@ -3,6 +3,7 @@
import Editor from "@monaco-editor/react";
import type { Monaco } from "@monaco-editor/react";
import React, { useEffect, useMemo, useRef } from "react";
import { getShortcutModifierKeyLabel } from "@/lib/keyboard-shortcuts";
import { Alert, Button, Textarea, Typography } from "@/components/ui";
import { PageLayout } from "../page-layout";
import { useAdminApp } from "../use-admin-app";
@ -21,6 +22,7 @@ type CompletionItem = Parameters<Monaco["languages"]["registerCompletionItemProv
export default function PageClient() {
const adminApp = useAdminApp();
const modifierKeyLabel = getShortcutModifierKeyLabel();
const [query, setQuery] = React.useState("SELECT 1 AS value;");
const [resultText, setResultText] = React.useState("");
const [error, setError] = React.useState<string | null>(null);
@ -168,7 +170,7 @@ export default function PageClient() {
loading={loading}
disabled={loading || !queryRef.current.trim()}
>
Run query ( + enter)
Run query (<span suppressHydrationWarning>{modifierKeyLabel}</span> + enter)
</Button>
</div>

View File

@ -1,6 +1,7 @@
"use client";
import { useRouter } from "@/components/router";
import { getShortcutModifierKeyLabel } from "@/lib/keyboard-shortcuts";
import { cn } from "@/lib/utils";
import {
LayoutIcon,
@ -118,6 +119,8 @@ const CyclingPlaceholder = memo(function CyclingPlaceholder({
}: {
onSelectQuery?: (query: string) => void,
}) {
const modifierKeyLabel = getShortcutModifierKeyLabel();
return (
<div className="h-full flex flex-col items-center select-none px-6">
{/* Top spacer */}
@ -149,7 +152,9 @@ const CyclingPlaceholder = memo(function CyclingPlaceholder({
<div className="relative text-center mb-4">
{/* Keybind reminder - like tape on the corner */}
<span className="absolute -top-4 -right-8 rotate-[30deg] flex items-center gap-0.5 text-[10px] text-muted-foreground/40">
<kbd className="px-1.5 py-0.5 rounded bg-foreground/[0.06] font-mono"></kbd>
<kbd suppressHydrationWarning className="px-1.5 py-0.5 rounded bg-foreground/[0.06] font-mono">
{modifierKeyLabel}
</kbd>
+
<kbd className="px-1.5 py-0.5 rounded bg-foreground/[0.06] font-mono">K</kbd>
</span>
@ -204,7 +209,9 @@ const CyclingPlaceholder = memo(function CyclingPlaceholder({
{/* Keyboard hints footer */}
<div className="py-3 border-t border-foreground/[0.06] w-full flex items-center justify-center gap-5 text-[10px] text-muted-foreground/40">
<div className="flex items-center gap-1.5">
<kbd className="px-1.5 py-0.5 rounded bg-foreground/[0.06] font-mono"></kbd>
<kbd suppressHydrationWarning className="px-1.5 py-0.5 rounded bg-foreground/[0.06] font-mono">
{modifierKeyLabel}
</kbd>
+
<kbd className="px-1.5 py-0.5 rounded bg-foreground/[0.06] font-mono">K</kbd>
<span>open</span>
@ -999,6 +1006,7 @@ export function CmdKSearch({
export function CmdKTrigger() {
const mouseCursorRef = useRef<HTMLDivElement>(null);
const mouseCursorParentRef = useRef<HTMLDivElement>(null);
const modifierKeyLabel = getShortcutModifierKeyLabel();
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
@ -1058,8 +1066,11 @@ export function CmdKTrigger() {
Control Center
</span>
<div className="pointer-events-none flex items-center gap-1">
<kbd className="flex h-5 min-w-[20px] select-none items-center justify-center rounded-md bg-foreground/[0.04] ring-1 ring-inset ring-foreground/[0.06] px-1.5 font-mono text-[10px] font-medium text-muted-foreground/50 group-hover:text-muted-foreground/70 transition-colors duration-300 group-hover:transition-none">
<kbd
suppressHydrationWarning
className="flex h-5 min-w-[20px] select-none items-center justify-center rounded-md bg-foreground/[0.04] ring-1 ring-inset ring-foreground/[0.06] px-1.5 font-mono text-[10px] font-medium text-muted-foreground/50 group-hover:text-muted-foreground/70 transition-colors duration-300 group-hover:transition-none"
>
{modifierKeyLabel}
</kbd>
<kbd className="flex h-5 min-w-[20px] select-none items-center justify-center rounded-md bg-foreground/[0.04] ring-1 ring-inset ring-foreground/[0.06] px-1.5 font-mono text-[10px] font-medium text-muted-foreground/50 group-hover:text-muted-foreground/70 transition-colors duration-300 group-hover:transition-none">
K

View File

@ -0,0 +1,19 @@
export function getShortcutModifierKeyLabel() {
if (typeof navigator === "undefined") {
return "⌘";
}
const platform = navigator.platform;
const userAgent = navigator.userAgent;
const isAppleDevice =
platform.startsWith("Mac") ||
platform === "iPhone" ||
platform === "iPad" ||
platform === "iPod" ||
userAgent.includes("Macintosh") ||
userAgent.includes("iPhone") ||
userAgent.includes("iPad") ||
userAgent.includes("iPod");
return isAppleDevice ? "⌘" : "Ctrl";
}