chore: lint project

This commit is contained in:
Bereket Engida
2024-09-26 08:14:28 +03:00
parent 4d879263da
commit d4f4b94386
360 changed files with 16260 additions and 16182 deletions

View File

@@ -19,5 +19,8 @@
"typescript.tsdk": "node_modules/typescript/lib",
"[astro]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
}
}

View File

@@ -3,12 +3,12 @@
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -18,111 +18,111 @@ import Link from "next/link";
import { useState } from "react";
export default function Component() {
const [email, setEmail] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSubmitted, setIsSubmitted] = useState(false);
const [error, setError] = useState("");
const [email, setEmail] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const [isSubmitted, setIsSubmitted] = useState(false);
const [error, setError] = useState("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
setError("");
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
setError("");
// Simulate API call
try {
const res = await client.forgetPassword({
email,
});
// If the API call is successful, set isSubmitted to true
setIsSubmitted(true);
} catch (err) {
setError("An error occurred. Please try again.");
} finally {
setIsSubmitting(false);
}
};
// Simulate API call
try {
const res = await client.forgetPassword({
email,
});
// If the API call is successful, set isSubmitted to true
setIsSubmitted(true);
} catch (err) {
setError("An error occurred. Please try again.");
} finally {
setIsSubmitting(false);
}
};
if (isSubmitted) {
return (
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Check your email</CardTitle>
<CardDescription>
We've sent a password reset link to your email.
</CardDescription>
</CardHeader>
<CardContent>
<Alert>
<CheckCircle2 className="h-4 w-4" />
<AlertDescription>
If you don't see the email, check your spam folder.
</AlertDescription>
</Alert>
</CardContent>
<CardFooter>
<Button
variant="outline"
className="w-full"
onClick={() => setIsSubmitted(false)}
>
<ArrowLeft className="mr-2 h-4 w-4" /> Back to reset password
</Button>
</CardFooter>
</Card>
</main>
);
}
if (isSubmitted) {
return (
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Check your email</CardTitle>
<CardDescription>
We've sent a password reset link to your email.
</CardDescription>
</CardHeader>
<CardContent>
<Alert>
<CheckCircle2 className="h-4 w-4" />
<AlertDescription>
If you don't see the email, check your spam folder.
</AlertDescription>
</Alert>
</CardContent>
<CardFooter>
<Button
variant="outline"
className="w-full"
onClick={() => setIsSubmitted(false)}
>
<ArrowLeft className="mr-2 h-4 w-4" /> Back to reset password
</Button>
</CardFooter>
</Card>
</main>
);
}
return (
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
{/* Radial gradient for the container to give a faded look */}
<div className="absolute pointer-events-none inset-0 flex items-center justify-center dark:bg-black bg-white [mask-image:radial-gradient(ellipse_at_center,transparent_20%,black)]"></div>
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Forgot password</CardTitle>
<CardDescription>
Enter your email to reset your password
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit}>
<div className="grid w-full items-center gap-4">
<div className="flex flex-col space-y-1.5">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="Enter your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
</div>
{error && (
<Alert variant="destructive" className="mt-4">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<Button
className="w-full mt-4"
type="submit"
disabled={isSubmitting}
>
{isSubmitting ? "Sending..." : "Send reset link"}
</Button>
</form>
</CardContent>
<CardFooter className="flex justify-center">
<Link href="/sign-in">
<Button variant="link" className="px-0">
Back to sign in
</Button>
</Link>
</CardFooter>
</Card>
</main>
);
return (
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
{/* Radial gradient for the container to give a faded look */}
<div className="absolute pointer-events-none inset-0 flex items-center justify-center dark:bg-black bg-white [mask-image:radial-gradient(ellipse_at_center,transparent_20%,black)]"></div>
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Forgot password</CardTitle>
<CardDescription>
Enter your email to reset your password
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit}>
<div className="grid w-full items-center gap-4">
<div className="flex flex-col space-y-1.5">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="Enter your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</div>
</div>
{error && (
<Alert variant="destructive" className="mt-4">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<Button
className="w-full mt-4"
type="submit"
disabled={isSubmitting}
>
{isSubmitting ? "Sending..." : "Send reset link"}
</Button>
</form>
</CardContent>
<CardFooter className="flex justify-center">
<Link href="/sign-in">
<Button variant="link" className="px-0">
Back to sign in
</Button>
</Link>
</CardFooter>
</Card>
</main>
);
}

View File

@@ -3,12 +3,12 @@
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { PasswordInput } from "@/components/ui/password-input";
@@ -19,78 +19,78 @@ import { useState } from "react";
import { toast } from "sonner";
export default function ResetPassword({
params,
params,
}: {
params: { token: string };
params: { token: string };
}) {
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState("");
const token = params.token;
const router = useRouter();
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setIsSubmitting(true);
setError("");
const res = await client.resetPassword({
newPassword: password,
});
if (res.error) {
toast.error(res.error.message);
}
setIsSubmitting(false);
router.push("/sign-in");
}
return (
<div className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Reset password</CardTitle>
<CardDescription>
Enter new password and confirm it to reset your password
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit}>
<div className="grid w-full items-center gap-2">
<div className="flex flex-col space-y-1.5">
<Label htmlFor="email">New password</Label>
<PasswordInput
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete="password"
placeholder="Password"
/>
</div>
<div className="flex flex-col space-y-1.5">
<Label htmlFor="email">Confirm password</Label>
<PasswordInput
id="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
autoComplete="password"
placeholder="Password"
/>
</div>
</div>
{error && (
<Alert variant="destructive" className="mt-4">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<Button
className="w-full mt-4"
type="submit"
disabled={isSubmitting}
>
{isSubmitting ? "Resetting..." : "Reset password"}
</Button>
</form>
</CardContent>
</Card>
</div>
);
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState("");
const token = params.token;
const router = useRouter();
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setIsSubmitting(true);
setError("");
const res = await client.resetPassword({
newPassword: password,
});
if (res.error) {
toast.error(res.error.message);
}
setIsSubmitting(false);
router.push("/sign-in");
}
return (
<div className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Reset password</CardTitle>
<CardDescription>
Enter new password and confirm it to reset your password
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit}>
<div className="grid w-full items-center gap-2">
<div className="flex flex-col space-y-1.5">
<Label htmlFor="email">New password</Label>
<PasswordInput
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete="password"
placeholder="Password"
/>
</div>
<div className="flex flex-col space-y-1.5">
<Label htmlFor="email">Confirm password</Label>
<PasswordInput
id="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
autoComplete="password"
placeholder="Password"
/>
</div>
</div>
{error && (
<Alert variant="destructive" className="mt-4">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<Button
className="w-full mt-4"
type="submit"
disabled={isSubmitting}
>
{isSubmitting ? "Resetting..." : "Reset password"}
</Button>
</form>
</CardContent>
</Card>
</div>
);
}

View File

@@ -5,26 +5,26 @@ import { SignUp } from "@/components/sign-up";
import { Tabs } from "@/components/ui/tabs2";
export default function Page() {
return (
<div className="w-full">
<div className="flex items-center flex-col justify-center w-full md:py-10">
<div className="md:w-[400px]">
<Tabs
tabs={[
{
title: "Sign In",
value: "sign-in",
content: <SignIn />,
},
{
title: "Sign Up",
value: "sign-up",
content: <SignUp />,
},
]}
/>
</div>
</div>
</div>
);
return (
<div className="w-full">
<div className="flex items-center flex-col justify-center w-full md:py-10">
<div className="md:w-[400px]">
<Tabs
tabs={[
{
title: "Sign In",
value: "sign-in",
content: <SignIn />,
},
{
title: "Sign Up",
value: "sign-up",
content: <SignUp />,
},
]}
/>
</div>
</div>
</div>
);
}

View File

@@ -2,12 +2,12 @@
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -17,105 +17,105 @@ import { useRouter } from "next/navigation";
import { useState } from "react";
export default function Component() {
const [otp, setOtp] = useState("");
const [isOtpSent, setIsOtpSent] = useState(false);
const [message, setMessage] = useState("");
const [isError, setIsError] = useState(false);
const [isValidated, setIsValidated] = useState(false);
const [OTP, setOTP] = useState("");
const [otp, setOtp] = useState("");
const [isOtpSent, setIsOtpSent] = useState(false);
const [message, setMessage] = useState("");
const [isError, setIsError] = useState(false);
const [isValidated, setIsValidated] = useState(false);
const [OTP, setOTP] = useState("");
// In a real app, this email would come from your authentication context
const userEmail = "user@example.com";
// In a real app, this email would come from your authentication context
const userEmail = "user@example.com";
const requestOTP = async () => {
const res = await client.twoFactor.sendOtp({
fetchOptions: {
body: {
returnOTP: true,
},
},
});
setOTP(res.data?.OTP || "");
// In a real app, this would call your backend API to send the OTP
setMessage("OTP sent to your email");
setIsError(false);
setIsOtpSent(true);
};
const router = useRouter();
const requestOTP = async () => {
const res = await client.twoFactor.sendOtp({
fetchOptions: {
body: {
returnOTP: true,
},
},
});
setOTP(res.data?.OTP || "");
// In a real app, this would call your backend API to send the OTP
setMessage("OTP sent to your email");
setIsError(false);
setIsOtpSent(true);
};
const router = useRouter();
const validateOTP = async () => {
const res = await client.twoFactor.verifyOtp({
code: otp,
});
if (res.data) {
setMessage("OTP validated successfully");
setIsError(false);
setIsValidated(true);
router.push("/");
} else {
setIsError(true);
setMessage("Invalid OTP");
}
};
return (
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Two-Factor Authentication</CardTitle>
<CardDescription>
Verify your identity with a one-time password
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid w-full items-center gap-4">
{!isOtpSent ? (
<Button onClick={requestOTP} className="w-full">
<Mail className="mr-2 h-4 w-4" /> Send OTP to Email
</Button>
) : (
<>
<div className="flex flex-col space-y-1.5">
<Label htmlFor="otp">One-Time Password</Label>
<Label className="py-2">
Use{" "}
<span className="text-blue-100 bg-slate-800 px-2">
{OTP}
</span>{" "}
(on real app, this would be sent to your email)
</Label>
<Input
id="otp"
placeholder="Enter 6-digit OTP"
value={otp}
onChange={(e) => setOtp(e.target.value)}
maxLength={6}
/>
</div>
<Button
onClick={validateOTP}
disabled={otp.length !== 6 || isValidated}
>
Validate OTP
</Button>
</>
)}
</div>
{message && (
<div
className={`flex items-center gap-2 mt-4 ${
isError ? "text-red-500" : "text-primary"
}`}
>
{isError ? (
<AlertCircle className="h-4 w-4" />
) : (
<CheckCircle2 className="h-4 w-4" />
)}
<p className="text-sm">{message}</p>
</div>
)}
</CardContent>
</Card>
</main>
);
const validateOTP = async () => {
const res = await client.twoFactor.verifyOtp({
code: otp,
});
if (res.data) {
setMessage("OTP validated successfully");
setIsError(false);
setIsValidated(true);
router.push("/");
} else {
setIsError(true);
setMessage("Invalid OTP");
}
};
return (
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Two-Factor Authentication</CardTitle>
<CardDescription>
Verify your identity with a one-time password
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid w-full items-center gap-4">
{!isOtpSent ? (
<Button onClick={requestOTP} className="w-full">
<Mail className="mr-2 h-4 w-4" /> Send OTP to Email
</Button>
) : (
<>
<div className="flex flex-col space-y-1.5">
<Label htmlFor="otp">One-Time Password</Label>
<Label className="py-2">
Use{" "}
<span className="text-blue-100 bg-slate-800 px-2">
{OTP}
</span>{" "}
(on real app, this would be sent to your email)
</Label>
<Input
id="otp"
placeholder="Enter 6-digit OTP"
value={otp}
onChange={(e) => setOtp(e.target.value)}
maxLength={6}
/>
</div>
<Button
onClick={validateOTP}
disabled={otp.length !== 6 || isValidated}
>
Validate OTP
</Button>
</>
)}
</div>
{message && (
<div
className={`flex items-center gap-2 mt-4 ${
isError ? "text-red-500" : "text-primary"
}`}
>
{isError ? (
<AlertCircle className="h-4 w-4" />
) : (
<CheckCircle2 className="h-4 w-4" />
)}
<p className="text-sm">{message}</p>
</div>
)}
</CardContent>
</Card>
</main>
);
}

View File

@@ -2,12 +2,12 @@
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -17,81 +17,81 @@ import Link from "next/link";
import { useState } from "react";
export default function Component() {
const [totpCode, setTotpCode] = useState("");
const [error, setError] = useState("");
const [success, setSuccess] = useState(false);
const [totpCode, setTotpCode] = useState("");
const [error, setError] = useState("");
const [success, setSuccess] = useState(false);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (totpCode.length !== 6 || !/^\d+$/.test(totpCode)) {
setError("TOTP code must be 6 digits");
return;
}
client.twoFactor
.verifyTotp({
code: totpCode,
})
.then((res) => {
if (res.data?.status) {
setSuccess(true);
setError("");
} else {
setError("Invalid TOTP code");
}
});
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (totpCode.length !== 6 || !/^\d+$/.test(totpCode)) {
setError("TOTP code must be 6 digits");
return;
}
client.twoFactor
.verifyTotp({
code: totpCode,
})
.then((res) => {
if (res.data?.status) {
setSuccess(true);
setError("");
} else {
setError("Invalid TOTP code");
}
});
};
return (
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
<Card className="w-[350px]">
<CardHeader>
<CardTitle>TOTP Verification</CardTitle>
<CardDescription>
Enter your 6-digit TOTP code to authenticate
</CardDescription>
</CardHeader>
<CardContent>
{!success ? (
<form onSubmit={handleSubmit}>
<div className="space-y-2">
<Label htmlFor="totp">TOTP Code</Label>
<Input
id="totp"
type="text"
inputMode="numeric"
pattern="\d{6}"
maxLength={6}
value={totpCode}
onChange={(e) => setTotpCode(e.target.value)}
placeholder="Enter 6-digit code"
required
/>
</div>
{error && (
<div className="flex items-center mt-2 text-red-500">
<AlertCircle className="w-4 h-4 mr-2" />
<span className="text-sm">{error}</span>
</div>
)}
<Button type="submit" className="w-full mt-4">
Verify
</Button>
</form>
) : (
<div className="flex flex-col items-center justify-center space-y-2">
<CheckCircle2 className="w-12 h-12 text-green-500" />
<p className="text-lg font-semibold">Verification Successful</p>
</div>
)}
</CardContent>
<CardFooter className="text-sm text-muted-foreground gap-2">
<Link href="/two-factor/otp">
<Button variant="link" size="sm">
Switch to Email Verification
</Button>
</Link>
</CardFooter>
</Card>
</main>
);
return (
<main className="flex flex-col items-center justify-center min-h-[calc(100vh-10rem)]">
<Card className="w-[350px]">
<CardHeader>
<CardTitle>TOTP Verification</CardTitle>
<CardDescription>
Enter your 6-digit TOTP code to authenticate
</CardDescription>
</CardHeader>
<CardContent>
{!success ? (
<form onSubmit={handleSubmit}>
<div className="space-y-2">
<Label htmlFor="totp">TOTP Code</Label>
<Input
id="totp"
type="text"
inputMode="numeric"
pattern="\d{6}"
maxLength={6}
value={totpCode}
onChange={(e) => setTotpCode(e.target.value)}
placeholder="Enter 6-digit code"
required
/>
</div>
{error && (
<div className="flex items-center mt-2 text-red-500">
<AlertCircle className="w-4 h-4 mr-2" />
<span className="text-sm">{error}</span>
</div>
)}
<Button type="submit" className="w-full mt-4">
Verify
</Button>
</form>
) : (
<div className="flex flex-col items-center justify-center space-y-2">
<CheckCircle2 className="w-12 h-12 text-green-500" />
<p className="text-lg font-semibold">Verification Successful</p>
</div>
)}
</CardContent>
<CardFooter className="text-sm text-muted-foreground gap-2">
<Link href="/two-factor/otp">
<Button variant="link" size="sm">
Switch to Email Verification
</Button>
</Link>
</CardFooter>
</Card>
</main>
);
}

View File

@@ -1,31 +1,43 @@
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { AlertCircle } from "lucide-react"
import Link from "next/link"
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { AlertCircle } from "lucide-react";
import Link from "next/link";
export function InvitationError() {
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<div className="flex items-center space-x-2">
<AlertCircle className="w-6 h-6 text-destructive" />
<CardTitle className="text-xl text-destructive">Invitation Error</CardTitle>
</div>
<CardDescription>
There was an issue with your invitation.
</CardDescription>
</CardHeader>
<CardContent>
<p className="mb-4 text-sm text-muted-foreground">
The invitation you're trying to access is either invalid or you don't have the correct permissions.
Please check your email for a valid invitation or contact the person who sent it.
</p>
</CardContent>
<CardFooter>
<Link href="/" className="w-full">
<Button variant="outline" className="w-full">Go back to home</Button>
</Link>
</CardFooter>
</Card>
)
}
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<div className="flex items-center space-x-2">
<AlertCircle className="w-6 h-6 text-destructive" />
<CardTitle className="text-xl text-destructive">
Invitation Error
</CardTitle>
</div>
<CardDescription>
There was an issue with your invitation.
</CardDescription>
</CardHeader>
<CardContent>
<p className="mb-4 text-sm text-muted-foreground">
The invitation you're trying to access is either invalid or you don't
have the correct permissions. Please check your email for a valid
invitation or contact the person who sent it.
</p>
</CardContent>
<CardFooter>
<Link href="/" className="w-full">
<Button variant="outline" className="w-full">
Go back to home
</Button>
</Link>
</CardFooter>
</Card>
);
}

View File

@@ -2,12 +2,12 @@
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { CheckIcon, XIcon } from "lucide-react";
import { useEffect, useState } from "react";
@@ -18,169 +18,169 @@ import { InvitationError } from "./invitation-error";
import { Invitation } from "@/lib/auth-types";
export default function InvitationPage({
params,
params,
}: {
params: {
id: string;
};
params: {
id: string;
};
}) {
const router = useRouter();
const [invitationStatus, setInvitationStatus] = useState<
"pending" | "accepted" | "rejected"
>("pending");
const router = useRouter();
const [invitationStatus, setInvitationStatus] = useState<
"pending" | "accepted" | "rejected"
>("pending");
const handleAccept = async () => {
await organization
.acceptInvitation({
invitationId: params.id,
})
.then((res) => {
if (res.error) {
setError(res.error.message || "An error occurred");
} else {
setInvitationStatus("accepted");
router.push(`/dashboard`);
}
});
};
const handleAccept = async () => {
await organization
.acceptInvitation({
invitationId: params.id,
})
.then((res) => {
if (res.error) {
setError(res.error.message || "An error occurred");
} else {
setInvitationStatus("accepted");
router.push(`/dashboard`);
}
});
};
const handleReject = async () => {
await organization
.rejectInvitation({
invitationId: params.id,
})
.then((res) => {
if (res.error) {
setError(res.error.message || "An error occurred");
} else {
setInvitationStatus("rejected");
}
});
};
const handleReject = async () => {
await organization
.rejectInvitation({
invitationId: params.id,
})
.then((res) => {
if (res.error) {
setError(res.error.message || "An error occurred");
} else {
setInvitationStatus("rejected");
}
});
};
const [invitation, setInvitation] = useState<{
organizationName: string;
organizationSlug: string;
inviterEmail: string;
id: string;
status: "pending" | "accepted" | "rejected" | "canceled";
email: string;
expiresAt: Date;
organizationId: string;
role: "member" | "admin" | "owner";
inviterId: string;
} | null>(null);
const [invitation, setInvitation] = useState<{
organizationName: string;
organizationSlug: string;
inviterEmail: string;
id: string;
status: "pending" | "accepted" | "rejected" | "canceled";
email: string;
expiresAt: Date;
organizationId: string;
role: "member" | "admin" | "owner";
inviterId: string;
} | null>(null);
const [error, setError] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
client.organization
.getInvitation({
query: {
id: params.id,
},
})
.then((res) => {
if (res.error) {
setError(res.error.message || "An error occurred");
} else {
setInvitation(res.data);
}
});
}, []);
useEffect(() => {
client.organization
.getInvitation({
query: {
id: params.id,
},
})
.then((res) => {
if (res.error) {
setError(res.error.message || "An error occurred");
} else {
setInvitation(res.data);
}
});
}, []);
return (
<div className="min-h-[80vh] flex items-center justify-center">
<div className="absolute pointer-events-none inset-0 flex items-center justify-center dark:bg-black bg-white [mask-image:radial-gradient(ellipse_at_center,transparent_20%,black)]"></div>
{invitation ? (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>Organization Invitation</CardTitle>
<CardDescription>
You've been invited to join an organization
</CardDescription>
</CardHeader>
<CardContent>
{invitationStatus === "pending" && (
<div className="space-y-4">
<p>
<strong>{invitation?.inviterEmail}</strong> has invited you to
join <strong>{invitation?.organizationName}</strong>.
</p>
<p>
This invitation was sent to{" "}
<strong>{invitation?.email}</strong>.
</p>
</div>
)}
{invitationStatus === "accepted" && (
<div className="space-y-4">
<div className="flex items-center justify-center w-16 h-16 mx-auto bg-green-100 rounded-full">
<CheckIcon className="w-8 h-8 text-green-600" />
</div>
<h2 className="text-2xl font-bold text-center">
Welcome to {invitation?.organizationName}!
</h2>
<p className="text-center">
You've successfully joined the organization. We're excited to
have you on board!
</p>
</div>
)}
{invitationStatus === "rejected" && (
<div className="space-y-4">
<div className="flex items-center justify-center w-16 h-16 mx-auto bg-red-100 rounded-full">
<XIcon className="w-8 h-8 text-red-600" />
</div>
<h2 className="text-2xl font-bold text-center">
Invitation Declined
</h2>
<p className="text-center">
You&lsquo;ve declined the invitation to join{" "}
{invitation?.organizationName}.
</p>
</div>
)}
</CardContent>
{invitationStatus === "pending" && (
<CardFooter className="flex justify-between">
<Button variant="outline" onClick={handleReject}>
Decline
</Button>
<Button onClick={handleAccept}>Accept Invitation</Button>
</CardFooter>
)}
</Card>
) : error ? (
<InvitationError />
) : (
<InvitationSkeleton />
)}
</div>
);
return (
<div className="min-h-[80vh] flex items-center justify-center">
<div className="absolute pointer-events-none inset-0 flex items-center justify-center dark:bg-black bg-white [mask-image:radial-gradient(ellipse_at_center,transparent_20%,black)]"></div>
{invitation ? (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>Organization Invitation</CardTitle>
<CardDescription>
You've been invited to join an organization
</CardDescription>
</CardHeader>
<CardContent>
{invitationStatus === "pending" && (
<div className="space-y-4">
<p>
<strong>{invitation?.inviterEmail}</strong> has invited you to
join <strong>{invitation?.organizationName}</strong>.
</p>
<p>
This invitation was sent to{" "}
<strong>{invitation?.email}</strong>.
</p>
</div>
)}
{invitationStatus === "accepted" && (
<div className="space-y-4">
<div className="flex items-center justify-center w-16 h-16 mx-auto bg-green-100 rounded-full">
<CheckIcon className="w-8 h-8 text-green-600" />
</div>
<h2 className="text-2xl font-bold text-center">
Welcome to {invitation?.organizationName}!
</h2>
<p className="text-center">
You've successfully joined the organization. We're excited to
have you on board!
</p>
</div>
)}
{invitationStatus === "rejected" && (
<div className="space-y-4">
<div className="flex items-center justify-center w-16 h-16 mx-auto bg-red-100 rounded-full">
<XIcon className="w-8 h-8 text-red-600" />
</div>
<h2 className="text-2xl font-bold text-center">
Invitation Declined
</h2>
<p className="text-center">
You&lsquo;ve declined the invitation to join{" "}
{invitation?.organizationName}.
</p>
</div>
)}
</CardContent>
{invitationStatus === "pending" && (
<CardFooter className="flex justify-between">
<Button variant="outline" onClick={handleReject}>
Decline
</Button>
<Button onClick={handleAccept}>Accept Invitation</Button>
</CardFooter>
)}
</Card>
) : error ? (
<InvitationError />
) : (
<InvitationSkeleton />
)}
</div>
);
}
function InvitationSkeleton() {
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<div className="flex items-center space-x-2">
<Skeleton className="w-6 h-6 rounded-full" />
<Skeleton className="h-6 w-24" />
</div>
<Skeleton className="h-4 w-full mt-2" />
<Skeleton className="h-4 w-2/3 mt-2" />
</CardHeader>
<CardContent>
<div className="space-y-2">
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-2/3" />
</div>
</CardContent>
<CardFooter className="flex justify-end">
<Skeleton className="h-10 w-24" />
</CardFooter>
</Card>
);
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<div className="flex items-center space-x-2">
<Skeleton className="w-6 h-6 rounded-full" />
<Skeleton className="h-6 w-24" />
</div>
<Skeleton className="h-4 w-full mt-2" />
<Skeleton className="h-4 w-2/3 mt-2" />
</CardHeader>
<CardContent>
<div className="space-y-2">
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-2/3" />
</div>
</CardContent>
<CardFooter className="flex justify-end">
<Skeleton className="h-10 w-24" />
</CardFooter>
</Card>
);
}

View File

@@ -1,4 +1,4 @@
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";
export const { GET, POST } = toNextJsHandler(auth);
export const { GET, POST } = toNextJsHandler(auth);

View File

@@ -1,9 +1,9 @@
"use client";
export function ManageAccount() {
return (
<div className="flex items-center gap-2">
<p>Manage Account</p>
</div>
);
return (
<div className="flex items-center gap-2">
<p>Manage Account</p>
</div>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,25 +5,25 @@ import UserCard from "./user-card";
import { OrganizationCard } from "./organization-card";
export default async function DashboardPage() {
const [session, activeSessions] = await Promise.all([
auth.api.getSession({
headers: headers(),
}),
auth.api.listSessions({
headers: headers(),
}),
]).catch((e) => {
throw redirect("/sign-in");
});
return (
<div className="w-full">
<div className="flex gap-4 flex-col">
<UserCard
session={JSON.parse(JSON.stringify(session))}
activeSessions={JSON.parse(JSON.stringify(activeSessions))}
/>
<OrganizationCard session={JSON.parse(JSON.stringify(session))} />
</div>
</div>
);
const [session, activeSessions] = await Promise.all([
auth.api.getSession({
headers: headers(),
}),
auth.api.listSessions({
headers: headers(),
}),
]).catch((e) => {
throw redirect("/sign-in");
});
return (
<div className="w-full">
<div className="flex gap-4 flex-col">
<UserCard
session={JSON.parse(JSON.stringify(session))}
activeSessions={JSON.parse(JSON.stringify(activeSessions))}
/>
<OrganizationCard session={JSON.parse(JSON.stringify(session))} />
</div>
</div>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,95 +5,94 @@ import { AnimatePresence, motion } from "framer-motion";
import { Logo } from "@/components/logo";
export function Features() {
return (
<>
<div className="flex flex-col lg:flex-row bg-white dark:bg-black w-full gap-4 mx-auto px-8">
<Card title="BetterAuth" icon={<Logo className=" w-44" />}>
</Card>
</div>
</>
);
return (
<>
<div className="flex flex-col lg:flex-row bg-white dark:bg-black w-full gap-4 mx-auto px-8">
<Card title="BetterAuth" icon={<Logo className=" w-44" />}></Card>
</div>
</>
);
}
const Card = ({
title,
icon,
children,
title,
icon,
children,
}: {
title: string;
icon: React.ReactNode;
children?: React.ReactNode;
title: string;
icon: React.ReactNode;
children?: React.ReactNode;
}) => {
const [hovered, setHovered] = React.useState(false);
return (
<div
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
className="border border-black/[0.2] group/canvas-card flex items-center justify-center dark:border-white/[0.2] max-w-sm w-full mx-auto p-4 relative h-[18rem]"
>
<Icon className="absolute h-6 w-6 -top-3 -left-3 dark:text-white text-black" />
<Icon className="absolute h-6 w-6 -bottom-3 -left-3 dark:text-white text-black" />
<Icon className="absolute h-6 w-6 -top-3 -right-3 dark:text-white text-black" />
<Icon className="absolute h-6 w-6 -bottom-3 -right-3 dark:text-white text-black" />
const [hovered, setHovered] = React.useState(false);
return (
<div
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
className="border border-black/[0.2] group/canvas-card flex items-center justify-center dark:border-white/[0.2] max-w-sm w-full mx-auto p-4 relative h-[18rem]"
>
<Icon className="absolute h-6 w-6 -top-3 -left-3 dark:text-white text-black" />
<Icon className="absolute h-6 w-6 -bottom-3 -left-3 dark:text-white text-black" />
<Icon className="absolute h-6 w-6 -top-3 -right-3 dark:text-white text-black" />
<Icon className="absolute h-6 w-6 -bottom-3 -right-3 dark:text-white text-black" />
<AnimatePresence>
{hovered && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="h-full w-full absolute inset-0"
>
{children}
</motion.div>
)}
</AnimatePresence>
<AnimatePresence>
{hovered && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="h-full w-full absolute inset-0"
>
{children}
</motion.div>
)}
</AnimatePresence>
<div className="relative z-20">
<div className="text-center group-hover/canvas-card:-translate-y-4 group-hover/canvas-card:opacity-0 transition duration-200 w-full mx-auto flex items-center justify-center">
{icon}
</div>
<h2 className="dark:text-white text-xl opacity-0 group-hover/canvas-card:opacity-100 relative z-10 text-black mt-4 font-bold group-hover/canvas-card:text-white group-hover/canvas-card:-translate-y-2 transition duration-200">
{title}
</h2>
</div>
</div>
);
<div className="relative z-20">
<div className="text-center group-hover/canvas-card:-translate-y-4 group-hover/canvas-card:opacity-0 transition duration-200 w-full mx-auto flex items-center justify-center">
{icon}
</div>
<h2 className="dark:text-white text-xl opacity-0 group-hover/canvas-card:opacity-100 relative z-10 text-black mt-4 font-bold group-hover/canvas-card:text-white group-hover/canvas-card:-translate-y-2 transition duration-200">
{title}
</h2>
</div>
</div>
);
};
const AceternityIcon = () => {
return (
<svg
width="66"
height="65"
viewBox="0 0 66 65"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="h-10 w-10 text-black dark:text-white group-hover/canvas-card:text-white "
>
<path
d="M8 8.05571C8 8.05571 54.9009 18.1782 57.8687 30.062C60.8365 41.9458 9.05432 57.4696 9.05432 57.4696"
stroke="currentColor"
strokeWidth="15"
strokeMiterlimit="3.86874"
strokeLinecap="round"
style={{ mixBlendMode: "darken" }}
/>
</svg>
);
return (
<svg
width="66"
height="65"
viewBox="0 0 66 65"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="h-10 w-10 text-black dark:text-white group-hover/canvas-card:text-white "
>
<path
d="M8 8.05571C8 8.05571 54.9009 18.1782 57.8687 30.062C60.8365 41.9458 9.05432 57.4696 9.05432 57.4696"
stroke="currentColor"
strokeWidth="15"
strokeMiterlimit="3.86874"
strokeLinecap="round"
style={{ mixBlendMode: "darken" }}
/>
</svg>
);
};
export const Icon = ({ className, ...rest }: any) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="1.5"
stroke="currentColor"
className={className}
{...rest}
>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 6v12m6-6H6" />
</svg>
);
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="1.5"
stroke="currentColor"
className={className}
{...rest}
>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 6v12m6-6H6" />
</svg>
);
};

View File

