fix: enable macOS window dragging and rename app to Claude Code Haha

Add core🪟allow-start-dragging permission and acceptFirstMouse
config to fix window dragging on macOS with overlay title bar. Also add
JS-based startDragging() fallback in AppShell and Sidebar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
程序员阿江(Relakkes) 2026-04-08 21:11:26 +08:00
parent 158f2de13e
commit 00a9cba066
4 changed files with 45 additions and 9 deletions

View File

@ -5,6 +5,7 @@
"windows": ["main"], "windows": ["main"],
"permissions": [ "permissions": [
"core:default", "core:default",
"core:window:allow-start-dragging",
"shell:allow-open", "shell:allow-open",
{ {
"identifier": "shell:allow-execute", "identifier": "shell:allow-execute",

View File

@ -1,6 +1,6 @@
{ {
"$schema": "https://raw.githubusercontent.com/nicegui/nicegui/main/nicegui/static/tauri-schema-v2.json", "$schema": "https://raw.githubusercontent.com/nicegui/nicegui/main/nicegui/static/tauri-schema-v2.json",
"productName": "Claude Code", "productName": "Claude Code Haha",
"version": "0.1.0", "version": "0.1.0",
"identifier": "com.claude-code.desktop", "identifier": "com.claude-code.desktop",
"build": { "build": {
@ -12,7 +12,7 @@
"app": { "app": {
"windows": [ "windows": [
{ {
"title": "Claude Code", "title": "Claude Code Haha",
"width": 1280, "width": 1280,
"height": 800, "height": 800,
"minWidth": 900, "minWidth": 900,
@ -20,7 +20,8 @@
"decorations": true, "decorations": true,
"titleBarStyle": "Overlay", "titleBarStyle": "Overlay",
"hiddenTitle": true, "hiddenTitle": true,
"transparent": false "transparent": false,
"acceptFirstMouse": true
} }
], ],
"security": { "security": {

View File

@ -1,4 +1,4 @@
import { useEffect, useState } from 'react' import { useEffect, useState, useCallback, useRef } from 'react'
import { Sidebar } from './Sidebar' import { Sidebar } from './Sidebar'
import { ContentRouter } from './ContentRouter' import { ContentRouter } from './ContentRouter'
import { ToastContainer } from '../shared/Toast' import { ToastContainer } from '../shared/Toast'
@ -12,6 +12,7 @@ export function AppShell() {
const fetchSettings = useSettingsStore((s) => s.fetchAll) const fetchSettings = useSettingsStore((s) => s.fetchAll)
const [ready, setReady] = useState(false) const [ready, setReady] = useState(false)
const [startupError, setStartupError] = useState<string | null>(null) const [startupError, setStartupError] = useState<string | null>(null)
const startDraggingRef = useRef<(() => Promise<void>) | null>(null)
useEffect(() => { useEffect(() => {
let cancelled = false let cancelled = false
@ -38,6 +39,22 @@ export function AppShell() {
} }
}, [fetchSettings]) }, [fetchSettings])
// Pre-cache Tauri window drag function
useEffect(() => {
if (!isTauri) return
import(/* @vite-ignore */ '@tauri-apps/api/window')
.then(({ getCurrentWindow }) => {
const win = getCurrentWindow()
startDraggingRef.current = () => win.startDragging()
})
.catch(() => {})
}, [])
const handleDragMouseDown = useCallback((e: React.MouseEvent) => {
if ((e.target as HTMLElement).closest('button, input, textarea, select, a, [role="button"]')) return
startDraggingRef.current?.()
}, [])
useKeyboardShortcuts() useKeyboardShortcuts()
if (startupError) { if (startupError) {
@ -65,12 +82,12 @@ export function AppShell() {
return ( return (
<div className="h-screen flex overflow-hidden relative"> <div className="h-screen flex overflow-hidden relative">
{/* Drag region for macOS Overlay title bar — only relevant in Tauri */} {/* Drag region for macOS Overlay title bar — full width strip at the top */}
{isTauri && ( {isTauri && (
<div <div
data-tauri-drag-region data-tauri-drag-region
className="absolute top-0 right-0 h-[38px] z-10" onMouseDown={handleDragMouseDown}
style={{ left: 'var(--sidebar-width)' }} className="absolute top-0 left-0 right-0 h-[38px] z-[9999]"
/> />
)} )}
<Sidebar /> <Sidebar />

View File

@ -1,4 +1,4 @@
import { useEffect, useState, useCallback, useMemo } from 'react' import { useEffect, useState, useCallback, useMemo, useRef } from 'react'
import { useSessionStore } from '../../stores/sessionStore' import { useSessionStore } from '../../stores/sessionStore'
import { useUIStore } from '../../stores/uiStore' import { useUIStore } from '../../stores/uiStore'
import { useTranslation } from '../../i18n' import { useTranslation } from '../../i18n'
@ -80,6 +80,23 @@ export function Sidebar() {
setRenameValue('') setRenameValue('')
}, [renamingId, renameValue, renameSession]) }, [renamingId, renameValue, renameSession])
const startDraggingRef = useRef<(() => Promise<void>) | null>(null)
useEffect(() => {
if (!isTauri) return
import(/* @vite-ignore */ '@tauri-apps/api/window')
.then(({ getCurrentWindow }) => {
const win = getCurrentWindow()
startDraggingRef.current = () => win.startDragging()
})
.catch(() => {})
}, [])
const handleSidebarDrag = useCallback((e: React.MouseEvent) => {
if ((e.target as HTMLElement).closest('button, input, textarea, select, a, [role="button"]')) return
startDraggingRef.current?.()
}, [])
const t = useTranslation() const t = useTranslation()
const TIME_GROUP_LABELS: Record<TimeGroup, string> = { const TIME_GROUP_LABELS: Record<TimeGroup, string> = {
@ -91,7 +108,7 @@ export function Sidebar() {
} }
return ( return (
<aside data-tauri-drag-region className="w-[var(--sidebar-width)] h-full flex flex-col bg-[var(--color-surface-sidebar)] border-r border-[var(--color-border)] select-none"> <aside data-tauri-drag-region onMouseDown={handleSidebarDrag} className="w-[var(--sidebar-width)] h-full flex flex-col bg-[var(--color-surface-sidebar)] border-r border-[var(--color-border)] select-none">
{/* Brand logo — extra top padding in desktop to clear macOS traffic lights */} {/* Brand logo — extra top padding in desktop to clear macOS traffic lights */}
<div className={`px-3 pb-1.5 flex items-center justify-between ${isTauri ? 'pt-[44px]' : 'pt-3'}`}> <div className={`px-3 pb-1.5 flex items-center justify-between ${isTauri ? 'pt-[44px]' : 'pt-3'}`}>
<div className="flex items-center gap-2.5"> <div className="flex items-center gap-2.5">