Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add new UI components and update dependencies #35

Merged
merged 5 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ yarn-error.log*

# local env files
.env*.local
.env

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
next-env.d.ts
20 changes: 10 additions & 10 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import type { Metadata } from "next";
import { Space_Grotesk } from 'next/font/google';
import { Space_Grotesk } from "next/font/google";
import "./globals.css";
import Navbar from "@/components/main/navbar/Navbar";
import { Toaster } from "@/components/ui/toaster";

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "AceXLabs",
description:
"From Concept to Create ion Making Ideas Happen From sleek websites to scalable SaaS platforms and innovative MVPs, we specialize in building with JavaScript, Golang, Rust, and Web3 technologies. Whether you need robust web applications or blockchain-powered products, our agency is your go-to partner in turning concepts into impactful digital experiences.",
};


const spaceGrotesk = Space_Grotesk({
subsets: ['latin'],
display: 'swap',
subsets: ["latin"],
display: "swap",
});

export default function RootLayout({
Expand All @@ -21,11 +22,10 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body
className={`${spaceGrotesk.className} antialiased dark`}
>
<Navbar/>
<body className={`${spaceGrotesk.className} antialiased dark`}>
<Navbar />
{children}
<Toaster />
</body>
</html>
);
Expand Down
10 changes: 6 additions & 4 deletions components/main/hero/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from "@/components/farmui/ShinyLights";
import Container from "../../shared/Container";
import Link from "next/link";
import { ShareYourVision } from "../share-your-vision";

export default function FUIDarkHeroSectionWithScrolls() {
const ref = useRef(null);
Expand All @@ -23,7 +24,10 @@ export default function FUIDarkHeroSectionWithScrolls() {
<Container>
<div className="relative md:h-full">
<div className="flex flex-col md:flex-row justify-between h-full items-start">
<div ref={ref} className="mx-auto max-sm:max-w-[400px] max-sm:mt-12 lg:mt-[8rem]">
<div
ref={ref}
className="mx-auto max-sm:max-w-[400px] max-sm:mt-12 lg:mt-[8rem]"
>
<GradualSpacing
textClassName="justify-start"
visiblity={isInView}
Expand Down Expand Up @@ -55,9 +59,7 @@ export default function FUIDarkHeroSectionWithScrolls() {
Book a call
</button>
</Link>
<button className="flex gap-2 justify-center items-center py-2 max-sm:px-4 px-10 mt-5 text-lg tracking-tighter text-center bg-black rounded-xl ring-2 ring-offset-2 transition-all hover:ring-transparent group/button w-fit font-geist text-md text-white ring-white/80 ring-offset-black hover:scale-[1.02] active:scale-[0.98] active:ring-white/70">
Share your vision
</button>
<ShareYourVision />
</div>
</div>

Expand Down
28 changes: 28 additions & 0 deletions components/main/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use client";
import * as React from "react";
import { cn } from "@/lib/utils";

const Input = React.forwardRef<HTMLInputElement, React.InputHTMLAttributes<HTMLInputElement>>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
`flex h-10 w-full border-none bg-slate-950 text-white shadow-input rounded-xl px-3 py-2 text-sm file:border-0 file:bg-transparent
file:text-sm file:font-medium placeholder:text-neutral-400 placeholder-text-neutral-600
focus-visible:outline-none focus-visible:ring-[2px]
disabled:cursor-not-allowed disabled:opacity-50
shadow-[0px_0px_1px_1px_var(--neutral-700)]
group-hover/input:shadow-none transition duration-400
`,
className
)}
ref={ref}
{...props}
/>
);
}
);
Input.displayName = "Input";

export { Input };
188 changes: 188 additions & 0 deletions components/main/share-your-vision.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Input } from "./input";
import { useState } from "react";
import { useToast } from "@/hooks/use-toast";