@@ -9,32 +9,32 @@ import { Wrapper, WrapperWithQuery } from "@/components/wrapper";
import { createMetadata } from "@/lib/metadata";
export const metadata = createMetadata({
title: {
template: "%s | Better Auth",
default: "Better Auth",
},
description: "The most comprehensive authentication library for typescript",
metadataBase: new URL("https://demo.better-auth.com"),
title: {
template: "%s | Better Auth",
default: "Better Auth",
},
description: "The most comprehensive authentication library for typescript",
metadataBase: new URL("https://demo.better-auth.com"),
});
export default function RootLayout({
children,
children,
}: Readonly<{
children: React.ReactNode;
children: React.ReactNode;
}>) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<link rel="icon" href="/favicon/favicon.ico" sizes="any" />
</head>
<body className={`${GeistSans.variable} ${GeistMono.variable} font-sans`}>
<ThemeProvider attribute="class" defaultTheme="dark">
<Wrapper>
<WrapperWithQuery>{children}</WrapperWithQuery>
</Wrapper>
<Toaster richColors closeButton />
</ThemeProvider>
</body>
</html>
);
return (
<html lang="en" suppressHydrationWarning>
<head>
<link rel="icon" href="/favicon/favicon.ico" sizes="any" />
</head>
<body className={`${GeistSans.variable} ${GeistMono.variable} font-sans`}>
<ThemeProvider attribute="class" defaultTheme="dark">
<Wrapper>
<WrapperWithQuery>{children}</WrapperWithQuery>
</Wrapper>
<Toaster richColors closeButton />
</ThemeProvider>
</body>
</html>
);
}

View File

@@ -3,61 +3,61 @@ import { headers } from "next/headers";
import { Suspense } from "react";
export default async function Home() {
const features = [
"Email & Password",
"Organization | Teams",
"Passkeys",
"Multi Factor",
"Password Reset",
"Roles & Permissions",
"Rate Limiting",
"Session Management",
];
return (
<div className="min-h-[80vh] flex items-center justify-center overflow-hidden no-visible-scrollbar px-6 md:px-0">
<main className="flex flex-col gap-4 row-start-2 items-center justify-center">
<div className="flex flex-col gap-1">
<h3 className="font-bold text-4xl text-black dark:text-white text-center">
Better Auth.
</h3>
<p className="text-center break-words text-sm md:text-base">
Official demo to showcase{" "}
<a
href="https://better-auth.com"
target="_blank"
className="italic underline"
>
better-auth.
</a>{" "}
features and capabilities. <br />
</p>
</div>
<div className="md:w-10/12 w-full flex flex-col gap-4">
<div className="flex flex-col gap-3 pt-2 flex-wrap">
<div className="border-y py-2 border-dotted bg-secondary/60 opacity-80">
<div className="text-xs flex items-center gap-2 justify-center text-muted-foreground ">
<span className="text-center">
All features on this demo are Implemented with better auth
without any custom backend code
</span>
</div>
</div>
<div className="flex gap-2 justify-center flex-wrap">
{features.map((feature) => (
<span
className="border-b pb-1 text-muted-foreground text-xs cursor-pointer hover:text-foreground duration-150 ease-in-out transition-all hover:border-foreground flex items-center gap-1"
key={feature}
>
{feature}.
</span>
))}
</div>
</div>
<Suspense fallback={<SignInFallback />}>
<SignInButton />
</Suspense>
</div>
</main>
</div>
);
const features = [
"Email & Password",
"Organization | Teams",
"Passkeys",
"Multi Factor",
"Password Reset",
"Roles & Permissions",
"Rate Limiting",
"Session Management",
];
return (
<div className="min-h-[80vh] flex items-center justify-center overflow-hidden no-visible-scrollbar px-6 md:px-0">
<main className="flex flex-col gap-4 row-start-2 items-center justify-center">
<div className="flex flex-col gap-1">
<h3 className="font-bold text-4xl text-black dark:text-white text-center">
Better Auth.
</h3>
<p className="text-center break-words text-sm md:text-base">
Official demo to showcase{" "}
<a
href="https://better-auth.com"
target="_blank"
className="italic underline"
>
better-auth.
</a>{" "}
features and capabilities. <br />
</p>
</div>
<div className="md:w-10/12 w-full flex flex-col gap-4">
<div className="flex flex-col gap-3 pt-2 flex-wrap">
<div className="border-y py-2 border-dotted bg-secondary/60 opacity-80">
<div className="text-xs flex items-center gap-2 justify-center text-muted-foreground ">
<span className="text-center">
All features on this demo are Implemented with better auth
without any custom backend code
</span>
</div>
</div>
<div className="flex gap-2 justify-center flex-wrap">
{features.map((feature) => (
<span
className="border-b pb-1 text-muted-foreground text-xs cursor-pointer hover:text-foreground duration-150 ease-in-out transition-all hover:border-foreground flex items-center gap-1"
key={feature}
>
{feature}.
</span>
))}
</div>
</div>
<Suspense fallback={<SignInFallback />}>
<SignInButton />
</Suspense>
</div>
</main>
</div>
);
}

View File

@@ -1,20 +1,20 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
}
}
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
}
}

View File

@@ -1,24 +1,24 @@
import { SVGProps } from "react";
export const Logo = (props: SVGProps<any>) => {
return (
<svg
width="22"
height="22"
viewBox="0 0 200 200"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<rect width="200" height="200" fill="#D9D9D9" />
<line x1="21.5" y1="2.18557e-08" x2="21.5" y2="200" stroke="#C4C4C4" />
<line x1="173.5" y1="2.18557e-08" x2="173.5" y2="200" stroke="#C4C4C4" />
<line x1="200" y1="176.5" x2="-4.37114e-08" y2="176.5" stroke="#C4C4C4" />
<line x1="200" y1="24.5" x2="-4.37114e-08" y2="24.5" stroke="#C4C4C4" />
<path
d="M64.4545 135V65.1818H88.8636C93.7273 65.1818 97.7386 66.0227 100.898 67.7045C104.057 69.3636 106.409 71.6023 107.955 74.4205C109.5 77.2159 110.273 80.3182 110.273 83.7273C110.273 86.7273 109.739 89.2045 108.67 91.1591C107.625 93.1136 106.239 94.6591 104.511 95.7955C102.807 96.9318 100.955 97.7727 98.9545 98.3182V99C101.091 99.1364 103.239 99.8864 105.398 101.25C107.557 102.614 109.364 104.568 110.818 107.114C112.273 109.659 113 112.773 113 116.455C113 119.955 112.205 123.102 110.614 125.898C109.023 128.693 106.511 130.909 103.08 132.545C99.6477 134.182 95.1818 135 89.6818 135H64.4545ZM72.9091 127.5H89.6818C95.2045 127.5 99.125 126.432 101.443 124.295C103.784 122.136 104.955 119.523 104.955 116.455C104.955 114.091 104.352 111.909 103.148 109.909C101.943 107.886 100.227 106.273 98 105.068C95.7727 103.841 93.1364 103.227 90.0909 103.227H72.9091V127.5ZM72.9091 95.8636H88.5909C91.1364 95.8636 93.4318 95.3636 95.4773 94.3636C97.5455 93.3636 99.1818 91.9545 100.386 90.1364C101.614 88.3182 102.227 86.1818 102.227 83.7273C102.227 80.6591 101.159 78.0568 99.0227 75.9205C96.8864 73.7614 93.5 72.6818 88.8636 72.6818H72.9091V95.8636ZM131.665 135.545C129.983 135.545 128.54 134.943 127.335 133.739C126.131 132.534 125.528 131.091 125.528 129.409C125.528 127.727 126.131 126.284 127.335 125.08C128.54 123.875 129.983 123.273 131.665 123.273C133.347 123.273 134.79 123.875 135.994 125.08C137.199 126.284 137.801 127.727 137.801 129.409C137.801 130.523 137.517 131.545 136.949 132.477C136.403 133.409 135.665 134.159 134.733 134.727C133.824 135.273 132.801 135.545 131.665 135.545Z"
fill="#302208"
/>
</svg>
);
return (
<svg
width="22"
height="22"
viewBox="0 0 200 200"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<rect width="200" height="200" fill="#D9D9D9" />
<line x1="21.5" y1="2.18557e-08" x2="21.5" y2="200" stroke="#C4C4C4" />
<line x1="173.5" y1="2.18557e-08" x2="173.5" y2="200" stroke="#C4C4C4" />
<line x1="200" y1="176.5" x2="-4.37114e-08" y2="176.5" stroke="#C4C4C4" />
<line x1="200" y1="24.5" x2="-4.37114e-08" y2="24.5" stroke="#C4C4C4" />
<path
d="M64.4545 135V65.1818H88.8636C93.7273 65.1818 97.7386 66.0227 100.898 67.7045C104.057 69.3636 106.409 71.6023 107.955 74.4205C109.5 77.2159 110.273 80.3182 110.273 83.7273C110.273 86.7273 109.739 89.2045 108.67 91.1591C107.625 93.1136 106.239 94.6591 104.511 95.7955C102.807 96.9318 100.955 97.7727 98.9545 98.3182V99C101.091 99.1364 103.239 99.8864 105.398 101.25C107.557 102.614 109.364 104.568 110.818 107.114C112.273 109.659 113 112.773 113 116.455C113 119.955 112.205 123.102 110.614 125.898C109.023 128.693 106.511 130.909 103.08 132.545C99.6477 134.182 95.1818 135 89.6818 135H64.4545ZM72.9091 127.5H89.6818C95.2045 127.5 99.125 126.432 101.443 124.295C103.784 122.136 104.955 119.523 104.955 116.455C104.955 114.091 104.352 111.909 103.148 109.909C101.943 107.886 100.227 106.273 98 105.068C95.7727 103.841 93.1364 103.227 90.0909 103.227H72.9091V127.5ZM72.9091 95.8636H88.5909C91.1364 95.8636 93.4318 95.3636 95.4773 94.3636C97.5455 93.3636 99.1818 91.9545 100.386 90.1364C101.614 88.3182 102.227 86.1818 102.227 83.7273C102.227 80.6591 101.159 78.0568 99.0227 75.9205C96.8864 73.7614 93.5 72.6818 88.8636 72.6818H72.9091V95.8636ZM131.665 135.545C129.983 135.545 128.54 134.943 127.335 133.739C126.131 132.534 125.528 131.091 125.528 129.409C125.528 127.727 126.131 126.284 127.335 125.08C128.54 123.875 129.983 123.273 131.665 123.273C133.347 123.273 134.79 123.875 135.994 125.08C137.199 126.284 137.801 127.727 137.801 129.409C137.801 130.523 137.517 131.545 136.949 132.477C136.403 133.409 135.665 134.159 134.733 134.727C133.824 135.273 132.801 135.545 131.665 135.545Z"
fill="#302208"
/>
</svg>
);
};

View File

@@ -4,62 +4,84 @@ import { auth } from "@/lib/auth";
import { headers } from "next/headers";
export async function SignInButton() {
const session = await auth.api.getSession({
headers: headers()
})
const session = await auth.api.getSession({
headers: headers(),
});
return (
<Link href={
session?.session ? "/dashboard" : "/sign-in"
} className="flex justify-center">
<Button className="gap-2 justify-between" variant="default">
{
!session?.session ? (
<svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24"><path fill="currentColor" d="M5 3H3v4h2V5h14v14H5v-2H3v4h18V3zm12 8h-2V9h-2V7h-2v2h2v2H3v2h10v2h-2v2h2v-2h2v-2h2z"></path></svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24"><path fill="currentColor" d="M2 3h20v18H2zm18 16V7H4v12z"></path></svg>
)
}
<span>
{
session?.session ? "Dashboard" : "Sign In"
}
</span>
</Button>
</Link>
)
return (
<Link
href={session?.session ? "/dashboard" : "/sign-in"}
className="flex justify-center"
>
<Button className="gap-2 justify-between" variant="default">
{!session?.session ? (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M5 3H3v4h2V5h14v14H5v-2H3v4h18V3zm12 8h-2V9h-2V7h-2v2h2v2H3v2h10v2h-2v2h2v-2h2v-2h2z"
></path>
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path fill="currentColor" d="M2 3h20v18H2zm18 16V7H4v12z"></path>
</svg>
)}
<span>{session?.session ? "Dashboard" : "Sign In"}</span>
</Button>
</Link>
);
}
function checkOptimisticSession(headers: Headers) {
const guessIsSignIn = headers.get("cookie")?.includes("better-auth.session") || headers.get("cookie")?.includes("__Secure-better-auth.session-token")
return !!guessIsSignIn;
const guessIsSignIn =
headers.get("cookie")?.includes("better-auth.session") ||
headers.get("cookie")?.includes("__Secure-better-auth.session-token");
return !!guessIsSignIn;
}
export function SignInFallback() {
//to avoid flash of unauthenticated state
const guessIsSignIn = checkOptimisticSession(headers())
return (
<Link href={
guessIsSignIn ? "/dashboard" : "/sign-in"
} className="flex justify-center">
<Button className="gap-2 justify-between" variant="default">
{
!guessIsSignIn ? (
<svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24"><path fill="currentColor" d="M5 3H3v4h2V5h14v14H5v-2H3v4h18V3zm12 8h-2V9h-2V7h-2v2h2v2H3v2h10v2h-2v2h2v-2h2v-2h2z"></path></svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24"><path fill="currentColor" d="M2 3h20v18H2zm18 16V7H4v12z"></path></svg>
)
}
<span>
{
guessIsSignIn ? "Dashboard" : "Sign In"
}
</span>
</Button>
</Link>
)
}
//to avoid flash of unauthenticated state
const guessIsSignIn = checkOptimisticSession(headers());
return (
<Link
href={guessIsSignIn ? "/dashboard" : "/sign-in"}
className="flex justify-center"
>
<Button className="gap-2 justify-between" variant="default">
{!guessIsSignIn ? (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M5 3H3v4h2V5h14v14H5v-2H3v4h18V3zm12 8h-2V9h-2V7h-2v2h2v2H3v2h10v2h-2v2h2v-2h2v-2h2z"
></path>
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path fill="currentColor" d="M2 3h20v18H2zm18 16V7H4v12z"></path>
</svg>
)}
<span>{guessIsSignIn ? "Dashboard" : "Sign In"}</span>
</Button>
</Link>
);
}

View File

@@ -2,12 +2,12 @@
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
@@ -22,156 +22,156 @@ import { useState } from "react";
import { toast } from "sonner";
export default function SignIn() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [rememberMe, setRememberMe] = useState(false);
const router = useRouter();
const [loading, setLoading] = useState(false);
return (
<Card className="z-50 rounded-md rounded-t-none max-w-md">
<CardHeader>
<CardTitle className="text-lg md:text-xl">Sign In</CardTitle>
<CardDescription className="text-xs md:text-sm">
Enter your email below to login to your account
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid gap-4">
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="m@example.com"
required
onChange={(e) => {
setEmail(e.target.value);
}}
value={email}
/>
</div>
<div className="grid gap-2">
<div className="flex items-center">
<Label htmlFor="password">Password</Label>
<Link
href="/forget-password"
className="ml-auto inline-block text-sm underline"
>
Forgot your password?
</Link>
</div>
<PasswordInput
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete="password"
placeholder="Password"
/>
</div>
<div className="flex items-center gap-2">
<Checkbox
onClick={() => {
setRememberMe(!rememberMe);
}}
/>
<Label>Remember me</Label>
</div>
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [rememberMe, setRememberMe] = useState(false);
const router = useRouter();
const [loading, setLoading] = useState(false);
return (
<Card className="z-50 rounded-md rounded-t-none max-w-md">
<CardHeader>
<CardTitle className="text-lg md:text-xl">Sign In</CardTitle>
<CardDescription className="text-xs md:text-sm">
Enter your email below to login to your account
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid gap-4">
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="m@example.com"
required
onChange={(e) => {
setEmail(e.target.value);
}}
value={email}
/>
</div>
<div className="grid gap-2">
<div className="flex items-center">
<Label htmlFor="password">Password</Label>
<Link
href="/forget-password"
className="ml-auto inline-block text-sm underline"
>
Forgot your password?
</Link>
</div>
<PasswordInput
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete="password"
placeholder="Password"
/>
</div>
<div className="flex items-center gap-2">
<Checkbox
onClick={() => {
setRememberMe(!rememberMe);
}}
/>
<Label>Remember me</Label>
</div>
<Button
type="submit"
className="w-full"
disabled={loading}
onClick={async () => {
await signIn.email({
email: email,
password: password,
callbackURL: "/dashboard",
dontRememberMe: !rememberMe,
fetchOptions: {
onRequest: () => {
setLoading(true);
},
onResponse: () => {
setLoading(false);
},
onError: (ctx) => {
toast.error(ctx.error.message);
},
},
});
}}
>
{loading ? <Loader2 size={16} className="animate-spin" /> : "Login"}
</Button>
<Button
variant="outline"
className="w-full gap-2"
onClick={async () => {
await signIn.social({
provider: "github",
callbackURL: "/dashboard",
});
}}
>
<GitHubLogoIcon />
Continue with Github
</Button>
<Button
variant="outline"
className="w-full gap-2"
onClick={async () => {
await signIn.social({
provider: "google",
callbackURL: "/dashboard",
});
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="0.98em"
height="1em"
viewBox="0 0 256 262"
>
<path
fill="#4285F4"
d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"
/>
<path
fill="#34A853"
d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"
/>
<path
fill="#FBBC05"
d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"
/>
<path
fill="#EB4335"
d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"
/>
</svg>
Continue with Google
</Button>
<Button
variant="outline"
className="gap-2"
onClick={async () => {
await signIn.passkey({
callbackURL: "/dashboard",
});
}}
>
<Key size={16} />
Sign-in with Passkey
</Button>
</div>
</CardContent>
<CardFooter>
<div className="flex justify-center w-full border-t py-4">
<p className="text-center text-xs text-neutral-500">
Secured by <span className="text-orange-400">better-auth.</span>
</p>
</div>
</CardFooter>
</Card>
);
<Button
type="submit"
className="w-full"
disabled={loading}
onClick={async () => {
await signIn.email({
email: email,
password: password,
callbackURL: "/dashboard",
dontRememberMe: !rememberMe,
fetchOptions: {
onRequest: () => {
setLoading(true);
},
onResponse: () => {
setLoading(false);
},
onError: (ctx) => {
toast.error(ctx.error.message);
},
},
});
}}
>
{loading ? <Loader2 size={16} className="animate-spin" /> : "Login"}
</Button>
<Button
variant="outline"
className="w-full gap-2"
onClick={async () => {
await signIn.social({
provider: "github",
callbackURL: "/dashboard",
});
}}
>
<GitHubLogoIcon />
Continue with Github
</Button>
<Button
variant="outline"
className="w-full gap-2"
onClick={async () => {
await signIn.social({
provider: "google",
callbackURL: "/dashboard",
});
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="0.98em"
height="1em"
viewBox="0 0 256 262"
>
<path
fill="#4285F4"
d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"
/>
<path
fill="#34A853"
d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"
/>
<path
fill="#FBBC05"
d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"
/>
<path
fill="#EB4335"
d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"
/>
</svg>
Continue with Google
</Button>
<Button
variant="outline"
className="gap-2"
onClick={async () => {
await signIn.passkey({
callbackURL: "/dashboard",
});
}}
>
<Key size={16} />
Sign-in with Passkey
</Button>
</div>
</CardContent>
<CardFooter>
<div className="flex justify-center w-full border-t py-4">
<p className="text-center text-xs text-neutral-500">
Secured by <span className="text-orange-400">better-auth.</span>
</p>
</div>
</CardFooter>
</Card>
);
}

View File

@@ -2,12 +2,12 @@
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -20,244 +20,244 @@ import { Loader2, X } from "lucide-react";
import { toast } from "sonner";
export function SignUp() {
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [passwordConfirmation, setPasswordConfirmation] = useState("");
const [image, setImage] = useState<File | null>(null);
const [imagePreview, setImagePreview] = useState<string | null>(null);
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [passwordConfirmation, setPasswordConfirmation] = useState("");
const [image, setImage] = useState<File | null>(null);
const [imagePreview, setImagePreview] = useState<string | null>(null);
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
setImage(file);
const reader = new FileReader();
reader.onloadend = () => {
setImagePreview(reader.result as string);
};
reader.readAsDataURL(file);
}
};
const [loading, setLoading] = useState(false);
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
setImage(file);
const reader = new FileReader();
reader.onloadend = () => {
setImagePreview(reader.result as string);
};
reader.readAsDataURL(file);
}
};
const [loading, setLoading] = useState(false);
return (
<Card className="z-50 rounded-md rounded-t-none max-w-md">
<CardHeader>
<CardTitle className="text-lg md:text-xl">Sign Up</CardTitle>
<CardDescription className="text-xs md:text-sm">
Enter your information to create an account
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid gap-4">
<div className="grid grid-cols-2 gap-4">
<div className="grid gap-2">
<Label htmlFor="first-name">First name</Label>
<Input
id="first-name"
placeholder="Max"
required
onChange={(e) => {
setFirstName(e.target.value);
}}
value={firstName}
/>
</div>
<div className="grid gap-2">
<Label htmlFor="last-name">Last name</Label>
<Input
id="last-name"
placeholder="Robinson"
required
onChange={(e) => {
setLastName(e.target.value);
}}
value={lastName}
/>
</div>
</div>
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="m@example.com"
required
onChange={(e) => {
setEmail(e.target.value);
}}
value={email}
/>
</div>
<div className="grid gap-2">
<Label htmlFor="password">Password</Label>
<PasswordInput
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete="new-password"
placeholder="Password"
/>
</div>
<div className="grid gap-2">
<Label htmlFor="password">Confirm Password</Label>
<PasswordInput
id="password_confirmation"
value={passwordConfirmation}
onChange={(e) => setPasswordConfirmation(e.target.value)}
autoComplete="new-password"
placeholder="Confirm Password"
/>
</div>
<div className="grid gap-2">
<Label htmlFor="image">Profile Image (optional)</Label>
<div className="flex items-end gap-4">
{imagePreview && (
<div className="relative w-16 h-16 rounded-sm overflow-hidden">
<Image
src={imagePreview}
alt="Profile preview"
layout="fill"
objectFit="cover"
/>
</div>
)}
<div className="flex items-center gap-2 w-full">
<Input
id="image"
type="file"
accept="image/*"
onChange={handleImageChange}
className="w-full"
/>
{imagePreview && (
<X
className="cursor-pointer"
onClick={() => {
setImage(null);
setImagePreview(null);
}}
/>
)}
</div>
</div>
</div>
<Button
type="submit"
className="w-full"
disabled={loading}
onClick={async () => {
await signUp.email({
email,
password,
name: `${firstName} ${lastName}`,
image: image ? await convertImageToBase64(image) : "",
callbackURL: "/dashboard",
fetchOptions: {
onResponse: () => {
setLoading(false);
},
onRequest: () => {
setLoading(true);
},
onError: (ctx) => {
toast.error(ctx.error.message);
},
},
});
}}
>
{loading ? (
<Loader2 size={16} className="animate-spin" />
) : (
"Create an account"
)}
</Button>
<Button
variant="outline"
className="w-full gap-2"
onClick={async () => {
const res = await client.signIn.social({
provider: "google",
callbackURL: "/dashboard",
fetchOptions: {
onRequest: () => {
setLoading(true);
},
onResponse: () => {
setLoading(false);
},
},
});
}}
disabled={loading}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="0.98em"
height="1em"
viewBox="0 0 256 262"
>
<path
fill="#4285F4"
d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"
/>
<path
fill="#34A853"
d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"
/>
<path
fill="#FBBC05"
d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"
/>
<path
fill="#EB4335"
d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"
/>
</svg>
Continue with Google
</Button>
<Button
variant="outline"
className="w-full gap-2"
onClick={async () => {
await signIn.social({
provider: "github",
callbackURL: "/dashboard",
fetchOptions: {
onRequest: () => {
setLoading(true);
},
onResponse: () => {
setLoading(false);
},
},
});
}}
disabled={loading}
>
<GitHubLogoIcon />
Continue with Github
</Button>
</div>
</CardContent>
<CardFooter>
<div className="flex justify-center w-full border-t py-4">
<p className="text-center text-xs text-neutral-500">
Secured by <span className="text-orange-400">better-auth.</span>
</p>
</div>
</CardFooter>
</Card>
);
return (
<Card className="z-50 rounded-md rounded-t-none max-w-md">
<CardHeader>
<CardTitle className="text-lg md:text-xl">Sign Up</CardTitle>
<CardDescription className="text-xs md:text-sm">
Enter your information to create an account
</CardDescription>
</CardHeader>
<CardContent>
<div className="grid gap-4">
<div className="grid grid-cols-2 gap-4">
<div className="grid gap-2">
<Label htmlFor="first-name">First name</Label>
<Input
id="first-name"
placeholder="Max"
required
onChange={(e) => {
setFirstName(e.target.value);
}}
value={firstName}
/>
</div>
<div className="grid gap-2">
<Label htmlFor="last-name">Last name</Label>
<Input
id="last-name"
placeholder="Robinson"
required
onChange={(e) => {
setLastName(e.target.value);
}}
value={lastName}
/>
</div>
</div>
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="m@example.com"
required
onChange={(e) => {
setEmail(e.target.value);
}}
value={email}
/>
</div>
<div className="grid gap-2">
<Label htmlFor="password">Password</Label>
<PasswordInput
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete="new-password"
placeholder="Password"
/>
</div>
<div className="grid gap-2">
<Label htmlFor="password">Confirm Password</Label>
<PasswordInput
id="password_confirmation"
value={passwordConfirmation}
onChange={(e) => setPasswordConfirmation(e.target.value)}
autoComplete="new-password"
placeholder="Confirm Password"
/>
</div>
<div className="grid gap-2">
<Label htmlFor="image">Profile Image (optional)</Label>
<div className="flex items-end gap-4">
{imagePreview && (
<div className="relative w-16 h-16 rounded-sm overflow-hidden">
<Image
src={imagePreview}
alt="Profile preview"
layout="fill"
objectFit="cover"
/>
</div>
)}
<div className="flex items-center gap-2 w-full">
<Input
id="image"
type="file"
accept="image/*"
onChange={handleImageChange}
className="w-full"
/>
{imagePreview && (
<X
className="cursor-pointer"
onClick={() => {
setImage(null);
setImagePreview(null);
}}
/>
)}
</div>
</div>
</div>
<Button
type="submit"
className="w-full"
disabled={loading}
onClick={async () => {
await signUp.email({
email,
password,
name: `${firstName} ${lastName}`,
image: image ? await convertImageToBase64(image) : "",
callbackURL: "/dashboard",
fetchOptions: {
onResponse: () => {
setLoading(false);
},
onRequest: () => {
setLoading(true);
},
onError: (ctx) => {
toast.error(ctx.error.message);
},
},
});
}}
>
{loading ? (
<Loader2 size={16} className="animate-spin" />
) : (
"Create an account"
)}
</Button>
<Button
variant="outline"
className="w-full gap-2"
onClick={async () => {
const res = await client.signIn.social({
provider: "google",
callbackURL: "/dashboard",
fetchOptions: {
onRequest: () => {
setLoading(true);
},
onResponse: () => {
setLoading(false);
},
},
});
}}
disabled={loading}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="0.98em"
height="1em"
viewBox="0 0 256 262"
>
<path
fill="#4285F4"
d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"
/>
<path
fill="#34A853"
d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"
/>
<path
fill="#FBBC05"
d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"
/>
<path
fill="#EB4335"
d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"
/>
</svg>
Continue with Google
</Button>
<Button
variant="outline"
className="w-full gap-2"
onClick={async () => {
await signIn.social({
provider: "github",
callbackURL: "/dashboard",
fetchOptions: {
onRequest: () => {
setLoading(true);
},
onResponse: () => {
setLoading(false);
},
},
});
}}
disabled={loading}
>
<GitHubLogoIcon />
Continue with Github
</Button>
</div>
</CardContent>
<CardFooter>
<div className="flex justify-center w-full border-t py-4">
<p className="text-center text-xs text-neutral-500">
Secured by <span className="text-orange-400">better-auth.</span>
</p>
</div>
</CardFooter>
</Card>
);
}
async function convertImageToBase64(file: File): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result as string);
reader.onerror = reject;
reader.readAsDataURL(file);
});
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result as string);
reader.onerror = reject;
reader.readAsDataURL(file);
});
}

View File

@@ -5,5 +5,5 @@ import { ThemeProvider as NextThemesProvider } from "next-themes";
import { type ThemeProviderProps } from "next-themes/dist/types";
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}

View File

@@ -7,17 +7,17 @@ import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button";
export function ThemeToggle() {
const { setTheme, theme } = useTheme();
const { setTheme, theme } = useTheme();
return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
<Sun className="h-[1.5rem] w-[1.3rem] dark:hidden" color="#000" />
<Moon className="hidden h-5 w-5 dark:block" />
<span className="sr-only">Toggle theme</span>
</Button>
);
return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
>
<Sun className="h-[1.5rem] w-[1.3rem] dark:hidden" color="#000" />
<Moon className="hidden h-5 w-5 dark:block" />
<span className="sr-only">Toggle theme</span>
</Button>
);
}

View File

@@ -1,57 +1,57 @@
"use client"
"use client";
import * as React from "react"
import * as AccordionPrimitive from "@radix-ui/react-accordion"
import { ChevronDownIcon } from "@radix-ui/react-icons"
import * as React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDownIcon } from "@radix-ui/react-icons";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Accordion = AccordionPrimitive.Root
const Accordion = AccordionPrimitive.Root;
const AccordionItem = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
React.ElementRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item
ref={ref}
className={cn("border-b", className)}
{...props}
/>
))
AccordionItem.displayName = "AccordionItem"
<AccordionPrimitive.Item
ref={ref}
className={cn("border-b", className)}
{...props}
/>
));
AccordionItem.displayName = "AccordionItem";
const AccordionTrigger = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
React.ElementRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
className
)}
{...props}
>
{children}
<ChevronDownIcon className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
))
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
className,
)}
{...props}
>
{children}
<ChevronDownIcon className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
const AccordionContent = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
React.ElementRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
{...props}
>
<div className={cn("pb-4 pt-0", className)}>{children}</div>
</AccordionPrimitive.Content>
))
AccordionContent.displayName = AccordionPrimitive.Content.displayName
<AccordionPrimitive.Content
ref={ref}
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
{...props}
>
<div className={cn("pb-4 pt-0", className)}>{children}</div>
</AccordionPrimitive.Content>
));
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };

View File

@@ -1,141 +1,141 @@
"use client"
"use client";
import * as React from "react"
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
import * as React from "react";
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
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<typeof AlertDialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
ref={ref}
/>
))
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
<AlertDialogPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
ref={ref}
/>
));
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
const AlertDialogContent = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
React.ElementRef<typeof AlertDialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
>(({ className, ...props }, ref) => (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
)}
{...props}
/>
</AlertDialogPortal>
))
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className,
)}
{...props}
/>
</AlertDialogPortal>
));
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
const AlertDialogHeader = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
)
AlertDialogHeader.displayName = "AlertDialogHeader"
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
AlertDialogHeader.displayName = "AlertDialogHeader";
const AlertDialogFooter = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
AlertDialogFooter.displayName = "AlertDialogFooter"
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
AlertDialogFooter.displayName = "AlertDialogFooter";
const AlertDialogTitle = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
React.ElementRef<typeof AlertDialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold", className)}
{...props}
/>
))
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
<AlertDialogPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold", className)}
{...props}
/>
));
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
const AlertDialogDescription = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
React.ElementRef<typeof AlertDialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
<AlertDialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
AlertDialogDescription.displayName =
AlertDialogPrimitive.Description.displayName
AlertDialogPrimitive.Description.displayName;
const AlertDialogAction = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Action>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
React.ElementRef<typeof AlertDialogPrimitive.Action>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Action
ref={ref}
className={cn(buttonVariants(), className)}
{...props}
/>
))
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
<AlertDialogPrimitive.Action
ref={ref}
className={cn(buttonVariants(), className)}
{...props}
/>
));
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
const AlertDialogCancel = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Cancel
ref={ref}
className={cn(
buttonVariants({ variant: "outline" }),
"mt-2 sm:mt-0",
className
)}
{...props}
/>
))
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
<AlertDialogPrimitive.Cancel
ref={ref}
className={cn(
buttonVariants({ variant: "outline" }),
"mt-2 sm:mt-0",
className,
)}
{...props}
/>
));
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
export {
AlertDialog,
AlertDialogPortal,
AlertDialogOverlay,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
}
AlertDialog,
AlertDialogPortal,
AlertDialogOverlay,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
};

