Skip to content

Commit

Permalink
feat(theme): introduce Autocomplete Classic Theme (#409)
Browse files Browse the repository at this point in the history
Co-authored-by: François Chalifour <francois.chalifour@gmail.com>
  • Loading branch information
Shipow and francoischalifour committed Jan 29, 2021
1 parent 74e319f commit 226fc54
Show file tree
Hide file tree
Showing 19 changed files with 811 additions and 282 deletions.
11 changes: 4 additions & 7 deletions .stylelintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,16 @@
"stylelint-prettier/recommended"
],
"rules": {
"order/properties-alphabetical-order": true,
"no-descending-specificity": null,
"selector-class-pattern": ["^aa-[A-Za-z0-9-]*$"],
"prettier/prettier": true,
"max-nesting-depth": [
2,
{
"ignore": ["pseudo-classes"],
"ignoreAtRules": ["media"]
}
],
"max-nesting-depth": null,
"rule-empty-line-before": [
"always",
{ "ignore": ["after-comment", "first-nested", "inside-block"] }
],
"selector-max-compound-selectors": null,
"plugin/no-unsupported-browser-features": [
null,
{
Expand Down
2 changes: 1 addition & 1 deletion bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
},
{
"path": "packages/autocomplete-plugin-query-suggestions/dist/umd/index.production.js",
"maxSize": "2.8 kB"
"maxSize": "3 kB"
}
]
}
65 changes: 53 additions & 12 deletions examples/js/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@
import {
autocomplete,
getAlgoliaHits,
highlightHit,
snippetHit,
} from '@algolia/autocomplete-js';
import { createAlgoliaInsightsPlugin } from '@algolia/autocomplete-plugin-algolia-insights';
import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions';
import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches';
import { Hit } from '@algolia/client-search';
import algoliasearch from 'algoliasearch';
import { h } from 'preact';
import { h, Fragment } from 'preact';
import insightsClient from 'search-insights';

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

type Product = { name: string; image: string };
import { shortcutsPlugin } from './shortcutsPlugin';

type Product = {
name: string;
image: string;
description: string;
};
type ProductHit = Hit<Product>;

