mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-02 03:37:48 +02:00
feat: multiple playground choices (#5207)
* poc of using netlify functions for playground redirections * push * cleanup * restore files * fix netlify functions? * fix netlify functions? * implement serverless functions for playgrounds with persistent cookie * move new.docusaurus.io to monorepo packages * move new.docusaurus.io to monorepo packages * lockfile * push * catch-all redirect * Translate/Interpolate: add better error message if not used correctly * Add /docs/playground page * Add some additional doc
This commit is contained in:
parent
2b5fd2b490
commit
700a82aefe
19 changed files with 1426 additions and 129 deletions
|
@ -1,9 +1,9 @@
|
||||||
# new.docusaurus.io
|
# new.docusaurus.io
|
||||||
|
|
||||||
This is a Netlify deployment that only redirects to the official CodeSandbox template.
|
This is a Netlify deployment to handle the Docusaurus playgrounds shortcut [new.docusaurus.io](https://new.docusaurus.io).
|
||||||
|
|
||||||
https://codesandbox.io/s/github/facebook/docusaurus/tree/master/examples/classic
|
We use serverless functions because we want to persist the latest choice of the user in a cookie, so that it redirects directly to the preferred playground next time user visits this link. This is better to do it server-side with cookies and 302 redirects than with client redirects and localStorage.
|
||||||
|
|
||||||
The Netlify deployment (Joel can give access): https://app.netlify.com/sites/docusaurus-new/overview
|
Netlify deployment (Joel can give access): https://app.netlify.com/sites/docusaurus-new/overview
|
||||||
|
|
||||||
Builds are stopped because we shouldn't need to redeploy the \_redirects file. You can just trigger a manual build if needed.
|
Builds are stopped because we shouldn't need to redeploy very often. You can just trigger a manual build if needed.
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
/* https://codesandbox.io/s/docusaurus
|
|
77
admin/new.docusaurus.io/functionUtils/playgroundUtils.ts
Normal file
77
admin/new.docusaurus.io/functionUtils/playgroundUtils.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/**
|
||||||
|
* 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 {HandlerEvent, HandlerResponse} from '@netlify/functions';
|
||||||
|
|
||||||
|
const CookieName = 'DocusaurusPlaygroundName';
|
||||||
|
|
||||||
|
const PlaygroundConfigs = {
|
||||||
|
codesandbox: 'https://codesandbox.io/s/docusaurus',
|
||||||
|
stackblitz: 'https://stackblitz.com/fork/docusaurus',
|
||||||
|
};
|
||||||
|
|
||||||
|
const PlaygroundDocumentationUrl = 'https://docusaurus.io/docs/playground';
|
||||||
|
|
||||||
|
export type PlaygroundName = keyof typeof PlaygroundConfigs;
|
||||||
|
|
||||||
|
function isValidPlaygroundName(
|
||||||
|
playgroundName: string,
|
||||||
|
): playgroundName is PlaygroundName {
|
||||||
|
return Object.keys(PlaygroundConfigs).includes(playgroundName);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createPlaygroundDocumentationResponse(): HandlerResponse {
|
||||||
|
return {
|
||||||
|
statusCode: 302,
|
||||||
|
headers: {
|
||||||
|
Location: PlaygroundDocumentationUrl,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createPlaygroundResponse(
|
||||||
|
playgroundName: PlaygroundName,
|
||||||
|
): HandlerResponse {
|
||||||
|
const playgroundUrl = PlaygroundConfigs[playgroundName];
|
||||||
|
return {
|
||||||
|
statusCode: 302,
|
||||||
|
headers: {
|
||||||
|
Location: playgroundUrl,
|
||||||
|
'Set-Cookie': `${CookieName}=${playgroundName}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspired by https://stackoverflow.com/a/3409200/82609
|
||||||
|
function parseCookieString(cookieString: string): Record<string, string> {
|
||||||
|
const result: Record<string, string> = {};
|
||||||
|
cookieString.split(';').forEach(function (cookie) {
|
||||||
|
const [name, value] = cookie.split('=');
|
||||||
|
result[name.trim()] = decodeURI(value);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readPlaygroundName(
|
||||||
|
event: HandlerEvent,
|
||||||
|
): PlaygroundName | undefined {
|
||||||
|
const parsedCookie: Record<string, string> = event.headers.cookie
|
||||||
|
? parseCookieString(event.headers.cookie)
|
||||||
|
: {};
|
||||||
|
const playgroundName: string | undefined = parsedCookie[CookieName];
|
||||||
|
|
||||||
|
if (playgroundName) {
|
||||||
|
if (isValidPlaygroundName(playgroundName)) {
|
||||||
|
return playgroundName;
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
`playgroundName found in cookie was invalid: ${playgroundName}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
14
admin/new.docusaurus.io/functions/codesandbox.ts
Normal file
14
admin/new.docusaurus.io/functions/codesandbox.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* 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 {Handler} from '@netlify/functions';
|
||||||
|
|
||||||
|
import {createPlaygroundResponse} from '../functionUtils/playgroundUtils';
|
||||||
|
|
||||||
|
export const handler: Handler = async function (_event, _context) {
|
||||||
|
return createPlaygroundResponse('codesandbox');
|
||||||
|
};
|
20
admin/new.docusaurus.io/functions/index.ts
Normal file
20
admin/new.docusaurus.io/functions/index.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* 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 {Handler} from '@netlify/functions';
|
||||||
|
|
||||||
|
import {
|
||||||
|
readPlaygroundName,
|
||||||
|
createPlaygroundResponse,
|
||||||
|
createPlaygroundDocumentationResponse,
|
||||||
|
} from '../functionUtils/playgroundUtils';
|
||||||
|
|
||||||
|
export const handler: Handler = async (event, _context) => {
|
||||||
|
const playgroundName = readPlaygroundName(event);
|
||||||
|
return playgroundName
|
||||||
|
? createPlaygroundResponse(playgroundName)
|
||||||
|
: createPlaygroundDocumentationResponse();
|
||||||
|
};
|
14
admin/new.docusaurus.io/functions/stackblitz.ts
Normal file
14
admin/new.docusaurus.io/functions/stackblitz.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* 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 {Handler} from '@netlify/functions';
|
||||||
|
|
||||||
|
import {createPlaygroundResponse} from '../functionUtils/playgroundUtils';
|
||||||
|
|
||||||
|
export const handler: Handler = async function (_event, _context) {
|
||||||
|
return createPlaygroundResponse('stackblitz');
|
||||||
|
};
|
23
admin/new.docusaurus.io/netlify.toml
Normal file
23
admin/new.docusaurus.io/netlify.toml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
[functions]
|
||||||
|
directory = "functions"
|
||||||
|
|
||||||
|
[[redirects]]
|
||||||
|
from = "/"
|
||||||
|
to = "/.netlify/functions/index"
|
||||||
|
status = 200
|
||||||
|
|
||||||
|
[[redirects]]
|
||||||
|
from = "/codesandbox"
|
||||||
|
to = "/.netlify/functions/codesandbox"
|
||||||
|
status = 200
|
||||||
|
|
||||||
|
[[redirects]]
|
||||||
|
from = "/stackblitz"
|
||||||
|
to = "/.netlify/functions/stackblitz"
|
||||||
|
status = 200
|
||||||
|
|
||||||
|
[[redirects]]
|
||||||
|
from = "/*"
|
||||||
|
to = "/.netlify/functions/index"
|
||||||
|
status = 200
|
14
admin/new.docusaurus.io/package.json
Normal file
14
admin/new.docusaurus.io/package.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"name": "new.docusaurus.io",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "netlify dev"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@netlify/functions": "^0.7.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"netlify-cli": "^5.2.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*",
|
"packages/*",
|
||||||
"website",
|
"website",
|
||||||
"packages/docusaurus-init/templates/*"
|
"packages/docusaurus-init/templates/*",
|
||||||
|
"admin/new.docusaurus.io"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "yarn build:packages && yarn start:v2",
|
"start": "yarn build:packages && yarn start:v2",
|
||||||
|
|
|
@ -92,5 +92,11 @@ export default function Interpolate<Str extends string>({
|
||||||
children,
|
children,
|
||||||
values,
|
values,
|
||||||
}: InterpolateProps<Str>): ReactNode {
|
}: InterpolateProps<Str>): ReactNode {
|
||||||
|
if (typeof children !== 'string') {
|
||||||
|
console.warn('Illegal <Interpolate> children', children);
|
||||||
|
throw new Error(
|
||||||
|
'The Docusaurus <Interpolate> component only accept simple string values',
|
||||||
|
);
|
||||||
|
}
|
||||||
return interpolate(children, values);
|
return interpolate(children, values);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,13 @@ export default function Translate<Str extends string>({
|
||||||
id,
|
id,
|
||||||
values,
|
values,
|
||||||
}: TranslateProps<Str>): JSX.Element {
|
}: TranslateProps<Str>): JSX.Element {
|
||||||
|
if (typeof children !== 'string') {
|
||||||
|
console.warn('Illegal <Translate> children', children);
|
||||||
|
throw new Error(
|
||||||
|
'The Docusaurus <Translate> component only accept simple string values',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const localizedMessage: string =
|
const localizedMessage: string =
|
||||||
getLocalizedMessage({message: children, id}) ?? children;
|
getLocalizedMessage({message: children, id}) ?? children;
|
||||||
|
|
||||||
|
|
24
website/docs/playground.mdx
Normal file
24
website/docs/playground.mdx
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Playground
|
||||||
|
|
||||||
|
Playgrounds allow you to run Docusaurus **in your browser, without installing anything**!
|
||||||
|
|
||||||
|
They are mostly useful for:
|
||||||
|
|
||||||
|
- Testing Docusaurus
|
||||||
|
- Reporting bugs
|
||||||
|
|
||||||
|
Use [new.docusaurus.io](https://new.docusaurus.io) as an easy-to-remember shortcut.
|
||||||
|
|
||||||
|
Choose one of the available options below.
|
||||||
|
|
||||||
|
```mdx-code-block
|
||||||
|
import {PlaygroundCardsRow} from '@site/src/components/Playground';
|
||||||
|
|
||||||
|
<PlaygroundCardsRow />
|
||||||
|
```
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
|
||||||
|
For convenience, we'll remember your choice next time you visit [new.docusaurus.io](https://new.docusaurus.io).
|
||||||
|
|
||||||
|
:::
|
|
@ -12,7 +12,12 @@ module.exports = {
|
||||||
type: 'category',
|
type: 'category',
|
||||||
label: 'Getting Started',
|
label: 'Getting Started',
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
items: ['installation', 'configuration', 'typescript-support'],
|
items: [
|
||||||
|
'installation',
|
||||||
|
'configuration',
|
||||||
|
'playground',
|
||||||
|
'typescript-support',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'category',
|
type: 'category',
|
||||||
|
|
81
website/src/components/Playground/index.js
Normal file
81
website/src/components/Playground/index.js
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/**
|
||||||
|
* 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 Translate from '@docusaurus/Translate';
|
||||||
|
import Link from '@docusaurus/Link';
|
||||||
|
import Image from '@theme/IdealImage';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
const Playgrounds = [
|
||||||
|
{
|
||||||
|
name: '📦 CodeSandbox',
|
||||||
|
image: require('@site/static/img/playgrounds/codesandbox.png'),
|
||||||
|
url: 'https://new.docusaurus.io/codesandbox',
|
||||||
|
description: (
|
||||||
|
<Translate id="playground.codesandbox.description">
|
||||||
|
CodeSandbox is a popular playground solution. Runs Docusaurus in a
|
||||||
|
remote Docker container.
|
||||||
|
</Translate>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '⚡ StackBlitz 🆕',
|
||||||
|
image: require('@site/static/img/playgrounds/stackblitz.png'),
|
||||||
|
url: 'https://new.docusaurus.io/stackblitz',
|
||||||
|
description: (
|
||||||
|
<Translate
|
||||||
|
id="playground.stackblitz.description"
|
||||||
|
values={{
|
||||||
|
webContainersLink: (
|
||||||
|
<Link target="https://blog.stackblitz.com/posts/introducing-webcontainers/">
|
||||||
|
WebContainers
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
}}>
|
||||||
|
{
|
||||||
|
'StackBlitz uses a novel {webContainersLink} technology to run Docusaurus directly in your browser.'
|
||||||
|
}
|
||||||
|
</Translate>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function PlaygroundCard({name, image, url, description}) {
|
||||||
|
return (
|
||||||
|
<div className="col col--6 margin-bottom--lg">
|
||||||
|
<div className={clsx('card')}>
|
||||||
|
<div className={clsx('card__image')}>
|
||||||
|
<Link to={url}>
|
||||||
|
<Image img={image} alt={`${name}'s image`} />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className="card__body">
|
||||||
|
<h3>{name}</h3>
|
||||||
|
<p>{description}</p>
|
||||||
|
</div>
|
||||||
|
<div className="card__footer">
|
||||||
|
<div className="button-group button-group--block">
|
||||||
|
<Link className="button button--secondary" to={url}>
|
||||||
|
<Translate id="playground.tryItButton">Try it now!</Translate>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PlaygroundCardsRow() {
|
||||||
|
return (
|
||||||
|
<div className="row">
|
||||||
|
{Playgrounds.map((playground) => (
|
||||||
|
<PlaygroundCard key={playground.name} {...playground} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
BIN
website/static/img/playgrounds/codesandbox.png
Normal file
BIN
website/static/img/playgrounds/codesandbox.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 373 KiB |
BIN
website/static/img/playgrounds/stackblitz.png
Normal file
BIN
website/static/img/playgrounds/stackblitz.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 394 KiB |
24
website/versioned_docs/version-2.0.0-beta.3/playground.mdx
Normal file
24
website/versioned_docs/version-2.0.0-beta.3/playground.mdx
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Playground
|
||||||
|
|
||||||
|
Playgrounds allow you to run Docusaurus **in your browser, without installing anything**!
|
||||||
|
|
||||||
|
They are mostly useful for:
|
||||||
|
|
||||||
|
- Testing Docusaurus
|
||||||
|
- Reporting bugs
|
||||||
|
|
||||||
|
Use [new.docusaurus.io](https://new.docusaurus.io) as an easy-to-remember shortcut.
|
||||||
|
|
||||||
|
Choose one of the available options below.
|
||||||
|
|
||||||
|
```mdx-code-block
|
||||||
|
import {PlaygroundCardsRow} from '@site/src/components/Playground';
|
||||||
|
|
||||||
|
<PlaygroundCardsRow />
|
||||||
|
```
|
||||||
|
|
||||||
|
:::tip
|
||||||
|
|
||||||
|
For convenience, we'll remember your choice next time you visit [new.docusaurus.io](https://new.docusaurus.io).
|
||||||
|
|
||||||
|
:::
|
|
@ -17,6 +17,10 @@
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
"id": "version-2.0.0-beta.3/configuration"
|
"id": "version-2.0.0-beta.3/configuration"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "doc",
|
||||||
|
"id": "version-2.0.0-beta.3/playground"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
"id": "version-2.0.0-beta.3/typescript-support"
|
"id": "version-2.0.0-beta.3/typescript-support"
|
||||||
|
|
Loading…
Add table
Reference in a new issue