View File

@@ -1,59 +1,59 @@
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const alertVariants = cva(
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
{
variants: {
variant: {
default: "bg-background text-foreground",
destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
},
},
defaultVariants: {
variant: "default",
},
}
)
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
{
variants: {
variant: {
default: "bg-background text-foreground",
destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
},
},
defaultVariants: {
variant: "default",
},
},
);
const Alert = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
>(({ className, variant, ...props }, ref) => (
<div
ref={ref}
role="alert"
className={cn(alertVariants({ variant }), className)}
{...props}
/>
))
Alert.displayName = "Alert"
<div
ref={ref}
role="alert"
className={cn(alertVariants({ variant }), className)}
{...props}
/>
));
Alert.displayName = "Alert";
const AlertTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h5
ref={ref}
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props}
/>
))
AlertTitle.displayName = "AlertTitle"
<h5
ref={ref}
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props}
/>
));
AlertTitle.displayName = "AlertTitle";
const AlertDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props}
/>
))
AlertDescription.displayName = "AlertDescription"
<div
ref={ref}
className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props}
/>
));
AlertDescription.displayName = "AlertDescription";
export { Alert, AlertTitle, AlertDescription }
export { Alert, AlertTitle, AlertDescription };

View File

@@ -1,7 +1,7 @@
"use client"
"use client";
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio";
const AspectRatio = AspectRatioPrimitive.Root
const AspectRatio = AspectRatioPrimitive.Root;
export { AspectRatio }
export { AspectRatio };

View File

@@ -1,50 +1,50 @@
"use client"
"use client";
import * as React from "react"
import * as AvatarPrimitive from "@radix-ui/react-avatar"
import * as React from "react";
import * as AvatarPrimitive from "@radix-ui/react-avatar";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
React.ElementRef<typeof AvatarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Root
ref={ref}
className={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
className
)}
{...props}
/>
))
Avatar.displayName = AvatarPrimitive.Root.displayName
<AvatarPrimitive.Root
ref={ref}
className={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
className,
)}
{...props}
/>
));
Avatar.displayName = AvatarPrimitive.Root.displayName;
const AvatarImage = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Image>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
React.ElementRef<typeof AvatarPrimitive.Image>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Image
ref={ref}
className={cn("aspect-square h-full w-full", className)}
{...props}
/>
))
AvatarImage.displayName = AvatarPrimitive.Image.displayName
<AvatarPrimitive.Image
ref={ref}
className={cn("aspect-square h-full w-full", className)}
{...props}
/>
));
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
const AvatarFallback = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Fallback>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
React.ElementRef<typeof AvatarPrimitive.Fallback>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-muted",
className
)}
{...props}
/>
))
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-muted",
className,
)}
{...props}
/>
));
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
export { Avatar, AvatarImage, AvatarFallback }
export { Avatar, AvatarImage, AvatarFallback };

View File

@@ -1,36 +1,36 @@
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const badgeVariants = cva(
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {
default:
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
secondary:
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
outline: "text-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
)
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {
default:
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
secondary:
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
outline: "text-foreground",
},
},
defaultVariants: {
variant: "default",
},
},
);
export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
function Badge({ className, variant, ...props }: BadgeProps) {
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
)
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
);
}
export { Badge, badgeVariants }
export { Badge, badgeVariants };

View File

@@ -1,115 +1,115 @@
import * as React from "react"
import { ChevronRightIcon, DotsHorizontalIcon } from "@radix-ui/react-icons"
import { Slot } from "@radix-ui/react-slot"
import * as React from "react";
import { ChevronRightIcon, DotsHorizontalIcon } from "@radix-ui/react-icons";
import { Slot } from "@radix-ui/react-slot";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Breadcrumb = React.forwardRef<
HTMLElement,
React.ComponentPropsWithoutRef<"nav"> & {
separator?: React.ReactNode
}
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />)
Breadcrumb.displayName = "Breadcrumb"
HTMLElement,
React.ComponentPropsWithoutRef<"nav"> & {
separator?: React.ReactNode;
}
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />);
Breadcrumb.displayName = "Breadcrumb";
const BreadcrumbList = React.forwardRef<
HTMLOListElement,
React.ComponentPropsWithoutRef<"ol">
HTMLOListElement,
React.ComponentPropsWithoutRef<"ol">
>(({ className, ...props }, ref) => (
<ol
ref={ref}
className={cn(
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
className
)}
{...props}
/>
))
BreadcrumbList.displayName = "BreadcrumbList"
<ol
ref={ref}
className={cn(
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
className,
)}
{...props}
/>
));
BreadcrumbList.displayName = "BreadcrumbList";
const BreadcrumbItem = React.forwardRef<
HTMLLIElement,
React.ComponentPropsWithoutRef<"li">
HTMLLIElement,
React.ComponentPropsWithoutRef<"li">
>(({ className, ...props }, ref) => (
<li
ref={ref}
className={cn("inline-flex items-center gap-1.5", className)}
{...props}
/>
))
BreadcrumbItem.displayName = "BreadcrumbItem"
<li
ref={ref}
className={cn("inline-flex items-center gap-1.5", className)}
{...props}
/>
));
BreadcrumbItem.displayName = "BreadcrumbItem";
const BreadcrumbLink = React.forwardRef<
HTMLAnchorElement,
React.ComponentPropsWithoutRef<"a"> & {
asChild?: boolean
}
HTMLAnchorElement,
React.ComponentPropsWithoutRef<"a"> & {
asChild?: boolean;
}
>(({ asChild, className, ...props }, ref) => {
const Comp = asChild ? Slot : "a"
const Comp = asChild ? Slot : "a";
return (
<Comp
ref={ref}
className={cn("transition-colors hover:text-foreground", className)}
{...props}
/>
)
})
BreadcrumbLink.displayName = "BreadcrumbLink"
return (
<Comp
ref={ref}
className={cn("transition-colors hover:text-foreground", className)}
{...props}
/>
);
});
BreadcrumbLink.displayName = "BreadcrumbLink";
const BreadcrumbPage = React.forwardRef<
HTMLSpanElement,
React.ComponentPropsWithoutRef<"span">
HTMLSpanElement,
React.ComponentPropsWithoutRef<"span">
>(({ className, ...props }, ref) => (
<span
ref={ref}
role="link"
aria-disabled="true"
aria-current="page"
className={cn("font-normal text-foreground", className)}
{...props}
/>
))
BreadcrumbPage.displayName = "BreadcrumbPage"
<span
ref={ref}
role="link"
aria-disabled="true"
aria-current="page"
className={cn("font-normal text-foreground", className)}
{...props}
/>
));
BreadcrumbPage.displayName = "BreadcrumbPage";
const BreadcrumbSeparator = ({
children,
className,
...props
children,
className,
...props
}: React.ComponentProps<"li">) => (
<li
role="presentation"
aria-hidden="true"
className={cn("[&>svg]:size-3.5", className)}
{...props}
>
{children ?? <ChevronRightIcon />}
</li>
)
BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
<li
role="presentation"
aria-hidden="true"
className={cn("[&>svg]:size-3.5", className)}
{...props}
>
{children ?? <ChevronRightIcon />}
</li>
);
BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
const BreadcrumbEllipsis = ({
className,
...props
className,
...props
}: React.ComponentProps<"span">) => (
<span
role="presentation"
aria-hidden="true"
className={cn("flex h-9 w-9 items-center justify-center", className)}
{...props}
>
<DotsHorizontalIcon className="h-4 w-4" />
<span className="sr-only">More</span>
</span>
)
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
<span
role="presentation"
aria-hidden="true"
className={cn("flex h-9 w-9 items-center justify-center", className)}
{...props}
>
<DotsHorizontalIcon className="h-4 w-4" />
<span className="sr-only">More</span>
</span>
);
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis";
export {
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
}
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
};

View File

@@ -1,57 +1,57 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
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";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
},
);
Button.displayName = "Button";
export { Button, buttonVariants }
export { Button, buttonVariants };

View File

@@ -1,72 +1,72 @@
"use client"
"use client";
import * as React from "react"
import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons"
import { DayPicker } from "react-day-picker"
import * as React from "react";
import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons";
import { DayPicker } from "react-day-picker";
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/ui/button";
export type CalendarProps = React.ComponentProps<typeof DayPicker>
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
function Calendar({
className,
classNames,
showOutsideDays = true,
...props
className,
classNames,
showOutsideDays = true,
...props
}: CalendarProps) {
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn("p-3", className)}
classNames={{
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
month: "space-y-4",
caption: "flex justify-center pt-1 relative items-center",
caption_label: "text-sm font-medium",
nav: "space-x-1 flex items-center",
nav_button: cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
),
nav_button_previous: "absolute left-1",
nav_button_next: "absolute right-1",
table: "w-full border-collapse space-y-1",
head_row: "flex",
head_cell:
"text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
row: "flex w-full mt-2",
cell: cn(
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md",
props.mode === "range"
? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
: "[&:has([aria-selected])]:rounded-md"
),
day: cn(
buttonVariants({ variant: "ghost" }),
"h-8 w-8 p-0 font-normal aria-selected:opacity-100"
),
day_range_start: "day-range-start",
day_range_end: "day-range-end",
day_selected:
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
day_today: "bg-accent text-accent-foreground",
day_outside:
"day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
day_disabled: "text-muted-foreground opacity-50",
day_range_middle:
"aria-selected:bg-accent aria-selected:text-accent-foreground",
day_hidden: "invisible",
...classNames,
}}
components={{
IconLeft: ({ ...props }) => <ChevronLeftIcon className="h-4 w-4" />,
IconRight: ({ ...props }) => <ChevronRightIcon className="h-4 w-4" />,
}}
{...props}
/>
)
return (
<DayPicker
showOutsideDays={showOutsideDays}
className={cn("p-3", className)}
classNames={{
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
month: "space-y-4",
caption: "flex justify-center pt-1 relative items-center",
caption_label: "text-sm font-medium",
nav: "space-x-1 flex items-center",
nav_button: cn(
buttonVariants({ variant: "outline" }),
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100",
),
nav_button_previous: "absolute left-1",
nav_button_next: "absolute right-1",
table: "w-full border-collapse space-y-1",
head_row: "flex",
head_cell:
"text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
row: "flex w-full mt-2",
cell: cn(
"relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md",
props.mode === "range"
? "[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
: "[&:has([aria-selected])]:rounded-md",
),
day: cn(
buttonVariants({ variant: "ghost" }),
"h-8 w-8 p-0 font-normal aria-selected:opacity-100",
),
day_range_start: "day-range-start",
day_range_end: "day-range-end",
day_selected:
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
day_today: "bg-accent text-accent-foreground",
day_outside:
"day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
day_disabled: "text-muted-foreground opacity-50",
day_range_middle:
"aria-selected:bg-accent aria-selected:text-accent-foreground",
day_hidden: "invisible",
...classNames,
}}
components={{
IconLeft: ({ ...props }) => <ChevronLeftIcon className="h-4 w-4" />,
IconRight: ({ ...props }) => <ChevronRightIcon className="h-4 w-4" />,
}}
{...props}
/>
);
}
Calendar.displayName = "Calendar"
Calendar.displayName = "Calendar";
export { Calendar }
export { Calendar };

View File

