Run prettier format

This commit is contained in:
Boris Martinovic 2023-11-02 21:46:07 +01:00 committed by Martin Šošić
parent 4c362f3651
commit 6cfc495ca4
55 changed files with 1184 additions and 1071 deletions

View File

@ -1,3 +1,3 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
}

View File

@ -1,11 +1,11 @@
import React from "react";
import React from 'react'
const DiscordLink = (props) => {
return (
<span>
<a href="https://discord.gg/rzdnErX"> Discord </a>
<a href="https://discord.gg/rzdnErX"> Discord </a>
</span>
);
};
)
}
export default DiscordLink;
export default DiscordLink

View File

@ -1,19 +1,26 @@
import React from "react";
import useBaseUrl from "@docusaurus/useBaseUrl";
import React from 'react'
import useBaseUrl from '@docusaurus/useBaseUrl'
const ImgWithCaption = (props) => {
return (
<div>
<p align='center'>
<p align="center">
<figure>
<img style={{ width: props.width }} alt={props.alt} src={useBaseUrl(props.source)} />
<figcaption class='image-caption' style={{ fontStyle: 'italic', opacity: 0.6, fontSize: '0.9rem' }}>
<img
style={{ width: props.width }}
alt={props.alt}
src={useBaseUrl(props.source)}
/>
<figcaption
class="image-caption"
style={{ fontStyle: 'italic', opacity: 0.6, fontSize: '0.9rem' }}
>
{props.caption}
</figcaption>
</figure>
</p>
</div>
);
};
)
}
export default ImgWithCaption;
export default ImgWithCaption

View File

@ -1,28 +1,30 @@
import React from 'react'
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import Link from '@docusaurus/Link'
import useBaseUrl from '@docusaurus/useBaseUrl'
const Divider = () => (
<span className='in-blog-cta--divider'> </span>
)
const Divider = () => <span className="in-blog-cta--divider"> </span>
const InBlogCta = () => (
<p className='in-blog-cta-link-container'>
<Link className='in-blog-cta--link'
to='https://e44cy1h4s0q.typeform.com/to/ycUzQa5A'>
We are in Beta (try it out)!
</Link>
<Divider />
<Link className='in-blog-cta--link' to='https://discord.gg/rzdnErX'>
Join our community
</Link>
<Divider />
<Link className='in-blog-cta--link'
to='https://wasp-lang.notion.site/Founding-Engineer-at-Wasp-402274568afa4d7eb7f428f8fa2c0816'>
Work with us
</Link>
</p>
<p className="in-blog-cta-link-container">
<Link
className="in-blog-cta--link"
to="https://e44cy1h4s0q.typeform.com/to/ycUzQa5A"
>
We are in Beta (try it out)!
</Link>
<Divider />
<Link className="in-blog-cta--link" to="https://discord.gg/rzdnErX">
Join our community
</Link>
<Divider />
<Link
className="in-blog-cta--link"
to="https://wasp-lang.notion.site/Founding-Engineer-at-Wasp-402274568afa4d7eb7f428f8fa2c0816"
>
Work with us
</Link>
</p>
)
export default InBlogCta

View File

@ -1,13 +1,13 @@
import Admonition from "@theme/Admonition";
import Link from "@docusaurus/Link";
import React from "react";
import Admonition from '@theme/Admonition'
import Link from '@docusaurus/Link'
import React from 'react'
export default function OldDocsNote() {
return (
<div
style={{
position: "sticky",
top: "calc(var(--ifm-navbar-height) + 1rem)",
position: 'sticky',
top: 'calc(var(--ifm-navbar-height) + 1rem)',
zIndex: 1,
}}
>
@ -21,5 +21,5 @@ export default function OldDocsNote() {
content.
</Admonition>
</div>
);
)
}

View File

@ -26,4 +26,4 @@
}
.deployment-methods-info {
color: var(--ifm-color-secondary-contrast-foreground);
}
}

View File

@ -1,19 +1,19 @@
import React from "react";
import "./DeploymentOptionsGrid.css";
import React from 'react'
import './DeploymentOptionsGrid.css'
export function DeploymentOptionsGrid() {
const deploymentMethods = [
{
title: "Using Wasp CLI",
description: "One command deployment & redeployment",
linkToDocs: "/docs/advanced/deployment/cli",
title: 'Using Wasp CLI',
description: 'One command deployment & redeployment',
linkToDocs: '/docs/advanced/deployment/cli',
},
{
title: "Deploying Manually",
description: "Build the app and deploy it manually",
linkToDocs: "/docs/advanced/deployment/manually",
title: 'Deploying Manually',
description: 'Build the app and deploy it manually',
linkToDocs: '/docs/advanced/deployment/manually',
},
];
]
return (
<>
<div className="deployment-methods-grid">
@ -29,7 +29,7 @@ export function DeploymentOptionsGrid() {
<small>Click on each deployment method for more details.</small>
</p>
</>
);
)
}
function DeploymentOptionBox({
@ -37,14 +37,14 @@ function DeploymentOptionBox({
title,
description,
}: {
linkToDocs: string;
title: string;
description: string;
linkToDocs: string
title: string
description: string
}) {
return (
<a href={linkToDocs} className="deployment-method-box">
<h3>{title} »</h3>
<p>{description}</p>
</a>
);
}
)
}

View File

@ -6,10 +6,10 @@
--auth-pills-username-and-pass: #fce7f3;
}
:root[data-theme="dark"] {
:root[data-theme='dark'] {
--auth-pills-color: #fff;
--auth-pills-email: #0c4a6e;
--auth-pills-github: #334155;
--auth-pills-google: #365314;
--auth-pills-username-and-pass: #831843;
}
}

View File

@ -1,18 +1,23 @@
import React from "react";
import './Pills.css';
import Link from '@docusaurus/Link';
import React from 'react'
import './Pills.css'
import Link from '@docusaurus/Link'
export function Pill({ children, linkToPage, style = {} }) {
return <Link to={linkToPage}
style={{
padding: "0.1rem 0.5rem",
borderRadius: "0.375rem",
color: "var(--auth-pills-color)",
textDecoration: "none",
display: "inline-block",
...style,
}}
>{children}</Link>;
return (
<Link
to={linkToPage}
style={{
padding: '0.1rem 0.5rem',
borderRadius: '0.375rem',
color: 'var(--auth-pills-color)',
textDecoration: 'none',
display: 'inline-block',
...style,
}}
>
{children}
</Link>
)
}
/*
@ -24,25 +29,53 @@ export function Pill({ children, linkToPage, style = {} }) {
}
*/
export function EmailPill() {
return <Pill style={{
backgroundColor: "var(--auth-pills-email)",
}} linkToPage="/docs/auth/email">Email</Pill>;
return (
<Pill
style={{
backgroundColor: 'var(--auth-pills-email)',
}}
linkToPage="/docs/auth/email"
>
Email
</Pill>
)
}
export function UsernameAndPasswordPill() {
return <Pill style={{
backgroundColor: "var(--auth-pills-username-and-pass)",
}} linkToPage="/docs/auth/username-and-pass">Username & Password</Pill>;
return (
<Pill
style={{
backgroundColor: 'var(--auth-pills-username-and-pass)',
}}
linkToPage="/docs/auth/username-and-pass"
>
Username & Password
</Pill>
)
}
export function GithubPill() {
return <Pill style={{
backgroundColor: "var(--auth-pills-github)",
}} linkToPage="/docs/auth/social-auth/github">Github</Pill>;
return (
<Pill
style={{
backgroundColor: 'var(--auth-pills-github)',
}}
linkToPage="/docs/auth/social-auth/github"
>
Github
</Pill>
)
}
export function GooglePill() {
return <Pill style={{
backgroundColor: "var(--auth-pills-google)",
}} linkToPage="/docs/auth/social-auth/google">Google</Pill>;
return (
<Pill
style={{
backgroundColor: 'var(--auth-pills-google)',
}}
linkToPage="/docs/auth/social-auth/google"
>
Google
</Pill>
)
}

View File

