mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
Mark <html data-touch-h5> before first paint when the bundle runs in a phone browser (no Electron host + coarse pointer) and scope every mobile-only fix under it, so desktop shells and desktop browsers are untouched: - raise form controls to 16px and cap the iOS viewport scale, so focusing the composer no longer zooms the page and never zooms back - disable content-visibility paint skipping on transcript/trace rows there (long-press selection on iOS WebKit jumps or drops selections when they extend into skipped rows); halve the virtualization thresholds on touch as the replacement paint bound for long sessions - size the app shell to visualViewport so the composer rides the soft keyboard instead of being covered, snap back WebKit's keyboard pan, and keep the transcript tail pinned while the container shrinks - pad the shell with safe-area insets (viewport-fit=cover) and drop the bottom inset while the keyboard is up - keep message action bars (copy/branch) always visible on touch since hover never fires there; kill the WKWebView tap flash and body rubber-banding - move the two inline content-visibility styles (trace message blocks, trace list rows) to classes so the touch scope can reach them Tested: cd desktop && npx vitest run (1474 tests) Tested: cd desktop && npx tsc --noEmit && npx vite build Tested: Playwright chromium smoke against the built dist - desktop context unchanged, iPhone/WeChat and Android contexts get the marker, viewport lock, 16px controls, visible action bars and selectable rows
69 lines
1.9 KiB
TypeScript
69 lines
1.9 KiB
TypeScript
import React from 'react'
|
|
import ReactDOM from 'react-dom/client'
|
|
import './theme/globals.css'
|
|
import { initializeAppZoom } from './lib/appZoom'
|
|
import { initializeTouchH5 } from './lib/touchH5'
|
|
import { runDesktopPersistenceMigrations } from './lib/persistenceMigrations'
|
|
|
|
declare global {
|
|
interface Window {
|
|
__CC_HAHA_BOOTSTRAPPED__?: boolean
|
|
__CC_HAHA_SHOW_STARTUP_ERROR__?: (reason: unknown) => void
|
|
}
|
|
}
|
|
|
|
type DesktopBootstrapModules = [
|
|
{ App: React.ComponentType },
|
|
{ ErrorBoundary: React.ComponentType<{ children: React.ReactNode }> },
|
|
{ installClientDiagnosticsCapture: () => void },
|
|
{ initializeTheme: () => void },
|
|
]
|
|
|
|
function loadDesktopBootstrapModules() {
|
|
return Promise.all([
|
|
import('./App'),
|
|
import('./components/ErrorBoundary'),
|
|
import('./lib/diagnosticsCapture'),
|
|
import('./stores/uiStore'),
|
|
])
|
|
}
|
|
|
|
export async function bootstrapDesktopApp(
|
|
root: HTMLElement | null = document.getElementById('root'),
|
|
loadModules: () => Promise<DesktopBootstrapModules> = loadDesktopBootstrapModules,
|
|
) {
|
|
try {
|
|
const [{ App }, { ErrorBoundary }, { installClientDiagnosticsCapture }, { initializeTheme }] = await loadModules()
|
|
initializeTheme()
|
|
installClientDiagnosticsCapture()
|
|
|
|
if (!root) {
|
|
throw new Error('Desktop root element not found')
|
|
}
|
|
|
|
ReactDOM.createRoot(root).render(
|
|
<React.StrictMode>
|
|
<ErrorBoundary>
|
|
<App />
|
|
</ErrorBoundary>
|
|
</React.StrictMode>,
|
|
)
|
|
window.__CC_HAHA_BOOTSTRAPPED__ = true
|
|
} catch (error) {
|
|
console.error('[desktop] Failed to bootstrap app', error)
|
|
if (root) {
|
|
if (window.__CC_HAHA_SHOW_STARTUP_ERROR__) {
|
|
window.__CC_HAHA_SHOW_STARTUP_ERROR__(error)
|
|
} else {
|
|
root.textContent = error instanceof Error ? error.message : String(error)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
runDesktopPersistenceMigrations()
|
|
initializeTouchH5()
|
|
void initializeAppZoom()
|
|
|
|
void bootstrapDesktopApp()
|