@@ -5,122 +5,122 @@ import React, { useMemo, useRef } from "react";
import * as THREE from "three";
export const CanvasRevealEffect = ({
animationSpeed = 0.4,
opacities = [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1],
colors = [[0, 255, 255]],
containerClassName,
dotSize,
showGradient = true,
animationSpeed = 0.4,
opacities = [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1],
colors = [[0, 255, 255]],
containerClassName,
dotSize,
showGradient = true,
}: {
/**
* 0.1 - slower
* 1.0 - faster
*/
animationSpeed?: number;
opacities?: number[];
colors?: number[][];
containerClassName?: string;
dotSize?: number;
showGradient?: boolean;
/**
* 0.1 - slower
* 1.0 - faster
*/
animationSpeed?: number;
opacities?: number[];
colors?: number[][];
containerClassName?: string;
dotSize?: number;
showGradient?: boolean;
}) => {
return (
<div className={cn("h-full relative bg-white w-full", containerClassName)}>
<div className="h-full w-full">
<DotMatrix
colors={colors ?? [[0, 255, 255]]}
dotSize={dotSize ?? 3}
opacities={
opacities ?? [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1]
}
shader={`
return (
<div className={cn("h-full relative bg-white w-full", containerClassName)}>
<div className="h-full w-full">
<DotMatrix
colors={colors ?? [[0, 255, 255]]}
dotSize={dotSize ?? 3}
opacities={
opacities ?? [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1]
}
shader={`
float animation_speed_factor = ${animationSpeed.toFixed(1)};
float intro_offset = distance(u_resolution / 2.0 / u_total_size, st2) * 0.01 + (random(st2) * 0.15);
opacity *= step(intro_offset, u_time * animation_speed_factor);
opacity *= clamp((1.0 - step(intro_offset + 0.1, u_time * animation_speed_factor)) * 1.25, 1.0, 1.25);
`}
center={["x", "y"]}
/>
</div>
{showGradient && (
<div className="absolute inset-0 bg-gradient-to-t from-gray-950 to-[84%]" />
)}
</div>
);
center={["x", "y"]}
/>
</div>
{showGradient && (
<div className="absolute inset-0 bg-gradient-to-t from-gray-950 to-[84%]" />
)}
</div>
);
};
interface DotMatrixProps {
colors?: number[][];
opacities?: number[];
totalSize?: number;
dotSize?: number;
shader?: string;
center?: ("x" | "y")[];
colors?: number[][];
opacities?: number[];
totalSize?: number;
dotSize?: number;
shader?: string;
center?: ("x" | "y")[];
}
const DotMatrix: React.FC<DotMatrixProps> = ({
colors = [[0, 0, 0]],
opacities = [0.04, 0.04, 0.04, 0.04, 0.04, 0.08, 0.08, 0.08, 0.08, 0.14],
totalSize = 4,
dotSize = 2,
shader = "",
center = ["x", "y"],
colors = [[0, 0, 0]],
opacities = [0.04, 0.04, 0.04, 0.04, 0.04, 0.08, 0.08, 0.08, 0.08, 0.14],
totalSize = 4,
dotSize = 2,
shader = "",
center = ["x", "y"],
}) => {
const uniforms = React.useMemo(() => {
let colorsArray = [
colors[0],
colors[0],
colors[0],
colors[0],
colors[0],
colors[0],
];
if (colors.length === 2) {
colorsArray = [
colors[0],
colors[0],
colors[0],
colors[1],
colors[1],
colors[1],
];
} else if (colors.length === 3) {
colorsArray = [
colors[0],
colors[0],
colors[1],
colors[1],
colors[2],
colors[2],
];
}
const uniforms = React.useMemo(() => {
let colorsArray = [
colors[0],
colors[0],
colors[0],
colors[0],
colors[0],
colors[0],
];
if (colors.length === 2) {
colorsArray = [
colors[0],
colors[0],
colors[0],
colors[1],
colors[1],
colors[1],
];
} else if (colors.length === 3) {
colorsArray = [
colors[0],
colors[0],
colors[1],
colors[1],
colors[2],
colors[2],
];
}
return {
u_colors: {
value: colorsArray.map((color) => [
color[0] / 255,
color[1] / 255,
color[2] / 255,
]),
type: "uniform3fv",
},
u_opacities: {
value: opacities,
type: "uniform1fv",
},
u_total_size: {
value: totalSize,
type: "uniform1f",
},
u_dot_size: {
value: dotSize,
type: "uniform1f",
},
};
}, [colors, opacities, totalSize, dotSize]);
return {
u_colors: {
value: colorsArray.map((color) => [
color[0] / 255,
color[1] / 255,
color[2] / 255,
]),
type: "uniform3fv",
},
u_opacities: {
value: opacities,
type: "uniform1fv",
},
u_total_size: {
value: totalSize,
type: "uniform1f",
},
u_dot_size: {
value: dotSize,
type: "uniform1f",
},
};
}, [colors, opacities, totalSize, dotSize]);
return (
<Shader
source={`
return (
<Shader
source={`
precision mediump float;
in vec2 fragCoord;
@@ -140,14 +140,16 @@ const DotMatrix: React.FC<DotMatrixProps> = ({
}
void main() {
vec2 st = fragCoord.xy;
${center.includes("x")
? "st.x -= abs(floor((mod(u_resolution.x, u_total_size) - u_dot_size) * 0.5));"
: ""
}
${center.includes("y")
? "st.y -= abs(floor((mod(u_resolution.y, u_total_size) - u_dot_size) * 0.5));"
: ""
}
${
center.includes("x")
? "st.x -= abs(floor((mod(u_resolution.x, u_total_size) - u_dot_size) * 0.5));"
: ""
}
${
center.includes("y")
? "st.y -= abs(floor((mod(u_resolution.y, u_total_size) - u_dot_size) * 0.5));"
: ""
}
float opacity = step(0.0, st.x);
opacity *= step(0.0, st.y);
@@ -167,95 +169,95 @@ const DotMatrix: React.FC<DotMatrixProps> = ({
fragColor = vec4(color, opacity);
fragColor.rgb *= fragColor.a;
}`}
uniforms={uniforms}
maxFps={60}
/>
);
uniforms={uniforms}
maxFps={60}
/>
);
};
type Uniforms = {
[key: string]: {
value: number[] | number[][] | number;
type: string;
};
[key: string]: {
value: number[] | number[][] | number;
type: string;
};
};
const ShaderMaterial = ({
source,
uniforms,
maxFps = 60,
source,
uniforms,
maxFps = 60,
}: {
source: string;
hovered?: boolean;
maxFps?: number;
uniforms: Uniforms;
source: string;
hovered?: boolean;
maxFps?: number;
uniforms: Uniforms;
}) => {
const { size } = useThree();
const ref = useRef<THREE.Mesh>();
let lastFrameTime = 0;
const { size } = useThree();
const ref = useRef<THREE.Mesh>();
let lastFrameTime = 0;
useFrame(({ clock }) => {
if (!ref.current) return;
const timestamp = clock.getElapsedTime();
if (timestamp - lastFrameTime < 1 / maxFps) {
return;
}
lastFrameTime = timestamp;
useFrame(({ clock }) => {
if (!ref.current) return;
const timestamp = clock.getElapsedTime();
if (timestamp - lastFrameTime < 1 / maxFps) {
return;
}
lastFrameTime = timestamp;
const material: any = ref.current.material;
const timeLocation = material.uniforms.u_time;
timeLocation.value = timestamp;
});
const material: any = ref.current.material;
const timeLocation = material.uniforms.u_time;
timeLocation.value = timestamp;
});
const getUniforms = () => {
const preparedUniforms: any = {};
const getUniforms = () => {
const preparedUniforms: any = {};
for (const uniformName in uniforms) {
const uniform: any = uniforms[uniformName];
for (const uniformName in uniforms) {
const uniform: any = uniforms[uniformName];
switch (uniform.type) {
case "uniform1f":
preparedUniforms[uniformName] = { value: uniform.value, type: "1f" };
break;
case "uniform3f":
preparedUniforms[uniformName] = {
value: new THREE.Vector3().fromArray(uniform.value),
type: "3f",
};
break;
case "uniform1fv":
preparedUniforms[uniformName] = { value: uniform.value, type: "1fv" };
break;
case "uniform3fv":
preparedUniforms[uniformName] = {
value: uniform.value.map((v: number[]) =>
new THREE.Vector3().fromArray(v)
),
type: "3fv",
};
break;
case "uniform2f":
preparedUniforms[uniformName] = {
value: new THREE.Vector2().fromArray(uniform.value),
type: "2f",
};
break;
default:
console.error(`Invalid uniform type for '${uniformName}'.`);
break;
}
}
switch (uniform.type) {
case "uniform1f":
preparedUniforms[uniformName] = { value: uniform.value, type: "1f" };
break;
case "uniform3f":
preparedUniforms[uniformName] = {
value: new THREE.Vector3().fromArray(uniform.value),
type: "3f",
};
break;
case "uniform1fv":
preparedUniforms[uniformName] = { value: uniform.value, type: "1fv" };
break;
case "uniform3fv":
preparedUniforms[uniformName] = {
value: uniform.value.map((v: number[]) =>
new THREE.Vector3().fromArray(v),
),
type: "3fv",
};
break;
case "uniform2f":
preparedUniforms[uniformName] = {
value: new THREE.Vector2().fromArray(uniform.value),
type: "2f",
};
break;
default:
console.error(`Invalid uniform type for '${uniformName}'.`);
break;
}
}
preparedUniforms["u_time"] = { value: 0, type: "1f" };
preparedUniforms["u_resolution"] = {
value: new THREE.Vector2(size.width * 2, size.height * 2),
}; // Initialize u_resolution
return preparedUniforms;
};
preparedUniforms["u_time"] = { value: 0, type: "1f" };
preparedUniforms["u_resolution"] = {
value: new THREE.Vector2(size.width * 2, size.height * 2),
}; // Initialize u_resolution
return preparedUniforms;
};
// Shader material
const material = useMemo(() => {
const materialObject = new THREE.ShaderMaterial({
vertexShader: `
// Shader material
const material = useMemo(() => {
const materialObject = new THREE.ShaderMaterial({
vertexShader: `
precision mediump float;
in vec2 coordinates;
uniform vec2 u_resolution;
@@ -268,39 +270,39 @@ const ShaderMaterial = ({
fragCoord.y = u_resolution.y - fragCoord.y;
}
`,
fragmentShader: source,
uniforms: getUniforms(),
glslVersion: THREE.GLSL3,
blending: THREE.CustomBlending,
blendSrc: THREE.SrcAlphaFactor,
blendDst: THREE.OneFactor,
});
fragmentShader: source,
uniforms: getUniforms(),
glslVersion: THREE.GLSL3,
blending: THREE.CustomBlending,
blendSrc: THREE.SrcAlphaFactor,
blendDst: THREE.OneFactor,
});
return materialObject;
}, [size.width, size.height, source]);
return materialObject;
}, [size.width, size.height, source]);
return (
<mesh ref={ref as any}>
<planeGeometry args={[2, 2]} />
<primitive object={material} attach="material" />
</mesh>
);
return (
<mesh ref={ref as any}>
<planeGeometry args={[2, 2]} />
<primitive object={material} attach="material" />
</mesh>
);
};
const Shader: React.FC<ShaderProps> = ({ source, uniforms, maxFps = 60 }) => {
return (
<Canvas className="absolute inset-0 h-full w-full">
<ShaderMaterial source={source} uniforms={uniforms} maxFps={maxFps} />
</Canvas>
);
return (
<Canvas className="absolute inset-0 h-full w-full">
<ShaderMaterial source={source} uniforms={uniforms} maxFps={maxFps} />
</Canvas>
);
};
interface ShaderProps {
source: string;
uniforms: {
[key: string]: {
value: number[] | number[][] | number;
type: string;
};
};
maxFps?: number;
source: string;
uniforms: {
[key: string]: {
value: number[] | number[][] | number;
type: string;
};
};
maxFps?: number;
}

View File

@@ -1,76 +1,83 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-xl border bg-card text-card-foreground shadow",
className
)}
{...props}
/>
))
Card.displayName = "Card"
<div
ref={ref}
className={cn(
"rounded-xl border bg-card text-card-foreground shadow",
className,
)}
{...props}
/>
));
Card.displayName = "Card";
const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
))
CardHeader.displayName = "CardHeader"
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
));
CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn("font-semibold leading-none tracking-tight", className)}
{...props}
/>
))
CardTitle.displayName = "CardTitle"
<h3
ref={ref}
className={cn("font-semibold leading-none tracking-tight", className)}
{...props}
/>
));
CardTitle.displayName = "CardTitle";
const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
CardDescription.displayName = "CardDescription"
<p
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
CardDescription.displayName = "CardDescription";
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
));
CardContent.displayName = "CardContent";
const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
))
CardFooter.displayName = "CardFooter"
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
));
CardFooter.displayName = "CardFooter";
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
};

View File

@@ -1,262 +1,262 @@
"use client"
"use client";
import * as React from "react"
import { ArrowLeftIcon, ArrowRightIcon } from "@radix-ui/react-icons"
import * as React from "react";
import { ArrowLeftIcon, ArrowRightIcon } from "@radix-ui/react-icons";
import useEmblaCarousel, {
type UseEmblaCarouselType,
} from "embla-carousel-react"
type UseEmblaCarouselType,
} from "embla-carousel-react";
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
type CarouselApi = UseEmblaCarouselType[1]
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
type CarouselOptions = UseCarouselParameters[0]
type CarouselPlugin = UseCarouselParameters[1]
type CarouselApi = UseEmblaCarouselType[1];
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>;
type CarouselOptions = UseCarouselParameters[0];
type CarouselPlugin = UseCarouselParameters[1];
type CarouselProps = {
opts?: CarouselOptions
plugins?: CarouselPlugin
orientation?: "horizontal" | "vertical"
setApi?: (api: CarouselApi) => void
}
opts?: CarouselOptions;
plugins?: CarouselPlugin;
orientation?: "horizontal" | "vertical";
setApi?: (api: CarouselApi) => void;
};
type CarouselContextProps = {
carouselRef: ReturnType<typeof useEmblaCarousel>[0]
api: ReturnType<typeof useEmblaCarousel>[1]
scrollPrev: () => void
scrollNext: () => void
canScrollPrev: boolean
canScrollNext: boolean
} & CarouselProps
carouselRef: ReturnType<typeof useEmblaCarousel>[0];
api: ReturnType<typeof useEmblaCarousel>[1];
scrollPrev: () => void;
scrollNext: () => void;
canScrollPrev: boolean;
canScrollNext: boolean;
} & CarouselProps;
const CarouselContext = React.createContext<CarouselContextProps | null>(null)
const CarouselContext = React.createContext<CarouselContextProps | null>(null);
function useCarousel() {
const context = React.useContext(CarouselContext)
const context = React.useContext(CarouselContext);
if (!context) {
throw new Error("useCarousel must be used within a <Carousel />")
}
if (!context) {
throw new Error("useCarousel must be used within a <Carousel />");
}
return context
return context;
}
const Carousel = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & CarouselProps
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & CarouselProps
>(
(
{
orientation = "horizontal",
opts,
setApi,
plugins,
className,
children,
...props
},
ref
) => {
const [carouselRef, api] = useEmblaCarousel(
{
...opts,
axis: orientation === "horizontal" ? "x" : "y",
},
plugins
)
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
const [canScrollNext, setCanScrollNext] = React.useState(false)
(
{
orientation = "horizontal",
opts,
setApi,
plugins,
className,
children,
...props
},
ref,
) => {
const [carouselRef, api] = useEmblaCarousel(
{
...opts,
axis: orientation === "horizontal" ? "x" : "y",
},
plugins,
);
const [canScrollPrev, setCanScrollPrev] = React.useState(false);
const [canScrollNext, setCanScrollNext] = React.useState(false);
const onSelect = React.useCallback((api: CarouselApi) => {
if (!api) {
return
}
const onSelect = React.useCallback((api: CarouselApi) => {
if (!api) {
return;
}
setCanScrollPrev(api.canScrollPrev())
setCanScrollNext(api.canScrollNext())
}, [])
setCanScrollPrev(api.canScrollPrev());
setCanScrollNext(api.canScrollNext());
}, []);
const scrollPrev = React.useCallback(() => {
api?.scrollPrev()
}, [api])
const scrollPrev = React.useCallback(() => {
api?.scrollPrev();
}, [api]);
const scrollNext = React.useCallback(() => {
api?.scrollNext()
}, [api])
const scrollNext = React.useCallback(() => {
api?.scrollNext();
}, [api]);
const handleKeyDown = React.useCallback(
(event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === "ArrowLeft") {
event.preventDefault()
scrollPrev()
} else if (event.key === "ArrowRight") {
event.preventDefault()
scrollNext()
}
},
[scrollPrev, scrollNext]
)
const handleKeyDown = React.useCallback(
(event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.key === "ArrowLeft") {
event.preventDefault();
scrollPrev();
} else if (event.key === "ArrowRight") {
event.preventDefault();
scrollNext();
}
},
[scrollPrev, scrollNext],
);
React.useEffect(() => {
if (!api || !setApi) {
return
}
React.useEffect(() => {
if (!api || !setApi) {
return;
}
setApi(api)
}, [api, setApi])
setApi(api);
}, [api, setApi]);
React.useEffect(() => {
if (!api) {
return
}
React.useEffect(() => {
if (!api) {
return;
}
onSelect(api)
api.on("reInit", onSelect)
api.on("select", onSelect)
onSelect(api);
api.on("reInit", onSelect);
api.on("select", onSelect);
return () => {
api?.off("select", onSelect)
}
}, [api, onSelect])
return () => {
api?.off("select", onSelect);
};
}, [api, onSelect]);
return (
<CarouselContext.Provider
value={{
carouselRef,
api: api,
opts,
orientation:
orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
scrollPrev,
scrollNext,
canScrollPrev,
canScrollNext,
}}
>
<div
ref={ref}
onKeyDownCapture={handleKeyDown}
className={cn("relative", className)}
role="region"
aria-roledescription="carousel"
{...props}
>
{children}
</div>
</CarouselContext.Provider>
)
}
)
Carousel.displayName = "Carousel"
return (
<CarouselContext.Provider
value={{
carouselRef,
api: api,
opts,
orientation:
orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
scrollPrev,
scrollNext,
canScrollPrev,
canScrollNext,
}}
>
<div
ref={ref}
onKeyDownCapture={handleKeyDown}
className={cn("relative", className)}
role="region"
aria-roledescription="carousel"
{...props}
>
{children}
</div>
</CarouselContext.Provider>
);
},
);
Carousel.displayName = "Carousel";
const CarouselContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const { carouselRef, orientation } = useCarousel()
const { carouselRef, orientation } = useCarousel();
return (
<div ref={carouselRef} className="overflow-hidden">
<div
ref={ref}
className={cn(
"flex",
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
className
)}
{...props}
/>
</div>
)
})
CarouselContent.displayName = "CarouselContent"
return (
<div ref={carouselRef} className="overflow-hidden">
<div
ref={ref}
className={cn(
"flex",
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
className,
)}
{...props}
/>
</div>
);
});
CarouselContent.displayName = "CarouselContent";
const CarouselItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const { orientation } = useCarousel()
const { orientation } = useCarousel();
return (
<div
ref={ref}
role="group"
aria-roledescription="slide"
className={cn(
"min-w-0 shrink-0 grow-0 basis-full",
orientation === "horizontal" ? "pl-4" : "pt-4",
className
)}
{...props}
/>
)
})
CarouselItem.displayName = "CarouselItem"
return (
<div
ref={ref}
role="group"
aria-roledescription="slide"
className={cn(
"min-w-0 shrink-0 grow-0 basis-full",
orientation === "horizontal" ? "pl-4" : "pt-4",
className,
)}
{...props}
/>
);
});
CarouselItem.displayName = "CarouselItem";
const CarouselPrevious = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<typeof Button>
HTMLButtonElement,
React.ComponentProps<typeof Button>
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
const { orientation, scrollPrev, canScrollPrev } = useCarousel();
return (
<Button
ref={ref}
variant={variant}
size={size}
className={cn(
"absolute h-8 w-8 rounded-full",
orientation === "horizontal"
? "-left-12 top-1/2 -translate-y-1/2"
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
className
)}
disabled={!canScrollPrev}
onClick={scrollPrev}
{...props}
>
<ArrowLeftIcon className="h-4 w-4" />
<span className="sr-only">Previous slide</span>
</Button>
)
})
CarouselPrevious.displayName = "CarouselPrevious"
return (
<Button
ref={ref}
variant={variant}
size={size}
className={cn(
"absolute h-8 w-8 rounded-full",
orientation === "horizontal"
? "-left-12 top-1/2 -translate-y-1/2"
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
className,
)}
disabled={!canScrollPrev}
onClick={scrollPrev}
{...props}
>
<ArrowLeftIcon className="h-4 w-4" />
<span className="sr-only">Previous slide</span>
</Button>
);
});
CarouselPrevious.displayName = "CarouselPrevious";
const CarouselNext = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<typeof Button>
HTMLButtonElement,
React.ComponentProps<typeof Button>
>(({ className, variant = "outline", size = "icon", ...props }, ref) => {
const { orientation, scrollNext, canScrollNext } = useCarousel()
const { orientation, scrollNext, canScrollNext } = useCarousel();
return (
<Button
ref={ref}
variant={variant}
size={size}
className={cn(
"absolute h-8 w-8 rounded-full",
orientation === "horizontal"
? "-right-12 top-1/2 -translate-y-1/2"
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
className
)}
disabled={!canScrollNext}
onClick={scrollNext}
{...props}
>
<ArrowRightIcon className="h-4 w-4" />
<span className="sr-only">Next slide</span>
</Button>
)
})
CarouselNext.displayName = "CarouselNext"
return (
<Button
ref={ref}
variant={variant}
size={size}
className={cn(
"absolute h-8 w-8 rounded-full",
orientation === "horizontal"
? "-right-12 top-1/2 -translate-y-1/2"
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
className,
)}
disabled={!canScrollNext}
onClick={scrollNext}
{...props}
>
<ArrowRightIcon className="h-4 w-4" />
<span className="sr-only">Next slide</span>
</Button>
);
});
CarouselNext.displayName = "CarouselNext";
export {
type CarouselApi,
Carousel,
CarouselContent,
CarouselItem,
CarouselPrevious,
CarouselNext,
}
type CarouselApi,
Carousel,
CarouselContent,
CarouselItem,
CarouselPrevious,
CarouselNext,
};

View File

@@ -1,370 +1,370 @@
"use client"
"use client";
import * as React from "react"
import * as RechartsPrimitive from "recharts"
import * as React from "react";
import * as RechartsPrimitive from "recharts";
import {
NameType,
Payload,
ValueType,
} from "recharts/types/component/DefaultTooltipContent"
NameType,
Payload,
ValueType,
} from "recharts/types/component/DefaultTooltipContent";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
// Format: { THEME_NAME: CSS_SELECTOR }
const THEMES = { light: "", dark: ".dark" } as const
const THEMES = { light: "", dark: ".dark" } as const;
export type ChartConfig = {
[k in string]: {
label?: React.ReactNode
icon?: React.ComponentType
} & (
| { color?: string; theme?: never }
| { color?: never; theme: Record<keyof typeof THEMES, string> }
)
}
[k in string]: {
label?: React.ReactNode;
icon?: React.ComponentType;
} & (
| { color?: string; theme?: never }
| { color?: never; theme: Record<keyof typeof THEMES, string> }
);
};
type ChartContextProps = {
config: ChartConfig
}
config: ChartConfig;
};
const ChartContext = React.createContext<ChartContextProps | null>(null)
const ChartContext = React.createContext<ChartContextProps | null>(null);
function useChart() {
const context = React.useContext(ChartContext)
const context = React.useContext(ChartContext);
if (!context) {
throw new Error("useChart must be used within a <ChartContainer />")
}
if (!context) {
throw new Error("useChart must be used within a <ChartContainer />");
}
return context
return context;
}
const ChartContainer = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
config: ChartConfig
children: React.ComponentProps<
typeof RechartsPrimitive.ResponsiveContainer
>["children"]
}
HTMLDivElement,
React.ComponentProps<"div"> & {
config: ChartConfig;
children: React.ComponentProps<
typeof RechartsPrimitive.ResponsiveContainer
>["children"];
}
>(({ id, className, children, config, ...props }, ref) => {
const uniqueId = React.useId()
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
const uniqueId = React.useId();
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
return (
<ChartContext.Provider value={{ config }}>
<div
data-chart={chartId}
ref={ref}
className={cn(
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
className
)}
{...props}
>
<ChartStyle id={chartId} config={config} />
<RechartsPrimitive.ResponsiveContainer>
{children}
</RechartsPrimitive.ResponsiveContainer>
</div>
</ChartContext.Provider>
)
})
ChartContainer.displayName = "Chart"
return (
<ChartContext.Provider value={{ config }}>
<div
data-chart={chartId}
ref={ref}
className={cn(
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
className,
)}
{...props}
>
<ChartStyle id={chartId} config={config} />
<RechartsPrimitive.ResponsiveContainer>
{children}
</RechartsPrimitive.ResponsiveContainer>
</div>
</ChartContext.Provider>
);
});
ChartContainer.displayName = "Chart";
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
const colorConfig = Object.entries(config).filter(
([_, config]) => config.theme || config.color
)
const colorConfig = Object.entries(config).filter(
([_, config]) => config.theme || config.color,
);
if (!colorConfig.length) {
return null
}
if (!colorConfig.length) {
return null;
}
return (
<style
dangerouslySetInnerHTML={{
__html: Object.entries(THEMES)
.map(
([theme, prefix]) => `
return (
<style
dangerouslySetInnerHTML={{
__html: Object.entries(THEMES)
.map(
([theme, prefix]) => `
${prefix} [data-chart=${id}] {
${colorConfig
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.color
return color ? ` --color-${key}: ${color};` : null
})
.join("\n")}
}
`
)
.join("\n"),
}}
/>
)
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.color;
return color ? ` --color-${key}: ${color};` : null;
})
.join("\n")}
}
`,
)
.join("\n"),
}}
/>
);
};
const ChartTooltip = RechartsPrimitive.Tooltip
const ChartTooltip = RechartsPrimitive.Tooltip;
const ChartTooltipContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
React.ComponentProps<"div"> & {
hideLabel?: boolean
hideIndicator?: boolean
indicator?: "line" | "dot" | "dashed"
nameKey?: string
labelKey?: string
}
HTMLDivElement,
React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
React.ComponentProps<"div"> & {
hideLabel?: boolean;
hideIndicator?: boolean;
indicator?: "line" | "dot" | "dashed";
nameKey?: string;
labelKey?: string;
}
>(
(
{
active,
payload,
className,
indicator = "dot",
hideLabel = false,
hideIndicator = false,
label,
labelFormatter,
labelClassName,
formatter,
color,
nameKey,
labelKey,
},
ref
) => {
const { config } = useChart()
(
{
active,
payload,
className,
indicator = "dot",
hideLabel = false,
hideIndicator = false,
label,
labelFormatter,
labelClassName,
formatter,
color,
nameKey,
labelKey,
},
ref,
) => {
const { config } = useChart();
const tooltipLabel = React.useMemo(() => {
if (hideLabel || !payload?.length) {
return null
}
const tooltipLabel = React.useMemo(() => {
if (hideLabel || !payload?.length) {
return null;
}
const [item] = payload
const key = `${labelKey || item.dataKey || item.name || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const value =
!labelKey && typeof label === "string"
? config[label as keyof typeof config]?.label || label
: itemConfig?.label
const [item] = payload;
const key = `${labelKey || item.dataKey || item.name || "value"}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const value =
!labelKey && typeof label === "string"
? config[label as keyof typeof config]?.label || label
: itemConfig?.label;
if (labelFormatter) {
return (
<div className={cn("font-medium", labelClassName)}>
{labelFormatter(value, payload)}
</div>
)
}
if (labelFormatter) {
return (
<div className={cn("font-medium", labelClassName)}>
{labelFormatter(value, payload)}
</div>
);
}
if (!value) {
return null
}
if (!value) {
return null;
}
return <div className={cn("font-medium", labelClassName)}>{value}</div>
}, [
label,
labelFormatter,
payload,
hideLabel,
labelClassName,
config,
labelKey,
])
return <div className={cn("font-medium", labelClassName)}>{value}</div>;
}, [
label,
labelFormatter,
payload,
hideLabel,
labelClassName,
config,
labelKey,
]);
if (!active || !payload?.length) {
return null
}
if (!active || !payload?.length) {
return null;
}
const nestLabel = payload.length === 1 && indicator !== "dot"
const nestLabel = payload.length === 1 && indicator !== "dot";
return (
<div
ref={ref}
className={cn(
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
className
)}
>
{!nestLabel ? tooltipLabel : null}
<div className="grid gap-1.5">
{payload.map((item, index) => {
const key = `${nameKey || item.name || item.dataKey || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const indicatorColor = color || item.payload.fill || item.color
return (
<div
ref={ref}
className={cn(
"grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
className,
)}
>
{!nestLabel ? tooltipLabel : null}
<div className="grid gap-1.5">
{payload.map((item, index) => {
const key = `${nameKey || item.name || item.dataKey || "value"}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const indicatorColor = color || item.payload.fill || item.color;
return (
<div
key={item.dataKey}
className={cn(
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
indicator === "dot" && "items-center"
)}
>
{formatter && item?.value !== undefined && item.name ? (
formatter(item.value, item.name, item, index, item.payload)
) : (
<>
{itemConfig?.icon ? (
<itemConfig.icon />
) : (
!hideIndicator && (
<div
className={cn(
"shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
{
"h-2.5 w-2.5": indicator === "dot",
"w-1": indicator === "line",
"w-0 border-[1.5px] border-dashed bg-transparent":
indicator === "dashed",
"my-0.5": nestLabel && indicator === "dashed",
}
)}
style={
{
"--color-bg": indicatorColor,
"--color-border": indicatorColor,
} as React.CSSProperties
}
/>
)
)}
<div
className={cn(
"flex flex-1 justify-between leading-none",
nestLabel ? "items-end" : "items-center"
)}
>
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">
{itemConfig?.label || item.name}
</span>
</div>
{item.value && (
<span className="font-mono font-medium tabular-nums text-foreground">
{item.value.toLocaleString()}
</span>
)}
</div>
</>
)}
</div>
)
})}
</div>
</div>
)
}
)
ChartTooltipContent.displayName = "ChartTooltip"
return (
<div
key={item.dataKey}
className={cn(
"flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
indicator === "dot" && "items-center",
)}
>
{formatter && item?.value !== undefined && item.name ? (
formatter(item.value, item.name, item, index, item.payload)
) : (
<>
{itemConfig?.icon ? (
<itemConfig.icon />
) : (
!hideIndicator && (
<div
className={cn(
"shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]",
{
"h-2.5 w-2.5": indicator === "dot",
"w-1": indicator === "line",
"w-0 border-[1.5px] border-dashed bg-transparent":
indicator === "dashed",
"my-0.5": nestLabel && indicator === "dashed",
},
)}
style={
{
"--color-bg": indicatorColor,
"--color-border": indicatorColor,
} as React.CSSProperties
}
/>
)
)}
<div
className={cn(
"flex flex-1 justify-between leading-none",
nestLabel ? "items-end" : "items-center",
)}
>
<div className="grid gap-1.5">
{nestLabel ? tooltipLabel : null}
<span className="text-muted-foreground">
{itemConfig?.label || item.name}
</span>
</div>
{item.value && (
<span className="font-mono font-medium tabular-nums text-foreground">
{item.value.toLocaleString()}
</span>
)}
</div>
</>
)}
</div>
);
})}
</div>
</div>
);
},
);
ChartTooltipContent.displayName = "ChartTooltip";
const ChartLegend = RechartsPrimitive.Legend
const ChartLegend = RechartsPrimitive.Legend;
const ChartLegendContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> &
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
hideIcon?: boolean
nameKey?: string
}
HTMLDivElement,
React.ComponentProps<"div"> &
Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
hideIcon?: boolean;
nameKey?: string;
}
>(
(
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
ref
) => {
const { config } = useChart()
(
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
ref,
) => {
const { config } = useChart();
if (!payload?.length) {
return null
}
if (!payload?.length) {
return null;
}
return (
<div
ref={ref}
className={cn(
"flex items-center justify-center gap-4",
verticalAlign === "top" ? "pb-3" : "pt-3",
className
)}
>
{payload.map((item) => {
const key = `${nameKey || item.dataKey || "value"}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
return (
<div
ref={ref}
className={cn(
"flex items-center justify-center gap-4",
verticalAlign === "top" ? "pb-3" : "pt-3",
className,
)}
>
{payload.map((item) => {
const key = `${nameKey || item.dataKey || "value"}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
return (
<div
key={item.value}
className={cn(
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
)}
>
{itemConfig?.icon && !hideIcon ? (
<itemConfig.icon />
) : (
<div
className="h-2 w-2 shrink-0 rounded-[2px]"
style={{
backgroundColor: item.color,
}}
/>
)}
{itemConfig?.label}
</div>
)
})}
</div>
)
}
)
ChartLegendContent.displayName = "ChartLegend"
return (
<div
key={item.value}
className={cn(
"flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground",
)}
>
{itemConfig?.icon && !hideIcon ? (
<itemConfig.icon />
) : (
<div
className="h-2 w-2 shrink-0 rounded-[2px]"
style={{
backgroundColor: item.color,
}}
/>
)}
{itemConfig?.label}
</div>
);
})}
</div>
);
},
);
ChartLegendContent.displayName = "ChartLegend";
// Helper to extract item config from a payload.
function getPayloadConfigFromPayload(
config: ChartConfig,
payload: unknown,
key: string
config: ChartConfig,
payload: unknown,
key: string,
) {
if (typeof payload !== "object" || payload === null) {
return undefined
}
if (typeof payload !== "object" || payload === null) {
return undefined;
}
const payloadPayload =
"payload" in payload &&
typeof payload.payload === "object" &&
payload.payload !== null
? payload.payload
: undefined
const payloadPayload =
"payload" in payload &&
typeof payload.payload === "object" &&
payload.payload !== null
? payload.payload
: undefined;
let configLabelKey: string = key
let configLabelKey: string = key;
if (
key in payload &&
typeof payload[key as keyof typeof payload] === "string"
) {
configLabelKey = payload[key as keyof typeof payload] as string
} else if (
payloadPayload &&
key in payloadPayload &&
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
) {
configLabelKey = payloadPayload[
key as keyof typeof payloadPayload
] as string
}
if (
key in payload &&
typeof payload[key as keyof typeof payload] === "string"
) {
configLabelKey = payload[key as keyof typeof payload] as string;
} else if (
payloadPayload &&
key in payloadPayload &&
typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
) {
configLabelKey = payloadPayload[
key as keyof typeof payloadPayload
] as string;
}
return configLabelKey in config
? config[configLabelKey]
: config[key as keyof typeof config]
return configLabelKey in config
? config[configLabelKey]
: config[key as keyof typeof config];
}
export {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
ChartLegend,
ChartLegendContent,
ChartStyle,
}
ChartContainer,
ChartTooltip,
ChartTooltipContent,
ChartLegend,
ChartLegendContent,
ChartStyle,
};

View File

@@ -1,30 +1,30 @@
"use client"
"use client";
import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { CheckIcon } from "@radix-ui/react-icons"
import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { CheckIcon } from "@radix-ui/react-icons";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
React.ElementRef<typeof CheckboxPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, ...props }, ref) => (
<CheckboxPrimitive.Root
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
className
)}
{...props}
>
<CheckboxPrimitive.Indicator
className={cn("flex items-center justify-center text-current")}
>
<CheckIcon className="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
))
Checkbox.displayName = CheckboxPrimitive.Root.displayName
<CheckboxPrimitive.Root
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
className,
)}
{...props}
>
<CheckboxPrimitive.Indicator
className={cn("flex items-center justify-center text-current")}
>
<CheckIcon className="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
));
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
export { Checkbox }
export { Checkbox };

View File

@@ -1,11 +1,11 @@
"use client"
"use client";
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
const Collapsible = CollapsiblePrimitive.Root
const Collapsible = CollapsiblePrimitive.Root;
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;
export { Collapsible, CollapsibleTrigger, CollapsibleContent }
export { Collapsible, CollapsibleTrigger, CollapsibleContent };

View File

@@ -1,155 +1,155 @@
"use client"
"use client";
import * as React from "react"
import { type DialogProps } from "@radix-ui/react-dialog"
import { MagnifyingGlassIcon } from "@radix-ui/react-icons"
import { Command as CommandPrimitive } from "cmdk"
import * as React from "react";
import { type DialogProps } from "@radix-ui/react-dialog";
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
import { Command as CommandPrimitive } from "cmdk";
import { cn } from "@/lib/utils"
import { Dialog, DialogContent } from "@/components/ui/dialog"
import { cn } from "@/lib/utils";
import { Dialog, DialogContent } from "@/components/ui/dialog";
const Command = React.forwardRef<
React.ElementRef<typeof CommandPrimitive>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
React.ElementRef<typeof CommandPrimitive>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
>(({ className, ...props }, ref) => (
<CommandPrimitive
ref={ref}
className={cn(
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
className
)}
{...props}
/>
))
Command.displayName = CommandPrimitive.displayName
<CommandPrimitive
ref={ref}
className={cn(
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
className,
)}
{...props}
/>
));
Command.displayName = CommandPrimitive.displayName;
interface CommandDialogProps extends DialogProps {}
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
return (
<Dialog {...props}>
<DialogContent className="overflow-hidden p-0">
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
{children}
</Command>
</DialogContent>
</Dialog>
)
}
return (
<Dialog {...props}>
<DialogContent className="overflow-hidden p-0">
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
{children}
</Command>
</DialogContent>
</Dialog>
);
};
const CommandInput = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Input>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
React.ElementRef<typeof CommandPrimitive.Input>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => (
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
<MagnifyingGlassIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
ref={ref}
className={cn(
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
/>
</div>
))
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
<MagnifyingGlassIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
ref={ref}
className={cn(
"flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
/>
</div>
));
CommandInput.displayName = CommandPrimitive.Input.displayName
CommandInput.displayName = CommandPrimitive.Input.displayName;
const CommandList = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.List>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
React.ElementRef<typeof CommandPrimitive.List>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
>(({ className, ...props }, ref) => (
<CommandPrimitive.List
ref={ref}
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
{...props}
/>
))
<CommandPrimitive.List
ref={ref}
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
{...props}
/>
));
CommandList.displayName = CommandPrimitive.List.displayName
CommandList.displayName = CommandPrimitive.List.displayName;
const CommandEmpty = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Empty>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
React.ElementRef<typeof CommandPrimitive.Empty>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
>((props, ref) => (
<CommandPrimitive.Empty
ref={ref}
className="py-6 text-center text-sm"
{...props}
/>
))
<CommandPrimitive.Empty
ref={ref}
className="py-6 text-center text-sm"
{...props}
/>
));
CommandEmpty.displayName = CommandPrimitive.Empty.displayName
CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
const CommandGroup = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Group>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
React.ElementRef<typeof CommandPrimitive.Group>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Group
ref={ref}
className={cn(
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
className
)}
{...props}
/>
))
<CommandPrimitive.Group
ref={ref}
className={cn(
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
className,
)}
{...props}
/>
));
CommandGroup.displayName = CommandPrimitive.Group.displayName
CommandGroup.displayName = CommandPrimitive.Group.displayName;
const CommandSeparator = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
React.ElementRef<typeof CommandPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Separator
ref={ref}
className={cn("-mx-1 h-px bg-border", className)}
{...props}
/>
))
CommandSeparator.displayName = CommandPrimitive.Separator.displayName
<CommandPrimitive.Separator
ref={ref}
className={cn("-mx-1 h-px bg-border", className)}
{...props}
/>
));
CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
const CommandItem = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
React.ElementRef<typeof CommandPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50",
className
)}
{...props}
/>
))
<CommandPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50",
className,
)}
{...props}
/>
));
CommandItem.displayName = CommandPrimitive.Item.displayName
CommandItem.displayName = CommandPrimitive.Item.displayName;
const CommandShortcut = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className
)}
{...props}
/>
)
}
CommandShortcut.displayName = "CommandShortcut"
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className,
)}
{...props}
/>
);
};
CommandShortcut.displayName = "CommandShortcut";
export {
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator,
}
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator,
};

View File

@@ -1,204 +1,204 @@
"use client"
"use client";
import * as React from "react"
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
import * as React from "react";
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
import {
CheckIcon,
ChevronRightIcon,
DotFilledIcon,
} from "@radix-ui/react-icons"
CheckIcon,
ChevronRightIcon,
DotFilledIcon,
} from "@radix-ui/react-icons";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const ContextMenu = ContextMenuPrimitive.Root
const ContextMenu = ContextMenuPrimitive.Root;
const ContextMenuTrigger = ContextMenuPrimitive.Trigger
const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
const ContextMenuGroup = ContextMenuPrimitive.Group
const ContextMenuGroup = ContextMenuPrimitive.Group;
const ContextMenuPortal = ContextMenuPrimitive.Portal
const ContextMenuPortal = ContextMenuPrimitive.Portal;
const ContextMenuSub = ContextMenuPrimitive.Sub
const ContextMenuSub = ContextMenuPrimitive.Sub;
const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup
const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
const ContextMenuSubTrigger = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
inset?: boolean
}
React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
<ContextMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
inset && "pl-8",
className
)}
{...props}
>
{children}
<ChevronRightIcon className="ml-auto h-4 w-4" />
</ContextMenuPrimitive.SubTrigger>
))
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName
<ContextMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
inset && "pl-8",
className,
)}
{...props}
>
{children}
<ChevronRightIcon className="ml-auto h-4 w-4" />
</ContextMenuPrimitive.SubTrigger>
));
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
const ContextMenuSubContent = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
>(({ className, ...props }, ref) => (
<ContextMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName
<ContextMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
));
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
const ContextMenuContent = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
React.ElementRef<typeof ContextMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
>(({ className, ...props }, ref) => (
<ContextMenuPrimitive.Portal>
<ContextMenuPrimitive.Content
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</ContextMenuPrimitive.Portal>
))
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName
<ContextMenuPrimitive.Portal>
<ContextMenuPrimitive.Content
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
</ContextMenuPrimitive.Portal>
));
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
const ContextMenuItem = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
inset?: boolean
}
React.ElementRef<typeof ContextMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<ContextMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8",
className
)}
{...props}
/>
))
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName
<ContextMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8",
className,
)}
{...props}
/>
));
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
const ContextMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
>(({ className, children, checked, ...props }, ref) => (
<ContextMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
</ContextMenuPrimitive.CheckboxItem>
))
<ContextMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
</ContextMenuPrimitive.CheckboxItem>
));
ContextMenuCheckboxItem.displayName =
ContextMenuPrimitive.CheckboxItem.displayName
ContextMenuPrimitive.CheckboxItem.displayName;
const ContextMenuRadioItem = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
<ContextMenuPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<DotFilledIcon className="h-4 w-4 fill-current" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
</ContextMenuPrimitive.RadioItem>
))
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName
<ContextMenuPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<DotFilledIcon className="h-4 w-4 fill-current" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
</ContextMenuPrimitive.RadioItem>
));
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
const ContextMenuLabel = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
inset?: boolean
}
React.ElementRef<typeof ContextMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<ContextMenuPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold text-foreground",
inset && "pl-8",
className
)}
{...props}
/>
))
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName
<ContextMenuPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold text-foreground",
inset && "pl-8",
className,
)}
{...props}
/>
));
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
const ContextMenuSeparator = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
React.ElementRef<typeof ContextMenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
<ContextMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-border", className)}
{...props}
/>
))
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName
<ContextMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-border", className)}
{...props}
/>
));
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
const ContextMenuShortcut = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className
)}
{...props}
/>
)
}
ContextMenuShortcut.displayName = "ContextMenuShortcut"
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className,
)}
{...props}
/>
);
};
ContextMenuShortcut.displayName = "ContextMenuShortcut";
export {
ContextMenu,
ContextMenuTrigger,
ContextMenuContent,
ContextMenuItem,
ContextMenuCheckboxItem,
ContextMenuRadioItem,
ContextMenuLabel,
ContextMenuSeparator,
ContextMenuShortcut,
ContextMenuGroup,
ContextMenuPortal,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuRadioGroup,
}
ContextMenu,
ContextMenuTrigger,
ContextMenuContent,
ContextMenuItem,
ContextMenuCheckboxItem,
ContextMenuRadioItem,
ContextMenuLabel,
ContextMenuSeparator,
ContextMenuShortcut,
ContextMenuGroup,
ContextMenuPortal,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuRadioGroup,
};

View File

@@ -1,53 +1,58 @@
import { useState, useEffect } from 'react'
import { Button } from "@/components/ui/button"
import { Copy, Check } from "lucide-react"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
import { useState, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Copy, Check } from "lucide-react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
interface CopyButtonProps {
textToCopy: string
textToCopy: string;
}
export default function CopyButton({ textToCopy }: CopyButtonProps) {
const [isCopied, setIsCopied] = useState(false)
const [isCopied, setIsCopied] = useState(false);
useEffect(() => {
if (isCopied) {
const timer = setTimeout(() => setIsCopied(false), 2000)
return () => clearTimeout(timer)
}
}, [isCopied])
useEffect(() => {
if (isCopied) {
const timer = setTimeout(() => setIsCopied(false), 2000);
return () => clearTimeout(timer);
}
}, [isCopied]);
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(textToCopy)
setIsCopied(true)
} catch (err) {
console.error('Failed to copy text: ', err)
}
}
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(textToCopy);
setIsCopied(true);
} catch (err) {
console.error("Failed to copy text: ", err);
}
};
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="link"
size="icon"
onClick={handleCopy}
className="h-8 w-8"
>
{isCopied ? (
<Check className="h-4 w-4 " />
) : (
<Copy className="h-4 w-4" />
)}
<span className="sr-only">Copy to clipboard</span>
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{isCopied ? 'Copied!' : 'Copy to clipboard'}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
)
}
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="link"
size="icon"
onClick={handleCopy}
className="h-8 w-8"
>
{isCopied ? (
<Check className="h-4 w-4 " />
) : (
<Copy className="h-4 w-4" />
)}
<span className="sr-only">Copy to clipboard</span>
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{isCopied ? "Copied!" : "Copy to clipboard"}</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}

View File

@@ -1,122 +1,122 @@
"use client"
"use client";
import * as React from "react"
import * as DialogPrimitive from "@radix-ui/react-dialog"
import { Cross2Icon } from "@radix-ui/react-icons"
import * as React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { Cross2Icon } from "@radix-ui/react-icons";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Dialog = DialogPrimitive.Root
const Dialog = DialogPrimitive.Root;
const DialogTrigger = DialogPrimitive.Trigger
const DialogTrigger = DialogPrimitive.Trigger;
const DialogPortal = DialogPrimitive.Portal
const DialogPortal = DialogPrimitive.Portal;
const DialogClose = DialogPrimitive.Close
const DialogClose = DialogPrimitive.Close;
const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
/>
))
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
/>
));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<Cross2Icon className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
))
DialogContent.displayName = DialogPrimitive.Content.displayName
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className,
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<Cross2Icon className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;
const DialogHeader = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className
)}
{...props}
/>
)
DialogHeader.displayName = "DialogHeader"
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className,
)}
{...props}
/>
);
DialogHeader.displayName = "DialogHeader";
const DialogFooter = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
DialogFooter.displayName = "DialogFooter"
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
DialogFooter.displayName = "DialogFooter";
const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DialogTitle.displayName = DialogPrimitive.Title.displayName
<DialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className,
)}
{...props}
/>
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;
const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DialogDescription.displayName = DialogPrimitive.Description.displayName
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;
export {
Dialog,
DialogPortal,
DialogOverlay,
DialogTrigger,
DialogClose,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
}
Dialog,
DialogPortal,
DialogOverlay,
DialogTrigger,
DialogClose,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
};

View File

@@ -1,118 +1,118 @@
"use client"
"use client";
import * as React from "react"
import { Drawer as DrawerPrimitive } from "vaul"
import * as React from "react";
import { Drawer as DrawerPrimitive } from "vaul";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Drawer = ({
shouldScaleBackground = true,
...props
shouldScaleBackground = true,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root
shouldScaleBackground={shouldScaleBackground}
{...props}
/>
)
Drawer.displayName = "Drawer"
<DrawerPrimitive.Root
shouldScaleBackground={shouldScaleBackground}
{...props}
/>
);
Drawer.displayName = "Drawer";
const DrawerTrigger = DrawerPrimitive.Trigger
const DrawerTrigger = DrawerPrimitive.Trigger;
const DrawerPortal = DrawerPrimitive.Portal
const DrawerPortal = DrawerPrimitive.Portal;
const DrawerClose = DrawerPrimitive.Close
const DrawerClose = DrawerPrimitive.Close;
const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-50 bg-black/80", className)}
{...props}
/>
))
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-50 bg-black/80", className)}
{...props}
/>
));
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
))
DrawerContent.displayName = "DrawerContent"
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className,
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
));
DrawerContent.displayName = "DrawerContent";
const DrawerHeader = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
{...props}
/>
)
DrawerHeader.displayName = "DrawerHeader"
<div
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
{...props}
/>
);
DrawerHeader.displayName = "DrawerHeader";
const DrawerFooter = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
)
DrawerFooter.displayName = "DrawerFooter"
<div
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
);
DrawerFooter.displayName = "DrawerFooter";
const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DrawerTitle.displayName = DrawerPrimitive.Title.displayName
<DrawerPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className,
)}
{...props}
/>
));
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DrawerDescription.displayName = DrawerPrimitive.Description.displayName
<DrawerPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
}
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
};

View File

@@ -1,205 +1,205 @@
"use client"
"use client";
import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import * as React from "react";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import {
CheckIcon,
ChevronRightIcon,
DotFilledIcon,
} from "@radix-ui/react-icons"
CheckIcon,
ChevronRightIcon,
DotFilledIcon,
} from "@radix-ui/react-icons";
import { cn } from "@/lib/utils"
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<typeof DropdownMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean
}
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
inset && "pl-8",
className
)}
{...props}
>
{children}
<ChevronRightIcon className="ml-auto h-4 w-4" />
</DropdownMenuPrimitive.SubTrigger>
))
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
inset && "pl-8",
className,
)}
{...props}
>
{children}
<ChevronRightIcon className="ml-auto h-4 w-4" />
</DropdownMenuPrimitive.SubTrigger>
));
DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName
DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
));
DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName
DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</DropdownMenuPrimitive.Portal>
))
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
<DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
</DropdownMenuPrimitive.Portal>
));
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean
}
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8",
className
)}
{...props}
/>
))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8",
className,
)}
{...props}
/>
));
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
>(({ className, children, checked, ...props }, ref) => (
<DropdownMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"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
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
))
<DropdownMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"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,
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
));
DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName
DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
<DropdownMenuPrimitive.RadioItem
ref={ref}
className={cn(
"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}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<DotFilledIcon className="h-4 w-4 fill-current" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
))
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
<DropdownMenuPrimitive.RadioItem
ref={ref}
className={cn(
"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}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<DotFilledIcon className="h-4 w-4 fill-current" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
));
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
const DropdownMenuLabel = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean
}
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className
)}
{...props}
/>
))
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
<DropdownMenuPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className,
)}
{...props}
/>
));
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
const DropdownMenuSeparator = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
));
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
)
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
);
};
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
export {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuCheckboxItem,
DropdownMenuRadioItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuGroup,
DropdownMenuPortal,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
}
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuCheckboxItem,
DropdownMenuRadioItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuGroup,
DropdownMenuPortal,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
};

View File

@@ -1,178 +1,179 @@
"use client"
"use client";
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { Slot } from "@radix-ui/react-slot"
import * as React from "react";
import * as LabelPrimitive from "@radix-ui/react-label";
import { Slot } from "@radix-ui/react-slot";
import {
Controller,
ControllerProps,
FieldPath,
FieldValues,
FormProvider,
useFormContext,
} from "react-hook-form"
Controller,
ControllerProps,
FieldPath,
FieldValues,
FormProvider,
useFormContext,
} from "react-hook-form";
import { cn } from "@/lib/utils"
import { Label } from "@/components/ui/label"
import { cn } from "@/lib/utils";
import { Label } from "@/components/ui/label";
const Form = FormProvider
const Form = FormProvider;
type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
> = {
name: TName
}
name: TName;
};
const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue
)
{} as FormFieldContextValue,
);
const FormField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
>({
...props
...props
}: ControllerProps<TFieldValues, TName>) => {
return (
<FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} />
</FormFieldContext.Provider>
)
}
return (
<FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} />
</FormFieldContext.Provider>
);
};
const useFormField = () => {
const fieldContext = React.useContext(FormFieldContext)
const itemContext = React.useContext(FormItemContext)
const { getFieldState, formState } = useFormContext()
const fieldContext = React.useContext(FormFieldContext);
const itemContext = React.useContext(FormItemContext);
const { getFieldState, formState } = useFormContext();
const fieldState = getFieldState(fieldContext.name, formState)
const fieldState = getFieldState(fieldContext.name, formState);
if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>")
}
if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>");
}
const { id } = itemContext
const { id } = itemContext;
return {
id,
name: fieldContext.name,
formItemId: `${id}-form-item`,
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
}
}
return {
id,
name: fieldContext.name,
formItemId: `${id}-form-item`,
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
};
};
type FormItemContextValue = {
id: string
}
id: string;
};
const FormItemContext = React.createContext<FormItemContextValue>(
{} as FormItemContextValue
)
{} as FormItemContextValue,
);
const FormItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const id = React.useId()
const id = React.useId();
return (
<FormItemContext.Provider value={{ id }}>
<div ref={ref} className={cn("space-y-2", className)} {...props} />
</FormItemContext.Provider>
)
})
FormItem.displayName = "FormItem"
return (
<FormItemContext.Provider value={{ id }}>
<div ref={ref} className={cn("space-y-2", className)} {...props} />
</FormItemContext.Provider>
);
});
FormItem.displayName = "FormItem";
const FormLabel = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => {
const { error, formItemId } = useFormField()
const { error, formItemId } = useFormField();
return (
<Label
ref={ref}
className={cn(error && "text-destructive", className)}
htmlFor={formItemId}
{...props}
/>
)
})
FormLabel.displayName = "FormLabel"
return (
<Label
ref={ref}
className={cn(error && "text-destructive", className)}
htmlFor={formItemId}
{...props}
/>
);
});
FormLabel.displayName = "FormLabel";
const FormControl = React.forwardRef<
React.ElementRef<typeof Slot>,
React.ComponentPropsWithoutRef<typeof Slot>
React.ElementRef<typeof Slot>,
React.ComponentPropsWithoutRef<typeof Slot>
>(({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
const { error, formItemId, formDescriptionId, formMessageId } =
useFormField();
return (
<Slot
ref={ref}
id={formItemId}
aria-describedby={
!error
? `${formDescriptionId}`
: `${formDescriptionId} ${formMessageId}`
}
aria-invalid={!!error}
{...props}
/>
)
})
FormControl.displayName = "FormControl"
return (
<Slot
ref={ref}
id={formItemId}
aria-describedby={
!error
? `${formDescriptionId}`
: `${formDescriptionId} ${formMessageId}`
}
aria-invalid={!!error}
{...props}
/>
);
});
FormControl.displayName = "FormControl";
const FormDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => {
const { formDescriptionId } = useFormField()
const { formDescriptionId } = useFormField();
return (
<p
ref={ref}
id={formDescriptionId}
className={cn("text-[0.8rem] text-muted-foreground", className)}
{...props}
/>
)
})
FormDescription.displayName = "FormDescription"
return (
<p
ref={ref}
id={formDescriptionId}
className={cn("text-[0.8rem] text-muted-foreground", className)}
{...props}
/>
);
});
FormDescription.displayName = "FormDescription";
const FormMessage = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, children, ...props }, ref) => {
const { error, formMessageId } = useFormField()
const body = error ? String(error?.message) : children
const { error, formMessageId } = useFormField();
const body = error ? String(error?.message) : children;
if (!body) {
return null
}
if (!body) {
return null;
}
return (
<p
ref={ref}
id={formMessageId}
className={cn("text-[0.8rem] font-medium text-destructive", className)}
{...props}
>
{body}
</p>
)
})
FormMessage.displayName = "FormMessage"
return (
<p
ref={ref}
id={formMessageId}
className={cn("text-[0.8rem] font-medium text-destructive", className)}
{...props}
>
{body}
</p>
);
});
FormMessage.displayName = "FormMessage";
export {
useFormField,
Form,
FormItem,
FormLabel,
FormControl,
FormDescription,
FormMessage,
FormField,
}
useFormField,
Form,
FormItem,
FormLabel,
FormControl,
FormDescription,
FormMessage,
FormField,
};

View File

@@ -1,29 +1,29 @@
"use client"
"use client";
import * as React from "react"
import * as HoverCardPrimitive from "@radix-ui/react-hover-card"
import * as React from "react";
import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const HoverCard = HoverCardPrimitive.Root
const HoverCard = HoverCardPrimitive.Root;
const HoverCardTrigger = HoverCardPrimitive.Trigger
const HoverCardTrigger = HoverCardPrimitive.Trigger;
const HoverCardContent = React.forwardRef<
React.ElementRef<typeof HoverCardPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
React.ElementRef<typeof HoverCardPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<HoverCardPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
<HoverCardPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
));
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
export { HoverCard, HoverCardTrigger, HoverCardContent }
export { HoverCard, HoverCardTrigger, HoverCardContent };

View File

@@ -1,71 +1,71 @@
"use client"
"use client";
import * as React from "react"
import { DashIcon } from "@radix-ui/react-icons"
import { OTPInput, OTPInputContext } from "input-otp"
import * as React from "react";
import { DashIcon } from "@radix-ui/react-icons";
import { OTPInput, OTPInputContext } from "input-otp";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const InputOTP = React.forwardRef<
React.ElementRef<typeof OTPInput>,
React.ComponentPropsWithoutRef<typeof OTPInput>
React.ElementRef<typeof OTPInput>,
React.ComponentPropsWithoutRef<typeof OTPInput>
>(({ className, containerClassName, ...props }, ref) => (
<OTPInput
ref={ref}
containerClassName={cn(
"flex items-center gap-2 has-[:disabled]:opacity-50",
containerClassName
)}
className={cn("disabled:cursor-not-allowed", className)}
{...props}
/>
))
InputOTP.displayName = "InputOTP"
<OTPInput
ref={ref}
containerClassName={cn(
"flex items-center gap-2 has-[:disabled]:opacity-50",
containerClassName,
)}
className={cn("disabled:cursor-not-allowed", className)}
{...props}
/>
));
InputOTP.displayName = "InputOTP";
const InputOTPGroup = React.forwardRef<
React.ElementRef<"div">,
React.ComponentPropsWithoutRef<"div">
React.ElementRef<"div">,
React.ComponentPropsWithoutRef<"div">
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex items-center", className)} {...props} />
))
InputOTPGroup.displayName = "InputOTPGroup"
<div ref={ref} className={cn("flex items-center", className)} {...props} />
));
InputOTPGroup.displayName = "InputOTPGroup";
const InputOTPSlot = React.forwardRef<
React.ElementRef<"div">,
React.ComponentPropsWithoutRef<"div"> & { index: number }
React.ElementRef<"div">,
React.ComponentPropsWithoutRef<"div"> & { index: number }
>(({ index, className, ...props }, ref) => {
const inputOTPContext = React.useContext(OTPInputContext)
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index]
const inputOTPContext = React.useContext(OTPInputContext);
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
return (
<div
ref={ref}
className={cn(
"relative flex h-9 w-9 items-center justify-center border-y border-r border-input text-sm shadow-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
isActive && "z-10 ring-1 ring-ring",
className
)}
{...props}
>
{char}
{hasFakeCaret && (
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
</div>
)}
</div>
)
})
InputOTPSlot.displayName = "InputOTPSlot"
return (
<div
ref={ref}
className={cn(
"relative flex h-9 w-9 items-center justify-center border-y border-r border-input text-sm shadow-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
isActive && "z-10 ring-1 ring-ring",
className,
)}
{...props}
>
{char}
{hasFakeCaret && (
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
</div>
)}
</div>
);
});
InputOTPSlot.displayName = "InputOTPSlot";
const InputOTPSeparator = React.forwardRef<
React.ElementRef<"div">,
React.ComponentPropsWithoutRef<"div">
React.ElementRef<"div">,
React.ComponentPropsWithoutRef<"div">
>(({ ...props }, ref) => (
<div ref={ref} role="separator" {...props}>
<DashIcon />
</div>
))
InputOTPSeparator.displayName = "InputOTPSeparator"
<div ref={ref} role="separator" {...props}>
<DashIcon />
</div>
));
InputOTPSeparator.displayName = "InputOTPSeparator";
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator }
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };

View File

@@ -1,25 +1,25 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = "Input"
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
ref={ref}
{...props}
/>
);
},
);
Input.displayName = "Input";
export { Input }
export { Input };

View File

@@ -1,26 +1,26 @@
"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 * 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";
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
);
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
));
Label.displayName = LabelPrimitive.Root.displayName;
export { Label }
export { Label };

View File

@@ -1,240 +1,240 @@
"use client"
"use client";
import * as React from "react"
import * as React from "react";
import {
CheckIcon,
ChevronRightIcon,
DotFilledIcon,
} from "@radix-ui/react-icons"
import * as MenubarPrimitive from "@radix-ui/react-menubar"
CheckIcon,
ChevronRightIcon,
DotFilledIcon,
} from "@radix-ui/react-icons";
import * as MenubarPrimitive from "@radix-ui/react-menubar";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const MenubarMenu = MenubarPrimitive.Menu
const MenubarMenu = MenubarPrimitive.Menu;
const MenubarGroup = MenubarPrimitive.Group
const MenubarGroup = MenubarPrimitive.Group;
const MenubarPortal = MenubarPrimitive.Portal
const MenubarPortal = MenubarPrimitive.Portal;
const MenubarSub = MenubarPrimitive.Sub
const MenubarSub = MenubarPrimitive.Sub;
const MenubarRadioGroup = MenubarPrimitive.RadioGroup
const MenubarRadioGroup = MenubarPrimitive.RadioGroup;
const Menubar = React.forwardRef<
React.ElementRef<typeof MenubarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>
React.ElementRef<typeof MenubarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>
>(({ className, ...props }, ref) => (
<MenubarPrimitive.Root
ref={ref}
className={cn(
"flex h-9 items-center space-x-1 rounded-md border bg-background p-1 shadow-sm",
className
)}
{...props}
/>
))
Menubar.displayName = MenubarPrimitive.Root.displayName
<MenubarPrimitive.Root
ref={ref}
className={cn(
"flex h-9 items-center space-x-1 rounded-md border bg-background p-1 shadow-sm",
className,
)}
{...props}
/>
));
Menubar.displayName = MenubarPrimitive.Root.displayName;
const MenubarTrigger = React.forwardRef<
React.ElementRef<typeof MenubarPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>
React.ElementRef<typeof MenubarPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>
>(({ className, ...props }, ref) => (
<MenubarPrimitive.Trigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-3 py-1 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
className
)}
{...props}
/>
))
MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName
<MenubarPrimitive.Trigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-3 py-1 text-sm font-medium outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
className,
)}
{...props}
/>
));
MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName;
const MenubarSubTrigger = React.forwardRef<
React.ElementRef<typeof MenubarPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & {
inset?: boolean
}
React.ElementRef<typeof MenubarPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & {
inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
<MenubarPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
inset && "pl-8",
className
)}
{...props}
>
{children}
<ChevronRightIcon className="ml-auto h-4 w-4" />
</MenubarPrimitive.SubTrigger>
))
MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName
<MenubarPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
inset && "pl-8",
className,
)}
{...props}
>
{children}
<ChevronRightIcon className="ml-auto h-4 w-4" />
</MenubarPrimitive.SubTrigger>
));
MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName;
const MenubarSubContent = React.forwardRef<
React.ElementRef<typeof MenubarPrimitive.SubContent>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubContent>
React.ElementRef<typeof MenubarPrimitive.SubContent>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubContent>
>(({ className, ...props }, ref) => (
<MenubarPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName
<MenubarPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
));
MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;
const MenubarContent = React.forwardRef<
React.ElementRef<typeof MenubarPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>
React.ElementRef<typeof MenubarPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>
>(
(
{ className, align = "start", alignOffset = -4, sideOffset = 8, ...props },
ref
) => (
<MenubarPrimitive.Portal>
<MenubarPrimitive.Content
ref={ref}
align={align}
alignOffset={alignOffset}
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</MenubarPrimitive.Portal>
)
)
MenubarContent.displayName = MenubarPrimitive.Content.displayName
(
{ className, align = "start", alignOffset = -4, sideOffset = 8, ...props },
ref,
) => (
<MenubarPrimitive.Portal>
<MenubarPrimitive.Content
ref={ref}
align={align}
alignOffset={alignOffset}
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
</MenubarPrimitive.Portal>
),
);
MenubarContent.displayName = MenubarPrimitive.Content.displayName;
const MenubarItem = React.forwardRef<
React.ElementRef<typeof MenubarPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {
inset?: boolean
}
React.ElementRef<typeof MenubarPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<MenubarPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8",
className
)}
{...props}
/>
))
MenubarItem.displayName = MenubarPrimitive.Item.displayName
<MenubarPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
inset && "pl-8",
className,
)}
{...props}
/>
));
MenubarItem.displayName = MenubarPrimitive.Item.displayName;
const MenubarCheckboxItem = React.forwardRef<
React.ElementRef<typeof MenubarPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.CheckboxItem>
React.ElementRef<typeof MenubarPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.CheckboxItem>
>(({ className, children, checked, ...props }, ref) => (
<MenubarPrimitive.CheckboxItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<MenubarPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</MenubarPrimitive.ItemIndicator>
</span>
{children}
</MenubarPrimitive.CheckboxItem>
))
MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName
<MenubarPrimitive.CheckboxItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<MenubarPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</MenubarPrimitive.ItemIndicator>
</span>
{children}
</MenubarPrimitive.CheckboxItem>
));
MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName;
const MenubarRadioItem = React.forwardRef<
React.ElementRef<typeof MenubarPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.RadioItem>
React.ElementRef<typeof MenubarPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
<MenubarPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<MenubarPrimitive.ItemIndicator>
<DotFilledIcon className="h-4 w-4 fill-current" />
</MenubarPrimitive.ItemIndicator>
</span>
{children}
</MenubarPrimitive.RadioItem>
))
MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName
<MenubarPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<MenubarPrimitive.ItemIndicator>
<DotFilledIcon className="h-4 w-4 fill-current" />
</MenubarPrimitive.ItemIndicator>
</span>
{children}
</MenubarPrimitive.RadioItem>
));
MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName;
const MenubarLabel = React.forwardRef<
React.ElementRef<typeof MenubarPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & {
inset?: boolean
}
React.ElementRef<typeof MenubarPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & {
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<MenubarPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className
)}
{...props}
/>
))
MenubarLabel.displayName = MenubarPrimitive.Label.displayName
<MenubarPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className,
)}
{...props}
/>
));
MenubarLabel.displayName = MenubarPrimitive.Label.displayName;
const MenubarSeparator = React.forwardRef<
React.ElementRef<typeof MenubarPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>
React.ElementRef<typeof MenubarPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>
>(({ className, ...props }, ref) => (
<MenubarPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName
<MenubarPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
));
MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName;
const MenubarShortcut = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className
)}
{...props}
/>
)
}
MenubarShortcut.displayname = "MenubarShortcut"
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className,
)}
{...props}
/>
);
};
MenubarShortcut.displayname = "MenubarShortcut";
export {
Menubar,
MenubarMenu,
MenubarTrigger,
MenubarContent,
MenubarItem,
MenubarSeparator,
MenubarLabel,
MenubarCheckboxItem,
MenubarRadioGroup,
MenubarRadioItem,
MenubarPortal,
MenubarSubContent,
MenubarSubTrigger,
MenubarGroup,
MenubarSub,
MenubarShortcut,
}
Menubar,
MenubarMenu,
MenubarTrigger,
MenubarContent,
MenubarItem,
MenubarSeparator,
MenubarLabel,
MenubarCheckboxItem,
MenubarRadioGroup,
MenubarRadioItem,
MenubarPortal,
MenubarSubContent,
MenubarSubTrigger,
MenubarGroup,
MenubarSub,
MenubarShortcut,
};

View File

@@ -1,128 +1,128 @@
import * as React from "react"
import { ChevronDownIcon } from "@radix-ui/react-icons"
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
import { cva } from "class-variance-authority"
import * as React from "react";
import { ChevronDownIcon } from "@radix-ui/react-icons";
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
import { cva } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const NavigationMenu = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Root
ref={ref}
className={cn(
"relative z-10 flex max-w-max flex-1 items-center justify-center",
className
)}
{...props}
>
{children}
<NavigationMenuViewport />
</NavigationMenuPrimitive.Root>
))
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
<NavigationMenuPrimitive.Root
ref={ref}
className={cn(
"relative z-10 flex max-w-max flex-1 items-center justify-center",
className,
)}
{...props}
>
{children}
<NavigationMenuViewport />
</NavigationMenuPrimitive.Root>
));
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
const NavigationMenuList = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.List>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
React.ElementRef<typeof NavigationMenuPrimitive.List>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.List
ref={ref}
className={cn(
"group flex flex-1 list-none items-center justify-center space-x-1",
className
)}
{...props}
/>
))
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
<NavigationMenuPrimitive.List
ref={ref}
className={cn(
"group flex flex-1 list-none items-center justify-center space-x-1",
className,
)}
{...props}
/>
));
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
const NavigationMenuItem = NavigationMenuPrimitive.Item
const NavigationMenuItem = NavigationMenuPrimitive.Item;
const navigationMenuTriggerStyle = cva(
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"
)
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50",
);
const NavigationMenuTrigger = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Trigger
ref={ref}
className={cn(navigationMenuTriggerStyle(), "group", className)}
{...props}
>
{children}{" "}
<ChevronDownIcon
className="relative top-[1px] ml-1 h-3 w-3 transition duration-300 group-data-[state=open]:rotate-180"
aria-hidden="true"
/>
</NavigationMenuPrimitive.Trigger>
))
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
<NavigationMenuPrimitive.Trigger
ref={ref}
className={cn(navigationMenuTriggerStyle(), "group", className)}
{...props}
>
{children}{" "}
<ChevronDownIcon
className="relative top-[1px] ml-1 h-3 w-3 transition duration-300 group-data-[state=open]:rotate-180"
aria-hidden="true"
/>
</NavigationMenuPrimitive.Trigger>
));
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
const NavigationMenuContent = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Content
ref={ref}
className={cn(
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ",
className
)}
{...props}
/>
))
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName
<NavigationMenuPrimitive.Content
ref={ref}
className={cn(
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ",
className,
)}
{...props}
/>
));
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
const NavigationMenuLink = NavigationMenuPrimitive.Link
const NavigationMenuLink = NavigationMenuPrimitive.Link;
const NavigationMenuViewport = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
>(({ className, ...props }, ref) => (
<div className={cn("absolute left-0 top-full flex justify-center")}>
<NavigationMenuPrimitive.Viewport
className={cn(
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
className
)}
ref={ref}
{...props}
/>
</div>
))
<div className={cn("absolute left-0 top-full flex justify-center")}>
<NavigationMenuPrimitive.Viewport
className={cn(
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
className,
)}
ref={ref}
{...props}
/>
</div>
));
NavigationMenuViewport.displayName =
NavigationMenuPrimitive.Viewport.displayName
NavigationMenuPrimitive.Viewport.displayName;
const NavigationMenuIndicator = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Indicator
ref={ref}
className={cn(
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
className
)}
{...props}
>
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
</NavigationMenuPrimitive.Indicator>
))
<NavigationMenuPrimitive.Indicator
ref={ref}
className={cn(
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
className,
)}
{...props}
>
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
</NavigationMenuPrimitive.Indicator>
));
NavigationMenuIndicator.displayName =
NavigationMenuPrimitive.Indicator.displayName
NavigationMenuPrimitive.Indicator.displayName;
export {
navigationMenuTriggerStyle,
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuContent,
NavigationMenuTrigger,
NavigationMenuLink,
NavigationMenuIndicator,
NavigationMenuViewport,
}
navigationMenuTriggerStyle,
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuContent,
NavigationMenuTrigger,
NavigationMenuLink,
NavigationMenuIndicator,
NavigationMenuViewport,
};

View File

@@ -1,121 +1,121 @@
import * as React from "react"
import * as React from "react";
import {
ChevronLeftIcon,
ChevronRightIcon,
DotsHorizontalIcon,
} from "@radix-ui/react-icons"
ChevronLeftIcon,
ChevronRightIcon,
DotsHorizontalIcon,
} from "@radix-ui/react-icons";
import { cn } from "@/lib/utils"
import { ButtonProps, buttonVariants } from "@/components/ui/button"
import { cn } from "@/lib/utils";
import { ButtonProps, buttonVariants } from "@/components/ui/button";
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
<nav
role="navigation"
aria-label="pagination"
className={cn("mx-auto flex w-full justify-center", className)}
{...props}
/>
)
Pagination.displayName = "Pagination"
<nav
role="navigation"
aria-label="pagination"
className={cn("mx-auto flex w-full justify-center", className)}
{...props}
/>
);
Pagination.displayName = "Pagination";
const PaginationContent = React.forwardRef<
HTMLUListElement,
React.ComponentProps<"ul">
HTMLUListElement,
React.ComponentProps<"ul">
>(({ className, ...props }, ref) => (
<ul
ref={ref}
className={cn("flex flex-row items-center gap-1", className)}
{...props}
/>
))
PaginationContent.displayName = "PaginationContent"
<ul
ref={ref}
className={cn("flex flex-row items-center gap-1", className)}
{...props}
/>
));
PaginationContent.displayName = "PaginationContent";
const PaginationItem = React.forwardRef<
HTMLLIElement,
React.ComponentProps<"li">
HTMLLIElement,
React.ComponentProps<"li">
>(({ className, ...props }, ref) => (
<li ref={ref} className={cn("", className)} {...props} />
))
PaginationItem.displayName = "PaginationItem"
<li ref={ref} className={cn("", className)} {...props} />
));
PaginationItem.displayName = "PaginationItem";
type PaginationLinkProps = {
isActive?: boolean
isActive?: boolean;
} & Pick<ButtonProps, "size"> &
React.ComponentProps<"a">
React.ComponentProps<"a">;
const PaginationLink = ({
className,
isActive,
size = "icon",
...props
className,
isActive,
size = "icon",
...props
}: PaginationLinkProps) => (
<a
aria-current={isActive ? "page" : undefined}
className={cn(
buttonVariants({
variant: isActive ? "outline" : "ghost",
size,
}),
className
)}
{...props}
/>
)
PaginationLink.displayName = "PaginationLink"
<a
aria-current={isActive ? "page" : undefined}
className={cn(
buttonVariants({
variant: isActive ? "outline" : "ghost",
size,
}),
className,
)}
{...props}
/>
);
PaginationLink.displayName = "PaginationLink";
const PaginationPrevious = ({
className,
...props
className,
...props
}: React.ComponentProps<typeof PaginationLink>) => (
<PaginationLink
aria-label="Go to previous page"
size="default"
className={cn("gap-1 pl-2.5", className)}
{...props}
>
<ChevronLeftIcon className="h-4 w-4" />
<span>Previous</span>
</PaginationLink>
)
PaginationPrevious.displayName = "PaginationPrevious"
<PaginationLink
aria-label="Go to previous page"
size="default"
className={cn("gap-1 pl-2.5", className)}
{...props}
>
<ChevronLeftIcon className="h-4 w-4" />
<span>Previous</span>
</PaginationLink>
);
PaginationPrevious.displayName = "PaginationPrevious";
const PaginationNext = ({
className,
...props
className,
...props
}: React.ComponentProps<typeof PaginationLink>) => (
<PaginationLink
aria-label="Go to next page"
size="default"
className={cn("gap-1 pr-2.5", className)}
{...props}
>
<span>Next</span>
<ChevronRightIcon className="h-4 w-4" />
</PaginationLink>
)
PaginationNext.displayName = "PaginationNext"
<PaginationLink
aria-label="Go to next page"
size="default"
className={cn("gap-1 pr-2.5", className)}
{...props}
>
<span>Next</span>
<ChevronRightIcon className="h-4 w-4" />
</PaginationLink>
);
PaginationNext.displayName = "PaginationNext";
const PaginationEllipsis = ({
className,
...props
className,
...props
}: React.ComponentProps<"span">) => (
<span
aria-hidden
className={cn("flex h-9 w-9 items-center justify-center", className)}
{...props}
>
<DotsHorizontalIcon className="h-4 w-4" />
<span className="sr-only">More pages</span>
</span>
)
PaginationEllipsis.displayName = "PaginationEllipsis"
<span
aria-hidden
className={cn("flex h-9 w-9 items-center justify-center", className)}
{...props}
>
<DotsHorizontalIcon className="h-4 w-4" />
<span className="sr-only">More pages</span>
</span>
);
PaginationEllipsis.displayName = "PaginationEllipsis";
export {
Pagination,
PaginationContent,
PaginationLink,
PaginationItem,
PaginationPrevious,
PaginationNext,
PaginationEllipsis,
}
Pagination,
PaginationContent,
PaginationLink,
PaginationItem,
PaginationPrevious,
PaginationNext,
PaginationEllipsis,
};

View File

@@ -8,39 +8,39 @@ import { Input, type InputProps } from "@/components/ui/input";
import { cn } from "@/lib/utils";
const PasswordInput = React.forwardRef<HTMLInputElement, InputProps>(
({ className, ...props }, ref) => {
const [showPassword, setShowPassword] = React.useState(false);
const disabled =
props.value === "" || props.value === undefined || props.disabled;
({ className, ...props }, ref) => {
const [showPassword, setShowPassword] = React.useState(false);
const disabled =
props.value === "" || props.value === undefined || props.disabled;
return (
<div className="relative">
<Input
type={showPassword ? "text" : "password"}
className={cn("hide-password-toggle pr-10", className)}
ref={ref}
{...props}
/>
<Button
type="button"
variant="ghost"
size="sm"
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
onClick={() => setShowPassword((prev) => !prev)}
disabled={disabled}
>
{showPassword && !disabled ? (
<EyeIcon className="h-4 w-4" aria-hidden="true" />
) : (
<EyeOffIcon className="h-4 w-4" aria-hidden="true" />
)}
<span className="sr-only">
{showPassword ? "Hide password" : "Show password"}
</span>
</Button>
return (
<div className="relative">
<Input
type={showPassword ? "text" : "password"}
className={cn("hide-password-toggle pr-10", className)}
ref={ref}
{...props}
/>
<Button
type="button"
variant="ghost"
size="sm"
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
onClick={() => setShowPassword((prev) => !prev)}
disabled={disabled}
>
{showPassword && !disabled ? (
<EyeIcon className="h-4 w-4" aria-hidden="true" />
) : (
<EyeOffIcon className="h-4 w-4" aria-hidden="true" />
)}
<span className="sr-only">
{showPassword ? "Hide password" : "Show password"}
</span>
</Button>
{/* hides browsers password toggles */}
<style>{`
{/* hides browsers password toggles */}
<style>{`
.hide-password-toggle::-ms-reveal,
.hide-password-toggle::-ms-clear {
visibility: hidden;
@@ -48,9 +48,9 @@ const PasswordInput = React.forwardRef<HTMLInputElement, InputProps>(
display: none;
}
`}</style>
</div>
);
}
</div>
);
},
);
PasswordInput.displayName = "PasswordInput";

View File

@@ -1,33 +1,33 @@
"use client"
"use client";
import * as React from "react"
import * as PopoverPrimitive from "@radix-ui/react-popover"
import * as React from "react";
import * as PopoverPrimitive from "@radix-ui/react-popover";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Popover = PopoverPrimitive.Root
const Popover = PopoverPrimitive.Root;
const PopoverTrigger = PopoverPrimitive.Trigger
const PopoverTrigger = PopoverPrimitive.Trigger;
const PopoverAnchor = PopoverPrimitive.Anchor
const PopoverAnchor = PopoverPrimitive.Anchor;
const PopoverContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
</PopoverPrimitive.Portal>
))
PopoverContent.displayName = PopoverPrimitive.Content.displayName
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
</PopoverPrimitive.Portal>
));
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };

View File

@@ -1,28 +1,28 @@
"use client"
"use client";
import * as React from "react"
import * as ProgressPrimitive from "@radix-ui/react-progress"
import * as React from "react";
import * as ProgressPrimitive from "@radix-ui/react-progress";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Progress = React.forwardRef<
React.ElementRef<typeof ProgressPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
React.ElementRef<typeof ProgressPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
>(({ className, value, ...props }, ref) => (
<ProgressPrimitive.Root
ref={ref}
className={cn(
"relative h-2 w-full overflow-hidden rounded-full bg-primary/20",
className
)}
{...props}
>
<ProgressPrimitive.Indicator
className="h-full w-full flex-1 bg-primary transition-all"
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
</ProgressPrimitive.Root>
))
Progress.displayName = ProgressPrimitive.Root.displayName
<ProgressPrimitive.Root
ref={ref}
className={cn(
"relative h-2 w-full overflow-hidden rounded-full bg-primary/20",
className,
)}
{...props}
>
<ProgressPrimitive.Indicator
className="h-full w-full flex-1 bg-primary transition-all"
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
</ProgressPrimitive.Root>
));
Progress.displayName = ProgressPrimitive.Root.displayName;
export { Progress }
export { Progress };

View File

@@ -1,44 +1,44 @@
"use client"
"use client";
import * as React from "react"
import { CheckIcon } from "@radix-ui/react-icons"
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
import * as React from "react";
import { CheckIcon } from "@radix-ui/react-icons";
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const RadioGroup = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
React.ElementRef<typeof RadioGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
>(({ className, ...props }, ref) => {
return (
<RadioGroupPrimitive.Root
className={cn("grid gap-2", className)}
{...props}
ref={ref}
/>
)
})
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
return (
<RadioGroupPrimitive.Root
className={cn("grid gap-2", className)}
{...props}
ref={ref}
/>
);
});
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
const RadioGroupItem = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
React.ElementRef<typeof RadioGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
>(({ className, ...props }, ref) => {
return (
<RadioGroupPrimitive.Item
ref={ref}
className={cn(
"aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
<CheckIcon className="h-3.5 w-3.5 fill-primary" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
)
})
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
return (
<RadioGroupPrimitive.Item
ref={ref}
className={cn(
"aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
<CheckIcon className="h-3.5 w-3.5 fill-primary" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
);
});
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
export { RadioGroup, RadioGroupItem }
export { RadioGroup, RadioGroupItem };

View File

@@ -1,45 +1,45 @@
"use client"
"use client";
import { DragHandleDots2Icon } from "@radix-ui/react-icons"
import * as ResizablePrimitive from "react-resizable-panels"
import { DragHandleDots2Icon } from "@radix-ui/react-icons";
import * as ResizablePrimitive from "react-resizable-panels";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const ResizablePanelGroup = ({
className,
...props
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
<ResizablePrimitive.PanelGroup
className={cn(
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
className
)}
{...props}
/>
)
<ResizablePrimitive.PanelGroup
className={cn(
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
className,
)}
{...props}
/>
);
const ResizablePanel = ResizablePrimitive.Panel
const ResizablePanel = ResizablePrimitive.Panel;
const ResizableHandle = ({
withHandle,
className,
...props
withHandle,
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
withHandle?: boolean
withHandle?: boolean;
}) => (
<ResizablePrimitive.PanelResizeHandle
className={cn(
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
className
)}
{...props}
>
{withHandle && (
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
<DragHandleDots2Icon className="h-2.5 w-2.5" />
</div>
)}
</ResizablePrimitive.PanelResizeHandle>
)
<ResizablePrimitive.PanelResizeHandle
className={cn(
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
className,
)}
{...props}
>
{withHandle && (
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
<DragHandleDots2Icon className="h-2.5 w-2.5" />
</div>
)}
</ResizablePrimitive.PanelResizeHandle>
);
export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
export { ResizablePanelGroup, ResizablePanel, ResizableHandle };

View File

@@ -1,48 +1,48 @@
"use client"
"use client";
import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
import * as React from "react";
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("relative overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
))
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("relative overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
));
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
>(({ className, orientation = "vertical", ...props }, ref) => (
<ScrollAreaPrimitive.ScrollAreaScrollbar
ref={ref}
orientation={orientation}
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
className
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
</ScrollAreaPrimitive.ScrollAreaScrollbar>
))
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
<ScrollAreaPrimitive.ScrollAreaScrollbar
ref={ref}
orientation={orientation}
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
className,
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
</ScrollAreaPrimitive.ScrollAreaScrollbar>
));
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
export { ScrollArea, ScrollBar }
export { ScrollArea, ScrollBar };

