From 9a172d7ddb9f3db254cc93c62e478081aae56db5 Mon Sep 17 00:00:00 2001 From: Matti Nannt Date: Wed, 7 Feb 2024 15:53:36 +0100 Subject: [PATCH] fix linting issues (#7) --- .eslintrc.js | 18 + .eslintrc.json | 31 - .prettierrc.js | 21 + app/(auth)/layout.tsx | 4 +- app/(auth)/login/page.tsx | 38 +- app/(auth)/register/page.tsx | 39 +- app/(dashboard)/client-page.tsx | 11 +- app/(dashboard)/contribute/loading.tsx | 11 +- app/(dashboard)/contribute/page.tsx | 24 +- app/(dashboard)/dashboard/page.tsx | 44 +- app/(dashboard)/enroll/calcom/page.tsx | 26 +- app/(dashboard)/enroll/formbricks/page.tsx | 24 +- app/(dashboard)/enroll/loading.tsx | 6 +- app/(dashboard)/enroll/page.tsx | 58 +- app/(dashboard)/issues/loading.tsx | 6 +- app/(dashboard)/issues/page.tsx | 42 +- app/(dashboard)/layout.tsx | 47 +- app/(dashboard)/loading.tsx | 8 +- app/(dashboard)/select-repo/actions.ts | 8 +- app/(dashboard)/select-repo/loading.tsx | 6 +- app/(dashboard)/select-repo/page.tsx | 35 +- app/(dashboard)/settings/loading.tsx | 15 +- app/(dashboard)/settings/page.tsx | 26 +- app/(marketing)/layout.tsx | 29 +- app/(marketing)/page.tsx | 676 ++++++++------------- app/[profile]/layout.tsx | 22 +- app/[profile]/page.tsx | 29 +- app/layout.tsx | 31 +- app/robots.ts | 4 +- components/card-skeleton.tsx | 6 +- components/empty-placeholder.tsx | 38 +- components/header.tsx | 14 +- components/main-nav.tsx | 32 +- components/mobile-nav.tsx | 29 +- components/mode-toggle.tsx | 5 +- components/nav.tsx | 24 +- components/repo-selecor.tsx | 19 +- components/shell.tsx | 13 +- components/site-footer.tsx | 17 +- components/tailwind-indicator.tsx | 8 +- components/theme-provider.tsx | 2 +- components/ui/alert-dialog.tsx | 93 +-- components/ui/avatar.tsx | 39 +- components/ui/button.tsx | 60 +- components/ui/card.tsx | 131 ++-- components/ui/dropdown-menu.tsx | 99 ++- components/ui/input.tsx | 40 +- components/ui/label.tsx | 28 +- components/ui/logo.tsx | 14 +- components/ui/skeleton.tsx | 16 +- components/ui/toast.tsx | 74 +-- components/ui/toaster.tsx | 16 +- components/ui/use-toast.ts | 130 ++-- components/user-account-nav.tsx | 38 +- components/user-auth-form.tsx | 8 +- components/user-avatar.tsx | 13 +- components/user-name-form.tsx | 55 +- config/dashboard.ts | 6 +- config/marketing.ts | 4 +- github/constants.ts | 14 +- github/hooks/installation.ts | 23 +- github/hooks/issue.ts | 59 +- github/index.ts | 27 +- github/services/repository.ts | 22 +- github/services/user.ts | 61 +- github/utils.ts | 24 +- hooks/use-lock-body.ts | 12 +- hooks/use-mounted.ts | 10 +- lib/auth.ts | 45 +- lib/session.ts | 9 +- lib/utils.ts | 2 +- lib/validations/auth.ts | 4 +- lib/validations/og.ts | 4 +- lib/validations/post.ts | 4 +- lib/validations/user.ts | 4 +- middleware.ts | 27 +- package.json | 28 +- pages/api/auth/[...nextauth].ts | 7 +- pages/api/github-webhook.ts | 17 +- pnpm-lock.yaml | 621 +++++++++++++------ prettier.config.js | 33 - tailwind.config.ts | 3 +- types/next-auth.d.ts | 18 +- 83 files changed, 1597 insertions(+), 1891 deletions(-) create mode 100644 .eslintrc.js delete mode 100644 .eslintrc.json create mode 100644 .prettierrc.js delete mode 100644 prettier.config.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..2b305dd --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,18 @@ +module.exports = { + extends: ["next", "prettier"], + rules: { + "@next/next/no-html-link-for-pages": "off", + "react/jsx-key": "off", + }, + settings: { + next: { + rootDir: true, + }, + }, + overrides: [ + { + files: ["*.ts", "*.tsx"], + parser: "@typescript-eslint/parser", + }, + ], +}; \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 0ba73ae..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/eslintrc", - "root": true, - "extends": [ - "next/core-web-vitals", - "prettier", - "plugin:tailwindcss/recommended" - ], - "plugins": ["tailwindcss"], - "rules": { - "@next/next/no-html-link-for-pages": "off", - "react/jsx-key": "off", - "tailwindcss/no-custom-classname": "off", - "tailwindcss/classnames-order": "error" - }, - "settings": { - "tailwindcss": { - "callees": ["cn"], - "config": "tailwind.config.js" - }, - "next": { - "rootDir": true - } - }, - "overrides": [ - { - "files": ["*.ts", "*.tsx"], - "parser": "@typescript-eslint/parser" - } - ] -} diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..f31abd8 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,21 @@ +module.exports = { + bracketSpacing: true, + bracketSameLine: true, + singleQuote: false, + jsxSingleQuote: false, + trailingComma: "es5", + semi: true, + printWidth: 110, + arrowParens: "always", + importOrder: [ + // Mocks must be at the top as they contain vi.mock calls + "(.*)/__mocks__/(.*)", + "server-only", + "", + "^~/(.*)$", + "^[./]", + ], + importOrderSeparation: true, + importOrderSortSpecifiers: true, + plugins: ["@trivago/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"], +}; diff --git a/app/(auth)/layout.tsx b/app/(auth)/layout.tsx index 2172f70..a8e6032 100644 --- a/app/(auth)/layout.tsx +++ b/app/(auth)/layout.tsx @@ -1,7 +1,7 @@ interface AuthLayoutProps { - children: React.ReactNode + children: React.ReactNode; } export default function AuthLayout({ children }: AuthLayoutProps) { - return
{children}
+ return
{children}
; } diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx index 1fe2e25..cc1db15 100644 --- a/app/(auth)/login/page.tsx +++ b/app/(auth)/login/page.tsx @@ -1,27 +1,22 @@ -import { Metadata } from "next" -import Link from "next/link" -import { ChevronLeft } from "lucide-react" - -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" -import { Logo } from "@/components/ui/logo" -import { UserAuthForm } from "@/components/user-auth-form" +import { buttonVariants } from "@/components/ui/button"; +import { Logo } from "@/components/ui/logo"; +import { UserAuthForm } from "@/components/user-auth-form"; +import { cn } from "@/lib/utils"; +import { ChevronLeft } from "lucide-react"; +import { Metadata } from "next"; +import Link from "next/link"; export const metadata: Metadata = { title: "Login", description: "Login to your account", -} +}; export default function LoginPage() { return (
+ className={cn(buttonVariants({ variant: "ghost" }), "absolute left-4 top-4 md:left-8 md:top-8")}> <> Back @@ -30,23 +25,16 @@ export default function LoginPage() {
-

- Welcome back -

-

- Use Github to sign in to your account -

+

Welcome back

+

Use Github to sign in to your account

- + Don't have an account? Sign Up

- ) + ); } diff --git a/app/(auth)/register/page.tsx b/app/(auth)/register/page.tsx index a5dd407..af8b707 100644 --- a/app/(auth)/register/page.tsx +++ b/app/(auth)/register/page.tsx @@ -1,25 +1,20 @@ -import Link from "next/link" - -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" -import { Logo } from "@/components/ui/logo" -import { UserAuthForm } from "@/components/user-auth-form" +import { buttonVariants } from "@/components/ui/button"; +import { Logo } from "@/components/ui/logo"; +import { UserAuthForm } from "@/components/user-auth-form"; +import { cn } from "@/lib/utils"; +import Link from "next/link"; export const metadata = { title: "Create an account", description: "Create an account to get started.", -} +}; export default function RegisterPage() { return (
+ className={cn(buttonVariants({ variant: "ghost" }), "absolute right-4 top-4 md:right-8 md:top-8")}> Login
@@ -27,27 +22,17 @@ export default function RegisterPage() {
-

- Create an account -

-

- Use Github to create your account -

+

Create an account

+

Use Github to create your account

By clicking continue, you agree to our{" "} - + Terms of Service {" "} and{" "} - + Privacy Policy . @@ -55,5 +40,5 @@ export default function RegisterPage() {

- ) + ); } diff --git a/app/(dashboard)/client-page.tsx b/app/(dashboard)/client-page.tsx index 5c34fdf..df8021e 100644 --- a/app/(dashboard)/client-page.tsx +++ b/app/(dashboard)/client-page.tsx @@ -1,16 +1,15 @@ -"use client" +"use client"; -import { Button } from "@/components/ui/button" +import { Button } from "@/components/ui/button"; export default function ConnectGitHubAppButton() { const handleRedirect = () => { - window.location.href = - "https://github.com/apps/ossgg-test/installations/new" - } + window.location.href = "https://github.com/apps/ossgg-test/installations/new"; + }; return ( - ) + ); } diff --git a/app/(dashboard)/contribute/loading.tsx b/app/(dashboard)/contribute/loading.tsx index 01e2592..5bf7bb9 100644 --- a/app/(dashboard)/contribute/loading.tsx +++ b/app/(dashboard)/contribute/loading.tsx @@ -1,13 +1,10 @@ -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; export default function DashboardSettingsLoading() { return ( - + - ) + ); } diff --git a/app/(dashboard)/contribute/page.tsx b/app/(dashboard)/contribute/page.tsx index 610daff..1e2e656 100644 --- a/app/(dashboard)/contribute/page.tsx +++ b/app/(dashboard)/contribute/page.tsx @@ -1,28 +1,24 @@ -import { redirect } from "next/navigation" - -import { authOptions } from "@/lib/auth" -import { getCurrentUser } from "@/lib/session" -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; +import { authOptions } from "@/lib/auth"; +import { getCurrentUser } from "@/lib/session"; +import { redirect } from "next/navigation"; export const metadata = { title: "Contribute to oss.gg", description: "Help us make this more fun and engaging.", -} +}; export default async function SettingsPage() { - const user = await getCurrentUser() + const user = await getCurrentUser(); if (!user) { - redirect(authOptions?.pages?.signIn || "/login") + redirect(authOptions?.pages?.signIn || "/login"); } return ( - +
- ) + ); } diff --git a/app/(dashboard)/dashboard/page.tsx b/app/(dashboard)/dashboard/page.tsx index 9e5e3bf..8ee3c23 100644 --- a/app/(dashboard)/dashboard/page.tsx +++ b/app/(dashboard)/dashboard/page.tsx @@ -1,34 +1,30 @@ -import Link from "next/link" -import { redirect } from "next/navigation" - -import { authOptions } from "@/lib/auth" -import { getCurrentUser } from "@/lib/session" -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; +import { authOptions } from "@/lib/auth"; +import { getCurrentUser } from "@/lib/session"; +import Link from "next/link"; +import { redirect } from "next/navigation"; export const metadata = { title: "oss.gg", description: "Gamify open source contributions. Less work, more fun!", -} +}; const cards = [ { href: "/enroll", title: "Find projects", - description: - "Enroll to play. Ship code or complete non-code tasks to gather points and level up.", + description: "Enroll to play. Ship code or complete non-code tasks to gather points and level up.", }, { href: "/issues", title: "Explore open issues", - description: - "Already enrolled? Explore open issues or non-code tasks specific to each OS project.", + description: "Already enrolled? Explore open issues or non-code tasks specific to each OS project.", }, { href: "/settings", title: "Settings", - description: - "Add your address to receive merch and change notification settings.", + description: "Add your address to receive merch and change notification settings.", }, { href: "/", @@ -45,35 +41,33 @@ const cards = [ { href: "/", title: "What is oss.gg?", - description: - "Find out why we’re building this - and how you can become a part of it!", + description: "Find out why we’re building this - and how you can become a part of it!", }, -] +]; export default async function DashboardPage() { - const user = await getCurrentUser() + const user = await getCurrentUser(); if (!user) { - redirect(authOptions?.pages?.signIn || "/login") + redirect(authOptions?.pages?.signIn || "/login"); } return ( -
+
{cards.map((card) => ( + className="flex items-center space-x-3 rounded-md border border-transparent bg-slate-50 p-6 transition-all duration-150 ease-in-out hover:scale-102 hover:cursor-pointer hover:border-slate-200 hover:bg-slate-100">
-

{card.title}

-

opened by {card.description}

+

{card.title}

+

opened by {card.description}

))}
- ) + ); } diff --git a/app/(dashboard)/enroll/calcom/page.tsx b/app/(dashboard)/enroll/calcom/page.tsx index 84827c5..4fbfcfe 100644 --- a/app/(dashboard)/enroll/calcom/page.tsx +++ b/app/(dashboard)/enroll/calcom/page.tsx @@ -1,29 +1,25 @@ -import { redirect } from "next/navigation" - -import { authOptions } from "@/lib/auth" -import { getCurrentUser } from "@/lib/session" -import { Button } from "@/components/ui/button" -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; +import { Button } from "@/components/ui/button"; +import { authOptions } from "@/lib/auth"; +import { getCurrentUser } from "@/lib/session"; +import { redirect } from "next/navigation"; export const metadata = { title: "Cal.com", description: "Scheduling infrastructure for everyone.", -} +}; export default async function SettingsPage() { - const user = await getCurrentUser() + const user = await getCurrentUser(); if (!user) { - redirect(authOptions?.pages?.signIn || "/login") + redirect(authOptions?.pages?.signIn || "/login"); } return ( - + - ) + ); } diff --git a/app/(dashboard)/enroll/formbricks/page.tsx b/app/(dashboard)/enroll/formbricks/page.tsx index 0603965..6e557c4 100644 --- a/app/(dashboard)/enroll/formbricks/page.tsx +++ b/app/(dashboard)/enroll/formbricks/page.tsx @@ -1,22 +1,20 @@ -import { redirect } from "next/navigation" - -import { authOptions } from "@/lib/auth" -import { getCurrentUser } from "@/lib/session" -import { Button } from "@/components/ui/button" -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; +import { Button } from "@/components/ui/button"; +import { authOptions } from "@/lib/auth"; +import { getCurrentUser } from "@/lib/session"; +import { redirect } from "next/navigation"; export const metadata = { title: "Formbricks", - description: - "Contribute to the worlds fastest growing survey infrastructure.", -} + description: "Contribute to the worlds fastest growing survey infrastructure.", +}; export default async function SettingsPage() { - const user = await getCurrentUser() + const user = await getCurrentUser(); if (!user) { - redirect(authOptions?.pages?.signIn || "/login") + redirect(authOptions?.pages?.signIn || "/login"); } return ( @@ -26,5 +24,5 @@ export default async function SettingsPage() { /> - ) + ); } diff --git a/app/(dashboard)/enroll/loading.tsx b/app/(dashboard)/enroll/loading.tsx index 9da1ca7..b2c86cf 100644 --- a/app/(dashboard)/enroll/loading.tsx +++ b/app/(dashboard)/enroll/loading.tsx @@ -1,5 +1,5 @@ -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; export default function DashboardSettingsLoading() { return ( @@ -9,5 +9,5 @@ export default function DashboardSettingsLoading() { text="Choose open source projects you want to contribute to - and gather points!" /> - ) + ); } diff --git a/app/(dashboard)/enroll/page.tsx b/app/(dashboard)/enroll/page.tsx index c4bf43c..9422e00 100644 --- a/app/(dashboard)/enroll/page.tsx +++ b/app/(dashboard)/enroll/page.tsx @@ -1,18 +1,16 @@ -import Image from "next/image" -import Link from "next/link" -import { redirect } from "next/navigation" - -import { authOptions } from "@/lib/auth" -import { getCurrentUser } from "@/lib/session" -import { Button } from "@/components/ui/button" -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; +import { Button } from "@/components/ui/button"; +import { authOptions } from "@/lib/auth"; +import { getCurrentUser } from "@/lib/session"; +import Image from "next/image"; +import Link from "next/link"; +import { redirect } from "next/navigation"; export const metadata = { title: "Enroll to play", - description: - "Choose open source projects you want to contribute to - and gather points!", -} + description: "Choose open source projects you want to contribute to - and gather points!", +}; const dummyProjects = [ { @@ -35,13 +33,13 @@ const dummyProjects = [ bountiesPaid: "45234", key: "1", }, -] +]; export default async function SettingsPage() { - const user = await getCurrentUser() + const user = await getCurrentUser(); if (!user) { - redirect(authOptions?.pages?.signIn || "/login") + redirect(authOptions?.pages?.signIn || "/login"); } return ( @@ -54,9 +52,8 @@ export default async function SettingsPage() { -
+ className="flex justify-between space-x-5 rounded-md border border-transparent bg-slate-50 p-6 transition-all hover:border-slate-200 hover:bg-slate-100"> +
-

{project.name}

-

{project.description}

-
-
- {project.stars} ⭐ -
-
- {project.bountiesPaid} ✅ -
-
- {project.bountiesOpen} 💰 -
+

{project.name}

+

{project.description}

+
+
{project.stars} ⭐
+
{project.bountiesPaid} ✅
+
{project.bountiesOpen} 💰
))} -
+

You run an OSS project and want to be part of oss.gg?

