@rspress-theme-anatole/theme-default 0.7.55 → 0.7.57

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.
Files changed (2) hide show
  1. package/dist/bundle.js +211 -89
  2. package/package.json +3 -3
package/dist/bundle.js CHANGED
@@ -324,6 +324,7 @@ function useLocaleSiteData() {
324
324
  nextPageText: themeConfig.nextPageText,
325
325
  sourceCodeText: themeConfig.sourceCodeText,
326
326
  searchPlaceholderText: themeConfig.searchPlaceholderText,
327
+ searchDidYouMeanText: themeConfig.searchDidYouMeanText,
327
328
  searchNoResultsText: themeConfig.searchNoResultsText,
328
329
  searchSuggestedQueryText: themeConfig.searchSuggestedQueryText,
329
330
  overview: themeConfig.overview
@@ -412,6 +413,13 @@ function markLockedSidebarItems(items, userContext) {
412
413
  if ('items' in item && Array.isArray(item.items)) {
413
414
  const markedItems = markLockedSidebarItems(item.items, userContext);
414
415
  nextItem = { ...nextItem, items: markedItems };
416
+ // If group has no direct lock but all navigable children are locked, propagate lock upward
417
+ if (!locked && !nextItem.locked && 'items' in nextItem && nextItem.items.length > 0) {
418
+ const navigableChildren = nextItem.items.filter(child => child && !('dividerType' in child));
419
+ if (navigableChildren.length > 0 && navigableChildren.every(child => child.locked === true)) {
420
+ nextItem = { ...nextItem, locked: true };
421
+ }
422
+ }
415
423
  }
416
424
  return nextItem;
417
425
  }).filter(Boolean);
@@ -6576,11 +6584,37 @@ function SuggestItem({ suggestion, query, closeSearch, isCurrent, setCurrentSugg
6576
6584
  });
6577
6585
  };
6578
6586
 
6587
+ const SUGGESTION_PREFIX_TOKEN = '__KB_SUGGESTION__';
6588
+ const SUGGESTION_SUFFIX_TOKEN = '__KB_SUGGESTION_END__';
6589
+ const parseGatewaySuggestion = (statement) => {
6590
+ if (!statement || 'string' != typeof statement) return {
6591
+ suggestionText: '',
6592
+ statementText: statement || ''
6593
+ };
6594
+ const prefixIndex = statement.indexOf(SUGGESTION_PREFIX_TOKEN);
6595
+ if (prefixIndex < 0) return {
6596
+ suggestionText: '',
6597
+ statementText: statement
6598
+ };
6599
+ const contentStart = prefixIndex + SUGGESTION_PREFIX_TOKEN.length;
6600
+ const suffixIndex = statement.indexOf(SUGGESTION_SUFFIX_TOKEN, contentStart);
6601
+ if (suffixIndex < 0) return {
6602
+ suggestionText: '',
6603
+ statementText: statement
6604
+ };
6605
+ const suggestionText = statement.slice(contentStart, suffixIndex).trim();
6606
+ const statementText = (statement.slice(0, prefixIndex) + ' ' + statement.slice(suffixIndex + SUGGESTION_SUFFIX_TOKEN.length)).trim();
6607
+ return {
6608
+ suggestionText,
6609
+ statementText
6610
+ };
6611
+ };
6579
6612
  const renderStatementMatch = () => {
6580
6613
  if ('content' !== suggestion.type) return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {});
6614
+ const parsed = parseGatewaySuggestion(suggestion.statement || '');
6581
6615
  return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
6582
6616
  className: "text-sm text-gray-light w-full",
6583
- children: getHighlightedFragments(suggestion.statement)
6617
+ children: getHighlightedFragments(parsed.statementText || suggestion.statement || '')
6584
6618
  });
6585
6619
  };
6586
6620
  const renderLink = () => {
@@ -6591,26 +6625,85 @@ function SuggestItem({ suggestion, query, closeSearch, isCurrent, setCurrentSugg
6591
6625
  children: cleanDisplayLink
6592
6626
  });
6593
6627
  };