View File

@@ -1,164 +1,164 @@
"use client"
"use client";
import * as React from "react"
import * as React from "react";
import {
CaretSortIcon,
CheckIcon,
ChevronDownIcon,
ChevronUpIcon,
} from "@radix-ui/react-icons"
import * as SelectPrimitive from "@radix-ui/react-select"
CaretSortIcon,
CheckIcon,
ChevronDownIcon,
ChevronUpIcon,
} from "@radix-ui/react-icons";
import * as SelectPrimitive from "@radix-ui/react-select";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Select = SelectPrimitive.Root
const Select = SelectPrimitive.Root;
const SelectGroup = SelectPrimitive.Group
const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value
const SelectValue = SelectPrimitive.Value;
const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<CaretSortIcon className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
))
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className,
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<CaretSortIcon className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
));
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
)}
{...props}
>
<ChevronUpIcon />
</SelectPrimitive.ScrollUpButton>
))
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
<SelectPrimitive.ScrollUpButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className,
)}
{...props}
>
<ChevronUpIcon />
</SelectPrimitive.ScrollUpButton>
));
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
)}
{...props}
>
<ChevronDownIcon />
</SelectPrimitive.ScrollDownButton>
))
<SelectPrimitive.ScrollDownButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className,
)}
{...props}
>
<ChevronDownIcon />
</SelectPrimitive.ScrollDownButton>
));
SelectScrollDownButton.displayName =
SelectPrimitive.ScrollDownButton.displayName
SelectPrimitive.ScrollDownButton.displayName;
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className,
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]",
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
));
SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
{...props}
/>
))
SelectLabel.displayName = SelectPrimitive.Label.displayName
<SelectPrimitive.Label
ref={ref}
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
{...props}
/>
));
SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
{...props}
>
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
));
SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
));
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
}
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
};