- ) + ); } diff --git a/app/(dashboard)/issues/loading.tsx b/app/(dashboard)/issues/loading.tsx index c8d23f6..c12e1ac 100644 --- a/app/(dashboard)/issues/loading.tsx +++ b/app/(dashboard)/issues/loading.tsx @@ -1,5 +1,5 @@ -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; export default function DashboardSettingsLoading() { return ( @@ -9,5 +9,5 @@ export default function DashboardSettingsLoading() { text="Comment on these issues to get assigned to work on them." /> - ) + ); } diff --git a/app/(dashboard)/issues/page.tsx b/app/(dashboard)/issues/page.tsx index 65eeeb4..5274e28 100644 --- a/app/(dashboard)/issues/page.tsx +++ b/app/(dashboard)/issues/page.tsx @@ -1,17 +1,16 @@ -import Image from "next/image" -import Link from "next/link" -import { redirect } from "next/navigation" - -import { authOptions } from "@/lib/auth" -import { getCurrentUser } from "@/lib/session" -import { Button } from "@/components/ui/button" -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; +import { Button } from "@/components/ui/button"; +import { authOptions } from "@/lib/auth"; +import { getCurrentUser } from "@/lib/session"; +import Image from "next/image"; +import Link from "next/link"; +import { redirect } from "next/navigation"; export const metadata = { title: "Open issues", description: "Comment on these issues to get assigned to work on them.", -} +}; const dummyIssues = [ { @@ -54,13 +53,13 @@ const dummyIssues = [ points: "500", key: "4", }, -] +]; export default async function SettingsPage() { - const user = await getCurrentUser() + const user = await getCurrentUser(); if (!user) { - redirect(authOptions?.pages?.signIn || "/login") + redirect(authOptions?.pages?.signIn || "/login"); } return ( @@ -75,28 +74,21 @@ export default async function SettingsPage() { href={issue.href} target="_blank" key={issue.key} - className="bg-slate-50 rounded-md p-3 flex space-x-3 items-center hover:bg-slate-100 hover:scale-102 border border-transparent hover:border-slate-200 transition-all hover:cursor-pointer ease-in-out duration-150" - > - {issue.title} + className="flex items-center space-x-3 rounded-md border border-transparent bg-slate-50 p-3 transition-all duration-150 ease-in-out hover:scale-102 hover:cursor-pointer hover:border-slate-200 hover:bg-slate-100"> + {issue.title}

{issue.title}

-

opened by {issue.author}

+

opened by {issue.author}

)) ) : ( -
+

You have not yet enrolled to play in a repository 🕹️

)}
- ) + ); } diff --git a/app/(dashboard)/layout.tsx b/app/(dashboard)/layout.tsx index 13234e2..d120610 100644 --- a/app/(dashboard)/layout.tsx +++ b/app/(dashboard)/layout.tsx @@ -1,36 +1,33 @@ -import Image from "next/image" -import Link from "next/link" -import { notFound } from "next/navigation" +import { DashboardNav } from "@/components/nav"; +import { UserAccountNav } from "@/components/user-account-nav"; +import { dashboardConfig } from "@/config/dashboard"; +import { getCurrentUser } from "@/lib/session"; +import Image from "next/image"; +import Link from "next/link"; +import { notFound } from "next/navigation"; -import { dashboardConfig } from "@/config/dashboard" -import { getCurrentUser } from "@/lib/session" -import { DashboardNav } from "@/components/nav" -import { UserAccountNav } from "@/components/user-account-nav" - -import OSSGGLogo from "../oss-gg-logo.png" -import ConnectGitHubAppButton from "./client-page" +import OSSGGLogo from "../oss-gg-logo.png"; +import ConnectGitHubAppButton from "./client-page"; interface DashboardLayoutProps { - children?: React.ReactNode + children?: React.ReactNode; } -export default async function DashboardLayout({ - children, -}: DashboardLayoutProps) { - const user = await getCurrentUser() +export default async function DashboardLayout({ children }: DashboardLayoutProps) { + const user = await getCurrentUser(); if (!user) { - return notFound() + return notFound(); } return ( -
- +
+ oss gg logo -
- ) + ); } diff --git a/app/(dashboard)/loading.tsx b/app/(dashboard)/loading.tsx index 71d410d..67a1a01 100644 --- a/app/(dashboard)/loading.tsx +++ b/app/(dashboard)/loading.tsx @@ -1,6 +1,6 @@ -import { Button } from "@/components/ui/button" -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; +import { Button } from "@/components/ui/button"; export default function DashboardLoading() { return ( @@ -9,5 +9,5 @@ export default function DashboardLoading() { - ) + ); } diff --git a/app/(dashboard)/select-repo/actions.ts b/app/(dashboard)/select-repo/actions.ts index a6743ae..8c5bb01 100644 --- a/app/(dashboard)/select-repo/actions.ts +++ b/app/(dashboard)/select-repo/actions.ts @@ -1,7 +1,7 @@ -"use server" +"use server"; -import { selectRepository } from "@/github/services/repository" +import { selectRepository } from "@/github/services/repository"; export const selectRepoActions = async (id: string) => { - return await selectRepository(id) -} + return await selectRepository(id); +}; diff --git a/app/(dashboard)/select-repo/loading.tsx b/app/(dashboard)/select-repo/loading.tsx index 2cfe7af..494eaa2 100644 --- a/app/(dashboard)/select-repo/loading.tsx +++ b/app/(dashboard)/select-repo/loading.tsx @@ -1,5 +1,5 @@ -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; export default function SelectRepoLoading() { return ( @@ -9,5 +9,5 @@ export default function SelectRepoLoading() { text="Select the repository you want to integrate oss.gg with." /> - ) + ); } diff --git a/app/(dashboard)/select-repo/page.tsx b/app/(dashboard)/select-repo/page.tsx index 0996b7d..ce81fa3 100644 --- a/app/(dashboard)/select-repo/page.tsx +++ b/app/(dashboard)/select-repo/page.tsx @@ -1,27 +1,26 @@ -import { redirect } from "next/navigation" -import { getRepositoriesForUser } from "@/github/services/repository" +import { DashboardHeader } from "@/components/header"; +import { RepoSelector } from "@/components/repo-selecor"; +import { DashboardShell } from "@/components/shell"; +import { getRepositoriesForUser } from "@/github/services/repository"; +import { authOptions } from "@/lib/auth"; +import { db } from "@/lib/db"; +import { getCurrentUser } from "@/lib/session"; +import { redirect } from "next/navigation"; -import { authOptions } from "@/lib/auth" -import { db } from "@/lib/db" -import { getCurrentUser } from "@/lib/session" -import { DashboardHeader } from "@/components/header" -import { RepoSelector } from "@/components/repo-selecor" -import { DashboardShell } from "@/components/shell" - -import { selectRepoActions } from "./actions" +import { selectRepoActions } from "./actions"; export const metadata = { title: "Connect a Repository", description: "Select the repository you want to integrate oss.gg with.", -} +}; export default async function SelectRepoPage() { - const user = await getCurrentUser() + const user = await getCurrentUser(); if (!user) { - redirect(authOptions?.pages?.signIn || "/login") + redirect(authOptions?.pages?.signIn || "/login"); } - const repos = await getRepositoriesForUser(user.id) + const repos = await getRepositoriesForUser(user.id); return ( @@ -31,13 +30,9 @@ export default async function SelectRepoPage() { />
{repos.map((repo) => ( - + ))}
- ) + ); } diff --git a/app/(dashboard)/settings/loading.tsx b/app/(dashboard)/settings/loading.tsx index 8f9eacb..c7c0f9d 100644 --- a/app/(dashboard)/settings/loading.tsx +++ b/app/(dashboard)/settings/loading.tsx @@ -1,18 +1,15 @@ -import { Card } from "@/components/ui/card" -import { CardSkeleton } from "@/components/card-skeleton" -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" +import { CardSkeleton } from "@/components/card-skeleton"; +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; +import { Card } from "@/components/ui/card"; export default function DashboardSettingsLoading() { return ( - +
- ) + ); } diff --git a/app/(dashboard)/settings/page.tsx b/app/(dashboard)/settings/page.tsx index e6e16e0..9812e46 100644 --- a/app/(dashboard)/settings/page.tsx +++ b/app/(dashboard)/settings/page.tsx @@ -1,32 +1,28 @@ -import { redirect } from "next/navigation" - -import { authOptions } from "@/lib/auth" -import { getCurrentUser } from "@/lib/session" -import { DashboardHeader } from "@/components/header" -import { DashboardShell } from "@/components/shell" -import { UserNameForm } from "@/components/user-name-form" +import { DashboardHeader } from "@/components/header"; +import { DashboardShell } from "@/components/shell"; +import { UserNameForm } from "@/components/user-name-form"; +import { authOptions } from "@/lib/auth"; +import { getCurrentUser } from "@/lib/session"; +import { redirect } from "next/navigation"; export const metadata = { title: "Settings", description: "Manage account and website settings.", -} +}; export default async function SettingsPage() { - const user = await getCurrentUser() + const user = await getCurrentUser(); if (!user) { - redirect(authOptions?.pages?.signIn || "/login") + redirect(authOptions?.pages?.signIn || "/login"); } return ( - +
- ) + ); } diff --git a/app/(marketing)/layout.tsx b/app/(marketing)/layout.tsx index 902099c..3f412e8 100644 --- a/app/(marketing)/layout.tsx +++ b/app/(marketing)/layout.tsx @@ -1,31 +1,22 @@ -import Link from "next/link" - -import { marketingConfig } from "@/config/marketing" -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" -import { MainNav } from "@/components/main-nav" -import { SiteFooter } from "@/components/site-footer" +import { MainNav } from "@/components/main-nav"; +import { SiteFooter } from "@/components/site-footer"; +import { buttonVariants } from "@/components/ui/button"; +import { marketingConfig } from "@/config/marketing"; +import { cn } from "@/lib/utils"; +import Link from "next/link"; interface MarketingLayoutProps { - children: React.ReactNode + children: React.ReactNode; } -export default async function MarketingLayout({ - children, -}: MarketingLayoutProps) { +export default async function MarketingLayout({ children }: MarketingLayoutProps) { return (
@@ -34,5 +25,5 @@ export default async function MarketingLayout({
{children}
- ) + ); } diff --git a/app/(marketing)/page.tsx b/app/(marketing)/page.tsx index efddede..aefe13b 100644 --- a/app/(marketing)/page.tsx +++ b/app/(marketing)/page.tsx @@ -1,48 +1,44 @@ -import Image from "next/image" -import Link from "next/link" +import { buttonVariants } from "@/components/ui/button"; +import { siteConfig } from "@/config/site"; +import { env } from "@/env.mjs"; +import { cn } from "@/lib/utils"; +import Image from "next/image"; +import Link from "next/link"; -import { env } from "@/env.mjs" -import { siteConfig } from "@/config/site" -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" - -import Auto1 from "../../public/automations-1.webp" -import Auto2 from "../../public/automations-2.webp" -import Levels2 from "../../public/levels-2.webp" -import Levels1 from "../../public/levels.webp" -import MergeCeleb from "../../public/merge-celeb.webp" -import ProblemsSolved from "../../public/problems-solved.webp" -import Problems from "../../public/problems-with-contributions.webp" +import Auto1 from "../../public/automations-1.webp"; +import Auto2 from "../../public/automations-2.webp"; +import Levels2 from "../../public/levels-2.webp"; +import Levels1 from "../../public/levels.webp"; +import MergeCeleb from "../../public/merge-celeb.webp"; +import ProblemsSolved from "../../public/problems-solved.webp"; +import Problems from "../../public/problems-with-contributions.webp"; async function getGitHubStars(): Promise { try { - const response = await fetch( - "https://api.github.com/repos/formbricks/oss.gg", - { - headers: { - Accept: "application/vnd.github+json", - Authorization: `Bearer ${env.GITHUB_ACCESS_TOKEN}`, - }, - next: { - revalidate: 60, - }, - } - ) + const response = await fetch("https://api.github.com/repos/formbricks/oss.gg", { + headers: { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${env.GITHUB_ACCESS_TOKEN}`, + }, + next: { + revalidate: 60, + }, + }); if (!response?.ok) { - return null + return null; } - const json = await response.json() + const json = await response.json(); - return parseInt(json["stargazers_count"]).toLocaleString() + return parseInt(json["stargazers_count"]).toLocaleString(); } catch (error) { - return null + return null; } } export default async function IndexPage() { - const stars = await getGitHubStars() + const stars = await getGitHubStars(); return ( <> @@ -62,110 +58,85 @@ export default async function IndexPage() { href={siteConfig.links.github} target="_blank" rel="noreferrer" - className={cn(buttonVariants({ variant: "outline", size: "lg" }))} - > + className={cn(buttonVariants({ variant: "outline", size: "lg" }))}> GitHub
-
-
-
-
+
+
+
+
-
-

- What’s oss.gg, why we need it and how you can become a part of it 🕹️ +
+

+ What's oss.gg, why we need it and how you can become a part of it 🕹️

- The concept of oss.gg emerged from a common challenge faced by - many open source founders and maintainers: the struggle to balance - community contributions while fully focusing on developing the - core product. In this write-up, we'll walk you through the most - common problems around community contributions, what has been - tried to solve them, what worked well and how oss.gg tries to - innovate in this space. Let's dive in! + The concept of oss.gg emerged from a common challenge faced by many open source founders and + maintainers: the struggle to balance community contributions while fully focusing on developing + the core product. In this write-up, we'll walk you through the most common problems around + community contributions, what has been tried to solve them, what worked well and how oss.gg + tries to innovate in this space. Let's dive in!

- Around 18 months ago, we released snoopForms - the Open Source - Typeform alternative. Within days, we had people request features - and offer contributions to make snoopForms better. While we loved - the spirit, we quickly experienced the challenges that come along - with running an open source community. + Around 18 months ago, we released snoopForms - the Open Source Typeform alternative. Within days, + we had people request features and offer contributions to make snoopForms better. While we loved + the spirit, we quickly experienced the challenges that come along with running an open source + community.

- Our experience isn’t unique. As we are building Formnbricks, we got - to know many more open source founders and all of them made a - similar experience. These are 8 problems we all face, in some - variation: + Our experience isn't unique. As we are building Formnbricks, we got to know many more open + source founders and all of them made a similar experience. These are 8 problems we all face, in + some variation:

- Problems + Problems

- This is a slide from a talk Johannes gave at the Open Core Summit in - San Francisco: + This is a slide from a talk Johannes gave at the Open Core Summit in San Francisco:

-
+
+ allowFullScreen>

