authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-15 14:33:56-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-02-15 15:51:05-08:00
log0a5aaf3e0e64fa70e90541c93842296e97d653a6
tree57843fdca667d988d879414cbe43dddc23c547dd
parent3d7ef8a833dbd38f847c4ba212ebee61eb53a9f1

tidy up


4 files changed, 30 insertions(+), 28 deletions(-)

apps/web/src/components/ChatView.tsx+7-8
...@@ -23,10 +23,7 @@ import {...@@ -23,10 +23,7 @@ import {
23 useState,23 useState,
24} from "react";24} from "react";
25import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";25import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
26import {26import { gitBranchesQueryOptions, gitCreateWorktreeMutationOptions } from "~/lib/gitReactQuery";
27 gitBranchesQueryOptions,
28 gitCreateWorktreeMutationOptions,
29} from "~/lib/gitReactQuery";
30import { serverConfigQueryOptions } from "~/lib/serverReactQuery";27import { serverConfigQueryOptions } from "~/lib/serverReactQuery";
3128
32import { isElectron } from "../env";29import { isElectron } from "../env";
...@@ -79,7 +76,7 @@ import { Separator } from "./ui/separator";...@@ -79,7 +76,7 @@ import { Separator } from "./ui/separator";
79import { Group, GroupSeparator } from "./ui/group";76import { Group, GroupSeparator } from "./ui/group";
80import { Menu, MenuItem, MenuPopup, MenuShortcut, MenuTrigger } from "./ui/menu";77import { Menu, MenuItem, MenuPopup, MenuShortcut, MenuTrigger } from "./ui/menu";
81import { CursorIcon, Icon } from "./Icons";78import { CursorIcon, Icon } from "./Icons";
82import { cn } from "~/lib/utils";79import { cn, isMacPlatform, isWindowsPlatform } from "~/lib/utils";
83import { Badge } from "./ui/badge";80import { Badge } from "./ui/badge";
8481
85function formatMessageMeta(createdAt: string, duration: string | null): string {82function formatMessageMeta(createdAt: string, duration: string | null): string {
...@@ -140,7 +137,9 @@ export default function ChatView() {...@@ -140,7 +137,9 @@ export default function ChatView() {
140 const { state, dispatch } = useStore();137 const { state, dispatch } = useStore();
141 const api = useNativeApi();138 const api = useNativeApi();
142 const queryClient = useQueryClient();139 const queryClient = useQueryClient();
143 const createWorktreeMutation = useMutation(gitCreateWorktreeMutationOptions({ api, queryClient }));140 const createWorktreeMutation = useMutation(
141 gitCreateWorktreeMutationOptions({ api, queryClient }),
142 );
144 const [prompt, setPrompt] = useState("");143 const [prompt, setPrompt] = useState("");
145 const [composerImages, setComposerImages] = useState<ComposerImageAttachment[]>([]);144 const [composerImages, setComposerImages] = useState<ComposerImageAttachment[]>([]);
146 const [isDragOverComposer, setIsDragOverComposer] = useState(false);145 const [isDragOverComposer, setIsDragOverComposer] = useState(false);
...@@ -1533,9 +1532,9 @@ function OpenInPicker({ keybindings }: { keybindings: ResolvedKeybindingsConfig...@@ -1533,9 +1532,9 @@ function OpenInPicker({ keybindings }: { keybindings: ResolvedKeybindingsConfig
1533 value: "cursor",1532 value: "cursor",
1534 },1533 },
1535 {1534 {
1536 label: navigator.platform.includes("Mac")1535 label: isMacPlatform(navigator.platform)
1537 ? "Finder"1536 ? "Finder"
1538 : navigator.platform.includes("Win")1537 : isWindowsPlatform(navigator.platform)
1539 ? "Explorer"1538 ? "Explorer"
1540 : "Files",1539 : "Files",
1541 Icon: FolderClosedIcon,1540 Icon: FolderClosedIcon,
apps/web/src/keybindings.ts+14-16
...@@ -4,6 +4,7 @@ import {...@@ -4,6 +4,7 @@ import {
4 type KeybindingWhenNode,4 type KeybindingWhenNode,
5 type ResolvedKeybindingsConfig,5 type ResolvedKeybindingsConfig,
6} from "@t3tools/contracts";6} from "@t3tools/contracts";
7import { isMacPlatform } from "./lib/utils";
78
8export interface ShortcutEventLike {9export interface ShortcutEventLike {
9 key: string;10 key: string;
...@@ -19,17 +20,11 @@ export interface ShortcutMatchContext {...@@ -19,17 +20,11 @@ export interface ShortcutMatchContext {
19 [key: string]: boolean;20 [key: string]: boolean;
20}21}
2122
22export type ResolvedKeybindings = ResolvedKeybindingsConfig;
23
24interface ShortcutMatchOptions {23interface ShortcutMatchOptions {
25 platform?: string;24 platform?: string;
26 context?: Partial<ShortcutMatchContext>;25 context?: Partial<ShortcutMatchContext>;
27}26}
2827
29function isMacPlatform(platform: string): boolean {
30 return /mac|iphone|ipad|ipod/i.test(platform);
31}
32
33function normalizeEventKey(key: string): string {28function normalizeEventKey(key: string): string {
34 const normalized = key.toLowerCase();29 const normalized = key.toLowerCase();
35 if (normalized === "esc") return "escape";30 if (normalized === "esc") return "escape";
...@@ -83,7 +78,7 @@ function evaluateWhenNode(node: KeybindingWhenNode, context: ShortcutMatchContex...@@ -83,7 +78,7 @@ function evaluateWhenNode(node: KeybindingWhenNode, context: ShortcutMatchContex
83}78}
8479
85function matchesWhenClause(80function matchesWhenClause(
86 whenAst: ResolvedKeybindings[number]["whenAst"],81 whenAst: ResolvedKeybindingsConfig[number]["whenAst"],
87 context: ShortcutMatchContext,82 context: ShortcutMatchContext,
88): boolean {83): boolean {
89 if (!whenAst) return true;84 if (!whenAst) return true;
...@@ -92,7 +87,7 @@ function matchesWhenClause(...@@ -92,7 +87,7 @@ function matchesWhenClause(
9287
93function matchesCommandShortcut(88function matchesCommandShortcut(
94 event: ShortcutEventLike,89 event: ShortcutEventLike,
95 keybindings: ResolvedKeybindings,90 keybindings: ResolvedKeybindingsConfig,
96 command: KeybindingCommand,91 command: KeybindingCommand,
97 options?: ShortcutMatchOptions,92 options?: ShortcutMatchOptions,
98): boolean {93): boolean {
...@@ -101,7 +96,7 @@ function matchesCommandShortcut(...@@ -101,7 +96,7 @@ function matchesCommandShortcut(
10196
102function resolveShortcutCommand(97function resolveShortcutCommand(
103 event: ShortcutEventLike,98 event: ShortcutEventLike,
104 keybindings: ResolvedKeybindings,99 keybindings: ResolvedKeybindingsConfig,
105 options?: ShortcutMatchOptions,100 options?: ShortcutMatchOptions,
106): KeybindingCommand | null {101): KeybindingCommand | null {
107 const platform = resolvePlatform(options);102 const platform = resolvePlatform(options);
...@@ -128,7 +123,10 @@ function formatShortcutKeyLabel(key: string): string {...@@ -128,7 +123,10 @@ function formatShortcutKeyLabel(key: string): string {
128 return key.slice(0, 1).toUpperCase() + key.slice(1);123 return key.slice(0, 1).toUpperCase() + key.slice(1);
129}124}
130125
131export function formatShortcutLabel(shortcut: KeybindingShortcut, platform = navigator.platform): string {126export function formatShortcutLabel(
127 shortcut: KeybindingShortcut,
128 platform = navigator.platform,
129): string {
132 const keyLabel = formatShortcutKeyLabel(shortcut.key);130 const keyLabel = formatShortcutKeyLabel(shortcut.key);
133 const useMetaForMod = isMacPlatform(platform);131 const useMetaForMod = isMacPlatform(platform);
134 const showMeta = shortcut.metaKey || (shortcut.modKey && useMetaForMod);132 const showMeta = shortcut.metaKey || (shortcut.modKey && useMetaForMod);
...@@ -150,7 +148,7 @@ export function formatShortcutLabel(shortcut: KeybindingShortcut, platform = nav...@@ -150,7 +148,7 @@ export function formatShortcutLabel(shortcut: KeybindingShortcut, platform = nav
150}148}
151149
152export function shortcutLabelForCommand(150export function shortcutLabelForCommand(
153 keybindings: ResolvedKeybindings,151 keybindings: ResolvedKeybindingsConfig,
154 command: KeybindingCommand,152 command: KeybindingCommand,
155 platform = navigator.platform,153 platform = navigator.platform,
156): string | null {154): string | null {
...@@ -164,7 +162,7 @@ export function shortcutLabelForCommand(...@@ -164,7 +162,7 @@ export function shortcutLabelForCommand(
164162
165export function isTerminalToggleShortcut(163export function isTerminalToggleShortcut(
166 event: ShortcutEventLike,164 event: ShortcutEventLike,
167 keybindings: ResolvedKeybindings,165 keybindings: ResolvedKeybindingsConfig,
168 options?: ShortcutMatchOptions,166 options?: ShortcutMatchOptions,
169): boolean {167): boolean {
170 return matchesCommandShortcut(event, keybindings, "terminal.toggle", options);168 return matchesCommandShortcut(event, keybindings, "terminal.toggle", options);
...@@ -172,7 +170,7 @@ export function isTerminalToggleShortcut(...@@ -172,7 +170,7 @@ export function isTerminalToggleShortcut(
172170
173export function isTerminalSplitShortcut(171export function isTerminalSplitShortcut(
174 event: ShortcutEventLike,172 event: ShortcutEventLike,
175 keybindings: ResolvedKeybindings,173 keybindings: ResolvedKeybindingsConfig,
176 options?: ShortcutMatchOptions,174 options?: ShortcutMatchOptions,
177): boolean {175): boolean {
178 return matchesCommandShortcut(event, keybindings, "terminal.split", options);176 return matchesCommandShortcut(event, keybindings, "terminal.split", options);
...@@ -180,7 +178,7 @@ export function isTerminalSplitShortcut(...@@ -180,7 +178,7 @@ export function isTerminalSplitShortcut(
180178
181export function isTerminalNewShortcut(179export function isTerminalNewShortcut(
182 event: ShortcutEventLike,180 event: ShortcutEventLike,
183 keybindings: ResolvedKeybindings,181 keybindings: ResolvedKeybindingsConfig,
184 options?: ShortcutMatchOptions,182 options?: ShortcutMatchOptions,
185): boolean {183): boolean {
186 return matchesCommandShortcut(event, keybindings, "terminal.new", options);184 return matchesCommandShortcut(event, keybindings, "terminal.new", options);
...@@ -188,7 +186,7 @@ export function isTerminalNewShortcut(...@@ -188,7 +186,7 @@ export function isTerminalNewShortcut(
188186
189export function isChatNewShortcut(187export function isChatNewShortcut(
190 event: ShortcutEventLike,188 event: ShortcutEventLike,
191 keybindings: ResolvedKeybindings,189 keybindings: ResolvedKeybindingsConfig,
192 options?: ShortcutMatchOptions,190 options?: ShortcutMatchOptions,
193): boolean {191): boolean {
194 return matchesCommandShortcut(event, keybindings, "chat.new", options);192 return matchesCommandShortcut(event, keybindings, "chat.new", options);
...@@ -196,7 +194,7 @@ export function isChatNewShortcut(...@@ -196,7 +194,7 @@ export function isChatNewShortcut(
196194
197export function isOpenFavoriteEditorShortcut(195export function isOpenFavoriteEditorShortcut(
198 event: ShortcutEventLike,196 event: ShortcutEventLike,
199 keybindings: ResolvedKeybindings,197 keybindings: ResolvedKeybindingsConfig,
200 options?: ShortcutMatchOptions,198 options?: ShortcutMatchOptions,
201): boolean {199): boolean {
202 return matchesCommandShortcut(event, keybindings, "editor.openFavorite", options);200 return matchesCommandShortcut(event, keybindings, "editor.openFavorite", options);
apps/web/src/lib/utils.ts+8
...@@ -4,3 +4,11 @@ import { twMerge } from "tailwind-merge";...@@ -4,3 +4,11 @@ import { twMerge } from "tailwind-merge";
4export function cn(...inputs: CxOptions) {4export function cn(...inputs: CxOptions) {
5 return twMerge(cx(inputs));5 return twMerge(cx(inputs));
6}6}
7
8export function isMacPlatform(platform: string): boolean {
9 return /mac|iphone|ipad|ipod/i.test(platform);
10}
11
12export function isWindowsPlatform(platform: string): boolean {
13 return /win|windows/i.test(platform);
14}
apps/web/src/terminal-links.ts+1-4
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1import { EDITORS, type EditorId } from "@t3tools/contracts";1import { EDITORS, type EditorId } from "@t3tools/contracts";
2import { isMacPlatform } from "./lib/utils";
23
3export type TerminalLinkKind = "url" | "path";4export type TerminalLinkKind = "url" | "path";
45
...@@ -15,10 +16,6 @@ const FILE_PATH_PATTERN =...@@ -15,10 +16,6 @@ const FILE_PATH_PATTERN =
15const TRAILING_PUNCTUATION_PATTERN = /[.,;!?]+$/;16const TRAILING_PUNCTUATION_PATTERN = /[.,;!?]+$/;
16const LAST_EDITOR_KEY = "t3code:last-editor";17const LAST_EDITOR_KEY = "t3code:last-editor";
1718
18function isMacPlatform(platform: string): boolean {
19 return /mac|iphone|ipad|ipod/i.test(platform);
20}
21
22function trimClosingDelimiters(value: string): string {19function trimClosingDelimiters(value: string): string {
23 let output = value.replace(TRAILING_PUNCTUATION_PATTERN, "");20 let output = value.replace(TRAILING_PUNCTUATION_PATTERN, "");
24 if (output.length === 0) return output;21 if (output.length === 0) return output;