style: style the code according to Prettier rules
This commit is contained in:
parent
fe3ab6cdf1
commit
7bb89ce202
125 changed files with 5263 additions and 5263 deletions
|
@ -1,7 +1,7 @@
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Admin // Changelogs",
|
title: "Admin // Changelogs"
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function logPages({ children }: { children: React.ReactNode }) {
|
export default function logPages({ children }: { children: React.ReactNode }) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
|
@ -19,7 +19,7 @@ import {
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { logsSchema } from "@/lib/validations/validation";
|
import { logsSchema } from "@/lib/validations/validation";
|
||||||
|
@ -46,13 +46,13 @@ const AdminLogPage = () => {
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
version: "",
|
version: "",
|
||||||
date: "",
|
date: "",
|
||||||
bullets: [{ point: "" }],
|
bullets: [{ point: "" }]
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control: form.control,
|
control: form.control,
|
||||||
name: "bullets",
|
name: "bullets"
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchLogs = async () => {
|
const fetchLogs = async () => {
|
||||||
|
@ -74,7 +74,7 @@ const AdminLogPage = () => {
|
||||||
const response = await fetch("/api/uploadlogs", {
|
const response = await fetch("/api/uploadlogs", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -91,7 +91,7 @@ const AdminLogPage = () => {
|
||||||
const deleteLog = async (id: string) => {
|
const deleteLog = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/delete/logs/${id}`, {
|
const response = await fetch(`/api/delete/logs/${id}`, {
|
||||||
method: "DELETE",
|
method: "DELETE"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
fetchLogs();
|
fetchLogs();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Admin // Downloads",
|
title: "Admin // Downloads"
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function logPages({ children }: { children: React.ReactNode }) {
|
export default function logPages({ children }: { children: React.ReactNode }) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { UploadButton } from "@/lib/uploadthing";
|
import { UploadButton } from "@/lib/uploadthing";
|
||||||
|
@ -23,7 +23,7 @@ import {
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
|
|
||||||
interface DownloadEntry {
|
interface DownloadEntry {
|
||||||
|
@ -46,14 +46,14 @@ const DownloadsPage = () => {
|
||||||
fileName: "",
|
fileName: "",
|
||||||
version: "",
|
version: "",
|
||||||
downloadLink: "",
|
downloadLink: "",
|
||||||
fileSize: "",
|
fileSize: ""
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchDownloads = async () => {
|
const fetchDownloads = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/downloads", {
|
const response = await fetch("/api/downloads", {
|
||||||
method: "GET",
|
method: "GET"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: DownloadEntry[] = await response.json();
|
const data: DownloadEntry[] = await response.json();
|
||||||
|
@ -82,9 +82,9 @@ const DownloadsPage = () => {
|
||||||
const response = await fetch("/api/upload", {
|
const response = await fetch("/api/upload", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json"
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -102,7 +102,7 @@ const DownloadsPage = () => {
|
||||||
const deleteDownload = async (id: string) => {
|
const deleteDownload = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/delete/downloads/${id}`, {
|
const response = await fetch(`/api/delete/downloads/${id}`, {
|
||||||
method: "DELETE",
|
method: "DELETE"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
fetchDownloads();
|
fetchDownloads();
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import {
|
import {
|
||||||
Pagination,
|
Pagination,
|
||||||
|
@ -17,7 +17,7 @@ import {
|
||||||
PaginationItem,
|
PaginationItem,
|
||||||
PaginationLink,
|
PaginationLink,
|
||||||
PaginationNext,
|
PaginationNext,
|
||||||
PaginationPrevious,
|
PaginationPrevious
|
||||||
} from "@/components/ui/pagination";
|
} from "@/components/ui/pagination";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ const EmailPage = () => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast({
|
toast({
|
||||||
title: "Error fetching subscribers",
|
title: "Error fetching subscribers",
|
||||||
description: `${error}`,
|
description: `${error}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ import MobileNav from "../_components/Mobilenav";
|
||||||
import Sidebar from "../_components/Sidebar";
|
import Sidebar from "../_components/Sidebar";
|
||||||
|
|
||||||
export default function PageLayout({
|
export default function PageLayout({
|
||||||
children,
|
children
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Admin // Mods",
|
title: "Admin // Mods"
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function logPages({ children }: { children: React.ReactNode }) {
|
export default function logPages({ children }: { children: React.ReactNode }) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { UploadButton } from "@/lib/uploadthing";
|
import { UploadButton } from "@/lib/uploadthing";
|
||||||
|
@ -23,13 +23,13 @@ import {
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
|
|
||||||
interface ModEntry {
|
interface ModEntry {
|
||||||
|
@ -54,8 +54,8 @@ const SvrjsModsAdminPage = () => {
|
||||||
fileName: "",
|
fileName: "",
|
||||||
version: "",
|
version: "",
|
||||||
downloadLink: "",
|
downloadLink: "",
|
||||||
fileSize: "",
|
fileSize: ""
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const dialogForm = useForm<z.infer<typeof modsSchema>>({
|
const dialogForm = useForm<z.infer<typeof modsSchema>>({
|
||||||
|
@ -64,8 +64,8 @@ const SvrjsModsAdminPage = () => {
|
||||||
fileName: "",
|
fileName: "",
|
||||||
version: "",
|
version: "",
|
||||||
downloadLink: "",
|
downloadLink: "",
|
||||||
fileSize: "",
|
fileSize: ""
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -83,7 +83,7 @@ const SvrjsModsAdminPage = () => {
|
||||||
fileName: editMod.fileName,
|
fileName: editMod.fileName,
|
||||||
version: editMod.version,
|
version: editMod.version,
|
||||||
downloadLink: editMod.downloadLink,
|
downloadLink: editMod.downloadLink,
|
||||||
fileSize: editMod.fileSize,
|
fileSize: editMod.fileSize
|
||||||
});
|
});
|
||||||
setDialogOpen(true); // Open dialog when a mod is being edited
|
setDialogOpen(true); // Open dialog when a mod is being edited
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ const SvrjsModsAdminPage = () => {
|
||||||
const fetchMods = async () => {
|
const fetchMods = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/mods", {
|
const response = await fetch("/api/mods", {
|
||||||
method: "GET",
|
method: "GET"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: ModEntry[] = await response.json();
|
const data: ModEntry[] = await response.json();
|
||||||
|
@ -112,16 +112,16 @@ const SvrjsModsAdminPage = () => {
|
||||||
? await fetch(`/api/update/mods/${editMod._id}`, {
|
? await fetch(`/api/update/mods/${editMod._id}`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json"
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data)
|
||||||
})
|
})
|
||||||
: await fetch("/api/uploadmods", {
|
: await fetch("/api/uploadmods", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json"
|
||||||
},
|
},
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -132,14 +132,14 @@ const SvrjsModsAdminPage = () => {
|
||||||
setEditMod(null);
|
setEditMod(null);
|
||||||
setDialogOpen(false); // Close dialog on successful submission
|
setDialogOpen(false); // Close dialog on successful submission
|
||||||
toast({
|
toast({
|
||||||
description: "Successfully Saved Changes",
|
description: "Successfully Saved Changes"
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.error("Save failed");
|
console.error("Save failed");
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
toast({
|
toast({
|
||||||
description: "Save failed",
|
description: "Save failed",
|
||||||
variant: "destructive",
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -147,7 +147,7 @@ const SvrjsModsAdminPage = () => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
toast({
|
toast({
|
||||||
description: "Save failed",
|
description: "Save failed",
|
||||||
variant: "destructive",
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -155,7 +155,7 @@ const SvrjsModsAdminPage = () => {
|
||||||
const deleteMod = async (id: string) => {
|
const deleteMod = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/delete/mods/${id}`, {
|
const response = await fetch(`/api/delete/mods/${id}`, {
|
||||||
method: "DELETE",
|
method: "DELETE"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
fetchMods();
|
fetchMods();
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Button } from "@/components/ui/button";
|
||||||
import { useToast } from "@/components/ui/use-toast";
|
import { useToast } from "@/components/ui/use-toast";
|
||||||
|
|
||||||
const MarkdownEditor = dynamic(() => import("@uiw/react-md-editor"), {
|
const MarkdownEditor = dynamic(() => import("@uiw/react-md-editor"), {
|
||||||
ssr: false,
|
ssr: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const EditPage = ({ params }: { params: { slug: string } }) => {
|
const EditPage = ({ params }: { params: { slug: string } }) => {
|
||||||
|
@ -37,7 +37,7 @@ const EditPage = ({ params }: { params: { slug: string } }) => {
|
||||||
const response = await fetch(`/api/mdx/pages/${slug}`, {
|
const response = await fetch(`/api/mdx/pages/${slug}`, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ title, content, vulnerabilities }),
|
body: JSON.stringify({ title, content, vulnerabilities })
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Admin // MultiLogs",
|
title: "Admin // MultiLogs"
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function logPages({ children }: { children: React.ReactNode }) {
|
export default function logPages({ children }: { children: React.ReactNode }) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
@ -17,7 +17,7 @@ import {
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogTitle,
|
DialogTitle
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
|
|
||||||
interface PageEntry {
|
interface PageEntry {
|
||||||
|
@ -47,7 +47,7 @@ const MultiLogs = () => {
|
||||||
const response = await fetch("/api/mdx/pages", {
|
const response = await fetch("/api/mdx/pages", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ title: pageTitle, slug, content: "" }),
|
body: JSON.stringify({ title: pageTitle, slug, content: "" })
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -68,7 +68,7 @@ const MultiLogs = () => {
|
||||||
const deletePage = async (slug: string) => {
|
const deletePage = async (slug: string) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await fetch(`/api/mdx/pages/${slug}`, {
|
const response = await fetch(`/api/mdx/pages/${slug}`, {
|
||||||
method: "DELETE",
|
method: "DELETE"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Admin // Vulnerabilities",
|
title: "Admin // Vulnerabilities"
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function logPages({ children }: { children: React.ReactNode }) {
|
export default function logPages({ children }: { children: React.ReactNode }) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
|
@ -19,7 +19,7 @@ import {
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
@ -29,7 +29,7 @@ import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectTrigger,
|
SelectTrigger
|
||||||
} from "@/components/ui/select";
|
} from "@/components/ui/select";
|
||||||
|
|
||||||
interface VulnerabiltyEntry {
|
interface VulnerabiltyEntry {
|
||||||
|
@ -50,13 +50,13 @@ const AdminLogPage = () => {
|
||||||
resolver: zodResolver(vulnerabilitiesSchema),
|
resolver: zodResolver(vulnerabilitiesSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
version: "",
|
version: "",
|
||||||
bullets: [{ point: "" }],
|
bullets: [{ point: "" }]
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const { fields, append, remove } = useFieldArray({
|
const { fields, append, remove } = useFieldArray({
|
||||||
control: form.control,
|
control: form.control,
|
||||||
name: "bullets",
|
name: "bullets"
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchLogs = async () => {
|
const fetchLogs = async () => {
|
||||||
|
@ -78,7 +78,7 @@ const AdminLogPage = () => {
|
||||||
const response = await fetch("/api/uploadvulnerabilities", {
|
const response = await fetch("/api/uploadvulnerabilities", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
@ -95,7 +95,7 @@ const AdminLogPage = () => {
|
||||||
const deleteLog = async (id: string) => {
|
const deleteLog = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/delete/vulnerability/${id}`, {
|
const response = await fetch(`/api/delete/vulnerability/${id}`, {
|
||||||
method: "DELETE",
|
method: "DELETE"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
fetchLogs();
|
fetchLogs();
|
||||||
|
|
|
@ -18,7 +18,7 @@ const EmailEditor = () => {
|
||||||
toast({
|
toast({
|
||||||
title: "Validation Error",
|
title: "Validation Error",
|
||||||
description: "Subject and content cannot be empty.",
|
description: "Subject and content cannot be empty.",
|
||||||
variant: "destructive",
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,12 @@ const EmailEditor = () => {
|
||||||
const response = await fetch("/api/newsletter/send", {
|
const response = await fetch("/api/newsletter/send", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json"
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
subject: subject,
|
subject: subject,
|
||||||
html: previewContent,
|
html: previewContent
|
||||||
}),
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
@ -48,14 +48,14 @@ const EmailEditor = () => {
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
toast({
|
toast({
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
description: result.message || "Emails sent successfully",
|
description: result.message || "Emails sent successfully"
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
toast({
|
toast({
|
||||||
title: "Uh oh!",
|
title: "Uh oh!",
|
||||||
description: `Failed to send emails: ${error}`,
|
description: `Failed to send emails: ${error}`,
|
||||||
variant: "destructive",
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
@ -70,12 +70,12 @@ const EmailEditor = () => {
|
||||||
const response = await fetch("/api/newsletter/test", {
|
const response = await fetch("/api/newsletter/test", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json"
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
subject: subject,
|
subject: subject,
|
||||||
html: previewContent,
|
html: previewContent
|
||||||
}),
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
@ -85,14 +85,14 @@ const EmailEditor = () => {
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
toast({
|
toast({
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
description: result.message || "Test email sent successfully",
|
description: result.message || "Test email sent successfully"
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
toast({
|
toast({
|
||||||
title: "Uh oh!",
|
title: "Uh oh!",
|
||||||
description: `Failed to send test email: ${error}`,
|
description: `Failed to send test email: ${error}`,
|
||||||
variant: "destructive",
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
|
@ -2,13 +2,9 @@ import React from "react";
|
||||||
import AuthProvider from "../../components/shared/providers/AuthProvider";
|
import AuthProvider from "../../components/shared/providers/AuthProvider";
|
||||||
|
|
||||||
export default function AdminLayout({
|
export default function AdminLayout({
|
||||||
children,
|
children
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return <AuthProvider>{children}</AuthProvider>;
|
||||||
<AuthProvider>
|
|
||||||
{children}
|
|
||||||
</AuthProvider>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ interface BlogSlugArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
params,
|
params
|
||||||
}: {
|
}: {
|
||||||
params: { slug: string };
|
params: { slug: string };
|
||||||
}): Promise<Metadata> {
|
}): Promise<Metadata> {
|
||||||
|
@ -50,7 +50,7 @@ export async function generateMetadata({
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return {
|
return {
|
||||||
title: "Not Found",
|
title: "Not Found",
|
||||||
description: "Blog post not found",
|
description: "Blog post not found"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,9 +67,9 @@ export async function generateMetadata({
|
||||||
url: urlFor(data.titleImage).url(),
|
url: urlFor(data.titleImage).url(),
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: `${data.title} - SVRJS`,
|
alt: `${data.title} - SVRJS`
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -77,8 +77,8 @@ export async function generateMetadata({
|
||||||
title: `${data.title} - SVRJS`,
|
title: `${data.title} - SVRJS`,
|
||||||
description: data.smallDescription,
|
description: data.smallDescription,
|
||||||
images: [urlFor(data.titleImage).url()],
|
images: [urlFor(data.titleImage).url()],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,12 +126,12 @@ const customPortableTextComponents: PortableTextComponents = {
|
||||||
<CopyButton code={value.code} />
|
<CopyButton code={value.code} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function BlogSlugArticle({
|
export default async function BlogSlugArticle({
|
||||||
params,
|
params
|
||||||
}: {
|
}: {
|
||||||
params: { slug: string };
|
params: { slug: string };
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -20,9 +20,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "Blog - SVRJS",
|
alt: "Blog - SVRJS"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -31,12 +31,12 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Welcome to the SVR.JS Blog! Explore our latest blog posts featuring web development, web application security, and web server administration tips. Stay tuned for the latest SVR.JS updates.",
|
"Welcome to the SVR.JS Blog! Explore our latest blog posts featuring web development, web application security, and web server administration tips. Stay tuned for the latest SVR.JS updates.",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const BlogPage = async ({
|
const BlogPage = async ({
|
||||||
searchParams,
|
searchParams
|
||||||
}: {
|
}: {
|
||||||
searchParams: { page?: string };
|
searchParams: { page?: string };
|
||||||
}) => {
|
}) => {
|
||||||
|
|
|
@ -16,9 +16,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "ChangeLogs - SVRJS",
|
alt: "ChangeLogs - SVRJS"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -27,8 +27,8 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Stay up-to-date with the latest improvements and updates to SVR.JS web server. Our change log page provides a comprehensive list of new features, bug fixes, and enhancements for each release.",
|
"Stay up-to-date with the latest improvements and updates to SVR.JS web server. Our change log page provides a comprehensive list of new features, bug fixes, and enhancements for each release.",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
const ContactLayout = ({ children }: { children: React.ReactNode }) => {
|
const ContactLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
return <main>{children}</main>;
|
return <main>{children}</main>;
|
||||||
|
|
|
@ -27,7 +27,7 @@ const LogsPage: React.FC = () => {
|
||||||
const fetchDownloads = async () => {
|
const fetchDownloads = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/logs", {
|
const response = await fetch("/api/logs", {
|
||||||
method: "GET",
|
method: "GET"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: LOGS[] = await response.json();
|
const data: LOGS[] = await response.json();
|
||||||
|
|
|
@ -16,9 +16,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "Contact Us - SVRJS",
|
alt: "Contact Us - SVRJS"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -27,8 +27,8 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Have questions about SVR.JS? Need technical support? Visit our Contact Us page to find various ways to get in touch with our team, including email, forums, and our official support channel.",
|
"Have questions about SVR.JS? Need technical support? Visit our Contact Us page to find various ways to get in touch with our team, including email, forums, and our official support channel.",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
const ContactLayout = ({ children }: { children: React.ReactNode }) => {
|
const ContactLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
return <main>{children}</main>;
|
return <main>{children}</main>;
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage
|
||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
@ -33,8 +33,8 @@ const ContactUs = () => {
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: "",
|
name: "",
|
||||||
email: "",
|
email: "",
|
||||||
message: "",
|
message: ""
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function onSubmit(values: z.infer<typeof contactFormSchema>) {
|
async function onSubmit(values: z.infer<typeof contactFormSchema>) {
|
||||||
|
@ -50,27 +50,27 @@ const ContactUs = () => {
|
||||||
body: JSON.stringify({ ...values, captchaToken }),
|
body: JSON.stringify({ ...values, captchaToken }),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Accept: "application/json",
|
Accept: "application/json"
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
form.reset();
|
form.reset();
|
||||||
setCaptchaToken(null); // Reset captcha token after successful submission
|
setCaptchaToken(null); // Reset captcha token after successful submission
|
||||||
toast({
|
toast({
|
||||||
description: "Your message has been sent.",
|
description: "Your message has been sent."
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast({
|
toast({
|
||||||
title: "Uh oh! Something went wrong.",
|
title: "Uh oh! Something went wrong.",
|
||||||
variant: "destructive",
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Uh oh! Something went wrong.",
|
title: "Uh oh! Something went wrong.",
|
||||||
variant: "destructive",
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
|
@ -18,9 +18,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "Contribute - SVRJS",
|
alt: "Contribute - SVRJS"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -29,8 +29,8 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Contribute to SVR.JS and be part of an exciting open-source project. Follow the step-by-step guidelines to make your code contributions.",
|
"Contribute to SVR.JS and be part of an exciting open-source project. Follow the step-by-step guidelines to make your code contributions.",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
const Contribute = () => {
|
const Contribute = () => {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -16,9 +16,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "Downloads - SVRJS",
|
alt: "Downloads - SVRJS"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -27,12 +27,12 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Ready to get started with SVR.JS? Visit our downloads page to access the latest stable releases, nightly builds, and archived versions. Find the right fit for your needs today!",
|
"Ready to get started with SVR.JS? Visit our downloads page to access the latest stable releases, nightly builds, and archived versions. Find the right fit for your needs today!",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function DownloadLayout({
|
export default function DownloadLayout({
|
||||||
children,
|
children
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { Download } from "lucide-react";
|
import { Download } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
@ -31,7 +31,7 @@ const DownloadPage: React.FC = () => {
|
||||||
const fetchDownloads = async () => {
|
const fetchDownloads = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/downloads", {
|
const response = await fetch("/api/downloads", {
|
||||||
method: "GET",
|
method: "GET"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: Download[] = await response.json();
|
const data: Download[] = await response.json();
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from "react";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Forum - SVRJS",
|
title: "Forum - SVRJS"
|
||||||
};
|
};
|
||||||
|
|
||||||
const Forum = () => {
|
const Forum = () => {
|
||||||
|
|
|
@ -20,9 +20,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "SVRJS - A Web Server running on Node.js",
|
alt: "SVRJS - A Web Server running on Node.js"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -31,12 +31,12 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Experience unparalleled flexibility with SVR.JS - the ultimate web server for Node.js. Host web pages, run server-side JavaScript, utilize mods for extended functionality, and more. Integrated log viewer and user management tools included. Also supports Bun (experimental).",
|
"Experience unparalleled flexibility with SVR.JS - the ultimate web server for Node.js. Host web pages, run server-side JavaScript, utilize mods for extended functionality, and more. Integrated log viewer and user management tools included. Also supports Bun (experimental).",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function PageLayout({
|
export default function PageLayout({
|
||||||
children,
|
children
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -16,9 +16,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "Mods - SVRJS",
|
alt: "Mods - SVRJS"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -27,8 +27,8 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Expand the functionality of SVR.JS with our collection of mods! Visit the mod downloads page to explore, download, and install a wide range of mods tailored to enhance your web server experience.",
|
"Expand the functionality of SVR.JS with our collection of mods! Visit the mod downloads page to explore, download, and install a wide range of mods tailored to enhance your web server experience.",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
const ModLayout = ({ children }: { children: React.ReactNode }) => {
|
const ModLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
return <main>{children}</main>;
|
return <main>{children}</main>;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
TableCell,
|
TableCell,
|
||||||
TableHead,
|
TableHead,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import { Download } from "lucide-react";
|
import { Download } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
@ -30,7 +30,7 @@ const ModsPage: React.FC = () => {
|
||||||
const fetchDownloads = async () => {
|
const fetchDownloads = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/mods", {
|
const response = await fetch("/api/mods", {
|
||||||
method: "GET",
|
method: "GET"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: Mods[] = await response.json();
|
const data: Mods[] = await response.json();
|
||||||
|
|
|
@ -20,9 +20,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "Privacy Policy - SVRJS",
|
alt: "Privacy Policy - SVRJS"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -31,8 +31,8 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Learn how we collect, use, and protect your data. Our Privacy Policy outlines our commitment to your privacy and the measures we take to safeguard your information when visiting our website.",
|
"Learn how we collect, use, and protect your data. Our Privacy Policy outlines our commitment to your privacy and the measures we take to safeguard your information when visiting our website.",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const PrivacyPolicy = () => {
|
const PrivacyPolicy = () => {
|
||||||
|
|
|
@ -18,9 +18,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "Terms of Service - SVRJS",
|
alt: "Terms of Service - SVRJS"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -29,8 +29,8 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Understand your rights and responsibilities when using SVR.JS. Our Terms of Service page outlines the conditions for visiting our website, ensuring a transparent and fair experience for all users.",
|
"Understand your rights and responsibilities when using SVR.JS. Our Terms of Service page outlines the conditions for visiting our website, ensuring a transparent and fair experience for all users.",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const TermsOfService = () => {
|
const TermsOfService = () => {
|
||||||
|
|
|
@ -16,9 +16,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "Vulnerabilities - SVRJS",
|
alt: "Vulnerabilities - SVRJS"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -27,8 +27,8 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Learn about potential security risks associated with outdated SVR.JS web server versions. Stay informed and safeguard your web applications from potential threats with timely updates.",
|
"Learn about potential security risks associated with outdated SVR.JS web server versions. Stay informed and safeguard your web applications from potential threats with timely updates.",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
const ModLayout = ({ children }: { children: React.ReactNode }) => {
|
const ModLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
return <main>{children}</main>;
|
return <main>{children}</main>;
|
||||||
|
|
|
@ -32,7 +32,7 @@ const Vulnerabilities = () => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/vulnerabilities", {
|
const response = await fetch("/api/vulnerabilities", {
|
||||||
method: "GET",
|
method: "GET"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: Vulnerabilities[] = await response.json();
|
const data: Vulnerabilities[] = await response.json();
|
||||||
|
@ -51,7 +51,7 @@ const Vulnerabilities = () => {
|
||||||
const fetchMods = async () => {
|
const fetchMods = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/mdx/pages`, {
|
const response = await fetch(`/api/mdx/pages`, {
|
||||||
method: "GET",
|
method: "GET"
|
||||||
});
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data: ModsVulnerability[] = await response.json();
|
const data: ModsVulnerability[] = await response.json();
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const authOptions: NextAuthOptions = {
|
||||||
name: "Credentials",
|
name: "Credentials",
|
||||||
credentials: {
|
credentials: {
|
||||||
username: { label: "Username", type: "text" },
|
username: { label: "Username", type: "text" },
|
||||||
password: { label: "Password", type: "password" },
|
password: { label: "Password", type: "password" }
|
||||||
},
|
},
|
||||||
async authorize(credentials: any): Promise<any> {
|
async authorize(credentials: any): Promise<any> {
|
||||||
const adminUsername = process.env.ADMIN_USERNAME;
|
const adminUsername = process.env.ADMIN_USERNAME;
|
||||||
|
@ -34,8 +34,8 @@ export const authOptions: NextAuthOptions = {
|
||||||
}
|
}
|
||||||
// If you return null then an error will be displayed that the user to check their details.
|
// If you return null then an error will be displayed that the user to check their details.
|
||||||
return null;
|
return null;
|
||||||
},
|
}
|
||||||
}),
|
})
|
||||||
],
|
],
|
||||||
callbacks: {
|
callbacks: {
|
||||||
async jwt({ token, user }) {
|
async jwt({ token, user }) {
|
||||||
|
@ -51,13 +51,13 @@ export const authOptions: NextAuthOptions = {
|
||||||
// session.user.id = token.id;
|
// session.user.id = token.id;
|
||||||
// session.user.name = token.name;
|
// session.user.name = token.name;
|
||||||
return session;
|
return session;
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
pages: {
|
pages: {
|
||||||
signIn: "/login",
|
signIn: "/login"
|
||||||
},
|
},
|
||||||
session: {
|
session: {
|
||||||
strategy: "jwt",
|
strategy: "jwt"
|
||||||
},
|
},
|
||||||
secret: process.env.NEXTAUTH_SECRET,
|
secret: process.env.NEXTAUTH_SECRET
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { NextRequest, NextResponse } from "next/server";
|
||||||
const CONTACT_MESSAGE_FIELDS: Record<string, string> = {
|
const CONTACT_MESSAGE_FIELDS: Record<string, string> = {
|
||||||
name: "Name",
|
name: "Name",
|
||||||
email: "Email",
|
email: "Email",
|
||||||
message: "Message",
|
message: "Message"
|
||||||
};
|
};
|
||||||
|
|
||||||
const escapeHtml = (text: string) => {
|
const escapeHtml = (text: string) => {
|
||||||
|
@ -90,7 +90,7 @@ const generateEmailContent = (data: Record<string, string>) => {
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</body>
|
</body>
|
||||||
</html>`,
|
</html>`
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ export async function POST(req: NextRequest) {
|
||||||
await transporter.sendMail({
|
await transporter.sendMail({
|
||||||
...mailOptions,
|
...mailOptions,
|
||||||
...generateEmailContent(data),
|
...generateEmailContent(data),
|
||||||
subject: "Contact Email",
|
subject: "Contact Email"
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|
|
@ -14,21 +14,21 @@ export async function POST(request: NextRequest) {
|
||||||
const cookie = serialize("auth", "authenticated", {
|
const cookie = serialize("auth", "authenticated", {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
path: "/",
|
path: "/",
|
||||||
maxAge: 60 * 60 * 24, // 1 day
|
maxAge: 60 * 60 * 24 // 1 day
|
||||||
});
|
});
|
||||||
|
|
||||||
return new NextResponse(JSON.stringify({ message: "Login successful" }), {
|
return new NextResponse(JSON.stringify({ message: "Login successful" }), {
|
||||||
headers: {
|
headers: {
|
||||||
"Set-Cookie": cookie,
|
"Set-Cookie": cookie,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json"
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NextResponse(JSON.stringify({ message: "Invalid credentials" }), {
|
return new NextResponse(JSON.stringify({ message: "Invalid credentials" }), {
|
||||||
status: 401,
|
status: 401,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json"
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ export const PUT = async (
|
||||||
if (result?.value) {
|
if (result?.value) {
|
||||||
const serializedResult = {
|
const serializedResult = {
|
||||||
...result.value,
|
...result.value,
|
||||||
_id: result.value._id.toString(), // Convert ObjectId to string
|
_id: result.value._id.toString() // Convert ObjectId to string
|
||||||
};
|
};
|
||||||
return NextResponse.json(serializedResult, { status: 200 });
|
return NextResponse.json(serializedResult, { status: 200 });
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,8 +8,8 @@ const transporter = nodemailer.createTransport({
|
||||||
port: 587,
|
port: 587,
|
||||||
auth: {
|
auth: {
|
||||||
user: process.env.EMAIL,
|
user: process.env.EMAIL,
|
||||||
pass: process.env.EMAIL_PASS,
|
pass: process.env.EMAIL_PASS
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const sendEmail = async (to: string[], subject: string, html: string) => {
|
const sendEmail = async (to: string[], subject: string, html: string) => {
|
||||||
|
@ -18,7 +18,7 @@ const sendEmail = async (to: string[], subject: string, html: string) => {
|
||||||
from: process.env.EMAIL_USER,
|
from: process.env.EMAIL_USER,
|
||||||
to: to.join(", "),
|
to: to.join(", "),
|
||||||
subject: subject,
|
subject: subject,
|
||||||
html: html,
|
html: html
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error sending email:", error);
|
console.error("Error sending email:", error);
|
||||||
|
|
|
@ -27,7 +27,7 @@ export async function GET(req: Request) {
|
||||||
subscribedAt:
|
subscribedAt:
|
||||||
doc.subscribedAt instanceof Date
|
doc.subscribedAt instanceof Date
|
||||||
? doc.subscribedAt
|
? doc.subscribedAt
|
||||||
: new Date(doc.subscribedAt),
|
: new Date(doc.subscribedAt)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const totalSubscribers = await collection.countDocuments();
|
const totalSubscribers = await collection.countDocuments();
|
||||||
|
@ -35,7 +35,7 @@ export async function GET(req: Request) {
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
subscribers,
|
subscribers,
|
||||||
totalSubscribers,
|
totalSubscribers,
|
||||||
totalPages: Math.ceil(totalSubscribers / limit),
|
totalPages: Math.ceil(totalSubscribers / limit)
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching subscribers:", error);
|
console.error("Error fetching subscribers:", error);
|
||||||
|
|
|
@ -7,8 +7,8 @@ const transporter = nodemailer.createTransport({
|
||||||
port: 587,
|
port: 587,
|
||||||
auth: {
|
auth: {
|
||||||
user: process.env.EMAIL,
|
user: process.env.EMAIL,
|
||||||
pass: process.env.EMAIL_PASS,
|
pass: process.env.EMAIL_PASS
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const sendEmail = async (to: string[], subject: string, html: string) => {
|
const sendEmail = async (to: string[], subject: string, html: string) => {
|
||||||
|
@ -17,7 +17,7 @@ const sendEmail = async (to: string[], subject: string, html: string) => {
|
||||||
from: process.env.EMAIL_USER,
|
from: process.env.EMAIL_USER,
|
||||||
to: to.join(", "),
|
to: to.join(", "),
|
||||||
subject: subject,
|
subject: subject,
|
||||||
html: html,
|
html: html
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error sending email:", error);
|
console.error("Error sending email:", error);
|
||||||
|
@ -32,7 +32,7 @@ export async function POST(req: NextRequest) {
|
||||||
// add ur email here
|
// add ur email here
|
||||||
const testEmails = [
|
const testEmails = [
|
||||||
"abhijitbhattacharjee333@gmail.com",
|
"abhijitbhattacharjee333@gmail.com",
|
||||||
"test2@example.com",
|
"test2@example.com"
|
||||||
];
|
];
|
||||||
|
|
||||||
if (testEmails.length === 0) {
|
if (testEmails.length === 0) {
|
||||||
|
|
|
@ -18,9 +18,9 @@ export async function POST(req: NextRequest) {
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
"Content-Type": "application/x-www-form-urlencoded"
|
||||||
},
|
},
|
||||||
body: `secret=${process.env.HCAPTCHA_SECRET}&response=${captchaToken}`,
|
body: `secret=${process.env.HCAPTCHA_SECRET}&response=${captchaToken}`
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ export async function PUT(
|
||||||
fileName,
|
fileName,
|
||||||
version,
|
version,
|
||||||
downloadLink,
|
downloadLink,
|
||||||
fileSize,
|
fileSize
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -33,14 +33,14 @@ export async function PUT(
|
||||||
} else {
|
} else {
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
success: false,
|
success: false,
|
||||||
message: "No document updated",
|
message: "No document updated"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Update failed", error);
|
console.error("Update failed", error);
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
success: false,
|
success: false,
|
||||||
message: "Failed to update mod",
|
message: "Failed to update mod"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ export async function POST(request: Request) {
|
||||||
fileName,
|
fileName,
|
||||||
version,
|
version,
|
||||||
downloadLink,
|
downloadLink,
|
||||||
fileSize,
|
fileSize
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json({ success: true, id: result.insertedId });
|
return NextResponse.json({ success: true, id: result.insertedId });
|
||||||
|
|
|
@ -14,7 +14,7 @@ export async function POST(request: Request) {
|
||||||
const result = await db.collection("logs").insertOne({
|
const result = await db.collection("logs").insertOne({
|
||||||
version,
|
version,
|
||||||
date,
|
date,
|
||||||
bullets,
|
bullets
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json({ success: true, id: result.insertedId });
|
return NextResponse.json({ success: true, id: result.insertedId });
|
||||||
|
|
|
@ -16,7 +16,7 @@ export async function POST(request: Request) {
|
||||||
fileName,
|
fileName,
|
||||||
version,
|
version,
|
||||||
downloadLink,
|
downloadLink,
|
||||||
fileSize,
|
fileSize
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json({ success: true, id: result.insertedId });
|
return NextResponse.json({ success: true, id: result.insertedId });
|
||||||
|
|
|
@ -7,10 +7,10 @@ const f = createUploadthing();
|
||||||
|
|
||||||
export const ourFileRouter = {
|
export const ourFileRouter = {
|
||||||
imageUploader: f({
|
imageUploader: f({
|
||||||
"application/zip": { maxFileSize: "8MB" },
|
"application/zip": { maxFileSize: "8MB" }
|
||||||
}).onUploadComplete(async ({ metadata, file }) => {
|
}).onUploadComplete(async ({ metadata, file }) => {
|
||||||
console.log("file url", file.url);
|
console.log("file url", file.url);
|
||||||
}),
|
})
|
||||||
} satisfies FileRouter;
|
} satisfies FileRouter;
|
||||||
|
|
||||||
export type OurFileRouter = typeof ourFileRouter;
|
export type OurFileRouter = typeof ourFileRouter;
|
||||||
|
|
|
@ -4,5 +4,5 @@ import { ourFileRouter } from "./core";
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
export const { GET, POST } = createRouteHandler({
|
export const { GET, POST } = createRouteHandler({
|
||||||
router: ourFileRouter,
|
router: ourFileRouter
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,7 @@ export async function POST(request: Request) {
|
||||||
|
|
||||||
const result = await db.collection("vulnerabilities").insertOne({
|
const result = await db.collection("vulnerabilities").insertOne({
|
||||||
version,
|
version,
|
||||||
bullets,
|
bullets
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json({ success: true, id: result.insertedId });
|
return NextResponse.json({ success: true, id: result.insertedId });
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Analytics } from "@vercel/analytics/react";
|
||||||
|
|
||||||
const poppins = Poppins({
|
const poppins = Poppins({
|
||||||
weight: ["400", "600", "700", "900"],
|
weight: ["400", "600", "700", "900"],
|
||||||
subsets: ["latin"],
|
subsets: ["latin"]
|
||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
|
@ -25,9 +25,9 @@ export const metadata: Metadata = {
|
||||||
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
url: "https://svrjs.vercel.app/metadata/svrjs-cover.png",
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
alt: "SVRJS - A Web Server running on Node.js",
|
alt: "SVRJS - A Web Server running on Node.js"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
|
@ -36,12 +36,12 @@ export const metadata: Metadata = {
|
||||||
description:
|
description:
|
||||||
"Experience unparalleled flexibility with SVR.JS - the ultimate web server for Node.js. Host web pages, run server-side JavaScript, utilize mods for extended functionality, and more. Integrated log viewer and user management tools included. Also supports Bun (experimental).",
|
"Experience unparalleled flexibility with SVR.JS - the ultimate web server for Node.js. Host web pages, run server-side JavaScript, utilize mods for extended functionality, and more. Integrated log viewer and user management tools included. Also supports Bun (experimental).",
|
||||||
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
images: ["https://svrjs.vercel.app/metadata/svrjs-cover.png"],
|
||||||
creator: "@SVR_JS",
|
creator: "@SVR_JS"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
|
@ -54,7 +54,6 @@ export default function RootLayout({
|
||||||
enableSystem
|
enableSystem
|
||||||
disableTransitionOnChange
|
disableTransitionOnChange
|
||||||
>
|
>
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
<Toaster />
|
<Toaster />
|
||||||
<Analytics />
|
<Analytics />
|
||||||
|
|
|
@ -30,7 +30,7 @@ const LoginPage = () => {
|
||||||
const res = await signIn("credentials", {
|
const res = await signIn("credentials", {
|
||||||
redirect: false,
|
redirect: false,
|
||||||
username,
|
username,
|
||||||
password,
|
password
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res?.ok) {
|
if (res?.ok) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ export async function GET() {
|
||||||
site_url: `${SITE_URL}`,
|
site_url: `${SITE_URL}`,
|
||||||
image_url: `${SITE_URL}/metadata/svrjs-cover.png`,
|
image_url: `${SITE_URL}/metadata/svrjs-cover.png`,
|
||||||
language: "en-US",
|
language: "en-US",
|
||||||
pubDate: new Date().toUTCString(),
|
pubDate: new Date().toUTCString()
|
||||||
});
|
});
|
||||||
|
|
||||||
posts.forEach((post: any) => {
|
posts.forEach((post: any) => {
|
||||||
|
@ -35,7 +35,7 @@ export async function GET() {
|
||||||
title: post.title,
|
title: post.title,
|
||||||
description: toHTML(post.content),
|
description: toHTML(post.content),
|
||||||
url: `${SITE_URL}/blog/${post.slug}`,
|
url: `${SITE_URL}/blog/${post.slug}`,
|
||||||
date: new Date(post._createdAt).toUTCString(),
|
date: new Date(post._createdAt).toUTCString()
|
||||||
// uncomment this if u want to
|
// uncomment this if u want to
|
||||||
// enclosure: { url: urlFor(post.titleImage).url() },
|
// enclosure: { url: urlFor(post.titleImage).url() },
|
||||||
// author: "SVRJS",
|
// author: "SVRJS",
|
||||||
|
@ -44,7 +44,7 @@ export async function GET() {
|
||||||
|
|
||||||
return new NextResponse(feed.xml({ indent: true }), {
|
return new NextResponse(feed.xml({ indent: true }), {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/xml",
|
"Content-Type": "application/xml"
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,15 +15,15 @@ export default async function sitemap() {
|
||||||
"/privacy-policy",
|
"/privacy-policy",
|
||||||
"/tos",
|
"/tos",
|
||||||
"/vulnerabilities",
|
"/vulnerabilities",
|
||||||
"/newsletter",
|
"/newsletter"
|
||||||
].map((route) => ({
|
].map((route) => ({
|
||||||
url: `https://svrjs.vercel.app${route}`,
|
url: `https://svrjs.vercel.app${route}`,
|
||||||
lastModified: new Date().toISOString().split("T")[0],
|
lastModified: new Date().toISOString().split("T")[0]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const blogRoutes = blogPostSlugs.map((slug) => ({
|
const blogRoutes = blogPostSlugs.map((slug) => ({
|
||||||
url: `https://svrjs.vercel.app/blog/${slug.slug}`,
|
url: `https://svrjs.vercel.app/blog/${slug.slug}`,
|
||||||
lastModified: new Date().toISOString().split("T")[0],
|
lastModified: new Date().toISOString().split("T")[0]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return [...baseRoutes, ...blogRoutes];
|
return [...baseRoutes, ...blogRoutes];
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
PaginationItem,
|
PaginationItem,
|
||||||
PaginationLink,
|
PaginationLink,
|
||||||
PaginationNext,
|
PaginationNext,
|
||||||
PaginationPrevious,
|
PaginationPrevious
|
||||||
} from "@/components/ui/pagination";
|
} from "@/components/ui/pagination";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ const CodeEditor = ({ onChange }: CodeEditorProps) => {
|
||||||
<Editor
|
<Editor
|
||||||
options={{
|
options={{
|
||||||
minimap: {
|
minimap: {
|
||||||
enabled: false,
|
enabled: false
|
||||||
},
|
}
|
||||||
}}
|
}}
|
||||||
height="75vh"
|
height="75vh"
|
||||||
theme="vs-dark"
|
theme="vs-dark"
|
||||||
|
|
|
@ -14,7 +14,7 @@ const TestimonialCard = ({
|
||||||
name,
|
name,
|
||||||
role,
|
role,
|
||||||
testimonial,
|
testimonial,
|
||||||
rating,
|
rating
|
||||||
}: TestimonialCard) => {
|
}: TestimonialCard) => {
|
||||||
return (
|
return (
|
||||||
<li className="inline-block w-full">
|
<li className="inline-block w-full">
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
AccordionItem,
|
AccordionItem,
|
||||||
AccordionTrigger,
|
AccordionTrigger
|
||||||
} from "../ui/accordion";
|
} from "../ui/accordion";
|
||||||
|
|
||||||
const Faq = () => {
|
const Faq = () => {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import Image from "next/image";
|
||||||
const happyMonkey = Happy_Monkey({
|
const happyMonkey = Happy_Monkey({
|
||||||
preload: true,
|
preload: true,
|
||||||
weight: ["400"],
|
weight: ["400"],
|
||||||
subsets: ["latin"],
|
subsets: ["latin"]
|
||||||
});
|
});
|
||||||
|
|
||||||
const Hero = () => {
|
const Hero = () => {
|
||||||
|
@ -29,7 +29,7 @@ const Hero = () => {
|
||||||
linux:
|
linux:
|
||||||
"curl -fsSL https://downloads.svrjs.org/installer/svr.js.installer.linux.20240509.sh > /tmp/installer.sh && sudo bash /tmp/installer.sh",
|
"curl -fsSL https://downloads.svrjs.org/installer/svr.js.installer.linux.20240509.sh > /tmp/installer.sh && sudo bash /tmp/installer.sh",
|
||||||
docker:
|
docker:
|
||||||
"docker pull svrjs/svrjs && docker run --name mysvrjs -d -p 80:80 --restart=always svrjs/svrjs",
|
"docker pull svrjs/svrjs && docker run --name mysvrjs -d -p 80:80 --restart=always svrjs/svrjs"
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyToClipboard = () => {
|
const copyToClipboard = () => {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
CardDescription,
|
CardDescription,
|
||||||
CardFooter,
|
CardFooter,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { Happy_Monkey } from "next/font/google";
|
import { Happy_Monkey } from "next/font/google";
|
||||||
|
@ -21,7 +21,7 @@ import { useRouter } from "next/navigation";
|
||||||
const happyMonkey = Happy_Monkey({
|
const happyMonkey = Happy_Monkey({
|
||||||
preload: true,
|
preload: true,
|
||||||
weight: ["400"],
|
weight: ["400"],
|
||||||
subsets: ["latin"],
|
subsets: ["latin"]
|
||||||
});
|
});
|
||||||
|
|
||||||
const HeroCards = () => {
|
const HeroCards = () => {
|
||||||
|
@ -34,8 +34,8 @@ const HeroCards = () => {
|
||||||
x: "https://x.com/SVR_JS",
|
x: "https://x.com/SVR_JS",
|
||||||
Mastodon: "https://mastodon.social/@svrjs",
|
Mastodon: "https://mastodon.social/@svrjs",
|
||||||
Bluesky: "https://bsky.app/profile/svrjs.org",
|
Bluesky: "https://bsky.app/profile/svrjs.org",
|
||||||
Odysee: "https://odysee.com/@SVRJS",
|
Odysee: "https://odysee.com/@SVRJS"
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
pricingCard: {
|
pricingCard: {
|
||||||
planName: "Pro Plan",
|
planName: "Pro Plan",
|
||||||
|
@ -48,26 +48,26 @@ const HeroCards = () => {
|
||||||
features: [
|
features: [
|
||||||
{
|
{
|
||||||
title: "Unlimited Projects",
|
title: "Unlimited Projects",
|
||||||
icons: <Infinity className="rounded-full" width={25} height={25} />,
|
icons: <Infinity className="rounded-full" width={25} height={25} />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Priority Support",
|
title: "Priority Support",
|
||||||
icons: (
|
icons: (
|
||||||
<ArchiveRestore className="rounded-full" width={25} height={25} />
|
<ArchiveRestore className="rounded-full" width={25} height={25} />
|
||||||
),
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Free Updates",
|
title: "Free Updates",
|
||||||
icons: <Headset className="rounded-full" width={25} height={25} />,
|
icons: <Headset className="rounded-full" width={25} height={25} />
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
curlyText: "Best Value!",
|
curlyText: "Best Value!"
|
||||||
},
|
},
|
||||||
serviceCard: {
|
serviceCard: {
|
||||||
title: "Our Services",
|
title: "Our Services",
|
||||||
description:
|
description:
|
||||||
"We offer a variety of services to cater to your needs, including web development, SEO, and more.",
|
"We offer a variety of services to cater to your needs, including web development, SEO, and more."
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {
|
||||||
SheetContent,
|
SheetContent,
|
||||||
SheetHeader,
|
SheetHeader,
|
||||||
SheetTitle,
|
SheetTitle,
|
||||||
SheetTrigger,
|
SheetTrigger
|
||||||
} from "../ui/sheet";
|
} from "../ui/sheet";
|
||||||
import { Menu } from "lucide-react";
|
import { Menu } from "lucide-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
@ -48,7 +48,7 @@ const MobileNav = () => {
|
||||||
href={href}
|
href={href}
|
||||||
target={target}
|
target={target}
|
||||||
className={`w-[110px] gap-2 ${buttonVariants({
|
className={`w-[110px] gap-2 ${buttonVariants({
|
||||||
variant: "secondary",
|
variant: "secondary"
|
||||||
})}`}
|
})}`}
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import {
|
import {
|
||||||
NavigationMenu,
|
NavigationMenu,
|
||||||
NavigationMenuItem,
|
NavigationMenuItem,
|
||||||
NavigationMenuList,
|
NavigationMenuList
|
||||||
} from "@radix-ui/react-navigation-menu";
|
} from "@radix-ui/react-navigation-menu";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
@ -44,7 +44,7 @@ const Navbar = () => {
|
||||||
className={`text-[17px] tracking-tight ${
|
className={`text-[17px] tracking-tight ${
|
||||||
pathname == href ? "bg-muted-foreground/20" : ""
|
pathname == href ? "bg-muted-foreground/20" : ""
|
||||||
} ${buttonVariants({
|
} ${buttonVariants({
|
||||||
variant: "ghost",
|
variant: "ghost"
|
||||||
})}`}
|
})}`}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
|
@ -61,7 +61,7 @@ const Navbar = () => {
|
||||||
target={target}
|
target={target}
|
||||||
className={`border ${buttonVariants({
|
className={`border ${buttonVariants({
|
||||||
variant: "ghost",
|
variant: "ghost",
|
||||||
size: "icon",
|
size: "icon"
|
||||||
})}`}
|
})}`}
|
||||||
>
|
>
|
||||||
<span className="sr-only">Git</span>
|
<span className="sr-only">Git</span>
|
||||||
|
|
|
@ -11,7 +11,7 @@ import HCaptcha from "@hcaptcha/react-hcaptcha";
|
||||||
const happyMonkey = Happy_Monkey({
|
const happyMonkey = Happy_Monkey({
|
||||||
preload: true,
|
preload: true,
|
||||||
weight: "400",
|
weight: "400",
|
||||||
subsets: ["latin"],
|
subsets: ["latin"]
|
||||||
});
|
});
|
||||||
|
|
||||||
const Newsletter = () => {
|
const Newsletter = () => {
|
||||||
|
@ -41,9 +41,9 @@ const Newsletter = () => {
|
||||||
const response = await fetch("/api/subscribe", {
|
const response = await fetch("/api/subscribe", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json"
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ email: input, captchaToken: token }),
|
body: JSON.stringify({ email: input, captchaToken: token })
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ const testimonials = [
|
||||||
avatar: "avatar1",
|
avatar: "avatar1",
|
||||||
testimonial:
|
testimonial:
|
||||||
"Working with this team was a fantastic experience. They developed our website exactly to our specifications, and everything was seamless and well-integrated.",
|
"Working with this team was a fantastic experience. They developed our website exactly to our specifications, and everything was seamless and well-integrated.",
|
||||||
rating: 5,
|
rating: 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Jane Smith",
|
name: "Jane Smith",
|
||||||
|
@ -16,7 +16,7 @@ const testimonials = [
|
||||||
avatar: "avatar2",
|
avatar: "avatar2",
|
||||||
testimonial:
|
testimonial:
|
||||||
"We're thrilled with the website. It's simple, clean, and has significantly boosted our sales. The developers did an excellent job.",
|
"We're thrilled with the website. It's simple, clean, and has significantly boosted our sales. The developers did an excellent job.",
|
||||||
rating: 4,
|
rating: 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sam Green",
|
name: "Sam Green",
|
||||||
|
@ -24,7 +24,7 @@ const testimonials = [
|
||||||
avatar: "avatar3",
|
avatar: "avatar3",
|
||||||
testimonial:
|
testimonial:
|
||||||
"Collaborating with this team to build a SaaS-integrated website was a perfect experience. I look forward to working with them again.",
|
"Collaborating with this team to build a SaaS-integrated website was a perfect experience. I look forward to working with them again.",
|
||||||
rating: 5,
|
rating: 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Chris Brown",
|
name: "Chris Brown",
|
||||||
|
@ -32,14 +32,14 @@ const testimonials = [
|
||||||
avatar: "avatar4",
|
avatar: "avatar4",
|
||||||
testimonial:
|
testimonial:
|
||||||
"The team's understanding of our needs and their ability to provide fitting solutions was impressive. Their support and guidance were invaluable.",
|
"The team's understanding of our needs and their ability to provide fitting solutions was impressive. Their support and guidance were invaluable.",
|
||||||
rating: 4,
|
rating: 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Alex Johnson",
|
name: "Alex Johnson",
|
||||||
avatar: "avatar5",
|
avatar: "avatar5",
|
||||||
testimonial:
|
testimonial:
|
||||||
"Exceptional service and outstanding results. They consistently deliver on time and within budget, making them our go-to partner for all our projects.",
|
"Exceptional service and outstanding results. They consistently deliver on time and within budget, making them our go-to partner for all our projects.",
|
||||||
rating: 5,
|
rating: 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Patricia Taylor",
|
name: "Patricia Taylor",
|
||||||
|
@ -47,7 +47,7 @@ const testimonials = [
|
||||||
avatar: "avatar6",
|
avatar: "avatar6",
|
||||||
testimonial:
|
testimonial:
|
||||||
"It was great to work with them. I needed a design for a SaaS project, and it was delivered within 2 days.",
|
"It was great to work with them. I needed a design for a SaaS project, and it was delivered within 2 days.",
|
||||||
rating: 4,
|
rating: 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Emily Davis",
|
name: "Emily Davis",
|
||||||
|
@ -55,22 +55,22 @@ const testimonials = [
|
||||||
avatar: "avatar7",
|
avatar: "avatar7",
|
||||||
testimonial:
|
testimonial:
|
||||||
"Collaborating with them has been a pleasure. Their creativity and user-centric approach have significantly enhanced our product's usability.",
|
"Collaborating with them has been a pleasure. Their creativity and user-centric approach have significantly enhanced our product's usability.",
|
||||||
rating: 5,
|
rating: 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Michael Lee",
|
name: "Michael Lee",
|
||||||
avatar: "avatar8",
|
avatar: "avatar8",
|
||||||
testimonial:
|
testimonial:
|
||||||
"They have a keen understanding of our business needs and consistently deliver top-notch solutions. Their reliability and efficiency are commendable.",
|
"They have a keen understanding of our business needs and consistently deliver top-notch solutions. Their reliability and efficiency are commendable.",
|
||||||
rating: 5,
|
rating: 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Sarah Wilson",
|
name: "Sarah Wilson",
|
||||||
avatar: "avatar9",
|
avatar: "avatar9",
|
||||||
testimonial:
|
testimonial:
|
||||||
"Their dedication to client satisfaction is evident in everything they do. We've seen remarkable improvements in our processes thanks to their expertise.",
|
"Their dedication to client satisfaction is evident in everything they do. We've seen remarkable improvements in our processes thanks to their expertise.",
|
||||||
rating: 4,
|
rating: 4
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const Testimonials = () => {
|
const Testimonials = () => {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { SessionProvider } from "next-auth/react";
|
import { SessionProvider } from "next-auth/react";
|
||||||
|
|
||||||
export default function AuthProvider({
|
export default function AuthProvider({
|
||||||
children,
|
children
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ interface ChangelogLayoutProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChangelogLayout: React.FC<ChangelogLayoutProps> = ({
|
export const ChangelogLayout: React.FC<ChangelogLayoutProps> = ({
|
||||||
children,
|
children
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="wrapper container py-24 md:py-28 gap-4 flex flex-col">
|
<div className="wrapper container py-24 md:py-28 gap-4 flex flex-col">
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import { ThemeProvider as NextThemesProvider } from "next-themes"
|
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||||
import { type ThemeProviderProps } from "next-themes/dist/types"
|
import { type ThemeProviderProps } from "next-themes/dist/types";
|
||||||
|
|
||||||
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
|
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
|
||||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { ReactNode } from "react";
|
||||||
|
|
||||||
export default function AnimatedGradientText({
|
export default function AnimatedGradientText({
|
||||||
children,
|
children,
|
||||||
className,
|
className
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
@ -12,7 +12,7 @@ export default function AnimatedGradientText({
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"group relative mx-auto flex max-w-fit flex-row items-center justify-center rounded-2xl bg-white/40 px-4 py-1.5 text-sm font-medium shadow-[inset_0_-8px_10px_#8fdfff1f] backdrop-blur-sm transition-shadow duration-500 ease-out [--bg-size:300%] hover:shadow-[inset_0_-5px_10px_#8fdfff3f] dark:bg-black/40",
|
"group relative mx-auto flex max-w-fit flex-row items-center justify-center rounded-2xl bg-white/40 px-4 py-1.5 text-sm font-medium shadow-[inset_0_-8px_10px_#8fdfff1f] backdrop-blur-sm transition-shadow duration-500 ease-out [--bg-size:300%] hover:shadow-[inset_0_-5px_10px_#8fdfff3f] dark:bg-black/40",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -10,13 +10,13 @@ interface AnimatedShinyTextProps {
|
||||||
const AnimatedShinyText: FC<AnimatedShinyTextProps> = ({
|
const AnimatedShinyText: FC<AnimatedShinyTextProps> = ({
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
shimmerWidth = 100,
|
shimmerWidth = 100
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<p
|
<p
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
"--shimmer-width": `${shimmerWidth}px`,
|
"--shimmer-width": `${shimmerWidth}px`
|
||||||
} as CSSProperties
|
} as CSSProperties
|
||||||
}
|
}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
@ -28,7 +28,7 @@ const AnimatedShinyText: FC<AnimatedShinyTextProps> = ({
|
||||||
// Shimmer gradient
|
// Shimmer gradient
|
||||||
"bg-gradient-to-r from-transparent via-black/80 via-50% to-transparent dark:via-white/80",
|
"bg-gradient-to-r from-transparent via-black/80 via-50% to-transparent dark:via-white/80",
|
||||||
|
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -13,7 +13,7 @@ const Avatar = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
@ -40,7 +40,7 @@ const AvatarFallback = React.forwardRef<
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
"flex h-full w-full items-center justify-center rounded-full bg-muted",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -14,13 +14,13 @@ const badgeVariants = cva(
|
||||||
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
destructive:
|
destructive:
|
||||||
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
||||||
outline: "text-foreground",
|
outline: "text-foreground"
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: "default"
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export interface BadgeProps
|
export interface BadgeProps
|
||||||
|
|
|
@ -19,7 +19,7 @@ export const BorderBeam = ({
|
||||||
borderWidth = 1.5,
|
borderWidth = 1.5,
|
||||||
colorFrom = "#8803AF",
|
colorFrom = "#8803AF",
|
||||||
colorTo = "#61DAFB",
|
colorTo = "#61DAFB",
|
||||||
delay = 0,
|
delay = 0
|
||||||
}: BorderBeamProps) => {
|
}: BorderBeamProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -31,7 +31,7 @@ export const BorderBeam = ({
|
||||||
"--border-width": borderWidth,
|
"--border-width": borderWidth,
|
||||||
"--color-from": colorFrom,
|
"--color-from": colorFrom,
|
||||||
"--color-to": colorTo,
|
"--color-to": colorTo,
|
||||||
"--delay": `-${delay}s`,
|
"--delay": `-${delay}s`
|
||||||
} as React.CSSProperties
|
} as React.CSSProperties
|
||||||
}
|
}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import { Slot } from "@radix-ui/react-slot"
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
|
@ -17,40 +17,40 @@ const buttonVariants = cva(
|
||||||
secondary:
|
secondary:
|
||||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||||
link: "text-primary underline-offset-4 hover:underline",
|
link: "text-primary underline-offset-4 hover:underline"
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "h-10 px-4 py-2",
|
default: "h-10 px-4 py-2",
|
||||||
sm: "h-9 rounded-md px-3",
|
sm: "h-9 rounded-md px-3",
|
||||||
lg: "h-11 rounded-md px-8",
|
lg: "h-11 rounded-md px-8",
|
||||||
icon: "h-10 w-10",
|
icon: "h-10 w-10"
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: "default",
|
||||||
size: "default",
|
size: "default"
|
||||||
},
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export interface ButtonProps
|
export interface ButtonProps
|
||||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||||
VariantProps<typeof buttonVariants> {
|
VariantProps<typeof buttonVariants> {
|
||||||
asChild?: boolean
|
asChild?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||||
const Comp = asChild ? Slot : "button"
|
const Comp = asChild ? Slot : "button";
|
||||||
return (
|
return (
|
||||||
<Comp
|
<Comp
|
||||||
className={cn(buttonVariants({ variant, size, className }))}
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
Button.displayName = "Button"
|
Button.displayName = "Button";
|
||||||
|
|
||||||
export { Button, buttonVariants }
|
export { Button, buttonVariants };
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Card = React.forwardRef<
|
const Card = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
|
@ -14,8 +14,8 @@ const Card = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Card.displayName = "Card"
|
Card.displayName = "Card";
|
||||||
|
|
||||||
const CardHeader = React.forwardRef<
|
const CardHeader = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
|
@ -26,8 +26,8 @@ const CardHeader = React.forwardRef<
|
||||||
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
CardHeader.displayName = "CardHeader"
|
CardHeader.displayName = "CardHeader";
|
||||||
|
|
||||||
const CardTitle = React.forwardRef<
|
const CardTitle = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
|
@ -41,8 +41,8 @@ const CardTitle = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
CardTitle.displayName = "CardTitle"
|
CardTitle.displayName = "CardTitle";
|
||||||
|
|
||||||
const CardDescription = React.forwardRef<
|
const CardDescription = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
|
@ -53,16 +53,16 @@ const CardDescription = React.forwardRef<
|
||||||
className={cn("text-sm text-muted-foreground", className)}
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
CardDescription.displayName = "CardDescription"
|
CardDescription.displayName = "CardDescription";
|
||||||
|
|
||||||
const CardContent = React.forwardRef<
|
const CardContent = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
React.HTMLAttributes<HTMLDivElement>
|
React.HTMLAttributes<HTMLDivElement>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||||||
))
|
));
|
||||||
CardContent.displayName = "CardContent"
|
CardContent.displayName = "CardContent";
|
||||||
|
|
||||||
const CardFooter = React.forwardRef<
|
const CardFooter = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
|
@ -73,7 +73,14 @@ const CardFooter = React.forwardRef<
|
||||||
className={cn("flex items-center p-6 pt-0", className)}
|
className={cn("flex items-center p-6 pt-0", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
CardFooter.displayName = "CardFooter"
|
CardFooter.displayName = "CardFooter";
|
||||||
|
|
||||||
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
export {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardFooter,
|
||||||
|
CardTitle,
|
||||||
|
CardDescription,
|
||||||
|
CardContent
|
||||||
|
};
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||||
import { X } from "lucide-react"
|
import { X } from "lucide-react";
|
||||||
|
|
||||||
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<
|
const DialogOverlay = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||||
|
@ -26,8 +26,8 @@ const DialogOverlay = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
const DialogContent = React.forwardRef<
|
const DialogContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
|
@ -50,8 +50,8 @@ const DialogContent = React.forwardRef<
|
||||||
</DialogPrimitive.Close>
|
</DialogPrimitive.Close>
|
||||||
</DialogPrimitive.Content>
|
</DialogPrimitive.Content>
|
||||||
</DialogPortal>
|
</DialogPortal>
|
||||||
))
|
));
|
||||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||||
|
|
||||||
const DialogHeader = ({
|
const DialogHeader = ({
|
||||||
className,
|
className,
|
||||||
|
@ -64,8 +64,8 @@ const DialogHeader = ({
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
DialogHeader.displayName = "DialogHeader"
|
DialogHeader.displayName = "DialogHeader";
|
||||||
|
|
||||||
const DialogFooter = ({
|
const DialogFooter = ({
|
||||||
className,
|
className,
|
||||||
|
@ -78,8 +78,8 @@ const DialogFooter = ({
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
DialogFooter.displayName = "DialogFooter"
|
DialogFooter.displayName = "DialogFooter";
|
||||||
|
|
||||||
const DialogTitle = React.forwardRef<
|
const DialogTitle = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||||
|
@ -93,8 +93,8 @@ const DialogTitle = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||||
|
|
||||||
const DialogDescription = React.forwardRef<
|
const DialogDescription = React.forwardRef<
|
||||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||||
|
@ -105,8 +105,8 @@ const DialogDescription = React.forwardRef<
|
||||||
className={cn("text-sm text-muted-foreground", className)}
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Dialog,
|
Dialog,
|
||||||
|
@ -118,5 +118,5 @@ export {
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogDescription,
|
DialogDescription
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
import { Check, ChevronRight, Circle } from "lucide-react";
|
||||||
|
|
||||||
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<
|
const DropdownMenuSubTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, children, ...props }, ref) => (
|
>(({ className, inset, children, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.SubTrigger
|
<DropdownMenuPrimitive.SubTrigger
|
||||||
|
@ -36,9 +36,9 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
||||||
{children}
|
{children}
|
||||||
<ChevronRight className="ml-auto h-4 w-4" />
|
<ChevronRight className="ml-auto h-4 w-4" />
|
||||||
</DropdownMenuPrimitive.SubTrigger>
|
</DropdownMenuPrimitive.SubTrigger>
|
||||||
))
|
));
|
||||||
DropdownMenuSubTrigger.displayName =
|
DropdownMenuSubTrigger.displayName =
|
||||||
DropdownMenuPrimitive.SubTrigger.displayName
|
DropdownMenuPrimitive.SubTrigger.displayName;
|
||||||
|
|
||||||
const DropdownMenuSubContent = React.forwardRef<
|
const DropdownMenuSubContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||||
|
@ -52,9 +52,9 @@ const DropdownMenuSubContent = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuSubContent.displayName =
|
DropdownMenuSubContent.displayName =
|
||||||
DropdownMenuPrimitive.SubContent.displayName
|
DropdownMenuPrimitive.SubContent.displayName;
|
||||||
|
|
||||||
const DropdownMenuContent = React.forwardRef<
|
const DropdownMenuContent = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||||
|
@ -71,13 +71,13 @@ const DropdownMenuContent = React.forwardRef<
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuPrimitive.Portal>
|
</DropdownMenuPrimitive.Portal>
|
||||||
))
|
));
|
||||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
|
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
||||||
|
|
||||||
const DropdownMenuItem = React.forwardRef<
|
const DropdownMenuItem = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, ...props }, ref) => (
|
>(({ className, inset, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.Item
|
<DropdownMenuPrimitive.Item
|
||||||
|
@ -89,8 +89,8 @@ const DropdownMenuItem = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
|
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
||||||
|
|
||||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||||
|
@ -112,9 +112,9 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
||||||
</span>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</DropdownMenuPrimitive.CheckboxItem>
|
</DropdownMenuPrimitive.CheckboxItem>
|
||||||
))
|
));
|
||||||
DropdownMenuCheckboxItem.displayName =
|
DropdownMenuCheckboxItem.displayName =
|
||||||
DropdownMenuPrimitive.CheckboxItem.displayName
|
DropdownMenuPrimitive.CheckboxItem.displayName;
|
||||||
|
|
||||||
const DropdownMenuRadioItem = React.forwardRef<
|
const DropdownMenuRadioItem = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||||
|
@ -135,13 +135,13 @@ const DropdownMenuRadioItem = React.forwardRef<
|
||||||
</span>
|
</span>
|
||||||
{children}
|
{children}
|
||||||
</DropdownMenuPrimitive.RadioItem>
|
</DropdownMenuPrimitive.RadioItem>
|
||||||
))
|
));
|
||||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
|
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
||||||
|
|
||||||
const DropdownMenuLabel = React.forwardRef<
|
const DropdownMenuLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||||
inset?: boolean
|
inset?: boolean;
|
||||||
}
|
}
|
||||||
>(({ className, inset, ...props }, ref) => (
|
>(({ className, inset, ...props }, ref) => (
|
||||||
<DropdownMenuPrimitive.Label
|
<DropdownMenuPrimitive.Label
|
||||||
|
@ -153,8 +153,8 @@ const DropdownMenuLabel = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
|
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
||||||
|
|
||||||
const DropdownMenuSeparator = React.forwardRef<
|
const DropdownMenuSeparator = React.forwardRef<
|
||||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||||
|
@ -165,8 +165,8 @@ const DropdownMenuSeparator = React.forwardRef<
|
||||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
|
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
||||||
|
|
||||||
const DropdownMenuShortcut = ({
|
const DropdownMenuShortcut = ({
|
||||||
className,
|
className,
|
||||||
|
@ -177,9 +177,9 @@ const DropdownMenuShortcut = ({
|
||||||
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
|
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
@ -196,5 +196,5 @@ export {
|
||||||
DropdownMenuSub,
|
DropdownMenuSub,
|
||||||
DropdownMenuSubContent,
|
DropdownMenuSubContent,
|
||||||
DropdownMenuSubTrigger,
|
DropdownMenuSubTrigger,
|
||||||
DropdownMenuRadioGroup,
|
DropdownMenuRadioGroup
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||||
import { Slot } from "@radix-ui/react-slot"
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
import {
|
import {
|
||||||
Controller,
|
Controller,
|
||||||
ControllerProps,
|
ControllerProps,
|
||||||
FieldPath,
|
FieldPath,
|
||||||
FieldValues,
|
FieldValues,
|
||||||
FormProvider,
|
FormProvider,
|
||||||
useFormContext,
|
useFormContext
|
||||||
} from "react-hook-form"
|
} from "react-hook-form";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label";
|
||||||
|
|
||||||
const Form = FormProvider
|
const Form = FormProvider;
|
||||||
|
|
||||||
type FormFieldContextValue<
|
type FormFieldContextValue<
|
||||||
TFieldValues extends FieldValues = FieldValues,
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
||||||
> = {
|
> = {
|
||||||
name: TName
|
name: TName;
|
||||||
}
|
};
|
||||||
|
|
||||||
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
const FormFieldContext = React.createContext<FormFieldContextValue>(
|
||||||
{} as FormFieldContextValue
|
{} as FormFieldContextValue
|
||||||
)
|
);
|
||||||
|
|
||||||
const FormField = <
|
const FormField = <
|
||||||
TFieldValues extends FieldValues = FieldValues,
|
TFieldValues extends FieldValues = FieldValues,
|
||||||
|
@ -36,21 +36,21 @@ const FormField = <
|
||||||
<FormFieldContext.Provider value={{ name: props.name }}>
|
<FormFieldContext.Provider value={{ name: props.name }}>
|
||||||
<Controller {...props} />
|
<Controller {...props} />
|
||||||
</FormFieldContext.Provider>
|
</FormFieldContext.Provider>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const useFormField = () => {
|
const useFormField = () => {
|
||||||
const fieldContext = React.useContext(FormFieldContext)
|
const fieldContext = React.useContext(FormFieldContext);
|
||||||
const itemContext = React.useContext(FormItemContext)
|
const itemContext = React.useContext(FormItemContext);
|
||||||
const { getFieldState, formState } = useFormContext()
|
const { getFieldState, formState } = useFormContext();
|
||||||
|
|
||||||
const fieldState = getFieldState(fieldContext.name, formState)
|
const fieldState = getFieldState(fieldContext.name, formState);
|
||||||
|
|
||||||
if (!fieldContext) {
|
if (!fieldContext) {
|
||||||
throw new Error("useFormField should be used within <FormField>")
|
throw new Error("useFormField should be used within <FormField>");
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id } = itemContext
|
const { id } = itemContext;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
|
@ -58,37 +58,37 @@ const useFormField = () => {
|
||||||
formItemId: `${id}-form-item`,
|
formItemId: `${id}-form-item`,
|
||||||
formDescriptionId: `${id}-form-item-description`,
|
formDescriptionId: `${id}-form-item-description`,
|
||||||
formMessageId: `${id}-form-item-message`,
|
formMessageId: `${id}-form-item-message`,
|
||||||
...fieldState,
|
...fieldState
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
type FormItemContextValue = {
|
type FormItemContextValue = {
|
||||||
id: string
|
id: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
const FormItemContext = React.createContext<FormItemContextValue>(
|
const FormItemContext = React.createContext<FormItemContextValue>(
|
||||||
{} as FormItemContextValue
|
{} as FormItemContextValue
|
||||||
)
|
);
|
||||||
|
|
||||||
const FormItem = React.forwardRef<
|
const FormItem = React.forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
React.HTMLAttributes<HTMLDivElement>
|
React.HTMLAttributes<HTMLDivElement>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const id = React.useId()
|
const id = React.useId();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormItemContext.Provider value={{ id }}>
|
<FormItemContext.Provider value={{ id }}>
|
||||||
<div ref={ref} className={cn("space-y-2", className)} {...props} />
|
<div ref={ref} className={cn("space-y-2", className)} {...props} />
|
||||||
</FormItemContext.Provider>
|
</FormItemContext.Provider>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormItem.displayName = "FormItem"
|
FormItem.displayName = "FormItem";
|
||||||
|
|
||||||
const FormLabel = React.forwardRef<
|
const FormLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const { error, formItemId } = useFormField()
|
const { error, formItemId } = useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Label
|
<Label
|
||||||
|
@ -97,15 +97,16 @@ const FormLabel = React.forwardRef<
|
||||||
htmlFor={formItemId}
|
htmlFor={formItemId}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormLabel.displayName = "FormLabel"
|
FormLabel.displayName = "FormLabel";
|
||||||
|
|
||||||
const FormControl = React.forwardRef<
|
const FormControl = React.forwardRef<
|
||||||
React.ElementRef<typeof Slot>,
|
React.ElementRef<typeof Slot>,
|
||||||
React.ComponentPropsWithoutRef<typeof Slot>
|
React.ComponentPropsWithoutRef<typeof Slot>
|
||||||
>(({ ...props }, ref) => {
|
>(({ ...props }, ref) => {
|
||||||
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
|
const { error, formItemId, formDescriptionId, formMessageId } =
|
||||||
|
useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slot
|
<Slot
|
||||||
|
@ -119,15 +120,15 @@ const FormControl = React.forwardRef<
|
||||||
aria-invalid={!!error}
|
aria-invalid={!!error}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormControl.displayName = "FormControl"
|
FormControl.displayName = "FormControl";
|
||||||
|
|
||||||
const FormDescription = React.forwardRef<
|
const FormDescription = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
React.HTMLAttributes<HTMLParagraphElement>
|
React.HTMLAttributes<HTMLParagraphElement>
|
||||||
>(({ className, ...props }, ref) => {
|
>(({ className, ...props }, ref) => {
|
||||||
const { formDescriptionId } = useFormField()
|
const { formDescriptionId } = useFormField();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p
|
<p
|
||||||
|
@ -136,19 +137,19 @@ const FormDescription = React.forwardRef<
|
||||||
className={cn("text-sm text-muted-foreground", className)}
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormDescription.displayName = "FormDescription"
|
FormDescription.displayName = "FormDescription";
|
||||||
|
|
||||||
const FormMessage = React.forwardRef<
|
const FormMessage = React.forwardRef<
|
||||||
HTMLParagraphElement,
|
HTMLParagraphElement,
|
||||||
React.HTMLAttributes<HTMLParagraphElement>
|
React.HTMLAttributes<HTMLParagraphElement>
|
||||||
>(({ className, children, ...props }, ref) => {
|
>(({ className, children, ...props }, ref) => {
|
||||||
const { error, formMessageId } = useFormField()
|
const { error, formMessageId } = useFormField();
|
||||||
const body = error ? String(error?.message) : children
|
const body = error ? String(error?.message) : children;
|
||||||
|
|
||||||
if (!body) {
|
if (!body) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -160,9 +161,9 @@ const FormMessage = React.forwardRef<
|
||||||
>
|
>
|
||||||
{body}
|
{body}
|
||||||
</p>
|
</p>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
FormMessage.displayName = "FormMessage"
|
FormMessage.displayName = "FormMessage";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useFormField,
|
useFormField,
|
||||||
|
@ -172,5 +173,5 @@ export {
|
||||||
FormControl,
|
FormControl,
|
||||||
FormDescription,
|
FormDescription,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
FormField,
|
FormField
|
||||||
}
|
};
|
||||||
|
|
|
@ -29,7 +29,7 @@ export function GridPattern({
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
className={cn(
|
className={cn(
|
||||||
"pointer-events-none absolute inset-0 h-full w-full fill-gray-400/35 stroke-gray-400/35",
|
"pointer-events-none absolute inset-0 h-full w-full fill-gray-400/35 stroke-gray-400/35",
|
||||||
className,
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
|
@ -26,50 +26,50 @@ const animationVariants = {
|
||||||
"from-bottom": {
|
"from-bottom": {
|
||||||
initial: { y: "100%", opacity: 0 },
|
initial: { y: "100%", opacity: 0 },
|
||||||
animate: { y: 0, opacity: 1 },
|
animate: { y: 0, opacity: 1 },
|
||||||
exit: { y: "100%", opacity: 0 },
|
exit: { y: "100%", opacity: 0 }
|
||||||
},
|
},
|
||||||
"from-center": {
|
"from-center": {
|
||||||
initial: { scale: 0.5, opacity: 0 },
|
initial: { scale: 0.5, opacity: 0 },
|
||||||
animate: { scale: 1, opacity: 1 },
|
animate: { scale: 1, opacity: 1 },
|
||||||
exit: { scale: 0.5, opacity: 0 },
|
exit: { scale: 0.5, opacity: 0 }
|
||||||
},
|
},
|
||||||
"from-top": {
|
"from-top": {
|
||||||
initial: { y: "-100%", opacity: 0 },
|
initial: { y: "-100%", opacity: 0 },
|
||||||
animate: { y: 0, opacity: 1 },
|
animate: { y: 0, opacity: 1 },
|
||||||
exit: { y: "-100%", opacity: 0 },
|
exit: { y: "-100%", opacity: 0 }
|
||||||
},
|
},
|
||||||
"from-left": {
|
"from-left": {
|
||||||
initial: { x: "-100%", opacity: 0 },
|
initial: { x: "-100%", opacity: 0 },
|
||||||
animate: { x: 0, opacity: 1 },
|
animate: { x: 0, opacity: 1 },
|
||||||
exit: { x: "-100%", opacity: 0 },
|
exit: { x: "-100%", opacity: 0 }
|
||||||
},
|
},
|
||||||
"from-right": {
|
"from-right": {
|
||||||
initial: { x: "100%", opacity: 0 },
|
initial: { x: "100%", opacity: 0 },
|
||||||
animate: { x: 0, opacity: 1 },
|
animate: { x: 0, opacity: 1 },
|
||||||
exit: { x: "100%", opacity: 0 },
|
exit: { x: "100%", opacity: 0 }
|
||||||
},
|
},
|
||||||
fade: {
|
fade: {
|
||||||
initial: { opacity: 0 },
|
initial: { opacity: 0 },
|
||||||
animate: { opacity: 1 },
|
animate: { opacity: 1 },
|
||||||
exit: { opacity: 0 },
|
exit: { opacity: 0 }
|
||||||
},
|
},
|
||||||
"top-in-bottom-out": {
|
"top-in-bottom-out": {
|
||||||
initial: { y: "-100%", opacity: 0 },
|
initial: { y: "-100%", opacity: 0 },
|
||||||
animate: { y: 0, opacity: 1 },
|
animate: { y: 0, opacity: 1 },
|
||||||
exit: { y: "100%", opacity: 0 },
|
exit: { y: "100%", opacity: 0 }
|
||||||
},
|
},
|
||||||
"left-in-right-out": {
|
"left-in-right-out": {
|
||||||
initial: { x: "-100%", opacity: 0 },
|
initial: { x: "-100%", opacity: 0 },
|
||||||
animate: { x: 0, opacity: 1 },
|
animate: { x: 0, opacity: 1 },
|
||||||
exit: { x: "100%", opacity: 0 },
|
exit: { x: "100%", opacity: 0 }
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function HeroVideoDialog({
|
export default function HeroVideoDialog({
|
||||||
animationStyle = "from-center",
|
animationStyle = "from-center",
|
||||||
videoSrc,
|
videoSrc,
|
||||||
thumbnailSrc,
|
thumbnailSrc,
|
||||||
thumbnailAlt = "Video thumbnail",
|
thumbnailAlt = "Video thumbnail"
|
||||||
}: HeroVideoProps) {
|
}: HeroVideoProps) {
|
||||||
const [isVideoOpen, setIsVideoOpen] = useState(false);
|
const [isVideoOpen, setIsVideoOpen] = useState(false);
|
||||||
const [isCloseHovered, setIsCloseHovered] = useState(false);
|
const [isCloseHovered, setIsCloseHovered] = useState(false);
|
||||||
|
@ -105,7 +105,7 @@ export default function HeroVideoDialog({
|
||||||
className="size-8 text-white"
|
className="size-8 text-white"
|
||||||
style={{
|
style={{
|
||||||
transform: isPlayHovered ? "scale(1.1)" : "scale(1)",
|
transform: isPlayHovered ? "scale(1.1)" : "scale(1)",
|
||||||
transition: "transform 0.3s ease",
|
transition: "transform 0.3s ease"
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,9 +10,9 @@ const Iconss = () => {
|
||||||
x: "https://x.com/SVR_JS",
|
x: "https://x.com/SVR_JS",
|
||||||
Mastodon: "https://mastodon.social/@svrjs",
|
Mastodon: "https://mastodon.social/@svrjs",
|
||||||
Bluesky: "https://bsky.app/profile/svrjs.org",
|
Bluesky: "https://bsky.app/profile/svrjs.org",
|
||||||
Odysee: "https://odysee.com/@SVRJS",
|
Odysee: "https://odysee.com/@SVRJS"
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -22,7 +22,7 @@ const Iconss = () => {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className={buttonVariants({
|
className={buttonVariants({
|
||||||
variant: "ghost",
|
variant: "ghost",
|
||||||
size: "sm",
|
size: "sm"
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<span className="sr-only">X icon</span>
|
<span className="sr-only">X icon</span>
|
||||||
|
@ -44,7 +44,7 @@ const Iconss = () => {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className={buttonVariants({
|
className={buttonVariants({
|
||||||
variant: "ghost",
|
variant: "ghost",
|
||||||
size: "sm",
|
size: "sm"
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<span className="sr-only">Mastodon icon</span>
|
<span className="sr-only">Mastodon icon</span>
|
||||||
|
@ -68,7 +68,7 @@ const Iconss = () => {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className={buttonVariants({
|
className={buttonVariants({
|
||||||
variant: "ghost",
|
variant: "ghost",
|
||||||
size: "sm",
|
size: "sm"
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<span className="sr-only">Bluesky icon</span>
|
<span className="sr-only">Bluesky icon</span>
|
||||||
|
@ -92,7 +92,7 @@ const Iconss = () => {
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className={buttonVariants({
|
className={buttonVariants({
|
||||||
variant: "ghost",
|
variant: "ghost",
|
||||||
size: "sm",
|
size: "sm"
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<span className="sr-only">Odysee icon</span>
|
<span className="sr-only">Odysee icon</span>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export interface InputProps
|
export interface InputProps
|
||||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||||
|
@ -17,9 +17,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
Input.displayName = "Input"
|
Input.displayName = "Input";
|
||||||
|
|
||||||
export { Input }
|
export { Input };
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label"
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const labelVariants = cva(
|
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<
|
const Label = React.forwardRef<
|
||||||
React.ElementRef<typeof LabelPrimitive.Root>,
|
React.ElementRef<typeof LabelPrimitive.Root>,
|
||||||
|
@ -20,7 +20,7 @@ const Label = React.forwardRef<
|
||||||
className={cn(labelVariants(), className)}
|
className={cn(labelVariants(), className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
Label.displayName = LabelPrimitive.Root.displayName
|
Label.displayName = LabelPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Label }
|
export { Label };
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
|
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
|
||||||
import { cva } from "class-variance-authority"
|
import { cva } from "class-variance-authority";
|
||||||
import { ChevronDown } from "lucide-react"
|
import { ChevronDown } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const NavigationMenu = React.forwardRef<
|
const NavigationMenu = React.forwardRef<
|
||||||
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
|
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
|
||||||
|
@ -20,8 +20,8 @@ const NavigationMenu = React.forwardRef<
|
||||||
{children}
|
{children}
|
||||||
<NavigationMenuViewport />
|
<NavigationMenuViewport />
|
||||||
</NavigationMenuPrimitive.Root>
|
</NavigationMenuPrimitive.Root>
|
||||||
))
|
));
|
||||||
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
|
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
|
||||||
|
|
||||||
const NavigationMenuList = React.forwardRef<
|
const NavigationMenuList = React.forwardRef<
|
||||||
React.ElementRef<typeof NavigationMenuPrimitive.List>,
|
React.ElementRef<typeof NavigationMenuPrimitive.List>,
|
||||||
|
@ -35,14 +35,14 @@ const NavigationMenuList = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
|
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
|
||||||
|
|
||||||
const NavigationMenuItem = NavigationMenuPrimitive.Item
|
const NavigationMenuItem = NavigationMenuPrimitive.Item;
|
||||||
|
|
||||||
const navigationMenuTriggerStyle = cva(
|
const navigationMenuTriggerStyle = cva(
|
||||||
"group inline-flex h-10 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-10 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<
|
const NavigationMenuTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
|
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
|
||||||
|
@ -59,8 +59,8 @@ const NavigationMenuTrigger = React.forwardRef<
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</NavigationMenuPrimitive.Trigger>
|
</NavigationMenuPrimitive.Trigger>
|
||||||
))
|
));
|
||||||
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
|
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
const NavigationMenuContent = React.forwardRef<
|
const NavigationMenuContent = React.forwardRef<
|
||||||
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
|
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
|
||||||
|
@ -74,10 +74,10 @@ const NavigationMenuContent = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName
|
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
|
||||||
|
|
||||||
const NavigationMenuLink = NavigationMenuPrimitive.Link
|
const NavigationMenuLink = NavigationMenuPrimitive.Link;
|
||||||
|
|
||||||
const NavigationMenuViewport = React.forwardRef<
|
const NavigationMenuViewport = React.forwardRef<
|
||||||
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
|
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
|
||||||
|
@ -93,9 +93,9 @@ const NavigationMenuViewport = React.forwardRef<
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))
|
));
|
||||||
NavigationMenuViewport.displayName =
|
NavigationMenuViewport.displayName =
|
||||||
NavigationMenuPrimitive.Viewport.displayName
|
NavigationMenuPrimitive.Viewport.displayName;
|
||||||
|
|
||||||
const NavigationMenuIndicator = React.forwardRef<
|
const NavigationMenuIndicator = React.forwardRef<
|
||||||
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
|
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
|
||||||
|
@ -111,9 +111,9 @@ const NavigationMenuIndicator = React.forwardRef<
|
||||||
>
|
>
|
||||||
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
|
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
|
||||||
</NavigationMenuPrimitive.Indicator>
|
</NavigationMenuPrimitive.Indicator>
|
||||||
))
|
));
|
||||||
NavigationMenuIndicator.displayName =
|
NavigationMenuIndicator.displayName =
|
||||||
NavigationMenuPrimitive.Indicator.displayName
|
NavigationMenuPrimitive.Indicator.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
navigationMenuTriggerStyle,
|
navigationMenuTriggerStyle,
|
||||||
|
@ -124,5 +124,5 @@ export {
|
||||||
NavigationMenuTrigger,
|
NavigationMenuTrigger,
|
||||||
NavigationMenuLink,
|
NavigationMenuLink,
|
||||||
NavigationMenuIndicator,
|
NavigationMenuIndicator,
|
||||||
NavigationMenuViewport,
|
NavigationMenuViewport
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"
|
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
import { ButtonProps, buttonVariants } from "@/components/ui/button"
|
import { ButtonProps, buttonVariants } from "@/components/ui/button";
|
||||||
|
|
||||||
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
|
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
|
||||||
<nav
|
<nav
|
||||||
|
@ -11,8 +11,8 @@ const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
|
||||||
className={cn("mx-auto flex w-full justify-center", className)}
|
className={cn("mx-auto flex w-full justify-center", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
Pagination.displayName = "Pagination"
|
Pagination.displayName = "Pagination";
|
||||||
|
|
||||||
const PaginationContent = React.forwardRef<
|
const PaginationContent = React.forwardRef<
|
||||||
HTMLUListElement,
|
HTMLUListElement,
|
||||||
|
@ -23,21 +23,21 @@ const PaginationContent = React.forwardRef<
|
||||||
className={cn("flex flex-row items-center gap-1", className)}
|
className={cn("flex flex-row items-center gap-1", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
PaginationContent.displayName = "PaginationContent"
|
PaginationContent.displayName = "PaginationContent";
|
||||||
|
|
||||||
const PaginationItem = React.forwardRef<
|
const PaginationItem = React.forwardRef<
|
||||||
HTMLLIElement,
|
HTMLLIElement,
|
||||||
React.ComponentProps<"li">
|
React.ComponentProps<"li">
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<li ref={ref} className={cn("", className)} {...props} />
|
<li ref={ref} className={cn("", className)} {...props} />
|
||||||
))
|
));
|
||||||
PaginationItem.displayName = "PaginationItem"
|
PaginationItem.displayName = "PaginationItem";
|
||||||
|
|
||||||
type PaginationLinkProps = {
|
type PaginationLinkProps = {
|
||||||
isActive?: boolean
|
isActive?: boolean;
|
||||||
} & Pick<ButtonProps, "size"> &
|
} & Pick<ButtonProps, "size"> &
|
||||||
React.ComponentProps<"a">
|
React.ComponentProps<"a">;
|
||||||
|
|
||||||
const PaginationLink = ({
|
const PaginationLink = ({
|
||||||
className,
|
className,
|
||||||
|
@ -50,14 +50,14 @@ const PaginationLink = ({
|
||||||
className={cn(
|
className={cn(
|
||||||
buttonVariants({
|
buttonVariants({
|
||||||
variant: isActive ? "outline" : "ghost",
|
variant: isActive ? "outline" : "ghost",
|
||||||
size,
|
size
|
||||||
}),
|
}),
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
PaginationLink.displayName = "PaginationLink"
|
PaginationLink.displayName = "PaginationLink";
|
||||||
|
|
||||||
const PaginationPrevious = ({
|
const PaginationPrevious = ({
|
||||||
className,
|
className,
|
||||||
|
@ -72,8 +72,8 @@ const PaginationPrevious = ({
|
||||||
<ChevronLeft className="h-4 w-4" />
|
<ChevronLeft className="h-4 w-4" />
|
||||||
<span>Previous</span>
|
<span>Previous</span>
|
||||||
</PaginationLink>
|
</PaginationLink>
|
||||||
)
|
);
|
||||||
PaginationPrevious.displayName = "PaginationPrevious"
|
PaginationPrevious.displayName = "PaginationPrevious";
|
||||||
|
|
||||||
const PaginationNext = ({
|
const PaginationNext = ({
|
||||||
className,
|
className,
|
||||||
|
@ -88,8 +88,8 @@ const PaginationNext = ({
|
||||||
<span>Next</span>
|
<span>Next</span>
|
||||||
<ChevronRight className="h-4 w-4" />
|
<ChevronRight className="h-4 w-4" />
|
||||||
</PaginationLink>
|
</PaginationLink>
|
||||||
)
|
);
|
||||||
PaginationNext.displayName = "PaginationNext"
|
PaginationNext.displayName = "PaginationNext";
|
||||||
|
|
||||||
const PaginationEllipsis = ({
|
const PaginationEllipsis = ({
|
||||||
className,
|
className,
|
||||||
|
@ -103,8 +103,8 @@ const PaginationEllipsis = ({
|
||||||
<MoreHorizontal className="h-4 w-4" />
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
<span className="sr-only">More pages</span>
|
<span className="sr-only">More pages</span>
|
||||||
</span>
|
</span>
|
||||||
)
|
);
|
||||||
PaginationEllipsis.displayName = "PaginationEllipsis"
|
PaginationEllipsis.displayName = "PaginationEllipsis";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Pagination,
|
Pagination,
|
||||||
|
@ -113,5 +113,5 @@ export {
|
||||||
PaginationItem,
|
PaginationItem,
|
||||||
PaginationLink,
|
PaginationLink,
|
||||||
PaginationNext,
|
PaginationNext,
|
||||||
PaginationPrevious,
|
PaginationPrevious
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
||||||
import { Check, ChevronDown, ChevronUp } from "lucide-react"
|
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
||||||
|
|
||||||
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<
|
const SelectTrigger = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||||
|
@ -29,8 +29,8 @@ const SelectTrigger = React.forwardRef<
|
||||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||||
</SelectPrimitive.Icon>
|
</SelectPrimitive.Icon>
|
||||||
</SelectPrimitive.Trigger>
|
</SelectPrimitive.Trigger>
|
||||||
))
|
));
|
||||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
const SelectScrollUpButton = React.forwardRef<
|
const SelectScrollUpButton = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
|
||||||
|
@ -46,8 +46,8 @@ const SelectScrollUpButton = React.forwardRef<
|
||||||
>
|
>
|
||||||
<ChevronUp className="h-4 w-4" />
|
<ChevronUp className="h-4 w-4" />
|
||||||
</SelectPrimitive.ScrollUpButton>
|
</SelectPrimitive.ScrollUpButton>
|
||||||
))
|
));
|
||||||
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
||||||
|
|
||||||
const SelectScrollDownButton = React.forwardRef<
|
const SelectScrollDownButton = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
|
||||||
|
@ -63,9 +63,9 @@ const SelectScrollDownButton = React.forwardRef<
|
||||||
>
|
>
|
||||||
<ChevronDown className="h-4 w-4" />
|
<ChevronDown className="h-4 w-4" />
|
||||||
</SelectPrimitive.ScrollDownButton>
|
</SelectPrimitive.ScrollDownButton>
|
||||||
))
|
));
|
||||||
SelectScrollDownButton.displayName =
|
SelectScrollDownButton.displayName =
|
||||||
SelectPrimitive.ScrollDownButton.displayName
|
SelectPrimitive.ScrollDownButton.displayName;
|
||||||
|
|
||||||
const SelectContent = React.forwardRef<
|
const SelectContent = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||||
|
@ -96,8 +96,8 @@ const SelectContent = React.forwardRef<
|
||||||
<SelectScrollDownButton />
|
<SelectScrollDownButton />
|
||||||
</SelectPrimitive.Content>
|
</SelectPrimitive.Content>
|
||||||
</SelectPrimitive.Portal>
|
</SelectPrimitive.Portal>
|
||||||
))
|
));
|
||||||
SelectContent.displayName = SelectPrimitive.Content.displayName
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||||
|
|
||||||
const SelectLabel = React.forwardRef<
|
const SelectLabel = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||||
|
@ -108,8 +108,8 @@ const SelectLabel = React.forwardRef<
|
||||||
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
|
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
||||||
|
|
||||||
const SelectItem = React.forwardRef<
|
const SelectItem = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||||
|
@ -131,8 +131,8 @@ const SelectItem = React.forwardRef<
|
||||||
|
|
||||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
</SelectPrimitive.Item>
|
</SelectPrimitive.Item>
|
||||||
))
|
));
|
||||||
SelectItem.displayName = SelectPrimitive.Item.displayName
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||||
|
|
||||||
const SelectSeparator = React.forwardRef<
|
const SelectSeparator = React.forwardRef<
|
||||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||||
|
@ -143,8 +143,8 @@ const SelectSeparator = React.forwardRef<
|
||||||
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
className={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Select,
|
Select,
|
||||||
|
@ -156,5 +156,5 @@ export {
|
||||||
SelectItem,
|
SelectItem,
|
||||||
SelectSeparator,
|
SelectSeparator,
|
||||||
SelectScrollUpButton,
|
SelectScrollUpButton,
|
||||||
SelectScrollDownButton,
|
SelectScrollDownButton
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as SeparatorPrimitive from "@radix-ui/react-separator"
|
import * as SeparatorPrimitive from "@radix-ui/react-separator";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Separator = React.forwardRef<
|
const Separator = React.forwardRef<
|
||||||
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
React.ElementRef<typeof SeparatorPrimitive.Root>,
|
||||||
|
@ -25,7 +25,7 @@ const Separator = React.forwardRef<
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)
|
);
|
||||||
Separator.displayName = SeparatorPrimitive.Root.displayName
|
Separator.displayName = SeparatorPrimitive.Root.displayName;
|
||||||
|
|
||||||
export { Separator }
|
export { Separator };
|
||||||
|
|
|
@ -40,12 +40,12 @@ const sheetVariants = cva(
|
||||||
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-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",
|
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:
|
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",
|
"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: {
|
defaultVariants: {
|
||||||
side: "right",
|
side: "right"
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -136,5 +136,5 @@ export {
|
||||||
SheetHeader,
|
SheetHeader,
|
||||||
SheetFooter,
|
SheetFooter,
|
||||||
SheetTitle,
|
SheetTitle,
|
||||||
SheetDescription,
|
SheetDescription
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Skeleton({
|
function Skeleton({
|
||||||
className,
|
className,
|
||||||
|
@ -9,7 +9,7 @@ function Skeleton({
|
||||||
className={cn("animate-pulse rounded-md bg-muted", className)}
|
className={cn("animate-pulse rounded-md bg-muted", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Skeleton }
|
export { Skeleton };
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const Table = React.forwardRef<
|
const Table = React.forwardRef<
|
||||||
HTMLTableElement,
|
HTMLTableElement,
|
||||||
|
@ -13,16 +13,16 @@ const Table = React.forwardRef<
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))
|
));
|
||||||
Table.displayName = "Table"
|
Table.displayName = "Table";
|
||||||
|
|
||||||
const TableHeader = React.forwardRef<
|
const TableHeader = React.forwardRef<
|
||||||
HTMLTableSectionElement,
|
HTMLTableSectionElement,
|
||||||
React.HTMLAttributes<HTMLTableSectionElement>
|
React.HTMLAttributes<HTMLTableSectionElement>
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
||||||
))
|
));
|
||||||
TableHeader.displayName = "TableHeader"
|
TableHeader.displayName = "TableHeader";
|
||||||
|
|
||||||
const TableBody = React.forwardRef<
|
const TableBody = React.forwardRef<
|
||||||
HTMLTableSectionElement,
|
HTMLTableSectionElement,
|
||||||
|
@ -33,8 +33,8 @@ const TableBody = React.forwardRef<
|
||||||
className={cn("[&_tr:last-child]:border-0", className)}
|
className={cn("[&_tr:last-child]:border-0", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableBody.displayName = "TableBody"
|
TableBody.displayName = "TableBody";
|
||||||
|
|
||||||
const TableFooter = React.forwardRef<
|
const TableFooter = React.forwardRef<
|
||||||
HTMLTableSectionElement,
|
HTMLTableSectionElement,
|
||||||
|
@ -48,8 +48,8 @@ const TableFooter = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableFooter.displayName = "TableFooter"
|
TableFooter.displayName = "TableFooter";
|
||||||
|
|
||||||
const TableRow = React.forwardRef<
|
const TableRow = React.forwardRef<
|
||||||
HTMLTableRowElement,
|
HTMLTableRowElement,
|
||||||
|
@ -63,8 +63,8 @@ const TableRow = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableRow.displayName = "TableRow"
|
TableRow.displayName = "TableRow";
|
||||||
|
|
||||||
const TableHead = React.forwardRef<
|
const TableHead = React.forwardRef<
|
||||||
HTMLTableCellElement,
|
HTMLTableCellElement,
|
||||||
|
@ -78,8 +78,8 @@ const TableHead = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableHead.displayName = "TableHead"
|
TableHead.displayName = "TableHead";
|
||||||
|
|
||||||
const TableCell = React.forwardRef<
|
const TableCell = React.forwardRef<
|
||||||
HTMLTableCellElement,
|
HTMLTableCellElement,
|
||||||
|
@ -90,8 +90,8 @@ const TableCell = React.forwardRef<
|
||||||
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableCell.displayName = "TableCell"
|
TableCell.displayName = "TableCell";
|
||||||
|
|
||||||
const TableCaption = React.forwardRef<
|
const TableCaption = React.forwardRef<
|
||||||
HTMLTableCaptionElement,
|
HTMLTableCaptionElement,
|
||||||
|
@ -102,8 +102,8 @@ const TableCaption = React.forwardRef<
|
||||||
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
className={cn("mt-4 text-sm text-muted-foreground", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
TableCaption.displayName = "TableCaption"
|
TableCaption.displayName = "TableCaption";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Table,
|
Table,
|
||||||
|
@ -113,5 +113,5 @@ export {
|
||||||
TableHead,
|
TableHead,
|
||||||
TableRow,
|
TableRow,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableCaption,
|
TableCaption
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
export interface TextareaProps
|
export interface TextareaProps
|
||||||
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||||
|
@ -16,9 +16,9 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||||
ref={ref}
|
ref={ref}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
Textarea.displayName = "Textarea"
|
Textarea.displayName = "Textarea";
|
||||||
|
|
||||||
export { Textarea }
|
export { Textarea };
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { Moon, Sun } from "lucide-react";
|
import { Moon, Sun } from "lucide-react";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
import * as ToastPrimitives from "@radix-ui/react-toast"
|
import * as ToastPrimitives from "@radix-ui/react-toast";
|
||||||
import { cva, type VariantProps } from "class-variance-authority"
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
import { X } from "lucide-react"
|
import { X } from "lucide-react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const ToastProvider = ToastPrimitives.Provider
|
const ToastProvider = ToastPrimitives.Provider;
|
||||||
|
|
||||||
const ToastViewport = React.forwardRef<
|
const ToastViewport = React.forwardRef<
|
||||||
React.ElementRef<typeof ToastPrimitives.Viewport>,
|
React.ElementRef<typeof ToastPrimitives.Viewport>,
|
||||||
|
@ -21,8 +21,8 @@ const ToastViewport = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
|
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
|
||||||
|
|
||||||
const toastVariants = cva(
|
const toastVariants = cva(
|
||||||
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
|
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
|
||||||
|
@ -31,14 +31,14 @@ const toastVariants = cva(
|
||||||
variant: {
|
variant: {
|
||||||
default: "border bg-background text-foreground",
|
default: "border bg-background text-foreground",
|
||||||
destructive:
|
destructive:
|
||||||
"destructive group border-destructive bg-destructive text-destructive-foreground",
|
"destructive group border-destructive bg-destructive text-destructive-foreground"
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: "default"
|
||||||
},
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const Toast = React.forwardRef<
|
const Toast = React.forwardRef<
|
||||||
React.ElementRef<typeof ToastPrimitives.Root>,
|
React.ElementRef<typeof ToastPrimitives.Root>,
|
||||||
|
@ -51,9 +51,9 @@ const Toast = React.forwardRef<
|
||||||
className={cn(toastVariants({ variant }), className)}
|
className={cn(toastVariants({ variant }), className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
Toast.displayName = ToastPrimitives.Root.displayName
|
Toast.displayName = ToastPrimitives.Root.displayName;
|
||||||
|
|
||||||
const ToastAction = React.forwardRef<
|
const ToastAction = React.forwardRef<
|
||||||
React.ElementRef<typeof ToastPrimitives.Action>,
|
React.ElementRef<typeof ToastPrimitives.Action>,
|
||||||
|
@ -67,8 +67,8 @@ const ToastAction = React.forwardRef<
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
ToastAction.displayName = ToastPrimitives.Action.displayName
|
ToastAction.displayName = ToastPrimitives.Action.displayName;
|
||||||
|
|
||||||
const ToastClose = React.forwardRef<
|
const ToastClose = React.forwardRef<
|
||||||
React.ElementRef<typeof ToastPrimitives.Close>,
|
React.ElementRef<typeof ToastPrimitives.Close>,
|
||||||
|
@ -85,8 +85,8 @@ const ToastClose = React.forwardRef<
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
</ToastPrimitives.Close>
|
</ToastPrimitives.Close>
|
||||||
))
|
));
|
||||||
ToastClose.displayName = ToastPrimitives.Close.displayName
|
ToastClose.displayName = ToastPrimitives.Close.displayName;
|
||||||
|
|
||||||
const ToastTitle = React.forwardRef<
|
const ToastTitle = React.forwardRef<
|
||||||
React.ElementRef<typeof ToastPrimitives.Title>,
|
React.ElementRef<typeof ToastPrimitives.Title>,
|
||||||
|
@ -97,8 +97,8 @@ const ToastTitle = React.forwardRef<
|
||||||
className={cn("text-sm font-semibold", className)}
|
className={cn("text-sm font-semibold", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
ToastTitle.displayName = ToastPrimitives.Title.displayName
|
ToastTitle.displayName = ToastPrimitives.Title.displayName;
|
||||||
|
|
||||||
const ToastDescription = React.forwardRef<
|
const ToastDescription = React.forwardRef<
|
||||||
React.ElementRef<typeof ToastPrimitives.Description>,
|
React.ElementRef<typeof ToastPrimitives.Description>,
|
||||||
|
@ -109,12 +109,12 @@ const ToastDescription = React.forwardRef<
|
||||||
className={cn("text-sm opacity-90", className)}
|
className={cn("text-sm opacity-90", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
));
|
||||||
ToastDescription.displayName = ToastPrimitives.Description.displayName
|
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 {
|
export {
|
||||||
type ToastProps,
|
type ToastProps,
|
||||||
|
@ -125,5 +125,5 @@ export {
|
||||||
ToastTitle,
|
ToastTitle,
|
||||||
ToastDescription,
|
ToastDescription,
|
||||||
ToastClose,
|
ToastClose,
|
||||||
ToastAction,
|
ToastAction
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Toast,
|
Toast,
|
||||||
|
@ -6,12 +6,12 @@ import {
|
||||||
ToastDescription,
|
ToastDescription,
|
||||||
ToastProvider,
|
ToastProvider,
|
||||||
ToastTitle,
|
ToastTitle,
|
||||||
ToastViewport,
|
ToastViewport
|
||||||
} from "@/components/ui/toast"
|
} from "@/components/ui/toast";
|
||||||
import { useToast } from "@/components/ui/use-toast"
|
import { useToast } from "@/components/ui/use-toast";
|
||||||
|
|
||||||
export function Toaster() {
|
export function Toaster() {
|
||||||
const { toasts } = useToast()
|
const { toasts } = useToast();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToastProvider>
|
<ToastProvider>
|
||||||
|
@ -27,9 +27,9 @@ export function Toaster() {
|
||||||
{action}
|
{action}
|
||||||
<ToastClose />
|
<ToastClose />
|
||||||
</Toast>
|
</Toast>
|
||||||
)
|
);
|
||||||
})}
|
})}
|
||||||
<ToastViewport />
|
<ToastViewport />
|
||||||
</ToastProvider>
|
</ToastProvider>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,106 +1,103 @@
|
||||||
"use client"
|
"use client";
|
||||||
|
|
||||||
// Inspired by react-hot-toast library
|
// Inspired by react-hot-toast library
|
||||||
import * as React from "react"
|
import * as React from "react";
|
||||||
|
|
||||||
import type {
|
import type { ToastActionElement, ToastProps } from "@/components/ui/toast";
|
||||||
ToastActionElement,
|
|
||||||
ToastProps,
|
|
||||||
} from "@/components/ui/toast"
|
|
||||||
|
|
||||||
const TOAST_LIMIT = 1
|
const TOAST_LIMIT = 1;
|
||||||
const TOAST_REMOVE_DELAY = 1000000
|
const TOAST_REMOVE_DELAY = 1000000;
|
||||||
|
|
||||||
type ToasterToast = ToastProps & {
|
type ToasterToast = ToastProps & {
|
||||||
id: string
|
id: string;
|
||||||
title?: React.ReactNode
|
title?: React.ReactNode;
|
||||||
description?: React.ReactNode
|
description?: React.ReactNode;
|
||||||
action?: ToastActionElement
|
action?: ToastActionElement;
|
||||||
}
|
};
|
||||||
|
|
||||||
const actionTypes = {
|
const actionTypes = {
|
||||||
ADD_TOAST: "ADD_TOAST",
|
ADD_TOAST: "ADD_TOAST",
|
||||||
UPDATE_TOAST: "UPDATE_TOAST",
|
UPDATE_TOAST: "UPDATE_TOAST",
|
||||||
DISMISS_TOAST: "DISMISS_TOAST",
|
DISMISS_TOAST: "DISMISS_TOAST",
|
||||||
REMOVE_TOAST: "REMOVE_TOAST",
|
REMOVE_TOAST: "REMOVE_TOAST"
|
||||||
} as const
|
} as const;
|
||||||
|
|
||||||
let count = 0
|
let count = 0;
|
||||||
|
|
||||||
function genId() {
|
function genId() {
|
||||||
count = (count + 1) % Number.MAX_SAFE_INTEGER
|
count = (count + 1) % Number.MAX_SAFE_INTEGER;
|
||||||
return count.toString()
|
return count.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionType = typeof actionTypes
|
type ActionType = typeof actionTypes;
|
||||||
|
|
||||||
type Action =
|
type Action =
|
||||||
| {
|
| {
|
||||||
type: ActionType["ADD_TOAST"]
|
type: ActionType["ADD_TOAST"];
|
||||||
toast: ToasterToast
|
toast: ToasterToast;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: ActionType["UPDATE_TOAST"]
|
type: ActionType["UPDATE_TOAST"];
|
||||||
toast: Partial<ToasterToast>
|
toast: Partial<ToasterToast>;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: ActionType["DISMISS_TOAST"]
|
type: ActionType["DISMISS_TOAST"];
|
||||||
toastId?: ToasterToast["id"]
|
toastId?: ToasterToast["id"];
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: ActionType["REMOVE_TOAST"]
|
type: ActionType["REMOVE_TOAST"];
|
||||||
toastId?: ToasterToast["id"]
|
toastId?: ToasterToast["id"];
|
||||||
}
|
};
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
toasts: ToasterToast[]
|
toasts: ToasterToast[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>()
|
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
|
||||||
|
|
||||||
const addToRemoveQueue = (toastId: string) => {
|
const addToRemoveQueue = (toastId: string) => {
|
||||||
if (toastTimeouts.has(toastId)) {
|
if (toastTimeouts.has(toastId)) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
toastTimeouts.delete(toastId)
|
toastTimeouts.delete(toastId);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "REMOVE_TOAST",
|
type: "REMOVE_TOAST",
|
||||||
toastId: toastId,
|
toastId: toastId
|
||||||
})
|
});
|
||||||
}, TOAST_REMOVE_DELAY)
|
}, TOAST_REMOVE_DELAY);
|
||||||
|
|
||||||
toastTimeouts.set(toastId, timeout)
|
toastTimeouts.set(toastId, timeout);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const reducer = (state: State, action: Action): State => {
|
export const reducer = (state: State, action: Action): State => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case "ADD_TOAST":
|
case "ADD_TOAST":
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
|
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT)
|
||||||
}
|
};
|
||||||
|
|
||||||
case "UPDATE_TOAST":
|
case "UPDATE_TOAST":
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
toasts: state.toasts.map((t) =>
|
toasts: state.toasts.map((t) =>
|
||||||
t.id === action.toast.id ? { ...t, ...action.toast } : t
|
t.id === action.toast.id ? { ...t, ...action.toast } : t
|
||||||
),
|
)
|
||||||
}
|
};
|
||||||
|
|
||||||
case "DISMISS_TOAST": {
|
case "DISMISS_TOAST": {
|
||||||
const { toastId } = action
|
const { toastId } = action;
|
||||||
|
|
||||||
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
// ! Side effects ! - This could be extracted into a dismissToast() action,
|
||||||
// but I'll keep it here for simplicity
|
// but I'll keep it here for simplicity
|
||||||
if (toastId) {
|
if (toastId) {
|
||||||
addToRemoveQueue(toastId)
|
addToRemoveQueue(toastId);
|
||||||
} else {
|
} else {
|
||||||
state.toasts.forEach((toast) => {
|
state.toasts.forEach((toast) => {
|
||||||
addToRemoveQueue(toast.id)
|
addToRemoveQueue(toast.id);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -109,48 +106,48 @@ export const reducer = (state: State, action: Action): State => {
|
||||||
t.id === toastId || toastId === undefined
|
t.id === toastId || toastId === undefined
|
||||||
? {
|
? {
|
||||||
...t,
|
...t,
|
||||||
open: false,
|
open: false
|
||||||
}
|
}
|
||||||
: t
|
: t
|
||||||
),
|
)
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
case "REMOVE_TOAST":
|
case "REMOVE_TOAST":
|
||||||
if (action.toastId === undefined) {
|
if (action.toastId === undefined) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
toasts: [],
|
toasts: []
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
toasts: state.toasts.filter((t) => t.id !== action.toastId),
|
toasts: state.toasts.filter((t) => t.id !== action.toastId)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const listeners: Array<(state: State) => void> = []
|
const listeners: Array<(state: State) => void> = [];
|
||||||
|
|
||||||
let memoryState: State = { toasts: [] }
|
let memoryState: State = { toasts: [] };
|
||||||
|
|
||||||
function dispatch(action: Action) {
|
function dispatch(action: Action) {
|
||||||
memoryState = reducer(memoryState, action)
|
memoryState = reducer(memoryState, action);
|
||||||
listeners.forEach((listener) => {
|
listeners.forEach((listener) => {
|
||||||
listener(memoryState)
|
listener(memoryState);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
type Toast = Omit<ToasterToast, "id">
|
type Toast = Omit<ToasterToast, "id">;
|
||||||
|
|
||||||
function toast({ ...props }: Toast) {
|
function toast({ ...props }: Toast) {
|
||||||
const id = genId()
|
const id = genId();
|
||||||
|
|
||||||
const update = (props: ToasterToast) =>
|
const update = (props: ToasterToast) =>
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "UPDATE_TOAST",
|
type: "UPDATE_TOAST",
|
||||||
toast: { ...props, id },
|
toast: { ...props, id }
|
||||||
})
|
});
|
||||||
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
|
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "ADD_TOAST",
|
type: "ADD_TOAST",
|
||||||
|
@ -159,36 +156,36 @@ function toast({ ...props }: Toast) {
|
||||||
id,
|
id,
|
||||||
open: true,
|
open: true,
|
||||||
onOpenChange: (open) => {
|
onOpenChange: (open) => {
|
||||||
if (!open) dismiss()
|
if (!open) dismiss();
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: id,
|
id: id,
|
||||||
dismiss,
|
dismiss,
|
||||||
update,
|
update
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function useToast() {
|
function useToast() {
|
||||||
const [state, setState] = React.useState<State>(memoryState)
|
const [state, setState] = React.useState<State>(memoryState);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
listeners.push(setState)
|
listeners.push(setState);
|
||||||
return () => {
|
return () => {
|
||||||
const index = listeners.indexOf(setState)
|
const index = listeners.indexOf(setState);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
listeners.splice(index, 1)
|
listeners.splice(index, 1);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}, [state])
|
}, [state]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
toast,
|
toast,
|
||||||
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
|
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId })
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export { useToast, toast }
|
export { useToast, toast };
|
||||||
|
|
|
@ -20,7 +20,7 @@ export default function Banner({
|
||||||
link,
|
link,
|
||||||
buttonText = "Learn More",
|
buttonText = "Learn More",
|
||||||
closeButton = true,
|
closeButton = true,
|
||||||
icon,
|
icon
|
||||||
}: BannerProps) {
|
}: BannerProps) {
|
||||||
const [isBannerVisible, setIsBannerVisible] = useState(true);
|
const [isBannerVisible, setIsBannerVisible] = useState(true);
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ export default function Banner({
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
clipPath:
|
clipPath:
|
||||||
"polygon(74.8% 41.9%, 97.2% 73.2%, 100% 34.9%, 92.5% 0.4%, 87.5% 0%, 75% 28.6%, 58.5% 54.6%, 50.1% 56.8%, 46.9% 44%, 48.3% 17.4%, 24.7% 53.9%, 0% 27.9%, 11.9% 74.2%, 24.9% 54.1%, 68.6% 100%, 74.8% 41.9%)",
|
"polygon(74.8% 41.9%, 97.2% 73.2%, 100% 34.9%, 92.5% 0.4%, 87.5% 0%, 75% 28.6%, 58.5% 54.6%, 50.1% 56.8%, 46.9% 44%, 48.3% 17.4%, 24.7% 53.9%, 0% 27.9%, 11.9% 74.2%, 24.9% 54.1%, 68.6% 100%, 74.8% 41.9%)"
|
||||||
}}
|
}}
|
||||||
className="aspect-[577/310] w-[36.0625rem] bg-gradient-to-r from-primary to-yellow-200 opacity-30"
|
className="aspect-[577/310] w-[36.0625rem] bg-gradient-to-r from-primary to-yellow-200 opacity-30"
|
||||||
/>
|
/>
|
||||||
|
@ -55,7 +55,7 @@ export default function Banner({
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
clipPath:
|
clipPath:
|
||||||
"polygon(74.8% 41.9%, 97.2% 73.2%, 100% 34.9%, 92.5% 0.4%, 87.5% 0%, 75% 28.6%, 58.5% 54.6%, 50.1% 56.8%, 46.9% 44%, 48.3% 17.4%, 24.7% 53.9%, 0% 27.9%, 11.9% 74.2%, 24.9% 54.1%, 68.6% 100%, 74.8% 41.9%)",
|
"polygon(74.8% 41.9%, 97.2% 73.2%, 100% 34.9%, 92.5% 0.4%, 87.5% 0%, 75% 28.6%, 58.5% 54.6%, 50.1% 56.8%, 46.9% 44%, 48.3% 17.4%, 24.7% 53.9%, 0% 27.9%, 11.9% 74.2%, 24.9% 54.1%, 68.6% 100%, 74.8% 41.9%)"
|
||||||
}}
|
}}
|
||||||
className="aspect-[577/310] w-[36.0625rem] bg-gradient-to-r from-primary to-[#9089fc] opacity-30"
|
className="aspect-[577/310] w-[36.0625rem] bg-gradient-to-r from-primary to-[#9089fc] opacity-30"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -9,7 +9,7 @@ export default function NumberTicker({
|
||||||
value,
|
value,
|
||||||
direction = "up",
|
direction = "up",
|
||||||
delay = 0,
|
delay = 0,
|
||||||
className,
|
className
|
||||||
}: {
|
}: {
|
||||||
value: number;
|
value: number;
|
||||||
direction?: "up" | "down";
|
direction?: "up" | "down";
|
||||||
|
@ -20,7 +20,7 @@ export default function NumberTicker({
|
||||||
const motionValue = useMotionValue(direction === "down" ? value : 0);
|
const motionValue = useMotionValue(direction === "down" ? value : 0);
|
||||||
const springValue = useSpring(motionValue, {
|
const springValue = useSpring(motionValue, {
|
||||||
damping: 60,
|
damping: 60,
|
||||||
stiffness: 100,
|
stiffness: 100
|
||||||
});
|
});
|
||||||
const isInView = useInView(ref, { once: true, margin: "0px" });
|
const isInView = useInView(ref, { once: true, margin: "0px" });
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ export const transporter = nodemailer.createTransport({
|
||||||
port: 587,
|
port: 587,
|
||||||
auth: {
|
auth: {
|
||||||
user: process.env.EMAIL,
|
user: process.env.EMAIL,
|
||||||
pass: process.env.EMAIL_PASS,
|
pass: process.env.EMAIL_PASS
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const mailOptions = {
|
export const mailOptions = {
|
||||||
|
@ -33,5 +33,5 @@ export const mailOptions = {
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
`,
|
`
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ const config = {
|
||||||
apiVersion: "2023-08-08",
|
apiVersion: "2023-08-08",
|
||||||
dataset: "production",
|
dataset: "production",
|
||||||
projectId: `${process.env.SANITY_PROJECT_ID}`,
|
projectId: `${process.env.SANITY_PROJECT_ID}`,
|
||||||
useCdn: false, // ensure fresh data
|
useCdn: false // ensure fresh data
|
||||||
};
|
};
|
||||||
|
|
||||||
export const client = createClient(config);
|
export const client = createClient(config);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import {
|
import {
|
||||||
generateUploadButton,
|
generateUploadButton,
|
||||||
generateUploadDropzone,
|
generateUploadDropzone
|
||||||
} from "@uploadthing/react";
|
} from "@uploadthing/react";
|
||||||
|
|
||||||
import type { OurFileRouter } from "@/app/api/uploadthing/core";
|
import type { OurFileRouter } from "@/app/api/uploadthing/core";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { type ClassValue, clsx } from "clsx"
|
import { type ClassValue, clsx } from "clsx";
|
||||||
import { twMerge } from "tailwind-merge"
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,14 @@ export const downloadSchema = z.object({
|
||||||
fileName: z.string().nonempty(),
|
fileName: z.string().nonempty(),
|
||||||
version: z.string().nonempty(),
|
version: z.string().nonempty(),
|
||||||
downloadLink: z.string().url().nonempty(),
|
downloadLink: z.string().url().nonempty(),
|
||||||
fileSize: z.string().nonempty(),
|
fileSize: z.string().nonempty()
|
||||||
});
|
});
|
||||||
|
|
||||||
export const modsSchema = z.object({
|
export const modsSchema = z.object({
|
||||||
fileName: z.string().nonempty(),
|
fileName: z.string().nonempty(),
|
||||||
version: z.string().nonempty(),
|
version: z.string().nonempty(),
|
||||||
downloadLink: z.string().url().nonempty(),
|
downloadLink: z.string().url().nonempty(),
|
||||||
fileSize: z.string().nonempty(),
|
fileSize: z.string().nonempty()
|
||||||
});
|
});
|
||||||
|
|
||||||
export const logsSchema = z.object({
|
export const logsSchema = z.object({
|
||||||
|
@ -19,18 +19,18 @@ export const logsSchema = z.object({
|
||||||
date: z.string(),
|
date: z.string(),
|
||||||
bullets: z.array(
|
bullets: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
point: z.string(),
|
point: z.string()
|
||||||
})
|
})
|
||||||
),
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
export const vulnerabilitiesSchema = z.object({
|
export const vulnerabilitiesSchema = z.object({
|
||||||
version: z.string(),
|
version: z.string(),
|
||||||
bullets: z.array(
|
bullets: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
point: z.string(),
|
point: z.string()
|
||||||
})
|
})
|
||||||
),
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ModsVulnerabilities = z.object({
|
export const ModsVulnerabilities = z.object({
|
||||||
|
@ -38,9 +38,9 @@ export const ModsVulnerabilities = z.object({
|
||||||
category: z.string(),
|
category: z.string(),
|
||||||
bullets: z.array(
|
bullets: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
point: z.string(),
|
point: z.string()
|
||||||
})
|
})
|
||||||
),
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
export type LogsFormValues = z.infer<typeof logsSchema>;
|
export type LogsFormValues = z.infer<typeof logsSchema>;
|
||||||
|
@ -51,12 +51,12 @@ export type ModsVulnerability = z.infer<typeof ModsVulnerabilities>;
|
||||||
|
|
||||||
export const contactFormSchema = z.object({
|
export const contactFormSchema = z.object({
|
||||||
name: z.string().min(2, {
|
name: z.string().min(2, {
|
||||||
message: "Name must be at least 2 characters.",
|
message: "Name must be at least 2 characters."
|
||||||
}),
|
}),
|
||||||
email: z.string().email({
|
email: z.string().email({
|
||||||
message: "Invalid email address.",
|
message: "Invalid email address."
|
||||||
}),
|
}),
|
||||||
message: z.string().min(10, {
|
message: z.string().min(10, {
|
||||||
message: "Message must be at least 10 characters.",
|
message: "Message must be at least 10 characters."
|
||||||
}),
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { AppProps } from "next/app";
|
||||||
|
|
||||||
const poppins = Poppins({
|
const poppins = Poppins({
|
||||||
weight: ["400", "600", "700", "900"],
|
weight: ["400", "600", "700", "900"],
|
||||||
subsets: ["latin"],
|
subsets: ["latin"]
|
||||||
});
|
});
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
|
|
Loading…
Reference in a new issue