feat(desktop): enable macOS version awareness for UI adjustments

- Fetch macOS major version from Rust to determine layout
- Adjust header padding and height for macOS versions
This commit is contained in:
Bohdan Triapitsyn
2026-01-30 02:46:43 +02:00
parent 5550193861
commit 2d305d18c6
8 changed files with 91 additions and 22 deletions
+25 -9
View File
@@ -108,15 +108,28 @@ export const Header: React.FC = () => {
}, []);
const macosMajorVersion = React.useMemo(() => {
if (typeof window === 'undefined') {
return null;
}
// Use Tauri-provided version if available (accurate), otherwise fall back to UA parsing
const desktopApi = (window as typeof window & { opencodeDesktop?: { macosMajorVersion?: number | null } }).opencodeDesktop;
if (desktopApi?.macosMajorVersion != null) {
return desktopApi.macosMajorVersion;
}
// Fallback: WebKit reports "Mac OS X 10_15_7" format where 10 is legacy prefix
if (typeof navigator === 'undefined') {
return null;
}
const match = (navigator.userAgent || '').match(/Mac OS X (\d+)[._]/);
const match = (navigator.userAgent || '').match(/Mac OS X (\d+)[._](\d+)/);
if (!match) {
return null;
}
const parsed = Number.parseInt(match[1], 10);
return Number.isNaN(parsed) ? null : parsed;
const first = Number.parseInt(match[1], 10);
const second = Number.parseInt(match[2], 10);
if (Number.isNaN(first)) {
return null;
}
return first === 10 ? second : first;
}, []);
useEffect(() => {
@@ -296,19 +309,22 @@ export const Header: React.FC = () => {
const desktopPaddingClass = React.useMemo(() => {
if (isDesktopApp && isMacPlatform) {
// Always reserve space for Mac traffic lights since header is always on top
return 'pl-[5.125rem]';
return 'pl-[5.5rem]';
}
return 'pl-3';
}, [isDesktopApp, isMacPlatform]);
const macosHeaderSizeClass = React.useMemo(() => {
if (!isDesktopApp || !isMacPlatform) {
if (!isDesktopApp || !isMacPlatform || macosMajorVersion === null) {
return '';
}
if (macosMajorVersion === null || macosMajorVersion > 15) {
return '';
if (macosMajorVersion >= 26) {
return 'h-12';
}
return 'h-14';
if (macosMajorVersion <= 15) {
return 'h-14';
}
return '';
}, [isDesktopApp, isMacPlatform, macosMajorVersion]);
const updateHeaderHeight = React.useCallback(() => {
@@ -351,7 +367,7 @@ export const Header: React.FC = () => {
useEffect(() => {
updateHeaderHeight();
}, [updateHeaderHeight, isMobile]);
}, [updateHeaderHeight, isMobile, macosHeaderSizeClass]);
const handleDragStart = React.useCallback(async (e: React.MouseEvent) => {
if ((e.target as HTMLElement).closest('button, a, input, select, textarea')) {