diff --git a/app/sub/[subId]/page.tsx b/app/sub/[subId]/page.tsx index 68ca7e5..9050619 100644 --- a/app/sub/[subId]/page.tsx +++ b/app/sub/[subId]/page.tsx @@ -1,9 +1,10 @@ -import React from "react"; +import MiniPostCreator from "@/components/pages/MiniPostCreator"; + +import PostFeed from "@/components/pages/PostFeed"; +import { Infinite_Scrolling_Pagination_Results } from "@/config"; import { getAuthSession } from "@/lib/auth"; import { db } from "@/lib/db"; -import { Infinite_Scrolling_Pagination_Results } from "@/config"; import { notFound } from "next/navigation"; -import MiniPostCreator from "@/components/pages/MiniPostCreator"; interface PageProps { params: { @@ -11,15 +12,11 @@ interface PageProps { }; } -export default async function page({ - params, -}: PageProps): Promise { +export default async function page({params}: PageProps): Promise { const { subId } = params; const session = await getAuthSession(); const subgroup = await db.subgroup.findFirst({ - where: { - name: subId, - }, + where: { name: subId }, include: { posts: { include: { @@ -28,6 +25,9 @@ export default async function page({ comments: true, subgroup: true, }, + orderBy: { + createdAt: 'desc' + }, take: Infinite_Scrolling_Pagination_Results, }, }, @@ -44,6 +44,8 @@ export default async function page({ + + ); } diff --git a/components/EditorOutput.tsx b/components/EditorOutput.tsx new file mode 100644 index 0000000..107b032 --- /dev/null +++ b/components/EditorOutput.tsx @@ -0,0 +1,58 @@ +"use client"; + +import dynamic from "next/dynamic"; +import Image from "next/image"; + +const Output = dynamic( + async () => (await import("editorjs-react-renderer")).default, + { + ssr: false, + } +); + +const renderers = { + image: CustomImageRenderer, + code: CustomCodeRenderer, +}; + +const style = { + paragraph: { + fontSize: "0.875rem", + lineHeight: "1.25rem", + }, +}; + +interface EditorComponentProps { + content: any; +} + +export default function EditorOutput({ content }: EditorComponentProps) { + return ( + + ); +} + +function CustomCodeRenderer({ data }: any) { + data; + + return ( +
+      {data.code}
+    
+ ); +} + +function CustomImageRenderer({ data }: any) { + const src = data.file.url; + + return ( +
+ image +
+ ); +} diff --git a/components/pages/PostFeed.tsx b/components/pages/PostFeed.tsx new file mode 100644 index 0000000..8d1acf9 --- /dev/null +++ b/components/pages/PostFeed.tsx @@ -0,0 +1,95 @@ +"use client"; +import { Infinite_Scrolling_Pagination_Results } from "@/config"; +import { ExtendedPost } from "@/types/db"; +import { useIntersection } from "@mantine/hooks"; +import { useInfiniteQuery } from "@tanstack/react-query"; +import axios from "axios"; +import { useSession } from "next-auth/react"; +import { useEffect, useRef } from "react"; +import Posts from "./Posts"; + +interface PostFeedTypes { + initialPosts: ExtendedPost[]; + subgroupName?: string; +} +export default function PostFeed({ + initialPosts, + subgroupName, +}: PostFeedTypes) { + const lastPostRef = useRef(null); + const { ref, entry } = useIntersection({ + root: lastPostRef.current, + threshold: 1, + }); + + const { data: session } = useSession(); + + // Functionality for Infinite Scrolling (TanSatck Query) + const { data, fetchNextPage, isFetchingNextPage } = useInfiniteQuery({ + queryKey: ["infinite-query", subgroupName], + queryFn: async ({ pageParam = 1 }) => { + const query = + `/api/posts?limit=${Infinite_Scrolling_Pagination_Results}&page=${pageParam}` + + (subgroupName ? `&sub=${subgroupName}` : ""); + + const { data } = await axios.get(query); + return data as ExtendedPost[]; + }, + initialPageParam: 1, + getNextPageParam: (lastPage, allPages, lastPageParam) => { + if (lastPage.length < Infinite_Scrolling_Pagination_Results) { + return undefined; + } + return lastPageParam + 1; + }, + initialData: { pages: [initialPosts], pageParams: [1] }, + }); + + useEffect(() => { + if (entry?.isIntersecting) { + fetchNextPage(); // Load more posts when the last post comes into view + } + }, [entry, fetchNextPage]); + + const posts = data.pages.flatMap((page) => page) ?? initialPosts; + + return ( +
    + {posts.map((post, index) => { + const totalVotes = post.votes.reduce((acc, vote) => { + if (vote.type === "UP") return acc + 1; + if (vote.type === "DOWN") return acc - 1; + return acc; + }, 0); + + const isVoted = post.votes.find( + (vote) => vote.userId === session?.user.id + ); + + if (index === posts.length - 1) + return ( +
  • + +
  • + ); + else + return ( + + ); + })} +
+ ); +} diff --git a/components/pages/Posts.tsx b/components/pages/Posts.tsx index 67d162e..94102fd 100644 --- a/components/pages/Posts.tsx +++ b/components/pages/Posts.tsx @@ -1,107 +1,78 @@ -import React from "react"; +// Preview Component for each Post +import { formatTimeToNow } from "@/lib/utils"; +import { Post, User, Vote } from "@prisma/client"; +import { MessageSquare } from "lucide-react"; +import Link from "next/link"; +import { useRef } from "react"; +import EditorOutput from "../EditorOutput"; -import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; -import { Card, CardHeader, CardContent, CardFooter } from "@/components/ui/card"; -import { - ArrowDown, - ArrowUp, - Filter, - MessageCircle, - MessageCircleReply, - MoveDiagonal, -} from "lucide-react"; -import Image from "next/image"; -import { Button } from "@/components/ui/button"; +type PartialVote = Pick; -type PostType = { - content: string | JSX.Element; - timeAgo: string; - upvotes: number; - comments: number; -}; -export function Posts() { - return ( -
-
-

Your Feed

- -
-
- - - } - timeAgo="1 day ago" - upvotes={456} - comments={78} - /> - -
-
- ); +interface PostProps { + post: Post & { + author: User; + votes: Vote[]; + }; + totalVotes: number; + subgroupName: string; + currentVote?: PartialVote; + commentAmt: number; } +export default function Posts({ + post, + totalVotes: _totalVotes, + currentVote: _currentVote, + subgroupName, + commentAmt, +}: PostProps) { + const pRef = useRef(null); -function Post({ content, timeAgo, upvotes, comments }: PostType) { return ( - - -
- - - UN - +
+
+
+
+ {subgroupName ? ( + <> + + sub/{subgroupName} + + • + + ) : null} + Posted by u/{post.author.username}{" "} + {formatTimeToNow(new Date(post.createdAt))} +
+ +

+ {post.title} +

+
-
-
Anonymous User
-
{timeAgo}
+
+ + {pRef.current?.clientHeight === 160 ? ( + // blur bottom if content is too long +
+ ) : null}
+
- - - - -
{content}
-
- - -
{upvotes} upvotes
- - -
{comments} comments
-
- +
+ + {commentAmt} comments + +
+
); } diff --git a/lib/utils.ts b/lib/utils.ts index d084cca..a47e92d 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,6 +1,56 @@ -import { type ClassValue, clsx } from "clsx" -import { twMerge } from "tailwind-merge" +import { type ClassValue, clsx } from "clsx"; +import { formatDistanceToNowStrict } from "date-fns"; +import { twMerge } from "tailwind-merge"; +import { enUS } from "date-fns/locale"; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) + return twMerge(clsx(inputs)); +} + +const formatDistanceLocale = { + lessThanXSeconds: "just now", + xSeconds: "just now", + halfAMinute: "just now", + lessThanXMinutes: "{{count}}m", + xMinutes: "{{count}}m", + aboutXHours: "{{count}}h", + xHours: "{{count}}h", + xDays: "{{count}}d", + aboutXWeeks: "{{count}}w", + xWeeks: "{{count}}w", + aboutXMonths: "{{count}}m", + xMonths: "{{count}}m", + aboutXYears: "{{count}}y", + xYears: "{{count}}y", + overXYears: "{{count}}y", + almostXYears: "{{count}}y", +}; + +function formatDistance(token: string, count: number, options?: any): string { + options = options || {}; + + const result = formatDistanceLocale[ + token as keyof typeof formatDistanceLocale + ].replace("{{count}}", count.toString()); + + if (options.addSuffix) { + if (options.comparison > 0) { + return "in " + result; + } else { + if (result === "just now") return result; + return result + " ago"; + } + } + + return result; +} + +export function formatTimeToNow(date: Date): string { + return formatDistanceToNowStrict(date, { + addSuffix: true, + locale: { + ...enUS, + formatDistance, + }, + }); } diff --git a/next.config.mjs b/next.config.mjs index 4bbaeeb..796d933 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -2,7 +2,7 @@ const nextConfig = { reactStrictMode: true, images: { - domains: ["lh3.googleusercontent.com"], + domains: ["lh3.googleusercontent.com", "utfs.io"], }, }; diff --git a/package-lock.json b/package-lock.json index 944fbf5..ccb4c51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,8 +17,10 @@ "@editorjs/inline-code": "^1.5.1", "@editorjs/link": "^2.6.2", "@editorjs/list": "^1.10.0", + "@editorjs/paragraph": "^2.11.6", "@editorjs/table": "^2.4.1", "@hookform/resolvers": "^3.9.0", + "@mantine/hooks": "^7.12.2", "@next-auth/prisma-adapter": "^1.0.7", "@prisma/client": "^5.18.0", "@radix-ui/react-avatar": "^1.1.0", @@ -39,9 +41,11 @@ "cmdk": "^1.0.0", "crypt": "file:", "date-fns": "^3.6.0", + "editorjs-react-renderer": "^3.5.1", "framer-motion": "^11.3.24", "lucide-react": "^0.399.0", - "next": "14.2.4", + "nanoid": "^5.0.7", + "next": "^14.2.13", "next-auth": "^4.24.7", "next-themes": "^0.3.0", "prisma": "^5.19.1", @@ -188,6 +192,21 @@ "integrity": "sha512-V8N/TY2TGyas4wLrPIFq7bcow68b3gu8DfDt1+rrHPtXxcexadKauRJL6eQgfG7Z0LCrN4boLRawR4S9gjIh/Q==", "license": "MIT" }, + "node_modules/@editorjs/paragraph": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@editorjs/paragraph/-/paragraph-2.11.6.tgz", + "integrity": "sha512-i9B50Ylvh+0ZzUGWIba09PfUXsA00Y//zFZMwqsyaXXKxMluSIJ6ADFJbbK0zaV9Ijx49Xocrlg+CEPRqATk9w==", + "license": "MIT", + "dependencies": { + "@codexteam/icons": "^0.0.4" + } + }, + "node_modules/@editorjs/paragraph/node_modules/@codexteam/icons": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@codexteam/icons/-/icons-0.0.4.tgz", + "integrity": "sha512-V8N/TY2TGyas4wLrPIFq7bcow68b3gu8DfDt1+rrHPtXxcexadKauRJL6eQgfG7Z0LCrN4boLRawR4S9gjIh/Q==", + "license": "MIT" + }, "node_modules/@editorjs/table": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@editorjs/table/-/table-2.4.1.tgz", @@ -433,6 +452,15 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mantine/hooks": { + "version": "7.12.2", + "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-7.12.2.tgz", + "integrity": "sha512-dVMw8jpM0hAzc8e7/GNvzkk9N0RN/m+PKycETB3H6lJGuXJJSRR4wzzgQKpEhHwPccktDpvb4rkukKDq2jA8Fg==", + "license": "MIT", + "peerDependencies": { + "react": "^18.2.0" + } + }, "node_modules/@next-auth/prisma-adapter": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@next-auth/prisma-adapter/-/prisma-adapter-1.0.7.tgz", @@ -443,9 +471,10 @@ } }, "node_modules/@next/env": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.4.tgz", - "integrity": "sha512-3EtkY5VDkuV2+lNmKlbkibIJxcO4oIHEhBWne6PaAp+76J9KoSsGvNikp6ivzAT8dhhBMYrm6op2pS1ApG0Hzg==" + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.13.tgz", + "integrity": "sha512-s3lh6K8cbW1h5Nga7NNeXrbe0+2jIIYK9YaA9T7IufDWnZpozdFUp6Hf0d5rNWUKu4fEuSX2rCKlGjCrtylfDw==", + "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { "version": "14.2.4", @@ -457,12 +486,13 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.4.tgz", - "integrity": "sha512-AH3mO4JlFUqsYcwFUHb1wAKlebHU/Hv2u2kb1pAuRanDZ7pD/A/KPD98RHZmwsJpdHQwfEc/06mgpSzwrJYnNg==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.13.tgz", + "integrity": "sha512-IkAmQEa2Htq+wHACBxOsslt+jMoV3msvxCn0WFSfJSkv/scy+i/EukBKNad36grRxywaXUYJc9mxEGkeIs8Bzg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -472,12 +502,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.4.tgz", - "integrity": "sha512-QVadW73sWIO6E2VroyUjuAxhWLZWEpiFqHdZdoQ/AMpN9YWGuHV8t2rChr0ahy+irKX5mlDU7OY68k3n4tAZTg==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.13.tgz", + "integrity": "sha512-Dv1RBGs2TTjkwEnFMVL5XIfJEavnLqqwYSD6LXgTPdEy/u6FlSrLBSSfe1pcfqhFEXRAgVL3Wpjibe5wXJzWog==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -487,12 +518,13 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.4.tgz", - "integrity": "sha512-KT6GUrb3oyCfcfJ+WliXuJnD6pCpZiosx2X3k66HLR+DMoilRb76LpWPGb4tZprawTtcnyrv75ElD6VncVamUQ==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.13.tgz", + "integrity": "sha512-yB1tYEFFqo4ZNWkwrJultbsw7NPAAxlPXURXioRl9SdW6aIefOLS+0TEsKrWBtbJ9moTDgU3HRILL6QBQnMevg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -502,12 +534,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.4.tgz", - "integrity": "sha512-Alv8/XGSs/ytwQcbCHwze1HmiIkIVhDHYLjczSVrf0Wi2MvKn/blt7+S6FJitj3yTlMwMxII1gIJ9WepI4aZ/A==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.13.tgz", + "integrity": "sha512-v5jZ/FV/eHGoWhMKYrsAweQ7CWb8xsWGM/8m1mwwZQ/sutJjoFaXchwK4pX8NqwImILEvQmZWyb8pPTcP7htWg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -517,12 +550,13 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.4.tgz", - "integrity": "sha512-ze0ShQDBPCqxLImzw4sCdfnB3lRmN3qGMB2GWDRlq5Wqy4G36pxtNOo2usu/Nm9+V2Rh/QQnrRc2l94kYFXO6Q==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.13.tgz", + "integrity": "sha512-aVc7m4YL7ViiRv7SOXK3RplXzOEe/qQzRA5R2vpXboHABs3w8vtFslGTz+5tKiQzWUmTmBNVW0UQdhkKRORmGA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -532,12 +566,13 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.4.tgz", - "integrity": "sha512-8dwC0UJoc6fC7PX70csdaznVMNr16hQrTDAMPvLPloazlcaWfdPogq+UpZX6Drqb1OBlwowz8iG7WR0Tzk/diQ==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.13.tgz", + "integrity": "sha512-4wWY7/OsSaJOOKvMsu1Teylku7vKyTuocvDLTZQq0TYv9OjiYYWt63PiE1nTuZnqQ4RPvME7Xai+9enoiN0Wrg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -547,12 +582,13 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.4.tgz", - "integrity": "sha512-jxyg67NbEWkDyvM+O8UDbPAyYRZqGLQDTPwvrBBeOSyVWW/jFQkQKQ70JDqDSYg1ZDdl+E3nkbFbq8xM8E9x8A==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.13.tgz", + "integrity": "sha512-uP1XkqCqV2NVH9+g2sC7qIw+w2tRbcMiXFEbMihkQ8B1+V6m28sshBwAB0SDmOe0u44ne1vFU66+gx/28RsBVQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -562,12 +598,13 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.4.tgz", - "integrity": "sha512-twrmN753hjXRdcrZmZttb/m5xaCBFa48Dt3FbeEItpJArxriYDunWxJn+QFXdJ3hPkm4u7CKxncVvnmgQMY1ag==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.13.tgz", + "integrity": "sha512-V26ezyjPqQpDBV4lcWIh8B/QICQ4v+M5Bo9ykLN+sqeKKBxJVDpEc6biDVyluTXTC40f5IqCU0ttth7Es2ZuMw==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -577,12 +614,13 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.4.tgz", - "integrity": "sha512-tkLrjBzqFTP8DVrAAQmZelEahfR9OxWpFR++vAI9FBhCiIxtwHwBHC23SBHCTURBtwB4kc/x44imVOnkKGNVGg==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.13.tgz", + "integrity": "sha512-WwzOEAFBGhlDHE5Z73mNU8CO8mqMNLqaG+AO9ETmzdCQlJhVtWZnOl2+rqgVQS+YHunjOWptdFmNfbpwcUuEsw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -2902,11 +2940,76 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/editorjs-react-renderer": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/editorjs-react-renderer/-/editorjs-react-renderer-3.5.1.tgz", + "integrity": "sha512-WeFNeLDxuVyc2s7AZpAB8bfqylLXNmPxvFFgeQ8W8M95+e5QNpvpvd/JCubXYL01JDtYjFab7pTyrZva5QeF2Q==", + "license": "ISC", + "dependencies": { + "html-react-parser": "^3.0.4", + "react": "^18.2.0" + } + }, "node_modules/effect": { "version": "3.4.8", "resolved": "https://registry.npmjs.org/effect/-/effect-3.4.8.tgz", @@ -2936,6 +3039,18 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-abstract": { "version": "1.23.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", @@ -4104,6 +4219,50 @@ "node": ">= 0.4" } }, + "node_modules/html-dom-parser": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/html-dom-parser/-/html-dom-parser-3.1.7.tgz", + "integrity": "sha512-cDgNF4YgF6J3H+d9mcldGL19p0GzVdS3iGuDNzYWQpU47q3+IRM85X3Xo07E+nntF4ek4s78A9V24EwxlPTjig==", + "license": "MIT", + "dependencies": { + "domhandler": "5.0.3", + "htmlparser2": "8.0.2" + } + }, + "node_modules/html-react-parser": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-3.0.16.tgz", + "integrity": "sha512-ysQZtRFPcg+McVb4B05oNWSnqM14zagpvTgGcI5e1/BvCl38YwzWzKibrbBmXeemg70olN1bAoeixo7o06G5Eg==", + "license": "MIT", + "dependencies": { + "domhandler": "5.0.3", + "html-dom-parser": "3.1.7", + "react-property": "2.0.0", + "style-to-js": "1.1.3" + }, + "peerDependencies": { + "react": "0.14 || 15 || 16 || 17 || 18" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -4155,6 +4314,12 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", + "license": "MIT" + }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -4865,20 +5030,21 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz", + "integrity": "sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { - "nanoid": "bin/nanoid.cjs" + "nanoid": "bin/nanoid.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^18 || >=20" } }, "node_modules/natural-compare": { @@ -4888,11 +5054,12 @@ "dev": true }, "node_modules/next": { - "version": "14.2.4", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.4.tgz", - "integrity": "sha512-R8/V7vugY+822rsQGQCjoLhMuC9oFj9SOi4Cl4b2wjDrseD0LRZ10W7R6Czo4w9ZznVSshKjuIomsRjvm9EKJQ==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.13.tgz", + "integrity": "sha512-BseY9YNw8QJSwLYD7hlZzl6QVDoSFHL/URN5K64kVEVpCsSOWeyjbIGK+dZUaRViHTaMQX8aqmnn0PHBbGZezg==", + "license": "MIT", "dependencies": { - "@next/env": "14.2.4", + "@next/env": "14.2.13", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -4907,15 +5074,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.4", - "@next/swc-darwin-x64": "14.2.4", - "@next/swc-linux-arm64-gnu": "14.2.4", - "@next/swc-linux-arm64-musl": "14.2.4", - "@next/swc-linux-x64-gnu": "14.2.4", - "@next/swc-linux-x64-musl": "14.2.4", - "@next/swc-win32-arm64-msvc": "14.2.4", - "@next/swc-win32-ia32-msvc": "14.2.4", - "@next/swc-win32-x64-msvc": "14.2.4" + "@next/swc-darwin-arm64": "14.2.13", + "@next/swc-darwin-x64": "14.2.13", + "@next/swc-linux-arm64-gnu": "14.2.13", + "@next/swc-linux-arm64-musl": "14.2.13", + "@next/swc-linux-x64-gnu": "14.2.13", + "@next/swc-linux-x64-musl": "14.2.13", + "@next/swc-win32-arm64-msvc": "14.2.13", + "@next/swc-win32-ia32-msvc": "14.2.13", + "@next/swc-win32-x64-msvc": "14.2.13" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -4973,6 +5140,24 @@ "react-dom": "^16.8 || ^17 || ^18" } }, + "node_modules/next/node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -5523,6 +5708,24 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/preact": { "version": "10.22.1", "resolved": "https://registry.npmjs.org/preact/-/preact-10.22.1.tgz", @@ -5682,6 +5885,12 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, + "node_modules/react-property": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz", + "integrity": "sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw==", + "license": "MIT" + }, "node_modules/react-remove-scroll": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz", @@ -6298,6 +6507,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-to-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.3.tgz", + "integrity": "sha512-zKI5gN/zb7LS/Vm0eUwjmjrXWw8IMtyA8aPBJZdYiQTXj4+wQ3IucOLIOnF7zCHxvW8UhIGh/uZh/t9zEHXNTQ==", + "license": "MIT", + "dependencies": { + "style-to-object": "0.4.1" + } + }, + "node_modules/style-to-object": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.1.tgz", + "integrity": "sha512-HFpbb5gr2ypci7Qw+IOhnP2zOU7e77b+rzM+wTzXzfi1PrtBCX0E7Pk4wL4iTLnhzZ+JgEGAhX81ebTg/aYjQw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, "node_modules/styled-jsx": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", diff --git a/package.json b/package.json index ad5d303..a9d6a9f 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,10 @@ "@editorjs/inline-code": "^1.5.1", "@editorjs/link": "^2.6.2", "@editorjs/list": "^1.10.0", + "@editorjs/paragraph": "^2.11.6", "@editorjs/table": "^2.4.1", "@hookform/resolvers": "^3.9.0", + "@mantine/hooks": "^7.12.2", "@next-auth/prisma-adapter": "^1.0.7", "@prisma/client": "^5.18.0", "@radix-ui/react-avatar": "^1.1.0", @@ -41,9 +43,11 @@ "cmdk": "^1.0.0", "crypt": "file:", "date-fns": "^3.6.0", + "editorjs-react-renderer": "^3.5.1", "framer-motion": "^11.3.24", "lucide-react": "^0.399.0", - "next": "14.2.4", + "nanoid": "^5.0.7", + "next": "^14.2.13", "next-auth": "^4.24.7", "next-themes": "^0.3.0", "prisma": "^5.19.1", diff --git a/types/db.d.ts b/types/db.d.ts new file mode 100644 index 0000000..f01389d --- /dev/null +++ b/types/db.d.ts @@ -0,0 +1,8 @@ +import { Comment, Post, Subgroup, User, Vote } from "@prisma/client"; + +export type ExtendedPost = Post & { + subgroup: Subgroup; + votes: Vote[]; + author: User; + comments: Comment[]; +};