diff --git a/app/(default)/event/_components/eventheader.tsx b/app/(default)/event/_components/eventheader.tsx
new file mode 100644
index 00000000..1dd22dfb
--- /dev/null
+++ b/app/(default)/event/_components/eventheader.tsx
@@ -0,0 +1,49 @@
+
+import { cn } from '@/lib/utils';
+import { UsersIcon } from '@heroicons/react/24/solid'
+import { HoverBorderGradient } from '@/components/ui/hover-border-gradient';
+import React from 'react'
+
+function EventHeader() {
+ return (
+
+
+
+
+
+ Events
+
+
+
+ Events
+
+
+ Explore Keploy events and webinars. Learn from each other, move forward together, and celebrate what’s next. Whether you’re a developer, architect, tester, community manager, or something in-between, you’ll find something here.
+
+
+
+ )
+}
+
+
+function HoverBorderGradientChip({
+ children,
+ className,
+}: {
+ children: React.ReactNode;
+ className?: string;
+}) {
+ return (
+
+
+ {children}
+
+
+ );
+}
+
+export default EventHeader
\ No newline at end of file
diff --git a/app/(default)/event/_components/header.tsx b/app/(default)/event/_components/header.tsx
new file mode 100644
index 00000000..299097c0
--- /dev/null
+++ b/app/(default)/event/_components/header.tsx
@@ -0,0 +1,111 @@
+"use client";
+
+import React, { useState, useEffect } from "react";
+import Link from "next/link";
+import MobileMenu from "@/components/ui/mobile-menu";
+import { FaSlack } from "react-icons/fa";
+import { StarIcon } from "@heroicons/react/24/solid";
+import CountingNumbers from "@/components/utils/countingNumbers";
+
+export default function Header() {
+ const [top, setTop] = useState(true);
+ const [starsCount, setStarsCount] = useState(0);
+
+ // detect whether user has scrolled the page down by 10px
+ const scrollHandler = () => {
+ window.pageYOffset > 10 ? setTop(false) : setTop(true);
+ };
+
+ useEffect(() => {
+ scrollHandler();
+ window.addEventListener("scroll", scrollHandler);
+ return () => {
+ window.removeEventListener("scroll", scrollHandler);
+ };
+ }, []);
+
+ useEffect(() => {
+ const fetchStarsCount = async () => {
+ try {
+ const response = await fetch(
+ "https://api.github.com/repos/keploy/keploy"
+ );
+ if (response.ok) {
+ const data = await response.json() as { stargazers_count: number };
+ const stars = data.stargazers_count;
+ return stars;
+ } else {
+ console.error("Failed to fetch stars count", response.statusText);
+ return 0; // Return a default value in case of error
+ }
+ } catch (error) {
+ console.error("Error fetching stars count:", error);
+ return 0; // Return a default value in case of error
+ }
+ };
+
+ void fetchStarsCount().then(setStarsCount);
+ }, []);
+
+ return (
+
+
+
+ {/* Site branding */}
+
+
+ {/* */}
+ Keploy
+
+
+
+ {/* Desktop navigation */}
+
+
+
+ {/* Sliding effect span */}
+
+
+
+
+ Github Logo
+
+
+
|
+
+
+
+
+
+
+
+
+
Join Slack
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/(default)/event/_data/events.ts b/app/(default)/event/_data/events.ts
new file mode 100644
index 00000000..09f2343e
--- /dev/null
+++ b/app/(default)/event/_data/events.ts
@@ -0,0 +1,94 @@
+export const events: EventType[] = [
+ {
+ id: 1,
+ title: "Keploy Meetup",
+ subtitle: "Keploy Meetup",
+ description: "Keploy Meetup",
+ startsAt: "2024-01-01",
+ duration: 60,
+ tags: ["Keploy", "Meetup"],
+ registerURL: "https://keploy.io",
+ createdAt: "2024-01-01",
+ updatedAt: "2024-01-01",
+ publishedAt: "2024-01-01",
+ banner: {
+ url: "https://keploy.io",
+ width: 100,
+ height: 100,
+ }
+ },
+ {
+ id: 1,
+ title: "Keploy Meetup",
+ subtitle: "Keploy Meetup",
+ description: "Keploy Meetup",
+ startsAt: "2024-01-01",
+ duration: 60,
+ tags: ["Keploy", "Meetup"],
+ registerURL: "https://keploy.io",
+ createdAt: "2024-01-01",
+ updatedAt: "2024-01-01",
+ publishedAt: "2024-01-01",
+ banner: {
+ url: "https://keploy.io",
+ width: 100,
+ height: 100,
+ }
+ },
+ {
+ id: 1,
+ title: "Keploy Meetup",
+ subtitle: "Keploy Meetup",
+ description: "Keploy Meetup",
+ startsAt: "2024-01-01",
+ duration: 60,
+ tags: ["Keploy", "Meetup"],
+ registerURL: "https://keploy.io",
+ createdAt: "2024-01-01",
+ updatedAt: "2024-01-01",
+ publishedAt: "2024-01-01",
+ banner: {
+ url: "https://keploy.io",
+ width: 100,
+ height: 100,
+ }
+ },
+ {
+ id: 1,
+ title: "Keploy Meetup",
+ subtitle: "Keploy Meetup",
+ description: "Keploy Meetup",
+ startsAt: "2024-01-01",
+ duration: 60,
+ tags: ["Keploy", "Meetup"],
+ registerURL: "https://keploy.io",
+ createdAt: "2024-01-01",
+ updatedAt: "2024-01-01",
+ publishedAt: "2024-01-01",
+ banner: {
+ url: "https://keploy.io",
+ width: 100,
+ height: 100,
+ }
+ }
+]
+
+
+export interface EventType {
+ id: number;
+ title: string;
+ subtitle: string;
+ description: string;
+ startsAt: string;
+ duration: number;
+ tags: string[];
+ registerURL: string | null;
+ createdAt: string;
+ updatedAt: string;
+ publishedAt: string;
+ banner: {
+ url: string;
+ width: number;
+ height: number;
+ };
+}
diff --git a/app/(default)/event/layout.tsx b/app/(default)/event/layout.tsx
new file mode 100644
index 00000000..cfd010ac
--- /dev/null
+++ b/app/(default)/event/layout.tsx
@@ -0,0 +1,36 @@
+import Header from './_components/header'
+
+import { Inter, Architects_Daughter } from 'next/font/google'
+
+
+const inter = Inter({
+ subsets: ['latin'],
+ variable: '--font-inter',
+ display: 'swap'
+})
+
+
+const architects_daughter = Architects_Daughter({
+ subsets: ['latin'],
+ variable: '--font-architects-daughter',
+ weight: '400',
+ display: 'swap'
+})
+
+export const metadata = {
+ title: "Events | Keploy",
+ description: "Keploy is your open-source, developer-centric backend testing tool. It makes backend testing easy and productive for engineering teams. Plus, it's easy-to-use, powerful and extensible. 🛠️Keploy creates test cases and data mocks/stubs from user-traffic by recording API calls and DB queries, significantly speeding up releases and enhancing reliability. 📈"
+}
+
+export default function EventLayout({ children, }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+ {children}
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/(default)/event/page.tsx b/app/(default)/event/page.tsx
new file mode 100644
index 00000000..beda3432
--- /dev/null
+++ b/app/(default)/event/page.tsx
@@ -0,0 +1,83 @@
+"use client"
+
+import React from 'react'
+import EventHeader from './_components/eventheader'
+import Button from '@mui/material/Button'
+
+import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@/components/ui/card'
+import { Badge } from '@/components/ui/badge'
+import { CalendarIcon, ClockIcon, } from '@heroicons/react/24/solid'
+import Image from 'next/image'
+import Link from 'next/link'
+
+import { events } from './_data/events'
+
+function EventPage() {
+ return (
+
+
+
+
+
+
+ {events.map((event, index) => (
+
+
+
+
+
+
+ {event.title}
+
+
+ {event.subtitle}
+
+
+
+
+
+
+ {new Date(event.startsAt).toLocaleString()}
+
+
+
+
+ {event.duration} minutes
+
+
+ {event.tags.slice(0, 3).map((tag, index) => (
+
+ {tag}
+
+ ))}
+
+
+
+
+
+ Register Now
+
+
+
+
+ ))}
+
+
+
+
+
+ )
+}
+
+export default EventPage
\ No newline at end of file
diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx
new file mode 100644
index 00000000..9cb0b878
--- /dev/null
+++ b/components/ui/badge.tsx
@@ -0,0 +1,39 @@
+/* eslint-disable @typescript-eslint/no-unsafe-argument */
+/* eslint-disable @typescript-eslint/no-unsafe-call */
+/* eslint-disable @typescript-eslint/no-unsafe-assignment */
+import * as React from "react"
+import { cva, type VariantProps } from "class-variance-authority"
+
+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",
+ {
+ variants: {
+ variant: {
+ default:
+ "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
+ secondary:
+ "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",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ },
+ }
+)
+
+export interface BadgeProps
+ extends React.HTMLAttributes,
+ VariantProps { }
+
+function Badge({ className, variant, ...props }: BadgeProps) {
+ return (
+
+ )
+}
+
+export { Badge, badgeVariants }
diff --git a/components/ui/card.tsx b/components/ui/card.tsx
new file mode 100644
index 00000000..5b8e64f7
--- /dev/null
+++ b/components/ui/card.tsx
@@ -0,0 +1,79 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+const Card = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+Card.displayName = "Card"
+
+const CardHeader = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardHeader.displayName = "CardHeader"
+
+const CardTitle = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardTitle.displayName = "CardTitle"
+
+const CardDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardDescription.displayName = "CardDescription"
+
+const CardContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardContent.displayName = "CardContent"
+
+const CardFooter = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+CardFooter.displayName = "CardFooter"
+
+export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
diff --git a/components/ui/hover-border-gradient.tsx b/components/ui/hover-border-gradient.tsx
new file mode 100644
index 00000000..5e710eec
--- /dev/null
+++ b/components/ui/hover-border-gradient.tsx
@@ -0,0 +1,101 @@
+'use client';
+import React, { useState, useEffect } from 'react';
+
+import { motion } from 'framer-motion';
+import { cn } from '@/lib/utils';
+
+type Direction = 'TOP' | 'LEFT' | 'BOTTOM' | 'RIGHT';
+
+export function HoverBorderGradient({
+ children,
+ containerClassName,
+ className,
+ as: Tag = 'button',
+ duration = 1,
+ clockwise = true,
+ ...props
+}: React.PropsWithChildren<
+ {
+ as?: React.ElementType;
+ containerClassName?: string;
+ className?: string;
+ duration?: number;
+ clockwise?: boolean;
+ } & React.HTMLAttributes
+>) {
+ const [hovered, setHovered] = useState(false);
+ const [direction, setDirection] = useState('TOP');
+
+ const rotateDirection = (currentDirection: Direction): Direction => {
+ const directions: Direction[] = ['TOP', 'LEFT', 'BOTTOM', 'RIGHT'];
+ const currentIndex = directions.indexOf(currentDirection);
+ const nextIndex = clockwise
+ ? (currentIndex - 1 + directions.length) % directions.length
+ : (currentIndex + 1) % directions.length;
+ return directions[nextIndex];
+ };
+
+ const movingMap: Record = {
+ TOP: 'radial-gradient(20.7% 50% at 50% 0%, #c8ff00 0%, rgba(200, 255, 0, 0) 100%)',
+ LEFT: 'radial-gradient(16.6% 43.1% at 0% 50%, #c8ff00 0%, rgba(200, 255, 0, 0) 100%)',
+ BOTTOM:
+ 'radial-gradient(20.7% 50% at 50% 100%, #c8ff00 0%, rgba(200, 255, 0, 0) 100%)',
+ RIGHT:
+ 'radial-gradient(16.2% 41.199999999999996% at 100% 50%, #c8ff00 0%, rgba(200, 255, 0, 0) 100%)',
+ };
+
+ const highlight =
+ 'radial-gradient(75% 181.15942028985506% at 50% 50%, #3275F8 0%, rgba(255, 255, 255, 0) 100%)';
+
+ useEffect(() => {
+ if (!hovered) {
+ const interval = setInterval(() => {
+ setDirection((prevState) => rotateDirection(prevState));
+ }, duration * 1000);
+ return () => { clearInterval(interval); };
+ }
+ }, [hovered]);
+ return (
+ ) => {
+ setHovered(true);
+ }}
+ onMouseLeave={() => {
+ setHovered(false);
+ }}
+ className={cn(
+ 'relative flex rounded-full border content-center bg-black/20 hover:bg-black/10 transition duration-500 dark:bg-white/20 items-center flex-col flex-nowrap gap-10 h-min justify-center overflow-visible p-px decoration-clone w-fit',
+ containerClassName
+ )}
+ {...props}
+ >
+
+ {children}
+
+
+
+
+ );
+}
diff --git a/components/utils/countingNumbers.tsx b/components/utils/countingNumbers.tsx
index 0d753fd3..1f231b9c 100644
--- a/components/utils/countingNumbers.tsx
+++ b/components/utils/countingNumbers.tsx
@@ -3,7 +3,7 @@
import { useInView } from "framer-motion";
import { useEffect, useRef, useState } from "react";
-const formatStars = (num:number)=>Intl.NumberFormat('en-US', {
+const formatStars = (num: number) => Intl.NumberFormat('en-US', {
notation: "compact",
maximumFractionDigits: 1
}).format(num);
@@ -47,7 +47,7 @@ export default function CountingNumbers({
"https://api.github.com/repos/keploy/keploy"
);
if (response.ok) {
- const data = await response.json();
+ const data = await response.json() as { stargazers_count: number };
// Use setStarsCount to update the state
setStarsCount(data.stargazers_count);
} else {
@@ -58,7 +58,7 @@ export default function CountingNumbers({
}
};
- fetchStarsCount();
+ void fetchStarsCount();
}, [starsCount]); // Include starsCount as a dependency
diff --git a/package-lock.json b/package-lock.json
index 31ff6423..0b51e32d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -30,6 +30,7 @@
"@types/react-dom": "^18.2.4",
"aos": "^3.0.0-beta.6",
"blitz": "^2.0.0-beta.31",
+ "class-variance-authority": "^0.7.0",
"clipboard": "^2.0.11",
"clsx": "^2.1.1",
"framer-motion": "^10.16.14",
@@ -4559,6 +4560,25 @@
"node": ">= 0.4"
}
},
+ "node_modules/class-variance-authority": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz",
+ "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==",
+ "dependencies": {
+ "clsx": "2.0.0"
+ },
+ "funding": {
+ "url": "https://joebell.co.uk"
+ }
+ },
+ "node_modules/class-variance-authority/node_modules/clsx": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
+ "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/classlist-polyfill": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz",
diff --git a/package.json b/package.json
index 372d0cb7..824f85ce 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
"@types/react-dom": "^18.2.4",
"aos": "^3.0.0-beta.6",
"blitz": "^2.0.0-beta.31",
+ "class-variance-authority": "^0.7.0",
"clipboard": "^2.0.11",
"clsx": "^2.1.1",
"framer-motion": "^10.16.14",