- Before we dive in, let’s have a look at what you can expect from the - rest of this article: + Before we dive in, let's have a look at what you can expect from the rest of this article:

  1. + href="#the-open-source-renaissance-and-what-it-did-to-communities"> Open source communities have changed and need new tools
  2. - + The problem(s) of open source communities
  3. - - What's been tried (and what we’ve learned) + + What's been tried (and what we've learned)
  4. - + oss.gg - the concept
  5. - + oss.gg - the tech
  6. @@ -176,164 +147,127 @@ export default async function IndexPage() {
-

- What’s the purpose of this blog post? +

+ What's the purpose of this blog post?

We want to catalyse the conversation.

- There is something in the air right now, lots of people work on - different ideas to one or several of these problems. Most do it as a - side project, which likely won’t work out, because community stuff - is hard. The idea is to bring everyone onto the same page so we can - move forward with a joint understanding and build something that - works together. So everything laid out in this article is up for - discussion, it’s supposed to get you involved 😉 + There is something in the air right now, lots of people work on different ideas to one or several + of these problems. Most do it as a side project, which likely won't work out, because + community stuff is hard. The idea is to bring everyone onto the same page so we can move forward + with a joint understanding and build something that works together. So everything laid out in this + article is up for discussion, it's supposed to get you involved 😉

+ className="mb-4 mt-3 text-2xl font-medium" + id="the-open-source-renaissance-and-what-it-did-to-communities"> The Open Source Renaissance and what it did to communities

- With the rise of hugely popular open source tools like Supabase, - Appflowy, cal.com (and Formbricks obviously 😋) open source - experiences something like a Renaissance. And it seems that this - also has a significant impact on the composition of open source - communities: + With the rise of hugely popular open source tools like Supabase, Appflowy, cal.com (and Formbricks + obviously 😋) open source experiences something like a Renaissance. And it seems that this also + has a significant impact on the composition of open source communities:

- Five years ago, open source contributions were mostly done by - experienced engineers with domain expertise who wanted to bring a - new technology to the world. + Five years ago, open source contributions were mostly done by experienced engineers with domain + expertise who wanted to bring a new technology to the world.

- Today, this cohort is outnumbered by young, aspiring engineers - predominantly from India, Pakistan, Nigeria, Kenia and several other - countries throughout Africa. They are mostly interested in working - on a product with real users, learn new technologies, learn from - more experienced product people and engineers and build a portfolio - of contributions to land a job in tech. + Today, this cohort is outnumbered by young, aspiring engineers predominantly from India, Pakistan, + Nigeria, Kenia and several other countries throughout Africa. They are mostly interested in + working on a product with real users, learn new technologies, learn from more experienced product + people and engineers and build a portfolio of contributions to land a job in tech.

- When the community changes, a new set of issues arises. These issues - call for a new set of tools, one of which is oss.gg - but let’s look - at what we’re solving first: + When the community changes, a new set of issues arises. These issues call for a new set of tools, + one of which is oss.gg - but let's look at what we're solving first:

-

+

The problem(s)

- With a new set of community members contributing to open source, we - see a new problems: + With a new set of community members contributing to open source, we see a new problems:

-
    +
    1. Handholding required: - Many of the engineers wanting to contribute have little experience - in software engineering or web development. They ask a lot of - questions, get stuck, need help. While maintainers are usually - happy to help the first set of contributors, it quickly gets out - of hand. We’ve referred juniors to ChatGPT a lot, but some things - need to be explained. While it’s fun to teach, we have to make - sure the efforts are not in vain because the contributor does not - stick around. + Many of the engineers wanting to contribute have little experience in software engineering or + web development. They ask a lot of questions, get stuck, need help. While maintainers are + usually happy to help the first set of contributors, it quickly gets out of hand. We've + referred juniors to ChatGPT a lot, but some things need to be explained. While it's fun to + teach, we have to make sure the efforts are not in vain because the contributor does not stick + around.
    2. Seniors leaving: - Every now and then, a more senior engineer gets excited by a - project and contributes. That’s obviously really cool and - valuable. The issue? They usually don’t stick around. While it’s - not an issue that a company with a commercialisation interest - maintains a project (vs. a completely free and community-run - project) these seniors make 1, 2, 3 contributions and then ask - themselves, why they are spending their evenings and weekends - creating value which will be harvest by someone else. Curiosity - and altruism only go so far. So why not pay them?{" "} + Every now and then, a more senior engineer gets excited by a project and contributes. + That's obviously really cool and valuable. The issue? They usually don't stick around. + While it's not an issue that a company with a commercialisation interest maintains a + project (vs. a completely free and community-run project) these seniors make 1, 2, 3 + contributions and then ask themselves, why they are spending their evenings and weekends + creating value which will be harvest by someone else. Curiosity and altruism only go so far. So + why not pay them?{" "}
    3. Incentive dilemma: - Incentives are a funny thing because they can shift the mental - model for looking at something. There is lots of research proving - that a financial incentive can lower the motivation for a specific - task, because it takes the aspects of reciprocity and signalling - out of the picture: If I receive money for it, I won’t get a - favour back nor can I tell myself I worked for the greater good - and feel good about it. This, and the short-term thinking attached - to doing the minimum to get the financial reward make it difficult - to just hang a price tag to an issue and wait for someone to fix - it properly. In most cases, it’s a quick and dirty patch. + Incentives are a funny thing because they can shift the mental model for looking at something. + There is lots of research proving that a financial incentive can lower the motivation for a + specific task, because it takes the aspects of reciprocity and signalling out of the picture: If + I receive money for it, I won't get a favour back nor can I tell myself I worked for the + greater good and feel good about it. This, and the short-term thinking attached to doing the + minimum to get the financial reward make it difficult to just hang a price tag to an issue and + wait for someone to fix it properly. In most cases, it's a quick and dirty patch.
    4. Review overhead: - Most tools of the Open Source Renaissance are maintained by small - teams. These teams are busy shipping features requested by their - design partners or large clients because after all, they are who - keep the project alive. Reviewing community contributions - generally and submitted by junior devs unfamiliar with the code - base is verrry time-consuming. We have to minimize the effort - reviews take to make the whole effort worthwhile. + Most tools of the Open Source Renaissance are maintained by small teams. These teams are busy + shipping features requested by their design partners or large clients because after all, they + are who keep the project alive. Reviewing community contributions generally and submitted by + junior devs unfamiliar with the code base is verrry time-consuming. We have to minimize the + effort reviews take to make the whole effort worthwhile.
    5. Manual recognition: - People keep coming back when they feel recognized. It not only - feels good to be appreciated for the time invested but is also an - important signal, for both side: Contributors can showcase their - work publicly (and share it) and projects show that their project - is actively contributed to. Win win. The only issue? It’s - time-consuming to keep track, write content and find the social - handles of contributors to tag them. This can be semi-automated. + People keep coming back when they feel recognized. It not only feels good to be appreciated for + the time invested but is also an important signal, for both side: Contributors can showcase + their work publicly (and share it) and projects show that their project is actively contributed + to. Win win. The only issue? It's time-consuming to keep track, write content and find the + social handles of contributors to tag them. This can be semi-automated.
    6. Hard to flex: - Along with the projects effort to recognize contributors, these - contributors have a hard time flexing with their contributions. - There isn’t really a good plaform to do that. Important - contributions on GitHub profiles get lost in other activity. CVs - are outdated. Contributors want a publicly accessible page where - they can collect contributions like stickers. + Along with the projects effort to recognize contributors, these contributors have a hard time + flexing with their contributions. There isn't really a good plaform to do that. Important + contributions on GitHub profiles get lost in other activity. CVs are outdated. Contributors want + a publicly accessible page where they can collect contributions like stickers.
    7. Assignment overhead & redundant work: - Keeping track of who works on which issue can get messy with an - active community. We ran a hackathon with a Macbook prize and for - every issue we released we had 5 people who wanted to work on it. - First come, first assigned works well, until people claim issues - and don’t deliver. This can be solved by automating the - enforcement of rules such as “If you don’t open a draft PR within - 48h, we will assign the issue to the next developer in line”. + Keeping track of who works on which issue can get messy with an active community. We ran a + hackathon with a Macbook prize and for every issue we released we had 5 people who wanted to + work on it. First come, first assigned works well, until people claim issues and don't + deliver. This can be solved by automating the enforcement of rules such as “If you don't + open a draft PR within 48h, we will assign the issue to the next developer in line”.
    8. Unfinished PRs - Along the lines of the previous problem: If contributors drop out, - maintainers have to notice. To be able to do that we have to - monitor all issues manually. It’d be much easier if a GitHub app - would do that for us. + Along the lines of the previous problem: If contributors drop out, maintainers have to notice. + To be able to do that we have to monitor all issues manually. It'd be much easier if a + GitHub app would do that for us.
    -

    +

    What has been tried so far

    -

    +

    The FormTribe hackathon

    - The idea of building a large-scale distributed learning game is - already a couple of months old. In October, we (the{" "} - Formbricks team) ran a - month-long gamified hackathon. It was great fun and worked really - well! We gained: + The idea of building a large-scale distributed learning game is already a couple of months old. In + October, we (the Formbricks team) ran a month-long + gamified hackathon. It was great fun and worked really well! We gained:

    -
      +
      • 100 contributors 👩‍💻
      • Shipped 12 relevant features
      • 2.000 GitHub stars ⭐
      • @@ -345,216 +279,148 @@ export default async function IndexPage() {

        What have we learned?

        -

        - Having so many developers pull on our repo led to a few great - insights: -

        -
          -
        • - It crystallised our understanding of the problems in the space, as - laid out above -
        • +

          Having so many developers pull on our repo led to a few great insights:

          +
            +
          • It crystallised our understanding of the problems in the space, as laid out above
          • - Points work (if they have a value). People really made sure to - collect all points they earned + Points work (if they have a value). People really made sure to collect all points they earned
          • Non-code contributions are picked up and appreciated
          • Manual overhead was unsustainable
          • -
          • - There is enough excitement for it to be worth building a system -
          • +
          • There is enough excitement for it to be worth building a system
          -

          - Novu’s Hero Directory +

          + Novu's Hero Directory

          Novu built a pretty cool directory of their{" "} - + community heroes.

          - Each contributor automatically gets a page with their contributions - with data being pulled from the GitHub API. People really appreciate - that, both contributors and other OSS founders - well done 😎 + Each contributor automatically gets a page with their contributions with data being pulled from + the GitHub API. People really appreciate that, both contributors and other OSS founders - well + done 😎

          -

          - Algora’s Bounty System +

          + Algora's Bounty System

          - The Algora team did a great job building a well-functioning GitHub - app as well as attracting a community of bounty-hungry contributors. - However, tying back to what I wrote above about incentives, I don’t - think it solve the right problem. In our experience (and what I’ve - heard from other projects) it’s not hard to find people who want to - contribute. It’s much harder to handle the contributions and keep - people familiar with the code base engaged over longer periods of - time. To some extent, bounties make the situation worse by sending - engineers our way who are only looking for a quick buck. They tend - to be more spammy and push for a quick review of their half-baked - code. This might sound harsh but it has been exactly our experience. + The Algora team did a great job building a well-functioning GitHub app as well as attracting a + community of bounty-hungry contributors. However, tying back to what I wrote above about + incentives, I don't think it solve the right problem. In our experience (and what I've + heard from other projects) it's not hard to find people who want to contribute. It's + much harder to handle the contributions and keep people familiar with the code base engaged over + longer periods of time. To some extent, bounties make the situation worse by sending engineers our + way who are only looking for a quick buck. They tend to be more spammy and push for a quick review + of their half-baked code. This might sound harsh but it has been exactly our experience.

          - We strongly believe in bounties and they are an essential element of{" "} - oss.gg but they have to be wrapped in a bigger picture (see below). + We strongly believe in bounties and they are an essential element of oss.gg but they have to be + wrapped in a bigger picture (see below).

          - Please note: I’m fully aware that many projects are - happy with Algora and their success justifies their approach :) + Please note: I'm fully aware that many projects are happy with Algora and + their success justifies their approach :)

          -

          +

          What is oss.gg?

          - So far we looked at the problems and what has been tried to solve - some of them. Let’s now have a closer look at how we imagine oss.gg - solve for all of the problems above. + So far we looked at the problems and what has been tried to solve some of them. Let's now + have a closer look at how we imagine oss.gg solve for all of the problems above.

          -

          +

          oss.gg - the concept

          To address all of the issues above, we leverage two things:{" "} Levels and Automations.

          -

          +

          Levels

          - Levels usually come with a set of abilities and limitations, which - comes in really handy. Here are the levels we came up with at - Formbricks, but each project will be able to come up with their own + Levels usually come with a set of abilities and limitations, which comes in really handy. Here are + the levels we came up with at Formbricks, but each project will be able to come up with their own levels which align with their brand voice and ideas:

          - Levels are fun -

          - The beauty of levels is that they make it very easy to communicate - and understand who is allowed to do what. Here is an overview: -

          - so much fun + Levels are fun

          - How does this help us? Let’s look at the problems: + The beauty of levels is that they make it very easy to communicate and understand who is allowed + to do what. Here is an overview:

          -
            + so much fun +

            How does this help us? Let's look at the problems:

            +
            • - Handholding: By limiting who can get assigned to - e.g. issues for end-to-end features, we limit the requests for - handholding significantly. We know that every “Deploy Deputy” - already went through a set of DevRel related tasks so is somewhat - familiar with the code base and tech stack. Secondly, we can - filter out a lot of the “I can quickly ship this” engineers. - Additionally, we as a team don’t have to help dozens of engineers - set up their development environment by limiting support to GitPod - when contributors are getting started. + Handholding: By limiting who can get assigned to e.g. issues for end-to-end + features, we limit the requests for handholding significantly. We know that every “Deploy + Deputy” already went through a set of DevRel related tasks so is somewhat familiar with the code + base and tech stack. Secondly, we can filter out a lot of the “I can quickly ship this” + engineers. Additionally, we as a team don't have to help dozens of engineers set up their + development environment by limiting support to GitPod when contributors are getting started.
            • - Seniors leaving + incentive dilemma: Earning the - right to be paid for contributions has a lot of positive side - effects. We exclude the “quick-buck-engineers” and reward sticking - around our community. Everyone in the Pushmaster Prime level has - merged several PRs in our repo so we know they are familiar with - the code style and capable. This allows us to pay out high - bounties without having to fear a lot of spam in out repo and - Discord. + Seniors leaving + incentive dilemma: Earning the right to be paid for + contributions has a lot of positive side effects. We exclude the “quick-buck-engineers” and + reward sticking around our community. Everyone in the Pushmaster Prime level has merged several + PRs in our repo so we know they are familiar with the code style and capable. This allows us to + pay out high bounties without having to fear a lot of spam in out repo and Discord.

            - These are only a handful of very basic ideas of what you can do with - levels. Super excited to see what other projects will invent and - implement 🤓 -

            - Problems -

            + These are only a handful of very basic ideas of what you can do with levels. Super excited to see + what other projects will invent and implement 🤓 +

            + Problems +

            Leveling up, merch and moments of celebration

            - A core aspect of building a community people love is sharing moments - of celebration with others. As an aspiring open source contributor, - there are a few moments we want to celebrate together: The first PR - getting merged, the first bounty earned, etc. + A core aspect of building a community people love is sharing moments of celebration with others. + As an aspiring open source contributor, there are a few moments we want to celebrate together: The + first PR getting merged, the first bounty earned, etc.

            - Secondly, handling merch is kinda annoying: You have to determine - who gets merch, when and why. We decided to just tie it to leveling - up, so that we can semi-automate it. If a user levels up, we check - if their address is added and if not, we ask them to update it. Once - this is done, we can order their merch (or even automate that as - well). + Secondly, handling merch is kinda annoying: You have to determine who gets merch, when and why. We + decided to just tie it to leveling up, so that we can semi-automate it. If a user levels up, we + check if their address is added and if not, we ask them to update it. Once this is done, we can + order their merch (or even automate that as well).

            -

            +

            Automations

            - The second big advantage of oss.gg is that you can automate many of - the tedious tasks - while making sure that the personal touch is not - getting lost. The key here is to strike the right balance. + The second big advantage of oss.gg is that you can automate many of the tedious tasks - while + making sure that the personal touch is not getting lost. The key here is to strike the right + balance.

            - Here is an example for what happens when a new issue is released - which is flagged as a community issue: + Here is an example for what happens when a new issue is released which is flagged as a community + issue:

            - Automations 2 - Automations + Automations 2 + Automations

            - As you can see, most of the overhead is automated away. We go from - Issue → Review without anyone in our team having to touch the issue - on GitHub. Especially when the number of issues grows, this will - come in super handy. + As you can see, most of the overhead is automated away. We go from Issue → Review without anyone + in our team having to touch the issue on GitHub. Especially when the number of issues grows, this + will come in super handy.

            Here is another one:

            - Automations + Automations

            - The Merge Celebration Flow. It nicely shows how the - community management side can get automated without losing the - personal touch. + The Merge Celebration Flow. It nicely shows how the community management side can + get automated without losing the personal touch.

            You get the idea!

            -

            +

            oss.gg - the tech

            - Now that we have an understanding of what we want to build and why, - let’s talk about the how. oss.gg consists of 5 different parts: + Now that we have an understanding of what we want to build and why, let's talk about the how. + oss.gg consists of 5 different parts:

            1. A web app +
            2. @@ -563,103 +429,87 @@ export default async function IndexPage() {
            3. A bounty system +
            4. An automations interface
            -

            Let’s go through them one by one:

            -

            +

            Let's go through them one by one:

            +

            1. A Web App

            - The heart of oss.gg is a web app. Both contributors and projects can - sign up to preform a set of actions. Here is a preliminary overview - of what people can do with the web app: + The heart of oss.gg is a web app. Both contributors and projects can sign up to preform a set of + actions. Here is a preliminary overview of what people can do with the web app:

            Contributors

            -
              +
              • Sign up
              • Add their social handles (to be tagged in shoutouts)
              • Add their address (to receive merch)
              • View a feed of issues they can work on
              • -
              • - Manage notification settings (alerts for issues they are eligible - to work on) -
              • +
              • Manage notification settings (alerts for issues they are eligible to work on)

              Projects

              -
                +
                • Manage API keys
                • Manage rights for different levels contributors can reach
                -

                +

                2. An API

                - The API provides all oss.gg related info so that the projects can - display them on their community pages. Think of it as an enrichment - layer over the GitHub API. It serves: + The API provides all oss.gg related info so that the projects can display them on their community + pages. Think of it as an enrichment layer over the GitHub API. It serves:

                -
                  +
                  • Points per contributor
                  • Contributor Level
                  • Contributor Rank
                  • -
                  • - Contributor social handles and addresses to build automations -
                  • +
                  • Contributor social handles and addresses to build automations
                  -

                  +

                  3. A GitHub App

                  - The GitHub app takes over many of the tasks which currently require - manual work. It makes the following things easy: + The GitHub app takes over many of the tasks which currently require manual work. It makes the + following things easy:

                  -
                    +
                    • - Assign first contributor to issue, if eligible (has enough points - / level required for this issue) + Assign first contributor to issue, if eligible (has enough points / level required for this + issue)
                    • -
                    • Unassign and reassign if contributor doesn’t ship
                    • +
                    • Unassign and reassign if contributor doesn't ship
                    • Follows up with dormant PRs
                    • Makes awarding points easy “/award 500 points”
                    • Makes tipping easy “/tip 10$”
                    • Create new bounty “/bounty $50”
                    -

                    +

                    4. A Bounty System

                    - Shoutout to Bailey who built a low-fee bounty system for the OSSHack - in NYC. It’s a very convenient and inexpensive way to pay out - bounties worldwide. We’ll leverage that for anyone who wants to open - a bounty for an issue. + Shoutout to Bailey who built a low-fee bounty system for the OSSHack in NYC. It's a very + convenient and inexpensive way to pay out bounties worldwide. We'll leverage that for anyone + who wants to open a bounty for an issue.

                    -

                    +

                    5. An Automations Interface (later on)

                    - Create automations based on triggers like “Contributor reaches new - Level” or “Contributor reaches X points” or “First contribution” - etc. These automations help us provide a personalized community - experience at scale, because we can e.g. create a new Linear ticket - for the Marketing team containing all info needed to write a tweet - and send a personal message to the contributor within 60 seconds. + Create automations based on triggers like “Contributor reaches new Level” or “Contributor reaches + X points” or “First contribution” etc. These automations help us provide a personalized community + experience at scale, because we can e.g. create a new Linear ticket for the Marketing team + containing all info needed to write a tweet and send a personal message to the contributor within + 60 seconds.

                    -

                    +

                    The oss.gg stack

                    -
                      +
                      • Next.js (React) + Typescript
                      • - TailwindCss +{" "} - ui.shadcn.com + TailwindCss + ui.shadcn.com
                      • PostgreSQL + Prisma
                      • Unkey? Anything to make building APIs easy?
                      • @@ -667,44 +517,38 @@ export default async function IndexPage() { trigger.dev for automations
                      -

                      +

                      What is the status quo?

                      - We’ve shipped the core for this launch so that we as a community can - pick up the fun stuff right away. Here is a broad plan forward: + We've shipped the core for this launch so that we as a community can pick up the fun stuff + right away. Here is a broad plan forward:

                      - Phase 1: To keep iteration cycles short, we limit - the number of projects who can participate to 2. This allows us to - build a solution which is somewhat generalizable (vs. - Formbricks-specific). And less people involved = faster shipping - speed! Once we have figured what works well we move to Phase 2. + Phase 1: To keep iteration cycles short, we limit the number of projects who can + participate to 2. This allows us to build a solution which is somewhat generalizable (vs. + Formbricks-specific). And less people involved = faster shipping speed! Once we have figured what + works well we move to Phase 2.

                      - Phase 2: We open oss.gg up to a total of 5 select - projects. These projects commit to work closely with the community - by providing sufficient open issues for the community members to - work on. + Phase 2: We open oss.gg up to a total of 5 select projects. These projects commit + to work closely with the community by providing sufficient open issues for the community members + to work on.

                      - Phase 3: Opening up to more and more projects. When - and how will be determined in the future. + Phase 3: Opening up to more and more projects. When and how will be determined in + the future.

                      -

                      +

                      Call for Contributions!

                      - Interested? Sign up on our waitlist to stay in the - loop + Interested? Sign up on our waitlist to stay in the loop

                      Have something to share?{" "} - Schedule a call with - me to share your experiences and ideas to make oss.gg better! + Schedule a call with me to share your experiences + and ideas to make oss.gg better!

                      Wanna help build? Join the oss.gg Discord! @@ -713,16 +557,14 @@ export default async function IndexPage() {

-

- 🕹️ -

+

🕹️

- Let's play + Let's play
- ) + ); } diff --git a/app/[profile]/layout.tsx b/app/[profile]/layout.tsx index 4b92ec6..96cf2d1 100644 --- a/app/[profile]/layout.tsx +++ b/app/[profile]/layout.tsx @@ -1,29 +1,27 @@ -import { getCurrentUser } from "@/lib/session" -import { Button } from "@/components/ui/button" -import { Logo } from "@/components/ui/logo" -import { SiteFooter } from "@/components/site-footer" +import { SiteFooter } from "@/components/site-footer"; +import { Button } from "@/components/ui/button"; +import { Logo } from "@/components/ui/logo"; +import { getCurrentUser } from "@/lib/session"; interface ProfileLayoutProps { - children?: React.ReactNode + children?: React.ReactNode; } export default async function ProfileLayout({ children }: ProfileLayoutProps) { - const user = await getCurrentUser() + const user = await getCurrentUser(); return (
-
-
+
+
-
- {children} -
+
{children}
- ) + ); } diff --git a/app/[profile]/page.tsx b/app/[profile]/page.tsx index df5e68a..c367251 100644 --- a/app/[profile]/page.tsx +++ b/app/[profile]/page.tsx @@ -1,22 +1,22 @@ -import Image from "next/image" -import Link from "next/link" -import { Twitter } from "lucide-react" +import { Twitter } from "lucide-react"; +import Image from "next/image"; +import Link from "next/link"; export const metadata = { title: "Profile Page", -} +}; async function fetchGithubUserData(userName: string) { - const res = await fetch(`https://api.github.com/users/${userName}`) - const data = await res.json() - return data + const res = await fetch(`https://api.github.com/users/${userName}`); + const data = await res.json(); + return data; } export default async function ProfilePage({ params }) { - const userData = await fetchGithubUserData(params.profile) + const userData = await fetchGithubUserData(params.profile); return (
-
+
github avatar
-

{userData.name}

+

{userData.name}

{userData.bio}

- + @@ -45,5 +42,5 @@ export default async function ProfilePage({ params }) {
- ) + ); } diff --git a/app/layout.tsx b/app/layout.tsx index 10e7a70..f3cc443 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,20 +1,18 @@ -import { Inter as FontSans } from "next/font/google" - -import { siteConfig } from "@/config/site" -import { cn } from "@/lib/utils" -import { Toaster } from "@/components/ui/toaster" -import { TailwindIndicator } from "@/components/tailwind-indicator" -import { ThemeProvider } from "@/components/theme-provider" - -import "@/styles/globals.css" +import { TailwindIndicator } from "@/components/tailwind-indicator"; +import { ThemeProvider } from "@/components/theme-provider"; +import { Toaster } from "@/components/ui/toaster"; +import { siteConfig } from "@/config/site"; +import { cn } from "@/lib/utils"; +import "@/styles/globals.css"; +import { Inter as FontSans } from "next/font/google"; const fontSans = FontSans({ subsets: ["latin"], variable: "--font-sans", -}) +}); interface RootLayoutProps { - children: React.ReactNode + children: React.ReactNode; } export const metadata = { @@ -52,18 +50,13 @@ export const metadata = { apple: "/apple-touch-icon.png", }, manifest: `${siteConfig.url}/site.webmanifest`, -} +}; export default function RootLayout({ children }: RootLayoutProps) { return ( - + {children} @@ -71,5 +64,5 @@ export default function RootLayout({ children }: RootLayoutProps) { - ) + ); } diff --git a/app/robots.ts b/app/robots.ts index f86f167..fc42c63 100644 --- a/app/robots.ts +++ b/app/robots.ts @@ -1,4 +1,4 @@ -import { MetadataRoute } from "next" +import { MetadataRoute } from "next"; export default function robots(): MetadataRoute.Robots { return { @@ -6,5 +6,5 @@ export default function robots(): MetadataRoute.Robots { userAgent: "*", allow: "/", }, - } + }; } diff --git a/components/card-skeleton.tsx b/components/card-skeleton.tsx index e945cc0..31bec20 100644 --- a/components/card-skeleton.tsx +++ b/components/card-skeleton.tsx @@ -1,5 +1,5 @@ -import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card" -import { Skeleton } from "@/components/ui/skeleton" +import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; export function CardSkeleton() { return ( @@ -13,5 +13,5 @@ export function CardSkeleton() { - ) + ); } diff --git a/components/empty-placeholder.tsx b/components/empty-placeholder.tsx index 3ef32e2..1222f01 100644 --- a/components/empty-placeholder.tsx +++ b/components/empty-placeholder.tsx @@ -1,23 +1,17 @@ -import * as React from "react"; - import { cn } from "@/lib/utils"; import { DoorClosed } from "lucide-react"; +import * as React from "react"; interface EmptyPlaceholderProps extends React.HTMLAttributes {} -export function EmptyPlaceholder({ - className, - children, - ...props -}: EmptyPlaceholderProps) { +export function EmptyPlaceholder({ className, children, ...props }: EmptyPlaceholderProps) { return (
+ {...props}>
{children}
@@ -25,11 +19,7 @@ export function EmptyPlaceholder({ ); } -EmptyPlaceholder.Icon = function EmptyPlaceHolderIcon({ - name, - className, - ...props -}) { +EmptyPlaceholder.Icon = function EmptyPlaceHolderIcon({ name, className, ...props }) { return (
@@ -37,20 +27,13 @@ EmptyPlaceholder.Icon = function EmptyPlaceHolderIcon({ ); }; -interface EmptyPlacholderTitleProps - extends React.HTMLAttributes {} +interface EmptyPlacholderTitleProps extends React.HTMLAttributes {} -EmptyPlaceholder.Title = function EmptyPlaceholderTitle({ - className, - ...props -}: EmptyPlacholderTitleProps) { - return ( -

- ); +EmptyPlaceholder.Title = function EmptyPlaceholderTitle({ className, ...props }: EmptyPlacholderTitleProps) { + return

; }; -interface EmptyPlacholderDescriptionProps - extends React.HTMLAttributes {} +interface EmptyPlacholderDescriptionProps extends React.HTMLAttributes {} EmptyPlaceholder.Description = function EmptyPlaceholderDescription({ className, @@ -58,10 +41,7 @@ EmptyPlaceholder.Description = function EmptyPlaceholderDescription({ }: EmptyPlacholderDescriptionProps) { return (

); diff --git a/components/header.tsx b/components/header.tsx index 4cfdb47..0b7e993 100644 --- a/components/header.tsx +++ b/components/header.tsx @@ -1,14 +1,10 @@ interface DashboardHeaderProps { - heading: string - text?: string - children?: React.ReactNode + heading: string; + text?: string; + children?: React.ReactNode; } -export function DashboardHeader({ - heading, - text, - children, -}: DashboardHeaderProps) { +export function DashboardHeader({ heading, text, children }: DashboardHeaderProps) { return (

@@ -17,5 +13,5 @@ export function DashboardHeader({
{children}
- ) + ); } diff --git a/components/main-nav.tsx b/components/main-nav.tsx index e2f4dd1..39a6467 100644 --- a/components/main-nav.tsx +++ b/components/main-nav.tsx @@ -1,22 +1,21 @@ -"use client" +"use client"; -import * as React from "react" -import { useSelectedLayoutSegment } from "next/navigation" -import { X } from "lucide-react" +import { MobileNav } from "@/components/mobile-nav"; +import { X } from "lucide-react"; +import { useSelectedLayoutSegment } from "next/navigation"; +import * as React from "react"; +import { MainNavItem } from "types"; -import { MainNavItem } from "types" -import { MobileNav } from "@/components/mobile-nav" - -import { Logo } from "./ui/logo" +import { Logo } from "./ui/logo"; interface MainNavProps { - items?: MainNavItem[] - children?: React.ReactNode + items?: MainNavItem[]; + children?: React.ReactNode; } export function MainNav({ items, children }: MainNavProps) { - const segment = useSelectedLayoutSegment() - const [showMobileMenu, setShowMobileMenu] = React.useState(false) + const segment = useSelectedLayoutSegment(); + const [showMobileMenu, setShowMobileMenu] = React.useState(false); return (
@@ -43,14 +42,11 @@ export function MainNav({ items, children }: MainNavProps) { ) : null} */} - {showMobileMenu && items && ( - {children} - )} + {showMobileMenu && items && {children}}
- ) + ); } diff --git a/components/mobile-nav.tsx b/components/mobile-nav.tsx index 0a4e668..4dfd818 100644 --- a/components/mobile-nav.tsx +++ b/components/mobile-nav.tsx @@ -1,27 +1,25 @@ -import * as React from "react" -import Link from "next/link" +import { siteConfig } from "@/config/site"; +import { useLockBody } from "@/hooks/use-lock-body"; +import { cn } from "@/lib/utils"; +import Link from "next/link"; +import * as React from "react"; +import { MainNavItem } from "types"; -import { MainNavItem } from "types" -import { siteConfig } from "@/config/site" -import { cn } from "@/lib/utils" -import { useLockBody } from "@/hooks/use-lock-body" - -import { Logo } from "./ui/logo" +import { Logo } from "./ui/logo"; interface MobileNavProps { - items: MainNavItem[] - children?: React.ReactNode + items: MainNavItem[]; + children?: React.ReactNode; } export function MobileNav({ items, children }: MobileNavProps) { - useLockBody() + useLockBody(); return (
+ )}>
@@ -35,8 +33,7 @@ export function MobileNav({ items, children }: MobileNavProps) { className={cn( "flex w-full items-center rounded-md p-2 text-sm font-medium hover:underline", item.disabled && "cursor-not-allowed opacity-60" - )} - > + )}> {item.title} ))} @@ -44,5 +41,5 @@ export function MobileNav({ items, children }: MobileNavProps) { {children}
- ) + ); } diff --git a/components/mode-toggle.tsx b/components/mode-toggle.tsx index 31203cd..759bf62 100644 --- a/components/mode-toggle.tsx +++ b/components/mode-toggle.tsx @@ -1,8 +1,5 @@ "use client"; -import * as React from "react"; -import { useTheme } from "next-themes"; - import { Button } from "@/components/ui/button"; import { DropdownMenu, @@ -11,6 +8,8 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Laptop, Moon, Sun } from "lucide-react"; +import { useTheme } from "next-themes"; +import * as React from "react"; export function ModeToggle() { const { setTheme } = useTheme(); diff --git a/components/nav.tsx b/components/nav.tsx index f0749e3..6eb3b74 100644 --- a/components/nav.tsx +++ b/components/nav.tsx @@ -1,20 +1,19 @@ -"use client" +"use client"; -import Link from "next/link" -import { usePathname } from "next/navigation" - -import { BottomNavItem } from "types" -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { BottomNavItem } from "types"; interface DashboardNavProps { - items: BottomNavItem[] + items: BottomNavItem[]; } export function DashboardNav({ items }: DashboardNavProps) { - const path = usePathname() + const path = usePathname(); if (!items?.length) { - return null + return null; } return ( @@ -28,14 +27,13 @@ export function DashboardNav({ items }: DashboardNavProps) { "group flex items-center rounded-md px-3 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground", path === item.href ? "bg-accent" : "transparent", item.disabled && "cursor-not-allowed opacity-80" - )} - > + )}> {item.title} ) - ) + ); })} - ) + ); } diff --git a/components/repo-selecor.tsx b/components/repo-selecor.tsx index 3bd32ef..0320dda 100644 --- a/components/repo-selecor.tsx +++ b/components/repo-selecor.tsx @@ -1,21 +1,20 @@ -"use client" +"use client"; -import { useToast } from "@/components/ui/use-toast" +import { useToast } from "@/components/ui/use-toast"; export const RepoSelector = ({ repo, selectRepoAction }) => { - const { toast } = useToast() + const { toast } = useToast(); return (
{ - selectRepoAction(repo.id) + selectRepoAction(repo.id); toast({ title: `${repo.name} selected`, description: "Next steps to be built", - }) - }} - > + }); + }}> {repo.name}
- ) -} + ); +}; diff --git a/components/shell.tsx b/components/shell.tsx index ee95821..564a957 100644 --- a/components/shell.tsx +++ b/components/shell.tsx @@ -1,17 +1,12 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; +import * as React from "react"; interface DashboardShellProps extends React.HTMLAttributes {} -export function DashboardShell({ - children, - className, - ...props -}: DashboardShellProps) { +export function DashboardShell({ children, className, ...props }: DashboardShellProps) { return (
{children}
- ) + ); } diff --git a/components/site-footer.tsx b/components/site-footer.tsx index a30a5c2..a890bf9 100644 --- a/components/site-footer.tsx +++ b/components/site-footer.tsx @@ -1,8 +1,7 @@ -import * as React from "react" - -import { siteConfig } from "@/config/site" -import { cn } from "@/lib/utils" -import { ModeToggle } from "@/components/mode-toggle" +import { ModeToggle } from "@/components/mode-toggle"; +import { siteConfig } from "@/config/site"; +import { cn } from "@/lib/utils"; +import * as React from "react"; export function SiteFooter({ className }: React.HTMLAttributes) { return ( @@ -15,8 +14,7 @@ export function SiteFooter({ className }: React.HTMLAttributes) { href={siteConfig.links.twitter} target="_blank" rel="noreferrer" - className="font-medium underline underline-offset-4" - > + className="font-medium underline underline-offset-4"> Formbricks . The source code is available on{" "} @@ -24,8 +22,7 @@ export function SiteFooter({ className }: React.HTMLAttributes) { href={siteConfig.links.github} target="_blank" rel="noreferrer" - className="font-medium underline underline-offset-4" - > + className="font-medium underline underline-offset-4"> GitHub . @@ -34,5 +31,5 @@ export function SiteFooter({ className }: React.HTMLAttributes) {

- ) + ); } diff --git a/components/tailwind-indicator.tsx b/components/tailwind-indicator.tsx index 5bd69ac..0058d5a 100644 --- a/components/tailwind-indicator.tsx +++ b/components/tailwind-indicator.tsx @@ -1,16 +1,14 @@ export function TailwindIndicator() { - if (process.env.NODE_ENV === "production") return null + if (process.env.NODE_ENV === "production") return null; return (
xs
-
- sm -
+
sm
md
lg
xl
2xl
- ) + ); } diff --git a/components/theme-provider.tsx b/components/theme-provider.tsx index b4e8e4f..93d93c0 100644 --- a/components/theme-provider.tsx +++ b/components/theme-provider.tsx @@ -1,8 +1,8 @@ "use client"; -import * as React from "react"; import { ThemeProvider as NextThemesProvider } from "next-themes"; import { ThemeProviderProps } from "next-themes/dist/types"; +import * as React from "react"; export function ThemeProvider({ children, ...props }: ThemeProviderProps) { return {children}; diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx index 25e7b47..510995e 100644 --- a/components/ui/alert-dialog.tsx +++ b/components/ui/alert-dialog.tsx @@ -1,16 +1,15 @@ -"use client" +"use client"; -import * as React from "react" -import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" +import { buttonVariants } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; +import * as React from "react"; -import { cn } from "@/lib/utils" -import { buttonVariants } from "@/components/ui/button" +const AlertDialog = AlertDialogPrimitive.Root; -const AlertDialog = AlertDialogPrimitive.Root +const AlertDialogTrigger = AlertDialogPrimitive.Trigger; -const AlertDialogTrigger = AlertDialogPrimitive.Trigger - -const AlertDialogPortal = AlertDialogPrimitive.Portal +const AlertDialogPortal = AlertDialogPrimitive.Portal; const AlertDialogOverlay = React.forwardRef< React.ElementRef, @@ -24,8 +23,8 @@ const AlertDialogOverlay = React.forwardRef< {...props} ref={ref} /> -)) -AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName +)); +AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; const AlertDialogContent = React.forwardRef< React.ElementRef, @@ -42,48 +41,29 @@ const AlertDialogContent = React.forwardRef< {...props} /> -)) -AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName +)); +AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; -const AlertDialogHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -AlertDialogHeader.displayName = "AlertDialogHeader" +const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( +
+); +AlertDialogHeader.displayName = "AlertDialogHeader"; -const AlertDialogFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( +const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes) => (
-) -AlertDialogFooter.displayName = "AlertDialogFooter" +); +AlertDialogFooter.displayName = "AlertDialogFooter"; const AlertDialogTitle = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName + +)); +AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; const AlertDialogDescription = React.forwardRef< React.ElementRef, @@ -94,21 +74,16 @@ const AlertDialogDescription = React.forwardRef< className={cn("text-sm text-muted-foreground", className)} {...props} /> -)) -AlertDialogDescription.displayName = - AlertDialogPrimitive.Description.displayName +)); +AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName; const AlertDialogAction = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName + +)); +AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; const AlertDialogCancel = React.forwardRef< React.ElementRef, @@ -116,15 +91,11 @@ const AlertDialogCancel = React.forwardRef< >(({ className, ...props }, ref) => ( -)) -AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName +)); +AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; export { AlertDialog, @@ -138,4 +109,4 @@ export { AlertDialogDescription, AlertDialogAction, AlertDialogCancel, -} +}; diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx index 51e507b..0591788 100644 --- a/components/ui/avatar.tsx +++ b/components/ui/avatar.tsx @@ -1,9 +1,8 @@ -"use client" +"use client"; -import * as React from "react" -import * as AvatarPrimitive from "@radix-ui/react-avatar" - -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; +import * as AvatarPrimitive from "@radix-ui/react-avatar"; +import * as React from "react"; const Avatar = React.forwardRef< React.ElementRef, @@ -11,26 +10,19 @@ const Avatar = React.forwardRef< >(({ className, ...props }, ref) => ( -)) -Avatar.displayName = AvatarPrimitive.Root.displayName +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; const AvatarImage = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -AvatarImage.displayName = AvatarPrimitive.Image.displayName + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; const AvatarFallback = React.forwardRef< React.ElementRef, @@ -38,13 +30,10 @@ const AvatarFallback = React.forwardRef< >(({ className, ...props }, ref) => ( -)) -AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; -export { Avatar, AvatarImage, AvatarFallback } +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/components/ui/button.tsx b/components/ui/button.tsx index e7c6973..142619d 100644 --- a/components/ui/button.tsx +++ b/components/ui/button.tsx @@ -1,8 +1,7 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; +import { Slot } from "@radix-ui/react-slot"; +import { type VariantProps, cva } from "class-variance-authority"; +import * as React from "react"; 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", @@ -10,12 +9,9 @@ const buttonVariants = cva( 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", + 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", }, @@ -31,36 +27,22 @@ const buttonVariants = cva( size: "default", }, } -) +); export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { - asChild?: boolean - href?: string - openInNewTab?: boolean + asChild?: boolean; + href?: string; + openInNewTab?: boolean; } -const Button = React.forwardRef< - HTMLButtonElement | HTMLAnchorElement, - ButtonProps ->( - ( - { - className, - variant, - size, - asChild = false, - href, - openInNewTab = false, - ...props - }, - ref - ) => { - let Comp: React.ElementType = asChild ? Slot : "button" +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, href, openInNewTab = false, ...props }, ref) => { + let Comp: React.ElementType = asChild ? Slot : "button"; if (href) { - Comp = "a" // Use anchor tag if href is provided + Comp = "a"; // Use anchor tag if href is provided } return ( @@ -69,14 +51,12 @@ const Button = React.forwardRef< className={cn(buttonVariants({ variant, size }), className)} ref={ref} {...props} - {...(href && openInNewTab - ? { target: "_blank", rel: "noopener noreferrer" } - : {})} + {...(href && openInNewTab ? { target: "_blank", rel: "noopener noreferrer" } : {})} /> - ) + ); } -) +); -Button.displayName = "Button" +Button.displayName = "Button"; -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/components/ui/card.tsx b/components/ui/card.tsx index afa13ec..6213d88 100644 --- a/components/ui/card.tsx +++ b/components/ui/card.tsx @@ -1,79 +1,52 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -const Card = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -Card.displayName = "Card" - -const CardHeader = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardHeader.displayName = "CardHeader" - -const CardTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardTitle.displayName = "CardTitle" - -const CardDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardDescription.displayName = "CardDescription" - -const CardContent = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardContent.displayName = "CardContent" - -const CardFooter = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardFooter.displayName = "CardFooter" - -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } +import { cn } from "@/lib/utils"; +import * as React from "react"; + +const Card = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef>( + ({ className, ...props }, ref) => ( +

