Merge release into main (#854)

Release -> Main
This commit is contained in:
Filip Sodić 2022-11-28 14:19:05 +01:00 committed by GitHub
commit 19b931c935
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 515 additions and 79 deletions

View File

@ -50,16 +50,16 @@ entity Task {=psl
psl=}
query getTasks {
fn: import { getTasks } from "@server/queries",
fn: import { getTasks } from "@server/queries.js",
entities: [Task]
}
action createTask {
fn: import { createTask } from "@server/actions",
fn: import { createTask } from "@server/actions.js",
entities: [Task]
}
action updateTask {
fn: import { updateTask } from "@server/actions",
fn: import { updateTask } from "@server/actions.js",
entities: [Task]
}

View File

@ -45,10 +45,10 @@ get by running `wasp new project` from this point onwards):
Main differences:
- All server-side code must be located inside the `src/server` directory. Wasp
declarations must import this code with `import foo from "@server/foo"`
declarations must import this code with `import foo from "@server/foo.js"`
(instead of `import foo from "@ext/foo.js"`)
- All client-side code must be located inside the `src/client` directory. Wasp
declarations must import this code with `import foo from "@client/bar"`
declarations must import this code with `import foo from "@client/bar.js"`
(instead of `import bar from "@ext/bar.js"`)
- All shared code (i.e., used on both the client and the server) must be
located inside the `src/shared` and imported where needed through a relative import.
@ -107,7 +107,7 @@ directory `foo`, you should:
query getTasks {
// This resolves to src/server/queries.js
fn: import { getTasks } from "@server/queries",
fn: import { getTasks } from "@server/queries.js",
}
```
Do this for all external imports in your `.wasp` file. After you're done, there shouldn't be any occurences of the string `"@ext"`.

View File

@ -76,7 +76,7 @@ entity User {=psl
psl=}
```
Check [here](https://github.com/wasp-lang/wasp/blob/main/examples/tutorials/TodoApp/main.wasp) for the complete example.
Check [here](https://github.com/wasp-lang/wasp/blob/release/examples/tutorials/TodoApp/main.wasp) for the complete example.
## Why a language (DSL), arent frameworks solving this already?

View File

@ -13,7 +13,7 @@ import ImgWithCaption from './components/ImgWithCaption'
![Enter Waspello](../static/img/waspello-screenshot.png)
<p align="center">
<Link to={'https://waspello.netlify.app/'}>Try Waspello here!</Link> | <Link to={'https://github.com/wasp-lang/wasp/blob/main/examples/waspello/main.wasp'}>See the code</Link>
<Link to={'https://waspello.netlify.app/'}>Try Waspello here!</Link> | <Link to={'https://github.com/wasp-lang/wasp/blob/release/examples/waspello/main.wasp'}>See the code</Link>
</p>
We've built a Trello clone using Wasp! Read on to learn how it went and how you can contribute.
@ -127,7 +127,7 @@ export const getListsAndCards = async (args, context) => {
```
This is just a regular Node.js function, there are no limits on what you can return! All the stuff provided by Wasp (user data, Prisma SDK for a specific entity) comes in a `context` variable.
The code for actions is very similar (we just need to use `action` keyword instead of `query`) so I won't repeat it here. You can check out the code for `updateCard` action [here](https://github.com/wasp-lang/wasp/blob/main/examples/waspello/main.wasp#L103).
The code for actions is very similar (we just need to use `action` keyword instead of `query`) so I won't repeat it here. You can check out the code for `updateCard` action [here](https://github.com/wasp-lang/wasp/blob/release/examples/waspello/main.wasp#L103).
#### Pages, routing & components
To display all the nice data we have, we'll use React components. There are no limits to how you can use React components within Wasp, the only one is that each `page` has its root component:

View File

@ -14,7 +14,7 @@ import ImgWithCaption from './components/ImgWithCaption'
![Hello, Waspleau](../static/img/waspleau-screenshot.png)
<p align="center">
<Link to={'https://waspleau.netlify.app/'}>See Waspleau here!</Link> | <Link to={'https://github.com/wasp-lang/wasp/blob/main/examples/waspleau'}>See the code</Link>
<Link to={'https://waspleau.netlify.app/'}>See Waspleau here!</Link> | <Link to={'https://github.com/wasp-lang/wasp/blob/release/examples/waspleau'}>See the code</Link>
</p>
We've built a dashboard powered by a job queue using Wasp!
@ -124,7 +124,7 @@ const workerFunction = async (opts) => {
export const githubWorker = { name: 'GitHub API', fn: workerFunction, schedule: '*/10 * * * *' }
```
_Note: Please see the [actual serverSetup.js file](https://github.com/wasp-lang/wasp/blob/main/examples/waspleau/src/server/serverSetup.js) for how we use this abstraction in practice._
_Note: Please see the [actual serverSetup.js file](https://github.com/wasp-lang/wasp/blob/release/examples/waspleau/src/server/serverSetup.js) for how we use this abstraction in practice._
### Server → client
@ -165,7 +165,7 @@ const { data: dashboardData, isFetching, error } = useQuery(refreshDashboardData
## Congratulations, lets dance!
Whew, we did it! If youd like to deploy your own customized version of this dashboard, please clone [our repo](https://github.com/wasp-lang/wasp) and check out the Waspleau example [README.md](https://github.com/wasp-lang/wasp/blob/main/examples/waspleau/README.md) for tips on getting started. You can also [check out our docs](https://wasp-lang.dev/docs) to dive deeper into anything.
Whew, we did it! If youd like to deploy your own customized version of this dashboard, please clone [our repo](https://github.com/wasp-lang/wasp) and check out the Waspleau example [README.md](https://github.com/wasp-lang/wasp/blob/release/examples/waspleau/README.md) for tips on getting started. You can also [check out our docs](https://wasp-lang.dev/docs) to dive deeper into anything.
![Rickroll](../static/img/waspleau-rickroll.gif)

View File

@ -144,7 +144,7 @@ For those interested, check out the [full diff here](https://github.com/wasp-lan
## Looks neat! Whats next?
First off, please check out our docs for Jobs: [https://wasp-lang.dev/docs/language/features#jobs](https://wasp-lang.dev/docs/language/features#jobs) There, you will find all the info you need to start using them. Next, if you want to see the code for this example in full, you can find it here: [https://github.com/wasp-lang/wasp/tree/main/examples/waspleau](https://github.com/wasp-lang/wasp/tree/main/examples/waspleau)
First off, please check out our docs for Jobs: [https://wasp-lang.dev/docs/language/features#jobs](https://wasp-lang.dev/docs/language/features#jobs) There, you will find all the info you need to start using them. Next, if you want to see the code for this example in full, you can find it here: [https://github.com/wasp-lang/wasp/tree/release/examples/waspleau](https://github.com/wasp-lang/wasp/tree/release/examples/waspleau)
In the future, we plan to add more job executors, including support for polyglot workers (imagine running your Python ML function from Wasp!). We are also open to any other ideas on how jobs can become more useful to you (like client-side access to server-side jobs, or client-side jobs using similar abstractions?). Let us know what you think!

View File

@ -23,7 +23,7 @@ Well use Michele Gerarduzzis [open-source project](https://github.com/mich
- Building an app shouldnt take more than 15 minutes.
- Use modern web dev technologies (NodeJS + React)
As a result well get a simple and fun pet project. You can find the complete codebase [here](https://github.com/wasp-lang/wasp/tree/main/examples/tutorials/ItWaspsOnMyMachine).
As a result well get a simple and fun pet project. You can find the complete codebase [here](https://github.com/wasp-lang/wasp/tree/release/examples/tutorials/ItWaspsOnMyMachine).
![Final result](../static/img/final-excuse-app.png)

View File

@ -0,0 +1,137 @@
---
title: 'Why we chose Prisma as a database layer for Wasp'
authors: [martinsos]
image: /img/why-we-chose-prisma/wasp-loves-prisma.png
tags: [webdev, wasp, 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'
<ImgWithCaption
alt="Beta is coming"
source="img/why-we-chose-prisma/wasp-loves-prisma.png"
/>
Wasp is a full-stack JS web dev framework, covering frontend, backend, and database. When choosing the solution to build our database layer on top, we chose Prisma, even though it was still somehwat new tech at that point, and we believe today we made a great choice -> read on to learn why!
<!--truncate-->
At Wasp, [we aim](/docs/vision) to simplify full-stack web development via a specialized high-level language. This language allows you to describe the main parts of your web app succinctly, avoiding a lot of usual boilerplate and configuration while giving you lots of features and ensuring best practices. Wasp is essentially a full-stack web framework implemented as a specialized language that works with React & Node.js!
When we started working on Wasp, we wanted to keep it easy to learn and to the point, so we decided:
- the Wasp language should only be used at a high level, so you would still use React, NodeJS, HTML, CSS, etc. to implement your custom logic. If a full-stack web app is an orchestra, Wasp is the conductor.
- the Wasp language should be declarative and simple, very similar to JSON, but “smarter” in the sense it understands web app concepts and makes sure your app follows them.
With that in mind, we focused on identifying high-level web app concepts that are worth capturing in the Wasp language. We identified the following parts of a web app:
- General app info (title, head, favicon, …)
- Pages and Routes
- Data Models (aka Entities), e.g. User, Task, Organization, Article, … .
- Operations (communication between client and server; CRUD on data models, 3rd party APIs, …)
- Deployment
## Entities
Of all of those, Entities are in the middle of everything, present through the whole codebase, and are central to all the other parts of the web app: client, server, and database. They were, however, also the most daunting part to implement!
When we started, we imagined an Entity would look something like this in Wasp:
```
entity User {
id: Id,
username: String @unique,
email: String @unique
groups: [Group]
}
```
While adding this initial syntax to our language was feasible, there were also much bigger tasks to tackle in order to make this a proper solution:
- expand syntax to be flexible enough for real-life use cases
- support migrations (data and schema)
- generate code that users can call from JS/TS to query and update entities in the DB
- and probably a lot of other things that we hadnt even thought of yet!
## Mongoose, Sequelize, … or Prisma?
We already decided that we would pick an ORM(ish) solution for JS/TS which we would build the rest of the features on top of. We started evaluating different ones: Mongoose, Sequelize, TypeORM, … .
But then we looked at Prisma, and the winner was clear! Not only was Prisma taking care of everything that we cared about, but it had one additional feature that made it a perfect fit:
```
model User {
id Int @id @default(autoincrement())
username String @unique
password String
}
```
No, this is not another idea of how the syntax for Entities could look like in Wasp language → this is the Prisma Schema Language (PSL)!!!
## Prisma Schema Language (PSL)
Indeed, Prisma is unique in having a special, declarative language for describing data models (schema), and it was exactly what we needed for Wasp.
So instead of implementing our own syntax for describing Entities, we decided to use Prisma and their PSL to describe Entities (data models) inside the Wasp language.
Today, Entities are described like this in Wasp language:
```
... some Wasp code ...
entity User {=psl
id Int @id @default(autoincrement())
username String @unique
password String
psl=}
... some Wasp code ...
```
So in the middle of Wasp, you just switch to writing PSL (Prisma Schema Language) to describe an entity!
Another great thing is that the PSL is at its core a pretty simple language, so we [implemented our own parser](https://github.com/wasp-lang/wasp/blob/main/waspc/src/Wasp/Psl/Parser/Model.hs) for it → that means that Wasp actually understands what you wrote, even though it is PSL, and can fully work with it. So we lost nothing by using PSL instead of our own syntax and instead gained all the features that Prisma brings.
## Other Benefits
Besides PSL, there were plenty of other reasons why we felt Prisma is a great fit for us:
- It is targeting Javascript / Typescript.
- It takes care of migrations and has a nice workflow for doing it.
- It supports different databases: Mongo, PostgreSQL, CockroachDB, …, which is very important for Wasp since our vision is to support different stacks in the future.
- It has Prisma Studio - UI for inspecting your database, which we also make available to you via Wasp CLI.
- It keeps improving quickly and is very focused on a nice developer experience, which is also our focus here at Wasp.
- Community is extremely welcoming and the core team is super helpful - all of our questions and issues were answered super quickly!
## Challenges
While integrating Prisma into Wasp went really smoothly, there were a few hiccups:
- Getting Prisma CLI to provide interactive output while being called programmatically by Wasp was tricky, and in the end, we had to use a bit of a dirty approach to trick the Prisma CLI into thinking it is called interactively. We opened an issue for this with Prisma, so hopefully, we will be able to remove this once it is resolved: https://github.com/prisma/prisma/issues/7113.
- In the early days, there were some bugs, however, they were always quickly solved, so updating to the newest Prisma version was often the solution.
- It took us a bit of fiddling to get Prisma to work with its schema outside of the servers root directory, but we did get it working in the end!
Most of these were due to us stretching the boundaries of how Prisma was imagined to be used, but in total Prisma proved to be fairly flexible!
## Summary
With its declarative language for describing schema, focus on ergonomics, and JS/TS as the target language, Prisma was really a stroke of luck for us - if not for it, it would have taken much more effort to get the Entities working in Wasp.
When we started using it, Prisma was still somewhat early, and it was certainly the least-mature technology in our stack - but we decided to bet on it because it was just a perfect fit, and it made so much sense. Today, with Prisma being a mature and popular solution, we are more than happy we made that choice!
## Future
Already, Prisma is playing a big role at Wasp, but there is still more that we plan and want to do:
- support Prismas Enum and Type declarations
- expose more of Prismas CLI commands, especially database seeding
- add support in Wasp for multiple databases (which Prisma already supports)
- improve IDE support for PSL within the Wasp language
If you are interested in helping with any of these, reach out to us on this issue https://github.com/wasp-lang/wasp/issues/641, or in any case, join us on our [Discord server](https://discord.gg/rzdnErX)!

View File

@ -3,8 +3,8 @@ title: Examples
---
Todo App:
- source code: https://github.com/wasp-lang/wasp/tree/main/examples/tutorials/TodoApp .
- source code: https://github.com/wasp-lang/wasp/tree/release/examples/tutorials/TodoApp .
Real World App (clone of Medium):
- source code: https://github.com/wasp-lang/wasp/tree/main/examples/realworld .
- source code: https://github.com/wasp-lang/wasp/tree/release/examples/realworld .
- hosted at: https://wasp-rwa.netlify.app/ .

View File

@ -94,6 +94,10 @@ With Wasp for Windows, we are almost there: Wasp is successfully compiling and r
In the meantime, the best way to start using Wasp on Windows is by using [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10). Once you set up Ubuntu on WSL, just follow Linux instructions for installing Wasp. If you need further help, reach out to us on [Discord](https://discord.gg/rzdnErX) - we have some community members using WSL that might be able to help you.
:::caution
If you are using WSL2, make sure that your Wasp project is not on Windows file system, but instead on Linux file system. Otherwise, Wasp won't be able to detect file changes, due to the [issue in WSL2](https://github.com/microsoft/WSL/issues/4739).
:::
</div>
</TabItem>
@ -140,7 +144,8 @@ The extension brings the following functionality:
## 4. What next?
**Check out the 🤓 [Pick a Tutorial page](pick-a-tutorial.md) 🤓. Choose an app that you'd like to build and it will take you through all the core features of Wasp!**
**Check out the 🤓 [Todo App tutorial](tutorials/todo-app.md) 🤓 , which will take you through all the core features of Wasp!**
Also, we would be excited to have you **join our community on [Discord](https://discord.gg/rzdnErX)!** Any feedback or questions you have, we are there for you.
Finally, to stay up to date with updates in Wasp, you can **subscribe 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!

View File

@ -1,32 +0,0 @@
---
title: Pick a Tutorial
---
import useBaseUrl from '@docusaurus/useBaseUrl';
import DiscordLink from '../blog/components/DiscordLink';
Congrats, you're now familiar with the basic concepts of Wasp! 🥳
It's time to build something cool and check the capabilities of Wasp in action. Pick one of the tutorials below and let us know your impressions on <DiscordLink />!
### To-Do app
[The To-Do app](tutorials/todo-app) is a thorough journey covering most of the Wasp's concepts, from very basics to features like auth, dependency management, operations, ... . If you'd like to get familiar with Wasp on a more detailed level - this is a tutorial for you!
Time estimate: ~45 minutes
### Dev excuses app
[Dev excuses app](tutorials/dev-excuses-app) is a fun, quick overview of how you can build a full-stack app with Wasp in a matter of minutes. Do not expect any detailed concept explanations, and refer to this tutorial if you'd like to get a fast overview of Wasp's possibilities.
Time estimate: ~20 minutes
<hr/>
<img alt="Let's build!"
src={useBaseUrl('img/develop-an-app.jpg')}
style={{ border: "1px solid black" }}
height="400px"
/>
P.S: If you decided to build an app on your own - we'd love to see it! If it's simple enough, let's turn it into a tutorial! Please check our [contribution guide](contributing) for detailed instructions and reach us on Discord.

View File

@ -18,7 +18,7 @@ Well use Michele Gerarduzzis [open-source project](https://github.com/mich
- Building an app shouldnt take more than 15 minutes.
- Use modern web dev technologies (NodeJS + React)
As a result well get a simple and fun pet project. You can find the complete codebase [here](https://github.com/wasp-lang/wasp/tree/main/examples/tutorials/ItWaspsOnMyMachine).
As a result well get a simple and fun pet project. You can find the complete codebase [here](https://github.com/wasp-lang/wasp/tree/release/examples/tutorials/ItWaspsOnMyMachine).
<img alt="Final result"
src={useBaseUrl('img/dev-excuses-live-preview.gif')}

View File

@ -22,7 +22,7 @@ This tutorial will take you step by step through the most important features of
If you get stuck at any point (or just want to chat), reach out to us on [Discord](https://discord.gg/rzdnErX) and we will help you!
You can check out the complete code of the app we are about to build with Wasp [here](https://github.com/wasp-lang/wasp/tree/main/examples/tutorials/TodoApp).
You can check out the complete code of the app we are about to build with Wasp [here](https://github.com/wasp-lang/wasp/tree/release/examples/tutorials/TodoApp).
:::tip
If you are interested at any moment in what is Wasp actually generating in the background, take a look at `.wasp/out/` directory in your project.

View File

@ -32,12 +32,17 @@ query getTasks {
// We specify that JS implementation of the query (which is an async JS function)
// can be found in `src/server/queries.js` as the named export `getTasks`.
// Use '@server' to reference files inside the src/server folder.
fn: import { getTasks } from "@server/queries",
fn: import { getTasks } from "@server/queries.js",
// We tell Wasp that this query is doing something with entity `Task`. With that, Wasp will
// automatically refresh the results of this query when tasks change.
entities: [Task]
}
```
:::caution
Even if you use TypeScript and have the file `queries.ts`, you will still need to import it using the `.js` extension. Wasp internally uses `esnext` module resultion, which always requires specifying the extension as `.js` (i.e., the extension used in the emitted JS file). This applies to all `@server` immports (and files on the server in general). It does not apply to client files.
Read more about ES modules in TypeScript [here](https://www.typescriptlang.org/docs/handbook/esm-node.html). If you're interested in the discussion and the reasoning behind this, read about it [in this GitHub issue](https://github.com/microsoft/TypeScript/issues/33588).
:::
### JS implementation
Next, create a new file `src/server/queries.js` and define the JS we've just used in the `query` declaration above:

View File

@ -19,7 +19,7 @@ First we declare the action in Wasp:
// ...
action createTask {
fn: import { createTask } from "@server/actions",
fn: import { createTask } from "@server/actions.js",
entities: [Task]
}
```

View File

@ -20,7 +20,7 @@ We declare a Wasp action:
// ...
action updateTask {
fn: import { updateTask } from "@server/actions",
fn: import { updateTask } from "@server/actions.js",
entities: [Task]
}
```

View File

@ -12,7 +12,7 @@ We did it! For all those that followed the instructions closely and created "Bui
style={{ border: '1px solid black' }}
/>
You can check out the whole code of the app that we just built [here](https://github.com/wasp-lang/wasp/tree/main/examples/tutorials/TodoApp).
You can check out the whole code of the app that we just built [here](https://github.com/wasp-lang/wasp/tree/release/examples/tutorials/TodoApp).
If you are interested in what is Wasp actually generating in the background, you can check the `.wasp/out/` directory in your project.
@ -30,3 +30,5 @@ Or, you could use Wasp to build something of your own!
If you notice that some of the features you'd like to have are missing, or have any other kind of feedback, please write to us on [Discord](https://discord.gg/rzdnErX) or create an issue on [Github](https://github.com/wasp-lang/wasp), so we can learn which features to add/improve next.
Even better, if you would like to contribute or help building the feature, let us know!
You can find more details on contributing [here](contributing.md).
Oh, and do **subscribe 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!

View File

@ -20,9 +20,10 @@ module.exports = {
],
themeConfig: {
announcementBar: {
id: 'Beta_is_coming',
content: '<strong>We are releasing Beta on Nov 27! 🚀 Sign up <a href="#signup">here</a> to get notified. 🔔</strong>',
backgroundColor: '#ffcc00',
id: 'Beta_is_here',
content: 'Wasp Beta is live on Product Hunt 🚀 <strong><a href="https://www.producthunt.com/posts/wasp-lang-beta">Support us now!</a></strong>',
backgroundColor: '#ff6154',
textColor: '#fff',
isCloseable: false,
},
navbar: {

45
web/package-lock.json generated
View File

@ -23,6 +23,7 @@
"react-feather": "^2.0.10",
"react-modal": "^3.14.3",
"react-syntax-highlighter": "^15.5.0",
"react-transition-group": "^4.4.5",
"tailwindcss": "^3.2.4"
},
"devDependencies": {
@ -5462,6 +5463,15 @@
"utila": "~0.4"
}
},
"node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"dependencies": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
@ -9834,6 +9844,21 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
"dependencies": {
"@babel/runtime": "^7.5.5",
"dom-helpers": "^5.0.1",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": ">=16.6.0",
"react-dom": ">=16.6.0"
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@ -16717,6 +16742,15 @@
"utila": "~0.4"
}
},
"dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"requires": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
@ -19794,6 +19828,17 @@
"use-latest": "^1.2.1"
}
},
"react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
"requires": {
"@babel/runtime": "^7.5.5",
"dom-helpers": "^5.0.1",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2"
}
},
"read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",

View File

@ -29,6 +29,7 @@
"react-feather": "^2.0.10",
"react-modal": "^3.14.3",
"react-syntax-highlighter": "^15.5.0",
"react-transition-group": "^4.4.5",
"tailwindcss": "^3.2.4"
},
"devDependencies": {

View File

@ -8,7 +8,6 @@ module.exports = {
'getting-started',
'about',
'how-it-works',
'pick-a-tutorial'
]
},
{
@ -39,19 +38,6 @@ module.exports = {
'tutorials/todo-app/08-the-end'
]
},
{
type: 'category',
label: 'Dev Excuses app',
collapsed: true,
items: [
'tutorials/dev-excuses-app',
'tutorials/dev-excuses-app/01-creating-the-project',
'tutorials/dev-excuses-app/02-modifying-main-wasp-file',
'tutorials/dev-excuses-app/03-adding-operations',
'tutorials/dev-excuses-app/04-updating-main-page-js-file',
'tutorials/dev-excuses-app/05-perform-migration-and-run',
]
}
]
},
{

View File

@ -20,6 +20,7 @@ const faqs = [
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, Django, etc?',
answer: <p>
@ -36,6 +37,7 @@ const faqs = [
you under the hood.
</p>
},
*/
{
question: 'How hard is it to learn Wasp?',
answer: <p>

View File

@ -56,7 +56,7 @@ const ActionButtons = () => (
const PHBadge = () => (
<a
href="https://www.producthunt.com/posts/wasp-lang-alpha?utm_source=badge-top-post-badge&utm_medium=badge&utm_souce=badge-wasp&#0045;lang&#0045;alpha"
href="https://www.producthunt.com/posts/wasp-lang-beta"
target="_blank"
rel="noreferrer"
>
@ -93,7 +93,7 @@ page MainPage {
<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'>
<div className='lg:col-span-6 space-y-12 z-10'>
{/* Hero title and subtitle */}
<div>
<h1

View File

@ -0,0 +1,47 @@
import React from 'react'
import { ChevronRight, X } from 'react-feather'
const Announcement = () => {
const handleLink = () => {
window.open('https://www.producthunt.com/posts/wasp-lang-beta')
}
return (
<div
onClick={handleLink}
className={`
overflow-hidden
cursor-pointer flex-row
space-x-3
text-white
bg-[#ff6154]
`}
>
<div
className={`
mx-auto flex items-center justify-center divide-white p-3
text-sm font-medium
lg:container lg:divide-x lg:px-16 xl:px-20
`}
>
<span className='item-center flex gap-2 px-3'>
<span>Wasp Beta is live on Product Hunt 🚀</span>
</span>
<span className='hidden items-center space-x-2 px-3 lg:flex'>
<span>Support us now!</span>
<ChevronRight size={14} />
</span>
</div>
</div>
)
}
export default Announcement

View File

@ -1,11 +1,15 @@
import React from 'react'
import React, { useState } from 'react'
import Link from '@docusaurus/Link'
import { Star, Twitter } from 'react-feather'
import Announcement from './Announcement'
import Transition from '../../lib/Transition'
import { DiscordIcon, TwitterIcon } from './SocialIcons'
const Nav = () => {
const [open, setOpen] = useState(false)
const Logo = () => (
<div className='flex flex-shrink-0 items-center'>
<Link to='/'>
@ -57,8 +61,11 @@ const Nav = () => {
</a>
)
const HamburgerButton = () => (
<div className='absolute inset-y-0 left-0 px-2 flex items-center lg:hidden'>
const HamburgerButton = ({ toggleFlyOut }) => (
<div
className='absolute inset-y-0 left-0 px-2 flex items-center lg:hidden'
onClick={() => toggleFlyOut()}
>
<button
className={`
inline-flex items-center p-2
@ -91,6 +98,7 @@ const Nav = () => {
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'>
@ -101,7 +109,7 @@ const Nav = () => {
lg:container lg:px-16 xl:px-20
'
>
<HamburgerButton />
<HamburgerButton toggleFlyOut={() => setOpen(true)} />
<div className='
flex flex-1
items-center justify-center
@ -200,10 +208,131 @@ const Nav = () => {
url='https://twitter.com/WaspLang'
/>
</div> {/* EOF right side */}
</div>
</div>
{/* Mobile Nav Menu */}
<Transition
appear={true}
show={open}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<div
className={`
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="-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
`}
>
<span className="sr-only">Close menu</span>
<svg
className="h-6 w-6"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
</div>
<div className='mt-6 mb-12'>
{/* Docs */}
<div className='space-y-1 pt-2 pb-4'>
<Link to="/docs">
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
Docs
</span>
</Link>
</div>
{/* Docs */}
<div className='space-y-1 pt-2 pb-4'>
<Link to="/blog">
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
Blog
</span>
</Link>
</div>
{/* FAQ */}
<div className='space-y-1 pt-2 pb-4'>
<Link to="#faq" onClick={() => setOpen(false)}>
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
FAQ
</span>
</Link>
</div>
{/* Join the list */}
<div className='space-y-1 pt-2 pb-4'>
<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
`}>
📬 Join the list
</span>
</Link>
</div>
{/* GitHub */}
<div className='space-y-1 pt-2 pb-4'>
<Link to="https://github.com/wasp-lang/wasp">
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
GitHub
</span>
</Link>
</div>
{/* Discord */}
<div className='space-y-1 pt-2 pb-4'>
<Link to="https://discord.gg/rzdnErX">
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
👾 Discord
</span>
</Link>
</div>
{/* Twitter */}
<div className='space-y-1 pt-2 pb-4'>
<Link to="https://twitter.com/WaspLang">
<span className="text-neutral-700 block pl-3 pr-4 text-base font-medium">
🐦 Twitter
</span>
</Link>
</div>
</div>
</div>
</Transition>
</div>
</nav>

108
web/src/lib/Transition.js Normal file
View File

@ -0,0 +1,108 @@
// From: https://gist.github.com/adamwathan/3b9f3ad1a285a2d1b482769aeb862467
import { CSSTransition as ReactCSSTransition } from 'react-transition-group'
import React, { useRef, useEffect, useContext } from 'react'
const TransitionContext = React.createContext({
parent: {},
})
function useIsInitialRender() {
const isInitialRender = useRef(true)
useEffect(() => {
isInitialRender.current = false
}, [])
return isInitialRender.current
}
function CSSTransition({
show,
enter = '',
enterFrom = '',
enterTo = '',
leave = '',
leaveFrom = '',
leaveTo = '',
appear,
children,
}) {
const enterClasses = enter.split(' ').filter((s) => s.length)
const enterFromClasses = enterFrom.split(' ').filter((s) => s.length)
const enterToClasses = enterTo.split(' ').filter((s) => s.length)
const leaveClasses = leave.split(' ').filter((s) => s.length)
const leaveFromClasses = leaveFrom.split(' ').filter((s) => s.length)
const leaveToClasses = leaveTo.split(' ').filter((s) => s.length)
function addClasses(node, classes) {
classes.length && node.classList.add(...classes)
}
function removeClasses(node, classes) {
classes.length && node.classList.remove(...classes)
}
return (
<ReactCSSTransition
appear={appear}
unmountOnExit
in={show}
addEndListener={(node, done) => {
node.addEventListener('transitionend', done, false)
}}
onEnter={(node) => {
addClasses(node, [...enterClasses, ...enterFromClasses])
}}
onEntering={(node) => {
removeClasses(node, enterFromClasses)
addClasses(node, enterToClasses)
}}
onEntered={(node) => {
removeClasses(node, [...enterToClasses, ...enterClasses])
}}
onExit={(node) => {
addClasses(node, [...leaveClasses, ...leaveFromClasses])
}}
onExiting={(node) => {
removeClasses(node, leaveFromClasses)
addClasses(node, leaveToClasses)
}}
onExited={(node) => {
removeClasses(node, [...leaveToClasses, ...leaveClasses])
}}
>
{children}
</ReactCSSTransition>
)
}
function Transition({ show, appear, ...rest }) {
const { parent } = useContext(TransitionContext)
const isInitialRender = useIsInitialRender()
const isChild = show === undefined
if (isChild) {
return (
<CSSTransition
appear={parent.appear || !parent.isInitialRender}
show={parent.show}
{...rest}
/>
)
}
return (
<TransitionContext.Provider
value={{
parent: {
show,
isInitialRender,
appear,
},
}}
>
<CSSTransition appear={appear} show={show} {...rest} />
</TransitionContext.Provider>
)
}
export default Transition

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB