Skip to content

Commit 1a61a2e

Browse files
authored
Merge pull request #4863 from Blargian/fix_on_enter
Bug fix: wrong link when pressing enter
2 parents cd66703 + 7e44437 commit 1a61a2e

File tree

3 files changed

+177
-67
lines changed

3 files changed

+177
-67
lines changed

src/theme/SearchBar/index.js

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import {
99
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
1010
import { createPortal } from 'react-dom';
1111
import translations from '@theme/SearchTranslations';
12-
import {useAskAI} from '@site/src/hooks/useAskAI'
12+
import { useAskAI } from '@site/src/hooks/useAskAI'
1313
import { shouldPreventSearchAction, handleSearchKeyboardConflict } from './utils/aiConflictHandler';
1414
import { initializeSearchAnalytics, createEnhancedSearchClient } from './utils/searchAnalytics';
1515
import { useDocSearchModal } from './utils/useDocSearchModal';
16-
import {
17-
createSearchParameters,
18-
createSearchNavigator,
19-
transformSearchItems
16+
import {
17+
createSearchParameters,
18+
createSearchNavigator,
19+
transformSearchItems
2020
} from './utils/searchConfig';
2121
import { SearchHit } from './searchHit';
2222
import { SearchResultsFooter } from './searchResultsFooter';
@@ -31,10 +31,10 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) {
3131
const { isAskAIOpen } = useAskAI();
3232
const history = useHistory();
3333
const searchButtonRef = useRef(null);
34-
34+
3535
const [selectedDocTypes, setSelectedDocTypes] = useState(null);
3636
const searchParametersRef = useRef(null);
37-
37+
3838
const {
3939
isOpen,
4040
initialQuery,
@@ -49,12 +49,12 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) {
4949
// Update searchParameters ref instead of creating new object
5050
useEffect(() => {
5151
const newParams = createSearchParameters(
52-
props,
53-
contextualSearch,
52+
props,
53+
contextualSearch,
5454
contextualSearchFacetFilters,
5555
selectedDocTypes
5656
);
57-
57+
5858
if (!searchParametersRef.current) {
5959
searchParametersRef.current = newParams;
6060
} else {
@@ -67,8 +67,8 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) {
6767
// Initialize on mount
6868
if (!searchParametersRef.current) {
6969
searchParametersRef.current = createSearchParameters(
70-
props,
71-
contextualSearch,
70+
props,
71+
contextualSearch,
7272
contextualSearchFacetFilters,
7373
selectedDocTypes
7474
);
@@ -77,14 +77,14 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) {
7777
// Track input changes to capture the query
7878
useEffect(() => {
7979
if (!isOpen) return;
80-
80+
8181
const handleInput = (e) => {
8282
const input = e.target;
8383
if (input.classList.contains('DocSearch-Input')) {
8484
lastQueryRef.current = input.value;
8585
}
8686
};
87-
87+
8888
document.addEventListener('input', handleInput, true);
8989
return () => document.removeEventListener('input', handleInput, true);
9090
}, [isOpen]);
@@ -94,15 +94,15 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) {
9494
}, [props.appId, props.apiKey]);
9595

9696
const navigator = useMemo(
97-
() => createSearchNavigator(history, externalUrlRegex),
98-
[history, externalUrlRegex]
97+
() => createSearchNavigator(history, externalUrlRegex, currentLocale),
98+
[history, externalUrlRegex, currentLocale]
9999
);
100100

101101
const transformItems = useCallback((items, state) => {
102102
if (state?.query) {
103103
lastQueryRef.current = state.query;
104104
}
105-
105+
106106
return transformSearchItems(items, {
107107
transformItems: props.transformItems,
108108
processSearchResultUrl,
@@ -111,34 +111,34 @@ function DocSearch({ contextualSearch, externalUrlRegex, ...props }) {
111111
});
112112
}, [props.transformItems, processSearchResultUrl, currentLocale]);
113113

114-
const handleDocTypeChange = useCallback((docTypes) => {
115-
setSelectedDocTypes(docTypes);
116-
117-
// Re-trigger search with updated filters after state update completes
118-
setTimeout(() => {
119-
const input = document.querySelector('.DocSearch-Input');
120-
const query = lastQueryRef.current;
121-
122-
if (input && query) {
123-
// Access React's internal value setter to bypass readonly property
124-
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
125-
window.HTMLInputElement.prototype,
126-
'value'
127-
).set;
128-
129-
// Clear input to trigger change detection
130-
nativeInputValueSetter.call(input, '');
131-
input.dispatchEvent(new Event('input', { bubbles: true }));
132-
133-
// Restore original query to execute search with new filters
134-
setTimeout(() => {
135-
nativeInputValueSetter.call(input, query);
114+
const handleDocTypeChange = useCallback((docTypes) => {
115+
setSelectedDocTypes(docTypes);
116+
117+
// Re-trigger search with updated filters after state update completes
118+
setTimeout(() => {
119+
const input = document.querySelector('.DocSearch-Input');
120+
const query = lastQueryRef.current;
121+
122+
if (input && query) {
123+
// Access React's internal value setter to bypass readonly property
124+
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
125+
window.HTMLInputElement.prototype,
126+
'value'
127+
).set;
128+
129+
// Clear input to trigger change detection
130+
nativeInputValueSetter.call(input, '');
136131
input.dispatchEvent(new Event('input', { bubbles: true }));
137-
input.focus();
138-
}, 0);
139-
}
140-
}, 100);
141-
}, []);
132+
133+
// Restore original query to execute search with new filters
134+
setTimeout(() => {
135+
nativeInputValueSetter.call(input, query);
136+
input.dispatchEvent(new Event('input', { bubbles: true }));
137+
input.focus();
138+
}, 0);
139+
}
140+
}, 100);
141+
}, []);
142142

143143
const resultsFooterComponent = useMemo(
144144
() => (footerProps) => <SearchResultsFooter {...footerProps} onClose={onClose} />,
@@ -147,13 +147,13 @@ const handleDocTypeChange = useCallback((docTypes) => {
147147

148148
const transformSearchClient = useCallback((searchClient) => {
149149
const enhancedClient = createEnhancedSearchClient(
150-
searchClient,
151-
siteMetadata.docusaurusVersion,
150+
searchClient,
151+
siteMetadata.docusaurusVersion,
152152
queryIDRef
153153
);
154-
154+
155155
const originalSearch = enhancedClient.search.bind(enhancedClient);
156-
156+
157157
let debounceTimeout;
158158
enhancedClient.search = (...args) => {
159159
return new Promise((resolve, reject) => {
@@ -165,7 +165,7 @@ const handleDocTypeChange = useCallback((docTypes) => {
165165
}, 200);
166166
});
167167
};
168-
168+
169169
return enhancedClient;
170170
}, [siteMetadata.docusaurusVersion]);
171171

@@ -190,7 +190,7 @@ const handleDocTypeChange = useCallback((docTypes) => {
190190
onInput: handleOnInput,
191191
searchButtonRef,
192192
});
193-
193+
194194
return (
195195
<>
196196
<Head>
@@ -214,7 +214,7 @@ const handleDocTypeChange = useCallback((docTypes) => {
214214
DocSearchModal &&
215215
searchContainer &&
216216
createPortal(
217-
<>
217+
<>
218218
<DocSearchModal
219219
onClose={onClose}
220220
initialScrollY={window.scrollY}
@@ -232,7 +232,7 @@ const handleDocTypeChange = useCallback((docTypes) => {
232232
placeholder={translations.placeholder}
233233
translations={translations.modal}
234234
/>
235-
235+
236236
<div style={{
237237
position: 'fixed',
238238
top: window.innerWidth < 768 ? '55px' : '120px',
@@ -241,7 +241,7 @@ const handleDocTypeChange = useCallback((docTypes) => {
241241
backgroundColor: 'var(--docsearch-modal-background)',
242242
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
243243
}}>
244-
<DocTypeSelector
244+
<DocTypeSelector
245245
selectedDocTypes={selectedDocTypes}
246246
onSelectionChange={handleDocTypeChange}
247247
/>

src/theme/SearchBar/searchHit.jsx

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,85 @@
11
import Link from '@docusaurus/Link';
22
import { trackSearchResultClick } from './utils/searchAnalytics';
3+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
34

45
export function SearchHit({ hit, children }) {
6+
const { i18n: { currentLocale } } = useDocusaurusContext();
57
const handleClick = () => trackSearchResultClick(hit);
6-
8+
9+
// Transform the URL to ensure it's correct
10+
// This is a safety measure in case transformSearchItems doesn't work
11+
let transformedUrl = hit.url;
12+
13+
try {
14+
let pathname, hash;
15+
16+
// If it's an absolute URL, extract pathname and hash
17+
if (hit.url.startsWith('http://') || hit.url.startsWith('https://')) {
18+
const urlObj = new URL(hit.url);
19+
pathname = urlObj.pathname;
20+
hash = urlObj.hash;
21+
} else {
22+
// It's already a relative URL, split pathname and hash
23+
const hashIndex = hit.url.indexOf('#');
24+
if (hashIndex !== -1) {
25+
pathname = hit.url.substring(0, hashIndex);
26+
hash = hit.url.substring(hashIndex);
27+
} else {
28+
pathname = hit.url;
29+
hash = '';
30+
}
31+
}
32+
33+
// Now transform the pathname
34+
if (currentLocale !== 'en') {
35+
const prefix = `/docs/${currentLocale}`;
36+
if (pathname.startsWith(prefix)) {
37+
transformedUrl = pathname.substring(prefix.length) || '/';
38+
} else {
39+
transformedUrl = pathname;
40+
}
41+
} else {
42+
const prefix = '/docs';
43+
if (pathname.startsWith(prefix)) {
44+
transformedUrl = pathname.substring(prefix.length) || '/';
45+
} else {
46+
transformedUrl = pathname;
47+
}
48+
}
49+
50+
transformedUrl += hash;
51+
} catch (e) {
52+
// If transformation fails, use original URL
53+
}
54+
755
// Extract multiple URL segments after /docs/ and clean them up
856
const segments = hit.url.split('/docs/')[1]?.split('/').filter(Boolean) || [];
957
const breadcrumbs = segments
1058
.slice(0, 3) // Take first 3 segments max
1159
.map(segment => segment.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()));
12-
60+
1361
// Format doc_type for display, stripping quotes and formatting
1462
const formatDocType = (docType) => {
1563
if (!docType) return null;
1664
// Remove surrounding quotes and format
1765
const cleaned = docType.replace(/^'|'$/g, '');
1866
return cleaned.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
1967
};
20-
68+
2169
const docTypeDisplay = formatDocType(hit.doc_type);
22-
70+
2371
return (
24-
<Link onClick={handleClick} to={hit.url}>
72+
<Link onClick={handleClick} to={transformedUrl}>
2573
{children}
26-
<div style={{
27-
fontSize: '10px',
74+
<div style={{
75+
fontSize: '10px',
2876
color: '#888',
2977
lineHeight: '1',
3078
marginBottom: '12px'
3179
}}>
3280
{/* Doc type badge */}
3381
{docTypeDisplay && (
34-
<span style={{
82+
<span style={{
3583
backgroundColor: '#f3f4f6',
3684
color: '#374151',
3785
padding: '2px 6px',
@@ -42,7 +90,7 @@ export function SearchHit({ hit, children }) {
4290
{docTypeDisplay}
4391
</span>
4492
)}
45-
93+
4694
{/* Breadcrumbs */}
4795
{breadcrumbs.length > 0 && (
4896
<span>{breadcrumbs.join(' › ')}</span>

0 commit comments

Comments
 (0)