😊

【Convex】NextJs14 と Convex【#6Convex Sign In】

2024/03/28に公開

【#6Convex Sign In】

YouTube: https://youtu.be/kN24lG81_q8

https://youtu.be/kN24lG81_q8

今回はログインボタンとローディング画面を実装します。

my-app/app/global.css
@tailwind base;
@tailwind components;
@tailwind utilities;

html,
body,
:root {
  height: 100%;
}

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;

    --card: 0 0% 100%;
    --card-foreground: 222.2 84% 4.9%;

    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;

    --primary: 222.2 47.4% 11.2%;
    --primary-foreground: 210 40% 98%;

    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;

    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;

    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;

    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;

    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 222.2 84% 4.9%;

    --radius: 0.5rem;
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;

    --card: 222.2 84% 4.9%;
    --card-foreground: 210 40% 98%;

    --popover: 222.2 84% 4.9%;
    --popover-foreground: 210 40% 98%;

    --primary: 210 40% 98%;
    --primary-foreground: 222.2 47.4% 11.2%;

    --secondary: 217.2 32.6% 17.5%;
    --secondary-foreground: 210 40% 98%;

    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;

    --accent: 217.2 32.6% 17.5%;
    --accent-foreground: 210 40% 98%;

    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 210 40% 98%;

    --border: 217.2 32.6% 17.5%;
    --input: 217.2 32.6% 17.5%;
    --ring: 212.7 26.8% 83.9%;
  }
}

@layer base {
  * {
    @apply border-border;
  }
  body {
    @apply bg-background text-foreground;
  }
}
my-app/components/loader.tsx
import { LoaderIcon } from "lucide-react";

export const Loader = () => {
  return (
    <div className="h-full w-full flex flex-col items-center justify-center">
      <LoaderIcon className="h-8 w-8 animate-spin mb-1.5" />
      <p className="animate-bounce text-muted-foreground text-lg">Loading...</p>
    </div>
  );
};
my-app/components/auth-buttons.tsx
import { SignInButton, SignUpButton } from "@clerk/nextjs";

import { Button } from "@/components/ui/button";

export const AuthButtons = () => {
  return (
    <div className="h-full w-full flex flex-col items-center justify-center gap-y-3">
      <h2 className="text-3xl font-semibold">Sign In or Sign Up</h2>
      <div className="flex items-center justify-center gap-x-2">
        <SignInButton mode="modal" afterSignInUrl="/" afterSignUpUrl="/">
          <Button variant="default">Sign In</Button>
        </SignInButton>
        <SignUpButton mode="modal" afterSignInUrl="/" afterSignUpUrl="/">
          <Button variant="outline">Sign Up</Button>
        </SignUpButton>
      </div>
    </div>
  );
};
my-app/components/providers/convex-client-provider.tsx
"use client";

import { ClerkProvider, useAuth } from "@clerk/nextjs";
import {
  AuthLoading,
  Authenticated,
  ConvexReactClient,
  Unauthenticated,
} from "convex/react";
import { ConvexProviderWithClerk } from "convex/react-clerk";

import { Loader } from "@/components/loader";
import { AuthButtons } from "@/components/auth-buttons";

const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL!;
const convex = new ConvexReactClient(convexUrl);

interface Props {
  children: React.ReactNode;
}

export const ConvexClientProvider = ({ children }: Props) => {
  return (
    <ClerkProvider>
      <ConvexProviderWithClerk useAuth={useAuth} client={convex}>
        <Authenticated>{children}</Authenticated>
        <Unauthenticated>
          <AuthButtons />
        </Unauthenticated>
        <AuthLoading>
          <Loader />
        </AuthLoading>
      </ConvexProviderWithClerk>
    </ClerkProvider>
  );
};

Discussion