View File

@@ -1,31 +1,31 @@
"use client"
"use client";
import * as React from "react"
import * as SeparatorPrimitive from "@radix-ui/react-separator"
import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(
(
{ className, orientation = "horizontal", decorative = true, ...props },
ref
) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className
)}
{...props}
/>
)
)
Separator.displayName = SeparatorPrimitive.Root.displayName
(
{ className, orientation = "horizontal", decorative = true, ...props },
ref,
) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className,
)}
{...props}
/>
),
);
Separator.displayName = SeparatorPrimitive.Root.displayName;
export { Separator }
export { Separator };

View File

@@ -1,140 +1,140 @@
"use client"
"use client";
import * as React from "react"
import * as SheetPrimitive from "@radix-ui/react-dialog"
import { Cross2Icon } from "@radix-ui/react-icons"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { Cross2Icon } from "@radix-ui/react-icons";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Sheet = SheetPrimitive.Root
const Sheet = SheetPrimitive.Root;
const SheetTrigger = SheetPrimitive.Trigger
const SheetTrigger = SheetPrimitive.Trigger;
const SheetClose = SheetPrimitive.Close
const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
ref={ref}
/>
))
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
ref={ref}
/>
));
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
}
)
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
},
);
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<Cross2Icon className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
{children}
</SheetPrimitive.Content>
</SheetPortal>
))
SheetContent.displayName = SheetPrimitive.Content.displayName
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<Cross2Icon className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
{children}
</SheetPrimitive.Content>
</SheetPortal>
));
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
)
SheetHeader.displayName = "SheetHeader"
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
SheetFooter.displayName = "SheetFooter"
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
))
SheetTitle.displayName = SheetPrimitive.Title.displayName
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
SheetDescription.displayName = SheetPrimitive.Description.displayName
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetPortal,
SheetOverlay,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
}
Sheet,
SheetPortal,
SheetOverlay,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
};

View File

@@ -1,15 +1,15 @@
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function Skeleton({
className,
...props
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn("animate-pulse rounded-md bg-primary/10", className)}
{...props}
/>
)
return (
<div
className={cn("animate-pulse rounded-md bg-primary/10", className)}
{...props}
/>
);
}
export { Skeleton }
export { Skeleton };

View File

@@ -1,28 +1,28 @@
"use client"
"use client";
import * as React from "react"
import * as SliderPrimitive from "@radix-ui/react-slider"
import * as React from "react";
import * as SliderPrimitive from "@radix-ui/react-slider";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Slider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className
)}
{...props}
>
<SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20">
<SliderPrimitive.Range className="absolute h-full bg-primary" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
))
Slider.displayName = SliderPrimitive.Root.displayName
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className,
)}
{...props}
>
<SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20">
<SliderPrimitive.Range className="absolute h-full bg-primary" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
));
Slider.displayName = SliderPrimitive.Root.displayName;
export { Slider }
export { Slider };

View File

@@ -1,31 +1,31 @@
"use client"
"use client";
import { useTheme } from "next-themes"
import { Toaster as Sonner } from "sonner"
import { useTheme } from "next-themes";
import { Toaster as Sonner } from "sonner";
type ToasterProps = React.ComponentProps<typeof Sonner>
type ToasterProps = React.ComponentProps<typeof Sonner>;
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
const { theme = "system" } = useTheme();
return (
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
toastOptions={{
classNames: {
toast:
"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
description: "group-[.toast]:text-muted-foreground",
actionButton:
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
cancelButton:
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
},
}}
{...props}
/>
)
}
return (
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
toastOptions={{
classNames: {
toast:
"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
description: "group-[.toast]:text-muted-foreground",
actionButton:
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
cancelButton:
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
},
}}
{...props}
/>
);
};
export { Toaster }
export { Toaster };

View File

@@ -1,29 +1,29 @@
"use client"
"use client";
import * as React from "react"
import * as SwitchPrimitives from "@radix-ui/react-switch"
import * as React from "react";
import * as SwitchPrimitives from "@radix-ui/react-switch";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
React.ElementRef<typeof SwitchPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
)}
/>
</SwitchPrimitives.Root>
))
Switch.displayName = SwitchPrimitives.Root.displayName
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className,
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0",
)}
/>
</SwitchPrimitives.Root>
));
Switch.displayName = SwitchPrimitives.Root.displayName;
export { Switch }
export { Switch };

View File

@@ -1,120 +1,120 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Table = React.forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<table
ref={ref}
className={cn("w-full caption-bottom text-sm", className)}
{...props}
/>
</div>
))
Table.displayName = "Table"
<div className="relative w-full overflow-auto">
<table
ref={ref}
className={cn("w-full caption-bottom text-sm", className)}
{...props}
/>
</div>
));
Table.displayName = "Table";
const TableHeader = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
))
TableHeader.displayName = "TableHeader"
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
));
TableHeader.displayName = "TableHeader";
const TableBody = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tbody
ref={ref}
className={cn("[&_tr:last-child]:border-0", className)}
{...props}
/>
))
TableBody.displayName = "TableBody"
<tbody
ref={ref}
className={cn("[&_tr:last-child]:border-0", className)}
{...props}
/>
));
TableBody.displayName = "TableBody";
const TableFooter = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn(
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
className
)}
{...props}
/>
))
TableFooter.displayName = "TableFooter"
<tfoot
ref={ref}
className={cn(
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
className,
)}
{...props}
/>
));
TableFooter.displayName = "TableFooter";
const TableRow = React.forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
className
)}
{...props}
/>
))
TableRow.displayName = "TableRow"
<tr
ref={ref}
className={cn(
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
className,
)}
{...props}
/>
));
TableRow.displayName = "TableRow";
const TableHead = React.forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<th
ref={ref}
className={cn(
"h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className
)}
{...props}
/>
))
TableHead.displayName = "TableHead"
<th
ref={ref}
className={cn(
"h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className,
)}
{...props}
/>
));
TableHead.displayName = "TableHead";
const TableCell = React.forwardRef<
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn(
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className
)}
{...props}
/>
))
TableCell.displayName = "TableCell"
<td
ref={ref}
className={cn(
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className,
)}
{...props}
/>
));
TableCell.displayName = "TableCell";
const TableCaption = React.forwardRef<
HTMLTableCaptionElement,
React.HTMLAttributes<HTMLTableCaptionElement>
HTMLTableCaptionElement,
React.HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => (
<caption
ref={ref}
className={cn("mt-4 text-sm text-muted-foreground", className)}
{...props}
/>
))
TableCaption.displayName = "TableCaption"
<caption
ref={ref}
className={cn("mt-4 text-sm text-muted-foreground", className)}
{...props}
/>
));
TableCaption.displayName = "TableCaption";
export {
Table,
TableHeader,
TableBody,
TableFooter,
TableHead,
TableRow,
TableCell,
TableCaption,
}
Table,
TableHeader,
TableBody,
TableFooter,
TableHead,
TableRow,
TableCell,
TableCaption,
};

View File

@@ -1,55 +1,55 @@
"use client"
"use client";
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import * as React from "react";
import * as TabsPrimitive from "@radix-ui/react-tabs";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Tabs = TabsPrimitive.Root
const Tabs = TabsPrimitive.Root;
const TabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
React.ElementRef<typeof TabsPrimitive.List>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
className
)}
{...props}
/>
))
TabsList.displayName = TabsPrimitive.List.displayName
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
className,
)}
{...props}
/>
));
TabsList.displayName = TabsPrimitive.List.displayName;
const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
className
)}
{...props}
/>
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
className,
)}
{...props}
/>
));
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
const TabsContent = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
React.ElementRef<typeof TabsPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className
)}
{...props}
/>
))
TabsContent.displayName = TabsPrimitive.Content.displayName
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className,
)}
{...props}
/>
));
TabsContent.displayName = TabsPrimitive.Content.displayName;
export { Tabs, TabsList, TabsTrigger, TabsContent }
export { Tabs, TabsList, TabsTrigger, TabsContent };

View File

@@ -5,142 +5,142 @@ import { motion } from "framer-motion";
import { cn } from "@/lib/utils";
type Tab = {
title: string;
value: string;
content?: string | React.ReactNode | any;
title: string;
value: string;
content?: string | React.ReactNode | any;
};
export const Tabs = ({
tabs: propTabs,
containerClassName,
activeTabClassName,
tabClassName,
contentClassName,
tabs: propTabs,
containerClassName,
activeTabClassName,
tabClassName,
contentClassName,
}: {
tabs: Tab[];
containerClassName?: string;
activeTabClassName?: string;
tabClassName?: string;
contentClassName?: string;
tabs: Tab[];
containerClassName?: string;
activeTabClassName?: string;
tabClassName?: string;
contentClassName?: string;
}) => {
const [active, setActive] = useState<Tab>(propTabs[0]);
const [tabs, setTabs] = useState<Tab[]>(propTabs);
const [active, setActive] = useState<Tab>(propTabs[0]);
const [tabs, setTabs] = useState<Tab[]>(propTabs);
const moveSelectedTabToTop = (idx: number) => {
const newTabs = [...propTabs];
const selectedTab = newTabs.splice(idx, 1);
newTabs.unshift(selectedTab[0]);
setTabs(newTabs);
setActive(newTabs[0]);
};
const moveSelectedTabToTop = (idx: number) => {
const newTabs = [...propTabs];
const selectedTab = newTabs.splice(idx, 1);
newTabs.unshift(selectedTab[0]);
setTabs(newTabs);
setActive(newTabs[0]);
};
const [hovering, setHovering] = useState(false);
const [hovering, setHovering] = useState(false);
return (
<>
<div
className={cn(
"flex flex-row items-center justify-start mt-0 [perspective:1000px] relative overflow-auto sm:overflow-visible no-visible-scrollbar border-x w-full border-t max-w-max bg-opacity-0",
containerClassName
)}
>
{propTabs.map((tab, idx) => (
<button
key={tab.title}
onClick={() => {
moveSelectedTabToTop(idx);
}}
onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)}
className={cn(
"relative px-4 py-2 rounded-full opacity-80 hover:opacity-100",
tabClassName
)}
style={{
transformStyle: "preserve-3d",
}}
>
{active.value === tab.value && (
<motion.div
transition={{
duration: 0.2,
delay: 0.1,
return (
<>
<div
className={cn(
"flex flex-row items-center justify-start mt-0 [perspective:1000px] relative overflow-auto sm:overflow-visible no-visible-scrollbar border-x w-full border-t max-w-max bg-opacity-0",
containerClassName,
)}
>
{propTabs.map((tab, idx) => (
<button
key={tab.title}
onClick={() => {
moveSelectedTabToTop(idx);
}}
onMouseEnter={() => setHovering(true)}
onMouseLeave={() => setHovering(false)}
className={cn(
"relative px-4 py-2 rounded-full opacity-80 hover:opacity-100",
tabClassName,
)}
style={{
transformStyle: "preserve-3d",
}}
>
{active.value === tab.value && (
<motion.div
transition={{
duration: 0.2,
delay: 0.1,
type: "keyframes",
}}
animate={{
x: tabs.indexOf(tab) === 0 ? [0, 0, 0] : [0, 0, 0],
}}
className={cn(
"absolute inset-0 bg-gray-200 dark:bg-zinc-900/90 opacity-100",
activeTabClassName
)}
/>
)}
type: "keyframes",
}}
animate={{
x: tabs.indexOf(tab) === 0 ? [0, 0, 0] : [0, 0, 0],
}}
className={cn(
"absolute inset-0 bg-gray-200 dark:bg-zinc-900/90 opacity-100",
activeTabClassName,
)}
/>
)}
<span
className={cn(
"relative block text-black dark:text-white",
active.value === tab.value
? "text-opacity-100 font-medium"
: "opacity-40 "
)}
>
{tab.title}
</span>
</button>
))}
</div>
<FadeInDiv
tabs={tabs}
active={active}
key={active.value}
hovering={hovering}
className={cn("", contentClassName)}
/>
</>
);
<span
className={cn(
"relative block text-black dark:text-white",
active.value === tab.value
? "text-opacity-100 font-medium"
: "opacity-40 ",
)}
>
{tab.title}
</span>
</button>
))}
</div>
<FadeInDiv
tabs={tabs}
active={active}
key={active.value}
hovering={hovering}
className={cn("", contentClassName)}
/>
</>
);
};
export const FadeInDiv = ({
className,
tabs,
className,
tabs,
}: {
className?: string;
key?: string;
tabs: Tab[];
active: Tab;
hovering?: boolean;
className?: string;
key?: string;
tabs: Tab[];
active: Tab;
hovering?: boolean;
}) => {
const isActive = (tab: Tab) => {
return tab.value === tabs[0].value;
};
return (
<div className="relative w-full h-full">
{tabs.map((tab, idx) => (
<motion.div
key={tab.value}
style={{
scale: 1 - idx * 0.1,
zIndex: -idx,
opacity: idx < 3 ? 1 - idx * 0.1 : 0,
}}
animate={{
transition: {
duration: 0.2,
delay: 0.1,
type: "keyframes",
},
}}
className={cn(
"w-50 h-full",
isActive(tab) ? "" : "hidden",
className
)}
>
{tab.content}
</motion.div>
))}
</div>
);
const isActive = (tab: Tab) => {
return tab.value === tabs[0].value;
};
return (
<div className="relative w-full h-full">
{tabs.map((tab, idx) => (
<motion.div
key={tab.value}
style={{
scale: 1 - idx * 0.1,
zIndex: -idx,
opacity: idx < 3 ? 1 - idx * 0.1 : 0,
}}
animate={{
transition: {
duration: 0.2,
delay: 0.1,
type: "keyframes",
},
}}
className={cn(
"w-50 h-full",
isActive(tab) ? "" : "hidden",
className,
)}
>
{tab.content}
</motion.div>
))}
</div>
);
};

View File

@@ -1,24 +1,24 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Textarea.displayName = "Textarea"
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
ref={ref}
{...props}
/>
);
},
);
Textarea.displayName = "Textarea";
export { Textarea }
export { Textarea };

View File

@@ -1,129 +1,129 @@
"use client"
"use client";
import * as React from "react"
import { Cross2Icon } from "@radix-ui/react-icons"
import * as ToastPrimitives from "@radix-ui/react-toast"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import { Cross2Icon } from "@radix-ui/react-icons";
import * as ToastPrimitives from "@radix-ui/react-toast";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const ToastProvider = ToastPrimitives.Provider
const ToastProvider = ToastPrimitives.Provider;
const ToastViewport = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Viewport>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
React.ElementRef<typeof ToastPrimitives.Viewport>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Viewport
ref={ref}
className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
className
)}
{...props}
/>
))
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
<ToastPrimitives.Viewport
ref={ref}
className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
className,
)}
{...props}
/>
));
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
const toastVariants = cva(
"group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 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",
{
variants: {
variant: {
default: "border bg-background text-foreground",
destructive:
"destructive group border-destructive bg-destructive text-destructive-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
)
"group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 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",
{
variants: {
variant: {
default: "border bg-background text-foreground",
destructive:
"destructive group border-destructive bg-destructive text-destructive-foreground",
},
},
defaultVariants: {
variant: "default",
},
},
);
const Toast = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
VariantProps<typeof toastVariants>
React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
return (
<ToastPrimitives.Root
ref={ref}
className={cn(toastVariants({ variant }), className)}
{...props}
/>
)
})
Toast.displayName = ToastPrimitives.Root.displayName
return (
<ToastPrimitives.Root
ref={ref}
className={cn(toastVariants({ variant }), className)}
{...props}
/>
);
});
Toast.displayName = ToastPrimitives.Root.displayName;
const ToastAction = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Action>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
React.ElementRef<typeof ToastPrimitives.Action>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Action
ref={ref}
className={cn(
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
className
)}
{...props}
/>
))
ToastAction.displayName = ToastPrimitives.Action.displayName
<ToastPrimitives.Action
ref={ref}
className={cn(
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
className,
)}
{...props}
/>
));
ToastAction.displayName = ToastPrimitives.Action.displayName;
const ToastClose = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Close>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
React.ElementRef<typeof ToastPrimitives.Close>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Close
ref={ref}
className={cn(
"absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
className
)}
toast-close=""
{...props}
>
<Cross2Icon className="h-4 w-4" />
</ToastPrimitives.Close>
))
ToastClose.displayName = ToastPrimitives.Close.displayName
<ToastPrimitives.Close
ref={ref}
className={cn(
"absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
className,
)}
toast-close=""
{...props}
>
<Cross2Icon className="h-4 w-4" />
</ToastPrimitives.Close>
));
ToastClose.displayName = ToastPrimitives.Close.displayName;
const ToastTitle = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Title>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
React.ElementRef<typeof ToastPrimitives.Title>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Title
ref={ref}
className={cn("text-sm font-semibold [&+div]:text-xs", className)}
{...props}
/>
))
ToastTitle.displayName = ToastPrimitives.Title.displayName
<ToastPrimitives.Title
ref={ref}
className={cn("text-sm font-semibold [&+div]:text-xs", className)}
{...props}
/>
));
ToastTitle.displayName = ToastPrimitives.Title.displayName;
const ToastDescription = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Description>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
React.ElementRef<typeof ToastPrimitives.Description>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Description
ref={ref}
className={cn("text-sm opacity-90", className)}
{...props}
/>
))
ToastDescription.displayName = ToastPrimitives.Description.displayName
<ToastPrimitives.Description
ref={ref}
className={cn("text-sm opacity-90", className)}
{...props}
/>
));
ToastDescription.displayName = ToastPrimitives.Description.displayName;
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
type ToastActionElement = React.ReactElement<typeof ToastAction>
type ToastActionElement = React.ReactElement<typeof ToastAction>;
export {
type ToastProps,
type ToastActionElement,
ToastProvider,
ToastViewport,
Toast,
ToastTitle,
ToastDescription,
ToastClose,
ToastAction,
}
type ToastProps,
type ToastActionElement,
ToastProvider,
ToastViewport,
Toast,
ToastTitle,
ToastDescription,
ToastClose,
ToastAction,
};

View File

@@ -1,35 +1,35 @@
"use client"
"use client";
import { useToast } from "@/hooks/use-toast"
import { useToast } from "@/hooks/use-toast";
import {
Toast,
ToastClose,
ToastDescription,
ToastProvider,
ToastTitle,
ToastViewport,
} from "@/components/ui/toast"
Toast,
ToastClose,
ToastDescription,
ToastProvider,
ToastTitle,
ToastViewport,
} from "@/components/ui/toast";
export function Toaster() {
const { toasts } = useToast()
const { toasts } = useToast();
return (
<ToastProvider>
{toasts.map(function ({ id, title, description, action, ...props }) {
return (
<Toast key={id} {...props}>
<div className="grid gap-1">
{title && <ToastTitle>{title}</ToastTitle>}
{description && (
<ToastDescription>{description}</ToastDescription>
)}
</div>
{action}
<ToastClose />
</Toast>
)
})}
<ToastViewport />
</ToastProvider>
)
return (
<ToastProvider>
{toasts.map(function ({ id, title, description, action, ...props }) {
return (
<Toast key={id} {...props}>
<div className="grid gap-1">
{title && <ToastTitle>{title}</ToastTitle>}
{description && (
<ToastDescription>{description}</ToastDescription>
)}
</div>
{action}
<ToastClose />
</Toast>
);
})}
<ToastViewport />
</ToastProvider>
);
}

View File

@@ -1,61 +1,61 @@
"use client"
"use client";
import * as React from "react"
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"
import { type VariantProps } from "class-variance-authority"
import * as React from "react";
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
import { type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { toggleVariants } from "@/components/ui/toggle"
import { cn } from "@/lib/utils";
import { toggleVariants } from "@/components/ui/toggle";
const ToggleGroupContext = React.createContext<
VariantProps<typeof toggleVariants>
VariantProps<typeof toggleVariants>
>({
size: "default",
variant: "default",
})
size: "default",
variant: "default",
});
const ToggleGroup = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
VariantProps<typeof toggleVariants>
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
VariantProps<typeof toggleVariants>
>(({ className, variant, size, children, ...props }, ref) => (
<ToggleGroupPrimitive.Root
ref={ref}
className={cn("flex items-center justify-center gap-1", className)}
{...props}
>
<ToggleGroupContext.Provider value={{ variant, size }}>
{children}
</ToggleGroupContext.Provider>
</ToggleGroupPrimitive.Root>
))
<ToggleGroupPrimitive.Root
ref={ref}
className={cn("flex items-center justify-center gap-1", className)}
{...props}
>
<ToggleGroupContext.Provider value={{ variant, size }}>
{children}
</ToggleGroupContext.Provider>
</ToggleGroupPrimitive.Root>
));
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
const ToggleGroupItem = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
VariantProps<typeof toggleVariants>
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
VariantProps<typeof toggleVariants>
>(({ className, children, variant, size, ...props }, ref) => {
const context = React.useContext(ToggleGroupContext)
const context = React.useContext(ToggleGroupContext);
return (
<ToggleGroupPrimitive.Item
ref={ref}
className={cn(
toggleVariants({
variant: context.variant || variant,
size: context.size || size,
}),
className
)}
{...props}
>
{children}
</ToggleGroupPrimitive.Item>
)
})
return (
<ToggleGroupPrimitive.Item
ref={ref}
className={cn(
toggleVariants({
variant: context.variant || variant,
size: context.size || size,
}),
className,
)}
{...props}
>
{children}
</ToggleGroupPrimitive.Item>
);
});
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
export { ToggleGroup, ToggleGroupItem }
export { ToggleGroup, ToggleGroupItem };

View File

