Refactored the project now that there is a plan!

This commit is contained in:
2023-03-17 23:36:07 -05:00
parent 6c45d5cbea
commit be9fb61471
32 changed files with 447 additions and 411 deletions

View File

@@ -6,12 +6,12 @@
# When adding additional env variables, the schema in /env/schema.mjs should be updated accordingly
# Prisma
DATABASE_URL=file:./db.sqlite
DATABASE_URL="postgresql://postgres:{YOUR_PASSWORD}@localhost:5432/postgres"
# Next Auth
# You can generate the secret via 'openssl rand -base64 32' on Linux
# More info: https://next-auth.js.org/configuration/options#secret
# NEXTAUTH_SECRET=
NEXTAUTH_SECRET=
NEXTAUTH_URL=http://localhost:3000
# Next Auth Providers

View File

@@ -1,60 +1,60 @@
generator client {
provider = "prisma-client-js"
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
provider = "postgresql"
url = env("DATABASE_URL")
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
@@unique([identifier, token])
}
model Project {
id String @id
title String
isComplete Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime
id String @id
title String
isComplete Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime
}

View File

@@ -1,6 +1,6 @@
import { typo } from "@styles/typography";
import type { VariantProps } from "class-variance-authority";
import { cx, cva } from "class-variance-authority";
import Text, { text } from "@components/Text";
const button = cva(
[
@@ -13,8 +13,8 @@ const button = cva(
{
variants: {
size: {
default: "px-14 py-3",
small: "px-10 py-2",
default: cx(typo({ size: "2xl" }), "px-14 py-3"),
small: cx(typo({ size: "lg" }), "px-10 py-2"),
},
},
}
@@ -37,14 +37,7 @@ export const Button: React.FC<
...buttonProps
}) => {
return (
<button
className={cx(
button(variant),
text({ size: variant.size === "default" ? "h4" : "h6" }),
className
)}
{...buttonProps}
>
<button className={cx(button(variant), className)} {...buttonProps}>
{children}
</button>
);
@@ -63,13 +56,8 @@ export const Anchor: React.FC<
...anchorProps
}) => {
return (
<a {...anchorProps}>
<Text
styleLike={variant.size === "default" ? "h4" : "h6"}
className={cx(button(variant), className)}
>
{children}
</Text>
<a {...anchorProps} className={cx(button(variant), className)}>
{children}
</a>
// <div className={cx(button(variant), className)}>
// <a

View File

@@ -1,4 +1,6 @@
const Divider: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
import type { Children } from "@utils/types/props";
const Divider: React.FC<Children> = ({ children }) => {
if (children === undefined)
return <div className="container my-24 h-1.5 border-y-2 border-y-fg/10" />;

12
src/components/Footer.tsx Normal file
View File

@@ -0,0 +1,12 @@
import { typo } from "@styles/typography";
import React from "react";
export const Footer: React.FC = () => {
return (
<footer className="container flex flex-row justify-center py-32">
{/* <nav> */}
<h2 className={typo({ tag: "h2" })}>Footer goes here!</h2>
{/* </nav> */}
</footer>
);
};

View File

@@ -1,8 +1,8 @@
import { useState, useEffect } from "react";
import { cva, cx } from "class-variance-authority";
import { Anchor, Button } from "@components/Button";
import Text from "@components/Text";
import { Button } from "@components/Button";
import { signIn } from "next-auth/react";
import { typo } from "@styles/typography";
const header = cva(
["fixed top-0 z-50 w-full transition-all duration-300 ease-in-out"],
@@ -16,7 +16,7 @@ const header = cva(
}
);
const HomeHeader: React.FC = () => {
export const Header: React.FC = () => {
const [isLargeBar, setIsLargeBar] = useState(true);
// Scroll Listener
@@ -36,9 +36,7 @@ const HomeHeader: React.FC = () => {
});
const FlexDivider = () => (
<Text tag="span" styleLike="h4" className="text-fg/25">
||
</Text>
<span className={cx(typo({ tag: "h4" }), "text-fg/25")}>||</span>
);
const Background = () => (
@@ -59,18 +57,19 @@ const HomeHeader: React.FC = () => {
>
<Background />
<nav className="container flex flex-row items-center justify-between gap-x-4">
<a href="#">
<Text styleLike="h4" className="min-w-max text-primary">
<span className="text-fg">||</span> Parallel
</Text>
<a
href="#"
className={cx(typo({ tag: "h4" }), "min-w-max text-primary")}
>
<span className="text-fg">||</span> Parallel
</a>
<div className="flex flex-row items-center gap-x-4 sm:gap-x-8">
<a href="#">
<Text weight="medium">About Us</Text>
<a href="#" className={cx(typo({ tag: "p" }), "font-medium")}>
About Us
</a>
<FlexDivider />
<a href="#">
<Text weight="medium">Premium</Text>
<a href="#" className={cx(typo({ tag: "p" }), "font-medium")}>
Premium
</a>
</div>
<Button variant={{ size: "small" }} onClick={() => void signIn()}>
@@ -80,5 +79,3 @@ const HomeHeader: React.FC = () => {
</header>
);
};
export default HomeHeader;

View File

@@ -1,18 +0,0 @@
import React from "react";
import { cva } from "class-variance-authority";
import { Button } from "@components/Button";
import Text from "@components/Text";
const footer = cva();
const HomeFooter: React.FC = () => {
return (
<footer className="container flex flex-row justify-center py-32">
{/* <nav> */}
<Text styleLike="h1">Footer goes here!</Text>
{/* </nav> */}
</footer>
);
};
export default HomeFooter;

View File

@@ -1,89 +0,0 @@
import React from "react";
import { cva } from "class-variance-authority";
import type { Tag, Weight } from "@utils/types/tw";
import Link from "next/link";
export const text = cva("", {
variants: {
size: {
p: "text-sm md:text-base 2xl:text-lg",
h1: "text-3xl md:text-4xl 2xl:text-5xl",
h2: "text-2xl md:text-3xl 2xl:text-4xl",
h3: "text-xl md:text-2xl 2xl:text-3xl",
h4: "text-lg md:text-xl 2xl:text-2xl",
h5: "text-base md:text-lg 2xl:text-xl",
h6: "text-sm md:text-base 2xl:text-lg",
},
weight: {
p: "font-normal",
h1: "font-bold",
h2: "font-bold",
h3: "font-bold",
h4: "font-bold",
h5: "font-semibold",
h6: "font-semibold",
thin: "font-thin",
extralight: "font-extralight",
light: "font-light",
normal: "font-normal",
medium: "font-medium",
semibold: "font-semibold",
bold: "font-bold",
extrabold: "font-extrabold",
black: "font-black",
},
},
});
interface Props {
children: React.ReactNode;
tag?: Tag | "span" | "a";
styleLike?: Tag;
href?: string;
// Override default tag styling
size?: Tag;
weight?: Weight;
className?: string;
}
const Text: React.FC<Props> = ({
children,
tag = "p",
styleLike,
href = "#",
size,
weight,
className = "",
}) => {
// Links
if (tag === "a") {
return (
<Link
href={href}
className={text({
className: className,
size: size ?? styleLike ?? "p",
weight: weight ?? styleLike ?? "p",
})}
>
{children}
</Link>
);
}
// Other tags
const styleTag: Tag = tag === "span" ? "p" : tag;
return React.createElement(
tag,
{
className: text({
className: className,
size: size ?? styleLike ?? styleTag,
weight: weight ?? styleLike ?? styleTag,
}),
},
children
);
};
export default Text;

View File

@@ -1,35 +1,35 @@
import Text from "@components/Text";
import { cva } from "class-variance-authority";
import { typo } from "@styles/typography";
import { cva, cx } from "class-variance-authority";
import type { ZodString } from "zod";
const input = cva([
typo({ tag: "p" }),
"appearance-none",
"w-full rounded border-[6px] py-2 px-3 md:py-3 md:px-4 leading-tight text-fg border-fg placeholder-fg/50 bg-fg/20",
"w-full rounded border-[6px] py-2 px-3 md:py-3 md:px-4 leading-tight border-fg placeholder-fg/50 bg-fg/20",
"focus:outline-none",
]);
interface Props {
label: string;
validator: ZodString;
validator?: ZodString;
}
const TextInput: React.FC<
export const TextInput: React.FC<
Props &
React.DetailedHTMLProps<
React.InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>
> = ({ label, validator, name, type = "text", ...inputProps }) => {
> = ({ label, name, type = "text", ...inputProps }) => {
return (
<div className="w-full">
<label htmlFor={name} className="mb-1 block text-fg">
<Text weight="bold">{label}</Text>
<label
htmlFor={name}
className={cx(typo({ size: "base" }), "mb-1 block text-fg")}
>
{label}
</label>
<Text size="h5">
<input name={name} type={type} className={input()} {...inputProps} />
</Text>
<input name={name} type={type} className={input()} {...inputProps} />
</div>
);
};
export default TextInput;

View File

@@ -1,23 +0,0 @@
import Link from "next/link";
import { IoClose } from "react-icons/io5";
interface Props {
children: React.ReactNode;
}
const AuthLayout: React.FC<Props> = ({ children }) => {
return (
<Link
href="/"
className="relative flex min-h-screen flex-col items-center justify-center"
>
<IoClose
size="2rem"
className="absolute top-0 left-0 m-4 rounded-full hover:bg-fg/10 focus-visible:outline focus-visible:outline-8 focus-visible:outline-offset-2 focus-visible:outline-fg"
/>
{children}
</Link>
);
};
export default AuthLayout;

View File

@@ -0,0 +1,28 @@
import { MainLayout } from "@components/layouts";
import { TextInput } from "@components/TextInput";
import { typo } from "@styles/typography";
import type { Children } from "@utils/types/props";
import Link from "next/link";
export const DiscoverLayout: React.FC<Children> = ({ children }) => {
return (
<MainLayout>
<header>
<nav className="mb-4 flex flex-row gap-x-4">
<Link className="hover:text-tertiary" href="/discover/proposals">
Proposals
</Link>
<Link className="hover:text-tertiary" href="/discover/revisions">
Revisions
</Link>
<Link className="hover:text-tertiary" href="/discover/archive">
Archive
</Link>
</nav>
</header>
<h1 className={typo({ tag: "h1" })}>Discover</h1>
<TextInput label="Search" />
{children}
</MainLayout>
);
};

View File

@@ -1,18 +1,13 @@
import HomeFooter from "@components/HomeFooter";
import HomeHeader from "@components/HomeHeader";
import { Footer } from "@components/Footer";
import { Header } from "@components/Header";
import type { Children } from "@utils/types/props";
interface Props {
children: React.ReactNode;
}
const HomeLayout: React.FC<Props> = ({ children }) => {
export const HomeLayout: React.FC<Children> = ({ children }) => {
return (
<>
<HomeHeader />
<Header />
{children}
<HomeFooter />
<Footer />
</>
);
};
export default HomeLayout;

View File

@@ -1,9 +1,20 @@
interface Props {
children: React.ReactNode;
}
import type { Children } from "@utils/types/props";
import Link from "next/link";
import { IoClose } from "react-icons/io5";
const InfoLayout: React.FC<Props> = ({ children }) => {
return <>{children}</>;
export const InfoLayout: React.FC<Children> = ({ children }) => {
return (
<>
<Link
href="/"
className="relative flex min-h-screen flex-col items-center justify-center"
>
<IoClose
size="2rem"
className="absolute top-0 left-0 m-4 rounded-full hover:bg-fg/10 focus-visible:outline focus-visible:outline-8 focus-visible:outline-offset-2 focus-visible:outline-fg"
/>
</Link>
{children}
</>
);
};
export default InfoLayout;

View File

@@ -1,41 +0,0 @@
import { Murecho } from "@next/font/google";
import { useRouter } from "next/router";
import AuthLayout from "@components/layouts/AuthLayout";
import HomeLayout from "@components/layouts/HomeLayout";
import InfoLayout from "@components/layouts/InfoLayout";
import { useEffect, useState } from "react";
const murecho = Murecho({
subsets: ["latin"],
weight: ["400", "500", "600", "700"],
display: "swap",
variable: "--font-murecho",
});
type LayoutWrapper = "none" | "home" | "auth" | "info";
const layoutWrappers: Record<
LayoutWrapper,
React.FC<{ children: React.ReactNode }>
> = {
none: ({ children }: { children: React.ReactNode }) => <>{children}</>,
home: HomeLayout,
info: InfoLayout,
auth: AuthLayout,
};
interface Props {
children: React.ReactNode;
layout?: LayoutWrapper;
}
const Layout: React.FC<Props> = ({ layout = "none", children }) => {
const ContextualLayout = layoutWrappers[layout];
return (
<main className={`${murecho.variable} font-sans`}>
<ContextualLayout>{children}</ContextualLayout>
</main>
);
};
export default Layout;

View File

@@ -0,0 +1,28 @@
import type { Children } from "@utils/types/props";
import Link from "next/link";
const TempHeader = () => (
<header>
<nav className="flex flex-row gap-x-4">
<Link className="hover:text-tertiary" href="/projects">
Projects
</Link>
<Link className="hover:text-tertiary" href="/discover">
Discover
</Link>
<Link className="hover:text-tertiary" href="/profile">
Profile
</Link>
</nav>
</header>
);
export const MainLayout: React.FC<Children> = ({ children }) => {
return (
<>
<TempHeader />
{/* <SidePanel/> */}
{children}
</>
);
};

View File

@@ -0,0 +1,13 @@
import { Murecho } from "@next/font/google";
import type { Children } from "@utils/types/props";
const murecho = Murecho({
subsets: ["latin"],
weight: ["400", "500", "600", "700"],
display: "swap",
variable: "--font-murecho",
});
export const RootLayout: React.FC<Children> = ({ children }) => {
return <main className={`${murecho.variable} font-sans`}>{children}</main>;
};

View File

@@ -0,0 +1,5 @@
export * from "./RootLayout";
export * from "./HomeLayout";
export * from "./MainLayout";
export * from "./InfoLayout";
export * from "./DiscoverLayout";

View File

@@ -1,8 +1,8 @@
import Layout from "@components/layouts/Layout";
import { InfoLayout } from "@components/layouts";
import { type NextPage } from "next";
const Error: NextPage = () => {
return <Layout layout="info">Error</Layout>;
return <InfoLayout>Error</InfoLayout>;
};
export default Error;

View File

@@ -1,6 +1,5 @@
import { Button } from "@components/Button";
import TextInput from "@components/TextInput";
import Text from "@components/Text";
import { TextInput } from "@components/TextInput";
import type {
GetServerSidePropsContext,
InferGetServerSidePropsType,
@@ -10,8 +9,11 @@ import Image from "next/image";
import Divider from "@components/Divider";
import { useRouter } from "next/router";
import { useEffect } from "react";
import Layout from "@components/layouts/Layout";
import { InfoLayout } from "@components/layouts";
import { SignInFields } from "@constants/auth";
import { typo } from "@styles/typography";
import { cx } from "class-variance-authority";
import Link from "next/link";
const SignIn = ({
csrfToken,
@@ -35,10 +37,15 @@ const SignIn = ({
};
return (
<Layout layout="auth">
<Text styleLike="h3" className="my-6 mx-10 text-center text-primary">
<InfoLayout>
<h1
className={cx(
typo({ tag: "h3" }),
"my-6 mx-10 text-center text-primary"
)}
>
Welcome back. Sign in.
</Text>
</h1>
<form
onSubmit={handleAuth}
className="flex w-full max-w-lg flex-col items-center justify-center gap-y-2.5 px-4"
@@ -51,17 +58,18 @@ const SignIn = ({
Sign In
</Button>
</form>
<Text className="mt-8 mb-12">
<p className={cx(typo({ tag: "p" }), "mt-8 mb-12")}>
{"Don't have an account? "}
<Text
tag="a"
href="/auth/sign-up"
weight="semibold"
className="text-tertiary hover:text-tertiary-600"
<Link
href="/auth/sign-in"
className={cx(
typo({ size: "base" }),
"font-semibold text-tertiary hover:text-tertiary-600"
)}
>
Sign up
</Text>
</Text>
</Link>
</p>
<div className="w-full min-w-max max-w-md px-12">
<Divider>or sign in with</Divider>
</div>
@@ -70,7 +78,7 @@ const SignIn = ({
<AuthWith name="Google" />
<AuthWith name="Apple" />
</div>
</Layout>
</InfoLayout>
);
};

View File

@@ -1,6 +1,5 @@
import { Button } from "@components/Button";
import TextInput from "@components/TextInput";
import Text from "@components/Text";
import { TextInput } from "@components/TextInput";
import type {
GetServerSidePropsContext,
InferGetServerSidePropsType,
@@ -11,8 +10,10 @@ import Divider from "@components/Divider";
import { useRouter } from "next/router";
import Link from "next/link";
import { useEffect } from "react";
import Layout from "@components/layouts/Layout";
import { InfoLayout } from "@components/layouts";
import { SignUpFields } from "@constants/auth";
import { cx } from "class-variance-authority";
import { typo } from "@styles/typography";
const SignUp = ({
csrfToken,
@@ -33,10 +34,15 @@ const SignUp = ({
};
return (
<Layout layout="auth">
<Text styleLike="h3" className="my-6 mx-10 text-center text-primary">
<InfoLayout>
<h1
className={cx(
typo({ tag: "h3" }),
"my-6 mx-10 text-center text-primary"
)}
>
Sign up. Get Connected.
</Text>
</h1>
<form
onSubmit={handleEmailAuth}
className="flex w-full max-w-lg flex-col items-center justify-center gap-y-2.5 px-4"
@@ -49,17 +55,18 @@ const SignUp = ({
Sign Up
</Button>
</form>
<Text className="mt-8 mb-12">
<p className={cx(typo({ tag: "p" }), "mt-8 mb-12")}>
Already have an account?{" "}
<Text
tag="a"
<Link
href="/auth/sign-in"
weight="semibold"
className="text-tertiary hover:text-tertiary-600"
className={cx(
typo({ size: "base" }),
"font-semibold text-tertiary hover:text-tertiary-600"
)}
>
Sign in
</Text>
</Text>
</Link>
</p>
<div className="w-full min-w-max max-w-md px-12">
<Divider>or sign up with</Divider>
</div>
@@ -68,7 +75,7 @@ const SignUp = ({
<AuthWith name="Google" />
<AuthWith name="Apple" />
</div>
</Layout>
</InfoLayout>
);
};

View File

@@ -1,8 +1,8 @@
import Layout from "@components/layouts/Layout";
import { InfoLayout } from "@components/layouts";
import { type NextPage } from "next";
const VerifyRequest: NextPage = () => {
return <Layout layout="info">Verify Request</Layout>;
return <InfoLayout>Verify Request</InfoLayout>;
};
export default VerifyRequest;

View File

@@ -3,6 +3,7 @@ import { type Session } from "next-auth";
import { SessionProvider } from "next-auth/react";
import { SSRProvider } from "react-aria";
import Head from "next/head";
import { RootLayout } from "@components/layouts";
import { api } from "@utils/api";
import "@styles/globals.css";
@@ -19,7 +20,9 @@ const ParallelApp: AppType<{ session: Session | null }> = ({
</Head>
<SSRProvider>
<SessionProvider session={session}>
<Component {...pageProps} />
<RootLayout>
<Component {...pageProps} />
</RootLayout>
</SessionProvider>
</SSRProvider>
</>

View File

@@ -1,13 +0,0 @@
import Layout from "@components/layouts/Layout";
import Text from "@components/Text";
import type { NextPage } from "next";
const About: NextPage = () => {
return (
<Layout layout="home">
<Text tag="h1">About</Text>
</Layout>
);
};
export default About;

View File

@@ -0,0 +1,13 @@
import type { NextPage } from "next";
import { DiscoverLayout } from "@components/layouts";
import { typo } from "@styles/typography";
const Archive: NextPage = () => {
return (
<DiscoverLayout>
<h2 className={typo({ tag: "h2" })}>Archive</h2>
</DiscoverLayout>
);
};
export default Archive;

View File

@@ -0,0 +1,20 @@
import { DiscoverLayout } from "@components/layouts";
import type {
GetServerSidePropsContext,
InferGetServerSidePropsType,
NextPage,
} from "next";
const Discover: NextPage<
InferGetServerSidePropsType<typeof getServerSideProps>
> = ({ query }) => {
return <DiscoverLayout />;
};
export default Discover;
export function getServerSideProps(context: GetServerSidePropsContext) {
const query = context.query;
// Call a backend endpoint and return that list
return { props: { query } };
}

View File

@@ -0,0 +1,13 @@
import type { NextPage } from "next";
import { DiscoverLayout } from "@components/layouts";
import { typo } from "@styles/typography";
const Proposals: NextPage = () => {
return (
<DiscoverLayout>
<h2 className={typo({ tag: "h2" })}>Proposals</h2>
</DiscoverLayout>
);
};
export default Proposals;

View File

@@ -0,0 +1,13 @@
import type { NextPage } from "next";
import { DiscoverLayout } from "@components/layouts";
import { typo } from "@styles/typography";
const Revisions: NextPage = () => {
return (
<DiscoverLayout>
<h2 className={typo({ tag: "h2" })}>Revisions</h2>
</DiscoverLayout>
);
};
export default Revisions;

View File

@@ -6,14 +6,15 @@ import type {
import Image from "next/image";
import { Button } from "@components/Button";
import Divider from "@components/Divider";
import Text from "@components/Text";
import Layout from "@components/layouts/Layout";
import { getServerAuthSession } from "@server/auth";
import { signIn } from "next-auth/react";
import { HomeLayout } from "@components/layouts";
import { cx } from "class-variance-authority";
import { typo } from "@styles/typography";
const Home: NextPage = () => {
return (
<Layout layout="home">
<HomeLayout>
<Hero />
<Divider />
<About />
@@ -21,7 +22,7 @@ const Home: NextPage = () => {
<Premium />
<Divider />
<CTA />
</Layout>
</HomeLayout>
);
};
@@ -47,14 +48,19 @@ const Hero: React.FC = () => {
return (
<section className="custom-home-bg">
<div className="container">
<Text tag="h1" className="leading-tight text-primary drop-shadow-blur">
<h1
className={cx(
typo({ tag: "h1" }),
"leading-tight text-primary drop-shadow-blur"
)}
>
Collaborate with experts.
<br />
Educate the world.
</Text>
<Text size="h3" weight="bold" className="mt-6 mb-16 drop-shadow-blur">
Create educational content.
</h1>
<h3 className={cx(typo({ tag: "h3" }), "mt-6 mb-16 drop-shadow-blur")}>
Get connected with Parallel
</Text>
</h3>
<Button onClick={() => void signIn()}>Get Started</Button>
</div>
</section>
@@ -64,25 +70,33 @@ const Hero: React.FC = () => {
const About: React.FC = () => {
return (
<section className="container">
<Text tag="h2" className="mb-5 text-center text-primary">
<h2 className={cx(typo({ tag: "h2" }), "mb-5 text-center text-primary")}>
About Parallel
</Text>
<Text className="mx-auto mb-24 max-w-6xl text-center">
Lorem ipsum dolor sit amet consectetur adipiscing elit Ut et massa mi.
Aliquam in hendrerit urna. Pellentesque sit amet sapien fringilla,
mattis ligula consectetur, ultrices mauris. Maecenas vitae mattis
tellus.
</Text>
</h2>
<p
className={cx(
typo({ tag: "p" }),
"mx-auto mb-24 max-w-6xl text-center"
)}
>
Parallel{"'"}s mission is to address the disparity between the number of
educators who can produce high-quality educational content and the
number of content creators who have the expertise to tackle complex
subject matter. We connect content creators with educators, enabling
them to collaborate and produce exceptional educational content. Users
can assemble teams, work together on projects, and then publish a final
piece to platforms like YouTube.
</p>
<div className="grid grid-cols-1 gap-x-24 gap-y-9 md:grid-cols-[1fr_2fr_1fr] md:items-center">
<div className="md:col-start-2">
<Text tag="h3" styleLike="h4" className="mb-3">
For Educators
</Text>
<Text>
Lorem ipsum dolor sit amet consectetur adipiscing elit Ut et massa
mi. Aliquam in hendrerit urna. Pellentesque sit amet sapien
fringilla, mattis ligula consectetur, ultrices mauris.
</Text>
<h3 className={cx(typo({ tag: "h4" }), "mb-3")}>For Educators</h3>
<p className={typo({ tag: "p" })}>
Parallel provides educators with a platform to share their expertise
with a wider audience by collaborating with content creators. By
working together, educators can produce engaging and informative
videos that are accessible to students everywhere, without investing
too much time in video production.
</p>
</div>
<Image
priority
@@ -101,14 +115,16 @@ const About: React.FC = () => {
className="w-24 justify-self-end md:w-auto"
/>
<div className="md:col-start-2">
<Text tag="h3" styleLike="h4" className="mb-3">
<h3 className={cx(typo({ tag: "h4" }), "mb-3")}>
For Content Creators
</Text>
<Text>
Lorem ipsum dolor sit amet consectetur adipiscing elit Ut et massa
mi. Aliquam in hendrerit urna. Pellentesque sit amet sapien
fringilla, mattis ligula consectetur, ultrices mauris.
</Text>
</h3>
<p className={typo({ tag: "p" })}>
Parallel empowers content creators to produce high-quality
educational content that they may not have had the expertise to
tackle on their own. By collaborating with educators, creators can
explore new topics and create more comprehensive videos that engage
and inform their audience.
</p>
</div>
</div>
</section>
@@ -118,20 +134,21 @@ const About: React.FC = () => {
const Premium: React.FC = () => {
return (
<section className="container text-center">
<Text tag="h2" className="text-primary">
<h2 className={cx(typo({ tag: "h2" }), "text-primary")}>
Parallel Premium
</Text>
<Text className="my-5">
</h2>
<p className={cx(typo({ tag: "p" }), "my-5")}>
Using Parallel is completely free, but you can enjoy exclusive features
and support the platform with our premium version.
</Text>
<a href="#">
<Text
weight="semibold"
className="text-tertiary hover:text-tertiary-600"
>
Learn more about Premium
</Text>
</p>
<a
href="#"
className={cx(
typo({ tag: "p" }),
"font-semibold text-tertiary hover:text-tertiary-600"
)}
>
Learn more about Premium
</a>
</section>
);

View File

@@ -0,0 +1,55 @@
import { Button } from "@components/Button";
import { MainLayout } from "@components/layouts";
import { getServerAuthSession } from "@server/auth";
import { typo } from "@styles/typography";
import type { GetServerSideProps, GetServerSidePropsContext } from "next";
import { type NextPage } from "next";
import type { Session } from "next-auth";
import { signOut, useSession } from "next-auth/react";
interface Props {
session: Session;
}
const Profile: NextPage<Props> = ({ session }) => {
const { data, status } = useSession();
return (
<MainLayout>
<h1 className={typo({ tag: "h1" })}>Profile</h1>
<p className={typo({ tag: "p" })}>{status}</p>
<p className={typo({ tag: "p" })}>
(Server side) Signed in as {session?.user.name}
</p>
<p className={typo({ tag: "p" })}>
(Client side) Signed in as {data?.user.name}
</p>
<Button
onClick={() =>
void signOut({
callbackUrl: "/",
redirect: true,
})
}
>
Sign Out
</Button>
</MainLayout>
);
};
export const getServerSideProps: GetServerSideProps<Props> = async (
ctx: GetServerSidePropsContext
) => {
const session = await getServerAuthSession(ctx);
if (session === null || session.user === null || session.user.id === null) {
return {
redirect: { destination: "/api/auth/signin", permanent: false },
};
}
return { props: { session } };
};
export default Profile;

View File

@@ -1,50 +1,13 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { getServerAuthSession } from "@server/auth";
import type {
GetServerSideProps,
GetServerSidePropsContext,
InferGetServerSidePropsType,
NextPage,
} from "next";
import Text from "@components/Text";
import { Button } from "@components/Button";
import { signOut } from "next-auth/react";
import Layout from "@components/layouts/Layout";
import type { NextPage } from "next";
import { MainLayout } from "@components/layouts";
import { typo } from "@styles/typography";
const Projects: NextPage = ({
session,
}: InferGetServerSidePropsType<typeof getServerSideProps>) => {
const Projects: NextPage = () => {
return (
<Layout>
<Text tag="h1">Projects</Text>
<Text>Signed in as {session?.user?.id}</Text>
<Button
onClick={() =>
void signOut({
callbackUrl: "/",
redirect: true,
})
}
>
Sign Out
</Button>
</Layout>
<MainLayout>
<h1 className={typo({ tag: "h1" })}>Projects</h1>
</MainLayout>
);
};
export const getServerSideProps: GetServerSideProps = async (
ctx: GetServerSidePropsContext
) => {
const session = await getServerAuthSession(ctx);
if (!session) {
return {
redirect: { destination: "/api/auth/signin", permanent: false },
};
}
return { props: { session } };
};
export default Projects;

26
src/styles/typography.ts Normal file
View File

@@ -0,0 +1,26 @@
import { cva, cx } from "class-variance-authority";
const responsiveText = {
base: "text-sm md:text-base 2xl:text-lg",
lg: "text-sm md:text-base 2xl:text-lg",
xl: "text-base md:text-lg 2xl:text-xl",
"2xl": "text-lg md:text-xl 2xl:text-2xl",
"3xl": "text-xl md:text-2xl 2xl:text-3xl",
"4xl": "text-2xl md:text-3xl 2xl:text-4xl",
"5xl": "text-3xl md:text-4xl 2xl:text-5xl",
};
export const typo = cva("", {
variants: {
tag: {
p: cx("font-normal", responsiveText["lg"]),
h1: cx("font-bold", responsiveText["5xl"]),
h2: cx("font-bold", responsiveText["4xl"]),
h3: cx("font-bold", responsiveText["3xl"]),
h4: cx("font-bold", responsiveText["2xl"]),
h5: cx("font-semibold", responsiveText["xl"]),
h6: cx("font-semibold", responsiveText["lg"]),
},
size: responsiveText,
},
});

3
src/utils/types/props.ts Normal file
View File

@@ -0,0 +1,3 @@
export interface Children {
children?: React.ReactNode;
}