Skip to content

Commit b296f22

Browse files
Create a custom Algolia search for docs (aws-amplify#4100)
* Update algolia search to use custom index * Update naming of SearchItem * sourceId is products * Change sitemap domain back to docs.amplify.aws * Remove old docsearch * Remove default options if query is empty * Increase hits per page * Revert "Increase hits per page" This reverts commit b48b318. * Fix content error in headless.mdx * Fix content error in workflows.mdx * Fix content issues in cli/graphql/overview.mdx * Fix url in cli/restapi/testing.mdx * Fix content issues in commands.mdx * Fix angle brackets in files.mdx * Remove comment in export-to-cdk * Fix files.mdx * Fix example url to be code string in cli/usage/containers.mdx * Use html entity characters in cli/teams/commands.mdx * Remove comments from cli/function/build-options.mdx * Fix transformer-migration.mdx * Use html entity characters in cli/start/workflows.mdx Co-authored-by: Tim Nguyen <[email protected]>
1 parent 857b165 commit b296f22

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+5527
-4399
lines changed

adobe.d.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
interface AdobeS {
2+
// Configuration properties
3+
trackExternalLinks: boolean;
4+
5+
// Variables to set when tracking
6+
linkTrackVars: string;
7+
linkTrackEvents: string;
8+
events: string;
9+
pageURL: string;
10+
eVar26: string;
11+
eVar27: string;
12+
13+
// Tracking functions
14+
t: () => void;
15+
tl: (
16+
linkObject: true | undefined,
17+
linkType: string,
18+
linkName: string
19+
) => void;
20+
}
21+
22+
interface AWSCShortbreadObject {
23+
checkForCookieConsent: () => void;
24+
}
25+
26+
declare const s: AdobeS;
27+
declare const docsearch: (obj: object) => void;
28+
declare const AWSCShortbread: (obj: object) => AWSCShortbreadObject;

amplify.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ frontend:
77
build:
88
commands:
99
- NODE_ENV=production yarn build
10+
- node tasks/build-algolia-search.mjs
1011
artifacts:
1112
# IMPORTANT - Please verify your build output directory
1213
baseDirectory: /client/www/next-build
1314
files:
14-
- "**/*"
15+
- '**/*'
1516
cache:
1617
paths:
1718
- node_modules/**/*

next-env.d.ts

+3-29
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,5 @@
11
/// <reference types="next" />
2-
/// <reference types="next/types/global" />
2+
/// <reference types="next/image-types/global" />
33

4-
interface AdobeS {
5-
// Configuration properties
6-
trackExternalLinks: boolean;
7-
8-
// Variables to set when tracking
9-
linkTrackVars: string;
10-
linkTrackEvents: string;
11-
events: string;
12-
pageURL: string;
13-
eVar26: string;
14-
eVar27: string;
15-
16-
// Tracking functions
17-
t: () => void;
18-
tl: (
19-
linkObject: true | undefined,
20-
linkType: string,
21-
linkName: string,
22-
) => void;
23-
}
24-
25-
interface AWSCShortbreadObject {
26-
checkForCookieConsent: () => void;
27-
}
28-
29-
declare const s: AdobeS;
30-
declare const docsearch: (obj: object) => void;
31-
declare const AWSCShortbread: (obj: object) => AWSCShortbreadObject;
4+
// NOTE: This file should not be edited
5+
// see https://nextjs.org/docs/basic-features/typescript for more information.

next.config.js

+53-42
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,64 @@
1+
const withTM = require('next-transpile-modules')([
2+
'@algolia/autocomplete-shared'
3+
]); // pass the modules you would like to see transpiled
4+
15
const mdxRenderer = `
26
import { mdx } from "@mdx-js/react";
37
48
`;
59

610
// eslint-disable-next-line @typescript-eslint/no-var-requires
7-
const directory = require("./src/directory/directory.js");
8-
// eslint-disable-next-line @typescript-eslint/no-var-requires
9-
const headingLinkPlugin = require("./src/plugins/headings.tsx");
10-
// eslint-disable-next-line @typescript-eslint/no-var-requires
11-
const pagePlugin = require("./src/plugins/page.tsx");
12-
// eslint-disable-next-line @typescript-eslint/no-var-requires
13-
const importPlugin = require("./src/plugins/import.tsx");
14-
// eslint-disable-next-line @typescript-eslint/no-var-requires
15-
const codeBlockPlugin = require("./src/plugins/code-block.tsx");
16-
// eslint-disable-next-line @typescript-eslint/no-var-requires
17-
const internalLinkPlugin = require("./src/plugins/internal-link.tsx");
18-
// eslint-disable-next-line @typescript-eslint/no-var-requires
19-
const withMDX = require("@next/mdx")({
20-
extension: /\.mdx$/,
21-
options: {
22-
remarkPlugins: [
23-
importPlugin,
24-
headingLinkPlugin,
25-
pagePlugin,
26-
internalLinkPlugin,
27-
],
28-
rehypePlugins: [codeBlockPlugin],
29-
renderer: mdxRenderer,
30-
},
31-
});
32-
33-
module.exports = withMDX({
34-
pageExtensions: ["js", "jsx", "mdx", "tsx", "ts"],
35-
typescript: {
36-
// !! WARN !!
37-
// Dangerously allow production builds to successfully complete even if
38-
// your project has type errors.
39-
// !! WARN !!
40-
ignoreBuildErrors: true,
41-
},
42-
future: {
43-
webpack5: true,
44-
},
45-
exportPathMap,
46-
trailingSlash: true,
47-
});
11+
const directory = require('./src/directory/directory.js');
12+
13+
module.exports = async (phase, { defaultConfig }) => {
14+
// eslint-disable-next-line @typescript-eslint/no-var-requires
15+
const headingLinkPlugin = await require('./src/plugins/headings.tsx');
16+
// eslint-disable-next-line @typescript-eslint/no-var-requires
17+
const pagePlugin = await require('./src/plugins/page.tsx');
18+
// eslint-disable-next-line @typescript-eslint/no-var-requires
19+
const internalLinkPlugin = await require('./src/plugins/internal-link.tsx');
20+
// eslint-disable-next-line @typescript-eslint/no-var-requires
21+
const codeBlockPlugin = await require('./src/plugins/code-block.tsx');
22+
// eslint-disable-next-line @typescript-eslint/no-var-requires
23+
const importPlugin = await require('./src/plugins/import.tsx');
24+
25+
const withMDX = require('@next/mdx')({
26+
extension: /\.mdx$/,
27+
options: {
28+
remarkPlugins: [
29+
importPlugin,
30+
headingLinkPlugin,
31+
pagePlugin,
32+
internalLinkPlugin
33+
],
34+
rehypePlugins: [codeBlockPlugin],
35+
renderer: mdxRenderer
36+
}
37+
});
38+
39+
const nextConfig = withTM(
40+
withMDX({
41+
pageExtensions: ['js', 'jsx', 'mdx', 'tsx', 'ts'],
42+
typescript: {
43+
// !! WARN !!
44+
// Dangerously allow production builds to successfully complete even if
45+
// your project has type errors.
46+
// !! WARN !!
47+
ignoreBuildErrors: true
48+
},
49+
future: {
50+
webpack5: true
51+
},
52+
exportPathMap,
53+
trailingSlash: true
54+
})
55+
);
56+
57+
return nextConfig;
58+
};
4859

4960
// eslint-disable-next-line @typescript-eslint/no-var-requires
50-
const generatePathMap = require("./generatePathMap.cjs");
61+
const generatePathMap = require('./generatePathMap.cjs');
5162
function exportPathMap(defaultPathMap, props) {
5263
return generatePathMap(directory);
5364
}

package.json

+23-4
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,40 @@
1212
"capi"
1313
],
1414
"dependencies": {
15+
"@algolia/autocomplete-js": "^1.5.3",
16+
"@algolia/autocomplete-plugin-query-suggestions": "^1.5.6",
17+
"@algolia/autocomplete-plugin-recent-searches": "^1.5.6",
18+
"@algolia/autocomplete-shared": "^1.5.6",
19+
"@algolia/autocomplete-theme-classic": "^1.6.1",
20+
"@algolia/client-search": "^4.13.0",
1521
"@aws-amplify/ui-components": "latest",
1622
"@aws-amplify/ui-react": "^1.2.5",
1723
"@emotion/react": "^11.1.5",
1824
"@emotion/styled": "^11.3.0",
25+
"@mdx-js/mdx": "^2.0.0",
26+
"algoliasearch": "^4.12.1",
1927
"array-flatten": "^3.0.0",
2028
"aws-amplify": "latest",
2129
"copy-to-clipboard": "^3.2.1",
30+
"dotenv": "^16.0.0",
2231
"emotion": "^10.0.23",
32+
"extract-mdx-metadata": "^2.0.0",
2333
"html-entities": "^1.2.1",
24-
"next": "^10.2.0",
34+
"instantsearch.js": "^4.39.1",
35+
"next": "^12.1.4",
36+
"next-transpile-modules": "^9.0.0",
37+
"parse-imports": "^1.1.0",
2538
"prismjs": "^1.21.0",
39+
"ramda": "^0.28.0",
2640
"react": "^17.0.2",
2741
"react-dom": "^17.0.2",
2842
"rehype": "^11.0.0",
29-
"theme-ui": "^0.7.5"
43+
"remark": "^14.0.2",
44+
"remark-mdx": "^2.0.0",
45+
"remark-mdx-searchable": "^0.1.3",
46+
"theme-ui": "^0.7.5",
47+
"unified": "^10.1.2",
48+
"unist-util-visit": "^4.1.0"
3049
},
3150
"devDependencies": {
3251
"@mdx-js/loader": "^1.6.22",
@@ -90,8 +109,8 @@
90109
"spellcheck": "cspell 'src/**/*.mdx'",
91110
"spellcheck-diff": "cspell --no-must-find-files $(git diff --cached --name-only | awk '/src.*\\.mdx/{print}' | cat - <(echo 'preventNoFilesPrintout'))",
92111
"dev": "next dev",
93-
"build": "yarn task patch-next-scrolling && yarn task generate-sitemap && next build && next export -o client/www/next-build",
112+
"build": "yarn task generate-sitemap && next build && next export -o client/www/next-build",
94113
"next-build": "next build",
95114
"next-start": "next start"
96115
}
97-
}
116+
}

