Port more content to website-next (#1435)
Summary: This builds upon https://github.com/facebook/yoga/pull/1433 and starts porting over and fixing some of the code in website-next. 1. Create a hero similar to current https://yogalayout.com hero 2. Start moving from `antd` and harcoded colors to [Infima](https://infima.dev/docs/getting-started/introduction/) primitives provided by Docusaurus 3. Replaced some more stock docusaurus assets, links, and text with the ones for Yoga. There is still a lot to do here (not the least, adding real content), but it's beginning to look like a website, and is already pretty snappy. Eventually I want to get SSR working correctly with Playground, which is still a little broken in the port. Pull Request resolved: https://github.com/facebook/yoga/pull/1435 Test Plan: **Gatsby Original** <img width="1795" alt="image" src="https://github.com/facebook/yoga/assets/835219/7670d53a-00a8-4146-a100-e4a05dd77488"> **New (light mode)** <img width="800" alt="image" src="https://github.com/facebook/yoga/assets/835219/ebe11d15-5f6f-445f-bcc8-9ec51ecfac62"> **New (dark mode)** <img width="800" alt="image" src="https://github.com/facebook/yoga/assets/835219/ca44a492-46df-410a-8303-baec3029ec49"> Reviewed By: yungsters Differential Revision: D50523462 Pulled By: NickGerleman fbshipit-source-id: 61b4610104f695a4e38a7d4bb6a0c2488bd6f89e
This commit is contained in:
committed by
Facebook GitHub Bot
parent
a20559063e
commit
92860077f9
4
.github/workflows/validate-website-next.yml
vendored
4
.github/workflows/validate-website-next.yml
vendored
@@ -17,10 +17,6 @@ on:
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup-js
|
||||
|
||||
- name: Build Yoga
|
||||
run: yarn build
|
||||
working-directory: javascript
|
||||
|
||||
- name: Build Website
|
||||
run: yarn build
|
||||
working-directory: website-next
|
||||
|
@@ -22,6 +22,7 @@ const {
|
||||
|
||||
const {readFile, writeFile} = require('fs/promises');
|
||||
|
||||
const chalk = require('chalk');
|
||||
const glob = require('glob');
|
||||
const path = require('path');
|
||||
const which = require('which');
|
||||
@@ -132,10 +133,37 @@ function runBenchTask() {
|
||||
};
|
||||
}
|
||||
|
||||
function findExecutable(name, failureMessage) {
|
||||
const exec = which.sync(name, {nothrow: true});
|
||||
if (exec) {
|
||||
return exec;
|
||||
}
|
||||
|
||||
logger.error(chalk.bold.red(failureMessage));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function tryFindExecutable(name, failureMessage) {
|
||||
const exec = which.sync(name, {nothrow: true});
|
||||
if (exec) {
|
||||
return exec;
|
||||
}
|
||||
|
||||
logger.warn(chalk.bold.yellow(failureMessage));
|
||||
return exec;
|
||||
}
|
||||
|
||||
function emcmakeGenerateTask() {
|
||||
return () => {
|
||||
const emcmake = which.sync('emcmake');
|
||||
const ninja = which.sync('ninja', {nothrow: true});
|
||||
const ninja = tryFindExecutable(
|
||||
'ninja',
|
||||
'Warning: Install Ninja (e.g. "brew install ninja") for faster builds',
|
||||
);
|
||||
const emcmake = findExecutable(
|
||||
'emcmake',
|
||||
'Error: Please install the emscripten SDK: https://emscripten.org/docs/getting_started/',
|
||||
);
|
||||
|
||||
const args = [
|
||||
'cmake',
|
||||
'-S',
|
||||
@@ -152,7 +180,10 @@ function emcmakeGenerateTask() {
|
||||
|
||||
function cmakeBuildTask(opts) {
|
||||
return () => {
|
||||
const cmake = which.sync('cmake');
|
||||
const cmake = findExecutable(
|
||||
'cmake',
|
||||
'Error: Please install CMake (e.g. "brew install cmake")',
|
||||
);
|
||||
const args = [
|
||||
'--build',
|
||||
'build',
|
||||
|
@@ -4,7 +4,8 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix"
|
||||
"lint:fix": "eslint . --fix",
|
||||
"tsc": "yarn workspaces run tsc"
|
||||
},
|
||||
"workspaces": [
|
||||
"javascript",
|
||||
|
@@ -7,11 +7,10 @@
|
||||
|
||||
// @ts-check
|
||||
|
||||
const lightCodeTheme = require('prism-react-renderer/themes/github');
|
||||
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
|
||||
import {themes as prismThemes} from 'prism-react-renderer';
|
||||
|
||||
/** @type {import('@docusaurus/types').Config} */
|
||||
const config = {
|
||||
export default {
|
||||
title: 'Yoga',
|
||||
tagline:
|
||||
'Build flexible layouts on any platform with a highly optimized open source layout engine designed with speed, size, and ease of use in mind.',
|
||||
@@ -63,13 +62,13 @@ const config = {
|
||||
items: [
|
||||
{
|
||||
type: 'docSidebar',
|
||||
sidebarId: 'tutorialSidebar',
|
||||
sidebarId: 'docsSidebar',
|
||||
position: 'left',
|
||||
label: 'Tutorial',
|
||||
label: 'Documentation',
|
||||
},
|
||||
{to: '/blog', label: 'Blog', position: 'left'},
|
||||
{
|
||||
href: 'https://github.com/facebook/docusaurus',
|
||||
href: 'https://github.com/facebook/yoga',
|
||||
label: 'GitHub',
|
||||
position: 'right',
|
||||
},
|
||||
@@ -77,6 +76,13 @@ const config = {
|
||||
},
|
||||
footer: {
|
||||
style: 'dark',
|
||||
logo: {
|
||||
alt: 'Meta Open Source',
|
||||
src: 'img/meta_oss.svg',
|
||||
href: 'https://opensource.fb.com',
|
||||
width: 300,
|
||||
height: 64,
|
||||
},
|
||||
links: [
|
||||
{
|
||||
title: 'Docs',
|
||||
@@ -117,10 +123,8 @@ const config = {
|
||||
copyright: `Copyright © ${new Date().getFullYear()} Meta Platforms, Inc.`,
|
||||
},
|
||||
prism: {
|
||||
theme: lightCodeTheme,
|
||||
darkTheme: darkCodeTheme,
|
||||
theme: prismThemes.github,
|
||||
darkTheme: prismThemes.dracula,
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
module.exports = config;
|
@@ -4,8 +4,8 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"start": "yarn workspace yoga-layout build && docusaurus start",
|
||||
"build": "yarn workspace yoga-layout build && docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
@@ -17,34 +17,22 @@
|
||||
"lint:fix": "eslint . --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "2.4.1",
|
||||
"@docusaurus/preset-classic": "2.4.1",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"antd": "^3.6.5",
|
||||
"@docusaurus/core": "3.0.0",
|
||||
"@docusaurus/preset-classic": "3.0.0",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"clsx": "^1.2.1",
|
||||
"immutable": "^4.0.0",
|
||||
"prism-react-renderer": "^1.3.5",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-syntax-highlighter": "^8.0.0",
|
||||
"prism-react-renderer": "^2.1.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"yoga-layout": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.4.1",
|
||||
"@tsconfig/docusaurus": "^1.0.5"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.5%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
"@docusaurus/module-type-aliases": "3.0.0",
|
||||
"@docusaurus/tsconfig": "3.0.0",
|
||||
"@docusaurus/types": "3.0.0"
|
||||
},
|
||||
"browserslist": "> 0.5%, last 2 versions, Firefox ESR, not dead",
|
||||
"engines": {
|
||||
"node": ">=16.14"
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@
|
||||
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
|
||||
const sidebars = {
|
||||
// By default, Docusaurus generates a sidebar from the docs folder structure
|
||||
tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],
|
||||
docsSidebar: [{type: 'autogenerated', dirName: '.'}],
|
||||
|
||||
// But you can create a sidebar manually
|
||||
/*
|
||||
|
@@ -1,77 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and 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';
|
||||
|
||||
type FeatureItem = {
|
||||
title: string;
|
||||
Svg: React.ComponentType<React.ComponentProps<'svg'>>;
|
||||
description: JSX.Element;
|
||||
};
|
||||
|
||||
const FeatureList: FeatureItem[] = [
|
||||
{
|
||||
title: 'Easy to Use',
|
||||
Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Docusaurus was designed from the ground up to be easily installed and
|
||||
used to get your website up and running quickly.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Focus on What Matters',
|
||||
Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Docusaurus lets you focus on your docs, and we'll do the chores. Go
|
||||
ahead and move your docs into the <code>docs</code> directory.
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Powered by React',
|
||||
Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
|
||||
description: (
|
||||
<>
|
||||
Extend or customize your website layout by reusing React. Docusaurus can
|
||||
be extended while reusing the same header and footer.
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
function Feature({title, Svg, description}: FeatureItem) {
|
||||
return (
|
||||
<div className={clsx('col col--4')}>
|
||||
<div className="text--center">
|
||||
<Svg className={styles.featureSvg} role="img" />
|
||||
</div>
|
||||
<div className="text--center padding-horiz--md">
|
||||
<h3>{title}</h3>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function HomepageFeatures(): JSX.Element {
|
||||
return (
|
||||
<section className={styles.features}>
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
{FeatureList.map((props, idx) => (
|
||||
<Feature key={idx} {...props} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
@@ -5,14 +5,6 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.features {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 2rem 0;
|
||||
.input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.featureSvg {
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
}
|
@@ -10,7 +10,8 @@
|
||||
import React from 'react';
|
||||
import YogaEnumSelect from './YogaEnumSelect';
|
||||
import YogaPositionEditor from './YogaPositionEditor';
|
||||
import {Input} from 'antd';
|
||||
|
||||
import styles from './EditValue.module.css';
|
||||
|
||||
type Props<T> = {
|
||||
property: string;
|
||||
@@ -20,6 +21,7 @@ type Props<T> = {
|
||||
placeholder?: string;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export default (props: Props<any>) => {
|
||||
if (YogaEnumSelect.availableProperties.indexOf(props.property) > -1) {
|
||||
// @ts-ignore
|
||||
@@ -31,7 +33,8 @@ export default (props: Props<any>) => {
|
||||
return <YogaPositionEditor {...props} />;
|
||||
} else {
|
||||
return (
|
||||
<Input
|
||||
<input
|
||||
className={styles.input}
|
||||
type="text"
|
||||
{...props}
|
||||
onChange={e => props.onChange(props.property, e.target.value)}
|
||||
|
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.Editor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
border-top: 1px solid #E8E8E8;
|
||||
}
|
||||
|
||||
.Editor .field {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.Editor .ant-btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.Editor h2 {
|
||||
margin-bottom: 8px;
|
||||
margin-top: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #444950;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.Editor h2:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.Editor .ant-tabs-nav .ant-tabs-tab {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.Editor .EditorTabs {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.Editor .ant-tabs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.Editor .ant-tabs-bar {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.Editor .ant-tabs-tabpane {
|
||||
overflow-y: auto;
|
||||
min-height: 320px;
|
||||
height: 100%;
|
||||
max-height: 25vh;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.Editor .EditorButtons {
|
||||
padding: 15px;
|
||||
}
|
32
website-next/src/components/Playground/Editor.module.css
Normal file
32
website-next/src/components/Playground/Editor.module.css
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.editor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.editor h2 {
|
||||
margin-bottom: 8px;
|
||||
margin-top: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--ifm-color-content-secondary);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.tabItem {
|
||||
overflow-y: auto;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
.editorButtons {
|
||||
display: flex;
|
||||
margin-top: auto;
|
||||
gap: 5px;
|
||||
}
|
@@ -7,18 +7,21 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import {Row, Col, Button, Tabs} from 'antd';
|
||||
import EditValue from './EditValue';
|
||||
import type {LayoutRecordType} from './LayoutRecord';
|
||||
import type {Direction} from 'yoga-layout';
|
||||
import InfoText from './InfoText';
|
||||
import './Editor.css';
|
||||
const TabPane = Tabs.TabPane;
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
import React from 'react';
|
||||
import EditValue from './EditValue';
|
||||
import styles from './Editor.module.css';
|
||||
|
||||
type Props = {
|
||||
node: LayoutRecordType;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onChangeLayout: (key: string, value: any) => void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onChangeSetting: (key: string, value: any) => void;
|
||||
direction: Direction;
|
||||
selectedNodeIsRoot: boolean;
|
||||
@@ -26,344 +29,240 @@ type Props = {
|
||||
onAdd?: () => void;
|
||||
};
|
||||
|
||||
export default class Editor extends Component<Props> {
|
||||
componentDidMount() {
|
||||
document.addEventListener('keydown', this.onKeyDown);
|
||||
}
|
||||
export default function Editor(props: Props) {
|
||||
const {node, selectedNodeIsRoot} = props;
|
||||
const disabled = node == null;
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('keydown', this.onKeyDown);
|
||||
}
|
||||
return (
|
||||
<div className={styles.editor}>
|
||||
<Tabs block={true}>
|
||||
<TabItem
|
||||
value="flex"
|
||||
label="Flex"
|
||||
className={styles.tabItem}
|
||||
default={true}>
|
||||
<h2>Direction</h2>
|
||||
<EditValue
|
||||
property="direction"
|
||||
value={props.direction}
|
||||
onChange={props.onChangeSetting}
|
||||
/>
|
||||
<h2>Flex Direction</h2>
|
||||
<EditValue
|
||||
disabled={disabled}
|
||||
property="flexDirection"
|
||||
value={node ? node.flexDirection : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
|
||||
onKeyDown = (e: KeyboardEvent) => {
|
||||
if (
|
||||
(e.key === 'Delete' || e.key === 'Backspace') &&
|
||||
this.props.onRemove &&
|
||||
!(e.target instanceof HTMLInputElement)
|
||||
) {
|
||||
this.props.onRemove();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {node, selectedNodeIsRoot} = this.props;
|
||||
const disabled = !node;
|
||||
|
||||
return (
|
||||
<div className="Editor">
|
||||
{/* @ts-ignore */}
|
||||
<Tabs defaultActiveKey="1" className="EditorTabs">
|
||||
{/* @ts-ignore */}
|
||||
<TabPane tab="Flex" key="1">
|
||||
<h2>
|
||||
Direction
|
||||
<InfoText doclink="/docs/layout-direction">
|
||||
Defines the direction of which text and items are laid out
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
property="direction"
|
||||
value={this.props.direction}
|
||||
onChange={this.props.onChangeSetting}
|
||||
/>
|
||||
<h2>
|
||||
Flex Direction
|
||||
<InfoText doclink="/docs/flex-direction">
|
||||
Defines the direction of the main-axis
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
disabled={disabled}
|
||||
property="flexDirection"
|
||||
value={node ? node.flexDirection : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
|
||||
<Row gutter={15} style={{marginTop: 30}}>
|
||||
<Col span={8}>
|
||||
<h2>
|
||||
Basis
|
||||
<InfoText doclink="/docs/flex">
|
||||
Default size of a node along the main axis
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
property="flexBasis"
|
||||
placeholder="auto"
|
||||
disabled={disabled || selectedNodeIsRoot}
|
||||
value={node ? node.flexBasis : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<h2>
|
||||
Grow
|
||||
<InfoText doclink="/docs/flex">
|
||||
The factor of remaining space should be given to this node
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
property="flexGrow"
|
||||
placeholder="0"
|
||||
disabled={disabled || selectedNodeIsRoot}
|
||||
value={node ? node.flexGrow : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<h2>
|
||||
Shrink
|
||||
<InfoText doclink="/docs/flex">
|
||||
The shrink factor of this element if parent has no space
|
||||
left
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
property="flexShrink"
|
||||
placeholder="1"
|
||||
disabled={disabled || selectedNodeIsRoot}
|
||||
value={node ? node.flexShrink : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<h2>
|
||||
Flex Wrap
|
||||
<InfoText doclink="/docs/flex-wrap">
|
||||
Wrapping behaviour when child nodes don't fit into a single line
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
disabled={disabled}
|
||||
property="flexWrap"
|
||||
value={node ? node.flexWrap : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</TabPane>
|
||||
{/* @ts-ignore */}
|
||||
<TabPane tab="Alignment" key="2">
|
||||
<h2>
|
||||
Justify Content
|
||||
<InfoText doclink="/docs/justify-content">
|
||||
Aligns child nodes along the main-axis
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
disabled={disabled}
|
||||
property="justifyContent"
|
||||
value={node ? node.justifyContent : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
|
||||
<h2>
|
||||
Align Items
|
||||
<InfoText doclink="/docs/align-items">
|
||||
Aligns child nodes along the cross-axis
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
disabled={disabled}
|
||||
property="alignItems"
|
||||
value={node ? node.alignItems : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
|
||||
<h2>
|
||||
Align Self
|
||||
<InfoText doclink="/docs/align-items">
|
||||
Override align items of parent
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
disabled={disabled || selectedNodeIsRoot}
|
||||
property="alignSelf"
|
||||
value={node ? node.alignSelf : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
|
||||
<h2>
|
||||
Align Content
|
||||
<InfoText doclink="/docs/align-content">
|
||||
Alignment of lines along the cross-axis when wrapping
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
disabled={disabled}
|
||||
property="alignContent"
|
||||
value={node ? node.alignContent : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</TabPane>
|
||||
{/* @ts-ignore */}
|
||||
<TabPane tab="Layout" key="3" className="ant-tabs-tabpane">
|
||||
<h2>
|
||||
Width × Height
|
||||
<InfoText doclink="/docs/width-height">
|
||||
Dimensions of the node
|
||||
</InfoText>
|
||||
</h2>
|
||||
<Row gutter={15}>
|
||||
<Col span={12}>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="auto"
|
||||
property="width"
|
||||
disabled={disabled}
|
||||
value={node ? node.width : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="auto"
|
||||
property="height"
|
||||
disabled={disabled}
|
||||
value={node ? node.height : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<h2>
|
||||
Max-Width × Max-Height
|
||||
<InfoText doclink="/docs/min-max">
|
||||
Maximum dimensions of the node
|
||||
</InfoText>
|
||||
</h2>
|
||||
<Row gutter={15}>
|
||||
<Col span={12}>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="none"
|
||||
property="maxWidth"
|
||||
disabled={disabled}
|
||||
value={node ? node.maxWidth : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="none"
|
||||
property="maxHeight"
|
||||
disabled={disabled}
|
||||
value={node ? node.maxHeight : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<h2>
|
||||
Min-Width × Min-Height
|
||||
<InfoText doclink="/docs/min-max">
|
||||
Minimum dimensions of the node
|
||||
</InfoText>
|
||||
</h2>
|
||||
<Row gutter={15}>
|
||||
<Col span={12}>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="0"
|
||||
property="minWidth"
|
||||
disabled={disabled}
|
||||
value={node ? node.minWidth : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="0"
|
||||
property="minHeight"
|
||||
disabled={disabled}
|
||||
value={node ? node.minHeight : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<h2>
|
||||
Aspect Ratio
|
||||
<InfoText doclink="/docs/aspect-ratio">
|
||||
Width/Height aspect ratio of node
|
||||
</InfoText>
|
||||
</h2>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="auto"
|
||||
property="aspectRatio"
|
||||
disabled={disabled}
|
||||
value={node ? node.aspectRatio : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
|
||||
{['padding', 'border', 'margin'].map(property => (
|
||||
<div className="row margin--none">
|
||||
<div className="col col--4">
|
||||
<h2>Basis</h2>
|
||||
<EditValue
|
||||
property={property}
|
||||
key={property}
|
||||
value={node ? node[property] : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
disabled={property === 'margin' && selectedNodeIsRoot}
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
property="flexBasis"
|
||||
placeholder="auto"
|
||||
disabled={disabled || selectedNodeIsRoot}
|
||||
value={node ? node.flexBasis : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
))}
|
||||
<h2>
|
||||
Position Type
|
||||
<InfoText doclink="/docs/absolute-relative-layout">
|
||||
Relative position offsets the node from it's calculated
|
||||
position. Absolute position removes the node from the flexbox
|
||||
flow and positions it at the given position.
|
||||
</InfoText>
|
||||
</h2>
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
<h2>Grow</h2>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
property="flexGrow margin--none"
|
||||
placeholder="0"
|
||||
disabled={disabled || selectedNodeIsRoot}
|
||||
value={node ? node.flexGrow : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</div>
|
||||
<div className="col col--4">
|
||||
<h2>Shrink</h2>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
property="flexShrink"
|
||||
placeholder="1"
|
||||
disabled={disabled || selectedNodeIsRoot}
|
||||
value={node ? node.flexShrink : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<EditValue
|
||||
disabled={disabled || selectedNodeIsRoot}
|
||||
property="positionType"
|
||||
value={node ? node.positionType : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
<EditValue
|
||||
disabled={selectedNodeIsRoot}
|
||||
property="position"
|
||||
value={node ? node.position : undefined}
|
||||
onChange={this.props.onChangeLayout}
|
||||
/>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
<h2>Flex Wrap</h2>
|
||||
<EditValue
|
||||
disabled={disabled}
|
||||
property="flexWrap"
|
||||
value={node ? node.flexWrap : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</TabItem>
|
||||
<TabItem value="alignment" label="Alignment" className={styles.tabItem}>
|
||||
<h2>Justify Content</h2>
|
||||
<EditValue
|
||||
disabled={disabled}
|
||||
property="justifyContent"
|
||||
value={node ? node.justifyContent : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
|
||||
<Row gutter={15} className="EditorButtons">
|
||||
<Col span={12}>
|
||||
<Button
|
||||
icon="plus-circle-o"
|
||||
disabled={!this.props.onAdd}
|
||||
onClick={this.props.onAdd}
|
||||
type="primary">
|
||||
add child node
|
||||
</Button>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Button
|
||||
icon="close-circle-o"
|
||||
disabled={!this.props.onRemove}
|
||||
onClick={this.props.onRemove}
|
||||
type="danger">
|
||||
remove node
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<h2>Align Items</h2>
|
||||
<EditValue
|
||||
disabled={disabled}
|
||||
property="alignItems"
|
||||
value={node ? node.alignItems : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
|
||||
<h2>Align Self</h2>
|
||||
<EditValue
|
||||
disabled={disabled || selectedNodeIsRoot}
|
||||
property="alignSelf"
|
||||
value={node ? node.alignSelf : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
|
||||
<h2>Align Content</h2>
|
||||
<EditValue
|
||||
disabled={disabled}
|
||||
property="alignContent"
|
||||
value={node ? node.alignContent : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</TabItem>
|
||||
<TabItem value="layout" label="Layout" className={styles.tabItem}>
|
||||
<h2>Width × Height</h2>
|
||||
<div className="row margin--none">
|
||||
<div className="col col--6">
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="auto"
|
||||
property="width"
|
||||
disabled={disabled}
|
||||
value={node ? node.width : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</div>
|
||||
<div className="col col--6">
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="auto"
|
||||
property="height"
|
||||
disabled={disabled}
|
||||
value={node ? node.height : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Max-Width × Max-Height</h2>
|
||||
<div className="row margin--none">
|
||||
<div className="col col--6">
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="none"
|
||||
property="maxWidth"
|
||||
disabled={disabled}
|
||||
value={node ? node.maxWidth : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</div>
|
||||
<div className="col col--6">
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="none"
|
||||
property="maxHeight"
|
||||
disabled={disabled}
|
||||
value={node ? node.maxHeight : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Min-Width × Min-Height</h2>
|
||||
<div className="row margin--none">
|
||||
<div className="col col--6">
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="0"
|
||||
property="minWidth"
|
||||
disabled={disabled}
|
||||
value={node ? node.minWidth : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</div>
|
||||
<div className="col col--6">
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="0"
|
||||
property="minHeight"
|
||||
disabled={disabled}
|
||||
value={node ? node.minHeight : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Aspect Ratio</h2>
|
||||
<EditValue
|
||||
// @ts-ignore
|
||||
type="text"
|
||||
placeholder="auto"
|
||||
property="aspectRatio"
|
||||
disabled={disabled}
|
||||
value={node ? node.aspectRatio : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
|
||||
{['padding', 'border', 'margin'].map(property => (
|
||||
<EditValue
|
||||
property={property}
|
||||
key={property}
|
||||
value={node ? node[property] : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
disabled={property === 'margin' && selectedNodeIsRoot}
|
||||
/>
|
||||
))}
|
||||
<h2>Position Type</h2>
|
||||
|
||||
<EditValue
|
||||
disabled={disabled || selectedNodeIsRoot}
|
||||
property="positionType"
|
||||
value={node ? node.positionType : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
<EditValue
|
||||
disabled={selectedNodeIsRoot}
|
||||
property="position"
|
||||
value={node ? node.position : undefined}
|
||||
onChange={props.onChangeLayout}
|
||||
/>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<div className={styles.editorButtons}>
|
||||
<button
|
||||
className="button button--block button--primary button--sm"
|
||||
disabled={!props.onRemove}
|
||||
onClick={props.onAdd}>
|
||||
add child
|
||||
</button>
|
||||
<button
|
||||
className="button button--block button--danger button--sm"
|
||||
disabled={!props.onRemove}
|
||||
onClick={props.onAdd}>
|
||||
remove
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.InfoText {
|
||||
max-width: 230px;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
.InfoText .docs-link {
|
||||
margin-top: 0px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.InfoTextIcon {
|
||||
margin-left: 5px;
|
||||
opacity: 0.5;
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import {Popover, Icon} from 'antd';
|
||||
import Link from '@docusaurus/Link';
|
||||
import './InfoText.css';
|
||||
|
||||
type Props = {
|
||||
children: any;
|
||||
doclink: string;
|
||||
};
|
||||
|
||||
export default class InfoText extends Component<Props> {
|
||||
render() {
|
||||
return (
|
||||
<Popover
|
||||
content={
|
||||
<div className="InfoText">
|
||||
<p>{this.props.children}</p>
|
||||
<Link className="docs-link" to={this.props.doclink}>
|
||||
DOCUMENTATION
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
trigger="hover">
|
||||
{/*@ts-ignore*/}
|
||||
<Icon className="InfoTextIcon" type="info-circle-o" />
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
}
|
31
website-next/src/components/Playground/Playground.module.css
Normal file
31
website-next/src/components/Playground/Playground.module.css
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
html[data-theme='light'] {
|
||||
--yg-color-playound-background: var(--ifm-color-gray-200);
|
||||
}
|
||||
|
||||
html[data-theme='dark'] {
|
||||
--yg-color-playound-background: var(--ifm-color-background);
|
||||
}
|
||||
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: var(--yg-color-playound-background);
|
||||
min-height: 600px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.playground {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
@@ -16,22 +16,25 @@ import PositionRecord from './PositionRecord';
|
||||
import LayoutRecord from './LayoutRecord';
|
||||
import Sidebar from './Sidebar';
|
||||
import type {LayoutRecordType} from './LayoutRecord';
|
||||
import './index.css';
|
||||
import styles from './Playground.module.css';
|
||||
import clsx from 'clsx';
|
||||
|
||||
type Props = {
|
||||
layoutDefinition: LayoutRecordType;
|
||||
direction: Direction;
|
||||
maxDepth: number;
|
||||
layoutDefinition?: LayoutRecordType;
|
||||
direction?: Direction;
|
||||
maxDepth?: number;
|
||||
maxChildren?: number;
|
||||
minChildren?: number;
|
||||
selectedNodePath?: Array<number>;
|
||||
showGuides: boolean;
|
||||
showGuides?: boolean;
|
||||
className?: string;
|
||||
height?: string | number;
|
||||
persist?: boolean;
|
||||
renderSidebar?: (
|
||||
layoutDefinition: LayoutRecordType,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onChange: () => any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
) => any;
|
||||
};
|
||||
|
||||
@@ -126,6 +129,7 @@ export default class Playground extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onChangeLayout = (key: string, value: any) => {
|
||||
const {selectedNodePath} = this.state;
|
||||
if (selectedNodePath) {
|
||||
@@ -158,7 +162,9 @@ export default class Playground extends Component<Props, State> {
|
||||
};
|
||||
|
||||
modifyAtPath(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
path: Array<any>,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
value: any,
|
||||
selectedNodePath: Array<number> = this.state.selectedNodePath,
|
||||
) {
|
||||
@@ -235,76 +241,60 @@ export default class Playground extends Component<Props, State> {
|
||||
: null;
|
||||
|
||||
const playground = (
|
||||
<div className="playground-background">
|
||||
<div
|
||||
className={`Playground ${
|
||||
this.props.renderSidebar ? '' : 'standalone'
|
||||
}`}
|
||||
onMouseDown={this.onMouseDown}
|
||||
style={{height, maxHeight: height}}
|
||||
ref={ref => {
|
||||
this._containerRef = ref;
|
||||
}}>
|
||||
<YogaNode
|
||||
layoutDefinition={layoutDefinition}
|
||||
selectedNodePath={selectedNodePath}
|
||||
onClick={selectedNodePath => this.setState({selectedNodePath})}
|
||||
onDoubleClick={this.onAdd}
|
||||
direction={direction}
|
||||
showGuides={this.props.showGuides}
|
||||
/>
|
||||
{!this.props.renderSidebar && (
|
||||
<Sidebar>
|
||||
{this.state.selectedNodePath ? (
|
||||
<Editor
|
||||
node={selectedNode}
|
||||
selectedNodeIsRoot={
|
||||
selectedNodePath ? selectedNodePath.length === 0 : false
|
||||
}
|
||||
onChangeLayout={this.onChangeLayout}
|
||||
// @ts-ignore
|
||||
onChangeSetting={(key, value) =>
|
||||
this.setState({[key]: value})
|
||||
}
|
||||
direction={direction}
|
||||
onRemove={
|
||||
selectedNodePath && selectedNodePath.length > 0
|
||||
? this.onRemove
|
||||
: undefined
|
||||
}
|
||||
onAdd={
|
||||
selectedNodePath &&
|
||||
selectedNodePath.length < this.props.maxDepth
|
||||
? this.onAdd
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<div className="NoContent">
|
||||
Select a node to edit its properties
|
||||
</div>
|
||||
)}
|
||||
</Sidebar>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={styles.playground}
|
||||
onMouseDown={this.onMouseDown}
|
||||
style={{height, maxHeight: height}}
|
||||
ref={ref => {
|
||||
this._containerRef = ref;
|
||||
}}>
|
||||
<YogaNode
|
||||
layoutDefinition={layoutDefinition}
|
||||
selectedNodePath={selectedNodePath}
|
||||
onClick={selectedNodePath => this.setState({selectedNodePath})}
|
||||
onDoubleClick={this.onAdd}
|
||||
direction={direction}
|
||||
showGuides={this.props.showGuides}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
if (this.props.renderSidebar) {
|
||||
return (
|
||||
<div className={`PlaygroundContainer ${this.props.className || ''}`}>
|
||||
<div>
|
||||
{this.props.renderSidebar(
|
||||
const sidebarContent = this.props.renderSidebar
|
||||
? this.props.renderSidebar(
|
||||
// @ts-ignore
|
||||
layoutDefinition.getIn(getPath(selectedNodePath)),
|
||||
this.onChangeLayout,
|
||||
)
|
||||
: this.state.selectedNodePath != null && (
|
||||
<Editor
|
||||
node={selectedNode}
|
||||
selectedNodeIsRoot={
|
||||
selectedNodePath ? selectedNodePath.length === 0 : false
|
||||
}
|
||||
onChangeLayout={this.onChangeLayout}
|
||||
onChangeSetting={(key, value) =>
|
||||
// @ts-ignore
|
||||
layoutDefinition.getIn(getPath(selectedNodePath)),
|
||||
this.onChangeLayout,
|
||||
)}
|
||||
</div>
|
||||
{playground}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return playground;
|
||||
}
|
||||
this.setState({[key]: value})
|
||||
}
|
||||
direction={direction}
|
||||
onRemove={
|
||||
selectedNodePath && selectedNodePath.length > 0
|
||||
? this.onRemove
|
||||
: undefined
|
||||
}
|
||||
onAdd={
|
||||
selectedNodePath && selectedNodePath.length < this.props.maxDepth
|
||||
? this.onAdd
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={clsx(styles.container, this.props.className)}>
|
||||
{playground}
|
||||
<Sidebar>{sidebarContent}</Sidebar>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@@ -5,18 +5,17 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.Sidebar {
|
||||
position: absolute;
|
||||
.placeholder {
|
||||
color: var(--ifm-color-content-secondary);
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
z-index: 3;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 350px;
|
||||
background: white;
|
||||
width: 320px;
|
||||
background: var(--ifm-background-surface-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 25px;
|
||||
max-height: calc(100% - 50px);
|
||||
border-radius: 6px;
|
||||
bottom: auto;
|
||||
box-shadow: 3px 3px 15px rgba(0, 0, 0, 0.15);
|
||||
padding: 20px;
|
||||
}
|
@@ -8,18 +8,30 @@
|
||||
*/
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import './Sidebar.css';
|
||||
import styles from './Sidebar.module.css';
|
||||
import clsx from 'clsx';
|
||||
|
||||
type Props = {
|
||||
width?: number;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
children: any;
|
||||
};
|
||||
|
||||
function PlaceholderContent() {
|
||||
return (
|
||||
<div className={styles.placeholder}>
|
||||
<p>Select a node to edit its properties</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default class Sidebar extends Component<Props> {
|
||||
render() {
|
||||
return (
|
||||
<div className="Sidebar" style={{width: this.props.width}}>
|
||||
{this.props.children}
|
||||
<div
|
||||
className={clsx('card', styles.sidebar)}
|
||||
style={{width: this.props.width}}>
|
||||
{this.props.children || <PlaceholderContent />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.YogaEnumSelect {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.YogaEnumSelect.ant-radio-group .ant-radio-button-wrapper {
|
||||
flex-grow: 1;
|
||||
flex-basis: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.YogaEnumSelect .ant-btn {
|
||||
flex-grow: 1;
|
||||
flex-basis: 0;
|
||||
}
|
||||
|
||||
.YogaEnumSelect .ant-radio-button-wrapper {
|
||||
white-space: nowrap;
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.buttonGroup {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.button {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.select {
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
padding: calc(var(--ifm-button-padding-vertical) * 0.8) calc(var(--ifm-button-padding-horizontal) * 0.8);
|
||||
background: transparent;
|
||||
color: var(--ifm-font-color-base);
|
||||
border: var(--ifm-button-border-width) solid var(--ifm-color-secondary);
|
||||
border-radius: var(--ifm-button-border-radius);
|
||||
font-size: calc(0.875rem * 0.8);
|
||||
font-weight: var(--ifm-button-font-weight);
|
||||
line-height: 1.5;
|
||||
}
|
@@ -8,11 +8,10 @@
|
||||
*/
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import clsx from 'clsx';
|
||||
import Yoga from 'yoga-layout';
|
||||
import {Radio, Menu, Dropdown, Button, Icon} from 'antd';
|
||||
import './YogaEnumSelect.css';
|
||||
const RadioButton = Radio.Button;
|
||||
const RadioGroup = Radio.Group;
|
||||
|
||||
import styles from './YogaEnumSelect.module.css';
|
||||
|
||||
const PROPERTY_LOOKUP = {
|
||||
flexDirection: 'FLEX_DIRECTION',
|
||||
@@ -65,41 +64,30 @@ export default class YogaEnumSelect extends Component<Props> {
|
||||
const selected = this.values.find(({value}) => value === this.props.value);
|
||||
|
||||
return this.values.length > 3 ? (
|
||||
<div className="YogaEnumSelect">
|
||||
{/*@ts-ignore*/}
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
disabled={this.props.disabled}
|
||||
overlay={
|
||||
// @ts-ignore
|
||||
<Menu onClick={this.handleMenuClick}>
|
||||
{this.values.map(({key, value}) => (
|
||||
// @ts-ignore
|
||||
<Menu.Item key={key} value={value}>
|
||||
{this.getTitle(property, key)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu>
|
||||
}>
|
||||
<Button>
|
||||
{selected ? this.getTitle(property, selected.key) : ''}
|
||||
{/*@ts-ignore*/}
|
||||
<Icon type="down" />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
) : (
|
||||
<RadioGroup
|
||||
{...this.props}
|
||||
onChange={e => this.props.onChange(this.props.property, e.target.value)}
|
||||
defaultValue="a"
|
||||
className="YogaEnumSelect">
|
||||
<select className={styles.select} name={this.props.property}>
|
||||
{this.values.map(({key, value}) => (
|
||||
<RadioButton key={key} value={value}>
|
||||
{this.getTitle(property, key)}
|
||||
</RadioButton>
|
||||
<option key={key} value={value}>
|
||||
{selected ? this.getTitle(property, key) : ''}
|
||||
</option>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</select>
|
||||
) : (
|
||||
<div className={clsx('button-group', styles.buttonGroup)}>
|
||||
{this.values.map(({key, value}) => (
|
||||
<button
|
||||
className={clsx(
|
||||
'button',
|
||||
'button--sm',
|
||||
'button--outline',
|
||||
'button--secondary',
|
||||
value === this.props.value && 'button--active',
|
||||
styles.button,
|
||||
)}
|
||||
onClick={() => this.props.onChange(this.props.property, value)}>
|
||||
{this.getTitle(property, key)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -5,17 +5,30 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.YogaNode {
|
||||
background: white;
|
||||
.YogaNode {
|
||||
box-sizing: border-box;
|
||||
background: var(--ifm-background-surface-color);
|
||||
position: absolute;
|
||||
transform: scale(1);
|
||||
box-shadow: inset 0 0 0px 1px rgba(48, 56, 69, 0.2);
|
||||
transition: 0.2s all, 0s outline, 0s box-shadow;
|
||||
box-shadow: var(--ifm-global-shadow-lw);
|
||||
cursor: pointer;
|
||||
animation: yoga-node-fadein 200ms ease;
|
||||
}
|
||||
|
||||
.YogaNode.hover {
|
||||
background-color: #F0FFF9;
|
||||
@keyframes yoga-node-fadein {
|
||||
0% {
|
||||
transform: scale(1.05);
|
||||
opacity: 0%;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1.0);
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.YogaNode.hover:not(.focused) {
|
||||
background-color: var(--ifm-color-emphasis-100);
|
||||
}
|
||||
|
||||
.YogaNode .YogaNode {
|
||||
@@ -26,13 +39,8 @@
|
||||
background: rgba(240, 255, 249, 0.7);
|
||||
}
|
||||
|
||||
.YogaNode:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.YogaNode.focused {
|
||||
box-shadow: 0 0 0 2px #68CFBB, 0 0 15px rgba(0, 0, 0, 0.2),
|
||||
inset 0 0 0px 1px rgba(255, 255, 255, 0.2);
|
||||
outline: 2px solid var(--ifm-color-primary);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
@@ -14,6 +14,7 @@ import PositionRecord from './PositionRecord';
|
||||
import LayoutRecord from './LayoutRecord';
|
||||
import type {LayoutRecordType} from './LayoutRecord';
|
||||
import {Direction, Display, Edge, Node, Wrap} from 'yoga-layout';
|
||||
import clsx from 'clsx';
|
||||
|
||||
import './YogaNode.css';
|
||||
|
||||
@@ -261,9 +262,14 @@ export default class YogaNode extends Component<Props, State> {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`YogaNode ${isFocused ? 'focused' : ''} ${className || ''} ${
|
||||
this.state.visible ? '' : 'invisible'
|
||||
} ${this.state.hovered ? 'hover' : ''}`}
|
||||
className={clsx(
|
||||
'card',
|
||||
'YogaNode',
|
||||
className,
|
||||
isFocused && 'focused',
|
||||
this.state.hovered && 'hover',
|
||||
this.state.visible === false && 'invisible',
|
||||
)}
|
||||
style={path.length == 0 ? {width, height} : {left, top, width, height}}
|
||||
onDoubleClick={this.onDoubleClick}
|
||||
onMouseMove={this.onMouseMove}
|
||||
|
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import {Input} from 'antd';
|
||||
import PositionRecord from './PositionRecord';
|
||||
import type {PositionRecordType} from './PositionRecord';
|
||||
import './YogaPositionEditor.css';
|
||||
@@ -33,14 +32,14 @@ export default class YogaPositionEditor extends Component<Props> {
|
||||
const {onChange, value, property, disabled} = this.props;
|
||||
return (
|
||||
<div className="YogaPositionEditor">
|
||||
<Input
|
||||
<input
|
||||
type="text"
|
||||
value={Number.isNaN(value.top) ? '' : value.top}
|
||||
disabled={disabled}
|
||||
onChange={e => onChange(property, value.set('top', e.target.value))}
|
||||
/>
|
||||
<div className="YogaPositionEditorRow">
|
||||
<Input
|
||||
<input
|
||||
type="text"
|
||||
value={Number.isNaN(value.left) ? '' : value.left}
|
||||
disabled={disabled}
|
||||
@@ -49,7 +48,7 @@ export default class YogaPositionEditor extends Component<Props> {
|
||||
}
|
||||
/>
|
||||
{property.toUpperCase()}
|
||||
<Input
|
||||
<input
|
||||
type="text"
|
||||
value={Number.isNaN(value.right) ? '' : value.right}
|
||||
disabled={disabled}
|
||||
@@ -58,7 +57,7 @@ export default class YogaPositionEditor extends Component<Props> {
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
<input
|
||||
type="text"
|
||||
value={Number.isNaN(value.bottom) ? '' : value.bottom}
|
||||
disabled={disabled}
|
||||
|
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
.PlaygroundContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.playground-background {
|
||||
background: linear-gradient(-90deg, rgba(0, 0, 0, 0.02) 1px, transparent 1px),
|
||||
linear-gradient(rgba(0, 0, 0, 0.02) 1px, transparent 1px),
|
||||
linear-gradient(-90deg, rgba(0, 0, 0, 0.03) 1px, transparent 1px),
|
||||
linear-gradient(rgba(0, 0, 0, 0.03) 1px, transparent 1px),
|
||||
linear-gradient(
|
||||
transparent 4px,
|
||||
#f5f5f5 4px,
|
||||
#f5f5f5 97px,
|
||||
transparent 97px
|
||||
),
|
||||
linear-gradient(-90deg, #e5e5e5 1px, transparent 1px),
|
||||
linear-gradient(
|
||||
-90deg,
|
||||
transparent 4px,
|
||||
#f5f5f5 4px,
|
||||
#f5f5f5 97px,
|
||||
transparent 97px
|
||||
),
|
||||
linear-gradient(#e5e5e5 1px, transparent 1px), #f5f5f5;
|
||||
background-size: 10px 10px, 10px 10px, 100px 100px, 100px 100px, 100px 100px,
|
||||
100px 100px, 100px 100px, 100px 100px;
|
||||
}
|
||||
|
||||
.Playground {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
animation: playground-content-fade-in-frames 50ms ease-in;
|
||||
}
|
||||
|
||||
.Playground > .YogaNode {
|
||||
margin: auto;
|
||||
position: static;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.Playground.standalone > .YogaNode {
|
||||
transform: translateX(-175px);
|
||||
}
|
||||
|
||||
.Playground .Actions {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.Playground .Actions .ant-btn {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.Playground .NoContent {
|
||||
border-top: 1px solid #E8E8E8;
|
||||
font-size: 18px;
|
||||
padding: 30px 50px;
|
||||
text-align: center;
|
||||
color: #D9D9D9;
|
||||
font-weight: 300;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
.ant-modal-content {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@keyframes playground-content-fade-in-frames {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
@@ -13,25 +13,25 @@
|
||||
|
||||
/* You can override the default Infima variables here. */
|
||||
:root {
|
||||
--ifm-color-primary: #2e8555;
|
||||
--ifm-color-primary-dark: #29784c;
|
||||
--ifm-color-primary-darker: #277148;
|
||||
--ifm-color-primary-darkest: #205d3b;
|
||||
--ifm-color-primary-light: #33925d;
|
||||
--ifm-color-primary-lighter: #359962;
|
||||
--ifm-color-primary-lightest: #3cad6e;
|
||||
--ifm-color-primary-lightest: rgb(99, 183, 168);
|
||||
--ifm-color-primary-lighter: rgb(70, 159, 143);
|
||||
--ifm-color-primary-light: rgb(48, 135, 119);
|
||||
--ifm-color-primary: rgb(33, 111, 97);
|
||||
--ifm-color-primary-dark: rgb(22, 87, 75);
|
||||
--ifm-color-primary-darker: rgb(14, 63, 54);
|
||||
--ifm-color-primary-darkest: rgb(8, 39, 33);
|
||||
--ifm-code-font-size: 95%;
|
||||
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* For readability concerns, you should choose a lighter palette in dark mode. */
|
||||
[data-theme='dark'] {
|
||||
--ifm-color-primary: #25c2a0;
|
||||
--ifm-color-primary-dark: #21af90;
|
||||
--ifm-color-primary-darker: #1fa588;
|
||||
--ifm-color-primary-darkest: #1a8870;
|
||||
--ifm-color-primary-light: #29d5b0;
|
||||
--ifm-color-primary-lighter: #32d8b4;
|
||||
--ifm-color-primary-lightest: #4fddbf;
|
||||
--ifm-color-primary-lightest: rgb(192, 231, 224);
|
||||
--ifm-color-primary-lighter: rgb(146, 207, 196);
|
||||
--ifm-color-primary-light: rgb(106, 183, 169);
|
||||
--ifm-color-primary: rgb(74, 159, 144);
|
||||
--ifm-color-primary-dark: rgb(51, 135, 120);
|
||||
--ifm-color-primary-darker: rgb(34, 111, 97);
|
||||
--ifm-color-primary-darkest: rgb(22, 87, 75);
|
||||
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
@@ -10,47 +10,151 @@
|
||||
* and scoped locally.
|
||||
*/
|
||||
|
||||
html[data-theme='light'] {
|
||||
--yg-color-playound-background: var(--ifm-color-gray-200);
|
||||
}
|
||||
|
||||
html[data-theme='dark'] {
|
||||
--yg-color-playound-background: var(--ifm-color-background);
|
||||
}
|
||||
|
||||
.heroBanner {
|
||||
padding: 4rem 0;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 996px) {
|
||||
.heroBanner {
|
||||
padding: 2rem;
|
||||
}
|
||||
.heroRow {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
.blueprintColumn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.playgroundFallback {
|
||||
height: 500px;
|
||||
width: 100%;
|
||||
background: linear-gradient(-90deg, rgba(0, 0, 0, 0.02) 1px, transparent 1px),
|
||||
linear-gradient(rgba(0, 0, 0, 0.02) 1px, transparent 1px),
|
||||
linear-gradient(-90deg, rgba(0, 0, 0, 0.03) 1px, transparent 1px),
|
||||
linear-gradient(rgba(0, 0, 0, 0.03) 1px, transparent 1px),
|
||||
linear-gradient(
|
||||
transparent 4px,
|
||||
#f5f5f5 4px,
|
||||
#f5f5f5 97px,
|
||||
transparent 97px
|
||||
),
|
||||
linear-gradient(-90deg, #e5e5e5 1px, transparent 1px),
|
||||
linear-gradient(
|
||||
-90deg,
|
||||
transparent 4px,
|
||||
#f5f5f5 4px,
|
||||
#f5f5f5 97px,
|
||||
transparent 97px
|
||||
),
|
||||
linear-gradient(#e5e5e5 1px, transparent 1px), #f5f5f5;
|
||||
background-size: 10px 10px, 10px 10px, 100px 100px, 100px 100px, 100px 100px,
|
||||
100px 100px, 100px 100px, 100px 100px;
|
||||
@media (max-width: 996px) {
|
||||
.blueprintColumn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.blueprint {
|
||||
--blueprint-gap: 5%;
|
||||
--fadein-duration: 500ms;
|
||||
box-shadow: var(--ifm-global-shadow-tl);
|
||||
background-color: var(--ifm-background-surface-color);
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
.blueprintContainer {
|
||||
position: relative;
|
||||
width: var(--ifm-col-width);
|
||||
aspect-ratio: 1.0;
|
||||
background-color: var(--ifm-color-primary-lighter);
|
||||
box-shadow: var(--ifm-global-shadow-lw);
|
||||
}
|
||||
|
||||
.blueprintAvatar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
margin: var(--blueprint-gap) 0 0 var(--blueprint-gap);
|
||||
width: calc(25% - (var(--blueprint-gap)));
|
||||
height: calc(25% - (var(--blueprint-gap)));
|
||||
animation: avatar-fadein var(--fadein-duration) ease;
|
||||
}
|
||||
|
||||
@keyframes avatar-fadein {
|
||||
0% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0%;
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.0);
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.blueprintTitle {
|
||||
position: absolute;
|
||||
left: 25%;
|
||||
top: 0;
|
||||
right: 10%;
|
||||
margin: var(--blueprint-gap) var(--blueprint-gap) 0 var(--blueprint-gap);
|
||||
height: calc(10% - (var(--blueprint-gap)));
|
||||
animation: title-fadein var(--fadein-duration) ease;
|
||||
}
|
||||
|
||||
.blueprintSubtitle {
|
||||
position: absolute;
|
||||
left: 25%;
|
||||
top: 10%;
|
||||
right: 30%;
|
||||
margin: var(--blueprint-gap);
|
||||
height: calc(10% - (var(--blueprint-gap)));
|
||||
animation: title-fadein var(--fadein-duration) ease;
|
||||
}
|
||||
|
||||
@keyframes title-fadein {
|
||||
0% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0%;
|
||||
}
|
||||
|
||||
25% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0%;
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: scale(1.0);
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.blueprintContent {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
margin: var(--blueprint-gap);
|
||||
width: calc(100% - (var(--blueprint-gap) * 2));
|
||||
height: calc(75% - (var(--blueprint-gap) * 2));
|
||||
animation: content-fadein var(--fadein-duration) ease;
|
||||
}
|
||||
|
||||
@keyframes content-fadein {
|
||||
0% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0%;
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0%;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1.0);
|
||||
opacity: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.playgroundSection {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 600px;
|
||||
width: 100%;
|
||||
background-color: var(--yg-color-playound-background);
|
||||
}
|
||||
|
||||
@media (max-width: 996px) {
|
||||
.playgroundSection {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@@ -8,59 +8,82 @@
|
||||
import React, {Suspense} from 'react';
|
||||
import clsx from 'clsx';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import Layout from '@theme/Layout';
|
||||
import HomepageFeatures from '@site/src/components/HomepageFeatures';
|
||||
import BrowserOnly from '@docusaurus/BrowserOnly';
|
||||
|
||||
import styles from './index.module.css';
|
||||
|
||||
function HomepageHeader() {
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
function HeroSection() {
|
||||
return (
|
||||
<header className={clsx('hero hero--primary', styles.heroBanner)}>
|
||||
<div className="container">
|
||||
<h1 className="hero__title">{siteConfig.title}</h1>
|
||||
<p className="hero__subtitle">{siteConfig.tagline}</p>
|
||||
<div className={styles.buttons}>
|
||||
<Link
|
||||
className="button button--secondary button--lg"
|
||||
to="/docs/intro">
|
||||
Docusaurus Tutorial - 5min ⏱️
|
||||
<header className={clsx('hero', styles.heroBanner)}>
|
||||
<div className={clsx('row', 'container', styles.heroRow)}>
|
||||
<div className="col col--6">
|
||||
<h1 className="hero__title">Yoga Layout</h1>
|
||||
<p className="hero__subtitle">
|
||||
A portable and perfomant layout engine targeting web standards
|
||||
</p>
|
||||
|
||||
<Link className="button button--primary button--lg" to="/docs/intro">
|
||||
Learn more
|
||||
</Link>
|
||||
</div>
|
||||
<div className={clsx(['col col--6', styles.blueprintColumn])}>
|
||||
<div className={clsx([styles.blueprint, styles.blueprintContainer])}>
|
||||
<div className={styles.blueprintHeader}>
|
||||
<div
|
||||
className={clsx([styles.blueprint, styles.blueprintAvatar])}
|
||||
/>
|
||||
<div
|
||||
className={clsx([styles.blueprint, styles.blueprintTitle])}
|
||||
/>
|
||||
<div
|
||||
className={clsx([styles.blueprint, styles.blueprintSubtitle])}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={clsx([styles.blueprint, styles.blueprintContent])}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
const LazyPlayground = React.lazy(() => import('../components/Playground'));
|
||||
|
||||
function ClientPlayground() {
|
||||
const fallback = <div className={styles.playgroundFallback} />;
|
||||
const LazyPlayground = React.lazy(
|
||||
() => import('../components/Playground/Playground'),
|
||||
);
|
||||
|
||||
// Docusaurus SSR does not correctly support top-level await
|
||||
// 1. https://github.com/facebook/docusaurus/issues/7238
|
||||
// 2. https://github.com/facebook/docusaurus/issues/9468
|
||||
function BrowserOnlyPlayground() {
|
||||
return (
|
||||
<BrowserOnly fallback={fallback}>
|
||||
<BrowserOnly fallback={null}>
|
||||
{() => (
|
||||
<Suspense fallback={fallback}>
|
||||
<LazyPlayground />
|
||||
<Suspense fallback={null}>
|
||||
<LazyPlayground className={styles.playground} />
|
||||
</Suspense>
|
||||
)}
|
||||
</BrowserOnly>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Home(): JSX.Element {
|
||||
const {siteConfig} = useDocusaurusContext();
|
||||
function PlaygroundSection() {
|
||||
return (
|
||||
<Layout
|
||||
title={`Hello from ${siteConfig.title}`}
|
||||
description="Description will go into a meta tag in <head />">
|
||||
<HomepageHeader />
|
||||
<main>
|
||||
<HomepageFeatures />
|
||||
<ClientPlayground />
|
||||
</main>
|
||||
<main className={styles.playgroundSection}>
|
||||
<div className="container">
|
||||
<BrowserOnlyPlayground />
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Home(): JSX.Element {
|
||||
return (
|
||||
<Layout title="Yoga Layout | A cross-platform layout engine">
|
||||
<HeroSection />
|
||||
<PlaygroundSection />
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
1
website-next/static/img/meta_oss.svg
Normal file
1
website-next/static/img/meta_oss.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 14 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
// This file is not used in compilation. It is here just for a nice editor experience.
|
||||
"extends": "@tsconfig/docusaurus/tsconfig.json",
|
||||
"extends": "@docusaurus/tsconfig",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"target": "esnext",
|
||||
|
Reference in New Issue
Block a user