diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 0e9038b94caf054072cb9778b7d78f9cf5333cb3..716b8d812b980df9787a44532b327ba00a7ae2a9 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -23,10 +23,7 @@ import { useState, } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { - gitBranchesQueryOptions, - gitCreateWorktreeMutationOptions, -} from "~/lib/gitReactQuery"; +import { gitBranchesQueryOptions, gitCreateWorktreeMutationOptions } from "~/lib/gitReactQuery"; import { serverConfigQueryOptions } from "~/lib/serverReactQuery"; import { isElectron } from "../env"; @@ -79,7 +76,7 @@ import { Separator } from "./ui/separator"; import { Group, GroupSeparator } from "./ui/group"; import { Menu, MenuItem, MenuPopup, MenuShortcut, MenuTrigger } from "./ui/menu"; import { CursorIcon, Icon } from "./Icons"; -import { cn } from "~/lib/utils"; +import { cn, isMacPlatform, isWindowsPlatform } from "~/lib/utils"; import { Badge } from "./ui/badge"; function formatMessageMeta(createdAt: string, duration: string | null): string { @@ -140,7 +137,9 @@ export default function ChatView() { const { state, dispatch } = useStore(); const api = useNativeApi(); const queryClient = useQueryClient(); - const createWorktreeMutation = useMutation(gitCreateWorktreeMutationOptions({ api, queryClient })); + const createWorktreeMutation = useMutation( + gitCreateWorktreeMutationOptions({ api, queryClient }), + ); const [prompt, setPrompt] = useState(""); const [composerImages, setComposerImages] = useState([]); const [isDragOverComposer, setIsDragOverComposer] = useState(false); @@ -1533,9 +1532,9 @@ function OpenInPicker({ keybindings }: { keybindings: ResolvedKeybindingsConfig value: "cursor", }, { - label: navigator.platform.includes("Mac") + label: isMacPlatform(navigator.platform) ? "Finder" - : navigator.platform.includes("Win") + : isWindowsPlatform(navigator.platform) ? "Explorer" : "Files", Icon: FolderClosedIcon, diff --git a/apps/web/src/keybindings.ts b/apps/web/src/keybindings.ts index da376c5772f3477bb9f726fbd2cf8de8441be7eb..0dce1d4e0d95d13e5b0dd645c7f14b182fee9874 100644 --- a/apps/web/src/keybindings.ts +++ b/apps/web/src/keybindings.ts @@ -4,6 +4,7 @@ import { type KeybindingWhenNode, type ResolvedKeybindingsConfig, } from "@t3tools/contracts"; +import { isMacPlatform } from "./lib/utils"; export interface ShortcutEventLike { key: string; @@ -19,17 +20,11 @@ export interface ShortcutMatchContext { [key: string]: boolean; } -export type ResolvedKeybindings = ResolvedKeybindingsConfig; - interface ShortcutMatchOptions { platform?: string; context?: Partial; } -function isMacPlatform(platform: string): boolean { - return /mac|iphone|ipad|ipod/i.test(platform); -} - function normalizeEventKey(key: string): string { const normalized = key.toLowerCase(); if (normalized === "esc") return "escape"; @@ -83,7 +78,7 @@ function evaluateWhenNode(node: KeybindingWhenNode, context: ShortcutMatchContex } function matchesWhenClause( - whenAst: ResolvedKeybindings[number]["whenAst"], + whenAst: ResolvedKeybindingsConfig[number]["whenAst"], context: ShortcutMatchContext, ): boolean { if (!whenAst) return true; @@ -92,7 +87,7 @@ function matchesWhenClause( function matchesCommandShortcut( event: ShortcutEventLike, - keybindings: ResolvedKeybindings, + keybindings: ResolvedKeybindingsConfig, command: KeybindingCommand, options?: ShortcutMatchOptions, ): boolean { @@ -101,7 +96,7 @@ function matchesCommandShortcut( function resolveShortcutCommand( event: ShortcutEventLike, - keybindings: ResolvedKeybindings, + keybindings: ResolvedKeybindingsConfig, options?: ShortcutMatchOptions, ): KeybindingCommand | null { const platform = resolvePlatform(options); @@ -128,7 +123,10 @@ function formatShortcutKeyLabel(key: string): string { return key.slice(0, 1).toUpperCase() + key.slice(1); } -export function formatShortcutLabel(shortcut: KeybindingShortcut, platform = navigator.platform): string { +export function formatShortcutLabel( + shortcut: KeybindingShortcut, + platform = navigator.platform, +): string { const keyLabel = formatShortcutKeyLabel(shortcut.key); const useMetaForMod = isMacPlatform(platform); const showMeta = shortcut.metaKey || (shortcut.modKey && useMetaForMod); @@ -150,7 +148,7 @@ export function formatShortcutLabel(shortcut: KeybindingShortcut, platform = nav } export function shortcutLabelForCommand( - keybindings: ResolvedKeybindings, + keybindings: ResolvedKeybindingsConfig, command: KeybindingCommand, platform = navigator.platform, ): string | null { @@ -164,7 +162,7 @@ export function shortcutLabelForCommand( export function isTerminalToggleShortcut( event: ShortcutEventLike, - keybindings: ResolvedKeybindings, + keybindings: ResolvedKeybindingsConfig, options?: ShortcutMatchOptions, ): boolean { return matchesCommandShortcut(event, keybindings, "terminal.toggle", options); @@ -172,7 +170,7 @@ export function isTerminalToggleShortcut( export function isTerminalSplitShortcut( event: ShortcutEventLike, - keybindings: ResolvedKeybindings, + keybindings: ResolvedKeybindingsConfig, options?: ShortcutMatchOptions, ): boolean { return matchesCommandShortcut(event, keybindings, "terminal.split", options); @@ -180,7 +178,7 @@ export function isTerminalSplitShortcut( export function isTerminalNewShortcut( event: ShortcutEventLike, - keybindings: ResolvedKeybindings, + keybindings: ResolvedKeybindingsConfig, options?: ShortcutMatchOptions, ): boolean { return matchesCommandShortcut(event, keybindings, "terminal.new", options); @@ -188,7 +186,7 @@ export function isTerminalNewShortcut( export function isChatNewShortcut( event: ShortcutEventLike, - keybindings: ResolvedKeybindings, + keybindings: ResolvedKeybindingsConfig, options?: ShortcutMatchOptions, ): boolean { return matchesCommandShortcut(event, keybindings, "chat.new", options); @@ -196,7 +194,7 @@ export function isChatNewShortcut( export function isOpenFavoriteEditorShortcut( event: ShortcutEventLike, - keybindings: ResolvedKeybindings, + keybindings: ResolvedKeybindingsConfig, options?: ShortcutMatchOptions, ): boolean { return matchesCommandShortcut(event, keybindings, "editor.openFavorite", options); diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts index d27850a379532fb32ef895464f6572e570463c16..c9a08957aa942053355496ef4ca1bfd7e3c30728 100644 --- a/apps/web/src/lib/utils.ts +++ b/apps/web/src/lib/utils.ts @@ -4,3 +4,11 @@ import { twMerge } from "tailwind-merge"; export function cn(...inputs: CxOptions) { return twMerge(cx(inputs)); } + +export function isMacPlatform(platform: string): boolean { + return /mac|iphone|ipad|ipod/i.test(platform); +} + +export function isWindowsPlatform(platform: string): boolean { + return /win|windows/i.test(platform); +} diff --git a/apps/web/src/terminal-links.ts b/apps/web/src/terminal-links.ts index f46cc6563bf9e040e13d018efae0f362ece86d79..64e18670fadb082435678023467d1f3eb6af0354 100644 --- a/apps/web/src/terminal-links.ts +++ b/apps/web/src/terminal-links.ts @@ -1,4 +1,5 @@ import { EDITORS, type EditorId } from "@t3tools/contracts"; +import { isMacPlatform } from "./lib/utils"; export type TerminalLinkKind = "url" | "path"; @@ -15,10 +16,6 @@ const FILE_PATH_PATTERN = const TRAILING_PUNCTUATION_PATTERN = /[.,;!?]+$/; const LAST_EDITOR_KEY = "t3code:last-editor"; -function isMacPlatform(platform: string): boolean { - return /mac|iphone|ipad|ipod/i.test(platform); -} - function trimClosingDelimiters(value: string): string { let output = value.replace(TRAILING_PUNCTUATION_PATTERN, ""); if (output.length === 0) return output;