Skip to content

Commit

Permalink
add contact page and form
Browse files Browse the repository at this point in the history
  • Loading branch information
asmitbm committed Dec 10, 2023
1 parent 0ad56df commit e6c5a66
Show file tree
Hide file tree
Showing 16 changed files with 1,688 additions and 1 deletion.
28 changes: 28 additions & 0 deletions app/api/send/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { EmailTemplate } from "@/components/EmailTemplate/email-template";
import { NextResponse } from "next/server";
import { Resend } from "resend";

const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST(request) {
try {
const body = await request.json();
console.log("body", body);
const { email, name, subject } = body;
const data = await resend.emails.send({
from: "Asmit Malakannawar <[email protected]>",
to: email,
reply_to: "[email protected]",
cc: "[email protected]",
subject: subject,
react: EmailTemplate({ firstName: name }),
});

if (data.status === "success") {
return NextResponse.json({ message: "Email Successfully Sent!" });
}
return NextResponse.json(data);
} catch (error) {
console.log("error", error);
}
}
9 changes: 9 additions & 0 deletions app/contact/layout.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Contact from "./page";

export const metadata = {
title: "Projects by Asmit Malakannawar",
description:
"See what Asmit has been working on! Explore Asmit's projects and case studies to see the creative solutions that he has crafted.",
};

export default Contact;
39 changes: 39 additions & 0 deletions app/contact/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use client";
import { useEffect } from "react";
import ContactForm from "@/components/ContactForm";
import { ContactCard } from "@/components/ContactCard";
import AnimatedTitle from "@/components/Animations/AnimatedTitle";
import AnimatedText from "@/components/Animations/AnimatedText";
import styles from "./page.module.css";

export default function Contact() {
useEffect(() => {
window.scrollTo(0, 0);
}, []);
return (
<div className={styles.background_image}>
<div className={styles.main}>
<div className={styles.header}>
<div className={styles.header_name}>
<h1>
<AnimatedTitle title="Contact." />
</h1>
</div>
<div className={styles.header_para}>
<p>
<AnimatedText content="Send me a message." />
</p>
</div>
</div>
<div className={styles.contact}>
<div className={styles.contact_card}>
<ContactCard />
</div>
<div className={styles.contact_form}>
<ContactForm />
</div>
</div>
</div>
</div>
);
}
97 changes: 97 additions & 0 deletions app/contact/page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
.background_image {
background-image: url("/contact.svg");
background-repeat: no-repeat;
background-size: 90vw;
background-position: 50% 0%;
}

.main {
display: flex;
flex-direction: column;
margin-top: 2vw;
margin-left: 8vw;
margin-right: 8vw;
margin-bottom: 4vw;
}

.header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-end;
flex-wrap: wrap;
margin-bottom: 2vw;
}

.header_name {
display: flex;
flex-direction: column;
}

.header_name h1 {
font-size: clamp(3rem, 5vw + 0.9rem, 6rem);
font-weight: 600;
}

.header_para {
display: flex;
align-items: flex-end;
justify-content: flex-end;
width: 40%;
}

.header_para p {
font-size: clamp(1rem, 1vw + 0.3rem, 2rem);
font-weight: 500;
padding-bottom: 24px;
color: #747474;
}

.contact {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: center;
gap: 2vw;
}

.contact_card {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
width: 100%;
}

.contact_form {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
width: 100%;
}

@media only screen and (max-width: 900px) {
.header {
flex-direction: column;
align-items: flex-start;
justify-content: center;
}

.header_para {
margin-top: 3vw;
margin-bottom: 3vw;
width: auto;
}

.contact {
flex-direction: column;
align-items: center;
}
}

@media only screen and (max-width: 500px) {
.contact_form {
width: 100%;
}
}
11 changes: 11 additions & 0 deletions app/layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import "./globals.css";
import { Inter } from "next/font/google";
import Navbar from "@/components/Navbar";
import Footer from "@/components/Footer";
import { Toaster } from "react-hot-toast";
import Script from "next/script";

const inter = Inter({ subsets: ["latin"] });
Expand All @@ -16,6 +17,16 @@ export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>
<Toaster
position="top-center"
toastOptions={{
duration: 3000,
style: {
background: "#333",
color: "#fff",
},
}}
/>
<Navbar />
{children}
<Footer />
Expand Down
106 changes: 106 additions & 0 deletions components/ContactCard/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"use client";
import React, { useEffect, useRef, useState } from "react";
import { motion } from "framer-motion";
import AnimatedText from "@/components/Animations/AnimatedText";
import Stars from "./stars";
import styles from "./styles.module.css";

export const ContactCard = () => {
return (
<div>
<AnimatedCard />
</div>
);
};

const AnimatedCard = () => {
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);
}
}, []);

function mouseMoveHandler(event) {
event.preventDefault();

const { clientX } = event;
if (cardRef.current) {
const relativeX = clientX - left;
setWidthPercentage((relativeX / localWidth) * 100);
}
}

function mouseLeaveHandler() {
setIsMouseOver(false);
setWidthPercentage(0);
}
function mouseEnterHandler() {
setIsMouseOver(true);
}

const rotateDeg = (widthPercentage - 50) * 0.1;
return (
<div
onMouseEnter={mouseEnterHandler}
onMouseLeave={mouseLeaveHandler}
onMouseMove={mouseMoveHandler}
ref={cardRef}
className={styles.card}
>
<div className={styles.card_heading}>
<h2>
<AnimatedText content="Let's Get in Touch!" />
</h2>
</div>
<div className={styles.slide_container}>
<motion.div
animate={
isMouseOver
? {
opacity: widthPercentage > 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={styles.hover_text}
>
<p>I&#39;ll Bring a Creative Touch To It.</p>
</motion.div>
<motion.div
animate={{
left: `${widthPercentage}%`,
rotate: `${rotateDeg}deg`,
opacity: widthPercentage > 0 ? 1 : 0,
}}
transition={
isMouseOver ? { duration: 0 } : { duration: 0.4 }
}
className={styles.slider}
></motion.div>

<div className={styles.base_text}>
<p>Have an idea? or Want to Work With Me?</p>
<Stars />
</div>
</div>
</div>
);
};
41 changes: 41 additions & 0 deletions components/ContactCard/stars.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { memo } from "react";
import { motion } from "framer-motion";

const Stars = () => {
const randomMove = () => Math.random() * 4 - 2;
const randomOpacity = () => Math.random();
const random = () => Math.random();
return (
<div className="absolute inset-0">
{[...Array(140)].map((_, i) => (
<motion.span
key={`star-${i}`}
animate={{
top: `calc(${random() * 100}% + ${randomMove()}px)`,
left: `calc(${random() * 100}% + ${randomMove()}px)`,
opacity: randomOpacity(),
scale: [1, 1.2, 0],
}}
transition={{
duration: random() * 10 + 20,
repeat: Infinity,
ease: "linear",
}}
style={{
position: "absolute",
top: `${random() * 100}%`,
left: `${random() * 100}%`,
width: `4px`,
height: `4px`,
backgroundColor: "#000",
borderRadius: "50%",
zIndex: 1,
}}
className="inline-block"
></motion.span>
))}
</div>
);
};

export default memo(Stars);
Loading

0 comments on commit e6c5a66

Please sign in to comment.