Merge branch 'release'

This commit is contained in:
vincanger 2023-04-18 16:38:54 +02:00
commit 3065999359
26 changed files with 425 additions and 80 deletions

View File

@ -99,7 +99,6 @@ app MyApp {
email: "hello@itsme.com"
},
emailVerification: {
allowUnverifiedLogin: false,
getEmailContentFn: import { getVerificationEmailContent } from "@server/auth/email.js",
clientRoute: EmailVerificationRoute,
},
@ -107,6 +106,7 @@ app MyApp {
getEmailContentFn: import { getPasswordResetEmailContent } from "@server/auth/email.js",
clientRoute: PasswordResetRoute
},
allowUnverifiedLogin: false,
},
}
}

View File

@ -34,6 +34,7 @@ app todoApp {
getEmailContentFn: import { getPasswordResetEmailContent } from "@server/auth/email.js",
clientRoute: PasswordResetRoute
},
allowUnverifiedLogin: false,
},
},
onAuthFailedRedirectTo: "/login",

View File

@ -1,7 +1,7 @@
---
title: 'Wasp Auth UI: The simplest way to a full-stack auth!'
title: 'Wasp Auth UI: The first full-stack auth with self-updating forms!'
authors: [matijasos]
image: /img/auth-ui/auth-ui-demo.png
image: /img/auth-ui/auth-customize-code.png
tags: [webdev, wasp, startups, github]
---
@ -10,7 +10,8 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
import InBlogCta from './components/InBlogCta';
import WaspIntro from './_wasp-intro.md';
import ImgWithCaption from './components/ImgWithCaption'
import ImgWithCaption from './components/ImgWithCaption';
import DiscordLink from './components/DiscordLink';
One of the main benefits of Wasp is having deep understanding of your entire full-stack app - e.g. what routes you have, what data models you defined, but also what methods you use for authentication. And that enables us to do some pretty cool stuff for you!
@ -23,6 +24,8 @@ One of the main benefits of Wasp is having deep understanding of your entire ful
Once you've listed auth methods you want to use in your `.wasp` config file, you're done - from that Wasp generates a full authentication form that you simply import as a React component. **And the best part is that is updates dynamically as you add/remove auth providers!**
You can [see the docs and give it a try here](/docs/guides/auth-ui).
<!--truncate-->
## Auto-updating magic 🔮
@ -60,4 +63,4 @@ Although it looks nice, all of this wouldn't be really useful if you couldn't cu
And that's it! You can see the whole list of tokens you can customize [here](https://github.com/wasp-lang/wasp/blob/main/waspc/data/Generator/templates/react-app/src/stitches.config.js). More are coming in the future!
Wasp out 🐝 🎤- give it a try and let us know how you liked it in [our Discord](https://discord.gg/rzdnErX)!
Wasp out 🐝 🎤- [give it a try](/docs/guides/auth-ui) and let us know how you liked it in our <DiscordLink />!

View File

@ -0,0 +1,131 @@
---
title: 'Wasp steps up its database game with Fully Managed Dev DB & DB Seeding'
authors: [martinsos]
image: /img/db-start-and-seed/wasp-db-improvements.png
tags: [database, wasp, webdev, prisma]
---
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import InBlogCta from './components/InBlogCta';
import WaspIntro from './_wasp-intro.md';
import ImgWithCaption from './components/ImgWithCaption';
import DiscordLink from './components/DiscordLink';
As a full-stack framework, Wasp doesnt care “just” about frontend and backend, but it also covers the database!
It does this by allowing you to define Prisma data models in a Wasp file, connecting them to the relevant Wasp Operations, warning you if you need to do database migrations, deploying the database for you (if you choose so), … .
Since Wasp knows so much about your database, that puts us in a good position to keep finding ways to improve the developer experience regarding dealing with the database. For Wasp v0.10, we focused on:
1. Wasp running the dev database for you with no config needed → **Fully Managed Dev Database** 🚀
2. Wasp helping you to initialize the database with some data → **Db Seeding** 🌱
<ImgWithCaption
caption="Wasp now has `wasp start db` and `wasp db seed`!"
alt="strong wasp database"
source="img/db-start-and-seed/wasp-db-improvements.png"
/>
<!--truncate-->
## Fully Managed Dev Database 🚀
You might have asked yourself:
> If Wasp already knows so much about my database, why do I need to bother running it on my own!?
>
Ok, when you start a new Wasp project it is easy because you are using an SQLite database, but once you switch to Postgres, it falls onto you to take care of it: run it, provide its URL to Wasp via env var, handle multiple databases if you have multiple Wasp apps, … .
This can get tedious quickly, especially if you are visiting your Wasp project that you havent worked on for a bit and need to figure out again how to run the db, or you need to check out somebody elses Wasp project and dont have it all set up yet. It is something most of us are used to, especially with other frameworks, but still, we can do better at Wasp!
This is where `wasp start db` comes in!
<ImgWithCaption
caption="wasp start db in action, running a posgtres dev db for you"
alt="wasp start db running in terminal"
source="img/db-start-and-seed/wasp-start-db-terminal.png"
/>
Now, all you need to do to run the development database, is run `wasp start db`, and Wasp will run it for you and will know how to connect to it during development.
No env var setting, no remembering how to run the db. The only requirement is that you have `Docker` installed on your machine. Data from your database will be persisted on the disk between the runs, and each Wasp app will have its own database assigned.
Btw, you can still use a custom database that you ran on your own if you want, the same way it was done before in Wasp: by setting env var `DATABASE_URL`.
## Database seeding 🌱
**Database seeding** is a term for populating the database with some initial data.
Seeding is most commonly used for two following scenarios:
1. To put the development database into a state convenient for testing / playing with it.
2. To initialize the dev/staging/prod database with some essential data needed for it to be useful, for example, default currencies in a Currency table.
Wasp so far had no direct support for seeding, so you had to either come up with your own solution (e.g. script that connects to the db and executes some queries), or massage data manually via Prisma Studio (`wasp db studio`).
There is one big drawback to both of the approaches I mentioned above though: there is no easy way to reuse logic that you have already implemented in your Wasp app, especially Actions (e.g. `createTask`)! This is pretty bad, as it makes your seeding logic brittle.
This is where `wasp db seed` comes in! Now, Wasp allows you to write a JS/TS function, import any server logic (including Actions) into it as you wish, and then seed the database with it.
<ImgWithCaption
caption="wasp db seed in action, initializing the db with dev data"
alt="wasp db seed running in terminal"
source="img/db-start-and-seed/wasp-db-seed-terminal.png"
/>
Registering seed functions in Wasp is easy:
```jsx
app MyApp {
// ...
db: {
// ...
seeds: [
import { devSeedSimple } from "@server/dbSeeds.js",
import { prodSeed } from "@server/dbSeeds.js"
]
}
}
```
Example of a seed function from above, `devSeedSimple`:
```jsx
import { createTask } from './actions.js'
export const devSeedSimple = async (prismaClient) => {
const user = await createUser(prismaClient, {
username: "RiuTheDog",
password: "bark1234"
})
await createTask(
{ description: "Chase the cat" },
{ user, entities: { Task: prismaClient.task } }
)
}
async function createUser (prismaClient, data) {
const { password, ...newUser } = await prismaClient.user.create({ data })
return newUser
}
```
Finally, to run these seeds, you can either do:
- `wasp db seed`: If you have just one seed function, it will run it. If you have multiple, it will interactively ask you to choose one to run.
- `wasp db seed <seed-name>`: It will run the seed function with the specified name, where the name is the identifier you used in its `import` expression in the `app.db.seeds` list. Example: `wasp db seed devSeedSimple`.
We also added `wasp db reset` command (calls `prisma db reset` in the background) that cleans up the database for you (removes all data and tables and re-applies migrations), which is great to use in combination with `wasp db seed`, as a precursor.
## Plans for the future 🔮
- allow customization of managed dev database (Postgres plugins, custom Dockerfile, …)
- have Wasp run the managed dev database automatically whenever it needs it (instead of you having to run `wasp start db` manually)
- dynamically find a free port for managed dev database (right now it requires port 5432)
- provide utility functions to make writing seeding functions easier (e.g. functions for creating new users)
- right now seeding functions are defined as part of a Wasp server code → it might be interesting to separate them in a standalone “project” in the future, while still keeping their easy access to the server logic.
- do you have any ideas/suggestions? Let us know in our <DiscordLink />!

View File

@ -0,0 +1,48 @@
---
title: 'How I Built CoverLetterGPT - SaaS app with the PERN stack, GPT, Stripe, & Chakra UI'
authors: [vinny]
tags: [wasp, ai, gpt, fullstack, PERN, stripe, chakra, saas]
---
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import InBlogCta from './components/InBlogCta';
import WaspIntro from './_wasp-intro.md';
import ImgWithCaption from './components/ImgWithCaption'
<br/>
<div style={{ textAlign: "center", width: "100%", height: "400px", display: "inline-block" }}>
<iframe height="100%" width ="100%" src="https://www.youtube.com/embed/D1l0iwGUed0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="true"></iframe>
</div>
<!--truncate-->
---
Like many other software developers, I enjoy trying out new technologies even if it's just to get a feel for what they can do.
So when I first learned about the [OpenAI API](https://platform.openai.com/docs/api-reference), I knew I wanted to give it a try. I had already wanted to create a SaaS app that could help manage the process of applying to numerous jobs, and the prospect of adding GPT into the mix made it even more interesting. So with API access and a bit of free time, I decided to give it a shot.
I threw together a simple version of the app in about 3-4 days and [CoverLetterGPT](https://coverlettergpt.xyz) was born, a SaaS app that uses GPT-3.5-turbo to generate, revise, and manage cover letters for you based on your skills and the specific job descriptions.
Even though I did think it had potential as a SaaS app, I was approaching it mostly as a way to learn how to build one for the first time. And after seeing so many people "building in public" and sharing their progress, I thought it would be fun to try it out myself.
<div style={{ marginBottom: "1rem" }}>
<a href="https://twitter.com/hot_town/status/1633873684573323265?s=20">
<img src={useBaseUrl('img/coverlettergpt.png')} alt="Hey peeps. Check out http://coverlettergpt.xyz. You can try it out now and create your own cover letters for free (no Payment/API key). I'm working on A LOT more features. Stay Tuned!"/>
</a>
</div>
So I started sharing my progress on Twitter, Reddit, and Indie Hackers. I made my first post about it on March 9th, and because I was just experimenting and trying my hand at a SaaS app for the first time, I also [open-sourced the app](https://github.com/vincanger/coverlettergpt) to share the code and what I was learning with others. This led to a lot of interest and great feedback, and I ended up getting featured in the [indiehackers newsletter](https://www.indiehackers.com/post/whats-new-don-t-build-things-no-one-wants-833ee752ba?utm_source=indie-hackers-emails&utm_campaign=ih-newsletter&utm_medium=email), which led to even more interest.
Within the first month, I got over 1,000 sign-ups along with my first paying customers. Pretty surprising, to say the least!
So to continue in the spirit of curiosity, learning, and just "wingin' it," I decided to make a code walkthrough video that explains how I built the app, the tools I used to build it, and a little bit about how I marketed the app without spending any money.
As an extra bonus, I also give a quick introduction to the [free SaaS template](https://github.com/wasp-lang/SaaS-Template-GPT) I created for building your own SaaS app, with or without GPT, on the PERN stack (PostgreSQL/Prisma, Express, React, NodeJS).
My hope is that others will learn something from my experience, and that it could inspire them to try out new technologies and build that app idea they've had in mind (and if they do, they should make sure to share it with me on Twitter [@hot_town](https://twitter.com/hot_town) -- I'd love to see it!)
*Want to stay in the loop? → [Join our newsletter!](https://wasp-lang.dev/#signup)*

View File

@ -61,12 +61,12 @@ app myApp {
emailVerification: {
clientRoute: EmailVerificationRoute,
getEmailContentFn: import { getVerificationEmailContent } from "@server/auth/email.js",
allowUnverifiedLogin: false,
},
passwordReset: {
clientRoute: PasswordResetRoute,
getEmailContentFn: import { getPasswordResetEmailContent } from "@server/auth/email.js",
},
allowUnverifiedLogin: false,
},
},
onAuthFailedRedirectTo: "/login",
@ -228,7 +228,6 @@ Our setup looks like this:
emailVerification: {
clientRoute: EmailVerificationRoute,
getEmailContentFn: import { getVerificationEmailContent } from "@server/auth/email.js",
allowUnverifiedLogin: false,
}
```

View File

@ -1,6 +1,6 @@
---
title: Getting Started
slug: /
title: Quick Start
slug: /quick-start
next: /tutorials/todo-app
---
@ -8,16 +8,18 @@ import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import useBaseUrl from '@docusaurus/useBaseUrl';
## Quick Start
## Installation
Welcome, new Waspeteer 🐝!
To install Wasp on Linux / OSX, open your terminal and run:
To install Wasp on Linux / OSX / WSL(Win), open your terminal and run:
```shell
curl -sSL https://get.wasp-lang.dev/installer.sh | sh
```
Wasp requires `node` and will warn you if it is missing: check below for [more details](#requirements).
Then, create a new app by running:
@ -36,16 +38,16 @@ Anything went wrong, or you have additional questions? Check [More Details](#mor
### What next?
- If you are using VSCode, install our [Wasp language extension](https://marketplace.visualstudio.com/items?itemName=wasp-lang.wasp).
- ➡️ **Check out the [Todo App tutorial](tutorials/todo-app.md) , which will take you through all the core features of Wasp!** ⬅️
- **Join us on [Discord](https://discord.gg/rzdnErX)!** Any feedback or questions you have, we are there for you.
- Follow Wasp development by **subscribing to our newsletter: https://wasp-lang.dev/#signup ** . We usually send 1 per month, and Matija does his best to unleash his creativity to make them engaging and fun to read :D!
- [ ] 👉 **Check out the [Todo App tutorial](tutorials/todo-app.md) , which will take you through all the core features of Wasp!** 👈
- [ ] If you are using VSCode, install our [Wasp language extension](https://marketplace.visualstudio.com/items?itemName=wasp-lang.wasp).
- [ ] Join us on [Discord](https://discord.gg/rzdnErX)! Any feedback or questions you have, we are there for you.
- [ ] Follow Wasp development by subscribing to our newsletter: https://wasp-lang.dev/#signup . We usually send 1 per month, and Matija does his best to unleash his creativity to make them engaging and fun to read :D!
------
## More details
## More details
### 1. Requirements
### Requirements
You must have `node` (and `npm`) installed on your machine and available in `PATH`. We rely on the latest Node.js LTS version (currently `v18.14.2`).
@ -82,7 +84,7 @@ We recommend using [nvm](https://github.com/nvm-sh/nvm) for managing your Node.j
</details>
### 2. Installation
### Installation
<Tabs
defaultValue='linux/osx'

View File

@ -1,23 +1,28 @@
---
title: What is Wasp?
title: Introduction
slug: /
---
import ImgWithCaption from '../../blog/components/ImgWithCaption'
:::note
If you are looking for the installation instructions, check out the [Quick Start](/docs/quick-start) section.
:::
We will give a brief overview of what Wasp is, how it works on a high level and when to use it.
## Wasp is a tool to build modern web applications
It is an opinionated way of building **full-stack web applications**. It takes care of all three
major parts of a web application: **client** (front-end), **server** (back-end) and **deployment**.
major parts of a web application: **client** (front-end), **server** (back-end) and **database**.
#### Works well with your existing stack
### Works well with your existing stack
Wasp is not trying to do everything at once but rather focuses on the complexity
which arises from connecting all the parts of the stack (client, server, deployment) together.
which arises from connecting all the parts of the stack (client, server, database, deployment) together.
Wasp is using **React**, **Node.js** and **Prisma** under the hood and relies on them to define web components and server queries and actions.
#### Wasp's secret sauce
### Wasp's secret sauce
At the core is the Wasp compiler which takes the Wasp config and your Javascript code and outputs the client app, server app and deployment code.
@ -41,35 +46,34 @@ Define your app in the Wasp config and get:
You don't need to write any code for these features, Wasp will take care of it for you 🤯 And what's even better, Wasp also maintains the code for you, so you don't have to worry about keeping up with the latest security best practices. As Wasp updates, so does your app.
### But what does it look like?
## So what does the code look like?
Let's say you want to build a web app that allows users to **create and share their favorite recipes**.
You would start by defining your app in the Wasp file:
Let's start with the main.wasp file: it is the central file of your app, where you describe the app from the high level.
Let's give our app a title and let's immediatelly turn on the full-stack authentication via username and password:
```c title="main.wasp"
app recepieApp {
app RecipeApp {
title: "My Recipes",
wasp: {
version: "^0.10.0"
},
wasp: { version: "^0.10.0" },
auth: {
methods: {
google: {} // out-of-the-box auth with Google
},
methods: { usernameAndPassword: {} },
onAuthFailedRedirectTo: "/login",
onAuthSucceededRedirectTo: "/",
},
userEntity: User
}
}
```
Let's then add the data model for your recipes:
Let's then add the data models for your recipes. We will want to have Users and Users can own Recipes:
```c title="main.wasp"
// Use Prisma schema syntax to define your data model
entity User {=psl
...
entity User {=psl // Data models are defined using Prisma Schema Language.
id Int @id @default(autoincrement())
name String
username String @unique
password String
recipes Recipe[]
psl=}
@ -82,44 +86,67 @@ entity Recipe {=psl
psl=}
```
Next, you would define some queries and actions...
Next, let's define how to do something with these data models!
We do that by defining Operations, in this case a Query `getRecipes` and Action `addRecipe`,
which are in their essence a Node.js functions that execute on server and can, thanks to Wasp, very easily be called from the client.
First, we define these Operations in our main.wasp file, so Wasp knows about them and can "beef them up":
```c title="main.wasp"
// Queries have automatic cache invalidation and are type-safe
// Queries have automatic cache invalidation and are type-safe.
query getRecipes {
fn: import { getRecipes } from "@server/queries.js",
fn: import { getRecipes } from "@server/recipe.js",
entities: [Recipe],
}
// Actions are type-safe and can be used to perform side-effects
// Actions are type-safe and can be used to perform side-effects.
action addRecipe {
fn: import { addRecipe } from "@server/actions.js",
fn: import { addRecipe } from "@server/recipe.js",
entities: [Recipe],
}
```
... which you would implement in your Javascript or Typescript code:
... and then implement them in our Javascript (or TypeScript) code (we show just the query here, using TypeScript):
```ts title="src/server/queries.ts"
// Wasp compiler will generate types for you based on your data model
import { GetRecipes } from "@wasp/queries/types";
import { Recipe } from "@wasp/entities";
```ts title="src/server/recipe.ts"
// Wasp generates types for you.
import type { GetRecipes } from "@wasp/queries/types";
import type { Recipe } from "@wasp/entities";
export const getRecipes: GetRecipes<{}, Recipe[]> = async (_args, context) => {
// Use Prisma to query your database
return context.entities.Recipe.findMany();
return context.entities.Recipe.findMany( // Prisma query
{ where: { user: { id: context.user.id } } }
);
};
export const addRecipe ...
```
And then use it in your React component:
Now we can very easily use these in our React components!
```tsx title="src/client/pages/RecipeListPage.tsx"
For the end, let's create a home page of our app.
First we define it in main.wasp:
```c title="main.wasp"
...
route HomeRoute { path: "/", to: HomePage }
component HomePage {
component: import { HomePage } from "@client/pages/HomePage",
authRequired: true // Will send user to /login if not authenticated.
}
```
and then implement it as a React component in JS/TS (that calls the Operations we previously defined):
```tsx title="src/client/pages/HomePage.tsx"
import getRecipes from "@wasp/queries/getRecipes";
import { useQuery } from "@wasp/queries";
import type { User } from "@wasp/entities";
export function Homepage({ user }: { user: User }) {
// Due to full-stack type safety, `recipes` will be of type `Recipe[]` here
const { data: recipes, isLoading } = useQuery(getRecipes);
export function HomePage({ user }: { user: User }) {
// Due to full-stack type safety, `recipes` will be of type `Recipe[]` here.
const { data: recipes, isLoading } = useQuery(getRecipes); // Calling our query here!
if (isLoading) {
return <div>Loading...</div>;
@ -129,11 +156,12 @@ export function Homepage({ user }: { user: User }) {
<div>
<h1>Recipes</h1>
<ul>
{recipes.map((recipe) => (
{recipes ? recipes.map((recipe) => (
<li key={recipe.id}>
<Link to={`/recipes/${recipe.id}`}>{recipe.title}</Link>
<div>{recipe.title}</div>
<div>{recipe.description}</div>
</li>
))}
)) : 'No recipes defined yet!'}
</ul>
</div>
);
@ -144,6 +172,10 @@ And voila! We are listing all the recipes in our app 🎉
This was just a quick example to give you a taste of what Wasp is. For step by step tour through the most important Wasp features, check out the [Todo app tutorial](/docs/tutorials/todo-app).
:::note
Above we skipped defining /login and /signup pages to keep the example a bit shorter, but those are very simple to do by using Wasp's Auth UI feature.
:::
## When to use Wasp
Wasp is addressing the same core problems that typical web app frameworks are addressing, and it in big part [looks, swims and quacks](https://en.wikipedia.org/wiki/Duck_test) like a web app framework.
@ -171,4 +203,4 @@ Other examples of *DSL*s that are often used today are e.g. *SQL* for databases
The main advantage and reason why *DSL*s exist is that they need to do only one task (e.g. database queries)
so they can do it well and provide the best possible experience for the developer.
The same idea stands behind Wasp - a language that will allow developers to **build modern web applications with 10x less code and less stack-specific knowledge**.
The same idea stands behind Wasp - a language that will allow developers to **build modern web applications with 10x less code and less stack-specific knowledge**.

View File

@ -1246,7 +1246,6 @@ app MyApp {
email: "hello@itsme.com"
},
emailVerification: {
allowUnverifiedLogin: false,
clientRoute: EmailVerificationRoute,
getEmailContentFn: import { getVerificationEmailContent } from "@server/auth/email.js",
},
@ -1254,6 +1253,7 @@ app MyApp {
clientRoute: PasswordResetRoute
getEmailContentFn: import { getPasswordResetEmailContent } from "@server/auth/email.js",
},
allowUnverifiedLogin: false,
},
},
onAuthFailedRedirectTo: "/someRoute"
@ -1302,10 +1302,6 @@ export const getVerificationEmailContent: GetVerificationEmailContentFn = ({
})
```
- `allowUnverifiedLogin: Boolean`: a boolean that specifies whether the user can login without verifying their e-mail address. (optional)
It defaults to `false`. If `allowUnverifiedLogin` is set to `true`, the user can login without verifying their e-mail address, otherwise users will receive a `401` error when trying to login without verifying their e-mail address.
##### `passwordReset: PasswordResetConfig` (required)
`passwordReset` is a dict that specifies the password reset process. It is required to be defined. The object has the following fields:
- `clientRoute: Route`: a route that is used for the user to reset their password. (required)
@ -1324,6 +1320,10 @@ import { resetPassword } from '@wasp/auth/email/actions';
await resetPassword({ password, token })
```
##### `allowUnverifiedLogin: bool`: a boolean that specifies whether the user can login without verifying their e-mail address. (optional)
It defaults to `false`. If `allowUnverifiedLogin` is set to `true`, the user can login without verifying their e-mail address, otherwise users will receive a `401` error when trying to login without verifying their e-mail address.
Read on how to do it the easiest way with Auth UI in the [email authentication guide](/docs/guides/email-auth).

View File

@ -6,7 +6,7 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
import DiscordLink from '../../blog/components/DiscordLink';
:::info
Make sure you've set up Wasp! Check out [Getting Started](/docs) first for installation instructions, and then continue with the tutorial. In case of any issues - please, ping us on <DiscordLink />.
Make sure you've set up Wasp! Check out [Getting Started](/docs/quick-start) first for installation instructions, and then continue with the tutorial. In case of any issues - please, ping us on <DiscordLink />.
:::
Well build a web app to solve every developer's most common problem finding an excuse to justify our messy work! We will start with a single config file that outlines the full-stack architecture of our app plus several dozen lines of code for our specific business logic. There's no faster way to do it, so we cant excuse ourselves from building it!

View File

@ -5,7 +5,7 @@ title: Creating the project
import useBaseUrl from '@docusaurus/useBaseUrl';
By now you've already learned [how to install Wasp and create a new project](/docs). So lets create a new web app appropriately named `ItWaspsOnMyMachine`.
By now you've already learned [how to install Wasp and create a new project](/docs/quick-start). So lets create a new web app appropriately named `ItWaspsOnMyMachine`.
```
wasp new ItWaspsOnMyMachine

View File

@ -2,9 +2,12 @@ module.exports = {
docs: [
{
type: "category",
label: "Introduction",
label: "Getting started",
collapsed: false,
items: ["introduction/getting-started", "introduction/what-is-wasp"],
items: [
"introduction/what-is-wasp",
"introduction/getting-started"
],
},
{
type: "category",

View File

@ -77,7 +77,7 @@ const Features = () => {
<Feature
Icon={Unlock}
title='Full-stack Auth'
url='/docs/language/features#authentication--authorization'
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.
`}
@ -115,7 +115,7 @@ const Features = () => {
<Feature
Icon={Mail}
title='Email Sending'
url='/docs'
url='/docs/guides/sending-emails'
description={`
All you need to do is connect an email provider and you can send emails!
`}

View File

@ -123,6 +123,15 @@ const Footer = () => {
inputBgColor='bg-transparent'
/>
<span className='flex items-center mt-6'>
<small className='text-neutral-500 text-xs'>Backed by</small>
<img
className='w-24 ml-2'
src='img/lp/yc-logo-rounded.png'
alt='YC'
/>
</span>
</div>
</div>
<div className='pt-8 mt-8'>

View File

@ -23,7 +23,7 @@ const StartIcon = () => (
const ActionButtons = () => (
<div className='flex items-center gap-2'>
<Link to='/docs'>
<Link to='/docs/quick-start'>
<button
className={`
inline-flex items-center space-x-2
@ -39,7 +39,7 @@ const ActionButtons = () => (
</button>
</Link>
<Link to='/docs/tutorials/todo-app'>
<Link to='/docs'>
<button
className={`
inline-flex items-center space-x-2
@ -52,7 +52,7 @@ const ActionButtons = () => (
`}
>
<BookOpen size={16} />
<span>Tutorial</span>
<span>Quick Guide</span>
</button>
</Link>
</div>
@ -77,7 +77,8 @@ const Hero = () => {
`app todoApp {
title: "ToDo App", // visible in the browser tab
auth: { // full-stack auth out-of-the-box
userEntity: User, methods: { email: {...} }
userEntity: User,
methods: { google: {}, gitHub: {}, email: {...} }
}
}
@ -119,7 +120,7 @@ entity Task {=psl ... psl=} // Your Prisma data model.
<ActionButtons />
<div className='flex flex-col gap-4'>
<small className='text-neutral-500 text-xs'>works with</small>
<small className='text-neutral-500 text-xs'>Works with</small>
<div className='flex'>
<img
@ -138,6 +139,15 @@ entity Task {=psl ... psl=} // Your Prisma data model.
alt='Prisma'
/>
</div>
<span className='flex items-center mt-6'>
<small className='text-neutral-500 text-xs'>Backed by</small>
<img
className='w-24 ml-2'
src='img/lp/yc-logo-rounded.png'
alt='YC'
/>
</span>
</div>
</div>

View File

@ -9,10 +9,11 @@ const Announcement = () => {
let history = useHistory()
const handleLink = () => {
history.push('/blog/2023/04/11/wasp-launch-week-two')
//history.push('/blog/2023/04/13/db-start-and-seed')
//history.push('/#signup')
//window.open('https://betathon.wasp-lang.dev/')
//window.open('https://twitter.com/MatijaSosic/status/1646532181324603395')
window.open('https://twitter.com/WaspLang/status/1647979490180575234')
}
return (
@ -34,7 +35,7 @@ const Announcement = () => {
>
<span className='item-center flex gap-2 px-3'>
<span>Wasp Launch Week 2 starts on <span className='underline'>April 12</span>! 🚀</span>
<span>Launch Week 2 is under way! 🚀</span>
</span>
<span className='hidden items-center space-x-2 px-3 lg:flex'>
@ -44,7 +45,7 @@ const Announcement = () => {
hover:bg-neutral-600
`}
>
See what's coming
Day 5: Testing🧪 + Full-stack Type Safety🛡
</span>
</span>

View File

@ -222,7 +222,7 @@ const Nav = () => {
<GitHubButton />
<Link to='/docs'>
<Link to='/docs/quick-start'>
<button
className={`
hidden lg:block text-xs

View File

@ -0,0 +1,104 @@
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 SectionContainer from './Layouts/SectionContainer'
import styles from '../pages/styles.module.css'
// TODO(matija): this is duplication from HowItWorks section.
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
`}
>
<div className='group inline-flex gap-1 items-center'>
<span>{label}</span>
<div className='transition-all group-hover:ml-0.5'>
<span className='text-yellow-400'>
<ArrowRight size={14} strokeWidth={2} />
</span>
</div>
</div>
</span>
</Link>
)
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'>
<span>
<span className='text-neutral-600'>{f[0]}</span>
{f[1] && <>&nbsp;<GhIssueLink url={'https://github.com/wasp-lang/wasp/issues/' + f[1]} label={f[1]} /></>}
</span>
</div>
</li>
))}
</ul>
)
const Roadmap = () => (
<SectionContainer className='space-y-16 lg:py-18' 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'>
🚧 Roadmap 🚧
</h2>
<p className='text-neutral-500'>
Work on Wasp never stops: get a glimpse of what is coming next!
</p>
</div>
</div>
<div className='grid grid-cols-1 lg:grid-cols-2 md:gap-16'>
<div
className={`
bg-yellow-500/5 border border-yellow-500/25
p-5 rounded-lg
`}
>
<div className='font-bold text-center mb-6'>Near-term improvements and features</div>
<Section features={[
['Improve Wasp project structure', 734],
['Allow custom steps in the build pipeline', 906],
['Support for SSR / SSG', 911],
['Automatic generation of API for Operations', 863],
['Better Prisma support (more features, IDE)', 641],
['Support for backend testing', 110],
['Better way to define JS dependencies', 243]
]} />
</div>
<div
className={`
bg-yellow-500/20 border border-yellow-500/25
p-5 rounded-lg
mt-6 lg:mt-0
`}
>
<div className='font-bold text-center mb-6'>Advanced Features</div>
<Section features={[
['Top-level data schema', 642],
['Automatic generation of CRUD UI', 489],
['Multiple targets (e.g. mobile)', 1088],
['Multiple servers, serverless'],
['Polyglot'],
['Multiple frontend libraries'],
['Full-stack modules']
]} />
</div>
</div>
</SectionContainer>
)
export default Roadmap

View File

@ -5,6 +5,7 @@ import Head from '@docusaurus/Head'
import Nav from '../components/Nav/index'
import Hero from '../components/Hero'
import Features from '../components/Features'
import Roadmap from '../components/Roadmap'
import Benefits from '../components/Benefits'
import Testimonials from '../components/Testimonials'
import ExampleWaspApps from '../components/ExampleWaspApps'
@ -63,6 +64,7 @@ const Index = () => {
<LightsTwo />
<ShowcaseGallery />
<Newsletter />
<Roadmap />
<Faq />
</div>
{/* eof container */}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB