refactor(website): polish on Showcase page (#5969)

This commit is contained in:
Sébastien Lorber 2021-11-20 18:31:20 +01:00 committed by GitHub
parent 63bd6b9025
commit 668f3c2506
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 268 additions and 161 deletions

View file

@ -33,8 +33,9 @@ module.exports = {
},
setupFiles: ['./jest/stylelint-rule-test.js', './jest/polyfills.js'],
moduleNameMapper: {
// Jest can't resolve CSS imports
'^.+\\.css$': '<rootDir>/jest/emptyModule.js',
// Jest can't resolve CSS or asset imports
'^.+\\.(css|jpg|jpeg|png|svg)$': '<rootDir>/jest/emptyModule.js',
// TODO we need to allow Jest to resolve core Webpack aliases automatically
'@docusaurus/(browserContext|BrowserOnly|ComponentCreator|constants|docusaurusContext|ExecutionEnvironment|Head|Interpolate|isInternalUrl|Link|Noop|renderRoutes|router|Translate|use.*)':
'@docusaurus/core/lib/client/exports/$1',
@ -42,5 +43,6 @@ module.exports = {
'@generated/.*': '<rootDir>/jest/emptyModule.js',
// TODO maybe use "projects" + multiple configs if we plan to add tests to another theme?
'@theme/(.*)': '@docusaurus/theme-classic/src/theme/$1',
'@site/(.*)': 'website/$1',
},
};

View file

@ -68,7 +68,10 @@
},
"devDependencies": {
"@tsconfig/docusaurus": "^1.0.4",
"@types/jest": "^25.2.1",
"cross-env": "^7.0.3",
"fs-extra": "^10.0.0",
"image-size": "^1.0.0",
"raw-loader": "^4.0.2"
}
}

View file