const appId = 'latency';
Expand Down Expand Up @@ -44,6 +50,7 @@ autocomplete({
debug: true,
openOnFocus: true,
plugins: [
shortcutsPlugin,
algoliaInsightsPlugin,
recentSearchesPlugin,
querySuggestionsPlugin,
Expand All @@ -58,16 +65,37 @@ autocomplete({
getItems() {
return getAlgoliaHits<Product>({
searchClient,
queries: [{ indexName: 'instant_search', query }],
queries: [
{
indexName: 'instant_search',
query,
params: {
attributesToSnippet: ['name:10', 'description:35'],
snippetEllipsisText: '…',
},
},
],
});
},
templates: {
header() {
return (
<Fragment>
<span className="aa-SourceHeaderTitle">Products</span>
<div className="aa-SourceHeaderLine"></div>
</Fragment>
);
},
item({ item }) {
return <ProductItem hit={item} />;
},
empty() {
return (
<div className="aa-ItemContent">No results for this query.</div>
<div className="aa-ItemContent">
<div className="aa-ItemContentTitle">
No products for this query.
</div>
</div>
);
},
},
Expand All @@ -82,14 +110,27 @@ type ProductItemProps = {

function ProductItem({ hit }: ProductItemProps) {
return (
<div className="aa-ItemContent">
<div className="aa-ItemSourceIcon">
<img src={hit.image} alt={hit.name} width="20" height="20" />
<Fragment>
<div className="aa-ItemIcon">
<img src={hit.image} alt={hit.name} width="40" height="40" />
</div>

<div className="aa-ItemTitle">
{highlightHit<ProductHit>({ hit, attribute: 'name' })}
<div className="aa-ItemContent">
<div className="aa-ItemContentTitle">
{snippetHit<ProductHit>({ hit, attribute: 'name' })}
</div>
<div className="aa-ItemContentDescription">
{snippetHit<ProductHit>({ hit, attribute: 'description' })}
</div>
</div>
</div>
<button
className="aa-ItemActionButton aa-TouchOnly aa-ActiveOnly"
type="button"
title="Select"
>
<svg fill="currentColor" viewBox="0 0 24 24" width="20" height="20">
<path d="M18.984 6.984h2.016v6h-15.188l3.609 3.609-1.406 1.406-6-6 6-6 1.406 1.406-3.609 3.609h13.172v-4.031z"></path>
</svg>
</button>
</Fragment>
);
}
31 changes: 31 additions & 0 deletions examples/js/darkMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
function initTheme() {
if (isDarkThemeSelected()) {
applyDarkTheme();
} else {
applyLightTheme();
}
}

export function isDarkThemeSelected() {
return localStorage.getItem('darkMode') === 'dark';
}

function applyDarkTheme() {
document.body.setAttribute('data-theme', 'dark');
localStorage.setItem('darkMode', 'dark');
}

function applyLightTheme() {
document.body.removeAttribute('data-theme');
localStorage.removeItem('darkMode');
}

export function toggleTheme() {
if (isDarkThemeSelected()) {
applyLightTheme();
} else {
applyDarkTheme();
}
}

initTheme();
2 changes: 2 additions & 0 deletions examples/js/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<title>Autocomplete JavaScript Playground</title>
</head>

<body>
<div class="container">
<div id="autocomplete"></div>
Expand Down Expand Up @@ -47,6 +48,7 @@
</div>

<script src="env.ts"></script>
<script src="darkMode.ts"></script>
<script src="app.tsx"></script>
</body>
</html>
98 changes: 98 additions & 0 deletions examples/js/shortcutsPlugin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { AutocompletePlugin } from '@algolia/autocomplete-js';

import { toggleTheme, isDarkThemeSelected } from './darkMode';

type DarkModeItem = {
label: string;
};

export const shortcutsPlugin: AutocompletePlugin<DarkModeItem> = {
getSources({ query }) {
if (query !== '/' && query !== 'dark' && query !== 'light') {
return [];
}

return [
{
getItems() {
return [
{
label: 'Toggle dark mode',
},
];
},
onSelect({ setIsOpen }) {
toggleTheme();
setIsOpen(true);
},
templates: {
header({ createElement, Fragment }) {
return createElement(
Fragment,
{},
createElement(
'span',
{ className: 'aa-SourceHeaderTitle' },
'Shortcuts'
),
createElement('div', { className: 'aa-SourceHeaderLine' })
);
},
item({ item, createElement, Fragment }) {
const darkIcon = createElement(
'svg',
{
xmlns: 'http://www.w3.org/2000/svg',
fill: 'none',
viewBox: '0 0 24 24',
stroke: 'currentColor',
},
createElement('path', {
strokeLinecap: 'round',
strokeLinejoin: 'round',
strokeWidth: 2,
d:
'M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z',
})
);
const lightIcon = createElement(
'svg',
{
xmlns: 'http://www.w3.org/2000/svg',
fill: 'none',
viewBox: '0 0 24 24',
stroke: 'currentColor',
},
createElement('path', {
strokeLinecap: 'round',
strokeLinejoin: 'round',
strokeWidth: 2,
d:
'M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z',
})
);

return createElement(
Fragment,
{},
createElement(
'div',
{ className: 'aa-ItemIcon' },
isDarkThemeSelected() ? lightIcon : darkIcon
),
createElement(
'div',
{ className: 'aa-ItemContent' },
createElement(
'div',
{ className: 'aa-ItemContentTitle' },
item.label
)
)
);
},
},
},
];
},
};
11 changes: 9 additions & 2 deletions examples/js/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,32 @@
}

body {
background-color: rgb(244, 244, 249);
color: rgb(65, 65, 65);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding: 1rem;
}

.container {
margin: 0 auto;
max-width: 640px;
padding: 1rem;

width: 100%;
}

.content p {
color: #555;
line-height: 1.6;
}

.content img {
max-width: 100%;
}

body[data-theme='dark'] {
background-color: rgb(0, 0, 0);
color: rgb(183, 192, 199);
}
6 changes: 5 additions & 1 deletion examples/react-renderer/src/App.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
.container {
margin: 0 auto;
max-width: 640px;
padding: 1rem;
width: 100%;
}

.aa-Panel {
max-width: 640px;
width: 100%;
}
2 changes: 1 addition & 1 deletion examples/react-renderer/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import './App.css';
export function App() {
return (
<div className="container">
<Autocomplete openOnFocus={true} />
<Autocomplete openOnFocus={true} debug={true} />
</div>
);
}
13 changes: 10 additions & 3 deletions examples/react-renderer/src/Autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,19 @@ export function Autocomplete(
className="aa-Form"
{...autocomplete.getFormProps({ inputElement: inputRef.current })}
>
<div className="aa-InputWrapper">
<div className="aa-InputWrapperPrefix">
<label className="aa-Label" {...autocomplete.getLabelProps({})}>
<SearchIcon />
</label>
</div>
<div className="aa-InputWrapper">
<input
className="aa-Input"
ref={inputRef}
{...autocomplete.getInputProps({ inputElement: inputRef.current })}
/>
</div>
<div className="aa-InputWrapperSuffix">
<button className="aa-ResetButton" type="reset">
<ResetIcon />
</button>
Expand All @@ -131,6 +135,7 @@ export function Autocomplete(
ref={panelRef}
className={[
'aa-Panel',
'aa-Panel--desktop',
autocompleteState.status === 'stalled' && 'aa-Panel--stalled',
]
.filter(Boolean)
Expand All @@ -152,10 +157,12 @@ export function Autocomplete(
className="aa-Item"
{...autocomplete.getItemProps({ item, source })}
>
<div className="aa-ItemIcon aa-ItemIcon--no-border">
<SearchIcon />
</div>
<div className="aa-ItemContent">
<SearchIcon className="aa-ItemSourceIcon" />
<div
className="aa-ItemTitle"
className="aa-ItemContentTitle"
dangerouslySetInnerHTML={{
__html: item._highlightResult.query.value,
}}
Expand Down

0 comments on commit 226fc54

Please sign in to comment.