@rspress-theme-anatole/theme-default 0.7.16 → 0.7.17

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 +182 -4
  2. package/package.json +3 -3
package/dist/bundle.js CHANGED
@@ -5738,9 +5738,9 @@ function SearchPanel({ focused, setFocused }) {
5738
5738
  });
5739
5739
  }
5740
5740
  };
5741
- const { siteData, page: { lang, version } } = (0, __WEBPACK_EXTERNAL_MODULE__rspress_runtime_0abd3046__.usePageData)();
5741
+ const { siteData, page: { lang, version, frontmatter, routePath } } = (0, __WEBPACK_EXTERNAL_MODULE__rspress_runtime_0abd3046__.usePageData)();
5742
5742
  const { searchPlaceholderText = 'Search Docs' } = useLocaleSiteData();
5743
- const { search, title: siteTitle } = siteData;
5743
+ const { search, title: siteTitle, base } = siteData;
5744
5744
  const versionedSearch = search && 'remote' !== search.mode && search.versioned;
5745
5745
  const DEFAULT_RESULT = [
5746
5746
  {
@@ -5752,6 +5752,100 @@ function SearchPanel({ focused, setFocused }) {
5752
5752
  const currentSuggestions = searchResult[resultTabIndex]?.result ?? [];
5753
5753
  const currentRenderType = searchResult[resultTabIndex]?.renderType ?? types_RenderType.Default;
5754
5754
  if (false === search) return null;
5755
+ // Extract related products from frontmatter for solution pages
5756
+ const getRelatedProductsFromFrontmatter = (frontmatter) => {
5757
+ if (!frontmatter?.features?.rows) return [];
5758
+
5759
+ const products = [];
5760
+
5761
+ // Loop through all rows and items in features
5762
+ frontmatter.features.rows.forEach(row => {
5763
+ if (row.items) {
5764
+ row.items.forEach(item => {
5765
+ if (item.link) {
5766
+ // Extract product name from link
5767
+ const linkPath = item.link
5768
+ .replace(/^\.\.\//, '') // Remove ../
5769
+ .replace(/^\.\//, ''); // Remove ./
5770
+
5771
+ const productName = linkPath.split('/')[0];
5772
+
5773
+ if (productName && !products.includes(productName)) {
5774
+ products.push(productName);
5775
+ }
5776
+ }
5777
+ });
5778
+ }
5779
+ });
5780
+
5781
+ return products;
5782
+ };
5783
+ // Calculate search scope
5784
+ const searchScope = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(() => {
5785
+ if (typeof window === 'undefined') return null;
5786
+
5787
+ const pathname = window.location.pathname;
5788
+ const pathParts = pathname.split('/').filter(Boolean);
5789
+
5790
+ // Get language settings from site config
5791
+ const localeLanguages = Object.values(siteData?.themeConfig?.locales || {});
5792
+ const langArr = localeLanguages.map((item) => item.lang) || [];
5793
+
5794
+ let startIndex = 0;
5795
+
5796
+ // Skip base path if present
5797
+ const baseTrimmed = (base || '').replace(/^\/|\/$/g, '');
5798
+ if (baseTrimmed && pathParts[startIndex] === baseTrimmed) {
5799
+ startIndex++;
5800
+ }
5801
+
5802
+ // Skip language prefix if present (e.g., /en/, /vn/, /zh/)
5803
+ if (langArr.includes(pathParts[startIndex])) {
5804
+ startIndex++;
5805
+ }
5806
+
5807
+ const firstSegment = pathParts[startIndex] || null;
5808
+ const secondSegment = pathParts[startIndex + 1] || null;
5809
+
5810
+ // Check if this is a solution page (contains 'solution-pages' in path)
5811
+ if (firstSegment === 'solution-pages') {
5812
+ const solutionFile = secondSegment || '';
5813
+ const solutionName = solutionFile.replace(/\.html$/, '');
5814
+
5815
+ // Get related products from frontmatter
5816
+ const relatedProducts = getRelatedProductsFromFrontmatter(frontmatter);
5817
+
5818
+ return {
5819
+ scopeType: 'solution',
5820
+ solutionName: solutionName,
5821
+ relatedProducts: relatedProducts,
5822
+ scopePath: null
5823
+ };
5824
+ }
5825
+
5826
+ // Product page: /m365/... or /d365/...
5827
+ const productName = firstSegment;
5828
+
5829
+ // Exclude common non-product paths
5830
+ const excludedPaths = ['index.html', 'index', 'what-is-coming-in-cloud', 'what-is-coming-in-cloud.html', 'solution-pages'];
5831
+
5832
+ if (productName && !excludedPaths.includes(productName)) {
5833
+
5834
+ return {
5835
+ scopeType: 'product',
5836
+ productName: productName,
5837
+ scopePath: `/${productName}`,
5838
+ relatedProducts: null
5839
+ };
5840
+ }
5841
+
5842
+ // No specific scope (homepage or other pages)
5843
+ return {
5844
+ scopeType: null,
5845
+ scopePath: null,
5846
+ relatedProducts: null
5847
+ };
5848
+ }, [focused, siteData, base, frontmatter]);
5755
5849
  const createSearcher = () => {
5756
5850
  if (pageSearcherRef.current) return pageSearcherRef.current;
5757
5851
  const pageSearcherConfig = {
@@ -5876,6 +5970,69 @@ function SearchPanel({ focused, setFocused }) {
5876
5970
  version,
5877
5971
  versionedSearch
5878
5972
  ]);
5973
+ const filterResultsByScope = (results, scope, basePath, currentLang) => {
5974
+ if (!scope || !scope.scopeType) {
5975
+ return results;
5976
+ }
5977
+
5978
+ return results.map(resultGroup => {
5979
+ const filteredResult = resultGroup.result.filter(item => {
5980
+ // Get the link path without domain
5981
+ const linkPath = removeDomain(item.link);
5982
+
5983
+ // Remove base path for comparison
5984
+ const baseTrimmed = (basePath || '').replace(/^\/|\/$/g, '');
5985
+ let cleanPath = linkPath;
5986
+ if (baseTrimmed) {
5987
+ cleanPath = cleanPath.replace(new RegExp(`^/?${baseTrimmed}/?`), '/');
5988
+ }
5989
+
5990
+ // Ensure leading slash
5991
+ if (!cleanPath.startsWith('/')) {
5992
+ cleanPath = `/${cleanPath}`;
5993
+ }
5994
+
5995
+ // Remove language prefix if present
5996
+ if (currentLang) {
5997
+ cleanPath = cleanPath.replace(new RegExp(`^/${currentLang}/`), '/');
5998
+ }
5999
+
6000
+ if (scope.scopeType === 'product') {
6001
+ // Product page: only show results from this product
6002
+ const matches = cleanPath.startsWith(scope.scopePath + '/') ||
6003
+ cleanPath === scope.scopePath ||
6004
+ cleanPath.startsWith(scope.scopePath + '.html');
6005
+ return matches;
6006
+ }
6007
+
6008
+ if (scope.scopeType === 'solution') {
6009
+ // Solution page: search across related products
6010
+ const relatedProducts = scope.relatedProducts || [];
6011
+
6012
+ if (relatedProducts.length === 0) {
6013
+ // No related products found in frontmatter, return all results
6014
+ return true;
6015
+ }
6016
+
6017
+ // Check if the result is in any of the related products
6018
+ const matches = relatedProducts.some(product => {
6019
+ return cleanPath.startsWith(`/${product}/`) ||
6020
+ cleanPath === `/${product}` ||
6021
+ cleanPath.startsWith(`/${product}.html`);
6022
+ });
6023
+
6024
+ return matches;
6025
+ }
6026
+
6027
+ return true;
6028
+ });
6029
+
6030
+ return {
6031
+ ...resultGroup,
6032
+ result: filteredResult
6033
+ };
6034
+ });
6035
+ };
5879
6036
  const handleQueryChangedImpl = async (value) => {
5880
6037
  let newQuery = value;
5881
6038
  setQuery(newQuery);
@@ -5903,7 +6060,13 @@ function SearchPanel({ focused, setFocused }) {
5903
6060
  }
5904
6061
  const currQuery = searchInputRef.current?.value;
5905
6062
  if (currQuery === newQuery) {
5906
- setSearchResult(searchResult || DEFAULT_RESULT);
6063
+ const filteredResult = filterResultsByScope(
6064
+ searchResult || DEFAULT_RESULT,
6065
+ searchScope,
6066
+ base,
6067
+ lang
6068
+ );
6069
+ setSearchResult(filteredResult);
5907
6070
  setIsSearching(false);
5908
6071
  }
5909
6072
  }
@@ -5997,6 +6160,21 @@ function SearchPanel({ focused, setFocused }) {
5997
6160
  })
5998
6161
  });
5999
6162
  };
6163
+ const getScopedPlaceholder = () => {
6164
+ if (!searchScope || !searchScope.scopeType) return searchPlaceholderText;
6165
+
6166
+ if (searchScope.scopeType === 'product') {
6167
+ return `Search in ${searchScope.productName.toUpperCase()}...`;
6168
+ }
6169
+ if (searchScope.scopeType === 'solution') {
6170
+ const formattedName = searchScope.solutionName
6171
+ .split('-')
6172
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
6173
+ .join(' ');
6174
+ return `Search in ${formattedName}...`;
6175
+ }
6176
+ return searchPlaceholderText;
6177
+ };
6000
6178
  return (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.Fragment, {
6001
6179
  children: focused && (0, __WEBPACK_EXTERNAL_MODULE_react_dom_7136dc57__.createPortal)((0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
6002
6180
  className: Search_index_module.mask,
@@ -6024,7 +6202,7 @@ function SearchPanel({ focused, setFocused }) {
6024
6202
  (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("input", {
6025
6203
  className: `rspress-search-panel-input ${Search_index_module.input}`,
6026
6204
  ref: searchInputRef,
6027
- placeholder: searchPlaceholderText,
6205
+ placeholder: getScopedPlaceholder(),
6028
6206
  "aria-label": "SearchPanelInput",
6029
6207
  autoComplete: "off",
6030
6208
  autoFocus: true,
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.16",
4
+ "version": "0.7.17",
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.16",
25
- "@rspress-theme-anatole/shared": "0.7.16",
24
+ "@rspress-theme-anatole/rspress-plugin-mermaid": "0.7.17",
25
+ "@rspress-theme-anatole/shared": "0.7.17",
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",