@@ -1,45 +1,45 @@
"use client"
"use client";
import * as React from "react"
import * as TogglePrimitive from "@radix-ui/react-toggle"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import * as TogglePrimitive from "@radix-ui/react-toggle";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const toggleVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
{
variants: {
variant: {
default: "bg-transparent",
outline:
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-9 px-3",
sm: "h-8 px-2",
lg: "h-10 px-3",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
{
variants: {
variant: {
default: "bg-transparent",
outline:
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-9 px-3",
sm: "h-8 px-2",
lg: "h-10 px-3",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
const Toggle = React.forwardRef<
React.ElementRef<typeof TogglePrimitive.Root>,
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
VariantProps<typeof toggleVariants>
React.ElementRef<typeof TogglePrimitive.Root>,
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> &
VariantProps<typeof toggleVariants>
>(({ className, variant, size, ...props }, ref) => (
<TogglePrimitive.Root
ref={ref}
className={cn(toggleVariants({ variant, size, className }))}
{...props}
/>
))
<TogglePrimitive.Root
ref={ref}
className={cn(toggleVariants({ variant, size, className }))}
{...props}
/>
));
Toggle.displayName = TogglePrimitive.Root.displayName
Toggle.displayName = TogglePrimitive.Root.displayName;
export { Toggle, toggleVariants }
export { Toggle, toggleVariants };

View File

@@ -1,30 +1,30 @@
"use client"
"use client";
import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
import * as React from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const TooltipProvider = TooltipPrimitive.Provider
const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = TooltipPrimitive.Root
const Tooltip = TooltipPrimitive.Root;
const TooltipTrigger = TooltipPrimitive.Trigger
const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

View File

@@ -1,42 +1,36 @@
"use client"
"use client";
import Link from "next/link";
import { ThemeToggle } from "./theme-toggle";
import { Logo } from "./logo";
import {
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
export function Wrapper(props: { children: React.ReactNode }) {
return (
<div className="min-h-screen w-full dark:bg-black bg-white dark:bg-grid-small-white/[0.2] bg-grid-small-black/[0.2] relative flex justify-center">
<div className="absolute pointer-events-none inset-0 md:flex items-center justify-center dark:bg-black bg-white [mask-image:radial-gradient(ellipse_at_center,transparent_20%,black)] hidden"></div>
<div className="bg-white dark:bg-black border-b py-2 flex justify-between items-center border-border absolute z-50 w-full lg:w-8/12 px-4 md:px-1">
<Link href="/">
<div className="flex gap-2 cursor-pointer">
<Logo />
<p className="dark:text-white text-black">BETTER-AUTH.</p>
</div>
</Link>
<div className="z-50 flex items-center">
<ThemeToggle />
</div>
</div>
<div className="mt-20 lg:w-7/12 w-full">
{props.children}
</div>
</div>
)
return (
<div className="min-h-screen w-full dark:bg-black bg-white dark:bg-grid-small-white/[0.2] bg-grid-small-black/[0.2] relative flex justify-center">
<div className="absolute pointer-events-none inset-0 md:flex items-center justify-center dark:bg-black bg-white [mask-image:radial-gradient(ellipse_at_center,transparent_20%,black)] hidden"></div>
<div className="bg-white dark:bg-black border-b py-2 flex justify-between items-center border-border absolute z-50 w-full lg:w-8/12 px-4 md:px-1">
<Link href="/">
<div className="flex gap-2 cursor-pointer">
<Logo />
<p className="dark:text-white text-black">BETTER-AUTH.</p>
</div>
</Link>
<div className="z-50 flex items-center">
<ThemeToggle />
</div>
</div>
<div className="mt-20 lg:w-7/12 w-full">{props.children}</div>
</div>
);
}
const queryClient = new QueryClient()
const queryClient = new QueryClient();
export function WrapperWithQuery(props: { children: React.ReactNode }) {
return (
<QueryClientProvider client={queryClient}>
{props.children}
</QueryClientProvider>
)
}
return (
<QueryClientProvider client={queryClient}>
{props.children}
</QueryClientProvider>
);
}

View File

@@ -95,6 +95,7 @@ export const reducer = (state: State, action: Action): State => {
if (toastId) {
addToRemoveQueue(toastId);
} else {
// biome-ignore lint/complexity/noForEach: <explanation>
state.toasts.forEach((toast) => {
addToRemoveQueue(toast.id);
});
@@ -132,6 +133,7 @@ let memoryState: State = { toasts: [] };
function dispatch(action: Action) {
memoryState = reducer(memoryState, action);
// biome-ignore lint/complexity/noForEach: <explanation>
listeners.forEach((listener) => {
listener(memoryState);
});

View File

@@ -1,110 +1,108 @@
import {
Body,
Button,
Container,
Column,
Head,
Heading,
Hr,
Html,
Img,
Link,
Preview,
Row,
Section,
Text,
Tailwind,
Body,
Button,
Container,
Column,
Head,
Heading,
Hr,
Html,
Img,
Link,
Preview,
Row,
Section,
Text,
Tailwind,
} from "@react-email/components";
import * as React from "react";
interface BetterAuthInviteUserEmailProps {
username?: string;
invitedByUsername?: string;
invitedByEmail?: string;
teamName?: string;
teamImage?: string;
inviteLink?: string;
username?: string;
invitedByUsername?: string;
invitedByEmail?: string;
teamName?: string;
teamImage?: string;
inviteLink?: string;
}
export const InviteUserEmail = ({
username,
invitedByUsername,
invitedByEmail,
teamName,
teamImage,
inviteLink,
username,
invitedByUsername,
invitedByEmail,
teamName,
teamImage,
inviteLink,
}: BetterAuthInviteUserEmailProps) => {
const previewText = `Join ${invitedByUsername} on BetterAuth`;
return (
<Html>
<Head />
<Preview>{previewText}</Preview>
<Tailwind>
<Body className="bg-white my-auto mx-auto font-sans px-2">
<Container className="border border-solid border-[#eaeaea] rounded my-[40px] mx-auto p-[20px] max-w-[465px]">
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
Join <strong>{invitedByUsername}</strong> on <strong>Better Auth.</strong>
</Heading>
<Text className="text-black text-[14px] leading-[24px]">
Hello there,
</Text>
<Text className="text-black text-[14px] leading-[24px]">
<strong>{invitedByUsername}</strong> (
<Link
href={`mailto:${invitedByEmail}`}
className="text-blue-600 no-underline"
>
{invitedByEmail}
</Link>
) has invited you to the <strong>{teamName}</strong> team on{" "}
<strong>Better Auth</strong>.
</Text>
<Section>
{
teamImage ? <Row>
<Column align="left">
<Img
className="rounded-full"
src={teamImage}
width="64"
height="64"
fetchPriority="high"
/>
</Column>
</Row> : null
}
</Section>
<Section className="text-center mt-[32px] mb-[32px]">
<Button
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
href={inviteLink}
>
Join the team
</Button>
</Section>
<Text className="text-black text-[14px] leading-[24px]">
or copy and paste this URL into your browser:{" "}
<Link href={inviteLink} className="text-blue-600 no-underline">
{inviteLink}
</Link>
</Text>
<Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" />
<Text className="text-[#666666] text-[12px] leading-[24px]">
This invitation was intended for{" "}
<span className="text-black">{username}</span>. If you
were not expecting this invitation, you can ignore this email.
</Text>
</Container>
</Body>
</Tailwind>
</Html>
);
const previewText = `Join ${invitedByUsername} on BetterAuth`;
return (
<Html>
<Head />
<Preview>{previewText}</Preview>
<Tailwind>
<Body className="bg-white my-auto mx-auto font-sans px-2">
<Container className="border border-solid border-[#eaeaea] rounded my-[40px] mx-auto p-[20px] max-w-[465px]">
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
Join <strong>{invitedByUsername}</strong> on{" "}
<strong>Better Auth.</strong>
</Heading>
<Text className="text-black text-[14px] leading-[24px]">
Hello there,
</Text>
<Text className="text-black text-[14px] leading-[24px]">
<strong>{invitedByUsername}</strong> (
<Link
href={`mailto:${invitedByEmail}`}
className="text-blue-600 no-underline"
>
{invitedByEmail}
</Link>
) has invited you to the <strong>{teamName}</strong> team on{" "}
<strong>Better Auth</strong>.
</Text>
<Section>
{teamImage ? (
<Row>
<Column align="left">
<Img
className="rounded-full"
src={teamImage}
width="64"
height="64"
fetchPriority="high"
/>
</Column>
</Row>
) : null}
</Section>
<Section className="text-center mt-[32px] mb-[32px]">
<Button
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
href={inviteLink}
>
Join the team
</Button>
</Section>
<Text className="text-black text-[14px] leading-[24px]">
or copy and paste this URL into your browser:{" "}
<Link href={inviteLink} className="text-blue-600 no-underline">
{inviteLink}
</Link>
</Text>
<Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" />
<Text className="text-[#666666] text-[12px] leading-[24px]">
This invitation was intended for{" "}
<span className="text-black">{username}</span>. If you were not
expecting this invitation, you can ignore this email.
</Text>
</Container>
</Body>
</Tailwind>
</Html>
);
};
export function reactInvitationEmail(props: BetterAuthInviteUserEmailProps) {
console.log(props)
return <InviteUserEmail {...props} />
}
console.log(props);
return <InviteUserEmail {...props} />;
}

View File

@@ -1,71 +1,76 @@
import {
Body,
Button,
Container,
Head,
Heading,
Hr,
Html,
Link,
Preview,
Text,
Tailwind,
Section,
Body,
Button,
Container,
Head,
Heading,
Hr,
Html,
Link,
Preview,
Text,
Tailwind,
Section,
} from "@react-email/components";
import * as React from "react";
interface BetterAuthResetPasswordEmailProps {
username?: string;
resetLink?: string;
username?: string;
resetLink?: string;
}
export const ResetPasswordEmail = ({
username,
resetLink,
username,
resetLink,
}: BetterAuthResetPasswordEmailProps) => {
const previewText = `Reset your BetterAuth password`;
return (
<Html>
<Head />
<Preview>{previewText}</Preview>
<Tailwind>
<Body className="bg-white my-auto mx-auto font-sans px-2">
<Container className="border border-solid border-[#eaeaea] rounded my-[40px] mx-auto p-[20px] max-w-[465px]">
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
Reset your <strong>Better Auth</strong> password
</Heading>
<Text className="text-black text-[14px] leading-[24px]">
Hello {username},
</Text>
<Text className="text-black text-[14px] leading-[24px]">
We received a request to reset your password for your Better Auth account. If you didn't make this request, you can safely ignore this email.
</Text>
<Section className="text-center mt-[32px] mb-[32px]">
<Button
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
href={resetLink}
>
Reset Password
</Button>
</Section>
<Text className="text-black text-[14px] leading-[24px]">
Or copy and paste this URL into your browser:{" "}
<Link href={resetLink} className="text-blue-600 no-underline">
{resetLink}
</Link>
</Text>
<Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" />
<Text className="text-[#666666] text-[12px] leading-[24px]">
If you didn't request a password reset, please ignore this email or contact support if you have concerns.
</Text>
</Container>
</Body>
</Tailwind>
</Html>
);
const previewText = `Reset your BetterAuth password`;
return (
<Html>
<Head />
<Preview>{previewText}</Preview>
<Tailwind>
<Body className="bg-white my-auto mx-auto font-sans px-2">
<Container className="border border-solid border-[#eaeaea] rounded my-[40px] mx-auto p-[20px] max-w-[465px]">
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
Reset your <strong>Better Auth</strong> password
</Heading>
<Text className="text-black text-[14px] leading-[24px]">
Hello {username},
</Text>
<Text className="text-black text-[14px] leading-[24px]">
We received a request to reset your password for your Better Auth
account. If you didn't make this request, you can safely ignore
this email.
</Text>
<Section className="text-center mt-[32px] mb-[32px]">
<Button
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
href={resetLink}
>
Reset Password
</Button>
</Section>
<Text className="text-black text-[14px] leading-[24px]">
Or copy and paste this URL into your browser:{" "}
<Link href={resetLink} className="text-blue-600 no-underline">
{resetLink}
</Link>
</Text>
<Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" />
<Text className="text-[#666666] text-[12px] leading-[24px]">
If you didn't request a password reset, please ignore this email
or contact support if you have concerns.
</Text>
</Container>
</Body>
</Tailwind>
</Html>
);
};
export function reactResetPasswordEmail(props: BetterAuthResetPasswordEmailProps) {
console.log(props);
return <ResetPasswordEmail {...props} />;
export function reactResetPasswordEmail(
props: BetterAuthResetPasswordEmailProps,
) {
console.log(props);
return <ResetPasswordEmail {...props} />;
}

View File

@@ -1,6 +1,6 @@
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
return twMerge(clsx(inputs));
}

View File

@@ -1,8 +1,8 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
plugins: {
tailwindcss: {},
},
};
export default config;

View File

@@ -4,126 +4,126 @@ const svgToDataUri = require("mini-svg-data-uri");
const colors = require("tailwindcss/colors");
const {
default: flattenColorPalette,
default: flattenColorPalette,
} = require("tailwindcss/lib/util/flattenColorPalette");
const config = {
darkMode: ["class"],
content: [
"./pages/**/*.{ts,tsx}",
"./components/**/*.{ts,tsx}",
"./app/**/*.{ts,tsx}",
"./src/**/*.{ts,tsx}",
],
prefix: "",
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
boxShadow: {
input: `0px 2px 3px -1px rgba(0,0,0,0.1), 0px 1px 0px 0px rgba(25,28,33,0.02), 0px 0px 0px 1px rgba(25,28,33,0.08)`,
},
},
},
plugins: [
require("tailwindcss-animate"),
addVariablesForColors,
function ({ matchUtilities, theme }: any) {
matchUtilities(
{
"bg-grid": (value: any) => ({
backgroundImage: `url("${svgToDataUri(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="none" stroke="${value}"><path d="M0 .5H31.5V32"/></svg>`
)}")`,
}),
"bg-grid-small": (value: any) => ({
backgroundImage: `url("${svgToDataUri(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="8" height="8" fill="none" stroke="${value}"><path d="M0 .5H31.5V32"/></svg>`
)}")`,
}),
"bg-dot": (value: any) => ({
backgroundImage: `url("${svgToDataUri(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="16" height="16" fill="none"><circle fill="${value}" id="pattern-circle" cx="10" cy="10" r="1.6257413380501518"></circle></svg>`
)}")`,
}),
},
{
values: flattenColorPalette(theme("backgroundColor")),
type: "color",
}
);
},
],
darkMode: ["class"],
content: [
"./pages/**/*.{ts,tsx}",
"./components/**/*.{ts,tsx}",
"./app/**/*.{ts,tsx}",
"./src/**/*.{ts,tsx}",
],
prefix: "",
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
boxShadow: {
input: `0px 2px 3px -1px rgba(0,0,0,0.1), 0px 1px 0px 0px rgba(25,28,33,0.02), 0px 0px 0px 1px rgba(25,28,33,0.08)`,
},
},
},
plugins: [
require("tailwindcss-animate"),
addVariablesForColors,
function ({ matchUtilities, theme }: any) {
matchUtilities(
{
"bg-grid": (value: any) => ({
backgroundImage: `url("${svgToDataUri(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="none" stroke="${value}"><path d="M0 .5H31.5V32"/></svg>`,
)}")`,
}),
"bg-grid-small": (value: any) => ({
backgroundImage: `url("${svgToDataUri(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="8" height="8" fill="none" stroke="${value}"><path d="M0 .5H31.5V32"/></svg>`,
)}")`,
}),
"bg-dot": (value: any) => ({
backgroundImage: `url("${svgToDataUri(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="16" height="16" fill="none"><circle fill="${value}" id="pattern-circle" cx="10" cy="10" r="1.6257413380501518"></circle></svg>`,
)}")`,
}),
},
{
values: flattenColorPalette(theme("backgroundColor")),
type: "color",
},
);
},
],
} satisfies Config;
function addVariablesForColors({ addBase, theme }: any) {
let allColors = flattenColorPalette(theme("colors"));
let newVars = Object.fromEntries(
Object.entries(allColors).map(([key, val]) => [`--${key}`, val])
);
let allColors = flattenColorPalette(theme("colors"));
let newVars = Object.fromEntries(
Object.entries(allColors).map(([key, val]) => [`--${key}`, val]),
);
addBase({
":root": newVars,
});
addBase({
":root": newVars,
});
}
export default config;

View File

@@ -1,27 +1,27 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@@ -1,27 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}

View File

@@ -11,16 +11,18 @@ export default function Home() {
return (
<main class="text-center mx-auto text-gray-700 p-4 min-h-screen flex flex-col items-center justify-center">
<Show
fallback={<button
class="bg-sky-600 text-white px-4 py-2 rounded-md"
onclick={async () => {
await client.signIn.social({
provider: "github",
});
}}
>
Continue with github
</button>}
fallback={
<button
class="bg-sky-600 text-white px-4 py-2 rounded-md"
onclick={async () => {
await client.signIn.social({
provider: "github",
});
}}
>
Continue with github
</button>
}
when={!!session().data?.session}
>
<div class="flex flex-col gap-2 border border-blue-400/10 px-6 py-5">

View File

@@ -5,5 +5,3 @@ export const client = createAuthClient({
baseURL: "http://localhost:3000/api/auth",
plugins: [organizationClient()],
});

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import { client } from "$lib/client";
import { client } from "$lib/client";
const organizations = client.useListOrganizations();
const activeOrganization = client.useActiveOrganization();
const organizations = client.useListOrganizations();
const activeOrganization = client.useActiveOrganization();
</script>
<h1>Organizations</h1>

View File

@@ -1,111 +1,110 @@
import { useId } from 'react'
import { useId } from "react";
import { Intro, IntroFooter } from "./changelog-layout"
import { StarField } from './stat-field'
import { Intro, IntroFooter } from "./changelog-layout";
import { StarField } from "./stat-field";
function Timeline() {
let id = useId()
let id = useId();
return (
<div className="pointer-events-none absolute inset-0 z-50 overflow-hidden lg:right-[calc(max(2rem,50%-38rem)+40rem)] lg:min-w-[32rem] lg:overflow-visible">
<svg
className="absolute left-[max(0px,calc(50%-18.125rem))] top-0 h-full w-1.5 lg:left-full lg:ml-1 xl:left-auto xl:right-1 xl:ml-0"
aria-hidden="true"
>
<defs>
<pattern id={id} width="6" height="8" patternUnits="userSpaceOnUse">
<path
d="M0 0H6M0 8H6"
className="stroke-sky-900/10 xl:stroke-white/10 dark:stroke-white/10"
fill="none"
/>
</pattern>
</defs>
<rect width="100%" height="100%" fill={`url(#${id})`} />
</svg>
someone is
</div>
)
return (
<div className="pointer-events-none absolute inset-0 z-50 overflow-hidden lg:right-[calc(max(2rem,50%-38rem)+40rem)] lg:min-w-[32rem] lg:overflow-visible">
<svg
className="absolute left-[max(0px,calc(50%-18.125rem))] top-0 h-full w-1.5 lg:left-full lg:ml-1 xl:left-auto xl:right-1 xl:ml-0"
aria-hidden="true"
>
<defs>
<pattern id={id} width="6" height="8" patternUnits="userSpaceOnUse">
<path
d="M0 0H6M0 8H6"
className="stroke-sky-900/10 xl:stroke-white/10 dark:stroke-white/10"
fill="none"
/>
</pattern>
</defs>
<rect width="100%" height="100%" fill={`url(#${id})`} />
</svg>
someone is
</div>
);
}
function Glow() {
let id = useId()
let id = useId();
return (
<div className="absolute inset-0 overflow-hidden lg:right-[calc(max(2rem,50%-38rem)+40rem)] lg:min-w-[32rem]">
<svg
className="absolute -bottom-48 left-[-40%] h-[80rem] w-[180%] lg:-right-40 lg:bottom-auto lg:left-auto lg:top-[-40%] lg:h-[180%] lg:w-[80rem]"
aria-hidden="true"
>
<defs>
<radialGradient id={`${id}-desktop`} cx="100%">
<stop offset="0%" stopColor="rgba(214, 211, 209, 0.6)" />
<stop offset="53.95%" stopColor="rgba(214, 200, 209, 0.09)" />
<stop offset="100%" stopColor="rgba(10, 14, 23, 0)" />
</radialGradient>
<radialGradient id={`${id}-mobile`} cy="100%">
<stop offset="0%" stopColor="rgba(56, 189, 248, 0.3)" />
<stop offset="53.95%" stopColor="rgba(0, 71, 255, 0.09)" />
<stop offset="100%" stopColor="rgba(10, 14, 23, 0)" />
</radialGradient>
</defs>
<rect
width="100%"
height="100%"
fill={`url(#${id}-desktop)`}
className="hidden lg:block"
/>
<rect
width="100%"
height="100%"
fill={`url(#${id}-mobile)`}
className="lg:hidden"
/>
</svg>
<div className="absolute inset-x-0 bottom-0 right-0 h-px bg-white mix-blend-overlay lg:left-auto lg:top-0 lg:h-auto lg:w-px" />
</div>
)
return (
<div className="absolute inset-0 overflow-hidden lg:right-[calc(max(2rem,50%-38rem)+40rem)] lg:min-w-[32rem]">
<svg
className="absolute -bottom-48 left-[-40%] h-[80rem] w-[180%] lg:-right-40 lg:bottom-auto lg:left-auto lg:top-[-40%] lg:h-[180%] lg:w-[80rem]"
aria-hidden="true"
>
<defs>
<radialGradient id={`${id}-desktop`} cx="100%">
<stop offset="0%" stopColor="rgba(214, 211, 209, 0.6)" />
<stop offset="53.95%" stopColor="rgba(214, 200, 209, 0.09)" />
<stop offset="100%" stopColor="rgba(10, 14, 23, 0)" />
</radialGradient>
<radialGradient id={`${id}-mobile`} cy="100%">
<stop offset="0%" stopColor="rgba(56, 189, 248, 0.3)" />
<stop offset="53.95%" stopColor="rgba(0, 71, 255, 0.09)" />
<stop offset="100%" stopColor="rgba(10, 14, 23, 0)" />
</radialGradient>
</defs>
<rect
width="100%"
height="100%"
fill={`url(#${id}-desktop)`}
className="hidden lg:block"
/>
<rect
width="100%"
height="100%"
fill={`url(#${id}-mobile)`}
className="lg:hidden"
/>
</svg>
<div className="absolute inset-x-0 bottom-0 right-0 h-px bg-white mix-blend-overlay lg:left-auto lg:top-0 lg:h-auto lg:w-px" />
</div>
);
}
function FixedSidebar({
main,
footer,
main,
footer,
}: {
main: React.ReactNode
footer: React.ReactNode
main: React.ReactNode;
footer: React.ReactNode;
}) {
return (
<div className="relative flex-none overflow-hidden px-10 lg:pointer-events-none lg:fixed lg:inset-0 lg:z-40 lg:flex lg:px-0">
<Glow />
<div className="relative flex w-full lg:pointer-events-auto lg:mr-[calc(max(2rem,50%-35rem)+40rem)] lg:min-w-[32rem] lg:overflow-y-auto lg:overflow-x-hidden lg:pl-[max(4rem,calc(50%-38rem))]">
<div className="mx-auto max-w-lg lg:mx-auto lg:flex lg:max-w-4xl lg:flex-col lg:before:flex-1 lg:before:pt-6">
<div className="pb-16 pt-20 sm:pb-20 sm:pt-32 lg:py-20">
<div className="relative pr-10">
<StarField className="-right-44 top-14" />
{main}
</div>
</div>
<div className="flex flex-1 items-end justify-center pb-4 lg:justify-start lg:pb-6">
{footer}
</div>
</div>
</div>
</div>
)
return (
<div className="relative flex-none overflow-hidden px-10 lg:pointer-events-none lg:fixed lg:inset-0 lg:z-40 lg:flex lg:px-0">
<Glow />
<div className="relative flex w-full lg:pointer-events-auto lg:mr-[calc(max(2rem,50%-35rem)+40rem)] lg:min-w-[32rem] lg:overflow-y-auto lg:overflow-x-hidden lg:pl-[max(4rem,calc(50%-38rem))]">
<div className="mx-auto max-w-lg lg:mx-auto lg:flex lg:max-w-4xl lg:flex-col lg:before:flex-1 lg:before:pt-6">
<div className="pb-16 pt-20 sm:pb-20 sm:pt-32 lg:py-20">
<div className="relative pr-10">
<StarField className="-right-44 top-14" />
{main}
</div>
</div>
<div className="flex flex-1 items-end justify-center pb-4 lg:justify-start lg:pb-6">
{footer}
</div>
</div>
</div>
</div>
);
}
export function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<FixedSidebar main={<Intro />} footer={<IntroFooter />} />
<div />
<div className="relative flex-auto">
<Timeline />
<main className="grid ml-auto grid-cols-12 col-span-5 ml-auto space-y-20 py-20 sm:space-y-32 sm:py-32">
{children}
</main>
</div>
</>
)
return (
<>
<FixedSidebar main={<Intro />} footer={<IntroFooter />} />
<div />
<div className="relative flex-auto">
<Timeline />
<main className="grid ml-auto grid-cols-12 col-span-5 ml-auto space-y-20 py-20 sm:space-y-32 sm:py-32">
{children}
</main>
</div>
</>
);
}

View File

@@ -1,130 +1,140 @@
import Link from 'next/link'
import Link from "next/link";
import { Button } from '@/components/ui/button'
import { useId } from 'react'
import { Button } from "@/components/ui/button";
import { useId } from "react";
import clsx from 'clsx'
import clsx from "clsx";
function BookIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 16 16" aria-hidden="true" fill="currentColor" {...props}>
<path d="M7 3.41a1 1 0 0 0-.668-.943L2.275 1.039a.987.987 0 0 0-.877.166c-.25.192-.398.493-.398.812V12.2c0 .454.296.853.725.977l3.948 1.365A1 1 0 0 0 7 13.596V3.41ZM9 13.596a1 1 0 0 0 1.327.946l3.948-1.365c.429-.124.725-.523.725-.977V2.017c0-.32-.147-.62-.398-.812a.987.987 0 0 0-.877-.166L9.668 2.467A1 1 0 0 0 9 3.41v10.186Z" />
</svg>
)
function BookIcon(props: React.ComponentPropsWithoutRef<"svg">) {
return (
<svg viewBox="0 0 16 16" aria-hidden="true" fill="currentColor" {...props}>
<path d="M7 3.41a1 1 0 0 0-.668-.943L2.275 1.039a.987.987 0 0 0-.877.166c-.25.192-.398.493-.398.812V12.2c0 .454.296.853.725.977l3.948 1.365A1 1 0 0 0 7 13.596V3.41ZM9 13.596a1 1 0 0 0 1.327.946l3.948-1.365c.429-.124.725-.523.725-.977V2.017c0-.32-.147-.62-.398-.812a.987.987 0 0 0-.877-.166L9.668 2.467A1 1 0 0 0 9 3.41v10.186Z" />
</svg>
);
}
function GitHubIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 16 16" aria-hidden="true" fill="currentColor" {...props}>
<path d="M8 .198a8 8 0 0 0-8 8 7.999 7.999 0 0 0 5.47 7.59c.4.076.547-.172.547-.384 0-.19-.007-.694-.01-1.36-2.226.482-2.695-1.074-2.695-1.074-.364-.923-.89-1.17-.89-1.17-.725-.496.056-.486.056-.486.803.056 1.225.824 1.225.824.714 1.224 1.873.87 2.33.666.072-.518.278-.87.507-1.07-1.777-.2-3.644-.888-3.644-3.954 0-.873.31-1.586.823-2.146-.09-.202-.36-1.016.07-2.118 0 0 .67-.214 2.2.82a7.67 7.67 0 0 1 2-.27 7.67 7.67 0 0 1 2 .27c1.52-1.034 2.19-.82 2.19-.82.43 1.102.16 1.916.08 2.118.51.56.82 1.273.82 2.146 0 3.074-1.87 3.75-3.65 3.947.28.24.54.73.54 1.48 0 1.07-.01 1.93-.01 2.19 0 .21.14.46.55.38A7.972 7.972 0 0 0 16 8.199a8 8 0 0 0-8-8Z" />
</svg>
)
function GitHubIcon(props: React.ComponentPropsWithoutRef<"svg">) {
return (
<svg viewBox="0 0 16 16" aria-hidden="true" fill="currentColor" {...props}>
<path d="M8 .198a8 8 0 0 0-8 8 7.999 7.999 0 0 0 5.47 7.59c.4.076.547-.172.547-.384 0-.19-.007-.694-.01-1.36-2.226.482-2.695-1.074-2.695-1.074-.364-.923-.89-1.17-.89-1.17-.725-.496.056-.486.056-.486.803.056 1.225.824 1.225.824.714 1.224 1.873.87 2.33.666.072-.518.278-.87.507-1.07-1.777-.2-3.644-.888-3.644-3.954 0-.873.31-1.586.823-2.146-.09-.202-.36-1.016.07-2.118 0 0 .67-.214 2.2.82a7.67 7.67 0 0 1 2-.27 7.67 7.67 0 0 1 2 .27c1.52-1.034 2.19-.82 2.19-.82.43 1.102.16 1.916.08 2.118.51.56.82 1.273.82 2.146 0 3.074-1.87 3.75-3.65 3.947.28.24.54.73.54 1.48 0 1.07-.01 1.93-.01 2.19 0 .21.14.46.55.38A7.972 7.972 0 0 0 16 8.199a8 8 0 0 0-8-8Z" />
</svg>
);
}
function FeedIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 16 16" aria-hidden="true" fill="currentColor" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2.5 3a.5.5 0 0 1 .5-.5h.5c5.523 0 10 4.477 10 10v.5a.5.5 0 0 1-.5.5h-.5a.5.5 0 0 1-.5-.5v-.5A8.5 8.5 0 0 0 3.5 4H3a.5.5 0 0 1-.5-.5V3Zm0 4.5A.5.5 0 0 1 3 7h.5A5.5 5.5 0 0 1 9 12.5v.5a.5.5 0 0 1-.5.5H8a.5.5 0 0 1-.5-.5v-.5a4 4 0 0 0-4-4H3a.5.5 0 0 1-.5-.5v-.5Zm0 5a1 1 0 1 1 2 0 1 1 0 0 1-2 0Z"
/>
</svg>
)
function FeedIcon(props: React.ComponentPropsWithoutRef<"svg">) {
return (
<svg viewBox="0 0 16 16" aria-hidden="true" fill="currentColor" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M2.5 3a.5.5 0 0 1 .5-.5h.5c5.523 0 10 4.477 10 10v.5a.5.5 0 0 1-.5.5h-.5a.5.5 0 0 1-.5-.5v-.5A8.5 8.5 0 0 0 3.5 4H3a.5.5 0 0 1-.5-.5V3Zm0 4.5A.5.5 0 0 1 3 7h.5A5.5 5.5 0 0 1 9 12.5v.5a.5.5 0 0 1-.5.5H8a.5.5 0 0 1-.5-.5v-.5a4 4 0 0 0-4-4H3a.5.5 0 0 1-.5-.5v-.5Zm0 5a1 1 0 1 1 2 0 1 1 0 0 1-2 0Z"
/>
</svg>
);
}
function XIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 16 16" aria-hidden="true" fill="currentColor" {...props}>
<path d="M9.51762 6.77491L15.3459 0H13.9648L8.90409 5.88256L4.86212 0H0.200195L6.31244 8.89547L0.200195 16H1.58139L6.92562 9.78782L11.1942 16H15.8562L9.51728 6.77491H9.51762ZM7.62588 8.97384L7.00658 8.08805L2.07905 1.03974H4.20049L8.17706 6.72795L8.79636 7.61374L13.9654 15.0075H11.844L7.62588 8.97418V8.97384Z" />
</svg>
)
function XIcon(props: React.ComponentPropsWithoutRef<"svg">) {
return (
<svg viewBox="0 0 16 16" aria-hidden="true" fill="currentColor" {...props}>
<path d="M9.51762 6.77491L15.3459 0H13.9648L8.90409 5.88256L4.86212 0H0.200195L6.31244 8.89547L0.200195 16H1.58139L6.92562 9.78782L11.1942 16H15.8562L9.51728 6.77491H9.51762ZM7.62588 8.97384L7.00658 8.08805L2.07905 1.03974H4.20049L8.17706 6.72795L8.79636 7.61374L13.9654 15.0075H11.844L7.62588 8.97418V8.97384Z" />
</svg>
);
}
export function Intro() {
return (
<>
<div className=''>
<Link href="/">
{/* <Logo className="inline-block h-8 w-auto" /> */}
</Link>
</div>
<h1 className="mt-14 font-sans font-semibold tracking-tighter text-5xl">
All of the changes made will be {' '}
<span className="">available here.</span>
</h1>
<p className="mt-4 text-sm text-gray-600 dark:text-gray-300">
Better Auth is advanced authentication library for typescript packed by customizable and extendible plugin ecosystem
</p>
<hr className='h-px bg-gray-300 mt-5' />
<div className="mt-8 flex flex-wrap text-gray-600 dark:text-gray-300 justify-center gap-x-1 gap-y-3 sm:gap-x-2 lg:justify-start">
<IconLink href="/docs" icon={BookIcon} className="flex-none text-gray-600 dark:text-gray-300">
Documentation
</IconLink>
<IconLink href="https://github.com/better-auth/better-auth" icon={GitHubIcon} className="flex-none text-gray-600 dark:text-gray-300">
GitHub
</IconLink>
<IconLink href="/feed.xml" icon={FeedIcon} className="flex-none text-gray-600 dark:text-gray-300">
RSS
</IconLink>
</div>
</>
)
return (
<>
<div className="">
<Link href="/">
{/* <Logo className="inline-block h-8 w-auto" /> */}
</Link>
</div>
<h1 className="mt-14 font-sans font-semibold tracking-tighter text-5xl">
All of the changes made will be{" "}
<span className="">available here.</span>
</h1>
<p className="mt-4 text-sm text-gray-600 dark:text-gray-300">
Better Auth is advanced authentication library for typescript packed by
customizable and extendible plugin ecosystem
</p>
<hr className="h-px bg-gray-300 mt-5" />
<div className="mt-8 flex flex-wrap text-gray-600 dark:text-gray-300 justify-center gap-x-1 gap-y-3 sm:gap-x-2 lg:justify-start">
<IconLink
href="/docs"
icon={BookIcon}
className="flex-none text-gray-600 dark:text-gray-300"
>
Documentation
</IconLink>
<IconLink
href="https://github.com/better-auth/better-auth"
icon={GitHubIcon}
className="flex-none text-gray-600 dark:text-gray-300"
>
GitHub
</IconLink>
<IconLink
href="/feed.xml"
icon={FeedIcon}
className="flex-none text-gray-600 dark:text-gray-300"
>
RSS
</IconLink>
</div>
</>
);
}
export function IntroFooter() {
return (
<p className="flex items-baseline gap-x-2 text-[0.8125rem]/6 text-gray-500">
Brought to you by{' '}
<IconLink href="#" icon={XIcon} compact>
BETTER-AUTH.
</IconLink>
</p>
)
return (
<p className="flex items-baseline gap-x-2 text-[0.8125rem]/6 text-gray-500">
Brought to you by{" "}
<IconLink href="#" icon={XIcon} compact>
BETTER-AUTH.
</IconLink>
</p>
);
}
export function SignUpForm() {
let id = useId()
let id = useId();
return (
<form className="relative isolate mt-8 flex items-center pr-1">
<label htmlFor={id} className="sr-only">
Email address
</label>
return (
<form className="relative isolate mt-8 flex items-center pr-1">
<label htmlFor={id} className="sr-only">
Email address
</label>
<div className="absolute inset-0 -z-10 rounded-lg transition peer-focus:ring-4 peer-focus:ring-sky-300/15" />
<div className="absolute inset-0 -z-10 rounded-lg bg-white/2.5 ring-1 ring-white/15 transition peer-focus:ring-sky-300" />
</form>
)
<div className="absolute inset-0 -z-10 rounded-lg transition peer-focus:ring-4 peer-focus:ring-sky-300/15" />
<div className="absolute inset-0 -z-10 rounded-lg bg-white/2.5 ring-1 ring-white/15 transition peer-focus:ring-sky-300" />
</form>
);
}
export function IconLink({
children,
className,
compact = false,
icon: Icon,
...props
children,
className,
compact = false,
icon: Icon,
...props
}: React.ComponentPropsWithoutRef<typeof Link> & {
compact?: boolean
icon?: React.ComponentType<{ className?: string }>
compact?: boolean;
icon?: React.ComponentType<{ className?: string }>;
}) {
return (
<Link
{...props}
className={clsx(
className,
'group relative isolate flex items-center rounded-lg px-2 py-0.5 text-[0.8125rem]/6 font-medium text-black/70 dark:text-white/30 transition-colors hover:text-stone-300',
compact ? 'gap-x-2' : 'gap-x-3',
)}
>
<span className="absolute inset-0 -z-10 scale-75 rounded-lg bg-white/5 opacity-0 transition group-hover:scale-100 group-hover:opacity-100" />
{Icon && <Icon className="h-4 w-4 flex-none" />}
<span className="self-baseline text-black/70 dark:text-white">{children}</span>
</Link>
)
return (
<Link
{...props}
className={clsx(
className,
"group relative isolate flex items-center rounded-lg px-2 py-0.5 text-[0.8125rem]/6 font-medium text-black/70 dark:text-white/30 transition-colors hover:text-stone-300",
compact ? "gap-x-2" : "gap-x-3",
)}
>
<span className="absolute inset-0 -z-10 scale-75 rounded-lg bg-white/5 opacity-0 transition group-hover:scale-100 group-hover:opacity-100" />
{Icon && <Icon className="h-4 w-4 flex-none" />}
<span className="self-baseline text-black/70 dark:text-white">
{children}
</span>
</Link>
);
}

View File

@@ -1,21 +1,25 @@
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const dateFormatter = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
timeZone: 'UTC',
})
const dateFormatter = new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "short",
day: "numeric",
timeZone: "UTC",
});
export function FormattedDate({
date,
...props
}: React.ComponentPropsWithoutRef<'time'> & { date: string | Date }) {
date = typeof date === 'string' ? new Date(date) : date
date,
...props
}: React.ComponentPropsWithoutRef<"time"> & { date: string | Date }) {
date = typeof date === "string" ? new Date(date) : date;
return (
<time className={cn(props.className , '')} dateTime={date.toISOString()} {...props}>
{dateFormatter.format(date)}
</time>
)
}
return (
<time
className={cn(props.className, "")}
dateTime={date.toISOString()}
{...props}
>
{dateFormatter.format(date)}
</time>
);
}

