diff --git a/.gitignore b/.gitignore index fd3dbb5..00bba9b 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ yarn-error.log* # local env files .env*.local +.env # vercel .vercel diff --git a/app/globals.css b/app/globals.css index cf0bdfa..916a232 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,75 +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: 221.2 83.2% 53.3%; - --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% 44%; - --accent: 210 40% 96.1%; - --accent-foreground: 222.2 47.4% 11.2%; - --destructive: 0 72% 51%; - --destructive-foreground: 210 40% 98%; - --border: 220 13% 91%; - --input: 214.3 31.8% 91.4%; - --ring: 221.2 83.2% 53.3%; - --radius: 0.5rem; - } + @tailwind components; + @tailwind utilities; - .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: 217.2 91.2% 59.8%; - --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: 224.3 76.3% 48%; - } -} + @layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; -@layer base { - * { - @apply border-border; - } + --card: 0 0% 100%; + --card-foreground: 240 10% 3.9%; - body { - @apply bg-background text-foreground font-body; - } + --popover: 0 0% 100%; + --popover-foreground: 240 10% 3.9%; - h1, h2, h3, h4, h5, h6 { - @apply font-heading; - } + --primary: 240 5.9% 10%; + --primary-foreground: 0 0% 98%; - - /* Define the font-body class */ - .font-body { - font-family: 'YourFontFamily', sans-serif; /* Replace 'YourFontFamily' with your desired font family */ - } + --secondary: 240 4.8% 95.9%; + --secondary-foreground: 240 5.9% 10%; + + --muted: 240 4.8% 95.9%; + --muted-foreground: 240 3.8% 46.1%; + + --accent: 240 4.8% 95.9%; + --accent-foreground: 240 5.9% 10%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + + --border: 240 5.9% 90%; + --input: 240 5.9% 90%; + --ring: 240 10% 3.9%; - /* Define the font-heading class */ - .font-heading { - font-family: 'YourHeadingFontFamily', sans-serif; /* Replace 'YourHeadingFontFamily' with your desired heading font family */ + --radius: 0.5rem; + } + + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + + --card: 240 10% 3.9%; + --card-foreground: 0 0% 98%; + + --popover: 240 10% 3.9%; + --popover-foreground: 0 0% 98%; + + --primary: 0 0% 98%; + --primary-foreground: 240 5.9% 10%; + + --secondary: 240 3.7% 15.9%; + --secondary-foreground: 0 0% 98%; + + --muted: 240 3.7% 15.9%; + --muted-foreground: 240 5% 64.9%; + + --accent: 240 3.7% 15.9%; + --accent-foreground: 0 0% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + + --border: 240 3.7% 15.9%; + --input: 240 3.7% 15.9%; + --ring: 240 4.9% 83.9%; + } } -} \ No newline at end of file + + @layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } + } \ No newline at end of file diff --git a/prisma/migrations/20240711095436_init/migration.sql b/prisma/migrations/20240711095436_init/migration.sql new file mode 100644 index 0000000..68f29dd --- /dev/null +++ b/prisma/migrations/20240711095436_init/migration.sql @@ -0,0 +1,57 @@ +-- CreateTable +CREATE TABLE "Account" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "type" TEXT NOT NULL, + "provider" TEXT NOT NULL, + "providerAccountId" TEXT NOT NULL, + "refresh_token" TEXT, + "access_token" TEXT, + "expires_at" INTEGER, + "token_type" TEXT, + "scope" TEXT, + "id_token" TEXT, + "session_state" TEXT, + + CONSTRAINT "Account_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Session" ( + "id" TEXT NOT NULL, + "sessionToken" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "expires" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Session_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "name" TEXT, + "email" TEXT, + "emailVerified" TIMESTAMP(3), + "username" TEXT, + "image" TEXT, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_username_key" ON "User"("username"); + +-- AddForeignKey +ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20240811171035_added_interactions/migration.sql b/prisma/migrations/20240811171035_added_interactions/migration.sql new file mode 100644 index 0000000..3397dee --- /dev/null +++ b/prisma/migrations/20240811171035_added_interactions/migration.sql @@ -0,0 +1,107 @@ +-- CreateEnum +CREATE TYPE "VoteType" AS ENUM ('UP', 'DOWN'); + +-- CreateTable +CREATE TABLE "Subgroup" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "creatorId" TEXT, + + CONSTRAINT "Subgroup_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Post" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "content" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "authorId" TEXT NOT NULL, + "subgroupId" TEXT NOT NULL, + + CONSTRAINT "Post_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Subscription" ( + "userId" TEXT NOT NULL, + "subgroupId" TEXT NOT NULL, + + CONSTRAINT "Subscription_pkey" PRIMARY KEY ("userId","subgroupId") +); + +-- CreateTable +CREATE TABLE "Comment" ( + "id" TEXT NOT NULL, + "text" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "authorId" TEXT NOT NULL, + "postId" TEXT NOT NULL, + "replyToId" TEXT, + "commentId" TEXT, + + CONSTRAINT "Comment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Vote" ( + "userId" TEXT NOT NULL, + "postId" TEXT NOT NULL, + "type" "VoteType" NOT NULL, + + CONSTRAINT "Vote_pkey" PRIMARY KEY ("userId","postId") +); + +-- CreateTable +CREATE TABLE "CommentVote" ( + "userId" TEXT NOT NULL, + "commentId" TEXT NOT NULL, + "type" "VoteType" NOT NULL, + + CONSTRAINT "CommentVote_pkey" PRIMARY KEY ("userId","commentId") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Subgroup_name_key" ON "Subgroup"("name"); + +-- CreateIndex +CREATE INDEX "Subgroup_name_idx" ON "Subgroup"("name"); + +-- AddForeignKey +ALTER TABLE "Subgroup" ADD CONSTRAINT "Subgroup_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Post" ADD CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Post" ADD CONSTRAINT "Post_subgroupId_fkey" FOREIGN KEY ("subgroupId") REFERENCES "Subgroup"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_subgroupId_fkey" FOREIGN KEY ("subgroupId") REFERENCES "Subgroup"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Comment" ADD CONSTRAINT "Comment_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Comment" ADD CONSTRAINT "Comment_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Comment" ADD CONSTRAINT "Comment_replyToId_fkey" FOREIGN KEY ("replyToId") REFERENCES "Comment"("id") ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- AddForeignKey +ALTER TABLE "Vote" ADD CONSTRAINT "Vote_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Vote" ADD CONSTRAINT "Vote_postId_fkey" FOREIGN KEY ("postId") REFERENCES "Post"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "CommentVote" ADD CONSTRAINT "CommentVote_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "CommentVote" ADD CONSTRAINT "CommentVote_commentId_fkey" FOREIGN KEY ("commentId") REFERENCES "Comment"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..fbffa92 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..8643879 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,134 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") + directUrl = env("DIRECT_URL") +} + +enum VoteType { + UP + DOWN +} + +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) + + @@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? + username String? @unique + image String? + createdSubgroups Subgroup[] @relation("CreatedBy") + + accounts Account[] + sessions Session[] + Post Post[] + Comment Comment[] + CommentVote CommentVote[] + Subscriptions Subscription[] + Vote Vote[] +} + +model Subgroup { + id String @id @default(cuid()) + name String @unique + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + posts Post[] + + Creator User? @relation("CreatedBy", fields: [creatorId], references: [id]) + creatorId String? + subscribers Subscription[] + + @@index([name]) +} + +model Post { + id String @id @default(cuid()) + title String + content Json? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + author User @relation(fields: [authorId], references: [id]) + authorId String + + subgroup Subgroup @relation(fields: [subgroupId], references: [id]) + subgroupId String + comments Comment[] + votes Vote[] +} + +model Subscription { + user User @relation(fields: [userId], references: [id]) + userId String + subgroup Subgroup @relation(fields: [subgroupId], references: [id]) + subgroupId String + + @@id([userId, subgroupId]) +} + +model Comment { + id String @id @default(cuid()) + text String + createdAt DateTime @default(now()) + author User @relation(fields: [authorId], references: [id]) + authorId String + post Post @relation(fields: [postId], references: [id], onDelete: Cascade) + postId String + + replyToId String? + replyTo Comment? @relation("ReplyTo", fields: [replyToId], references: [id], onDelete: NoAction, onUpdate: NoAction) + replies Comment[] @relation("ReplyTo") + + votes CommentVote[] + commentId String? +} + +model Vote { + user User @relation(fields: [userId], references: [id]) + userId String + post Post @relation(fields: [postId], references: [id], onDelete: Cascade) + postId String + type VoteType + + @@id([userId, postId]) +} + +model CommentVote { + user User @relation(fields: [userId], references: [id]) + userId String + comment Comment @relation(fields: [commentId], references: [id], onDelete: Cascade) + commentId String + type VoteType + + @@id([userId, commentId]) +}