😊
【Convex】NextJs14 と Convex【#6Convex Sign In】
【#6Convex Sign In】
YouTube: 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