View File

@@ -1,221 +1,221 @@
'use client'
"use client";
import { useEffect, useId, useRef } from 'react'
import clsx from 'clsx'
import { type TimelineSegment, animate, timeline } from 'motion'
import { useEffect, useId, useRef } from "react";
import clsx from "clsx";
import { type TimelineSegment, animate, timeline } from "motion";
type Star = [x: number, y: number, dim?: boolean, blur?: boolean]
type Star = [x: number, y: number, dim?: boolean, blur?: boolean];
const stars: Array<Star> = [
[4, 4, true, true],
[4, 44, true],
[36, 22],
[50, 146, true, true],
[64, 43, true, true],
[76, 30, true],
[101, 116],
[140, 36, true],
[149, 134],
[162, 74, true],
[171, 96, true, true],
[210, 56, true, true],
[235, 90],
[275, 82, true, true],
[306, 6],
[307, 64, true, true],
[380, 68, true],
[380, 108, true, true],
[391, 148, true, true],
[405, 18, true],
[412, 86, true, true],
[426, 210, true, true],
[427, 56, true, true],
[538, 138],
[563, 88, true, true],
[611, 154, true, true],
[637, 150],
[651, 146, true],
[682, 70, true, true],
[683, 128],
[781, 82, true, true],
[785, 158, true],
[832, 146, true, true],
[852, 89],
]
[4, 4, true, true],
[4, 44, true],
[36, 22],
[50, 146, true, true],
[64, 43, true, true],
[76, 30, true],
[101, 116],
[140, 36, true],
[149, 134],
[162, 74, true],
[171, 96, true, true],
[210, 56, true, true],
[235, 90],
[275, 82, true, true],
[306, 6],
[307, 64, true, true],
[380, 68, true],
[380, 108, true, true],
[391, 148, true, true],
[405, 18, true],
[412, 86, true, true],
[426, 210, true, true],
[427, 56, true, true],
[538, 138],
[563, 88, true, true],
[611, 154, true, true],
[637, 150],
[651, 146, true],
[682, 70, true, true],
[683, 128],
[781, 82, true, true],
[785, 158, true],
[832, 146, true, true],
[852, 89],
];
const constellations: Array<Array<Star>> = [
[
[247, 103],
[261, 86],
[307, 104],
[357, 36],
],
[
[586, 120],
[516, 100],
[491, 62],
[440, 107],
[477, 180],
[516, 100],
],
[
[733, 100],
[803, 120],
[879, 113],
[823, 164],
[803, 120],
],
]
[
[247, 103],
[261, 86],
[307, 104],
[357, 36],
],
[
[586, 120],
[516, 100],
[491, 62],
[440, 107],
[477, 180],
[516, 100],
],
[
[733, 100],
[803, 120],
[879, 113],
[823, 164],
[803, 120],
],
];
function Star({
blurId,
point: [cx, cy, dim, blur],
blurId,
point: [cx, cy, dim, blur],
}: {
blurId: string
point: Star
blurId: string;
point: Star;
}) {
let groupRef = useRef<React.ElementRef<'g'>>(null)
let ref = useRef<React.ElementRef<'circle'>>(null)
let groupRef = useRef<React.ElementRef<"g">>(null);
let ref = useRef<React.ElementRef<"circle">>(null);
useEffect(() => {
if (!groupRef.current || !ref.current) {
return
}
useEffect(() => {
if (!groupRef.current || !ref.current) {
return;
}
let delay = Math.random() * 2
let delay = Math.random() * 2;
let animations = [
animate(groupRef.current, { opacity: 1 }, { duration: 4, delay }),
animate(
ref.current,
{
opacity: dim ? [0.2, 0.5] : [1, 0.6],
scale: dim ? [1, 1.2] : [1.2, 1],
},
{
delay,
duration: Math.random() * 2 + 2,
direction: 'alternate',
repeat: Infinity,
},
),
]
let animations = [
animate(groupRef.current, { opacity: 1 }, { duration: 4, delay }),
animate(
ref.current,
{
opacity: dim ? [0.2, 0.5] : [1, 0.6],
scale: dim ? [1, 1.2] : [1.2, 1],
},
{
delay,
duration: Math.random() * 2 + 2,
direction: "alternate",
repeat: Infinity,
},
),
];
return () => {
for (let animation of animations) {
animation.cancel()
}
}
}, [dim])
return () => {
for (let animation of animations) {
animation.cancel();
}
};
}, [dim]);
return (
<g ref={groupRef} className="opacity-0">
<circle
ref={ref}
cx={cx}
cy={cy}
r={1}
style={{
transformOrigin: `${cx / 16}rem ${cy / 16}rem`,
opacity: dim ? 0.2 : 1,
transform: `scale(${dim ? 1 : 1.2})`,
}}
filter={blur ? `url(#${blurId})` : undefined}
/>
</g>
)
return (
<g ref={groupRef} className="opacity-0">
<circle
ref={ref}
cx={cx}
cy={cy}
r={1}
style={{
transformOrigin: `${cx / 16}rem ${cy / 16}rem`,
opacity: dim ? 0.2 : 1,
transform: `scale(${dim ? 1 : 1.2})`,
}}
filter={blur ? `url(#${blurId})` : undefined}
/>
</g>
);
}
function Constellation({
points,
blurId,
points,
blurId,
}: {
points: Array<Star>
blurId: string
points: Array<Star>;
blurId: string;
}) {
let ref = useRef<React.ElementRef<'path'>>(null)
let uniquePoints = points.filter(
(point, pointIndex) =>
points.findIndex((p) => String(p) === String(point)) === pointIndex,
)
let isFilled = uniquePoints.length !== points.length
let ref = useRef<React.ElementRef<"path">>(null);
let uniquePoints = points.filter(
(point, pointIndex) =>
points.findIndex((p) => String(p) === String(point)) === pointIndex,
);
let isFilled = uniquePoints.length !== points.length;
useEffect(() => {
if (!ref.current) {
return
}
useEffect(() => {
if (!ref.current) {
return;
}
let sequence: Array<TimelineSegment> = [
[
ref.current,
{ strokeDashoffset: 0, visibility: 'visible' },
{ duration: 5, delay: Math.random() * 3 + 2 },
],
]
let sequence: Array<TimelineSegment> = [
[
ref.current,
{ strokeDashoffset: 0, visibility: "visible" },
{ duration: 5, delay: Math.random() * 3 + 2 },
],
];
if (isFilled) {
sequence.push([
ref.current,
{ fill: 'rgb(255 255 255 / 0.02)' },
{ duration: 1 },
])
}
if (isFilled) {
sequence.push([
ref.current,
{ fill: "rgb(255 255 255 / 0.02)" },
{ duration: 1 },
]);
}
let animation = timeline(sequence)
let animation = timeline(sequence);
return () => {
animation.cancel()
}
}, [isFilled])
return () => {
animation.cancel();
};
}, [isFilled]);
return (
<>
<path
ref={ref}
stroke="white"
strokeOpacity="0.2"
strokeDasharray={1}
strokeDashoffset={1}
pathLength={1}
fill="transparent"
d={`M ${points.join('L')}`}
className="invisible"
/>
{uniquePoints.map((point, pointIndex) => (
<Star key={pointIndex} point={point} blurId={blurId} />
))}
</>
)
return (
<>
<path
ref={ref}
stroke="white"
strokeOpacity="0.2"
strokeDasharray={1}
strokeDashoffset={1}
pathLength={1}
fill="transparent"
d={`M ${points.join("L")}`}
className="invisible"
/>
{uniquePoints.map((point, pointIndex) => (
<Star key={pointIndex} point={point} blurId={blurId} />
))}
</>
);
}
export function StarField({ className }: { className?: string }) {
let blurId = useId()
let blurId = useId();
return (
<svg
viewBox="0 0 881 211"
fill="white"
aria-hidden="true"
className={clsx(
'pointer-events-none absolute w-[55.0625rem] origin-top-right rotate-[30deg] overflow-visible opacity-70',
className,
)}
>
<defs>
<filter id={blurId}>
<feGaussianBlur in="SourceGraphic" stdDeviation=".5" />
</filter>
</defs>
{constellations.map((points, constellationIndex) => (
<Constellation
key={constellationIndex}
points={points}
blurId={blurId}
/>
))}
{stars.map((point, pointIndex) => (
<Star key={pointIndex} point={point} blurId={blurId} />
))}
</svg>
)
return (
<svg
viewBox="0 0 881 211"
fill="white"
aria-hidden="true"
className={clsx(
"pointer-events-none absolute w-[55.0625rem] origin-top-right rotate-[30deg] overflow-visible opacity-70",
className,
)}
>
<defs>
<filter id={blurId}>
<feGaussianBlur in="SourceGraphic" stdDeviation=".5" />
</filter>
</defs>
{constellations.map((points, constellationIndex) => (
<Constellation
key={constellationIndex}
points={points}
blurId={blurId}
/>
))}
{stars.map((point, pointIndex) => (
<Star key={pointIndex} point={point} blurId={blurId} />
))}
</svg>
);
}

View File

@@ -5,29 +5,29 @@ const listOfFeatures = ["The first better-auth public beta release"];
const bugFixes = [""];
const ChangelogOne = () => {
return (
<AnimatePresence>
<div className="flex flex-col gap-4 items-start justify-center max-w-full md:max-w-2xl">
<div className="flex flex-col gap-2">
<h2 className="text-2xl font-bold tracking-tighter">
Public Beta Release
</h2>
<p>
The first public beta release of better-auth is now available. This
release includes a lot of new features and improvements.
</p>
</div>
<p className="text-gray-600 dark:text-gray-300 text-[0.855rem]"></p>
<div className="flex flex-col gap-2">
<h4 className="text-xl tracking-tighter">Features</h4>
</div>
<ul className="list-disc ml-10 text-[0.855rem] text-gray-600 dark:text-gray-300">
{listOfFeatures.map((change, i) => (
<li key={i}>{change}</li>
))}
</ul>
</div>
</AnimatePresence>
);
return (
<AnimatePresence>
<div className="flex flex-col gap-4 items-start justify-center max-w-full md:max-w-2xl">
<div className="flex flex-col gap-2">
<h2 className="text-2xl font-bold tracking-tighter">
Public Beta Release
</h2>
<p>
The first public beta release of better-auth is now available. This
release includes a lot of new features and improvements.
</p>
</div>
<p className="text-gray-600 dark:text-gray-300 text-[0.855rem]"></p>
<div className="flex flex-col gap-2">
<h4 className="text-xl tracking-tighter">Features</h4>
</div>
<ul className="list-disc ml-10 text-[0.855rem] text-gray-600 dark:text-gray-300">
{listOfFeatures.map((change, i) => (
<li key={i}>{change}</li>
))}
</ul>
</div>
</AnimatePresence>
);
};
export default ChangelogOne;

View File

@@ -1,8 +1,8 @@
import ChangelogOne from "./2024-09-28";
export const Logs = [
{
name: "Changelog 1",
date: "2024-09-28",
component: ChangelogOne,
},
{
name: "Changelog 1",
date: "2024-09-28",
component: ChangelogOne,
},
];

View File

@@ -5,108 +5,108 @@ import { Intro, IntroFooter } from "./_components/changelog-layout";
import { StarField } from "./_components/stat-field";
function Timeline() {
let id = useId();
let id = useId();
return (
<div className="pointer-events-none absolute inset-0 z-50 overflow-hidden lg:right-[calc(max(2rem,50%-38rem)+40rem)] lg:min-w-[32rem] lg:overflow-visible">
<svg
className="absolute left-[max(0px,calc(50%-18.125rem))] top-0 h-full w-1.5 lg:left-full lg:ml-1 xl:left-auto xl:right-1 xl:ml-0"
aria-hidden="true"
>
<defs>
<pattern id={id} width="6" height="8" patternUnits="userSpaceOnUse">
<path
d="M0 0H6M0 8H6"
className="stroke-sky-900/10 xl:stroke-white/10 dark:stroke-white/10"
fill="none"
/>
</pattern>
</defs>
<rect width="100%" height="100%" fill={`url(#${id})`} />
</svg>
</div>
);
return (
<div className="pointer-events-none absolute inset-0 z-50 overflow-hidden lg:right-[calc(max(2rem,50%-38rem)+40rem)] lg:min-w-[32rem] lg:overflow-visible">
<svg
className="absolute left-[max(0px,calc(50%-18.125rem))] top-0 h-full w-1.5 lg:left-full lg:ml-1 xl:left-auto xl:right-1 xl:ml-0"
aria-hidden="true"
>
<defs>
<pattern id={id} width="6" height="8" patternUnits="userSpaceOnUse">
<path
d="M0 0H6M0 8H6"
className="stroke-sky-900/10 xl:stroke-white/10 dark:stroke-white/10"
fill="none"
/>
</pattern>
</defs>
<rect width="100%" height="100%" fill={`url(#${id})`} />
</svg>
</div>
);
}
function Glow() {
let id = useId();
let id = useId();
return (
<div className="absolute inset-0 -z-10 overflow-hidden bg-gradient-to-tr from-transparent via-stone-950/5 to-transparent/10 lg:right-[calc(max(2rem,50%-38rem)+40rem)] lg:min-w-[32rem]">
<svg
className="absolute -bottom-48 left-[-40%] h-[80rem] w-[180%] lg:-right-40 lg:bottom-auto lg:left-auto lg:top-[-40%] lg:h-[180%] lg:w-[80rem]"
aria-hidden="true"
>
<defs>
<radialGradient id={`${id}-desktop`} cx="100%">
<stop offset="0%" stopColor="rgba(41, 37, 36, 0.4)" />
<stop offset="53.95%" stopColor="rgba(28, 25, 23, 0.09)" />
<stop offset="100%" stopColor="rgba(0, 0, 0, 0)" />
</radialGradient>
<radialGradient id={`${id}-mobile`} cy="100%">
<stop offset="0%" stopColor="rgba(41, 37, 36, 0.3)" />
<stop offset="53.95%" stopColor="rgba(28, 25, 23, 0.09)" />
<stop offset="100%" stopColor="rgba(0, 0, 0, 0)" />
</radialGradient>
</defs>
<rect
width="100%"
height="100%"
fill={`url(#${id}-desktop)`}
className="hidden lg:block"
/>
<rect
width="100%"
height="100%"
fill={`url(#${id}-mobile)`}
className="lg:hidden"
/>
</svg>
<div className="absolute inset-x-0 bottom-0 right-0 h-px bg-white/5 mix-blend-overlay lg:left-auto lg:top-0 lg:h-auto lg:w-px" />
</div>
);
return (
<div className="absolute inset-0 -z-10 overflow-hidden bg-gradient-to-tr from-transparent via-stone-950/5 to-transparent/10 lg:right-[calc(max(2rem,50%-38rem)+40rem)] lg:min-w-[32rem]">
<svg
className="absolute -bottom-48 left-[-40%] h-[80rem] w-[180%] lg:-right-40 lg:bottom-auto lg:left-auto lg:top-[-40%] lg:h-[180%] lg:w-[80rem]"
aria-hidden="true"
>
<defs>
<radialGradient id={`${id}-desktop`} cx="100%">
<stop offset="0%" stopColor="rgba(41, 37, 36, 0.4)" />
<stop offset="53.95%" stopColor="rgba(28, 25, 23, 0.09)" />
<stop offset="100%" stopColor="rgba(0, 0, 0, 0)" />
</radialGradient>
<radialGradient id={`${id}-mobile`} cy="100%">
<stop offset="0%" stopColor="rgba(41, 37, 36, 0.3)" />
<stop offset="53.95%" stopColor="rgba(28, 25, 23, 0.09)" />
<stop offset="100%" stopColor="rgba(0, 0, 0, 0)" />
</radialGradient>
</defs>
<rect
width="100%"
height="100%"
fill={`url(#${id}-desktop)`}
className="hidden lg:block"
/>
<rect
width="100%"
height="100%"
fill={`url(#${id}-mobile)`}
className="lg:hidden"
/>
</svg>
<div className="absolute inset-x-0 bottom-0 right-0 h-px bg-white/5 mix-blend-overlay lg:left-auto lg:top-0 lg:h-auto lg:w-px" />
</div>
);
}
function FixedSidebar({
main,
footer,
main,
footer,
}: {
main: React.ReactNode;
footer: React.ReactNode;
main: React.ReactNode;
footer: React.ReactNode;
}) {
return (
<div className="relative flex-none overflow-hidden px-10 lg:pointer-events-none md:fixed lg:inset-0 lg:z-40 lg:flex lg:px-0">
<Glow />
<div className="relative flex w-full lg:pointer-events-auto lg:mr-[calc(max(2rem,50%-35rem)+40rem)] lg:min-w-[32rem] lg:overflow-y-auto lg:overflow-x-hidden lg:pl-[max(4rem,calc(50%-44rem))]">
<div className="mx-auto pr-20 max-w-lg lg:mx-auto lg:flex lg:max-w-4xl lg:flex-col lg:before:flex-1 lg:before:pt-6">
<div className="pb-16 pt-20 sm:pb-20 sm:pt-32 lg:py-20">
<div className="relative ">
<StarField className="-right-44 top-14" />
{main}
</div>
</div>
<div className="flex flex-1 items-end justify-center pb-4 lg:justify-start lg:pb-6">
{footer}
</div>
</div>
</div>
</div>
);
return (
<div className="relative flex-none overflow-hidden px-10 lg:pointer-events-none md:fixed lg:inset-0 lg:z-40 lg:flex lg:px-0">
<Glow />
<div className="relative flex w-full lg:pointer-events-auto lg:mr-[calc(max(2rem,50%-35rem)+40rem)] lg:min-w-[32rem] lg:overflow-y-auto lg:overflow-x-hidden lg:pl-[max(4rem,calc(50%-44rem))]">
<div className="mx-auto pr-20 max-w-lg lg:mx-auto lg:flex lg:max-w-4xl lg:flex-col lg:before:flex-1 lg:before:pt-6">
<div className="pb-16 pt-20 sm:pb-20 sm:pt-32 lg:py-20">
<div className="relative ">
<StarField className="-right-44 top-14" />
{main}
</div>
</div>
<div className="flex flex-1 items-end justify-center pb-4 lg:justify-start lg:pb-6">
{footer}
</div>
</div>
</div>
</div>
);
}
const ChangeLogLayout = ({ children }: { children: React.ReactNode }) => {
return (
<div className="h-full font-sans overflow-y-auto">
<FixedSidebar main={<Intro />} footer={<IntroFooter />} />
<div />
<div className="relative overflow-y-auto flex gap-2 justify-start items-start">
<Timeline />
<div className="space-y-20 py-20 w-[80%] mx-auto md:mx-0 md:ml-auto md:w-1/2 h-screen sm:space-y-20 sm:py-20">
{children}
</div>
</div>
</div>
);
return (
<div className="h-full font-sans overflow-y-auto">
<FixedSidebar main={<Intro />} footer={<IntroFooter />} />
<div />
<div className="relative overflow-y-auto flex gap-2 justify-start items-start">
<Timeline />
<div className="space-y-20 py-20 w-[80%] mx-auto md:mx-0 md:ml-auto md:w-1/2 h-screen sm:space-y-20 sm:py-20">
{children}
</div>
</div>
</div>
);
};
export default ChangeLogLayout;

View File

@@ -2,24 +2,24 @@ import { AnimatePresence } from "@/components/ui/fade-in";
import { Logs } from "./_logs";
import { FormattedDate } from "./_components/fmt-dates";
const ChangelogPage = () => {
return (
<div>
<div className="mt-10 overflow-visible h-full flex flex-col gap-10">
{Logs.map((log) => {
return (
<div className="relative my-5 h-auto">
<div className="sticky top-2 flex-1 h-full">
<FormattedDate
className="absolute md:-left-32 left-0 text-sm -top-8 md:top-0 font-light"
date={log.date}
/>
</div>
<log.component />
</div>
);
})}
</div>
</div>
);
return (
<div>
<div className="mt-10 overflow-visible h-full flex flex-col gap-10">
{Logs.map((log) => {
return (
<div className="relative my-5 h-auto">
<div className="sticky top-2 flex-1 h-full">
<FormattedDate
className="absolute md:-left-32 left-0 text-sm -top-8 md:top-0 font-light"
date={log.date}
/>
</div>
<log.component />
</div>
);
})}
</div>
</div>
);
};
export default ChangelogPage;

View File

@@ -4,14 +4,14 @@ import { docsOptions } from "../layout.config";
import ArticleLayout from "@/components/side-bar";
export default function Layout({ children }: { children: ReactNode }) {
return (
<DocsLayout
{...docsOptions}
sidebar={{
component: <ArticleLayout />,
}}
>
{children}
</DocsLayout>
);
return (
<DocsLayout
{...docsOptions}
sidebar={{
component: <ArticleLayout />,
}}
>
{children}
</DocsLayout>
);
}

View File

@@ -9,45 +9,45 @@ import { baseUrl, createMetadata } from "@/lib/metadata";
import { Banner } from "fumadocs-ui/components/banner";
import Link from "next/link";
export const metadata = createMetadata({
title: {
template: "%s | Better Auth",
default: "Better Auth",
},
description: "The authentication library for typescript",
metadataBase: baseUrl,
title: {
template: "%s | Better Auth",
default: "Better Auth",
},
description: "The authentication library for typescript",
metadataBase: baseUrl,
});
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<link rel="icon" href="/favicon/favicon.ico" sizes="any" />
</head>
<body
className={`${GeistSans.variable} ${GeistMono.variable} font-sans overflow-x-hidden`}
>
<Banner
id="public-beta"
className="lg:text-sm tracking-tight text-xs hidden md:flex bg-gradient-to-tr from-white to-stone-100 border dark:from-stone-900 dark:to-stone-950"
>
🚧 Heads up! We're still in beta. It isn't quite production-ready just
yet. If you run into any bugs or quirks, please report them on{" "}
<Link
target="_blank"
className="mx-1 underline pb-px hover:opacity-80 transition-all"
href="https://github.com/better-auth/better-auth/issues"
>
{" "}
Github.
</Link>{" "}
</Banner>
<RootProvider>
<NavbarProvider>
<Navbar />
{children}
</NavbarProvider>
</RootProvider>
</body>
</html>
);
return (
<html lang="en" suppressHydrationWarning>
<head>
<link rel="icon" href="/favicon/favicon.ico" sizes="any" />
</head>
<body
className={`${GeistSans.variable} ${GeistMono.variable} font-sans overflow-x-hidden`}
>
<Banner
id="public-beta"
className="lg:text-sm tracking-tight text-xs hidden md:flex bg-gradient-to-tr from-white to-stone-100 border dark:from-stone-900 dark:to-stone-950"
>
🚧 Heads up! We're still in beta. It isn't quite production-ready just
yet. If you run into any bugs or quirks, please report them on{" "}
<Link
target="_blank"
className="mx-1 underline pb-px hover:opacity-80 transition-all"
href="https://github.com/better-auth/better-auth/issues"
>
{" "}
Github.
</Link>{" "}
</Banner>
<RootProvider>
<NavbarProvider>
<Navbar />
{children}
</NavbarProvider>
</RootProvider>
</body>
</html>
);
}

View File

@@ -13,8 +13,7 @@ export default function HomePage() {
>
<Hero />
<Features />
<hr className="h-px bg-gray-200"/>
<hr className="h-px bg-gray-200" />
</Section>
</main>
);

View File

@@ -1,11 +1,11 @@
import badgestyle from './badge.module.css'
import badgestyle from "./badge.module.css";
export const PulicBetaBadge = ({ text }: { text?: string }) => {
return (
<div className={badgestyle.beta}>
<span className={badgestyle.top_key}></span>
<span className={badgestyle.text}>{text || "BETA"}</span>
<span className={badgestyle.bottom_key_1}></span>
<span className={badgestyle.bottom_key_2}></span>
</div>
)
}
return (
<div className={badgestyle.beta}>
<span className={badgestyle.top_key}></span>
<span className={badgestyle.text}>{text || "BETA"}</span>
<span className={badgestyle.bottom_key_1}></span>
<span className={badgestyle.bottom_key_2}></span>
</div>
);
};

View File

@@ -2,135 +2,135 @@ import React from "react";
import { useId } from "react";
export function Features() {
return (
<div className="py-2">
<div className="mt-2 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-10 md:gap-2 max-w-7xl mx-auto">
{grid.map((feature, i) => (
<div
key={feature.title}
className="relative bg-gradient-to-b dark:from-neutral-900 from-neutral-100 dark:to-neutral-950 to-white px-6 py-2 overflow-hidden"
>
<Grid size={i * 5 + 10} />
<p className="text-base font-bold text-neutral-800 dark:text-white relative z-20">
{feature.title}
</p>
<p className="text-neutral-600 dark:text-neutral-400 text-base font-normal relative z-20">
{feature.description}
</p>
</div>
))}
</div>
</div>
);
return (
<div className="py-2">
<div className="mt-2 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-10 md:gap-2 max-w-7xl mx-auto">
{grid.map((feature, i) => (
<div
key={feature.title}
className="relative bg-gradient-to-b dark:from-neutral-900 from-neutral-100 dark:to-neutral-950 to-white px-6 py-2 overflow-hidden"
>
<Grid size={i * 5 + 10} />
<p className="text-base font-bold text-neutral-800 dark:text-white relative z-20">
{feature.title}
</p>
<p className="text-neutral-600 dark:text-neutral-400 text-base font-normal relative z-20">
{feature.description}
</p>
</div>
))}
</div>
</div>
);
}
const grid = [
{
title: "Framework Agnostic",
description: "Support for most popular frameworks",
},
{
title: "Email & Password",
description:
"Built-in support for secure email and password authentication",
},
{
title: "Account & Session Management",
description: "Manage user accounts and sessions with ease",
},
{
title: "Built In Rate Limiter",
description: "Built in rate limiter with custom rules",
},
{
title: "Automatic Database Management",
description: "Automatic database management and migrations",
},
{
title: "Social Sign-on",
description: "multiple social sign-on providers",
},
{
title: "Organization & Access Control",
description: "Manage organizations and access control",
},
{
title: "Two Factor Authentication",
description: "Secure your users with two factor authentication",
},
{
title: "Plugin Ecosystem",
description: "Even more capabilities with plugins",
},
{
title: "Framework Agnostic",
description: "Support for most popular frameworks",
},
{
title: "Email & Password",
description:
"Built-in support for secure email and password authentication",
},
{
title: "Account & Session Management",
description: "Manage user accounts and sessions with ease",
},
{
title: "Built In Rate Limiter",
description: "Built in rate limiter with custom rules",
},
{
title: "Automatic Database Management",
description: "Automatic database management and migrations",
},
{
title: "Social Sign-on",
description: "multiple social sign-on providers",
},
{
title: "Organization & Access Control",
description: "Manage organizations and access control",
},
{
title: "Two Factor Authentication",
description: "Secure your users with two factor authentication",
},
{
title: "Plugin Ecosystem",
description: "Even more capabilities with plugins",
},
];
export const Grid = ({
pattern,
size,
pattern,
size,
}: {
pattern?: number[][];
size?: number;
pattern?: number[][];
size?: number;
}) => {
const p = pattern ?? [
[Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1],
[Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1],
[Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1],
[Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1],
[Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1],
];
return (
<div className="pointer-events-none absolute left-1/2 top-0 -ml-20 -mt-2 h-full w-full [mask-image:linear-gradient(white,transparent)]">
<div className="absolute inset-0 bg-gradient-to-r [mask-image:radial-gradient(farthest-side_at_top,white,transparent)] dark:from-zinc-900/30 from-zinc-100/30 to-zinc-300/30 dark:to-zinc-900/30 opacity-100">
<GridPattern
width={size ?? 20}
height={size ?? 20}
x="-12"
y="4"
squares={p}
className="absolute inset-0 h-full w-full mix-blend-overlay dark:fill-white/10 dark:stroke-white/10 stroke-black/10 fill-black/10"
/>
</div>
</div>
);
const p = pattern ?? [
[Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1],
[Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1],
[Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1],
[Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1],
[Math.floor(Math.random() * 4) + 7, Math.floor(Math.random() * 6) + 1],
];
return (
<div className="pointer-events-none absolute left-1/2 top-0 -ml-20 -mt-2 h-full w-full [mask-image:linear-gradient(white,transparent)]">
<div className="absolute inset-0 bg-gradient-to-r [mask-image:radial-gradient(farthest-side_at_top,white,transparent)] dark:from-zinc-900/30 from-zinc-100/30 to-zinc-300/30 dark:to-zinc-900/30 opacity-100">
<GridPattern
width={size ?? 20}
height={size ?? 20}
x="-12"
y="4"
squares={p}
className="absolute inset-0 h-full w-full mix-blend-overlay dark:fill-white/10 dark:stroke-white/10 stroke-black/10 fill-black/10"
/>
</div>
</div>
);
};
export function GridPattern({ width, height, x, y, squares, ...props }: any) {
const patternId = useId();
const patternId = useId();
return (
<svg aria-hidden="true" {...props}>
<defs>
<pattern
id={patternId}
width={width}
height={height}
patternUnits="userSpaceOnUse"
x={x}
y={y}
>
<path d={`M.5 ${height}V.5H${width}`} fill="none" />
</pattern>
</defs>
<rect
width="100%"
height="100%"
strokeWidth={0}
fill={`url(#${patternId})`}
/>
{squares && (
<svg x={x} y={y} className="overflow-visible">
{squares.map(([x, y]: any) => (
<rect
strokeWidth="0"
key={`${x}-${y}`}
width={width + 1}
height={height + 1}
x={x * width}
y={y * height}
/>
))}
</svg>
)}
</svg>
);
return (
<svg aria-hidden="true" {...props}>
<defs>
<pattern
id={patternId}
width={width}
height={height}
patternUnits="userSpaceOnUse"
x={x}
y={y}
>
<path d={`M.5 ${height}V.5H${width}`} fill="none" />
</pattern>
</defs>
<rect
width="100%"
height="100%"
strokeWidth={0}
fill={`url(#${patternId})`}
/>
{squares && (
<svg x={x} y={y} className="overflow-visible">
{squares.map(([x, y]: any) => (
<rect
strokeWidth="0"
key={`${x}-${y}`}
width={width + 1}
height={height + 1}
x={x * width}
y={y * height}
/>
))}
</svg>
)}
</svg>
);
}

View File

@@ -1,42 +1,42 @@
import { cn } from "@/lib/utils";
import { techStackIcons } from "./techstack-icons";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
export const TechStackDisplay = ({
skills,
className,
skills,
className,
}: {
skills: string[];
className?: string;
skills: string[];
className?: string;
}) => {
return (
<div
className={cn(
"flex gap-7 flex-wrap mt-3 justify-center items-center max-w-4xl",
className
)}
>
{skills.map((icon) => {
return (
<TooltipProvider key={icon}>
<Tooltip>
<TooltipTrigger asChild>
<span className="transform duration-300 hover:rotate-12 transition-transform">
{techStackIcons[icon].icon}
</span>
</TooltipTrigger>
<TooltipContent className="text-white/80 bg-gradient-to-tr from-black/80 via-black to-black/90 z-1">
{techStackIcons[icon].name}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
})}
</div>
);
return (
<div
className={cn(
"flex gap-7 flex-wrap mt-3 justify-center items-center max-w-4xl",
className,
)}
>
{skills.map((icon) => {
return (
<TooltipProvider key={icon}>
<Tooltip>
<TooltipTrigger asChild>
<span className="transform duration-300 hover:rotate-12 transition-transform">
{techStackIcons[icon].icon}
</span>
</TooltipTrigger>
<TooltipContent className="text-white/80 bg-gradient-to-tr from-black/80 via-black to-black/90 z-1">
{techStackIcons[icon].name}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
})}
</div>
);
};

Some files were not shown because too many files have changed in this diff Show More