Merge pull request #73 from thornbill/clients-page

Add clients page
This commit is contained in:
Bill Thornton
2022-08-05 16:47:46 -04:00
committed by GitHub
7 changed files with 997 additions and 4 deletions
+80
View File
@@ -0,0 +1,80 @@
/* stylelint-disable docusaurus/copyright-header */
.client__header {
display: flex;
align-items: center;
}
.client__header__start {
flex-grow: 1;
display: flex;
}
.client__header__start h3 {
margin-bottom: 0;
}
.client__header__start__badges {
margin-left: 1rem;
}
.client__footer {
display: flex;
}
.client__platform-icon {
margin-left: 1rem;
}
.client__footer .button {
margin-left: 1rem;
}
.client__footer .button:first-of-type {
margin-left: 0;
}
@media (max-width: 420px) {
.client__header {
flex-direction: column;
text-align: center;
}
.client__platform-icon {
margin-top: 0.5rem;
}
.client__platform-icon:first-of-type {
margin-left: 0;
}
.card__body {
padding-top: 0;
}
}
@media (max-width: 560px) {
.client__header__start {
flex-direction: column;
}
.client__header__start__badges {
margin-top: 0.5rem;
}
.client__header__start__badges:first-of-type {
margin-left: 0;
}
.client__footer {
flex-direction: column;
}
.client__footer .button {
margin: 1rem 0 0;
}
.client__footer .button:first-of-type {
margin-top: 0;
}
}
+57
View File
@@ -0,0 +1,57 @@
import React from 'react';
import PlatformIcon from './PlatformIcon';
import { Client, ClientType, LicenseType } from '../data/clients';
import './ClientDetails.css';
const ClientTypeBadge = ({ clientType }: { clientType: ClientType }) => {
if (clientType === ClientType.Official) {
return <span className='badge badge--primary margin-right--sm'>Official</span>;
} else if (clientType === ClientType.ThirdParty) {
return <span className='badge badge--secondary margin-right--sm'>Third Party</span>;
}
};
const LicenseTypeBadge = ({ licenseType }: { licenseType: LicenseType }) => {
if (licenseType === LicenseType.OpenSource) {
return <span className='badge badge--success margin-right--sm'>Open Source</span>;
} else if (licenseType === LicenseType.Proprietary) {
return <span className='badge badge--warning margin-right--sm'>Proprietary</span>;
}
};
const ClientDetails = ({ client }: { client: Client }) => (
<div className='card client margin-bottom--md'>
<div className='card__header client__header'>
<div className='client__header__start'>
<h3>{client.name}</h3>
<div className='client__header__start__badges'>
<ClientTypeBadge clientType={client.clientType} />
<LicenseTypeBadge licenseType={client.licenseType} />
</div>
</div>
<div>
{client.platforms.map((platform, index) => (
<PlatformIcon key={`${platform}-${index}`} platform={platform} size={36} className='client__platform-icon' />
))}
</div>
</div>
<div className='card__body padding-top--sm'>{client.description}</div>
<div className='card__footer client__footer'>
{client.secondaryLinks?.map(({ id, url, name }) => (
<a key={id} href={url} className='button button--outline button--primary'>
{name}
</a>
))}
<div style={{ flexGrow: 1 }} />
{client.primaryLinks.map(({ id, url, name }) => (
<a key={id} href={url} className='button button--primary'>
{name}
</a>
))}
</div>
</div>
);
export default ClientDetails;
+27
View File
@@ -0,0 +1,27 @@
import clsx from 'clsx';
import React, { FunctionComponent, ReactNode } from 'react';
type PillParams = {
children: ReactNode;
active: boolean;
onClick(): void;
};
const Pill: FunctionComponent<PillParams> = ({ children, active, onClick }: PillParams) => (
<li
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-to-interactive-role
role='button'
tabIndex={0}
className={clsx('pills__item', { 'pills__item--active': active })}
onClick={onClick}
onKeyUp={(keyEvent) => {
if (keyEvent.key === 'Enter') {
onClick();
}
}}
>
{children}
</li>
);
export default Pill;
+70
View File
@@ -0,0 +1,70 @@
import {
Amazonfiretv,
Android,
Appletv,
Discord,
Ios,
Kodi,
Lg,
Roku,
Sailfishos
} from '@icons-pack/react-simple-icons';
import clsx from 'clsx';
import React from 'react';
import { Platform } from '../data/clients';
import Desktop from '../../static/images/icons/monitor.svg';
import Web from '../../static/images/icons/web.svg';
const PlatformIcon = ({
platform,
size,
className = ''
}: {
platform: Platform;
size: string | number;
className?: string;
}) => {
className = clsx(className, 'fill--white');
switch (platform) {
case Platform.Android:
case Platform.AndroidTV:
return <Android size={size} className={className} />;
case Platform.Browser:
return <Web width={size} height={size} className={className} />;
case Platform.Desktop:
return <Desktop width={size} height={size} className={className} />;
case Platform.Discord:
return <Discord size={size} className={className} />;
case Platform.FireOS:
return <Amazonfiretv size={size} className={className} />;
case Platform.IOS:
return <Ios size={size} className={className} />;
case Platform.Kodi:
return <Kodi size={size} className={className} />;
case Platform.Roku:
return <Roku size={size} className={className} />;
case Platform.SailfishOS:
return <Sailfishos size={size} className={className} />;
case Platform.TVOS:
return <Appletv size={size} className={className} />;
case Platform.WebOS:
return <Lg size={size} className={className} />;
default:
return null;
}
};
export default PlatformIcon;
+2
View File
@@ -29,7 +29,9 @@
--ifm-code-background: #292d3e; /* match code blocks */
--ifm-navbar-background-color: #000b25;
--ifm-background-color: #000b25 !important;
--ifm-card-background-color: #172138;
--ifm-footer-background-color: #333c44;
--ifm-pills-color-background-active: #172138;
--ifm-font-family-base: "Noto Sans", sans-serif;
--ifm-h1-font-size: 2.074em;
--ifm-h2-font-size: 1.728em;
+701
View File
@@ -0,0 +1,701 @@
export enum ClientType {
Official,
ThirdParty
}
export enum DeviceType {
Desktop,
Mobile,
TV
}
export enum LicenseType {
OpenSource,
Proprietary
}
export enum Platform {
Android,
AndroidTV,
Browser,
Desktop,
Discord,
FireOS,
IOS,
Kodi,
Roku,
SailfishOS,
TVOS,
WebOS
}
type Link = {
id: string;
name: string;
url: string;
};
export type Client = {
id: string;
name: string;
description: string;
clientType: ClientType;
deviceTypes: Array<DeviceType>;
licenseType: LicenseType;
platforms: Array<Platform>;
primaryLinks: Array<Link>;
secondaryLinks?: Array<Link>;
recommended?: boolean;
};
export const Clients: Array<Client> = [
{
id: 'jellyfin-media-player',
name: 'Jellyfin Media Player',
description: 'The official Jellyfin desktop client.',
clientType: ClientType.Official,
deviceTypes: [DeviceType.Desktop],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Desktop],
primaryLinks: [
{
id: 'flathub',
name: 'Flathub (Linux)',
url: 'https://flathub.org/apps/details/com.github.iwalton3.jellyfin-media-player'
},
{
id: 'gh-downloads',
name: 'GitHub Downloads',
url: 'https://github.com/jellyfin/jellyfin-media-player/releases'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jellyfin/jellyfin-media-player'
}
],
recommended: true
},
{
id: 'jellyfin-mpv-shim',
name: 'Jellyfin MPV Shim',
description: 'A cross-platform cast client for Jellyfin.',
clientType: ClientType.Official,
deviceTypes: [DeviceType.Desktop],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Desktop],
primaryLinks: [
{
id: 'flathub',
name: 'Flathub (Linux)',
url: 'https://flathub.org/apps/details/com.github.iwalton3.jellyfin-mpv-shim'
},
{
id: 'gh-downloads',
name: 'GitHub Downloads',
url: 'https://github.com/jellyfin/jellyfin-mpv-shim/releases'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jellyfin/jellyfin-mpv-shim'
}
]
},
{
id: 'jellyamp',
name: 'Jellyamp',
description: 'A desktop client for listening to music from a Jellyfin server.',
clientType: ClientType.ThirdParty,
deviceTypes: [DeviceType.Desktop],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Desktop],
primaryLinks: [
{
id: 'gh-downloads',
name: 'GitHub Downloads',
url: 'https://github.com/m0ngr31/jellyamp/releases'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/m0ngr31/jellyamp'
}
]
},
{
id: 'preserve',
name: 'Preserve',
description: 'A music client inspired by players such as foobar2000 or Clementine.',
clientType: ClientType.ThirdParty,
deviceTypes: [DeviceType.Desktop],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Browser, Platform.Desktop],
primaryLinks: [
{
id: 'browser',
name: 'Open in Browser',
url: 'https://preserveplayer.com/'
},
{
id: 'gl-downloads',
name: 'GitLab Downloads',
url: 'https://gitlab.com/tonyfinn/preserve/-/releases'
}
],
secondaryLinks: [
{
id: 'gitlab',
name: 'GitLab',
url: 'https://gitlab.com/tonyfinn/preserve'
}
]
},
{
id: 'sonixd',
name: 'Sonixd',
description: 'A full-featured Subsonic/Jellyfin compatible desktop music player.',
clientType: ClientType.ThirdParty,
deviceTypes: [DeviceType.Desktop],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Desktop],
primaryLinks: [
{
id: 'install',
name: 'Installation Guide',
url: 'https://github.com/jeffvli/sonixd#install'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jeffvli/sonixd'
}
]
},
{
id: 'tauon-music-box',
name: 'Tauon Music Box',
description: "A modern streamlined music player for desktop with a minimal interface that's packed with features!",
clientType: ClientType.ThirdParty,
deviceTypes: [DeviceType.Desktop],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Desktop],
primaryLinks: [
{
id: 'flathub',
name: 'Flathub (Linux)',
url: 'https://flathub.org/apps/details/com.github.taiko2k.tauonmb'
},
{
id: 'install',
name: 'Installation Guide',
url: 'https://github.com/Taiko2k/TauonMusicBox#download-and-install-dizzy'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/Taiko2k/TauonMusicBox'
},
{
id: 'tauon',
name: 'Website',
url: 'https://tauonmusicbox.rocks'
}
]
},
{
id: 'jellycon',
name: 'JellyCon',
description:
'A lightweight Kodi add-on that lets you browse and play media files directly from your Jellyfin server within the Kodi interface.',
clientType: ClientType.Official,
deviceTypes: [DeviceType.Desktop, DeviceType.Mobile, DeviceType.TV],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Kodi],
primaryLinks: [
{
id: 'install',
name: 'Installation Guide',
url: 'https://github.com/jellyfin/jellycon#installation'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jellyfin/jellycon'
}
],
recommended: true
},
{
id: 'jellyfin-kodi',
name: 'Jellyfin for Kodi',
description: 'A Kodi add-on that syncs metadata from selected Jellyfin libraries into the local Kodi database.',
clientType: ClientType.Official,
deviceTypes: [DeviceType.Desktop, DeviceType.Mobile, DeviceType.TV],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Kodi],
primaryLinks: [
{
id: 'install',
name: 'Installation Guide',
url: 'https://docs.jellyfin.org/general/clients/kodi.html'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jellyfin/jellyfin-kodi'
}
]
},
{
id: 'jellyfin-android',
name: 'Jellyfin for Android',
description: 'The official Jellyfin app for Android devices.',
clientType: ClientType.Official,
deviceTypes: [DeviceType.Mobile],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Android],
primaryLinks: [
{
id: 'fdroid',
name: 'F-Droid',
url: 'https://f-droid.org/en/packages/org.jellyfin.mobile/'
},
{
id: 'amazon-store',
name: 'Amazon Appstore',
url: 'https://www.amazon.com/gp/aw/d/B081RFTTQ9'
},
{
id: 'play-store',
name: 'Play Store',
url: 'https://play.google.com/store/apps/details?id=org.jellyfin.mobile'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jellyfin/jellyfin-android'
}
],
recommended: true
},
{
id: 'jellyfin-expo',
name: 'Jellyfin Mobile for iOS',
description: 'The official Jellyfin app for iOS and iPadOS devices.',
clientType: ClientType.Official,
deviceTypes: [DeviceType.Mobile],
licenseType: LicenseType.OpenSource,
platforms: [Platform.IOS],
primaryLinks: [
{
id: 'apple-store',
name: 'App Store',
url: 'https://apps.apple.com/us/app/jellyfin-mobile/id1480192618?mt=8'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jellyfin/jellyfin-expo'
}
],
recommended: true
},
{
id: 'findroid',
name: 'Findroid',
description:
'A third-party Android application for Jellyfin that provides a native user interface to browse and play movies and series.',
clientType: ClientType.ThirdParty,
deviceTypes: [DeviceType.Mobile],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Android],
primaryLinks: [
{
id: 'izzy-fdroid',
name: 'IzzyOnDroid',
url: 'https://apt.izzysoft.de/fdroid/index/apk/dev.jdtech.jellyfin'
},
{
id: 'play-store',
name: 'Play Store',
url: 'https://play.google.com/store/apps/details?id=dev.jdtech.jellyfin'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jarnedemeulemeester/findroid'
}
]
},
{
id: 'gelli',
name: 'Gelli',
description:
'A native music player for Android devices with transcoding support, gapless playback, favorites, playlists, and many other features.',
clientType: ClientType.ThirdParty,
deviceTypes: [DeviceType.Mobile],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Android],
primaryLinks: [
{
id: 'gh-downloads',
name: 'GitHub Downloads',
url: 'https://github.com/dkanada/gelli/releases'
},
{
id: 'fdroid',
name: 'F-Droid',
url: 'https://f-droid.org/packages/com.dkanada.gramophone/'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/dkanada/gelli'
}
]
},
{
id: 'finamp',
name: 'Finamp',
description: 'A third party app for music playback with support for offline mode/downloading songs.',
clientType: ClientType.ThirdParty,
deviceTypes: [DeviceType.Mobile],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Android, Platform.IOS],
primaryLinks: [
{
id: 'fdroid',
name: 'F-Droid',
url: 'https://f-droid.org/packages/com.unicornsonlsd.finamp/'
},
{
id: 'play-store',
name: 'Play Store',
url: 'https://play.google.com/store/apps/details?id=com.unicornsonlsd.finamp'
},
{
id: 'app-store',
name: 'App Store',
url: 'https://apps.apple.com/us/app/finamp/id1574922594'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/UnicornsOnLSD/finamp'
}
]
},
{
id: 'sailfin',
name: 'Sailfin',
description: 'A Sailfish OS client for Jellyfin.',
clientType: ClientType.ThirdParty,
deviceTypes: [DeviceType.Mobile],
licenseType: LicenseType.OpenSource,
platforms: [Platform.SailfishOS],
primaryLinks: [
{
id: 'open-repos',
name: 'OpenRepos',
url: 'https://openrepos.net/content/ahappyhuman/sailfin'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/heartfin/harbour-sailfin'
}
]
},
{
id: 'yatse',
name: 'Yatse',
description: 'A third party remote control for Jellyfin with support for Chromecast playback.',
clientType: ClientType.ThirdParty,
deviceTypes: [DeviceType.Mobile],
licenseType: LicenseType.Proprietary,
platforms: [Platform.Android],
primaryLinks: [
{
id: 'play-store',
name: 'Play Store',
url: 'https://play.google.com/store/apps/details?id=org.leetzone.android.yatsewidgetfree'
}
],
secondaryLinks: [
{
id: 'yatse',
name: 'Website',
url: 'https://yatse.tv/'
}
]
},
{
id: 'jellyfin-androidtv',
name: 'Jellyfin for Android TV',
description: 'The official Jellyfin app for Android TV devices.',
clientType: ClientType.Official,
deviceTypes: [DeviceType.TV],
licenseType: LicenseType.OpenSource,
platforms: [Platform.AndroidTV, Platform.FireOS],
primaryLinks: [
{
id: 'amazon-store',
name: 'Amazon Appstore',
url: 'https://www.amazon.com/gp/aw/d/B07TX7Z725'
},
{
id: 'play-store',
name: 'Play Store',
url: 'https://play.google.com/store/apps/details?id=org.jellyfin.androidtv'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jellyfin/jellyfin-androidtv'
}
],
recommended: true
},
{
id: 'jellyfin-roku',
name: 'Jellyfin for Roku',
description: 'The official Jellyfin app for Roku devices.',
clientType: ClientType.Official,
deviceTypes: [DeviceType.TV],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Roku],
primaryLinks: [
{
id: 'roku-store',
name: 'Channel Store',
url: 'https://channelstore.roku.com/details/592369/jellyfin'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jellyfin/jellyfin-roku'
}
],
recommended: true
},
{
id: 'jellyfin-webos',
name: 'Jellyfin for WebOS',
description: 'The official Jellyfin app for WebOS devices.',
clientType: ClientType.Official,
deviceTypes: [DeviceType.TV],
licenseType: LicenseType.OpenSource,
platforms: [Platform.WebOS],
primaryLinks: [
{
id: 'jf-blog',
name: 'Older webOS Versions',
url: '/posts/webos-july2022'
},
{
id: 'lg-store',
name: 'Content Store - webOS 6+',
url: 'https://us.lgappstv.com/main/tvapp/detail?appId=1030579'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jellyfin/jellyfin-webos'
}
],
recommended: true
},
{
id: 'infuse',
name: 'Infuse',
description: 'A third-party client for iOS, iPadOS, and tvOS devices.',
clientType: ClientType.ThirdParty,
deviceTypes: [DeviceType.Mobile, DeviceType.TV],
licenseType: LicenseType.Proprietary,
platforms: [Platform.IOS, Platform.TVOS],
primaryLinks: [
{
id: 'apple-store',
name: 'App Store',
url: 'https://apps.apple.com/app/id1136220934?mt=8'
}
],
secondaryLinks: [
{
id: 'website',
name: 'Website',
url: 'https://firecore.com/infuse'
}
],
recommended: true
},
{
id: 'mopidy',
name: 'Mopidy-Jellyfin',
description: 'An official plugin for Mopidy that uses Jellyfin as a backend.',
clientType: ClientType.Official,
deviceTypes: [],
licenseType: LicenseType.OpenSource,
platforms: [],
primaryLinks: [
{
id: 'install',
name: 'Installation Guide',
url: 'https://jellyfin.org/docs/general/clients/mopidy.html'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/jellyfin/mopidy-jellyfin'
}
]
},
{
id: 'volumio',
name: 'Jellyfin Plugin for Volumio',
description: 'A Volumio plugin for playing audio from one or more Jellyfin servers.',
clientType: ClientType.ThirdParty,
deviceTypes: [],
licenseType: LicenseType.OpenSource,
platforms: [],
primaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/patrickkfkan/volumio-jellyfin'
}
]
},
{
id: 'discord-music',
name: 'Discord Music Bot for Jellyfin',
description: 'A Discord bot that allows playing your Jellyfin music library in Discord voice channels.',
clientType: ClientType.ThirdParty,
deviceTypes: [],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Discord],
primaryLinks: [
{
id: 'install',
name: 'Installation Guide',
url: 'https://github.com/kgt1/jellyfin-discord-music-bot#getting-started'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/kgt1/jellyfin-discord-music-bot'
}
]
},
{
id: 'jellycli',
name: 'Jellycli',
description: 'A terminal player for Jellyfin, only for music at the moment.',
clientType: ClientType.ThirdParty,
deviceTypes: [],
licenseType: LicenseType.OpenSource,
platforms: [],
primaryLinks: [
{
id: 'gh-downloads',
name: 'GitHub Downloads',
url: 'https://github.com/tryffel/jellycli/releases'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/tryffel/jellycli'
}
]
},
{
id: 'jftui',
name: 'jftui',
description: 'A terminal client for Jellyfin built as a REPL interface, that uses mpv for multimedia playback.',
clientType: ClientType.ThirdParty,
deviceTypes: [],
licenseType: LicenseType.OpenSource,
platforms: [],
primaryLinks: [
{
id: 'install',
name: 'Installation Guide',
url: 'https://github.com/Aanok/jftui#installation'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/Aanok/jftui'
}
]
},
{
id: 'web-scrobbler',
name: 'Web Scrobbler',
description: 'Web Scrobbler helps online music listeners to scrobble their playback history.',
clientType: ClientType.ThirdParty,
deviceTypes: [],
licenseType: LicenseType.OpenSource,
platforms: [Platform.Browser],
primaryLinks: [
{
id: 'install',
name: 'Installation Guide',
url: 'https://github.com/web-scrobbler/web-scrobbler#installation'
}
],
secondaryLinks: [
{
id: 'github',
name: 'GitHub',
url: 'https://github.com/web-scrobbler/web-scrobbler'
},
{
id: 'website',
name: 'Website',
url: 'https://web-scrobbler.com'
}
]
}
];
+60 -4
View File
@@ -1,11 +1,67 @@
import React from 'react';
import Layout from '@theme/Layout';
import React, { useState } from 'react';
import ClientDetails from '../components/ClientDetails';
import Pill from '../components/Pill';
import { Clients, DeviceType, Platform } from '../data/clients';
type ClientFilter = {
recommended: boolean;
deviceType?: DeviceType;
platform?: Platform;
};
export default function Plugins() {
const [filter, setFilter] = useState<ClientFilter>({
recommended: true
});
return (
<Layout>
<h1>Clients</h1>
<p>Placeholder page</p>
<Layout title='Clients'>
<h1 className='text--center'>Clients</h1>
<main className='margin-vert--lg'>
<section className='container'>
<ul className='pills'>
<Pill
active={filter.recommended}
onClick={() => {
setFilter({ ...filter, recommended: true });
}}
>
Recommended Clients
</Pill>
<Pill
active={!filter.recommended}
onClick={() => {
setFilter({ ...filter, recommended: false });
}}
>
All Clients
</Pill>
</ul>
{Clients.filter((client) => {
let result = true;
if (filter.recommended) {
result = result && !!client.recommended;
}
if (typeof filter.deviceType !== 'undefined') {
result = result && client.deviceTypes.includes(filter.deviceType);
}
if (typeof filter.platform !== 'undefined') {
result = result && client.platforms.includes(filter.platform);
}
return result;
}).map((client) => (
<ClientDetails key={client.id} client={client} />
))}
</section>
</main>
</Layout>
);
}