mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-21 13:06:58 +02:00
refactor(website): convert website to TypeScript (#5328)
* Initial work Signed-off-by: Josh-Cena <sidachen2003@gmail.com> * Minor changes Signed-off-by: Josh-Cena <sidachen2003@gmail.com> * Fix error Signed-off-by: Josh-Cena <sidachen2003@gmail.com> * This looks better Signed-off-by: Josh-Cena <sidachen2003@gmail.com> * Address suggestions Signed-off-by: Josh-Cena <sidachen2003@gmail.com> * Better style Signed-off-by: Josh-Cena <sidachen2003@gmail.com> * Better style Signed-off-by: Josh-Cena <sidachen2003@gmail.com> * Better context typing Signed-off-by: Josh-Cena <sidachen2003@gmail.com> * Update edit URL Signed-off-by: Josh-Cena <sidachen2003@gmail.com> * Minor refactor Signed-off-by: Josh-Cena <sidachen2003@gmail.com>
This commit is contained in:
parent
9afc900780
commit
6c21061e34
20 changed files with 193 additions and 111 deletions
|
@ -63,6 +63,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@tsconfig/docusaurus": "^1.0.3",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"raw-loader": "^4.0.2"
|
"raw-loader": "^4.0.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,17 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, {ReactNode} from 'react';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
function BrowserWindow({children, minHeight, url}) {
|
interface Props {
|
||||||
|
children: ReactNode;
|
||||||
|
minHeight: number;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function BrowserWindow({children, minHeight, url}: Props) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.browserWindow} style={{minHeight}}>
|
<div className={styles.browserWindow} style={{minHeight}}>
|
||||||
<div className={styles.browserWindowHeader}>
|
<div className={styles.browserWindowHeader}>
|
|
@ -6,17 +6,23 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
|
|
||||||
import Color from 'color';
|
import Color from 'color';
|
||||||
|
|
||||||
import CodeBlock from '@theme/CodeBlock';
|
import CodeBlock from '@theme/CodeBlock';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
const COLOR_SHADES = {
|
const COLOR_SHADES: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
adjustment: number;
|
||||||
|
adjustmentInput: string;
|
||||||
|
displayOrder: number;
|
||||||
|
codeOrder: number;
|
||||||
|
}
|
||||||
|
> = {
|
||||||
'--ifm-color-primary': {
|
'--ifm-color-primary': {
|
||||||
adjustment: 0,
|
adjustment: 0,
|
||||||
adjustmentInput: 0,
|
adjustmentInput: '0',
|
||||||
displayOrder: 3,
|
displayOrder: 3,
|
||||||
codeOrder: 0,
|
codeOrder: 0,
|
||||||
},
|
},
|
||||||
|
@ -60,7 +66,7 @@ const COLOR_SHADES = {
|
||||||
|
|
||||||
const DEFAULT_PRIMARY_COLOR = '3578e5';
|
const DEFAULT_PRIMARY_COLOR = '3578e5';
|
||||||
|
|
||||||
function ColorGenerator({children, minHeight, url}) {
|
function ColorGenerator() {
|
||||||
const [baseColor, setBaseColor] = useState(DEFAULT_PRIMARY_COLOR);
|
const [baseColor, setBaseColor] = useState(DEFAULT_PRIMARY_COLOR);
|
||||||
const [shades, setShades] = useState(COLOR_SHADES);
|
const [shades, setShades] = useState(COLOR_SHADES);
|
||||||
const color = Color('#' + baseColor);
|
const color = Color('#' + baseColor);
|
|
@ -45,7 +45,14 @@ const Playgrounds = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
function PlaygroundCard({name, image, url, description}) {
|
interface Props {
|
||||||
|
name: string;
|
||||||
|
image: any;
|
||||||
|
url: string;
|
||||||
|
description: JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
function PlaygroundCard({name, image, url, description}: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="col col--6 margin-bottom--lg">
|
<div className="col col--6 margin-bottom--lg">
|
||||||
<div className={clsx('card')}>
|
<div className={clsx('card')}>
|
|
@ -5,11 +5,11 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, {ReactNode} from 'react';
|
||||||
import Translate from '@docusaurus/Translate';
|
import Translate from '@docusaurus/Translate';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
|
|
||||||
function WebsiteLink({to, children}) {
|
function WebsiteLink({to, children}: {to: string; children?: ReactNode}) {
|
||||||
return (
|
return (
|
||||||
<Link to={to}>
|
<Link to={to}>
|
||||||
{children || (
|
{children || (
|
||||||
|
@ -19,7 +19,21 @@ function WebsiteLink({to, children}) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TeamProfileCard({className, name, children, githubUrl, twitterUrl}) {
|
interface ProfileProps {
|
||||||
|
className?: string;
|
||||||
|
name: string;
|
||||||
|
children: ReactNode;
|
||||||
|
githubUrl?: string;
|
||||||
|
twitterUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function TeamProfileCard({
|
||||||
|
className,
|
||||||
|
name,
|
||||||
|
children,
|
||||||
|
githubUrl,
|
||||||
|
twitterUrl,
|
||||||
|
}: ProfileProps) {
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<div className="card card--full-height">
|
<div className="card card--full-height">
|
||||||
|
@ -55,7 +69,7 @@ function TeamProfileCard({className, name, children, githubUrl, twitterUrl}) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TeamProfileCardCol(props) {
|
function TeamProfileCardCol(props: ProfileProps) {
|
||||||
return (
|
return (
|
||||||
<TeamProfileCard {...props} className={'col col--6 margin-bottom--lg'} />
|
<TeamProfileCard {...props} className={'col col--6 margin-bottom--lg'} />
|
||||||
);
|
);
|
|
@ -10,10 +10,10 @@ import React, {memo} from 'react';
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import Image from '@theme/IdealImage';
|
import Image from '@theme/IdealImage';
|
||||||
import {Tags, TagList} from '../../../data/users';
|
import {Tags, TagList, TagType, User, Tag} from '../../../data/users';
|
||||||
import {sortBy} from '../../../utils/jsUtils';
|
import {sortBy} from '../../../utils/jsUtils';
|
||||||
|
|
||||||
function TagIcon({label, description, icon}) {
|
function TagIcon({label, description, icon}: Tag) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={styles.tagIcon}
|
className={styles.tagIcon}
|
||||||
|
@ -24,7 +24,7 @@ function TagIcon({label, description, icon}) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ShowcaseCardTagIcons({tags}) {
|
function ShowcaseCardTagIcons({tags}: {tags: TagType[]}) {
|
||||||
const tagObjects = tags
|
const tagObjects = tags
|
||||||
.map((tag) => ({tag, ...Tags[tag]}))
|
.map((tag) => ({tag, ...Tags[tag]}))
|
||||||
.filter((tagObject) => !!tagObject.icon);
|
.filter((tagObject) => !!tagObject.icon);
|
||||||
|
@ -34,12 +34,16 @@ function ShowcaseCardTagIcons({tags}) {
|
||||||
TagList.indexOf(tagObject.tag),
|
TagList.indexOf(tagObject.tag),
|
||||||
);
|
);
|
||||||
|
|
||||||
return tagObjectsSorted.map((tagObject, index) => (
|
return (
|
||||||
<TagIcon key={index} {...tagObject} />
|
<>
|
||||||
));
|
{tagObjectsSorted.map((tagObject, index) => (
|
||||||
|
<TagIcon key={index} {...tagObject} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ShowcaseCard = memo(function ({user}) {
|
const ShowcaseCard = memo(function ({user}: {user: User}) {
|
||||||
return (
|
return (
|
||||||
<div key={user.title} className="col col--4 margin-bottom--lg">
|
<div key={user.title} className="col col--4 margin-bottom--lg">
|
||||||
<div className={clsx('card', styles.showcaseCard)}>
|
<div className={clsx('card', styles.showcaseCard)}>
|
|
@ -1,36 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 React from 'react';
|
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
|
||||||
|
|
||||||
function ShowcaseCheckbox({
|
|
||||||
className,
|
|
||||||
name,
|
|
||||||
label,
|
|
||||||
onChange,
|
|
||||||
checked,
|
|
||||||
...props
|
|
||||||
}) {
|
|
||||||
const id = `showcase_checkbox_id_${name};`;
|
|
||||||
return (
|
|
||||||
<div className={clsx(props.className, styles.checkboxContainer)} {...props}>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
id={id}
|
|
||||||
name={name}
|
|
||||||
onChange={onChange}
|
|
||||||
checked={checked}
|
|
||||||
/>
|
|
||||||
<label htmlFor={id}>{label}</label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ShowcaseCheckbox;
|
|
27
website/src/components/showcase/ShowcaseCheckbox/index.tsx
Normal file
27
website/src/components/showcase/ShowcaseCheckbox/index.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
* 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 React, {ComponentProps, ReactNode} from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
interface Props extends ComponentProps<'input'> {
|
||||||
|
label: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ShowcaseCheckbox({title, className, label, ...props}: Props) {
|
||||||
|
const id = `showcase_checkbox_id_${props.name};`;
|
||||||
|
return (
|
||||||
|
<div className={clsx(className, styles.checkboxContainer)} title={title}>
|
||||||
|
<input type="checkbox" id={id} {...props} />
|
||||||
|
<label htmlFor={id}>{label}</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ShowcaseCheckbox;
|
|
@ -5,17 +5,21 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, {ComponentProps} from 'react';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
function ShowcaseSelect({tag, label, onChange, value, children}) {
|
interface Props extends ComponentProps<'select'> {
|
||||||
const id = `showcase_select_id_${tag};`;
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ShowcaseSelect({label, ...props}: Props) {
|
||||||
|
const id = `showcase_select_id_${props.name};`;
|
||||||
return (
|
return (
|
||||||
<div className={styles.selectContainer}>
|
<div className={styles.selectContainer}>
|
||||||
<label htmlFor={id}>{label}</label>
|
<label htmlFor={id}>{label}</label>
|
||||||
<select id={id} name={tag} onChange={onChange} value={value}>
|
<select id={id} {...props}>
|
||||||
{children}
|
{props.children}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
|
@ -39,10 +39,38 @@ import {difference, sortBy} from '../utils/jsUtils';
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export type Tag = {
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
icon: JSX.Element;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TagType =
|
||||||
|
| 'favorite'
|
||||||
|
| 'opensource'
|
||||||
|
| 'product'
|
||||||
|
| 'design'
|
||||||
|
| 'i18n'
|
||||||
|
| 'versioning'
|
||||||
|
| 'multiInstance'
|
||||||
|
| 'large'
|
||||||
|
| 'facebook'
|
||||||
|
| 'personal'
|
||||||
|
| 'rtl';
|
||||||
|
|
||||||
|
export type User = {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
preview: any;
|
||||||
|
website: string;
|
||||||
|
source: string;
|
||||||
|
tags: TagType[];
|
||||||
|
};
|
||||||
|
|
||||||
// LIST OF AVAILABLE TAGS
|
// LIST OF AVAILABLE TAGS
|
||||||
// Available tags to assign to your site
|
// Available tags to assign to your site
|
||||||
// Please choose widely, we'll remove unappropriate tags
|
// Please choose widely, we'll remove unappropriate tags
|
||||||
export const Tags = {
|
export const Tags: Record<TagType, Tag> = {
|
||||||
// DO NOT USE THIS TAG: we choose sites to add to favorites
|
// DO NOT USE THIS TAG: we choose sites to add to favorites
|
||||||
favorite: {
|
favorite: {
|
||||||
label: 'Favorite',
|
label: 'Favorite',
|
||||||
|
@ -123,7 +151,7 @@ export const Tags = {
|
||||||
|
|
||||||
// Add your site to this list
|
// Add your site to this list
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const Users = [
|
const Users: User[] = [
|
||||||
{
|
{
|
||||||
title: 'Aide Jeune',
|
title: 'Aide Jeune',
|
||||||
description: 'French Discord server that helps young people who have been bullied or feel bad about themselves',
|
description: 'French Discord server that helps young people who have been bullied or feel bad about themselves',
|
||||||
|
@ -1276,7 +1304,7 @@ const Users = [
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export const TagList = Object.keys(Tags);
|
export const TagList = Object.keys(Tags) as TagType[];
|
||||||
function sortUsers() {
|
function sortUsers() {
|
||||||
let result = Users;
|
let result = Users;
|
||||||
// Sort by site name
|
// Sort by site name
|
||||||
|
@ -1289,7 +1317,7 @@ function sortUsers() {
|
||||||
export const SortedUsers = sortUsers();
|
export const SortedUsers = sortUsers();
|
||||||
|
|
||||||
// Fail-fast on common errors
|
// Fail-fast on common errors
|
||||||
function ensureUserValid(user) {
|
function ensureUserValid(user: User) {
|
||||||
function checkFields() {
|
function checkFields() {
|
||||||
const keys = Object.keys(user);
|
const keys = Object.keys(user);
|
||||||
const validKeys = [
|
const validKeys = [
|
||||||
|
@ -1346,7 +1374,11 @@ function ensureUserValid(user) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkTags() {
|
function checkTags() {
|
||||||
if (!user.tags || !(user.tags instanceof Array) || user.tags.includes('')) {
|
if (
|
||||||
|
!user.tags ||
|
||||||
|
!(user.tags instanceof Array) ||
|
||||||
|
(user.tags as string[]).includes('')
|
||||||
|
) {
|
||||||
throw new Error(`Bad showcase tags=[${JSON.stringify(user.tags)}]`);
|
throw new Error(`Bad showcase tags=[${JSON.stringify(user.tags)}]`);
|
||||||
}
|
}
|
||||||
const unknownTags = difference(user.tags, TagList);
|
const unknownTags = difference(user.tags, TagList);
|
|
@ -5,10 +5,10 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, {useState} from 'react';
|
||||||
|
|
||||||
export default function MyComponent() {
|
export default function MyComponent() {
|
||||||
const [bool, setBool] = React.useState(false);
|
const [bool, setBool] = useState(false);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>MyComponent rendered !</p>
|
<p>MyComponent rendered !</p>
|
|
@ -17,8 +17,8 @@ const BOARD_TOKEN = '054e0e53-d951-b14c-7e74-9eb8f9ed2f91';
|
||||||
function Feedback() {
|
function Feedback() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
canny();
|
canny();
|
||||||
window.Canny &&
|
(window as any).Canny &&
|
||||||
window.Canny('render', {
|
(window as any).Canny('render', {
|
||||||
boardToken: BOARD_TOKEN,
|
boardToken: BOARD_TOKEN,
|
||||||
basePath: '/feedback',
|
basePath: '/feedback',
|
||||||
});
|
});
|
|
@ -79,10 +79,14 @@ const QUOTES = [
|
||||||
];
|
];
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
const context = useDocusaurusContext();
|
const {
|
||||||
const {siteConfig: {customFields = {}, tagline} = {}} = context;
|
siteConfig: {
|
||||||
|
customFields: {description},
|
||||||
|
tagline,
|
||||||
|
},
|
||||||
|
} = useDocusaurusContext();
|
||||||
return (
|
return (
|
||||||
<Layout title={tagline} description={customFields.description}>
|
<Layout title={tagline} description={description as string}>
|
||||||
<main>
|
<main>
|
||||||
<div className={styles.hero}>
|
<div className={styles.hero}>
|
||||||
<div className={styles.heroInner}>
|
<div className={styles.heroInner}>
|
|
@ -16,14 +16,20 @@ import clsx from 'clsx';
|
||||||
import {useHistory, useLocation} from '@docusaurus/router';
|
import {useHistory, useLocation} from '@docusaurus/router';
|
||||||
|
|
||||||
import {toggleListItem} from '../../utils/jsUtils';
|
import {toggleListItem} from '../../utils/jsUtils';
|
||||||
import {SortedUsers, Tags, TagList} from '../../data/users';
|
import {SortedUsers, Tags, TagList, User, TagType} from '../../data/users';
|
||||||
|
|
||||||
|
type Operator = 'OR' | 'AND';
|
||||||
|
|
||||||
const TITLE = 'Docusaurus Site Showcase';
|
const TITLE = 'Docusaurus Site Showcase';
|
||||||
const DESCRIPTION = 'List of websites people are building with Docusaurus';
|
const DESCRIPTION = 'List of websites people are building with Docusaurus';
|
||||||
const EDIT_URL =
|
const EDIT_URL =
|
||||||
'https://github.com/facebook/docusaurus/edit/master/website/src/data/users.js';
|
'https://github.com/facebook/docusaurus/edit/master/website/src/data/users.tsx';
|
||||||
|
|
||||||
function filterUsers(users, selectedTags, operator) {
|
function filterUsers(
|
||||||
|
users: User[],
|
||||||
|
selectedTags: TagType[],
|
||||||
|
operator: Operator,
|
||||||
|
) {
|
||||||
if (selectedTags.length === 0) {
|
if (selectedTags.length === 0) {
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +45,11 @@ function filterUsers(users, selectedTags, operator) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function useFilteredUsers(users, selectedTags, operator) {
|
function useFilteredUsers(
|
||||||
|
users: User[],
|
||||||
|
selectedTags: TagType[],
|
||||||
|
operator: Operator,
|
||||||
|
) {
|
||||||
return useMemo(() => filterUsers(users, selectedTags, operator), [
|
return useMemo(() => filterUsers(users, selectedTags, operator), [
|
||||||
users,
|
users,
|
||||||
selectedTags,
|
selectedTags,
|
||||||
|
@ -49,11 +59,11 @@ function useFilteredUsers(users, selectedTags, operator) {
|
||||||
|
|
||||||
const TagQueryStringKey = 'tags';
|
const TagQueryStringKey = 'tags';
|
||||||
|
|
||||||
function readSearchTags(search) {
|
function readSearchTags(search: string) {
|
||||||
return new URLSearchParams(search).getAll(TagQueryStringKey);
|
return new URLSearchParams(search).getAll(TagQueryStringKey) as TagType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceSearchTags(search, newTags) {
|
function replaceSearchTags(search: string, newTags: TagType[]) {
|
||||||
const searchParams = new URLSearchParams(search);
|
const searchParams = new URLSearchParams(search);
|
||||||
searchParams.delete(TagQueryStringKey);
|
searchParams.delete(TagQueryStringKey);
|
||||||
newTags.forEach((tag) => searchParams.append(TagQueryStringKey, tag));
|
newTags.forEach((tag) => searchParams.append(TagQueryStringKey, tag));
|
||||||
|
@ -66,7 +76,7 @@ function useSelectedTags() {
|
||||||
const {push} = useHistory();
|
const {push} = useHistory();
|
||||||
|
|
||||||
// On SSR / first mount (hydration) no tag is selected
|
// On SSR / first mount (hydration) no tag is selected
|
||||||
const [selectedTags, setSelectedTags] = useState([]);
|
const [selectedTags, setSelectedTags] = useState<TagType[]>([]);
|
||||||
|
|
||||||
// Sync tags from QS to state (delayed on purpose to avoid SSR/Client hydration mismatch)
|
// Sync tags from QS to state (delayed on purpose to avoid SSR/Client hydration mismatch)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -76,7 +86,7 @@ function useSelectedTags() {
|
||||||
|
|
||||||
// Update the QS value
|
// Update the QS value
|
||||||
const toggleTag = useCallback(
|
const toggleTag = useCallback(
|
||||||
(tag) => {
|
(tag: TagType) => {
|
||||||
const tags = readSearchTags(location.search);
|
const tags = readSearchTags(location.search);
|
||||||
const newTags = toggleListItem(tags, tag);
|
const newTags = toggleListItem(tags, tag);
|
||||||
const newSearch = replaceSearchTags(location.search, newTags);
|
const newSearch = replaceSearchTags(location.search, newTags);
|
||||||
|
@ -106,7 +116,19 @@ function ShowcaseHeader() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ShowcaseFilters({selectedTags, toggleTag, operator, setOperator}) {
|
interface Props {
|
||||||
|
selectedTags: TagType[];
|
||||||
|
toggleTag: (tag: TagType) => void;
|
||||||
|
operator: Operator;
|
||||||
|
setOperator: (op: Operator) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ShowcaseFilters({
|
||||||
|
selectedTags,
|
||||||
|
toggleTag,
|
||||||
|
operator,
|
||||||
|
setOperator,
|
||||||
|
}: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="margin-top--l margin-bottom--md container">
|
<div className="margin-top--l margin-bottom--md container">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
|
@ -138,7 +160,7 @@ function ShowcaseFilters({selectedTags, toggleTag, operator, setOperator}) {
|
||||||
name="operator"
|
name="operator"
|
||||||
label="Filter: "
|
label="Filter: "
|
||||||
value={operator}
|
value={operator}
|
||||||
onChange={(e) => setOperator(e.target.value)}>
|
onChange={(e) => setOperator(e.target.value as Operator)}>
|
||||||
<option value="OR">OR</option>
|
<option value="OR">OR</option>
|
||||||
<option value="AND">AND</option>
|
<option value="AND">AND</option>
|
||||||
</ShowcaseSelect>
|
</ShowcaseSelect>
|
||||||
|
@ -148,7 +170,7 @@ function ShowcaseFilters({selectedTags, toggleTag, operator, setOperator}) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ShowcaseCards({filteredUsers}) {
|
function ShowcaseCards({filteredUsers}: {filteredUsers: User[]}) {
|
||||||
return (
|
return (
|
||||||
<section className="container margin-top--lg">
|
<section className="container margin-top--lg">
|
||||||
<h2>
|
<h2>
|
||||||
|
@ -176,7 +198,7 @@ function ShowcaseCards({filteredUsers}) {
|
||||||
|
|
||||||
function Showcase() {
|
function Showcase() {
|
||||||
const {selectedTags, toggleTag} = useSelectedTags();
|
const {selectedTags, toggleTag} = useSelectedTags();
|
||||||
const [operator, setOperator] = useState('OR');
|
const [operator, setOperator] = useState<Operator>('OR');
|
||||||
const filteredUsers = useFilteredUsers(SortedUsers, selectedTags, operator);
|
const filteredUsers = useFilteredUsers(SortedUsers, selectedTags, operator);
|
||||||
return (
|
return (
|
||||||
<Layout title={TITLE} description={DESCRIPTION}>
|
<Layout title={TITLE} description={DESCRIPTION}>
|
|
@ -17,14 +17,16 @@ import VersionsArchived from '@site/versionsArchived.json';
|
||||||
const VersionsArchivedList = Object.entries(VersionsArchived);
|
const VersionsArchivedList = Object.entries(VersionsArchived);
|
||||||
|
|
||||||
function Version() {
|
function Version() {
|
||||||
const {siteConfig} = useDocusaurusContext();
|
const {
|
||||||
|
siteConfig: {organizationName, projectName},
|
||||||
|
} = useDocusaurusContext();
|
||||||
const versions = useVersions();
|
const versions = useVersions();
|
||||||
const latestVersion = useLatestVersion();
|
const latestVersion = useLatestVersion();
|
||||||
const currentVersion = versions.find((version) => version.name === 'current');
|
const currentVersion = versions.find((version) => version.name === 'current');
|
||||||
const pastVersions = versions.filter(
|
const pastVersions = versions.filter(
|
||||||
(version) => version !== latestVersion && version.name !== 'current',
|
(version) => version !== latestVersion && version.name !== 'current',
|
||||||
);
|
);
|
||||||
const repoUrl = `https://github.com/${siteConfig.organizationName}/${siteConfig.projectName}`;
|
const repoUrl = `https://github.com/${organizationName}/${projectName}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout
|
<Layout
|
||||||
|
@ -77,7 +79,7 @@ function Version() {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(pastVersions.length > 0 || VersionsArchived.length > 0) && (
|
{(pastVersions.length > 0 || VersionsArchivedList.length > 0) && (
|
||||||
<div className="margin-bottom--lg">
|
<div className="margin-bottom--lg">
|
||||||
<h3 id="archive">Past versions (Not maintained anymore)</h3>
|
<h3 id="archive">Past versions (Not maintained anymore)</h3>
|
||||||
<p>
|
<p>
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React, {ComponentProps} from 'react';
|
||||||
|
|
||||||
export const ButtonExample = (props) => (
|
export const ButtonExample = (props: ComponentProps<'button'>) => (
|
||||||
<button
|
<button
|
||||||
{...props}
|
{...props}
|
||||||
style={{
|
style={{
|
10
website/src/types.d.ts
vendored
10
website/src/types.d.ts
vendored
|
@ -1,10 +0,0 @@
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// eslint-disable-next-line spaced-comment
|
|
||||||
/// <reference types="@docusaurus/module-type-aliases" />
|
|
||||||
/// <reference types="@docusaurus/theme-classic" />
|
|
|
@ -1,12 +1,12 @@
|
||||||
// Inspired by https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_difference
|
// Inspired by https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_difference
|
||||||
export function difference(...arrays) {
|
export function difference<T>(...arrays: T[][]) {
|
||||||
return arrays.reduce((a, b) => a.filter((c) => !b.includes(c)));
|
return arrays.reduce((a, b) => a.filter((c) => !b.includes(c)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inspired by https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_sortby-and-_orderby
|
// Inspired by https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_sortby-and-_orderby
|
||||||
export function sortBy(array, getter) {
|
export function sortBy<T>(array: T[], getter: (item: T) => unknown) {
|
||||||
function compareBy(getter) {
|
function compareBy(getter: (item: T) => unknown) {
|
||||||
return (a, b) =>
|
return (a: T, b: T) =>
|
||||||
getter(a) > getter(b) ? 1 : getter(b) > getter(a) ? -1 : 0;
|
getter(a) > getter(b) ? 1 : getter(b) > getter(a) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ export function sortBy(array, getter) {
|
||||||
return sortedArray;
|
return sortedArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toggleListItem(list, item) {
|
export function toggleListItem<T>(list: T[], item: T) {
|
||||||
const itemIndex = list.indexOf(item);
|
const itemIndex = list.indexOf(item);
|
||||||
if (itemIndex === -1) {
|
if (itemIndex === -1) {
|
||||||
return list.concat(item);
|
return list.concat(item);
|
|
@ -1,12 +1,11 @@
|
||||||
{
|
{
|
||||||
// This file is not used in compilation. It is here just for a nice editor experience.
|
// This file is not used in compilation. It is here just for a nice editor experience.
|
||||||
|
"extends": "@tsconfig/docusaurus/tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowJs": true,
|
"paths": {
|
||||||
"esModuleInterop": true,
|
"@site/*": ["./*"]
|
||||||
"jsx": "react",
|
},
|
||||||
"lib": ["DOM"],
|
"resolveJsonModule": true
|
||||||
"noEmit": true,
|
|
||||||
"noImplicitAny": false
|
|
||||||
},
|
},
|
||||||
"include": ["src/"]
|
"include": ["src/"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue