Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs landing page #1383

Merged
merged 15 commits into from
Nov 18, 2024
Merged
327 changes: 180 additions & 147 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions website/docs/compare-matrix-landing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
| Feature | [uniforms](https://github.com/vazco/uniforms) | [Formik](https://github.com/jaredpalmer/formik) | [redux-form](https://github.com/erikras/redux-form) | [React Final Form](https://github.com/final-form/react-final-form) | [react-hook-form](https://github.com/react-hook-form/react-hook-form) |
| :----------------------------------------------------------------------------- | :---------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------: | ----------------------------------------------------------------------------------- |
| Automatic form layout | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) |
| Manual state management | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) |
| Manually trigger validation | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) |
| AntD, Bootstrap 3, Bootstrap 4, Bootstrap 5, Material, MUI, Semantic UI themes | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) |
| JSON, GraphQL, SimpleSchema, Zod and custom schema support | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) |
| Field level validation | ![unsupported](https://github.githubassets.com/images/icons/emoji/unicode/2716.png) | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) | ![supported](https://github.githubassets.com/images/icons/emoji/unicode/2714.png) |
58 changes: 58 additions & 0 deletions website/docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,49 @@ const config: Config = {
],
],

customFields: {
email: '[email protected]',
companies: [
{ url: 'https://www.deskpro.com/', image: 'deskpro.png', alt: 'Deskpro' },
{ url: 'https://www.nokia.com/', image: 'nokia.png', alt: 'Nokia' },
{
url: 'https://github.com/react-page/react-page/tree/master/packages/plugins/createPluginMaterialUi',
image: 'react-page.png',
alt: 'React Page',
},
{
url: 'https://graphback.dev',
image: 'graphback.png',
alt: 'Graphback',
},
{
url: 'https://www.onyx-one.com/',
image: 'onyx-one.png',
alt: 'Onyx one',
},
{ url: 'https://aerogear.org', image: 'aerogear.png', alt: 'Aerogear' },
{
url: 'https://cleverbeagle.com/together',
image: 'cleverbeagle.png',
alt: 'Clever Beagle',
},
{ url: 'http://www.orionjs.org', image: 'orionjs.png', alt: 'Orion.js' },
{
url: 'https://boulder.care',
image: 'boulder.svg',
alt: 'Boulder Care',
},
],
},

