mirror of
https://github.com/wasp-lang/open-saas.git
synced 2025-06-07 13:39:57 +02:00
Extended Dark mode for landing page and user-facing app (#10)
* Extended Dark mode for landing page and user-facing app * Update LandingPage.tsx * Fixed issues with dark mode * Landing Page changes based on comments * removed migrations --------- Co-authored-by: vincanger <70215737+vincanger@users.noreply.github.com>
This commit is contained in:
parent
b2f8fb481f
commit
3d12c73c02
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
|||||||
*/.env.client
|
*/.env.client
|
||||||
*/.DS_Store
|
*/.DS_Store
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
*/migrations
|
@ -43,14 +43,16 @@ export default function App({ children }: { children: ReactNode }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className='min-h-screen dark:text-white dark:bg-boxdark-2'>
|
||||||
{isAdminDashboard ? (
|
{isAdminDashboard ? (
|
||||||
<>{children}</>
|
<>{children}</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{shouldDisplayAppNavBar && <AppNavBar />}
|
{shouldDisplayAppNavBar && <AppNavBar />}
|
||||||
<div className='mx-auto max-w-7xl sm:px-6 lg:px-8 '>{children}</div>
|
<div className='mx-auto max-w-7xl sm:px-6 lg:px-8'>{children}</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -34,20 +34,20 @@ export default function GptPage() {
|
|||||||
} = useForm();
|
} = useForm();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='my-10 lg:mt-20'>
|
<div className='my-10 lg:mt-20 dark:bg-boxdark-2'>
|
||||||
<div className='mx-auto max-w-7xl px-6 lg:px-8'>
|
<div className='mx-auto max-w-7xl px-6 lg:px-8 dark:bg-boxdark'>
|
||||||
<div id='pricing' className='mx-auto max-w-4xl text-center'>
|
<div id='pricing' className='mx-auto max-w-4xl text-center'>
|
||||||
<h2 className='mt-2 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl'>
|
<h2 className='mt-2 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl dark:text-white'>
|
||||||
Create your AI-powered <span className='text-yellow-500'>SaaS</span>
|
Create your AI-powered <span className='text-yellow-500'>SaaS</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p className='mx-auto mt-6 max-w-2xl text-center text-lg leading-8 text-gray-600'>
|
<p className='mx-auto mt-6 max-w-2xl text-center text-lg leading-8 text-gray-600 dark:text-white'>
|
||||||
Below is an example of integrating the OpenAI API into your SaaS.
|
Below is an example of integrating the OpenAI API into your SaaS.
|
||||||
</p>
|
</p>
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className='py-8 mt-10 sm:mt-20 ring-1 ring-gray-200 rounded-lg'>
|
<form onSubmit={handleSubmit(onSubmit)} className='py-8 mt-10 sm:mt-20 ring-1 ring-gray-200 rounded-lg'>
|
||||||
<div className='space-y-6 sm:w-[90%] md:w-[60%] mx-auto border-b border-gray-900/10 px-6 pb-12'>
|
<div className='space-y-6 sm:w-[90%] md:w-[60%] mx-auto border-b border-gray-900/10 px-6 pb-12'>
|
||||||
<div className='col-span-full'>
|
<div className='col-span-full'>
|
||||||
<label htmlFor='instructions' className='block text-sm font-medium leading-6 text-gray-900'>
|
<label htmlFor='instructions' className='block text-sm font-medium leading-6 text-gray-900 dark:text-white'>
|
||||||
Instructions -- How should GPT behave?
|
Instructions -- How should GPT behave?
|
||||||
</label>
|
</label>
|
||||||
<div className='mt-2'>
|
<div className='mt-2'>
|
||||||
@ -71,7 +71,7 @@ export default function GptPage() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className='col-span-full'>
|
<div className='col-span-full'>
|
||||||
<label htmlFor='command' className='block text-sm font-medium leading-6 text-gray-900'>
|
<label htmlFor='command' className='block text-sm font-medium leading-6 text-gray-900 dark:text-white'>
|
||||||
Command -- What should GPT do?
|
Command -- What should GPT do?
|
||||||
</label>
|
</label>
|
||||||
<div className='mt-2'>
|
<div className='mt-2'>
|
||||||
@ -95,8 +95,8 @@ export default function GptPage() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='h-10 '>
|
<div className='h-10'>
|
||||||
<label htmlFor='temperature' className='w-full text-gray-700 text-sm font-semibold'>
|
<label htmlFor='temperature' className='w-full text-gray-700 text-sm font-semibold dark:text-white'>
|
||||||
Temperature Input -- Controls How Random GPT's Output is
|
Temperature Input -- Controls How Random GPT's Output is
|
||||||
</label>
|
</label>
|
||||||
<div className='w-32 mt-2'>
|
<div className='w-32 mt-2'>
|
||||||
@ -133,9 +133,9 @@ export default function GptPage() {
|
|||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
isSubmitting && 'animate-pulse'
|
isSubmitting && 'animate-pulse'
|
||||||
} mt-4 mx-6 flex justify-center rounded-lg border border-dashed border-gray-900/25 sm:w-[90%] md:w-[50%] mx-auto mt-12 px-6 py-10`}
|
} mt-4 mx-6 flex justify-center rounded-lg border border-dashed border-gray-900/25 dark:border-white sm:w-[90%] md:w-[50%] mx-auto mt-12 px-6 py-10`}
|
||||||
>
|
>
|
||||||
<div className='space-y-2 flex flex-col gap-2 text-center text-sm text-gray-500 w-full'>
|
<div className='space-y-2 flex flex-col gap-2 text-center text-sm text-gray-500 w-full dark:text-white'>
|
||||||
{response.length > 0 ? response.map((str) => <p key={str}>{str}</p>) : <p>GPT Response will load here</p>}
|
{response.length > 0 ? response.map((str) => <p key={str}>{str}</p>) : <p>GPT Response will load here</p>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -57,14 +57,14 @@ const PricingPage = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='my-10 lg:mt-20'>
|
<div className='py-10 lg:mt-10'>
|
||||||
<div className='mx-auto max-w-7xl px-6 lg:px-8'>
|
<div className='mx-auto max-w-7xl px-6 lg:px-8'>
|
||||||
<div id='pricing' className='mx-auto max-w-4xl text-center'>
|
<div id='pricing' className='mx-auto max-w-4xl text-center'>
|
||||||
<h2 className='mt-2 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl'>
|
<h2 className='mt-2 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl dark:text-white'>
|
||||||
Pick your <span className='text-yellow-500'>pricing</span>
|
Pick your <span className='text-yellow-500'>pricing</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p className='mx-auto mt-6 max-w-2xl text-center text-lg leading-8 text-gray-600'>
|
<p className='mx-auto mt-6 max-w-2xl text-center text-lg leading-8 text-gray-600 dark:text-white'>
|
||||||
Stripe subscriptions and secure webhooks are built-in. Just add your Stripe Product IDs! Try it out below with
|
Stripe subscriptions and secure webhooks are built-in. Just add your Stripe Product IDs! Try it out below with
|
||||||
test credit card number{' '}
|
test credit card number{' '}
|
||||||
<span className='px-2 py-1 bg-gray-100 rounded-md text-gray-500'>4242 4242 4242 4242 4242</span>
|
<span className='px-2 py-1 bg-gray-100 rounded-md text-gray-500'>4242 4242 4242 4242 4242</span>
|
||||||
@ -80,7 +80,7 @@ const PricingPage = () => {
|
|||||||
{tier.bestDeal && (
|
{tier.bestDeal && (
|
||||||
<div className='absolute top-0 right-0 -z-10 w-full h-full transform-gpu blur-3xl' aria-hidden='true'>
|
<div className='absolute top-0 right-0 -z-10 w-full h-full transform-gpu blur-3xl' aria-hidden='true'>
|
||||||
<div
|
<div
|
||||||
className='absolute w-full h-full bg-gradient-to-br from-amber-400 to-purple-300 opacity-30'
|
className='absolute w-full h-full bg-gradient-to-br from-amber-400 to-purple-300 opacity-30 dark:opacity-50'
|
||||||
style={{
|
style={{
|
||||||
clipPath: 'circle(670% at 50% 50%)',
|
clipPath: 'circle(670% at 50% 50%)',
|
||||||
}}
|
}}
|
||||||
@ -89,16 +89,16 @@ const PricingPage = () => {
|
|||||||
)}
|
)}
|
||||||
<div className='mb-8'>
|
<div className='mb-8'>
|
||||||
<div className='flex items-center justify-between gap-x-4'>
|
<div className='flex items-center justify-between gap-x-4'>
|
||||||
<h3 id={tier.id} className='text-gray-900 text-lg font-semibold leading-8'>
|
<h3 id={tier.id} className='text-gray-900 text-lg font-semibold leading-8 dark:text-white'>
|
||||||
{tier.name}
|
{tier.name}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<p className='mt-4 text-sm leading-6 text-gray-600'>{tier.description}</p>
|
<p className='mt-4 text-sm leading-6 text-gray-600 dark:text-white'>{tier.description}</p>
|
||||||
<p className='mt-6 flex items-baseline gap-x-1'>
|
<p className='mt-6 flex items-baseline gap-x-1 dark:text-white'>
|
||||||
<span className='text-4xl font-bold tracking-tight text-gray-900'>{tier.priceMonthly}</span>
|
<span className='text-4xl font-bold tracking-tight text-gray-900 dark:text-white'>{tier.priceMonthly}</span>
|
||||||
<span className='text-sm font-semibold leading-6 text-gray-600'>/month</span>
|
<span className='text-sm font-semibold leading-6 text-gray-600 dark:text-white'>/month</span>
|
||||||
</p>
|
</p>
|
||||||
<ul role='list' className='mt-8 space-y-3 text-sm leading-6 text-gray-600'>
|
<ul role='list' className='mt-8 space-y-3 text-sm leading-6 text-gray-600 dark:text-white'>
|
||||||
{tier.features.map((feature) => (
|
{tier.features.map((feature) => (
|
||||||
<li key={feature} className='flex gap-x-3'>
|
<li key={feature} className='flex gap-x-3'>
|
||||||
<AiFillCheckCircle className='h-6 w-5 flex-none text-yellow-500' aria-hidden='true' />
|
<AiFillCheckCircle className='h-6 w-5 flex-none text-yellow-500' aria-hidden='true' />
|
||||||
@ -127,7 +127,7 @@ const PricingPage = () => {
|
|||||||
<button
|
<button
|
||||||
onClick={() => handleBuyNowClick(tier.id)}
|
onClick={() => handleBuyNowClick(tier.id)}
|
||||||
aria-describedby={tier.id}
|
aria-describedby={tier.id}
|
||||||
className={`
|
className={`dark:text-white
|
||||||
${tier.id === 'enterprise-tier' ? 'opacity-50 cursor-not-allowed' : 'opacity-100 cursor-pointer'}
|
${tier.id === 'enterprise-tier' ? 'opacity-50 cursor-not-allowed' : 'opacity-100 cursor-pointer'}
|
||||||
${
|
${
|
||||||
tier.bestDeal
|
tier.bestDeal
|
||||||
|
@ -20,7 +20,7 @@ export default function Login() {
|
|||||||
<AuthWrapper>
|
<AuthWrapper>
|
||||||
<LoginForm />
|
<LoginForm />
|
||||||
<br />
|
<br />
|
||||||
<span className='text-sm font-medium text-gray-900'>
|
<span className='text-sm font-medium text-gray-900 dark:text-gray-900'>
|
||||||
Don't have an account yet?{' '}
|
Don't have an account yet?{' '}
|
||||||
<Link to='/signup' className='underline'>
|
<Link to='/signup' className='underline'>
|
||||||
go to signup
|
go to signup
|
||||||
|
@ -2,9 +2,9 @@ import { ReactNode } from 'react';
|
|||||||
|
|
||||||
export function AuthWrapper({children} : {children: ReactNode }) {
|
export function AuthWrapper({children} : {children: ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<div className='flex min-h-full flex-col justify-center mt-10 sm:px-6 lg:px-8'>
|
<div className='flex min-h-full flex-col justify-center pt-10 sm:px-6 lg:px-8'>
|
||||||
<div className='sm:mx-auto sm:w-full sm:max-w-md'>
|
<div className='sm:mx-auto sm:w-full sm:max-w-md'>
|
||||||
<div className='bg-white py-8 px-4 shadow-xl ring-1 ring-gray-900/10 sm:rounded-lg sm:px-10'>
|
<div className='bg-white py-8 px-4 shadow-xl ring-1 ring-gray-900/10 sm:rounded-lg sm:px-10 dark:bg-white dark:text-gray-900'>
|
||||||
<div className='-mt-8'>
|
<div className='-mt-8'>
|
||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,6 +5,7 @@ import useAuth from '@wasp/auth/useAuth';
|
|||||||
import logo from '../static/logo.png';
|
import logo from '../static/logo.png';
|
||||||
import DropdownUser from './DropdownUser';
|
import DropdownUser from './DropdownUser';
|
||||||
import { DOCS_URL, BLOG_URL } from '@wasp/shared/constants';
|
import { DOCS_URL, BLOG_URL } from '@wasp/shared/constants';
|
||||||
|
import DarkModeSwitcher from '../admin/components/DarkModeSwitcher';
|
||||||
|
|
||||||
const navigation = [
|
const navigation = [
|
||||||
{ name: 'GPT Wrapper', href: '/gpt' },
|
{ name: 'GPT Wrapper', href: '/gpt' },
|
||||||
@ -18,7 +19,7 @@ export default function AppNavBar() {
|
|||||||
|
|
||||||
const { data: user, isLoading: isUserLoading } = useAuth();
|
const { data: user, isLoading: isUserLoading } = useAuth();
|
||||||
return (
|
return (
|
||||||
<header className='absolute inset-x-0 top-0 z-50 shadow sticky bg-white bg-opacity-50 backdrop-blur-lg backdrop-filter'>
|
<header className='absolute inset-x-0 top-0 z-50 shadow sticky bg-white bg-opacity-50 backdrop-blur-lg backdrop-filter dark:border-strokedark dark:bg-boxdark-2'>
|
||||||
<nav className='flex items-center justify-between p-6 lg:px-8' aria-label='Global'>
|
<nav className='flex items-center justify-between p-6 lg:px-8' aria-label='Global'>
|
||||||
<div className='flex lg:flex-1'>
|
<div className='flex lg:flex-1'>
|
||||||
<a href='/' className='-m-1.5 p-1.5'>
|
<a href='/' className='-m-1.5 p-1.5'>
|
||||||
@ -40,24 +41,32 @@ export default function AppNavBar() {
|
|||||||
<a
|
<a
|
||||||
key={item.name}
|
key={item.name}
|
||||||
href={item.href}
|
href={item.href}
|
||||||
className='text-sm font-semibold leading-6 text-gray-900 duration-300 ease-in-out hover:text-yellow-500'
|
className='text-sm font-semibold leading-6 text-gray-900 duration-300 ease-in-out hover:text-yellow-500 dark:text-white'
|
||||||
>
|
>
|
||||||
{item.name}
|
{item.name}
|
||||||
</a>
|
</a>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className='hidden lg:flex lg:flex-1 lg:justify-end lg:align-end'>
|
<div className='hidden lg:flex lg:flex-1 lg:justify-end items-center'>
|
||||||
|
<div className='flex items-center gap-3 2xsm:gap-7'>
|
||||||
|
<ul className='flex justify-center items-center gap-2 2xsm:gap-4'>
|
||||||
|
<DarkModeSwitcher />
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
{isUserLoading ? null : !user ? (
|
{isUserLoading ? null : !user ? (
|
||||||
<a href={!user ? '/login' : '/account'} className='text-sm font-semibold leading-6 '>
|
<a href={!user ? '/login' : '/account'} className='text-sm font-semibold leading-6 ml-4'>
|
||||||
<div className='flex justify-end items-center duration-300 ease-in-out text-gray-900 hover:text-yellow-500'>
|
<div className='flex items-center duration-300 ease-in-out text-gray-900 hover:text-yellow-500 dark:text-white'>
|
||||||
Log in <BiLogIn size='1.1rem' className='ml-1 mt-[0.1rem]' />
|
Log in <BiLogIn size='1.1rem' className='ml-1 mt-[0.1rem]' />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
<DropdownUser user={user} />
|
<div className='ml-4'>
|
||||||
|
<DropdownUser user={user} />
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -43,9 +43,9 @@ const DropdownUser = ({ user } : { user: Partial<User> }) => {
|
|||||||
<span className='hidden text-right lg:block'>
|
<span className='hidden text-right lg:block'>
|
||||||
<span className='block text-sm font-medium dark:text-white'>{user.username}</span>
|
<span className='block text-sm font-medium dark:text-white'>{user.username}</span>
|
||||||
</span>
|
</span>
|
||||||
<CgProfile size='1.1rem' className='ml-1 mt-[0.1rem]' />
|
<CgProfile size='1.1rem' className='ml-1 mt-[0.1rem] dark:text-white' />
|
||||||
<svg
|
<svg
|
||||||
className={`hidden fill-current sm:block ${dropdownOpen ? 'rotate-180' : ''}`}
|
className={`hidden fill-current dark:fill-white sm:block ${dropdownOpen ? 'rotate-180' : ''}`}
|
||||||
width='12'
|
width='12'
|
||||||
height='8'
|
height='8'
|
||||||
viewBox='0 0 12 8'
|
viewBox='0 0 12 8'
|
||||||
@ -64,7 +64,7 @@ const DropdownUser = ({ user } : { user: Partial<User> }) => {
|
|||||||
{/* <!-- Dropdown --> */}
|
{/* <!-- Dropdown --> */}
|
||||||
<div
|
<div
|
||||||
ref={dropdown}
|
ref={dropdown}
|
||||||
className={`absolute right-0 mt-4 flex w-62.5 flex-col rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark ${
|
className={`absolute right-0 mt-4 flex w-62.5 flex-col rounded-sm border border-stroke bg-white shadow-default dark:border-strokedark dark:bg-boxdark dark:text-white ${
|
||||||
dropdownOpen === true ? 'block' : 'hidden'
|
dropdownOpen === true ? 'block' : 'hidden'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user