Skip to content

Commit

Permalink
feat: add mobile-specific functionality to examples index
Browse files Browse the repository at this point in the history
  • Loading branch information
jamiehenson committed Jan 13, 2025
1 parent 060f478 commit 3b04788
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 49 deletions.
6 changes: 3 additions & 3 deletions src/components/Examples/ExamplesContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const ExamplesContent = ({ exampleImages }: { exampleImages: ImageProps[] }) =>

return (
<>
<section className="mx-auto px-24 md:px-0 max-w-[1152px] relative z-10">
<section className="mx-auto px-24 md:px-0 max-w-[1152px] relative">
<div className="w-full sm:w-1/2 max-w-[600px] pt-80 sm:pt-96">
<h1 className="ui-text-title text-title">Examples</h1>
<p className="ui-text-sub-header mt-16">
Expand Down Expand Up @@ -90,15 +90,15 @@ const ExamplesContent = ({ exampleImages }: { exampleImages: ImageProps[] }) =>
width={660}
height={282}
alt="Grid Pattern"
className="absolute z-0 right-0 top-64 hidden sm:block w-[60%] md:w-[40%]"
className="absolute -z-10 right-0 top-64 hidden sm:block w-[60%] md:w-[40%]"
/>

<StaticImage
src="./images/GridMobile.png"
placeholder="blurred"
width={260}
alt="Grid Pattern"
className="z-0 right-0 top-64 absolute block sm:hidden"
className="-z-10 right-0 top-64 absolute block sm:hidden"
/>
</>
);
Expand Down
78 changes: 75 additions & 3 deletions src/components/Examples/ExamplesFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import React from 'react';
import React, { useEffect } from 'react';
import ReactDOM from 'react-dom';
import Icon from '@ably/ui/core/Icon';
import { products } from '@ably/ui/core/ProductTile/data';
import ExamplesCheckbox from './ExamplesCheckbox';
import examples from '../../data/examples';
import Button from '@ably/ui/core/Button';
import cn from '@ably/ui/core/utils/cn';
import { useOnClickOutside } from 'src/hooks';
import Badge from '@ably/ui/core/Badge';

