Setup app

This commit is contained in:
KMKoushik
2024-03-19 09:34:23 +11:00
parent 7ee4e89e5f
commit 9032efa9b2
71 changed files with 3199 additions and 5419 deletions

3
packages/db/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules
# Keep environment variables out of version control
.env

1
packages/db/client.ts Normal file
View File

@@ -0,0 +1 @@
export * from "@prisma/client";

21
packages/db/index.ts Normal file
View File

@@ -0,0 +1,21 @@
import { PrismaClient } from "@prisma/client";
declare global {
// We need `var` to declare a global variable in TypeScript
// eslint-disable-next-line no-var
var prisma: PrismaClient | undefined;
}
if (!globalThis.prisma) {
globalThis.prisma = new PrismaClient({
datasourceUrl: process.env.DATABASE_URL,
});
}
export const prisma =
globalThis.prisma ||
new PrismaClient({
datasourceUrl: process.env.DATABASE_URL,
});
export const getPrismaClient = () => prisma;

18
packages/db/package.json Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "@unsend/db",
"version": "0.0.0",
"main": "./index.ts",
"types": "./index.ts",
"dependencies": {
"@prisma/client": "^5.11.0",
"prisma": "^5.11.0"
},
"scripts": {
"post-install": "prisma generate",
"generate": "prisma generate",
"push": "prisma db push --skip-generate",
"migrate-dev": "prisma migrate dev",
"migrate-deploy": "prisma migrate deploy",
"studio": "prisma studio"
}
}

View File

@@ -0,0 +1,73 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
// NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below
// Further reading:
// https://next-auth.js.org/adapters/prisma#create-the-prisma-schema
// https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string
url = env("DATABASE_URL")
}
model Post {
id Int @id @default(autoincrement())
name String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdBy User @relation(fields: [createdById], references: [id])
createdById String
@@index([name])
}
// Necessary for Next auth
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? // @db.Text
access_token String? // @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? // @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@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)
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
posts Post[]
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}

View File

@@ -0,0 +1,21 @@
{
"name": "@unsend/tailwind-config",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@types/node": "^20.11.24",
"autoprefixer": "^10.4.18",
"postcss": "^8.4.35",
"tailwindcss": "^3.4.1"
}
}

View File

@@ -0,0 +1,79 @@
import type { Config } from "tailwindcss";
const config = {
darkMode: ["class"],
content: ["./src/**/*.{ts,tsx}"],
prefix: "",
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
// fontFamily: {
// sans: ["var(--font-geist-sans)"],
// mono: ["var(--font-geist-mono)"],
// },
},
},
plugins: [require("tailwindcss-animate")],
} satisfies Config;
export default config;

View File

@@ -0,0 +1,9 @@
{
"extends": "@unsend/typescript-config/base.json",
"compilerOptions": {
"allowJs": true,
"noEmit": true
},
"include": ["tailwind.config.ts"],
"exclude": ["node_modules", "dist"]
}

1
packages/ui/index.ts Normal file
View File

@@ -0,0 +1 @@
export {};

6
packages/ui/lib/utils.ts Normal file
View File

@@ -0,0 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

View File

@@ -2,25 +2,39 @@
"name": "@unsend/ui",
"version": "0.0.0",
"private": true,
"exports": {
"./button": "./src/button.tsx",
"./card": "./src/card.tsx",
"./code": "./src/code.tsx"
},
"main": "./index.ts",
"types": "./index.ts",
"files": [
"src"
],
"scripts": {
"lint": "eslint . --max-warnings 0",
"generate:component": "turbo gen react-component"
"lint": "eslint . --max-warnings 0"
},
"devDependencies": {
"@unsend/eslint-config": "workspace:*",
"@unsend/typescript-config": "workspace:*",
"@turbo/gen": "^1.12.4",
"@types/node": "^20.11.24",
"@types/eslint": "^8.56.5",
"@types/node": "^20.11.24",
"@types/react": "^18.2.61",
"@types/react-dom": "^18.2.19",
"@unsend/eslint-config": "workspace:*",
"@unsend/tailwind-config": "workspace:*",
"@unsend/typescript-config": "workspace:*",
"eslint": "^8.57.0",
"postcss": "^8.4.36",
"prettier": "^3.2.5",
"prettier-plugin-tailwindcss": "^0.5.12",
"react": "^18.2.0",
"tailwindcss": "^3.4.1",
"typescript": "^5.3.3"
},
"dependencies": {
"@radix-ui/react-slot": "^1.0.2",
"add": "^2.0.6",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"lucide-react": "^0.359.0",
"next-themes": "^0.3.0",
"pnpm": "^8.15.5",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7"
}
}

View File

@@ -1,20 +1,56 @@
"use client";
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { ReactNode } from "react";
import { cn } from "../lib/utils";
interface ButtonProps {
children: ReactNode;
className?: string;
appName: string;
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}
export const Button = ({ children, className, appName }: ButtonProps) => {
return (
<button
className={className}
onClick={() => alert(`Hello from your ${appName} app!`)}
>
{children}
</button>
);
};
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
}
);
Button.displayName = "Button";
export { Button, buttonVariants };

View File

@@ -1,25 +0,0 @@
export function Card({
className,
title,
children,
href,
}: {
className?: string;
title: string;
children: React.ReactNode;
href: string;
}): JSX.Element {
return (
<a
className={className}
href={`${href}?utm_source=create-turbo&utm_medium=basic&utm_campaign=create-turbo"`}
rel="noopener noreferrer"
target="_blank"
>
<h2>
{title} <span>-&gt;</span>
</h2>
<p>{children}</p>
</a>
);
}

View File

@@ -1,9 +0,0 @@
export function Code({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}): JSX.Element {
return <code className={className}>{children}</code>;
}

View File

@@ -0,0 +1,76 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}

View File

@@ -0,0 +1,7 @@
import { type Config } from "tailwindcss";
import sharedConfig from "@unsend/tailwind-config/tailwind.config";
export default {
...sharedConfig,
content: ["./src/**/*.tsx"],
} satisfies Config;

View File

@@ -0,0 +1,9 @@
"use client";
import * as React from "react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { type ThemeProviderProps } from "next-themes/dist/types";
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}

View File

@@ -3,6 +3,6 @@
"compilerOptions": {
"outDir": "dist"
},
"include": ["src"],
"include": ["src", "index.ts"],
"exclude": ["node_modules", "dist"]
}

View File

@@ -1,30 +0,0 @@
import type { PlopTypes } from "@turbo/gen";
// Learn more about Turborepo Generators at https://turbo.build/repo/docs/core-concepts/monorepos/code-generation
export default function generator(plop: PlopTypes.NodePlopAPI): void {
// A simple generator to add a new React component to the internal UI library
plop.setGenerator("react-component", {
description: "Adds a new react component",
prompts: [
{
type: "input",
name: "name",
message: "What is the name of the component?",
},
],
actions: [
{
type: "add",
path: "src/{{kebabCase name}}.tsx",
templateFile: "templates/component.hbs",
},
{
type: "append",
path: "package.json",
pattern: /"exports": {(?<insertion>)/g,
template: '"./{{kebabCase name}}": "./src/{{kebabCase name}}.tsx",',
},
],
});
}

View File

@@ -1,8 +0,0 @@
export const {{ pascalCase name }} = ({ children }: { children: React.ReactNode }) => {
return (
<div>
<h1>{{ pascalCase name }} Component</h1>
{children}
</div>
);
};