mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-26 13:19:34 +07:00
🐛 fix: add separate border-radius for bottom-right corner on macOS 26 Chrome (#11287)
* 🐛 fix: add separate border-radius for bottom-right corner on macOS 26 Chrome Fix issue where the main container's bottom-right corner radius was not applied correctly on macOS 26 Chrome. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * 📝 docs(CLAUDE): add PR Linear Issue Association guidelines Include a new section in CLAUDE.md outlining the requirement to use magic keywords in PR bodies for associating with Linear issues, enhancing clarity on issue tracking. Signed-off-by: Innei <tukon479@gmail.com> --------- Signed-off-by: Innei <tukon479@gmail.com> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -74,6 +74,10 @@ The project follows a well-organized monorepo structure:
|
||||
- **Dev**: Translate `locales/zh-CN/namespace.json` locale file only for preview
|
||||
- DON'T run `pnpm i18n`, let CI auto handle it
|
||||
|
||||
## Linear Issue Management
|
||||
|
||||
Follow [Linear rules in CLAUDE.md](CLAUDE.md#linear-issue-management-ignore-if-not-installed-linear-mcp) when working with Linear issues.
|
||||
|
||||
## Project Rules Index
|
||||
|
||||
All following rules are saved under `.cursor/rules/` directory:
|
||||
|
||||
@@ -78,6 +78,10 @@ When creating new Linear issues using `mcp__linear-server__create_issue`, **MUST
|
||||
- Code review context
|
||||
- Future reference and debugging
|
||||
|
||||
### PR Linear Issue Association (REQUIRED)
|
||||
|
||||
**When creating PRs for Linear issues, MUST include magic keywords in PR body:** `Fixes LOBE-123`, `Closes LOBE-123`, or `Resolves LOBE-123`
|
||||
|
||||
### IMPORTANT: Per-Issue Completion Rule
|
||||
|
||||
**When working on multiple issues (e.g., parent issue with sub-issues), you MUST update status and add comment for EACH issue IMMEDIATELY after completing it.** Do NOT wait until all issues are done to update them in batch.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { isArc, isSonomaOrLaterSafari } from './platform';
|
||||
import { isArc, isMacOSWithLargeWindowBorders, isSonomaOrLaterSafari } from './platform';
|
||||
|
||||
describe('isSonomaOrLaterSafari', () => {
|
||||
beforeEach(() => {
|
||||
@@ -12,6 +12,31 @@ describe('isSonomaOrLaterSafari', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isMacOSWithLargeWindowBorders', () => {
|
||||
it('should return true for macOS 10.15+', () => {
|
||||
vi.stubGlobal('navigator', {
|
||||
userAgent:
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36',
|
||||
});
|
||||
|
||||
expect(isMacOSWithLargeWindowBorders()).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for non-macOS userAgent', () => {
|
||||
vi.stubGlobal('navigator', { userAgent: 'Windows NT 10.0; Win64; x64' });
|
||||
expect(isMacOSWithLargeWindowBorders()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false in Electron', () => {
|
||||
vi.stubGlobal('navigator', {
|
||||
userAgent:
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Electron/30.0.0 Safari/537.36',
|
||||
});
|
||||
|
||||
expect(isMacOSWithLargeWindowBorders()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return false when userAgent is not Macintosh', () => {
|
||||
vi.stubGlobal('navigator', { userAgent: 'Windows NT 10.0; Win64; x64' });
|
||||
expect(isSonomaOrLaterSafari()).toBe(false);
|
||||
|
||||
@@ -25,6 +25,28 @@ export const browserInfo = {
|
||||
|
||||
export const isMacOS = () => getPlatform() === 'Mac OS';
|
||||
|
||||
/**
|
||||
*
|
||||
* We can't use it to detect the macOS real version, and we also don't know if it's macOS 26, only an estimated value.
|
||||
* @returns true if the current browser is macOS and the version is 10.15 or later
|
||||
*/
|
||||
export const isMacOSWithLargeWindowBorders = () => {
|
||||
if (isOnServerSide || typeof navigator === 'undefined') return false;
|
||||
|
||||
// keep consistent with the original logic: only for macOS on web (exclude Electron)
|
||||
const isElectron =
|
||||
/Electron\//.test(navigator.userAgent) || Boolean((window as any)?.process?.type);
|
||||
if (isElectron || !isMacOS()) return false;
|
||||
|
||||
const match = navigator.userAgent.match(/Mac OS X (\d+)[._](\d+)/);
|
||||
if (!match) return false;
|
||||
|
||||
const majorVersion = parseInt(match[1], 10);
|
||||
const minorVersion = parseInt(match[2], 10);
|
||||
|
||||
return majorVersion >= 10 && minorVersion >= 15;
|
||||
};
|
||||
|
||||
export const isArc = () => {
|
||||
if (isOnServerSide) return false;
|
||||
return (
|
||||
|
||||
@@ -6,6 +6,7 @@ import { isDesktop } from '@/const/version';
|
||||
import { useIsDark } from '@/hooks/useIsDark';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { systemStatusSelectors } from '@/store/global/selectors';
|
||||
import { isMacOSWithLargeWindowBorders } from '@/utils/platform';
|
||||
|
||||
import { styles } from './DesktopLayoutContainer/style';
|
||||
|
||||
@@ -23,12 +24,15 @@ const DesktopLayoutContainer: FC<PropsWithChildren> = ({ children }) => {
|
||||
);
|
||||
|
||||
const innerCssVariables = useMemo<Record<string, string>>(() => {
|
||||
const borderRadius =
|
||||
typeof window !== 'undefined' && (window.lobeEnv?.darwinMajorVersion ?? 0) >= 25
|
||||
? '12px'
|
||||
: cssVar.borderRadius;
|
||||
const darwinMajorVersion =
|
||||
typeof window !== 'undefined' ? (window.lobeEnv?.darwinMajorVersion ?? 0) : 0;
|
||||
|
||||
const borderRadius = darwinMajorVersion >= 25 ? '12px' : cssVar.borderRadius;
|
||||
const borderBottomRightRadius =
|
||||
darwinMajorVersion >= 26 || isMacOSWithLargeWindowBorders() ? '12px' : borderRadius;
|
||||
|
||||
return {
|
||||
'--container-border-bottom-right-radius': borderBottomRightRadius,
|
||||
'--container-border-color': isDarkMode ? cssVar.colorBorderSecondary : cssVar.colorBorder,
|
||||
'--container-border-radius': borderRadius,
|
||||
};
|
||||
|
||||
@@ -11,6 +11,10 @@ export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
|
||||
border: 1px solid var(--container-border-color, ${cssVar.colorBorder});
|
||||
border-radius: var(--container-border-radius, ${cssVar.borderRadius});
|
||||
border-end-end-radius: var(
|
||||
--container-border-bottom-right-radius,
|
||||
var(--container-border-radius, ${cssVar.borderRadius})
|
||||
);
|
||||
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
|
||||
Reference in New Issue
Block a user