const ExamplesFilter = ({
selectProduct,
Expand All @@ -17,11 +22,31 @@ const ExamplesFilter = ({
selectedProducts: string[];
selectedUseCases: string[];
}) => {
const filterMenuRef = React.useRef<HTMLDivElement>(null);
const [expandFilterMenu, setExpandFilterMenu] = React.useState(false);
const filters = [
{ key: 'product', data: products, selected: selectedProducts, handleSelect: selectProduct },
{ key: 'use-case', data: examples.useCases, selected: selectedUseCases, handleSelect: selectUseCases },
];

useOnClickOutside(() => setExpandFilterMenu(false), filterMenuRef);

useEffect(() => {
const handleResize = () => {
if (window.innerWidth >= 1040) {
setExpandFilterMenu(false);
}
};

window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

const activeFilters = React.useMemo(
() => selectedProducts.length + selectedUseCases.length,
[selectedProducts, selectedUseCases],
);

return (
<>
<div className="h-[34px] sm:h-[30px] w-20 absolute left-8 top-4 flex items-center justify-center select-none cursor-default">
Expand All @@ -36,9 +61,37 @@ const ExamplesFilter = ({
role="searchbox"
onChange={(e) => handleSearch(e)}
/>
<div className="flex flex-col gap-20 mt-20">
<Button
className="flex sm:hidden mt-16 w-full"
variant="secondary"
leftIcon="icon-gui-copy"
onClick={() => setExpandFilterMenu(true)}
>
Filter
{activeFilters > 0 ? <Badge>{activeFilters}</Badge> : null}
</Button>
{expandFilterMenu &&
ReactDOM.createPortal(
<div className="fixed inset-0 bg-neutral-1300 opacity-10 z-20" onClick={() => setExpandFilterMenu(false)} />,
document.body,
)}
<div
ref={filterMenuRef}
className={cn(
'fixed bottom-0 bg-white dark:bg-neutral-1300 z-30 w-full left-0 gap-20 mt-20 translate-y-full sm:static sm:translate-y-0 sm:flex sm:flex-col sm:bg-transparent sm:z-0 transition-[transform,colors] rounded-t-2xl sm:rounded-none max-h-[calc(100%-64px)] overflow-y-scroll',
{
'translate-y-0': expandFilterMenu,
},
)}
>
<div className="flex justify-between items-center sm:hidden h-64 px-16 py-8 bg-neutral-000 dark:bg-neutral-1300 border border-neutral-300 dark:border-neutral-1000 rounded-t-2xl sm:rounded-none">
<p className="ui-text-p1 font-bold text-neutral-1300 dark:text-neutral-000">Filters</p>
<button onClick={() => setExpandFilterMenu(false)} aria-label="Close filter menu">
<Icon name="icon-gui-close" size="24px" />
</button>
</div>
{filters.map(({ key, selected, handleSelect, data }) => (
<div key={key}>
<div key={key} className="p-16 pt-24">
<p className="ui-text-overline2 font-medium text-neutral-700">{key.replace(/-/g, ' ').toUpperCase()}</p>
<div className="mt-8 flex ui-text-p4 flex-col gap-8">
<ExamplesCheckbox
Expand All @@ -62,6 +115,25 @@ const ExamplesFilter = ({
</div>
</div>
))}
<div className="sm:hidden p-16 flex gap-12">
<Button
className="w-full flex-1"
variant="primary"
disabled={selectedProducts.length === 0 && selectedUseCases.length === 0}
>
Apply
</Button>
<Button
variant="secondary"
className="w-48 h-48 p-8"
onClick={() => {
selectProduct({ target: { value: 'all', checked: true } } as React.ChangeEvent<HTMLInputElement>);
selectUseCases({ target: { value: 'all', checked: true } } as React.ChangeEvent<HTMLInputElement>);
}}
>
<Icon name="icon-gui-refresh" />
</Button>
</div>
</div>
</>
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/Examples/ExamplesGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const ExamplesGrid = ({
}) => {
const displayExampleImage = (exampleImages: ImageProps[], selectedImage: string, productName: string) => {
const productImage = exampleImages.find((image) => image.name === selectedImage);
return productImage ? <Image image={productImage} alt={productName} /> : null;
return productImage ? <Image image={productImage} alt={productName} className="h-full" /> : null;
};

const badgeColorForProduct = (product: ProductName) => {
Expand Down Expand Up @@ -61,7 +61,7 @@ const ExamplesGrid = ({
<div className="w-full" key={`${name}-${key}`}>
<div className="bg-neutral-100 h-256 sm:h-200 relative flex justify-center items-center">
{exampleImages ? displayExampleImage(exampleImages, image, name) : null}
<div className="flex bg-neutral-000 gap-x-6 py-6 px-8 absolute right-12 bottom-12 rounded border border-neutral-200 z-20">
<div className="flex bg-neutral-000 gap-x-6 py-6 px-8 absolute right-12 bottom-12 rounded border border-neutral-200 z-10">
{languages
? languages.map((language) => (
<Icon key={language} name={`icon-tech-${language}` as IconName} size="18px" />
Expand Down
20 changes: 20 additions & 0 deletions src/components/Examples/ExamplesList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import examplesData from '../../data/examples';

const ExamplesList: React.FC = () => {
return (
<div className="flex flex-col gap-24 py-12">
{examplesData.examples.map((example) => (
<a
key={example.name}
href={'#'}
className="px-16 ui-text-menu1 text-neutral-1000 dark:text-neutral-300 font-bold hover:text-neutral-1300 dark:hover:text-neutral-000"
>
{example.name}
</a>
))}
</div>
);
};

export default ExamplesList;
6 changes: 5 additions & 1 deletion src/components/Layout/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import AblyLogo from './images/ably-logo.png';
import LeftSidebar from './LeftSidebar';
import UserContext from 'src/contexts/user-context';
import { pathWithBase } from './utils';
import ExamplesList from '../Examples/ExamplesList';

type HeaderProps = {
hideSearchBar?: boolean;
Expand Down Expand Up @@ -172,7 +173,10 @@ const Header: React.FC<HeaderProps> = ({ hideSearchBar = false }) => {
>
<TabMenu
tabs={tabs}
contents={[<LeftSidebar inHeader key="nav-mobile-documentation-tab" />, null]}
contents={[
<LeftSidebar inHeader key="nav-mobile-documentation-tab" />,
<ExamplesList key="nav-mobile-examples-tab" />,
]}
rootClassName="h-full overflow-y-hidden min-h-[51px] flex flex-col"
contentClassName="h-full py-16 overflow-y-scroll"
tabClassName="ui-text-menu2 !px-16"
Expand Down
40 changes: 0 additions & 40 deletions src/data/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,46 +70,6 @@ export default {
products: ['pubsub'],
useCases: ['live-chat'],
},
{
name: 'Member location',
description: 'Display the live location of a user within the app using this React starter-kit.',
image: 'typing-indicator-thumbnail',
languages: ['javascript', 'react', 'python'],
products: ['spaces'],
useCases: ['live-chat'],
},
{
name: 'Component locking',
description: 'Add component locking to specific parts of your app with this React starter-kit.',
image: 'typing-indicator-thumbnail',
languages: ['javascript', 'react'],
products: ['luve-sync '],
useCases: ['live-chat'],
},
{
name: 'Avatar stack',
description: 'Add a visual representation of a user’s presence, showing them as online and connected.',
image: 'typing-indicator-thumbnail',
languages: ['javascript', 'react'],
products: ['pubsub'],
useCases: ['live-chat'],
},
{
name: 'Member location',
description: 'Display the live location of a user within the app using this React starter-kit.',
image: 'typing-indicator-thumbnail',
languages: ['javascript', 'react'],
products: ['spaces'],
useCases: ['live-chat'],
},
{
name: 'Component locking',
description: 'Add component locking to specific parts of your app with this React starter-kit.',
image: 'typing-indicator-thumbnail',
languages: ['javascript', 'react'],
products: ['live-sync '],
useCases: ['live-chat'],
},
] as Example[],
useCases: {
'live-chat': {
Expand Down

0 comments on commit 3b04788

Please sign in to comment.