6594
- let hitContent = null;
6595
- switch (suggestion.type) {
6596
- case 'title':
6597
- case 'header':
6598
- hitContent = renderHeaderMatch();
6599
- break;
6600
- case 'content':
6601
- hitContent = (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.Fragment, {
6602
- children: [
6603
- renderStatementMatch(),
6604
- (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("p", {
6605
- className: Search_index_module.titleForContent,
6606
- children: suggestion.title
6607
- })
6608
- ]
6609
- });
6610
- break;
6611
- default:
6612
- break;
6613
- }
6628
+ const BREADCRUMB_SKIPPED_SEGMENTS = new Set([
6629
+ 'en',
6630
+ 'ja',
6631
+ 'product-page',
6632
+ 'solution-pages',
6633
+ 'index',
6634
+ 'index.html'
6635
+ ]);
6636
+ const formatBreadcrumbLabel = (segment) => {
6637
+ if (!segment) return '';
6638
+ const raw = decodeURIComponent(segment).replace(/\.html$/i, '').trim();
6639
+ if (!raw) return '';
6640
+ const normalized = raw.toLowerCase();
6641
+ if (BREADCRUMB_SKIPPED_SEGMENTS.has(normalized)) return '';
6642
+ if ('iaas-paas' === normalized) return 'IAAS & PAAS';
6643
+ const words = raw.split(/[-_]+/).filter(Boolean);
6644
+ const acronyms = new Set([
6645
+ 'iaas',
6646
+ 'paas',
6647
+ 'api',
6648
+ 'sql',
6649
+ 'vm',
6650
+ 'sso',
6651
+ 'kb',
6652
+ 'aws',
6653
+ 'gcp'
6654
+ ]);
6655
+ const lowerCaseWords = new Set([
6656
+ 'a',
6657
+ 'an',
6658
+ 'and',
6659
+ 'as',
6660
+ 'at',
6661
+ 'by',
6662
+ 'for',
6663
+ 'from',
6664
+ 'in',
6665
+ 'of',
6666
+ 'on',
6667
+ 'or',
6668
+ 'the',
6669
+ 'to',
6670
+ 'via',
6671
+ 'with'
6672
+ ]);
6673
+ return words.map((word, index) => {
6674
+ const lower = word.toLowerCase();
6675
+ if (acronyms.has(lower)) return lower.toUpperCase();
6676
+ if (/^[a-z]+\d+$/i.test(word)) {
6677
+ return lower.charAt(0).toUpperCase() + lower.slice(1);
6678
+ }
6679
+ if (index > 0 && lowerCaseWords.has(lower)) return lower;
6680
+ return lower.charAt(0).toUpperCase() + lower.slice(1);
6681
+ }).join(' ');
6682
+ };
6683
+ const buildBreadcrumbFromLink = () => {
6684
+ const stripHtmlSuffix = (value) => 'string' == typeof value ? value.replace(/\.html(?=$|[?#\s])/gi, '').replace(/\?/g, '').trim() : value;
6685
+ const displayLink = removeDomain(suggestion.link || '');
6686
+ if (!displayLink) return '';
6687
+ const sanitized = displayLink.replace(/([?&])kb_highlight=[^&#]*/g, '$1').replace(/[?&]$/, '');
6688
+ const [pathWithQuery, hashPartRaw] = sanitized.split('#');
6689
+ const pathPart = pathWithQuery.split('?')[0];
6690
+ const pathSegments = pathPart.split('/').filter(Boolean).map(formatBreadcrumbLabel).filter(Boolean);
6691
+ let hashPart = hashPartRaw ? stripHtmlSuffix(formatBreadcrumbLabel(hashPartRaw)) : '';
6692
+ if (hashPartRaw && suggestion.header) {
6693
+ hashPart = stripHtmlSuffix(suggestion.header);
6694
+ }
6695
+ const parts = hashPart ? [...pathSegments, hashPart] : pathSegments;
6696
+ return parts.map(stripHtmlSuffix).join(' > ');
6697
+ };
6698
+ const hitContent = (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.Fragment, {
6699
+ children: [
6700
+ renderStatementMatch(),
6701
+ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("p", {
6702
+ className: Search_index_module.titleForContent,
6703
+ children: buildBreadcrumbFromLink()
6704
+ })
6705
+ ]
6706
+ });
6614
6707
  return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("li", {
6615
6708
  className: `rspress-search-suggest-item ${Search_index_module.suggestItem} ${isCurrent ? Search_index_module.current : ''}`,
6616
6709
  onMouseEnter: setCurrentSuggestionIndex,
@@ -6638,7 +6731,7 @@ function SuggestItem({ suggestion, query, closeSearch, isCurrent, setCurrentSugg
6638
6731
  (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("span", {
6639
6732
  children: hitContent
6640
6733
  }),
6641
- renderLink()
6734
+ // renderLink()
6642
6735
  ]
6643
6736
  }),
6644
6737
  (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
@@ -6663,7 +6756,10 @@ const SEARCH_PREWARM_EVENT = 'rspress-search-prewarm';
6663
6756
  const useDebounce = (cb) => {
6664
6757
  const cbRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(cb);
6665
6758
  cbRef.current = cb;
6666
- const debounced = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((0, __WEBPACK_EXTERNAL_MODULE_lodash_es_18c59938__.debounce)((...args) => cbRef.current(...args), 150), []);
6759
+ // 300ms debounce: only fire after the user stops typing for 300ms.
6760
+ const debounced = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((0, __WEBPACK_EXTERNAL_MODULE_lodash_es_18c59938__.debounce)((...args) => cbRef.current(...args), 300), []);
6761
+ // Cancel any pending debounced call on unmount to prevent stale gateway requests.
6762
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(() => () => debounced.cancel(), [debounced]);
6667
6763
  return debounced;
6668
6764
  };
6669
6765
  function SearchPanel({ focused, setFocused }) {
@@ -6698,7 +6794,7 @@ function SearchPanel({ focused, setFocused }) {
6698
6794
  }
6699
6795
  };
6700
6796
  const { siteData, page: { lang, version, frontmatter, routePath } } = (0, __WEBPACK_EXTERNAL_MODULE__rspress_runtime_0abd3046__.usePageData)();
6701
- const { searchPlaceholderText = 'Search Docs', scopedSearchPrefixText = 'Search in', searchingText = 'Searching...' } = useLocaleSiteData();
6797
+ const { searchPlaceholderText = 'Search Docs', searchDidYouMeanText = 'Did you mean', scopedSearchPrefixText = 'Search in', searchingText = 'Searching...' } = useLocaleSiteData();
6702
6798
  const { search, title: siteTitle, base } = siteData;
6703
6799
  const versionedSearch = search && 'remote' !== search.mode && search.versioned;
6704
6800
  const DEFAULT_RESULT = [
@@ -6922,37 +7018,16 @@ function SearchPanel({ focused, setFocused }) {
6922
7018
  ]);
6923
7019
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(() => {
6924
7020
  if (focused) {
7021
+ // typesense-only focus flow: opening search must not initialize the browser search index.
7022
+ // typesense-only result visibility: mark search ready without PageSearcher init.
7023
+ setInitStatus('inited');
6925
7024
  setSearchResult(DEFAULT_RESULT);
6926
- initSearch();
6927
7025
  } else setQuery('');
6928
7026
  }, [
6929
7027
  focused
6930
7028
  ]);
6931
7029
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(() => {
6932
- if ('undefined' === typeof window) return;
6933
- let idleCallbackId;
6934
- const prewarm = () => {
6935
- ensureSearcherReady().catch(() => {});
6936
- };
6937
- const onPrewarm = () => {
6938
- prewarm();
6939
- };
6940
- window.addEventListener(SEARCH_PREWARM_EVENT, onPrewarm);
6941
- if (!pageSearcherRef.current) {
6942
- if ('requestIdleCallback' in window) idleCallbackId = window.requestIdleCallback(() => {
6943
- prewarm();
6944
- });
6945
- else idleCallbackId = window.setTimeout(() => {
6946
- prewarm();
6947
- }, 300);
6948
- }
6949
- return () => {
6950
- window.removeEventListener(SEARCH_PREWARM_EVENT, onPrewarm);
6951
- if (void 0 !== idleCallbackId) {
6952
- if ('cancelIdleCallback' in window) window.cancelIdleCallback(idleCallbackId);
6953
- else window.clearTimeout(idleCallbackId);
6954
- }
6955
- };
7030
+ // typesense-only prewarm removal: Gateway search does not use PageSearcher indexes.
6956
7031
  }, []);
6957
7032
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(() => {
6958
7033
  if (!pageSearcherConfigRef.current) return;
@@ -7115,12 +7190,7 @@ function SearchPanel({ focused, setFocused }) {
7115
7190
 
7116
7191
  if (defaultSearchResult) localResult.push(...defaultSearchResult);
7117
7192
 
7118
- // Re-run onSearch/afterSearch với local result
7119
- if ('onSearch' in __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__) {
7120
- const key = 'onSearch';
7121
- await __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__[key](newQuery, localResult, searchScope);
7122
- }
7123
-
7193
+ // Keep a single onSearch invocation per debounced query.
7124
7194
  if ('afterSearch' in __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__) {
7125
7195
  const key = 'afterSearch';
7126
7196
  await __WEBPACK_EXTERNAL_MODULE_virtual_search_hooks_9d01d01f__[key](newQuery, localResult);
@@ -7172,6 +7242,44 @@ function SearchPanel({ focused, setFocused }) {
7172
7242
  }, item.group))
7173
7243
  });
7174
7244
  };
7245
+ const SUGGESTION_PREFIX_TOKEN = '__KB_SUGGESTION__';
7246
+ const SUGGESTION_SUFFIX_TOKEN = '__KB_SUGGESTION_END__';
7247
+ const parseGatewaySuggestion = (statement) => {
7248
+ if (!statement || 'string' != typeof statement) return {
7249
+ suggestionText: '',
7250
+ statementText: statement || ''
7251
+ };
7252
+ const prefixIndex = statement.indexOf(SUGGESTION_PREFIX_TOKEN);
7253
+ if (prefixIndex < 0) return {
7254
+ suggestionText: '',
7255
+ statementText: statement
7256
+ };
7257
+ const contentStart = prefixIndex + SUGGESTION_PREFIX_TOKEN.length;
7258
+ const suffixIndex = statement.indexOf(SUGGESTION_SUFFIX_TOKEN, contentStart);
7259
+ if (suffixIndex < 0) return {
7260
+ suggestionText: '',
7261
+ statementText: statement
7262
+ };
7263
+ const suggestionText = statement.slice(contentStart, suffixIndex).trim();
7264
+ const statementText = (statement.slice(0, prefixIndex) + ' ' + statement.slice(suffixIndex + SUGGESTION_SUFFIX_TOKEN.length)).trim();
7265
+ return {
7266
+ suggestionText,
7267
+ statementText
7268
+ };
7269
+ };
7270
+ const extractSuggestionText = (suggestions) => {
7271
+ for (const item of suggestions || []) {
7272
+ if ('content' !== item?.type) continue;
7273
+ const parsed = parseGatewaySuggestion(item.statement || '');
7274
+ if (parsed.suggestionText) return parsed.suggestionText;
7275
+ }
7276
+ return '';
7277
+ };
7278
+ const getGatewaySuggestionText = () => {
7279
+ if ('undefined' == typeof window) return '';
7280
+ const suggestion = window.__KB_GATEWAY_SUGGESTION__;
7281
+ return 'string' == typeof suggestion ? suggestion.trim() : '';
7282
+ };
7175
7283
  const renderSearchResultItem = (suggestionList, query, isSearching) => {
7176
7284
  if (isSearching) return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
7177
7285
  className: "flex flex-col items-center",
@@ -7189,43 +7297,57 @@ function SearchPanel({ focused, setFocused }) {
7189
7297
  if (0 === suggestionList.length && 'inited' === initStatus) return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(NoSearchResult, {
7190
7298
  query: query
7191
7299
  });
7300
+ const suggestionText = getGatewaySuggestionText();
7192
7301
  const normalizedSuggestions = normalizeSuggestions(suggestionList);
7193
7302
  let accumulateIndex = -1;
7194
- return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("ul", {
7195
- className: Search_index_module.suggestList,
7196
- children: Object.keys(normalizedSuggestions).map((group) => {
7197
- const groupSuggestions = normalizedSuggestions[group] || [];
7198
- return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("li", {
7199
- children: (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("ul", {
7200
- // className: "pb-2",
7201
- children: groupSuggestions.map((suggestion) => {
7202
- accumulateIndex++;
7203
- const suggestionIndex = accumulateIndex;
7204
- return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(SuggestItem, {
7205
- suggestion: suggestion,
7206
- query: query,
7207
- isCurrent: suggestionIndex === currentSuggestionIndex,
7208
- setCurrentSuggestionIndex: (event) => {
7209
- if (mousePositionRef.current.pageX === event.pageX && mousePositionRef.current.pageY === event.pageY) return;
7210
- setCanScroll(false);
7211
- setCurrentSuggestionIndex(suggestionIndex);
7212
- },
7213
- onMouseMove: (event) => {
7214
- mousePositionRef.current = {
7215
- pageX: event.pageX,
7216
- pageY: event.pageY
7217
- };
7218
- },
7219
- closeSearch: () => {
7220
- clearSearchState();
7221
- },
7222
- inCurrentDocIndex: 0 === resultTabIndex,
7223
- scrollTo: scrollTo
7224
- }, `${suggestion.title}-${suggestionIndex}`);
7225
- })
7303
+ return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.Fragment, {
7304
+ children: [
7305
+ suggestionText ? (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("p", {
7306
+ className: "kb-search-suggestion-banner",
7307
+ children: [
7308
+ searchDidYouMeanText,
7309
+ " \"",
7310
+ suggestionText,
7311
+ "\"?"
7312
+ ]
7313
+ }) : null,
7314
+ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("ul", {
7315
+ className: Search_index_module.suggestList,
7316
+ children: Object.keys(normalizedSuggestions).map((group) => {
7317
+ const groupSuggestions = normalizedSuggestions[group] || [];
7318
+ return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("li", {
7319
+ children: (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("ul", {
7320
+ // className: "pb-2",
7321
+ children: groupSuggestions.map((suggestion) => {
7322
+ accumulateIndex++;
7323
+ const suggestionIndex = accumulateIndex;
7324
+ return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(SuggestItem, {
7325
+ suggestion: suggestion,
7326
+ query: query,
7327
+ isCurrent: suggestionIndex === currentSuggestionIndex,
7328
+ setCurrentSuggestionIndex: (event) => {
7329
+ if (mousePositionRef.current.pageX === event.pageX && mousePositionRef.current.pageY === event.pageY) return;
7330
+ setCanScroll(false);
7331
+ setCurrentSuggestionIndex(suggestionIndex);
7332
+ },
7333
+ onMouseMove: (event) => {
7334
+ mousePositionRef.current = {
7335
+ pageX: event.pageX,
7336
+ pageY: event.pageY
7337
+ };
7338
+ },
7339
+ closeSearch: () => {
7340
+ clearSearchState();
7341
+ },
7342
+ inCurrentDocIndex: 0 === resultTabIndex,
7343
+ scrollTo: scrollTo
7344
+ }, `${suggestion.title}-${suggestionIndex}`);
7345
+ })
7346
+ })
7347
+ }, group);
7226
7348
  })
7227
- }, group);
7228
- })
7349
+ })
7350
+ ]
7229
7351
  });
7230
7352
  };
7231
7353
  const getScopedPlaceholder = () => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rspress-theme-anatole/theme-default",
3
3
  "author": "Anatole Tong",
4
- "version": "0.7.55",
4
+ "version": "0.7.57",
5
5
  "license": "MIT",
6
6
  "sideEffects": [
7
7
  "*.css",
@@ -21,8 +21,8 @@
21
21
  "types": "./dist/bundle.d.ts",
22
22
  "dependencies": {
23
23
  "@mdx-js/react": "2.3.0",
24
- "@rspress-theme-anatole/rspress-plugin-mermaid": "0.7.55",
25
- "@rspress-theme-anatole/shared": "0.7.55",
24
+ "@rspress-theme-anatole/rspress-plugin-mermaid": "0.7.57",
25
+ "@rspress-theme-anatole/shared": "0.7.57",
26
26
  "@rspress/runtime": "1.43.8",
27
27
  "body-scroll-lock": "4.0.0-beta.0",
28
28
  "copy-to-clipboard": "^3.3.3",