export const ShareYourVision = () => {
const [loading, setLoading] = useState(false);
const { toast } = useToast();
const accessKey = process.env.NEXT_PUBLIC_WEB3FORM_ACCESS_KEY as string;

const schema = z.object({
name: z.string().min(3, "Name is too short"),
email: z.string().email("Invalid email address"),
projectIdea: z.string().min(10, "Project idea is too short"),
access_key: z.string().default(accessKey),
xUsername: z.string().optional(),
});

const form = useForm<z.infer<typeof schema>>({
resolver: zodResolver(schema),
});

const onValueChange = (e: React.ChangeEvent<HTMLInputElement>) => {
form.setValue(
e.target.name as keyof z.infer<typeof schema>,
e.target.value
);
};

const onSubmit = async (data: z.infer<typeof schema>) => {
setLoading(true);
const response = await fetch("https://api.web3forms.com/submit", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({
access_key: data.access_key,
name: data.name,
email: data.email,
message: data.projectIdea,
X: data.xUsername,
}),
});
const result = await response.json();
if (result.success) {
toast({ title: result.message, variant: "success" });
form.reset();
} else {
toast({ title: result.message, variant: "destructive" });
form.reset();
}
setLoading(false);
};
return (
<Dialog>
<DialogTrigger asChild>
<button className="flex gap-2 justify-center items-center py-2 max-sm:px-4 px-10 mt-5 text-lg tracking-tighter text-center bg-black rounded-xl ring-2 ring-offset-2 transition-all hover:ring-transparent group/button w-fit font-geist text-md text-white ring-white/80 ring-offset-black hover:scale-[1.02] active:scale-[0.98] active:ring-white/70">
Share your vision
</button>
</DialogTrigger>
<DialogContent className="bg-black w-full max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="text-xl font-semibold">
Share your vision
</DialogTitle>
<DialogDescription className="text-gray-500">
Tell us about your project idea. We&apos;ll get back to you soon!
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form
className="flex flex-col items-center justify-start w-full gap-3"
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Name</FormLabel>
<FormControl>
<Input
disabled={loading}
className="bg-slate-800"
{...field}
onChange={onValueChange}
placeholder="John Doe"
/>
</FormControl>
<FormMessage className="text-xs text-red-500 text-end" />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Email Address</FormLabel>
<FormControl>
<Input
disabled={loading}
className="bg-slate-800"
{...field}
onChange={onValueChange}
placeholder="[email protected]"
/>
</FormControl>
<FormMessage className="text-xs text-red-500 text-end" />
</FormItem>
)}
/>
<FormField
control={form.control}
name="projectIdea"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>Project Idea</FormLabel>
<FormControl>
<textarea
disabled={loading}
rows={3}
className="bg-slate-800 w-full px-3 py-2 rounded-xl text-sm flex border-none text-white shadow-input file:border-0 file:bg-transparent
file:text-sm file:font-medium placeholder:text-neutral-400 placeholder-text-neutral-600
focus-visible:outline-none focus-visible:ring-[2px]
disabled:cursor-not-allowed disabled:opacity-50
shadow-[0px_0px_1px_1px_var(--neutral-700)]
group-hover/input:shadow-none transition duration-400"
{...field}
placeholder="Project Idea.."
/>
</FormControl>
<FormMessage className="text-xs text-red-500 text-end" />
</FormItem>
)}
/>
<FormField
control={form.control}
name="xUsername"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel>X (optional)</FormLabel>
<FormControl>
<Input
disabled={loading}
className="bg-slate-800"
{...field}
onChange={onValueChange}
placeholder="@username"
/>
</FormControl>
<FormMessage className="text-xs text-red-500 text-end" />
</FormItem>
)}
/>
<button
className="flex border rounded-xl w-full justify-center items-center h-10 bg-gradient-to-r from-sky-700 to-pink-700 mt-4 hover:from-sky-800 hover:to-pink-800 transition-colors duration-150 delay-150"
type="submit"
disabled={loading}
>
{loading ? "Please wait..." : "Submit Your Vision"}
</button>
</form>
</Form>
</DialogContent>
</Dialog>
);
};
Loading