public/scripts/docsearchv2_6_3.js

-2
This file was deleted.

src/components/Layout/index.tsx

+17-17
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import Head from "next/head";
2-
import UniversalNav from "../UniversalNav/index";
3-
import SecondaryNav from "../SecondaryNav/index";
4-
import Footer from "../Footer/index";
5-
import {LayoutStyle} from "./styles";
6-
import {Container} from "../Container";
7-
import {useRouter} from "next/router";
1+
import Head from 'next/head';
2+
import UniversalNav from '../UniversalNav/index';
3+
import SecondaryNav from '../SecondaryNav/index';
4+
import Footer from '../Footer/index';
5+
import { LayoutStyle } from './styles';
6+
import { Container } from '../Container';
7+
import { useRouter } from 'next/router';
88

99
export default function Layout({
1010
children,
1111
meta,
1212
filterKey,
13-
filterMetadataByOption,
13+
filterMetadataByOption
1414
}: {
1515
children: any;
1616
meta?: any;
@@ -22,19 +22,19 @@ export default function Layout({
2222

2323
const filterMetadata = filterKey
2424
? filterMetadataByOption[filterKey].label
25-
: "";
25+
: '';
2626

2727
const title = !meta
28-
? ""
29-
: [meta.chapterTitle, meta.title, filterMetadata, "AWS Amplify Docs"]
30-
.filter((s) => s !== "")
31-
.join(" - ");
28+
? ''
29+
: [meta.chapterTitle, meta.title, filterMetadata, 'AWS Amplify Docs']
30+
.filter((s) => s !== '')
31+
.join(' - ');
3232

3333
const description = !meta
34-
? ""
35-
: [meta.description, filterMetadata, "AWS Amplify Docs"]
36-
.filter((s) => s !== "")
37-
.join(" - ");
34+
? ''
35+
: [meta.description, filterMetadata, 'AWS Amplify Docs']
36+
.filter((s) => s !== '')
37+
.join(' - ');
3838

3939
return (
4040
<>
+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { autocomplete } from '@algolia/autocomplete-js';
2+
import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions';
3+
import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches';
4+
import algoliasearch from 'algoliasearch';
5+
6+
import React, { createElement, Fragment, useEffect, useRef } from 'react';
7+
import { render } from 'react-dom';
8+
9+
import { pipe } from 'ramda';
10+
11+
import { groupBy, limit, uniqBy } from './functions/index';
12+
13+
const appId = 'W6Q5N5WUDV';
14+
const apiKey = 'a82ff7ed9cd894525d84229ba4a886db';
15+
const searchClient = algoliasearch(appId, apiKey);
16+
17+
const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
18+
key: 'search',
19+
limit: 20
20+
});
21+
const querySuggestionsPlugin = createQuerySuggestionsPlugin({
22+
searchClient,
23+
indexName: 'custom_search_staging',
24+
getSearchParams() {
25+
return {
26+
hitsPerPage: 20
27+
};
28+
}
29+
});
30+
31+
const dedupeAndLimitSuggestions = pipe(
32+
uniqBy(({ source, item }) =>
33+
source.sourceId === 'querySuggestionsPlugin' ? item.query : item.title
34+
),
35+
limit(10)
36+
);
37+
38+
const groupByCategory = groupBy((hit) => hit.category, {
39+
getSource({ name, items }) {
40+
return {
41+
getItems() {
42+
return items;
43+
},
44+
templates: {
45+
header() {
46+
return (
47+
<>
48+
<span className="aa-SourceHeaderTitle">{name}</span>
49+
<div className="aa-SourceHeaderLine" />
50+
</>
51+
);
52+
}
53+
}
54+
};
55+
}
56+
});
57+
58+
export function Autocomplete(props) {
59+
const containerRef = useRef(null);
60+
61+
useEffect(() => {
62+
if (!containerRef.current) {
63+
return undefined;
64+
}
65+
66+
const search = autocomplete({
67+
container: containerRef.current,
68+
renderer: { createElement, Fragment },
69+
plugins: [recentSearchesPlugin, querySuggestionsPlugin],
70+
getSources({ query }) {
71+
if (!query) {
72+
return [];
73+
}
74+
},
75+
reshape({ sourcesBySourceId }) {
76+
const {
77+
recentSearchesPlugin,
78+
querySuggestionsPlugin,
79+
products,
80+
...rest
81+
} = sourcesBySourceId;
82+
83+
return [
84+
dedupeAndLimitSuggestions(),
85+
groupByCategory(products),
86+
Object.values(rest)
87+
];
88+
},
89+
render({ children }, root) {
90+
render(children, root);
91+
},
92+
...props
93+
});
94+
95+
return () => {
96+
search.destroy();
97+
};
98+
}, [props]);
99+
100+
return <div ref={containerRef} />;
101+
}

0 commit comments

Comments
 (0)