Skip to content

Commit

Permalink
docs: add two-columns layout example (#908)
Browse files Browse the repository at this point in the history
* docs(examples): scaffold two columns layout example

* fix consistent naming

* chore: fix linting

* chore: fix styles

* chore: fix deps

* chore: add missing dep for Codesandbox

* apply suggestions from code review

* remove useless media queries

* apply suggestions from code review

* docs(two-column-layout-example): add products plugin (#909)

* docs(two-columns-layout-example): add products plugin

* apply suggestions from review

* remove useless type

* use classic header for recent searches and fix padding

* apply suggestions from code review

* docs(two-column-layout-example): add categories, brands and faq plugins (#910)

* chore(two-columns-layout-example): add categories plugin

* chore(two-columns-layout-example): add brands plugin

* chore(two-columns-layout-example): add faq plugin

* apply suggestions from code review

* remove debug option

* docs(two-column-layout-example): add articles and popular plugins (#911)

* chore(two-columns-layout-example): add articles plugin

* chore(two-columns-layout-example): add popular plugin

* apply suggestions from code review

* docs(two-column-layout-example): add reshape functions and quick access plugin (#912)

* chore(two-columns-layout-example): add reshape functions

* docs(two-columns-layout-example): add quick access plugin

* chore: move reshape functions at file top-level

* apply suggestions from code review

* docs(two-column-layout-example): add smart preview feature (#913)

* docs(two-columns-layout-example): add smart preview feature

* docs(two-columns-layout-example): add faq article preview

* apply suggestions from code review

* docs(two-column-layout-example): add no results state and popular categories plugin (#914)

* docs(two-columns-layout-example): add no results state and popular categories plugin

* chore: fix empty div with Fragment

* chore: fix empty div when no recent searches exist

* chore: fix casing

* apply suggestions from code review

* apply suggestions from pair session

* fix empty recent searches

* fix linting

* apply suggestion from code review

* smart preview no longer depends on the DOM

* apply suggestions from feedback

* apply suggestions from feedback

* apply suggestion from code review

* apply suggestion from feedback

* remove smart preview for now

* add quick access selected transition

* fix see all link margin

* add getItemInputValue for faq

* apply feedback

* apply feedback

* apply feedback

* apply last fixes
  • Loading branch information
FabienMotte authored Mar 29, 2022
1 parent 6f59dd5 commit 927b1bc
Show file tree
Hide file tree
Showing 46 changed files with 2,460 additions and 1 deletion.
23 changes: 23 additions & 0 deletions examples/two-column-layout/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.

# dependencies
/node_modules

# testing
/coverage

# production
/dist
/.cache
/.parcel-cache

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
34 changes: 34 additions & 0 deletions examples/two-column-layout/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Autocomplete with a two-column layout example

This example shows how to integrate Autocomplete with a two-column layout.

<p align="center"><img src="capture.png?raw=true" alt="A capture of the Autocomplete with a two-column layout example" /></p>

## Demo

[Access the demo](https://codesandbox.io/s/github/algolia/autocomplete/tree/next/examples/two-column-layout)

## How to run this example locally

### 1. Clone this repository

```sh
git clone [email protected]:algolia/autocomplete.git
```

### 2. Install the dependencies and run the server

```sh
yarn
yarn workspace @algolia/autocomplete-example-two-column-layout start
```

Alternatively, you may use npm:

```sh
cd examples/two-column-layout
npm install
npm run start
```

Open <http://localhost:1234> to see your app.
Binary file added examples/two-column-layout/capture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/two-column-layout/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions examples/two-column-layout/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<link rel="shortcut icon" href="favicon.png" type="image/x-icon" />
<link rel="stylesheet" href="style.css" />

<title>Autocomplete with a two-column layout</title>
</head>

<body>
<noscript> You need to enable JavaScript to run this app. </noscript>

<div class="container">
<div id="autocomplete"></div>
</div>

<script src="src/app.tsx"></script>
</body>
</html>
34 changes: 34 additions & 0 deletions examples/two-column-layout/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "@algolia/autocomplete-example-two-column-layout",
"description": "Autocomplete example with two-column layout",
"version": "1.5.3",
"private": true,
"license": "MIT",
"scripts": {
"build": "parcel build index.html",
"start": "parcel index.html"
},
"dependencies": {
"@algolia/autocomplete-core": "1.5.3",
"@algolia/autocomplete-js": "1.5.3",
"@algolia/autocomplete-plugin-query-suggestions": "1.5.3",
"@algolia/autocomplete-plugin-recent-searches": "1.5.3",
"@algolia/autocomplete-theme-classic": "1.5.3",
"@algolia/autocomplete-shared": "1.5.3",
"@algolia/client-search": "4.12.1",
"algoliasearch": "4.12.1",
"blurhash": "^1.1.5",
"dequal": "^2.0.2",
"preact": "10.5.14",
"ramda": "^0.28.0",
"typescript": "^4.6.2"
},
"devDependencies": {
"parcel": "2.0.0-beta.2"
},
"keywords": [
"algolia",
"autocomplete",
"typescript"
]
}
199 changes: 199 additions & 0 deletions examples/two-column-layout/src/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/** @jsx h */
import { autocomplete } from '@algolia/autocomplete-js';
import { h, render } from 'preact';
import { pipe } from 'ramda';

import { createFillWith, uniqBy } from './functions';
import { articlesPlugin } from './plugins/articlesPlugin';
import { brandsPlugin } from './plugins/brandsPlugin';
import { categoriesPlugin } from './plugins/categoriesPlugin';
import { faqPlugin } from './plugins/faqPlugin';
import { popularCategoriesPlugin } from './plugins/popularCategoriesPlugin';
import { popularPlugin } from './plugins/popularPlugin';
import { productsPlugin } from './plugins/productsPlugin';
import { querySuggestionsPlugin } from './plugins/querySuggestionsPlugin';
import { quickAccessPlugin } from './plugins/quickAccessPlugin';
import { recentSearchesPlugin } from './plugins/recentSearchesPlugin';
import { cx, hasSourceActiveItem, isDetached } from './utils';

import '@algolia/autocomplete-theme-classic';

const removeDuplicates = uniqBy(({ source, item }) => {
const sourceIds = ['recentSearchesPlugin', 'querySuggestionsPlugin'];
if (sourceIds.indexOf(source.sourceId) === -1) {
return item;
}

return source.sourceId === 'querySuggestionsPlugin' ? item.query : item.label;
});

const fillWith = createFillWith({
mainSourceId: 'querySuggestionsPlugin',
limit: isDetached() ? 6 : 10,
});

const combine = pipe(removeDuplicates, fillWith);

autocomplete({
container: '#autocomplete',
placeholder: 'Search products, articles, and FAQs',
autoFocus: true,
openOnFocus: true,
plugins: [
recentSearchesPlugin,
querySuggestionsPlugin,
categoriesPlugin,
brandsPlugin,
faqPlugin,
productsPlugin,
articlesPlugin,
popularPlugin,
quickAccessPlugin,
popularCategoriesPlugin,
],
reshape({ sourcesBySourceId, sources, state }) {
const {
recentSearchesPlugin: recentSearches,
querySuggestionsPlugin: querySuggestions,
categoriesPlugin: categories,
brandsPlugin: brands,
faqPlugin: faq,
popularPlugin: popular,
popularCategoriesPlugin: popularCategories,
...rest
} = sourcesBySourceId;

const sourceIdsToExclude = ['popularPlugin', 'popularCategoriesPlugin'];
const shouldDisplayPopularCategories = sources.every((source) => {
if (sourceIdsToExclude.indexOf(source.sourceId) !== -1) {
return true;
}
return source.getItems().length === 0;
});

return [
combine(recentSearches, querySuggestions, categories, brands, faq),
[
!state.query && popular,
...Object.values(rest),
shouldDisplayPopularCategories && popularCategories,
].filter(Boolean),
];
},
render({ elements, state, Fragment }, root) {
const {
recentSearchesPlugin: recentSearches,
querySuggestionsPlugin: querySuggestions,
categoriesPlugin: categories,
brandsPlugin: brands,
faqPlugin: faq,
productsPlugin: products,
articlesPlugin: articles,
popularPlugin: popular,
quickAccessPlugin: quickAccess,
popularCategoriesPlugin: popularCategories,
} = elements;

const sourceIdsToExclude = ['popularPlugin', 'popularCategoriesPlugin'];
const hasResults =
state.collections
.filter(
({ source }) => sourceIdsToExclude.indexOf(source.sourceId) === -1
)
.reduce((prev, curr) => prev + curr.items.length, 0) > 0;

render(
<div className="aa-PanelLayout aa-Panel--scrollable">
{!hasResults && (
<div className="aa-NoResultsQuery">
No results for "{state.query}".
</div>
)}

<div className="aa-PanelSections">
<div className="aa-PanelSection--left">
{hasResults ? (
(!state.query && recentSearches && (
<Fragment>
<div className="aa-SourceHeader">
<span className="aa-SourceHeaderTitle">
Recent searches
</span>
<div className="aa-SourceHeaderLine" />
</div>
{recentSearches}
</Fragment>
)) ||
(state.query && (
<Fragment>
<div className="aa-SourceHeader">
<span className="aa-SourceHeaderTitle">Suggestions</span>
<div className="aa-SourceHeaderLine" />
</div>

<div className="aa-PanelSectionSources">
{recentSearches}
{querySuggestions}
{categories}
{brands}
{faq}
</div>
</Fragment>
))
) : (
<div className="aa-NoResultsAdvices">
<ul className="aa-NoResultsAdvicesList">
<li>Double-check your spelling</li>
<li>Use fewer keywords</li>
<li>Search for a less specific item</li>
<li>Try navigate using on the of the popular categories</li>
</ul>
</div>
)}

{!state.query && (
<div className="aa-PanelSection--popular">{popular}</div>
)}
</div>
<div className="aa-PanelSection--right">
{products && (
<div className="aa-PanelSection--products">
<div className="aa-PanelSectionSource">{products}</div>
</div>
)}
{articles && (
<div className="aa-PanelSection--articles">
<div className="aa-PanelSectionSource">{articles}</div>
</div>
)}

{quickAccess && (
<div
className={cx(
'aa-PanelSection--quickAccess aa-PanelSection--zoomable',
hasSourceActiveItem('quickAccessPlugin', state) &&
'aa-PanelSection--active'
)}
>
{quickAccess}
</div>
)}

{!hasResults && (
<div
className={cx(
'aa-PanelSection--popularCategories aa-PanelSection--zoomable',
hasSourceActiveItem('popularCategoriesPlugin', state) &&
'aa-PanelSection--active'
)}
>
{popularCategories}
</div>
)}
</div>
</div>
</div>,
root
);
},
});
33 changes: 33 additions & 0 deletions examples/two-column-layout/src/components/Blurhash.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/** @jsx h */
import { decode } from 'blurhash';
import { h } from 'preact';
import { useEffect, useRef } from 'preact/hooks';

export interface BlurhashProps {
hash: string;
width: number;
height: number;
punch?: number;
}

export function Blurhash({ hash, width, height, punch = 1 }: BlurhashProps) {
const canvasRef = useRef<HTMLCanvasElement>(null);

useEffect(() => {
const pixels = decode(hash, width, height, punch);

const ctx = canvasRef.current.getContext('2d');
const imageData = ctx.createImageData(width, height);
imageData.data.set(pixels);
ctx.putImageData(imageData, 0, 0);
}, [hash, width, height, punch]);

return (
<canvas
ref={canvasRef}
height={height}
width={width}
className="aa-BlurhashCanvas"
/>
);
}
23 changes: 23 additions & 0 deletions examples/two-column-layout/src/components/Breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/** @jsx h */
import { h } from 'preact';

import { intersperse } from '../utils';

import { ChevronRightIcon } from './Icons';

type BreadcrumbProps = {
items: JSX.Element[];
};

export function Breadcrumb({ items }: BreadcrumbProps) {
return (
<div className="aa-Breadcrumb">
{intersperse(
items,
<div className="aa-ItemIcon aa-ItemIcon--noBorder aa-FavoriteIcon">
<ChevronRightIcon />
</div>
)}
</div>
);
}
Loading

0 comments on commit 927b1bc

Please sign in to comment.