-
+ return (
+
+
-
-
- Explore DevResume
-
-
- {/* Gradients */}
-
-
-
-
+
+
+ Explore DevResume
+
+
+ {/* Gradients */}
+
+
+
+
- {/* Core component */}
- {/*
*/}
- {/* Radial Gradient to prevent sharp edges */}
- {/*
*/}
-
-
+ {/* Radial Gradient to prevent sharp edges */}
+ {/*
*/}
- );
+
+
+ );
}
diff --git a/components/explore/Testimonials.tsx b/components/explore/Testimonials.tsx
index 93eb6f3..7b964ab 100644
--- a/components/explore/Testimonials.tsx
+++ b/components/explore/Testimonials.tsx
@@ -1,49 +1,51 @@
-"use client";
+'use client';
-import { TypographyH1 } from "../common/Typography";
-import { InfiniteMovingCards } from "../ui/infinite-moving-cards";
+import { TypographyH1 } from '../common/Typography';
+import { InfiniteMovingCards } from '../ui/infinite-moving-cards';
export default function TestimonialsSection() {
- return (
-
- What's People saying about us ?
-
-
- );
+ return (
+
+
+ What's People saying about us ?
+
+
+
+ );
}
const testimonials = [
- {
- quote:
- "It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair.",
- name: "Charles Dickens",
- title: "A Tale of Two Cities",
- },
- {
- quote:
- "To be, or not to be, that is the question: Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune, Or to take Arms against a Sea of troubles, And by opposing end them: to die, to sleep.",
- name: "William Shakespeare",
- title: "Hamlet",
- },
- {
- quote: "All that we see or seem is but a dream within a dream.",
- name: "Edgar Allan Poe",
- title: "A Dream Within a Dream",
- },
- {
- quote:
- "It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife.",
- name: "Jane Austen",
- title: "Pride and Prejudice",
- },
- {
- quote:
- "Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.",
- name: "Herman Melville",
- title: "Moby-Dick",
- },
+ {
+ quote:
+ 'It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair.',
+ name: 'Charles Dickens',
+ title: 'A Tale of Two Cities',
+ },
+ {
+ quote:
+ "To be, or not to be, that is the question: Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune, Or to take Arms against a Sea of troubles, And by opposing end them: to die, to sleep.",
+ name: 'William Shakespeare',
+ title: 'Hamlet',
+ },
+ {
+ quote: 'All that we see or seem is but a dream within a dream.',
+ name: 'Edgar Allan Poe',
+ title: 'A Dream Within a Dream',
+ },
+ {
+ quote:
+ 'It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife.',
+ name: 'Jane Austen',
+ title: 'Pride and Prejudice',
+ },
+ {
+ quote:
+ 'Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.',
+ name: 'Herman Melville',
+ title: 'Moby-Dick',
+ },
];
diff --git a/components/form/delete-post-form.tsx b/components/form/delete-post-form.tsx
index 90fec19..3bfe823 100644
--- a/components/form/delete-post-form.tsx
+++ b/components/form/delete-post-form.tsx
@@ -1,78 +1,80 @@
-"use client";
-
-
-import { deletePost } from "@/lib/actions";
-import { cn } from "@/lib/utils";
-import { Input } from "@nextui-org/react";
-import va from "@vercel/analytics";
-import { Loader2 } from "lucide-react";
-import { useParams, useRouter } from "next/navigation";
-import { useFormStatus } from "react-dom";
-import { toast } from "sonner";
+'use client';
+import { deletePost } from '@/lib/actions';
+import { cn } from '@/lib/utils';
+import { Input } from '@nextui-org/react';
+import va from '@vercel/analytics';
+import { Loader2 } from 'lucide-react';
+import { useParams, useRouter } from 'next/navigation';
+import { useFormStatus } from 'react-dom';
+import { toast } from 'sonner';
export default function DeletePostForm({ postName }: { postName: string }) {
- const { blogslug, slug } = useParams() as { blogslug: string, slug: string };
- const router = useRouter();
- return (
-
- );
+
+
+ This action is irreversible. Please proceed with caution.
+
+
+
+
+
+
+ );
}
function FormButton() {
- const { pending } = useFormStatus();
- return (
-
- {pending ? : Confirm Delete
}
-
- );
+ const { pending } = useFormStatus();
+ return (
+
+ {pending ? (
+
+ ) : (
+ Confirm Delete
+ )}
+
+ );
}
diff --git a/components/form/delete-site-form.tsx b/components/form/delete-site-form.tsx
index 7a3e607..3bad568 100644
--- a/components/form/delete-site-form.tsx
+++ b/components/form/delete-site-form.tsx
@@ -1,80 +1,84 @@
-"use client";
-
-import { deleteSite } from "@/lib/actions";
-import { cn } from "@/lib/utils";
-import { Input } from "@nextui-org/react";
-import va from "@vercel/analytics";
-import { Loader2 } from "lucide-react";
-import { useParams, useRouter } from "next/navigation";
-import { useFormStatus } from "react-dom";
-import { toast } from "sonner";
+'use client';
+import { deleteSite } from '@/lib/actions';
+import { cn } from '@/lib/utils';
+import { Input } from '@nextui-org/react';
+import va from '@vercel/analytics';
+import { Loader2 } from 'lucide-react';
+import { useParams, useRouter } from 'next/navigation';
+import { useFormStatus } from 'react-dom';
+import { toast } from 'sonner';
export default function DeleteSiteForm({ siteName }: { siteName: string }) {
- const { slug } = useParams() as { slug: string };
- const router = useRouter();
- return (
-
- window.confirm("Are you sure you want to delete your site?") &&
- deleteSite(data, slug, "delete")
- .then(async (res) => {
- if (res.error) {
- toast.error("An error occurred. Please try again later.");
- } else {
- va.track("Deleted Site");
- router.refresh();
- router.push("/dashboard/portfolio");
- toast.success("Site deleted successfully.");
- }
- })
- .catch((err: Error) => {
- toast.error("An error occurred. Please try again later.");
- })}
- className="rounded-lg border border-red-600 bg-white dark:bg-black"
- >
-
-
Delete Site
-
- Deletes your site and all posts associated with it. Type in the name
- of your site {siteName} to confirm.
-
+ const { slug } = useParams() as { slug: string };
+ const router = useRouter();
+ return (
+
+ window.confirm('Are you sure you want to delete your site?') &&
+ deleteSite(data, slug, 'delete')
+ .then(async (res) => {
+ if (res.error) {
+ toast.error('An error occurred. Please try again later.');
+ } else {
+ va.track('Deleted Site');
+ router.refresh();
+ router.push('/dashboard/portfolio');
+ toast.success('Site deleted successfully.');
+ }
+ })
+ .catch((err: Error) => {
+ toast.error('An error occurred. Please try again later.');
+ })
+ }
+ className="rounded-lg border border-red-600 bg-white dark:bg-black"
+ >
+
+
Delete Site
+
+ Deletes your site and all posts associated with it. Type in the name
+ of your site {siteName} to confirm.
+
-
-
+
+
-
-
- This action is irreversible. Please proceed with caution.
-
-
-
-
-
-
- );
+
+
+ This action is irreversible. Please proceed with caution.
+
+
+
+
+
+
+ );
}
function FormButton() {
- const { pending } = useFormStatus();
- return (
-
- {pending ? : Confirm Delete
}
-
- );
+ const { pending } = useFormStatus();
+ return (
+
+ {pending ? (
+
+ ) : (
+ Confirm Delete
+ )}
+
+ );
}
diff --git a/components/form/domain-configuration.tsx b/components/form/domain-configuration.tsx
index 311c22e..82ba3b5 100644
--- a/components/form/domain-configuration.tsx
+++ b/components/form/domain-configuration.tsx
@@ -1,167 +1,167 @@
-"use client";
+'use client';
-import { getSubdomain } from "@/lib/domains";
-import { cn } from "@/lib/utils";
-import { AlertCircle, XCircle } from "lucide-react";
-import { useState } from "react";
-import { useDomainStatus } from "./use-domain-status";
+import { getSubdomain } from '@/lib/domains';
+import { cn } from '@/lib/utils';
+import { AlertCircle, XCircle } from 'lucide-react';
+import { useState } from 'react';
+import { useDomainStatus } from './use-domain-status';
export const InlineSnippet = ({
- className,
- children,
+ className,
+ children,
}: {
- className?: string;
- children: string;
+ className?: string;
+ children: string;
}) => {
- return (
-
- {children}
-
- );
+ return (
+
+ {children}
+
+ );
};
export default function DomainConfiguration({ domain }: { domain: string }) {
- const [recordType, setRecordType] = useState<"A" | "CNAME">("A");
+ const [recordType, setRecordType] = useState<'A' | 'CNAME'>('A');
- const { status, domainJson } = useDomainStatus({ domain });
+ const { status, domainJson } = useDomainStatus({ domain });
- if (!status || status === "Valid Configuration" || !domainJson) return null;
+ if (!status || status === 'Valid Configuration' || !domainJson) return null;
- const subdomain = getSubdomain(domainJson.name, domainJson.apexName);
+ const subdomain = getSubdomain(domainJson.name, domainJson.apexName);
- const txtVerification =
- (status === "Pending Verification" &&
- domainJson.verification.find((x: any) => x.type === "TXT")) ||
- null;
+ const txtVerification =
+ (status === 'Pending Verification' &&
+ domainJson.verification.find((x: any) => x.type === 'TXT')) ||
+ null;
- return (
-
-
- {status === "Pending Verification" ? (
-
- ) : (
-
+ return (
+
+
+ {status === 'Pending Verification' ? (
+
+ ) : (
+
+ )}
+
{status}
+
+ {txtVerification ? (
+ <>
+
+ Please set the following TXT record on{' '}
+ {domainJson.apexName} to prove
+ ownership of {domainJson.name} :
+
+
+
+
Type
+
{txtVerification.type}
+
+
+
Name
+
+ {txtVerification.domain.slice(
+ 0,
+ txtVerification.domain.length - domainJson.apexName.length - 1
)}
-
{status}
+
+
+
+
Value
+
+ {txtVerification.value}
+
- {txtVerification ? (
- <>
-
- Please set the following TXT record on{" "}
- {domainJson.apexName} to prove
- ownership of {domainJson.name} :
-
-
-
-
Type
-
{txtVerification.type}
-
-
-
Name
-
- {txtVerification.domain.slice(
- 0,
- txtVerification.domain.length -
- domainJson.apexName.length -
- 1,
- )}
-
-
-
-
Value
-
- {txtVerification.value}
-
-
-
-
- Warning: if you are using this domain for another site, setting this
- TXT record will transfer domain ownership away from that site and
- break it. Please exercise caution when setting this record.
-
- >
- ) : status === "Unknown Error" ? (
-
- {domainJson.error.message}
+
+
+ Warning: if you are using this domain for another site, setting this
+ TXT record will transfer domain ownership away from that site and
+ break it. Please exercise caution when setting this record.
+
+ >
+ ) : status === 'Unknown Error' ? (
+
+ {domainJson.error.message}
+
+ ) : (
+ <>
+
+ setRecordType('A')}
+ className={`${
+ recordType == 'A'
+ ? 'border-black text-black dark:border-white dark:text-white'
+ : 'border-white text-stone-400 dark:border-black dark:text-stone-600'
+ } ease border-b-2 pb-1 text-sm transition-all duration-150`}
+ >
+ A Record{!subdomain && ' (recommended)'}
+
+ setRecordType('CNAME')}
+ className={`${
+ recordType == 'CNAME'
+ ? 'border-black text-black dark:border-white dark:text-white'
+ : 'border-white text-stone-400 dark:border-black dark:text-stone-600'
+ } ease border-b-2 pb-1 text-sm transition-all duration-150`}
+ >
+ CNAME Record{subdomain && ' (recommended)'}
+
+
+
+
+ To configure your{' '}
+ {recordType === 'A' ? 'apex domain' : 'subdomain'} (
+
+ {recordType === 'A' ? domainJson.apexName : domainJson.name}
+
+ ), set the following {recordType} record on your DNS provider to
+ continue:
+
+
+
+
+
Name
+
+ {recordType === 'A' ? '@' : subdomain ?? 'www'}
- ) : (
- <>
-
- setRecordType("A")}
- className={`${recordType == "A"
- ? "border-black text-black dark:border-white dark:text-white"
- : "border-white text-stone-400 dark:border-black dark:text-stone-600"
- } ease border-b-2 pb-1 text-sm transition-all duration-150`}
- >
- A Record{!subdomain && " (recommended)"}
-
- setRecordType("CNAME")}
- className={`${recordType == "CNAME"
- ? "border-black text-black dark:border-white dark:text-white"
- : "border-white text-stone-400 dark:border-black dark:text-stone-600"
- } ease border-b-2 pb-1 text-sm transition-all duration-150`}
- >
- CNAME Record{subdomain && " (recommended)"}
-
-
-
-
- To configure your{" "}
- {recordType === "A" ? "apex domain" : "subdomain"} (
-
- {recordType === "A" ? domainJson.apexName : domainJson.name}
-
- ), set the following {recordType} record on your DNS provider to
- continue:
-
-
-
-
-
Name
-
- {recordType === "A" ? "@" : subdomain ?? "www"}
-
-
-
-
Value
-
- {recordType === "A"
- ? `76.76.21.21`
- : `cname.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`}
-
-
-
-
-
- Note: for TTL, if 86400 is not
- available, set the highest value possible. Also, domain
- propagation can take up to an hour.
-
-
- >
- )}
-
- );
+
+
+
Value
+
+ {recordType === 'A'
+ ? '76.76.21.21'
+ : `cname.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`}
+
+
+
+
+
+ Note: for TTL, if 86400 is not
+ available, set the highest value possible. Also, domain
+ propagation can take up to an hour.
+
+
+ >
+ )}
+
+ );
}
diff --git a/components/form/domain-status.tsx b/components/form/domain-status.tsx
index 6f095d5..31076e7 100644
--- a/components/form/domain-status.tsx
+++ b/components/form/domain-status.tsx
@@ -1,30 +1,30 @@
-"use client";
+'use client';
-import { AlertCircle, CheckCircle2, Loader2, XCircle } from "lucide-react";
-import { useDomainStatus } from "./use-domain-status";
+import { AlertCircle, CheckCircle2, Loader2, XCircle } from 'lucide-react';
+import { useDomainStatus } from './use-domain-status';
export default function DomainStatus({ domain }: { domain: string }) {
- const { status, loading } = useDomainStatus({ domain });
+ const { status, loading } = useDomainStatus({ domain });
- return loading ? (
-
- ) : status === "Valid Configuration" ? (
-
- ) : status === "Pending Verification" ? (
-
- ) : (
-
- );
+ return loading ? (
+
+ ) : status === 'Valid Configuration' ? (
+
+ ) : status === 'Pending Verification' ? (
+
+ ) : (
+
+ );
}
diff --git a/components/form/education-form.tsx b/components/form/education-form.tsx
index 0e426d6..c20235d 100644
--- a/components/form/education-form.tsx
+++ b/components/form/education-form.tsx
@@ -1,375 +1,384 @@
-"use client";
+'use client';
import {
- AlertDialog,
- AlertDialogAction,
- AlertDialogCancel,
- AlertDialogContent,
- AlertDialogDescription,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogTitle,
- AlertDialogTrigger,
-} from "@/components/ui/alert-dialog";
-import { Button } from "@/components/ui/button";
-import { Calendar } from "@/components/ui/calendar";
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+} from '@/components/ui/alert-dialog';
+import { Button } from '@/components/ui/button';
+import { Calendar } from '@/components/ui/calendar';
import {
- Form,
- FormControl,
- FormField,
- FormItem,
- FormLabel,
- FormMessage
-} from "@/components/ui/form";
-import { Input } from "@/components/ui/input";
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form';
+import { Input } from '@/components/ui/input';
import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@/components/ui/popover";
-import { ScrollArea } from "@/components/ui/scroll-area";
-import { addEducation, updateEducation } from "@/lib/actions";
-import { cn } from "@/lib/utils";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { UserEducation } from "@prisma/client";
-import { CalendarIcon } from "lucide-react";
-import { useParams, useRouter } from "next/navigation";
-import { useState } from "react";
-import { useForm } from "react-hook-form";
-import { toast } from "sonner";
-import { z } from "zod";
-import { Textarea } from "../ui/textarea";
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from '@/components/ui/popover';
+import { ScrollArea } from '@/components/ui/scroll-area';
+import { addEducation, updateEducation } from '@/lib/actions';
+import { cn } from '@/lib/utils';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { UserEducation } from '@prisma/client';
+import { CalendarIcon } from 'lucide-react';
+import { useParams, useRouter } from 'next/navigation';
+import { useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { toast } from 'sonner';
+import { z } from 'zod';
+import { Textarea } from '../ui/textarea';
const CreateEducationSchema = z.object({
- school_name: z.string({
- description: "Name is required",
- required_error: "Name is required",
- invalid_type_error: "Name is must be string",
- }),
- school_location: z.string({
- description: "Location is required",
- required_error: "Location is required",
- invalid_type_error: "Location is must be string",
- }),
- school_degree: z.string(),
- school_major: z.string(),
- school_start_date: z.date({
- description: "Start Date is required",
- }),
- school_end_date: z.date({
- description: "End Date is required",
- }),
- education_note: z.string({
- description: "Note is required",
- }).max(225, {
- message: "Note must be at most 225 characters long"
+ school_name: z.string({
+ description: 'Name is required',
+ required_error: 'Name is required',
+ invalid_type_error: 'Name is must be string',
+ }),
+ school_location: z.string({
+ description: 'Location is required',
+ required_error: 'Location is required',
+ invalid_type_error: 'Location is must be string',
+ }),
+ school_degree: z.string(),
+ school_major: z.string(),
+ school_start_date: z.date({
+ description: 'Start Date is required',
+ }),
+ school_end_date: z.date({
+ description: 'End Date is required',
+ }),
+ education_note: z
+ .string({
+ description: 'Note is required',
})
-})
-
-
+ .max(225, {
+ message: 'Note must be at most 225 characters long',
+ }),
+});
export default function AddEducationForm({
- title,
- method,
- education
+ title,
+ method,
+ education,
}: {
- title: string;
- method: 'add' | 'edit';
+ title: string;
+ method: 'add' | 'edit';
} & (
- | { method: 'add'; education?: never }
- | {
- method: 'edit';
- education: UserEducation;
- }
- )) {
-
- const [open, setOpen] = useState(false);
- const { slug } = useParams() as { slug: string };
- const router = useRouter();
+ | { method: 'add'; education?: never }
+ | {
+ method: 'edit';
+ education: UserEducation;
+ }
+)) {
+ const [open, setOpen] = useState(false);
+ const { slug } = useParams() as { slug: string };
+ const router = useRouter();
- const form = useForm
>({
- resolver: zodResolver(CreateEducationSchema),
- defaultValues: education ? {
- school_name: education.school_name,
- school_location: education.school_location || "",
- school_degree: education.school_degree || "",
- school_major: education.school_major || "",
- school_start_date: education.school_start_date || new Date(),
- school_end_date: education.school_end_date || new Date(),
- education_note: education.education_note || "",
- } : {
- school_start_date: new Date(),
- school_end_date: new Date(),
+ const form = useForm>({
+ resolver: zodResolver(CreateEducationSchema),
+ defaultValues: education
+ ? {
+ school_name: education.school_name,
+ school_location: education.school_location || '',
+ school_degree: education.school_degree || '',
+ school_major: education.school_major || '',
+ school_start_date: education.school_start_date || new Date(),
+ school_end_date: education.school_end_date || new Date(),
+ education_note: education.education_note || '',
+ }
+ : {
+ school_start_date: new Date(),
+ school_end_date: new Date(),
},
- })
-
+ });
- function onSubmit(values: z.infer) {
- if (form.formState.isValid) {
- try {
- const formData = new FormData();
- formData.append("school_name", values.school_name);
- formData.append("school_location", values.school_location);
- formData.append("school_degree", values.school_degree);
- formData.append("school_major", values.school_major);
- formData.append("school_start_date", values.school_start_date.toISOString());
- formData.append("school_end_date", values.school_end_date.toISOString());
- formData.append("education_note", values.education_note);
+ function onSubmit(values: z.infer) {
+ if (form.formState.isValid) {
+ try {
+ const formData = new FormData();
+ formData.append('school_name', values.school_name);
+ formData.append('school_location', values.school_location);
+ formData.append('school_degree', values.school_degree);
+ formData.append('school_major', values.school_major);
+ formData.append(
+ 'school_start_date',
+ values.school_start_date.toISOString()
+ );
+ formData.append(
+ 'school_end_date',
+ values.school_end_date.toISOString()
+ );
+ formData.append('education_note', values.education_note);
- if (method === "add") {
- addEducation(formData, "profile", slug).then(async (res: any) => {
- if (res.error) {
- // toast.error(res.error);
- console.log(res.error)
- toast("An error occurred.");
- } else {
- if (slug) {
- setOpen(false)
- router.refresh();
- } else {
- setOpen(false)
- router.refresh();
- }
- toast("🌱 Successfully added Education!");
- }
- });
- } else if (method === "edit") {
- console.log(education.id)
- updateEducation(
- education.id,
- "null",
- formData
- ).then(async (res: any) => {
- if (res.error) {
- // toast.error(res.error);
- console.log(res.error)
- toast("An error occurred.");
- } else {
- if (slug) {
- setOpen(false)
- router.refresh();
- } else {
- setOpen(false)
- router.refresh();
- }
- toast("🌱 Successfully updated Education!");
- }
- }
- );
+ if (method === 'add') {
+ addEducation(formData, 'profile', slug).then(async (res: any) => {
+ if (res.error) {
+ // toast.error(res.error);
+ console.log(res.error);
+ toast('An error occurred.');
+ } else {
+ if (slug) {
+ setOpen(false);
+ router.refresh();
+ } else {
+ setOpen(false);
+ router.refresh();
+ }
+ toast('🌱 Successfully added Education!');
+ }
+ });
+ } else if (method === 'edit') {
+ console.log(education.id);
+ updateEducation(education.id, 'null', formData).then(
+ async (res: any) => {
+ if (res.error) {
+ // toast.error(res.error);
+ console.log(res.error);
+ toast('An error occurred.');
+ } else {
+ if (slug) {
+ setOpen(false);
+ router.refresh();
} else {
- toast("method not allowed");
+ setOpen(false);
+ router.refresh();
}
- } catch (error) {
- console.log(error)
- toast("An error occurred.");
+ toast('🌱 Successfully updated Education!');
+ }
}
+ );
} else {
- toast("Kindly fill the form correctly.");
+ toast('method not allowed');
}
+ } catch (error) {
+ console.log(error);
+ toast('An error occurred.');
+ }
+ } else {
+ toast('Kindly fill the form correctly.');
}
+ }
-
-
- return (
- <>
-
-
- {
- method === "add" ? "Add Education" : "Edit"
- }
-
-
-
- {title}
-
- This will be visible in your Portfolio.
-
-
-
-
- (
-
- Institute name
-
-
-
-
-
- )}
- />
-
-
(
-
- From
-
-
-
-
-
-
- {field.value ? (
- {field.value?.toLocaleDateString()}
- ) : (
- Pick a date
- )}
-
-
-
-
-
- {
- field.onChange(new Date(date))
- }}
- className="rounded-md border"
- />
-
-
-
-
-
- )}
- />
- (
-
- To
-
-
-
-
-
-
- {field.value ? (
- {field.value?.toLocaleDateString()}
- ) : (
- Pick a date
- )}
-
-
-
-
-
- {
- field.onChange(new Date(date))
- }}
- className="rounded-md border"
- />
-
-
-
-
-
- )}
- />
-
- (
-
- Degree
-
-
-
-
-
- )}
- />
- (
-
- Field of Study
-
-
-
-
-
- )}
- />
- (
-
- Institute Location
-
-
-
-
-
- )}
- />
- (
-
- Note
-
-
-
-
-
- )}
- />
-
-
-
-
-
- Cancel
- {
- e.preventDefault();
- form.handleSubmit(onSubmit)();
- }
- }>
- {method === "add" ? "Add" : "Update"}
-
-
-
-
-
-
-
- >
- );
+ return (
+ <>
+
+
+
+ {method === 'add' ? 'Add Education' : 'Edit'}
+
+
+
+
+ {title}
+
+ This will be visible in your Portfolio.
+
+
+
+
+ (
+
+ Institute name
+
+
+
+
+
+ )}
+ />
+
+
(
+
+ From
+
+
+
+
+
+
+ {field.value ? (
+
+ {field.value?.toLocaleDateString()}
+
+ ) : (
+ Pick a date
+ )}
+
+
+
+
+
+ {
+ field.onChange(new Date(date));
+ }}
+ className="rounded-md border"
+ />
+
+
+
+
+
+ )}
+ />
+ (
+
+ To
+
+
+
+
+
+
+ {field.value ? (
+
+ {field.value?.toLocaleDateString()}
+
+ ) : (
+ Pick a date
+ )}
+
+
+
+
+
+ {
+ field.onChange(new Date(date));
+ }}
+ className="rounded-md border"
+ />
+
+
+
+
+
+ )}
+ />
+
+ (
+
+ Degree
+
+
+
+
+
+ )}
+ />
+ (
+
+ Field of Study
+
+
+
+
+
+ )}
+ />
+ (
+
+ Institute Location
+
+
+
+
+
+ )}
+ />
+ (
+
+ Note
+
+
+
+
+
+ )}
+ />
+
+
+
+
+
+ Cancel
+ {
+ e.preventDefault();
+ form.handleSubmit(onSubmit)();
+ }}
+ >
+ {method === 'add' ? 'Add' : 'Update'}
+
+
+
+
+ >
+ );
}
-
-
diff --git a/components/form/index.tsx b/components/form/index.tsx
index 263a3ac..16124e9 100644
--- a/components/form/index.tsx
+++ b/components/form/index.tsx
@@ -1,178 +1,193 @@
-"use client";
+'use client';
-import { cn } from "@/lib/utils";
-import { fontList } from "@/styles/fonts";
-import { Input, Textarea } from "@nextui-org/react";
-import va from "@vercel/analytics";
-import { Loader2 } from "lucide-react";
-import { useParams, useRouter } from "next/navigation";
-import { useFormStatus } from "react-dom";
-import { toast } from "sonner";
-import DomainConfiguration from "./domain-configuration";
-import DomainStatus from "./domain-status";
-import Uploader from "./uploader";
+import { cn } from '@/lib/utils';
+import { fontList } from '@/styles/fonts';
+import { Input, Textarea } from '@nextui-org/react';
+import va from '@vercel/analytics';
+import { Loader2 } from 'lucide-react';
+import { useParams, useRouter } from 'next/navigation';
+import { useFormStatus } from 'react-dom';
+import { toast } from 'sonner';
+import DomainConfiguration from './domain-configuration';
+import DomainStatus from './domain-status';
+import Uploader from './uploader';
export default function Form({
- title,
- description,
- helpText,
- inputAttrs,
- handleSubmit,
+ title,
+ description,
+ helpText,
+ inputAttrs,
+ handleSubmit,
}: {
- title: string;
- description: string;
- helpText: string;
- inputAttrs: {
- name: string;
- type: string;
- defaultValue: string;
- placeholder?: string;
- maxLength?: number;
- pattern?: string;
- };
- handleSubmit: any;
+ title: string;
+ description: string;
+ helpText: string;
+ inputAttrs: {
+ name: string;
+ type: string;
+ defaultValue: string;
+ placeholder?: string;
+ maxLength?: number;
+ pattern?: string;
+ };
+ handleSubmit: any;
}) {
- const { slug, blogslug } = useParams() as { slug?: string, blogslug?: string };
- const router = useRouter();
- return (
- {
- if (
- inputAttrs.name === "customDomain" &&
- inputAttrs.defaultValue &&
- data.get("customDomain") !== inputAttrs.defaultValue &&
- !confirm("Are you sure you want to change your custom domain?")
- ) {
- return;
- }
+ const { slug, blogslug } = useParams() as {
+ slug?: string;
+ blogslug?: string;
+ };
+ const router = useRouter();
+ return (
+ {
+ if (
+ inputAttrs.name === 'customDomain' &&
+ inputAttrs.defaultValue &&
+ data.get('customDomain') !== inputAttrs.defaultValue &&
+ !confirm('Are you sure you want to change your custom domain?')
+ ) {
+ return;
+ }
- let modifiedslug;
+ let modifiedslug;
- if (blogslug) {
- modifiedslug = blogslug
- } else {
- modifiedslug = slug
- }
+ if (blogslug) {
+ modifiedslug = blogslug;
+ } else {
+ modifiedslug = slug;
+ }
- handleSubmit(data, modifiedslug, inputAttrs.name).then(async (res: any) => {
- if (res.error) {
- // toast.error(res.error);
- console.log(res.error)
- toast.error("An error occurred. Please try again later.");
- } else {
- va.track(`Updated ${inputAttrs.name}`, slug ? { slug } : {});
- if (slug) {
- router.refresh();
- } else {
- router.refresh();
- }
- toast.success(`Successfully updated ${inputAttrs.name}!`);
- }
- });
- }}
- className="rounded-lg border border-stone-200 bg-white dark:border-stone-700 dark:bg-black"
- >
-
-
{title}
-
- {description}
-
- {inputAttrs.name === "image" || inputAttrs.name === "avatar" || inputAttrs.name === "logo" ? (
-
- ) : inputAttrs.name === "font" ? (
-
-
- {fontList.map((font, index) => {
- return {font.name}
- })}
-
-
- ) : inputAttrs.name === "subdomain" ? (
-
-
-
- {process.env.NEXT_PUBLIC_ROOT_DOMAIN}
-
-
- ) : inputAttrs.name === "customDomain" ? (
-
-
- {inputAttrs.defaultValue && (
-
-
-
- )}
-
- ) : inputAttrs.type === "description" ? (
-
- ) : inputAttrs.type === "about" ? (
-
- ) : (
-
- )}
+ handleSubmit(data, modifiedslug, inputAttrs.name).then(
+ async (res: any) => {
+ if (res.error) {
+ // toast.error(res.error);
+ console.log(res.error);
+ toast.error('An error occurred. Please try again later.');
+ } else {
+ va.track(`Updated ${inputAttrs.name}`, slug ? { slug } : {});
+ if (slug) {
+ router.refresh();
+ } else {
+ router.refresh();
+ }
+ toast.success(`Successfully updated ${inputAttrs.name}!`);
+ }
+ }
+ );
+ }}
+ className="rounded-lg border border-stone-200 bg-white dark:border-stone-700 dark:bg-black"
+ >
+
+
{title}
+
+ {description}
+
+ {inputAttrs.name === 'image' ||
+ inputAttrs.name === 'avatar' ||
+ inputAttrs.name === 'logo' ? (
+
+ ) : inputAttrs.name === 'font' ? (
+
+
+ {fontList.map((font, index) => {
+ return (
+
+ {font.name}
+
+ );
+ })}
+
+
+ ) : inputAttrs.name === 'subdomain' ? (
+
+
+
+ {process.env.NEXT_PUBLIC_ROOT_DOMAIN}
- {inputAttrs.name === "customDomain" && inputAttrs.defaultValue && (
-
+
+ ) : inputAttrs.name === 'customDomain' ? (
+
+
+ {inputAttrs.defaultValue && (
+
+
+
)}
-
-
- );
+
+ ) : inputAttrs.type === 'description' ? (
+
+ ) : inputAttrs.type === 'about' ? (
+
+ ) : (
+
+ )}
+
+ {inputAttrs.name === 'customDomain' && inputAttrs.defaultValue && (
+
+ )}
+
+
+ );
}
function FormButton() {
- const { pending } = useFormStatus();
- return (
-
- {pending ? : Save Changes
}
-
- );
+ const { pending } = useFormStatus();
+ return (
+
+ {pending ? (
+
+ ) : (
+ Save Changes
+ )}
+
+ );
}
diff --git a/components/form/site-about-form.tsx b/components/form/site-about-form.tsx
index e66f23c..878d82f 100644
--- a/components/form/site-about-form.tsx
+++ b/components/form/site-about-form.tsx
@@ -1,85 +1,76 @@
-"use client";
-
-import { updateAboutSite } from "@/lib/actions";
-import { Editor as NovelEditor } from "novel";
-import { useEffect, useState, useTransition } from "react";
-import { ScrollArea } from "../ui/scroll-area";
-
-
+'use client';
+import { updateAboutSite } from '@/lib/actions';
+import { Editor as NovelEditor } from 'novel';
+import { useEffect, useState, useTransition } from 'react';
+import { ScrollArea } from '../ui/scroll-area';
export default function AboutEditor({
- siteid,
- defaultValue,
- name,
- Title,
- description,
- helpText,
+ siteid,
+ defaultValue,
+ name,
+ Title,
+ description,
+ helpText,
}: {
- siteid: string;
- defaultValue: string;
- name: string;
- Title: string;
- description: string;
- helpText: string;
-
+ siteid: string;
+ defaultValue: string;
+ name: string;
+ Title: string;
+ description: string;
+ helpText: string;
}) {
+ let [isPendingSaving, startTransitionSaving] = useTransition();
+ let [isPendingPublishing, startTransitionPublishing] = useTransition();
+ const [data, setData] = useState
(defaultValue);
+ const [hydrated, setHydrated] = useState(false);
- let [isPendingSaving, startTransitionSaving] = useTransition();
- let [isPendingPublishing, startTransitionPublishing] = useTransition();
- const [data, setData] = useState(defaultValue);
- const [hydrated, setHydrated] = useState(false);
+ useEffect(() => {
+ const onKeyDown = (e: KeyboardEvent) => {
+ if (e.metaKey && e.key === 's') {
+ e.preventDefault();
+ startTransitionSaving(async () => {
+ await updateAboutSite(data, siteid);
+ });
+ }
+ };
+ document.addEventListener('keydown', onKeyDown);
+ return () => {
+ document.removeEventListener('keydown', onKeyDown);
+ };
+ }, [data, siteid, startTransitionSaving]);
- useEffect(() => {
- const onKeyDown = (e: KeyboardEvent) => {
- if (e.metaKey && e.key === "s") {
- e.preventDefault();
- startTransitionSaving(async () => {
- await updateAboutSite(data, siteid);
- });
+ return (
+
+
{name}
+
+ {description}
+
+
+ {
+ setData(editor?.storage.markdown.getMarkdown());
+ }}
+ onDebouncedUpdate={() => {
+ if (data === defaultValue) {
+ return;
}
- };
- document.addEventListener("keydown", onKeyDown);
- return () => {
- document.removeEventListener("keydown", onKeyDown);
- };
- }, [data, siteid, startTransitionSaving]);
-
- return (
-
-
{name}
-
- {description}
-
-
- {
- setData(editor?.storage.markdown.getMarkdown());
- }}
- onDebouncedUpdate={() => {
- if (
- data === defaultValue
- ) {
- return;
- }
- startTransitionSaving(async () => {
- await updateAboutSite(data, siteid);
- });
- }}
- />
-
-
-
- {helpText}
-
-
- {isPendingSaving ? "Saving..." : "Saved"}
-
-
+ startTransitionSaving(async () => {
+ await updateAboutSite(data, siteid);
+ });
+ }}
+ />
+
+
+
{helpText}
+
+ {isPendingSaving ? 'Saving...' : 'Saved'}
- )
-}
\ No newline at end of file
+
+
+ );
+}
diff --git a/components/form/social-media-form.tsx b/components/form/social-media-form.tsx
index 7a06596..0f28c8e 100644
--- a/components/form/social-media-form.tsx
+++ b/components/form/social-media-form.tsx
@@ -1,144 +1,157 @@
-"use client";
+'use client';
-import { updateSite } from "@/lib/actions";
-import { cn } from "@/lib/utils";
-import { Input } from "@nextui-org/react";
-import { GitHubLogoIcon, GlobeIcon, InstagramLogoIcon, LinkedInLogoIcon, TwitterLogoIcon } from "@radix-ui/react-icons";
-import { Loader2, YoutubeIcon } from "lucide-react";
-import { useParams } from "next/navigation";
-import { useFormStatus } from "react-dom";
-import { toast } from "sonner";
-import { TypographyP } from "../common/Typography";
-
-export default function SocialMediaForm({ socials }: {
- socials: {
- twitterid: string,
- linkedinid: string,
- githubid: string,
- websiteurl: string
- instagramid: string,
- youtubeurl: string
-
- }
+import { updateSite } from '@/lib/actions';
+import { cn } from '@/lib/utils';
+import { Input } from '@nextui-org/react';
+import {
+ GitHubLogoIcon,
+ GlobeIcon,
+ InstagramLogoIcon,
+ LinkedInLogoIcon,
+ TwitterLogoIcon,
+} from '@radix-ui/react-icons';
+import { Loader2, YoutubeIcon } from 'lucide-react';
+import { useParams } from 'next/navigation';
+import { useFormStatus } from 'react-dom';
+import { toast } from 'sonner';
+import { TypographyP } from '../common/Typography';
+export default function SocialMediaForm({
+ socials,
+}: {
+ socials: {
+ twitterid: string;
+ linkedinid: string;
+ githubid: string;
+ websiteurl: string;
+ instagramid: string;
+ youtubeurl: string;
+ };
}) {
- const { slug } = useParams() as { slug: string };
- return (
-
- updateSite(data, slug, "socials")
- .then(async (res) => {
- if (res.error) {
- toast.error("An error occurred. Please try again later.");
- } else {
-
- toast.success("Social Media Links Updated Successfully.");
- }
- })
- .catch((err: Error) => {
- toast.error("An error occurred. Please try again later.");
- })}
- className="rounded-lg border border-stone-200 bg-white dark:border-stone-700 dark:bg-black"
- >
-
-
-
-
- Instagram Profile
-
-
-
-
-
-
- LinkedIn Profile
-
-
-
-
-
- Twitter Profile
-
-
-
-
-
- Youtube Profile
-
-
-
-
-
-
-
-
-
+ const { slug } = useParams() as { slug: string };
+ return (
+
+ updateSite(data, slug, 'socials')
+ .then(async (res) => {
+ if (res.error) {
+ toast.error('An error occurred. Please try again later.');
+ } else {
+ toast.success('Social Media Links Updated Successfully.');
+ }
+ })
+ .catch((err: Error) => {
+ toast.error('An error occurred. Please try again later.');
+ })
+ }
+ className="rounded-lg border border-stone-200 bg-white dark:border-stone-700 dark:bg-black"
+ >
+
+
+
+
+ {' '}
+ Instagram Profile
-
- form>
- )
+
+
+
+
+ {' '}
+ Github Profile
+
+
+
+
+
+ {' '}
+ LinkedIn Profile
+
+
+
+
+
+ {' '}
+ Twitter Profile
+
+
+
+
+
+ {' '}
+ Youtube Profile
+
+
+
+
+
+ {' '}
+ Your website
+
+
+
+
+
+
+
+
+
+ );
}
-
function FormButton() {
- const { pending } = useFormStatus();
- return (
-
- {pending ? : Save Changes
}
-
- );
-}
\ No newline at end of file
+ const { pending } = useFormStatus();
+ return (
+
+ {pending ? (
+
+ ) : (
+ Save Changes
+ )}
+
+ );
+}
diff --git a/components/form/uploader.tsx b/components/form/uploader.tsx
index 9927355..d2919e9 100644
--- a/components/form/uploader.tsx
+++ b/components/form/uploader.tsx
@@ -1,163 +1,164 @@
-"use client";
-
-import { cn } from "@/lib/utils";
-import { useRef, useState } from "react";
-import { toast } from "sonner";
+'use client';
+import { cn } from '@/lib/utils';
+import { useRef, useState } from 'react';
+import { toast } from 'sonner';
export default function Uploader({
- defaultValue,
- name,
+ defaultValue,
+ name,
}: {
- defaultValue: string | null;
- name: "image" | "avatar" | "logo";
+ defaultValue: string | null;
+ name: 'image' | 'avatar' | 'logo';
}) {
- const aspectRatio = name === "image" ? "aspect-video" : "aspect-square";
- const inputRef = useRef
(null);
- const [data, setData] = useState({
- [name]: defaultValue,
- });
- const [dragActive, setDragActive] = useState(false);
- const handleUpload = (file: File | null) => {
- if (file) {
- if (file.size / 1024 / 1024 > 2) {
- toast.error("File size too big (max 2MB)");
- } else if (
- !file.type.includes("png") &&
- !file.type.includes("jpg") &&
- !file.type.includes("jpeg")
- ) {
- toast.error("Invalid file type (must be .png, .jpg, or .jpeg)");
- } else {
- const reader = new FileReader();
- reader.onload = (e) => {
- setData((prev) => ({ ...prev, [name]: e.target?.result as string }));
- };
- reader.readAsDataURL(file);
- }
- }
- };
-
- return (
-
-
- {
- e.preventDefault();
- e.stopPropagation();
- setDragActive(true);
- }}
- onDragEnter={(e) => {
- e.preventDefault();
- e.stopPropagation();
- setDragActive(true);
- }}
- onDragLeave={(e) => {
- e.preventDefault();
- e.stopPropagation();
- setDragActive(false);
- }}
- onDrop={(e) => {
- e.preventDefault();
- e.stopPropagation();
- setDragActive(false);
-// need to resolve this issue :)-- maye fixed who knows
- const file = e.dataTransfer.files&& e.dataTransfer.files[0];
- if (file) {
- if (file.size / 1024 / 1024 > 2) {
- toast.error("File size too big (max 2MB)");
- } else if (
- !file.type.includes("png") &&
- !file.type.includes("jpg") &&
- !file.type.includes("jpeg")
- ) {
- toast.error("Invalid file type (must be .png, .jpg, or .jpeg)");
- } else {
- inputRef.current!.files = e.dataTransfer.files; // set input file to dropped file
- handleUpload(file);
- }
- }
- }}
- />
-
-
-
-
-
-
-
- Drag and drop or click to upload.
-
-
- Max file size: 2MB
-
-
Photo upload
-
- {data[name] && (
- // eslint-disable-next-line @next/next/no-img-element
-
- )}
-
-
- {
- const file = e.currentTarget.files && e.currentTarget.files[0];
- if (file) {
- if (file.size / 1024 / 1024 > 2) {
- toast.error("File size too big (max 2MB)");
- } else if (
- !file.type.includes("png") &&
- !file.type.includes("jpg") &&
- !file.type.includes("jpeg")
- ) {
- toast.error("Invalid file type (must be .png, .jpg, or .jpeg)");
- } else {
- handleUpload(file);
- }
- }
+ const aspectRatio = name === 'image' ? 'aspect-video' : 'aspect-square';
+ const inputRef = useRef(null);
+ const [data, setData] = useState({
+ [name]: defaultValue,
+ });
+ const [dragActive, setDragActive] = useState(false);
+ const handleUpload = (file: File | null) => {
+ if (file) {
+ if (file.size / 1024 / 1024 > 2) {
+ toast.error('File size too big (max 2MB)');
+ } else if (
+ !file.type.includes('png') &&
+ !file.type.includes('jpg') &&
+ !file.type.includes('jpeg')
+ ) {
+ toast.error('Invalid file type (must be .png, .jpg, or .jpeg)');
+ } else {
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ setData((prev) => ({ ...prev, [name]: e.target?.result as string }));
+ };
+ reader.readAsDataURL(file);
+ }
+ }
+ };
- }}
- />
-
+ return (
+
+
+ {
+ e.preventDefault();
+ e.stopPropagation();
+ setDragActive(true);
+ }}
+ onDragEnter={(e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ setDragActive(true);
+ }}
+ onDragLeave={(e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ setDragActive(false);
+ }}
+ onDrop={(e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ setDragActive(false);
+ // need to resolve this issue :)-- maye fixed who knows
+ const file = e.dataTransfer.files?.[0];
+ if (file) {
+ if (file.size / 1024 / 1024 > 2) {
+ toast.error('File size too big (max 2MB)');
+ } else if (
+ !file.type.includes('png') &&
+ !file.type.includes('jpg') &&
+ !file.type.includes('jpeg')
+ ) {
+ toast.error('Invalid file type (must be .png, .jpg, or .jpeg)');
+ } else {
+ inputRef.current!.files = e.dataTransfer.files; // set input file to dropped file
+ handleUpload(file);
+ }
+ }
+ }}
+ />
+
+
+
+
+
+
+
+ Drag and drop or click to upload.
+
+
+ Max file size: 2MB
+
+
Photo upload
- );
+ {data[name] && (
+ // eslint-disable-next-line @next/next/no-img-element
+
+ )}
+
+
+ {
+ const file = e.currentTarget.files?.[0];
+ if (file) {
+ if (file.size / 1024 / 1024 > 2) {
+ toast.error('File size too big (max 2MB)');
+ } else if (
+ !file.type.includes('png') &&
+ !file.type.includes('jpg') &&
+ !file.type.includes('jpeg')
+ ) {
+ toast.error('Invalid file type (must be .png, .jpg, or .jpeg)');
+ } else {
+ handleUpload(file);
+ }
+ }
+ }}
+ />
+
+
+ );
}
diff --git a/components/form/use-domain-status.ts b/components/form/use-domain-status.ts
index e93bd32..00ebd50 100644
--- a/components/form/use-domain-status.ts
+++ b/components/form/use-domain-status.ts
@@ -1,20 +1,20 @@
-import { DomainResponse, DomainVerificationStatusProps } from "@/lib/types";
-import { fetcher } from "@/lib/utils";
-import useSWR from "swr";
+import { DomainResponse, DomainVerificationStatusProps } from '@/lib/types';
+import { fetcher } from '@/lib/utils';
+import useSWR from 'swr';
export function useDomainStatus({ domain }: { domain: string }) {
- const { data, isValidating } = useSWR<{
- status: DomainVerificationStatusProps;
- domainJson: DomainResponse & { error: { code: string; message: string } };
- }>(`/api/domain/${domain}/verify`, fetcher, {
- revalidateOnMount: true,
- refreshInterval: 5000,
- keepPreviousData: true,
- });
+ const { data, isValidating } = useSWR<{
+ status: DomainVerificationStatusProps;
+ domainJson: DomainResponse & { error: { code: string; message: string } };
+ }>(`/api/domain/${domain}/verify`, fetcher, {
+ revalidateOnMount: true,
+ refreshInterval: 5000,
+ keepPreviousData: true,
+ });
- return {
- status: data?.status,
- domainJson: data?.domainJson,
- loading: isValidating,
- };
+ return {
+ status: data?.status,
+ domainJson: data?.domainJson,
+ loading: isValidating,
+ };
}
diff --git a/components/form/work-form.tsx b/components/form/work-form.tsx
index c9877f9..b3df793 100644
--- a/components/form/work-form.tsx
+++ b/components/form/work-form.tsx
@@ -1,382 +1,404 @@
-"use client";
+'use client';
import {
- AlertDialog,
- AlertDialogAction,
- AlertDialogCancel,
- AlertDialogContent,
- AlertDialogDescription,
- AlertDialogFooter,
- AlertDialogHeader,
- AlertDialogTitle,
- AlertDialogTrigger,
-} from "@/components/ui/alert-dialog";
-import { Button } from "@/components/ui/button";
-import { Calendar } from "@/components/ui/calendar";
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+} from '@/components/ui/alert-dialog';
+import { Button } from '@/components/ui/button';
+import { Calendar } from '@/components/ui/calendar';
import {
- Form,
- FormControl,
- FormField,
- FormItem,
- FormLabel,
- FormMessage
-} from "@/components/ui/form";
-import { Input } from "@/components/ui/input";
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form';
+import { Input } from '@/components/ui/input';
import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from "@/components/ui/popover";
-import { ScrollArea } from "@/components/ui/scroll-area";
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from '@/components/ui/popover';
+import { ScrollArea } from '@/components/ui/scroll-area';
import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select";
-import { addWorkExperience, updateWorkExperience } from "@/lib/actions";
-import { cn } from "@/lib/utils";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { UserWorkExperience } from "@prisma/client";
-import { CalendarIcon } from "lucide-react";
-import { useParams, useRouter } from "next/navigation";
-import { useState } from "react";
-import { useForm } from "react-hook-form";
-import { toast } from "sonner";
-import { z } from "zod";
-import { Textarea } from "../ui/textarea";
-
-
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select';
+import { addWorkExperience, updateWorkExperience } from '@/lib/actions';
+import { cn } from '@/lib/utils';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { UserWorkExperience } from '@prisma/client';
+import { CalendarIcon } from 'lucide-react';
+import { useParams, useRouter } from 'next/navigation';
+import { useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { toast } from 'sonner';
+import { z } from 'zod';
+import { Textarea } from '../ui/textarea';
const CreateWorkExperienceSchema = z.object({
- company_name: z.string({
- required_error: "Company name is required",
- }),
- employment_position: z.string({
- required_error: "Company position is required",
- }),
- employment_start_date: z.date({
- required_error: "Company start date is required",
- }),
- employment_end_date: z.date({
- required_error: "Company end date is required",
- }).optional().nullable(),
- description: z.string({
- required_error: "Company description is required",
- }),
- employment_type: z.string({
- required_error: "Employment type is required",
- }),
+ company_name: z.string({
+ required_error: 'Company name is required',
+ }),
+ employment_position: z.string({
+ required_error: 'Company position is required',
+ }),
+ employment_start_date: z.date({
+ required_error: 'Company start date is required',
+ }),
+ employment_end_date: z
+ .date({
+ required_error: 'Company end date is required',
+ })
+ .optional()
+ .nullable(),
+ description: z.string({
+ required_error: 'Company description is required',
+ }),
+ employment_type: z.string({
+ required_error: 'Employment type is required',
+ }),
});
-
export default function WorkExperienceForm({
- title,
- method,
- work
+ title,
+ method,
+ work,
}: {
- title: string;
- method: "add" | "update";
+ title: string;
+ method: 'add' | 'update';
} & (
- | { method: "add"; work?: never } |
- { method: "update"; work: UserWorkExperience }
- )) {
+ | { method: 'add'; work?: never }
+ | { method: 'update'; work: UserWorkExperience }
+)) {
+ const [open, setOpen] = useState(false);
+ const { slug } = useParams() as { slug: string };
+ const router = useRouter();
- const [open, setOpen] = useState(false);
- const { slug } = useParams() as { slug: string };
- const router = useRouter();
-
-
- const form = useForm>({
- resolver: zodResolver(CreateWorkExperienceSchema),
- defaultValues: work ? {
- company_name: work.company_name,
- employment_position: work.employment_position,
- employment_start_date: new Date(work.employment_start_date),
- employment_end_date: work.employment_end_date ? new Date(work.employment_end_date) : null,
- description: work.descriptions || "", // Fix: Set description to an empty string if it's null or undefined
- employment_type: work.employment_type || "",
- } : {
- company_name: "",
- employment_position: "",
- employment_start_date: new Date(),
- employment_end_date: null,
- description: "", // Set description to an empty string
- employment_type: "",
+ const form = useForm>({
+ resolver: zodResolver(CreateWorkExperienceSchema),
+ defaultValues: work
+ ? {
+ company_name: work.company_name,
+ employment_position: work.employment_position,
+ employment_start_date: new Date(work.employment_start_date),
+ employment_end_date: work.employment_end_date
+ ? new Date(work.employment_end_date)
+ : null,
+ description: work.descriptions || '', // Fix: Set description to an empty string if it's null or undefined
+ employment_type: work.employment_type || '',
+ }
+ : {
+ company_name: '',
+ employment_position: '',
+ employment_start_date: new Date(),
+ employment_end_date: null,
+ description: '', // Set description to an empty string
+ employment_type: '',
},
- })
+ });
-
-
- function onSubmit(values: z.infer) {
- try {
- const formData = new FormData();
- formData.append("company_name", values.company_name);
- formData.append("employment_position", values.employment_position);
- formData.append("employment_start_date", values.employment_start_date.toISOString());
- formData.append("employment_end_date", values.employment_end_date ? values.employment_end_date.toISOString() : '');
- formData.append("description", values.description);
- formData.append("employment_type", values.employment_type);
- if (method === "add") {
- addWorkExperience(formData, "profile", slug).then(async (res: any) => {
- if (res.error) {
- // toast.error(res.error);
- console.log(res.error)
- toast("An error occurred.");
- } else {
- if (slug) {
- setOpen(false)
- router.refresh();
- } else {
- setOpen(false)
- router.refresh();
- }
- toast("🌱 Successfully added Work Experience!");
- }
- });
- } else if (method === "update") {
- console.log(work.id)
- updateWorkExperience(
- work.id,
- "null",
- formData
- ).then(async (res: any) => {
- if (res.error) {
- // toast.error(res.error);
- console.log(res.error)
- toast("An error occurred.");
- } else {
- if (slug) {
- setOpen(false)
- router.refresh();
- } else {
- setOpen(false)
- router.refresh();
- }
- toast("🌱 Successfully updated Work Experience!");
- }
- }
- );
+ function onSubmit(values: z.infer) {
+ try {
+ const formData = new FormData();
+ formData.append('company_name', values.company_name);
+ formData.append('employment_position', values.employment_position);
+ formData.append(
+ 'employment_start_date',
+ values.employment_start_date.toISOString()
+ );
+ formData.append(
+ 'employment_end_date',
+ values.employment_end_date
+ ? values.employment_end_date.toISOString()
+ : ''
+ );
+ formData.append('description', values.description);
+ formData.append('employment_type', values.employment_type);
+ if (method === 'add') {
+ addWorkExperience(formData, 'profile', slug).then(async (res: any) => {
+ if (res.error) {
+ // toast.error(res.error);
+ console.log(res.error);
+ toast('An error occurred.');
+ } else {
+ if (slug) {
+ setOpen(false);
+ router.refresh();
} else {
- toast("method not allowed");
+ setOpen(false);
+ router.refresh();
}
- } catch (error) {
- console.log(error)
- toast("An error occurred.");
- }
+ toast('🌱 Successfully added Work Experience!');
+ }
+ });
+ } else if (method === 'update') {
+ console.log(work.id);
+ updateWorkExperience(work.id, 'null', formData).then(
+ async (res: any) => {
+ if (res.error) {
+ // toast.error(res.error);
+ console.log(res.error);
+ toast('An error occurred.');
+ } else {
+ if (slug) {
+ setOpen(false);
+ router.refresh();
+ } else {
+ setOpen(false);
+ router.refresh();
+ }
+ toast('🌱 Successfully updated Work Experience!');
+ }
+ }
+ );
+ } else {
+ toast('method not allowed');
+ }
+ } catch (error) {
+ console.log(error);
+ toast('An error occurred.');
}
+ }
-
- return (
-
-
- {
- method === "add" ? "Add work experience" : "Edit work experience"
- }
-
-
-
- {title}
-
- This will be visible in your Portfolio.
-
-
-
-
- (
-
- Company name
-
-
-
-
-
- )}
- />
-
-
(
-
- From
-
-
-
-
-
-
- {field.value ? (
- {field.value?.toLocaleDateString()}
- ) : (
- Pick a date
- )}
-
-
-
-
-
- {
- field.onChange(new Date(date))
- }}
- className="rounded-md border"
- />
-
-
-
-
-
- )}
- />
- (
-
- To
-
-
-
-
-
-
- {/* RangeError: Invalid time value */}
- {field.value ? (
- {field.value?.toLocaleDateString()}
- ) : (
- Pick a date
- )}
-
-
-
-
-
- {
- field.onChange(new Date(date))
- }}
- className="rounded-md border"
- />
-
-
-
-
-
- )}
- />
-
-
- (
-
- Title
-
-
-
-
-
- )}
- />
- (
-
- Employment Type
-
- {
- field.onChange(value)
- }}
- >
-
-
-
-
- Full Time
- Part Time
- Self Employed
- Freelance
- Internship
-
-
-
-
-
- )}
- />
-
- (
-
- Description
-
-
-
-
-
- )}
- />
-
-
-
-
-
- Cancel
- {
- e.preventDefault();
- form.handleSubmit(onSubmit)();
- }
- }>
- {method === "add" ? "Add" : "Update"}
-
-
-
-
- )
+ return (
+
+
+
+ {method === 'add' ? 'Add work experience' : 'Edit work experience'}
+
+
+
+
+ {title}
+
+ This will be visible in your Portfolio.
+
+
+
+
+ (
+
+ Company name
+
+
+
+
+
+ )}
+ />
+
+
(
+
+ From
+
+
+
+
+
+
+ {field.value ? (
+
+ {field.value?.toLocaleDateString()}
+
+ ) : (
+ Pick a date
+ )}
+
+
+
+
+
+ {
+ field.onChange(new Date(date));
+ }}
+ className="rounded-md border"
+ />
+
+
+
+
+
+ )}
+ />
+ (
+
+ To
+
+
+
+
+
+
+ {/* RangeError: Invalid time value */}
+ {field.value ? (
+
+ {field.value?.toLocaleDateString()}
+
+ ) : (
+ Pick a date
+ )}
+
+
+
+
+
+ {
+ field.onChange(new Date(date));
+ }}
+ className="rounded-md border"
+ />
+
+
+
+
+
+ )}
+ />
+
+
+ (
+
+ Title
+
+
+
+
+
+ )}
+ />
+ (
+
+ Employment Type
+
+ {
+ field.onChange(value);
+ }}
+ >
+
+
+
+
+
+ Full Time
+
+
+ Part Time
+
+
+ Self Employed
+
+
+ Freelance
+
+
+ Internship
+
+
+
+
+
+
+ )}
+ />
+
+ (
+
+ Description
+
+
+
+
+
+ )}
+ />
+
+
+
+
+
+ Cancel
+ {
+ e.preventDefault();
+ form.handleSubmit(onSubmit)();
+ }}
+ >
+ {method === 'add' ? 'Add' : 'Update'}
+
+
+
+
+ );
}
function addEducation(formData: FormData, arg1: string, slug: string) {
- throw new Error("Function not implemented.");
+ throw new Error('Function not implemented.');
}
function updateEducation(id: any, arg1: string, formData: FormData) {
- throw new Error("Function not implemented.");
+ throw new Error('Function not implemented.');
}
-
diff --git a/components/home/WaitListForm.tsx b/components/home/WaitListForm.tsx
index 822c604..1df0f8f 100644
--- a/components/home/WaitListForm.tsx
+++ b/components/home/WaitListForm.tsx
@@ -1,148 +1,141 @@
-"use client";
+'use client';
-
-import { Button } from "@/components/ui/button";
+import { Button } from '@/components/ui/button';
import {
- Form,
- FormControl,
- FormDescription,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
-} from "@/components/ui/form";
-import { Input } from "@/components/ui/input";
-import { JOIN_MAILING_LIST } from "@/lib/contants";
-import prisma from "@/lib/db";
-import { zodResolver } from "@hookform/resolvers/zod";
-import confetti from "canvas-confetti";
-import { Loader2, MailIcon } from "lucide-react";
-import Image from "next/image";
-import { useState } from "react";
-import { useForm } from "react-hook-form";
-import { toast } from "sonner";
-import * as z from "zod";
-import { TypographyH1 } from "../common/Typography";
-
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from '@/components/ui/form';
+import { Input } from '@/components/ui/input';
+import { JOIN_MAILING_LIST } from '@/lib/contants';
+import prisma from '@/lib/db';
+import { zodResolver } from '@hookform/resolvers/zod';
+import confetti from 'canvas-confetti';
+import { Loader2, MailIcon } from 'lucide-react';
+import Image from 'next/image';
+import { useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { toast } from 'sonner';
+import * as z from 'zod';
+import { TypographyH1 } from '../common/Typography';
const formSchema = z.object({
- email: z.string().email(),
-})
-
+ email: z.string().email(),
+});
export default function WaitlistForm() {
+ const [sending, setSending] = useState(false);
- const [sending, setSending] = useState(false);
-
+ const form = useForm>({
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ email: '',
+ },
+ });
- const form = useForm>({
- resolver: zodResolver(formSchema),
- defaultValues: {
- email: "",
+ async function onSubmit(values: z.infer) {
+ // Do something with the form values.
+ // ✅ This will be type-safe and validated.
+ console.log(values);
+ setSending(true);
+ try {
+ await prisma.newsletter.create({
+ data: {
+ email: values.email,
},
- })
-
-
- async function onSubmit(values: z.infer) {
- // Do something with the form values.
- // ✅ This will be type-safe and validated.
- console.log(values)
- setSending(true);
- try {
- await prisma.newsletter.create({
- data: {
- email: values.email
- }
- });
- return handleSubmit;
- } catch (error: any) {
- if (error.code === "P2002") {
- toast("Email is Already in Waiting List")
- return {
- error: `Email is Already in Waiting List`,
- };
- } else {
- toast.error(error.title)
- return {
- error: error.message,
- };
- }
- }
+ });
+ return handleSubmit;
+ } catch (error: any) {
+ if (error.code === 'P2002') {
+ toast('Email is Already in Waiting List');
+ return {
+ error: 'Email is Already in Waiting List',
+ };
+ } else {
+ toast.error(error.title);
+ return {
+ error: error.message,
+ };
+ }
}
+ }
+ const handleSubmit = async () => {
+ let id = setTimeout(() => {
+ setSending(false);
+ toast.success('You are in the waiting list now 🎉');
+ confetti({
+ angle: 60,
+ spread: 55,
+ origin: { x: 0 },
+ });
+ confetti({
+ angle: 120,
+ spread: 55,
+ origin: { x: 1 },
+ });
+ clearTimeout(id);
+ }, 2000);
+ };
- const handleSubmit = async () => {
-
- let id = setTimeout(() => {
- setSending(false);
- toast.success("You are in the waiting list now 🎉");
- confetti({
- angle: 60,
- spread: 55,
- origin: { x: 0 },
- });
- confetti({
- angle: 120,
- spread: 55,
- origin: { x: 1 },
- });
- clearTimeout(id);
- }, 2000);
- };
-
- return (
-
-
-
Ready to join our waitlist?{" "}
-
+ return (
+
+
+ Ready to join our waitlist?
+
+
+
+
+
+
-
-
-
-
-
-
- )
-}
\ No newline at end of file
+
+
+
+
+
+ );
+}
diff --git a/components/home/buildbyDevelopers.tsx b/components/home/buildbyDevelopers.tsx
index e99a09f..f36cce3 100644
--- a/components/home/buildbyDevelopers.tsx
+++ b/components/home/buildbyDevelopers.tsx
@@ -1,30 +1,27 @@
-"use client";
-import { AnimatedTooltip } from "@/components/ui/animated-tooltip";
+'use client';
+import { AnimatedTooltip } from '@/components/ui/animated-tooltip';
const people = [
- {
- id: 1,
- name: "AbhisheK Kushwaha",
- designation: "Full Stack Developer",
- image:
- "https://avatars.githubusercontent.com/u/86338762?v=4",
- },
- {
- id: 2,
- name: "Shemanti Pal",
- designation: "Designer @DevResume",
- image:
- "https://avatars.githubusercontent.com/u/116779027?v=4",
- },
+ {
+ id: 1,
+ name: 'AbhisheK Kushwaha',
+ designation: 'Full Stack Developer',
+ image: 'https://avatars.githubusercontent.com/u/86338762?v=4',
+ },
+ {
+ id: 2,
+ name: 'Shemanti Pal',
+ designation: 'Designer @DevResume',
+ image: 'https://avatars.githubusercontent.com/u/116779027?v=4',
+ },
];
-
function BuildByDevelopers() {
- return (
-
- )
+ return (
+
+ );
}
-export default BuildByDevelopers
\ No newline at end of file
+export default BuildByDevelopers;
diff --git a/components/home/buildwithcreativity.tsx b/components/home/buildwithcreativity.tsx
index 30432a1..65ef248 100644
--- a/components/home/buildwithcreativity.tsx
+++ b/components/home/buildwithcreativity.tsx
@@ -1,37 +1,37 @@
-"use client";
-import { GoogleGeminiEffect } from "@/components/ui/google-gemini-effect";
-import { useScroll, useTransform } from "framer-motion";
-import React from "react";
+'use client';
+import { GoogleGeminiEffect } from '@/components/ui/google-gemini-effect';
+import { useScroll, useTransform } from 'framer-motion';
+import React from 'react';
export function BuildWithCreativity() {
- const ref = React.useRef(null);
- const { scrollYProgress } = useScroll({
- target: ref,
- offset: ["start start", "end start"],
- });
+ const ref = React.useRef(null);
+ const { scrollYProgress } = useScroll({
+ target: ref,
+ offset: ['start start', 'end start'],
+ });
- const pathLengthFirst = useTransform(scrollYProgress, [0, 0.8], [0.2, 1.2]);
- const pathLengthSecond = useTransform(scrollYProgress, [0, 0.8], [0.15, 1.2]);
- const pathLengthThird = useTransform(scrollYProgress, [0, 0.8], [0.1, 1.2]);
- const pathLengthFourth = useTransform(scrollYProgress, [0, 0.8], [0.05, 1.2]);
- const pathLengthFifth = useTransform(scrollYProgress, [0, 0.8], [0, 1.2]);
+ const pathLengthFirst = useTransform(scrollYProgress, [0, 0.8], [0.2, 1.2]);
+ const pathLengthSecond = useTransform(scrollYProgress, [0, 0.8], [0.15, 1.2]);
+ const pathLengthThird = useTransform(scrollYProgress, [0, 0.8], [0.1, 1.2]);
+ const pathLengthFourth = useTransform(scrollYProgress, [0, 0.8], [0.05, 1.2]);
+ const pathLengthFifth = useTransform(scrollYProgress, [0, 0.8], [0, 1.2]);
- return (
-
-
-
- );
+ return (
+
+
+
+ );
}
diff --git a/components/home/landingsection.tsx b/components/home/landingsection.tsx
index cebb422..fe5a930 100644
--- a/components/home/landingsection.tsx
+++ b/components/home/landingsection.tsx
@@ -1,79 +1,82 @@
-
-import { AnimatedTooltip } from "@/components/ui/animated-tooltip";
-import { APP_CORE_DEVELOPER, APP_DASHBOARD_LINK, APP_DESC, APP_GITHUB_REPO_LINK, APP_NAME } from "@/lib/contants";
-import { Button } from "@nextui-org/react";
-import { GitHubLogoIcon } from "@radix-ui/react-icons";
-import Image from "next/image";
-import Link from "next/link";
-import { TypewriterEffect } from "../ui/typewriter-effect";
+import { AnimatedTooltip } from '@/components/ui/animated-tooltip';
+import {
+ APP_CORE_DEVELOPER,
+ APP_DASHBOARD_LINK,
+ APP_DESC,
+ APP_GITHUB_REPO_LINK,
+ APP_NAME,
+} from '@/lib/contants';
+import { Button } from '@nextui-org/react';
+import { GitHubLogoIcon } from '@radix-ui/react-icons';
+import Image from 'next/image';
+import Link from 'next/link';
+import { TypewriterEffect } from '../ui/typewriter-effect';
function LandingSection() {
- return (
-
- {/* Radial gradient for the container to give a faded look */}
-
-
-
-
-
- {APP_DESC}
-
-
-
+ {/* Radial gradient for the container to give a faded look */}
+
+
+
+
+
{APP_DESC}
+
+
+
-
-
-
- Get Started
-
-
-
- }
- >
- Github
-
-
-
-
Proudly brought to you by
-
-
-
-
+ // style="width: 250px; height: 54px;" width="250" height="54"
+ />
+
+
+
+
+ Get Started
+
+
+
+ }
+ >
+ Github
+
+
+
+
Proudly brought to you by
+
+
-
- )
+
+
+ );
}
-export default LandingSection
\ No newline at end of file
+export default LandingSection;
diff --git a/components/mdx.module.css b/components/mdx.module.css
index beee16c..b845539 100644
--- a/components/mdx.module.css
+++ b/components/mdx.module.css
@@ -1,23 +1,23 @@
.root :global(.react-tweet-theme) :is(p, img) {
- margin: 0;
- }
-
+ margin: 0;
+}
+
.root :global(.react-tweet-theme) a {
- font-weight: 300;
+ font-weight: 300;
}
-.root :global(h1 , h2 , h3 , h4) {
- @apply font-title bg-primary
+.root :global(h1, h2, h3, h4) {
+ @apply font-title bg-primary;
}
-
+
.root :global code[class*='language-'] {
/* color: #d6e7ff; */
/* background: #030314; */
text-shadow: none;
- font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
+ font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
line-height: 1.5;
- letter-spacing: .2px;
+ letter-spacing: 0.2px;
white-space: pre;
word-spacing: normal;
word-break: normal;
@@ -32,21 +32,23 @@
hyphens: none;
}
-.root :global(pre[class*='language-']::-moz-selection,
-pre[class*='language-'] ::-moz-selection,
-code[class*='language-']::-moz-selection,
-code[class*='language-'] ::-moz-selection,
-pre[class*='language-']::selection,
-pre[class*='language-'] ::selection,
-code[class*='language-']::selection,
-code[class*='language-'] ::selection) {
+.root
+ :global(
+ pre[class*='language-']::-moz-selection,
+ pre[class*='language-'] ::-moz-selection,
+ code[class*='language-']::-moz-selection,
+ code[class*='language-'] ::-moz-selection,
+ pre[class*='language-']::selection,
+ pre[class*='language-'] ::selection,
+ code[class*='language-']::selection,
+ code[class*='language-'] ::selection
+ ) {
color: inherit;
background: #1d3b54;
text-shadow: none;
}
-.root :global pre[class*='language-']
- {
+.root :global pre[class*='language-'] {
border: 1px solid #2a4555;
border-radius: 5px;
padding: 1.5em 1em;
@@ -54,7 +56,7 @@ code[class*='language-'] ::selection) {
overflow: auto;
}
-.root :global :not(pre)>code[class*='language-'] {
+.root :global :not(pre) > code[class*='language-'] {
color: #f0f6f6;
background: #2a4555;
padding: 0.2em 0.3em;
@@ -62,14 +64,11 @@ code[class*='language-'] ::selection) {
box-decoration-break: clone;
}
-.root :global(.token.comment,
-.token.prolog,
-.token.doctype,
-.token.cdata) {
+.root :global(.token.comment, .token.prolog, .token.doctype, .token.cdata) {
color: #446e69;
}
-.root :global .token.punctuation {
+.root :global .token.punctuation {
color: #d6b007;
}
@@ -79,7 +78,7 @@ code[class*='language-'] ::selection) {
.token.number,
.token.constant,
.token.symbol,
-.token.deleted {
+.token.deleted {
color: #d6e7ff;
}
@@ -90,33 +89,32 @@ code[class*='language-'] ::selection) {
color: #e60067;
}
-.root .token.string , .token.char {
+.root .token.string,
+.token.char {
color: #49c6ec;
}
-.root :global(.token.operator,
-.token.entity,
-.token.url,
-.language-css .token.string,
-.style .token.string) {
+.root
+ :global(
+ .token.operator,
+ .token.entity,
+ .token.url,
+ .language-css .token.string,
+ .style .token.string
+ ) {
color: #ec8e01;
background: transparent;
}
-.root :global(.token.atrule,
-.token.attr-value,
-.token.keyword) {
+.root :global(.token.atrule, .token.attr-value, .token.keyword) {
color: #0fe468;
}
-.root :global(.token.function,
-.token.class-name ){
+.root :global(.token.function, .token.class-name) {
color: #78f3e9;
}
-.root :global(.token.regex,
-.token.important,
-.token.variable) {
+.root :global(.token.regex, .token.important, .token.variable) {
color: #d6e7ff;
}
@@ -124,7 +122,6 @@ code[class*='language-'] ::selection) {
overflow-x: auto;
}
-
/**
* Inspired by gatsby remark prism - https://www.gatsbyjs.com/plugins/gatsby-remark-prismjs/
* 1. Make the element just wide enough to fit its content.
@@ -138,7 +135,7 @@ code[class*='language-'] ::selection) {
/* 2 */
}
-.root :global(.code-line ){
+.root :global(.code-line) {
display: block;
padding-left: 16px;
padding-right: 16px;
@@ -148,7 +145,7 @@ code[class*='language-'] ::selection) {
/* Set placeholder for highlight accent border color to transparent */
}
-.root :global(.code-line.inserted ){
+.root :global(.code-line.inserted) {
background-color: rgba(16, 185, 129, 0.2);
/* Set inserted line (+) color */
}
@@ -176,6 +173,3 @@ code[class*='language-'] ::selection) {
color: rgb(156, 163, 175);
content: attr(line);
}
-
-
-
diff --git a/components/mdx.tsx b/components/mdx.tsx
index 56dc946..4532adc 100644
--- a/components/mdx.tsx
+++ b/components/mdx.tsx
@@ -1,97 +1,96 @@
-"use client";
+'use client';
-import BlurImage from "@/components/blur-image";
-import { replaceLinks } from "@/lib/remark-plugins";
-import { Blog } from "@prisma/client";
-import { MDXRemote, MDXRemoteProps } from "next-mdx-remote";
+import BlurImage from '@/components/blur-image';
+import { replaceLinks } from '@/lib/remark-plugins';
+import { Blog } from '@prisma/client';
+import { MDXRemote, MDXRemoteProps } from 'next-mdx-remote';
import 'prismjs/plugins/line-numbers/prism-line-numbers.css';
// import 'prismjs/themes//';
-import { Tweet } from "react-tweet";
-import styles from "./mdx.module.css";
-
+import { Tweet } from 'react-tweet';
+import styles from './mdx.module.css';
export default function MDX({ source }: { source: MDXRemoteProps }) {
- const components = {
- a: replaceLinks,
- BlurImage,
- Examples,
- Tweet,
- };
+ const components = {
+ a: replaceLinks,
+ BlurImage,
+ Examples,
+ Tweet,
+ };
- return (
-
- {/* @ts-ignore */}
-
-
- );
+ return (
+
+ {/* @ts-expect-error */}
+
+
+ );
}
interface ExampleCardProps
- extends Pick
{
- name: string | null;
- url: string | null;
+ extends Pick {
+ name: string | null;
+ url: string | null;
}
function Examples({ data }: { data: string }) {
- if (!data) return null;
- const parsedData = JSON.parse(data) as Array;
- return (
-
- {parsedData.map((d) => (
-
- ))}
-
- );
+ if (!data) return null;
+ const parsedData = JSON.parse(data) as Array;
+ return (
+
+ {parsedData.map((d) => (
+
+ ))}
+
+ );
}
function ExamplesCard({ data }: { data: ExampleCardProps }) {
- return (
-
-
-
-
-
-
-
- {data.name}
-
-
- {data.description}
-
-
-
-
-
-
-
-
-
- {data.name}
-
-
- {data.description}
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+ {data.name}
+
+
+ {data.description}
+
+
+
+
+
+
+
+
+
+ {data.name}
+
+
+ {data.description}
+
+
+
+
+ );
}
diff --git a/components/placeholder-card.tsx b/components/placeholder-card.tsx
index 38ed6ee..7439449 100644
--- a/components/placeholder-card.tsx
+++ b/components/placeholder-card.tsx
@@ -1,12 +1,12 @@
export default function PlaceholderCard() {
- return (
-
- );
-}
\ No newline at end of file
+ return (
+
+ );
+}
diff --git a/components/themes/DefaultTheme.tsx b/components/themes/DefaultTheme.tsx
index 7b7bae4..79eabbf 100644
--- a/components/themes/DefaultTheme.tsx
+++ b/components/themes/DefaultTheme.tsx
@@ -1,99 +1,94 @@
-import { Projects, SiteTechStack, UserCertificate, UserEducation, UserWorkExperience } from "@prisma/client";
-import { MDXRemoteSerializeResult } from "next-mdx-remote";
-import AboutSection from "./default/AboutSection";
-import ContactSection from "./default/ContactSection";
-import EducationSection from "./default/EducationSection";
-import ExperienceSection from "./default/ExperienceSection";
-import FooterSection from "./default/FooterSection";
-import HomeSection from "./default/HomeSection";
-import UserPortfolioNavbar from "./default/Navbar";
-import ProjectSection from "./default/ProjectSection";
-import TechStackSection from "./default/TechStack";
+import {
+ Projects,
+ SiteTechStack,
+ UserCertificate,
+ UserEducation,
+ UserWorkExperience,
+} from '@prisma/client';
+import { MDXRemoteSerializeResult } from 'next-mdx-remote';
+import AboutSection from './default/AboutSection';
+import ContactSection from './default/ContactSection';
+import EducationSection from './default/EducationSection';
+import ExperienceSection from './default/ExperienceSection';
+import FooterSection from './default/FooterSection';
+import HomeSection from './default/HomeSection';
+import UserPortfolioNavbar from './default/Navbar';
+import ProjectSection from './default/ProjectSection';
+import TechStackSection from './default/TechStack';
function DefaultTheme({
- sitedata,
- about
+ sitedata,
+ about,
}: {
- // sitedata conatins mixed tyypes
- sitedata: {
- id: string,
- education: UserEducation[],
- certificates: UserCertificate[],
- workexperience: UserWorkExperience[],
- projects: Projects[],
- siteTechStack: SiteTechStack[],
- name: string,
- tagline: string,
- logo: string | null,
- twitterid: string | null,
- githubid: string | null,
- linkedinid: string | null,
- websiteurl: string | null,
- youtubeurl: string | null,
- instagramid: string | null,
- skills: string[],
-
- }
- about: {
- about: string
- mdxSource: MDXRemoteSerializeResult, Record>
- }
+ // sitedata conatins mixed tyypes
+ sitedata: {
+ id: string;
+ education: UserEducation[];
+ certificates: UserCertificate[];
+ workexperience: UserWorkExperience[];
+ projects: Projects[];
+ siteTechStack: SiteTechStack[];
+ name: string;
+ tagline: string;
+ logo: string | null;
+ twitterid: string | null;
+ githubid: string | null;
+ linkedinid: string | null;
+ websiteurl: string | null;
+ youtubeurl: string | null;
+ instagramid: string | null;
+ skills: string[];
+ };
+ about: {
+ about: string;
+ mdxSource: MDXRemoteSerializeResult<
+ Record,
+ Record
+ >;
+ };
}) {
- return (
- <>
-
-
-
-
-
-
-
-
+ return (
+ <>
+
+
- >
- )
+
+
+ >
+ );
}
-export default DefaultTheme
\ No newline at end of file
+export default DefaultTheme;
diff --git a/components/themes/default/AboutSection.tsx b/components/themes/default/AboutSection.tsx
index bb28025..f66badb 100644
--- a/components/themes/default/AboutSection.tsx
+++ b/components/themes/default/AboutSection.tsx
@@ -1,46 +1,46 @@
-"use client";
+'use client';
-import { TypographyH2 } from "@/components/common/Typography";
-import MDX from "@/components/mdx";
+import { TypographyH2 } from '@/components/common/Typography';
+import MDX from '@/components/mdx';
-function AboutSection({ skills, mdxabout }: { skills: string[], mdxabout: any }) {
+function AboutSection({
+ skills,
+ mdxabout,
+}: {
+ skills: string[];
+ mdxabout: any;
+}) {
+ // console.log(mdxabout)
- // console.log(mdxabout)
-
- return (
-
-
About
-
-
-
-
-
- Skill Stacks
-
- {
- skills?.slice(0, 5).map((skill, index) => (
-
-
{skill}
-
- ))
- }
-
-
+ return (
+
+
About
+
+
+
+
+
+ Skill Stacks
+
+ {skills?.slice(0, 5).map((skill, index) => (
+
+
{skill}
+
+ ))}
+
- )
+
+
+ );
}
-export default AboutSection
\ No newline at end of file
+export default AboutSection;
diff --git a/components/themes/default/ContactSection.tsx b/components/themes/default/ContactSection.tsx
index e2f31de..84220d1 100644
--- a/components/themes/default/ContactSection.tsx
+++ b/components/themes/default/ContactSection.tsx
@@ -1,106 +1,84 @@
-import { TypographyH2, TypographyP } from "@/components/common/Typography"
-import { InstagramLogoIcon } from "@radix-ui/react-icons"
-import { GithubIcon, Globe2Icon, LinkedinIcon, Twitter, YoutubeIcon } from "lucide-react"
-import Link from "next/link"
+import { TypographyH2, TypographyP } from '@/components/common/Typography';
+import { InstagramLogoIcon } from '@radix-ui/react-icons';
+import {
+ GithubIcon,
+ Globe2Icon,
+ LinkedinIcon,
+ Twitter,
+ YoutubeIcon,
+} from 'lucide-react';
+import Link from 'next/link';
-function ContactSection({ twitterid, githubid, linkedinid, websiteurl, youtubeurl, instagramid }: {
- twitterid: string,
- githubid: string,
- linkedinid: string,
- websiteurl: string,
- youtubeurl: string,
- instagramid: string
+function ContactSection({
+ twitterid,
+ githubid,
+ linkedinid,
+ websiteurl,
+ youtubeurl,
+ instagramid,
+}: {
+ twitterid: string;
+ githubid: string;
+ linkedinid: string;
+ websiteurl: string;
+ youtubeurl: string;
+ instagramid: string;
}) {
- return (
-
- )
+
+ Let's Collaborate
+
+ If you're interested in collaborating or have any inquiries,
+
+ Please don't hesitate to get in touch. I'm open to exciting
+ opportunities and projects.
+
+
+
+ {twitterid ? (
+
+
+
+ ) : null}
+ {githubid ? (
+
+
+
+ ) : null}
+ {linkedinid ? (
+
+
+
+ ) : null}
+ {youtubeurl ? (
+
+
+
+ ) : null}
+ {instagramid ? (
+
+
+
+ ) : null}
+ {websiteurl ? (
+
+
+
+ ) : null}
+
+
+ );
}
-export default ContactSection
\ No newline at end of file
+export default ContactSection;
diff --git a/components/themes/default/EducationSection.tsx b/components/themes/default/EducationSection.tsx
index 045d31c..6062f23 100644
--- a/components/themes/default/EducationSection.tsx
+++ b/components/themes/default/EducationSection.tsx
@@ -1,41 +1,48 @@
-import { TypographyH4, TypographyMuted, TypographyP } from "@/components/common/Typography";
-import { toDateString } from "@/lib/utils";
-import { UserEducation } from "@prisma/client";
+import {
+ TypographyH4,
+ TypographyMuted,
+ TypographyP,
+} from '@/components/common/Typography';
+import { toDateString } from '@/lib/utils';
+import { UserEducation } from '@prisma/client';
function EducationSection({ education }: { education: UserEducation[] }) {
+ if (education.length === 0) return null;
-
- if (education.length === 0) return null;
-
- return (
-
- Education
-
-
+ Education
+
+
- Academics
-
+ >
+ Academics
+
+
+
+ {education.length > 0 &&
+ education.map((edu, index) => (
+
+
+
+ {edu.school_degree} in {edu.school_major}
+
+
+ {edu.school_name} ,{' '}
+ {edu.school_location}
+
+
+ {toDateString(edu.school_start_date!)} -{' '}
+ {toDateString(edu.school_end_date!)}
+
+
+ {edu.education_note}
+
+
-
- {education.length > 0 &&
- education.map((edu, index) => (
-
-
- {edu.school_degree} in {edu.school_major}
-
- {edu.school_name} , {edu.school_location}
-
- {toDateString(edu.school_start_date!)} - {toDateString(edu.school_end_date!)}
-
- {edu.education_note}
-
-
-
- ))
- }
- {/*
+ ))}
+ {/*
Bachelor's Degree in Computer Science & Engineering
@@ -47,9 +54,9 @@ function EducationSection({ education }: { education: UserEducation[] }) {
*/}
-
-
- )
+
+
+ );
}
-export default EducationSection
\ No newline at end of file
+export default EducationSection;
diff --git a/components/themes/default/ExperienceSection.tsx b/components/themes/default/ExperienceSection.tsx
index d798abd..040eddd 100644
--- a/components/themes/default/ExperienceSection.tsx
+++ b/components/themes/default/ExperienceSection.tsx
@@ -1,51 +1,64 @@
-import { TypographyH3, TypographyH4, TypographyMuted, TypographyP } from "@/components/common/Typography";
-import { TextGenerateEffect } from "@/components/ui/text-generate-effect";
-import { toDateString } from "@/lib/utils";
-import { UserWorkExperience } from "@prisma/client";
+import {
+ TypographyH3,
+ TypographyH4,
+ TypographyMuted,
+ TypographyP,
+} from '@/components/common/Typography';
+import { TextGenerateEffect } from '@/components/ui/text-generate-effect';
+import { toDateString } from '@/lib/utils';
+import { UserWorkExperience } from '@prisma/client';
+function ExperienceSection({
+ workexperience,
+}: {
+ workexperience: UserWorkExperience[];
+}) {
+ if (workexperience.length === 0) return null;
-
-function ExperienceSection({ workexperience }: { workexperience: UserWorkExperience[] }) {
-
-
-
- if (workexperience.length === 0) return null;
-
-
- return (
-
- Experience
-
-
+ Experience
+
+
- profile
-
-
-
- {workexperience.length > 0 &&
- workexperience.map((work, index) => (
-
-
- {work.employment_position}
- {work.company_name}
-
- {work.company_location}
-
- {
- toDateString(work.employment_start_date!)} -
- {
- work.still_working ? Present : work.employment_end_date && toDateString(work.employment_end_date)
- }
-
-
-
- ))
- }
+ >
+ profile
+
+
+
+ {workexperience.length > 0 &&
+ workexperience.map((work, index) => (
+
+
+
+
+ {work.employment_position}
+
+
+ {work.company_name}
+
+ {work.company_location}
+
+
+ {toDateString(work.employment_start_date!)} -
+ {work.still_working ? (
+ Present
+ ) : (
+ work.employment_end_date &&
+ toDateString(work.employment_end_date)
+ )}
+
+
+
-
- )
+ ))}
+
+
+ );
}
-export default ExperienceSection
\ No newline at end of file
+export default ExperienceSection;
diff --git a/components/themes/default/FooterSection.tsx b/components/themes/default/FooterSection.tsx
index e230084..8a2a353 100644
--- a/components/themes/default/FooterSection.tsx
+++ b/components/themes/default/FooterSection.tsx
@@ -1,21 +1,21 @@
-import { TypographyH4 } from "@/components/common/Typography"
-import Link from "next/link"
+import { TypographyH4 } from '@/components/common/Typography';
+import Link from 'next/link';
function FooterSection() {
- return (
-
- Built with 💚 and
-
- Dresume.me
-
-
-
- )
+ return (
+
+
+ Built with 💚 and
+
+ Dresume.me
+
+
+
+ );
}
-export default FooterSection
\ No newline at end of file
+export default FooterSection;
diff --git a/components/themes/default/HomeSection.tsx b/components/themes/default/HomeSection.tsx
index c6de6c0..65bb95b 100644
--- a/components/themes/default/HomeSection.tsx
+++ b/components/themes/default/HomeSection.tsx
@@ -1,114 +1,99 @@
-import { TypographyH1 } from "@/components/common/Typography";
-import { InstagramLogoIcon } from "@radix-ui/react-icons";
-import { GithubIcon, Globe2Icon, LinkedinIcon, Twitter, YoutubeIcon } from 'lucide-react';
-import Image from "next/image";
-import Link from "next/link";
+import { TypographyH1 } from '@/components/common/Typography';
+import { InstagramLogoIcon } from '@radix-ui/react-icons';
+import {
+ GithubIcon,
+ Globe2Icon,
+ LinkedinIcon,
+ Twitter,
+ YoutubeIcon,
+} from 'lucide-react';
+import Image from 'next/image';
+import Link from 'next/link';
-
-function HomeSection({ name, image, tagline, twitterid, githubid, linkedinid, websiteurl, youtubeurl, instagramid }: {
- name: string,
- image: string,
- tagline: string,
- twitterid: string,
- githubid: string,
- linkedinid: string,
- youtubeurl: string,
- instagramid: string,
- websiteurl: string,
+function HomeSection({
+ name,
+ image,
+ tagline,
+ twitterid,
+ githubid,
+ linkedinid,
+ websiteurl,
+ youtubeurl,
+ instagramid,
+}: {
+ name: string;
+ image: string;
+ tagline: string;
+ twitterid: string;
+ githubid: string;
+ linkedinid: string;
+ youtubeurl: string;
+ instagramid: string;
+ websiteurl: string;
}) {
- return (
-
-
-
-
{name}
-
{tagline}
-
- {
- twitterid ? (
-
-
-
- ) : null
- }
- {
- githubid ? (
-
-
-
- ) : null
- }
- {
- linkedinid ? (
-
-
-
- ) : null
- }
- {
- youtubeurl ? (
-
-
-
- ) : null
- }
- {
- instagramid ? (
-
-
-
- ) : null
- }
- {
- websiteurl ? (
-
-
-
- ) : null
- }
-
-
-
-
-
-
-
- Let's
- Talk!
-
-
-
-
- )
+ return (
+
+
+
+ {name}
+
+
{tagline}
+
+ {twitterid ? (
+
+
+
+ ) : null}
+ {githubid ? (
+
+
+
+ ) : null}
+ {linkedinid ? (
+
+
+
+ ) : null}
+ {youtubeurl ? (
+
+
+
+ ) : null}
+ {instagramid ? (
+
+
+
+ ) : null}
+ {websiteurl ? (
+
+
+
+ ) : null}
+
+
+
+
+
+
+ Let's Talk!
+
+
+ );
}
-export default HomeSection
\ No newline at end of file
+export default HomeSection;
diff --git a/components/themes/default/Navbar.tsx b/components/themes/default/Navbar.tsx
index ee8dd55..0c3afe5 100644
--- a/components/themes/default/Navbar.tsx
+++ b/components/themes/default/Navbar.tsx
@@ -1,131 +1,130 @@
-"use client";
-import { TypographyLarge } from "@/components/common/Typography";
-import {
- Sheet,
- SheetContent,
- SheetTrigger
-} from "@/components/ui/sheet";
-import { Menu } from "lucide-react";
-import Image from "next/image";
-import Link from "next/link";
-import { useEffect, useState } from "react";
+'use client';
+import { TypographyLarge } from '@/components/common/Typography';
+import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
+import { Menu } from 'lucide-react';
+import Image from 'next/image';
+import Link from 'next/link';
+import { useEffect, useState } from 'react';
-function UserPortfolioNavbar({ name, logo, siteid }: {
- name: string,
- logo: string,
- siteid: string
+function UserPortfolioNavbar({
+ name,
+ logo,
+ siteid,
+}: {
+ name: string;
+ logo: string;
+ siteid: string;
}) {
+ useEffect(() => {
+ const track = async () => {
+ try {
+ const res = await fetch('/api/track', {
+ method: 'POST',
+ body: JSON.stringify({
+ namespace: 'sites',
+ event: {
+ path: window.location.pathname,
+ event: {
+ siteId: siteid,
+ width: window.innerWidth,
+ height: window.innerHeight,
+ },
+ },
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ const data = await res.json();
+ console.log(data);
+ } catch (error) {
+ console.log(error);
+ }
+ };
+ track();
+ }, [siteid]);
- useEffect(() => {
-
- const track = async () => {
- try {
- const res = await fetch('/api/track', {
- method: 'POST',
- body: JSON.stringify({
- namespace: "sites",
- event: {
- path: window.location.pathname,
- event: {
- siteId: siteid,
- width: window.innerWidth,
- height: window.innerHeight
- }
- }
- }),
- headers: {
- 'Content-Type': 'application/json'
- }
- })
- const data = await res.json()
- console.log(data)
- } catch (error) {
- console.log(error)
- }
- }
- track()
- }, [siteid])
-
-
-
-
- const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
- const navigation = [
- { name: 'About', href: '#About' },
- { name: 'Skills', href: '#Skills' },
- { name: 'Education', href: '#Education' },
- { name: 'Experience', href: '#Experience' },
- { name: 'Project', href: '#Projects' },
- { name: 'Blog', href: '/blog' },
- { name: 'Contact', href: '#Contact' },
- ]
- return (
-
-
+
+
+
+
+ {name} | Dev Resume
+ {logo && (
+
+ )}
+
+ {name}
+
+
+
+
+ {/* the menu to open side bar in mobile */}
+
+
+
+ setMobileMenuOpen(true)}
+ >
+ Open main menu
+
+
+
+
+
+ {navigation.map((item) => (
+ {
+ setMobileMenuOpen(false);
+ }}
+ >
+
+ {item.name}
+
+
+ ))}
+
+
+
+
+
+ {navigation.map((item) => (
+
-
-
-
- {name} | Dev Resume
- {logo &&
- }
- {name}
-
-
-
- {/* the menu to open side bar in mobile */}
-
-
-
- setMobileMenuOpen(true)}
- >
- Open main menu
-
-
-
-
-
- {navigation.map((item) => (
- {
- setMobileMenuOpen(false)
- }
- }
- >
-
- {item.name}
-
-
- ))}
-
-
-
-
-
- {navigation.map((item) => (
-
- {item.name}
-
-
- ))}
-
-
-
- )
+ {item.name}
+
+ ))}
+
+
+
+ );
}
-export default UserPortfolioNavbar
\ No newline at end of file
+export default UserPortfolioNavbar;
diff --git a/components/themes/default/ProjectSection.tsx b/components/themes/default/ProjectSection.tsx
index 9ea715f..8723d3a 100644
--- a/components/themes/default/ProjectSection.tsx
+++ b/components/themes/default/ProjectSection.tsx
@@ -1,81 +1,72 @@
-import { TypographyH2, TypographyP } from "@/components/common/Typography"
-import { Projects } from "@prisma/client"
-import { GlobeIcon } from "@radix-ui/react-icons"
-import { GithubIcon } from "lucide-react"
-import Link from "next/link"
-
+import { TypographyH2, TypographyP } from '@/components/common/Typography';
+import { Projects } from '@prisma/client';
+import { GlobeIcon } from '@radix-ui/react-icons';
+import { GithubIcon } from 'lucide-react';
+import Link from 'next/link';
function ProjectSection({ projects }: { projects: Projects[] }) {
-
- if (projects.length === 0) return null;
- return (
- <>
-
- Projects
-
-
+
+ Projects
+
+
+ OPEN SOURCE
+
+
+
+ {projects.map((project, index) => (
+
+
+
{project.name}
+
+ {project.oneliner}
+
+
+
Skills Acquired
+
+ {project.skills.map((skill, index) => (
+
+ {skill},
+
+ ))}
+
+
+
+ {project.repourl && (
+
+
+
+ )}
+ {project.url && (
+
- OPEN SOURCE
-
+
+
+ )}
-
-
- {projects.map((project, index) => (
-
-
-
{project.name}
-
- {project.oneliner}
-
-
-
- Skills Acquired
-
-
- {
- project.skills.map((skill, index) => (
-
- {skill},
-
- ))
- }
-
-
-
- {project.repourl &&
-
- }
- {project.url &&
-
- }
-
-
-
-
- {project.description}
-
-
-
-
- ))
- }
-
+
+
+ {project.description}
+
-
-
- >
- )
+
+
+ ))}
+
+
+ >
+ );
}
-export default ProjectSection
\ No newline at end of file
+export default ProjectSection;
diff --git a/components/themes/default/TechStack.tsx b/components/themes/default/TechStack.tsx
index a645464..9fca467 100644
--- a/components/themes/default/TechStack.tsx
+++ b/components/themes/default/TechStack.tsx
@@ -1,62 +1,53 @@
-import prisma from "@/lib/db";
-import Image from "next/image";
-
-
-
-
-async function TechStackSection({
- siteId
-}: {
- siteId: string
-}) {
-
- const techstack = await prisma.siteTechStack.findMany({
- where: {
- siteId: siteId
- },
- select: {
- TechStack: true
- }
- })
-
- if (techstack.length === 0) return null;
-
- return (
-
-
Tech I'm Familiar With
-
-
-
- {
- techstack.map((tech, index) => (
-
-
-
-
{tech.TechStack.name}
-
-
- ))
- }
-
+import prisma from '@/lib/db';
+import Image from 'next/image';
+
+async function TechStackSection({ siteId }: { siteId: string }) {
+ const techstack = await prisma.siteTechStack.findMany({
+ where: {
+ siteId: siteId,
+ },
+ select: {
+ TechStack: true,
+ },
+ });
+
+ if (techstack.length === 0) return null;
+
+ return (
+
+
Tech I'm Familiar With
+
+
+
+ {techstack.map((tech, index) => (
+
+
+
+
+ {tech.TechStack.name}
+
+
-
+ ))}
- )
+
+
+ );
}
-export default TechStackSection
\ No newline at end of file
+export default TechStackSection;
diff --git a/components/ui/3d-card.tsx b/components/ui/3d-card.tsx
index 61f9c6c..1f5047a 100644
--- a/components/ui/3d-card.tsx
+++ b/components/ui/3d-card.tsx
@@ -1,153 +1,154 @@
-"use client";
+'use client';
-import { cn } from "@/lib/utils";
+import { cn } from '@/lib/utils';
import React, {
- createContext,
- useContext,
- useEffect,
- useRef,
- useState,
-} from "react";
+ createContext,
+ useContext,
+ useEffect,
+ useRef,
+ useState,
+} from 'react';
const MouseEnterContext = createContext<
- [boolean, React.Dispatch
>] | undefined
+ [boolean, React.Dispatch>] | undefined
>(undefined);
export const CardContainer = ({
- children,
- className,
- containerClassName,
+ children,
+ className,
+ containerClassName,
}: {
- children?: React.ReactNode;
- className?: string;
- containerClassName?: string;
+ children?: React.ReactNode;
+ className?: string;
+ containerClassName?: string;
}) => {
- const containerRef = useRef(null);
- const [isMouseEntered, setIsMouseEntered] = useState(false);
+ const containerRef = useRef(null);
+ const [isMouseEntered, setIsMouseEntered] = useState(false);
- const handleMouseMove = (e: React.MouseEvent) => {
- if (!containerRef.current) return;
- const { left, top, width, height } =
- containerRef.current.getBoundingClientRect();
- const x = (e.clientX - left - width / 2) / 25;
- const y = (e.clientY - top - height / 2) / 25;
- containerRef.current.style.transform = `rotateY(${x}deg) rotateX(${y}deg)`;
- };
+ const handleMouseMove = (e: React.MouseEvent) => {
+ if (!containerRef.current) return;
+ const { left, top, width, height } =
+ containerRef.current.getBoundingClientRect();
+ const x = (e.clientX - left - width / 2) / 25;
+ const y = (e.clientY - top - height / 2) / 25;
+ containerRef.current.style.transform = `rotateY(${x}deg) rotateX(${y}deg)`;
+ };
- const handleMouseEnter = (e: React.MouseEvent) => {
- setIsMouseEntered(true);
- if (!containerRef.current) return;
- };
+ const handleMouseEnter = (e: React.MouseEvent) => {
+ setIsMouseEntered(true);
+ if (!containerRef.current) return;
+ };
- const handleMouseLeave = (e: React.MouseEvent) => {
- if (!containerRef.current) return;
- setIsMouseEntered(false);
- containerRef.current.style.transform = `rotateY(0deg) rotateX(0deg)`;
- };
- return (
-
-
-
- );
+ const handleMouseLeave = (e: React.MouseEvent) => {
+ if (!containerRef.current) return;
+ setIsMouseEntered(false);
+ containerRef.current.style.transform = 'rotateY(0deg) rotateX(0deg)';
+ };
+ return (
+
+
+
+ );
};
export const CardBody = ({
- children,
- className,
+ children,
+ className,
}: {
- children: React.ReactNode;
- className?: string;
+ children: React.ReactNode;
+ className?: string;
}) => {
- return (
- *]:[transform-style:preserve-3d]",
- className
- )}
- >
- {children}
-
- );
+ return (
+ *]:[transform-style:preserve-3d]',
+ className
+ )}
+ >
+ {children}
+
+ );
};
export const CardItem = ({
- as: Tag = "div",
- children,
- className,
- translateX = 0,
- translateY = 0,
- translateZ = 0,
- rotateX = 0,
- rotateY = 0,
- rotateZ = 0,
- ...rest
+ as: Tag = 'div',
+ children,
+ className,
+ translateX = 0,
+ translateY = 0,
+ translateZ = 0,
+ rotateX = 0,
+ rotateY = 0,
+ rotateZ = 0,
+ ...rest
}: {
- as?: React.ElementType;
- children: React.ReactNode;
- className?: string;
- translateX?: number | string;
- translateY?: number | string;
- translateZ?: number | string;
- rotateX?: number | string;
- rotateY?: number | string;
- rotateZ?: number | string;
+ as?: React.ElementType;
+ children: React.ReactNode;
+ className?: string;
+ translateX?: number | string;
+ translateY?: number | string;
+ translateZ?: number | string;
+ rotateX?: number | string;
+ rotateY?: number | string;
+ rotateZ?: number | string;
}) => {
- const ref = useRef(null);
- const [isMouseEntered] = useMouseEnter();
+ const ref = useRef(null);
+ const [isMouseEntered] = useMouseEnter();
- useEffect(() => {
- handleAnimations();
- }, [isMouseEntered]);
+ useEffect(() => {
+ handleAnimations();
+ }, [isMouseEntered]);
- const handleAnimations = () => {
- if (!ref.current) return;
- if (isMouseEntered) {
- ref.current.style.transform = `translateX(${translateX}px) translateY(${translateY}px) translateZ(${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotateZ(${rotateZ}deg)`;
- } else {
- ref.current.style.transform = `translateX(0px) translateY(0px) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg)`;
- }
- };
+ const handleAnimations = () => {
+ if (!ref.current) return;
+ if (isMouseEntered) {
+ ref.current.style.transform = `translateX(${translateX}px) translateY(${translateY}px) translateZ(${translateZ}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) rotateZ(${rotateZ}deg)`;
+ } else {
+ ref.current.style.transform =
+ 'translateX(0px) translateY(0px) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg)';
+ }
+ };
- return (
-
- {children}
-
- );
+ return (
+
+ {children}
+
+ );
};
// Create a hook to use the context
export const useMouseEnter = () => {
- const context = useContext(MouseEnterContext);
- if (context === undefined) {
- throw new Error("useMouseEnter must be used within a MouseEnterProvider");
- }
- return context;
+ const context = useContext(MouseEnterContext);
+ if (context === undefined) {
+ throw new Error('useMouseEnter must be used within a MouseEnterProvider');
+ }
+ return context;
};
diff --git a/components/ui/Spotlight.tsx b/components/ui/Spotlight.tsx
index 17c66d8..32a22de 100644
--- a/components/ui/Spotlight.tsx
+++ b/components/ui/Spotlight.tsx
@@ -1,55 +1,55 @@
-import { cn } from "@/lib/utils";
+import { cn } from '@/lib/utils';
type SpotlightProps = {
- className?: string;
- fill?: string;
+ className?: string;
+ fill?: string;
};
export const Spotlight = ({ className, fill }: SpotlightProps) => {
- return (
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
- );
+
+
+
+
+
+
+ );
};
diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx
index 000ca56..1db8c30 100644
--- a/components/ui/alert-dialog.tsx
+++ b/components/ui/alert-dialog.tsx
@@ -1,16 +1,16 @@
-"use client"
+'use client';
-import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
-import * as React from "react"
+import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
+import * as React from 'react';
-import { buttonVariants } from "@/components/ui/button"
-import { cn } from "@/lib/utils"
+import { buttonVariants } from '@/components/ui/button';
+import { cn } from '@/lib/utils';
-const AlertDialog = AlertDialogPrimitive.Root
+const AlertDialog = AlertDialogPrimitive.Root;
-const AlertDialogTrigger = AlertDialogPrimitive.Trigger
+const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
-const AlertDialogPortal = AlertDialogPrimitive.Portal
+const AlertDialogPortal = AlertDialogPrimitive.Portal;
const AlertDialogOverlay = React.forwardRef<
React.ElementRef,
@@ -18,14 +18,14 @@ const AlertDialogOverlay = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
+));
+AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
const AlertDialogContent = React.forwardRef<
React.ElementRef,
@@ -36,14 +36,14 @@ const AlertDialogContent = React.forwardRef<
-))
-AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
+));
+AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
const AlertDialogHeader = ({
className,
@@ -51,13 +51,13 @@ const AlertDialogHeader = ({
}: React.HTMLAttributes) => (
-)
-AlertDialogHeader.displayName = "AlertDialogHeader"
+);
+AlertDialogHeader.displayName = 'AlertDialogHeader';
const AlertDialogFooter = ({
className,
@@ -65,13 +65,13 @@ const AlertDialogFooter = ({
}: React.HTMLAttributes) => (
-)
-AlertDialogFooter.displayName = "AlertDialogFooter"
+);
+AlertDialogFooter.displayName = 'AlertDialogFooter';
const AlertDialogTitle = React.forwardRef<
React.ElementRef,
@@ -79,11 +79,11 @@ const AlertDialogTitle = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
+));
+AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
const AlertDialogDescription = React.forwardRef<
React.ElementRef,
@@ -91,12 +91,12 @@ const AlertDialogDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
+));
AlertDialogDescription.displayName =
- AlertDialogPrimitive.Description.displayName
+ AlertDialogPrimitive.Description.displayName;
const AlertDialogAction = React.forwardRef<
React.ElementRef,
@@ -104,11 +104,15 @@ const AlertDialogAction = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
+));
+AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
const AlertDialogCancel = React.forwardRef<
React.ElementRef,
@@ -117,17 +121,25 @@ const AlertDialogCancel = React.forwardRef<
-))
-AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
+));
+AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
export {
- AlertDialog, AlertDialogAction,
- AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger
-}
-
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogOverlay,
+ AlertDialogPortal,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+};
diff --git a/components/ui/alert.tsx b/components/ui/alert.tsx
index 41fa7e0..d2b59cc 100644
--- a/components/ui/alert.tsx
+++ b/components/ui/alert.tsx
@@ -1,23 +1,23 @@
-import * as React from "react"
-import { cva, type VariantProps } from "class-variance-authority"
+import * as React from 'react';
+import { cva, type VariantProps } from 'class-variance-authority';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
const alertVariants = cva(
- "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",
+ 'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground',
{
variants: {
variant: {
- default: "bg-background text-foreground",
+ default: 'bg-background text-foreground',
destructive:
- "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
+ 'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
},
},
defaultVariants: {
- variant: "default",
+ variant: 'default',
},
}
-)
+);
const Alert = React.forwardRef<
HTMLDivElement,
@@ -29,8 +29,8 @@ const Alert = React.forwardRef<
className={cn(alertVariants({ variant }), className)}
{...props}
/>
-))
-Alert.displayName = "Alert"
+));
+Alert.displayName = 'Alert';
const AlertTitle = React.forwardRef<
HTMLParagraphElement,
@@ -38,11 +38,11 @@ const AlertTitle = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-AlertTitle.displayName = "AlertTitle"
+));
+AlertTitle.displayName = 'AlertTitle';
const AlertDescription = React.forwardRef<
HTMLParagraphElement,
@@ -50,10 +50,10 @@ const AlertDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-AlertDescription.displayName = "AlertDescription"
+));
+AlertDescription.displayName = 'AlertDescription';
-export { Alert, AlertTitle, AlertDescription }
+export { Alert, AlertTitle, AlertDescription };
diff --git a/components/ui/animated-tooltip.tsx b/components/ui/animated-tooltip.tsx
index e43efb8..b65ac4e 100644
--- a/components/ui/animated-tooltip.tsx
+++ b/components/ui/animated-tooltip.tsx
@@ -1,92 +1,92 @@
-"use client";
+'use client';
import {
- AnimatePresence,
- motion,
- useMotionValue,
- useSpring,
- useTransform,
-} from "framer-motion";
-import Image from "next/image";
-import { useState } from "react";
+ AnimatePresence,
+ motion,
+ useMotionValue,
+ useSpring,
+ useTransform,
+} from 'framer-motion';
+import Image from 'next/image';
+import { useState } from 'react';
export const AnimatedTooltip = ({
- items,
+ items,
}: {
- items: {
- id: number;
- name: string;
- designation: string;
- image: string;
- }[];
+ items: {
+ id: number;
+ name: string;
+ designation: string;
+ image: string;
+ }[];
}) => {
- const [hoveredIndex, setHoveredIndex] = useState(null);
- const springConfig = { stiffness: 100, damping: 5 };
- const x = useMotionValue(0); // going to set this value on mouse move
- // rotate the tooltip
- const rotate = useSpring(
- useTransform(x, [-100, 100], [-45, 45]),
- springConfig
- );
- // translate the tooltip
- const translateX = useSpring(
- useTransform(x, [-100, 100], [-50, 50]),
- springConfig
- );
- const handleMouseMove = (event: any) => {
- const halfWidth = event.target.offsetWidth / 2;
- x.set(event.nativeEvent.offsetX - halfWidth); // set the x value, which is then used in transform and rotate
- };
+ const [hoveredIndex, setHoveredIndex] = useState(null);
+ const springConfig = { stiffness: 100, damping: 5 };
+ const x = useMotionValue(0); // going to set this value on mouse move
+ // rotate the tooltip
+ const rotate = useSpring(
+ useTransform(x, [-100, 100], [-45, 45]),
+ springConfig
+ );
+ // translate the tooltip
+ const translateX = useSpring(
+ useTransform(x, [-100, 100], [-50, 50]),
+ springConfig
+ );
+ const handleMouseMove = (event: any) => {
+ const halfWidth = event.target.offsetWidth / 2;
+ x.set(event.nativeEvent.offsetX - halfWidth); // set the x value, which is then used in transform and rotate
+ };
- return (
- <>
- {items.map((item, idx) => (
- setHoveredIndex(item.id)}
- onMouseLeave={() => setHoveredIndex(null)}
- >
-
- {hoveredIndex === item.id && (
-
-
-
-
- {item.name}
-
- {item.designation}
-
- )}
-
-
+ return (
+ <>
+ {items.map((item, idx) => (
+
setHoveredIndex(item.id)}
+ onMouseLeave={() => setHoveredIndex(null)}
+ >
+
+ {hoveredIndex === item.id && (
+
+
+
+
+ {item.name}
- ))}
- >
- );
+ {item.designation}
+
+ )}
+
+
+
+ ))}
+ >
+ );
};
diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx
index 51e507b..1346957 100644
--- a/components/ui/avatar.tsx
+++ b/components/ui/avatar.tsx
@@ -1,9 +1,9 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as AvatarPrimitive from "@radix-ui/react-avatar"
+import * as React from 'react';
+import * as AvatarPrimitive from '@radix-ui/react-avatar';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
const Avatar = React.forwardRef<
React.ElementRef
,
@@ -12,13 +12,13 @@ const Avatar = React.forwardRef<
-))
-Avatar.displayName = AvatarPrimitive.Root.displayName
+));
+Avatar.displayName = AvatarPrimitive.Root.displayName;
const AvatarImage = React.forwardRef<
React.ElementRef,
@@ -26,11 +26,11 @@ const AvatarImage = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-AvatarImage.displayName = AvatarPrimitive.Image.displayName
+));
+AvatarImage.displayName = AvatarPrimitive.Image.displayName;
const AvatarFallback = React.forwardRef<
React.ElementRef,
@@ -39,12 +39,12 @@ const AvatarFallback = React.forwardRef<
-))
-AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
+));
+AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
-export { Avatar, AvatarImage, AvatarFallback }
+export { Avatar, AvatarImage, AvatarFallback };
diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx
index f000e3e..2eb790a 100644
--- a/components/ui/badge.tsx
+++ b/components/ui/badge.tsx
@@ -1,27 +1,27 @@
-import * as React from "react"
-import { cva, type VariantProps } from "class-variance-authority"
+import * as React from 'react';
+import { cva, type VariantProps } from 'class-variance-authority';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
const badgeVariants = cva(
- "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
+ 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
{
variants: {
variant: {
default:
- "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
+ 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
secondary:
- "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
destructive:
- "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
- outline: "text-foreground",
+ 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
+ outline: 'text-foreground',
},
},
defaultVariants: {
- variant: "default",
+ variant: 'default',
},
}
-)
+);
export interface BadgeProps
extends React.HTMLAttributes,
@@ -30,7 +30,7 @@ export interface BadgeProps
function Badge({ className, variant, ...props }: BadgeProps) {
return (
- )
+ );
}
-export { Badge, badgeVariants }
+export { Badge, badgeVariants };
diff --git a/components/ui/button.tsx b/components/ui/button.tsx
index 87668dc..ffad8b5 100644
--- a/components/ui/button.tsx
+++ b/components/ui/button.tsx
@@ -1,58 +1,58 @@
-import { Slot } from "@radix-ui/react-slot"
-import { cva, type VariantProps } from "class-variance-authority"
-import * as React from "react"
+import { Slot } from '@radix-ui/react-slot';
+import { cva, type VariantProps } from 'class-variance-authority';
+import * as React from 'react';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
const buttonVariants = cva(
- "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium 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',
{
variants: {
variant: {
- default: "!bg-primary text-primary-foreground hover:bg-primary/80",
+ default: '!bg-primary text-primary-foreground hover:bg-primary/80',
destructive:
- "bg-destructive text-destructive-foreground hover:bg-destructive/90",
+ 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline:
- "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
+ 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
bordered:
- "border border-primary bg-background hover:bg-accent hover:text-accent-foreground",
+ 'border border-primary bg-background hover:bg-accent hover:text-accent-foreground',
secondary:
- "bg-secondary text-secondary-foreground hover:bg-secondary/80",
- ghost: "hover:bg-accent hover:text-accent-foreground",
- link: "text-primary underline-offset-4 hover:underline",
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
+ ghost: 'hover:bg-accent hover:text-accent-foreground',
+ link: 'text-primary underline-offset-4 hover:underline',
},
size: {
- default: "h-10 px-4 py-2",
- sm: "h-9 rounded-md px-3",
- lg: "h-11 rounded-md px-8",
- icon: "h-10 w-10",
+ default: 'h-10 px-4 py-2',
+ sm: 'h-9 rounded-md px-3',
+ lg: 'h-11 rounded-md px-8',
+ icon: 'h-10 w-10',
},
},
defaultVariants: {
- variant: "default",
- size: "default",
+ variant: 'default',
+ size: 'default',
},
}
-)
+);
export interface ButtonProps
extends React.ButtonHTMLAttributes,
- VariantProps {
- asChild?: boolean
+ VariantProps {
+ asChild?: boolean;
}
const Button = React.forwardRef(
({ className, variant, size, asChild = false, ...props }, ref) => {
- const Comp = asChild ? Slot : "button"
+ const Comp = asChild ? Slot : 'button';
return (
- )
+ );
}
-)
-Button.displayName = "Button"
+);
+Button.displayName = 'Button';
-export { Button, buttonVariants }
+export { Button, buttonVariants };
diff --git a/components/ui/calendar.tsx b/components/ui/calendar.tsx
index 2f02434..7ee4f82 100644
--- a/components/ui/calendar.tsx
+++ b/components/ui/calendar.tsx
@@ -1,13 +1,13 @@
-"use client"
+'use client';
-import * as React from "react"
-import { ChevronLeft, ChevronRight } from "lucide-react"
-import { DayPicker } from "react-day-picker"
+import * as React from 'react';
+import { ChevronLeft, ChevronRight } from 'lucide-react';
+import { DayPicker } from 'react-day-picker';
-import { cn } from "@/lib/utils"
-import { buttonVariants } from "@/components/ui/button"
+import { cn } from '@/lib/utils';
+import { buttonVariants } from '@/components/ui/button';
-export type CalendarProps = React.ComponentProps
+export type CalendarProps = React.ComponentProps;
function Calendar({
className,
@@ -18,39 +18,39 @@ function Calendar({
return (
- )
+ );
}
-Calendar.displayName = "Calendar"
+Calendar.displayName = 'Calendar';
-export { Calendar }
+export { Calendar };
diff --git a/components/ui/card.tsx b/components/ui/card.tsx
index afa13ec..fca7be4 100644
--- a/components/ui/card.tsx
+++ b/components/ui/card.tsx
@@ -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<
HTMLDivElement,
@@ -9,13 +9,13 @@ const Card = React.forwardRef<
-))
-Card.displayName = "Card"
+));
+Card.displayName = 'Card';
const CardHeader = React.forwardRef<
HTMLDivElement,
@@ -23,11 +23,11 @@ const CardHeader = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-CardHeader.displayName = "CardHeader"
+));
+CardHeader.displayName = 'CardHeader';
const CardTitle = React.forwardRef<
HTMLParagraphElement,
@@ -36,13 +36,13 @@ const CardTitle = React.forwardRef<
-))
-CardTitle.displayName = "CardTitle"
+));
+CardTitle.displayName = 'CardTitle';
const CardDescription = React.forwardRef<
HTMLParagraphElement,
@@ -50,19 +50,19 @@ const CardDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-CardDescription.displayName = "CardDescription"
+));
+CardDescription.displayName = 'CardDescription';
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes
>(({ className, ...props }, ref) => (
-
-))
-CardContent.displayName = "CardContent"
+
+));
+CardContent.displayName = 'CardContent';
const CardFooter = React.forwardRef<
HTMLDivElement,
@@ -70,10 +70,17 @@ const CardFooter = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-CardFooter.displayName = "CardFooter"
+));
+CardFooter.displayName = 'CardFooter';
-export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardDescription,
+ CardContent,
+};
diff --git a/components/ui/command.tsx b/components/ui/command.tsx
index 17cc641..15e2dc2 100644
--- a/components/ui/command.tsx
+++ b/components/ui/command.tsx
@@ -1,12 +1,12 @@
-"use client"
+'use client';
-import * as React from "react"
-import { type DialogProps } from "@radix-ui/react-dialog"
-import { Command as CommandPrimitive } from "cmdk"
-import { Search } from "lucide-react"
+import * as React from 'react';
+import { type DialogProps } from '@radix-ui/react-dialog';
+import { Command as CommandPrimitive } from 'cmdk';
+import { Search } from 'lucide-react';
-import { cn } from "@/lib/utils"
-import { Dialog, DialogContent } from "@/components/ui/dialog"
+import { cn } from '@/lib/utils';
+import { Dialog, DialogContent } from '@/components/ui/dialog';
const Command = React.forwardRef<
React.ElementRef,
@@ -15,13 +15,13 @@ const Command = React.forwardRef<
-))
-Command.displayName = CommandPrimitive.displayName
+));
+Command.displayName = CommandPrimitive.displayName;
interface CommandDialogProps extends DialogProps {}
@@ -34,8 +34,8 @@ const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
- )
-}
+ );
+};
const CommandInput = React.forwardRef<
React.ElementRef,
@@ -46,15 +46,15 @@ const CommandInput = React.forwardRef<
-))
+));
-CommandInput.displayName = CommandPrimitive.Input.displayName
+CommandInput.displayName = CommandPrimitive.Input.displayName;
const CommandList = React.forwardRef<
React.ElementRef,
@@ -62,12 +62,12 @@ const CommandList = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
+));
-CommandList.displayName = CommandPrimitive.List.displayName
+CommandList.displayName = CommandPrimitive.List.displayName;
const CommandEmpty = React.forwardRef<
React.ElementRef,
@@ -78,9 +78,9 @@ const CommandEmpty = React.forwardRef<
className="py-6 text-center text-sm"
{...props}
/>
-))
+));
-CommandEmpty.displayName = CommandPrimitive.Empty.displayName
+CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
const CommandGroup = React.forwardRef<
React.ElementRef,
@@ -89,14 +89,14 @@ const CommandGroup = React.forwardRef<
-))
+));
-CommandGroup.displayName = CommandPrimitive.Group.displayName
+CommandGroup.displayName = CommandPrimitive.Group.displayName;
const CommandSeparator = React.forwardRef<
React.ElementRef,
@@ -104,11 +104,11 @@ const CommandSeparator = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-CommandSeparator.displayName = CommandPrimitive.Separator.displayName
+));
+CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
const CommandItem = React.forwardRef<
React.ElementRef,
@@ -117,14 +117,14 @@ const CommandItem = React.forwardRef<
-))
+));
-CommandItem.displayName = CommandPrimitive.Item.displayName
+CommandItem.displayName = CommandPrimitive.Item.displayName;
const CommandShortcut = ({
className,
@@ -133,14 +133,14 @@ const CommandShortcut = ({
return (
- )
-}
-CommandShortcut.displayName = "CommandShortcut"
+ );
+};
+CommandShortcut.displayName = 'CommandShortcut';
export {
Command,
@@ -152,4 +152,4 @@ export {
CommandItem,
CommandShortcut,
CommandSeparator,
-}
+};
diff --git a/components/ui/container-scroll-animation.tsx b/components/ui/container-scroll-animation.tsx
index c2da7da..93de96c 100644
--- a/components/ui/container-scroll-animation.tsx
+++ b/components/ui/container-scroll-animation.tsx
@@ -1,136 +1,135 @@
-"use client";
-import { motion, useScroll, useTransform } from "framer-motion";
-import Image from "next/image";
-import React, { useRef } from "react";
-
+'use client';
+import { motion, useScroll, useTransform } from 'framer-motion';
+import Image from 'next/image';
+import React, { useRef } from 'react';
export const ContainerScroll = ({
- users,
- titleComponent,
+ users,
+ titleComponent,
}: {
- users: {
- name: string;
- designation: string;
- image: string;
- badge?: string;
- }[];
- titleComponent: string | React.ReactNode;
+ users: {
+ name: string;
+ designation: string;
+ image: string;
+ badge?: string;
+ }[];
+ titleComponent: string | React.ReactNode;
}) => {
- const containerRef = useRef(null);
- const { scrollYProgress } = useScroll({
- target: containerRef,
- });
- const [isMobile, setIsMobile] = React.useState(false);
-
- React.useEffect(() => {
- const checkMobile = () => {
- setIsMobile(window.innerWidth <= 768);
- };
- checkMobile();
- window.addEventListener("resize", checkMobile);
- return () => {
- window.removeEventListener("resize", checkMobile);
- };
- }, []);
+ const containerRef = useRef(null);
+ const { scrollYProgress } = useScroll({
+ target: containerRef,
+ });
+ const [isMobile, setIsMobile] = React.useState(false);
- const scaleDimensions = () => {
- return isMobile ? [0.7, 0.9] : [1.05, 1];
+ React.useEffect(() => {
+ const checkMobile = () => {
+ setIsMobile(window.innerWidth <= 768);
};
+ checkMobile();
+ window.addEventListener('resize', checkMobile);
+ return () => {
+ window.removeEventListener('resize', checkMobile);
+ };
+ }, []);
- const rotate = useTransform(scrollYProgress, [0, 1], [20, 0]);
- const scale = useTransform(scrollYProgress, [0, 1], scaleDimensions());
- const translate = useTransform(scrollYProgress, [0, 1], [0, -100]);
+ const scaleDimensions = () => {
+ return isMobile ? [0.7, 0.9] : [1.05, 1];
+ };
- return (
-
- );
+ const rotate = useTransform(scrollYProgress, [0, 1], [20, 0]);
+ const scale = useTransform(scrollYProgress, [0, 1], scaleDimensions());
+ const translate = useTransform(scrollYProgress, [0, 1], [0, -100]);
+
+ return (
+
+ );
};
export const Header = ({ translate, titleComponent }: any) => {
- return (
-
- {titleComponent}
-
- );
+ return (
+
+ {titleComponent}
+
+ );
};
export const Card = ({
- rotate,
- scale,
- translate,
- users,
+ rotate,
+ scale,
+ translate,
+ users,
}: {
- rotate: any;
- scale: any;
- translate: any;
- users: {
- name: string;
- designation: string;
- image: string;
- badge?: string;
- }[];
+ rotate: any;
+ scale: any;
+ translate: any;
+ users: {
+ name: string;
+ designation: string;
+ image: string;
+ badge?: string;
+ }[];
}) => {
- return (
-
+
+ {users.map((user, idx: number) => (
+
-
- {users.map((user, idx: number) => (
-
-
- {user.badge}
-
-
-
-
{user.name}
- {user.designation}
-
-
- ))}
+ >
+
+ {user.badge}
+
+
+
+
{user.name}
+ {user.designation}
-
- );
+
+ ))}
+
+
+ );
};
diff --git a/components/ui/dialog.tsx b/components/ui/dialog.tsx
index cad6f58..40ca7c1 100644
--- a/components/ui/dialog.tsx
+++ b/components/ui/dialog.tsx
@@ -1,18 +1,18 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as DialogPrimitive from "@radix-ui/react-dialog"
-import { X } from "lucide-react"
+import * as React from 'react';
+import * as DialogPrimitive from '@radix-ui/react-dialog';
+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<
React.ElementRef
,
@@ -21,13 +21,13 @@ const DialogOverlay = React.forwardRef<
-))
-DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
+));
+DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = React.forwardRef<
React.ElementRef,
@@ -38,7 +38,7 @@ const DialogContent = React.forwardRef<
-))
-DialogContent.displayName = DialogPrimitive.Content.displayName
+));
+DialogContent.displayName = DialogPrimitive.Content.displayName;
const DialogHeader = ({
className,
@@ -59,13 +59,13 @@ const DialogHeader = ({
}: React.HTMLAttributes) => (
-)
-DialogHeader.displayName = "DialogHeader"
+);
+DialogHeader.displayName = 'DialogHeader';
const DialogFooter = ({
className,
@@ -73,13 +73,13 @@ const DialogFooter = ({
}: React.HTMLAttributes) => (
-)
-DialogFooter.displayName = "DialogFooter"
+);
+DialogFooter.displayName = 'DialogFooter';
const DialogTitle = React.forwardRef<
React.ElementRef,
@@ -88,13 +88,13 @@ const DialogTitle = React.forwardRef<
-))
-DialogTitle.displayName = DialogPrimitive.Title.displayName
+));
+DialogTitle.displayName = DialogPrimitive.Title.displayName;
const DialogDescription = React.forwardRef<
React.ElementRef,
@@ -102,11 +102,11 @@ const DialogDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-DialogDescription.displayName = DialogPrimitive.Description.displayName
+));
+DialogDescription.displayName = DialogPrimitive.Description.displayName;
export {
Dialog,
@@ -119,4 +119,4 @@ export {
DialogFooter,
DialogTitle,
DialogDescription,
-}
+};
diff --git a/components/ui/dropdown-menu.tsx b/components/ui/dropdown-menu.tsx
index f69a0d6..283467c 100644
--- a/components/ui/dropdown-menu.tsx
+++ b/components/ui/dropdown-menu.tsx
@@ -1,34 +1,34 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
-import { Check, ChevronRight, Circle } from "lucide-react"
+import * as React from 'react';
+import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
+import { Check, ChevronRight, Circle } from 'lucide-react';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
-const DropdownMenu = DropdownMenuPrimitive.Root
+const DropdownMenu = DropdownMenuPrimitive.Root;
-const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
+const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
-const DropdownMenuGroup = DropdownMenuPrimitive.Group
+const DropdownMenuGroup = DropdownMenuPrimitive.Group;
-const DropdownMenuPortal = DropdownMenuPrimitive.Portal
+const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
-const DropdownMenuSub = DropdownMenuPrimitive.Sub
+const DropdownMenuSub = DropdownMenuPrimitive.Sub;
-const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
+const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
-))
+));
DropdownMenuSubTrigger.displayName =
- DropdownMenuPrimitive.SubTrigger.displayName
+ DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = React.forwardRef<
React.ElementRef,
@@ -47,14 +47,14 @@ const DropdownMenuSubContent = React.forwardRef<
-))
+));
DropdownMenuSubContent.displayName =
- DropdownMenuPrimitive.SubContent.displayName
+ DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = React.forwardRef<
React.ElementRef,
@@ -65,32 +65,32 @@ const DropdownMenuContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
- "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className
)}
{...props}
/>
-))
-DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
+));
+DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
-))
-DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
+));
+DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef,
@@ -99,7 +99,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
{children}
-))
+));
DropdownMenuCheckboxItem.displayName =
- DropdownMenuPrimitive.CheckboxItem.displayName
+ DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef,
@@ -123,7 +123,7 @@ const DropdownMenuRadioItem = React.forwardRef<
{children}
-))
-DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
+));
+DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
const DropdownMenuLabel = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
-))
-DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
+));
+DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
const DropdownMenuSeparator = React.forwardRef<
React.ElementRef,
@@ -162,11 +162,11 @@ const DropdownMenuSeparator = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
+));
+DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({
className,
@@ -174,12 +174,12 @@ const DropdownMenuShortcut = ({
}: React.HTMLAttributes) => {
return (
- )
-}
-DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
+ );
+};
+DropdownMenuShortcut.displayName = 'DropdownMenuShortcut';
export {
DropdownMenu,
@@ -197,4 +197,4 @@ export {
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
-}
+};
diff --git a/components/ui/form.tsx b/components/ui/form.tsx
index 4603f8b..b948a8f 100644
--- a/components/ui/form.tsx
+++ b/components/ui/form.tsx
@@ -1,6 +1,6 @@
-import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
-import { Slot } from "@radix-ui/react-slot"
+import * as React from 'react';
+import * as LabelPrimitive from '@radix-ui/react-label';
+import { Slot } from '@radix-ui/react-slot';
import {
Controller,
ControllerProps,
@@ -8,27 +8,27 @@ import {
FieldValues,
FormProvider,
useFormContext,
-} from "react-hook-form"
+} from 'react-hook-form';
-import { cn } from "@/lib/utils"
-import { Label } from "@/components/ui/label"
+import { cn } from '@/lib/utils';
+import { Label } from '@/components/ui/label';
-const Form = FormProvider
+const Form = FormProvider;
type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
- TName extends FieldPath = FieldPath
+ TName extends FieldPath = FieldPath,
> = {
- name: TName
-}
+ name: TName;
+};
const FormFieldContext = React.createContext(
{} as FormFieldContextValue
-)
+);
const FormField = <
TFieldValues extends FieldValues = FieldValues,
- TName extends FieldPath = FieldPath
+ TName extends FieldPath = FieldPath,
>({
...props
}: ControllerProps) => {
@@ -36,21 +36,21 @@ const FormField = <
- )
-}
+ );
+};
const useFormField = () => {
- const fieldContext = React.useContext(FormFieldContext)
- const itemContext = React.useContext(FormItemContext)
- const { getFieldState, formState } = useFormContext()
+ const fieldContext = React.useContext(FormFieldContext);
+ const itemContext = React.useContext(FormItemContext);
+ const { getFieldState, formState } = useFormContext();
- const fieldState = getFieldState(fieldContext.name, formState)
+ const fieldState = getFieldState(fieldContext.name, formState);
if (!fieldContext) {
- throw new Error("useFormField should be used within ")
+ throw new Error('useFormField should be used within ');
}
- const { id } = itemContext
+ const { id } = itemContext;
return {
id,
@@ -59,53 +59,54 @@ const useFormField = () => {
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
- }
-}
+ };
+};
type FormItemContextValue = {
- id: string
-}
+ id: string;
+};
const FormItemContext = React.createContext(
{} as FormItemContextValue
-)
+);
const FormItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes
>(({ className, ...props }, ref) => {
- const id = React.useId()
+ const id = React.useId();
return (
-
+
- )
-})
-FormItem.displayName = "FormItem"
+ );
+});
+FormItem.displayName = 'FormItem';
const FormLabel = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
>(({ className, ...props }, ref) => {
- const { error, formItemId } = useFormField()
+ const { error, formItemId } = useFormField();
return (
- )
-})
-FormLabel.displayName = "FormLabel"
+ );
+});
+FormLabel.displayName = 'FormLabel';
const FormControl = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
>(({ ...props }, ref) => {
- const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
+ const { error, formItemId, formDescriptionId, formMessageId } =
+ useFormField();
return (
- )
-})
-FormControl.displayName = "FormControl"
+ );
+});
+FormControl.displayName = 'FormControl';
const FormDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes
>(({ className, ...props }, ref) => {
- const { formDescriptionId } = useFormField()
+ const { formDescriptionId } = useFormField();
return (
- )
-})
-FormDescription.displayName = "FormDescription"
+ );
+});
+FormDescription.displayName = 'FormDescription';
const FormMessage = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes
>(({ className, children, ...props }, ref) => {
- const { error, formMessageId } = useFormField()
- const body = error ? String(error?.message) : children
+ const { error, formMessageId } = useFormField();
+ const body = error ? String(error?.message) : children;
if (!body) {
- return null
+ return null;
}
return (
{body}
- )
-})
-FormMessage.displayName = "FormMessage"
+ );
+});
+FormMessage.displayName = 'FormMessage';
export {
useFormField,
@@ -173,4 +174,4 @@ export {
FormDescription,
FormMessage,
FormField,
-}
+};
diff --git a/components/ui/google-gemini-effect.tsx b/components/ui/google-gemini-effect.tsx
index b9eed10..eac41d0 100644
--- a/components/ui/google-gemini-effect.tsx
+++ b/components/ui/google-gemini-effect.tsx
@@ -1,158 +1,158 @@
-"use client";
-import { cn } from "@/lib/utils";
-import { motion, MotionValue } from "framer-motion";
+'use client';
+import { cn } from '@/lib/utils';
+import { motion, MotionValue } from 'framer-motion';
const transition = {
- duration: 0,
- ease: "linear",
+ duration: 0,
+ ease: 'linear',
};
export const GoogleGeminiEffect = ({
- pathLengths,
- title,
- description,
- className,
+ pathLengths,
+ title,
+ description,
+ className,
}: {
- pathLengths: MotionValue[];
- title?: string;
- description?: string;
- className?: string;
+ pathLengths: MotionValue[];
+ title?: string;
+ description?: string;
+ className?: string;
}) => {
- return (
-
-
- {title}
-
-
- {description}
-
-
-
- app.dresume.me
-
-
-
-
-
-
-
-
+ return (
+
+
+ {title}
+
+
+ {description}
+
+
+
+ app.dresume.me
+
+
+
+
+
+
+
+
- {/* Gaussian blur for the background paths */}
+ {/* Gaussian blur for the background paths */}
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
- );
+
+
+
+
+
+
+
+ );
};
diff --git a/components/ui/infinite-moving-cards.tsx b/components/ui/infinite-moving-cards.tsx
index 48cfdf7..30cb0a2 100644
--- a/components/ui/infinite-moving-cards.tsx
+++ b/components/ui/infinite-moving-cards.tsx
@@ -1,121 +1,121 @@
-"use client";
+'use client';
-import { cn } from "@/lib/utils";
-import React, { useEffect, useState } from "react";
+import { cn } from '@/lib/utils';
+import React, { useEffect, useState } from 'react';
export const InfiniteMovingCards = ({
- items,
- direction = "left",
- speed = "fast",
- pauseOnHover = true,
- className,
+ items,
+ direction = 'left',
+ speed = 'fast',
+ pauseOnHover = true,
+ className,
}: {
- items: {
- quote: string;
- name: string;
- title: string;
- }[];
- direction?: "left" | "right";
- speed?: "fast" | "normal" | "slow";
- pauseOnHover?: boolean;
- className?: string;
+ items: {
+ quote: string;
+ name: string;
+ title: string;
+ }[];
+ direction?: 'left' | 'right';
+ speed?: 'fast' | 'normal' | 'slow';
+ pauseOnHover?: boolean;
+ className?: string;
}) => {
- const containerRef = React.useRef(null);
- const scrollerRef = React.useRef(null);
+ const containerRef = React.useRef(null);
+ const scrollerRef = React.useRef(null);
- useEffect(() => {
- addAnimation();
- }, []);
- const [start, setStart] = useState(false);
- function addAnimation() {
- if (containerRef.current && scrollerRef.current) {
- const scrollerContent = Array.from(scrollerRef.current.children);
+ useEffect(() => {
+ addAnimation();
+ }, []);
+ const [start, setStart] = useState(false);
+ function addAnimation() {
+ if (containerRef.current && scrollerRef.current) {
+ const scrollerContent = Array.from(scrollerRef.current.children);
- scrollerContent.forEach((item) => {
- const duplicatedItem = item.cloneNode(true);
- if (scrollerRef.current) {
- scrollerRef.current.appendChild(duplicatedItem);
- }
- });
-
- getDirection();
- getSpeed();
- setStart(true);
+ scrollerContent.forEach((item) => {
+ const duplicatedItem = item.cloneNode(true);
+ if (scrollerRef.current) {
+ scrollerRef.current.appendChild(duplicatedItem);
}
+ });
+
+ getDirection();
+ getSpeed();
+ setStart(true);
}
- const getDirection = () => {
- if (containerRef.current) {
- if (direction === "left") {
- containerRef.current.style.setProperty(
- "--animation-direction",
- "forwards"
- );
- } else {
- containerRef.current.style.setProperty(
- "--animation-direction",
- "reverse"
- );
- }
- }
- };
- const getSpeed = () => {
- if (containerRef.current) {
- if (speed === "fast") {
- containerRef.current.style.setProperty("--animation-duration", "20s");
- } else if (speed === "normal") {
- containerRef.current.style.setProperty("--animation-duration", "40s");
- } else {
- containerRef.current.style.setProperty("--animation-duration", "80s");
- }
- }
- };
- return (
-
-
- {items.map((item, idx) => (
-
-
-
-
- {item.quote}
-
-
-
-
- {item.name}
-
-
- {item.title}
-
-
-
-
-
- ))}
-
-
- );
+ }
+ const getDirection = () => {
+ if (containerRef.current) {
+ if (direction === 'left') {
+ containerRef.current.style.setProperty(
+ '--animation-direction',
+ 'forwards'
+ );
+ } else {
+ containerRef.current.style.setProperty(
+ '--animation-direction',
+ 'reverse'
+ );
+ }
+ }
+ };
+ const getSpeed = () => {
+ if (containerRef.current) {
+ if (speed === 'fast') {
+ containerRef.current.style.setProperty('--animation-duration', '20s');
+ } else if (speed === 'normal') {
+ containerRef.current.style.setProperty('--animation-duration', '40s');
+ } else {
+ containerRef.current.style.setProperty('--animation-duration', '80s');
+ }
+ }
+ };
+ return (
+
+
+ {items.map((item, idx) => (
+
+
+
+
+ {item.quote}
+
+
+
+
+ {item.name}
+
+
+ {item.title}
+
+
+
+
+
+ ))}
+
+
+ );
};
diff --git a/components/ui/input.tsx b/components/ui/input.tsx
index 59ece33..9282bc4 100644
--- a/components/ui/input.tsx
+++ b/components/ui/input.tsx
@@ -1,9 +1,9 @@
-import * as React from "react"
+import * as React from 'react';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
export interface InputProps
- extends React.InputHTMLAttributes { }
+ extends React.InputHTMLAttributes {}
const Input = React.forwardRef(
({ className, type, ...props }, ref) => {
@@ -11,15 +11,15 @@ const Input = React.forwardRef(
- )
+ );
}
-)
-Input.displayName = "Input"
+);
+Input.displayName = 'Input';
-export { Input }
+export { Input };
diff --git a/components/ui/label.tsx b/components/ui/label.tsx
index 5341821..1e24ec0 100644
--- a/components/ui/label.tsx
+++ b/components/ui/label.tsx
@@ -1,14 +1,14 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
-import { cva, type VariantProps } from "class-variance-authority"
+import * as React from 'react';
+import * as LabelPrimitive from '@radix-ui/react-label';
+import { cva, type VariantProps } from 'class-variance-authority';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
const labelVariants = cva(
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
-)
+ 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
+);
const Label = React.forwardRef<
React.ElementRef,
@@ -20,7 +20,7 @@ const Label = React.forwardRef<
className={cn(labelVariants(), className)}
{...props}
/>
-))
-Label.displayName = LabelPrimitive.Root.displayName
+));
+Label.displayName = LabelPrimitive.Root.displayName;
-export { Label }
+export { Label };
diff --git a/components/ui/lamp.tsx b/components/ui/lamp.tsx
index 3ecb87a..c097f12 100644
--- a/components/ui/lamp.tsx
+++ b/components/ui/lamp.tsx
@@ -1,104 +1,106 @@
-"use client";
-import { cn } from "@/lib/utils";
-import { motion } from "framer-motion";
-import React from "react";
+'use client';
+import { cn } from '@/lib/utils';
+import { motion } from 'framer-motion';
+import React from 'react';
export function LampDemo() {
- return (
-
-
- Build lamps the right way
-
-
- );
+ return (
+
+
+ Build lamps the right way
+
+
+ );
}
export const LampContainer = ({
- children,
- className,
+ children,
+ className,
}: {
- children: React.ReactNode;
- className?: string;
+ children: React.ReactNode;
+ className?: string;
}) => {
- return (
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
- {children}
-
-
- );
+
+ {children}
+
+
+ );
};
diff --git a/components/ui/macbook-scroll.tsx b/components/ui/macbook-scroll.tsx
index 212ed77..332e752 100644
--- a/components/ui/macbook-scroll.tsx
+++ b/components/ui/macbook-scroll.tsx
@@ -1,655 +1,663 @@
-"use client";
-import { cn } from "@/lib/utils";
+'use client';
+import { cn } from '@/lib/utils';
import {
- IconBrightnessDown,
- IconBrightnessUp,
- IconCaretDownFilled,
- IconCaretLeftFilled,
- IconCaretRightFilled,
- IconCaretUpFilled,
- IconChevronUp,
- IconCommand,
- IconMicrophone,
- IconMoon,
- IconPlayerSkipForward,
- IconPlayerTrackNext,
- IconPlayerTrackPrev,
- IconSearch,
- IconTable,
- IconVolume,
- IconVolume2,
- IconVolume3,
- IconWorld,
-} from "@tabler/icons-react";
-import { MotionValue, motion, useScroll, useTransform } from "framer-motion";
-import Image from "next/image";
-import React, { useEffect, useRef, useState } from "react";
+ IconBrightnessDown,
+ IconBrightnessUp,
+ IconCaretDownFilled,
+ IconCaretLeftFilled,
+ IconCaretRightFilled,
+ IconCaretUpFilled,
+ IconChevronUp,
+ IconCommand,
+ IconMicrophone,
+ IconMoon,
+ IconPlayerSkipForward,
+ IconPlayerTrackNext,
+ IconPlayerTrackPrev,
+ IconSearch,
+ IconTable,
+ IconVolume,
+ IconVolume2,
+ IconVolume3,
+ IconWorld,
+} from '@tabler/icons-react';
+import { MotionValue, motion, useScroll, useTransform } from 'framer-motion';
+import Image from 'next/image';
+import React, { useEffect, useRef, useState } from 'react';
export const MacbookScroll = ({
- src,
- showGradient,
- title,
- badge,
+ src,
+ showGradient,
+ title,
+ badge,
}: {
- src?: string;
- showGradient?: boolean;
- title?: string | React.ReactNode;
- badge?: React.ReactNode;
+ src?: string;
+ showGradient?: boolean;
+ title?: string | React.ReactNode;
+ badge?: React.ReactNode;
}) => {
- const ref = useRef(null);
- const { scrollYProgress } = useScroll({
- target: ref,
- offset: ["start start", "end start"],
- });
+ const ref = useRef(null);
+ const { scrollYProgress } = useScroll({
+ target: ref,
+ offset: ['start start', 'end start'],
+ });
- const [isMobile, setIsMobile] = useState(false);
+ const [isMobile, setIsMobile] = useState(false);
- useEffect(() => {
- if (window && window.innerWidth < 768) {
- setIsMobile(true);
- }
- }, []);
+ useEffect(() => {
+ if (window && window.innerWidth < 768) {
+ setIsMobile(true);
+ }
+ }, []);
- const scaleX = useTransform(
- scrollYProgress,
- [0, 0.3],
- [1.2, isMobile ? 1 : 1.5]
- );
- const scaleY = useTransform(
- scrollYProgress,
- [0, 0.3],
- [0.6, isMobile ? 1 : 1.5]
- );
- const translate = useTransform(scrollYProgress, [0, 1], [0, 1500]);
- const rotate = useTransform(scrollYProgress, [0.1, 0.12, 0.3], [-28, -28, 0]);
- const textTransform = useTransform(scrollYProgress, [0, 0.3], [0, 100]);
- const textOpacity = useTransform(scrollYProgress, [0, 0.2], [1, 0]);
+ const scaleX = useTransform(
+ scrollYProgress,
+ [0, 0.3],
+ [1.2, isMobile ? 1 : 1.5]
+ );
+ const scaleY = useTransform(
+ scrollYProgress,
+ [0, 0.3],
+ [0.6, isMobile ? 1 : 1.5]
+ );
+ const translate = useTransform(scrollYProgress, [0, 1], [0, 1500]);
+ const rotate = useTransform(scrollYProgress, [0.1, 0.12, 0.3], [-28, -28, 0]);
+ const textTransform = useTransform(scrollYProgress, [0, 0.3], [0, 100]);
+ const textOpacity = useTransform(scrollYProgress, [0, 0.2], [1, 0]);
- return (
-
-
- {title || (
-
- This Macbook is built with Tailwindcss. No kidding.
-
- )}
-
- {/* Lid */}
-
- {/* Base area */}
-
- {/* above keyboard bar */}
-
-
-
-
- {showGradient && (
-
- )}
- {badge &&
{badge}
}
-
+ return (
+
+
+ {title || (
+
+ This Macbook is built with Tailwindcss. No kidding.
+
+ )}
+
+ {/* Lid */}
+
+ {/* Base area */}
+
+ {/* above keyboard bar */}
+
+
- );
+
+
+ {showGradient && (
+
+ )}
+ {badge &&
{badge}
}
+
+
+ );
};
export const Lid = ({
- scaleX,
- scaleY,
- rotate,
- translate,
- src,
+ scaleX,
+ scaleY,
+ rotate,
+ translate,
+ src,
}: {
- scaleX: MotionValue
;
- scaleY: MotionValue;
- rotate: MotionValue;
- translate: MotionValue;
- src?: string;
+ scaleX: MotionValue;
+ scaleY: MotionValue;
+ rotate: MotionValue;
+ translate: MotionValue;
+ src?: string;
}) => {
- return (
-
-
-
-
-
-
+ return (
+
+ );
};
export const Trackpad = () => {
- return (
-
- );
+ return (
+
+ );
};
export const Keypad = () => {
- return (
-
- {/* First Row */}
-
-
- esc
-
-
-
- F1
-
+ return (
+
+ {/* First Row */}
+
+
+ esc
+
+
+
+ F1
+
-
-
- F2
-
-
-
- F3
-
-
-
- F4
-
-
-
- F5
-
-
-
- F6
-
-
-
- F7
-
-
-
- F8
-
-
-
- F8
-
-
-
- F10
-
-
-
- F11
-
-
-
- F12
-
-
-
-
-
+
+
+ F2
+
+
+
+ F3
+
+
+
+ F4
+
+
+
+ F5
+
+
+
+ F6
+
+
+
+ F7
+
+
+
+ F8
+
+
+
+ F8
+
+
+
+ F10
+
+
+
+ F11
+
+
+
+ F12
+
+
+
+
+
- {/* Second row */}
-
-
- ~
- `
-
+ {/* Second row */}
+
+
+ ~
+ `
+
-
- !
- 1
-
-
- @
- 2
-
-
- #
- 3
-
-
- $
- 4
-
-
- %
- 5
-
-
- ^
- 6
-
-
- &
- 7
-
-
- *
- 8
-
-
- (
- 9
-
-
- )
- 0
-
-
- —
- _
-
-
- +
- =
-
-
- delete
-
-
+
+ !
+ 1
+
+
+ @
+ 2
+
+
+ #
+ 3
+
+
+ $
+ 4
+
+
+ %
+ 5
+
+
+ ^
+ 6
+
+
+ &
+ 7
+
+
+ *
+ 8
+
+
+ (
+ 9
+
+
+ )
+ 0
+
+
+ —
+ _
+
+
+ +
+ =
+
+
+ delete
+
+
- {/* Third row */}
-
-
- tab
-
-
- Q
-
+ {/* Third row */}
+
+
+ tab
+
+
+ Q
+
-
- W
-
-
- E
-
-
- R
-
-
- T
-
-
- Y
-
-
- U
-
-
- I
-
-
- O
-
-
- P
-
-
- {`{`}
- {`[`}
-
-
- {`}`}
- {`]`}
-
-
- {`|`}
- {`\\`}
-
-
+
+ W
+
+
+ E
+
+
+ R
+
+
+ T
+
+
+ Y
+
+
+ U
+
+
+ I
+
+
+ O
+
+
+ P
+
+
+ {'{'}
+ {'['}
+
+
+ {'}'}
+ {']'}
+
+
+ {'|'}
+ {'\\'}
+
+
- {/* Fourth Row */}
-
-
- caps lock
-
-
- A
-
+ {/* Fourth Row */}
+
+
+ caps lock
+
+
+ A
+
-
- S
-
-
- D
-
-
- F
-
-
- G
-
-
- H
-
-
- J
-
-
- K
-
-
- L
-
-
- {`:`}
- {`;`}
-
-
- {`"`}
- {`'`}
-
-
- return
-
-
+
+ S
+
+
+ D
+
+
+ F
+
+
+ G
+
+
+ H
+
+
+ J
+
+
+ K
+
+
+ L
+
+
+ {':'}
+ {';'}
+
+
+ {'"'}
+ {"'"}
+
+
+ return
+
+
- {/* Fifth Row */}
-
-
- shift
-
-
- Z
-
-
- X
-
-
- C
-
-
- V
-
-
- B
-
-
- N
-
-
- M
-
-
- {`<`}
- {`,`}
-
-
- {`>`}
- {`.`}
- {" "}
-
- {`?`}
- {`/`}
-
-
- shift
-
-
+ {/* Fifth Row */}
+
+
+ shift
+
+
+ Z
+
+
+ X
+
+
+ C
+
+
+ V
+
+
+ B
+
+
+ N
+
+
+ M
+
+
+ {'<'}
+ {','}
+
+
+ {'>'}
+ {'.'}
+ {' '}
+
+ {'?'}
+ {'/'}
+
+
+ shift
+
+
- {/* sixth Row */}
-
-
-
- fn
-
-
-
-
-
-
-
-
-
-
- control
-
-
-
-
-
-
-
- option
-
-
-
-
-
-
-
- command
-
-
-
-
-
-
-
-
- command
-
-
-
-
-
-
-
- option
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ {/* sixth Row */}
+
+
+
+ fn
+
+
+
+
+
+
+
+
+
+
+ control
+
+
+
+
+
+
+
+ option
+
+
+
+
+
+
+
+ command
+
+
+
+
+
+
+
+
+ command
+
+
+
+
+
+
+
+ option
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- );
+
+
+ );
};
export const KBtn = ({
- className,
- children,
- childrenClassName,
- backlit = true,
+ className,
+ children,
+ childrenClassName,
+ backlit = true,
}: {
- className?: string;
- children?: React.ReactNode;
- childrenClassName?: string;
- backlit?: boolean;
+ className?: string;
+ children?: React.ReactNode;
+ childrenClassName?: string;
+ backlit?: boolean;
}) => {
- return (
+ return (
+
+ );
};
export const Row = ({ children }: { children: React.ReactNode }) => {
- return (
-
- {children}
-
- );
+ return (
+
+ {children}
+
+ );
};
export const SpeakerGrid = () => {
- return (
-
- );
+ return (
+
+ );
};
export const OptionKey = ({ className }: { className: string }) => {
- return (
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+ );
};
const DevResumeLogo = () => {
- return (
-
-
-
-
- );
+ return (
+
+
+
+ );
};
diff --git a/components/ui/navigation-menu.tsx b/components/ui/navigation-menu.tsx
index 1419f56..97ec318 100644
--- a/components/ui/navigation-menu.tsx
+++ b/components/ui/navigation-menu.tsx
@@ -1,9 +1,9 @@
-import * as React from "react"
-import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
-import { cva } from "class-variance-authority"
-import { ChevronDown } from "lucide-react"
+import * as React from 'react';
+import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu';
+import { cva } from 'class-variance-authority';
+import { ChevronDown } from 'lucide-react';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
const NavigationMenu = React.forwardRef<
React.ElementRef,
@@ -12,7 +12,7 @@ const NavigationMenu = React.forwardRef<
-))
-NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
+));
+NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
const NavigationMenuList = React.forwardRef<
React.ElementRef,
@@ -30,19 +30,19 @@ const NavigationMenuList = React.forwardRef<
-))
-NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
+));
+NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
-const NavigationMenuItem = NavigationMenuPrimitive.Item
+const NavigationMenuItem = NavigationMenuPrimitive.Item;
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<
React.ElementRef,
@@ -50,17 +50,17 @@ const NavigationMenuTrigger = React.forwardRef<
>(({ className, children, ...props }, ref) => (
- {children}{" "}
+ {children}{' '}
-))
-NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
+));
+NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
const NavigationMenuContent = React.forwardRef<
React.ElementRef,
@@ -69,33 +69,33 @@ const NavigationMenuContent = React.forwardRef<
-))
-NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName
+));
+NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
-const NavigationMenuLink = NavigationMenuPrimitive.Link
+const NavigationMenuLink = NavigationMenuPrimitive.Link;
const NavigationMenuViewport = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
>(({ className, ...props }, ref) => (
-
+
-))
+));
NavigationMenuViewport.displayName =
- NavigationMenuPrimitive.Viewport.displayName
+ NavigationMenuPrimitive.Viewport.displayName;
const NavigationMenuIndicator = React.forwardRef<
React.ElementRef
,
@@ -104,16 +104,16 @@ const NavigationMenuIndicator = React.forwardRef<
-))
+));
NavigationMenuIndicator.displayName =
- NavigationMenuPrimitive.Indicator.displayName
+ NavigationMenuPrimitive.Indicator.displayName;
export {
navigationMenuTriggerStyle,
@@ -125,4 +125,4 @@ export {
NavigationMenuLink,
NavigationMenuIndicator,
NavigationMenuViewport,
-}
+};
diff --git a/components/ui/new-tabs.tsx b/components/ui/new-tabs.tsx
index 8490c54..eebf826 100644
--- a/components/ui/new-tabs.tsx
+++ b/components/ui/new-tabs.tsx
@@ -1,124 +1,124 @@
-"use client";
+'use client';
-import { cn } from "@/lib/utils";
-import { motion } from "framer-motion";
-import { useState } from "react";
+import { cn } from '@/lib/utils';
+import { motion } from 'framer-motion';
+import { useState } from 'react';
type Tab = {
- title: string;
- value: string;
- content?: string | React.ReactNode | any;
+ title: string;
+ value: string;
+ content?: string | React.ReactNode | any;
};
export const Tabs = ({
- tabs: propTabs,
- containerClassName,
- activeTabClassName,
- tabClassName,
- contentClassName,
+ tabs: propTabs,
+ containerClassName,
+ activeTabClassName,
+ tabClassName,
+ contentClassName,
}: {
- tabs: Tab[];
- containerClassName?: string;
- activeTabClassName?: string;
- tabClassName?: string;
- contentClassName?: string;
+ tabs: Tab[];
+ containerClassName?: string;
+ activeTabClassName?: string;
+ tabClassName?: string;
+ contentClassName?: string;
}) => {
- const [active, setActive] = useState(propTabs[0]);
- const [tabs, setTabs] = useState(propTabs);
+ const [active, setActive] = useState(propTabs[0]);
+ const [tabs, setTabs] = useState(propTabs);
- const moveSelectedTabToTop = (idx: number) => {
- const newTabs = [...propTabs];
- const selectedTab = newTabs.splice(idx, 1);
- newTabs.unshift(selectedTab[0]);
- setTabs(newTabs);
- setActive(newTabs[0]);
- };
+ const moveSelectedTabToTop = (idx: number) => {
+ const newTabs = [...propTabs];
+ const selectedTab = newTabs.splice(idx, 1);
+ newTabs.unshift(selectedTab[0]);
+ setTabs(newTabs);
+ setActive(newTabs[0]);
+ };
- const [hovering, setHovering] = useState(false);
+ const [hovering, setHovering] = useState(false);
- return (
- <>
-
+
+ {propTabs.map((tab, idx) => (
+ {
+ moveSelectedTabToTop(idx);
+ }}
+ onMouseEnter={() => setHovering(true)}
+ onMouseLeave={() => setHovering(false)}
+ className={cn('relative px-4 py-2 rounded-full', tabClassName)}
+ style={{
+ transformStyle: 'preserve-3d',
+ }}
+ >
+ {active.value === tab.value && (
+
- {propTabs.map((tab, idx) => (
- {
- moveSelectedTabToTop(idx);
- }}
- onMouseEnter={() => setHovering(true)}
- onMouseLeave={() => setHovering(false)}
- className={cn("relative px-4 py-2 rounded-full", tabClassName)}
- style={{
- transformStyle: "preserve-3d",
- }}
- >
- {active.value === tab.value && (
-
- )}
+ />
+ )}
-
- {tab.title}
-
-
- ))}
-
-
- >
- );
+
+ {tab.title}
+
+
+ ))}
+
+
+ >
+ );
};
export const FadeInDiv = ({
- className,
- tabs,
- hovering,
+ className,
+ tabs,
+ hovering,
}: {
- className?: string;
- key?: any;
- tabs: Tab[];
- active: Tab;
- hovering?: boolean;
+ className?: string;
+ key?: any;
+ tabs: Tab[];
+ active: Tab;
+ hovering?: boolean;
}) => {
- const isActive = (tab: Tab) => {
- return tab.value === tabs[0].value;
- };
- return (
-
- {tabs.map((tab, idx) => (
-
- {tab.content}
-
- ))}
-
- );
+ const isActive = (tab: Tab) => {
+ return tab.value === tabs[0].value;
+ };
+ return (
+
+ {tabs.map((tab, idx) => (
+
+ {tab.content}
+
+ ))}
+
+ );
};
diff --git a/components/ui/parallax-scroll.tsx b/components/ui/parallax-scroll.tsx
index 91cd314..389d0be 100644
--- a/components/ui/parallax-scroll.tsx
+++ b/components/ui/parallax-scroll.tsx
@@ -1,84 +1,84 @@
-"use client";
-import { cn } from "@/lib/utils";
-import { motion, useScroll, useTransform } from "framer-motion";
-import Image from "next/image";
-import { useRef } from "react";
+'use client';
+import { cn } from '@/lib/utils';
+import { motion, useScroll, useTransform } from 'framer-motion';
+import Image from 'next/image';
+import { useRef } from 'react';
export const ParallaxScroll = ({
- images,
- className,
+ images,
+ className,
}: {
- images: string[];
- className?: string;
+ images: string[];
+ className?: string;
}) => {
- const gridRef = useRef(null);
- const { scrollYProgress } = useScroll({
- container: gridRef, // remove this if your container is not fixed height
- offset: ["start start", "end start"], // remove this if your container is not fixed height
- });
+ const gridRef = useRef(null);
+ const { scrollYProgress } = useScroll({
+ container: gridRef, // remove this if your container is not fixed height
+ offset: ['start start', 'end start'], // remove this if your container is not fixed height
+ });
- const translateFirst = useTransform(scrollYProgress, [0, 1], [0, -200]);
- const translateSecond = useTransform(scrollYProgress, [0, 1], [0, 200]);
- const translateThird = useTransform(scrollYProgress, [0, 1], [0, -200]);
+ const translateFirst = useTransform(scrollYProgress, [0, 1], [0, -200]);
+ const translateSecond = useTransform(scrollYProgress, [0, 1], [0, 200]);
+ const translateThird = useTransform(scrollYProgress, [0, 1], [0, -200]);
- const third = Math.ceil(images.length / 3);
+ const third = Math.ceil(images.length / 3);
- const firstPart = images.slice(0, third);
- const secondPart = images.slice(third, 2 * third);
- const thirdPart = images.slice(2 * third);
+ const firstPart = images.slice(0, third);
+ const secondPart = images.slice(third, 2 * third);
+ const thirdPart = images.slice(2 * third);
- return (
-
-
+
+
+ {firstPart.map((el, idx) => (
+
-
- {firstPart.map((el, idx) => (
-
-
-
- ))}
-
-
- {secondPart.map((el, idx) => (
-
-
-
- ))}
-
-
- {thirdPart.map((el, idx) => (
-
-
-
- ))}
-
-
+
+
+ ))}
- );
+
+ {secondPart.map((el, idx) => (
+
+
+
+ ))}
+
+
+ {thirdPart.map((el, idx) => (
+
+
+
+ ))}
+
+
+
+ );
};
diff --git a/components/ui/popover.tsx b/components/ui/popover.tsx
index a0ec48b..f224d5e 100644
--- a/components/ui/popover.tsx
+++ b/components/ui/popover.tsx
@@ -1,31 +1,31 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as PopoverPrimitive from "@radix-ui/react-popover"
+import * as React from 'react';
+import * as PopoverPrimitive from '@radix-ui/react-popover';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
-const Popover = PopoverPrimitive.Root
+const Popover = PopoverPrimitive.Root;
-const PopoverTrigger = PopoverPrimitive.Trigger
+const PopoverTrigger = PopoverPrimitive.Trigger;
const PopoverContent = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
->(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
+>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
-))
-PopoverContent.displayName = PopoverPrimitive.Content.displayName
+));
+PopoverContent.displayName = PopoverPrimitive.Content.displayName;
-export { Popover, PopoverTrigger, PopoverContent }
+export { Popover, PopoverTrigger, PopoverContent };
diff --git a/components/ui/scroll-area.tsx b/components/ui/scroll-area.tsx
index 0b4a48d..75c68fa 100644
--- a/components/ui/scroll-area.tsx
+++ b/components/ui/scroll-area.tsx
@@ -1,9 +1,9 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
+import * as React from 'react';
+import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
const ScrollArea = React.forwardRef<
React.ElementRef,
@@ -11,7 +11,7 @@ const ScrollArea = React.forwardRef<
>(({ className, children, ...props }, ref) => (
@@ -20,29 +20,29 @@ const ScrollArea = React.forwardRef<
-))
-ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
+));
+ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
const ScrollBar = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
->(({ className, orientation = "vertical", ...props }, ref) => (
+>(({ className, orientation = 'vertical', ...props }, ref) => (
-))
-ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
+));
+ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
-export { ScrollArea, ScrollBar }
+export { ScrollArea, ScrollBar };
diff --git a/components/ui/select.tsx b/components/ui/select.tsx
index cbe5a36..9f3ef21 100644
--- a/components/ui/select.tsx
+++ b/components/ui/select.tsx
@@ -1,16 +1,16 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as SelectPrimitive from "@radix-ui/react-select"
-import { Check, ChevronDown, ChevronUp } from "lucide-react"
+import * as React from 'react';
+import * as SelectPrimitive from '@radix-ui/react-select';
+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<
React.ElementRef,
@@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
span]:line-clamp-1",
+ 'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
className
)}
{...props}
@@ -29,8 +29,8 @@ const SelectTrigger = React.forwardRef<
-))
-SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
+));
+SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectScrollUpButton = React.forwardRef<
React.ElementRef,
@@ -39,15 +39,15 @@ const SelectScrollUpButton = React.forwardRef<
-))
-SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
+));
+SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
const SelectScrollDownButton = React.forwardRef<
React.ElementRef,
@@ -56,28 +56,28 @@ const SelectScrollDownButton = React.forwardRef<
-))
+));
SelectScrollDownButton.displayName =
- SelectPrimitive.ScrollDownButton.displayName
+ SelectPrimitive.ScrollDownButton.displayName;
const SelectContent = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
->(({ className, children, position = "popper", ...props }, ref) => (
+>(({ className, children, position = 'popper', ...props }, ref) => (
{children}
@@ -96,8 +96,8 @@ const SelectContent = React.forwardRef<
-))
-SelectContent.displayName = SelectPrimitive.Content.displayName
+));
+SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<
React.ElementRef,
@@ -105,11 +105,11 @@ const SelectLabel = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-SelectLabel.displayName = SelectPrimitive.Label.displayName
+));
+SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<
React.ElementRef,
@@ -118,7 +118,7 @@ const SelectItem = React.forwardRef<
{children}
-))
-SelectItem.displayName = SelectPrimitive.Item.displayName
+));
+SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectSeparator = React.forwardRef<
React.ElementRef,
@@ -140,11 +140,11 @@ const SelectSeparator = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-SelectSeparator.displayName = SelectPrimitive.Separator.displayName
+));
+SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
export {
Select,
@@ -157,4 +157,4 @@ export {
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
-}
+};
diff --git a/components/ui/separator.tsx b/components/ui/separator.tsx
index 12d81c4..da04061 100644
--- a/components/ui/separator.tsx
+++ b/components/ui/separator.tsx
@@ -1,16 +1,16 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as SeparatorPrimitive from "@radix-ui/react-separator"
+import * as React from 'react';
+import * as SeparatorPrimitive from '@radix-ui/react-separator';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
const Separator = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef
>(
(
- { className, orientation = "horizontal", decorative = true, ...props },
+ { className, orientation = 'horizontal', decorative = true, ...props },
ref
) => (
)
-)
-Separator.displayName = SeparatorPrimitive.Root.displayName
+);
+Separator.displayName = SeparatorPrimitive.Root.displayName;
-export { Separator }
+export { Separator };
diff --git a/components/ui/sheet.tsx b/components/ui/sheet.tsx
index 6a95894..be1ab64 100644
--- a/components/ui/sheet.tsx
+++ b/components/ui/sheet.tsx
@@ -1,19 +1,19 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as SheetPrimitive from "@radix-ui/react-dialog"
-import { cva, type VariantProps } from "class-variance-authority"
-import { X } from "lucide-react"
+import * as React from 'react';
+import * as SheetPrimitive from '@radix-ui/react-dialog';
+import { cva, type VariantProps } from 'class-variance-authority';
+import { X } from 'lucide-react';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
-const Sheet = SheetPrimitive.Root
+const Sheet = SheetPrimitive.Root;
-const SheetTrigger = SheetPrimitive.Trigger
+const SheetTrigger = SheetPrimitive.Trigger;
-const SheetClose = SheetPrimitive.Close
+const SheetClose = SheetPrimitive.Close;
-const SheetPortal = SheetPrimitive.Portal
+const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef,
@@ -21,33 +21,33 @@ const SheetOverlay = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
+));
+SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
- "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
+ 'fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
{
variants: {
side: {
- top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
+ top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
bottom:
- "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
- left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
+ 'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
+ left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
right:
- "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
+ 'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
},
},
defaultVariants: {
- side: "right",
+ side: 'right',
},
}
-)
+);
interface SheetContentProps
extends React.ComponentPropsWithoutRef,
@@ -56,7 +56,7 @@ interface SheetContentProps
const SheetContent = React.forwardRef<
React.ElementRef,
SheetContentProps
->(({ side = "right", className, children, ...props }, ref) => (
+>(({ side = 'right', className, children, ...props }, ref) => (
-))
-SheetContent.displayName = SheetPrimitive.Content.displayName
+));
+SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
@@ -80,13 +80,13 @@ const SheetHeader = ({
}: React.HTMLAttributes) => (
-)
-SheetHeader.displayName = "SheetHeader"
+);
+SheetHeader.displayName = 'SheetHeader';
const SheetFooter = ({
className,
@@ -94,13 +94,13 @@ const SheetFooter = ({
}: React.HTMLAttributes) => (
-)
-SheetFooter.displayName = "SheetFooter"
+);
+SheetFooter.displayName = 'SheetFooter';
const SheetTitle = React.forwardRef<
React.ElementRef,
@@ -108,11 +108,11 @@ const SheetTitle = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-SheetTitle.displayName = SheetPrimitive.Title.displayName
+));
+SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef,
@@ -120,11 +120,11 @@ const SheetDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-SheetDescription.displayName = SheetPrimitive.Description.displayName
+));
+SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
@@ -137,4 +137,4 @@ export {
SheetFooter,
SheetTitle,
SheetDescription,
-}
+};
diff --git a/components/ui/sonner.tsx b/components/ui/sonner.tsx
index 452f4d9..b38ad1e 100644
--- a/components/ui/sonner.tsx
+++ b/components/ui/sonner.tsx
@@ -1,31 +1,31 @@
-"use client"
+'use client';
-import { useTheme } from "next-themes"
-import { Toaster as Sonner } from "sonner"
+import { useTheme } from 'next-themes';
+import { Toaster as Sonner } from 'sonner';
-type ToasterProps = React.ComponentProps
+type ToasterProps = React.ComponentProps;
const Toaster = ({ ...props }: ToasterProps) => {
- const { theme = "system" } = useTheme()
+ const { theme = 'system' } = useTheme();
return (
- )
-}
+ );
+};
-export { Toaster }
+export { Toaster };
diff --git a/components/ui/sparkles.tsx b/components/ui/sparkles.tsx
index 063ac6d..f9bd6e2 100644
--- a/components/ui/sparkles.tsx
+++ b/components/ui/sparkles.tsx
@@ -1,433 +1,433 @@
-"use client";
-import { cn } from "@/lib/utils";
-import type { Container } from "@tsparticles/engine";
-import Particles, { initParticlesEngine } from "@tsparticles/react";
-import { loadSlim } from "@tsparticles/slim";
-import { motion, useAnimation } from "framer-motion";
-import { useEffect, useState } from "react";
+'use client';
+import { cn } from '@/lib/utils';
+import type { Container } from '@tsparticles/engine';
+import Particles, { initParticlesEngine } from '@tsparticles/react';
+import { loadSlim } from '@tsparticles/slim';
+import { motion, useAnimation } from 'framer-motion';
+import { useEffect, useState } from 'react';
type ParticlesProps = {
- id?: string;
- className?: string;
- background?: string;
- particleSize?: number;
- minSize?: number;
- maxSize?: number;
- speed?: number;
- particleColor?: string;
- particleDensity?: number;
+ id?: string;
+ className?: string;
+ background?: string;
+ particleSize?: number;
+ minSize?: number;
+ maxSize?: number;
+ speed?: number;
+ particleColor?: string;
+ particleDensity?: number;
};
export const SparklesCore = (props: ParticlesProps) => {
- const {
- id,
- className,
- background,
- minSize,
- maxSize,
- speed,
- particleColor,
- particleDensity,
- } = props;
- const [init, setInit] = useState(false);
- useEffect(() => {
- initParticlesEngine(async (engine) => {
- await loadSlim(engine);
- }).then(() => {
- setInit(true);
- });
- }, []);
- const controls = useAnimation();
+ const {
+ id,
+ className,
+ background,
+ minSize,
+ maxSize,
+ speed,
+ particleColor,
+ particleDensity,
+ } = props;
+ const [init, setInit] = useState(false);
+ useEffect(() => {
+ initParticlesEngine(async (engine) => {
+ await loadSlim(engine);
+ }).then(() => {
+ setInit(true);
+ });
+ }, []);
+ const controls = useAnimation();
- const particlesLoaded = async (container?: Container) => {
- if (container) {
- console.log(container);
- controls.start({
- opacity: 1,
- transition: {
- duration: 1,
- },
- });
- }
- };
+ const particlesLoaded = async (container?: Container) => {
+ if (container) {
+ console.log(container);
+ controls.start({
+ opacity: 1,
+ transition: {
+ duration: 1,
+ },
+ });
+ }
+ };
- return (
-
- {init && (
-
+ {init && (
+
- )}
-
- );
+ fpsLimit: 120,
+ interactivity: {
+ events: {
+ onClick: {
+ enable: true,
+ mode: 'push',
+ },
+ onHover: {
+ enable: false,
+ mode: 'repulse',
+ },
+ resize: true as any,
+ },
+ modes: {
+ push: {
+ quantity: 4,
+ },
+ repulse: {
+ distance: 200,
+ duration: 0.4,
+ },
+ },
+ },
+ particles: {
+ bounce: {
+ horizontal: {
+ value: 1,
+ },
+ vertical: {
+ value: 1,
+ },
+ },
+ collisions: {
+ absorb: {
+ speed: 2,
+ },
+ bounce: {
+ horizontal: {
+ value: 1,
+ },
+ vertical: {
+ value: 1,
+ },
+ },
+ enable: false,
+ maxSpeed: 50,
+ mode: 'bounce',
+ overlap: {
+ enable: true,
+ retries: 0,
+ },
+ },
+ color: {
+ value: particleColor || '#ffffff',
+ animation: {
+ h: {
+ count: 0,
+ enable: false,
+ speed: 1,
+ decay: 0,
+ delay: 0,
+ sync: true,
+ offset: 0,
+ },
+ s: {
+ count: 0,
+ enable: false,
+ speed: 1,
+ decay: 0,
+ delay: 0,
+ sync: true,
+ offset: 0,
+ },
+ l: {
+ count: 0,
+ enable: false,
+ speed: 1,
+ decay: 0,
+ delay: 0,
+ sync: true,
+ offset: 0,
+ },
+ },
+ },
+ effect: {
+ close: true,
+ fill: true,
+ options: {},
+ type: {} as any,
+ },
+ groups: {},
+ move: {
+ angle: {
+ offset: 0,
+ value: 90,
+ },
+ attract: {
+ distance: 200,
+ enable: false,
+ rotate: {
+ x: 3000,
+ y: 3000,
+ },
+ },
+ center: {
+ x: 50,
+ y: 50,
+ mode: 'percent',
+ radius: 0,
+ },
+ decay: 0,
+ distance: {},
+ direction: 'none',
+ drift: 0,
+ enable: true,
+ gravity: {
+ acceleration: 9.81,
+ enable: false,
+ inverse: false,
+ maxSpeed: 50,
+ },
+ path: {
+ clamp: true,
+ delay: {
+ value: 0,
+ },
+ enable: false,
+ options: {},
+ },
+ outModes: {
+ default: 'out',
+ },
+ random: false,
+ size: false,
+ speed: {
+ min: 0.1,
+ max: 1,
+ },
+ spin: {
+ acceleration: 0,
+ enable: false,
+ },
+ straight: false,
+ trail: {
+ enable: false,
+ length: 10,
+ fill: {},
+ },
+ vibrate: false,
+ warp: false,
+ },
+ number: {
+ density: {
+ enable: true,
+ width: 400,
+ height: 400,
+ },
+ limit: {
+ mode: 'delete',
+ value: 0,
+ },
+ value: particleDensity || 120,
+ },
+ opacity: {
+ value: {
+ min: 0.1,
+ max: 1,
+ },
+ animation: {
+ count: 0,
+ enable: true,
+ speed: speed || 4,
+ decay: 0,
+ delay: 0,
+ sync: false,
+ mode: 'auto',
+ startValue: 'random',
+ destroy: 'none',
+ },
+ },
+ reduceDuplicates: false,
+ shadow: {
+ blur: 0,
+ color: {
+ value: '#000',
+ },
+ enable: false,
+ offset: {
+ x: 0,
+ y: 0,
+ },
+ },
+ shape: {
+ close: true,
+ fill: true,
+ options: {},
+ type: 'circle',
+ },
+ size: {
+ value: {
+ min: minSize || 1,
+ max: maxSize || 3,
+ },
+ animation: {
+ count: 0,
+ enable: false,
+ speed: 5,
+ decay: 0,
+ delay: 0,
+ sync: false,
+ mode: 'auto',
+ startValue: 'random',
+ destroy: 'none',
+ },
+ },
+ stroke: {
+ width: 0,
+ },
+ zIndex: {
+ value: 0,
+ opacityRate: 1,
+ sizeRate: 1,
+ velocityRate: 1,
+ },
+ destroy: {
+ bounds: {},
+ mode: 'none',
+ split: {
+ count: 1,
+ factor: {
+ value: 3,
+ },
+ rate: {
+ value: {
+ min: 4,
+ max: 9,
+ },
+ },
+ sizeOffset: true,
+ },
+ },
+ roll: {
+ darken: {
+ enable: false,
+ value: 0,
+ },
+ enable: false,
+ enlighten: {
+ enable: false,
+ value: 0,
+ },
+ mode: 'vertical',
+ speed: 25,
+ },
+ tilt: {
+ value: 0,
+ animation: {
+ enable: false,
+ speed: 0,
+ decay: 0,
+ sync: false,
+ },
+ direction: 'clockwise',
+ enable: false,
+ },
+ twinkle: {
+ lines: {
+ enable: false,
+ frequency: 0.05,
+ opacity: 1,
+ },
+ particles: {
+ enable: false,
+ frequency: 0.05,
+ opacity: 1,
+ },
+ },
+ wobble: {
+ distance: 5,
+ enable: false,
+ speed: {
+ angle: 50,
+ move: 10,
+ },
+ },
+ life: {
+ count: 0,
+ delay: {
+ value: 0,
+ sync: false,
+ },
+ duration: {
+ value: 0,
+ sync: false,
+ },
+ },
+ rotate: {
+ value: 0,
+ animation: {
+ enable: false,
+ speed: 0,
+ decay: 0,
+ sync: false,
+ },
+ direction: 'clockwise',
+ path: false,
+ },
+ orbit: {
+ animation: {
+ count: 0,
+ enable: false,
+ speed: 1,
+ decay: 0,
+ delay: 0,
+ sync: false,
+ },
+ enable: false,
+ opacity: 1,
+ rotation: {
+ value: 45,
+ },
+ width: 1,
+ },
+ links: {
+ blink: false,
+ color: {
+ value: '#fff',
+ },
+ consent: false,
+ distance: 100,
+ enable: false,
+ frequency: 1,
+ opacity: 1,
+ shadow: {
+ blur: 5,
+ color: {
+ value: '#000',
+ },
+ enable: false,
+ },
+ triangles: {
+ enable: false,
+ frequency: 1,
+ },
+ width: 1,
+ warp: false,
+ },
+ repulse: {
+ value: 0,
+ enabled: false,
+ distance: 1,
+ duration: 1,
+ factor: 1,
+ speed: 1,
+ },
+ },
+ detectRetina: true,
+ }}
+ />
+ )}
+
+ );
};
diff --git a/components/ui/tabs.tsx b/components/ui/tabs.tsx
index 26eb109..7315537 100644
--- a/components/ui/tabs.tsx
+++ b/components/ui/tabs.tsx
@@ -1,11 +1,11 @@
-"use client"
+'use client';
-import * as React from "react"
-import * as TabsPrimitive from "@radix-ui/react-tabs"
+import * as React from 'react';
+import * as TabsPrimitive from '@radix-ui/react-tabs';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
-const Tabs = TabsPrimitive.Root
+const Tabs = TabsPrimitive.Root;
const TabsList = React.forwardRef<
React.ElementRef,
@@ -14,13 +14,13 @@ const TabsList = React.forwardRef<
-))
-TabsList.displayName = TabsPrimitive.List.displayName
+));
+TabsList.displayName = TabsPrimitive.List.displayName;
const TabsTrigger = React.forwardRef<
React.ElementRef,
@@ -29,13 +29,13 @@ const TabsTrigger = React.forwardRef<
-))
-TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
+));
+TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
const TabsContent = React.forwardRef<
React.ElementRef,
@@ -44,12 +44,12 @@ const TabsContent = React.forwardRef<
-))
-TabsContent.displayName = TabsPrimitive.Content.displayName
+));
+TabsContent.displayName = TabsPrimitive.Content.displayName;
-export { Tabs, TabsList, TabsTrigger, TabsContent }
+export { Tabs, TabsList, TabsTrigger, TabsContent };
diff --git a/components/ui/text-generate-effect.tsx b/components/ui/text-generate-effect.tsx
index 1932718..701a344 100644
--- a/components/ui/text-generate-effect.tsx
+++ b/components/ui/text-generate-effect.tsx
@@ -1,54 +1,52 @@
-"use client";
-import { cn } from "@/lib/utils";
-import { motion, stagger, useAnimate } from "framer-motion";
-import { useEffect } from "react";
+'use client';
+import { cn } from '@/lib/utils';
+import { motion, stagger, useAnimate } from 'framer-motion';
+import { useEffect } from 'react';
export const TextGenerateEffect = ({
- words,
- className,
+ words,
+ className,
}: {
- words: string;
- className?: string;
+ words: string;
+ className?: string;
}) => {
- const [scope, animate] = useAnimate();
- let wordsArray = words.split(" ");
- useEffect(() => {
- animate(
- "span",
- {
- opacity: 1,
- },
- {
- duration: 2,
- delay: stagger(0.2),
- }
- );
- }, [scope.current]);
-
- const renderWords = () => {
- return (
-
- {wordsArray.map((word, idx) => {
- return (
-
- {word}{" "}
-
- );
- })}
-
- );
- };
+ const [scope, animate] = useAnimate();
+ let wordsArray = words.split(' ');
+ useEffect(() => {
+ animate(
+ 'span',
+ {
+ opacity: 1,
+ },
+ {
+ duration: 2,
+ delay: stagger(0.2),
+ }
+ );
+ }, [scope.current]);
+ const renderWords = () => {
return (
-
+
+ {wordsArray.map((word, idx) => {
+ return (
+
+ {word}{' '}
+
+ );
+ })}
+
);
+ };
+
+ return (
+
+ );
};
diff --git a/components/ui/text-reveal-card.tsx b/components/ui/text-reveal-card.tsx
index ead1efd..4a07bdd 100644
--- a/components/ui/text-reveal-card.tsx
+++ b/components/ui/text-reveal-card.tsx
@@ -1,176 +1,176 @@
-"use client";
-import { cn } from "@/lib/utils";
-import { motion } from "framer-motion";
-import React, { memo, useEffect, useRef, useState } from "react";
-import { twMerge } from "tailwind-merge";
+'use client';
+import { cn } from '@/lib/utils';
+import { motion } from 'framer-motion';
+import React, { memo, useEffect, useRef, useState } from 'react';
+import { twMerge } from 'tailwind-merge';
export const TextRevealCard = ({
- text,
- revealText,
- children,
- className,
+ text,
+ revealText,
+ children,
+ className,
}: {
- text: string;
- revealText: string;
- children?: React.ReactNode;
- className?: string;
+ text: string;
+ revealText: string;
+ children?: React.ReactNode;
+ className?: string;
}) => {
- const [widthPercentage, setWidthPercentage] = useState(0);
- const cardRef = useRef(null);
- const [left, setLeft] = useState(0);
- const [localWidth, setLocalWidth] = useState(0);
- const [isMouseOver, setIsMouseOver] = useState(false);
+ const [widthPercentage, setWidthPercentage] = useState(0);
+ const cardRef = useRef(null);
+ const [left, setLeft] = useState(0);
+ const [localWidth, setLocalWidth] = useState(0);
+ const [isMouseOver, setIsMouseOver] = useState(false);
- useEffect(() => {
- if (cardRef.current) {
- const { left, width: localWidth } =
- cardRef.current.getBoundingClientRect();
- setLeft(left);
- setLocalWidth(localWidth);
- }
- }, []);
+ useEffect(() => {
+ if (cardRef.current) {
+ const { left, width: localWidth } =
+ cardRef.current.getBoundingClientRect();
+ setLeft(left);
+ setLocalWidth(localWidth);
+ }
+ }, []);
- function mouseMoveHandler(event: any) {
- event.preventDefault();
+ function mouseMoveHandler(event: any) {
+ event.preventDefault();
- const { clientX } = event;
- if (cardRef.current) {
- const relativeX = clientX - left;
- setWidthPercentage((relativeX / localWidth) * 100);
- }
+ const { clientX } = event;
+ if (cardRef.current) {
+ const relativeX = clientX - left;
+ setWidthPercentage((relativeX / localWidth) * 100);
}
+ }
- function mouseLeaveHandler() {
- setIsMouseOver(false);
- setWidthPercentage(0);
- }
- function mouseEnterHandler() {
- setIsMouseOver(true);
- }
+ function mouseLeaveHandler() {
+ setIsMouseOver(false);
+ setWidthPercentage(0);
+ }
+ function mouseEnterHandler() {
+ setIsMouseOver(true);
+ }
- const rotateDeg = (widthPercentage - 50) * 0.1;
- return (
-
- {children}
+ const rotateDeg = (widthPercentage - 50) * 0.1;
+ return (
+
+ {children}
-
-
0 ? 1 : 0,
- clipPath: `inset(0 ${100 - widthPercentage}% 0 0)`,
- }
- : {
- clipPath: `inset(0 ${100 - widthPercentage}% 0 0)`,
- }
- }
- transition={isMouseOver ? { duration: 0 } : { duration: 0.4 }}
- className="absolute bg-[#1d1c20] z-20 will-change-transform"
- >
-
- {revealText}
-
-
-
0 ? 1 : 0,
- }}
- transition={isMouseOver ? { duration: 0 } : { duration: 0.4 }}
- className="h-40 w-[8px] bg-gradient-to-b from-transparent via-neutral-800 to-transparent absolute z-50 will-change-transform"
- >
+
+
0 ? 1 : 0,
+ clipPath: `inset(0 ${100 - widthPercentage}% 0 0)`,
+ }
+ : {
+ clipPath: `inset(0 ${100 - widthPercentage}% 0 0)`,
+ }
+ }
+ transition={isMouseOver ? { duration: 0 } : { duration: 0.4 }}
+ className="absolute bg-[#1d1c20] z-20 will-change-transform"
+ >
+
+ {revealText}
+
+
+
0 ? 1 : 0,
+ }}
+ transition={isMouseOver ? { duration: 0 } : { duration: 0.4 }}
+ className="h-40 w-[8px] bg-gradient-to-b from-transparent via-neutral-800 to-transparent absolute z-50 will-change-transform"
+ />
-
-
+
- );
+
+
+ );
};
export const TextRevealCardTitle = ({
- children,
- className,
+ children,
+ className,
}: {
- children: React.ReactNode;
- className?: string;
+ children: React.ReactNode;
+ className?: string;
}) => {
- return (
-
- {children}
-
- );
+ return (
+
+ {children}
+
+ );
};
export const TextRevealCardDescription = ({
- children,
- className,
+ children,
+ className,
}: {
- children: React.ReactNode;
- className?: string;
+ children: React.ReactNode;
+ className?: string;
}) => {
- return (
-
{children}
- );
+ return (
+
{children}
+ );
};
const Stars = () => {
- const randomMove = () => Math.random() * 4 - 2;
- const randomOpacity = () => Math.random();
- const random = () => Math.random();
- return (
-
- {[...Array(140)].map((_, i) => (
-
- ))}
-
- );
+ const randomMove = () => Math.random() * 4 - 2;
+ const randomOpacity = () => Math.random();
+ const random = () => Math.random();
+ return (
+
+ {[...Array(140)].map((_, i) => (
+
+ ))}
+
+ );
};
export const MemoizedStars = memo(Stars);
diff --git a/components/ui/textarea.tsx b/components/ui/textarea.tsx
index 9f9a6dc..4ca0611 100644
--- a/components/ui/textarea.tsx
+++ b/components/ui/textarea.tsx
@@ -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
extends React.TextareaHTMLAttributes
{}
@@ -10,15 +10,15 @@ const Textarea = React.forwardRef(
return (
- )
+ );
}
-)
-Textarea.displayName = "Textarea"
+);
+Textarea.displayName = 'Textarea';
-export { Textarea }
+export { Textarea };
diff --git a/components/ui/toast.tsx b/components/ui/toast.tsx
index a822477..b599393 100644
--- a/components/ui/toast.tsx
+++ b/components/ui/toast.tsx
@@ -1,11 +1,11 @@
-import * as React from "react"
-import * as ToastPrimitives from "@radix-ui/react-toast"
-import { cva, type VariantProps } from "class-variance-authority"
-import { X } from "lucide-react"
+import * as React from 'react';
+import * as ToastPrimitives from '@radix-ui/react-toast';
+import { cva, type VariantProps } from 'class-variance-authority';
+import { X } from 'lucide-react';
-import { cn } from "@/lib/utils"
+import { cn } from '@/lib/utils';
-const ToastProvider = ToastPrimitives.Provider
+const ToastProvider = ToastPrimitives.Provider;
const ToastViewport = React.forwardRef<
React.ElementRef,
@@ -14,29 +14,29 @@ const ToastViewport = React.forwardRef<
-))
-ToastViewport.displayName = ToastPrimitives.Viewport.displayName
+));
+ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
const toastVariants = cva(
- "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
+ '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',
{
variants: {
variant: {
- default: "border bg-background text-foreground",
+ default: 'border bg-background text-foreground',
destructive:
- "destructive group border-destructive bg-destructive text-destructive-foreground",
+ 'destructive group border-destructive bg-destructive text-destructive-foreground',
},
},
defaultVariants: {
- variant: "default",
+ variant: 'default',
},
}
-)
+);
const Toast = React.forwardRef<
React.ElementRef,
@@ -49,9 +49,9 @@ const Toast = React.forwardRef<
className={cn(toastVariants({ variant }), className)}
{...props}
/>
- )
-})
-Toast.displayName = ToastPrimitives.Root.displayName
+ );
+});
+Toast.displayName = ToastPrimitives.Root.displayName;
const ToastAction = React.forwardRef<
React.ElementRef,
@@ -60,13 +60,13 @@ const ToastAction = React.forwardRef<
-))
-ToastAction.displayName = ToastPrimitives.Action.displayName
+));
+ToastAction.displayName = ToastPrimitives.Action.displayName;
const ToastClose = React.forwardRef<
React.ElementRef,
@@ -75,7 +75,7 @@ const ToastClose = React.forwardRef<
-))
-ToastClose.displayName = ToastPrimitives.Close.displayName
+));
+ToastClose.displayName = ToastPrimitives.Close.displayName;
const ToastTitle = React.forwardRef<
React.ElementRef,
@@ -92,11 +92,11 @@ const ToastTitle = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-ToastTitle.displayName = ToastPrimitives.Title.displayName
+));
+ToastTitle.displayName = ToastPrimitives.Title.displayName;
const ToastDescription = React.forwardRef<
React.ElementRef,
@@ -104,15 +104,15 @@ const ToastDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
-))
-ToastDescription.displayName = ToastPrimitives.Description.displayName
+));
+ToastDescription.displayName = ToastPrimitives.Description.displayName;
-type ToastProps = React.ComponentPropsWithoutRef
+type ToastProps = React.ComponentPropsWithoutRef;
-type ToastActionElement = React.ReactElement
+type ToastActionElement = React.ReactElement;
export {
type ToastProps,
@@ -124,4 +124,4 @@ export {
ToastDescription,
ToastClose,
ToastAction,
-}
+};
diff --git a/components/ui/toaster.tsx b/components/ui/toaster.tsx
index e223385..beb7f25 100644
--- a/components/ui/toaster.tsx
+++ b/components/ui/toaster.tsx
@@ -1,4 +1,4 @@
-"use client"
+'use client';
import {
Toast,
@@ -7,11 +7,11 @@ import {
ToastProvider,
ToastTitle,
ToastViewport,
-} from "@/components/ui/toast"
-import { useToast } from "@/components/ui/use-toast"
+} from '@/components/ui/toast';
+import { useToast } from '@/components/ui/use-toast';
export function Toaster() {
- const { toasts } = useToast()
+ const { toasts } = useToast();
return (
@@ -27,9 +27,9 @@ export function Toaster() {
{action}
- )
+ );
})}
- )
+ );
}
diff --git a/components/ui/tracing-beam.tsx b/components/ui/tracing-beam.tsx
index 1ecc6fd..be72de4 100644
--- a/components/ui/tracing-beam.tsx
+++ b/components/ui/tracing-beam.tsx
@@ -1,138 +1,138 @@
-"use client";
-import { cn } from "@/lib/utils";
+'use client';
+import { cn } from '@/lib/utils';
import {
- motion,
- useScroll,
- useSpring,
- useTransform,
- useVelocity,
-} from "framer-motion";
-import React, { useEffect, useRef, useState } from "react";
+ motion,
+ useScroll,
+ useSpring,
+ useTransform,
+ useVelocity,
+} from 'framer-motion';
+import React, { useEffect, useRef, useState } from 'react';
export const TracingBeam = ({
- children,
- className,
+ children,
+ className,
}: {
- children: React.ReactNode;
- className?: string;
+ children: React.ReactNode;
+ className?: string;
}) => {
- const ref = useRef(null);
- const { scrollYProgress } = useScroll({
- target: ref,
- offset: ["start start", "end start"],
- });
+ const ref = useRef(null);
+ const { scrollYProgress } = useScroll({
+ target: ref,
+ offset: ['start start', 'end start'],
+ });
- // track velocity of scroll to increase or decrease distance between svg gradient y coordinates.
- const scrollYProgressVelocity = useVelocity(scrollYProgress);
- const [velo, setVelocity] = React.useState(0);
+ // track velocity of scroll to increase or decrease distance between svg gradient y coordinates.
+ const scrollYProgressVelocity = useVelocity(scrollYProgress);
+ const [velo, setVelocity] = React.useState(0);
- const contentRef = useRef(null);
+ const contentRef = useRef(null);
- const [svgHeight, setSvgHeight] = useState(0);
+ const [svgHeight, setSvgHeight] = useState(0);
- useEffect(() => {
- if (contentRef.current) {
- setSvgHeight(contentRef.current.offsetHeight);
- }
- }, []);
- useEffect(() => {
- return scrollYProgressVelocity.onChange((latestVelocity) => {
- setVelocity(latestVelocity);
- });
- }, []);
+ useEffect(() => {
+ if (contentRef.current) {
+ setSvgHeight(contentRef.current.offsetHeight);
+ }
+ }, []);
+ useEffect(() => {
+ return scrollYProgressVelocity.onChange((latestVelocity) => {
+ setVelocity(latestVelocity);
+ });
+ }, []);
- const y1 = useSpring(
- useTransform(scrollYProgress, [0, 0.8], [50, svgHeight - velo * 500]),
- {
- stiffness: 500,
- damping: 90,
- }
- );
- const y2 = useSpring(
- useTransform(scrollYProgress, [0, 1], [50, svgHeight - velo * 2000]),
- {
- stiffness: 500,
- damping: 90,
- }
- );
+ const y1 = useSpring(
+ useTransform(scrollYProgress, [0, 0.8], [50, svgHeight - velo * 500]),
+ {
+ stiffness: 500,
+ damping: 90,
+ }
+ );
+ const y2 = useSpring(
+ useTransform(scrollYProgress, [0, 1], [50, svgHeight - velo * 2000]),
+ {
+ stiffness: 500,
+ damping: 90,
+ }
+ );
- return (
+ return (
+
+
0
+ ? 'none'
+ : 'rgba(0, 0, 0, 0.24) 0px 3px 8px',
+ }}
+ className="ml-[27px] h-4 w-4 rounded-full border border-netural-200 shadow-sm flex items-center justify-center"
>
-
- 0
- ? "none"
- : "rgba(0, 0, 0, 0.24) 0px 3px 8px",
- }}
- className="ml-[27px] h-4 w-4 rounded-full border border-netural-200 shadow-sm flex items-center justify-center"
- >
- 0 ? "white" : "var(--emerald-500)",
- borderColor:
- scrollYProgress.get() > 0 ? "white" : "var(--emerald-600)",
- }}
- className="h-2 w-2 rounded-full border border-neutral-300 bg-white"
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {children}
+ 0 ? 'white' : 'var(--emerald-500)',
+ borderColor:
+ scrollYProgress.get() > 0 ? 'white' : 'var(--emerald-600)',
+ }}
+ className="h-2 w-2 rounded-full border border-neutral-300 bg-white"
+ />
- );
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {children}
+
+ );
};
diff --git a/components/ui/typewriter-effect.tsx b/components/ui/typewriter-effect.tsx
index ee47142..5c3b5e5 100644
--- a/components/ui/typewriter-effect.tsx
+++ b/components/ui/typewriter-effect.tsx
@@ -1,186 +1,186 @@
-"use client";
+'use client';
-import { cn } from "@/lib/utils";
-import { motion, stagger, useAnimate, useInView } from "framer-motion";
-import { useEffect } from "react";
+import { cn } from '@/lib/utils';
+import { motion, stagger, useAnimate, useInView } from 'framer-motion';
+import { useEffect } from 'react';
export const TypewriterEffect = ({
- words,
- className,
- cursorClassName,
+ words,
+ className,
+ cursorClassName,
}: {
- words: {
- text: string;
- className?: string;
- }[];
+ words: {
+ text: string;
className?: string;
- cursorClassName?: string;
+ }[];
+ className?: string;
+ cursorClassName?: string;
}) => {
- // split text inside of words into array of characters
- const wordsArray = words.map((word) => {
- return {
- ...word,
- text: word.text.split(""),
- };
- });
+ // split text inside of words into array of characters
+ const wordsArray = words.map((word) => {
+ return {
+ ...word,
+ text: word.text.split(''),
+ };
+ });
- const [scope, animate] = useAnimate();
- const isInView = useInView(scope);
- useEffect(() => {
- if (isInView) {
- animate(
- "span",
- {
- display: "inline-block",
- opacity: 1,
- },
- {
- duration: 0.3,
- delay: stagger(0.1),
- ease: "easeInOut",
- }
- );
+ const [scope, animate] = useAnimate();
+ const isInView = useInView(scope);
+ useEffect(() => {
+ if (isInView) {
+ animate(
+ 'span',
+ {
+ display: 'inline-block',
+ opacity: 1,
+ },
+ {
+ duration: 0.3,
+ delay: stagger(0.1),
+ ease: 'easeInOut',
}
- }, [isInView]);
+ );
+ }
+ }, [isInView]);
- const renderWords = () => {
- return (
-
- {wordsArray.map((word, idx) => {
- return (
-
- {word.text.map((char, index) => (
-
- {char}
-
- ))}
-
-
- );
- })}
-
- );
- };
+ const renderWords = () => {
return (
-
- {renderWords()}
-
-
+
+ {wordsArray.map((word, idx) => {
+ return (
+
+ {word.text.map((char, index) => (
+
+ {char}
+
+ ))}
+
+
+ );
+ })}
+
);
+ };
+ return (
+
+ {renderWords()}
+
+
+ );
};
export const TypewriterEffectSmooth = ({
- words,
- className,
- cursorClassName,
+ words,
+ className,
+ cursorClassName,
}: {
- words: {
- text: string;
- className?: string;
- }[];
+ words: {
+ text: string;
className?: string;
- cursorClassName?: string;
+ }[];
+ className?: string;
+ cursorClassName?: string;
}) => {
- // split text inside of words into array of characters
- const wordsArray = words.map((word) => {
- return {
- ...word,
- text: word.text.split(""),
- };
- });
- const renderWords = () => {
- return (
-
- {wordsArray.map((word, idx) => {
- return (
-
- {word.text.map((char, index) => (
-
- {char}
-
- ))}
-
-
- );
- })}
-
- );
+ // split text inside of words into array of characters
+ const wordsArray = words.map((word) => {
+ return {
+ ...word,
+ text: word.text.split(''),
};
-
+ });
+ const renderWords = () => {
return (
-
-
-
+ {wordsArray.map((word, idx) => {
+ return (
+
+ {word.text.map((char, index) => (
+
- {renderWords()}{" "}
-
{" "}
-
-
-
+ {char}
+
+ ))}
+
+
+ );
+ })}
+
);
+ };
+
+ return (
+
+
+
+ {renderWords()}{' '}
+
{' '}
+
+
+
+ );
};
diff --git a/components/ui/use-toast.ts b/components/ui/use-toast.ts
index 1671307..f2ee001 100644
--- a/components/ui/use-toast.ts
+++ b/components/ui/use-toast.ts
@@ -1,104 +1,101 @@
// Inspired by react-hot-toast library
-import * as React from "react"
+import * as React from 'react';
-import type {
- ToastActionElement,
- ToastProps,
-} from "@/components/ui/toast"
+import type { ToastActionElement, ToastProps } from '@/components/ui/toast';
-const TOAST_LIMIT = 1
-const TOAST_REMOVE_DELAY = 1000000
+const TOAST_LIMIT = 1;
+const TOAST_REMOVE_DELAY = 1000000;
type ToasterToast = ToastProps & {
- id: string
- title?: React.ReactNode
- description?: React.ReactNode
- action?: ToastActionElement
-}
+ id: string;
+ title?: React.ReactNode;
+ description?: React.ReactNode;
+ action?: ToastActionElement;
+};
const actionTypes = {
- ADD_TOAST: "ADD_TOAST",
- UPDATE_TOAST: "UPDATE_TOAST",
- DISMISS_TOAST: "DISMISS_TOAST",
- REMOVE_TOAST: "REMOVE_TOAST",
-} as const
+ ADD_TOAST: 'ADD_TOAST',
+ UPDATE_TOAST: 'UPDATE_TOAST',
+ DISMISS_TOAST: 'DISMISS_TOAST',
+ REMOVE_TOAST: 'REMOVE_TOAST',
+} as const;
-let count = 0
+let count = 0;
function genId() {
- count = (count + 1) % Number.MAX_SAFE_INTEGER
- return count.toString()
+ count = (count + 1) % Number.MAX_SAFE_INTEGER;
+ return count.toString();
}
-type ActionType = typeof actionTypes
+type ActionType = typeof actionTypes;
type Action =
| {
- type: ActionType["ADD_TOAST"]
- toast: ToasterToast
+ type: ActionType['ADD_TOAST'];
+ toast: ToasterToast;
}
| {
- type: ActionType["UPDATE_TOAST"]
- toast: Partial
+ type: ActionType['UPDATE_TOAST'];
+ toast: Partial;
}
| {
- type: ActionType["DISMISS_TOAST"]
- toastId?: ToasterToast["id"]
+ type: ActionType['DISMISS_TOAST'];
+ toastId?: ToasterToast['id'];
}
| {
- type: ActionType["REMOVE_TOAST"]
- toastId?: ToasterToast["id"]
- }
+ type: ActionType['REMOVE_TOAST'];
+ toastId?: ToasterToast['id'];
+ };
interface State {
- toasts: ToasterToast[]
+ toasts: ToasterToast[];
}
-const toastTimeouts = new Map>()
+const toastTimeouts = new Map>();
const addToRemoveQueue = (toastId: string) => {
if (toastTimeouts.has(toastId)) {
- return
+ return;
}
const timeout = setTimeout(() => {
- toastTimeouts.delete(toastId)
+ toastTimeouts.delete(toastId);
dispatch({
- type: "REMOVE_TOAST",
+ type: 'REMOVE_TOAST',
toastId: toastId,
- })
- }, TOAST_REMOVE_DELAY)
+ });
+ }, TOAST_REMOVE_DELAY);
- toastTimeouts.set(toastId, timeout)
-}
+ toastTimeouts.set(toastId, timeout);
+};
export const reducer = (state: State, action: Action): State => {
switch (action.type) {
- case "ADD_TOAST":
+ case 'ADD_TOAST':
return {
...state,
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
- }
+ };
- case "UPDATE_TOAST":
+ case 'UPDATE_TOAST':
return {
...state,
toasts: state.toasts.map((t) =>
t.id === action.toast.id ? { ...t, ...action.toast } : t
),
- }
+ };
- case "DISMISS_TOAST": {
- const { toastId } = action
+ case 'DISMISS_TOAST': {
+ const { toastId } = action;
// ! Side effects ! - This could be extracted into a dismissToast() action,
// but I'll keep it here for simplicity
if (toastId) {
- addToRemoveQueue(toastId)
+ addToRemoveQueue(toastId);
} else {
state.toasts.forEach((toast) => {
- addToRemoveQueue(toast.id)
- })
+ addToRemoveQueue(toast.id);
+ });
}
return {
@@ -111,82 +108,82 @@ export const reducer = (state: State, action: Action): State => {
}
: t
),
- }
+ };
}
- case "REMOVE_TOAST":
+ case 'REMOVE_TOAST':
if (action.toastId === undefined) {
return {
...state,
toasts: [],
- }
+ };
}
return {
...state,
toasts: state.toasts.filter((t) => t.id !== action.toastId),
- }
+ };
}
-}
+};
-const listeners: Array<(state: State) => void> = []
+const listeners: Array<(state: State) => void> = [];
-let memoryState: State = { toasts: [] }
+let memoryState: State = { toasts: [] };
function dispatch(action: Action) {
- memoryState = reducer(memoryState, action)
+ memoryState = reducer(memoryState, action);
listeners.forEach((listener) => {
- listener(memoryState)
- })
+ listener(memoryState);
+ });
}
-type Toast = Omit
+type Toast = Omit;
function toast({ ...props }: Toast) {
- const id = genId()
+ const id = genId();
const update = (props: ToasterToast) =>
dispatch({
- type: "UPDATE_TOAST",
+ type: 'UPDATE_TOAST',
toast: { ...props, id },
- })
- const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
+ });
+ const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id });
dispatch({
- type: "ADD_TOAST",
+ type: 'ADD_TOAST',
toast: {
...props,
id,
open: true,
onOpenChange: (open) => {
- if (!open) dismiss()
+ if (!open) dismiss();
},
},
- })
+ });
return {
id: id,
dismiss,
update,
- }
+ };
}
function useToast() {
- const [state, setState] = React.useState(memoryState)
+ const [state, setState] = React.useState(memoryState);
React.useEffect(() => {
- listeners.push(setState)
+ listeners.push(setState);
return () => {
- const index = listeners.indexOf(setState)
+ const index = listeners.indexOf(setState);
if (index > -1) {
- listeners.splice(index, 1)
+ listeners.splice(index, 1);
}
- }
- }, [state])
+ };
+ }, [state]);
return {
...state,
toast,
- dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
- }
+ dismiss: (toastId?: string) => dispatch({ type: 'DISMISS_TOAST', toastId }),
+ };
}
-export { useToast, toast }
+export { useToast, toast };
diff --git a/lib/actions.ts b/lib/actions.ts
index 60a3141..c22b1bf 100644
--- a/lib/actions.ts
+++ b/lib/actions.ts
@@ -1,813 +1,801 @@
-"use server";
+'use server';
-import prisma from "@/lib/db";
-import { Blog, Site, UserEducation } from "@prisma/client";
-import { nanoid } from "nanoid";
-import { revalidateTag } from "next/cache";
+import prisma from '@/lib/db';
+import { Blog, Site, UserEducation } from '@prisma/client';
+import { nanoid } from 'nanoid';
+import { revalidateTag } from 'next/cache';
import {
- addDomainToVercel,
- // getApexDomain,
- removeDomainFromVercelProject,
- // removeDomainFromVercelTeam,
- validDomainRegex,
-} from "@/lib/domains";
-import { getBlurDataURL } from "@/lib/utils";
-import { auth } from "@clerk/nextjs/server";
-import { UTApi } from "uploadthing/server";
-import { withBlogAuth, withEducationAuth, withSiteAuth, withWorkAuth } from "./auth";
+ addDomainToVercel,
+ // getApexDomain,
+ removeDomainFromVercelProject,
+ // removeDomainFromVercelTeam,
+ validDomainRegex,
+} from '@/lib/domains';
+import { getBlurDataURL } from '@/lib/utils';
+import { auth } from '@clerk/nextjs/server';
+import { UTApi } from 'uploadthing/server';
+import {
+ withBlogAuth,
+ withEducationAuth,
+ withSiteAuth,
+ withWorkAuth,
+} from './auth';
const utapi = new UTApi();
+export const createSite = async (formData: FormData) => {
+ const session = auth();
+ if (!session.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+
+ const name = formData.get('name') as string;
+ const description = formData.get('description') as string;
+ const subdomain = formData.get('subdomain') as string;
+ const logo = 'https://app.dresume.me/placeholder.png';
+ try {
+ const userdata = await prisma.user.findUnique({
+ where: { id: session.userId },
+ select: {
+ avatar: true,
+ },
+ });
+ if (!userdata?.avatar) {
+ return {
+ error: 'kindly upload your picture in settings',
+ };
+ }
+ const response = await prisma.site.create({
+ data: {
+ name,
+ description,
+ subdomain,
+ logo: userdata?.avatar,
+ user: {
+ connect: {
+ id: session.userId,
+ },
+ },
+ },
+ });
+ await revalidateTag(
+ `${subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-metadata`
+ );
+ return response;
+ } catch (error: any) {
+ if (error.code === 'P2002') {
+ return {
+ error: 'This subdomain is already taken',
+ };
+ } else {
+ return {
+ error: error.message,
+ };
+ }
+ }
+};
+export const updateSite = withSiteAuth(
+ async (formData: FormData, site: Site, key: string) => {
+ // const value = formData.get(key) as string;
-export const createSite = async (formData: FormData) => {
const session = auth();
if (!session.userId) {
- return {
- error: "Not authenticated",
- };
+ return {
+ error: 'Not authenticated',
+ };
}
-
-
- const name = formData.get("name") as string;
- const description = formData.get("description") as string;
- const subdomain = formData.get("subdomain") as string;
- const logo = "https://app.dresume.me/placeholder.png"
try {
+ let response;
- const userdata = await prisma.user.findUnique({
- where: { id: session.userId },
- select: {
- avatar: true
- }
- })
-
- if (!userdata?.avatar) {
- return {
- error: "kindly upload your picture in settings",
- };
- }
-
- const response = await prisma.site.create({
+ if (key === 'customDomain') {
+ const value = formData.get(key) as string;
+ if (value.includes('dresume.me')) {
+ return {
+ error: 'Cannot use dresume.me subdomain as your custom domain',
+ };
+
+ // if the custom domain is valid, we need to add it to Vercel
+ } else if (validDomainRegex.test(value)) {
+ response = await prisma.site.update({
+ where: {
+ id: site.id,
+ },
data: {
- name,
- description,
- subdomain,
- logo: userdata?.avatar,
- user: {
- connect: {
- id: session.userId,
- },
- },
+ customDomain: value,
},
- });
- await revalidateTag(
- `${subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-metadata`,
- );
- return response;
- } catch (error: any) {
- if (error.code === "P2002") {
- return {
- error: `This subdomain is already taken`,
- };
- } else {
- return {
- error: error.message,
- };
+ });
+ await Promise.all([
+ addDomainToVercel(value),
+ // Optional: add www subdomain as well and redirect to apex domain
+ // addDomainToVercel(`www.${value}`),
+ ]);
+
+ // empty value means the user wants to remove the custom domain
+ } else if (value === '') {
+ response = await prisma.site.update({
+ where: {
+ id: site.id,
+ },
+ data: {
+ customDomain: null,
+ },
+ });
}
- }
-};
-export const updateSite = withSiteAuth(
- async (formData: FormData, site: Site, key: string) => {
- // const value = formData.get(key) as string;
-
- const session = auth();
- if (!session.userId) {
- return {
- error: "Not authenticated",
- };
+ // if the site had a different customDomain before, we need to remove it from Vercel
+ if (site.customDomain && site.customDomain !== value) {
+ response = await removeDomainFromVercelProject(site.customDomain);
+ }
+ } else if (key === 'image' || key === 'logo') {
+ const value = formData.get(key) as string;
+ if (!process.env.UPLOADTHING_SECRET) {
+ return {
+ error:
+ 'Missing UPLOADTHING_SECRET token. Note: Vercel Blob is currently in beta – please fill out this form for access: https://tally.so/r/nPDMNd',
+ };
}
+ const file = formData.get(key) as File;
+ const filename = `${nanoid()}.${file.type.split('/')[1]}`;
+
+ // const { url } = await Uploader(filename, file, {
+ // access: "public",
+ // });
- try {
- let response;
-
- if (key === "customDomain") {
- const value = formData.get(key) as string;
- if (value.includes("dresume.me")) {
- return {
- error: "Cannot use dresume.me subdomain as your custom domain",
- };
-
- // if the custom domain is valid, we need to add it to Vercel
- } else if (validDomainRegex.test(value)) {
- response = await prisma.site.update({
- where: {
- id: site.id,
- },
- data: {
- customDomain: value,
- },
- });
- await Promise.all([
- addDomainToVercel(value),
- // Optional: add www subdomain as well and redirect to apex domain
- // addDomainToVercel(`www.${value}`),
- ]);
-
- // empty value means the user wants to remove the custom domain
- } else if (value === "") {
- response = await prisma.site.update({
- where: {
- id: site.id,
- },
- data: {
- customDomain: null,
- },
- });
- }
-
- // if the site had a different customDomain before, we need to remove it from Vercel
- if (site.customDomain && site.customDomain !== value) {
- response = await removeDomainFromVercelProject(site.customDomain);
- }
- } else if (key === "image" || key === "logo") {
- const value = formData.get(key) as string;
- if (!process.env.UPLOADTHING_SECRET) {
- return {
- error:
- "Missing UPLOADTHING_SECRET token. Note: Vercel Blob is currently in beta – please fill out this form for access: https://tally.so/r/nPDMNd",
- };
- }
- const file = formData.get(key) as File;
- const filename = `${nanoid()}.${file.type.split("/")[1]}`;
-
- // const { url } = await Uploader(filename, file, {
- // access: "public",
- // });
-
- const res = await utapi.uploadFiles(file)
-
- if (res.error) {
- return {
- error: res.error
- }
- }
-
- // console.log("after image upload", res)
-
- const blurhash = key === "image" ? await getBlurDataURL(res.data?.url) : null;
-
- response = await prisma.site.update({
- where: {
- id: site.id,
- },
- data: {
- [key]: res.data?.url,
- ...(blurhash && { imageBlurhash: blurhash }),
- },
- });
- } else if (key === "socials") {
- const twitterid = formData.get("twitterid") as string;
- const githubid = formData.get("githubid") as string;
- const linkedinid = formData.get("linkedinid") as string;
- const instagramid = formData.get("instagramid") as string;
- const youtubeurl = formData.get("youtubeurl") as string;
- const websiteurl = formData.get("websiteurl") as string;
- response = await prisma.site.update({
- where: {
- id: site.id,
- },
- data: {
- twitterid,
- githubid,
- linkedinid,
- instagramid,
- youtubeurl,
- websiteurl
- },
- });
- } else if (key === "skills") {
- const skills = formData.getAll(key) as string[];
- console.log(skills)
- response = await prisma.site.update({
- where: {
- id: site.id,
- },
- data: {
- skills,
- },
- });
- } else {
- const value = formData.get(key) as string;
- response = await prisma.site.update({
- where: {
- id: site.id,
- },
- data: {
- [key]: value,
- },
- });
- }
- console.log(
- "Updated site data! Revalidating tags: ",
- `${site.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-metadata`,
- `${site.customDomain}-metadata`,
- );
- await revalidateTag(
- `${site.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-metadata`,
- );
- site.customDomain &&
- (await revalidateTag(`${site.customDomain}-metadata`));
-
- return response;
- } catch (error: any) {
- if (error.code === "P2002") {
- return {
- error: `This ${key} is already taken`,
- };
- } else {
- return {
- error: error.message,
- };
- }
+ const res = await utapi.uploadFiles(file);
+
+ if (res.error) {
+ return {
+ error: res.error,
+ };
}
- },
-);
+ // console.log("after image upload", res)
+ const blurhash =
+ key === 'image' ? await getBlurDataURL(res.data?.url) : null;
-export const deleteSite = withSiteAuth(async (_: FormData, site: Site) => {
- try {
- const response = await prisma.site.delete({
- where: {
- id: site.id,
- },
+ response = await prisma.site.update({
+ where: {
+ id: site.id,
+ },
+ data: {
+ [key]: res.data?.url,
+ ...(blurhash && { imageBlurhash: blurhash }),
+ },
+ });
+ } else if (key === 'socials') {
+ const twitterid = formData.get('twitterid') as string;
+ const githubid = formData.get('githubid') as string;
+ const linkedinid = formData.get('linkedinid') as string;
+ const instagramid = formData.get('instagramid') as string;
+ const youtubeurl = formData.get('youtubeurl') as string;
+ const websiteurl = formData.get('websiteurl') as string;
+ response = await prisma.site.update({
+ where: {
+ id: site.id,
+ },
+ data: {
+ twitterid,
+ githubid,
+ linkedinid,
+ instagramid,
+ youtubeurl,
+ websiteurl,
+ },
+ });
+ } else if (key === 'skills') {
+ const skills = formData.getAll(key) as string[];
+ console.log(skills);
+ response = await prisma.site.update({
+ where: {
+ id: site.id,
+ },
+ data: {
+ skills,
+ },
});
- await revalidateTag(
- `${site.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-metadata`,
- );
- response.customDomain &&
- (await revalidateTag(`${site.customDomain}-metadata`));
- return response;
+ } else {
+ const value = formData.get(key) as string;
+ response = await prisma.site.update({
+ where: {
+ id: site.id,
+ },
+ data: {
+ [key]: value,
+ },
+ });
+ }
+ console.log(
+ 'Updated site data! Revalidating tags: ',
+ `${site.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-metadata`,
+ `${site.customDomain}-metadata`
+ );
+ await revalidateTag(
+ `${site.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-metadata`
+ );
+
+ return response;
} catch (error: any) {
+ if (error.code === 'P2002') {
+ return {
+ error: `This ${key} is already taken`,
+ };
+ } else {
return {
- error: error.message,
+ error: error.message,
};
+ }
}
+ }
+);
+
+export const deleteSite = withSiteAuth(async (_: FormData, site: Site) => {
+ try {
+ const response = await prisma.site.delete({
+ where: {
+ id: site.id,
+ },
+ });
+ await revalidateTag(
+ `${site.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-metadata`
+ );
+
+ return response;
+ } catch (error: any) {
+ return {
+ error: error.message,
+ };
+ }
});
export const getSiteFromPostId = async (postId: string) => {
- const post = await prisma.blog.findUnique({
- where: {
- id: postId,
- },
- select: {
- siteId: true,
- },
- });
- return post?.siteId;
+ const post = await prisma.blog.findUnique({
+ where: {
+ id: postId,
+ },
+ select: {
+ siteId: true,
+ },
+ });
+ return post?.siteId;
};
export const createPost = withSiteAuth(async (_: FormData, site: Site) => {
- const UserId = auth();
- if (!UserId?.userId) {
- return {
- error: "Not authenticated",
- };
- }
- const response = await prisma.blog.create({
- data: {
- siteId: site.id,
- userId: UserId?.userId,
- },
- });
+ const UserId = auth();
+ if (!UserId?.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const response = await prisma.blog.create({
+ data: {
+ siteId: site.id,
+ userId: UserId?.userId,
+ },
+ });
- await revalidateTag(
- `${site.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-posts`,
- );
- site.customDomain && (await revalidateTag(`${site.customDomain}-posts`));
+ await revalidateTag(
+ `${site.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-posts`
+ );
- return response;
+ return response;
});
// creating a separate function for this because we're not using FormData
export const updatePost = async (data: Blog) => {
- const UserId = auth();
- if (!UserId?.userId) {
- return {
- error: "Not authenticated",
- };
- }
- const post = await prisma.blog.findUnique({
- where: {
- id: data.id,
- },
- include: {
- site: true,
- },
+ const UserId = auth();
+ if (!UserId?.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const post = await prisma.blog.findUnique({
+ where: {
+ id: data.id,
+ },
+ include: {
+ site: true,
+ },
+ });
+ if (!post || post.userId !== UserId.userId) {
+ return {
+ error: 'Post not found',
+ };
+ }
+ try {
+ const response = await prisma.blog.update({
+ where: {
+ id: data.id,
+ },
+ data: {
+ title: data.title,
+ description: data.description,
+ content: data.content,
+ },
});
- if (!post || post.userId !== UserId.userId) {
- return {
- error: "Post not found",
- };
- }
- try {
- const response = await prisma.blog.update({
- where: {
- id: data.id,
- },
- data: {
- title: data.title,
- description: data.description,
- content: data.content,
- },
- });
- await revalidateTag(
- `${post.site?.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-posts`,
- );
- await revalidateTag(
- `${post.site?.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-${post.slug}`,
- );
+ await revalidateTag(
+ `${post.site?.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-posts`
+ );
+ await revalidateTag(
+ `${post.site?.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-${post.slug}`
+ );
- // if the site has a custom domain, we need to revalidate those tags too
- post.site?.customDomain &&
- (await revalidateTag(`${post.site?.customDomain}-posts`),
- await revalidateTag(`${post.site?.customDomain}-${post.slug}`));
+ // if the site has a custom domain, we need to revalidate those tags too
- return response;
- } catch (error: any) {
- return {
- error: error.message,
- };
- }
+ return response;
+ } catch (error: any) {
+ return {
+ error: error.message,
+ };
+ }
};
export const updatePostMetadata = withBlogAuth(
- async (
- formData: FormData,
- blog: Blog & {
- site: Site;
- },
- key: string,
- ) => {
- const value = formData.get(key) as string;
-
- try {
- let response;
- if (key === "image") {
- const file = formData.get("image") as File;
- const filename = `${nanoid(7)}.${file.type.split("/")[1]}`;
-
- const res = await utapi.uploadFiles(file, {
- metadata: {
- title: blog.title,
- description: blog.description
- }
- })
- // const { url, } = await put(filename, file, {
- // access: "public",
- // });
-
- if (res.error) {
- return {
- error: res.error
- }
- }
-
- const blurhash = await getBlurDataURL(res.data.url);
-
- response = await prisma.blog.update({
- where: {
- id: blog.id,
- },
- data: {
- image: res.data.url,
- imageBlurhash: blurhash,
- },
- });
- } else {
- response = await prisma.blog.update({
- where: {
- id: blog.id,
- },
- data: {
- [key]: key === "published" ? value === "true" : value,
- },
- });
- }
-
- await revalidateTag(
- `${blog.site?.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-posts`,
- );
- await revalidateTag(
- `${blog.site?.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-${blog.slug}`,
- );
-
- // if the site has a custom domain, we need to revalidate those tags too
- blog.site?.customDomain &&
- (await revalidateTag(`${blog.site?.customDomain}-posts`),
- await revalidateTag(`${blog.site?.customDomain}-${blog.slug}`));
-
- return response;
- } catch (error: any) {
- if (error.code === "P2002") {
- return {
- error: `This slug is already in use`,
- };
- } else {
- return {
- error: error.message,
- };
- }
- }
+ async (
+ formData: FormData,
+ blog: Blog & {
+ site: Site;
},
-);
+ key: string
+ ) => {
+ const value = formData.get(key) as string;
-export const deletePost = withBlogAuth(async (_: FormData, blog: Blog) => {
try {
- const response = await prisma.blog.delete({
- where: {
- id: blog.id,
- },
- select: {
- siteId: true,
- },
+ let response;
+ if (key === 'image') {
+ const file = formData.get('image') as File;
+ const filename = `${nanoid(7)}.${file.type.split('/')[1]}`;
+
+ const res = await utapi.uploadFiles(file, {
+ metadata: {
+ title: blog.title,
+ description: blog.description,
+ },
});
- return response;
+ // const { url, } = await put(filename, file, {
+ // access: "public",
+ // });
+
+ if (res.error) {
+ return {
+ error: res.error,
+ };
+ }
+
+ const blurhash = await getBlurDataURL(res.data.url);
+
+ response = await prisma.blog.update({
+ where: {
+ id: blog.id,
+ },
+ data: {
+ image: res.data.url,
+ imageBlurhash: blurhash,
+ },
+ });
+ } else {
+ response = await prisma.blog.update({
+ where: {
+ id: blog.id,
+ },
+ data: {
+ [key]: key === 'published' ? value === 'true' : value,
+ },
+ });
+ }
+
+ await revalidateTag(
+ `${blog.site?.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-posts`
+ );
+ await revalidateTag(
+ `${blog.site?.subdomain}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}-${blog.slug}`
+ );
+
+ // if the site has a custom domain, we need to revalidate those tags too
+
+ return response;
} catch (error: any) {
+ if (error.code === 'P2002') {
+ return {
+ error: 'This slug is already in use',
+ };
+ } else {
return {
- error: error.message,
+ error: error.message,
};
+ }
}
+ }
+);
+
+export const deletePost = withBlogAuth(async (_: FormData, blog: Blog) => {
+ try {
+ const response = await prisma.blog.delete({
+ where: {
+ id: blog.id,
+ },
+ select: {
+ siteId: true,
+ },
+ });
+ return response;
+ } catch (error: any) {
+ return {
+ error: error.message,
+ };
+ }
});
export const editUser = async (
- formData: FormData,
- _id: unknown,
- key: string,
+ formData: FormData,
+ _id: unknown,
+ key: string
) => {
- const UserId = auth();
- if (!UserId?.userId) {
+ const UserId = auth();
+ if (!UserId?.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const value = formData.get(key) as string;
+
+ try {
+ let response;
+
+ if (key === 'avatar') {
+ if (!process.env.UPLOADTHING_SECRET) {
return {
- error: "Not authenticated",
+ error: 'Missing UPLOADTHING_SECRET token.',
};
- }
- const value = formData.get(key) as string;
-
- try {
- let response;
-
- if (key === "avatar") {
- if (!process.env.UPLOADTHING_SECRET) {
- return {
- error:
- "Missing UPLOADTHING_SECRET token.",
- };
- }
- const file = formData.get(key) as File;
- const filename = `${nanoid(7)}.${file.type.split("/")[1]}`;
-
-
- const res = await utapi.uploadFiles(file)
-
- if (res.error) {
- return {
- error: res.error
- }
- }
-
- // const { url } = await put(filename, file, {
- // access: "public",
- // });
-
- // const blurhash = await getBlurDataURL(url);
-
- response = await prisma.user.update({
- where: {
- id: UserId.userId,
- },
- data: {
- avatar: res.data.url,
- },
- });
- } else {
- response = await prisma.user.update({
- where: {
- id: UserId.userId,
- },
- data: {
- [key]: value,
- },
- });
- }
- return response;
- } catch (error: any) {
- if (error.code === "P2002") {
- return {
- error: `This ${key} is already in use`,
- };
- } else {
- return {
- error: error.message,
- };
- }
- }
-};
-
-
-export const updateAboutSite = async (about: string, id: string) => {
+ }
+ const file = formData.get(key) as File;
+ const filename = `${nanoid(7)}.${file.type.split('/')[1]}`;
+ const res = await utapi.uploadFiles(file);
- const session = auth()
- if (!session.userId) {
+ if (res.error) {
return {
- error: "Not authenticated",
+ error: res.error,
};
- }
+ }
- try {
- const response = await prisma.site.update({
- where: {
- id: id,
- },
- data: {
- about: about,
- },
- });
+ // const { url } = await put(filename, file, {
+ // access: "public",
+ // });
- return response;
- } catch (error: any) {
- return {
- error: error.message,
- };
- }
-}
+ // const blurhash = await getBlurDataURL(url);
-
-export const addEducation = async (formData: FormData, key: string, slug: string) => {
- const session = auth();
- if (!session.userId) {
- return {
- error: "Not authenticated",
- };
+ response = await prisma.user.update({
+ where: {
+ id: UserId.userId,
+ },
+ data: {
+ avatar: res.data.url,
+ },
+ });
+ } else {
+ response = await prisma.user.update({
+ where: {
+ id: UserId.userId,
+ },
+ data: {
+ [key]: value,
+ },
+ });
}
- const school_name = formData.get("school_name") as string;
- const school_location = formData.get("school_location") as string;
- const school_degree = formData.get("school_degree") as string;
- const school_major = formData.get("school_major") as string;
- const school_start_date = formData.get("school_start_date") as string;
- const school_end_date = formData.get("school_end_date") as string;
- const education_note = formData.get("education_note") as string;
-
- try {
- let response;
- response = await prisma.userEducation.create({
- data: {
- user_id: session.userId,
- school_name,
- school_location,
- school_degree,
- school_major,
- school_start_date: new Date(school_start_date),
- school_end_date: new Date(school_end_date),
- education_note,
- site: {
- connect: {
- id: slug
- }
- }
- },
- });
- return response;
- } catch (error: any) {
- if (error.code === "P2002") {
- return {
- error: `something happend unexpected 😢`,
- };
- } else {
- return {
- error: error.message,
- };
- }
+ return response;
+ } catch (error: any) {
+ if (error.code === 'P2002') {
+ return {
+ error: `This ${key} is already in use`,
+ };
+ } else {
+ return {
+ error: error.message,
+ };
}
+ }
+};
+export const updateAboutSite = async (about: string, id: string) => {
+ const session = auth();
+ if (!session.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+
+ try {
+ const response = await prisma.site.update({
+ where: {
+ id: id,
+ },
+ data: {
+ about: about,
+ },
+ });
+ return response;
+ } catch (error: any) {
+ return {
+ error: error.message,
+ };
+ }
+};
-}
-
+export const addEducation = async (
+ formData: FormData,
+ key: string,
+ slug: string
+) => {
+ const session = auth();
+ if (!session.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const school_name = formData.get('school_name') as string;
+ const school_location = formData.get('school_location') as string;
+ const school_degree = formData.get('school_degree') as string;
+ const school_major = formData.get('school_major') as string;
+ const school_start_date = formData.get('school_start_date') as string;
+ const school_end_date = formData.get('school_end_date') as string;
+ const education_note = formData.get('education_note') as string;
+
+ try {
+ let response;
+ response = await prisma.userEducation.create({
+ data: {
+ user_id: session.userId,
+ school_name,
+ school_location,
+ school_degree,
+ school_major,
+ school_start_date: new Date(school_start_date),
+ school_end_date: new Date(school_end_date),
+ education_note,
+ site: {
+ connect: {
+ id: slug,
+ },
+ },
+ },
+ });
+ return response;
+ } catch (error: any) {
+ if (error.code === 'P2002') {
+ return {
+ error: 'something happend unexpected 😢',
+ };
+ } else {
+ return {
+ error: error.message,
+ };
+ }
+ }
+};
-export const updateEducation = withEducationAuth(async (education: UserEducation, key: string, formdata: FormData) => {
+export const updateEducation = withEducationAuth(
+ async (education: UserEducation, key: string, formdata: FormData) => {
try {
- const response = await prisma.userEducation.update({
- where: {
- id: education.id,
- },
- data: {
- school_degree: formdata.get("school_degree") as string,
- school_major: formdata.get("school_major") as string,
- school_name: formdata.get("school_name") as string,
- school_location: formdata.get("school_location") as string,
- school_start_date: new Date(formdata.get("school_start_date") as string),
- school_end_date: new Date(formdata.get("school_end_date") as string),
- education_note: formdata.get("education_note") as string,
-
- },
- });
- return response;
+ const response = await prisma.userEducation.update({
+ where: {
+ id: education.id,
+ },
+ data: {
+ school_degree: formdata.get('school_degree') as string,
+ school_major: formdata.get('school_major') as string,
+ school_name: formdata.get('school_name') as string,
+ school_location: formdata.get('school_location') as string,
+ school_start_date: new Date(
+ formdata.get('school_start_date') as string
+ ),
+ school_end_date: new Date(formdata.get('school_end_date') as string),
+ education_note: formdata.get('education_note') as string,
+ },
+ });
+ return response;
} catch (error: any) {
- return {
- error: error.message,
- };
+ return {
+ error: error.message,
+ };
}
-});
-
+ }
+);
-export const deleteEducation = withEducationAuth(async (education: UserEducation) => {
+export const deleteEducation = withEducationAuth(
+ async (education: UserEducation) => {
try {
- const response = await prisma.userEducation.delete({
- where: {
- id: education.id,
- },
- select: {
- siteId: true,
- },
- });
- return response;
+ const response = await prisma.userEducation.delete({
+ where: {
+ id: education.id,
+ },
+ select: {
+ siteId: true,
+ },
+ });
+ return response;
} catch (error: any) {
- return {
- error: error.message,
- };
+ return {
+ error: error.message,
+ };
}
-});
-
-
-
-
-export const addWorkExperience = async (formData: FormData, key: string, slug: string) => {
- const session = auth();
- if (!session.userId) {
- return {
- error: "Not authenticated",
- };
- }
- const company_name = formData.get("company_name") as string;
- const company_location = formData.get("company_location") as string;
- const employment_position = formData.get("employment_position") as string;
- const employment_start_date = formData.get("employment_start_date") as string;
- const employment_end_date = formData.get("employment_end_date") as string; // string | ""
- const employment_type = formData.get("employment_type") as string;
- const description = formData.get("description") as string;
+ }
+);
- try {
- let response;
- response = await prisma.userWorkExperience.create({
- data: {
- user_id: session.userId,
- company_name,
- company_location,
- employment_position,
- employment_start_date: new Date(employment_start_date),
- // check ig employement_end_data is null then give it null
- employment_end_date: employment_end_date === "" ? null : new Date(employment_end_date),
- still_working: employment_end_date === "" ? true : false,
- descriptions: description || null,
- employment_type,
- site: {
- connect: {
- id: slug
- }
- }
- },
- });
- return response;
- } catch (error: any) {
- if (error.code === "P2002") {
- return {
- error: `something happend unexpected 😢`,
- };
- } else {
- return {
- error: error.message,
- };
- }
+export const addWorkExperience = async (
+ formData: FormData,
+ key: string,
+ slug: string
+) => {
+ const session = auth();
+ if (!session.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const company_name = formData.get('company_name') as string;
+ const company_location = formData.get('company_location') as string;
+ const employment_position = formData.get('employment_position') as string;
+ const employment_start_date = formData.get('employment_start_date') as string;
+ const employment_end_date = formData.get('employment_end_date') as string; // string | ""
+ const employment_type = formData.get('employment_type') as string;
+ const description = formData.get('description') as string;
+
+ try {
+ let response;
+ response = await prisma.userWorkExperience.create({
+ data: {
+ user_id: session.userId,
+ company_name,
+ company_location,
+ employment_position,
+ employment_start_date: new Date(employment_start_date),
+ // check ig employement_end_data is null then give it null
+ employment_end_date:
+ employment_end_date === '' ? null : new Date(employment_end_date),
+ still_working: employment_end_date === '' ? true : false,
+ descriptions: description || null,
+ employment_type,
+ site: {
+ connect: {
+ id: slug,
+ },
+ },
+ },
+ });
+ return response;
+ } catch (error: any) {
+ if (error.code === 'P2002') {
+ return {
+ error: 'something happend unexpected 😢',
+ };
+ } else {
+ return {
+ error: error.message,
+ };
}
+ }
};
-
-
-export const updateWorkExperience = withWorkAuth(async (work: any, key: string, formdata: FormData) => {
+export const updateWorkExperience = withWorkAuth(
+ async (work: any, key: string, formdata: FormData) => {
try {
- const response = await prisma.userWorkExperience.update({
- where: {
- id: work.id,
- },
- data: {
- company_name: formdata.get("company_name") as string,
- company_location: formdata.get("company_location") as string,
- employment_position: formdata.get("employment_position") as string,
- employment_start_date: new Date(formdata.get("employment_start_date") as string),
- employment_end_date:
- !formdata.get("employment_end_date") ? null : new Date(formdata.get("employment_end_date") as string),
- still_working: !formdata.get("employment_end_date") ? true : false,
- descriptions: formdata.get("description") as string,
- employment_type: formdata.get("employment_type") as string,
- },
- });
- return response;
+ const response = await prisma.userWorkExperience.update({
+ where: {
+ id: work.id,
+ },
+ data: {
+ company_name: formdata.get('company_name') as string,
+ company_location: formdata.get('company_location') as string,
+ employment_position: formdata.get('employment_position') as string,
+ employment_start_date: new Date(
+ formdata.get('employment_start_date') as string
+ ),
+ employment_end_date: !formdata.get('employment_end_date')
+ ? null
+ : new Date(formdata.get('employment_end_date') as string),
+ still_working: !formdata.get('employment_end_date') ? true : false,
+ descriptions: formdata.get('description') as string,
+ employment_type: formdata.get('employment_type') as string,
+ },
+ });
+ return response;
} catch (error: any) {
- return {
- error: error.message,
- };
+ return {
+ error: error.message,
+ };
}
-});
-
-
+ }
+);
export const deleteWorkExperience = withWorkAuth(async (work: any) => {
- try {
- const response = await prisma.userWorkExperience.delete({
- where: {
- id: work.id,
- },
- select: {
- siteId: true,
- },
- });
- return response;
- } catch (error: any) {
- return {
- error: error.message,
- };
- }
+ try {
+ const response = await prisma.userWorkExperience.delete({
+ where: {
+ id: work.id,
+ },
+ select: {
+ siteId: true,
+ },
+ });
+ return response;
+ } catch (error: any) {
+ return {
+ error: error.message,
+ };
+ }
});
-
-
-
-export const updateSiteTechStack = withSiteAuth(async (formData: FormData, slug: Site, Key: string) => {
+export const updateSiteTechStack = withSiteAuth(
+ async (formData: FormData, slug: Site, Key: string) => {
const session = auth();
if (!session.userId) {
- return {
- error: "Not authenticated",
- };
+ return {
+ error: 'Not authenticated',
+ };
}
- const techstacks = formData.getAll("techstack") as string[];
+ const techstacks = formData.getAll('techstack') as string[];
try {
- let response;
- if (techstacks.length === 0) {
- console.log("deleting all techstacks for site", slug.id)
- return prisma.siteTechStack.deleteMany({
- where: {
- siteId: slug.id
- }
- })
- }
-
+ let response;
+ if (techstacks.length === 0) {
+ console.log('deleting all techstacks for site', slug.id);
+ return prisma.siteTechStack.deleteMany({
+ where: {
+ siteId: slug.id,
+ },
+ });
+ }
+
+ const alltechstack = await prisma.techStack.findMany();
+ const alltechstackids = alltechstack.map((tech) => tech.id.toString());
+ const toDelete = alltechstackids.filter(
+ (tech) => !techstacks.includes(tech)
+ );
+ const toAdd = techstacks.filter((tech) => alltechstackids.includes(tech));
+ response = await Promise.all([
+ prisma.siteTechStack.deleteMany({
+ where: {
+ siteId: slug.id,
+ techStackId: {
+ in: toDelete.map((id) => Number(id)),
+ },
+ },
+ }),
- const alltechstack = await prisma.techStack.findMany()
- const alltechstackids = alltechstack.map((tech) => tech.id.toString())
- const toDelete = alltechstackids.filter((tech) => !techstacks.includes(tech))
- const toAdd = techstacks.filter((tech) => alltechstackids.includes(tech))
- response = await Promise.all([
- prisma.siteTechStack.deleteMany({
- where: {
- siteId: slug.id,
- techStackId: {
- in: toDelete.map((id) => Number(id))
- }
- }
- }),
-
- toAdd.map(async (tech) => {
- return prisma.siteTechStack.upsert({
- where: {
- siteId_techStackId: {
- siteId: slug.id,
- techStackId: Number(tech),
- },
- },
- create: {
- siteId: slug.id,
- techStackId: Number(tech),
- },
- update: {
- siteId: slug.id,
- techStackId: Number(tech),
- },
- })
- }),
- ])
- return response;
+ toAdd.map(async (tech) => {
+ return prisma.siteTechStack.upsert({
+ where: {
+ siteId_techStackId: {
+ siteId: slug.id,
+ techStackId: Number(tech),
+ },
+ },
+ create: {
+ siteId: slug.id,
+ techStackId: Number(tech),
+ },
+ update: {
+ siteId: slug.id,
+ techStackId: Number(tech),
+ },
+ });
+ }),
+ ]);
+ return response;
} catch (error: any) {
- return {
- error: error.message,
- };
+ return {
+ error: error.message,
+ };
}
-})
+ }
+);
diff --git a/lib/analytics.ts b/lib/analytics.ts
index 29c260d..bcc089c 100644
--- a/lib/analytics.ts
+++ b/lib/analytics.ts
@@ -1,425 +1,436 @@
-
-import prisma from "@/lib/db";
-
+import prisma from '@/lib/db';
type AnalyticsArgs = {
- os?: string,
- browser?: string,
- device?: string,
- location?: string,
- siteId?: string,
- blogId?: string,
- path: string
-}
-
+ os?: string;
+ browser?: string;
+ device?: string;
+ location?: string;
+ siteId?: string;
+ blogId?: string;
+ path: string;
+};
type getAnalyticsArgs = {
- type: "allsites" | "allblogs" | "site" | "blog",
- siteId?: string,
- blogId?: string,
- userId?: string,
- nDays: number | 30
-}
-
-export const TrackAnalytics = async (namespace: "sites" | "blog" | "other", event: AnalyticsArgs) => {
-
- try {
- const response = await prisma.analytics.create({
- data: {
- type: namespace,
- os: event.os,
- browser: event.browser,
- device: event.device,
- location: event.location,
- path: event.path,
- siteId: event.siteId || null,
- blogId: event.blogId || null,
- }
- })
- if (event.siteId) {
- await prisma.site.update({
- where: {
- id: event.siteId
- },
- data: {
- totalviews: {
- increment: 1
- }
- }
- })
- }
-
- if (event.blogId) {
- await prisma.blog.update({
- where: {
- id: event.blogId
- },
- data: {
- totalviews: {
- increment: 1
- }
- }
- })
- }
- return response
- } catch (error) {
- console.log(error)
+ type: 'allsites' | 'allblogs' | 'site' | 'blog';
+ siteId?: string;
+ blogId?: string;
+ userId?: string;
+ nDays: number | 30;
+};
+
+export const TrackAnalytics = async (
+ namespace: 'sites' | 'blog' | 'other',
+ event: AnalyticsArgs
+) => {
+ try {
+ const response = await prisma.analytics.create({
+ data: {
+ type: namespace,
+ os: event.os,
+ browser: event.browser,
+ device: event.device,
+ location: event.location,
+ path: event.path,
+ siteId: event.siteId || null,
+ blogId: event.blogId || null,
+ },
+ });
+ if (event.siteId) {
+ await prisma.site.update({
+ where: {
+ id: event.siteId,
+ },
+ data: {
+ totalviews: {
+ increment: 1,
+ },
+ },
+ });
}
-}
-
-
-export const getSitesAnalytics = async (siteid: string, nDays: number): Promise<{
- analytics: {
- date: string,
- views: number
- }[],
- totalviews: number,
- weekviews: number,
- avgviews: number,
- weekavgviews: number,
- monthviews: number,
- monthavgviews: number
-}> => {
- try {
- const response = await prisma.analytics.findMany({
- where: {
- type: "sites",
- siteId: siteid,
- created_at: {
- gte: new Date(new Date().setDate(new Date().getDate() - nDays))
- },
- },
- orderBy: {
- created_at: "asc"
- }
- })
-
- let data: { date: string, views: number }[] = []
-
- for (let i = nDays - 1; i > 1; i--) {
- let date = new Date(new Date().setDate(new Date().getDate() - i)).toLocaleDateString()
- let index = data.findIndex(d => d.date === date)
- if (index === -1) {
- data.push({ date, views: 0 })
- }
- }
- response.reduce((acc: { date: string, views: number }[], curr) => {
- let date = new Date(curr.created_at).toLocaleDateString()
-
- let index = acc.findIndex(d => d.date === date)
- if (index !== -1) {
- acc[index].views += 1
- } else {
- acc.push({ date, views: 1 })
- }
- return acc
- }, data)
-
- let totalviews = 0
- let weekviews = 0
- let monthviews = 0
- let weekavgviews = 0
- let monthavgviews = 0
- let avgviews = 0
- let week = 0
- let month = 0
-
- data.forEach(d => {
- totalviews += d.views
- if (week < 7) {
- weekviews = weekviews + d.views
- }
- if (month < 30) {
- monthviews += d.views
- month += 1
- }
- })
- const daysInMonth = new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).getDate();
- avgviews = totalviews / data.length;
-
- weekavgviews = parseFloat((weekviews / 7).toFixed(2));
- monthavgviews = parseFloat((monthviews / daysInMonth).toFixed(2));
- return { analytics: data, totalviews, weekviews, avgviews, weekavgviews, monthviews, monthavgviews }
-
-
- // return data;
- } catch (error) {
- console.log(error)
- return {
- analytics: [],
- totalviews: 0,
- weekviews: 0,
- avgviews: 0,
- weekavgviews: 0,
- monthviews: 0,
- monthavgviews: 0
- }
- }
-}
-
-
-
-export const getSiteBlogAnalytics = async (siteid: string) => {
-
-
- try {
-
- // get all the blogs of with that siteid
- let blogs = await prisma.blog.findMany({
- where: {
- siteId: siteid,
- published: true
- },
- orderBy: {
- totalviews: "desc"
- }
- })
-
- let data: { name: string, value: number }[] = []
-
- blogs.forEach(blog => {
- data.push({ name: blog.title || blog.slug, value: blog.totalviews })
- })
-
-
- return data;
-
- } catch (error) {
- console.log(error)
-
- return [{ name: "No Blogs", value: 0 }]
+ if (event.blogId) {
+ await prisma.blog.update({
+ where: {
+ id: event.blogId,
+ },
+ data: {
+ totalviews: {
+ increment: 1,
+ },
+ },
+ });
}
-}
-
-
-export const getBlogsAnalytics = async (blogid: string, nDays: number): Promise<{
- analytics: {
- date: string,
- hits: string
- }[],
- totalviews: number,
- weekviews: number,
- avgviews: number,
- weekavgviews: number,
- monthviews: number,
- monthavgviews: number
+ return response;
+ } catch (error) {
+ console.log(error);
+ }
+};
+
+export const getSitesAnalytics = async (
+ siteid: string,
+ nDays: number
+): Promise<{
+ analytics: {
+ date: string;
+ views: number;
+ }[];
+ totalviews: number;
+ weekviews: number;
+ avgviews: number;
+ weekavgviews: number;
+ monthviews: number;
+ monthavgviews: number;
}> => {
- try {
- const response = await prisma.analytics.findMany({
- where: {
- type: "blog",
- blogId: blogid,
- created_at: {
- gte: new Date(new Date().setDate(new Date().getDate() - nDays))
- },
- },
- orderBy: {
- created_at: "desc"
- }
- })
-
-
- let data: { date: string, hits: number }[] = []
- response.reduce((acc: { date: string, hits: number }[], curr) => {
- let date = new Date(curr.created_at).toLocaleDateString()
- let index = acc.findIndex(d => d.date === date)
- if (index !== -1) {
- acc[index].hits += 1
- } else {
- acc.push({ date, hits: 1 })
- }
- return acc
- }, data)
-
- // convert hits from number to strings
-
- let newdata = data.map(d => {
- return {
- date: d.date,
- hits: d.hits.toString()
- }
- })
-
- let totalviews = 0
- let weekviews = 0
- let monthviews = 0
- let weekavgviews = 0
- let monthavgviews = 0
- let avgviews = 0
- let week = 0
- let month = 0
- data.forEach(d => {
- totalviews += d.hits
- if (week < 7) {
- weekviews += d.hits
- week += 1
- }
- if (month < 30) {
- monthviews += d.hits
- month += 1
- }
- })
- const daysInMonth = new Date(new Date().getFullYear(), new Date().
- getMonth() + 1, 0).getDate()
- avgviews = totalviews / data.length
- weekavgviews = weekviews / 7
- monthavgviews = monthviews / daysInMonth
-
-
- return { analytics: newdata, totalviews, weekviews, avgviews, weekavgviews, monthviews, monthavgviews }
-
- } catch (error) {
- console.log(error)
- return {
- analytics: [],
- totalviews: 0,
- weekviews: 0,
- avgviews: 0,
- weekavgviews: 0,
- monthviews: 0,
- monthavgviews: 0
- }
+ try {
+ const response = await prisma.analytics.findMany({
+ where: {
+ type: 'sites',
+ siteId: siteid,
+ created_at: {
+ gte: new Date(new Date().setDate(new Date().getDate() - nDays)),
+ },
+ },
+ orderBy: {
+ created_at: 'asc',
+ },
+ });
+
+ let data: { date: string; views: number }[] = [];
+
+ for (let i = nDays - 1; i > 1; i--) {
+ let date = new Date(
+ new Date().setDate(new Date().getDate() - i)
+ ).toLocaleDateString();
+ let index = data.findIndex((d) => d.date === date);
+ if (index === -1) {
+ data.push({ date, views: 0 });
+ }
}
-}
-
-
-
-export const getAnalytics = async (namespace: "sites" | "blog" | "other", event: getAnalyticsArgs) => {
- try {
- const response = await prisma.analytics.findMany({
- where: {
- type: namespace,
- siteId: event.siteId || null,
- blogId: event.blogId || null,
- created_at: {
- gte: new Date(new Date().setDate(new Date().getDate() - event.nDays))
- },
- }
- })
- return response
- } catch (error) {
- console.log(error)
- }
-}
-
+ response.reduce((acc: { date: string; views: number }[], curr) => {
+ let date = new Date(curr.created_at).toLocaleDateString();
+
+ let index = acc.findIndex((d) => d.date === date);
+ if (index !== -1) {
+ acc[index].views += 1;
+ } else {
+ acc.push({ date, views: 1 });
+ }
+ return acc;
+ }, data);
+
+ let totalviews = 0;
+ let weekviews = 0;
+ let monthviews = 0;
+ let weekavgviews = 0;
+ let monthavgviews = 0;
+ let avgviews = 0;
+ let week = 0;
+ let month = 0;
+
+ data.forEach((d) => {
+ totalviews += d.views;
+ if (week < 7) {
+ weekviews = weekviews + d.views;
+ }
+ if (month < 30) {
+ monthviews += d.views;
+ month += 1;
+ }
+ });
+ const daysInMonth = new Date(
+ new Date().getFullYear(),
+ new Date().getMonth() + 1,
+ 0
+ ).getDate();
+ avgviews = totalviews / data.length;
+
+ weekavgviews = parseFloat((weekviews / 7).toFixed(2));
+ monthavgviews = parseFloat((monthviews / daysInMonth).toFixed(2));
+ return {
+ analytics: data,
+ totalviews,
+ weekviews,
+ avgviews,
+ weekavgviews,
+ monthviews,
+ monthavgviews,
+ };
+
+ // return data;
+ } catch (error) {
+ console.log(error);
+ return {
+ analytics: [],
+ totalviews: 0,
+ weekviews: 0,
+ avgviews: 0,
+ weekavgviews: 0,
+ monthviews: 0,
+ monthavgviews: 0,
+ };
+ }
+};
+export const getSiteBlogAnalytics = async (siteid: string) => {
+ try {
+ // get all the blogs of with that siteid
+ let blogs = await prisma.blog.findMany({
+ where: {
+ siteId: siteid,
+ published: true,
+ },
+ orderBy: {
+ totalviews: 'desc',
+ },
+ });
+
+ let data: { name: string; value: number }[] = [];
+
+ blogs.forEach((blog) => {
+ data.push({ name: blog.title || blog.slug, value: blog.totalviews });
+ });
+
+ return data;
+ } catch (error) {
+ console.log(error);
+
+ return [{ name: 'No Blogs', value: 0 }];
+ }
+};
+
+export const getBlogsAnalytics = async (
+ blogid: string,
+ nDays: number
+): Promise<{
+ analytics: {
+ date: string;
+ hits: string;
+ }[];
+ totalviews: number;
+ weekviews: number;
+ avgviews: number;
+ weekavgviews: number;
+ monthviews: number;
+ monthavgviews: number;
+}> => {
+ try {
+ const response = await prisma.analytics.findMany({
+ where: {
+ type: 'blog',
+ blogId: blogid,
+ created_at: {
+ gte: new Date(new Date().setDate(new Date().getDate() - nDays)),
+ },
+ },
+ orderBy: {
+ created_at: 'desc',
+ },
+ });
+
+ let data: { date: string; hits: number }[] = [];
+ response.reduce((acc: { date: string; hits: number }[], curr) => {
+ let date = new Date(curr.created_at).toLocaleDateString();
+ let index = acc.findIndex((d) => d.date === date);
+ if (index !== -1) {
+ acc[index].hits += 1;
+ } else {
+ acc.push({ date, hits: 1 });
+ }
+ return acc;
+ }, data);
+
+ // convert hits from number to strings
+
+ let newdata = data.map((d) => {
+ return {
+ date: d.date,
+ hits: d.hits.toString(),
+ };
+ });
+
+ let totalviews = 0;
+ let weekviews = 0;
+ let monthviews = 0;
+ let weekavgviews = 0;
+ let monthavgviews = 0;
+ let avgviews = 0;
+ let week = 0;
+ let month = 0;
+ data.forEach((d) => {
+ totalviews += d.hits;
+ if (week < 7) {
+ weekviews += d.hits;
+ week += 1;
+ }
+ if (month < 30) {
+ monthviews += d.hits;
+ month += 1;
+ }
+ });
+ const daysInMonth = new Date(
+ new Date().getFullYear(),
+ new Date().getMonth() + 1,
+ 0
+ ).getDate();
+ avgviews = totalviews / data.length;
+ weekavgviews = weekviews / 7;
+ monthavgviews = monthviews / daysInMonth;
+
+ return {
+ analytics: newdata,
+ totalviews,
+ weekviews,
+ avgviews,
+ weekavgviews,
+ monthviews,
+ monthavgviews,
+ };
+ } catch (error) {
+ console.log(error);
+ return {
+ analytics: [],
+ totalviews: 0,
+ weekviews: 0,
+ avgviews: 0,
+ weekavgviews: 0,
+ monthviews: 0,
+ monthavgviews: 0,
+ };
+ }
+};
+
+export const getAnalytics = async (
+ namespace: 'sites' | 'blog' | 'other',
+ event: getAnalyticsArgs
+) => {
+ try {
+ const response = await prisma.analytics.findMany({
+ where: {
+ type: namespace,
+ siteId: event.siteId || null,
+ blogId: event.blogId || null,
+ created_at: {
+ gte: new Date(new Date().setDate(new Date().getDate() - event.nDays)),
+ },
+ },
+ });
+ return response;
+ } catch (error) {
+ console.log(error);
+ }
+};
export const getSiteUserAgentAnalytics = async (siteid: string) => {
- try {
- const response = await prisma.analytics.findMany({
- where: {
- type: "sites",
- siteId: siteid,
- created_at: {
- gte: new Date(new Date().setDate(new Date().getDate() - 30))
- },
- }
- })
-
- let osdata: {
- name: string,
- value: number
- }[] = []
-
-
- let browserdata: {
- name: string,
- value: number
- }[] = []
-
-
- let devicedata: {
- name: string,
- value: number
- }[] = []
-
- response.reduce((acc: { name: string, value: number, }[], curr) => {
- if (curr.os === null) return acc;
- let tempname: string;
- if (curr.os?.toLowerCase().includes("windows")) {
- tempname = "🪟 Windows"
- } else if (curr.os?.toLowerCase().includes("android")) {
- tempname = "🔋 Android"
- } else if (curr.os?.toLowerCase().includes("linux")) {
- tempname = "🐧 Linux"
- } else if (curr.os?.toLowerCase().includes("mac")) {
- tempname = "💻 Mac Os"
- } else {
- tempname = "🐘 Other"
- }
- let index = acc.findIndex(d => d.name === (tempname))
- if (index !== -1) {
- acc[index].value += 1
- } else {
- acc.push({
- name: tempname,
- value: 1
- })
- }
- return acc
- }, osdata)
-
-
- response.reduce((acc: { name: string, value: number, }[], curr) => {
- if (curr.browser === null) return acc;
- let tempname: string;
- if (curr.browser?.toLowerCase().includes("chrome")) {
- tempname = "🌎 Chrome"
- } else if (curr.browser?.toLowerCase().includes("edge")) {
- tempname = "📐 Edge"
- } else if (curr.browser?.toLowerCase().includes("firefox")) {
- tempname = "🦊 Firefox"
- } else {
- tempname = "🐘 Other"
- }
-
- let index = acc.findIndex(d => d.name === (tempname))
- if (index !== -1) {
- acc[index].value += 1
- } else {
- acc.push({
- name: tempname,
- value: 1
- })
- }
- return acc
- }, browserdata)
-
-
- response.reduce((acc: { name: string, value: number, }[], curr) => {
- if (curr.device === null) return acc;
- let tempname: string;
- if (curr.device?.toLowerCase().includes("mobile")) {
- tempname = "📱 Mobile"
- } else if (curr.device?.toLowerCase().includes("tablet")) {
- tempname = "📲 Tablet"
- } else {
- tempname = "🖥️ Laptop/Pc"
- }
- let index = acc.findIndex(d => d.name === (tempname))
- if (index !== -1) {
- acc[index].value += 1
- } else {
- acc.push({
- name: tempname,
- value: 1
- })
- }
- return acc
- }, devicedata)
-
- return {
- os: osdata,
- browser: browserdata,
- device: devicedata
- }
- } catch (error) {
- console.log(error)
- return {
- os: [],
- browser: [],
- device: []
- }
- }
-}
\ No newline at end of file
+ try {
+ const response = await prisma.analytics.findMany({
+ where: {
+ type: 'sites',
+ siteId: siteid,
+ created_at: {
+ gte: new Date(new Date().setDate(new Date().getDate() - 30)),
+ },
+ },
+ });
+
+ let osdata: {
+ name: string;
+ value: number;
+ }[] = [];
+
+ let browserdata: {
+ name: string;
+ value: number;
+ }[] = [];
+
+ let devicedata: {
+ name: string;
+ value: number;
+ }[] = [];
+
+ response.reduce((acc: { name: string; value: number }[], curr) => {
+ if (curr.os === null) return acc;
+ let tempname: string;
+ if (curr.os?.toLowerCase().includes('windows')) {
+ tempname = '🪟 Windows';
+ } else if (curr.os?.toLowerCase().includes('android')) {
+ tempname = '🔋 Android';
+ } else if (curr.os?.toLowerCase().includes('linux')) {
+ tempname = '🐧 Linux';
+ } else if (curr.os?.toLowerCase().includes('mac')) {
+ tempname = '💻 Mac Os';
+ } else {
+ tempname = '🐘 Other';
+ }
+ let index = acc.findIndex((d) => d.name === tempname);
+ if (index !== -1) {
+ acc[index].value += 1;
+ } else {
+ acc.push({
+ name: tempname,
+ value: 1,
+ });
+ }
+ return acc;
+ }, osdata);
+
+ response.reduce((acc: { name: string; value: number }[], curr) => {
+ if (curr.browser === null) return acc;
+ let tempname: string;
+ if (curr.browser?.toLowerCase().includes('chrome')) {
+ tempname = '🌎 Chrome';
+ } else if (curr.browser?.toLowerCase().includes('edge')) {
+ tempname = '📐 Edge';
+ } else if (curr.browser?.toLowerCase().includes('firefox')) {
+ tempname = '🦊 Firefox';
+ } else {
+ tempname = '🐘 Other';
+ }
+
+ let index = acc.findIndex((d) => d.name === tempname);
+ if (index !== -1) {
+ acc[index].value += 1;
+ } else {
+ acc.push({
+ name: tempname,
+ value: 1,
+ });
+ }
+ return acc;
+ }, browserdata);
+
+ response.reduce((acc: { name: string; value: number }[], curr) => {
+ if (curr.device === null) return acc;
+ let tempname: string;
+ if (curr.device?.toLowerCase().includes('mobile')) {
+ tempname = '📱 Mobile';
+ } else if (curr.device?.toLowerCase().includes('tablet')) {
+ tempname = '📲 Tablet';
+ } else {
+ tempname = '🖥️ Laptop/Pc';
+ }
+ let index = acc.findIndex((d) => d.name === tempname);
+ if (index !== -1) {
+ acc[index].value += 1;
+ } else {
+ acc.push({
+ name: tempname,
+ value: 1,
+ });
+ }
+ return acc;
+ }, devicedata);
+
+ return {
+ os: osdata,
+ browser: browserdata,
+ device: devicedata,
+ };
+ } catch (error) {
+ console.log(error);
+ return {
+ os: [],
+ browser: [],
+ device: [],
+ };
+ }
+};
diff --git a/lib/auth.ts b/lib/auth.ts
index 6c95540..9181730 100644
--- a/lib/auth.ts
+++ b/lib/auth.ts
@@ -1,186 +1,179 @@
-
-import prisma from "@/lib/db";
-import { auth } from "@clerk/nextjs/server";
+import prisma from '@/lib/db';
+import { auth } from '@clerk/nextjs/server';
export function withSiteAuth(action: any) {
- return async (
- formData: FormData | null,
- siteId: string,
- key: string | null,
- ) => {
- const session = auth();
- if (!session.userId) {
- return {
- error: "Not authenticated",
- };
- }
- const site = await prisma.site.findUnique({
- where: {
- id: siteId,
- },
- });
- if (!site || site.userId !== session.userId) {
- return {
- error: "Not authorized",
- };
- }
-
- return action(formData, site, key);
- };
+ return async (
+ formData: FormData | null,
+ siteId: string,
+ key: string | null
+ ) => {
+ const session = auth();
+ if (!session.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const site = await prisma.site.findUnique({
+ where: {
+ id: siteId,
+ },
+ });
+ if (!site || site.userId !== session.userId) {
+ return {
+ error: 'Not authorized',
+ };
+ }
+
+ return action(formData, site, key);
+ };
}
-
export function withBlogAuth(action: any) {
- return async (
- formData: FormData | null,
- postId: string,
- key: string | null,
- ) => {
- const session = auth();
- if (!session.userId) {
- return {
- error: "Not authenticated",
- };
- }
- const post = await prisma.blog.findUnique({
- where: {
- id: postId,
- },
- include: {
- site: true,
- },
- });
- if (!post || post.userId !== session.userId) {
- return {
- error: "Post not found",
- };
- }
-
- return action(formData, post, key);
- };
+ return async (
+ formData: FormData | null,
+ postId: string,
+ key: string | null
+ ) => {
+ const session = auth();
+ if (!session.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const post = await prisma.blog.findUnique({
+ where: {
+ id: postId,
+ },
+ include: {
+ site: true,
+ },
+ });
+ if (!post || post.userId !== session.userId) {
+ return {
+ error: 'Post not found',
+ };
+ }
+
+ return action(formData, post, key);
+ };
}
-
export function withEducationAuth(action: any) {
- return async (
- postId: number,
- key: string | null,
- formdata: FormData | null
- ) => {
- const session = auth();
- if (!session.userId) {
- return {
- error: "Not authenticated",
- };
- }
- const post = await prisma.userEducation.findUnique({
- where: {
- id: postId,
- },
- include: {
- site: true,
- },
- });
- if (!post || post.user_id !== session.userId) {
- return {
- error: "education not found",
- };
- }
-
- return action(post, key, formdata);
- };
+ return async (
+ postId: number,
+ key: string | null,
+ formdata: FormData | null
+ ) => {
+ const session = auth();
+ if (!session.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const post = await prisma.userEducation.findUnique({
+ where: {
+ id: postId,
+ },
+ include: {
+ site: true,
+ },
+ });
+ if (!post || post.user_id !== session.userId) {
+ return {
+ error: 'education not found',
+ };
+ }
+
+ return action(post, key, formdata);
+ };
}
-
-
export function withWorkAuth(action: any) {
- return async (
- postId: number,
- key: string | null,
- formdata: FormData | null
- ) => {
- const session = auth();
- if (!session.userId) {
- return {
- error: "Not authenticated",
- };
- }
- const post = await prisma.userWorkExperience.findUnique({
- where: {
- id: postId,
- },
- include: {
- site: true,
- },
- });
- if (!post || post.user_id !== session.userId) {
- return {
- error: "work not found",
- };
- }
-
- return action(post, key, formdata);
- };
+ return async (
+ postId: number,
+ key: string | null,
+ formdata: FormData | null
+ ) => {
+ const session = auth();
+ if (!session.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const post = await prisma.userWorkExperience.findUnique({
+ where: {
+ id: postId,
+ },
+ include: {
+ site: true,
+ },
+ });
+ if (!post || post.user_id !== session.userId) {
+ return {
+ error: 'work not found',
+ };
+ }
+
+ return action(post, key, formdata);
+ };
}
-
export function withProjectAuth(action: any) {
- return async (
- postId: number,
- key: string | null,
- formdata: FormData | null
- ) => {
- const session = auth();
- if (!session.userId) {
- return {
- error: "Not authenticated",
- };
- }
- const post = await prisma.projects.findUnique({
- where: {
- id: postId,
- },
- include: {
- site: true,
- },
- });
- if (!post || post.user_id !== session.userId) {
- return {
- error: "project not found",
- };
- }
-
- return action(post, key, formdata);
- };
+ return async (
+ postId: number,
+ key: string | null,
+ formdata: FormData | null
+ ) => {
+ const session = auth();
+ if (!session.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const post = await prisma.projects.findUnique({
+ where: {
+ id: postId,
+ },
+ include: {
+ site: true,
+ },
+ });
+ if (!post || post.user_id !== session.userId) {
+ return {
+ error: 'project not found',
+ };
+ }
+
+ return action(post, key, formdata);
+ };
}
-
export function withCertificateAuth(action: any) {
- return async (
- postId: number,
- key: string | null,
- formdata: FormData | null
- ) => {
- const session = auth();
- if (!session.userId) {
- return {
- error: "Not authenticated",
- };
- }
- const post = await prisma.userCertificate.findUnique({
- where: {
- id: postId,
- },
- include: {
- site: true,
- },
- });
- if (!post || post.user_id !== session.userId) {
- return {
- error: "certificate not found",
- };
- }
-
- return action(post, key, formdata);
- };
-}
\ No newline at end of file
+ return async (
+ postId: number,
+ key: string | null,
+ formdata: FormData | null
+ ) => {
+ const session = auth();
+ if (!session.userId) {
+ return {
+ error: 'Not authenticated',
+ };
+ }
+ const post = await prisma.userCertificate.findUnique({
+ where: {
+ id: postId,
+ },
+ include: {
+ site: true,
+ },
+ });
+ if (!post || post.user_id !== session.userId) {
+ return {
+ error: 'certificate not found',
+ };
+ }
+
+ return action(post, key, formdata);
+ };
+}
diff --git a/lib/contants.ts b/lib/contants.ts
index be9cee5..5fed55f 100644
--- a/lib/contants.ts
+++ b/lib/contants.ts
@@ -1,35 +1,43 @@
-export const APP_NAME = "DevResume.";
-export const APP_DESC = "Craft your developer Portfolio within Few Seconds.";
-export const APP_DASHBOARD_LINK = "/dashboard";
-export const APP_LOGIN_LINK = "/sign-in";
+export const APP_NAME = 'DevResume.';
+export const APP_DESC = 'Craft your developer Portfolio within Few Seconds.';
+export const APP_DASHBOARD_LINK = '/dashboard';
+export const APP_LOGIN_LINK = '/sign-in';
export const APP_CORE_DEVELOPER = [
- {
- id: 1,
- name: "AbhisheK Kushwaha",
- designation: "Full Stack Developer",
- image:
- "https://avatars.githubusercontent.com/u/86338762?v=4",
- },
+ {
+ id: 1,
+ name: 'AbhisheK Kushwaha',
+ designation: 'Full Stack Developer',
+ image: 'https://avatars.githubusercontent.com/u/86338762?v=4',
+ },
];
-
-export const APP_GITHUB_REPO_LINK = "https://github.com/Abbhiishek/dresume";
-export const WORKING_GIRL_UNDER_TREE = "https://illustrations.popsy.co/emerald/digital-nomad.svg"
-export const COUPLE_BUILDING_STUFF = "https://illustrations.popsy.co/emerald/creative-work.svg"
-export const ROCKET_INTO_SPACE = "https://illustrations.popsy.co/emerald/man-riding-a-rocket.svg"
-export const ASTRONAUT_ON_MOON = "https://illustrations.popsy.co/emerald/success.svg"
-export const IDEA_BRAINSTORMING = "https://illustrations.popsy.co/emerald/team-idea.svg"
-export const ENTREPRENEUR_WITH_COMPUTER = "https://illustrations.popsy.co/emerald/idea-launch.svg"
-export const PROUDLY_OPENSOURCED = "https://illustrations.popsy.co/emerald/woman-holding-a-heart.svg"
-export const COMMUNICATION_CONNECT_NETWORK = "https://illustrations.popsy.co/emerald/communication.svg"
-
+export const APP_GITHUB_REPO_LINK = 'https://github.com/Abbhiishek/dresume';
+export const WORKING_GIRL_UNDER_TREE =
+ 'https://illustrations.popsy.co/emerald/digital-nomad.svg';
+export const COUPLE_BUILDING_STUFF =
+ 'https://illustrations.popsy.co/emerald/creative-work.svg';
+export const ROCKET_INTO_SPACE =
+ 'https://illustrations.popsy.co/emerald/man-riding-a-rocket.svg';
+export const ASTRONAUT_ON_MOON =
+ 'https://illustrations.popsy.co/emerald/success.svg';
+export const IDEA_BRAINSTORMING =
+ 'https://illustrations.popsy.co/emerald/team-idea.svg';
+export const ENTREPRENEUR_WITH_COMPUTER =
+ 'https://illustrations.popsy.co/emerald/idea-launch.svg';
+export const PROUDLY_OPENSOURCED =
+ 'https://illustrations.popsy.co/emerald/woman-holding-a-heart.svg';
+export const COMMUNICATION_CONNECT_NETWORK =
+ 'https://illustrations.popsy.co/emerald/communication.svg';
// MAILING LIST
-export const JOIN_MAILING_LIST = "https://illustrations.popsy.co/emerald/paper-plane.svg"
-
+export const JOIN_MAILING_LIST =
+ 'https://illustrations.popsy.co/emerald/paper-plane.svg';
// CTA
-export const START_BUILDING_NOW = "https://illustrations.popsy.co/emerald/achievement.svg"
-export const DEPLOY_IN_SECONDS = "https://illustrations.popsy.co/emerald/surreal-hourglass.svg"
+export const START_BUILDING_NOW =
+ 'https://illustrations.popsy.co/emerald/achievement.svg';
+export const DEPLOY_IN_SECONDS =
+ 'https://illustrations.popsy.co/emerald/surreal-hourglass.svg';
// PRICING
-export const GROW_WITH_FREE_TIER = "https://illustrations.popsy.co/emerald/celebrating-business-success.svg"
+export const GROW_WITH_FREE_TIER =
+ 'https://illustrations.popsy.co/emerald/celebrating-business-success.svg';
diff --git a/lib/db.ts b/lib/db.ts
index c6b0b1b..c8b8cab 100644
--- a/lib/db.ts
+++ b/lib/db.ts
@@ -1,12 +1,11 @@
-
-import { PrismaClient } from "@prisma/client";
+import { PrismaClient } from '@prisma/client';
declare global {
- var prisma: PrismaClient | undefined;
+ var prisma: PrismaClient | undefined;
}
const prisma = global.prisma || new PrismaClient();
-if (process.env.NODE_ENV === "development") global.prisma = prisma;
+if (process.env.NODE_ENV === 'development') global.prisma = prisma;
export default prisma;
diff --git a/lib/domains.ts b/lib/domains.ts
index 93933ee..cf99f35 100644
--- a/lib/domains.ts
+++ b/lib/domains.ts
@@ -1,141 +1,141 @@
import {
- DomainConfigResponse,
- DomainResponse,
- DomainVerificationResponse,
-} from "@/lib/types";
-
+ DomainConfigResponse,
+ DomainResponse,
+ DomainVerificationResponse,
+} from '@/lib/types';
export const addDomainToVercel = async (domain: string) => {
- return await fetch(
- `https://api.vercel.com/v10/projects/${process.env.PROJECT_ID_VERCEL
- }/domains${process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ""
- }`,
- {
- method: "POST",
- headers: {
- Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
- "Content-Type": "application/json",
- },
- body: JSON.stringify({
- name: domain,
- // Optional: Redirect www. to root domain
- // ...(domain.startsWith("www.") && {
- // redirect: domain.replace("www.", ""),
- // }),
- }),
- },
- ).then((res) => res.json());
+ return await fetch(
+ `https://api.vercel.com/v10/projects/${
+ process.env.PROJECT_ID_VERCEL
+ }/domains${
+ process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ''
+ }`,
+ {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ name: domain,
+ // Optional: Redirect www. to root domain
+ // ...(domain.startsWith("www.") && {
+ // redirect: domain.replace("www.", ""),
+ // }),
+ }),
+ }
+ ).then((res) => res.json());
};
-
-
export const removeDomainFromVercelProject = async (domain: string) => {
- return await fetch(
- `https://api.vercel.com/v9/projects/${process.env.PROJECT_ID_VERCEL
- }/domains/${domain}${process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ""
- }`,
- {
- headers: {
- Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
- },
- method: "DELETE",
- },
- ).then((res) => res.json());
+ return await fetch(
+ `https://api.vercel.com/v9/projects/${
+ process.env.PROJECT_ID_VERCEL
+ }/domains/${domain}${
+ process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ''
+ }`,
+ {
+ headers: {
+ Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
+ },
+ method: 'DELETE',
+ }
+ ).then((res) => res.json());
};
-
export const removeDomainFromVercelTeam = async (domain: string) => {
- return await fetch(
- `https://api.vercel.com/v6/domains/${domain}${process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ""
- }`,
- {
- headers: {
- Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
- },
- method: "DELETE",
- },
- ).then((res) => res.json());
+ return await fetch(
+ `https://api.vercel.com/v6/domains/${domain}${
+ process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ''
+ }`,
+ {
+ headers: {
+ Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
+ },
+ method: 'DELETE',
+ }
+ ).then((res) => res.json());
};
export const getDomainResponse = async (
- domain: string,
+ domain: string
): Promise => {
- return await fetch(
- `https://api.vercel.com/v9/projects/${process.env.PROJECT_ID_VERCEL
- }/domains/${domain}${process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ""
- }`,
- {
- method: "GET",
- headers: {
- Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
- "Content-Type": "application/json",
- },
- },
- ).then((res) => {
- return res.json();
- });
+ return await fetch(
+ `https://api.vercel.com/v9/projects/${
+ process.env.PROJECT_ID_VERCEL
+ }/domains/${domain}${
+ process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ''
+ }`,
+ {
+ method: 'GET',
+ headers: {
+ Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
+ 'Content-Type': 'application/json',
+ },
+ }
+ ).then((res) => {
+ return res.json();
+ });
};
-
-
export const getConfigResponse = async (
- domain: string,
+ domain: string
): Promise => {
- return await fetch(
- `https://api.vercel.com/v6/domains/${domain}/config${process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ""
- }`,
- {
- method: "GET",
- headers: {
- Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
- "Content-Type": "application/json",
- },
- },
- ).then((res) => res.json());
+ return await fetch(
+ `https://api.vercel.com/v6/domains/${domain}/config${
+ process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ''
+ }`,
+ {
+ method: 'GET',
+ headers: {
+ Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
+ 'Content-Type': 'application/json',
+ },
+ }
+ ).then((res) => res.json());
};
export const verifyDomain = async (
- domain: string,
+ domain: string
): Promise => {
- return await fetch(
- `https://api.vercel.com/v9/projects/${process.env.PROJECT_ID_VERCEL
- }/domains/${domain}/verify${process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ""
- }`,
- {
- method: "POST",
- headers: {
- Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
- "Content-Type": "application/json",
- },
- },
- ).then((res) => res.json());
+ return await fetch(
+ `https://api.vercel.com/v9/projects/${
+ process.env.PROJECT_ID_VERCEL
+ }/domains/${domain}/verify${
+ process.env.TEAM_ID_VERCEL ? `?teamId=${process.env.TEAM_ID_VERCEL}` : ''
+ }`,
+ {
+ method: 'POST',
+ headers: {
+ Authorization: `Bearer ${process.env.AUTH_BEARER_TOKEN}`,
+ 'Content-Type': 'application/json',
+ },
+ }
+ ).then((res) => res.json());
};
-
export const getSubdomain = (name: string, apexName: string) => {
- if (name === apexName) return null;
- return name.slice(0, name.length - apexName.length - 1);
+ if (name === apexName) return null;
+ return name.slice(0, name.length - apexName.length - 1);
};
-
export const getApexDomain = (url: string) => {
- let domain;
- try {
- domain = new URL(url).hostname;
- } catch (e) {
- return "";
- }
- const parts = domain.split(".");
- if (parts.length > 2) {
- // if it's a subdomain (e.g. dub.vercel.app), return the last 2 parts
- return parts.slice(-2).join(".");
- }
- // if it's a normal domain (e.g. dub.sh), we return the domain
- return domain;
+ let domain;
+ try {
+ domain = new URL(url).hostname;
+ } catch (e) {
+ return '';
+ }
+ const parts = domain.split('.');
+ if (parts.length > 2) {
+ // if it's a subdomain (e.g. dub.vercel.app), return the last 2 parts
+ return parts.slice(-2).join('.');
+ }
+ // if it's a normal domain (e.g. dub.sh), we return the domain
+ return domain;
};
export const validDomainRegex = new RegExp(
- /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/,
+ /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/
);
-
-
diff --git a/lib/edgedb.ts b/lib/edgedb.ts
index 1aa7b81..5535d5e 100644
--- a/lib/edgedb.ts
+++ b/lib/edgedb.ts
@@ -1,8 +1,6 @@
-
-import { PrismaClient } from "@prisma/client/edge";
+import { PrismaClient } from '@prisma/client/edge';
import { withAccelerate } from '@prisma/extension-accelerate';
-const prisma = new PrismaClient().$extends(withAccelerate())
-
+const prisma = new PrismaClient().$extends(withAccelerate());
export default prisma;
diff --git a/lib/fetchers.ts b/lib/fetchers.ts
index 86e7947..08a4968 100644
--- a/lib/fetchers.ts
+++ b/lib/fetchers.ts
@@ -1,207 +1,195 @@
-import prisma from "@/lib/db";
-import { replaceExamples, replaceTweets } from "@/lib/remark-plugins";
-import { serialize } from "next-mdx-remote/serialize";
-import { unstable_cache } from "next/cache";
+import prisma from '@/lib/db';
+import { replaceExamples, replaceTweets } from '@/lib/remark-plugins';
+import { serialize } from 'next-mdx-remote/serialize';
+import { unstable_cache } from 'next/cache';
import rehypePrism from 'rehype-prism-plus';
-import rehypeSlug from "rehype-slug";
+import rehypeSlug from 'rehype-slug';
// make a typoe which extend Site and adds external data
export async function getSiteData(domain: string) {
- /**
- * Fetches site data from the database.
- * @returns A promise that resolves to the site data, including user, education, work experience, projects, certificates, blog, and tech stack.
- */
- const subdomain = domain.endsWith(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`)
- ? domain.replace(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`, "")
- : null;
-
- // console.log(subdomain)
-
- return await unstable_cache(
- async () => {
-
- const data = prisma.site.findUnique({
- where: subdomain ? { subdomain } : { customDomain: domain },
- include: {
- user: true,
- education: {
- orderBy: {
- school_start_date: "desc",
- },
- },
- workexperience: {
- orderBy: {
- employment_start_date: "desc",
- },
- },
- projects: true,
- certificates: true,
- Blog: true,
- siteTechStack: true,
- }
- })
- if (!data) return null;
- // const [aboutmdxSource] = await Promise.all([
- // getMdxSource(data.about!),
- // ]);
- return {
- ...data,
- }
+ /**
+ * Fetches site data from the database.
+ * @returns A promise that resolves to the site data, including user, education, work experience, projects, certificates, blog, and tech stack.
+ */
+ const subdomain = domain.endsWith(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`)
+ ? domain.replace(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`, '')
+ : null;
+
+ // console.log(subdomain)
+
+ return await unstable_cache(
+ async () => {
+ const data = prisma.site.findUnique({
+ where: subdomain ? { subdomain } : { customDomain: domain },
+ include: {
+ user: true,
+ education: {
+ orderBy: {
+ school_start_date: 'desc',
+ },
+ },
+ workexperience: {
+ orderBy: {
+ employment_start_date: 'desc',
+ },
+ },
+ projects: true,
+ certificates: true,
+ Blog: true,
+ siteTechStack: true,
},
- [`${domain}-metadata`],
- {
- revalidate: 900,
- tags: [`${domain}-metadata`],
- },
- )();
+ });
+ if (!data) return null;
+ // const [aboutmdxSource] = await Promise.all([
+ // getMdxSource(data.about!),
+ // ]);
+ return {
+ ...data,
+ };
+ },
+ [`${domain}-metadata`],
+ {
+ revalidate: 900,
+ tags: [`${domain}-metadata`],
+ }
+ )();
}
-
export async function getSiteAbout(domain: string) {
-
- const subdomain = domain.endsWith(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`)
- ? domain.replace(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`, "")
- : null;
-
-
- return await unstable_cache(
- async () => {
- const data = await prisma.site.findUnique({
- where: subdomain ? { subdomain } : { customDomain: domain },
- select: {
- about: true
- }
- })
-
- if (!data) return null;
- const [mdxSource] = await Promise.all([
- getMdxSource(data.about!),
- ])
- return {
- ...data,
- mdxSource,
- };
- },
- [`${domain}-about`],
- {
- revalidate: 1,
- tags: [`${domain}-about`],
+ const subdomain = domain.endsWith(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`)
+ ? domain.replace(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`, '')
+ : null;
+
+ return await unstable_cache(
+ async () => {
+ const data = await prisma.site.findUnique({
+ where: subdomain ? { subdomain } : { customDomain: domain },
+ select: {
+ about: true,
},
- )();
+ });
+
+ if (!data) return null;
+ const [mdxSource] = await Promise.all([getMdxSource(data.about!)]);
+ return {
+ ...data,
+ mdxSource,
+ };
+ },
+ [`${domain}-about`],
+ {
+ revalidate: 1,
+ tags: [`${domain}-about`],
+ }
+ )();
}
export async function getBlogsForSite(domain: string) {
- const subdomain = domain.endsWith(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`)
- ? domain.replace(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`, "")
- : null;
-
- return await unstable_cache(
- async () => {
- return prisma.blog.findMany({
- where: {
- site: subdomain ? { subdomain } : { customDomain: domain },
- published: true,
- },
- select: {
- title: true,
- description: true,
- slug: true,
- image: true,
- imageBlurhash: true,
- createdAt: true,
- },
- orderBy: [
- {
- createdAt: "desc",
- },
- ],
- });
+ const subdomain = domain.endsWith(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`)
+ ? domain.replace(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`, '')
+ : null;
+
+ return await unstable_cache(
+ async () => {
+ return prisma.blog.findMany({
+ where: {
+ site: subdomain ? { subdomain } : { customDomain: domain },
+ published: true,
},
- [`${domain}-posts`],
- {
- revalidate: 900,
- tags: [`${domain}-posts`],
+ select: {
+ title: true,
+ description: true,
+ slug: true,
+ image: true,
+ imageBlurhash: true,
+ createdAt: true,
},
- )();
+ orderBy: [
+ {
+ createdAt: 'desc',
+ },
+ ],
+ });
+ },
+ [`${domain}-posts`],
+ {
+ revalidate: 900,
+ tags: [`${domain}-posts`],
+ }
+ )();
}
export async function getBlogData(domain: string, slug: string) {
- const subdomain = domain.endsWith(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`)
- ? domain.replace(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`, "")
- : null;
-
- return await unstable_cache(
- async () => {
- const data = await prisma.blog.findFirst({
- where: {
- site: subdomain ? { subdomain } : { customDomain: domain },
- slug,
- published: true,
- },
- include: {
- site: {
- include: {
- user: true,
- },
- },
- },
- });
-
- if (!data) return null;
-
- const [mdxSource, adjacentPosts] = await Promise.all([
- getMdxSource(data.content!),
- prisma.blog.findMany({
- where: {
- site: subdomain ? { subdomain } : { customDomain: domain },
- published: true,
- NOT: {
- id: data.id,
- },
- },
- select: {
- slug: true,
- title: true,
- createdAt: true,
- description: true,
- image: true,
- imageBlurhash: true,
- },
- }),
- ]);
-
- return {
- ...data,
- mdxSource,
- adjacentPosts,
- };
+ const subdomain = domain.endsWith(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`)
+ ? domain.replace(`.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`, '')
+ : null;
+
+ return await unstable_cache(
+ async () => {
+ const data = await prisma.blog.findFirst({
+ where: {
+ site: subdomain ? { subdomain } : { customDomain: domain },
+ slug,
+ published: true,
},
- [`${domain}-${slug}`],
- {
- revalidate: 900, // 15 minutes
- tags: [`${domain}-${slug}`],
+ include: {
+ site: {
+ include: {
+ user: true,
+ },
+ },
},
- )();
+ });
+
+ if (!data) return null;
+
+ const [mdxSource, adjacentPosts] = await Promise.all([
+ getMdxSource(data.content!),
+ prisma.blog.findMany({
+ where: {
+ site: subdomain ? { subdomain } : { customDomain: domain },
+ published: true,
+ NOT: {
+ id: data.id,
+ },
+ },
+ select: {
+ slug: true,
+ title: true,
+ createdAt: true,
+ description: true,
+ image: true,
+ imageBlurhash: true,
+ },
+ }),
+ ]);
+
+ return {
+ ...data,
+ mdxSource,
+ adjacentPosts,
+ };
+ },
+ [`${domain}-${slug}`],
+ {
+ revalidate: 900, // 15 minutes
+ tags: [`${domain}-${slug}`],
+ }
+ )();
}
-
-
async function getMdxSource(postContents: string) {
- // transforms links like to [link](link) as MDX doesn't support syntax
- // https://mdxjs.com/docs/what-is-mdx/#markdown
- const content =
- postContents?.replaceAll(/<(https?:\/\/\S+)>/g, "[$1]($1)") ?? "";
- // Serialize the content string into MDX
- const mdxSource = await serialize(content, {
- mdxOptions: {
- remarkPlugins: [replaceTweets, () => replaceExamples(prisma)],
- rehypePlugins: [
- [rehypeSlug],
- rehypePrism,
-
- ],
- },
- });
-
- return mdxSource;
+ // transforms links like to [link](link) as MDX doesn't support syntax
+ // https://mdxjs.com/docs/what-is-mdx/#markdown
+ const content =
+ postContents?.replaceAll(/<(https?:\/\/\S+)>/g, '[$1]($1)') ?? '';
+ // Serialize the content string into MDX
+ const mdxSource = await serialize(content, {
+ mdxOptions: {
+ remarkPlugins: [replaceTweets, () => replaceExamples(prisma)],
+ rehypePlugins: [[rehypeSlug], rehypePrism],
+ },
+ });
+
+ return mdxSource;
}
diff --git a/lib/hooks/use-window-size.ts b/lib/hooks/use-window-size.ts
index 491a610..90b8d13 100644
--- a/lib/hooks/use-window-size.ts
+++ b/lib/hooks/use-window-size.ts
@@ -1,38 +1,38 @@
-import { useEffect, useState } from "react";
+import { useEffect, useState } from 'react';
export default function useWindowSize() {
- const [windowSize, setWindowSize] = useState<{
- width: number | undefined;
- height: number | undefined;
- }>({
- width: undefined,
- height: undefined,
- });
+ const [windowSize, setWindowSize] = useState<{
+ width: number | undefined;
+ height: number | undefined;
+ }>({
+ width: undefined,
+ height: undefined,
+ });
- useEffect(() => {
- // Handler to call on window resize
- function handleResize() {
- // Set window width/height to state
- setWindowSize({
- width: window.innerWidth,
- height: window.innerHeight,
- });
- }
+ useEffect(() => {
+ // Handler to call on window resize
+ function handleResize() {
+ // Set window width/height to state
+ setWindowSize({
+ width: window.innerWidth,
+ height: window.innerHeight,
+ });
+ }
- // Add event listener
- window.addEventListener("resize", handleResize);
+ // Add event listener
+ window.addEventListener('resize', handleResize);
- // Call handler right away so state gets updated with initial window size
- handleResize();
+ // Call handler right away so state gets updated with initial window size
+ handleResize();
- // Remove event listener on cleanup
- return () => window.removeEventListener("resize", handleResize);
- }, []); // Empty array ensures that effect is only run on mount
+ // Remove event listener on cleanup
+ return () => window.removeEventListener('resize', handleResize);
+ }, []); // Empty array ensures that effect is only run on mount
- return {
- windowSize,
- isMobile: typeof windowSize?.width === "number" && windowSize?.width < 768,
- isDesktop:
- typeof windowSize?.width === "number" && windowSize?.width >= 768,
- };
+ return {
+ windowSize,
+ isMobile: typeof windowSize?.width === 'number' && windowSize?.width < 768,
+ isDesktop:
+ typeof windowSize?.width === 'number' && windowSize?.width >= 768,
+ };
}
diff --git a/lib/remark-plugins.tsx b/lib/remark-plugins.tsx
index 44dd734..cd817ea 100644
--- a/lib/remark-plugins.tsx
+++ b/lib/remark-plugins.tsx
@@ -1,119 +1,127 @@
/* eslint-disable no-useless-escape */
/* eslint-disable no-async-promise-executor */
-import type { Example, PrismaClient } from "@prisma/client";
-import Link from "next/link";
-import { ReactNode } from "react";
-import { visit } from "unist-util-visit";
+import type { Example, PrismaClient } from '@prisma/client';
+import Link from 'next/link';
+import { ReactNode } from 'react';
+import { visit } from 'unist-util-visit';
export function replaceLinks({
- href,
- children,
+ href,
+ children,
}: {
- href?: string;
- children: ReactNode;
+ href?: string;
+ children: ReactNode;
}) {
- // this is technically not a remark plugin but it
- // replaces internal links with component
- // and external links with
- return href?.startsWith("/") || href === "" ? (
-
- {children}
-
- ) : (
-
- {children} ↗
-
- );
+ // this is technically not a remark plugin but it
+ // replaces internal links with component
+ // and external links with
+ return href?.startsWith('/') || href === '' ? (
+
+ {children}
+
+ ) : (
+
+ {children} ↗
+
+ );
}
export function replaceTweets() {
- return (tree: any) =>
- new Promise(async (resolve, reject) => {
- const nodesToChange = new Array();
+ return (tree: any) =>
+ new Promise(async (resolve, reject) => {
+ const nodesToChange = [];
- visit(tree, "link", (node: any) => {
- if (
- node.url.match(
- /https?:\/\/x\.com\/(?:#!\/)?(\w+)\/status(?:es)?\/(\d+)([^\?])(\?.*)?/g,
- )
- ) {
- nodesToChange.push({
- node,
- });
- }
- });
- for (const { node } of nodesToChange) {
- try {
- const regex = /\/status\/(\d+)/gm;
- const matches = regex.exec(node.url);
+ visit(tree, 'link', (node: any) => {
+ if (
+ node.url.match(
+ /https?:\/\/x\.com\/(?:#!\/)?(\w+)\/status(?:es)?\/(\d+)([^\?])(\?.*)?/g
+ )
+ ) {
+ nodesToChange.push({
+ node,
+ });
+ }
+ });
+ for (const { node } of nodesToChange) {
+ try {
+ const regex = /\/status\/(\d+)/gm;
+ const matches = regex.exec(node.url);
- if (!matches) throw new Error(`Failed to get tweet: ${node}`);
+ if (!matches) throw new Error(`Failed to get tweet: ${node}`);
- const id = matches[1];
+ const id = matches[1];
- node.type = "mdxJsxFlowElement";
- node.name = "Tweet";
- node.attributes = [
- {
- type: "mdxJsxAttribute",
- name: "id",
- value: id,
- },
- ];
- } catch (e) {
- console.log("ERROR", e);
- return reject(e);
- }
- }
+ node.type = 'mdxJsxFlowElement';
+ node.name = 'Tweet';
+ node.attributes = [
+ {
+ type: 'mdxJsxAttribute',
+ name: 'id',
+ value: id,
+ },
+ ];
+ } catch (e) {
+ console.log('ERROR', e);
+ return reject(e);
+ }
+ }
- resolve();
- });
+ resolve();
+ });
}
export function replaceExamples(prisma: PrismaClient) {
- return (tree: any) =>
- new Promise(async (resolve, reject) => {
- const nodesToChange = new Array();
+ return (tree: any) =>
+ new Promise(async (resolve, reject) => {
+ const nodesToChange = [];
- visit(tree, "mdxJsxFlowElement", (node: any) => {
- if (node.name == "Examples") {
- nodesToChange.push({
- node,
- });
- }
- });
- for (const { node } of nodesToChange) {
- try {
- const data = await getExamples(node, prisma);
- node.attributes = [
- {
- type: "mdxJsxAttribute",
- name: "data",
- value: data,
- },
- ];
- } catch (e) {
- return reject(e);
- }
- }
+ visit(tree, 'mdxJsxFlowElement', (node: any) => {
+ if (node.name == 'Examples') {
+ nodesToChange.push({
+ node,
+ });
+ }
+ });
+ for (const { node } of nodesToChange) {
+ try {
+ const data = await getExamples(node, prisma);
+ node.attributes = [
+ {
+ type: 'mdxJsxAttribute',
+ name: 'data',
+ value: data,
+ },
+ ];
+ } catch (e) {
+ return reject(e);
+ }
+ }
- resolve();
- });
+ resolve();
+ });
}
async function getExamples(node: any, prisma: PrismaClient) {
- const names = node?.attributes[0].value.split(",");
+ const names = node?.attributes[0].value.split(',');
- const data = new Array();
+ const data = new Array();
- for (let i = 0; i < names.length; i++) {
- const results = await prisma.example.findUnique({
- where: {
- id: parseInt(names[i]),
- },
- });
- data.push(results);
- }
+ for (let i = 0; i < names.length; i++) {
+ const results = await prisma.example.findUnique({
+ where: {
+ id: parseInt(names[i]),
+ },
+ });
+ data.push(results);
+ }
- return JSON.stringify(data);
+ return JSON.stringify(data);
}
diff --git a/lib/types.ts b/lib/types.ts
index c1a5d6a..f3a8277 100644
--- a/lib/types.ts
+++ b/lib/types.ts
@@ -1,58 +1,58 @@
export type DomainVerificationStatusProps =
- | "Valid Configuration"
- | "Invalid Configuration"
- | "Pending Verification"
- | "Domain Not Found"
- | "Unknown Error";
+ | 'Valid Configuration'
+ | 'Invalid Configuration'
+ | 'Pending Verification'
+ | 'Domain Not Found'
+ | 'Unknown Error';
// From https://vercel.com/docs/rest-api/endpoints#get-a-project-domain
export interface DomainResponse {
- name: string;
- apexName: string;
- projectId: string;
- redirect?: string | null;
- redirectStatusCode?: (307 | 301 | 302 | 308) | null;
- gitBranch?: string | null;
- updatedAt?: number;
- createdAt?: number;
- /** `true` if the domain is verified for use with the project. If `false` it will not be used as an alias on this project until the challenge in `verification` is completed. */
- verified: boolean;
- /** A list of verification challenges, one of which must be completed to verify the domain for use on the project. After the challenge is complete `POST /projects/:idOrName/domains/:domain/verify` to verify the domain. Possible challenges: - If `verification.type = TXT` the `verification.domain` will be checked for a TXT record matching `verification.value`. */
- verification: {
- type: string;
- domain: string;
- value: string;
- reason: string;
- }[];
+ name: string;
+ apexName: string;
+ projectId: string;
+ redirect?: string | null;
+ redirectStatusCode?: (307 | 301 | 302 | 308) | null;
+ gitBranch?: string | null;
+ updatedAt?: number;
+ createdAt?: number;
+ /** `true` if the domain is verified for use with the project. If `false` it will not be used as an alias on this project until the challenge in `verification` is completed. */
+ verified: boolean;
+ /** A list of verification challenges, one of which must be completed to verify the domain for use on the project. After the challenge is complete `POST /projects/:idOrName/domains/:domain/verify` to verify the domain. Possible challenges: - If `verification.type = TXT` the `verification.domain` will be checked for a TXT record matching `verification.value`. */
+ verification: {
+ type: string;
+ domain: string;
+ value: string;
+ reason: string;
+ }[];
}
// From https://vercel.com/docs/rest-api/endpoints#get-a-domain-s-configuration
export interface DomainConfigResponse {
- /** How we see the domain's configuration. - `CNAME`: Domain has a CNAME pointing to Vercel. - `A`: Domain's A record is resolving to Vercel. - `http`: Domain is resolving to Vercel but may be behind a Proxy. - `null`: Domain is not resolving to Vercel. */
- configuredBy?: ("CNAME" | "A" | "http") | null;
- /** Which challenge types the domain can use for issuing certs. */
- acceptedChallenges?: ("dns-01" | "http-01")[];
- /** Whether or not the domain is configured AND we can automatically generate a TLS certificate. */
- misconfigured: boolean;
+ /** How we see the domain's configuration. - `CNAME`: Domain has a CNAME pointing to Vercel. - `A`: Domain's A record is resolving to Vercel. - `http`: Domain is resolving to Vercel but may be behind a Proxy. - `null`: Domain is not resolving to Vercel. */
+ configuredBy?: ('CNAME' | 'A' | 'http') | null;
+ /** Which challenge types the domain can use for issuing certs. */
+ acceptedChallenges?: ('dns-01' | 'http-01')[];
+ /** Whether or not the domain is configured AND we can automatically generate a TLS certificate. */
+ misconfigured: boolean;
}
// From https://vercel.com/docs/rest-api/endpoints#verify-project-domain
export interface DomainVerificationResponse {
- name: string;
- apexName: string;
- projectId: string;
- redirect?: string | null;
- redirectStatusCode?: (307 | 301 | 302 | 308) | null;
- gitBranch?: string | null;
- updatedAt?: number;
- createdAt?: number;
- /** `true` if the domain is verified for use with the project. If `false` it will not be used as an alias on this project until the challenge in `verification` is completed. */
- verified: boolean;
- /** A list of verification challenges, one of which must be completed to verify the domain for use on the project. After the challenge is complete `POST /projects/:idOrName/domains/:domain/verify` to verify the domain. Possible challenges: - If `verification.type = TXT` the `verification.domain` will be checked for a TXT record matching `verification.value`. */
- verification?: {
- type: string;
- domain: string;
- value: string;
- reason: string;
- }[];
+ name: string;
+ apexName: string;
+ projectId: string;
+ redirect?: string | null;
+ redirectStatusCode?: (307 | 301 | 302 | 308) | null;
+ gitBranch?: string | null;
+ updatedAt?: number;
+ createdAt?: number;
+ /** `true` if the domain is verified for use with the project. If `false` it will not be used as an alias on this project until the challenge in `verification` is completed. */
+ verified: boolean;
+ /** A list of verification challenges, one of which must be completed to verify the domain for use on the project. After the challenge is complete `POST /projects/:idOrName/domains/:domain/verify` to verify the domain. Possible challenges: - If `verification.type = TXT` the `verification.domain` will be checked for a TXT record matching `verification.value`. */
+ verification?: {
+ type: string;
+ domain: string;
+ value: string;
+ reason: string;
+ }[];
}
diff --git a/lib/uploadthing.ts b/lib/uploadthing.ts
index e2098d7..145941f 100644
--- a/lib/uploadthing.ts
+++ b/lib/uploadthing.ts
@@ -1,6 +1,6 @@
-import { generateComponents } from "@uploadthing/react";
+import { generateComponents } from '@uploadthing/react';
-import type { OurFileRouter } from "@/app/api/uploadthing/core";
+import type { OurFileRouter } from '@/app/api/uploadthing/core';
export const { UploadButton, UploadDropzone, Uploader } =
- generateComponents();
\ No newline at end of file
+ generateComponents();
diff --git a/lib/utils.ts b/lib/utils.ts
index bf594e8..af8bbcc 100644
--- a/lib/utils.ts
+++ b/lib/utils.ts
@@ -1,76 +1,73 @@
/* eslint-disable no-undef */
-import { clsx, type ClassValue } from "clsx";
+import { clsx, type ClassValue } from 'clsx';
import { format, subDays } from 'date-fns';
-import { twMerge } from "tailwind-merge";
-
+import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
+ return twMerge(clsx(inputs));
}
-
-
export const getDate = (sub: number = 0) => {
- const dateXDaysAgo = subDays(new Date(), sub)
-
- return format(dateXDaysAgo, 'dd/MM/yyyy')
-}
+ const dateXDaysAgo = subDays(new Date(), sub);
+ return format(dateXDaysAgo, 'dd/MM/yyyy');
+};
export async function fetcher(
input: RequestInfo,
- init?: RequestInit,
+ init?: RequestInit
): Promise {
- const response = await fetch(input, { ...init, cache: "no-store" });
+ const response = await fetch(input, { ...init, cache: 'no-store' });
return response.json();
}
export const capitalize = (s: string) => {
- if (typeof s !== "string") return "";
+ if (typeof s !== 'string') return '';
return s.charAt(0).toUpperCase() + s.slice(1);
};
export const truncate = (str: string, num: number) => {
- if (!str) return "";
+ if (!str) return '';
if (str.length <= num) {
return str;
}
- return str.slice(0, num) + "...";
+ return str.slice(0, num) + '...';
};
-
export const getBlurDataURL = async (url: string | null) => {
if (!url) {
- return "data:image/webp;base64,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+ return 'data:image/webp;base64,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';
}
try {
const response = await fetch(
- `https://wsrv.nl/?url=${url}&w=50&h=50&blur=5`,
+ `https://wsrv.nl/?url=${url}&w=50&h=50&blur=5`
);
const buffer = await response.arrayBuffer();
- const base64 = Buffer.from(buffer).toString("base64");
+ const base64 = Buffer.from(buffer).toString('base64');
return `data:image/png;base64,${base64}`;
} catch (error) {
- return "data:image/webp;base64,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+ return 'data:image/webp;base64,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';
}
};
-
export const placeholderBlurhash =
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAoJJREFUWEfFl4lu4zAMRO3cx/9/au6reMaOdkxTTl0grQFCRoqaT+SQotq2bV9N8rRt28xms87m83l553eZ/9vr9Wpkz+ezkT0ej+6dv1X81AFw7M4FBACPVn2c1Z3zLgDeJwHgeLFYdAARYioAEAKJEG2WAjl3gCwNYymQQ9b7/V4spmIAwO6Wy2VnAMikBWlDURBELf8CuN1uHQSrPwMAHK5WqwFELQ01AIXdAa7XawfAb3p6AOwK5+v1ugAoEq4FRSFLgavfQ49jAGQpAE5wjgGCeRrGdBArwHOPcwFcLpcGU1X0IsBuN5tNgYhaiFFwHTiAwq8I+O5xfj6fOz38K+X/fYAdb7fbAgFAjIJ6Aav3AYlQ6nfnDoDz0+lUxNiLALvf7XaDNGQ6GANQBKR85V27B4D3QQRw7hGIYlQKWGM79hSweyCUe1blXhEAogfABwHAXAcqSYkxCtHLUK3XBajSc4Dj8dilAeiSAgD2+30BAEKV4GKcAuDqB4TdYwBgPQByCgApUBoE4EJUGvxUjF3Q69/zLw3g/HA45ABKgdIQu+JPIyDnisCfAxAFNFM0EFNQ64gfS0EUoQP8ighrZSjn3oziZEQpauyKbfjbZchHUL/3AS/Dd30gAkxuRACgfO+EWQW8qwI1o+wseNuKcQiESjALvwNoMI0TcRzD4lFcPYwIM+JTF5x6HOs8yI7jeB5oKhpMRFH9UwaSCDB2Jmg4rc6E2TT0biIaG0rQhNqyhpHBcayTTSXH6vcDL7/sdqRK8LkwTsU499E8vRcAojHcZ4AxABdilgrp4lsXk8oVqgwh7+6H3phqd8J0Kk4vbx/+sZqCD/vNLya/5dT9fAH8g1WdNGgwbQAAAABJRU5ErkJggg==";
+ 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAoJJREFUWEfFl4lu4zAMRO3cx/9/au6reMaOdkxTTl0grQFCRoqaT+SQotq2bV9N8rRt28xms87m83l553eZ/9vr9Wpkz+ezkT0ej+6dv1X81AFw7M4FBACPVn2c1Z3zLgDeJwHgeLFYdAARYioAEAKJEG2WAjl3gCwNYymQQ9b7/V4spmIAwO6Wy2VnAMikBWlDURBELf8CuN1uHQSrPwMAHK5WqwFELQ01AIXdAa7XawfAb3p6AOwK5+v1ugAoEq4FRSFLgavfQ49jAGQpAE5wjgGCeRrGdBArwHOPcwFcLpcGU1X0IsBuN5tNgYhaiFFwHTiAwq8I+O5xfj6fOz38K+X/fYAdb7fbAgFAjIJ6Aav3AYlQ6nfnDoDz0+lUxNiLALvf7XaDNGQ6GANQBKR85V27B4D3QQRw7hGIYlQKWGM79hSweyCUe1blXhEAogfABwHAXAcqSYkxCtHLUK3XBajSc4Dj8dilAeiSAgD2+30BAEKV4GKcAuDqB4TdYwBgPQByCgApUBoE4EJUGvxUjF3Q69/zLw3g/HA45ABKgdIQu+JPIyDnisCfAxAFNFM0EFNQ64gfS0EUoQP8ighrZSjn3oziZEQpauyKbfjbZchHUL/3AS/Dd30gAkxuRACgfO+EWQW8qwI1o+wseNuKcQiESjALvwNoMI0TcRzD4lFcPYwIM+JTF5x6HOs8yI7jeB5oKhpMRFH9UwaSCDB2Jmg4rc6E2TT0biIaG0rQhNqyhpHBcayTTSXH6vcDL7/sdqRK8LkwTsU499E8vRcAojHcZ4AxABdilgrp4lsXk8oVqgwh7+6H3phqd8J0Kk4vbx/+sZqCD/vNLya/5dT9fAH8g1WdNGgwbQAAAABJRU5ErkJggg==';
export const toDateString = (date: Date) => {
- return new Date(date).toLocaleDateString("en-US", {
- month: "short",
- day: "numeric",
- year: "numeric",
+ return new Date(date).toLocaleDateString('en-US', {
+ month: 'short',
+ day: 'numeric',
+ year: 'numeric',
});
};
-
-export const getDuration = (start: Date, end?: Date, stillworking?: boolean): string => {
+export const getDuration = (
+ start: Date,
+ end?: Date,
+ stillworking?: boolean
+): string => {
const startdate = new Date(start);
const enddate = !stillworking && end ? new Date(end) : new Date();
let months = enddate.getMonth() - startdate.getMonth() + 1;
@@ -86,7 +83,7 @@ export const getDuration = (start: Date, end?: Date, stillworking?: boolean): st
return `${years} years`;
}
return `${years} years ${months} months`;
-}
+};
export const random = (min: number, max: number) => {
return Math.floor(Math.random() * (max - min + 1) + min);
diff --git a/middleware.ts b/middleware.ts
index a2b981a..748bca9 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -1,71 +1,59 @@
-import { authMiddleware, redirectToSignIn } from "@clerk/nextjs";
-import { NextResponse } from "next/server";
+import { authMiddleware, redirectToSignIn } from '@clerk/nextjs';
+import { NextResponse } from 'next/server';
export default authMiddleware({
- async afterAuth(auth, req, evt) {
-
-
- const url = req.nextUrl;
- // console.log(url)
-
- let hostname = req.headers
- .get("host")!
- .replace(".localhost:3000", `.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`);
- if (
- hostname.includes("---") &&
- hostname.endsWith(`.${process.env.NEXT_PUBLIC_VERCEL_DEPLOYMENT_SUFFIX}`)
- ) {
- hostname = `${hostname.split("---")[0]}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`;
-
- // console.log("host name 12111", hostname)
- }
-
- const searchParams = req.nextUrl.searchParams.toString();
-
- // console.log("search params", searchParams)
- // Get the pathname of the request (e.g. /, /about, /blog/first-post)
- const path = `${url.pathname}${searchParams.length > 0 ? `?${searchParams}` : ""}`;
- // console.log("path", path)
- // rewrite root application to `/home` folder when user goes to /
-
- if (hostname == `app.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`) {
-
- if (!auth.userId && !auth.isPublicRoute) {
- return redirectToSignIn({ returnBackUrl: req.url });
- }
-
- return NextResponse.rewrite(
- new URL(`/app${path === "/" ? "" : path}`, req.url),
- );
- }
-
- if (hostname === "dresume.me") {
- return NextResponse.redirect(
- "https://app.dresume.me",
- );
- }
- if (
- hostname === "localhost:3000" ||
- hostname === process.env.NEXT_PUBLIC_ROOT_DOMAIN
- ) {
-
- // console.log("rewriting /home")
- return NextResponse.rewrite(
- new URL(`/home${path === "/" ? "" : path}`, req.url),
- );
- }
-
-
-
- return NextResponse.rewrite(new URL(`/${hostname}${path}`, req.url));
- },
-
-
- publicRoutes: ["/", "/api/webhook/user"]
+ async afterAuth(auth, req, evt) {
+ const url = req.nextUrl;
+ // console.log(url)
+
+ let hostname = req.headers
+ .get('host')!
+ .replace('.localhost:3000', `.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`);
+ if (
+ hostname.includes('---') &&
+ hostname.endsWith(`.${process.env.NEXT_PUBLIC_VERCEL_DEPLOYMENT_SUFFIX}`)
+ ) {
+ hostname = `${hostname.split('---')[0]}.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`;
+
+ // console.log("host name 12111", hostname)
+ }
+
+ const searchParams = req.nextUrl.searchParams.toString();
+
+ // console.log("search params", searchParams)
+ // Get the pathname of the request (e.g. /, /about, /blog/first-post)
+ const path = `${url.pathname}${searchParams.length > 0 ? `?${searchParams}` : ''}`;
+ // console.log("path", path)
+ // rewrite root application to `/home` folder when user goes to /
+
+ if (hostname == `app.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`) {
+ if (!auth.userId && !auth.isPublicRoute) {
+ return redirectToSignIn({ returnBackUrl: req.url });
+ }
+
+ return NextResponse.rewrite(
+ new URL(`/app${path === '/' ? '' : path}`, req.url)
+ );
+ }
+
+ if (hostname === 'dresume.me') {
+ return NextResponse.redirect('https://app.dresume.me');
+ }
+ if (
+ hostname === 'localhost:3000' ||
+ hostname === process.env.NEXT_PUBLIC_ROOT_DOMAIN
+ ) {
+ // console.log("rewriting /home")
+ return NextResponse.rewrite(
+ new URL(`/home${path === '/' ? '' : path}`, req.url)
+ );
+ }
+
+ return NextResponse.rewrite(new URL(`/${hostname}${path}`, req.url));
+ },
+
+ publicRoutes: ['/', '/api/webhook/user'],
});
-
-
export const config = {
- matcher: ['/((?!api/|_next/|_static/|_vercel|[\\w-]+\\.\\w+).*)',],
+ matcher: ['/((?!api/|_next/|_static/|_vercel|[\\w-]+\\.\\w+).*)'],
};
-
diff --git a/next.config.js b/next.config.js
index 62196c2..5c5a4ed 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,32 +1,32 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
- reactStrictMode: true,
- experimental: {
- serverActions: {
- allowedOrigins: ["app.localhost:3000"],
- },
- },
- images: {
- dangerouslyAllowSVG: true,
- domains: [
- "ha3zldst15jisuvj.public.blob.vercel-storage.com",
- "public.blob.vercel-storage.com",
- "img.clerk.com",
- "res.cloudinary.com",
- "images.unsplash.com",
- "cdn.pixabay.com",
- "pbs.twimg.com",
- "abs.twimg.com",
- "dresume.vercel.app",
- "dresume.me",
- "utfs.io",
- "images.clerk.dev",
- "illustrations.popsy.co",
- "api.producthunt.com",
- "avatars.githubusercontent.com",
- "cdn.jsdelivr.net"
- ],
- },
-};
+ reactStrictMode: true,
+ experimental: {
+ serverActions: {
+ allowedOrigins: ['app.localhost:3000']
+ }
+ },
+ images: {
+ dangerouslyAllowSVG: true,
+ domains: [
+ 'ha3zldst15jisuvj.public.blob.vercel-storage.com',
+ 'public.blob.vercel-storage.com',
+ 'img.clerk.com',
+ 'res.cloudinary.com',
+ 'images.unsplash.com',
+ 'cdn.pixabay.com',
+ 'pbs.twimg.com',
+ 'abs.twimg.com',
+ 'dresume.vercel.app',
+ 'dresume.me',
+ 'utfs.io',
+ 'images.clerk.dev',
+ 'illustrations.popsy.co',
+ 'api.producthunt.com',
+ 'avatars.githubusercontent.com',
+ 'cdn.jsdelivr.net'
+ ]
+ }
+}
-module.exports = nextConfig;
+module.exports = nextConfig
diff --git a/postcss.config.js b/postcss.config.js
index e569373..311ffbe 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -3,6 +3,6 @@ module.exports = {
'postcss-import': {},
'tailwindcss/nesting': {},
tailwindcss: {},
- autoprefixer: {},
- },
-};
+ autoprefixer: {}
+ }
+}
diff --git a/styles/fonts.ts b/styles/fonts.ts
index 6c7b643..5ff1fc8 100644
--- a/styles/fonts.ts
+++ b/styles/fonts.ts
@@ -1,130 +1,126 @@
import {
- EB_Garamond,
- Faustina,
- Inter,
- Kanit,
- Lora,
- Shadows_Into_Light,
- Silkscreen,
- Work_Sans
-} from "next/font/google";
-import localFont from "next/font/local";
-
+ EB_Garamond,
+ Faustina,
+ Inter,
+ Kanit,
+ Lora,
+ Shadows_Into_Light,
+ Silkscreen,
+ Work_Sans,
+} from 'next/font/google';
+import localFont from 'next/font/local';
export const inter = Inter({
- variable: "--font-inter",
- subsets: ["latin"],
+ variable: '--font-inter',
+ subsets: ['latin'],
});
export const cal = localFont({
- src: "./CalSans-SemiBold.otf",
- variable: "--font-cal",
- weight: "600",
- display: "swap",
+ src: './CalSans-SemiBold.otf',
+ variable: '--font-cal',
+ weight: '600',
+ display: 'swap',
});
export const calTitle = localFont({
- src: "./CalSans-SemiBold.otf",
- variable: "--font-title",
- weight: "600",
- display: "swap",
+ src: './CalSans-SemiBold.otf',
+ variable: '--font-title',
+ weight: '600',
+ display: 'swap',
});
export const lora = Lora({
- variable: "--font-title",
- subsets: ["latin"],
- weight: "600",
- display: "swap",
+ variable: '--font-title',
+ subsets: ['latin'],
+ weight: '600',
+ display: 'swap',
});
export const work = Work_Sans({
- variable: "--font-title",
- subsets: ["latin"],
- weight: "600",
- display: "swap",
+ variable: '--font-title',
+ subsets: ['latin'],
+ weight: '600',
+ display: 'swap',
});
export const garamond = EB_Garamond({
- variable: "--font-title",
- subsets: ["latin"],
- weight: "600",
- display: "swap",
-})
-
+ variable: '--font-title',
+ subsets: ['latin'],
+ weight: '600',
+ display: 'swap',
+});
export const shadowIntoLight = Shadows_Into_Light({
- variable: "--font-title",
- subsets: ["latin"],
- weight: "400",
- display: "swap",
-})
+ variable: '--font-title',
+ subsets: ['latin'],
+ weight: '400',
+ display: 'swap',
+});
export const futura = Faustina({
- variable: "--font-title",
- weight: "600",
- subsets: ["vietnamese"],
- display: "swap",
+ variable: '--font-title',
+ weight: '600',
+ subsets: ['vietnamese'],
+ display: 'swap',
});
-
export const kanit = Kanit({
- variable: "--font-title",
- weight: "600",
- subsets: ["latin", "latin-ext", "vietnamese", "thai"],
- display: "swap",
+ variable: '--font-title',
+ weight: '600',
+ subsets: ['latin', 'latin-ext', 'vietnamese', 'thai'],
+ display: 'swap',
});
export const silkscreen = Silkscreen({
- variable: "--font-title",
- weight: "700",
- subsets: ["latin"],
- display: "swap",
+ variable: '--font-title',
+ weight: '700',
+ subsets: ['latin'],
+ display: 'swap',
});
export const fontList = [
- {
- name: "Cal Sans",
- value: "font-cal",
- },
- {
- name: "Lora",
- value: "font-lora",
- },
- {
- name: "Work Sans",
- value: "font-work",
- },
- {
- name: "Shadows Into Light",
- value: "font-shadow-into-light",
- },
- {
- name: "EB Garamond",
- value: "font-garamond",
- },
- {
- name: "Faustina",
- value: "font-futura",
- },
- {
- name: "Kanit",
- value: "font-kanit",
- },
- {
- name: "Silkscreen",
- value: "font-silkscreen",
- },
+ {
+ name: 'Cal Sans',
+ value: 'font-cal',
+ },
+ {
+ name: 'Lora',
+ value: 'font-lora',
+ },
+ {
+ name: 'Work Sans',
+ value: 'font-work',
+ },
+ {
+ name: 'Shadows Into Light',
+ value: 'font-shadow-into-light',
+ },
+ {
+ name: 'EB Garamond',
+ value: 'font-garamond',
+ },
+ {
+ name: 'Faustina',
+ value: 'font-futura',
+ },
+ {
+ name: 'Kanit',
+ value: 'font-kanit',
+ },
+ {
+ name: 'Silkscreen',
+ value: 'font-silkscreen',
+ },
];
export const fontMapper = {
- "font-cal": calTitle.variable,
- "font-lora": lora.variable,
- "font-work": work.variable,
- "font-shadow-into-light": shadowIntoLight.variable,
- "font-garamond": garamond.variable,
- "font-futura": futura.variable,
- "font-helvetica": futura.variable,
- "font-silkscreen": silkscreen.variable,
- "font-kanit": kanit.variable,
+ 'font-cal': calTitle.variable,
+ 'font-lora': lora.variable,
+ 'font-work': work.variable,
+ 'font-shadow-into-light': shadowIntoLight.variable,
+ 'font-garamond': garamond.variable,
+ 'font-futura': futura.variable,
+ 'font-helvetica': futura.variable,
+ 'font-silkscreen': silkscreen.variable,
+ 'font-kanit': kanit.variable,
} as Record;
-
//font-futura
-//font-helvetica
\ No newline at end of file
+//font-helvetica
diff --git a/styles/globals.css b/styles/globals.css
index c0481db..7b679d7 100644
--- a/styles/globals.css
+++ b/styles/globals.css
@@ -1,7 +1,6 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
-
@layer base {
:root {
@@ -26,7 +25,7 @@
--ring: 142.1 76.2% 36.3%;
--radius: 1rem;
}
-
+
.dark {
--background: 20 14.3% 4.1%;
--foreground: 0 0% 95%;
@@ -49,28 +48,27 @@
--ring: 142.4 71.8% 29.2%;
}
}
-
+
@layer base {
* {
- @apply border-border ;
+ @apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
-
html {
scroll-behavior: smooth;
}
-
-article > h1 , article > h2 , article > h3 , article > h4 {
- @apply font-title !important
+article > h1,
+article > h2,
+article > h3,
+article > h4 {
+ @apply font-title !important;
}
-
-
@layer utilities {
.overflow-hidden {
-webkit-mask-image: -webkit-radial-gradient(white, black);
@@ -110,18 +108,18 @@ article > h1 , article > h2 , article > h3 , article > h4 {
/* Custom TODO list checkboxes – shoutout to this awesome tutorial: https://moderncss.dev/pure-css-custom-checkbox-style/ */
-ul[data-type="taskList"] li > label {
+ul[data-type='taskList'] li > label {
margin-right: 0.2rem;
user-select: none;
}
@media screen and (max-width: 768px) {
- ul[data-type="taskList"] li > label {
+ ul[data-type='taskList'] li > label {
margin-right: 0.5rem;
}
}
-ul[data-type="taskList"] li > label input[type="checkbox"] {
+ul[data-type='taskList'] li > label input[type='checkbox'] {
-webkit-appearance: none;
appearance: none;
background-color: #fff;
@@ -145,7 +143,7 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
}
&::before {
- content: "";
+ content: '';
width: 0.65em;
height: 0.65em;
transform: scale(0);
@@ -160,22 +158,21 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
}
}
-ul[data-type="taskList"] li[data-checked="true"] > div > p {
+ul[data-type='taskList'] li[data-checked='true'] > div > p {
color: #a8a29e;
text-decoration: line-through;
text-decoration-thickness: 2px;
}
-
code[class*='language-'],
pre[class*='language-'] {
/* color: #d6e7ff; */
/* background: #030314; */
text-shadow: none;
- font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
+ font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
line-height: 1.5;
- letter-spacing: .2px;
+ letter-spacing: 0.2px;
white-space: pre;
word-spacing: normal;
word-break: normal;
@@ -211,7 +208,7 @@ pre[class*='language-'] {
overflow: auto;
}
-:not(pre)>code[class*='language-'] {
+:not(pre) > code[class*='language-'] {
color: #f0f6f6;
background: #2a4555;
padding: 0.2em 0.3em;
@@ -282,7 +279,6 @@ pre {
overflow-x: auto;
}
-
/**
* Inspired by gatsby remark prism - https://www.gatsbyjs.com/plugins/gatsby-remark-prismjs/
* 1. Make the element just wide enough to fit its content.
@@ -335,13 +331,12 @@ pre {
content: attr(line);
}
-
.no-visible-scrollbar {
scrollbar-width: none;
-ms-overflow-style: none;
-webkit-overflow-scrolling: touch;
}
-
+
.no-visible-scrollbar::-webkit-scrollbar {
display: none;
-}
\ No newline at end of file
+}
diff --git a/styles/theme.ts b/styles/theme.ts
index 7ee59d5..ea5667f 100644
--- a/styles/theme.ts
+++ b/styles/theme.ts
@@ -1,6 +1,6 @@
export const themeList = [
- {
- name: "Default",
- value: "theme-default",
- },
-];
\ No newline at end of file
+ {
+ name: 'Default',
+ value: 'theme-default',
+ },
+];
diff --git a/tailwind.config.ts b/tailwind.config.ts
index f486783..695204e 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -1,25 +1,23 @@
/** @type {import('tailwindcss').Config} */
-import { withUt } from "uploadthing/tw";
+import { withUt } from 'uploadthing/tw';
-import * as react from "@nextui-org/react";
+import * as react from '@nextui-org/react';
import colors from 'tailwindcss/colors';
-import { fontFamily } from "tailwindcss/defaultTheme";
+import { fontFamily } from 'tailwindcss/defaultTheme';
-
-const svgToDataUri = require("mini-svg-data-uri");
+const svgToDataUri = require('mini-svg-data-uri');
const {
default: flattenColorPalette,
-} = require("tailwindcss/lib/util/flattenColorPalette");
-
+} = require('tailwindcss/lib/util/flattenColorPalette');
export default withUt({
- darkMode: ["class"],
+ darkMode: ['class'],
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
'./src/**/*.{ts,tsx}',
- "./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}",
+ './node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}',
'./node_modules/@tremor/**/*.{js,ts,jsx,tsx}',
],
theme: {
@@ -27,21 +25,21 @@ export default withUt({
current: 'currentColor',
container: {
center: true,
- padding: "2rem",
+ padding: '2rem',
screens: {
- "2xl": "1400px",
- xl: "1200px",
- lg: "1024px",
- md: "768px",
- sm: "640px",
+ '2xl': '1400px',
+ xl: '1200px',
+ lg: '1024px',
+ md: '768px',
+ sm: '640px',
},
},
- darkMode: "class",
+ darkMode: 'class',
extend: {
colors: {
tremor: {
brand: {
- faint: "#4af500",
+ faint: '#4af500',
muted: colors.blue[900],
subtle: colors.blue[400],
DEFAULT: colors.blue[500],
@@ -98,38 +96,38 @@ export default withUt({
inverted: colors.gray[950],
},
},
- border: "hsl(var(--border))",
- input: "hsl(var(--input))",
- ring: "hsl(var(--ring))",
- background: "hsl(var(--background))",
- foreground: "hsl(var(--foreground))",
+ border: 'hsl(var(--border))',
+ input: 'hsl(var(--input))',
+ ring: 'hsl(var(--ring))',
+ background: 'hsl(var(--background))',
+ foreground: 'hsl(var(--foreground))',
primary: {
- DEFAULT: "hsl(var(--primary))",
- foreground: "hsl(var(--primary-foreground))",
+ DEFAULT: 'hsl(var(--primary))',
+ foreground: 'hsl(var(--primary-foreground))',
},
secondary: {
- DEFAULT: "hsl(var(--secondary))",
- foreground: "hsl(var(--secondary-foreground))",
+ DEFAULT: 'hsl(var(--secondary))',
+ foreground: 'hsl(var(--secondary-foreground))',
},
destructive: {
- DEFAULT: "hsl(var(--destructive))",
- foreground: "hsl(var(--destructive-foreground))",
+ DEFAULT: 'hsl(var(--destructive))',
+ foreground: 'hsl(var(--destructive-foreground))',
},
muted: {
- DEFAULT: "hsl(var(--muted))",
- foreground: "hsl(var(--muted-foreground))",
+ DEFAULT: 'hsl(var(--muted))',
+ foreground: 'hsl(var(--muted-foreground))',
},
accent: {
- DEFAULT: "hsl(var(--accent))",
- foreground: "hsl(var(--accent-foreground))",
+ DEFAULT: 'hsl(var(--accent))',
+ foreground: 'hsl(var(--accent-foreground))',
},
popover: {
- DEFAULT: "hsl(var(--popover))",
- foreground: "hsl(var(--popover-foreground))",
+ DEFAULT: 'hsl(var(--popover))',
+ foreground: 'hsl(var(--popover-foreground))',
},
card: {
- DEFAULT: "hsl(var(--card))",
- foreground: "hsl(var(--card-foreground))",
+ DEFAULT: 'hsl(var(--card))',
+ foreground: 'hsl(var(--card-foreground))',
},
},
boxShadow: {
@@ -147,23 +145,23 @@ export default withUt({
'0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
},
borderRadius: {
- lg: "var(--radius)",
- md: "calc(var(--radius) - 2px)",
- sm: "calc(var(--radius) - 4px)",
+ lg: 'var(--radius)',
+ md: 'calc(var(--radius) - 2px)',
+ sm: 'calc(var(--radius) - 4px)',
'tremor-small': '0.375rem',
'tremor-default': '0.5rem',
'tremor-full': '9999px',
},
keyframes: {
- "accordion-down": {
- from: { height: "0" },
- to: { height: "var(--radix-accordion-content-height)" },
+ 'accordion-down': {
+ from: { height: '0' },
+ to: { height: 'var(--radix-accordion-content-height)' },
},
- "accordion-up": {
- from: { height: "var(--radix-accordion-content-height)" },
- to: { height: "0" },
+ 'accordion-up': {
+ from: { height: 'var(--radix-accordion-content-height)' },
+ to: { height: '0' },
},
- "color-border": {
+ 'color-border': {
'0%, 100%': {
'background-size': '200% 200%',
'background-position': 'left center',
@@ -175,15 +173,15 @@ export default withUt({
},
scroll: {
to: {
- transform: "translate(calc(-50% - 0.5rem))",
+ transform: 'translate(calc(-50% - 0.5rem))',
},
},
},
fontFamily: {
- default: ["var(--font-inter)", ...fontFamily.sans],
- cal: ["var(--font-cal)", ...fontFamily.sans],
- title: ["var(--font-title)", ...fontFamily.sans],
- mono: ["Consolas", ...fontFamily.mono],
+ default: ['var(--font-inter)', ...fontFamily.sans],
+ cal: ['var(--font-cal)', ...fontFamily.sans],
+ title: ['var(--font-title)', ...fontFamily.sans],
+ mono: ['Consolas', ...fontFamily.mono],
},
fontSize: {
'tremor-label': ['0.75rem', { lineHeight: '1rem' }],
@@ -195,68 +193,68 @@ export default withUt({
DEFAULT: {
css: {
h1: {
- fontFamily: "Cal Sans",
+ fontFamily: 'Cal Sans',
},
h2: {
- fontFamily: "Cal Sans",
+ fontFamily: 'Cal Sans',
},
h3: {
- fontFamily: "Cal Sans",
+ fontFamily: 'Cal Sans',
},
- "blockquote p:first-of-type::before": { content: "none" },
- "blockquote p:first-of-type::after": { content: "none" },
+ 'blockquote p:first-of-type::before': { content: 'none' },
+ 'blockquote p:first-of-type::after': { content: 'none' },
},
},
},
animation: {
- "accordion-down": "accordion-down 0.2s ease-out",
- "accordion-up": "accordion-up 0.2s ease-out",
- "color-border": "color-border 5s ease infinite",
+ 'accordion-down': 'accordion-down 0.2s ease-out',
+ 'accordion-up': 'accordion-up 0.2s ease-out',
+ 'color-border': 'color-border 5s ease infinite',
scroll:
- "scroll var(--animation-duration, 40s) var(--animation-direction, forwards) linear infinite",
+ 'scroll var(--animation-duration, 40s) var(--animation-direction, forwards) linear infinite',
},
},
},
plugins: [
- require("tailwindcss-animate"),
+ require('tailwindcss-animate'),
react.nextui(),
require('@headlessui/tailwindcss'),
- require("@tailwindcss/typography"),
+ require('@tailwindcss/typography'),
addVariablesForColors,
function ({ matchUtilities, theme }: any) {
matchUtilities(
{
- "bg-grid": (value: any) => ({
+ 'bg-grid': (value: any) => ({
backgroundImage: `url("${svgToDataUri(
` `
)}")`,
}),
- "bg-grid-small": (value: any) => ({
+ 'bg-grid-small': (value: any) => ({
backgroundImage: `url("${svgToDataUri(
` `
)}")`,
}),
- "bg-dot": (value: any) => ({
+ 'bg-dot': (value: any) => ({
backgroundImage: `url("${svgToDataUri(
` `
)}")`,
}),
},
- { values: flattenColorPalette(theme("backgroundColor")), type: "color" }
+ { values: flattenColorPalette(theme('backgroundColor')), type: 'color' }
);
- }
+ },
],
-})
+});
// This plugin adds each Tailwind color as a global CSS variable, e.g. var(--gray-200).
function addVariablesForColors({ addBase, theme }: any) {
- let allColors = flattenColorPalette(theme("colors"));
+ let allColors = flattenColorPalette(theme('colors'));
let newVars = Object.fromEntries(
Object.entries(allColors).map(([key, val]) => [`--${key}`, val])
);
addBase({
- ":root": newVars,
+ ':root': newVars,
});
-}
\ No newline at end of file
+}