Skip to content

Commit 75723f5

Browse files
committed
Fix nav hover styles and ensure light mode colors for React Best Practices page content
1 parent 0b7ada0 commit 75723f5

File tree

2 files changed

+111
-213
lines changed

2 files changed

+111
-213
lines changed

src/shared-components/navigation/PageSubNav/SubNavLink.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ export const SubNavLink: React.FC<SubNavLinkProps> = ({ item, onClick, isExpande
9696
pointerEvents: isClickable ? 'auto' : 'none',
9797
// Dim only if not clickable
9898
opacity: isClickable ? 1 : 0.7,
99+
// Improve hover feedback with a more noticeable transition
100+
transition: 'all 0.2s ease',
101+
'&:hover': isClickable ? {
102+
backgroundColor: isActive ? 'rgba(66, 153, 225, 0.1)' : 'rgba(0, 0, 0, 0.05)',
103+
borderLeftColor: !isHeader && isInteractive ? theme.colors[theme.primaryColor][5] : undefined,
104+
} : undefined,
99105
},
100106
label: {
101107
// fontWeight handled in textStyle
Lines changed: 105 additions & 213 deletions
Original file line numberDiff line numberDiff line change
@@ -1,221 +1,113 @@
11
import { MantineTheme, rem, useMantineTheme } from '@mantine/core';
2-
import type { CSSProperties } from 'react'; // Use React's CSSProperties
2+
import { useMemo } from 'react';
33

4-
// Note: createStyles is deprecated. Using object syntax directly.
5-
// This hook will provide the styles object based on the current theme.
4+
// Utility to create a simple styles class naming system
65
export const useStyles = () => {
76
const theme = useMantineTheme();
87

9-
// Defensive check for theme and colorScheme
10-
const isDark = theme.black === '#000';
11-
12-
// If theme is somehow unavailable, return empty styles to prevent crash
13-
if (!theme) {
14-
console.error('Mantine theme context is missing. Ensure MantineProvider wraps this component.');
15-
return { classes: {}, cx: (...args: any[]) => args.filter(Boolean).join(' ') };
16-
}
17-
18-
const styles: Record<string, CSSProperties & Record<string, any>> = {
19-
detailedContentContainer: {
20-
width: '100%',
21-
margin: `${theme.spacing.xl} 0 ${rem(64)}`,
22-
paddingBottom: rem(70),
23-
opacity: 0,
24-
transform: 'translateY(20px)',
25-
transition: 'opacity 0.5s ease-out, transform 0.5s ease-out',
26-
27-
'&.visible': {
28-
opacity: 1,
29-
transform: 'translateY(0)',
30-
},
31-
},
32-
33-
visible: {
34-
opacity: 1,
35-
transform: 'translateY(0)',
36-
},
37-
38-
titleWrapper: {
39-
display: 'flex',
40-
flexDirection: 'row',
41-
alignItems: 'center',
42-
gap: theme.spacing.md,
43-
marginBottom: theme.spacing.lg,
44-
},
45-
46-
sectionIcon: {
47-
display: 'flex',
48-
alignItems: 'center',
49-
justifyContent: 'center',
50-
width: rem(48),
51-
height: rem(48),
52-
borderRadius: '50%',
53-
backgroundColor: isDark ? theme.colors.dark[6] : theme.black,
54-
padding: theme.spacing.xs,
55-
flexShrink: 0,
56-
57-
'& svg, & img': {
58-
width: '100%',
59-
height: '100%',
60-
objectFit: 'contain',
61-
fill: theme.white,
62-
},
63-
64-
[`@media (max-width: ${theme.breakpoints.xs})`]: {
65-
width: rem(40),
66-
height: rem(40),
67-
},
68-
},
69-
70-
detailedContentTitle: {
71-
fontSize: theme.headings.sizes.h2.fontSize,
72-
fontWeight: theme.headings.sizes.h2.fontWeight,
73-
color: isDark ? theme.white : theme.black,
74-
wordBreak: 'break-word',
75-
overflowWrap: 'break-word',
76-
flex: 1,
77-
minWidth: 0,
78-
margin: 0,
79-
80-
[`@media (max-width: ${theme.breakpoints.md})`]: {
81-
fontSize: `calc(${theme.headings.sizes.h2.fontSize} * 0.875)`,
82-
},
83-
[`@media (max-width: ${theme.breakpoints.sm})`]: {
84-
fontSize: `calc(${theme.headings.sizes.h2.fontSize} * 0.75)`,
85-
},
86-
},
87-
88-
detailedContentText: {
89-
fontSize: theme.fontSizes.lg,
90-
lineHeight: 1.6,
91-
marginBottom: theme.spacing.lg,
92-
color: isDark ? theme.colors.dark[1] : theme.colors.gray[7],
93-
},
94-
95-
detailedContentList: {
96-
fontSize: theme.fontSizes.lg,
97-
lineHeight: 1.6,
98-
marginBottom: theme.spacing.lg,
99-
color: isDark ? theme.colors.dark[1] : theme.colors.gray[7],
100-
paddingLeft: theme.spacing.xl,
101-
listStylePosition: 'inside',
102-
103-
'& ul': {
104-
listStyle: 'disc',
105-
margin: 0,
106-
paddingLeft: theme.spacing.md,
107-
},
108-
'& li': {
109-
marginBottom: theme.spacing.sm,
8+
// Create a css-in-js classNames object that will work with the component
9+
return useMemo(() => {
10+
// Each key in this object will be a className string that can be applied to elements
11+
const classes = {
12+
sectionIcon: 'detailed-content-section-icon',
13+
detailedContentTitle: 'detailed-content-title',
14+
detailedContentText: 'detailed-content-text',
15+
detailedContentList: 'detailed-content-list',
16+
detailedContentSubtitle: 'detailed-content-subtitle',
17+
codeBlock: 'detailed-content-code-block',
18+
sectionTitle: 'detailed-content-section-title',
19+
sectionSubtitle: 'detailed-content-section-subtitle',
20+
subtitleWrapper: 'detailed-content-subtitle-wrapper',
21+
textContent: 'detailed-content-text-content',
22+
listContent: 'detailed-content-list-content',
23+
};
24+
25+
// Add global styles for these classes - would normally be in a separate GlobalStyles component
26+
// but this ensures the styles are applied
27+
if (typeof document !== 'undefined') {
28+
const styleId = 'detailed-content-dynamic-styles';
29+
let styleEl = document.getElementById(styleId) as HTMLStyleElement;
30+
31+
if (!styleEl) {
32+
styleEl = document.createElement('style');
33+
styleEl.id = styleId;
34+
document.head.appendChild(styleEl);
11035
}
111-
},
112-
113-
iconWrapper: {
114-
display: 'flex',
115-
alignItems: 'center',
116-
justifyContent: 'center',
117-
width: rem(32),
118-
height: rem(32),
119-
borderRadius: '50%',
120-
backgroundColor: isDark ? theme.colors.dark[6] : theme.black,
121-
padding: rem(6),
122-
flexShrink: 0,
123-
124-
'& svg': {
125-
fill: theme.white,
126-
},
127-
},
128-
129-
titleWithIconWrapper: {
130-
display: 'flex',
131-
alignItems: 'center',
132-
gap: theme.spacing.sm,
133-
marginBottom: theme.spacing.md,
134-
},
135-
136-
sectionTitle: {
137-
fontSize: theme.headings.sizes.h3.fontSize,
138-
fontWeight: theme.headings.sizes.h3.fontWeight,
139-
color: isDark ? theme.white : theme.black,
140-
margin: 0,
141-
wordBreak: 'break-word',
142-
overflowWrap: 'break-word',
143-
flex: 1,
144-
minWidth: 0,
145-
146-
[`@media (max-width: ${theme.breakpoints.md})`]: {
147-
fontSize: `calc(${theme.headings.sizes.h3.fontSize} * 0.85)`,
148-
},
149-
[`@media (max-width: ${theme.breakpoints.sm})`]: {
150-
fontSize: `calc(${theme.headings.sizes.h3.fontSize} * 0.75)`,
151-
},
152-
},
153-
154-
sectionSubtitle: {
155-
fontSize: theme.fontSizes.xl,
156-
color: isDark ? theme.colors.dark[1] : theme.colors.gray[7],
157-
margin: `0 0 ${theme.spacing.md} 0`,
158-
fontWeight: 500,
159-
},
160-
161-
subtitleWrapper: {
162-
display: 'flex',
163-
alignItems: 'center',
164-
gap: theme.spacing.xs,
165-
marginBottom: theme.spacing.xs,
166-
},
167-
168-
textContent: {
169-
fontSize: theme.fontSizes.lg,
170-
lineHeight: 1.6,
171-
marginBottom: theme.spacing.lg,
172-
color: isDark ? theme.colors.dark[1] : theme.colors.gray[7],
173-
},
174-
175-
listContent: {
176-
marginBottom: theme.spacing.lg,
177-
paddingLeft: theme.spacing.xl,
178-
listStylePosition: 'inside',
179-
180-
'& ul': {
181-
listStyle: 'disc',
182-
margin: 0,
183-
paddingLeft: theme.spacing.md,
184-
},
185-
'& li': {
186-
fontSize: theme.fontSizes.lg,
187-
lineHeight: 1.6,
188-
color: isDark ? theme.colors.dark[1] : theme.colors.gray[7],
189-
marginBottom: theme.spacing.sm,
190-
}
191-
},
192-
193-
codeBlock: {
194-
backgroundColor: isDark ? theme.colors.dark[8] : theme.colors.gray[0],
195-
borderRadius: theme.radius.md,
196-
padding: theme.spacing.lg,
197-
overflowX: 'auto',
198-
marginBottom: theme.spacing.lg,
199-
fontFamily: theme.fontFamilyMonospace,
200-
fontSize: theme.fontSizes.sm,
201-
lineHeight: 1.5,
202-
color: isDark ? theme.white : theme.black,
203-
whiteSpace: 'pre',
204-
},
205-
};
206-
207-
// Create a classes object mapping keys to empty strings to satisfy types
208-
const classNames: Record<string, string> = {};
209-
for (const key in styles) {
210-
classNames[key] = ''; // Assign empty string
211-
}
212-
213-
// Mantine's hooks usually return { classes, cx, theme, etc. }
214-
// To maintain compatibility with how it's used in DetailedContent.tsx ({ classes, cx } = useStyles()),
215-
// we wrap the styles object.
216-
// A proper `cx` function would be needed if conditional classes are complex.
217-
const cx = (...args: any[]) => args.filter(Boolean).join(' ');
21836

219-
// Return the object mapping keys to empty strings
220-
return { classes: classNames, cx };
37+
const css = `
38+
.${classes.sectionIcon} {
39+
display: flex;
40+
align-items: center;
41+
justify-content: center;
42+
width: ${rem(48)};
43+
height: ${rem(48)};
44+
border-radius: 50%;
45+
background-color: ${theme.black};
46+
padding: ${theme.spacing.xs};
47+
flex-shrink: 0;
48+
}
49+
.${classes.sectionIcon} svg, .${classes.sectionIcon} img {
50+
width: 100%;
51+
height: 100%;
52+
object-fit: contain;
53+
fill: ${theme.white};
54+
}
55+
56+
.${classes.detailedContentTitle} {
57+
font-size: ${theme.headings.sizes.h2.fontSize};
58+
font-weight: ${theme.headings.sizes.h2.fontWeight};
59+
line-height: 1.3;
60+
margin: 0;
61+
color: ${theme.black};
62+
}
63+
64+
.${classes.detailedContentText} {
65+
font-size: ${theme.fontSizes.md};
66+
line-height: 1.7;
67+
margin-top: ${theme.spacing.md};
68+
color: ${theme.colors.gray[7]};
69+
overflow-wrap: break-word;
70+
word-break: break-word;
71+
}
72+
73+
.${classes.detailedContentList} {
74+
margin-top: ${theme.spacing.md};
75+
margin-bottom: ${theme.spacing.lg};
76+
}
77+
78+
.${classes.detailedContentList} ul {
79+
padding-left: ${theme.spacing.xl};
80+
margin: 0;
81+
}
82+
83+
.${classes.detailedContentList} li {
84+
line-height: 1.7;
85+
margin-bottom: ${theme.spacing.xs};
86+
font-size: ${theme.fontSizes.md};
87+
color: ${theme.colors.gray[7]};
88+
}
89+
90+
.${classes.codeBlock} {
91+
background-color: ${theme.colors.gray[0]};
92+
border-radius: ${theme.radius.md};
93+
padding: ${theme.spacing.lg};
94+
overflow-x: auto;
95+
margin-top: ${theme.spacing.lg};
96+
margin-bottom: ${theme.spacing.lg};
97+
font-family: ${theme.fontFamilyMonospace};
98+
font-size: ${theme.fontSizes.sm};
99+
line-height: 1.5;
100+
color: ${theme.black};
101+
white-space: pre;
102+
}
103+
`;
104+
105+
styleEl.innerHTML = css;
106+
}
107+
108+
return {
109+
classes,
110+
cx: (...args: string[]) => args.filter(Boolean).join(' ')
111+
};
112+
}, [theme]);
221113
};

0 commit comments

Comments
 (0)