@ -1,22 +1,22 @@
import React from "react";
import Link from '@docusaurus/Link';
import "./SocialAuthGrid.css";
import React from 'react'
import Link from '@docusaurus/Link'
import './SocialAuthGrid.css'
export function SocialAuthGrid({
pagePart = "", // e.g. #overrides
pagePart = '', // e.g. #overrides
}) {
const authMethods = [
{
title: "Google",
description: "Users sign in with their Google account.",
linkToDocs: "/docs/auth/social-auth/google" + pagePart,
title: 'Google',
description: 'Users sign in with their Google account.',
linkToDocs: '/docs/auth/social-auth/google' + pagePart,
},
{
title: "Github",
description: "Users sign in with their Github account.",
linkToDocs: "/docs/auth/social-auth/github" + pagePart,
title: 'Github',
description: 'Users sign in with their Github account.',
linkToDocs: '/docs/auth/social-auth/github' + pagePart,
},
];
]
return (
<>
<div className="social-auth-grid">
@ -32,7 +32,7 @@ export function SocialAuthGrid({
<small>Click on each provider for more details.</small>
</p>
</>
);
)
}
function AuthMethodBox({
@ -40,14 +40,14 @@ function AuthMethodBox({
title,
description,
}: {
linkToDocs: string;
title: string;
description: string;
linkToDocs: string
title: string
description: string
}) {
return (
<Link to={linkToDocs} className="auth-method-box">
<h3>{title} »</h3>
<p>{description}</p>
</Link>
);
)
}

View File

@ -1,25 +1,25 @@
const lightCodeTheme = require("prism-react-renderer/themes/github");
const lightCodeTheme = require('prism-react-renderer/themes/github')
const autoImportTabs = require("./src/remark/auto-import-tabs");
const fileExtSwitcher = require("./src/remark/file-ext-switcher");
const autoImportTabs = require('./src/remark/auto-import-tabs')
const fileExtSwitcher = require('./src/remark/file-ext-switcher')
/** @type {import('@docusaurus/types').DocusaurusConfig} */
module.exports = {
title: "Wasp",
title: 'Wasp',
tagline:
"A simple language for developing full-stack web apps with less code.",
'A simple language for developing full-stack web apps with less code.',
// url, baseUrl, organizationName, projectName and trailingSlash are set according to the
// instructions in https://docusaurus.io/docs/deployment#deploying-to-github-pages .
url: "https://wasp-lang.dev",
baseUrl: "/", // Should be name of repo if hosted on Github Pages, but can be just '/' if custom domain is used.
organizationName: "wasp-lang", // Should be GitHub org/user name if hosted on Github Pages.
projectName: "wasp", // Should be repo name if hosted on Github Pages.
url: 'https://wasp-lang.dev',
baseUrl: '/', // Should be name of repo if hosted on Github Pages, but can be just '/' if custom domain is used.
organizationName: 'wasp-lang', // Should be GitHub org/user name if hosted on Github Pages.
projectName: 'wasp', // Should be repo name if hosted on Github Pages.
trailingSlash: false,
onBrokenLinks: "throw",
onBrokenMarkdownLinks: "warn",
favicon: "img/favicon.ico",
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',
stylesheets: [
"https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap",
'https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap',
],
themeConfig: {
/*
@ -47,86 +47,86 @@ module.exports = {
},
},
navbar: {
title: ".wasp (beta)",
title: '.wasp (beta)',
logo: {
alt: "Wasp logo",
src: "img/wasp-logo-eqpar-circle.png",
href: "https://wasp-lang.dev/",
target: "_self"
alt: 'Wasp logo',
src: 'img/wasp-logo-eqpar-circle.png',
href: 'https://wasp-lang.dev/',
target: '_self'
},
items: [
{
to: "docs/",
activeBasePath: "docs",
label: "Docs",
position: "left",
className: "navbar-item-docs navbar-item-outside",
to: 'docs/',
activeBasePath: 'docs',
label: 'Docs',
position: 'left',
className: 'navbar-item-docs navbar-item-outside',
},
{
to: "blog",
label: "Blog",
position: "left",
to: 'blog',
label: 'Blog',
position: 'left',
},
{
href: "https://github.com/wasp-lang/wasp",
className: "navbar-item-github",
position: "right",
href: 'https://github.com/wasp-lang/wasp',
className: 'navbar-item-github',
position: 'right',
},
{
href: "https://twitter.com/WaspLang",
className: "navbar-item-twitter",
position: "right",
href: 'https://twitter.com/WaspLang',
className: 'navbar-item-twitter',
position: 'right',
},
{
href: "https://discord.gg/rzdnErX",
className: "navbar-item-discord",
position: "right",
href: 'https://discord.gg/rzdnErX',
className: 'navbar-item-discord',
position: 'right',
},
],
},
prism: {
additionalLanguages: ["shell-session", "haskell"],
additionalLanguages: ['shell-session', 'haskell'],
theme: lightCodeTheme,
},
footer: {
style: "dark",
style: 'dark',
links: [
{
title: "Docs",
title: 'Docs',
items: [
{
label: "Getting started",
to: "docs",
label: 'Getting started',
to: 'docs',
},
{
label: "Todo app tutorial",
to: "docs/tutorial/create",
label: 'Todo app tutorial',
to: 'docs/tutorial/create',
},
{
label: "Reference",
to: "docs/language/features",
label: 'Reference',
to: 'docs/language/features',
},
],
},
{
title: "Community",
title: 'Community',
items: [
{
label: "Discord",
href: "https://discord.gg/rzdnErX",
label: 'Discord',
href: 'https://discord.gg/rzdnErX',
},
],
},
{
title: "More",
title: 'More',
items: [
{
label: "GitHub",
href: "https://github.com/wasp-lang/wasp",
label: 'GitHub',
href: 'https://github.com/wasp-lang/wasp',
},
{
label: "Contact",
to: "docs/contact",
label: 'Contact',
to: 'docs/contact',
},
],
},
@ -134,59 +134,59 @@ module.exports = {
copyright: `Copyright © ${new Date().getFullYear()} Wasp.`,
},
algolia: {
appId: "RG0JSZOWH4",
apiKey: "feaa2a25dc596d40418c82cd040e2cbe",
indexName: "wasp-lang",
appId: 'RG0JSZOWH4',
apiKey: 'feaa2a25dc596d40418c82cd040e2cbe',
indexName: 'wasp-lang',
// TODO: contextualSearch is useful when you are doing versioning,
// it searches only in v1 docs if you are searching from v1 docs.
// We should enable it if we start doing versioning.
// contextualSearch: true
},
image: "img/wasp_twitter_cover.png",
metadata: [{ name: "twitter:card", content: "summary_large_image" }],
image: 'img/wasp_twitter_cover.png',
metadata: [{ name: 'twitter:card', content: 'summary_large_image' }],
},
presets: [
[
"@docusaurus/preset-classic",
'@docusaurus/preset-classic',
{
gtag: {
trackingID: "GTM-PQ4JFCK",
trackingID: 'GTM-PQ4JFCK',
anonymizeIP: true,
},
docs: {
sidebarPath: require.resolve("./sidebars.js"),
sidebarPath: require.resolve('./sidebars.js'),
sidebarCollapsible: true,
// Please change this to your repo.
editUrl: "https://github.com/wasp-lang/wasp/edit/release/web",
editUrl: 'https://github.com/wasp-lang/wasp/edit/release/web',
remarkPlugins: [autoImportTabs, fileExtSwitcher],
},
blog: {
showReadingTime: true,
// Please change this to your repo.
blogSidebarCount: "ALL",
blogSidebarTitle: "All our posts",
postsPerPage: "ALL",
editUrl: "https://github.com/wasp-lang/wasp/edit/release/web",
blogSidebarCount: 'ALL',
blogSidebarTitle: 'All our posts',
postsPerPage: 'ALL',
editUrl: 'https://github.com/wasp-lang/wasp/edit/release/web',
},
theme: {
customCss: [require.resolve("./src/css/custom.css")],
customCss: [require.resolve('./src/css/custom.css')],
},
},
],
],
scripts: ["/scripts/posthog.js", "/js/fix-multiple-trailing-slashes.js"],
scripts: ['/scripts/posthog.js', '/js/fix-multiple-trailing-slashes.js'],
plugins: [
"plugin-image-zoom",
'plugin-image-zoom',
async function myPlugin(context, options) {
return {
name: "docusaurus-tailwindcss",
name: 'docusaurus-tailwindcss',
configurePostCss(postcssOptions) {
// Appends TailwindCSS and AutoPrefixer.
postcssOptions.plugins.push(require("tailwindcss"));
postcssOptions.plugins.push(require("autoprefixer"));
return postcssOptions;
postcssOptions.plugins.push(require('tailwindcss'))
postcssOptions.plugins.push(require('autoprefixer'))
return postcssOptions
},
};
}
},
[
'@docusaurus/plugin-client-redirects',
@ -218,7 +218,7 @@ module.exports = {
},
{
from: '/docs/guides/email-auth',
to: '/docs/auth/email'
to: '/docs/auth/email',
},
{
from: '/docs/guides/crud',
@ -244,4 +244,4 @@ module.exports = {
},
],
],
};
}

View File

@ -26,4 +26,4 @@
}
.auth-methods-info {
color: var(--ifm-color-secondary-contrast-foreground);
}
}

View File

@ -1,29 +1,29 @@
import React from "react";
import "./AuthMethodsGrid.css";
import React from 'react'
import './AuthMethodsGrid.css'
export function AuthMethodsGrid() {
const authMethods = [
{
title: "Email",
description: "Email verification, password reset, etc.",
linkToDocs: "/docs/auth/email",
title: 'Email',
description: 'Email verification, password reset, etc.',
linkToDocs: '/docs/auth/email',
},
{
title: "Username & Password",
description: "The simplest way to get started",
linkToDocs: "/docs/auth/username-and-pass",
title: 'Username & Password',
description: 'The simplest way to get started',
linkToDocs: '/docs/auth/username-and-pass',
},
{
title: "Google",
description: "Users sign in with their Google account",
linkToDocs: "/docs/auth/social-auth/google",
title: 'Google',
description: 'Users sign in with their Google account',
linkToDocs: '/docs/auth/social-auth/google',
},
{
title: "Github",
description: "Users sign in with their Github account",
linkToDocs: "/docs/auth/social-auth/github",
title: 'Github',
description: 'Users sign in with their Github account',
linkToDocs: '/docs/auth/social-auth/github',
},
];
]
return (
<>
<div className="auth-methods-grid">
@ -39,7 +39,7 @@ export function AuthMethodsGrid() {
<small>Click on each auth method for more details.</small>
</p>
</>
);
)
}
function AuthMethodBox({
@ -47,14 +47,14 @@ function AuthMethodBox({
title,
description,
}: {
linkToDocs: string;
title: string;
description: string;
linkToDocs: string
title: string
description: string
}) {
return (
<a href={linkToDocs} className="auth-method-box">
<h3>{title} »</h3>
<p>{description}</p>
</a>
);
)
}

View File

@ -8,52 +8,47 @@ import styles from '../pages/styles.module.css'
const Lang = () => (
<>
<span className='underline decoration-yellow-500 font-bold'>
language
</span>
<span className="font-bold underline decoration-yellow-500">language</span>
</>
)
const Benefit = ({ Icon, title, description }) => (
<div className='mb-10 md:mb-0 space-y-4'>
<div className='flex items-center'>
<div className="mb-10 space-y-4 md:mb-0">
<div className="flex items-center">
<div
className={`
inline-flex h-8 w-8 rounded-md
items-center justify-center
text-yellow-500 bg-neutral-700
inline-flex h-8 w-8 items-center
justify-center rounded-md
bg-neutral-700 text-yellow-500
`}
>
<Icon size={20} />
</div>
<dt className='ml-4 text-neutral-700'>
{ title }
</dt>
<dt className="ml-4 text-neutral-700">{title}</dt>
</div>
<p className='text-neutral-700'>
{ description }
</p>
<p className="text-neutral-700">{description}</p>
</div>
)
const Benefits = () => {
return (
<SectionContainer className='space-y-16'>
<div className='grid grid-cols-12'>
<div className='col-span-12 text-center'>
<h2 className='text-xl lg:text-2xl text-neutral-700 mb-4'>
<SectionContainer className="space-y-16">
<div className="grid grid-cols-12">
<div className="col-span-12 text-center">
<h2 className="mb-4 text-xl text-neutral-700 lg:text-2xl">
Get started in minutes - zero config required.
</h2>
<p className='text-neutral-500'>
Wasp provides all the best practices out-of-the-box and lets you focus on your code.
<p className="text-neutral-500">
Wasp provides all the best practices out-of-the-box and lets you
focus on your code.
</p>
</div>
</div>
<dl className='grid grid-cols-1 lg:grid-cols-3 md:gap-16 lg:gap-x-8 xl:gap-x-24'>
<dl className="grid grid-cols-1 md:gap-16 lg:grid-cols-3 lg:gap-x-8 xl:gap-x-24">
<Benefit
Icon={Layers}
title='Truly full-stack'
title="Truly full-stack"
description={`
When we say full-stack, we really mean it. Wasp has you covered from front-end,
back-end and database to deployment. Zero config required to get started.
@ -62,7 +57,7 @@ const Benefits = () => {
<Benefit
Icon={Coffee}
title='The wheel can take a break'
title="The wheel can take a break"
description={`
No reinventing the wheel here. Write your code in React & Node.js as you are used to,
along with your favourite NPM packages.
@ -71,7 +66,7 @@ const Benefits = () => {
<Benefit
Icon={Code}
title='Less boilerplate'
title="Less boilerplate"
description={`
The .wasp config file allows us to immensely improve developer experience.
E.g., full-stack auth takes only 5 lines of code.
@ -83,17 +78,16 @@ const Benefits = () => {
}
const BenefitsWithSkewedBorder = () => (
<div className='relative'>
<div className="relative">
<div className={classNames(styles.sectionSkewedContainer)}>
<div
className={classNames(
styles.sectionSkewed,
'border-t border-b border-yellow-500/25 bg-neutral-100/50'
'border-b border-t border-yellow-500/25 bg-neutral-100/50'
)}
>
</div>
></div>
</div>
<div className='relative'>
<div className="relative">
<Benefits />
</div>
</div>

View File

@ -1,14 +1,12 @@
import React, { useState } from 'react'
import CodeBlock from '@theme/CodeBlock'
export default function CodeBlockWithTitle ({ title, children, language }) {
export default function CodeBlockWithTitle({ title, children, language }) {
return (
<div className='code-with-header'>
<div className="code-header">{ title }</div>
<div className="code-with-header">
<div className="code-header">{title}</div>
<CodeBlock language={language}>
{ children }
</CodeBlock>
<CodeBlock language={language}>{children}</CodeBlock>
</div>
)
}

View File

@ -1,39 +1,39 @@
import React, { useEffect } from "react";
import Prism from "prismjs";
import "../css/prismjs-github-theme.css";
import React, { useEffect } from 'react'
import Prism from 'prismjs'
import '../css/prismjs-github-theme.css'
export default function CodeHighlight(props = {}) {
const codeRef = React.createRef();
const codeRef = React.createRef()
const {
prefixCls = "code-highlight-wrapper",
prefixCls = 'code-highlight-wrapper',
className,
language,
source,
children,
...others
} = props;
const langCls = language ? `language-${language}` : "";
} = props
const langCls = language ? `language-${language}` : ''
async function highlight() {
if (codeRef.current) {
Prism.highlightElement(codeRef.current);
Prism.highlightElement(codeRef.current)
}
}
useEffect(() => {
highlight();
}, [language, source]);
highlight()
}, [language, source])
return (
<pre
className={`${prefixCls} ${className || ""} ${langCls}`}
className={`${prefixCls} ${className || ''} ${langCls}`}
{...others}
style={{
borderBottomLeftRadius: "10px",
borderBottomRightRadius: "10px",
paddingLeft: "15px",
borderBottomLeftRadius: '10px',
borderBottomRightRadius: '10px',
paddingLeft: '15px',
}}
>
<code className={langCls} ref={codeRef}>
{source || children}
</code>
</pre>
);
)
}

View File

@ -1,12 +1,15 @@
import React from 'react'
import Details from '@theme/MDXComponents/Details'
export default function Collapse(props: { children: React.ReactNode; title: string }) {
const { children, title } = props;
return (
<Details>
<summary mdxType="summary">{title}</summary>
{children}
</Details>
)
export default function Collapse(props: {
children: React.ReactNode
title: string
}) {
const { children, title } = props
return (
<Details>
<summary mdxType="summary">{title}</summary>
{children}
</Details>
)
}

View File

@ -3,20 +3,20 @@ import { Sun, Moon } from 'react-feather'
const DarkModeToggle = () => {
const [isDarkMode, setIsDarkMode] = useState(false)
const toggleDarkMode = () => {
setIsDarkMode(!isDarkMode)
}
return (
<div className='flex items-end'>
<Sun strokeWidth={2} size={22} className='text-neutral-500' />
<div className="flex items-end">
<Sun strokeWidth={2} size={22} className="text-neutral-500" />
<button
type='button'
aria-pressed='false'
type="button"
aria-pressed="false"
className={`
relative inline-flex
h-6 w-11 mx-3 flex-shrink-0 cursor-pointer
relative mx-3
inline-flex h-6 w-11 flex-shrink-0 cursor-pointer
rounded-full border-2 border-transparent
bg-neutral-500
transition-colors duration-200 ease-in-out focus:outline-none
@ -24,20 +24,18 @@ const DarkModeToggle = () => {
onClick={() => toggleDarkMode()}
>
<span
aria-hidden='true'
aria-hidden="true"
className={`
${isDarkMode ? 'translate-x-5' : 'translate-x-0'}
inline-block h-5 w-5
bg-white shadow-lg rounded-full ring-0
transform transition duration-200 ease-in-out
transform rounded-full bg-white shadow-lg
ring-0 transition duration-200 ease-in-out
`}
/>
</button>
<Moon strokeWidth={2} size={22} className='text-neutral-500' />
<Moon strokeWidth={2} size={22} className="text-neutral-500" />
</div>
)
}

View File

@ -1,31 +1,29 @@
import React from 'react';
import React from 'react'
import './emailSignupForm.css'
const EmailSignupForm = ({ placeholder }) => {
return (
<form
className="email-signup-form"
action="https://gmail.us4.list-manage.com/subscribe/post?u=8139c7de74df98aa17054b235&amp;id=f0c6ba5f1d"
method="post"
className="email-signup-form"
action="https://gmail.us4.list-manage.com/subscribe/post?u=8139c7de74df98aa17054b235&amp;id=f0c6ba5f1d"
method="post"
>
<input
aria-label="Email address"
name="EMAIL"
type="email"
required
className="input"
placeholder={placeholder || "Enter your email"}
placeholder={placeholder || 'Enter your email'}
/>
<div className="">
<button className="button button--primary" type="submit">
Subscribe
</button>
</div>
</form>
)
}
export default EmailSignupForm;
export default EmailSignupForm

View File

@ -40,11 +40,11 @@ const SeeTheCodeButton = ({ repoUrl }) => (
<button
className={`
flex items-center
text-xs
px-2.5 py-1 rounded
bg-transparent border border-yellow-500 text-neutral-500
hover:text-neutral-400
transition ease-out duration-200
rounded
border border-yellow-500 bg-transparent
px-2.5 py-1 text-xs text-neutral-500
transition
duration-200 ease-out hover:text-neutral-400
`}
>
<span>See the code</span>
@ -58,11 +58,11 @@ const DemoButton = ({ demoUrl }) => (
<button
className={`
flex items-center
text-xs
px-2.5 py-1 rounded
bg-yellow-500 text-white
hover:bg-yellow-400
transition ease-out duration-200
rounded
bg-yellow-500 px-2.5 py-1
text-xs text-white
transition
duration-200 ease-out hover:bg-yellow-400
`}
>
<span>Demo</span>
@ -76,17 +76,17 @@ const ExampleCard = (props) => (
{/* Top half */}
<div
className={`
flex
h-40 flex-col rounded rounded-b-none
border-l border-r
border-t border-yellow-500/25
bg-yellow-500/5
border-t border-l border-r border-yellow-500/25
rounded rounded-b-none
flex flex-col
h-40
p-5
`}
>
<div className="mb-4">
<h4 className="mb-4 text-neutral-700">{props.title}</h4>
<p className="text-sm mb-4 text-neutral-500">{props.description}</p>
<p className="mb-4 text-sm text-neutral-500">{props.description}</p>
<div>
<img
className="inline w-6 rounded-full"
@ -103,10 +103,10 @@ const ExampleCard = (props) => (
{/* Bottom half */}
<div
className={`
bg-yellow-500/20
border-b border-l border-r border-yellow-500/25
rounded rounded-t-none
flex flex-col
flex
flex-col rounded rounded-t-none border-b
border-l border-r
border-yellow-500/25 bg-yellow-500/20
p-5
`}
>
@ -136,7 +136,7 @@ const ExampleWaspApps = () => {
<SectionContainer className="space-y-16" id="examples">
<div className="grid grid-cols-12">
<div className="col-span-12 text-center">
<h2 className="text-xl lg:text-2xl text-neutral-700 mb-4">
<h2 className="mb-4 text-xl text-neutral-700 lg:text-2xl">
Show, don't tell.
</h2>
<p className="text-neutral-500">
@ -158,11 +158,11 @@ const ExampleWaspApps = () => {
<Link to="https://github.com/wasp-lang/wasp/tree/main/examples">
<span
className={`
text-neutral-500
underline decoration-2 decoration-yellow-500 font-medium
hover:text-neutral-400
transition ease-out duration-200
flex items-center
flex
items-center font-medium text-neutral-500 underline
decoration-yellow-500
decoration-2 transition duration-200
ease-out hover:text-neutral-400
`}
>
<span>See all examples</span>

View File

@ -7,75 +7,113 @@ import SectionContainer from './Layouts/SectionContainer'
const faqs = [
{
question: 'How is Wasp different from Next.js / Nuxt.js / Gatsby?',
answer: <p>
<strong>TL;DR</strong> - These are frontend-first frameworks, with some limited backend capabilities.
Wasp is a full-stack framework.
<br/><br/>
The main difference between Wasp and the solutions listed above is that Wasp is a trully full-stack
framework, meaning it brings both back-end and database next to front-end. You can think of it as
Ruby on Rails, but made for JS (React & Node.js) and full-stack.
<br/><br/>
Next.js, Gatsby and others started out as frontend frameworks for static sites. Although some of them
now offer an option to use serverless functions, you still have to bring your own database and you'll
also need some kind of a server/backend if you'll need to run more complex operations.
</p>
answer: (
<p>
<strong>TL;DR</strong> - These are frontend-first frameworks, with some
limited backend capabilities. Wasp is a full-stack framework.
<br />
<br />
The main difference between Wasp and the solutions listed above is that
Wasp is a trully full-stack framework, meaning it brings both back-end
and database next to front-end. You can think of it as Ruby on Rails,
but made for JS (React & Node.js) and full-stack.
<br />
<br />
Next.js, Gatsby and others started out as frontend frameworks for static
sites. Although some of them now offer an option to use serverless
functions, you still have to bring your own database and you'll also
need some kind of a server/backend if you'll need to run more complex
operations.
</p>
),
},
{
question: 'How is Wasp different from Ruby on Rails or Django?',
answer: <p>
<strong>TL;DR</strong> - while Ruby on Rails and Django are considered full-stack frameworks, they require extra work to support modern desktop experience that most web apps offer today.
Wasp is made specifically for that use case and supports it out-of-the-box, with a lot of extra niceties that make developer's life easier.
<br/><br/>
Ruby on Rails and Django both fall in the category of full-stack web frameworks - they allow you to write backend/server code and also generate html/css that gets sent to the client.
<br/><br/>
The main reason why they are often today not used as a standalone solution, but rather as an API server combined with frontend libraries such as React & Vue, is to add support for the client side manipulation of DOM.
Thats especially important for web applications with a lot of dynamic content (e.g. dashboards) where you want smooth experience of a desktop app.
Imagine expanding a post on Twitter or moving a Trello card and suddenly the whole site starts reloading - that's why you need React or Vue.
<br/><br/>
Wasp supports this behaviour out-of-the-box, along with all the best practices. One of the biggest time savers is automatic sharing of data models between the database, frontend
and the client - with RoR of Django youd typically have implement a custom API (e.g. rest or graphql), while with Wasp you can skip that step in entirety.
</p>
answer: (
<p>
<strong>TL;DR</strong> - while Ruby on Rails and Django are considered
full-stack frameworks, they require extra work to support modern
desktop experience that most web apps offer today. Wasp is made
specifically for that use case and supports it out-of-the-box, with a
lot of extra niceties that make developer's life easier.
<br />
<br />
Ruby on Rails and Django both fall in the category of full-stack web
frameworks - they allow you to write backend/server code and also
generate html/css that gets sent to the client.
<br />
<br />
The main reason why they are often today not used as a standalone
solution, but rather as an API server combined with frontend libraries
such as React & Vue, is to add support for the client side manipulation
of DOM. Thats especially important for web applications with a lot of
dynamic content (e.g. dashboards) where you want smooth experience of
a desktop app. Imagine expanding a post on Twitter or moving a Trello
card and suddenly the whole site starts reloading - that's why you need
React or Vue.
<br />
<br />
Wasp supports this behaviour out-of-the-box, along with all the best
practices. One of the biggest time savers is automatic sharing of data
models between the database, frontend and the client - with RoR of
Django youd typically have implement a custom API (e.g. rest or
graphql), while with Wasp you can skip that step in entirety.
</p>
),
},
{
question: 'How hard is it to learn Wasp?',
answer: <p>
We measured! <strong>It takes about 30 minutes to get going</strong>, and
most users find it pretty straight-forward.
Since the majority of your coding will still be done in the tools you're familiar with (currently
React & Node.js), it's really a marginal change to what you're used to.
<br/><br/>
The reason for that is that Wasp is a really simple configuration language, without any
loops or variables - you can think of it as a JSON that is easier to read and is a bit smarter.
<br/><br/>
Still, although simple (and we plan to keep it that way), it's a real language so you get all the
IDE goodies with it - syntax highlighting, auto-completion, live error reporting, ...
</p>
answer: (
<p>
We measured! <strong>It takes about 30 minutes to get going</strong>,
and most users find it pretty straight-forward. Since the majority of
your coding will still be done in the tools you're familiar with
(currently React & Node.js), it's really a marginal change to what
you're used to.
<br />
<br />
The reason for that is that Wasp is a really simple configuration
language, without any loops or variables - you can think of it as a JSON
that is easier to read and is a bit smarter.
<br />
<br />
Still, although simple (and we plan to keep it that way), it's a real
language so you get all the IDE goodies with it - syntax highlighting,
auto-completion, live error reporting, ...
</p>
),
},
{
question: 'Do you support only React & Node.js currently?',
answer:<p>
Yes, that is currently the supported stack. But, Wasp is being developed as a language/framework and
architecture-agnostic tool, so we plan to add support for more languages and frameworks in the future.
<br/><br/>
This is something we're pretty excited about and think could be potentially be a unique opportunity
due to the language approach we're taking with Wasp.
</p>
}
answer: (
<p>
Yes, that is currently the supported stack. But, Wasp is being developed
as a language/framework and architecture-agnostic tool, so we plan to
add support for more languages and frameworks in the future.
<br />
<br />
This is something we're pretty excited about and think could be
potentially be a unique opportunity due to the language approach we're
taking with Wasp.
</p>
),
},
]
const FaqItem = ({ keyP, faq }) => {
const [isExpanded, setIsExpanded] = useState(false)
return (
<div className='py-6'>
<dt key={keyP} className='text-base text-neutral-700'>
<div className="py-6">
<dt key={keyP} className="text-base text-neutral-700">
<button
className='text-left w-full flex items-center justify-between'
onClick={() => { setIsExpanded(!isExpanded) }}
className="flex w-full items-center justify-between text-left"
onClick={() => {
setIsExpanded(!isExpanded)
}}
>
<span>{faq.question}</span>
<div className='ml-6 text-yellow-500'>
<div className="ml-6 text-yellow-500">
{isExpanded ? (
<ChevronDown size={20} />
) : (
@ -84,11 +122,7 @@ const FaqItem = ({ keyP, faq }) => {
</div>
</button>
</dt>
{isExpanded && (
<dd className='mt-2 text-neutral-500'>
{faq.answer}
</dd>
)}
{isExpanded && <dd className="mt-2 text-neutral-500">{faq.answer}</dd>}
</div>
)
}
@ -96,29 +130,29 @@ const FaqItem = ({ keyP, faq }) => {
const Faq = () => {
return (
<SectionContainer>
<div className='grid grid-cols-12' id='faq'>
<div className='col-span-12 text-center'>
<h2 className='text-xl lg:text-2xl text-neutral-700 mb-4'>
<div className="grid grid-cols-12" id="faq">
<div className="col-span-12 text-center">
<h2 className="mb-4 text-xl text-neutral-700 lg:text-2xl">
Frequently asked questions
</h2>
<p className='text-neutral-500'>
<p className="text-neutral-500">
For anything not covered here, join&nbsp;
<a
href='https://discord.gg/rzdnErX'
className='underline decoration-2 decoration-yellow-500 font-medium'
<a
href="https://discord.gg/rzdnErX"
className="font-medium underline decoration-yellow-500 decoration-2"
>
our Discord
</a>!
</a>
!
</p>
</div>
</div>
<dl className='mt-6 max-w-3xl mx-auto divide-y divide-neutral-300'>
<dl className="mx-auto mt-6 max-w-3xl divide-y divide-neutral-300">
{faqs.map((faq, idx) => (
<FaqItem keyP={idx} key={idx} faq={faq} />
))}
</dl>
</SectionContainer>
)
}

View File

@ -1,7 +1,23 @@
import React from 'react'
import Link from '@docusaurus/Link'
import classNames from 'classnames'
import { Terminal, Layers, Coffee, Code, Unlock, Repeat, Send, Link2, Grid, ArrowRight, Globe, Settings, Mail, Type, Star } from 'react-feather'
import {
Terminal,
Layers,
Coffee,
Code,
Unlock,
Repeat,
Send,
Link2,
Grid,
ArrowRight,
Globe,
Settings,
Mail,
Type,
Star,
} from 'react-feather'
import SectionContainer from './Layouts/SectionContainer'
@ -9,33 +25,27 @@ import styles from '../pages/styles.module.css'
const Lang = () => (
<>
<span className='underline decoration-yellow-500 font-bold'>
language
</span>
<span className="font-bold underline decoration-yellow-500">language</span>
</>
)
const Feature = ({ Icon, title, description, url }) => (
<div className='mb-10 md:mb-0 space-y-4'>
<div className='flex items-center'>
<div className="mb-10 space-y-4 md:mb-0">
<div className="flex items-center">
<div
className={`
inline-flex h-8 w-8 rounded-md
items-center justify-center
text-yellow-500 bg-neutral-700
inline-flex h-8 w-8 items-center
justify-center rounded-md
bg-neutral-700 text-yellow-500
`}
>
<Icon size={20} />
</div>
<dt className='ml-4 text-neutral-700'>
{ title }
</dt>
<dt className="ml-4 text-neutral-700">{title}</dt>
</div>
<p className='text-neutral-700'>
{ description }
</p>
<TextLink url={url} label='Learn more' />
<p className="text-neutral-700">{description}</p>
<TextLink url={url} label="Learn more" />
</div>
)
@ -48,10 +58,10 @@ const TextLink = ({ url, label }) => (
text-neutral-500 hover:text-neutral-400
`}
>
<div className='group flex gap-1 items-center'>
<div className="group flex items-center gap-1">
<span>{label}</span>
<div className='transition-all group-hover:ml-0.5'>
<span className='text-yellow-600'>
<div className="transition-all group-hover:ml-0.5">
<span className="text-yellow-600">
<ArrowRight size={14} strokeWidth={2} />
</span>
</div>
@ -62,13 +72,12 @@ const TextLink = ({ url, label }) => (
const Features = () => {
return (
<SectionContainer className='space-y-16 lg:py-18'>
<dl className='grid grid-cols-1 lg:grid-cols-4 md:gap-16 lg:gap-x-8 xl:gap-x-16'>
<SectionContainer className="lg:py-18 space-y-16">
<dl className="grid grid-cols-1 md:gap-16 lg:grid-cols-4 lg:gap-x-8 xl:gap-x-16">
<Feature
Icon={Star}
title='Open Source'
url='https://github.com/wasp-lang/wasp'
title="Open Source"
url="https://github.com/wasp-lang/wasp"
description={`
This is the way. Wasp is fully open-source and you're welcome to contribute!
`}
@ -76,8 +85,8 @@ const Features = () => {
<Feature
Icon={Unlock}
title='Full-stack Auth'
url='/blog/2023/04/12/auth-ui'
title="Full-stack Auth"
url="/blog/2023/04/12/auth-ui"
description={`
Add login with social providers or email in a few lines of code with powerful UI helpers. No third party vendor lock-in.
`}
@ -85,8 +94,8 @@ const Features = () => {
<Feature
Icon={Link2}
title='RPC (Client <-> Server)'
url='/docs/data-model/operations/overview'
title="RPC (Client <-> Server)"
url="/docs/data-model/operations/overview"
description={`
Wasp provides a typesafe RPC layer that instantly brings your data models and server logic to the client.
`}
@ -94,18 +103,17 @@ const Features = () => {
<Feature
Icon={Send}
title='Simple Deployment'
url='/docs/advanced/deployment/overview'
title="Simple Deployment"
url="/docs/advanced/deployment/overview"
description={`
Deploy your app to any platform. Wasp offers CLI helpers for the most popular options.
`}
/>
<Feature
Icon={Settings}
title='Jobs'
url='/docs/advanced/jobs'
title="Jobs"
url="/docs/advanced/jobs"
description={`
Easily define, schedule and run specialized server tasks.
Persistent, retryable, delayable.
@ -114,8 +122,8 @@ const Features = () => {
<Feature
Icon={Mail}
title='Email Sending'
url='/docs/advanced/email'
title="Email Sending"
url="/docs/advanced/email"
description={`
All you need to do is connect an email provider and you can send emails!
`}
@ -123,8 +131,8 @@ const Features = () => {
<Feature
Icon={Type}
title='Full-stack Type Safety'
url='/docs/tutorial/queries#implementing-a-query'
title="Full-stack Type Safety"
url="/docs/tutorial/queries#implementing-a-query"
description={`
Full support for TypeScript with auto-generated types that span the whole stack.
`}
@ -132,8 +140,8 @@ const Features = () => {
<Feature
Icon={Grid}
title='And More!'
url='/docs'
title="And More!"
url="/docs"
description={`
Custom API routes, database seeding, optimistic updates, automatic cache invalidation on the client, ...
`}
@ -144,17 +152,16 @@ const Features = () => {
}
const FeaturesWithSkewedBorder = () => (
<div className='relative'>
<div className="relative">
<div className={classNames(styles.sectionSkewedContainer)}>
<div
className={classNames(
styles.sectionSkewed,
'border-b border-yellow-500/25 bg-neutral-100/50'
)}
>
</div>
></div>
</div>
<div className='relative'>
<div className="relative">
<Features />
</div>
</div>

View File

@ -1,5 +1,5 @@
// Copied from
// https://github.com/redwoodjs/redwood/blob/bd903c5755925ea7174775a2fdaba371b700c910/docs/src/components/FileExtSwitcher.tsx
// Copied from
// https://github.com/redwoodjs/redwood/blob/bd903c5755925ea7174775a2fdaba371b700c910/docs/src/components/FileExtSwitcher.tsx
import * as React from 'react'

View File

@ -57,7 +57,7 @@ const Logo = () => (
<Link to="/">
<img src="img/lp/wasp-logo.png" width={35} height={35} alt="Wasp Logo" />
</Link>
<span className="ml-3 font-semibold text-lg text-neutral-700">Wasp</span>
<span className="ml-3 text-lg font-semibold text-neutral-700">Wasp</span>
</div>
)
@ -71,8 +71,8 @@ const Segment = ({ title, links }) => (
<a
href={l.url}
className={`
text-sm text-neutral-500 hover:text-neutral-400
transition-colors
text-sm text-neutral-500 transition-colors
hover:text-neutral-400
`}
>
{l.text}
@ -111,17 +111,17 @@ const Footer = () => {
inputBgColor="bg-transparent"
/>
<span className="flex items-center mt-6">
<small className="text-neutral-500 text-xs">Backed by</small>
<span className="mt-6 flex items-center">
<small className="text-xs text-neutral-500">Backed by</small>
<img
className="w-24 ml-2"
className="ml-2 w-24"
src="img/lp/yc-logo-rounded.png"
alt="YC"
/>
</span>
</div>
</div>
<div className="pt-8 mt-8">
<div className="mt-8 pt-8">
<Logo />
<div className="flex justify-between">
<p className="mt-4 text-xs text-neutral-400">

View File

@ -5,9 +5,17 @@ import './prismCustomization'
import CodeHighlight from './CodeHighlight'
import { Terminal, ArrowUpRight, Play, BookOpen, Grid, Layout, Trello } from 'react-feather'
import {
Terminal,
ArrowUpRight,
Play,
BookOpen,
Grid,
Layout,
Trello,
} from 'react-feather'
// Terminal, BookOpen, Grid, Layout, Trello, FileText
// Terminal, BookOpen, Grid, Layout, Trello, FileText
import InstallCmd from './InstallCmd'
import SectionContainer from './Layouts/SectionContainer'
@ -15,9 +23,15 @@ import SectionContainer from './Layouts/SectionContainer'
const StartIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="currentColor" strokeWidth="2" strokeLinecap="round"
strokeLinejoin="round" opacity="0.5"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
opacity="0.5"
>
<polyline points="13 17 18 12 13 7"></polyline>
<polyline points="6 17 11 12 6 7"></polyline>
@ -25,16 +39,16 @@ const StartIcon = () => (
)
const ActionButtons = () => (
<div className='flex items-center gap-2'>
<Link to='/docs/quick-start'>
<div className="flex items-center gap-2">
<Link to="/docs/quick-start">
<button
className={`
inline-flex items-center space-x-2
px-3 py-2 rounded
bg-yellow-500 text-white text-sm leading-4
border border-yellow-500 hover:border-yellow-400
hover:bg-yellow-400
transition ease-out duration-200
rounded border border-yellow-500
bg-yellow-500 px-3 py-2 text-sm
leading-4 text-white transition
duration-200
ease-out hover:border-yellow-400 hover:bg-yellow-400
`}
>
<Terminal size={16} />
@ -42,16 +56,16 @@ const ActionButtons = () => (
</button>
</Link>
<Link to='/docs'>
<Link to="/docs">
<button
className={`
inline-flex items-center space-x-2
px-3 py-2 rounded
border border-neutral-500
rounded border border-neutral-500
px-3 py-2
text-sm leading-4
text-neutral-700
hover:text-neutral-400 hover:border-neutral-400
transition ease-out duration-200
transition duration-200
ease-out hover:border-neutral-400 hover:text-neutral-400
`}
>
<BookOpen size={16} />
@ -68,7 +82,7 @@ const PHBadge = () => (
rel="noreferrer"
>
<img
className='w-32 md:w-[180px]'
className="w-32 md:w-[180px]"
src="https://api.producthunt.com/widgets/embed-image/v1/top-post-badge.svg?post_id=277135&theme=light&period=daily"
alt="Wasp&#0045;lang&#0032;Alpha - Develop&#0032;web&#0032;apps&#0032;in&#0032;React&#0032;&#0038;&#0032;Node&#0046;js&#0032;with&#0032;no&#0032;boilerplate | Product Hunt"
/>
@ -76,8 +90,7 @@ const PHBadge = () => (
)
const Hero = () => {
const codeString =
`app todoApp {
const codeString = `app todoApp {
title: "ToDo App", // visible in the browser tab
auth: { // full-stack auth out-of-the-box
userEntity: User,
@ -100,96 +113,92 @@ entity Task {=psl ... psl=} // Your Prisma data model.
`
return (
<SectionContainer className='pb-5 pt-24'>
<div className='lg:grid lg:grid-cols-12 lg:gap-16'>
<div className='lg:col-span-6 space-y-12 z-10'>
<SectionContainer className="pb-5 pt-24">
<div className="lg:grid lg:grid-cols-12 lg:gap-16">
<div className="z-10 space-y-12 lg:col-span-6">
{/* Hero title and subtitle */}
<div>
<h1
className={`
text-4xl lg:text-5xl lg:leading-tight
font-extrabold text-neutral-700
text-4xl font-extrabold text-neutral-700
lg:text-5xl lg:leading-tight
`}
>
Develop full-stack web apps <span className='underline decoration-yellow-500'>faster</span>.
Develop full-stack web apps{' '}
<span className="underline decoration-yellow-500">faster</span>.
</h1>
<p className='mt-4 sm:mt-5 text-xl lg:text-xl text-neutral-500'>
Rails-like framework for React, Node.js and Prisma. Build your app in a day and deploy it with a single CLI command.
<p className="mt-4 text-xl text-neutral-500 sm:mt-5 lg:text-xl">
Rails-like framework for React, Node.js and Prisma. Build your app
in a day and deploy it with a single CLI command.
</p>
</div> {/* EOF Hero title and subtitle */}
</div>{' '}
{/* EOF Hero title and subtitle */}
<ActionButtons />
<div className="flex flex-col gap-4">
<small className="text-xs text-neutral-500">Works with</small>
<div className='flex flex-col gap-4'>
<small className='text-neutral-500 text-xs'>Works with</small>
<div className='flex'>
<div className="flex">
<img
className='h-8 md:h-10 pr-5 md:pr-10'
src='img/lp/react-logo-gray.svg'
alt='React'
className="h-8 pr-5 md:h-10 md:pr-10"
src="img/lp/react-logo-gray.svg"
alt="React"
/>
<img
className='h-8 md:h-10 pr-5 md:pr-10'
src='img/lp/nodejs-logo-gray.svg'
alt='Node'
className="h-8 pr-5 md:h-10 md:pr-10"
src="img/lp/nodejs-logo-gray.svg"
alt="Node"
/>
<img
className='h-8 md:h-10 pr-5 md:pr-10'
src='img/lp/prisma-logo-gray.svg'
alt='Prisma'
className="h-8 pr-5 md:h-10 md:pr-10"
src="img/lp/prisma-logo-gray.svg"
alt="Prisma"
/>
</div>
<span className='flex items-center mt-6'>
<small className='text-neutral-500 text-xs'>Backed by</small>
<span className="mt-6 flex items-center">
<small className="text-xs text-neutral-500">Backed by</small>
<img
className='w-24 ml-2'
src='img/lp/yc-logo-rounded.png'
alt='YC'
className="ml-2 w-24"
src="img/lp/yc-logo-rounded.png"
alt="YC"
/>
</span>
</div>
</div>
<div className='lg:col-span-6 lg:mt-0 mt-16'>
<div className='relative flex flex-col items-center justify-center'>
<div className="mt-16 lg:col-span-6 lg:mt-0">
<div className="relative flex flex-col items-center justify-center">
{/* Editor header bar */}
<div className='bg-yellow-500/10 flex h-6 w-full items-center justify-between rounded-t-md px-2'>
<Link to='https://github.com/wasp-lang/wasp/blob/main/examples/todo-typescript/main.wasp'>
<div className="flex h-6 w-full items-center justify-between rounded-t-md bg-yellow-500/10 px-2">
<Link to="https://github.com/wasp-lang/wasp/blob/main/examples/todo-typescript/main.wasp">
<span
className={`
text-sm text-neutral-500 flex items-center space-x-1 hover:text-neutral-400
transition ease-out duration-200
flex items-center space-x-1 text-sm text-neutral-500 transition
duration-200 ease-out hover:text-neutral-400
`}
>
<span>todoApp.wasp</span>
<ArrowUpRight size={14} />
<span className='text-neutral-400'>· Wasp config file</span>
<span className="text-neutral-400">· Wasp config file</span>
</span>
</Link>
<div className='flex space-x-2'>
<div className='bg-yellow-500 h-2 w-2 rounded-full' />
<div className='bg-yellow-500 h-2 w-2 rounded-full' />
<div className='bg-yellow-500 h-2 w-2 rounded-full' />
<div className="flex space-x-2">
<div className="h-2 w-2 rounded-full bg-yellow-500" />
<div className="h-2 w-2 rounded-full bg-yellow-500" />
<div className="h-2 w-2 rounded-full bg-yellow-500" />
</div>
</div>
{/* Editor body */}
<div className='w-full text-sm shadow-2xl rounded-b-md'>
<CodeHighlight
language='wasp'
source={codeString}
/>
</div> {/* EOF code block wrapper */}
</div> {/* EOF wrapper of header + code */}
</div> {/* EOF col-span-6 */}
<div className="w-full rounded-b-md text-sm shadow-2xl">
<CodeHighlight language="wasp" source={codeString} />
</div>{' '}
{/* EOF code block wrapper */}
</div>{' '}
{/* EOF wrapper of header + code */}
</div>{' '}
{/* EOF col-span-6 */}
</div>
{/* 1-min video */}
{/*
<div className='flex justify-center mt-20'>
@ -227,10 +236,8 @@ entity Task {=psl ... psl=} // Your Prisma data model.
/>
</div>
*/}
</SectionContainer>
)
}
export default Hero

View File

@ -9,7 +9,7 @@ const Feature = ({ title, description, url }) => (
<div className="lg:mt-5">
<dt>
<h4 className="mb-4">
<span className="text-neutral-700 bg-yellow-500/25 px-2 py-1 rounded">
<span className="rounded bg-yellow-500/25 px-2 py-1 text-neutral-700">
{title}
</span>
</h4>
@ -28,7 +28,7 @@ const TextLink = ({ url, label }) => (
text-neutral-600 hover:text-neutral-500
`}
>
<div className="group flex gap-1 items-center">
<div className="group flex items-center gap-1">
<span>{label}</span>
<div className="transition-all group-hover:ml-0.5">
<span className="text-yellow-600">
@ -45,7 +45,7 @@ const HowItWorks = () => {
<SectionContainer className="lg:pb-8">
<div className="grid grid-cols-12">
<div className="col-span-12 lg:col-span-4">
<h2 className="text-xl lg:text-2xl text-neutral-700 mb-4">
<h2 className="mb-4 text-xl text-neutral-700 lg:text-2xl">
How does it work? 🧐
</h2>
<p className="text-neutral-700">

View File

@ -2,22 +2,20 @@ import React from 'react'
import ReactTooltip from 'react-tooltip'
import { Clipboard } from 'react-feather'
const copyToClipboard = (text) => {
navigator.clipboard.writeText(text)
}
const InstallCmd = () => {
const code = 'curl -sSL https://get.wasp-lang.dev/installer.sh | sh'
return (
<div
className='cursor-pointer text-sm text-neutral-500 border border-yellow-500/75 rounded'
className="cursor-pointer rounded border border-yellow-500/75 text-sm text-neutral-500"
data-tip
data-event='click'
data-event-off='click'
data-delay-hide='2000'
data-event="click"
data-event-off="click"
data-delay-hide="2000"
>
<pre
className={`
@ -26,17 +24,17 @@ const InstallCmd = () => {
>
<strong>
<code>
<span className='select-none'>$ </span>
<span className="select-none">$ </span>
{code}
</code>
</strong>
<Clipboard size={18} />
</pre>
<ReactTooltip
place='top'
effect='float'
backgroundColor='#eab307'
textColor='white'
place="top"
effect="float"
backgroundColor="#eab307"
textColor="white"
afterShow={() => copyToClipboard(code)}
>
<b>Copied to clipboard!</b>

View File

@ -2,16 +2,16 @@ import React from 'react'
import classNames from 'classnames'
const SectionContainer = ({ children, className, id }) => (
<div
<div
className={classNames(
'container mx-auto px-6 py-16 sm:py-18',
'sm:py-18 container mx-auto px-6 py-16',
'md:py-24',
'lg:px-16 lg:py-24 xl:px-20',
className
)}
id={id}
>
{ children }
{children}
</div>
)

View File

@ -1,12 +1,12 @@
import React from "react";
import classNames from "classnames";
import { useHistory } from "@docusaurus/router";
import { ChevronRight, X } from "react-feather";
import React from 'react'
import classNames from 'classnames'
import { useHistory } from '@docusaurus/router'
import { ChevronRight, X } from 'react-feather'
import styles from "../../pages/styles.module.css";
import styles from '../../pages/styles.module.css'
const Announcement = () => {
let history = useHistory();
let history = useHistory()
const handleLink = () => {
window.open('https://magic-app-generator.wasp-lang.dev/')
@ -17,7 +17,7 @@ const Announcement = () => {
//window.open('https://twitter.com/WaspLang/status/1647979490180575234')
//window.open('https://www.producthunt.com/posts/free-saas-template-gpt-stripe-auth')
// window.open("https://hackathon.wasp-lang.dev");
};
}
return (
<div
@ -25,9 +25,9 @@ const Announcement = () => {
className={classNames(
styles.gradientBackground,
`
cursor-pointer
flex-row space-x-3
overflow-hidden
cursor-pointer flex-row
space-x-3
text-white
`
)}
@ -39,14 +39,14 @@ const Announcement = () => {
lg:container lg:divide-x lg:px-16 xl:px-20
`}
>
<span className='item-center flex gap-2 px-3'>
<span className="item-center flex gap-2 px-3">
<span>Try our GPT-Powered Web App Starter!</span>
</span>
<span className='hidden items-center space-x-2 px-3 lg:flex'>
<span className="hidden items-center space-x-2 px-3 lg:flex">
<span
className={`
bg-neutral-700 px-2.5 py-1 text-xs rounded-full cursor-pointer
cursor-pointer rounded-full bg-neutral-700 px-2.5 py-1 text-xs
hover:bg-neutral-600
`}
>
@ -55,7 +55,7 @@ const Announcement = () => {
</span>
</div>
</div>
);
};
)
}
export default Announcement;
export default Announcement

View File

@ -7,32 +7,34 @@ import Transition from '../../lib/Transition'
import { GitHubIcon, DiscordIcon, TwitterIcon } from './SocialIcons'
const Nav = () => {
const [open, setOpen] = useState(false)
const Logo = () => (
<div className='flex flex-shrink-0 items-center'>
<Link to='/'>
<div className="flex flex-shrink-0 items-center">
<Link to="/">
<img
src='img/lp/wasp-logo.png'
src="img/lp/wasp-logo.png"
width={35}
height={35}
alt='Wasp Logo'
alt="Wasp Logo"
/>
</Link>
<span className='ml-3 font-semibold text-lg text-neutral-700'>
Wasp <sup className='text-base text-yellow-500'>βeta</sup>
<span className="ml-3 text-lg font-semibold text-neutral-700">
Wasp <sup className="text-base text-yellow-500">βeta</sup>
</span>
</div>
)
const SocialIcon = ({ Icon, url }) => (
<a href={url} target='_blank' rel='noreferrer'
<a
href={url}
target="_blank"
rel="noreferrer"
className={`
text-neutral-700
hidden lg:flex hover:opacity-75 py-5
hover:text-yellow-500 hover:border-yellow-500
border-b-2 border-transparent
hidden
border-b-2 border-transparent py-5 text-neutral-700
hover:border-yellow-500 hover:text-yellow-500
hover:opacity-75 lg:flex
`}
>
<Icon />
@ -43,58 +45,62 @@ const Nav = () => {
<>
{/* NOTE(matija): If I put width to 100 or less, the badge gets cut off in half. */}
<iframe
src="https://ghbtns.com/github-btn.html?user=wasp-lang&repo=wasp&type=star&count=true"
src="https://ghbtns.com/github-btn.html?user=wasp-lang&repo=wasp&type=star&count=true"
frameBorder="0"
scrolling="0"
width="101px"
height="20px"
>
</iframe>
></iframe>
</>
)
// NOTE(matija): this one does not show the exact count, but e.g. 2k.
const WaspGhStarsShield = () => (
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/wasp-lang/wasp?style=social" />
<img
alt="GitHub Repo stars"
src="https://img.shields.io/github/stars/wasp-lang/wasp?style=social"
/>
)
const GitHubButton = () => (
<a href='https://github.com/wasp-lang/wasp' target='_blank' rel='noreferrer'
<a
href="https://github.com/wasp-lang/wasp"
target="_blank"
rel="noreferrer"
className={`
px-2.5 py-1 rounded
hover:bg-neutral-200
transition ease-out duration-200
hidden lg:flex items-center space-x-2 text-xs
group
group hidden items-center
space-x-2
rounded px-2.5 py-1
text-xs transition duration-200 ease-out hover:bg-neutral-200
lg:flex
`}
>
<div
className={`
flex h-3 w-3 items-center justify-center
group-hover:h-4 group-hover:w-4
text-neutral-700
text-neutral-700 group-hover:h-4
group-hover:w-4
group-hover:text-yellow-500
`}
>
<Star strokeWidth={2} />
</div>
<span className='truncate text-neutral-700'>Star us on GitHub</span>
<span className="truncate text-neutral-700">Star us on GitHub</span>
</a>
)
const HamburgerButton = ({ toggleFlyOut }) => (
<div
className='absolute inset-y-0 left-0 px-2 flex items-center lg:hidden'
className="absolute inset-y-0 left-0 flex items-center px-2 lg:hidden"
onClick={() => toggleFlyOut()}
>
<button
className={`
inline-flex items-center p-2
rounded-md hover:bg-gray-50
focus:ring-yellow-500 focus:outline-none focus:ring-2 focus:ring-inset
inline-flex items-center rounded-md
p-2 hover:bg-gray-50
focus:outline-none focus:ring-2 focus:ring-inset focus:ring-yellow-500
`}
>
<span className="sr-only">Open menu</span>
<svg
@ -114,103 +120,106 @@ const Nav = () => {
</svg>
</button>
</div>
)
return (
<>
<Announcement />
<div className='sticky top-0 z-50'>
<div className='bg-[#f5f4f0] absolute top-0 h-full w-full opacity-80'></div>
<nav className='border-b backdrop-blur-sm'>
<div className='
<div className="sticky top-0 z-50">
<div className="absolute top-0 h-full w-full bg-[#f5f4f0] opacity-80"></div>
<nav className="border-b backdrop-blur-sm">
<div
className="
relative mx-auto
flex justify-between
h-16
flex h-16
justify-between
lg:container lg:px-16 xl:px-20
'
"
>
<HamburgerButton toggleFlyOut={() => setOpen(true)} />
<div className='
<div
className="
flex flex-1
items-center justify-center
sm:items-stretch
lg:justify-between
'
"
>
<div className='flex items-center'> {/* Navbar left side */}
<div className="flex items-center">
{' '}
{/* Navbar left side */}
<Logo />
<div className='hidden pl-4 sm:ml-6 sm:space-x-4 lg:flex'> {/* Left items */}
<div className="hidden pl-4 sm:ml-6 sm:space-x-4 lg:flex">
{' '}
{/* Left items */}
{/* Docs */}
<Link to='/docs'>
<Link to="/docs">
<span
className={`
py-5 px-1
text-neutral-700
hover:text-yellow-500 hover:border-yellow-500
border-b-solid border-b-2 border-transparent
text-sm font-semibold
border-b-solid border-b-2
border-transparent
px-1 py-5
text-sm font-semibold text-neutral-700
hover:border-yellow-500 hover:text-yellow-500
`}
>
Docs
</span>
</Link>
{/* Blog */}
<Link to='/blog'>
<Link to="/blog">
<span
className={`
py-5 px-1
text-neutral-700
hover:text-yellow-500 hover:border-yellow-500
border-b-2 border-transparent
text-sm font-semibold
px-1
py-5 text-sm
font-semibold text-neutral-700
hover:border-yellow-500 hover:text-yellow-500
`}
>
Blog
</span>
</Link>
{/* FAQ */}
<Link to='#faq'>
<Link to="#faq">
<span
className={`
py-5 px-1
text-neutral-700
hover:text-yellow-500 hover:border-yellow-500
border-b-2 border-transparent
text-sm font-medium
px-1
py-5 text-sm
font-medium text-neutral-700
hover:border-yellow-500 hover:text-yellow-500
`}
>
FAQ
</span>
</Link>
{/* Join newsletter */}
<Link to='#signup'>
<Link to="#signup">
<span
className={`
py-5 px-1
border-b-2 border-transparent
px-1 py-5
text-sm font-medium
`}
>
<span
className={`
text-neutral-700
px-2 py-1 rounded bg-yellow-500/25 hover:bg-yellow-500/10
rounded
bg-yellow-500/25 px-2 py-1 text-neutral-700 hover:bg-yellow-500/10
`}
>
📬 Join the list
</span>
</span>
</Link>
</div> {/* EOF left items */}
</div> {/* EOF left side */}
<div className='flex items-center gap-2 space-x-2'> {/* Navbar right side */}
</div>{' '}
{/* EOF left items */}
</div>{' '}
{/* EOF left side */}
<div className="flex items-center gap-2 space-x-2">
{' '}
{/* Navbar right side */}
{/* GH stars badge */}
{/*
<span className='hidden lg:inline'>
@ -219,38 +228,34 @@ const Nav = () => {
</Link>
</span>
*/}
<GitHubButton />
<Link to='/docs/quick-start'>
<Link to="/docs/quick-start">
<button
className={`
hidden lg:block text-xs
px-2.5 py-1 rounded
bg-yellow-500 text-white
hover:bg-yellow-400
transition ease-out duration-200
hidden rounded bg-yellow-500
px-2.5 py-1 text-xs
text-white transition
duration-200
ease-out hover:bg-yellow-400 lg:block
`}
>
Get Started
</button>
</Link>
<SocialIcon
Icon={ GitHubIcon }
url='https://github.com/wasp-lang/wasp'
Icon={GitHubIcon}
url="https://github.com/wasp-lang/wasp"
/>
<SocialIcon
Icon={ DiscordIcon }
url='https://discord.gg/rzdnErX'
Icon={DiscordIcon}
url="https://discord.gg/rzdnErX"
/>
<SocialIcon
Icon={ TwitterIcon }
url='https://twitter.com/WaspLang'
Icon={TwitterIcon}
url="https://twitter.com/WaspLang"
/>
</div> {/* EOF right side */}
</div>{' '}
{/* EOF right side */}
</div>
</div>
@ -270,14 +275,14 @@ const Nav = () => {
fixed -inset-y-0 z-50 h-screen w-screen transform overflow-y-scroll bg-white p-4 md:p-8
`}
>
<div className='absolute right-4 top-4 items-center justify-between'>
<div className="absolute right-4 top-4 items-center justify-between">
<div className="-mr-2">
<button
type="button"
onClick={() => setOpen(false)}
className={`
text-neutral-700 inline-flex items-center justify-center rounded-md
bg-white p-2 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset
inline-flex items-center justify-center rounded-md bg-white
p-2 text-neutral-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset
`}
>
<span className="sr-only">Close menu</span>
@ -300,52 +305,53 @@ const Nav = () => {
</div>
</div>
<div className='mt-6 mb-12'>
<div className="mb-12 mt-6">
{/* Docs */}
<div className='space-y-1 pt-2 pb-4'>
<div className="space-y-1 pb-4 pt-2">
<Link to="/docs">
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
<span className="block pl-3 pr-4 text-base font-medium text-neutral-700">
Docs
</span>
</Link>
</div>
{/* Docs */}
<div className='space-y-1 pt-2 pb-4'>
<div className="space-y-1 pb-4 pt-2">
<Link to="/blog">
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
<span className="block pl-3 pr-4 text-base font-medium text-neutral-700">
Blog
</span>
</Link>
</div>
{/* FAQ */}
<div className='space-y-1 pt-2 pb-4'>
<div className="space-y-1 pb-4 pt-2">
<Link to="#faq" onClick={() => setOpen(false)}>
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
<span className="block pl-3 pr-4 text-base font-medium text-neutral-700">
FAQ
</span>
</Link>
</div>
{/* Join the list */}
<div className='space-y-1 pt-2 pb-4'>
<div className="space-y-1 pb-4 pt-2">
<Link to="#signup" onClick={() => setOpen(false)}>
<span
className={`
text-neutral-700 block pl-3 pr-4 text-base font-medium
px-2 py-1 rounded bg-yellow-500/25 hover:bg-yellow-500/10
`}>
block rounded bg-yellow-500/25 px-2 py-1 pl-3
pr-4 text-base font-medium text-neutral-700 hover:bg-yellow-500/10
`}
>
📬 Join the list
</span>
</Link>
</div>
{/* GitHub */}
<div className='space-y-1 pt-2 pb-4'>
<div className="space-y-1 pb-4 pt-2">
<Link to="https://github.com/wasp-lang/wasp">
<span className='flex items-center'>
<span className="text-neutral-700 pl-3 pr-4 text-base font-medium">
<span className="flex items-center">
<span className="pl-3 pr-4 text-base font-medium text-neutral-700">
GitHub
</span>
<WaspGhStarsExactCount />
@ -354,38 +360,29 @@ const Nav = () => {
</div>
{/* Discord */}
<div className='space-y-1 pt-2 pb-4'>
<div className="space-y-1 pb-4 pt-2">
<Link to="https://discord.gg/rzdnErX">
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
<span className="block pl-3 pr-4 text-base font-medium text-neutral-700">
👾 Discord
</span>
</Link>
</div>
{/* Twitter */}
<div className='space-y-1 pt-2 pb-4'>
<div className="space-y-1 pb-4 pt-2">
<Link to="https://twitter.com/WaspLang">
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
<span className="block pl-3 pr-4 text-base font-medium text-neutral-700">
🐦 Twitter
</span>
</Link>
</div>
</div>
</div>
</Transition>
</nav>
</div>
</>
)
}
export default Nav

View File

@ -5,41 +5,33 @@ import SectionContainer from './Layouts/SectionContainer'
const Newsletter = () => {
return (
<SectionContainer id='signup'>
<div className='grid grid-cols-12'>
<div className='col-span-12'>
<SectionContainer id="signup">
<div className="grid grid-cols-12">
<div className="col-span-12">
<div
className={`
px-6 py-6 bg-yellow-500/25 rounded-lg
rounded-lg bg-yellow-500/25 px-6 py-6
md:p-12 lg:p-16
xl:flex xl:items-center
`}
>
<div className='xl:w-0 xl:flex-1'>
<h2 className='text-2xl font-extrabold text-neutral-700'>
<div className="xl:w-0 xl:flex-1">
<h2 className="text-2xl font-extrabold text-neutral-700">
Stay up to date 📬
</h2>
<p className='mt-3 text-lg text-neutral-500 leading-6'>
<p className="mt-3 text-lg leading-6 text-neutral-500">
Be the first to know when we ship new features and updates!
</p>
</div>
<div className='mt-8 sm:w-full sm:max-w-md xl:mt-0 xl:ml-8'>
<SubscribeForm
inputBgColor='bg-[#f5f5f5]'
/>
<div className="mt-8 sm:w-full sm:max-w-md xl:ml-8 xl:mt-0">
<SubscribeForm inputBgColor="bg-[#f5f5f5]" />
</div>
</div>
</div>
</div>
</SectionContainer>
)
}
export default Newsletter

View File

@ -1,22 +1,22 @@
import * as React from "react";
import * as React from 'react'
const color = "#f59e0b";
const color = '#f59e0b'
export function Required() {
return (
<span
style={{
border: `2px solid ${color}`,
display: "inline-block",
padding: "0.2em 0.4em",
display: 'inline-block',
padding: '0.2em 0.4em',
color: color,
borderRadius: "0.4em",
fontSize: "0.8em",
lineHeight: "1",
fontWeight: "bold",
borderRadius: '0.4em',
fontSize: '0.8em',
lineHeight: '1',
fontWeight: 'bold',
}}
>
required
</span>
);
)
}

View File

@ -28,12 +28,12 @@ const GhIssueLink = ({ url, label }) => (
<Link to={url}>
<span
className={`
cursor-pointer text-xs
bg-neutral-600 text-white
px-2.5 py-1 rounded-full
cursor-pointer rounded-full
bg-neutral-600 px-2.5
py-1 text-xs text-white
`}
>
<div className="group inline-flex gap-1 items-center">
<div className="group inline-flex items-center gap-1">
<span>{label}</span>
<div className="transition-all group-hover:ml-0.5">
<span className="text-yellow-400">
@ -49,7 +49,7 @@ const Section = ({ features }) => (
<ul className="space-y-6">
{features.map((f) => (
<li className="grid grid-cols-12">
<div className="flex items-center col-start-3 col-span-8">
<div className="col-span-8 col-start-3 flex items-center">
<span>
<span className="text-neutral-600">{f[0]}</span>
{f[1] && (
@ -69,10 +69,10 @@ const Section = ({ features }) => (
)
const Roadmap = () => (
<SectionContainer className="space-y-16 lg:py-18" id="roadmap">
<SectionContainer className="lg:py-18 space-y-16" id="roadmap">
<div className="grid grid-cols-12">
<div className="col-span-12 text-center">
<h2 className="text-xl lg:text-2xl text-neutral-700 mb-4">
<h2 className="mb-4 text-xl text-neutral-700 lg:text-2xl">
🚧 Roadmap 🚧
</h2>
<p className="text-neutral-500">
@ -81,14 +81,14 @@ const Roadmap = () => (
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 md:gap-16">
<div className="grid grid-cols-1 md:gap-16 lg:grid-cols-2">
<div
className={`
bg-yellow-500/5 border border-yellow-500/25
p-5 rounded-lg
rounded-lg border border-yellow-500/25
bg-yellow-500/5 p-5
`}
>
<div className="font-bold text-center text-neutral-700 mb-6">
<div className="mb-6 text-center font-bold text-neutral-700">
Near-term improvements and features
</div>
<Section
@ -106,12 +106,12 @@ const Roadmap = () => (
<div
className={`
bg-yellow-500/20 border border-yellow-500/25
p-5 rounded-lg
mt-6 lg:mt-0
mt-6 rounded-lg border
border-yellow-500/25 bg-yellow-500/20
p-5 lg:mt-0
`}
>
<div className="font-bold text-center text-neutral-700 mb-6">
<div className="mb-6 text-center font-bold text-neutral-700">
Advanced Features
</div>
<Section

View File

@ -4,10 +4,12 @@ import SectionContainer from './Layouts/SectionContainer'
const Tag = ({ text, className }) => (
<span
className={classNames(`
text-sm border rounded-md px-2.5 py-0.5
className={classNames(
`
rounded-md border px-2.5 py-0.5 text-sm
`, className
`,
className
)}
>
{text}
@ -17,45 +19,37 @@ const Tag = ({ text, className }) => (
const ShowcaseItem = ({ url, thumb, title, description, children }) => (
<div>
<a href={url}>
<div className='group inline-block min-w-full'>
<div className='flex flex-col space-y-3 pb-8 md:pb-0'>
<div className="group inline-block min-w-full">
<div className="flex flex-col space-y-3 pb-8 md:pb-0">
<div
className={`
border-neutral-300 relative mb-4 h-60 w-full overflow-auto
rounded-lg border shadow-lg overflow-y-hidden
relative mb-4 h-60 w-full overflow-auto overflow-y-hidden
rounded-lg border border-neutral-300 shadow-lg
`}
>
<img
src={thumb}
className='object-cover'
/>
<img src={thumb} className="object-cover" />
</div>
<h3 className='text-neutral-700 text-xl'>{title}</h3>
<h3 className="text-xl text-neutral-700">{title}</h3>
<div className='flex space-x-2'>
{children}
</div>
<p className='text-neutral-500 text-base'>{description}</p>
<div className="flex space-x-2">{children}</div>
<p className="text-base text-neutral-500">{description}</p>
</div>
</div>
</a>
</div>
)
const ShowcaseGallery = () => {
return (
<SectionContainer className='space-y-16' id='showcases'>
<div className='grid grid-cols-12'>
<div className='col-span-12 text-center'>
<h2 className='text-xl lg:text-2xl text-neutral-700 mb-4'>
<SectionContainer className="space-y-16" id="showcases">
<div className="grid grid-cols-12">
<div className="col-span-12 text-center">
<h2 className="mb-4 text-xl text-neutral-700 lg:text-2xl">
🏆 Showcase Gallery 🏆
</h2>
<p className='text-neutral-500'>
<p className="text-neutral-500">
See what others are building with Wasp.
</p>
</div>
@ -68,37 +62,49 @@ const ShowcaseGallery = () => {
`}
>
<ShowcaseItem
url='/blog/2022/10/28/farnance-hackathon-winner'
thumb='img/lp/showcase/farnance-dashboard.png'
title='Farnance: SaaS marketplace for farmers'
url="/blog/2022/10/28/farnance-hackathon-winner"
thumb="img/lp/showcase/farnance-dashboard.png"
title="Farnance: SaaS marketplace for farmers"
description="See how Julian won HackLBS 2021 among 250 participants and why Wasp was instrumental for the team's victory."
>
<Tag text='hackathon' className='text-yellow-600 border-yellow-600 bg-yellow-50' />
<Tag text='material-ui' className='text-blue-500 border-blue-500 bg-slate-50' />
<Tag
text="hackathon"
className="border-yellow-600 bg-yellow-50 text-yellow-600"
/>
<Tag
text="material-ui"
className="border-blue-500 bg-slate-50 text-blue-500"
/>
</ShowcaseItem>
<ShowcaseItem
url='/blog/2022/11/26/michael-curry-usecase'
thumb='img/lp/showcase/grabbit-hero.png'
title='Grabbit: Easily manage dev environments'
description='See how Michael built and deployed an internal tool for managing dev resources at StudentBeans.'
url="/blog/2022/11/26/michael-curry-usecase"
thumb="img/lp/showcase/grabbit-hero.png"
title="Grabbit: Easily manage dev environments"
description="See how Michael built and deployed an internal tool for managing dev resources at StudentBeans."
>
<Tag text='internal-tools' className='text-green-600 border-green-600 bg-green-50' />
<Tag
text="internal-tools"
className="border-green-600 bg-green-50 text-green-600"
/>
</ShowcaseItem>
<ShowcaseItem
url='/blog/2022/11/26/erlis-amicus-usecase'
thumb='img/lp/showcase/amicus-landing.png'
title='Amicus: Task and workflow management for legal teams'
description='See how Erlis rolled out fully-fledged SaaS as a team of one in record time and got first paying customers.'
url="/blog/2022/11/26/erlis-amicus-usecase"
thumb="img/lp/showcase/amicus-landing.png"
title="Amicus: Task and workflow management for legal teams"
description="See how Erlis rolled out fully-fledged SaaS as a team of one in record time and got first paying customers."
>
<Tag text='startup' className='text-fuchsia-600 border-fuchsia-600 bg-fuchsia-50' />
<Tag text='material-ui' className='text-blue-500 border-blue-500 bg-slate-50' />
<Tag
text="startup"
className="border-fuchsia-600 bg-fuchsia-50 text-fuchsia-600"
/>
<Tag
text="material-ui"
className="border-blue-500 bg-slate-50 text-blue-500"
/>
</ShowcaseItem>
</div>
</SectionContainer>
)
}

View File

@ -1,7 +1,8 @@
import React, { useState } from 'react'
import classNames from 'classnames'
const createNewEmailSubscriberApiEndpoint = "https://app.loops.so/api/newsletter-form/clg0zndc9000ajn0f8a1bhgmu"
const createNewEmailSubscriberApiEndpoint =
'https://app.loops.so/api/newsletter-form/clg0zndc9000ajn0f8a1bhgmu'
const SubscribeForm = ({ className, inputBgColor }) => {
const [email, setEmail] = useState('')
@ -13,14 +14,13 @@ const SubscribeForm = ({ className, inputBgColor }) => {
try {
const res = await fetch(createNewEmailSubscriberApiEndpoint, {
method: "POST",
method: 'POST',
body: 'userGroup=&email=' + email,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
'Content-Type': 'application/x-www-form-urlencoded',
},
})
setMessage('Thank you for subscribing! 🙏')
} catch (error) {
setMessage('🛑 Oops! Something went wrong. Please try again.')
}
@ -28,9 +28,9 @@ const SubscribeForm = ({ className, inputBgColor }) => {
return (
<>
{ message ?
<p className='text-lg text-neutral-500'>{message}</p>
:
{message ? (
<p className="text-lg text-neutral-500">{message}</p>
) : (
<form
onSubmit={handleSubmit}
className={classNames('sm:flex', className)}
@ -40,36 +40,39 @@ const SubscribeForm = ({ className, inputBgColor }) => {
type="email"
name="email"
value={email}
onChange={e => setEmail(e.target.value)}
onChange={(e) => setEmail(e.target.value)}
id="email-address"
required autoComplete='email'
placeholder='you@awesomedev.com'
className={`
text-sm w-full
appearance-none
placeholder:text-neutral-400
border border-yellow-500
px-4 py-2 rounded-md
required
autoComplete="email"
placeholder="you@awesomedev.com"
className={
`
w-full appearance-none
rounded-md
border
border-yellow-500 px-4
py-2 text-sm placeholder:text-neutral-400
focus:outline-none focus:ring-2 focus:ring-yellow-400
` + ` ${inputBgColor}`}
` + ` ${inputBgColor}`
}
/>
<div className='rounded-md mt-3 sm:mt-0 sm:ml-3'>
<div className="mt-3 rounded-md sm:ml-3 sm:mt-0">
<button
type='submit'
type="submit"
className={`
w-full
text-sm border border-transparent rounded-md
bg-yellow-500 text-white
rounded-md border border-transparent bg-yellow-500
px-4 py-2
hover:bg-yellow-400
transition ease-out duration-200
text-sm text-white
transition
duration-200 ease-out hover:bg-yellow-400
`}
>
Subscribe
</button>
</div>
</form>
}
)}
</>
)
}

View File

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react'
import Link from '@docusaurus/Link'
import classNames from 'classnames'
import create from "@kodingdotninja/use-tailwind-breakpoint";
import create from '@kodingdotninja/use-tailwind-breakpoint'
import resolveConfig from 'tailwindcss/resolveConfig'
import tailwindConfig from '../../tailwind.config.js'
@ -18,28 +18,28 @@ const PH = 'ph'
const testimonials = [
{
text: "I spent the one weekend building with Wasp and it was amazing, a real pleasure. I normally develop in Vue.js, but in a weekend I had time to learn Wasp, React and finish a full-stack app (only missing styling). This would have been impossible before.\n\nSo glad to see Wasp in Beta! 🍻",
text: 'I spent the one weekend building with Wasp and it was amazing, a real pleasure. I normally develop in Vue.js, but in a weekend I had time to learn Wasp, React and finish a full-stack app (only missing styling). This would have been impossible before.\n\nSo glad to see Wasp in Beta! 🍻',
url: 'https://www.producthunt.com/posts/wasp-lang-beta?comment=2048094',
name: 'Joan Reyero',
handle: '@joanreyero',
img: 'img/lp/tm/reyero.jpg',
source: PH
source: PH,
},
{
text: "The simplification of the main.wasp file is 👍. And it feels like a very light weight version of a few larger frameworks.",
text: 'The simplification of the main.wasp file is 👍. And it feels like a very light weight version of a few larger frameworks.',
url: 'https://twitter.com/tskaggs/status/1602513968207101954',
name: 'Tim ✌️',
handle: '@tskaggs',
img: 'img/lp/tm/tskaggs.png',
source: TWITTER
source: TWITTER,
},
{
text: "@WaspLang has been in the back of my mind for months now. It left an impression, and Im really not easy to impress. Thats gotta mean something… #programming #webdevelopment #FullStack",
text: '@WaspLang has been in the back of my mind for months now. It left an impression, and Im really not easy to impress. Thats gotta mean something… #programming #webdevelopment #FullStack',
url: 'https://twitter.com/AttilaTheDev/status/1583530646047117317',
name: 'Attila Vago',
handle: '@AttilaTheDev',
img: 'img/lp/tm/attila.jpg',
source: TWITTER
source: TWITTER,
},
{
text: "If it weren't for Wasp, my app Amicus would probably have never been finished. I estimate it saved me 100+ hours from the start and I'm still amazed that I did all this work as a team-of-one. Being able to quickly change existing features and add the new ones is the biggest advantage of Wasp for me. Wasp is my favorite producthunt find!",
@ -47,7 +47,7 @@ const testimonials = [
name: 'Erlis Kllogjri',
handle: '@erlis_kllogjri',
img: 'img/lp/tm/erlis.jpg',
source: PH
source: PH,
},
{
text: "When I first learned about Wasp on HN I was really excited about its DSL approach. It was amazing how fast I could get things running with Wasp - I had the first version within an hour! The language is also fairly simple and straightforward and plays well with React & Node.js + it removes a ton of boilerplate.\n\nI've used Wasp for a lot of personal projects and for some small utility tools at various workplaces. I'm looking forward to what Wasp will bring and mean not only for rapid prototyping but also for removing the friction of getting something going in the first instance, it'll save a lot of people a lot of time!",
@ -55,83 +55,77 @@ const testimonials = [
name: 'Michael Curry',
handle: '@michael_curry1',
img: 'img/lp/tm/cursorial.jpg',
source: PH
source: PH,
},
{
text: "I used Wasp to win a hackathon this year - it was such a pleasure to use! Ive done plenty of hackathons before where Ive built small SaaS apps, and theres just so much time wasted setting up common utilities - stuff like user management, databases, routing, etc. Wasp handled all that for me and let me build out our web app in record time.\n\nAlso, deploying the wasp app was incredibly easy - I didnt have time to stand up full infrastructure in the 2 day hackathon and dont have an infra/devops background, but I had something running on Netlify within an hour. Other projects at the hackathon struggled to do this, and putting access in the hands of the judges certainly helped get us 1st place.\n\n@matijash @martin_sosic keep up the great work.",
text: 'I used Wasp to win a hackathon this year - it was such a pleasure to use! Ive done plenty of hackathons before where Ive built small SaaS apps, and theres just so much time wasted setting up common utilities - stuff like user management, databases, routing, etc. Wasp handled all that for me and let me build out our web app in record time.\n\nAlso, deploying the wasp app was incredibly easy - I didnt have time to stand up full infrastructure in the 2 day hackathon and dont have an infra/devops background, but I had something running on Netlify within an hour. Other projects at the hackathon struggled to do this, and putting access in the hands of the judges certainly helped get us 1st place.\n\n@matijash @martin_sosic keep up the great work.',
url: 'https://www.producthunt.com/posts/wasp-lang-beta?comment=2048039',
name: 'Julian LaNeve',
handle: '@julian_laneve',
img: 'img/lp/tm/jlaneve.jpg',
source: PH
source: PH,
},
{
text: "I was a bit reluctant to contribute at first due to the complexity project, but I was really encouraged when I saw the HF issue list, documentation for developers and the activity on Discord; all of the great feedback from the maintainers made my experience even better!",
text: 'I was a bit reluctant to contribute at first due to the complexity project, but I was really encouraged when I saw the HF issue list, documentation for developers and the activity on Discord; all of the great feedback from the maintainers made my experience even better!',
url: 'https://twitter.com/NeoLight1010/status/1595032349552566277',
name: 'NeoLight1010',
handle: '@NeoLight1010',
img: 'img/lp/tm/neolight.jpg',
source: TWITTER
source: TWITTER,
},
{
text: "Yes, @WaspLang is amazing and anyone who wants to bootstrap a full stack React app should try it! 😍",
text: 'Yes, @WaspLang is amazing and anyone who wants to bootstrap a full stack React app should try it! 😍',
url: 'https://twitter.com/panphora/status/1547980602334294020',
name: 'David Miranda',
handle: '@panphora',
img: 'img/lp/tm/panphora.jpg',
source: TWITTER
source: TWITTER,
},
{
text: "Got my first @WaspLang PR merged. A big shoutout to the maintainers for leaving such helpful comments on my Haskell code!",
text: 'Got my first @WaspLang PR merged. A big shoutout to the maintainers for leaving such helpful comments on my Haskell code!',
url: 'https://twitter.com/infiniteverma/status/1582027815570264065',
name: 'Anant Verma',
handle: '@infiniteverma',
img: 'img/lp/tm/infiniteverma.jpg',
source: TWITTER
source: TWITTER,
},
]
const TestimonialCard = ({ url, text, name, handle, img, source }) => (
<div className=''>
<div className="">
<Link to={url}>
<div className='bg-yellow-500/5 border border-yellow-500/25 rounded-md p-6 shadow-sm drop-shadow-sm'>
<div className="rounded-md border border-yellow-500/25 bg-yellow-500/5 p-6 shadow-sm drop-shadow-sm">
{/* Header */}
<div className='flex'>
<img
className='rounded-full'
src={img}
width={45}
height={45}
/>
<div className="flex">
<img className="rounded-full" src={img} width={45} height={45} />
{/* Header right side */}
<div className='pl-3 w-full flex justify-between'>
<div className=''> {/* Name and handle */}
<h6 className='font-semibold text-md text-neutral-700'>{name}</h6>
<p className='text-sm text-neutral-500'>{handle}</p>
<div className="flex w-full justify-between pl-3">
<div className="">
{' '}
{/* Name and handle */}
<h6 className="text-md font-semibold text-neutral-700">{name}</h6>
<p className="text-sm text-neutral-500">{handle}</p>
</div>
<div> {/* Twitter or PH icon */}
{source === TWITTER &&
<div>
{' '}
{/* Twitter or PH icon */}
{source === TWITTER && (
<img className="h-5 w-5" src="img/lp/twitter-logo.png" />
)}
{source === PH && (
<img
className='w-5 h-5'
src='img/lp/twitter-logo.png'
className="h-5 w-5 rounded-full"
src="img/lp/ph-logo.png"
/>
}
{source === PH &&
<img
className='w-5 h-5 rounded-full'
src='img/lp/ph-logo.png'
/>
}
)}
</div>
</div> {/* EOF Header right side */}
</div>{' '}
{/* EOF Header right side */}
</div>
{/* Text */}
<div className='mt-2 text-neutral-700 whitespace-pre-wrap'>
{text}
</div>
<div className="mt-2 whitespace-pre-wrap text-neutral-700">{text}</div>
</div>
</Link>
</div>
@ -144,7 +138,6 @@ const testimonialLayoutConfig = {
}
const Testimonials = () => {
const [loadMoreCount, setLoadMoreCount] = useState(0)
const isSm = useBreakpoint('sm')
@ -152,75 +145,79 @@ const Testimonials = () => {
const isLg = useBreakpoint('lg')
useEffect(() => {
window.dispatchEvent(new Event("resize"));
}, []);
window.dispatchEvent(new Event('resize'))
}, [])
let layoutConfig = testimonialLayoutConfig.mobile
if (isLg) { layoutConfig = testimonialLayoutConfig.lg }
else if (isMd) { layoutConfig = testimonialLayoutConfig.md }
if (isLg) {
layoutConfig = testimonialLayoutConfig.lg
} else if (isMd) {
layoutConfig = testimonialLayoutConfig.md
}
const numOfItemsToShow = Math.min(
layoutConfig.initialNumOfItemsToShow + loadMoreCount * layoutConfig.loadMoreStep,
layoutConfig.initialNumOfItemsToShow +
loadMoreCount * layoutConfig.loadMoreStep,
testimonials.length
)
// Data structure for rendering - assign each testimonial into the appropriate column.
const cols = Array.from({length: layoutConfig.colsNum}, e => [])
const cols = Array.from({ length: layoutConfig.colsNum }, (e) => [])
for (let itemIdx = 0; itemIdx < numOfItemsToShow; itemIdx++) {
const targetCol = itemIdx % layoutConfig.colsNum
cols[targetCol].push(testimonials[itemIdx])
}
return (
<SectionContainer className='space-y-16' id='testimonials'>
<div className='grid grid-cols-12'>
<div className='col-span-12 text-center'>
<h2 className='text-xl lg:text-2xl text-neutral-700 mb-4'>
<SectionContainer className="space-y-16" id="testimonials">
<div className="grid grid-cols-12">
<div className="col-span-12 text-center">
<h2 className="mb-4 text-xl text-neutral-700 lg:text-2xl">
You're in a good crowd
</h2>
<p className='text-neutral-500'>
<p className="text-neutral-500">
Here's what folks using Wasp say about it. Join&nbsp;
<a
href='https://discord.gg/rzdnErX'
className='underline decoration-2 decoration-yellow-500 font-medium'
<a
href="https://discord.gg/rzdnErX"
className="font-medium underline decoration-yellow-500 decoration-2"
>
our Discord
</a> for more!
</a>{' '}
for more!
</p>
</div>
</div>
<div className='flex space-x-4'>
<div className="flex space-x-4">
{cols.map((col, colIdx) => (
<div key={colIdx} className={`flex flex-col space-y-4 w-1/${layoutConfig.colsNum}`}>
<div
key={colIdx}
className={`flex flex-col space-y-4 w-1/${layoutConfig.colsNum}`}
>
{col.map((item, itemIdx) => (
<TestimonialCard
key={itemIdx}
{...item}
/>
<TestimonialCard key={itemIdx} {...item} />
))}
</div>
))}
</div>
{numOfItemsToShow < testimonials.length &&
<div className='flex justify-center'>
{numOfItemsToShow < testimonials.length && (
<div className="flex justify-center">
<button
className={`
inline-flex items-center space-x-2
px-3 py-2 rounded
bg-yellow-500 text-white text-sm leading-4
border border-yellow-500 hover:border-yellow-400
hover:bg-yellow-400
transition ease-out duration-200
rounded border border-yellow-500
bg-yellow-500 px-3 py-2 text-sm
leading-4 text-white transition
duration-200
ease-out hover:border-yellow-400 hover:bg-yellow-400
`}
onClick={() => setLoadMoreCount(loadMoreCount + 1)}
>
🐝 Load more
</button>
</div>
}
)}
</SectionContainer>
)
}

View File

@ -25,7 +25,6 @@ export function ShowForTs({ children }: Props) {
return jsTs === 'ts' && <MDXContent>{children}</MDXContent>
}
/**
* Only renders this block if user has selected JS in the codeblocks
* @Note leave a blank space after opening the tag e.g.

View File

@ -6,41 +6,37 @@ import SectionContainer from './Layouts/SectionContainer'
const VideoAndTutorial = () => {
return (
<SectionContainer id='demo'>
<SectionContainer id="demo">
{/* 1-min video - a hacky way to hide controls */}
<div className='flex justify-center md:mt-10'>
<div className='flex flex-col items-center w-full gap-6'>
<div className='w-full lg:w-2/3 xl:w-3/5 overflow-hidden rounded-md shadow-lg'>
<div className='relative w-[200%] -left-[50%] pb-[56.25%] pt-25px'>
<div className="flex justify-center md:mt-10">
<div className="flex w-full flex-col items-center gap-6">
<div className="w-full overflow-hidden rounded-md shadow-lg lg:w-2/3 xl:w-3/5">
<div className="pt-25px relative -left-[50%] w-[200%] pb-[56.25%]">
<iframe
src='https://www.youtube-nocookie.com/embed/YaaTJOhx68I?playlist=YaaTJOhx68I&autoplay=0&loop=1&controls=0&showinfo=1&modestbranding=0&rel=0&disablekb=0&mute=1'
title='Demo video showcasing Wasp'
className='absolute h-full w-full top-0 left-0 rounded-md'
frameborder='0'
allow='accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; allowfullscreen;'
src="https://www.youtube-nocookie.com/embed/YaaTJOhx68I?playlist=YaaTJOhx68I&autoplay=0&loop=1&controls=0&showinfo=1&modestbranding=0&rel=0&disablekb=0&mute=1"
title="Demo video showcasing Wasp"
className="absolute left-0 top-0 h-full w-full rounded-md"
frameborder="0"
allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; allowfullscreen;"
allowfullscreen
/>
</div>
</div>
<Link to='/docs/tutorial/create'>
<Link to="/docs/tutorial/create">
<div
className={`
text-neutral-500 text-md
text-md text-neutral-500
hover:text-neutral-400
`}
>
<span className='underline decoration-neutral-500'>Want to jump in and try it yourself? Take our tutorial!</span>
<span className="underline decoration-neutral-500">
Want to jump in and try it yourself? Take our tutorial!
</span>
</div>
</Link>
</div>
</div>
</SectionContainer>
)
}

View File

@ -1,6 +1,6 @@
import Prism from "prismjs";
import addWaspLangauge from "../prism/wasp";
import addPrismaLanguage from "../prism/prisma";
import Prism from 'prismjs'
import addWaspLangauge from '../prism/wasp'
import addPrismaLanguage from '../prism/prisma'
addPrismaLanguage(Prism);
addWaspLangauge(Prism);
addPrismaLanguage(Prism)
addWaspLangauge(Prism)

View File

@ -5,7 +5,7 @@
* work well for content-centric websites.
*/
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap");
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap');
@tailwind base;
@tailwind components;
@ -90,7 +90,7 @@
--sidebar-category-spacing: 2em;
}
:root[data-theme="dark"] {
:root[data-theme='dark'] {
--custom-background-color-diff: #2a2a2a;
/* Blog */
@ -106,11 +106,13 @@
/******** DOCS SIDEBAR **********/
/* remove background from sidebar items (except for active) */
.menu__link:not(.menu__link--active), .menu__list-item-collapsible {
.menu__link:not(.menu__link--active),
.menu__list-item-collapsible {
background: initial !important;
}
/* less opaque on hover/focus */
.menu__link:hover:not(.menu__link--active):not(.menu__link--sublist), .menu__link:focus:not(.menu__link--active):not(.menu__link--sublist) {
.menu__link:hover:not(.menu__link--active):not(.menu__link--sublist),
.menu__link:focus:not(.menu__link--active):not(.menu__link--sublist) {
opacity: 0.7;
}
@ -123,7 +125,9 @@
padding-left: 0;
}
.theme-doc-sidebar-item-category-level-1 > .menu__list-item-collapsible > .menu__link {
.theme-doc-sidebar-item-category-level-1
> .menu__list-item-collapsible
> .menu__link {
color: var(--sidebar-category-color);
font-weight: bold;
font-size: var(--ifm-h6-font-size);

View File

@ -3,11 +3,11 @@
* Inspired by Github syntax coloring
*/
code[class*="language-"],
pre[class*="language-"] {
code[class*='language-'],
pre[class*='language-'] {
color: #393a34;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
"Liberation Mono", "Courier New", monospace;
'Liberation Mono', 'Courier New', monospace;
direction: ltr;
text-align: left;
white-space: pre;
@ -26,26 +26,26 @@ pre[class*="language-"] {
hyphens: none;
}
pre > code[class*="language-"] {
pre > code[class*='language-'] {
font-size: 1em;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
pre[class*='language-']::-moz-selection,
pre[class*='language-'] ::-moz-selection,
code[class*='language-']::-moz-selection,
code[class*='language-'] ::-moz-selection {
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
pre[class*='language-']::selection,
pre[class*='language-'] ::selection,
code[class*='language-']::selection,
code[class*='language-'] ::selection {
background: #b3d4fc;
}
/* Code blocks */
pre[class*="language-"] {
pre[class*='language-'] {
/* padding: 1em; */
/* margin: 0.5em 0; */
overflow: auto;
@ -54,7 +54,7 @@ pre[class*="language-"] {
}
/* Inline code */
:not(pre) > code[class*="language-"] {
:not(pre) > code[class*='language-'] {
padding: 0.2em;
padding-top: 1px;
padding-bottom: 1px;

View File

@ -1,4 +1,3 @@
html {
font-family: Inter, sans-serif;
}
@ -34,7 +33,6 @@ body {
linear-gradient(90deg,#B71 2%,#fb1 0,#fb1 98%,#B71 0%)0 0 #fb1;
background-size: 40px 60px;
*/
}
div.twLandingPage {

View File

@ -21,43 +21,52 @@ import styles from './styles.module.css'
import './index.css'
import './preflight.css'
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
const Background = () => {
return (
<div className='absolute top-0 left-0 w-full h-full overflow-hidden pointer-events-none'>
<div className="pointer-events-none absolute left-0 top-0 h-full w-full overflow-hidden">
<span className={classNames(styles.leftLights, 'opacity-100')} />
</div>
);
};
)
}
const LightsTwo = () => (
<div className='absolute top-[1800px] lg:top-[1000px] left-0 w-full h-full overflow-hidden pointer-events-none'>
<div className="pointer-events-none absolute left-0 top-[1800px] h-full w-full overflow-hidden lg:top-[1000px]">
<span className={classNames(styles.lightsTwo, 'opacity-100')} />
</div>
);
)
const Index = () => {
const { siteConfig } = useDocusaurusContext();
const coverPhotoAbsoluteUrl = `${siteConfig.url}${waspCoverPhoto}`;
const { siteConfig } = useDocusaurusContext()
const coverPhotoAbsoluteUrl = `${siteConfig.url}${waspCoverPhoto}`
return (
<div className='twLandingPage'>
<div className="twLandingPage">
<Head>
{/* opengraph / facebook */}
<meta property='og:type' content='website' />
<meta property='og:url' content='https://wasp-lang.dev/' />
<meta property='og:description' content='Develop full-stack web apps without boilerplate.' />
<meta property='og:image' content={coverPhotoAbsoluteUrl} />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://wasp-lang.dev/" />
<meta
property="og:description"
content="Develop full-stack web apps without boilerplate."
/>
<meta property="og:image" content={coverPhotoAbsoluteUrl} />
{/* twitter */}
<meta property='twitter:card' content='summary_large_image' />
<meta property='twitter:url' content='https://wasp-lang.dev/' />
<meta property='twitter:title' content='Develop full-stack web apps without boilerplate.' />
<meta property='twitter:image' content={coverPhotoAbsoluteUrl} />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content="https://wasp-lang.dev/" />
<meta
property="twitter:title"
content="Develop full-stack web apps without boilerplate."
/>
<meta property="twitter:image" content={coverPhotoAbsoluteUrl} />
<script id="wasp-langdev-2392a8eb" src="https://letsask.ai/widget.js"></script>
<script
id="wasp-langdev-2392a8eb"
src="https://letsask.ai/widget.js"
></script>
</Head>
<Nav />
<div className='min-h-screen'>
<div className="min-h-screen">
<main>
<Background />
<div>
@ -78,7 +87,7 @@ const Index = () => {
</div>
<Footer />
</div>
);
};
)
}
export default Index;
export default Index

View File

@ -30,8 +30,27 @@ html {
-webkit-text-size-adjust: 100%; /* 2 */
-moz-tab-size: 4; /* 3 */
tab-size: 4; /* 3 */
font-family: theme('fontFamily.sans', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); /* 4 */
font-feature-settings: theme('fontFamily.sans[1].fontFeatureSettings', normal); /* 5 */
font-family: theme(
'fontFamily.sans',
ui-sans-serif,
system-ui,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
'Helvetica Neue',
Arial,
'Noto Sans',
sans-serif,
'Apple Color Emoji',
'Segoe UI Emoji',
'Segoe UI Symbol',
'Noto Color Emoji'
); /* 4 */
font-feature-settings: theme(
'fontFamily.sans[1].fontFeatureSettings',
normal
); /* 5 */
}
/*
@ -105,7 +124,17 @@ Add the correct font weight in Edge and Safari.
.twLandingPage kbd,
.twLandingPage samp,
.twLandingPage pre {
font-family: theme('fontFamily.mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace); /* 1 */
font-family: theme(
'fontFamily.mono',
ui-monospace,
SFMono-Regular,
Menlo,
Monaco,
Consolas,
'Liberation Mono',
'Courier New',
monospace
); /* 1 */
font-size: 1em; /* 2 */
}
@ -322,7 +351,7 @@ Set the default cursor for buttons.
*/
button,
[role="button"] {
[role='button'] {
cursor: pointer;
}

View File

@ -16,7 +16,7 @@
}
.leftLights::after {
content: "";
content: '';
position: absolute;
pointer-events: none;
width: 1223px;
@ -30,7 +30,7 @@
background: radial-gradient(
50% 50% at 50% 50%,
rgba(255, 214, 0, 0.2) 0%,
rgba(255, 214, 0, 0.2) 0%,
rgba(255, 168, 0, 0) 100%
);
will-change: filter;
@ -38,7 +38,7 @@
}
.lightsTwo::after {
content: "";
content: '';
position: absolute;
pointer-events: none;
width: 1223px;
@ -52,7 +52,7 @@
background: radial-gradient(
50% 50% at 50% 50%,
rgba(255, 214, 0, 0.2) 0%,
rgba(255, 214, 0, 0.2) 0%,
rgba(255, 168, 0, 0) 100%
);
will-change: filter;

View File

@ -1,26 +1,26 @@
// Taken from the Prisma docs
module.exports = (Prism) => {
Prism.languages.prisma = Prism.languages.extend("clike", {
Prism.languages.prisma = Prism.languages.extend('clike', {
keyword: /\b(?:datasource|enum|generator|model|type|view)\b/,
"type-class-name": /(\s+)[A-Z]\w+/, ///(\b)(\s+)[A-Z]\w+/
});
'type-class-name': /(\s+)[A-Z]\w+/, ///(\b)(\s+)[A-Z]\w+/
})
Prism.languages.javascript["class-name"][0].pattern =
/(\b(?:model|datasource|enum|generator|type)\s+)[\w.\\]+/;
Prism.languages.javascript['class-name'][0].pattern =
/(\b(?:model|datasource|enum|generator|type)\s+)[\w.\\]+/
Prism.languages.insertBefore("prisma", "function", {
Prism.languages.insertBefore('prisma', 'function', {
annotation: {
pattern: /(^|[^.])@+\w+/,
lookbehind: true,
alias: "punctuation",
alias: 'punctuation',
},
});
})
Prism.languages.insertBefore("prisma", "punctuation", {
"type-args": /\b(?:references|fields|onDelete|onUpdate):/,
});
Prism.languages.insertBefore('prisma', 'punctuation', {
'type-args': /\b(?:references|fields|onDelete|onUpdate):/,
})
Prism.languages.insertBefore("prisma", "type-class-name", {
"not-class": /\n(\s+)[A-Z]\w+/,
});
};
Prism.languages.insertBefore('prisma', 'type-class-name', {
'not-class': /\n(\s+)[A-Z]\w+/,
})
}

View File

@ -1,7 +1,7 @@
// Converted from the TextMate definition at https://github.com/wasp-lang/vscode-wasp/blob/main/syntaxes/wasp.tmLanguage.yaml
module.exports = (Prism) => {
Prism.languages.wasp = {
"prisma-closure": {
'prisma-closure': {
pattern: /{=psl[\s\S]*?psl=}/,
inside: {
prisma: {
@ -14,7 +14,7 @@ module.exports = (Prism) => {
pattern: /\/\/.*|\/\*[\s\S]*?\*\//,
greedy: true,
},
"json-closure": {
'json-closure': {
pattern: /{=json[\s\S]*?json=}/,
inside: {
punctuation: /[{}[\],]/,
@ -33,11 +33,11 @@ module.exports = (Prism) => {
boolean: /\b(?:false|true)\b/,
null: {
pattern: /\bnull\b/,
alias: "keyword",
alias: 'keyword',
},
},
},
"js-import": {
'js-import': {
pattern: /import.*",?/,
inside: Prism.languages.javascript,
},
@ -50,23 +50,24 @@ module.exports = (Prism) => {
enum: {
pattern:
/\b(EmailAndPassword|PostgreSQL|SQLite|Simple|PgBoss|SMTP|SendGrid|Mailgun)\b/,
alias: "constant",
alias: 'constant',
},
"dict-key": {
'dict-key': {
pattern: /[a-zA-Z]+(?=:)/,
alias: "plain",
alias: 'plain',
},
"declaration-type": {
pattern: /\b(action|apiNamespace|api|app|entity|job|page|query|route|crud)\b/,
alias: "keyword",
'declaration-type': {
pattern:
/\b(action|apiNamespace|api|app|entity|job|page|query|route|crud)\b/,
alias: 'keyword',
},
"class-name": {
'class-name': {
pattern: /[a-zA-Z][0-9a-zA-Z]*/,
alias: "variable",
alias: 'variable',
},
"http-method": {
'http-method': {
pattern: /\b(ALL|GET|POST|PUT|DELETE)\b/,
alias: "constant",
alias: 'constant',
},
array: {
pattern: /\[[\s\S]*?\]/,
@ -74,10 +75,10 @@ module.exports = (Prism) => {
punctuation: /[{}[\],]/,
value: {
pattern: /[^,\s\]]+/,
alias: "variable",
alias: 'variable',
},
},
},
punctuation: /[{}[\],]/,
};
};
}
}

View File

@ -1,5 +1,5 @@
// Copied from
// https://github.com/redwoodjs/redwood/blob/bd903c5755925ea7174775a2fdaba371b700c910/docs/src/remark/auto-import-tabs.js
// https://github.com/redwoodjs/redwood/blob/bd903c5755925ea7174775a2fdaba371b700c910/docs/src/remark/auto-import-tabs.js
const needImports = (tree) =>
tree.children.some(

View File

@ -1,7 +1,7 @@
import React from 'react';
import clsx from 'clsx';
import Layout from '@theme/Layout';
import BlogSidebar from '@theme/BlogSidebar';
import React from 'react'
import clsx from 'clsx'
import Layout from '@theme/Layout'
import BlogSidebar from '@theme/BlogSidebar'
/*
@ -22,7 +22,7 @@ import BlogSidebar from '@theme/BlogSidebar';
// NOTE(matija): this component is used both when listing all the posts (on /blog) and when rendering a
// specific blog post.
export default function BlogLayout(props) {
const {sidebar, toc, children, ...layoutProps} = props;
const { sidebar, toc, children, ...layoutProps } = props
// NOTE(matija): if false, then it is an individual blog post.
//
@ -34,7 +34,7 @@ export default function BlogLayout(props) {
<Layout {...layoutProps}>
<div
className={clsx({
'container margin-vert--lg': !isListOfBlogPosts
'margin-vert--lg container': !isListOfBlogPosts,
})}
>
<div className="row">
@ -44,12 +44,13 @@ export default function BlogLayout(props) {
'col--7': !isListOfBlogPosts,
})}
itemScope
itemType="http://schema.org/Blog">
itemType="http://schema.org/Blog"
>
{children}
</main>
{toc && <div className="col col--2">{toc}</div>}
</div>
</div>
</Layout>
);
)
}

View File

@ -1,5 +1,5 @@
import React from 'react';
import BlogPostItem from '@theme-original/BlogPostItem';
import React from 'react'
import BlogPostItem from '@theme-original/BlogPostItem'
import Link from '@docusaurus/Link'
import SubscribeForm from '../../components/SubscribeForm'
@ -9,41 +9,38 @@ export default function BlogPostItemWrapper(props) {
<>
<BlogPostItem {...props} />
<div className='grid grid-cols-1 xl:grid-cols-2 gap-6 mt-8'>
<JoinOurCommunityCard/>
<JoinNewsletterCard/>
<div className="mt-8 grid grid-cols-1 gap-6 xl:grid-cols-2">
<JoinOurCommunityCard />
<JoinNewsletterCard />
</div>
</>
);
)
}
// TODO(matija): unifiy this with the icons used in navbar.
//
//import { DiscordIcon } from '../../components/Nav/SocialIcons'
const DiscordIcon = () => (
<svg height='100%' fill='currentColor' viewBox='0 5 30.67 23.25'>
<svg height="100%" fill="currentColor" viewBox="0 5 30.67 23.25">
<title>Discord</title>
<path d='M26.0015 6.9529C24.0021 6.03845 21.8787 5.37198 19.6623 5C19.3833 5.48048 19.0733 6.13144 18.8563 6.64292C16.4989 6.30193 14.1585 6.30193 11.8336 6.64292C11.6166 6.13144 11.2911 5.48048 11.0276 5C8.79575 5.37198 6.67235 6.03845 4.6869 6.9529C0.672601 12.8736 -0.41235 18.6548 0.130124 24.3585C2.79599 26.2959 5.36889 27.4739 7.89682 28.2489C8.51679 27.4119 9.07477 26.5129 9.55525 25.5675C8.64079 25.2265 7.77283 24.808 6.93587 24.312C7.15286 24.1571 7.36986 23.9866 7.57135 23.8161C12.6241 26.1255 18.0969 26.1255 23.0876 23.8161C23.3046 23.9866 23.5061 24.1571 23.7231 24.312C22.8861 24.808 22.0182 25.2265 21.1037 25.5675C21.5842 26.5129 22.1422 27.4119 22.7621 28.2489C25.2885 27.4739 27.8769 26.2959 30.5288 24.3585C31.1952 17.7559 29.4733 12.0212 26.0015 6.9529ZM10.2527 20.8402C8.73376 20.8402 7.49382 19.4608 7.49382 17.7714C7.49382 16.082 8.70276 14.7025 10.2527 14.7025C11.7871 14.7025 13.0425 16.082 13.0115 17.7714C13.0115 19.4608 11.7871 20.8402 10.2527 20.8402ZM20.4373 20.8402C18.9183 20.8402 17.6768 19.4608 17.6768 17.7714C17.6768 16.082 18.8873 14.7025 20.4373 14.7025C21.9717 14.7025 23.2271 16.082 23.1961 17.7714C23.1961 19.4608 21.9872 20.8402 20.4373 20.8402Z'></path>
<path d="M26.0015 6.9529C24.0021 6.03845 21.8787 5.37198 19.6623 5C19.3833 5.48048 19.0733 6.13144 18.8563 6.64292C16.4989 6.30193 14.1585 6.30193 11.8336 6.64292C11.6166 6.13144 11.2911 5.48048 11.0276 5C8.79575 5.37198 6.67235 6.03845 4.6869 6.9529C0.672601 12.8736 -0.41235 18.6548 0.130124 24.3585C2.79599 26.2959 5.36889 27.4739 7.89682 28.2489C8.51679 27.4119 9.07477 26.5129 9.55525 25.5675C8.64079 25.2265 7.77283 24.808 6.93587 24.312C7.15286 24.1571 7.36986 23.9866 7.57135 23.8161C12.6241 26.1255 18.0969 26.1255 23.0876 23.8161C23.3046 23.9866 23.5061 24.1571 23.7231 24.312C22.8861 24.808 22.0182 25.2265 21.1037 25.5675C21.5842 26.5129 22.1422 27.4119 22.7621 28.2489C25.2885 27.4739 27.8769 26.2959 30.5288 24.3585C31.1952 17.7559 29.4733 12.0212 26.0015 6.9529ZM10.2527 20.8402C8.73376 20.8402 7.49382 19.4608 7.49382 17.7714C7.49382 16.082 8.70276 14.7025 10.2527 14.7025C11.7871 14.7025 13.0425 16.082 13.0115 17.7714C13.0115 19.4608 11.7871 20.8402 10.2527 20.8402ZM20.4373 20.8402C18.9183 20.8402 17.6768 19.4608 17.6768 17.7714C17.6768 16.082 18.8873 14.7025 20.4373 14.7025C21.9717 14.7025 23.2271 16.082 23.1961 17.7714C23.1961 19.4608 21.9872 20.8402 20.4373 20.8402Z"></path>
</svg>
)
const JoinOurCommunityCard = () => {
const JoinOurCommunityButton = () => (
<Link to='https://discord.gg/rzdnErX'>
<span className={`
<Link to="https://discord.gg/rzdnErX">
<span
className={`
cursor-pointer
`}
>
<div className='group inline-flex gap-1 items-center'>
<div className="group inline-flex items-center gap-1">
<span>Join our Discord 👾</span>
<div className='transition-all group-hover:ml-0.5'>
<span className='text-yellow-400'></span>
<div className="transition-all group-hover:ml-0.5">
<span className="text-yellow-400"></span>
</div>
</div>
</span>
</Link>
)
@ -51,29 +48,28 @@ const JoinOurCommunityCard = () => {
return (
<div
className={`
bg-yellow-500/5 border border-yellow-500/25
p-8 rounded-lg
flex flex-col items-start
space-y-3
space-y-3 rounded-lg
border border-yellow-500/25 bg-yellow-500/5
p-8
`}
>
<span
<span
className={`
h-20
border border-yellow-500/25
px-4 py-5 rounded-full
bg-white text-neutral-800
rounded-full border
border-yellow-500/25 bg-white px-4
py-5 text-neutral-800
`}
>
<DiscordIcon/>
<DiscordIcon />
</span>
<h3 className='font-semibold text-xl'>
Join our developer community
</h3>
<h3 className="text-xl font-semibold">Join our developer community</h3>
<p>
Wasp is 100% open source. Join our Discord to learn from others and get help whenever you need it!
Wasp is 100% open source. Join our Discord to learn from others and get
help whenever you need it!
</p>
<JoinOurCommunityButton />
@ -82,41 +78,32 @@ const JoinOurCommunityCard = () => {
}
const JoinNewsletterCard = () => {
return (
<div
className={`
bg-yellow-500/20 border border-yellow-500/25
p-8 rounded-lg
flex flex-col items-start
space-y-3
space-y-3 rounded-lg
border border-yellow-500/25 bg-yellow-500/20
p-8
`}
>
<span
<span
className={`
h-20
border border-yellow-500/25
px-5 py-5 rounded-full
bg-white text-neutral-800
text-4xl
rounded-full border
border-yellow-500/25 bg-white px-5
py-5 text-4xl
text-neutral-800
`}
>
📫
</span>
<h3 className='font-semibold text-xl'>
Subscribe to our newsletter
</h3>
<h3 className="text-xl font-semibold">Subscribe to our newsletter</h3>
<p>
Once per month - receive useful blog posts and Wasp news.
</p>
<SubscribeForm className='self-stretch'/>
<p>Once per month - receive useful blog posts and Wasp news.</p>
<SubscribeForm className="self-stretch" />
</div>
)
}

View File

@ -1,27 +1,28 @@
import React from 'react';
import React from 'react'
import Link from '@docusaurus/Link'
import {BlogPostProvider} from '@docusaurus/theme-common/internal';
import BlogPostItem from '@theme/BlogPostItem';
import { BlogPostProvider } from '@docusaurus/theme-common/internal'
import BlogPostItem from '@theme/BlogPostItem'
import { ArrowRight } from 'react-feather'
const getReadingTimeStatement = (readingTimeFloat) => Math.ceil(readingTimeFloat) + ' min read'
const getReadingTimeStatement = (readingTimeFloat) =>
Math.ceil(readingTimeFloat) + ' min read'
export default function BlogPostItems({
items,
component: BlogPostItemComponent = BlogPostItem,
}) {
// TODO(matija): what if there are no items (blog posts)?
const featuredItem = items[0]
const coverImgSrc = featuredItem.content.frontMatter.image || 'img/blog-default-img.png'
const coverImgSrc =
featuredItem.content.frontMatter.image || 'img/blog-default-img.png'
return (
<>
<section
className={`
pb-20 py-20 md:py-36
bg-yellow-500
bg-yellow-500 py-20 pb-20
md:py-36
`}
>
<div
@ -31,95 +32,100 @@ export default function BlogPostItems({
>
<article
className={`
lg:grid grid-cols-2 gap-5 md:px-20 lg:px-24
items-stretch
relative
relative grid-cols-2 items-stretch gap-5 md:px-20
lg:grid
lg:px-24
`}
>
{/* Content - left col */}
<div className='self-center lg:pr-16'>
<div className="self-center lg:pr-16">
<span
className={`
flex items-center justify-between
uppercase text-[11px] text-neutral-600
font-semibold tracking-wider
mb-6
mb-6 flex items-center
justify-between text-[11px] font-semibold
uppercase tracking-wider
text-neutral-600
`}
>
<span>By {featuredItem.content.metadata.authors[0].name}</span>
<div className='flex-1 bg-neutral-600/20 h-px mx-2'></div>
<span>{getReadingTimeStatement(featuredItem.content.metadata.readingTime)}</span>
<div className="mx-2 h-px flex-1 bg-neutral-600/20"></div>
<span>
{getReadingTimeStatement(
featuredItem.content.metadata.readingTime
)}
</span>
</span>
{/* Title */}
<h1 className='text-4xl leading-tight text-neutral-800'>
<h1 className="text-4xl leading-tight text-neutral-800">
{featuredItem.content.frontMatter.title}
</h1>
{/* Read more button */}
<div className='mt-24'>
<span className={`
bg-neutral-600 text-white
px-3 py-1.5 rounded-md
<div className="mt-24">
<span
className={`
rounded-md bg-neutral-600
px-3 py-1.5 text-white
`}
>
<div className='group inline-flex gap-1 items-center'>
<div className="group inline-flex items-center gap-1">
<span>Read more</span>
<span className='text-yellow-400'></span>
<span className="text-yellow-400"></span>
</div>
</span>
</div>
</div>
{/* Image - right col */}
<img
<img
src={coverImgSrc}
className={`
object-cover
rounded-2xl mb-6
hidden lg:flex
className={`
mb-6
hidden rounded-2xl
object-cover lg:flex
`}
/>
<Link to={featuredItem.content.metadata.permalink} className='opacity-0 absolute inset-0'/>
<Link
to={featuredItem.content.metadata.permalink}
className="absolute inset-0 opacity-0"
/>
</article>
</div>
</section>
<section className='container mx-auto px-4 sm:px-6 md:px-20 lg:px-28'>
<div className='grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-5 mb-8 md:-mt-12'>
<section className="container mx-auto px-4 sm:px-6 md:px-20 lg:px-28">
<div className="mb-8 grid grid-cols-1 gap-5 md:-mt-12 md:grid-cols-2 xl:grid-cols-3">
{items.slice(1).map((item) => {
const BlogPostContent = item.content
const coverImgSrc = item.content.frontMatter.image || 'img/blog-default-img.png'
const coverImgSrc =
item.content.frontMatter.image || 'img/blog-default-img.png'
return (
<article
key={item.content.metadata.permalink}
className={`
relative
flex
flex-col
rounded-2xl
bg-[--custom-blog-card-background-color]
transition-all
shadow-sm shadow-yellow-500/25
hover:shadow-lg hover:shadow-yellow-500/25
border border-neutral-200/20
flex flex-col
p-8
bg-[--custom-blog-card-background-color] p-8
shadow-sm shadow-yellow-500/25
transition-all hover:shadow-lg
hover:shadow-yellow-500/25
`}
>
{/* Image */}
<img
<img
src={coverImgSrc}
className={`
object-cover
rounded-xl mb-6
md:max-w-none h-64 md:-mx-6 md:-mt-6
className={`
mb-6
h-64 rounded-xl
object-cover md:-mx-6 md:-mt-6 md:max-w-none
`}
/>
@ -127,23 +133,32 @@ export default function BlogPostItems({
<span
className={`
flex items-center
uppercase text-[11px] text-[--custom-blog-card-timestamp-color]
font-semibold tracking-wider
text-[11px] font-semibold uppercase
tracking-wider text-[--custom-blog-card-timestamp-color]
`}
>
<span className='truncate'>By {item.content.metadata.authors[0].name}</span>
<div className='flex-1 bg-gray-200 h-px mx-2'></div>
<span>{getReadingTimeStatement(item.content.metadata.readingTime)}</span>
<span className="truncate">
By {item.content.metadata.authors[0].name}
</span>
<div className="mx-2 h-px flex-1 bg-gray-200"></div>
<span>
{getReadingTimeStatement(item.content.metadata.readingTime)}
</span>
</span>
{/* Title */}
<h1 className='text-xl h-28 my-4'>
<h1 className="my-4 h-28 text-xl">
{item.content.frontMatter.title}
</h1>
<p className='text-yellow-600 font-semibold mt-0 mb-0'>Read more </p>
<p className="mb-0 mt-0 font-semibold text-yellow-600">
Read more
</p>
<Link to={item.content.metadata.permalink} className='opacity-0 absolute inset-0'/>
<Link
to={item.content.metadata.permalink}
className="absolute inset-0 opacity-0"
/>
</article>
)
@ -162,5 +177,5 @@ export default function BlogPostItems({
</div>
</section>
</>
);
)
}

View File

@ -1,24 +1,24 @@
// This file gets auto-generated when you "eject" to add custom languages to Docosaurus
// We use it to add support for Prisma and Wasp syntax highlighting
import siteConfig from "@generated/docusaurus.config";
import siteConfig from '@generated/docusaurus.config'
export default function prismIncludeLanguages(PrismObject) {
const {
themeConfig: { prism },
} = siteConfig;
const { additionalLanguages } = prism;
} = siteConfig
const { additionalLanguages } = prism
// Prism components work on the Prism instance on the window, while prism-
// react-renderer uses its own Prism instance. We temporarily mount the
// instance onto window, import components to enhance it, then remove it to
// avoid polluting global namespace.
// You can mutate PrismObject: registering plugins, deleting languages... As
// long as you don't re-assign it
globalThis.Prism = PrismObject;
globalThis.Prism = PrismObject
additionalLanguages.forEach((lang) => {
// eslint-disable-next-line global-require, import/no-dynamic-require
require(`prismjs/components/prism-${lang}`);
});
require(`prismjs/components/prism-${lang}`)
})
require("./prism-prisma");
require("./prism-wasp");
delete globalThis.Prism;
require('./prism-prisma')
require('./prism-wasp')
delete globalThis.Prism
}

View File

@ -1 +1 @@
require("../prism/prisma")(Prism);
require('../prism/prisma')(Prism)

View File

@ -1 +1 @@
require("../prism/wasp")(Prism);
require('../prism/wasp')(Prism)

View File

@ -1,6 +1,6 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
content: ['./src/**/*.{js,jsx,ts,tsx}'],
important: true,
corePlugins: {
preflight: false,
@ -8,9 +8,9 @@ module.exports = {
theme: {
extend: {
fontFamily: {
sans: ['Inter']
}
sans: ['Inter'],
},
},
},
plugins: [],
};
}