themeConfig: {
algolia: {
apiKey: '9bab87682792c2bd77ec707a56669e29',
appId: 'WWWW16GKXU',
contextualSearch: false,
indexName: 'uniforms',
searchPagePath: false,
},
navbar: {
logo: { alt: 'uniforms logo', src: 'img/uniforms.svg' },
items: [
Expand All @@ -46,11 +88,27 @@ const config: Config = {
position: 'left',
label: 'Docs',
},
{
label: 'Tutorial',
to: '/docs/tutorials-basic-uniforms-usage',
position: 'left',
},
{ label: 'Playground', to: '/playground', position: 'left' },
{
href: 'https://github.com/vazco/uniforms',
label: 'GitHub',
position: 'left',
},
{
label: 'Enterprise',
href: 'https://forminer.com/?utm_source=uniforms&utm_medium=Menu_CTA&utm_campaign=Forminer_uniforms_menu_CTA&utm_id=Forminer_uniforms_menu',
position: 'left',
},
{
label: 'Custom solutions',
href: 'https://www.vazco.eu/',
position: 'left',
},
],
},
prism: {
Expand Down
14 changes: 13 additions & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,28 @@
"@docusaurus/core": "3.5.2",
"@docusaurus/preset-classic": "3.5.2",
"@mdx-js/react": "^3.0.0",
"ajv": "8.17.1",
"antd": "5.21.5",
"classnames": "^2.0.0",
"clsx": "^2.0.0",
"lodash": "^4.0.0",
"lz-string": "1.5.0",
"message-box": "0.2.7",
"prism-react-renderer": "^2.3.0",
"raw-loader": "4.0.2",
"react": "^18.0.0",
"react-dom": "^18.0.0"
"react-dom": "^18.0.0",
"react-feather": "2.0.10",
"react-frame-component": "5.2.7",
"zod": "3.23.8"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.5.2",
"@docusaurus/theme-classic": "3.5.2",
"@docusaurus/tsconfig": "3.5.2",
"@docusaurus/types": "3.5.2",
"@types/simpl-schema": "1.12.8",
"simpl-schema": "1.13.1",
"typescript": "~5.5.2"
},
piotrpospiech marked this conversation as resolved.
Show resolved Hide resolved
"browserslist": {
Expand Down
45 changes: 45 additions & 0 deletions website/src/components/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Link from '@docusaurus/Link';
import classNames from 'classnames';
import React, { ComponentType } from 'react';

import styles from '../css/index.module.css';
import { Oval } from './Oval';

export type BadgeProps = {
border: number;
color: string;
icon: ComponentType<{ color?: string }>;
number?: string;
text: string;
to: string;
};

export function Badge({
border,
color,
icon: Icon,
number,
text,
to,
}: BadgeProps) {
return (
<Link to={to} className={classNames(styles.badge)}>
<img
className={styles['badge-image']}
src={`img/border-0${border}.svg`}
alt=""
/>
{Icon && (
<Oval className={styles['top-right-corner']}>
<Icon color={color} />
</Oval>
)}
<div className={classNames(styles['badge-centered'], styles.centered)}>
<div style={{ color }} className={styles['badge-number']}>
{number}
</div>
<p className={styles.text}>{text}</p>
</div>
</Link>
);
}
24 changes: 24 additions & 0 deletions website/src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Link from '@docusaurus/Link';
import classNames from 'classnames';
import React from 'react';

import styles from '../css/index.module.css';

export type ButtonProps = JSX.IntrinsicElements['button'] & { to: string };

export function Button({ children, className, to, ...props }: ButtonProps) {
return (
<Link to={to}>
<button
{...props}
className={classNames(
'button button--lg button--primary',
styles['call-to-action'],
className,
)}
>
{children}
</button>
</Link>
);
}
66 changes: 66 additions & 0 deletions website/src/components/CodeSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import components from '@theme/MDXComponents';
import React from 'react';

export type CodeSectionProps = {
language: string;
replace?: Record<string, string>;
section?: string;
source: string | { default: string };
};

export function CodeSection({
language,
replace,
section,
source,
}: CodeSectionProps) {
// Unwrap ES module.
if (typeof source === 'object' && 'default' in source) {
source = source.default;
}

// Cut out only desired section.
if (section) {
const pattern = new RegExp(
`// <${section}>\\s([\\s\\S]*?)\\s// </${section}>\\s`,
'g',
);

source = source
.split(pattern)
.reduce(
(source, part, index) =>
index % 2 === 0 ? source : `${source}\n\n${part}`,
'',
);
}

// Remove remaining section tags.
source = source.replace(/\/\/ <.*?\n/g, '');

// Replace all mapped things.
if (replace) {
for (const [pattern, value] of Object.entries(replace)) {
source = source.replace(new RegExp(pattern, 'gs'), value);
}
}

// At least one newline is required for non-inline view.
source = source.trim();
if (!source.includes('\n')) {
source += '\n';
}

return (
<components.pre>
<components.code
children={source}
className={`language-${language}`}
//@ts-expect-error: Property 'mdxType' does not exist on type 'IntrinsicAttributes & Props'.
mdxType="code"
originalType="code"
parentName="pre"
/>
</components.pre>
);
}
63 changes: 63 additions & 0 deletions website/src/components/ExampleCustomizer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { ComponentType } from 'react';
import { Box, Code, Database } from 'react-feather';

import { themeContext } from '../lib/universal';
import { CodeSection } from './CodeSection';
import { FormWrapper } from './FormWrapper';
import { TogglerTabs } from './TogglerTabs';

const tabs = [
{ name: 'Semantic', value: 'semantic' as const },
{ name: 'MUI', value: 'mui' as const },
{ name: 'Bootstrap4', value: 'bootstrap4' as const },
{ name: 'Bootstrap5', value: 'bootstrap5' as const },
{ name: 'AntD', value: 'antd' as const },
{ name: 'Unstyled', value: 'unstyled' as const },
];

const toggles = [
{ icon: <Box />, name: 'Example', tooltipText: 'Show example' },
{ icon: <Code />, name: 'Code', tooltipText: 'Show source code' },
{ icon: <Database />, name: 'Schema', tooltipText: 'Show schema' },
];

export type ExampleCustomizerProps = {
code: { default: string };
example: ComponentType;
schema: { default: string };
};

export function ExampleCustomizer({
code: { default: code },
example: Example,
schema: { default: schema },
}: ExampleCustomizerProps) {
return (
<TogglerTabs group="examples" tabsItems={tabs} togglerItems={toggles}>
{({ tab: { value: theme }, toggle: { name } }) => {
switch (name) {
case 'Code':
return (
<CodeSection
language="tsx"
replace={{ "'[^']*?/universal'": `'uniforms-${theme}'` }}
source={code}
/>
);
case 'Example':
return (
<themeContext.Provider value={theme}>
<FormWrapper>
<Example />
</FormWrapper>
</themeContext.Provider>
);
case 'Schema':
return <CodeSection language="tsx" source={schema} />;
default:
return null;
}
}}
</TogglerTabs>
);
}
21 changes: 21 additions & 0 deletions website/src/components/FormWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { ReactNode, useContext } from 'react';

import styles from '../css/index.module.css';
import { useFrameAutoResize } from '../lib/autoresize';
import { themeContext } from '../lib/universal';
import { PlaygroundWrap } from './Playground';

export type FormWrapperProps = {
children: ReactNode;
};

export function FormWrapper(props: FormWrapperProps) {
const theme = useContext(themeContext);
const frameProps = useFrameAutoResize([props.children]);

return (
<div className={styles['form-wrapper']}>
<PlaygroundWrap frameProps={frameProps} theme={theme} {...props} />
</div>
);
}
14 changes: 14 additions & 0 deletions website/src/components/Heading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import classNames from 'classnames';
import React from 'react';

import styles from '../css/index.module.css';

export type HeadingProps = JSX.IntrinsicElements['h1'];

export function Heading({ children, className, ...props }: HeadingProps) {
return (
<h2 {...props} className={classNames(styles.heading, className)}>
{children}
</h2>
);
}
28 changes: 28 additions & 0 deletions website/src/components/IconLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Link from '@docusaurus/Link';
import classNames from 'classnames';
import React, { ComponentType } from 'react';

import styles from '../css/index.module.css';

export type IconLinkProps = JSX.IntrinsicElements['div'] & {
icon: ComponentType;
to: string;
};

export function IconLink({
className,
icon: Icon,
to,
...props
}: IconLinkProps) {
return (
<Link to={to}>
<div
{...props}
className={classNames(styles['link-icon-container'], className)}
>
<Icon />
</div>
</Link>
);
}
14 changes: 14 additions & 0 deletions website/src/components/Oval.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import classNames from 'classnames';
import React from 'react';

import styles from '../css/index.module.css';

export type OvalProps = JSX.IntrinsicElements['span'];

export function Oval({ children, className, ...props }: OvalProps) {
return (
<span {...props} className={classNames(styles.oval, className)}>
{children}
</span>
);
}
Loading
Loading