Merge branch 'main' into link-component-navigation
@ -1,6 +1,6 @@
|
||||
public/public-banner.png
|
||||
src/client/static/avatar-placeholder.png
|
||||
src/client/static/open-saas-banner.png
|
||||
src/client/static/avatar-placeholder.webp
|
||||
src/client/static/da-boi.webp
|
||||
src/client/static/open-saas-banner.webp
|
||||
src/landing-page/logos/SalesforceLogo.tsx
|
||||
src/payment/lemonSqueezy/checkoutUtils.ts
|
||||
src/payment/lemonSqueezy/paymentDetails.ts
|
||||
|
@ -1,6 +1,6 @@
|
||||
--- template/app/main.wasp
|
||||
+++ opensaas-sh/app/main.wasp
|
||||
@@ -3,24 +3,24 @@
|
||||
@@ -3,30 +3,30 @@
|
||||
version: "^0.15.0"
|
||||
},
|
||||
|
||||
@ -8,35 +8,47 @@
|
||||
+ title: "Open SaaS",
|
||||
|
||||
head: [
|
||||
"<meta property='og:type' content='website' />",
|
||||
- "<meta property='og:title' content='My Open SaaS App' />",
|
||||
+ "<meta property='og:title' content='Open SaaS' />",
|
||||
"<meta property='og:url' content='https://opensaas.sh' />",
|
||||
- "<meta property='og:description' content='I made a SaaS App. Buy my stuff.' />",
|
||||
- "<meta property='og:image' content='https://opensaas.sh/public-banner.png' />",
|
||||
- "<meta name='twitter:image' content='https://opensaas.sh/public-banner.png' />",
|
||||
+ "<meta property='og:description' content='Free, open-source SaaS boilerplate starter for React & NodeJS.' />",
|
||||
+ "<meta property='og:image' content='https://opensaas.sh/banner.png' />",
|
||||
"<meta charset='utf-8' />",
|
||||
- "<meta name='description' content='Your apps main description and features.' />",
|
||||
- "<meta name='author' content='Your (App) Name' />",
|
||||
- "<meta name='keywords' content='saas, solution, product, app, service' />",
|
||||
-
|
||||
+ "<meta name='description' content='Build and launch your SaaS application faster with our free, open-source starter kit. Features include auth, payments, AI example app, and admin dashboard.' />",
|
||||
+ "<meta name='author' content='Open SaaS' />",
|
||||
+ "<meta name='keywords' content='saas, starter, boilerplate, free, open source, authentication, payments' />",
|
||||
+
|
||||
+ "<meta name=\"twitter:title\" content=\"Open SaaS\" />",
|
||||
+ "<meta name=\"twitter:text:title\" content=\"Open SaaS\" />",
|
||||
+ "<meta name='twitter:image' content='https://opensaas.sh/banner.png' />",
|
||||
+ "<meta name=\"twitter:image:alt\" content=\"Open SaaS\" />",
|
||||
"<meta name='twitter:image:width' content='800' />",
|
||||
"<meta name='twitter:image:height' content='400' />",
|
||||
"<meta name='twitter:card' content='summary_large_image' />",
|
||||
- // TODO: You can put your Plausible analytics scripts below (https://docs.opensaas.sh/guides/analytics/):
|
||||
- // NOTE: Plausible does not use Cookies, so you can simply add the scripts here.
|
||||
- // Google, on the other hand, does, so you must instead add the script dynamically
|
||||
- // via the Cookie Consent component after the user clicks the "Accept" cookies button.
|
||||
- "<script defer data-domain='<your-site-id>' src='https://plausible.io/js/script.js'></script>", // for production
|
||||
- "<script defer data-domain='<your-site-id>' src='https://plausible.io/js/script.local.js'></script>", // for development
|
||||
+ "<script defer data-domain='opensaas.sh' src='https://plausible.apps.twoducks.dev/js/script.js'></script>",
|
||||
+ "<script defer data-domain='opensaas.sh' src='https://plausible.apps.twoducks.dev/js/script.local.js'></script>",
|
||||
+ "<meta property='og:site_name' content='Open SaaS' />",
|
||||
"<meta property='og:type' content='website' />",
|
||||
- "<meta property='og:title' content='Your Open SaaS App' />",
|
||||
- "<meta property='og:site_name' content='Your Open SaaS App' />",
|
||||
- "<meta property='og:url' content='https://your-saas-app.com' />",
|
||||
- "<meta property='og:description' content='Your apps main description and features.' />",
|
||||
- "<meta property='og:image' content='https://your-saas-app.com/public-banner.webp' />",
|
||||
- "<meta name='twitter:image' content='https://your-saas-app.com/public-banner.webp' />",
|
||||
+ "<meta property='og:title' content='Open SaaS' />",
|
||||
+ "<meta property='og:url' content='https://opensaas.sh' />",
|
||||
+ "<meta property='og:description' content='Free, open-source SaaS boilerplate starter for React & NodeJS.' />",
|
||||
+ "<meta property='og:image' content='https://opensaas.sh/public-banner.webp' />",
|
||||
+
|
||||
+ "<meta name=\"twitter:title\" content=\"Open SaaS\" />",
|
||||
+ "<meta name=\"twitter:text:title\" content=\"Open SaaS\" />",
|
||||
+ "<meta name='twitter:image' content='https://opensaas.sh/public-banner.webp' />",
|
||||
+ "<meta name=\"twitter:image:alt\" content=\"Open SaaS\" />",
|
||||
"<meta name='twitter:image:width' content='800' />",
|
||||
"<meta name='twitter:image:height' content='400' />",
|
||||
"<meta name='twitter:card' content='summary_large_image' />",
|
||||
- // TODO: You can put your Plausible analytics scripts below (https://docs.opensaas.sh/guides/analytics/):
|
||||
- // NOTE: Plausible does not use Cookies, so you can simply add the scripts here.
|
||||
- // Google, on the other hand, does, so you must instead add the script dynamically
|
||||
- // via the Cookie Consent component after the user clicks the "Accept" cookies button.
|
||||
- "<script defer data-domain='<your-site-id>' src='https://plausible.io/js/script.js'></script>", // for production
|
||||
- "<script defer data-domain='<your-site-id>' src='https://plausible.io/js/script.local.js'></script>", // for development
|
||||
+ "<script defer data-domain='opensaas.sh' src='https://plausible.apps.twoducks.dev/js/script.js'></script>",
|
||||
+ "<script defer data-domain='opensaas.sh' src='https://plausible.apps.twoducks.dev/js/script.local.js'></script>",
|
||||
],
|
||||
|
||||
// 🔐 Auth out of the box! https://wasp-lang.dev/docs/auth/overview
|
||||
@@ -32,7 +32,7 @@
|
||||
@@ -38,7 +38,7 @@
|
||||
email: {
|
||||
fromField: {
|
||||
name: "Open SaaS App",
|
||||
@ -45,7 +57,7 @@
|
||||
},
|
||||
emailVerification: {
|
||||
clientRoute: EmailVerificationRoute,
|
||||
@@ -44,21 +44,18 @@
|
||||
@@ -50,21 +50,18 @@
|
||||
},
|
||||
userSignupFields: import { getEmailUserFields } from "@src/auth/userSignupFields",
|
||||
},
|
||||
@ -79,7 +91,7 @@
|
||||
},
|
||||
onAfterSignup: import { onAfterSignup } from "@src/auth/hooks",
|
||||
onAuthFailedRedirectTo: "/login",
|
||||
@@ -81,11 +78,11 @@
|
||||
@@ -87,11 +84,11 @@
|
||||
// NOTE: "Dummy" provider is just for local development purposes.
|
||||
// Make sure to check the server logs for the email confirmation url (it will not be sent to an address)!
|
||||
// Once you are ready for production, switch to e.g. "SendGrid" or "Mailgun" providers. Check out https://docs.opensaas.sh/guides/email-sending/ .
|
||||
@ -93,7 +105,7 @@
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -206,9 +203,9 @@
|
||||
@@ -212,9 +209,9 @@
|
||||
}
|
||||
|
||||
api paymentsWebhook {
|
||||
|
@ -0,0 +1,11 @@
|
||||
--- template/app/migrations/20241031103046_remove_checkout_session_id/migration.sql
|
||||
+++ opensaas-sh/app/migrations/20241031103046_remove_checkout_session_id/migration.sql
|
||||
@@ -0,0 +1,8 @@
|
||||
+/*
|
||||
+ Warnings:
|
||||
+
|
||||
+ - You are about to drop the column `checkoutSessionId` on the `User` table. All the data in the column will be lost.
|
||||
+
|
||||
+*/
|
||||
+-- AlterTable
|
||||
+ALTER TABLE "User" DROP COLUMN "checkoutSessionId";
|
@ -1,7 +1,7 @@
|
||||
--- template/app/src/landing-page/components/Clients.tsx
|
||||
+++ opensaas-sh/app/src/landing-page/components/Clients.tsx
|
||||
@@ -1,23 +1,64 @@
|
||||
+import logo from '../../client/static/logo.png';
|
||||
+import logo from '../../client/static/logo.webp';
|
||||
import AstroLogo from "../logos/AstroLogo";
|
||||
-import OpenAILogo from "../logos/OpenAILogo";
|
||||
import PrismaLogo from "../logos/PrismaLogo";
|
||||
|
@ -1,7 +1,7 @@
|
||||
--- template/app/src/landing-page/components/Hero.tsx
|
||||
+++ opensaas-sh/app/src/landing-page/components/Hero.tsx
|
||||
@@ -1,7 +1,25 @@
|
||||
-import openSaasBanner from '../../client/static/open-saas-banner.png';
|
||||
-import openSaasBannerWebp from '../../client/static/open-saas-banner.webp';
|
||||
-import { DocsUrl } from '../../shared/common';
|
||||
+import { useState, useEffect } from 'react';
|
||||
+import { AiFillGithub } from 'react-icons/ai';
|
||||
@ -26,9 +26,9 @@
|
||||
+ }, []);
|
||||
+
|
||||
return (
|
||||
<div className='relative pt-14 w-full '>
|
||||
<div
|
||||
@@ -29,30 +47,47 @@
|
||||
<div className='relative pt-14 w-full'>
|
||||
<TopGradient />
|
||||
@@ -9,31 +27,47 @@
|
||||
<div className='py-24 sm:py-32'>
|
||||
<div className='mx-auto max-w-8xl px-6 lg:px-8'>
|
||||
<div className='lg:mb-18 mx-auto max-w-3xl text-center'>
|
||||
@ -69,15 +69,17 @@
|
||||
+ </a>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-14 flow-root sm:mt-14 '>
|
||||
- <div className='-m-2 rounded-xl lg:-m-4 lg:rounded-2xl lg:p-4'>
|
||||
- <div className='mt-14 flow-root sm:mt-14'>
|
||||
- <div className='-m-2 flex justify-center rounded-xl lg:-m-4 lg:rounded-2xl lg:p-4'>
|
||||
- <img
|
||||
- src={openSaasBanner}
|
||||
- src={openSaasBannerWebp}
|
||||
- alt='App screenshot'
|
||||
- width={2432}
|
||||
- height={1442}
|
||||
- width={1000}
|
||||
- height={530}
|
||||
- loading='lazy'
|
||||
- className='rounded-md shadow-2xl ring-1 ring-gray-900/10'
|
||||
- />
|
||||
+ <div className='mt-14 flow-root sm:mt-14 '>
|
||||
+ <div className='-m-2 mx-auto rounded-xl lg:-m-4 lg:rounded-2xl lg:p-4'>
|
||||
+ <iframe
|
||||
+ className=' mx-auto w-full md:w-[85%] aspect-[4/3] shadow-2xl'
|
||||
|
@ -4,8 +4,8 @@
|
||||
import type { NavigationItem } from '../client/components/NavBar/NavBar';
|
||||
-import { routes } from 'wasp/client/router';
|
||||
-import { DocsUrl, BlogUrl } from '../shared/common';
|
||||
-import daBoiAvatar from '../client/static/da-boi.png';
|
||||
-import avatarPlaceholder from '../client/static/avatar-placeholder.png';
|
||||
-import daBoiAvatar from '../client/static/da-boi.webp';
|
||||
-import avatarPlaceholder from '../client/static/avatar-placeholder.webp';
|
||||
+import { DocsUrl, BlogUrl, GithubUrl } from '../shared/common';
|
||||
|
||||
export const landingPageNavigationItems: NavigationItem[] = [
|
||||
|
@ -1,13 +1,15 @@
|
||||
--- template/app/tailwind.config.cjs
|
||||
+++ opensaas-sh/app/tailwind.config.cjs
|
||||
@@ -8,6 +8,7 @@
|
||||
@@ -8,7 +8,8 @@
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
- satoshi: ['Satoshi', 'system-ui', 'sans-serif'],
|
||||
+ sans: ['ui-monospace', 'Liberation Mono', 'Menlo', 'monospace'],
|
||||
satoshi: ['Satoshi', 'sans-serif'],
|
||||
+ satoshi: ['Satoshi', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
current: 'currentColor',
|
||||
@@ -246,6 +247,9 @@
|
||||
'spin-2': 'spin 2s linear infinite',
|
||||
'spin-3': 'spin 3s linear infinite',
|
||||
|
@ -14,7 +14,7 @@ export default defineConfig({
|
||||
description: 'Open SaaS is a free, open-source, full-stack SaaS starter kit for React + NodeJS.',
|
||||
customCss: ['./src/styles/tailwind.css'],
|
||||
logo: {
|
||||
src: '/src/assets/logo.png',
|
||||
src: '/src/assets/logo.webp',
|
||||
alt: 'Open SaaS',
|
||||
},
|
||||
head: [
|
||||
|
Before Width: | Height: | Size: 24 KiB |
BIN
opensaas-sh/blog/src/assets/logo.webp
Normal file
After Width: | Height: | Size: 13 KiB |
@ -5,15 +5,25 @@ banner:
|
||||
🆕 Open SaaS is now running on <b><a href='https://wasp-lang.dev'>Wasp v0.15</a></b>! <br/>⚙️<br/>If you're running an older version and would like to upgrade, please follow the <a href="https://wasp-lang.dev/docs/migration-guides/migrate-from-0-14-to-0-15">migration instructions.</a>
|
||||
---
|
||||
|
||||
Because this SaaS app is a React/NodeJS/Postgres app built on top of [Wasp](https://wasp-lang.dev), we will direct you to the [Wasp Deployment Guide](https://wasp-lang.dev/docs/advanced/deployment/overview/) for more detailed instructions, except for where the instructions are specific to this template.
|
||||
Because this SaaS app is a React/NodeJS/Postgres app built on top of [Wasp](https://wasp-lang.dev), Open SaaS can take advantage of Wasp's easy, one-command deploy to Fly.io or manual deploy to any provider of your choice.
|
||||
|
||||
The simplest and quickest option is to take advantage of Wasp's one-command deploy to [Fly.io](#deploying-to-flyio) (`wasp deploy`).
|
||||
The simplest and quickest option is to take advantage of Wasp's one-command deploy to Fly.io.
|
||||
|
||||
Or if you prefer to deploy to a different provider, or your frontend and backend separately, you can follow the [Deploying Manually](#deploying-manually--to-other-providers) section below.
|
||||
|
||||
If you're looking to deploy your Astro Blog, you can follow the [Deploying your Blog](#deploying-your-blog) section at the end of this guide.
|
||||
Or if you prefer to deploy to a different provider, or your frontend and backend separately, you can follow the Deploying Manually section below.
|
||||
|
||||
## Deploying your App
|
||||
### Steps for Deploying
|
||||
|
||||
These are the steps necessary for you to deploy your app. We recommend you follow these steps in order.
|
||||
|
||||
- [ ] Get your [production API keys and environment variables](#prerequisites)
|
||||
- [ ] Deploy your app easily to [Fly.io](#deploying-to-flyio) or [manually](#deploying-manually--to-other-providers) to any provider.
|
||||
- [ ] Add the correct [redirect URL's to your social auth credentials](#adding-server-redirect-urls-to-social-auth)
|
||||
- [ ] Set up your [production webhooks for either [Stripe](#setting-up-your-production-stripe-webhook) or [Lemon Squeezy](#setting-up-your-production-lemon-squeezy-webhook)
|
||||
- [ ] Set your [production environment variables](#other-vars) on your deployed apps
|
||||
- [ ] (Optional) [Deploy your blog](#deploying-your-blog)
|
||||
|
||||
Each of these steps is covered in more detail below.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
@ -104,7 +114,7 @@ After deploying your server, you need to add the correct redirect URIs to the cr
|
||||
- [Google Auth](https://wasp-lang.dev/docs/auth/social-auth/google#3-creating-a-google-oauth-app:~:text=Under%20Authorized%20redirect%20URIs)
|
||||
- [Github Auth](https://wasp-lang.dev/docs/auth/social-auth/github#3-creating-a-github-oauth-app:~:text=Authorization%20callback%20URL)
|
||||
|
||||
### Setting up your Stripe Webhook
|
||||
### Setting up your Production Stripe Webhook
|
||||
|
||||
Now you need to set up your stripe webhook for production use. Below are some important steps and considerations you should take as you prepare to deploy your app to production.
|
||||
|
||||
@ -165,6 +175,23 @@ export const stripe = new Stripe(process.env.STRIPE_KEY!, {
|
||||
wasp deploy fly cmd --context server secrets set STRIPE_WEBHOOK_SECRET=whsec_...
|
||||
```
|
||||
|
||||
### Setting up your Production Lemon Squeezy Webhook
|
||||
|
||||
To set up your Lemon Squeezy webhook, you'll need the URL of you newly deployed server + `/payments-webhook`, e.g. `https://open-saas-wasp-sh-server.fly.dev/payments-webhook`.
|
||||
|
||||
With the webhook url ready, go to your [Lemon Squeezy Webhooks Dashboard](https://app.lemonsqueezy.com/settings/webhooks):
|
||||
- click the `+` button.
|
||||
- add the webhook forwarding url to the `Callback URL` section.
|
||||
- give your webhook a signing secret (a long, random string).
|
||||
- add this signing secret to your server's production environment variables under `LEMONSQUEEZY_WEBHOOK_SECRET=`
|
||||
- make sure to select at least the following updates to be sent:
|
||||
- order_created
|
||||
- subscription_created
|
||||
- subscription_updated
|
||||
- subscription_cancelled
|
||||
- click `save`
|
||||
|
||||
|
||||
## Deploying your Blog
|
||||
|
||||
Deploying your Astro Starlight blog is a bit different than deploying your SaaS app. As an example, we will show you how to deploy your blog for free to Netlify. You will need a Netlify account and [Netlify CLI](https://docs.netlify.com/cli/get-started/) installed to follow these instructions.
|
||||
|
@ -86,9 +86,9 @@ To set up your email sender, you first need an account with one of the supported
|
||||
</TabItem>
|
||||
<TabItem label="Mailgun">
|
||||
- Go to [Mailgun](https://mailgun.com) and create an account.
|
||||
- Go to [API Keys](https://app.mailgun.com/app/account/security/api_keys) and create a new API key.
|
||||
- Go to [API Keys](https://app.mailgun.com/settings/api_security/api_keys?onboardingTask=api-key) and create a new API key.
|
||||
- Copy the API key and add it to your .env.server file under the `MAILGUN_API_KEY=` variable.
|
||||
- Go to [Domains](https://app.mailgun.com/app/domains) and create a new domain.
|
||||
- Go to [Domains](https://app.mailgun.com/mg/sending/new-domain?onboardingTask=add-verify-domain) and create a new domain.
|
||||
- Copy the domain and add it to your .env.server file as `MAILGUN_DOMAIN=`.
|
||||
|
||||
Make sure to change the `defaultFrom` email address in the `main.wasp` file to use the same email address that you configured your account to send out emails with!
|
||||
@ -104,4 +104,4 @@ To set up your email sender, you first need an account with one of the supported
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
If you want more detailed info, or would like to use SMTP, check out the [Wasp docs](https://wasp-lang.dev/docs/advanced/email).
|
||||
If you want more detailed info, or would like to use SMTP, check out the [Wasp docs](https://wasp-lang.dev/docs/advanced/email).
|
||||
|
@ -22,7 +22,7 @@ app SaaSTemplate {
|
||||
"<meta property='og:url' content='https://opensaas.sh' />",
|
||||
"<meta property='og:title' content='Open SaaS' />",
|
||||
"<meta property='og:description' content='Free, open-source SaaS boilerplate starter for React & NodeJS.' />",
|
||||
"<meta property='og:image' content='https://opensaas.sh/public-banner.png' />",
|
||||
"<meta property='og:image' content='https://opensaas.sh/public-banner.webp' />",
|
||||
//...
|
||||
],
|
||||
//...
|
||||
|
@ -60,7 +60,7 @@ If you are using an older version of the OpenSaaS template with Wasp `v0.13.x` o
|
||||
.
|
||||
├── main.wasp # Wasp Config file. You define your app structure here.
|
||||
├── .wasp/ # Output dir for Wasp. DON'T MODIFY THESE FILES!
|
||||
├── public/ # Public assets dir, e.g. www.yourdomain.com/banner.png
|
||||
├── public/ # Public assets dir, e.g. www.yourdomain.com/public-banner.webp
|
||||
├── src/ # Your code goes here.
|
||||
│ ├── admin/ # Admin dashboard related pages and components.
|
||||
│ ├── analytics/ # Logic and background jobs for processing analytics.
|
||||
@ -320,11 +320,11 @@ But before you start setting up the main features, let's walk through the custom
|
||||
|
||||
#### Customizing the Look / Style of the App
|
||||
- [ ] Update your favicon at `public/favicon.ico`.
|
||||
- [ ] Update the banner image used when posting links to your site at `public/public-banner.png`.
|
||||
- [ ] Update the banner image used when posting links to your site at `public/public-banner.webp`.
|
||||
- [ ] Update the URL for this banner at `og:image` and `twitter:image` in `app.head` of the `main.wasp` file.
|
||||
- [ ] Make changes to your landing page, `landingPage.tsx`.
|
||||
- [ ] Customize the `navBar`, `features`, `testimonials`, and `faqs` in the `contentSections.ts` file.
|
||||
- [ ] Change/rename the `logo.png` and main banner (`open-saas-banner.png`) in the `static` folder.
|
||||
- [ ] Change/rename the `logo.webp` and main hero banner (`open-saas-banner.webp`) in the `static` folder.
|
||||
- [ ] If you want to make changes to the global styles of the app, you can do so in `tailwind.config.cjs`. **Be aware that the current custom global styles defined already are mostly used in the app's Admin Dashboard!**
|
||||
|
||||
#### Customizing the Analytics & Admin Dashboard
|
||||
|
@ -6,21 +6,27 @@ app OpenSaaS {
|
||||
title: "My Open SaaS App",
|
||||
|
||||
head: [
|
||||
"<meta property='og:type' content='website' />",
|
||||
"<meta property='og:title' content='My Open SaaS App' />",
|
||||
"<meta property='og:url' content='https://opensaas.sh' />",
|
||||
"<meta property='og:description' content='I made a SaaS App. Buy my stuff.' />",
|
||||
"<meta property='og:image' content='https://opensaas.sh/public-banner.png' />",
|
||||
"<meta name='twitter:image' content='https://opensaas.sh/public-banner.png' />",
|
||||
"<meta name='twitter:image:width' content='800' />",
|
||||
"<meta name='twitter:image:height' content='400' />",
|
||||
"<meta name='twitter:card' content='summary_large_image' />",
|
||||
// TODO: You can put your Plausible analytics scripts below (https://docs.opensaas.sh/guides/analytics/):
|
||||
// NOTE: Plausible does not use Cookies, so you can simply add the scripts here.
|
||||
// Google, on the other hand, does, so you must instead add the script dynamically
|
||||
// via the Cookie Consent component after the user clicks the "Accept" cookies button.
|
||||
"<script defer data-domain='<your-site-id>' src='https://plausible.io/js/script.js'></script>", // for production
|
||||
"<script defer data-domain='<your-site-id>' src='https://plausible.io/js/script.local.js'></script>", // for development
|
||||
"<meta charset='utf-8' />",
|
||||
"<meta name='description' content='Your apps main description and features.' />",
|
||||
"<meta name='author' content='Your (App) Name' />",
|
||||
"<meta name='keywords' content='saas, solution, product, app, service' />",
|
||||
|
||||
"<meta property='og:type' content='website' />",
|
||||
"<meta property='og:title' content='Your Open SaaS App' />",
|
||||
"<meta property='og:site_name' content='Your Open SaaS App' />",
|
||||
"<meta property='og:url' content='https://your-saas-app.com' />",
|
||||
"<meta property='og:description' content='Your apps main description and features.' />",
|
||||
"<meta property='og:image' content='https://your-saas-app.com/public-banner.webp' />",
|
||||
"<meta name='twitter:image' content='https://your-saas-app.com/public-banner.webp' />",
|
||||
"<meta name='twitter:image:width' content='800' />",
|
||||
"<meta name='twitter:image:height' content='400' />",
|
||||
"<meta name='twitter:card' content='summary_large_image' />",
|
||||
// TODO: You can put your Plausible analytics scripts below (https://docs.opensaas.sh/guides/analytics/):
|
||||
// NOTE: Plausible does not use Cookies, so you can simply add the scripts here.
|
||||
// Google, on the other hand, does, so you must instead add the script dynamically
|
||||
// via the Cookie Consent component after the user clicks the "Accept" cookies button.
|
||||
"<script defer data-domain='<your-site-id>' src='https://plausible.io/js/script.js'></script>", // for production
|
||||
"<script defer data-domain='<your-site-id>' src='https://plausible.io/js/script.local.js'></script>", // for development
|
||||
],
|
||||
|
||||
// 🔐 Auth out of the box! https://wasp-lang.dev/docs/auth/overview
|
||||
|
Before Width: | Height: | Size: 840 KiB |
Before Width: | Height: | Size: 246 KiB |
BIN
template/app/public/public-banner.webp
Normal file
After Width: | Height: | Size: 145 KiB |
@ -5,7 +5,7 @@ import TotalPageViewsCard from './TotalPageViewsCard';
|
||||
import TotalPayingUsersCard from './TotalPayingUsersCard';
|
||||
import TotalRevenueCard from './TotalRevenueCard';
|
||||
import RevenueAndProfitChart from './RevenueAndProfitChart';
|
||||
import SourcesTable from './PageViewSourcesTable';
|
||||
import SourcesTable from './SourcesTable';
|
||||
import DefaultLayout from '../../layout/DefaultLayout';
|
||||
import { useRedirectHomeUnlessUserIsAdmin } from '../../useRedirectHomeUnlessUserIsAdmin'
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { type PageViewSource } from 'wasp/entities';
|
||||
|
||||
const PageViewSourcesTable = ({ sources }: { sources: PageViewSource[] | undefined }) => {
|
||||
const SourcesTable = ({ sources }: { sources: PageViewSource[] | undefined }) => {
|
||||
return (
|
||||
<div className='rounded-sm border border-stroke bg-white px-5 pt-6 pb-2.5 shadow-default dark:border-strokedark dark:bg-boxdark sm:px-7.5 xl:pb-1'>
|
||||
<h4 className='mb-6 text-xl font-semibold text-black dark:text-white'>Top Sources</h4>
|
||||
@ -44,4 +44,4 @@ const PageViewSourcesTable = ({ sources }: { sources: PageViewSource[] | undefin
|
||||
);
|
||||
};
|
||||
|
||||
export default PageViewSourcesTable;
|
||||
export default SourcesTable;
|
@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { NavLink, useLocation } from 'react-router-dom';
|
||||
import Logo from '../../client/static/logo.png';
|
||||
import Logo from '../../client/static/logo.webp';
|
||||
import SidebarLinkGroup from './SidebarLinkGroup';
|
||||
import { cn } from '../../client/cn';
|
||||
|
||||
|
@ -21,7 +21,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Here is an example of how to add a custom font.
|
||||
* Fonts are stored in the public/fonts folder.
|
||||
* They are defined first here, then need to be referenced in the tailwind.config.js file
|
||||
* under `theme.extend.fontFamily`, and then can be used as a tailwind class, e.g. className='font-satoshi'.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Satoshi';
|
||||
src: url('/fonts/Satoshi-Regular.woff2') format('woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* third-party libraries CSS */
|
||||
|
||||
|
@ -6,7 +6,7 @@ import { Dialog } from '@headlessui/react';
|
||||
import { BiLogIn } from 'react-icons/bi';
|
||||
import { AiFillCloseCircle } from 'react-icons/ai';
|
||||
import { HiBars3 } from 'react-icons/hi2';
|
||||
import logo from '../../static/logo.png';
|
||||
import logo from '../static/logo.webp';
|
||||
import DropdownUser from '../../../user/DropdownUser';
|
||||
import { UserMenuItems } from '../../../user/UserMenuItems';
|
||||
import DarkModeSwitcher from '../DarkModeSwitcher';
|
||||
|
Before Width: | Height: | Size: 9.2 KiB |
BIN
template/app/src/client/static/avatar-placeholder.webp
Normal file
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 178 KiB |
BIN
template/app/src/client/static/da-boi.webp
Normal file
After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 24 KiB |
BIN
template/app/src/client/static/logo.webp
Normal file
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 840 KiB |
BIN
template/app/src/client/static/open-saas-banner.webp
Normal file
After Width: | Height: | Size: 145 KiB |
@ -1,31 +1,11 @@
|
||||
import openSaasBanner from '../../client/static/open-saas-banner.png';
|
||||
import openSaasBannerWebp from '../../client/static/open-saas-banner.webp';
|
||||
import { DocsUrl } from '../../shared/common';
|
||||
|
||||
export default function Hero() {
|
||||
return (
|
||||
<div className='relative pt-14 w-full '>
|
||||
<div
|
||||
className='absolute top-0 right-0 -z-10 transform-gpu overflow-hidden w-full blur-3xl sm:top-0 '
|
||||
aria-hidden='true'
|
||||
>
|
||||
<div
|
||||
className='aspect-[1020/880] w-[55rem] flex-none sm:right-1/4 sm:translate-x-1/2 dark:hidden bg-gradient-to-tr from-amber-400 to-purple-300 opacity-40'
|
||||
style={{
|
||||
clipPath: 'polygon(80% 20%, 90% 55%, 50% 100%, 70% 30%, 20% 50%, 50% 0)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className='absolute inset-x-0 top-[calc(100%-40rem)] sm:top-[calc(100%-65rem)] -z-10 transform-gpu overflow-hidden blur-3xl'
|
||||
aria-hidden='true'
|
||||
>
|
||||
<div
|
||||
className='relative aspect-[1020/880] sm:-left-3/4 sm:translate-x-1/4 dark:hidden bg-gradient-to-br from-amber-400 to-purple-300 opacity-50 w-[72.1875rem]'
|
||||
style={{
|
||||
clipPath: 'ellipse(80% 30% at 80% 50%)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='relative pt-14 w-full'>
|
||||
<TopGradient />
|
||||
<BottomGradient />
|
||||
<div className='py-24 sm:py-32'>
|
||||
<div className='mx-auto max-w-8xl px-6 lg:px-8'>
|
||||
<div className='lg:mb-18 mx-auto max-w-3xl text-center'>
|
||||
@ -44,13 +24,14 @@ export default function Hero() {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className='mt-14 flow-root sm:mt-14 '>
|
||||
<div className='-m-2 rounded-xl lg:-m-4 lg:rounded-2xl lg:p-4'>
|
||||
<div className='mt-14 flow-root sm:mt-14'>
|
||||
<div className='-m-2 flex justify-center rounded-xl lg:-m-4 lg:rounded-2xl lg:p-4'>
|
||||
<img
|
||||
src={openSaasBanner}
|
||||
src={openSaasBannerWebp}
|
||||
alt='App screenshot'
|
||||
width={2432}
|
||||
height={1442}
|
||||
width={1000}
|
||||
height={530}
|
||||
loading='lazy'
|
||||
className='rounded-md shadow-2xl ring-1 ring-gray-900/10'
|
||||
/>
|
||||
</div>
|
||||
@ -58,5 +39,37 @@ export default function Hero() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function TopGradient() {
|
||||
return (
|
||||
<div
|
||||
className='absolute top-0 right-0 -z-10 transform-gpu overflow-hidden w-full blur-3xl sm:top-0'
|
||||
aria-hidden='true'
|
||||
>
|
||||
<div
|
||||
className='aspect-[1020/880] w-[55rem] flex-none sm:right-1/4 sm:translate-x-1/2 dark:hidden bg-gradient-to-tr from-amber-400 to-purple-300 opacity-40'
|
||||
style={{
|
||||
clipPath: 'polygon(80% 20%, 90% 55%, 50% 100%, 70% 30%, 20% 50%, 50% 0)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function BottomGradient() {
|
||||
return (
|
||||
<div
|
||||
className='absolute inset-x-0 top-[calc(100%-40rem)] sm:top-[calc(100%-65rem)] -z-10 transform-gpu overflow-hidden blur-3xl'
|
||||
aria-hidden='true'
|
||||
>
|
||||
<div
|
||||
className='relative aspect-[1020/880] sm:-left-3/4 sm:translate-x-1/4 dark:hidden bg-gradient-to-br from-amber-400 to-purple-300 opacity-50 w-[72.1875rem]'
|
||||
style={{
|
||||
clipPath: 'ellipse(80% 30% at 80% 50%)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -22,7 +22,7 @@ export default function Testimonials({ testimonials }: { testimonials: Testimoni
|
||||
</blockquote>
|
||||
<figcaption className='mt-6 text-base text-white'>
|
||||
<a href={testimonial.socialUrl} className='flex items-center gap-x-2'>
|
||||
<img src={testimonial.avatarSrc} className='h-12 w-12 rounded-full' />
|
||||
<img src={testimonial.avatarSrc} loading='lazy' className='h-12 w-12 rounded-full' />
|
||||
<div>
|
||||
<div className='font-semibold hover:underline'>{testimonial.name}</div>
|
||||
<div className='mt-1'>{testimonial.role}</div>
|
||||
|
@ -1,8 +1,8 @@
|
||||
import type { NavigationItem } from '../client/components/NavBar/NavBar';
|
||||
import { routes } from 'wasp/client/router';
|
||||
import { DocsUrl, BlogUrl } from '../shared/common';
|
||||
import daBoiAvatar from '../client/static/da-boi.png';
|
||||
import avatarPlaceholder from '../client/static/avatar-placeholder.png';
|
||||
import daBoiAvatar from '../client/static/da-boi.webp';
|
||||
import avatarPlaceholder from '../client/static/avatar-placeholder.webp';
|
||||
|
||||
export const landingPageNavigationItems: NavigationItem[] = [
|
||||
{ name: 'Features', to: '#features' },
|
||||
|
@ -8,7 +8,7 @@ module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
satoshi: ['Satoshi', 'sans-serif'],
|
||||
satoshi: ['Satoshi', 'system-ui', 'sans-serif'],
|
||||
},
|
||||
colors: {
|
||||
current: 'currentColor',
|
||||
|
@ -14,7 +14,7 @@ export default defineConfig({
|
||||
customCss: ['./src/styles/tailwind.css'],
|
||||
description: 'Documentation for your SaaS.',
|
||||
logo: {
|
||||
src: '/src/assets/logo.png',
|
||||
src: '/src/assets/logo.webp',
|
||||
alt: 'Your SaaS',
|
||||
},
|
||||
head: [
|
||||
|