refactor(website): polish on Showcase page (#5969)
|
@ -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',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
165
website/src/data/__tests__/user.test.ts
Normal 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}`,
|
||||
);
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 500 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 521 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 623 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 392 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 400 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 245 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 1 MiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 518 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 562 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 210 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 525 KiB |
Before Width: | Height: | Size: 492 KiB After Width: | Height: | Size: 2.6 MiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 1 MiB |
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 379 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 643 KiB |
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 703 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 377 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 582 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 1 MiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 495 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 387 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 427 KiB |
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 636 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 381 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 227 KiB |
Before Width: | Height: | Size: 469 KiB After Width: | Height: | Size: 2.3 MiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 428 KiB |
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
BIN
website/src/data/showcase/profilo.png
Normal file
After Width: | Height: | Size: 308 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 339 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 1.5 MiB |
Before Width: | Height: | Size: 823 KiB After Width: | Height: | Size: 271 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 671 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 516 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 554 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 383 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 540 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 414 KiB |
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 2 MiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 433 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 357 KiB |
BIN
website/src/data/showcase/shotstack.png
Executable file → Normal file
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 402 KiB |
Before Width: | Height: | Size: 442 KiB After Width: | Height: | Size: 598 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 572 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 247 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 389 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 373 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 471 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 734 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 433 KiB |
|
@ -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);
|
||||
|
|
|
@ -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';
|
||||
|
|
@ -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 {
|
|
@ -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 />
|
|
@ -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} />
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
"compilerOptions": {
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"baseUrl": ".",
|
||||
"resolveJsonModule": true
|
||||
"resolveJsonModule": true,
|
||||
"types": ["@types/jest"]
|
||||
},
|
||||
"exclude": ["src/sw.js"]
|
||||
}
|
||||
|
|
39
yarn.lock
|
@ -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"
|
||||
|
|