+ ) +); +CardTitle.displayName = "CardTitle"; + +const CardDescription = React.forwardRef>( + ({ className, ...props }, ref) => ( +

+ ) +); +CardDescription.displayName = "CardDescription"; + +const CardContent = React.forwardRef>( + ({ className, ...props }, ref) =>

+); +CardContent.displayName = "CardContent"; + +const CardFooter = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +CardFooter.displayName = "CardFooter"; + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }; diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx index f69a0d6..9b97435 100644 --- a/components/ui/dropdown-menu.tsx +++ b/components/ui/dropdown-menu.tsx @@ -1,27 +1,26 @@ -"use client" +"use client"; -import * as React from "react" -import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" -import { Check, ChevronRight, Circle } from "lucide-react" +import { cn } from "@/lib/utils"; +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { Check, ChevronRight, Circle } from "lucide-react"; +import * as React from "react"; -import { cn } from "@/lib/utils" +const DropdownMenu = DropdownMenuPrimitive.Root; -const DropdownMenu = DropdownMenuPrimitive.Root +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; -const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger +const DropdownMenuGroup = DropdownMenuPrimitive.Group; -const DropdownMenuGroup = DropdownMenuPrimitive.Group +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; -const DropdownMenuPortal = DropdownMenuPrimitive.Portal +const DropdownMenuSub = DropdownMenuPrimitive.Sub; -const DropdownMenuSub = DropdownMenuPrimitive.Sub - -const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; const DropdownMenuSubTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { - inset?: boolean + inset?: boolean; } >(({ className, inset, children, ...props }, ref) => ( + {...props}> {children} -)) -DropdownMenuSubTrigger.displayName = - DropdownMenuPrimitive.SubTrigger.displayName +)); +DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName; const DropdownMenuSubContent = React.forwardRef< React.ElementRef, @@ -52,9 +49,8 @@ const DropdownMenuSubContent = React.forwardRef< )} {...props} /> -)) -DropdownMenuSubContent.displayName = - DropdownMenuPrimitive.SubContent.displayName +)); +DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName; const DropdownMenuContent = React.forwardRef< React.ElementRef, @@ -71,13 +67,13 @@ const DropdownMenuContent = React.forwardRef< {...props} /> -)) -DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; const DropdownMenuItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { - inset?: boolean + inset?: boolean; } >(({ className, inset, ...props }, ref) => ( -)) -DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; const DropdownMenuCheckboxItem = React.forwardRef< React.ElementRef, @@ -103,8 +99,7 @@ const DropdownMenuCheckboxItem = React.forwardRef< className )} checked={checked} - {...props} - > + {...props}> @@ -112,9 +107,8 @@ const DropdownMenuCheckboxItem = React.forwardRef< {children} -)) -DropdownMenuCheckboxItem.displayName = - DropdownMenuPrimitive.CheckboxItem.displayName +)); +DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName; const DropdownMenuRadioItem = React.forwardRef< React.ElementRef, @@ -126,8 +120,7 @@ const DropdownMenuRadioItem = React.forwardRef< "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className )} - {...props} - > + {...props}> @@ -135,26 +128,22 @@ const DropdownMenuRadioItem = React.forwardRef< {children} -)) -DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName +)); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; const DropdownMenuLabel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { - inset?: boolean + inset?: boolean; } >(({ className, inset, ...props }, ref) => ( -)) -DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; const DropdownMenuSeparator = React.forwardRef< React.ElementRef, @@ -165,21 +154,13 @@ const DropdownMenuSeparator = React.forwardRef< className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} /> -)) -DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName - -const DropdownMenuShortcut = ({ - className, - ...props -}: React.HTMLAttributes) => { - return ( - - ) -} -DropdownMenuShortcut.displayName = "DropdownMenuShortcut" +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { + return ; +}; +DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; export { DropdownMenu, @@ -197,4 +178,4 @@ export { DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuRadioGroup, -} +}; diff --git a/components/ui/input.tsx b/components/ui/input.tsx index 677d05f..fc0d342 100644 --- a/components/ui/input.tsx +++ b/components/ui/input.tsx @@ -1,25 +1,21 @@ -import * as React from "react" +import { cn } from "@/lib/utils"; +import * as React from "react"; -import { cn } from "@/lib/utils" +export interface InputProps extends React.InputHTMLAttributes {} -export interface InputProps - extends React.InputHTMLAttributes {} +const Input = React.forwardRef(({ className, type, ...props }, ref) => { + return ( + + ); +}); +Input.displayName = "Input"; -const Input = React.forwardRef( - ({ className, type, ...props }, ref) => { - return ( - - ) - } -) -Input.displayName = "Input" - -export { Input } +export { Input }; diff --git a/components/ui/label.tsx b/components/ui/label.tsx index 5341821..8b42d4a 100644 --- a/components/ui/label.tsx +++ b/components/ui/label.tsx @@ -1,26 +1,20 @@ -"use client" +"use client"; -import * as React from "react" -import * as LabelPrimitive from "@radix-ui/react-label" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; +import * as LabelPrimitive from "@radix-ui/react-label"; +import { type VariantProps, cva } from "class-variance-authority"; +import * as React from "react"; const labelVariants = cva( "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" -) +); const Label = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef & - VariantProps + React.ComponentPropsWithoutRef & VariantProps >(({ className, ...props }, ref) => ( - -)) -Label.displayName = LabelPrimitive.Root.displayName + +)); +Label.displayName = LabelPrimitive.Root.displayName; -export { Label } +export { Label }; diff --git a/components/ui/logo.tsx b/components/ui/logo.tsx index cf62516..63053bd 100644 --- a/components/ui/logo.tsx +++ b/components/ui/logo.tsx @@ -1,15 +1,15 @@ -import Image from "next/image" -import Link from "next/link" +import Image from "next/image"; +import Link from "next/link"; -import OSSGGLogoDark from "../../app/oss-gg-logo-dark.png" -import OSSGGLogoLight from "../../app/oss-gg-logo.png" +import OSSGGLogoDark from "../../app/oss-gg-logo-dark.png"; +import OSSGGLogoLight from "../../app/oss-gg-logo.png"; export const Logo = ({ theme = "light" }) => { - const logoSrc = theme === "dark" ? OSSGGLogoDark : OSSGGLogoLight + const logoSrc = theme === "dark" ? OSSGGLogoDark : OSSGGLogoLight; return ( gamify open source contributions - ) -} + ); +}; diff --git a/components/ui/skeleton.tsx b/components/ui/skeleton.tsx index 01b8b6d..6690a13 100644 --- a/components/ui/skeleton.tsx +++ b/components/ui/skeleton.tsx @@ -1,15 +1,7 @@ -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; -function Skeleton({ - className, - ...props -}: React.HTMLAttributes) { - return ( -
- ) +function Skeleton({ className, ...props }: React.HTMLAttributes) { + return
; } -export { Skeleton } +export { Skeleton }; diff --git a/components/ui/toast.tsx b/components/ui/toast.tsx index a822477..6bde619 100644 --- a/components/ui/toast.tsx +++ b/components/ui/toast.tsx @@ -1,11 +1,10 @@ -import * as React from "react" -import * as ToastPrimitives from "@radix-ui/react-toast" -import { cva, type VariantProps } from "class-variance-authority" -import { X } from "lucide-react" +import { cn } from "@/lib/utils"; +import * as ToastPrimitives from "@radix-ui/react-toast"; +import { type VariantProps, cva } from "class-variance-authority"; +import { X } from "lucide-react"; +import * as React from "react"; -import { cn } from "@/lib/utils" - -const ToastProvider = ToastPrimitives.Provider +const ToastProvider = ToastPrimitives.Provider; const ToastViewport = React.forwardRef< React.ElementRef, @@ -19,8 +18,8 @@ const ToastViewport = React.forwardRef< )} {...props} /> -)) -ToastViewport.displayName = ToastPrimitives.Viewport.displayName +)); +ToastViewport.displayName = ToastPrimitives.Viewport.displayName; const toastVariants = cva( "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", @@ -28,30 +27,22 @@ const toastVariants = cva( variants: { variant: { default: "border bg-background text-foreground", - destructive: - "destructive group border-destructive bg-destructive text-destructive-foreground", + destructive: "destructive group border-destructive bg-destructive text-destructive-foreground", }, }, defaultVariants: { variant: "default", }, } -) +); const Toast = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef & - VariantProps + React.ComponentPropsWithoutRef & VariantProps >(({ className, variant, ...props }, ref) => { - return ( - - ) -}) -Toast.displayName = ToastPrimitives.Root.displayName + return ; +}); +Toast.displayName = ToastPrimitives.Root.displayName; const ToastAction = React.forwardRef< React.ElementRef, @@ -65,8 +56,8 @@ const ToastAction = React.forwardRef< )} {...props} /> -)) -ToastAction.displayName = ToastPrimitives.Action.displayName +)); +ToastAction.displayName = ToastPrimitives.Action.displayName; const ToastClose = React.forwardRef< React.ElementRef, @@ -79,40 +70,31 @@ const ToastClose = React.forwardRef< className )} toast-close="" - {...props} - > + {...props}> -)) -ToastClose.displayName = ToastPrimitives.Close.displayName +)); +ToastClose.displayName = ToastPrimitives.Close.displayName; const ToastTitle = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -ToastTitle.displayName = ToastPrimitives.Title.displayName + +)); +ToastTitle.displayName = ToastPrimitives.Title.displayName; const ToastDescription = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -ToastDescription.displayName = ToastPrimitives.Description.displayName + +)); +ToastDescription.displayName = ToastPrimitives.Description.displayName; -type ToastProps = React.ComponentPropsWithoutRef +type ToastProps = React.ComponentPropsWithoutRef; -type ToastActionElement = React.ReactElement +type ToastActionElement = React.ReactElement; export { type ToastProps, @@ -124,4 +106,4 @@ export { ToastDescription, ToastClose, ToastAction, -} +}; diff --git a/components/ui/toaster.tsx b/components/ui/toaster.tsx index e223385..3aa665d 100644 --- a/components/ui/toaster.tsx +++ b/components/ui/toaster.tsx @@ -1,4 +1,4 @@ -"use client" +"use client"; import { Toast, @@ -7,11 +7,11 @@ import { ToastProvider, ToastTitle, ToastViewport, -} from "@/components/ui/toast" -import { useToast } from "@/components/ui/use-toast" +} from "@/components/ui/toast"; +import { useToast } from "@/components/ui/use-toast"; export function Toaster() { - const { toasts } = useToast() + const { toasts } = useToast(); return ( @@ -20,16 +20,14 @@ export function Toaster() {
{title && {title}} - {description && ( - {description} - )} + {description && {description}}
{action}
- ) + ); })}
- ) + ); } diff --git a/components/ui/use-toast.ts b/components/ui/use-toast.ts index 1671307..d606687 100644 --- a/components/ui/use-toast.ts +++ b/components/ui/use-toast.ts @@ -1,76 +1,72 @@ // Inspired by react-hot-toast library -import * as React from "react" +import type { ToastActionElement, ToastProps } from "@/components/ui/toast"; +import * as React from "react"; -import type { - ToastActionElement, - ToastProps, -} from "@/components/ui/toast" - -const TOAST_LIMIT = 1 -const TOAST_REMOVE_DELAY = 1000000 +const TOAST_LIMIT = 1; +const TOAST_REMOVE_DELAY = 1000000; type ToasterToast = ToastProps & { - id: string - title?: React.ReactNode - description?: React.ReactNode - action?: ToastActionElement -} + id: string; + title?: React.ReactNode; + description?: React.ReactNode; + action?: ToastActionElement; +}; const actionTypes = { ADD_TOAST: "ADD_TOAST", UPDATE_TOAST: "UPDATE_TOAST", DISMISS_TOAST: "DISMISS_TOAST", REMOVE_TOAST: "REMOVE_TOAST", -} as const +} as const; -let count = 0 +let count = 0; function genId() { - count = (count + 1) % Number.MAX_SAFE_INTEGER - return count.toString() + count = (count + 1) % Number.MAX_SAFE_INTEGER; + return count.toString(); } -type ActionType = typeof actionTypes +type ActionType = typeof actionTypes; type Action = | { - type: ActionType["ADD_TOAST"] - toast: ToasterToast + type: ActionType["ADD_TOAST"]; + toast: ToasterToast; } | { - type: ActionType["UPDATE_TOAST"] - toast: Partial + type: ActionType["UPDATE_TOAST"]; + toast: Partial; } | { - type: ActionType["DISMISS_TOAST"] - toastId?: ToasterToast["id"] + type: ActionType["DISMISS_TOAST"]; + toastId?: ToasterToast["id"]; } | { - type: ActionType["REMOVE_TOAST"] - toastId?: ToasterToast["id"] - } + type: ActionType["REMOVE_TOAST"]; + toastId?: ToasterToast["id"]; + }; interface State { - toasts: ToasterToast[] + toasts: ToasterToast[]; } -const toastTimeouts = new Map>() +const toastTimeouts = new Map>(); const addToRemoveQueue = (toastId: string) => { if (toastTimeouts.has(toastId)) { - return + return; } const timeout = setTimeout(() => { - toastTimeouts.delete(toastId) + toastTimeouts.delete(toastId); dispatch({ type: "REMOVE_TOAST", toastId: toastId, - }) - }, TOAST_REMOVE_DELAY) + }); + }, TOAST_REMOVE_DELAY); - toastTimeouts.set(toastId, timeout) -} + toastTimeouts.set(toastId, timeout); +}; export const reducer = (state: State, action: Action): State => { switch (action.type) { @@ -78,27 +74,25 @@ export const reducer = (state: State, action: Action): State => { return { ...state, toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), - } + }; case "UPDATE_TOAST": return { ...state, - toasts: state.toasts.map((t) => - t.id === action.toast.id ? { ...t, ...action.toast } : t - ), - } + toasts: state.toasts.map((t) => (t.id === action.toast.id ? { ...t, ...action.toast } : t)), + }; case "DISMISS_TOAST": { - const { toastId } = action + const { toastId } = action; // ! Side effects ! - This could be extracted into a dismissToast() action, // but I'll keep it here for simplicity if (toastId) { - addToRemoveQueue(toastId) + addToRemoveQueue(toastId); } else { state.toasts.forEach((toast) => { - addToRemoveQueue(toast.id) - }) + addToRemoveQueue(toast.id); + }); } return { @@ -111,44 +105,44 @@ export const reducer = (state: State, action: Action): State => { } : t ), - } + }; } case "REMOVE_TOAST": if (action.toastId === undefined) { return { ...state, toasts: [], - } + }; } return { ...state, toasts: state.toasts.filter((t) => t.id !== action.toastId), - } + }; } -} +}; -const listeners: Array<(state: State) => void> = [] +const listeners: Array<(state: State) => void> = []; -let memoryState: State = { toasts: [] } +let memoryState: State = { toasts: [] }; function dispatch(action: Action) { - memoryState = reducer(memoryState, action) + memoryState = reducer(memoryState, action); listeners.forEach((listener) => { - listener(memoryState) - }) + listener(memoryState); + }); } -type Toast = Omit +type Toast = Omit; function toast({ ...props }: Toast) { - const id = genId() + const id = genId(); const update = (props: ToasterToast) => dispatch({ type: "UPDATE_TOAST", toast: { ...props, id }, - }) - const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) + }); + const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }); dispatch({ type: "ADD_TOAST", @@ -157,36 +151,36 @@ function toast({ ...props }: Toast) { id, open: true, onOpenChange: (open) => { - if (!open) dismiss() + if (!open) dismiss(); }, }, - }) + }); return { id: id, dismiss, update, - } + }; } function useToast() { - const [state, setState] = React.useState(memoryState) + const [state, setState] = React.useState(memoryState); React.useEffect(() => { - listeners.push(setState) + listeners.push(setState); return () => { - const index = listeners.indexOf(setState) + const index = listeners.indexOf(setState); if (index > -1) { - listeners.splice(index, 1) + listeners.splice(index, 1); } - } - }, [state]) + }; + }, [state]); return { ...state, toast, dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), - } + }; } -export { useToast, toast } +export { useToast, toast }; diff --git a/components/user-account-nav.tsx b/components/user-account-nav.tsx index 3b36cb8..238b6d3 100644 --- a/components/user-account-nav.tsx +++ b/components/user-account-nav.tsx @@ -1,22 +1,21 @@ -"use client" - -import { User } from "next-auth" -import { signOut } from "next-auth/react" +"use client"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" -import { UserAvatar } from "@/components/user-avatar" +} from "@/components/ui/dropdown-menu"; +import { UserAvatar } from "@/components/user-avatar"; +import { User } from "next-auth"; +import { signOut } from "next-auth/react"; interface UserAccountNavProps { user: { - name: User["name"] - avatarUrl: User["image"] - email?: User["email"] - } + name: User["name"]; + avatarUrl: User["image"]; + email?: User["email"]; + }; } const topNavigation = [ @@ -24,12 +23,12 @@ const topNavigation = [ { label: "Enroll to play", url: "/enroll" }, { label: "Settings", url: "/settings" }, { label: "Your profile", url: "/", target: "_blank" }, -] +]; const bottomNavigation = [ { label: "What is oss.gg?", url: "https://oss.gg", target: "_blank" }, { label: "Help build oss.gg", url: "/contribute" }, -] +]; export function UserAccountNav({ user }: UserAccountNavProps) { return ( @@ -44,25 +43,20 @@ export function UserAccountNav({ user }: UserAccountNavProps) {
{user.name &&

{user.name}

} - {user.email && ( -

- {user.email} -

- )} + {user.email &&

{user.email}

}
{ - event.preventDefault() + event.preventDefault(); signOut({ callbackUrl: `${window.location.origin}/login`, - }) - }} - > + }); + }}> Sign out - ) + ); } diff --git a/components/user-auth-form.tsx b/components/user-auth-form.tsx index 61ca3ed..9dcb7dd 100644 --- a/components/user-auth-form.tsx +++ b/components/user-auth-form.tsx @@ -1,11 +1,10 @@ "use client"; -import { signIn } from "next-auth/react"; -import * as React from "react"; - import { buttonVariants } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { Loader2 } from "lucide-react"; +import { signIn } from "next-auth/react"; +import * as React from "react"; import { FaGithub } from "react-icons/fa"; interface UserAuthFormProps extends React.HTMLAttributes {} @@ -22,8 +21,7 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) { setIsGitHubLoading(true); signIn("github"); }} - disabled={isGitHubLoading} - > + disabled={isGitHubLoading}> {isGitHubLoading ? ( ) : ( diff --git a/components/user-avatar.tsx b/components/user-avatar.tsx index 7da1dd4..ffe0d83 100644 --- a/components/user-avatar.tsx +++ b/components/user-avatar.tsx @@ -1,11 +1,10 @@ -import { User } from "@prisma/client" -import { AvatarProps } from "@radix-ui/react-avatar" -import { UserIcon } from "lucide-react" - -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { User } from "@prisma/client"; +import { AvatarProps } from "@radix-ui/react-avatar"; +import { UserIcon } from "lucide-react"; interface UserAvatarProps extends AvatarProps { - user: Pick + user: Pick; } export function UserAvatar({ user, ...props }: UserAvatarProps) { @@ -20,5 +19,5 @@ export function UserAvatar({ user, ...props }: UserAvatarProps) { )} - ) + ); } diff --git a/components/user-name-form.tsx b/components/user-name-form.tsx index b800b75..5966845 100644 --- a/components/user-name-form.tsx +++ b/components/user-name-form.tsx @@ -1,27 +1,19 @@ "use client"; -import * as React from "react"; -import { useRouter } from "next/navigation"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { User } from "@prisma/client"; -import { useForm } from "react-hook-form"; -import * as z from "zod"; - -import { cn } from "@/lib/utils"; -import { userNameSchema } from "@/lib/validations/user"; import { buttonVariants } from "@/components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { toast } from "@/components/ui/use-toast"; +import { cn } from "@/lib/utils"; +import { userNameSchema } from "@/lib/validations/user"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { User } from "@prisma/client"; import { Loader2Icon } from "lucide-react"; +import { useRouter } from "next/navigation"; +import * as React from "react"; +import { useForm } from "react-hook-form"; +import * as z from "zod"; interface UserNameFormProps extends React.HTMLAttributes { user: Pick; @@ -52,24 +44,18 @@ export function UserNameForm({ user, className, ...props }: UserNameFormProps) { return toast({ title: "Something went wrong.", - description: - "The server action to save the user name is not yet implemented", + description: "The server action to save the user name is not yet implemented", variant: "destructive", }); } return ( -
+ Your Name - Please enter your full name or a display name you are comfortable - with. + Please enter your full name or a display name you are comfortable with. @@ -77,23 +63,12 @@ export function UserNameForm({ user, className, ...props }: UserNameFormProps) { - - {errors?.name && ( -

{errors.name.message}

- )} + + {errors?.name &&

{errors.name.message}

}
- diff --git a/config/dashboard.ts b/config/dashboard.ts index 6665fab..eb4c259 100644 --- a/config/dashboard.ts +++ b/config/dashboard.ts @@ -8,7 +8,7 @@ export const dashboardConfig: DashboardConfig = { { title: "Your profile", href: "/", external: true }, ], bottomNav: [ - { title: "What is oss.gg?", href: "/", external: true}, - { title: "Help build oss.gg", href: "/contribute" }, + { title: "What is oss.gg?", href: "/", external: true }, + { title: "Help build oss.gg", href: "/contribute" }, ], -}; \ No newline at end of file +}; diff --git a/config/marketing.ts b/config/marketing.ts index ff341f6..baa4d29 100644 --- a/config/marketing.ts +++ b/config/marketing.ts @@ -1,4 +1,4 @@ -import { MarketingConfig } from "types" +import { MarketingConfig } from "types"; export const marketingConfig: MarketingConfig = { mainNav: [ @@ -19,4 +19,4 @@ export const marketingConfig: MarketingConfig = { href: "/docs", }, ], -} +}; diff --git a/github/constants.ts b/github/constants.ts index 4dd2099..2f89c4a 100644 --- a/github/constants.ts +++ b/github/constants.ts @@ -1,9 +1,9 @@ -import { env } from "@/env.mjs" +import { env } from "@/env.mjs"; -export const LEVEL_LABEL = "level" +export const LEVEL_LABEL = "level"; -export const ASSIGN_IDENTIFIER = "/assign" as const -export const UNASSIGN_IDENTIFIER = "/unassign" as const +export const ASSIGN_IDENTIFIER = "/assign" as const; +export const UNASSIGN_IDENTIFIER = "/unassign" as const; export enum EVENT_TRIGGERS { ISSUE_OPENED = "issues.opened", @@ -11,8 +11,8 @@ export enum EVENT_TRIGGERS { ISSUE_COMMENTED = "issue_comment.created", } -export const ON_NEW_ISSUE = "Thanks for opening an issue! It's live on oss.gg!" +export const ON_NEW_ISSUE = "Thanks for opening an issue! It's live on oss.gg!"; -export const ON_REPO_NOT_REGISTERED = `This repository is not registered with oss.gg. Please register it at https://oss.gg.` +export const ON_REPO_NOT_REGISTERED = `This repository is not registered with oss.gg. Please register it at https://oss.gg.`; -export const GITHUB_APP_APP_ID = env.GITHUB_APP_APP_ID as string +export const GITHUB_APP_APP_ID = env.GITHUB_APP_APP_ID as string; diff --git a/github/hooks/installation.ts b/github/hooks/installation.ts index c7d08aa..3a7d170 100644 --- a/github/hooks/installation.ts +++ b/github/hooks/installation.ts @@ -1,19 +1,14 @@ -import { Webhooks } from "@octokit/webhooks" +import { Webhooks } from "@octokit/webhooks"; -import { EVENT_TRIGGERS } from "../constants" -import { sendInstallationDetails } from "../services/user" +import { EVENT_TRIGGERS } from "../constants"; +import { sendInstallationDetails } from "../services/user"; export const onInstallationCreated = async (webhooks: Webhooks) => { webhooks.on(EVENT_TRIGGERS.INSTALLATION_CREATED, async (context) => { - const installationId = context.payload.installation.id - const appId = context.payload.installation.app_id - const repos = context.payload.repositories + const installationId = context.payload.installation.id; + const appId = context.payload.installation.app_id; + const repos = context.payload.repositories; - await sendInstallationDetails( - installationId, - appId, - repos, - context.payload.installation - ) - }) -} + await sendInstallationDetails(installationId, appId, repos, context.payload.installation); + }); +}; diff --git a/github/hooks/issue.ts b/github/hooks/issue.ts index 85da7ae..bbf2c3a 100644 --- a/github/hooks/issue.ts +++ b/github/hooks/issue.ts @@ -1,18 +1,13 @@ -import { readFileSync } from "fs" -import path from "path" -import { Webhooks } from "@octokit/webhooks" +import { Webhooks } from "@octokit/webhooks"; +import { readFileSync } from "fs"; +import path from "path"; -import { - ASSIGN_IDENTIFIER, - EVENT_TRIGGERS, - LEVEL_LABEL, - UNASSIGN_IDENTIFIER, -} from "../constants" -import { getOctokitInstance } from "../utils" +import { ASSIGN_IDENTIFIER, EVENT_TRIGGERS, LEVEL_LABEL, UNASSIGN_IDENTIFIER } from "../constants"; +import { getOctokitInstance } from "../utils"; export const onIssueOpened = async (webhooks: Webhooks) => { webhooks.on(EVENT_TRIGGERS.ISSUE_OPENED, async (context) => { - const projectId = context.payload.repository.id + const projectId = context.payload.repository.id; // const isProjectRegistered = await getProject(projectId) // if (!isProjectRegistered) { @@ -24,11 +19,11 @@ export const onIssueOpened = async (webhooks: Webhooks) => { // return // } - const labels = context.payload.issue.labels?.map((label) => label.name) - const isLevelLabel = labels?.includes(LEVEL_LABEL) + const labels = context.payload.issue.labels?.map((label) => label.name); + const isLevelLabel = labels?.includes(LEVEL_LABEL); if (!isLevelLabel) { - return + return; } // await sendNewIssue( @@ -42,17 +37,17 @@ export const onIssueOpened = async (webhooks: Webhooks) => { // body: ON_NEW_ISSUE, // }) // ) - }) -} + }); +}; export const onAssignCommented = async (webhooks: Webhooks) => { webhooks.on(EVENT_TRIGGERS.ISSUE_COMMENTED, async (context) => { try { - const octokit = getOctokitInstance(context.payload.installation?.id!) + const octokit = getOctokitInstance(context.payload.installation?.id!); - const issueNumber = context.payload.issue.number - const repo = context.payload.repository.name - const issueCommentBody = context.payload.comment.body + const issueNumber = context.payload.issue.number; + const repo = context.payload.repository.name; + const issueCommentBody = context.payload.comment.body; if (issueCommentBody === ASSIGN_IDENTIFIER) { await octokit.issues.createComment({ @@ -60,22 +55,22 @@ export const onAssignCommented = async (webhooks: Webhooks) => { issue_number: issueNumber, repo, owner: "formbricks", - }) + }); } } catch (err) { - console.error(err) + console.error(err); } - }) -} + }); +}; export const onUnassignCommented = async (webhooks: Webhooks) => { webhooks.on(EVENT_TRIGGERS.ISSUE_COMMENTED, async (context) => { try { - const octokit = getOctokitInstance(context.payload.installation?.id!) + const octokit = getOctokitInstance(context.payload.installation?.id!); - const issueNumber = context.payload.issue.number - const repo = context.payload.repository.name - const issueCommentBody = context.payload.comment.body + const issueNumber = context.payload.issue.number; + const repo = context.payload.repository.name; + const issueCommentBody = context.payload.comment.body; if (issueCommentBody === UNASSIGN_IDENTIFIER) { await octokit.issues.createComment({ @@ -83,10 +78,10 @@ export const onUnassignCommented = async (webhooks: Webhooks) => { issue_number: issueNumber, repo, owner: "formbricks", - }) + }); } } catch (err) { - console.error(err) + console.error(err); } - }) -} + }); +}; diff --git a/github/index.ts b/github/index.ts index 10cc343..4986314 100644 --- a/github/index.ts +++ b/github/index.ts @@ -1,25 +1,20 @@ -import { createNodeMiddleware, Webhooks } from "@octokit/webhooks" +import { env } from "@/env.mjs"; +import { Webhooks, createNodeMiddleware } from "@octokit/webhooks"; -import { env } from "@/env.mjs" - -import { onInstallationCreated } from "./hooks/installation" -import { - onAssignCommented, - onIssueOpened, - onUnassignCommented, -} from "./hooks/issue" +import { onInstallationCreated } from "./hooks/installation"; +import { onAssignCommented, onIssueOpened, onUnassignCommented } from "./hooks/issue"; const webhooks = new Webhooks({ secret: env.GITHUB_WEBHOOK_SECRET as string, -}) +}); export const webhookMiddleware = createNodeMiddleware(webhooks, { path: "/api/github-webhook", -}) +}); export const registerHooks = async () => { - onIssueOpened(webhooks) - onInstallationCreated(webhooks) - onAssignCommented(webhooks) - onUnassignCommented(webhooks) -} + onIssueOpened(webhooks); + onInstallationCreated(webhooks); + onAssignCommented(webhooks); + onUnassignCommented(webhooks); +}; diff --git a/github/services/repository.ts b/github/services/repository.ts index e8102a3..41c6233 100644 --- a/github/services/repository.ts +++ b/github/services/repository.ts @@ -1,4 +1,4 @@ -import { db } from "@/lib/db" +import { db } from "@/lib/db"; export const selectRepository = async (id: string) => { try { @@ -9,12 +9,12 @@ export const selectRepository = async (id: string) => { data: { configured: true, }, - }) - return selectedRepository + }); + return selectedRepository; } catch (error) { - throw new Error(`Failed to select repository: ${error}`) + throw new Error(`Failed to select repository: ${error}`); } -} +}; export const getRepositoriesForUser = async (userId: string) => { try { @@ -22,7 +22,7 @@ export const getRepositoriesForUser = async (userId: string) => { where: { userId, }, - }) + }); const repos = await db.repository.findMany({ where: { @@ -31,10 +31,10 @@ export const getRepositoriesForUser = async (userId: string) => { }, configured: false, }, - }) - repos.sort((a, b) => a.name.localeCompare(b.name)) - return repos + }); + repos.sort((a, b) => a.name.localeCompare(b.name)); + return repos; } catch (error) { - throw new Error(`Failed to get repositories for user: ${error}`) + throw new Error(`Failed to get repositories for user: ${error}`); } -} +}; diff --git a/github/services/user.ts b/github/services/user.ts index 7285e36..65a068e 100644 --- a/github/services/user.ts +++ b/github/services/user.ts @@ -1,24 +1,23 @@ -import { readFileSync } from "fs" -import path from "path" -import { App } from "octokit" +import { env } from "@/env.mjs"; +import { db } from "@/lib/db"; +import { readFileSync } from "fs"; +import { App } from "octokit"; +import path from "path"; -import { env } from "@/env.mjs" -import { db } from "@/lib/db" - -const privateKeyPath = "../../../../key.pem" -const resolvedPath = path.resolve(__dirname, privateKeyPath) -const privateKey = readFileSync(resolvedPath, "utf8") +const privateKeyPath = "../../../../key.pem"; +const resolvedPath = path.resolve(__dirname, privateKeyPath); +const privateKey = readFileSync(resolvedPath, "utf8"); export const sendInstallationDetails = async ( installationId: number, appId: number, repos: | { - id: number - node_id: string - name: string - full_name: string - private: boolean + id: number; + node_id: string; + name: string; + full_name: string; + private: boolean; }[] | undefined, installation: any @@ -30,8 +29,8 @@ export const sendInstallationDetails = async ( webhooks: { secret: env.GITHUB_WEBHOOK_SECRET!, }, - }) - const octokit = await app.getInstallationOctokit(installationId) + }); + const octokit = await app.getInstallationOctokit(installationId); await db.$transaction(async (tx) => { const installationPrisma = await tx.installation.upsert({ @@ -41,14 +40,14 @@ export const sendInstallationDetails = async ( githubId: installationId, type: installation?.account?.type.toLowerCase(), }, - }) + }); - const userType = installation?.account?.type.toLowerCase() + const userType = installation?.account?.type.toLowerCase(); if (userType === "organization") { const membersOfOrg = await octokit.rest.orgs.listMembers({ org: installation?.account?.login, role: "all", - }) + }); await Promise.all( membersOfOrg.data.map(async (member) => { @@ -59,7 +58,7 @@ export const sendInstallationDetails = async ( githubId: member.id, login: member.login, }, - }) + }); await tx.membership.upsert({ where: { @@ -74,11 +73,11 @@ export const sendInstallationDetails = async ( installationId: installationPrisma.id, role: "member", }, - }) + }); }) - ) + ); } else { - const user = installation.account + const user = installation.account; const newUser = await tx.user.upsert({ where: { githubId: user.id }, update: {}, @@ -88,7 +87,7 @@ export const sendInstallationDetails = async ( name: user.name || "", email: user.email || "", }, - }) + }); await tx.membership.upsert({ where: { @@ -103,7 +102,7 @@ export const sendInstallationDetails = async ( installationId: installationPrisma.id, role: "owner", }, - }) + }); } if (repos) { @@ -117,13 +116,13 @@ export const sendInstallationDetails = async ( name: repo.name, installationId: installationPrisma.id, }, - }) + }); }) - ) + ); } - }) + }); } catch (error) { - console.error(`Failed to post installation details: ${error}`) - throw new Error(`Failed to post installation details: ${error}`) + console.error(`Failed to post installation details: ${error}`); + throw new Error(`Failed to post installation details: ${error}`); } -} +}; diff --git a/github/utils.ts b/github/utils.ts index dab42b9..ada2da1 100644 --- a/github/utils.ts +++ b/github/utils.ts @@ -1,17 +1,17 @@ -import { readFileSync } from "fs" -import path from "path" -import { createAppAuth } from "@octokit/auth-app" -import { Octokit } from "@octokit/rest" +import { createAppAuth } from "@octokit/auth-app"; +import { Octokit } from "@octokit/rest"; +import { readFileSync } from "fs"; +import path from "path"; -import { GITHUB_APP_APP_ID } from "./constants" +import { GITHUB_APP_APP_ID } from "./constants"; -const privateKeyPath = "../../../../key.pem" -const resolvedPath = path.resolve(__dirname, privateKeyPath) -const privateKey = readFileSync(resolvedPath, "utf8") +const privateKeyPath = "../../../../key.pem"; +const resolvedPath = path.resolve(__dirname, privateKeyPath); +const privateKey = readFileSync(resolvedPath, "utf8"); export const getOctokitInstance = (installationId: number) => { if (!installationId) { - throw new Error("No installation id provided") + throw new Error("No installation id provided"); } const octokit = new Octokit({ @@ -21,7 +21,7 @@ export const getOctokitInstance = (installationId: number) => { privateKey, installationId, }, - }) + }); - return octokit -} + return octokit; +}; diff --git a/hooks/use-lock-body.ts b/hooks/use-lock-body.ts index 3544a1b..a599069 100644 --- a/hooks/use-lock-body.ts +++ b/hooks/use-lock-body.ts @@ -1,12 +1,10 @@ -import * as React from "react" +import * as React from "react"; // @see https://usehooks.com/useLockBodyScroll. export function useLockBody() { React.useLayoutEffect((): (() => void) => { - const originalStyle: string = window.getComputedStyle( - document.body - ).overflow - document.body.style.overflow = "hidden" - return () => (document.body.style.overflow = originalStyle) - }, []) + const originalStyle: string = window.getComputedStyle(document.body).overflow; + document.body.style.overflow = "hidden"; + return () => (document.body.style.overflow = originalStyle); + }, []); } diff --git a/hooks/use-mounted.ts b/hooks/use-mounted.ts index 3a20c62..57bb851 100644 --- a/hooks/use-mounted.ts +++ b/hooks/use-mounted.ts @@ -1,11 +1,11 @@ -import * as React from "react" +import * as React from "react"; export function useMounted() { - const [mounted, setMounted] = React.useState(false) + const [mounted, setMounted] = React.useState(false); React.useEffect(() => { - setMounted(true) - }, []) + setMounted(true); + }, []); - return mounted + return mounted; } diff --git a/lib/auth.ts b/lib/auth.ts index f6d78b4..7d42a8c 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -1,8 +1,7 @@ -import { NextAuthOptions } from "next-auth" -import GitHubProvider from "next-auth/providers/github" - -import { env } from "@/env.mjs" -import { db } from "@/lib/db" +import { env } from "@/env.mjs"; +import { db } from "@/lib/db"; +import { NextAuthOptions } from "next-auth"; +import GitHubProvider from "next-auth/providers/github"; export const authOptions: NextAuthOptions = { pages: { @@ -17,7 +16,7 @@ export const authOptions: NextAuthOptions = { callbacks: { async signIn({ user, account, profile }: any) { if (account.type !== "oauth") { - return false + return false; } if (account.provider) { @@ -29,13 +28,13 @@ export const authOptions: NextAuthOptions = { where: { githubId: profile.id, }, - }) + }); if (existingUserWithAccount) { // User with this provider found // check if email still the same if (existingUserWithAccount.email === user.email) { - return true + return true; } // user seemed to change his email within the provider @@ -47,8 +46,8 @@ export const authOptions: NextAuthOptions = { data: { email: user.email, }, - }) - return true + }); + return true; } // create user if it does not exist @@ -65,25 +64,25 @@ export const authOptions: NextAuthOptions = { }, }, }, - }) + }); - return true + return true; } - return false + return false; }, async jwt({ token, user, profile }) { const dbUser = await db.user.findFirst({ where: { email: token.email as string, }, - }) + }); if (!dbUser) { if (user) { - token.id = user?.id + token.id = user?.id; } - return token + return token; } return { @@ -91,17 +90,17 @@ export const authOptions: NextAuthOptions = { name: dbUser.name, email: dbUser.email, avatarUrl: dbUser.avatarUrl, - } + }; }, async session({ token, session }) { if (token) { - session.user.id = token.id - if (token.name) session.user.name = token.name - if (token.email) session.user.email = token.email - if (token.avatarUrl) session.user.avatarUrl = token.avatarUrl as string + session.user.id = token.id; + if (token.name) session.user.name = token.name; + if (token.email) session.user.email = token.email; + if (token.avatarUrl) session.user.avatarUrl = token.avatarUrl as string; } - return session + return session; }, }, -} +}; diff --git a/lib/session.ts b/lib/session.ts index d570582..89c9a89 100644 --- a/lib/session.ts +++ b/lib/session.ts @@ -1,9 +1,8 @@ -import { getServerSession } from "next-auth/next" - -import { authOptions } from "@/lib/auth" +import { authOptions } from "@/lib/auth"; +import { getServerSession } from "next-auth/next"; export async function getCurrentUser() { - const session = await getServerSession(authOptions) + const session = await getServerSession(authOptions); - return session?.user + return session?.user; } diff --git a/lib/utils.ts b/lib/utils.ts index 42bc6df..f6fef47 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,5 +1,5 @@ import { env } from "@/env.mjs"; -import { clsx, type ClassValue } from "clsx"; +import { type ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { diff --git a/lib/validations/auth.ts b/lib/validations/auth.ts index b91e85a..dab2901 100644 --- a/lib/validations/auth.ts +++ b/lib/validations/auth.ts @@ -1,5 +1,5 @@ -import * as z from "zod" +import * as z from "zod"; export const userAuthSchema = z.object({ email: z.string().email(), -}) +}); diff --git a/lib/validations/og.ts b/lib/validations/og.ts index bc246f8..a26f14c 100644 --- a/lib/validations/og.ts +++ b/lib/validations/og.ts @@ -1,7 +1,7 @@ -import * as z from "zod" +import * as z from "zod"; export const ogImageSchema = z.object({ heading: z.string(), type: z.string(), mode: z.enum(["light", "dark"]).default("dark"), -}) +}); diff --git a/lib/validations/post.ts b/lib/validations/post.ts index 73ad1c6..783daa3 100644 --- a/lib/validations/post.ts +++ b/lib/validations/post.ts @@ -1,8 +1,8 @@ -import * as z from "zod" +import * as z from "zod"; export const postPatchSchema = z.object({ title: z.string().min(3).max(128).optional(), // TODO: Type this properly from editorjs block types? content: z.any().optional(), -}) +}); diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 035cc5a..3553cd5 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -1,5 +1,5 @@ -import * as z from "zod" +import * as z from "zod"; export const userNameSchema = z.object({ name: z.string().min(3).max(32), -}) +}); diff --git a/middleware.ts b/middleware.ts index 9f05fd1..017953d 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1,21 +1,20 @@ -import { getToken } from "next-auth/jwt" -import { withAuth } from "next-auth/middleware" -import { NextResponse } from "next/server" +import { getToken } from "next-auth/jwt"; +import { withAuth } from "next-auth/middleware"; +import { NextResponse } from "next/server"; export default withAuth( async function middleware(req) { - const token = await getToken({ req }) - const isAuth = !!token + const token = await getToken({ req }); + const isAuth = !!token; const isAuthPage = - req.nextUrl.pathname.startsWith("/login") || - req.nextUrl.pathname.startsWith("/register") + req.nextUrl.pathname.startsWith("/login") || req.nextUrl.pathname.startsWith("/register"); if (isAuthPage) { if (isAuth) { - return NextResponse.redirect(new URL("/dashboard", req.url)) + return NextResponse.redirect(new URL("/dashboard", req.url)); } - return null + return null; } if (!isAuth) { @@ -24,9 +23,7 @@ export default withAuth( from += req.nextUrl.search; } - return NextResponse.redirect( - new URL(`/login?from=${encodeURIComponent(from)}`, req.url) - ); + return NextResponse.redirect(new URL(`/login?from=${encodeURIComponent(from)}`, req.url)); } }, { @@ -35,12 +32,12 @@ export default withAuth( // This is a work-around for handling redirect on auth pages. // We return true here so that the middleware function above // is always called. - return true + return true; }, }, } -) +); export const config = { matcher: ["/dashboard/:path*", "/editor/:path*", "/login", "/register"], -} +}; diff --git a/package.json b/package.json index 7f571ac..3c59c95 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { + "clean": "rimraf .turbo node_modules .next", "db:migrate:deploy": "prisma migrate deploy", "db:migrate:dev": "pnpm prisma migrate dev", "db:up": "docker-compose -f docker-compose.dev.yml up -d", @@ -11,16 +12,17 @@ "db:down": "docker-compose -f docker-compose.dev.yml down", "dev": "pnpm db:start && next dev", "build": "next build", - "start": "next start", - "lint": "next lint" + "format": "prettier --write \"**/*.{ts,tsx,md}\"", + "lint": "next lint", + "start": "next start" }, "dependencies": { "@hookform/resolvers": "^3.3.4", "@next-auth/prisma-adapter": "^1.0.7", "@octokit/auth-app": "^6.0.3", "@octokit/rest": "^20.0.2", - "@octokit/webhooks": "^12.0.11", - "@prisma/client": "5.8.1", + "@octokit/webhooks": "^12.1.0", + "@prisma/client": "5.9.1", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-dropdown-menu": "^2.0.6", @@ -31,15 +33,16 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "jsonwebtoken": "^9.0.2", - "lucide-react": "^0.316.0", + "lucide-react": "^0.323.0", "next": "14.1.0", "next-auth": "^4.24.5", "next-themes": "^0.2.1", "octokit": "^3.1.2", "react": "^18", "react-dom": "^18", - "react-hook-form": "^7.49.3", + "react-hook-form": "^7.50.1", "react-icons": "^5.0.1", + "sharp": "^0.33.2", "tailwind-merge": "^2.2.1", "tailwindcss-animate": "^1.0.7", "zod": "^3.22.4" @@ -47,19 +50,22 @@ "devDependencies": { "@commitlint/cli": "^18.6.0", "@commitlint/config-conventional": "^18.6.0", - "@ianvs/prettier-plugin-sort-imports": "^4.1.1", + "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "autoprefixer": "^10.4.17", "eslint": "^8", "eslint-config-next": "14.1.0", - "husky": "^9.0.6", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-react": "^7.33.2", + "husky": "^9.0.10", "postcss": "^8", - "prettier": "^3.2.4", + "prettier": "^3.2.5", "prettier-plugin-tailwindcss": "^0.5.11", - "prisma": "^5.8.1", + "prisma": "^5.9.1", + "rimraf": "^5.0.5", "tailwindcss": "^3.4.1", "typescript": "^5" } -} +} \ No newline at end of file diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts index 2d2d579..7575ea6 100644 --- a/pages/api/auth/[...nextauth].ts +++ b/pages/api/auth/[...nextauth].ts @@ -1,6 +1,5 @@ -import NextAuth from "next-auth" - -import { authOptions } from "@/lib/auth" +import { authOptions } from "@/lib/auth"; +import NextAuth from "next-auth"; // @see ./lib/auth -export default NextAuth(authOptions) +export default NextAuth(authOptions); diff --git a/pages/api/github-webhook.ts b/pages/api/github-webhook.ts index cec305f..ffa8dee 100644 --- a/pages/api/github-webhook.ts +++ b/pages/api/github-webhook.ts @@ -1,20 +1,19 @@ -import { NextApiRequest, NextApiResponse } from "next" -import { registerHooks, webhookMiddleware } from "@/github" - -import "@/github/hooks/issue" +import { registerHooks, webhookMiddleware } from "@/github"; +import "@/github/hooks/issue"; +import { NextApiRequest, NextApiResponse } from "next"; export const config = { api: { bodyParser: false, }, -} +}; export default function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method === "POST") { - registerHooks() - webhookMiddleware(req, res, () => res.status(200).end()) + registerHooks(); + webhookMiddleware(req, res, () => res.status(200).end()); } else { - res.setHeader("Allow", "POST") - res.status(405).end("Method Not Allowed") + res.setHeader("Allow", "POST"); + res.status(405).end("Method Not Allowed"); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 46a41af..92c3573 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,10 +7,10 @@ settings: dependencies: '@hookform/resolvers': specifier: ^3.3.4 - version: 3.3.4(react-hook-form@7.49.3) + version: 3.3.4(react-hook-form@7.50.1) '@next-auth/prisma-adapter': specifier: ^1.0.7 - version: 1.0.7(@prisma/client@5.8.1)(next-auth@4.24.5) + version: 1.0.7(@prisma/client@5.9.1)(next-auth@4.24.5) '@octokit/auth-app': specifier: ^6.0.3 version: 6.0.3 @@ -18,11 +18,11 @@ dependencies: specifier: ^20.0.2 version: 20.0.2 '@octokit/webhooks': - specifier: ^12.0.11 - version: 12.0.11 + specifier: ^12.1.0 + version: 12.1.0 '@prisma/client': - specifier: 5.8.1 - version: 5.8.1(prisma@5.8.1) + specifier: 5.9.1 + version: 5.9.1(prisma@5.9.1) '@radix-ui/react-alert-dialog': specifier: ^1.0.5 version: 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) @@ -54,11 +54,11 @@ dependencies: specifier: ^9.0.2 version: 9.0.2 lucide-react: - specifier: ^0.316.0 - version: 0.316.0(react@18.2.0) + specifier: ^0.323.0 + version: 0.323.0(react@18.2.0) next: specifier: 14.1.0 - version: 14.1.0(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) + version: 14.1.0(react-dom@18.2.0)(react@18.2.0) next-auth: specifier: ^4.24.5 version: 4.24.5(next@14.1.0)(react-dom@18.2.0)(react@18.2.0) @@ -75,11 +75,14 @@ dependencies: specifier: ^18 version: 18.2.0(react@18.2.0) react-hook-form: - specifier: ^7.49.3 - version: 7.49.3(react@18.2.0) + specifier: ^7.50.1 + version: 7.50.1(react@18.2.0) react-icons: specifier: ^5.0.1 version: 5.0.1(react@18.2.0) + sharp: + specifier: ^0.33.2 + version: 0.33.2 tailwind-merge: specifier: ^2.2.1 version: 2.2.1 @@ -97,9 +100,9 @@ devDependencies: '@commitlint/config-conventional': specifier: ^18.6.0 version: 18.6.0 - '@ianvs/prettier-plugin-sort-imports': - specifier: ^4.1.1 - version: 4.1.1(prettier@3.2.4) + '@trivago/prettier-plugin-sort-imports': + specifier: ^4.3.0 + version: 4.3.0(prettier@3.2.5) '@types/node': specifier: ^20 version: 20.11.5 @@ -118,21 +121,30 @@ devDependencies: eslint-config-next: specifier: 14.1.0 version: 14.1.0(eslint@8.56.0)(typescript@5.3.3) + eslint-config-prettier: + specifier: ^9.1.0 + version: 9.1.0(eslint@8.56.0) + eslint-plugin-react: + specifier: ^7.33.2 + version: 7.33.2(eslint@8.56.0) husky: - specifier: ^9.0.6 - version: 9.0.6 + specifier: ^9.0.10 + version: 9.0.10 postcss: specifier: ^8 version: 8.4.33 prettier: - specifier: ^3.2.4 - version: 3.2.4 + specifier: ^3.2.5 + version: 3.2.5 prettier-plugin-tailwindcss: specifier: ^0.5.11 - version: 0.5.11(@ianvs/prettier-plugin-sort-imports@4.1.1)(prettier@3.2.4) + version: 0.5.11(@trivago/prettier-plugin-sort-imports@4.3.0)(prettier@3.2.5) prisma: - specifier: ^5.8.1 - version: 5.8.1 + specifier: ^5.9.1 + version: 5.9.1 + rimraf: + specifier: ^5.0.5 + version: 5.0.5 tailwindcss: specifier: ^3.4.1 version: 3.4.1 @@ -151,45 +163,22 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.21 - /@babel/code-frame@7.23.5: resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.23.4 chalk: 2.4.2 + dev: true - /@babel/compat-data@7.23.5: - resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} - engines: {node: '>=6.9.0'} - - /@babel/core@7.23.7: - resolution: {integrity: sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==} + /@babel/generator@7.17.7: + resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} engines: {node: '>=6.9.0'} dependencies: - '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) - '@babel/helpers': 7.23.8 - '@babel/parser': 7.23.6 - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 '@babel/types': 7.23.6 - convert-source-map: 2.0.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + jsesc: 2.5.2 + source-map: 0.5.7 + dev: true /@babel/generator@7.23.6: resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} @@ -199,20 +188,12 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.21 jsesc: 2.5.2 - - /@babel/helper-compilation-targets@7.23.6: - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/helper-validator-option': 7.23.5 - browserslist: 4.22.2 - lru-cache: 5.1.1 - semver: 6.3.1 + dev: true /@babel/helper-environment-visitor@7.22.20: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} + dev: true /@babel/helper-function-name@7.23.0: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} @@ -220,65 +201,31 @@ packages: dependencies: '@babel/template': 7.22.15 '@babel/types': 7.23.6 + dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.6 - - /@babel/helper-module-imports@7.22.15: - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.6 - - /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.7): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.23.7 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 - - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.6 + dev: true /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.6 + dev: true /@babel/helper-string-parser@7.23.4: resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} engines: {node: '>=6.9.0'} + dev: true /@babel/helper-validator-identifier@7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} - - /@babel/helper-validator-option@7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} - engines: {node: '>=6.9.0'} - - /@babel/helpers@7.23.8: - resolution: {integrity: sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.7 - '@babel/types': 7.23.6 - transitivePeerDependencies: - - supports-color + dev: true /@babel/highlight@7.23.4: resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} @@ -287,6 +234,7 @@ packages: '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 + dev: true /@babel/parser@7.23.6: resolution: {integrity: sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==} @@ -294,6 +242,7 @@ packages: hasBin: true dependencies: '@babel/types': 7.23.6 + dev: true /@babel/runtime@7.23.8: resolution: {integrity: sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==} @@ -308,9 +257,10 @@ packages: '@babel/code-frame': 7.23.5 '@babel/parser': 7.23.6 '@babel/types': 7.23.6 + dev: true - /@babel/traverse@7.23.7: - resolution: {integrity: sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==} + /@babel/traverse@7.23.2: + resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.23.5 @@ -325,6 +275,15 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color + dev: true + + /@babel/types@7.17.0: + resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.22.20 + to-fast-properties: 2.0.0 + dev: true /@babel/types@7.23.6: resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} @@ -333,6 +292,7 @@ packages: '@babel/helper-string-parser': 7.23.4 '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + dev: true /@commitlint/cli@18.6.0(@types/node@20.11.5)(typescript@5.3.3): resolution: {integrity: sha512-FiH23cr9QG8VdfbmvJJZmdfHGVMCouOOAzoXZ3Cd7czGC52RbycwNt8YCI7SA69pAl+t30vh8LMaO/N+kcel6w==} @@ -498,6 +458,14 @@ packages: chalk: 4.1.2 dev: true + /@emnapi/runtime@0.45.0: + resolution: {integrity: sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==} + requiresBuild: true + dependencies: + tslib: 2.6.2 + dev: false + optional: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.56.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -563,12 +531,12 @@ packages: resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} dev: false - /@hookform/resolvers@3.3.4(react-hook-form@7.49.3): + /@hookform/resolvers@3.3.4(react-hook-form@7.50.1): resolution: {integrity: sha512-o5cgpGOuJYrd+iMKvkttOclgwRW86EsWJZZRC23prf0uU2i48Htq4PuT73AVb9ionFyZrwYEITuOFGF+BydEtQ==} peerDependencies: react-hook-form: ^7.0.0 dependencies: - react-hook-form: 7.49.3(react@18.2.0) + react-hook-form: 7.50.1(react@18.2.0) dev: false /@humanwhocodes/config-array@0.11.14: @@ -591,25 +559,193 @@ packages: resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} dev: true - /@ianvs/prettier-plugin-sort-imports@4.1.1(prettier@3.2.4): - resolution: {integrity: sha512-kJhXq63ngpTQ2dxgf5GasbPJWsJA3LgoOdd7WGhpUSzLgLgI4IsIzYkbJf9kmpOHe7Vdm/o3PcRA3jmizXUuAQ==} - peerDependencies: - '@vue/compiler-sfc': '>=3.0.0' - prettier: 2 || 3 - peerDependenciesMeta: - '@vue/compiler-sfc': - optional: true + /@img/sharp-darwin-arm64@0.33.2: + resolution: {integrity: sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==} + engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.0.1 + dev: false + optional: true + + /@img/sharp-darwin-x64@0.33.2: + resolution: {integrity: sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==} + engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.0.1 + dev: false + optional: true + + /@img/sharp-libvips-darwin-arm64@1.0.1: + resolution: {integrity: sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==} + engines: {macos: '>=11', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-darwin-x64@1.0.1: + resolution: {integrity: sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==} + engines: {macos: '>=10.13', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linux-arm64@1.0.1: + resolution: {integrity: sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==} + engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linux-arm@1.0.1: + resolution: {integrity: sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==} + engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linux-s390x@1.0.1: + resolution: {integrity: sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==} + engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linux-x64@1.0.1: + resolution: {integrity: sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==} + engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linuxmusl-arm64@1.0.1: + resolution: {integrity: sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==} + engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-libvips-linuxmusl-x64@1.0.1: + resolution: {integrity: sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==} + engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-linux-arm64@0.33.2: + resolution: {integrity: sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==} + engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.0.1 + dev: false + optional: true + + /@img/sharp-linux-arm@0.33.2: + resolution: {integrity: sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==} + engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.0.1 + dev: false + optional: true + + /@img/sharp-linux-s390x@0.33.2: + resolution: {integrity: sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==} + engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [s390x] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.0.1 + dev: false + optional: true + + /@img/sharp-linux-x64@0.33.2: + resolution: {integrity: sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==} + engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.0.1 + dev: false + optional: true + + /@img/sharp-linuxmusl-arm64@0.33.2: + resolution: {integrity: sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==} + engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.0.1 + dev: false + optional: true + + /@img/sharp-linuxmusl-x64@0.33.2: + resolution: {integrity: sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==} + engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.0.1 + dev: false + optional: true + + /@img/sharp-wasm32@0.33.2: + resolution: {integrity: sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [wasm32] + requiresBuild: true dependencies: - '@babel/core': 7.23.7 - '@babel/generator': 7.23.6 - '@babel/parser': 7.23.6 - '@babel/traverse': 7.23.7 - '@babel/types': 7.23.6 - prettier: 3.2.4 - semver: 7.5.4 - transitivePeerDependencies: - - supports-color - dev: true + '@emnapi/runtime': 0.45.0 + dev: false + optional: true + + /@img/sharp-win32-ia32@0.33.2: + resolution: {integrity: sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@img/sharp-win32-x64@0.33.2: + resolution: {integrity: sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -647,13 +783,13 @@ packages: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - /@next-auth/prisma-adapter@1.0.7(@prisma/client@5.8.1)(next-auth@4.24.5): + /@next-auth/prisma-adapter@1.0.7(@prisma/client@5.9.1)(next-auth@4.24.5): resolution: {integrity: sha512-Cdko4KfcmKjsyHFrWwZ//lfLUbcLqlyFqjd/nYE2m3aZ7tjMNUjpks47iw7NTCnXf+5UWz5Ypyt1dSs1EP5QJw==} peerDependencies: '@prisma/client': '>=2.26.0 || >=3' next-auth: ^4 dependencies: - '@prisma/client': 5.8.1(prisma@5.8.1) + '@prisma/client': 5.9.1(prisma@5.9.1) next-auth: 4.24.5(next@14.1.0)(react-dom@18.2.0)(react@18.2.0) dev: false @@ -776,7 +912,7 @@ packages: '@octokit/oauth-app': 6.0.0 '@octokit/plugin-paginate-rest': 9.1.5(@octokit/core@5.0.2) '@octokit/types': 12.4.0 - '@octokit/webhooks': 12.0.11 + '@octokit/webhooks': 12.1.0 dev: false /@octokit/auth-app@6.0.3: @@ -1007,17 +1143,17 @@ packages: engines: {node: '>= 18'} dev: false - /@octokit/webhooks-types@7.1.0: - resolution: {integrity: sha512-y92CpG4kFFtBBjni8LHoV12IegJ+KFxLgKRengrVjKmGE5XMeCuGvlfRe75lTRrgXaG6XIWJlFpIDTlkoJsU8w==} + /@octokit/webhooks-types@7.3.2: + resolution: {integrity: sha512-JWOoOgtWTFnTSAamPXXyjTY5/apttvNxF+vPBnwdSu5cj5snrd7FO0fyw4+wTXy8fHduq626JjhO+TwCyyA6vA==} dev: false - /@octokit/webhooks@12.0.11: - resolution: {integrity: sha512-YEQOb7v0TZ662nh5jsbY1CMgJyMajCEagKrHWC30LTCwCtnuIrLtEpE20vq4AtH0SuZI90+PtV66/Bnnw0jkvg==} + /@octokit/webhooks@12.1.0: + resolution: {integrity: sha512-ppqZ1DyHhZklpeuxnx7WRn5S5WRxjHYt/fQlr33JNvbK+Dpaz6XFD5Zw/AFri62J4NH3jKreHeQFQkLouMqdog==} engines: {node: '>= 18'} dependencies: '@octokit/request-error': 5.0.1 '@octokit/webhooks-methods': 4.0.0 - '@octokit/webhooks-types': 7.1.0 + '@octokit/webhooks-types': 7.3.2 aggregate-error: 3.1.0 dev: false @@ -1031,8 +1167,8 @@ packages: requiresBuild: true optional: true - /@prisma/client@5.8.1(prisma@5.8.1): - resolution: {integrity: sha512-xQtMPfbIwLlbm0VVIVQY2yqQVOxPwRQhvIp7Z3m2900g1bu/zRHKhYZJQWELqmjl6d8YwBy0K2NvMqh47v1ubw==} + /@prisma/client@5.9.1(prisma@5.9.1): + resolution: {integrity: sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ==} engines: {node: '>=16.13'} requiresBuild: true peerDependencies: @@ -1041,35 +1177,35 @@ packages: prisma: optional: true dependencies: - prisma: 5.8.1 + prisma: 5.9.1 dev: false - /@prisma/debug@5.8.1: - resolution: {integrity: sha512-tjuw7eA0Us3T42jx9AmAgL58rzwzpFGYc3R7Y4Ip75EBYrKMBA1YihuWMcBC92ILmjlQ/u3p8VxcIE0hr+fZfg==} + /@prisma/debug@5.9.1: + resolution: {integrity: sha512-yAHFSFCg8KVoL0oRUno3m60GAjsUKYUDkQ+9BA2X2JfVR3kRVSJFc/GpQ2fSORi4pSHZR9orfM4UC9OVXIFFTA==} - /@prisma/engines-version@5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2: - resolution: {integrity: sha512-f5C3JM3l9yhGr3cr4FMqWloFaSCpNpMi58Om22rjD2DOz3owci2mFdFXMgnAGazFPKrCbbEhcxdsRfspEYRoFQ==} + /@prisma/engines-version@5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64: + resolution: {integrity: sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ==} - /@prisma/engines@5.8.1: - resolution: {integrity: sha512-TJgYLRrZr56uhqcXO4GmP5be+zjCIHtLDK20Cnfg+o9d905hsN065QOL+3Z0zQAy6YD31Ol4u2kzSfRmbJv/uA==} + /@prisma/engines@5.9.1: + resolution: {integrity: sha512-gkdXmjxQ5jktxWNdDA5aZZ6R8rH74JkoKq6LD5mACSvxd2vbqWeWIOV0Py5wFC8vofOYShbt6XUeCIUmrOzOnQ==} requiresBuild: true dependencies: - '@prisma/debug': 5.8.1 - '@prisma/engines-version': 5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2 - '@prisma/fetch-engine': 5.8.1 - '@prisma/get-platform': 5.8.1 + '@prisma/debug': 5.9.1 + '@prisma/engines-version': 5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64 + '@prisma/fetch-engine': 5.9.1 + '@prisma/get-platform': 5.9.1 - /@prisma/fetch-engine@5.8.1: - resolution: {integrity: sha512-+bgjjoSFa6uYEbAPlklfoVSStOEfcpheOjoBoNsNNSQdSzcwE2nM4Q0prun0+P8/0sCHo18JZ9xqa8gObvgOUw==} + /@prisma/fetch-engine@5.9.1: + resolution: {integrity: sha512-l0goQOMcNVOJs1kAcwqpKq3ylvkD9F04Ioe1oJoCqmz05mw22bNAKKGWuDd3zTUoUZr97va0c/UfLNru+PDmNA==} dependencies: - '@prisma/debug': 5.8.1 - '@prisma/engines-version': 5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2 - '@prisma/get-platform': 5.8.1 + '@prisma/debug': 5.9.1 + '@prisma/engines-version': 5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64 + '@prisma/get-platform': 5.9.1 - /@prisma/get-platform@5.8.1: - resolution: {integrity: sha512-wnA+6HTFcY+tkykMokix9GiAkaauPC5W/gg0O5JB0J8tCTNWrqpnQ7AsaGRfkYUbeOIioh6woDjQrGTTRf1Zag==} + /@prisma/get-platform@5.9.1: + resolution: {integrity: sha512-6OQsNxTyhvG+T2Ksr8FPFpuPeL4r9u0JF0OZHUBI/Uy9SS43sPyAIutt4ZEAyqWQt104ERh70EZedkHZKsnNbg==} dependencies: - '@prisma/debug': 5.8.1 + '@prisma/debug': 5.9.1 /@radix-ui/primitive@1.0.1: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} @@ -1733,6 +1869,26 @@ packages: zod: 3.22.4 dev: false + /@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.2.5): + resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==} + peerDependencies: + '@vue/compiler-sfc': 3.x + prettier: 2.x - 3.x + peerDependenciesMeta: + '@vue/compiler-sfc': + optional: true + dependencies: + '@babel/generator': 7.17.7 + '@babel/parser': 7.23.6 + '@babel/traverse': 7.23.2 + '@babel/types': 7.17.0 + javascript-natural-sort: 0.7.1 + lodash: 4.17.21 + prettier: 3.2.5 + transitivePeerDependencies: + - supports-color + dev: true + /@types/aws-lambda@8.10.131: resolution: {integrity: sha512-IWmFpqnVDvskYWnNSiu/qlRn80XlIOU0Gy5rKCl/NjhnI95pV8qIHs6L5b+bpHhyzuOSzjLgBcwgFSXrC1nZWA==} dev: false @@ -1911,6 +2067,7 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 + dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} @@ -2122,6 +2279,7 @@ packages: electron-to-chromium: 1.4.637 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) + dev: true /btoa-lite@1.0.0: resolution: {integrity: sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA==} @@ -2179,6 +2337,7 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 + dev: true /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -2240,6 +2399,7 @@ packages: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 + dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -2249,10 +2409,26 @@ packages: /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + /color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + dev: false + + /color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + dev: false + /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -2293,9 +2469,6 @@ packages: split2: 4.2.0 dev: true - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - /cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} @@ -2377,6 +2550,7 @@ packages: optional: true dependencies: ms: 2.1.2 + dev: true /decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} @@ -2422,6 +2596,11 @@ packages: engines: {node: '>=6'} dev: true + /detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + dev: false + /detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} dev: false @@ -2471,6 +2650,7 @@ packages: /electron-to-chromium@1.4.637: resolution: {integrity: sha512-G7j3UCOukFtxVO1vWrPQUoDk3kL70mtvjc/DC/k2o7lE0wAdq+Vwp1ipagOow+BH0uVztFysLWbkM/RTIrbK3w==} + dev: true /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2583,10 +2763,12 @@ packages: /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + dev: true /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + dev: true /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} @@ -2618,6 +2800,15 @@ packages: - supports-color dev: true + /eslint-config-prettier@9.1.0(eslint@8.56.0): + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.56.0 + dev: true + /eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: @@ -2997,10 +3188,6 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -3095,6 +3282,7 @@ packages: /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} + dev: true /globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} @@ -3147,6 +3335,7 @@ packages: /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} + dev: true /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -3198,8 +3387,8 @@ packages: engines: {node: '>=10.17.0'} dev: true - /husky@9.0.6: - resolution: {integrity: sha512-EEuw/rfTiMjOfuL7pGO/i9otg1u36TXxqjIA6D9qxVjd/UXoDOsLor/BSFf5hTK50shwzCU3aVVwdXDp/lp7RA==} + /husky@9.0.10: + resolution: {integrity: sha512-TQGNknoiy6bURzIO77pPRu+XHi6zI7T93rX+QnJsoYFf3xdjKOur+IlfqzJGMHIK/wXrLg+GsvMs8Op7vI2jVA==} engines: {node: '>=18'} hasBin: true dev: true @@ -3268,6 +3457,10 @@ packages: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true + /is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + dev: false + /is-async-function@2.0.0: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} @@ -3467,6 +3660,10 @@ packages: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + /javascript-natural-sort@0.7.1: + resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} + dev: true + /jiti@1.21.0: resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} hasBin: true @@ -3489,6 +3686,7 @@ packages: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true + dev: true /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -3517,11 +3715,6 @@ packages: minimist: 1.2.8 dev: true - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - /jsonparse@1.3.1: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} @@ -3700,19 +3893,14 @@ packages: resolution: {integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==} engines: {node: 14 || >=16.14} - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} dependencies: yallist: 4.0.0 - /lucide-react@0.316.0(react@18.2.0): - resolution: {integrity: sha512-dTmYX1H4IXsRfVcj/KUxworV6814ApTl7iXaS21AimK2RUEl4j4AfOmqD3VR8phe5V91m4vEJ8tCK4uT1jE5nA==} + /lucide-react@0.323.0(react@18.2.0): + resolution: {integrity: sha512-rTXZFILl2Y4d1SG9p1Mdcf17AcPvPvpc/egFIzUrp7IUy60MUQo3Oi1mu8LGYXUVwuRZYsSMt3csHRW5mAovJg==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 dependencies: @@ -3807,6 +3995,7 @@ packages: /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3842,7 +4031,7 @@ packages: '@panva/hkdf': 1.1.1 cookie: 0.5.0 jose: 4.15.4 - next: 14.1.0(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) + next: 14.1.0(react-dom@18.2.0)(react@18.2.0) oauth: 0.9.15 openid-client: 5.6.4 preact: 10.19.3 @@ -3859,12 +4048,12 @@ packages: react: '*' react-dom: '*' dependencies: - next: 14.1.0(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) + next: 14.1.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /next@14.1.0(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0): + /next@14.1.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==} engines: {node: '>=18.17.0'} hasBin: true @@ -3887,7 +4076,7 @@ packages: postcss: 8.4.31 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.1(@babel/core@7.23.7)(react@18.2.0) + styled-jsx: 5.1.1(react@18.2.0) optionalDependencies: '@next/swc-darwin-arm64': 14.1.0 '@next/swc-darwin-x64': 14.1.0 @@ -3905,6 +4094,7 @@ packages: /node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + dev: true /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -4258,7 +4448,7 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /prettier-plugin-tailwindcss@0.5.11(@ianvs/prettier-plugin-sort-imports@4.1.1)(prettier@3.2.4): + /prettier-plugin-tailwindcss@0.5.11(@trivago/prettier-plugin-sort-imports@4.3.0)(prettier@3.2.5): resolution: {integrity: sha512-AvI/DNyMctyyxGOjyePgi/gqj5hJYClZ1avtQvLlqMT3uDZkRbi4HhGUpok3DRzv9z7Lti85Kdj3s3/1CeNI0w==} engines: {node: '>=14.21.3'} peerDependencies: @@ -4307,12 +4497,12 @@ packages: prettier-plugin-twig-melody: optional: true dependencies: - '@ianvs/prettier-plugin-sort-imports': 4.1.1(prettier@3.2.4) - prettier: 3.2.4 + '@trivago/prettier-plugin-sort-imports': 4.3.0(prettier@3.2.5) + prettier: 3.2.5 dev: true - /prettier@3.2.4: - resolution: {integrity: sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==} + /prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} engines: {node: '>=14'} hasBin: true dev: true @@ -4321,13 +4511,13 @@ packages: resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} dev: false - /prisma@5.8.1: - resolution: {integrity: sha512-N6CpjzECnUHZ5beeYpDzkt2rYpEdAeqXX2dweu6BoQaeYkNZrC/WJHM+5MO/uidFHTak8QhkPKBWck1o/4MD4A==} + /prisma@5.9.1: + resolution: {integrity: sha512-Hy/8KJZz0ELtkw4FnG9MS9rNWlXcJhf98Z2QMqi0QiVMoS8PzsBkpla0/Y5hTlob8F3HeECYphBjqmBxrluUrQ==} engines: {node: '>=16.13'} hasBin: true requiresBuild: true dependencies: - '@prisma/engines': 5.8.1 + '@prisma/engines': 5.9.1 /prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -4360,9 +4550,9 @@ packages: scheduler: 0.23.0 dev: false - /react-hook-form@7.49.3(react@18.2.0): - resolution: {integrity: sha512-foD6r3juidAT1cOZzpmD/gOKt7fRsDhXXZ0y28+Al1CHgX+AY1qIN9VSIIItXRq1dN68QrRwl1ORFlwjBaAqeQ==} - engines: {node: '>=18', pnpm: '8'} + /react-hook-form@7.50.1(react@18.2.0): + resolution: {integrity: sha512-3PCY82oE0WgeOgUtIr3nYNNtNvqtJ7BZjsbxh6TnYNbXButaD5WpjOmTjdxZfheuHKR68qfeFnEDVYoSSFPMTQ==} + engines: {node: '>=12.22.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 dependencies: @@ -4570,6 +4760,14 @@ packages: glob: 7.2.3 dev: true + /rimraf@5.0.5: + resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==} + engines: {node: '>=14'} + hasBin: true + dependencies: + glob: 10.3.10 + dev: true + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -4611,6 +4809,7 @@ packages: /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + dev: true /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} @@ -4639,6 +4838,36 @@ packages: has-property-descriptors: 1.0.1 dev: true + /sharp@0.33.2: + resolution: {integrity: sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==} + engines: {libvips: '>=8.15.1', node: ^18.17.0 || ^20.3.0 || >=21.0.0} + requiresBuild: true + dependencies: + color: 4.2.3 + detect-libc: 2.0.2 + semver: 7.5.4 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.33.2 + '@img/sharp-darwin-x64': 0.33.2 + '@img/sharp-libvips-darwin-arm64': 1.0.1 + '@img/sharp-libvips-darwin-x64': 1.0.1 + '@img/sharp-libvips-linux-arm': 1.0.1 + '@img/sharp-libvips-linux-arm64': 1.0.1 + '@img/sharp-libvips-linux-s390x': 1.0.1 + '@img/sharp-libvips-linux-x64': 1.0.1 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.1 + '@img/sharp-libvips-linuxmusl-x64': 1.0.1 + '@img/sharp-linux-arm': 0.33.2 + '@img/sharp-linux-arm64': 0.33.2 + '@img/sharp-linux-s390x': 0.33.2 + '@img/sharp-linux-x64': 0.33.2 + '@img/sharp-linuxmusl-arm64': 0.33.2 + '@img/sharp-linuxmusl-x64': 0.33.2 + '@img/sharp-wasm32': 0.33.2 + '@img/sharp-win32-ia32': 0.33.2 + '@img/sharp-win32-x64': 0.33.2 + dev: false + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -4665,6 +4894,12 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + /simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + dependencies: + is-arrayish: 0.3.2 + dev: false + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -4674,6 +4909,11 @@ packages: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + /source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + dev: true + /spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: @@ -4807,7 +5047,7 @@ packages: engines: {node: '>=8'} dev: true - /styled-jsx@5.1.1(@babel/core@7.23.7)(react@18.2.0): + /styled-jsx@5.1.1(react@18.2.0): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} peerDependencies: @@ -4820,7 +5060,6 @@ packages: babel-plugin-macros: optional: true dependencies: - '@babel/core': 7.23.7 client-only: 0.0.1 react: 18.2.0 dev: false @@ -4843,6 +5082,7 @@ packages: engines: {node: '>=4'} dependencies: has-flag: 3.0.0 + dev: true /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -4937,6 +5177,7 @@ packages: /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} + dev: true /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} @@ -5076,6 +5317,7 @@ packages: browserslist: 4.22.2 escalade: 3.1.1 picocolors: 1.0.0 + dev: true /uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -5208,9 +5450,6 @@ packages: engines: {node: '>=10'} dev: true - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} diff --git a/prettier.config.js b/prettier.config.js deleted file mode 100644 index c72df58..0000000 --- a/prettier.config.js +++ /dev/null @@ -1,33 +0,0 @@ -/** @type {import('prettier').Config} */ -module.exports = { - endOfLine: "lf", - semi: false, - singleQuote: false, - tabWidth: 2, - trailingComma: "es5", - importOrder: [ - "^(react/(.*)$)|^(react$)", - "^(next/(.*)$)|^(next$)", - "", - "", - "^types$", - "^@/env(.*)$", - "^@/types/(.*)$", - "^@/config/(.*)$", - "^@/lib/(.*)$", - "^@/hooks/(.*)$", - "^@/components/ui/(.*)$", - "^@/components/(.*)$", - "^@/styles/(.*)$", - "^@/app/(.*)$", - "", - "^[./]", - ], - importOrderSeparation: false, - importOrderSortSpecifiers: true, - importOrderBuiltinModulesToTop: true, - importOrderParserPlugins: ["typescript", "jsx", "decorators-legacy"], - importOrderMergeDuplicateImports: true, - importOrderCombineTypeAndValueImports: true, - plugins: ["@ianvs/prettier-plugin-sort-imports"], -} diff --git a/tailwind.config.ts b/tailwind.config.ts index a2cd264..37ff386 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,4 +1,5 @@ import type { Config } from "tailwindcss"; + const { fontFamily } = require("tailwindcss/defaultTheme"); const config = { @@ -20,7 +21,7 @@ const config = { }, extend: { scale: { - '102': '1.02', + "102": "1.02", }, fontFamily: { sans: ["var(--font-sans)", ...fontFamily.sans], diff --git a/types/next-auth.d.ts b/types/next-auth.d.ts index ab96afd..cbe08c3 100644 --- a/types/next-auth.d.ts +++ b/types/next-auth.d.ts @@ -1,21 +1,21 @@ -import { User } from "next-auth" -import { JWT } from "next-auth/jwt" +import { User } from "next-auth"; +import { JWT } from "next-auth/jwt"; -type UserId = string +type UserId = string; declare module "next-auth/jwt" { interface JWT { - id: UserId + id: UserId; } } declare module "next-auth" { interface Session { user: { - id: string - name: string - email: string - avatarUrl: string - } + id: string; + name: string; + email: string; + avatarUrl: string; + }; } }