diff --git a/README.md b/README.md index 6526118a6db..8d5ca6cbfb4 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,11 @@ Toolpad Studio is in its beta stages of development. Feel free to run this appli Run: ```bash -npx create-toolpad-app@latest my-toolpad-studio-app +npx create-toolpad-app@latest --studio my-toolpad-studio-app # or -yarn create toolpad-app my-toolpad-studio-app +yarn create toolpad-app --studio my-toolpad-studio-app # or -pnpm create toolpad-app my-toolpad-studio-app +pnpm create toolpad-app --studio my-toolpad-studio-app ``` ## Documentation diff --git a/RELEASE.md b/RELEASE.md index 6579bdb3a15..6dad2b4460b 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -65,11 +65,22 @@ 1. Smoke test the release with the [CodeSandbox CI](https://ci.codesandbox.io/status/mui/mui-toolpad) package of the PR branch: - 1. Run + a. Run Toolpad Core ```bash npx https://pkg.csb.dev/mui/mui-toolpad/commit//create-toolpad-app smoke --use-pnpm cd smoke + pnpm add https://pkg.csb.dev/mui/mui-toolpad/commit//@toolpad/core -S + pnpm dedupe && pnpm dev + ``` + + And verify the app runs + + b. Run Toolpad Studio + + ```bash + npx https://pkg.csb.dev/mui/mui-toolpad/commit//create-toolpad-app --studio smoke --use-pnpm + cd smoke pnpm add https://pkg.csb.dev/mui/mui-toolpad/commit//@toolpad/studio -S pnpm dedupe && pnpm dev ``` diff --git a/docs/data/toolpad/core/introduction/installation.md b/docs/data/toolpad/core/introduction/installation.md index ddacfa79dde..6b93e49fbd2 100644 --- a/docs/data/toolpad/core/introduction/installation.md +++ b/docs/data/toolpad/core/introduction/installation.md @@ -13,15 +13,15 @@ title: Toolpad Core - Installation ```bash npm -npx create-toolpad-app@latest --core +npx create-toolpad-app@latest ``` ```bash pnpm -pnpm create toolpad-app --core +pnpm create toolpad-app ``` ```bash yarn -yarn create toolpad-app --core +yarn create toolpad-app ``` diff --git a/docs/data/toolpad/studio/getting-started/first-app.md b/docs/data/toolpad/studio/getting-started/first-app.md index 7bdb2a306a2..7eacaa0c07e 100644 --- a/docs/data/toolpad/studio/getting-started/first-app.md +++ b/docs/data/toolpad/studio/getting-started/first-app.md @@ -26,7 +26,7 @@ Make sure to [install Node.js](https://nodejs.org/en) on your system. 1. Create a new application ```bash - npx create-toolpad-app@latest dog-app + npx create-toolpad-app@latest --studio dog-app ``` 1. Start the development server diff --git a/docs/data/toolpad/studio/getting-started/installation.md b/docs/data/toolpad/studio/getting-started/installation.md index 572b2dd0d60..c177d3ff2f5 100644 --- a/docs/data/toolpad/studio/getting-started/installation.md +++ b/docs/data/toolpad/studio/getting-started/installation.md @@ -10,15 +10,15 @@ Then run the command: ```bash npm -npx create-toolpad-app@latest my-toolpad-app +npx create-toolpad-app@latest --studio my-toolpad-app ``` ```bash yarn -yarn create toolpad-app my-toolpad-app +yarn create toolpad-app --studio my-toolpad-app ``` ```bash pnpm -pnpm create toolpad-app my-toolpad-app +pnpm create toolpad-app --studio my-toolpad-app ``` diff --git a/docs/pages/toolpad/core/index.js b/docs/pages/toolpad/core/index.js deleted file mode 100644 index 8fe382a2f63..00000000000 --- a/docs/pages/toolpad/core/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import * as React from 'react'; -import BrandingCssVarsProvider from 'docs/src/BrandingCssVarsProvider'; -import Divider from '@mui/material/Divider'; -import CssBaseline from '@mui/material/CssBaseline'; -import AppHeader from 'docs/src/layouts/AppHeader'; -import AppFooter from 'docs/src/layouts/AppFooter'; -import AppHeaderBanner from 'docs/src/components/banner/AppHeaderBanner'; -import Examples from '../../../src/components/landing-core/Examples'; -import Hero from '../../../src/components/landing-core/Hero'; -import Features from '../../../src/components/landing-core/Features'; -import BuiltWith from '../../../src/components/landing-core/BuiltWith'; -import StudioIntro from '../../../src/components/landing-core/StudioIntro'; - -export default function Home() { - return ( - - - - -
- - - - - - - -
- -
- ); -} diff --git a/docs/pages/toolpad/index.js b/docs/pages/toolpad/index.js index 4e033d9f808..e7878c2d4e8 100644 --- a/docs/pages/toolpad/index.js +++ b/docs/pages/toolpad/index.js @@ -1,64 +1,30 @@ import * as React from 'react'; -import NoSsr from '@mui/material/NoSsr'; -import Head from 'docs/src/modules/components/Head'; -import CssBaseline from '@mui/material/CssBaseline'; -import Divider from '@mui/material/Divider'; import BrandingCssVarsProvider from 'docs/src/BrandingCssVarsProvider'; +import Divider from '@mui/material/Divider'; +import CssBaseline from '@mui/material/CssBaseline'; import AppHeader from 'docs/src/layouts/AppHeader'; import AppFooter from 'docs/src/layouts/AppFooter'; import AppHeaderBanner from 'docs/src/components/banner/AppHeaderBanner'; +import Examples from '../../src/components/landing/Examples'; import Hero from '../../src/components/landing/Hero'; -import HeroVideo from '../../src/components/landing/HeroVideo'; -import SignUpToast from '../../src/components/landing/SignUpToast'; -import UseCases from '../../src/components/landing/UseCases'; -import CardGrid from '../../src/components/landing/CardGrid'; -import Pricing from '../../src/components/landing/PricingTable'; -import Marquee from '../../src/components/landing/Marquee'; -import features from '../../data/toolpad/studio/landing/features'; -import useCases from '../../data/toolpad/studio/landing/useCases'; -import marquee from '../../data/toolpad/studio/landing/marquee'; -import { - Headline, - plans, - planInfo, - rowHeaders, - communityData, - commercialData, -} from '../../data/toolpad/studio/landing/pricing'; +import Features from '../../src/components/landing/Features'; +import BuiltWith from '../../src/components/landing/BuiltWith'; +import StudioIntro from '../../src/components/landing/StudioIntro'; export default function Home() { return ( - - - -
- - - - - - - + - + + + diff --git a/docs/pages/toolpad/studio/index.js b/docs/pages/toolpad/studio/index.js new file mode 100644 index 00000000000..066518fbed9 --- /dev/null +++ b/docs/pages/toolpad/studio/index.js @@ -0,0 +1,66 @@ +import * as React from 'react'; +import NoSsr from '@mui/material/NoSsr'; +import Head from 'docs/src/modules/components/Head'; +import CssBaseline from '@mui/material/CssBaseline'; +import Divider from '@mui/material/Divider'; +import BrandingCssVarsProvider from 'docs/src/BrandingCssVarsProvider'; +import AppHeader from 'docs/src/layouts/AppHeader'; +import AppFooter from 'docs/src/layouts/AppFooter'; +import AppHeaderBanner from 'docs/src/components/banner/AppHeaderBanner'; +import Hero from '../../../src/components/landing-studio/Hero'; +import HeroVideo from '../../../src/components/landing-studio/HeroVideo'; +import SignUpToast from '../../../src/components/landing-studio/SignUpToast'; +import UseCases from '../../../src/components/landing-studio/UseCases'; +import CardGrid from '../../../src/components/landing-studio/CardGrid'; +import Pricing from '../../../src/components/landing-studio/PricingTable'; +import Marquee from '../../../src/components/landing-studio/Marquee'; +import features from '../../../data/toolpad/studio/landing/features'; +import useCases from '../../../data/toolpad/studio/landing/useCases'; +import marquee from '../../../data/toolpad/studio/landing/marquee'; +import { + Headline, + plans, + planInfo, + rowHeaders, + communityData, + commercialData, +} from '../../../data/toolpad/studio/landing/pricing'; + +export default function Home() { + return ( + + + + + + + + +
+ + + + + + + + + + + + + + + ); +} diff --git a/docs/src/components/landing-core/Hero.js b/docs/src/components/landing-core/Hero.js deleted file mode 100644 index b4bf19608c4..00000000000 --- a/docs/src/components/landing-core/Hero.js +++ /dev/null @@ -1,82 +0,0 @@ -import * as React from 'react'; -import Typography from '@mui/material/Typography'; -import IconImage from 'docs/src/components/icon/IconImage'; -import Box from '@mui/material/Box'; -import GradientText from 'docs/src/components/typography/GradientText'; -import { Container } from '@mui/material'; -import GetStartedButtons from './GetStartedButtons'; - -export default function Hero() { - return ( - - - ({ - display: 'flex', - alignItems: 'center', - gap: 0.5, - color: (theme.vars || theme).palette.primary[600], - ...theme.applyDarkStyles({ - color: (theme.vars || theme).palette.primary[400], - }), - }), - ]} - > - - Toolpad - - - - Open-source dashboard -
- framework for React -
- - Toolpad offers the components needed for your next admin portal or internal tool. - Bootstrap from scratch in our CLI with well chosen defaults, or drop Toolpad into your - existing Next.js or Vite* project. - -
- - - -
-
- ); -} diff --git a/docs/src/components/landing/Banner.js b/docs/src/components/landing-studio/Banner.js similarity index 100% rename from docs/src/components/landing/Banner.js rename to docs/src/components/landing-studio/Banner.js diff --git a/docs/src/components/landing/CardGrid.js b/docs/src/components/landing-studio/CardGrid.js similarity index 100% rename from docs/src/components/landing/CardGrid.js rename to docs/src/components/landing-studio/CardGrid.js diff --git a/docs/src/components/landing/CodeBlock.js b/docs/src/components/landing-studio/CodeBlock.js similarity index 100% rename from docs/src/components/landing/CodeBlock.js rename to docs/src/components/landing-studio/CodeBlock.js diff --git a/docs/src/components/landing/DemoVideo.js b/docs/src/components/landing-studio/DemoVideo.js similarity index 100% rename from docs/src/components/landing/DemoVideo.js rename to docs/src/components/landing-studio/DemoVideo.js diff --git a/docs/src/components/landing-core/GetStartedButtons.js b/docs/src/components/landing-studio/GetStartedButtons.js similarity index 73% rename from docs/src/components/landing-core/GetStartedButtons.js rename to docs/src/components/landing-studio/GetStartedButtons.js index 0b3eaf4273b..3768475db59 100644 --- a/docs/src/components/landing-core/GetStartedButtons.js +++ b/docs/src/components/landing-studio/GetStartedButtons.js @@ -5,10 +5,9 @@ import Button from '@mui/material/Button'; import KeyboardArrowRightRounded from '@mui/icons-material/KeyboardArrowRightRounded'; import { Link } from '@mui/docs/Link'; import NpmCopyButton from 'docs/src/components/action/NpmCopyButton'; -import GithubStars from '../landing/GithubStars'; export default function GetStartedButtons(props) { - const { installation, primaryLabel, primaryUrl, ...other } = props; + const { installation, primaryLabel, primaryUrl, secondaryLabel, secondaryUrl, ...other } = props; return ( } sx={{ @@ -36,7 +36,20 @@ export default function GetStartedButtons(props) { > {primaryLabel} - + {secondaryUrl ? ( + + ) : null} diff --git a/docs/src/components/landing/GithubStars.js b/docs/src/components/landing-studio/GithubStars.js similarity index 100% rename from docs/src/components/landing/GithubStars.js rename to docs/src/components/landing-studio/GithubStars.js diff --git a/docs/src/components/landing-studio/Hero.js b/docs/src/components/landing-studio/Hero.js new file mode 100644 index 00000000000..e3621282e61 --- /dev/null +++ b/docs/src/components/landing-studio/Hero.js @@ -0,0 +1,295 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { styled, alpha } from '@mui/material/styles'; +import Box from '@mui/material/Box'; +import Switch from '@mui/material/Switch'; +import Typography from '@mui/material/Typography'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import SvgMuiLogo from 'docs/src/icons/SvgMuiLogomark'; +import BrushIcon from '@mui/icons-material/Brush'; +import GradientText from 'docs/src/components/typography/GradientText'; +import GetStartedButtons from 'docs/src/components/home/GetStartedButtons'; +import GithubStars from './GithubStars'; +import CodeBlock from './CodeBlock'; +import ROUTES from '../../route'; +import ToolpadHeroContainer from '../../layouts/ToolpadHeroContainer'; + +const HeroModeSwitch = styled(Switch)(({ theme }) => ({ + width: 36, + height: 22, + padding: 0, + borderRadius: 99, + border: '1px solid', + borderColor: theme.palette.grey[200], + justifySelf: 'center', + ...theme.applyDarkStyles({ + borderColor: theme.palette.primaryDark[600], + backgroundColor: theme.palette.primary[600], + }), + '& .MuiSwitch-switchBase': { + padding: 1, + color: '#fff', + '&.Mui-checked': { + transform: 'translateX(14px)', + '& + .MuiSwitch-track': { + backgroundColor: theme.palette.grey[50], + ...theme.applyDarkStyles({ + backgroundColor: theme.palette.primaryDark[800], + }), + }, + }, + }, + '& .MuiSwitch-thumb': { + padding: 0, + height: 14, + width: 14, + boxShadow: 'none', + backgroundColor: theme.palette.primary[400], + }, + '& .MuiSwitch-track': { + backgroundColor: theme.palette.grey[50], + ...theme.applyDarkStyles({ + backgroundColor: theme.palette.primaryDark[800], + }), + }, +})); + +const Img = styled('img')(({ theme }) => [ + { + overflow: 'hidden', + objectFit: 'cover', + width: '100%', + height: '100%', + borderRadius: 10, + border: '1px solid', + borderColor: (theme.vars || theme).palette.grey[100], + }, + theme.applyDarkStyles({ + borderColor: (theme.vars || theme).palette.primaryDark[700], + }), +]); + +const words = ['APIs', 'scripts', 'SQL']; + +const LETTER_DELAY = 100; +const FRAME_DELAY = 3000; +const FRAMES = 6; + +function TypingAnimation({ wordIndex, setWordIndex }) { + const [text, setText] = React.useState(words[wordIndex]); + const [fullText, setFullText] = React.useState(words[wordIndex]); + const [letterIndex, setLetterIndex] = React.useState(fullText.length); + const count = React.useRef(0); + + React.useEffect(() => { + let timer; + if (letterIndex < fullText.length) { + timer = setTimeout(() => { + setText(text + fullText[letterIndex]); + setLetterIndex(letterIndex + 1); + }, LETTER_DELAY); + } else { + timer = setTimeout( + () => { + const nextIndex = (wordIndex + 1) % words.length; + setWordIndex(nextIndex); + setFullText(words[nextIndex]); + setText(''); + setLetterIndex(0); + count.current += 1; + }, + 2 * FRAME_DELAY - (count.current ? LETTER_DELAY * fullText.length : 0), + ); + } + return () => clearTimeout(timer); + }, [letterIndex, wordIndex, fullText, text, setWordIndex]); + + return {text}; +} + +export default function Hero() { + const [heroAppMode, setHeroAppMode] = React.useState(false); + const isLargerThanMd = useMediaQuery((theme) => theme.breakpoints.up('md')); + const isSmallerThanSm = useMediaQuery((theme) => theme.breakpoints.down('sm')); + const handleModeChange = React.useCallback((event) => { + setHeroAppMode(event.target.checked); + }, []); + const [wordIndex, setWordIndex] = React.useState(0); + const [frameIndex, setFrameIndex] = React.useState(0); + + const [pauseHeroAnimation, setPauseHeroAnimation] = React.useState(false); + + React.useEffect(() => { + const loop = setInterval(() => { + if (!pauseHeroAnimation) { + setHeroAppMode((prev) => !prev); + } + if ((isLargerThanMd || isSmallerThanSm) && !pauseHeroAnimation) { + setFrameIndex((prev) => (prev + 1) % FRAMES); + } + }, FRAME_DELAY); + return () => clearInterval(loop); + }, [pauseHeroAnimation, frameIndex, isLargerThanMd, isSmallerThanSm]); + + const fileIndex = React.useMemo(() => Math.floor(frameIndex / 2), [frameIndex]); + + return ( + + + ({ + display: 'flex', + alignItems: 'center', + gap: 0.5, + color: (theme.vars || theme).palette.primary[600], + ...theme.applyDarkStyles({ + color: (theme.vars || theme).palette.primary[400], + }), + }), + ]} + > + + + Toolpad Studio + + + + Turn your +
+ into UIs +
+ + Build scalable and secure internal tools locally. Drag and drop to build UI, then connect + to data sources with your own code. + + + + + + + + + + Powered by Material UI + + + +
+ setPauseHeroAnimation(true)} + onMouseLeave={() => setPauseHeroAnimation(false)} + > + ({ + position: { xs: 'absolute', sm: 'relative', md: 'absolute' }, + gridRowStart: 1, + gridRowEnd: 2, + gridColumnStart: { xs: 'unset', sm: 1, md: 'unset' }, + width: '100%', + justifySelf: { xs: 'center', sm: 'unset' }, + '& > img': { + objectFit: { xs: 'cover', sm: 'unset' }, + objectPosition: { xs: 'top', sm: 'unset' }, + }, + height: '100%', + borderRadius: '16px', + padding: '8px', + background: `linear-gradient(120deg, ${ + (theme.vars || theme).palette.grey[50] + } 0%, ${alpha(theme.palette.primary[50], 0.5)} 150%)`, + border: '1px solid', + borderColor: (theme.vars || theme).palette.grey[100], + backfaceVisibility: 'hidden', + transition: 'all 0.3s ease', + transform: { + xs: `rotateY(${heroAppMode ? '0' : '180'}deg)`, + sm: 'unset', + md: `rotateY(${heroAppMode ? '0' : '180'}deg)`, + }, + boxShadow: `0 4px 8px ${alpha(theme.palette.grey[100], 0.9)}`, + }), + (theme) => + theme.applyDarkStyles({ + background: `linear-gradient(120deg, ${ + (theme.vars || theme).palette.primaryDark[500] + } 0%, ${alpha(theme.palette.primaryDark[800], 0.4)} 150%)`, + borderColor: `${alpha(theme.palette.primaryDark[300], 0.3)}`, + boxShadow: `0 4px 8px ${alpha(theme.palette.common.black, 0.8)}`, + }), + ]} + > + + + + + + + Code + + + + UI + + + + +
+ ); +} + +TypingAnimation.propTypes = { + setWordIndex: PropTypes.func, + wordIndex: PropTypes.number, +}; diff --git a/docs/src/components/landing/HeroVideo.js b/docs/src/components/landing-studio/HeroVideo.js similarity index 100% rename from docs/src/components/landing/HeroVideo.js rename to docs/src/components/landing-studio/HeroVideo.js diff --git a/docs/src/components/landing/Marquee.js b/docs/src/components/landing-studio/Marquee.js similarity index 100% rename from docs/src/components/landing/Marquee.js rename to docs/src/components/landing-studio/Marquee.js diff --git a/docs/src/components/landing/PricingTable.js b/docs/src/components/landing-studio/PricingTable.js similarity index 100% rename from docs/src/components/landing/PricingTable.js rename to docs/src/components/landing-studio/PricingTable.js diff --git a/docs/src/components/landing/SignUp.js b/docs/src/components/landing-studio/SignUp.js similarity index 100% rename from docs/src/components/landing/SignUp.js rename to docs/src/components/landing-studio/SignUp.js diff --git a/docs/src/components/landing/SignUpToast.js b/docs/src/components/landing-studio/SignUpToast.js similarity index 100% rename from docs/src/components/landing/SignUpToast.js rename to docs/src/components/landing-studio/SignUpToast.js diff --git a/docs/src/components/landing/UseCases.js b/docs/src/components/landing-studio/UseCases.js similarity index 100% rename from docs/src/components/landing/UseCases.js rename to docs/src/components/landing-studio/UseCases.js diff --git a/docs/src/components/landing-core/BuiltWith.js b/docs/src/components/landing/BuiltWith.js similarity index 100% rename from docs/src/components/landing-core/BuiltWith.js rename to docs/src/components/landing/BuiltWith.js diff --git a/docs/src/components/landing-core/Examples.js b/docs/src/components/landing/Examples.js similarity index 98% rename from docs/src/components/landing-core/Examples.js rename to docs/src/components/landing/Examples.js index 7ed66d0e187..639848fcd93 100644 --- a/docs/src/components/landing-core/Examples.js +++ b/docs/src/components/landing/Examples.js @@ -100,7 +100,7 @@ export default function Examples() { overline="Examples" title={ - Toolpad is ideal for building + Toolpad Core is ideal for building } /> @@ -157,7 +157,7 @@ export default function Examples() { Build much more! - Learn how to build these and many other apps using Toolpad! + Learn how to build these and many other apps using Toolpad Core! Check out docs diff --git a/docs/src/components/landing-core/Features.js b/docs/src/components/landing/Features.js similarity index 100% rename from docs/src/components/landing-core/Features.js rename to docs/src/components/landing/Features.js diff --git a/docs/src/components/landing/GetStartedButtons.js b/docs/src/components/landing/GetStartedButtons.js index 3768475db59..6d325d4472a 100644 --- a/docs/src/components/landing/GetStartedButtons.js +++ b/docs/src/components/landing/GetStartedButtons.js @@ -5,9 +5,10 @@ import Button from '@mui/material/Button'; import KeyboardArrowRightRounded from '@mui/icons-material/KeyboardArrowRightRounded'; import { Link } from '@mui/docs/Link'; import NpmCopyButton from 'docs/src/components/action/NpmCopyButton'; +import GithubStars from '../landing-studio/GithubStars'; export default function GetStartedButtons(props) { - const { installation, primaryLabel, primaryUrl, secondaryLabel, secondaryUrl, ...other } = props; + const { installation, primaryLabel, primaryUrl, ...other } = props; return ( } sx={{ @@ -36,20 +36,7 @@ export default function GetStartedButtons(props) { > {primaryLabel} - {secondaryUrl ? ( - - ) : null} + diff --git a/docs/src/components/landing/Hero.js b/docs/src/components/landing/Hero.js index 423c71acb0b..233507b829f 100644 --- a/docs/src/components/landing/Hero.js +++ b/docs/src/components/landing/Hero.js @@ -1,149 +1,25 @@ import * as React from 'react'; -import PropTypes from 'prop-types'; -import { styled, alpha } from '@mui/material/styles'; -import Box from '@mui/material/Box'; -import Chip from '@mui/material/Chip'; -import Switch from '@mui/material/Switch'; import Typography from '@mui/material/Typography'; -import useMediaQuery from '@mui/material/useMediaQuery'; -import SvgMuiLogo from 'docs/src/icons/SvgMuiLogomark'; -import IconImage from 'docs/src/components/icon/IconImage'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import SvgToolpadLogo from 'docs/src/icons/SvgToolpadLogo'; +import Box from '@mui/material/Box'; import GradientText from 'docs/src/components/typography/GradientText'; -// import GetStartedButtons from './GetStartedButtons'; -import GetStartedButtons from 'docs/src/components/home/GetStartedButtons'; -import GithubStars from './GithubStars'; -import CodeBlock from './CodeBlock'; -import ROUTES from '../../route'; -import ToolpadHeroContainer from '../../layouts/ToolpadHeroContainer'; - -const HeroModeSwitch = styled(Switch)(({ theme }) => ({ - width: 36, - height: 22, - padding: 0, - borderRadius: 99, - border: '1px solid', - borderColor: theme.palette.grey[200], - justifySelf: 'center', - ...theme.applyDarkStyles({ - borderColor: theme.palette.primaryDark[600], - backgroundColor: theme.palette.primary[600], - }), - '& .MuiSwitch-switchBase': { - padding: 1, - color: '#fff', - '&.Mui-checked': { - transform: 'translateX(14px)', - '& + .MuiSwitch-track': { - backgroundColor: theme.palette.grey[50], - ...theme.applyDarkStyles({ - backgroundColor: theme.palette.primaryDark[800], - }), - }, - }, - }, - '& .MuiSwitch-thumb': { - padding: 0, - height: 14, - width: 14, - boxShadow: 'none', - backgroundColor: theme.palette.primary[400], - }, - '& .MuiSwitch-track': { - backgroundColor: theme.palette.grey[50], - ...theme.applyDarkStyles({ - backgroundColor: theme.palette.primaryDark[800], - }), - }, -})); - -const Img = styled('img')(({ theme }) => [ - { - overflow: 'hidden', - objectFit: 'cover', - width: '100%', - height: '100%', - borderRadius: 10, - border: '1px solid', - borderColor: (theme.vars || theme).palette.grey[100], - }, - theme.applyDarkStyles({ - borderColor: (theme.vars || theme).palette.primaryDark[700], - }), -]); - -const words = ['APIs', 'scripts', 'SQL']; - -const LETTER_DELAY = 100; -const FRAME_DELAY = 3000; -const FRAMES = 6; - -function TypingAnimation({ wordIndex, setWordIndex }) { - const [text, setText] = React.useState(words[wordIndex]); - const [fullText, setFullText] = React.useState(words[wordIndex]); - const [letterIndex, setLetterIndex] = React.useState(fullText.length); - const count = React.useRef(0); - - React.useEffect(() => { - let timer; - if (letterIndex < fullText.length) { - timer = setTimeout(() => { - setText(text + fullText[letterIndex]); - setLetterIndex(letterIndex + 1); - }, LETTER_DELAY); - } else { - timer = setTimeout( - () => { - const nextIndex = (wordIndex + 1) % words.length; - setWordIndex(nextIndex); - setFullText(words[nextIndex]); - setText(''); - setLetterIndex(0); - count.current += 1; - }, - 2 * FRAME_DELAY - (count.current ? LETTER_DELAY * fullText.length : 0), - ); - } - return () => clearTimeout(timer); - }, [letterIndex, wordIndex, fullText, text, setWordIndex]); - - return {text}; -} +import { Container } from '@mui/material'; +import GetStartedButtons from './GetStartedButtons'; export default function Hero() { - const [heroAppMode, setHeroAppMode] = React.useState(false); - const isLargerThanMd = useMediaQuery((theme) => theme.breakpoints.up('md')); - const isSmallerThanSm = useMediaQuery((theme) => theme.breakpoints.down('sm')); - const handleModeChange = React.useCallback((event) => { - setHeroAppMode(event.target.checked); - }, []); - const [wordIndex, setWordIndex] = React.useState(0); - const [frameIndex, setFrameIndex] = React.useState(0); - - const [pauseHeroAnimation, setPauseHeroAnimation] = React.useState(false); - - React.useEffect(() => { - const loop = setInterval(() => { - if (!pauseHeroAnimation) { - setHeroAppMode((prev) => !prev); - } - if ((isLargerThanMd || isSmallerThanSm) && !pauseHeroAnimation) { - setFrameIndex((prev) => (prev + 1) % FRAMES); - } - }, FRAME_DELAY); - return () => clearInterval(loop); - }, [pauseHeroAnimation, frameIndex, isLargerThanMd, isSmallerThanSm]); - - const fileIndex = React.useMemo(() => Math.floor(frameIndex / 2), [frameIndex]); - return ( - + - - - Toolpad - - {}} - deleteIcon={} - sx={[ - (theme) => ({ - pb: 0.15, - ml: 0.8, - background: alpha(theme.palette.primary[50], 0.5), - borderColor: (theme.vars || theme).palette.primary[100], - ...theme.applyDarkStyles({ - color: (theme.vars || theme).palette.primary[200], - borderColor: (theme.vars || theme).palette.primary[700], - background: alpha(theme.palette.primary[800], 0.3), - }), - }), - ]} - /> - - - Turn your -
- into UIs -
- - Build scalable and secure internal tools locally. Drag and drop to build UI, then connect - to data sources with your own code. + + Toolpad Core - + + Open-source dashboard +
+ framework for React +
+ + From the creators of MUI, Toolpad Core offers the components needed for your next admin + panel and internal tools project. Bootstrap from scratch in our CLI with well chosen + defaults, or drop Toolpad Core into your existing Next.js or Vite* project. +
- - - - - Powered by Material UI - - - -
- setPauseHeroAnimation(true)} - onMouseLeave={() => setPauseHeroAnimation(false)} - > - ({ - position: { xs: 'absolute', sm: 'relative', md: 'absolute' }, - gridRowStart: 1, - gridRowEnd: 2, - gridColumnStart: { xs: 'unset', sm: 1, md: 'unset' }, - width: '100%', - justifySelf: { xs: 'center', sm: 'unset' }, - '& > img': { - objectFit: { xs: 'cover', sm: 'unset' }, - objectPosition: { xs: 'top', sm: 'unset' }, - }, - height: '100%', - borderRadius: '16px', - padding: '8px', - background: `linear-gradient(120deg, ${ - (theme.vars || theme).palette.grey[50] - } 0%, ${alpha(theme.palette.primary[50], 0.5)} 150%)`, - border: '1px solid', - borderColor: (theme.vars || theme).palette.grey[100], - backfaceVisibility: 'hidden', - transition: 'all 0.3s ease', - transform: { - xs: `rotateY(${heroAppMode ? '0' : '180'}deg)`, - sm: 'unset', - md: `rotateY(${heroAppMode ? '0' : '180'}deg)`, - }, - boxShadow: `0 4px 8px ${alpha(theme.palette.grey[100], 0.9)}`, - }), - (theme) => - theme.applyDarkStyles({ - background: `linear-gradient(120deg, ${ - (theme.vars || theme).palette.primaryDark[500] - } 0%, ${alpha(theme.palette.primaryDark[800], 0.4)} 150%)`, - borderColor: `${alpha(theme.palette.primaryDark[300], 0.3)}`, - boxShadow: `0 4px 8px ${alpha(theme.palette.common.black, 0.8)}`, - }), - ]} - > - - - - - - Code - - - - UI - - - -
+ ); } - -TypingAnimation.propTypes = { - setWordIndex: PropTypes.func, - wordIndex: PropTypes.number, -}; diff --git a/docs/src/components/landing-core/StudioIntro.js b/docs/src/components/landing/StudioIntro.js similarity index 96% rename from docs/src/components/landing-core/StudioIntro.js rename to docs/src/components/landing/StudioIntro.js index e868425e89b..10debd9c3b3 100644 --- a/docs/src/components/landing-core/StudioIntro.js +++ b/docs/src/components/landing/StudioIntro.js @@ -41,9 +41,9 @@ export default function StudioIntro() { /> diff --git a/docs/src/components/landing-core/ToolpadAuthDemo.tsx b/docs/src/components/landing/ToolpadAuthDemo.tsx similarity index 100% rename from docs/src/components/landing-core/ToolpadAuthDemo.tsx rename to docs/src/components/landing/ToolpadAuthDemo.tsx diff --git a/docs/src/components/landing-core/ToolpadDashboardLayout.tsx b/docs/src/components/landing/ToolpadDashboardLayout.tsx similarity index 100% rename from docs/src/components/landing-core/ToolpadDashboardLayout.tsx rename to docs/src/components/landing/ToolpadDashboardLayout.tsx diff --git a/docs/src/components/landing-core/ToolpadDialogDemo.tsx b/docs/src/components/landing/ToolpadDialogDemo.tsx similarity index 95% rename from docs/src/components/landing-core/ToolpadDialogDemo.tsx rename to docs/src/components/landing/ToolpadDialogDemo.tsx index 07b8a89f5d6..1296ea68b76 100644 --- a/docs/src/components/landing-core/ToolpadDialogDemo.tsx +++ b/docs/src/components/landing/ToolpadDialogDemo.tsx @@ -27,10 +27,8 @@ function DemoContent() { return (