@ -0,0 +1,165 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {TagList, User, sortedUsers} from '../users';
import {difference} from '@site/src/utils/jsUtils';
import fs from 'fs-extra';
import path from 'path';
import imageSize from 'image-size';
describe('users', () => {
test('are valid', () => {
sortedUsers.forEach(ensureUserValid);
});
test('have valid images', async () => {
const minCardImageWidth = 304;
const minCardImageHeight = 150;
const minCardImageHeightScaled = 140;
const imageDir = path.join(__dirname, '../showcase');
const files = await fs.readdir(imageDir);
// eslint-disable-next-line no-restricted-syntax
for (const file of files) {
const size = imageSize(path.join(imageDir, file));
if (size.width < minCardImageWidth) {
throw new Error(
`Image width should be >= ${minCardImageWidth}
Image=${file}`,
);
}
if (size.height < minCardImageHeight) {
throw new Error(
`Image height should be >= ${minCardImageHeight}
Image=${file}`,
);
}
const scaledHeight = size.height / (size.width / minCardImageWidth);
if (scaledHeight < minCardImageHeightScaled) {
throw new Error(
`Image height is too small compared to width
After downscaling to width=${minCardImageWidth}, height would be ${scaledHeight} while the minimum is ${minCardImageHeightScaled}
Image=${file}`,
);
}
}
});
});
// TODO, refactor legacy test code
// Fail-fast on common errors
function ensureUserValid(user: User) {
function checkFields() {
const keys = Object.keys(user);
const validKeys = [
'title',
'description',
'preview',
'website',
'source',
'tags',
];
const unknownKeys = difference(keys, validKeys);
if (unknownKeys.length > 0) {
throw new Error(
`Site contains unknown attribute names=[${unknownKeys.join(',')}]`,
);
}
}
function checkTitle() {
if (!user.title) {
throw new Error('Site title is missing');
}
}
function checkDescription() {
if (!user.description) {
throw new Error('Site description is missing');
}
}
function checkWebsite() {
if (!user.website) {
throw new Error('Site website is missing');
}
const isHttpUrl =
user.website.startsWith('http://') || user.website.startsWith('https://');
if (!isHttpUrl) {
throw new Error(
`Site website does not look like a valid url: ${user.website}`,
);
}
}
function checkPreview() {
if (
!user.preview ||
(user.preview instanceof String &&
(user.preview.startsWith('http') || user.preview.startsWith('//')))
) {
throw new Error(
`Site has bad image preview=[${user.preview}].\nThe image should be hosted on Docusaurus site, and not use remote HTTP or HTTPS URLs`,
);
}
}
function checkTags() {
if (
!user.tags ||
!(user.tags instanceof Array) ||
(user.tags as string[]).includes('')
) {
throw new Error(`Bad showcase tags=[${JSON.stringify(user.tags)}]`);
}
const unknownTags = difference(user.tags, TagList);
if (unknownTags.length > 0) {
throw new Error(
`Unknown tags=[${unknownTags.join(
',',
)}\nThe available tags are ${TagList.join(',')}`,
);
}
}
function checkOpenSource() {
if (typeof user.source === 'undefined') {
throw new Error(
"The source attribute is required.\nIf your Docusaurus site is not open-source, please make it explicit with 'source: null'",
);
} else {
const hasOpenSourceTag = user.tags.includes('opensource');
if (user.source === null && hasOpenSourceTag) {
throw new Error(
"You can't add the opensource tag to a site that does not have a link to source code.",
);
} else if (user.source && !hasOpenSourceTag) {
throw new Error(
"For open-source sites, please add the 'opensource' tag",
);
}
}
}
try {
checkFields();
checkTitle();
checkDescription();
checkWebsite();
checkPreview();
checkTags();
checkOpenSource();
} catch (e) {
throw new Error(
`Showcase site with title=${user.title} contains errors:\n${e.message}`,
);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 521 KiB

View file

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 623 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 518 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 562 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 525 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 KiB

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 643 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 703 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 582 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 495 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 387 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 636 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 469 KiB

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 823 KiB

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 671 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 516 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 554 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 414 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 433 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 357 KiB

BIN
website/src/data/showcase/shotstack.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 KiB

After

Width:  |  Height:  |  Size: 598 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 389 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 373 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 734 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 433 KiB

View file

@ -7,7 +7,7 @@
/* eslint-disable global-require */
import {difference, sortBy} from '@site/src/utils/jsUtils';
import {sortBy} from '@site/src/utils/jsUtils';
/*
* ADD YOUR SITE TO THE DOCUSAURUS SHOWCASE:
@ -54,7 +54,7 @@ export type TagType =
| 'i18n'
| 'versioning'
| 'large'
| 'facebook'
| 'meta'
| 'personal'
| 'rtl';
@ -121,9 +121,9 @@ export const Tags: Record<TagType, Tag> = {
color: '#8c2f00',
},
facebook: {
label: 'Facebook',
description: 'Docusaurus sites of Facebook projects',
meta: {
label: 'Meta',
description: 'Docusaurus sites of Meta (formerly Facebook) projects',
color: '#4267b2', // Facebook blue
},
@ -258,7 +258,7 @@ const Users: User[] = [
{
title: 'Blogasaurus',
description: 'A blog written using Docasaurus.',
preview: require('./showcase/Blogasaurus.png'),
preview: require('./showcase/blogasaurus.png'),
website: 'https://blog.palashsh.me/',
source: 'https://github.com/BattleOfPlassey/blogasaurus',
tags: ['personal', 'opensource'],
@ -330,7 +330,7 @@ const Users: User[] = [
preview: require('./showcase/componentkit.png'),
website: 'https://componentkit.org',
source: 'https://github.com/facebook/componentkit',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'ConfigCat Feature Flags',
@ -363,7 +363,7 @@ const Users: User[] = [
preview: require('./showcase/create-react-app.png'),
website: 'https://facebook.github.io/create-react-app/',
source: 'https://github.com/facebook/create-react-app',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'CryptoDevHub',
@ -432,7 +432,7 @@ const Users: User[] = [
preview: require('./showcase/draftjs.png'),
website: 'https://draftjs.org/',
source: 'https://github.com/facebook/draft-js',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'Easyjwt',
@ -483,7 +483,7 @@ const Users: User[] = [
preview: require('./showcase/fbt.png'),
website: 'https://facebookincubator.github.io/fbt/',
source: 'https://github.com/facebook/fbt',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'Fenghua Frontend Developer',
@ -515,7 +515,7 @@ const Users: User[] = [
preview: require('./showcase/flipper.png'),
website: 'https://fbflipper.com',
source: 'https://github.com/facebook/flipper',
tags: ['opensource', 'design', 'facebook'],
tags: ['opensource', 'design', 'meta'],
},
{
title: 'FlexIt Analytics',
@ -531,7 +531,7 @@ const Users: User[] = [
preview: require('./showcase/flux.png'),
website: 'https://facebook.github.io/flux/',
source: 'https://github.com/facebook/flux',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'FoalTS',
@ -629,7 +629,7 @@ const Users: User[] = [
preview: require('./showcase/hermes.png'),
website: 'https://hermesengine.dev',
source: 'https://github.com/facebook/hermes',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'Home Assistant',
@ -645,7 +645,7 @@ const Users: User[] = [
preview: require('./showcase/idb.png'),
website: 'https://www.fbidb.io/',
source: 'https://github.com/facebook/idb',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'IntelAGENT Billing',
@ -736,7 +736,7 @@ const Users: User[] = [
preview: require('./showcase/mapillaryjs.png'),
website: 'https://mapillary.github.io/mapillary-js/',
source: 'https://github.com/mapillary/mapillary-js',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'MediaMachine',
@ -761,7 +761,7 @@ const Users: User[] = [
preview: require('./showcase/metro.png'),
website: 'https://facebook.github.io/metro/',
source: 'https://github.com/facebook/metro',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'Mia-Platform',
@ -969,10 +969,10 @@ const Users: User[] = [
{
title: 'Profilo',
description: 'An Android performance library',
preview: require('./showcase/profolo.png'),
preview: require('./showcase/profilo.png'),
website: 'https://facebookincubator.github.io/profilo/',
source: 'https://github.com/facebookincubator/profilo',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'Pyre',
@ -980,7 +980,7 @@ const Users: User[] = [
preview: require('./showcase/pyre.png'),
website: 'https://pyre-check.org',
source: 'https://github.com/facebook/pyre-check',
tags: ['opensource', 'facebook'],
tags: ['opensource', 'meta'],
},
{
title: 'QA-Board',
@ -1042,7 +1042,7 @@ const Users: User[] = [
source: 'https://github.com/facebook/react-native-website',
tags: [
'opensource',
'facebook',
'meta',
'large',
'favorite',
'design',
@ -1363,7 +1363,7 @@ const Users: User[] = [
preview: require('./showcase/the-diff.png'),
website: 'https://thediffpodcast.com',
source: null,
tags: ['facebook'],
tags: ['meta'],
},
{
title: 'Tinaël Devresse',
@ -1604,114 +1604,3 @@ function sortUsers() {
}
export const sortedUsers = sortUsers();
// Fail-fast on common errors
function ensureUserValid(user: User) {
function checkFields() {
const keys = Object.keys(user);
const validKeys = [
'title',
'description',
'preview',
'website',
'source',
'tags',
];
const unknownKeys = difference(keys, validKeys);
if (unknownKeys.length > 0) {
throw new Error(
`Site contains unknown attribute names=[${unknownKeys.join(',')}]`,
);
}
}
function checkTitle() {
if (!user.title) {
throw new Error('Site title is missing');
}
}
function checkDescription() {
if (!user.description) {
throw new Error('Site description is missing');
}
}
function checkWebsite() {
if (!user.website) {
throw new Error('Site website is missing');
}
const isHttpUrl =
user.website.startsWith('http://') || user.website.startsWith('https://');
if (!isHttpUrl) {
throw new Error(
`Site website does not look like a valid url: ${user.website}`,
);
}
}
function checkPreview() {
if (
!user.preview ||
(user.preview instanceof String &&
(user.preview.startsWith('http') || user.preview.startsWith('//')))
) {
throw new Error(
`Site has bad image preview=[${user.preview}].\nThe image should be hosted on Docusaurus site, and not use remote HTTP or HTTPS URLs`,
);
}
}
function checkTags() {
if (
!user.tags ||
!(user.tags instanceof Array) ||
(user.tags as string[]).includes('')
) {
throw new Error(`Bad showcase tags=[${JSON.stringify(user.tags)}]`);
}
const unknownTags = difference(user.tags, TagList);
if (unknownTags.length > 0) {
throw new Error(
`Unknown tags=[${unknownTags.join(
',',
)}\nThe available tags are ${TagList.join(',')}`,
);
}
}
function checkOpenSource() {
if (typeof user.source === 'undefined') {
throw new Error(
"The source attribute is required.\nIf your Docusaurus site is not open-source, please make it explicit with 'source: null'",
);
} else {
const hasOpenSourceTag = user.tags.includes('opensource');
if (user.source === null && hasOpenSourceTag) {
throw new Error(
"You can't add the opensource tag to a site that does not have a link to source code.",
);
} else if (user.source && !hasOpenSourceTag) {
throw new Error(
"For open-source sites, please add the 'opensource' tag",
);
}
}
}
try {
checkFields();
checkTitle();
checkDescription();
checkWebsite();
checkPreview();
checkTags();
checkOpenSource();
} catch (e) {
throw new Error(
`Showcase site with title=${user.title} contains errors:\n${e.message}`,
);
}
}
Users.forEach(ensureUserValid);

View file

@ -12,7 +12,7 @@ import Link from '@docusaurus/Link';
import styles from './styles.module.css';
import FavoriteIcon from '@site/src/components/svgIcons/FavoriteIcon';
import Tooltip from '@site/src/components/showcase/ShowcaseTooltip';
import Tooltip from '../ShowcaseTooltip';
import {Tags, TagList, TagType, User, Tag} from '@site/src/data/users';
import {sortBy} from '@site/src/utils/jsUtils';

View file

@ -7,8 +7,8 @@
.showcaseCardImage {
overflow: hidden;
max-height: 150px;
border-bottom: 4px solid var(--ifm-color-primary);
height: 150px;
border-bottom: 2px solid var(--ifm-color-emphasis-200);
}
.showcaseCardHeader {

View file

@ -9,6 +9,7 @@ import React, {useState, useEffect, useCallback} from 'react';
import {useHistory, useLocation} from '@docusaurus/router';
import styles from './styles.module.css';
import clsx from 'clsx';
export type Operator = 'OR' | 'AND';
@ -36,7 +37,7 @@ export default function ShowcaseFilterToggle(): JSX.Element {
}, [operator, location, history]);
return (
<div className="shadow--md">
<div>
<input
type="checkbox"
id={id}
@ -51,7 +52,7 @@ export default function ShowcaseFilterToggle(): JSX.Element {
checked={operator}
/>
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
<label htmlFor={id} className={styles.checkboxLabel}>
<label htmlFor={id} className={clsx(styles.checkboxLabel, 'shadow--md')}>
<span className={styles.checkboxLabelOr}>OR</span>
<span className={styles.checkboxLabelAnd}>AND</span>
<span className={styles.checkboxToggle} aria-hidden />

View file

@ -13,14 +13,14 @@ import clsx from 'clsx';
import FavoriteIcon from '@site/src/components/svgIcons/FavoriteIcon';
import ShowcaseTagSelect, {
readSearchTags,
} from '@site/src/components/showcase/ShowcaseTagSelect';
} from './_components/ShowcaseTagSelect';
import ShowcaseFilterToggle, {
Operator,
readOperator,
} from '@site/src/components/showcase/ShowcaseFilterToggle';
import ShowcaseCard from '@site/src/components/showcase/ShowcaseCard';
} from './_components/ShowcaseFilterToggle';
import ShowcaseCard from './_components/ShowcaseCard';
import {sortedUsers, Tags, TagList, User, TagType} from '@site/src/data/users';
import Tooltip from '@site/src/components/showcase/ShowcaseTooltip';
import ShowcaseTooltip from './_components/ShowcaseTooltip';
import {useLocation} from '@docusaurus/router';
@ -82,15 +82,15 @@ function useSelectedTags() {
function ShowcaseHeader() {
return (
<section className="margin-top--lg margin-bottom--xl text--center">
<section className="margin-top--lg margin-bottom--lg text--center">
<h1>{TITLE}</h1>
<p>{DESCRIPTION}</p>
<a
className={clsx('button button--primary', styles.showcaseCardSrcBtn)}
className="button button--primary"
href={EDIT_URL}
target="_blank"
rel="noreferrer">
🙏 Add your site
🙏 Please add your site
</a>
</section>
);
@ -99,13 +99,13 @@ function ShowcaseHeader() {
function ShowcaseFilters() {
const filteredUsers = useFilteredUsers();
return (
<section className="container margin-top--xl margin-bottom--lg">
<section className="container margin-top--l margin-bottom--lg">
<div className={clsx('margin-bottom--sm', styles.filterCheckbox)}>
<span>
<h3>Filter</h3>
<p>{`(${filteredUsers.length} site${
<h2>Filters</h2>
<span>{`(${filteredUsers.length} site${
filteredUsers.length > 1 ? 's' : ''
})`}</p>
})`}</span>
</span>
<ShowcaseFilterToggle />
</div>
@ -116,7 +116,10 @@ function ShowcaseFilters() {
return (
<li key={i} className={styles.checkboxListItem}>
<Tooltip id={id} text={description} anchorEl="#__docusaurus">
<ShowcaseTooltip
id={id}
text={description}
anchorEl="#__docusaurus">
<ShowcaseTagSelect
tag={tag}
id={id}
@ -137,7 +140,7 @@ function ShowcaseFilters() {
)
}
/>
</Tooltip>
</ShowcaseTooltip>
</li>
);
})}
@ -161,7 +164,7 @@ function ShowcaseCards() {
return (
<section className="margin-top--lg margin-bottom--xl">
<div className="container padding-vert--md text--center">
<h3>No result</h3>
<h2>No result</h2>
</div>
</section>
);
@ -178,7 +181,7 @@ function ShowcaseCards() {
'margin-bottom--md',
styles.showcaseFavoriteHeader,
)}>
<h3>Our favorites</h3>
<h2>Our favorites</h2>
<FavoriteIcon svgClass={styles.svgIconFavorite} />
</div>
<ul className={clsx('container', styles.showcaseList)}>
@ -188,8 +191,8 @@ function ShowcaseCards() {
</ul>
</div>
</div>
<div className="container margin-top--xl">
<h3 className={styles.showcaseHeader}>All sites</h3>
<div className="container margin-top--lg">
<h2 className={styles.showcaseHeader}>All sites</h2>
<ul className={styles.showcaseList}>
{otherUsers.map((user) => (
<ShowcaseCard key={user.title} user={user} />

View file

@ -18,6 +18,7 @@
.filterCheckbox > span {
display: flex;
flex: 1 1 auto;
align-items: center;
}
.filterCheckbox > span > * {
@ -69,8 +70,8 @@
}
.showcaseFavorite {
padding-top: 3rem;
padding-bottom: 3rem;
padding-top: 2rem;
padding-bottom: 2rem;
background-color: var(--site-color-favorite-background);
}
@ -79,10 +80,15 @@
align-items: center;
}
.showcaseFavoriteHeader > h3 {
.showcaseFavoriteHeader > h2 {
margin-bottom: 0;
}
.showcaseFavoriteHeader > svg {
width: 30px;
height: 30px;
}
.svgIconFavoriteXs,
.svgIconFavorite {
color: var(--site-color-svgIcon-favorite);

View file

@ -4,7 +4,8 @@
"compilerOptions": {
"lib": ["DOM", "ESNext"],
"baseUrl": ".",
"resolveJsonModule": true
"resolveJsonModule": true,
"types": ["@types/jest"]
},
"exclude": ["src/sw.js"]
}

View file

@ -4231,6 +4231,14 @@
dependencies:
"@types/istanbul-lib-report" "*"
"@types/jest@^25.2.1":
version "25.2.3"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-25.2.3.tgz#33d27e4c4716caae4eced355097a47ad363fdcaf"
integrity sha512-JXc1nK/tXHiDhV55dvfzqtmP4S3sy3T3ouV2tkViZgxY/zeUkcpQcQPGRlgF4KmWzWW5oiWYSZwtCB+2RsE4Fw==
dependencies:
jest-diff "^25.2.1"
pretty-format "^25.2.1"
"@types/jest@^26.0.20":
version "26.0.24"
resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a"
@ -8361,6 +8369,11 @@ dezalgo@^1.0.0:
asap "^2.0.0"
wrappy "1"
diff-sequences@^25.2.6:
version "25.2.6"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd"
integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==
diff-sequences@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1"
@ -11227,6 +11240,13 @@ image-q@^1.1.1:
resolved "https://registry.yarnpkg.com/image-q/-/image-q-1.1.1.tgz#fc84099664460b90ca862d9300b6bfbbbfbf8056"
integrity sha1-/IQJlmRGC5DKhi2TALa/u7+/gFY=
image-size@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.0.0.tgz#58b31fe4743b1cec0a0ac26f5c914d3c5b2f0750"
integrity sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw==
dependencies:
queue "6.0.2"
immer@^9.0.6:
version "9.0.6"
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.6.tgz#7a96bf2674d06c8143e327cbf73539388ddf1a73"
@ -12139,6 +12159,16 @@ jest-config@^26.6.3:
micromatch "^4.0.2"
pretty-format "^26.6.2"
jest-diff@^25.2.1:
version "25.5.0"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9"
integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==
dependencies:
chalk "^3.0.0"
diff-sequences "^25.2.6"
jest-get-type "^25.2.6"
pretty-format "^25.5.0"
jest-diff@^26.0.0, jest-diff@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394"
@ -16417,7 +16447,7 @@ pretty-format@^24.9.0:
ansi-styles "^3.2.0"
react-is "^16.8.4"
pretty-format@^25.5.0:
pretty-format@^25.2.1, pretty-format@^25.5.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a"
integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==
@ -16699,6 +16729,13 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
queue@6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/queue/-/queue-6.0.2.tgz#b91525283e2315c7553d2efa18d83e76432fed65"
integrity sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==
dependencies:
inherits "~2.0.3"
quick-lru@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"