@patternfly/documentation-framework 6.10.33 → 6.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/components/example/example.js +91 -15
- package/hooks/useTheme.js +137 -0
- package/layouts/sideNavLayout/sideNavLayout.js +87 -30
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 6.11.0 (2025-06-16)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **ThemeSwitcher:** Enhanced theme switcher with system preference detection and tri-state selection ([#4639](https://github.com/patternfly/patternfly-org/issues/4639)) ([1b05742](https://github.com/patternfly/patternfly-org/commit/1b057425216a484dda1f46ba37842c22b77c7b87))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## 6.10.33 (2025-06-16)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @patternfly/documentation-framework
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useContext, useEffect } from 'react';
|
|
1
|
+
import React, { useContext, useEffect, useState, useCallback } from 'react';
|
|
2
2
|
import { useLocation } from '@reach/router';
|
|
3
3
|
import {
|
|
4
4
|
Button,
|
|
@@ -8,6 +8,10 @@ import {
|
|
|
8
8
|
debounce,
|
|
9
9
|
Label,
|
|
10
10
|
Switch,
|
|
11
|
+
Select,
|
|
12
|
+
SelectOption,
|
|
13
|
+
SelectList,
|
|
14
|
+
MenuToggle,
|
|
11
15
|
Tooltip,
|
|
12
16
|
Stack,
|
|
13
17
|
StackItem
|
|
@@ -19,6 +23,9 @@ import * as reactTableModule from '@patternfly/react-table';
|
|
|
19
23
|
import * as reactTableDeprecatedModule from '@patternfly/react-table/deprecated';
|
|
20
24
|
import { css } from '@patternfly/react-styles';
|
|
21
25
|
import { getParameters } from 'codesandbox/lib/api/define';
|
|
26
|
+
import SunIcon from '@patternfly/react-icons/dist/esm/icons/sun-icon';
|
|
27
|
+
import MoonIcon from '@patternfly/react-icons/dist/esm/icons/moon-icon';
|
|
28
|
+
import DesktopIcon from '@patternfly/react-icons/dist/esm/icons/desktop-icon';
|
|
22
29
|
import { ExampleToolbar } from './exampleToolbar.jsx';
|
|
23
30
|
import { AutoLinkHeader } from '../autoLinkHeader/autoLinkHeader';
|
|
24
31
|
import {
|
|
@@ -32,9 +39,89 @@ import {
|
|
|
32
39
|
import { convertToReactComponent } from '@patternfly/ast-helpers';
|
|
33
40
|
import missingThumbnail from './missing-thumbnail.jpg';
|
|
34
41
|
import { RtlContext } from '../../layouts';
|
|
42
|
+
import { useTheme } from '../../hooks/useTheme';
|
|
35
43
|
|
|
36
44
|
const errorComponent = (err) => <pre>{err.toString()}</pre>;
|
|
37
45
|
|
|
46
|
+
// Full-screen theme selector component using shared theme hook
|
|
47
|
+
const FullScreenThemeSelector = () => {
|
|
48
|
+
const { themeMode, setThemeMode, THEME_MODES } = useTheme();
|
|
49
|
+
const [isThemeSelectOpen, setIsThemeSelectOpen] = useState(false);
|
|
50
|
+
|
|
51
|
+
const handleThemeChange = (_event, selectedMode) => {
|
|
52
|
+
setThemeMode(selectedMode);
|
|
53
|
+
setIsThemeSelectOpen(false);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const getThemeDisplayText = (mode) => {
|
|
57
|
+
switch (mode) {
|
|
58
|
+
case THEME_MODES.LIGHT:
|
|
59
|
+
return 'Light';
|
|
60
|
+
case THEME_MODES.DARK:
|
|
61
|
+
return 'Dark';
|
|
62
|
+
default:
|
|
63
|
+
return 'System';
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const getThemeIcon = (mode) => {
|
|
68
|
+
switch (mode) {
|
|
69
|
+
case THEME_MODES.LIGHT:
|
|
70
|
+
return <SunIcon />;
|
|
71
|
+
case THEME_MODES.DARK:
|
|
72
|
+
return <MoonIcon />;
|
|
73
|
+
default:
|
|
74
|
+
return <DesktopIcon />;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Select
|
|
80
|
+
id="ws-example-theme-select"
|
|
81
|
+
isOpen={isThemeSelectOpen}
|
|
82
|
+
selected={themeMode}
|
|
83
|
+
onSelect={handleThemeChange}
|
|
84
|
+
onOpenChange={(isOpen) => setIsThemeSelectOpen(isOpen)}
|
|
85
|
+
toggle={(toggleRef) => (
|
|
86
|
+
<MenuToggle
|
|
87
|
+
ref={toggleRef}
|
|
88
|
+
onClick={() => setIsThemeSelectOpen(!isThemeSelectOpen)}
|
|
89
|
+
isExpanded={isThemeSelectOpen}
|
|
90
|
+
icon={getThemeIcon(themeMode)}
|
|
91
|
+
aria-label={`Theme selection, current: ${getThemeDisplayText(themeMode)}`}
|
|
92
|
+
>
|
|
93
|
+
{getThemeDisplayText(themeMode)}
|
|
94
|
+
</MenuToggle>
|
|
95
|
+
)}
|
|
96
|
+
shouldFocusToggleOnSelect
|
|
97
|
+
>
|
|
98
|
+
<SelectList>
|
|
99
|
+
<SelectOption
|
|
100
|
+
value={THEME_MODES.SYSTEM}
|
|
101
|
+
icon={<DesktopIcon />}
|
|
102
|
+
description="Follow system preference"
|
|
103
|
+
>
|
|
104
|
+
System
|
|
105
|
+
</SelectOption>
|
|
106
|
+
<SelectOption
|
|
107
|
+
value={THEME_MODES.LIGHT}
|
|
108
|
+
icon={<SunIcon />}
|
|
109
|
+
description="Always use light mode"
|
|
110
|
+
>
|
|
111
|
+
Light
|
|
112
|
+
</SelectOption>
|
|
113
|
+
<SelectOption
|
|
114
|
+
value={THEME_MODES.DARK}
|
|
115
|
+
icon={<MoonIcon />}
|
|
116
|
+
description="Always use dark mode"
|
|
117
|
+
>
|
|
118
|
+
Dark
|
|
119
|
+
</SelectOption>
|
|
120
|
+
</SelectList>
|
|
121
|
+
</Select>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
|
|
38
125
|
class ErrorBoundary extends React.Component {
|
|
39
126
|
constructor(props) {
|
|
40
127
|
super(props);
|
|
@@ -199,21 +286,10 @@ export const Example = ({
|
|
|
199
286
|
{(hasDarkThemeSwitcher || hasRTLSwitcher) && (
|
|
200
287
|
<Flex
|
|
201
288
|
direction={{ default: 'column' }}
|
|
202
|
-
gap={{ default: '
|
|
203
|
-
className="ws-full-page-utils pf-v6-m-dir-ltr
|
|
289
|
+
gap={{ default: 'gapMd' }}
|
|
290
|
+
className="ws-full-page-utils pf-v6-m-dir-ltr"
|
|
204
291
|
>
|
|
205
|
-
{hasDarkThemeSwitcher &&
|
|
206
|
-
<Switch
|
|
207
|
-
id="ws-example-theme-switch"
|
|
208
|
-
label="Dark theme"
|
|
209
|
-
defaultChecked={false}
|
|
210
|
-
onChange={() =>
|
|
211
|
-
document
|
|
212
|
-
.querySelector('html')
|
|
213
|
-
.classList.toggle('pf-v6-theme-dark')
|
|
214
|
-
}
|
|
215
|
-
/>
|
|
216
|
-
)}
|
|
292
|
+
{hasDarkThemeSwitcher && <FullScreenThemeSelector />}
|
|
217
293
|
{hasRTLSwitcher && (
|
|
218
294
|
<Switch
|
|
219
295
|
id="ws-example-rtl-switch"
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
const THEME_MODES = {
|
|
4
|
+
SYSTEM: 'system',
|
|
5
|
+
LIGHT: 'light',
|
|
6
|
+
DARK: 'dark'
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const THEME_STORAGE_KEY = 'theme-preference';
|
|
10
|
+
const DARK_MODE_CLASS = 'pf-v6-theme-dark';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Custom hook for managing theme state with system preference detection
|
|
14
|
+
* @returns {Object} Theme state and controls
|
|
15
|
+
* @returns {string} themeMode - Current theme mode ('system'|'light'|'dark')
|
|
16
|
+
* @returns {Function} setThemeMode - Function to change theme mode
|
|
17
|
+
* @returns {string} resolvedTheme - The actual applied theme ('light'|'dark')
|
|
18
|
+
* @returns {Object} THEME_MODES - Available theme mode constants
|
|
19
|
+
*/
|
|
20
|
+
export const useTheme = () => {
|
|
21
|
+
const getStoredThemeMode = () => {
|
|
22
|
+
if (typeof window === 'undefined' || !window.localStorage) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return localStorage.getItem(THEME_STORAGE_KEY);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const setStoredThemeMode = (mode) => {
|
|
29
|
+
if (typeof window === 'undefined' || !window.localStorage) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
localStorage.setItem(THEME_STORAGE_KEY, mode);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const getResolvedTheme = (mode) => {
|
|
36
|
+
// SSR-safe check for window and matchMedia
|
|
37
|
+
if (typeof window === 'undefined' || !window.matchMedia) {
|
|
38
|
+
return 'light';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (mode === THEME_MODES.SYSTEM) {
|
|
42
|
+
try {
|
|
43
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
44
|
+
} catch (error) {
|
|
45
|
+
// Fallback if matchMedia fails
|
|
46
|
+
console.warn('matchMedia not supported, defaulting to light theme');
|
|
47
|
+
return 'light';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return mode;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const updateThemeClass = (resolvedTheme) => {
|
|
54
|
+
if (typeof window === 'undefined' || !document) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const htmlElement = document.querySelector('html');
|
|
59
|
+
if (!htmlElement) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (resolvedTheme === 'dark') {
|
|
64
|
+
htmlElement.classList.add(DARK_MODE_CLASS);
|
|
65
|
+
} else {
|
|
66
|
+
htmlElement.classList.remove(DARK_MODE_CLASS);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const [themeMode, setThemeModeState] = useState(() => {
|
|
71
|
+
const stored = getStoredThemeMode();
|
|
72
|
+
return stored && Object.values(THEME_MODES).includes(stored) ? stored : THEME_MODES.SYSTEM;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const [resolvedTheme, setResolvedTheme] = useState(() => getResolvedTheme(themeMode));
|
|
76
|
+
|
|
77
|
+
const setThemeMode = useCallback((newMode) => {
|
|
78
|
+
setThemeModeState(newMode);
|
|
79
|
+
setStoredThemeMode(newMode);
|
|
80
|
+
|
|
81
|
+
const newResolvedTheme = getResolvedTheme(newMode);
|
|
82
|
+
setResolvedTheme(newResolvedTheme);
|
|
83
|
+
updateThemeClass(newResolvedTheme);
|
|
84
|
+
}, []);
|
|
85
|
+
|
|
86
|
+
// Listen for system preference changes
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
// Enhanced SSR-safe check
|
|
89
|
+
if (typeof window === 'undefined' || !window.matchMedia) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let mediaQuery;
|
|
94
|
+
try {
|
|
95
|
+
mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.warn('matchMedia not supported, skipping system theme detection');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const handleSystemThemeChange = (e) => {
|
|
102
|
+
if (themeMode === THEME_MODES.SYSTEM) {
|
|
103
|
+
const newSystemTheme = e.matches ? 'dark' : 'light';
|
|
104
|
+
setResolvedTheme(newSystemTheme);
|
|
105
|
+
updateThemeClass(newSystemTheme);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Check if addEventListener is available (some older browsers might not support it)
|
|
110
|
+
if (mediaQuery.addEventListener) {
|
|
111
|
+
mediaQuery.addEventListener('change', handleSystemThemeChange);
|
|
112
|
+
return () => {
|
|
113
|
+
mediaQuery.removeEventListener('change', handleSystemThemeChange);
|
|
114
|
+
};
|
|
115
|
+
} else if (mediaQuery.addListener) {
|
|
116
|
+
// Fallback for older browsers
|
|
117
|
+
mediaQuery.addListener(handleSystemThemeChange);
|
|
118
|
+
return () => {
|
|
119
|
+
mediaQuery.removeListener(handleSystemThemeChange);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}, [themeMode]);
|
|
123
|
+
|
|
124
|
+
// Initial theme application
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
const initialResolvedTheme = getResolvedTheme(themeMode);
|
|
127
|
+
setResolvedTheme(initialResolvedTheme);
|
|
128
|
+
updateThemeClass(initialResolvedTheme);
|
|
129
|
+
}, [themeMode]);
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
themeMode,
|
|
133
|
+
setThemeMode,
|
|
134
|
+
resolvedTheme,
|
|
135
|
+
THEME_MODES
|
|
136
|
+
};
|
|
137
|
+
};
|
|
@@ -23,17 +23,20 @@ import {
|
|
|
23
23
|
SkipToContent,
|
|
24
24
|
Switch,
|
|
25
25
|
SearchInput,
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
Select,
|
|
27
|
+
SelectOption,
|
|
28
|
+
SelectList,
|
|
28
29
|
MastheadLogo
|
|
29
30
|
} from '@patternfly/react-core';
|
|
30
31
|
import BarsIcon from '@patternfly/react-icons/dist/esm/icons/bars-icon';
|
|
31
32
|
import GithubIcon from '@patternfly/react-icons/dist/esm/icons/github-icon';
|
|
32
33
|
import MoonIcon from '@patternfly/react-icons/dist/esm/icons/moon-icon';
|
|
33
34
|
import SunIcon from '@patternfly/react-icons/dist/esm/icons/sun-icon';
|
|
35
|
+
import DesktopIcon from '@patternfly/react-icons/dist/esm/icons/desktop-icon';
|
|
34
36
|
import { SideNav, TopNav, GdprBanner } from '../../components';
|
|
35
37
|
import staticVersions from '../../versions.json';
|
|
36
38
|
import { Footer } from '@patternfly/documentation-framework/components';
|
|
39
|
+
import { useTheme } from '../../hooks/useTheme';
|
|
37
40
|
|
|
38
41
|
export const RtlContext = createContext(false);
|
|
39
42
|
|
|
@@ -46,8 +49,9 @@ const HeaderTools = ({
|
|
|
46
49
|
topNavItems,
|
|
47
50
|
isRTL,
|
|
48
51
|
setIsRTL,
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
themeMode,
|
|
53
|
+
setThemeMode,
|
|
54
|
+
THEME_MODES
|
|
51
55
|
}) => {
|
|
52
56
|
const latestVersion = versions.Releases.find((version) => version.latest);
|
|
53
57
|
const previousReleases = Object.values(versions.Releases).filter((version) => !version.hidden && !version.latest);
|
|
@@ -55,6 +59,7 @@ const HeaderTools = ({
|
|
|
55
59
|
const [isDropdownOpen, setDropdownOpen] = useState(false);
|
|
56
60
|
const [searchValue, setSearchValue] = React.useState('');
|
|
57
61
|
const [isSearchExpanded, setIsSearchExpanded] = React.useState(false);
|
|
62
|
+
const [isThemeSelectOpen, setIsThemeSelectOpen] = useState(false);
|
|
58
63
|
|
|
59
64
|
const getDropdownItem = (version, isLatest = false) => (
|
|
60
65
|
<DropdownItem itemId={version.name} key={version.name} to={isLatest ? '/' : `/${version.name}`}>
|
|
@@ -70,10 +75,31 @@ const HeaderTools = ({
|
|
|
70
75
|
setIsSearchExpanded(!isSearchExpanded);
|
|
71
76
|
};
|
|
72
77
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
78
|
+
const handleThemeChange = (_event, selectedMode) => {
|
|
79
|
+
setThemeMode(selectedMode);
|
|
80
|
+
setIsThemeSelectOpen(false);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const getThemeDisplayText = (mode) => {
|
|
84
|
+
switch (mode) {
|
|
85
|
+
case THEME_MODES.LIGHT:
|
|
86
|
+
return 'Light';
|
|
87
|
+
case THEME_MODES.DARK:
|
|
88
|
+
return 'Dark';
|
|
89
|
+
default:
|
|
90
|
+
return 'System';
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const getThemeIcon = (mode) => {
|
|
95
|
+
switch (mode) {
|
|
96
|
+
case THEME_MODES.LIGHT:
|
|
97
|
+
return <SunIcon />;
|
|
98
|
+
case THEME_MODES.DARK:
|
|
99
|
+
return <MoonIcon />;
|
|
100
|
+
default:
|
|
101
|
+
return <DesktopIcon />;
|
|
102
|
+
}
|
|
77
103
|
};
|
|
78
104
|
|
|
79
105
|
useEffect(() => {
|
|
@@ -92,24 +118,6 @@ const HeaderTools = ({
|
|
|
92
118
|
</ToolbarItem>
|
|
93
119
|
)}
|
|
94
120
|
<ToolbarGroup align={{ default: 'alignEnd' }}>
|
|
95
|
-
{hasDarkThemeSwitcher && (
|
|
96
|
-
<ToolbarItem>
|
|
97
|
-
<ToggleGroup aria-label="Dark theme toggle group">
|
|
98
|
-
<ToggleGroupItem
|
|
99
|
-
aria-label="light theme toggle"
|
|
100
|
-
icon={<SunIcon />}
|
|
101
|
-
isSelected={!isDarkTheme}
|
|
102
|
-
onChange={toggleDarkTheme}
|
|
103
|
-
/>
|
|
104
|
-
<ToggleGroupItem
|
|
105
|
-
aria-label="dark theme toggle"
|
|
106
|
-
icon={<MoonIcon />}
|
|
107
|
-
isSelected={isDarkTheme}
|
|
108
|
-
onChange={toggleDarkTheme}
|
|
109
|
-
/>
|
|
110
|
-
</ToggleGroup>
|
|
111
|
-
</ToolbarItem>
|
|
112
|
-
)}
|
|
113
121
|
{hasRTLSwitcher && (
|
|
114
122
|
<ToolbarItem>
|
|
115
123
|
<Switch
|
|
@@ -147,6 +155,53 @@ const HeaderTools = ({
|
|
|
147
155
|
<GithubIcon />
|
|
148
156
|
</Button>
|
|
149
157
|
</ToolbarItem>
|
|
158
|
+
{hasDarkThemeSwitcher && (
|
|
159
|
+
<ToolbarItem>
|
|
160
|
+
<Select
|
|
161
|
+
id="ws-theme-select"
|
|
162
|
+
isOpen={isThemeSelectOpen}
|
|
163
|
+
selected={themeMode}
|
|
164
|
+
onSelect={handleThemeChange}
|
|
165
|
+
onOpenChange={(isOpen) => setIsThemeSelectOpen(isOpen)}
|
|
166
|
+
toggle={(toggleRef) => (
|
|
167
|
+
<MenuToggle
|
|
168
|
+
ref={toggleRef}
|
|
169
|
+
onClick={() => setIsThemeSelectOpen(!isThemeSelectOpen)}
|
|
170
|
+
isExpanded={isThemeSelectOpen}
|
|
171
|
+
icon={getThemeIcon(themeMode)}
|
|
172
|
+
aria-label={`Theme selection, current: ${getThemeDisplayText(themeMode)}`}
|
|
173
|
+
>
|
|
174
|
+
{getThemeDisplayText(themeMode)}
|
|
175
|
+
</MenuToggle>
|
|
176
|
+
)}
|
|
177
|
+
shouldFocusToggleOnSelect
|
|
178
|
+
>
|
|
179
|
+
<SelectList>
|
|
180
|
+
<SelectOption
|
|
181
|
+
value={THEME_MODES.SYSTEM}
|
|
182
|
+
icon={<DesktopIcon />}
|
|
183
|
+
description="Follow system preference"
|
|
184
|
+
>
|
|
185
|
+
System
|
|
186
|
+
</SelectOption>
|
|
187
|
+
<SelectOption
|
|
188
|
+
value={THEME_MODES.LIGHT}
|
|
189
|
+
icon={<SunIcon />}
|
|
190
|
+
description="Always use light mode"
|
|
191
|
+
>
|
|
192
|
+
Light
|
|
193
|
+
</SelectOption>
|
|
194
|
+
<SelectOption
|
|
195
|
+
value={THEME_MODES.DARK}
|
|
196
|
+
icon={<MoonIcon />}
|
|
197
|
+
description="Always use dark mode"
|
|
198
|
+
>
|
|
199
|
+
Dark
|
|
200
|
+
</SelectOption>
|
|
201
|
+
</SelectList>
|
|
202
|
+
</Select>
|
|
203
|
+
</ToolbarItem>
|
|
204
|
+
)}
|
|
150
205
|
{hasVersionSwitcher && (
|
|
151
206
|
<ToolbarItem>
|
|
152
207
|
<Dropdown
|
|
@@ -245,7 +300,8 @@ export const SideNavLayout = ({ children, groupedRoutes, navOpen: navOpenProp })
|
|
|
245
300
|
|
|
246
301
|
const [versions, setVersions] = useState({ ...staticVersions });
|
|
247
302
|
const [isRTL, setIsRTL] = useState(false);
|
|
248
|
-
|
|
303
|
+
|
|
304
|
+
const { themeMode, setThemeMode, resolvedTheme, THEME_MODES } = useTheme();
|
|
249
305
|
|
|
250
306
|
useEffect(() => {
|
|
251
307
|
if (typeof window === 'undefined') {
|
|
@@ -338,8 +394,9 @@ export const SideNavLayout = ({ children, groupedRoutes, navOpen: navOpenProp })
|
|
|
338
394
|
topNavItems={topNavItems}
|
|
339
395
|
isRTL={isRTL}
|
|
340
396
|
setIsRTL={setIsRTL}
|
|
341
|
-
|
|
342
|
-
|
|
397
|
+
themeMode={themeMode}
|
|
398
|
+
setThemeMode={setThemeMode}
|
|
399
|
+
THEME_MODES={THEME_MODES}
|
|
343
400
|
/>
|
|
344
401
|
)}
|
|
345
402
|
</MastheadContent>
|
|
@@ -360,7 +417,7 @@ export const SideNavLayout = ({ children, groupedRoutes, navOpen: navOpenProp })
|
|
|
360
417
|
defaultManagedSidebarIsOpen={navOpenProp}
|
|
361
418
|
>
|
|
362
419
|
{children}
|
|
363
|
-
{process.env.hasFooter && <Footer isDarkTheme={
|
|
420
|
+
{process.env.hasFooter && <Footer isDarkTheme={resolvedTheme === 'dark'} />}
|
|
364
421
|
</Page>
|
|
365
422
|
<div id="ws-page-banners">{hasGdprBanner && <GdprBanner />}</div>
|
|
366
423
|
</RtlContext.Provider>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/documentation-framework",
|
|
3
3
|
"description": "A framework to build documentation for PatternFly.",
|
|
4
|
-
"version": "6.
|
|
4
|
+
"version": "6.11.0",
|
|
5
5
|
"author": "Red Hat",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"@babel/preset-env": "^7.24.3",
|
|
13
13
|
"@babel/preset-react": "^7.24.1",
|
|
14
14
|
"@mdx-js/util": "1.6.16",
|
|
15
|
-
"@patternfly/ast-helpers": "^1.4.0-alpha.
|
|
15
|
+
"@patternfly/ast-helpers": "^1.4.0-alpha.220",
|
|
16
16
|
"@reach/router": "npm:@gatsbyjs/reach-router@1.3.9",
|
|
17
17
|
"autoprefixer": "9.8.6",
|
|
18
18
|
"babel-loader": "^9.1.3",
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"react": "^17.0.0 || ^18.0.0",
|
|
80
80
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "3481a949f8c8f17ed8d74faba651b339acae54df"
|
|
83
83
|
}
|